Skip to content

Commit

Permalink
Initial implementation of cap PTE bits
Browse files Browse the repository at this point in the history
  • Loading branch information
PeterRugg committed Jun 1, 2020
1 parent 9e451f2 commit 3b4eecf
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 17 deletions.
23 changes: 20 additions & 3 deletions src_Core/ISA/ISA_Decls_Priv_S.bsv
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,8 @@ Integer pte_U_offset = 4; // Accessible-to-user-mode
Integer pte_G_offset = 5; // Global mapping
Integer pte_A_offset = 6; // Accessed
Integer pte_D_offset = 7; // Dirty
Integer pte_RSW_offset = 8; // Reserved for supervisor SW
Integer pte_cap_W_offset = 8;
Integer pte_cap_R_offset = 9;

This comment has been minimized.

Copy link
@nwf

nwf Jun 3, 2020

Member

These disagree with Sail (CTSRD-CHERI/sail-cheri-riscv@6fcae43), which places the StoreCap permission at 63 and the LoadCap permission at 62 in the PTE and leaves the RSW field alone. Confusingly, those (bits 63 and 62) are offsets 9 and 8 in the extended PTE flags field (extPte) in Sail, while RSW is offsets 9 and 8 in the base field (pteAttribs).

CTSRD-CHERI/sail-cheri-riscv#18 negates the sense of the StoreCap and LoadCap permissions to be inhibits, as done on CHERI-MIPS.

I don't particularly mind where the bits end up, really, but we should be consistent. (Though I think I like the high end a little better as it seems to me that a RSW field is likely a kind thing to provide for SW.)

This comment has been minimized.

Copy link
@PeterRugg

PeterRugg Jun 3, 2020

Author Collaborator

Well spotted! I assumed since the numbers lined up, you'd just trampled the RSW bit...

On negation the intention is to have the default (zero-filled?) to correspond to allowing cap load/store?

This comment has been minimized.

Copy link
@nwf

nwf Jun 3, 2020

Member

Right; the extended flags field is missing on sv32, so will be all-zeros, which is maximally permissive: tagged stores are OK and loads neither trap nor strip tags.


`ifdef RV32
Integer pte_PPN_0_offset = 10;
Expand Down Expand Up @@ -313,6 +314,14 @@ function Bit #(1) fn_PTE_to_D (PTE pte);
return pte [pte_D_offset];
endfunction

function Bit #(1) fn_PTE_to_cap_W (PTE pte);
return pte [pte_cap_W_offset];
endfunction

function Bit #(1) fn_PTE_to_cap_R (PTE pte);
return pte [pte_cap_R_offset];
endfunction

function PPN fn_PTE_to_PPN (PTE pte);
return pte [ppn_sz + pte_PPN_0_offset - 1 : pte_PPN_0_offset];
endfunction
Expand Down Expand Up @@ -355,6 +364,7 @@ endfunction

function Bool is_pte_denial (Bool dmem_not_imem, // load-store or fetch?
Bool read_not_write,
Bool capability,
Priv_Mode priv,
Bit #(1) sstatus_SUM,
Bit #(1) mstatus_MXR,
Expand All @@ -365,21 +375,28 @@ function Bool is_pte_denial (Bool dmem_not_imem, // load-store or f
let pte_w = fn_PTE_to_W (pte);
let pte_r = fn_PTE_to_R (pte);

let pte_cap_w = fn_PTE_to_cap_W(pte);
// pte_cap_r would not cause a denial

Bool priv_deny = ( ((priv == u_Priv_Mode) && (pte_u == 1'b0))
|| ((priv == s_Priv_Mode) && (pte_u == 1'b1) && (sstatus_SUM == 1'b0)));

Bool access_fetch = ((! dmem_not_imem) && read_not_write);
Bool access_load = (dmem_not_imem && read_not_write);
Bool access_store = (dmem_not_imem && (! read_not_write));
Bool access_cap = (dmem_not_imem && capability);

let pte_r_mxr = (pte_r | (mstatus_MXR & pte_x));

Bool access_ok = ( (access_fetch && (pte_x == 1'b1))
|| (access_load && (pte_r_mxr == 1'b1))
|| (access_store && (pte_w == 1'b1)));


return (priv_deny || (! access_ok));
Bool access_cap_ok = (! capability)
|| (access_load)
|| (access_store && (pte_cap_w == 1'b1));

return (priv_deny || (! access_ok) || (! access_cap_ok));
endfunction

// ----------------
Expand Down
34 changes: 21 additions & 13 deletions src_Core/Near_Mem_VM/MMU_Cache.bsv
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,7 @@ module mkMMU_Cache #(parameter Bool dmem_not_imem,
`endif
Reg #(WordXL) rg_addr <- mkRegU; // VA or PA
Reg #(Tuple2#(Bool, Bit #(128))) rg_st_amo_val <- mkRegU; // Store-value for ST, SC, AMO
Reg #(Bool) rg_allow_cap <- mkRegU; // Whether load result is allowed to be tagged by VM page bits

