diff --git a/libs/cheri-cap-lib b/libs/cheri-cap-lib index abfcb20..a812eda 160000 --- a/libs/cheri-cap-lib +++ b/libs/cheri-cap-lib @@ -1 +1 @@ -Subproject commit abfcb20d038c2bb4debebc562bb72453994b7917 +Subproject commit a812edaffaecc9b537f8974a528b915dda829bb6 diff --git a/src_Core/RISCY_OOO/procs/RV64G_OOO/FetchStage.bsv b/src_Core/RISCY_OOO/procs/RV64G_OOO/FetchStage.bsv index dc83079..3eae334 100644 --- a/src_Core/RISCY_OOO/procs/RV64G_OOO/FetchStage.bsv +++ b/src_Core/RISCY_OOO/procs/RV64G_OOO/FetchStage.bsv @@ -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; diff --git a/src_Core/RISCY_OOO/procs/RV64G_OOO/MemExePipeline.bsv b/src_Core/RISCY_OOO/procs/RV64G_OOO/MemExePipeline.bsv index 95a19eb..a9206e7 100644 --- a/src_Core/RISCY_OOO/procs/RV64G_OOO/MemExePipeline.bsv +++ b/src_Core/RISCY_OOO/procs/RV64G_OOO/MemExePipeline.bsv @@ -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); diff --git a/src_Core/RISCY_OOO/procs/RV64G_OOO/RenameStage.bsv b/src_Core/RISCY_OOO/procs/RV64G_OOO/RenameStage.bsv index 7ecdaa3..9dc2d1b 100644 --- a/src_Core/RISCY_OOO/procs/RV64G_OOO/RenameStage.bsv +++ b/src_Core/RISCY_OOO/procs/RV64G_OOO/RenameStage.bsv @@ -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); diff --git a/src_Core/RISCY_OOO/procs/lib/CapChecks.bsvi b/src_Core/RISCY_OOO/procs/lib/CapChecks.bsvi index 3e8d8ad..722ce39 100644 --- a/src_Core/RISCY_OOO/procs/lib/CapChecks.bsvi +++ b/src_Core/RISCY_OOO/procs/lib/CapChecks.bsvi @@ -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") diff --git a/src_Core/RISCY_OOO/procs/lib/DTlb.bsv b/src_Core/RISCY_OOO/procs/lib/DTlb.bsv index 9d273a9..2c699ac 100644 --- a/src_Core/RISCY_OOO/procs/lib/DTlb.bsv +++ b/src_Core/RISCY_OOO/procs/lib/DTlb.bsv @@ -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 diff --git a/src_Core/RISCY_OOO/procs/lib/Decode.bsv b/src_Core/RISCY_OOO/procs/lib/Decode.bsv index 7088a66..9a53fe9 100755 --- a/src_Core/RISCY_OOO/procs/lib/Decode.bsv +++ b/src_Core/RISCY_OOO/procs/lib/Decode.bsv @@ -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)); diff --git a/src_Core/RISCY_OOO/procs/lib/Exceptions.bsvi b/src_Core/RISCY_OOO/procs/lib/Exceptions.bsvi index 3bbfe5d..a1d2484 100644 --- a/src_Core/RISCY_OOO/procs/lib/Exceptions.bsvi +++ b/src_Core/RISCY_OOO/procs/lib/Exceptions.bsvi @@ -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) diff --git a/src_Core/RISCY_OOO/procs/lib/Exec.bsv b/src_Core/RISCY_OOO/procs/lib/Exec.bsv index a81fda2..0d914a9 100755 --- a/src_Core/RISCY_OOO/procs/lib/Exec.bsv +++ b/src_Core/RISCY_OOO/procs/lib/Exec.bsv @@ -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})); diff --git a/src_Core/RISCY_OOO/procs/lib/ITlb.bsv b/src_Core/RISCY_OOO/procs/lib/ITlb.bsv index 2755f1f..5af744c 100644 --- a/src_Core/RISCY_OOO/procs/lib/ITlb.bsv +++ b/src_Core/RISCY_OOO/procs/lib/ITlb.bsv @@ -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 diff --git a/src_Core/RISCY_OOO/procs/lib/L2Tlb.bsv b/src_Core/RISCY_OOO/procs/lib/L2Tlb.bsv index ab8b58e..139169f 100644 --- a/src_Core/RISCY_OOO/procs/lib/L2Tlb.bsv +++ b/src_Core/RISCY_OOO/procs/lib/L2Tlb.bsv @@ -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 }; diff --git a/src_Core/RISCY_OOO/procs/lib/ReorderBuffer.bsv b/src_Core/RISCY_OOO/procs/lib/ReorderBuffer.bsv index 377793e..4c43782 100755 --- a/src_Core/RISCY_OOO/procs/lib/ReorderBuffer.bsv +++ b/src_Core/RISCY_OOO/procs/lib/ReorderBuffer.bsv @@ -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 diff --git a/src_Core/RISCY_OOO/procs/lib/SplitLSQ.bsv b/src_Core/RISCY_OOO/procs/lib/SplitLSQ.bsv index 25b734f..527721e 100644 --- a/src_Core/RISCY_OOO/procs/lib/SplitLSQ.bsv +++ b/src_Core/RISCY_OOO/procs/lib/SplitLSQ.bsv @@ -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 diff --git a/src_Core/RISCY_OOO/procs/lib/TlbTypes.bsv b/src_Core/RISCY_OOO/procs/lib/TlbTypes.bsv index 41f4eda..9d15af0 100644 --- a/src_Core/RISCY_OOO/procs/lib/TlbTypes.bsv +++ b/src_Core/RISCY_OOO/procs/lib/TlbTypes.bsv @@ -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