-
Notifications
You must be signed in to change notification settings - Fork 167
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pmm support #452
Pmm support #452
Changes from 1 commit
f5a2c5a
64e9925
4c19fad
15bc3dd
687b24a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -321,28 +321,79 @@ function check_misaligned(vaddr : xlenbits, width : word_width) -> bool = | |
WORD => vaddr[0] == bitone | vaddr[1] == bitone, | ||
DOUBLE => vaddr[0] == bitone | vaddr[1] == bitone | vaddr[2] == bitone | ||
} | ||
function transform_VA (effective_address : xlenbits,PMLEN :int) -> xlenbits = { | ||
assert(PMLEN >= 0, "PMLEN out of range"); | ||
assert(PMLEN <= 63, "PMLEN out of range"); | ||
let XLEN = sizeof(xlen); | ||
let i = XLEN -(PMLEN +1); | ||
let effective_bit = effective_address[i..i]; | ||
let NVBITS = replicate_bits(effective_bit, PMLEN); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: This naming isn't quite accurate – NVBITS/VBITS is independent of pointer masking. I think what these variables describe are masked_bits/unmasked_bits. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have modified the variable names as suggested. |
||
let VBITS = effective_address[i..0]; | ||
NVBITS @ VBITS | ||
} | ||
|
||
function transform_PA (effective_address : xlenbits,PMLEN :int) -> xlenbits = { | ||
assert(PMLEN >= 0, "PMLEN out of range"); | ||
assert(PMLEN <= 63, "PMLEN out of range"); | ||
let XLEN = sizeof(xlen); | ||
let i = XLEN -(PMLEN + 1); | ||
let NVBITS = replicate_bits(0b0, PMLEN); | ||
let VBITS = effective_address[i..0]; | ||
NVBITS @ VBITS | ||
} | ||
|
||
function transform_effective_address(vaddr : xlenbits, pmm : bool) -> xlenbits = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For misaligned addresses, will this be applied to each byte of the address or just the initial address? (the spec mandates the former.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Currently, the misaligned extension is not integrated into the Sail model. Therefore, I am applying Pointer Masking only to the initial address. However, once the integration is complete, we will need to apply Pointer Masking to each byte of the address. |
||
if pmm then { | ||
let pmm_bits : bits(2) = get_pmm(); | ||
let mode : SATPMode = translationMode(cur_privilege); | ||
match (mode) { | ||
(Sbare) => { | ||
match (pmm_bits){ | ||
(0b10) => transform_PA (vaddr,7), | ||
(0b11) => transform_PA (vaddr,16), | ||
} | ||
}, | ||
(Sv48) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How will Sv39 be handled? Also, does the current code cover 2-stage address translation? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At present, the sail model does not support Hyper Visor, and therefore, it does not cover the 2-stage address translation Yet. However, I am implementing the PM for Sv39 mode. |
||
match (pmm_bits){ | ||
(0b10) => transform_VA (vaddr,7), | ||
(0b11) => transform_VA (vaddr,16), | ||
} | ||
}, | ||
(Sv57) => { | ||
match (pmm_bits){ | ||
(0b10) => transform_VA (vaddr,7), | ||
} | ||
}, | ||
} | ||
} | ||
else { | ||
vaddr //PMM is not active | ||
} | ||
} | ||
|
||
function clause execute(LOAD(imm, rs1, rd, is_unsigned, width, aq, rl)) = { | ||
let pmm = is_pmm_active(); | ||
let offset : xlenbits = sign_extend(imm); | ||
/* Get the address, X(rs1) + offset. | ||
Some extensions perform additional checks on address validity. */ | ||
match ext_data_get_addr(rs1, offset, Read(Data), width) { | ||
Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, | ||
Ext_DataAddr_OK(vaddr) => | ||
if check_misaligned(vaddr, width) | ||
then { handle_mem_exception(vaddr, E_Load_Addr_Align()); RETIRE_FAIL } | ||
else match translateAddr(vaddr, Read(Data)) { | ||
TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, | ||
let vaddr_ = transform_effective_address(vaddr, pmm) in | ||
if check_misaligned(vaddr_, width) | ||
then { handle_mem_exception(vaddr_, E_Load_Addr_Align()); RETIRE_FAIL } | ||
else match translateAddr(vaddr_, Read(Data)) { | ||
TR_Failure(e, _) => { handle_mem_exception(vaddr_, e); RETIRE_FAIL }, | ||
TR_Address(paddr, _) => | ||
match (width) { | ||
BYTE => | ||
process_load(rd, vaddr, mem_read(Read(Data), paddr, 1, aq, rl, false), is_unsigned), | ||
process_load(rd, vaddr_, mem_read(Read(Data), paddr, 1, aq, rl, false), is_unsigned), | ||
HALF => | ||
process_load(rd, vaddr, mem_read(Read(Data), paddr, 2, aq, rl, false), is_unsigned), | ||
process_load(rd, vaddr_, mem_read(Read(Data), paddr, 2, aq, rl, false), is_unsigned), | ||
WORD => | ||
process_load(rd, vaddr, mem_read(Read(Data), paddr, 4, aq, rl, false), is_unsigned), | ||
process_load(rd, vaddr_, mem_read(Read(Data), paddr, 4, aq, rl, false), is_unsigned), | ||
DOUBLE if sizeof(xlen) >= 64 => | ||
process_load(rd, vaddr, mem_read(Read(Data), paddr, 8, aq, rl, false), is_unsigned), | ||
process_load(rd, vaddr_, mem_read(Read(Data), paddr, 8, aq, rl, false), is_unsigned), | ||
_ => report_invalid_width(__FILE__, __LINE__, width, "load") | ||
} | ||
} | ||
|
@@ -379,16 +430,18 @@ mapping clause encdec = STORE(imm7 @ imm5, rs2, rs1, size, false, false) | |
/* NOTE: Currently, we only EA if address translation is successful. | ||
This may need revisiting. */ | ||
function clause execute (STORE(imm, rs2, rs1, width, aq, rl)) = { | ||
let pmm = is_pmm_active(); | ||
let offset : xlenbits = sign_extend(imm); | ||
/* Get the address, X(rs1) + offset. | ||
Some extensions perform additional checks on address validity. */ | ||
match ext_data_get_addr(rs1, offset, Write(Data), width) { | ||
Ext_DataAddr_Error(e) => { ext_handle_data_check_error(e); RETIRE_FAIL }, | ||
Ext_DataAddr_OK(vaddr) => | ||
let vaddr_ = transform_effective_address(vaddr, pmm) in | ||
if check_misaligned(vaddr, width) | ||
then { handle_mem_exception(vaddr, E_SAMO_Addr_Align()); RETIRE_FAIL } | ||
else match translateAddr(vaddr, Write(Data)) { | ||
TR_Failure(e, _) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, | ||
then { handle_mem_exception(vaddr_, E_SAMO_Addr_Align()); RETIRE_FAIL } | ||
else match translateAddr(vaddr_, Write(Data)) { | ||
TR_Failure(e, _) => { handle_mem_exception(vaddr_, e); RETIRE_FAIL }, | ||
TR_Address(paddr, _) => { | ||
let eares : MemoryOpResult(unit) = match width { | ||
BYTE => mem_write_ea(paddr, 1, aq, rl, false), | ||
|
@@ -397,7 +450,7 @@ function clause execute (STORE(imm, rs2, rs1, width, aq, rl)) = { | |
DOUBLE => mem_write_ea(paddr, 8, aq, rl, false) | ||
}; | ||
match (eares) { | ||
MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL }, | ||
MemException(e) => { handle_mem_exception(vaddr_, e); RETIRE_FAIL }, | ||
MemValue(_) => { | ||
let rs2_val = X(rs2); | ||
let res : MemoryOpResult(bool) = match (width) { | ||
|
@@ -411,7 +464,7 @@ function clause execute (STORE(imm, rs2, rs1, width, aq, rl)) = { | |
match (res) { | ||
MemValue(true) => RETIRE_SUCCESS, | ||
MemValue(false) => internal_error(__FILE__, __LINE__, "store got false from mem_write_value"), | ||
MemException(e) => { handle_mem_exception(vaddr, e); RETIRE_FAIL } | ||
MemException(e) => { handle_mem_exception(vaddr_, e); RETIRE_FAIL } | ||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -91,7 +91,8 @@ val sys_enable_next = {c: "sys_enable_next", ocaml: "Platform.enable_next", _: " | |
/* Whether FIOM bit of menvcfg/senvcfg is enabled. It must be enabled if | ||
supervisor mode is implemented and non-bare addressing modes are supported. */ | ||
val sys_enable_writable_fiom = {c: "sys_enable_writable_fiom", ocaml: "Platform.enable_writable_fiom", _: "sys_enable_writable_fiom"} : unit -> bool | ||
|
||
/* whether the PME extension was enabled at boot */ | ||
val sys_enable_pmm = {c: "sys_enable_pmm", ocaml: "Platform.enable_pmm", _: "sys_enable_pmm"} : unit -> bool | ||
/* How many PMP entries are implemented. This must be 0, 16 or 64 (this is checked at runtime). */ | ||
val sys_pmp_count = {c: "sys_pmp_count", ocaml: "Platform.pmp_count", _: "sys_pmp_count"} : unit -> range(0, 64) | ||
/* G parameter that specifies the PMP grain size. The grain size is 2^(G+2), e.g. | ||
|
@@ -807,7 +808,11 @@ bitfield Envcfg : bits(64) = { | |
// Page Based Memory Types Extension | ||
PBMTE : 62, | ||
// Reserved WPRI bits. | ||
wpri_1 : 61 .. 8, | ||
wpri_2 : 61 .. 34, | ||
// PMM bits of Pointer Masking Extension | ||
PMM : 33 .. 32, | ||
// Reserved WPRI bits. | ||
wpri_1 : 31 .. 8, | ||
// Cache Block Zero instruction Enable | ||
CBZE : 7, | ||
// Cache Block Clean and Flush instruction Enable | ||
|
@@ -825,7 +830,9 @@ register senvcfg : Envcfg | |
|
||
function legalize_envcfg(o : Envcfg, v : bits(64)) -> Envcfg = { | ||
let v = Mk_Envcfg(v); | ||
let o = [o with FIOM = if sys_enable_writable_fiom() then v[FIOM] else 0b0]; | ||
let o = update_FIOM(o, if sys_enable_writable_fiom() then v.FIOM() else 0b0); | ||
// Update PMM field only if Pointer Masking is enabled and Written value is legal | ||
let o = update_PMM(o, if (sys_enable_pmm() & (sizeof(xlen) != 32) & (v.PMM() != 0b01)) then v.PMM() else o.PMM()); | ||
// Other extensions are not implemented yet so all other fields are read only zero. | ||
o | ||
} | ||
|
@@ -840,6 +847,26 @@ function is_fiom_active() -> bool = { | |
User => (menvcfg[FIOM] | senvcfg[FIOM]) == 0b1, | ||
} | ||
} | ||
|
||
// Return whether or not PMM is currently active, based on the current | ||
// privilege and the menvcfg,senvcfg and mseccfg settings. | ||
function is_pmm_active() -> bool = { | ||
match cur_privilege { | ||
Machine => (mseccfg.PMM() == 0b11 | mseccfg.PMM() == 0b10), | ||
Supervisor => (menvcfg.PMM() == 0b11 | menvcfg.PMM() == 0b10), | ||
User => ((menvcfg.PMM() == 0b11 | menvcfg.PMM() == 0b10) | (senvcfg.PMM() == 0b11 | senvcfg.PMM() == 0b10)), | ||
} | ||
} | ||
|
||
//Returns the PMM bits value depends on the Privilege mode | ||
function get_pmm() -> bits(2) = { | ||
match cur_privilege { | ||
Machine => mseccfg.PMM(), | ||
Supervisor => menvcfg.PMM(), | ||
User => senvcfg.PMM(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is only the case if the system has all of these privilege modes. For example, if a system does not have a supervisor mode, then menvcfg controls the user mode pointer masking. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have updated the logic here as mentioned. |
||
} | ||
} | ||
|
||
/* vector csrs */ | ||
register vstart : bits(16) /* use the largest possible length of vstart */ | ||
register vxsat : bits(1) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Here and throughout the PR, pmm is used to refer to pointer masking. I think "pm" or "zpm" would be a better naming (PMM stands for "pointer masking mode", which is only referring to the bits used to configure pointer masking).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That’s a great suggestion. I will proceed with changing it to "zpm".