// The following are needed for VM
`ifdef ISA_PRIV_S
Expand Down Expand Up @@ -583,9 +584,9 @@ module mkMMU_Cache #(parameter Bool dmem_not_imem,
Reg #(Bool) dw_exc <- mkDWire (False);
Reg #(Exc_Code) rg_exc_code <- mkRegU;
Reg #(Exc_Code) dw_exc_code <- mkDWire (?);
Reg #(Tuple2#(Bool, Bit#(128))) rg_ld_val <- mkRegU; // Load-value for LOAD/LR/AMO, success/fail for SC
Reg #(Tuple2#(Bool, Bit#(128))) dw_output_ld_val <- mkDWire (?);
Reg #(Tuple2#(Bool, Bit#(128))) dw_output_st_amo_val <- mkDWire (?); // stored value for ST, SC, AMO (for verification only)
Reg #(Tuple2#(Bool, Bit#(128))) rg_ld_val <- mkReg(tuple2(False, ?)); // Load-value for LOAD/LR/AMO, success/fail for SC
Reg #(Tuple2#(Bool, Bit#(128))) dw_output_ld_val <- mkDWire (tuple2(False, ?));
Reg #(Tuple2#(Bool, Bit#(128))) dw_output_st_amo_val <- mkDWire (tuple2(False, ?)); // stored value for ST, SC, AMO (for verification only)

// This reg is used during PTWs
Reg #(PA) rg_pte_pa <- mkRegU;
Expand Down Expand Up @@ -685,11 +686,13 @@ module mkMMU_Cache #(parameter Bool dmem_not_imem,
// Functions to drive read-responses (outputs)

// Memory-read responses
function Action fa_drive_mem_rsp (Bit #(3) width_code, Bool is_unsigned, Addr addr, Cache_Entry ld_val, Cache_Entry st_amo_val, Bool commit);
function Action fa_drive_mem_rsp (Bit #(3) width_code, Bool is_unsigned, Addr addr, Cache_Entry ld_val, Cache_Entry st_amo_val, Bool allow_cap, Bool commit);
action
dw_valid <= commit;
// Value loaded into rd (LOAD, LR, AMO, SC success/fail result)
dw_output_ld_val <= fn_extract_and_extend_bytes (width_code, is_unsigned, addr, ld_val);
let extracted = fn_extract_and_extend_bytes (width_code, is_unsigned, addr, ld_val);
if (!allow_cap) extracted = tuple2(False, tpl_2(extracted));
dw_output_ld_val <= extracted;
// Value stored into mem (STORE, SC, AMO final value stored)
dw_output_st_amo_val <= tuple2(tpl_1(st_amo_val)[(valueOf(CLEN) == 64 && addr[4:0] == 0) ? 1 : 0] == 1'b1, tpl_2(st_amo_val));
if (cfg_verbosity > 1)
Expand All @@ -699,10 +702,11 @@ module mkMMU_Cache #(parameter Bool dmem_not_imem,
endfunction

// IO-read responses
function Action fa_drive_IO_read_rsp (Bit #(3) width_code, Bool is_unsigned, Addr addr, Tuple2#(Bool, Bit #(128)) ld_val);
function Action fa_drive_IO_read_rsp (Bit #(3) width_code, Bool is_unsigned, Addr addr, Tuple2#(Bool, Bit #(128)) ld_val, Bool allow_cap);
action
dw_valid <= True;
// Value loaded into rd (LOAD, LR, AMO, SC success/fail result)
if (!allow_cap) ld_val = tuple2(False, tpl_2(ld_val));
dw_output_ld_val <= ld_val;
if (cfg_verbosity > 1)
$display ("%0d: %s.drive_IO_read_rsp: addr 0x%0h ld_val 0x%0h", cur_cycle, d_or_i, addr, ld_val);
Expand Down Expand Up @@ -936,6 +940,7 @@ module mkMMU_Cache #(parameter Bool dmem_not_imem,
tlb_result,
dmem_not_imem,
((rg_op == CACHE_LD) || is_AMO_LR),
tpl_1(rg_st_amo_val),
rg_priv,
rg_sstatus_SUM,
rg_mstatus_MXR);
Expand Down Expand Up @@ -967,6 +972,7 @@ module mkMMU_Cache #(parameter Bool dmem_not_imem,
`endif

