Merge branch 'mem_perm_checks' into CHERI
This commit is contained in:
Submodule libs/cheri-cap-lib updated: abfcb20d03...a812edaffa
@@ -686,7 +686,7 @@ module mkFetchStage(FetchStage);
|
||||
f12f2.deq;
|
||||
|
||||
// Get TLB response
|
||||
match {.phys_pc, .cause} <- tlb_server.response.get;
|
||||
match {.phys_pc, .cause, .allow_cap} <- tlb_server.response.get;
|
||||
|
||||
// Access main mem or boot rom if no TLB exception
|
||||
Bool access_mmio = False;
|
||||
|
||||
@@ -108,6 +108,8 @@ typedef struct {
|
||||
ByteEn store_data_BE;
|
||||
`endif
|
||||
Bool misaligned;
|
||||
Bool capStore;
|
||||
Bool allowCap;
|
||||
Maybe#(CSR_XCapCause) capException;
|
||||
Maybe#(BoundsCheck) check;
|
||||
} MemExeToFinish deriving(Bits, FShow);
|
||||
@@ -158,7 +160,8 @@ module mkDTlbSynth(DTlbSynth);
|
||||
write: (case(x.mem_func)
|
||||
St, Sc, Amo: True;
|
||||
default: False;
|
||||
endcase)
|
||||
endcase),
|
||||
cap: x.capStore
|
||||
};
|
||||
endfunction
|
||||
let m <- mkDTlb(getTlbReq);
|
||||
@@ -448,7 +451,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
if(x.regs.src1 matches tagged Valid .src1 &&& src1 != 0) begin
|
||||
rVal1 <- readRFBypass(src1, regsReady.src1, inIfc.rf_rd1(src1), bypassWire);
|
||||
end
|
||||
if (x.ddc_offset) rVal1 = nullWithAddr(getAddr(rVal1) + getAddr(ddc));
|
||||
if (x.ddc_offset) rVal1 = incOffset(ddc, getAddr(rVal1)).value;
|
||||
|
||||
// get rVal2 (check bypass)
|
||||
CapPipe rVal2 = nullCap;
|
||||
@@ -524,7 +527,9 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
store_data_BE: origBE,
|
||||
`endif
|
||||
misaligned: memAddrMisaligned(getAddr(vaddr), origBE),
|
||||
capException: capChecks(x.rVal1, x.rVal2, ddc, x.cap_checks, ?),
|
||||
capStore: isValidCap(data) && pack(origBE) == ~0,
|
||||
allowCap: getHardPerms(x.rVal1).permitLoadCap,
|
||||
capException: capChecksMem(x.rVal1, x.rVal2, x.cap_checks, x.mem_func, origBE),
|
||||
check: prepareBoundsCheck(x.rVal1, x.rVal2, almightyCap/*ToDo: pcc*/,
|
||||
ddc, getAddr(vaddr), pack(countOnes(pack(origBE))), x.cap_checks)
|
||||
},
|
||||
@@ -536,7 +541,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
dTlb.deqProcResp;
|
||||
let dTlbResp = dTlb.procResp;
|
||||
let x = dTlbResp.inst;
|
||||
let {paddr, expCause} = dTlbResp.resp;
|
||||
let {paddr, expCause, allowCapPTE} = dTlbResp.resp;
|
||||
Maybe#(Trap) cause = Invalid;
|
||||
if (expCause matches tagged Valid .c) cause = Valid(Exception(c));
|
||||
|
||||
@@ -620,7 +625,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
|
||||
// update LSQ
|
||||
LSQUpdateAddrResult updRes <- lsq.updateAddr(
|
||||
x.ldstq_tag, cause, paddr, isMMIO, x.shiftedBE
|
||||
x.ldstq_tag, cause, x.allowCap && allowCapPTE, paddr, isMMIO, x.shiftedBE
|
||||
);
|
||||
|
||||
// issue non-MMIO Ld which has no exception and is not waiting for
|
||||
@@ -745,7 +750,9 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
LSQRespLdResult res <- lsq.respLd(tag, data);
|
||||
if(verbose) $display("%t : ", $time, rule_name, " ", fshow(tag), "; ", fshow(data), "; ", fshow(res));
|
||||
if(res.dst matches tagged Valid .dst) begin
|
||||
inIfc.writeRegFile(dst.indx, fromMem(unpack(pack(res.data))));
|
||||
CapPipe dataUnpacked = fromMem(unpack(pack(res.data)));
|
||||
dataUnpacked = setValidCap(dataUnpacked, res.allowCap && isValidCap(dataUnpacked));
|
||||
inIfc.writeRegFile(dst.indx, dataUnpacked);
|
||||
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
inIfc.rob_setExecuted_doFinishMem_RegData (res.instTag, res.data);
|
||||
@@ -908,7 +915,9 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
MemTaggedData resp = gatherLoad(lsqDeqLd.paddr, lsqDeqLd.byteEn, lsqDeqLd.unsignedLd, d);
|
||||
// write reg file & set ROB as Executed & wakeup rs
|
||||
if(lsqDeqLd.dst matches tagged Valid .dst) begin
|
||||
inIfc.writeRegFile(dst.indx, fromMem(unpack(pack(resp))));
|
||||
CapPipe dataUnpacked = fromMem(unpack(pack(resp)));
|
||||
dataUnpacked = setValidCap(dataUnpacked, lsqDeqLd.allowCap && isValidCap(dataUnpacked));
|
||||
inIfc.writeRegFile(dst.indx, dataUnpacked);
|
||||
inIfc.setRegReadyAggr_mem(dst.indx);
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
inIfc.rob_setExecuted_doFinishMem_RegData (lsqDeqLd.instTag, resp);
|
||||
@@ -996,7 +1005,9 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
MemTaggedData resp = gatherLoad(lsqDeqLd.paddr, lsqDeqLd.byteEn, lsqDeqLd.unsignedLd, d);
|
||||
// write reg file & wakeup rs (this wakeup is late but MMIO is rare) & set ROB as Executed
|
||||
if(lsqDeqLd.dst matches tagged Valid .dst) begin
|
||||
inIfc.writeRegFile(dst.indx, fromMem(tuple2(resp.tag,unpack(pack(resp.data)))));
|
||||
CapPipe dataUnpacked = fromMem(tuple2(resp.tag,unpack(pack(resp.data))));
|
||||
dataUnpacked = setValidCap(dataUnpacked, lsqDeqLd.allowCap && isValidCap(dataUnpacked));
|
||||
inIfc.writeRegFile(dst.indx, dataUnpacked);
|
||||
inIfc.setRegReadyAggr_mem(dst.indx);
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
inIfc.rob_setExecuted_doFinishMem_RegData (lsqDeqLd.instTag, resp);
|
||||
@@ -1249,7 +1260,9 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
MemTaggedData resp <- toGet(respLrScAmoQ).get;
|
||||
// write reg file & set ROB as Executed & wake up rs
|
||||
if(lsqDeqSt.dst matches tagged Valid .dst) begin
|
||||
inIfc.writeRegFile(dst.indx, fromMem(tuple2(resp.tag, pack(resp.data))));
|
||||
CapPipe dataUnpacked = fromMem(tuple2(resp.tag, pack(resp.data)));
|
||||
dataUnpacked = setValidCap(dataUnpacked, False); // TODO no allowCap around. Can a cap be loaded this way (e.g. AMOSWAP?)
|
||||
inIfc.writeRegFile(dst.indx, dataUnpacked);
|
||||
inIfc.setRegReadyAggr_mem(dst.indx);
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
inIfc.rob_setExecuted_doFinishMem_RegData (lsqDeqSt.instTag, resp);
|
||||
@@ -1355,7 +1368,9 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline);
|
||||
MemTaggedData resp = inIfc.mmioRespVal.data;
|
||||
// write reg file & wakeup rs (this wakeup is late but MMIO is rare) & set ROB as Executed
|
||||
if(lsqDeqSt.dst matches tagged Valid .dst) begin
|
||||
inIfc.writeRegFile(dst.indx, fromMem(tuple2(resp.tag, pack(resp.data))));
|
||||
CapPipe dataUnpacked = fromMem(tuple2(resp.tag, pack(resp.data)));
|
||||
dataUnpacked = setValidCap(dataUnpacked, False); // TODO no allowCap around. Can a cap be loaded this way (e.g. AMOSWAP?)
|
||||
inIfc.writeRegFile(dst.indx, dataUnpacked);
|
||||
inIfc.setRegReadyAggr_mem(dst.indx);
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
inIfc.rob_setExecuted_doFinishMem_RegData (lsqDeqSt.instTag, resp);
|
||||
|
||||
@@ -705,7 +705,7 @@ module mkRenameStage#(RenameInput inIfc)(RenameStage);
|
||||
"Mem (non-Fence) needs imm for virtual addr");
|
||||
// put in ldstq
|
||||
if(isLdQ) begin
|
||||
lsq.enqLd(inst_tag, mem_inst, phy_regs.dst, spec_bits);
|
||||
lsq.enqLd(inst_tag, mem_inst, allow_cap, phy_regs.dst, spec_bits);
|
||||
end
|
||||
else begin
|
||||
lsq.enqSt(inst_tag, mem_inst, phy_regs.dst, spec_bits);
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
`CAP_CHECK_FIELD(src1_type_not_reserved,"src1_type_not_reserved")
|
||||
`CAP_CHECK_FIELD(src1_perm_subset_src2,"src1_perm_subset_src2")
|
||||
`CAP_CHECK_FIELD(src1_derivable,"src1_derivable")
|
||||
`CAP_CHECK_FIELD(scr_read_only,"scr_read_only")
|
||||
`CAP_CHECK_FIELD(cfromptr_bypass,"cfromptr_bypass")
|
||||
`CAP_CHECK_FIELD(ccseal_bypass,"ccseal_bypass")
|
||||
`CAP_CHECK_FIELD(cap_exact,"cap_exact")
|
||||
|
||||
@@ -271,15 +271,18 @@ module mkDTlb#(
|
||||
end
|
||||
else if(pRs.entry matches tagged Valid .en) begin
|
||||
// check permission
|
||||
if(hasVMPermission(vm_info,
|
||||
en.pteType,
|
||||
en.ppn,
|
||||
en.level,
|
||||
r.write ? DataStore : DataLoad)) begin
|
||||
let permCheck = hasVMPermission(vm_info,
|
||||
en.pteType,
|
||||
en.pteUpperType,
|
||||
en.ppn,
|
||||
en.level,
|
||||
r.write ? DataStore : DataLoad,
|
||||
r.cap);
|
||||
if (permCheck.allowed) begin
|
||||
// fill TLB, and record resp
|
||||
tlb.addEntry(en);
|
||||
let trans_addr = translate(r.addr, en.ppn, en.level);
|
||||
pendResp[idx] <= tuple2(trans_addr, Invalid);
|
||||
pendResp[idx] <= tuple3(trans_addr, Invalid, permCheck.allowCap);
|
||||
if(verbose) begin
|
||||
$display("[DTLB] refill: idx %d; ", idx, fshow(r),
|
||||
"; ", fshow(trans_addr));
|
||||
@@ -287,8 +290,8 @@ module mkDTlb#(
|
||||
end
|
||||
else begin
|
||||
// page fault
|
||||
Exception fault = r.write ? excStorePageFault : excLoadPageFault;
|
||||
pendResp[idx] <= tuple2(?, Valid (fault));
|
||||
Exception fault = permCheck.excCode;
|
||||
pendResp[idx] <= tuple3(?, Valid (fault), False);
|
||||
if(verbose) begin
|
||||
$display("[DTLB] refill no permission: idx %d; ", idx, fshow(r));
|
||||
end
|
||||
@@ -297,7 +300,7 @@ module mkDTlb#(
|
||||
else begin
|
||||
// page fault
|
||||
Exception fault = r.write ? excStorePageFault : excLoadPageFault;
|
||||
pendResp[idx] <= tuple2(?, Valid (fault));
|
||||
pendResp[idx] <= tuple3(?, Valid (fault), False);
|
||||
if(verbose) $display("[DTLB] refill page fault: idx %d; ", idx, fshow(r));
|
||||
end
|
||||
|
||||
@@ -433,7 +436,7 @@ module mkDTlb#(
|
||||
// (Because we are always non speculative in M mode)
|
||||
if (!vm_info.sanctum_authShared && outOfProtectionDomain(vm_info, r.addr))begin
|
||||
pendWait[idx] <= None;
|
||||
pendResp[idx] <= tuple2(?, Valid (excLoadAccessFault));
|
||||
pendResp[idx] <= tuple3(?, Valid (excLoadAccessFault), False);
|
||||
end
|
||||
`else
|
||||
// No security check
|
||||
@@ -448,17 +451,21 @@ module mkDTlb#(
|
||||
// TLB hit
|
||||
let entry = trans_result.entry;
|
||||
// check permission
|
||||
if (hasVMPermission(vm_info,
|
||||
entry.pteType,
|
||||
entry.ppn,
|
||||
entry.level,
|
||||
r.write ? DataStore : DataLoad)) begin
|
||||
let permCheck = hasVMPermission(vm_info,
|
||||
entry.pteType,
|
||||
entry.pteUpperType,
|
||||
entry.ppn,
|
||||
entry.level,
|
||||
r.write ? DataStore : DataLoad,
|
||||
r.cap);
|
||||
$display("Permission check output 2: ", fshow(permCheck));
|
||||
if (permCheck.allowed) begin
|
||||
// update TLB replacement info
|
||||
tlb.updateRepByHit(trans_result.index);
|
||||
// translate addr
|
||||
Addr trans_addr = translate(r.addr, entry.ppn, entry.level);
|
||||
pendWait[idx] <= None;
|
||||
pendResp[idx] <= tuple2(trans_addr, Invalid);
|
||||
pendResp[idx] <= tuple3(trans_addr, Invalid, permCheck.allowCap);
|
||||
if(verbose) begin
|
||||
$display("[DTLB] req (hit): idx %d; ", idx, fshow(r),
|
||||
"; ", fshow(trans_result));
|
||||
@@ -472,9 +479,9 @@ module mkDTlb#(
|
||||
end
|
||||
else begin
|
||||
// page fault
|
||||
Exception fault = r.write ? excStorePageFault : excLoadPageFault;
|
||||
Exception fault = permCheck.excCode;
|
||||
pendWait[idx] <= None;
|
||||
pendResp[idx] <= tuple2(?, Valid (fault));
|
||||
pendResp[idx] <= tuple3(?, Valid (fault), False);
|
||||
if(verbose) $display("[DTLB] req no permission: idx %d; ", idx, fshow(r));
|
||||
end
|
||||
end
|
||||
@@ -518,7 +525,7 @@ module mkDTlb#(
|
||||
else begin
|
||||
// bare mode
|
||||
pendWait[idx] <= None;
|
||||
pendResp[idx] <= tuple2(r.addr, Invalid);
|
||||
pendResp[idx] <= tuple3(r.addr, Invalid, True);
|
||||
if(verbose) $display("DTLB %m req (bare): ", fshow(r));
|
||||
end
|
||||
|
||||
|
||||
@@ -257,12 +257,8 @@ function CapChecks memCapChecks(Bool cap_mode);
|
||||
capChecks.check_inclusive = True;
|
||||
if (cap_mode) begin
|
||||
capChecks.check_authority_src = Src1;
|
||||
capChecks.src1_tag = True;
|
||||
capChecks.src1_unsealed = True;
|
||||
end else begin
|
||||
capChecks.check_authority_src = Ddc;
|
||||
capChecks.ddc_tag = True;
|
||||
capChecks.ddc_unsealed = True;
|
||||
end
|
||||
return capChecks;
|
||||
endfunction
|
||||
@@ -958,7 +954,8 @@ function DecodeResult decode(Instruction inst, Bool cap_mode);
|
||||
dInst.iType = rs1 == 0 ? Cap : Scr;
|
||||
regs.dst = Valid(tagged Gpr rd);
|
||||
regs.src1 = Valid(tagged Gpr rs1);
|
||||
dInst.scr = Valid (unpackSCR(rs2));
|
||||
|
||||
let scr = unpackSCR(rs2);
|
||||
|
||||
let scrType = case (rs2[1:0])
|
||||
0: TCC;
|
||||
@@ -967,12 +964,13 @@ function DecodeResult decode(Instruction inst, Bool cap_mode);
|
||||
endcase;
|
||||
|
||||
// Decode SCR read to PCC as AUIPCC 0
|
||||
if (dInst.scr.Valid == scrAddrPCC) begin
|
||||
if (scr == scrAddrPCC) begin
|
||||
dInst.iType = Auipcc;
|
||||
dInst.execFunc = tagged Alu Add;
|
||||
regs.src1 = Invalid;
|
||||
dInst.csr = tagged Invalid;
|
||||
dInst.capChecks.scr_read_only = True;
|
||||
end else begin
|
||||
dInst.scr = Valid (scr);
|
||||
end
|
||||
|
||||
dInst.capFunc = CapModify (SpecialRW (scrType));
|
||||
|
||||
@@ -12,4 +12,6 @@
|
||||
`Exception(InstPageFault, 5'd12)
|
||||
`Exception(LoadPageFault, 5'd13)
|
||||
`Exception(StorePageFault, 5'd15)
|
||||
`Exception(LoadCapPageFault, 5'd26)
|
||||
`Exception(StoreCapPageFault, 5'd27)
|
||||
`Exception(CHERIFault, 5'd28)
|
||||
|
||||
@@ -45,10 +45,10 @@ import CHERICC_Fat::*;
|
||||
import ISA_Decls_CHERI::*;
|
||||
|
||||
(* noinline *)
|
||||
function Maybe#(CSR_XCapCause) capChecks(CapPipe a, CapPipe b, CapPipe ddc, CapChecks toCheck, Bool cap_exact);
|
||||
function Maybe#(CSR_XCapCause) capChecksExec(CapPipe a, CapPipe b, CapPipe ddc, CapChecks toCheck, Bool cap_exact);
|
||||
function Maybe#(CSR_XCapCause) e1(CHERIException e) = Valid(CSR_XCapCause{cheri_exc_reg: toCheck.rn1, cheri_exc_code: e});
|
||||
function Maybe#(CSR_XCapCause) e2(CHERIException e) = Valid(CSR_XCapCause{cheri_exc_reg: toCheck.rn2, cheri_exc_code: e});
|
||||
function Maybe#(CSR_XCapCause) eDDC(CHERIException e) = Valid(CSR_XCapCause{cheri_exc_reg: 6'b100001, cheri_exc_code: e}); // Not sure where the proper reg number of DDC is stored...
|
||||
function Maybe#(CSR_XCapCause) eDDC(CHERIException e) = Valid(CSR_XCapCause{cheri_exc_reg: {1'b1, pack(scrAddrDDC)}, cheri_exc_code: e});
|
||||
Maybe#(CSR_XCapCause) result = Invalid;
|
||||
if (toCheck.ddc_tag && !isValidCap(ddc))
|
||||
result = eDDC(cheriExcTagViolation);
|
||||
@@ -92,13 +92,39 @@ function Maybe#(CSR_XCapCause) capChecks(CapPipe a, CapPipe b, CapPipe ddc, CapC
|
||||
result = e2(cheriExcSoftwarePermViolation);
|
||||
else if (toCheck.src1_derivable && !isDerivable(a))
|
||||
result = e1(cheriExcLengthViolation);
|
||||
else if (toCheck.scr_read_only && (toCheck.rn1 != 0))
|
||||
result = Valid(CSR_XCapCause{cheri_exc_reg: {1,pack(scrAddrPCC)}, cheri_exc_code: cheriExcPermitASRViolation});
|
||||
else if (toCheck.cap_exact && !cap_exact)
|
||||
result = e1(cheriExcRepresentViolation);
|
||||
return result;
|
||||
endfunction
|
||||
|
||||
(* noinline *)
|
||||
function Maybe#(CSR_XCapCause) capChecksMem(CapPipe auth, CapPipe data, CapChecks toCheck, MemFunc mem_func, MemDataByteEn byteEn);
|
||||
function Maybe#(CSR_XCapCause) eAuth(CHERIException e) = Valid(CSR_XCapCause{cheri_exc_reg: case (toCheck.check_authority_src) matches Src1: toCheck.rn1;
|
||||
Ddc: {1'b1, pack(scrAddrDDC)};
|
||||
endcase
|
||||
, cheri_exc_code: e});
|
||||
Maybe#(CSR_XCapCause) result = Invalid;
|
||||
if (!isValidCap(auth))
|
||||
result = eAuth(cheriExcTagViolation);
|
||||
else if (getKind(auth) != UNSEALED)
|
||||
result = eAuth(cheriExcSealViolation);
|
||||
else if (mem_func == Ld || mem_func == Lr || mem_func == Amo) begin
|
||||
if (!getHardPerms(auth).permitLoad)
|
||||
result = eAuth(cheriExcPermitRViolation);
|
||||
end
|
||||
else if (mem_func == St || mem_func == Sc || mem_func == Amo) begin
|
||||
if (!getHardPerms(auth).permitStore)
|
||||
result = eAuth(cheriExcPermitWViolation);
|
||||
if (isValidCap(data) && byteEn == replicate(True)) begin
|
||||
if (!getHardPerms(auth).permitStoreCap)
|
||||
result = eAuth(cheriExcPermitWCapViolation);
|
||||
if (!getHardPerms(auth).permitStoreLocalCap && getHardPerms(data).global)
|
||||
result = eAuth(cheriExcPermitWLocalCapViolation);
|
||||
end
|
||||
end
|
||||
return result;
|
||||
endfunction
|
||||
|
||||
(* noinline *)
|
||||
function Maybe#(BoundsCheck) prepareBoundsCheck(CapPipe a, CapPipe b, CapPipe pcc,
|
||||
CapPipe ddc, Data vaddr, Bit#(5) size, // These two are only used in the memory pipe. May factor into two functions later.
|
||||
@@ -230,7 +256,7 @@ function Tuple2#(CapPipe,Bool) capModify(CapPipe a, CapPipe b, CapModifyFunc fun
|
||||
tagged SealEntry :
|
||||
t(setKind(a, SENTRY));
|
||||
tagged Seal :
|
||||
t((validAsType(b, getAddr(b)) && isValidCap(b)) ?
|
||||
t((validAsType(b, getAddr(b)) && isValidCap(b) && getKind(a) == UNSEALED) ?
|
||||
setKind(a, SEALED_WITH_TYPE (truncate(getAddr(b))))
|
||||
: a);
|
||||
tagged Unseal .src :
|
||||
@@ -375,12 +401,12 @@ function ExecResult basicExec(DecodedInst dInst, CapPipe rVal1, CapPipe rVal2, C
|
||||
BrFunc br_f = dInst.execFunc matches tagged Br .br_f ? br_f : NT;
|
||||
cf.taken = aluBr(getAddr(rVal1), getAddr(rVal2), br_f);
|
||||
cf.nextPc = brAddrCalc(pcc, rVal1, dInst.iType, fromMaybe(0,getDInstImm(dInst)), cf.taken, orig_inst, newPcc);
|
||||
|
||||
Maybe#(CSR_XCapCause) capException = capChecksExec(rVal1, aluVal2, nullCap, dInst.capChecks, cap_exact);
|
||||
if (dInst.execFunc matches tagged Br .unused) begin
|
||||
rVal1 = cf.nextPc;
|
||||
if (!cf.taken) dInst.capChecks.check_enable = False;
|
||||
end
|
||||
|
||||
Maybe#(CSR_XCapCause) capException = capChecks(rVal1, aluVal2, nullCap, dInst.capChecks, cap_exact);
|
||||
Maybe#(BoundsCheck) boundsCheck = prepareBoundsCheck(rVal1, aluVal2, pcc,
|
||||
nullCap, 0, 0, // These three are only used in the memory pipe
|
||||
dInst.capChecks);
|
||||
@@ -506,9 +532,12 @@ function Maybe#(Trap) checkForException(
|
||||
else if(dInst.scr matches tagged Valid .scr) begin
|
||||
Bool scr_has_priv = (prv >= pack(scr)[4:3]);
|
||||
Bool unimplemented = (scr == scrAddrNone);
|
||||
Bool writes_scr = regs.src1 == Valid (tagged Gpr 0) ? False : True;
|
||||
Bool read_only = (scr == scrAddrPCC);
|
||||
Bool write_deny = (writes_scr && read_only);
|
||||
Bool asr_deny = !getHardPerms(pcc).accessSysRegs && !(
|
||||
scr == scrAddrDDC);
|
||||
if(!scr_has_priv || unimplemented) begin // Writes to PCC checked in capChecks
|
||||
scr == scrAddrDDC || scr == scrAddrPCC);
|
||||
if(!scr_has_priv || unimplemented || write_deny) begin
|
||||
exception = Valid (Exception (excIllegalInst));
|
||||
end else if (asr_deny) begin
|
||||
exception = Valid (CapException (CSR_XCapCause {cheri_exc_reg: {1'b1, pack(scrAddrPCC)}, cheri_exc_code: cheriExcPermitASRViolation}));
|
||||
|
||||
@@ -176,13 +176,15 @@ module mkITlb(ITlb::ITlb);
|
||||
// check permission
|
||||
if(hasVMPermission(vm_info,
|
||||
en.pteType,
|
||||
en.pteUpperType,
|
||||
en.ppn,
|
||||
en.level,
|
||||
InstFetch)) begin
|
||||
InstFetch,
|
||||
False).allowed) begin
|
||||
// fill TLB and resp to proc
|
||||
tlb.addEntry(en);
|
||||
let trans_addr = translate(vaddr, en.ppn, en.level);
|
||||
hitQ.enq(tuple2(trans_addr, Invalid));
|
||||
hitQ.enq(tuple3(trans_addr, Invalid, False));
|
||||
if(verbose) begin
|
||||
$display("ITLB %m refill: ", fshow(vaddr),
|
||||
" ; ", fshow(trans_addr));
|
||||
@@ -190,7 +192,7 @@ module mkITlb(ITlb::ITlb);
|
||||
end
|
||||
else begin
|
||||
// page fault
|
||||
hitQ.enq(tuple2(?, Valid (excInstPageFault)));
|
||||
hitQ.enq(tuple3(?, Valid (excInstPageFault), False));
|
||||
if(verbose) begin
|
||||
$display("ITLB %m refill no permission: ", fshow(vaddr));
|
||||
end
|
||||
@@ -198,7 +200,7 @@ module mkITlb(ITlb::ITlb);
|
||||
end
|
||||
else begin
|
||||
// page fault
|
||||
hitQ.enq(tuple2(?, Valid (excInstPageFault)));
|
||||
hitQ.enq(tuple3(?, Valid (excInstPageFault), False));
|
||||
if(verbose) $display("ITLB %m refill page fault: ", fshow(vaddr));
|
||||
end
|
||||
// miss resolved
|
||||
@@ -285,16 +287,18 @@ module mkITlb(ITlb::ITlb);
|
||||
// check permission
|
||||
if(hasVMPermission(vm_info,
|
||||
entry.pteType,
|
||||
entry.pteUpperType,
|
||||
entry.ppn,
|
||||
entry.level,
|
||||
InstFetch)) begin
|
||||
InstFetch,
|
||||
False).allowed) begin
|
||||
// update replacement info
|
||||
tlb.updateRepByHit(trans_result.index);
|
||||
// translate addr
|
||||
Addr trans_addr = translate(
|
||||
vaddr, entry.ppn, entry.level
|
||||
);
|
||||
hitQ.enq(tuple2(trans_addr, Invalid));
|
||||
hitQ.enq(tuple3(trans_addr, Invalid, False));
|
||||
if(verbose) begin
|
||||
$display("ITLB %m req (hit): ", fshow(vaddr),
|
||||
" ; ", fshow(trans_result));
|
||||
@@ -302,7 +306,7 @@ module mkITlb(ITlb::ITlb);
|
||||
end
|
||||
else begin
|
||||
// page fault
|
||||
hitQ.enq(tuple2(?, Valid (excInstPageFault)));
|
||||
hitQ.enq(tuple3(?, Valid (excInstPageFault), False));
|
||||
if(verbose) begin
|
||||
$display("ITLB %m req no permission: ",
|
||||
fshow(vaddr));
|
||||
@@ -326,7 +330,7 @@ module mkITlb(ITlb::ITlb);
|
||||
end
|
||||
else begin
|
||||
// bare mode, no translation
|
||||
hitQ.enq(tuple2(vaddr, Invalid));
|
||||
hitQ.enq(tuple3(vaddr, Invalid, False));
|
||||
if (verbose) $display("ITLB %m req (bare): ", fshow(vaddr));
|
||||
end
|
||||
|
||||
|
||||
@@ -653,6 +653,7 @@ module mkL2Tlb(L2Tlb::L2Tlb);
|
||||
vpn: masked_vpn,
|
||||
ppn: masked_ppn,
|
||||
pteType: pte.pteType,
|
||||
pteUpperType: pte.pteUpperType,
|
||||
level: walkLevel,
|
||||
asid: vm_info.asid
|
||||
};
|
||||
|
||||
@@ -1253,7 +1253,7 @@ module mkSupReorderBuffer#(
|
||||
`endif
|
||||
Bool access_at_commit, Bool non_mmio_st_done
|
||||
`ifdef RVFI
|
||||
, tb
|
||||
, ExtraTraceBundle tb
|
||||
`endif
|
||||
) if(
|
||||
all(id, readVReg(setExeMem_SB_enq)) // ordering: < enq
|
||||
|
||||
@@ -294,6 +294,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
Bool wrongPath;
|
||||
Maybe#(PhyDst) dst;
|
||||
Bool allowCap;
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
InstTag instTag; // For recording Ld data in ROB
|
||||
`endif
|
||||
@@ -318,6 +319,7 @@ typedef struct {
|
||||
Bool isMMIO;
|
||||
MemDataByteEn shiftedBE;
|
||||
Maybe#(Trap) fault;
|
||||
Bool allowCap;
|
||||
Maybe#(LdKilledBy) killed;
|
||||
} LdQDeqEntry deriving (Bits, Eq, FShow);
|
||||
|
||||
@@ -332,6 +334,7 @@ typedef struct {
|
||||
Bool isMMIO;
|
||||
MemDataByteEn shiftedBE;
|
||||
MemTaggedData stData;
|
||||
Bool allowCap;
|
||||
Maybe#(Trap) fault;
|
||||
} StQDeqEntry deriving (Bits, Eq, FShow);
|
||||
|
||||
@@ -363,7 +366,7 @@ interface SplitLSQ;
|
||||
method ActionValue#(LSQUpdateAddrResult) updateAddr(
|
||||
LdStQTag lsqTag, Maybe#(Trap) fault,
|
||||
// below are only meaningful wen fault is Invalid
|
||||
Addr paddr, Bool isMMIO, MemDataByteEn shiftedBE
|
||||
Bool allowCap, Addr paddr, Bool isMMIO, MemDataByteEn shiftedBE
|
||||
);
|
||||
// Issue a load, and remove dependence on this load issue.
|
||||
method ActionValue#(LSQIssueLdResult) issueLd(
|
||||
@@ -631,6 +634,7 @@ module mkSplitLSQ(SplitLSQ);
|
||||
Vector#(LdQSize, Reg#(LdQMemFunc)) ld_memFunc <- replicateM(mkRegU);
|
||||
Vector#(LdQSize, Reg#(Bool)) ld_unsigned <- replicateM(mkRegU);
|
||||
Vector#(LdQSize, Reg#(MemDataByteEn)) ld_byteEn <- replicateM(mkRegU);
|
||||
Vector#(LdQSize, Reg#(Bool)) ld_allowCap <- replicateM(mkRegU);
|
||||
Vector#(LdQSize, Reg#(Bool)) ld_acq <- replicateM(mkRegU);
|
||||
Vector#(LdQSize, Reg#(Bool)) ld_rel <- replicateM(mkRegU);
|
||||
Vector#(LdQSize, Reg#(Maybe#(PhyDst))) ld_dst <- replicateM(mkRegU);
|
||||
@@ -1525,7 +1529,7 @@ module mkSplitLSQ(SplitLSQ);
|
||||
|
||||
method ActionValue#(LSQUpdateAddrResult) updateAddr(
|
||||
LdStQTag lsqTag, Maybe#(Trap) fault,
|
||||
Addr pa, Bool mmio, MemDataByteEn shift_be
|
||||
Bool allowCap, Addr pa, Bool mmio, MemDataByteEn shift_be
|
||||
);
|
||||
// index vec for vector functions
|
||||
Vector#(LdQSize, LdQTag) idxVec = genWith(fromInteger);
|
||||
@@ -1566,6 +1570,7 @@ module mkSplitLSQ(SplitLSQ);
|
||||
ld_fault_updAddr[tag] <= fault;
|
||||
ld_computed_updAddr[tag] <= !isValid(fault);
|
||||
ld_paddr_updAddr[tag] <= pa;
|
||||
ld_allowCap[tag] <= allowCap;
|
||||
ld_isMMIO_updAddr[tag] <= mmio;
|
||||
ld_shiftedBE_updAddr[tag] <= shift_be;
|
||||
|
||||
@@ -1994,6 +1999,7 @@ module mkSplitLSQ(SplitLSQ);
|
||||
let res = LSQRespLdResult {
|
||||
wrongPath: False,
|
||||
dst: Invalid,
|
||||
allowCap: False,
|
||||
`ifdef INCLUDE_TANDEM_VERIF
|
||||
instTag: ld_instTag [t], // For recording Ld data in ROB
|
||||
`endif
|
||||
@@ -2021,8 +2027,10 @@ module mkSplitLSQ(SplitLSQ);
|
||||
// In that case, the data needs to be nanboxed before writing to
|
||||
// the register files as the Toooba FPR is 64-bit
|
||||
let bEn = ld_byteEn[t];
|
||||
let allowCap = ld_allowCap[t];
|
||||
let dst = ld_dst[t];
|
||||
let is32BitLd = (bEn[3] && !bEn[7]);
|
||||
res.allowCap = allowCap;
|
||||
res.dst = ld_dst[t];
|
||||
if (dst.Valid.isFpuReg && is32BitLd)
|
||||
res.data = fv_nanbox_MemTaggedData(
|
||||
@@ -2057,6 +2065,7 @@ module mkSplitLSQ(SplitLSQ);
|
||||
isMMIO: ld_isMMIO_deqLd[deqP],
|
||||
shiftedBE: ld_shiftedBE_deqLd[deqP],
|
||||
fault: ld_fault_deqLd[deqP],
|
||||
allowCap: ld_allowCap[deqP],
|
||||
killed: ld_killed_deqLd[deqP]
|
||||
};
|
||||
endmethod
|
||||
|
||||
@@ -31,8 +31,9 @@ import ProcTypes::*;
|
||||
typedef struct{
|
||||
Addr addr;
|
||||
Bool write;
|
||||
Bool cap;
|
||||
} TlbReq deriving(Eq, Bits, FShow);
|
||||
typedef Tuple2#(Addr, Maybe#(Exception)) TlbResp;
|
||||
typedef Tuple3#(Addr, Maybe#(Exception), Bool) TlbResp;
|
||||
|
||||
// non-blocking DTLB
|
||||
typedef `DTLB_REQ_NUM DTlbReqNum;
|
||||
@@ -66,7 +67,13 @@ typedef struct {
|
||||
} PTEType deriving (Bits, Eq, FShow);
|
||||
|
||||
typedef struct {
|
||||
Bit#(10) reserved;
|
||||
Bool cap_writable;
|
||||
Bool cap_readable;
|
||||
} PTEUpperType deriving (Bits, Eq, FShow);
|
||||
|
||||
typedef struct {
|
||||
PTEUpperType pteUpperType;
|
||||
Bit#(8) reserved;
|
||||
Ppn ppn;
|
||||
Bit#(2) reserved_sw; // reserved for supervisor software
|
||||
PTEType pteType;
|
||||
@@ -78,6 +85,7 @@ typedef struct {
|
||||
Vpn vpn;
|
||||
Ppn ppn;
|
||||
PTEType pteType;
|
||||
PTEUpperType pteUpperType;
|
||||
PageWalkLevel level;
|
||||
Asid asid;
|
||||
} TlbEntry deriving (Bits, Eq, FShow);
|
||||
@@ -169,10 +177,17 @@ typedef enum {
|
||||
DataStore // also contain DataLoad
|
||||
} TlbAccessType deriving(Bits, Eq, FShow);
|
||||
|
||||
function Bool hasVMPermission(
|
||||
typedef struct {
|
||||
Bool allowed;
|
||||
Exception excCode; // Only defined if !allowed
|
||||
Bool allowCap; // Whether we can load caps
|
||||
} TlbPermissionCheck deriving(Bits, Eq, FShow);
|
||||
|
||||
function TlbPermissionCheck hasVMPermission(
|
||||
VMInfo vm_info,
|
||||
PTEType pte_type, Ppn ppn, PageWalkLevel level,
|
||||
TlbAccessType access
|
||||
PTEType pte_type, PTEUpperType pte_upper_type,
|
||||
Ppn ppn, PageWalkLevel level,
|
||||
TlbAccessType access, Bool cap
|
||||
);
|
||||
// try to find any page fault
|
||||
Bool fault = False;
|
||||
@@ -229,13 +244,27 @@ function Bool hasVMPermission(
|
||||
end
|
||||
endcase
|
||||
|
||||
// check if accessed or dirty bit needs to be set
|
||||
if(!pte_type.accessed) begin
|
||||
fault = True;
|
||||
end
|
||||
if(access == DataStore && !pte_type.dirty) begin
|
||||
fault = True;
|
||||
TlbPermissionCheck ret = TlbPermissionCheck {
|
||||
allowed: !fault,
|
||||
excCode: access == DataStore ? excStorePageFault : excLoadPageFault,
|
||||
allowCap: pte_upper_type.cap_readable};
|
||||
|
||||
if (!fault) begin
|
||||
if (cap && access == DataStore && !pte_upper_type.cap_writable) begin
|
||||
ret.allowed = False;
|
||||
ret.excCode = excStoreCapPageFault;
|
||||
end else begin
|
||||
// check if accessed or dirty bit needs to be set
|
||||
if(!pte_type.accessed) begin
|
||||
ret.allowed = False;
|
||||
ret.excCode = access == DataStore ? excStorePageFault : excLoadPageFault;
|
||||
end
|
||||
if(access == DataStore && !pte_type.dirty) begin
|
||||
ret.allowed = False;
|
||||
ret.excCode = access == DataStore ? excStorePageFault : excLoadPageFault;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return !fault;
|
||||
return ret;
|
||||
endfunction
|
||||
|
||||
Reference in New Issue
Block a user