rg_pa <= vm_xlate_result.pa;
rg_allow_cap <= vm_xlate_result.allow_cap;
let is_mem_addr = soc_map.m_is_mem_addr (fn_PA_to_Fabric_Addr (vm_xlate_result.pa));

// Access to non-memory
Expand All @@ -989,7 +995,7 @@ module mkMMU_Cache #(parameter Bool dmem_not_imem,
if ((rg_op == CACHE_LD) || is_AMO_LR || (! dmem_not_imem)) begin
if (hit) begin
// Cache hit; drive response
fa_drive_mem_rsp (rg_width_code, rg_is_unsigned, rg_addr, word128, unpack(0), dw_commit);
fa_drive_mem_rsp (rg_width_code, rg_is_unsigned, rg_addr, word128, unpack(0), vm_xlate_result.allow_cap, dw_commit);

`ifdef ISA_A
if (is_AMO_LR) begin
Expand Down Expand Up @@ -1091,7 +1097,7 @@ module mkMMU_Cache #(parameter Bool dmem_not_imem,
else begin // do_write == False
// SC fail
// Hard-code address to 0 to ensure fn_extract_and_extend_bytes takes the LSBs of our 1 value.
fa_drive_mem_rsp (rg_width_code, rg_is_unsigned, 0, tuple2(0,1), unpack(0), dw_commit);
fa_drive_mem_rsp (rg_width_code, rg_is_unsigned, 0, tuple2(0,1), unpack(0), False, dw_commit);
if (cfg_verbosity > 1)
$display (" AMO SC: Fail response for addr 0x%0h", rg_addr);
end
Expand Down Expand Up @@ -1635,7 +1641,9 @@ module mkMMU_Cache #(parameter Bool dmem_not_imem,

rule rl_ST_AMO_response (rg_state == CACHE_ST_AMO_RSP && dmem_not_imem);
dw_valid <= True;
dw_output_ld_val <= rg_ld_val; // Irrelevant for ST; relevant for SC, AMO
let ld_val = rg_ld_val;
if (!rg_allow_cap) ld_val = tuple2(False, tpl_2(ld_val));
dw_output_ld_val <= ld_val; // Irrelevant for ST; relevant for SC, AMO
dw_output_st_amo_val <= rg_st_amo_val;
endrule

Expand Down Expand Up @@ -1687,7 +1695,7 @@ module mkMMU_Cache #(parameter Bool dmem_not_imem,

// Successful read
if (rd_data.rresp == OKAY) begin
fa_drive_IO_read_rsp (rg_width_code, rg_is_unsigned, rg_addr, ld_val);
fa_drive_IO_read_rsp (rg_width_code, rg_is_unsigned, rg_addr, ld_val, rg_allow_cap);
rg_state <= IO_READ_RSP;
end

Expand All @@ -1705,7 +1713,7 @@ module mkMMU_Cache #(parameter Bool dmem_not_imem,
rg_lower_word64 <= rd_data.rdata;
end else begin // rg_lower_word64_full && rd_data.rlast
if (rd_data.rresp == OKAY) begin
fa_drive_IO_read_rsp(rg_width_code, rg_is_unsigned, rg_addr, tuple2(False, {rd_data.rdata, rg_lower_word64})); // No tags from IO mem
fa_drive_IO_read_rsp(rg_width_code, rg_is_unsigned, rg_addr, tuple2(False, {rd_data.rdata, rg_lower_word64}), rg_allow_cap); // No tags from IO mem
rg_ld_val <= tuple2(False, {rd_data.rdata, rg_lower_word64});
rg_lower_word64_full <= False;
end else begin
Expand All @@ -1724,7 +1732,7 @@ module mkMMU_Cache #(parameter Bool dmem_not_imem,
// Stays in this state until CPU's next request puts it back into RUNNING state

rule rl_maintain_io_read_rsp (!resetting && rg_state == IO_READ_RSP && dmem_not_imem);
fa_drive_IO_read_rsp (rg_width_code, rg_is_unsigned, rg_addr, rg_ld_val);
fa_drive_IO_read_rsp (rg_width_code, rg_is_unsigned, rg_addr, rg_ld_val, rg_allow_cap);
endrule

// ----------------------------------------------------------------
Expand Down Expand Up @@ -1838,7 +1846,7 @@ module mkMMU_Cache #(parameter Bool dmem_not_imem,
// Write back new st_val to fabric
fa_fabric_send_write_req (rg_width_code, rg_pa, new_st_val);

fa_drive_IO_read_rsp (rg_width_code, rg_is_unsigned, rg_addr, new_ld_val);
fa_drive_IO_read_rsp (rg_width_code, rg_is_unsigned, rg_addr, new_ld_val, rg_allow_cap);
rg_ld_val <= new_ld_val;
rg_state <= IO_READ_RSP;

Expand Down
5 changes: 4 additions & 1 deletion src_Core/Near_Mem_VM/TLB.bsv
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ deriving (Bits, Eq, FShow);

typedef struct {
VM_Xlate_Outcome outcome;
Bool allow_cap; // whether we will be allowed to load a cap
PA pa; // phys addr, if VM_XLATE_OK
Exc_Code exc_code; // if VM_XLATE_EXC
Bool pte_modified; // if VM_XLATE_OK and pte's A or D bits were modified
Expand All @@ -363,6 +364,7 @@ function ActionValue #(VM_Xlate_Result) fav_vm_xlate (WordXL addr,
TLB_Lookup_Result tlb_result,
Bool dmem_not_imem,
Bool read_not_write,
Bool capability,
Priv_Mode priv,
Bit #(1) sstatus_SUM,
Bit #(1) mstatus_MXR);
Expand All @@ -385,7 +387,7 @@ function ActionValue #(VM_Xlate_Result) fav_vm_xlate (WordXL addr,

if (xlate) begin
if (tlb_result.hit) begin
Bool deny = is_pte_denial (dmem_not_imem, read_not_write, priv, sstatus_SUM, mstatus_MXR, pte);
Bool deny = is_pte_denial (dmem_not_imem, read_not_write, capability, priv, sstatus_SUM, mstatus_MXR, pte);
if (deny) begin
outcome = VM_XLATE_EXCEPTION;
exc_code = fn_page_fault_exc_code (dmem_not_imem, read_not_write);
Expand Down Expand Up @@ -434,6 +436,7 @@ function ActionValue #(VM_Xlate_Result) fav_vm_xlate (WordXL addr,
outcome = VM_XLATE_TLB_MISS;
end
return VM_Xlate_Result {outcome: outcome,
allow_cap: fn_PTE_to_cap_R(pte) == 1'b1,
pa: pa,
exc_code: exc_code,
pte_modified: pte_modified,
Expand Down

0 comments on commit 3b4eecf

Please sign in to comment.