mirror of
https://github.com/openhwgroup/cvw
synced 2025-01-22 20:44:28 +00:00
Fixed PMP checking that top of access is still within range
This commit is contained in:
parent
029f9e2d55
commit
55b63ff486
@ -118,7 +118,7 @@ module mmu import cvw::*; #(parameter cvw_t P,
|
||||
if (P.PMP_ENTRIES > 0) begin : pmp
|
||||
pmpchecker #(P) pmpchecker(.PhysicalAddress, .PrivilegeModeW,
|
||||
.PMPCFG_ARRAY_REGW, .PMPADDR_ARRAY_REGW,
|
||||
.ExecuteAccessF, .WriteAccessM, .ReadAccessM, .CMOpM,
|
||||
.ExecuteAccessF, .WriteAccessM, .ReadAccessM, .Size, .CMOpM,
|
||||
.PMPInstrAccessFaultF, .PMPLoadAccessFaultM, .PMPStoreAmoAccessFaultM);
|
||||
end else begin
|
||||
assign PMPInstrAccessFaultF = 1'b0;
|
||||
@ -131,7 +131,7 @@ module mmu import cvw::*; #(parameter cvw_t P,
|
||||
|
||||
// Misaligned faults
|
||||
always_comb // exclusion-tag: immu-wordaccess
|
||||
case(Size[1:0])
|
||||
case(Size)
|
||||
2'b00: DataMisalignedM = 1'b0; // lb, sb, lbu
|
||||
2'b01: DataMisalignedM = VAdr[0]; // lh, sh, lhu
|
||||
2'b10: DataMisalignedM = VAdr[1] | VAdr[0]; // lw, sw, flw, fsw, lwu
|
||||
|
@ -35,9 +35,11 @@ module pmpadrdec import cvw::*; #(parameter cvw_t P) (
|
||||
input logic [P.PA_BITS-1:0] PhysicalAddress,
|
||||
input logic [7:0] PMPCfg,
|
||||
input logic [P.PA_BITS-3:0] PMPAdr,
|
||||
input logic FirstMatch,
|
||||
input logic PAgePMPAdrIn,
|
||||
output logic PAgePMPAdrOut,
|
||||
output logic Match,
|
||||
output logic [P.PA_BITS-1:0] PMPTop,
|
||||
output logic L, X, W, R
|
||||
);
|
||||
|
||||
@ -50,7 +52,8 @@ module pmpadrdec import cvw::*; #(parameter cvw_t P) (
|
||||
logic PAltPMPAdr;
|
||||
logic [P.PA_BITS-1:0] CurrentAdrFull;
|
||||
logic [1:0] AdrMode;
|
||||
|
||||
logic [P.PA_BITS-1:0] PMPTop1;
|
||||
|
||||
assign AdrMode = PMPCfg[4:3];
|
||||
|
||||
// The two lsb of the physical address don't matter for this checking.
|
||||
@ -71,20 +74,22 @@ module pmpadrdec import cvw::*; #(parameter cvw_t P) (
|
||||
assign NAMask[P.PA_BITS-1:2] = (PMPAdr + {{(P.PA_BITS-3){1'b0}}, (AdrMode == NAPOT)}) ^ PMPAdr;
|
||||
// form a mask where the bottom k bits are 1, corresponding to a size of 2^k bytes for this memory region.
|
||||
// This assumes we're using at least an NA4 region, but works for any size NAPOT region.
|
||||
assign NABase = {(PMPAdr & ~NAMask[P.PA_BITS-1:2]), 2'b00}; // base physical address of the pmp.
|
||||
|
||||
assign NABase = {(PMPAdr & ~NAMask[P.PA_BITS-1:2]), 2'b00}; // base physical address of the pmp region
|
||||
assign NAMatch = &((NABase ~^ PhysicalAddress) | NAMask); // check if upper bits of base address match, ignore lower bits correspoonding to inside the memory range
|
||||
|
||||
// finally pick the appropriate match for the access type
|
||||
assign Match = (AdrMode == TOR) ? TORMatch :
|
||||
(AdrMode == NA4 | AdrMode == NAPOT) ? NAMatch :
|
||||
1'b0;
|
||||
|
||||
// Report top of region for first matching region
|
||||
assign PMPTop1 = {PMPAdr,2'b00} | NAMask; // top of the pmp region. All 1s in the lower bits. Used to check the address doesn't pass the top
|
||||
assign PMPTop = FirstMatch ? PMPTop1 : '0; // AND portion of distributed AND-OR mux (OR portion in pmpchhecker)
|
||||
|
||||
// PMP should match but fail if the size is too big (8-byte accesses spanning to TOR or NA4 region)
|
||||
assign L = PMPCfg[7];
|
||||
assign X = PMPCfg[2];
|
||||
assign W = PMPCfg[1];
|
||||
assign R = PMPCfg[0];
|
||||
|
||||
// known bug: The size of the access is not yet checked. For example, if an NA4 entry matches 0xC-0xF and the system
|
||||
// attempts an 8-byte access to 0x8, the access should fail (see page 60 of privileged specification 20211203). This
|
||||
// implementation will not detect the failure.
|
||||
endmodule
|
||||
endmodule
|
||||
|
@ -43,6 +43,7 @@ module pmpchecker import cvw::*; #(parameter cvw_t P) (
|
||||
input var logic [7:0] PMPCFG_ARRAY_REGW[P.PMP_ENTRIES-1:0],
|
||||
input var logic [P.PA_BITS-3:0] PMPADDR_ARRAY_REGW [P.PMP_ENTRIES-1:0],
|
||||
input logic ExecuteAccessF, WriteAccessM, ReadAccessM,
|
||||
input logic [1:0] Size,
|
||||
input logic [3:0] CMOpM,
|
||||
output logic PMPInstrAccessFaultF,
|
||||
output logic PMPLoadAccessFaultM,
|
||||
@ -55,29 +56,56 @@ module pmpchecker import cvw::*; #(parameter cvw_t P) (
|
||||
logic [P.PMP_ENTRIES-1:0] FirstMatch; // onehot encoding for the first pmpaddr to match the current address.
|
||||
logic [P.PMP_ENTRIES-1:0] L, X, W, R; // PMP matches and has flag set
|
||||
logic [P.PMP_ENTRIES-1:0] PAgePMPAdr; // for TOR PMP matching, PhysicalAddress > PMPAdr[i]
|
||||
logic [P.PA_BITS-1:0] PMPTop[P.PMP_ENTRIES-1:0]; // Upper end of each region, for checking that the access is fully within the region
|
||||
logic PMPCMOAccessFault, PMPCBOMAccessFault, PMPCBOZAccessFault;
|
||||
|
||||
logic [2:0] SizeBytesMinus1;
|
||||
logic MatchingR, MatchingW, MatchingX, MatchingL;
|
||||
logic [P.PA_BITS-1:0] MatchingPMPTop, PhysicalAddressTop;
|
||||
logic TooBig;
|
||||
|
||||
if (P.PMP_ENTRIES > 0) begin: pmp // prevent complaints about array of no elements when PMP_ENTRIES = 0
|
||||
pmpadrdec #(P) pmpadrdecs[P.PMP_ENTRIES-1:0](
|
||||
.PhysicalAddress,
|
||||
.PMPCfg(PMPCFG_ARRAY_REGW),
|
||||
.PMPAdr(PMPADDR_ARRAY_REGW),
|
||||
.FirstMatch,
|
||||
.PAgePMPAdrIn({PAgePMPAdr[P.PMP_ENTRIES-2:0], 1'b1}),
|
||||
.PAgePMPAdrOut(PAgePMPAdr),
|
||||
.Match, .L, .X, .W, .R);
|
||||
.Match, .PMPTop, .L, .X, .W, .R);
|
||||
end
|
||||
|
||||
priorityonehot #(P.PMP_ENTRIES) pmppriority(.a(Match), .y(FirstMatch)); // combine the match signal from all the adress decoders to find the first one that matches.
|
||||
|
||||
// Only enforce PMP checking for S and U modes or in Machine mode when L bit is set in selected region
|
||||
assign EnforcePMP = (PrivilegeModeW != P.M_MODE) | (|(L & FirstMatch));
|
||||
// Distributed AND-OR mux to select the first matching results
|
||||
// If the access does not match all bytes of the PMP region, it is too big and the matches are disabled
|
||||
assign MatchingR = |(R & FirstMatch) & ~TooBig;
|
||||
assign MatchingW = |(W & FirstMatch) & ~TooBig;
|
||||
assign MatchingX = |(X & FirstMatch) & ~TooBig;
|
||||
assign MatchingL = |(L & FirstMatch);
|
||||
or_rows #(P.PMP_ENTRIES, P.PA_BITS) PTEOr(PMPTop, MatchingPMPTop);
|
||||
|
||||
assign PMPCBOMAccessFault = EnforcePMP & (|CMOpM[2:0]) & ~|((R|W) & FirstMatch) ; // exclusion-tag: immu-pmpcbom
|
||||
assign PMPCBOZAccessFault = EnforcePMP & CMOpM[3] & ~|(W & FirstMatch) ; // exclusion-tag: immu-pmpcboz
|
||||
// Matching PMP entry must match all bytes of an access, or the access fails (Priv Spec 3.7.1.3)
|
||||
// *** not fully implemented
|
||||
// *** check R=0,W=1 WARL is enforced
|
||||
// First find the size of the access in terms of the offset to the most significant byte
|
||||
always_comb
|
||||
case (Size)
|
||||
2'b00: SizeBytesMinus1 = 3'd0;
|
||||
2'b01: SizeBytesMinus1 = 3'd1;
|
||||
2'b10: SizeBytesMinus1 = 3'd3;
|
||||
2'b11: SizeBytesMinus1 = 3'd7;
|
||||
endcase
|
||||
assign PhysicalAddressTop = PhysicalAddress + {{P.PA_BITS-3{1'b0}}, SizeBytesMinus1}; // top of the access range
|
||||
assign TooBig = PhysicalAddressTop > MatchingPMPTop; // check if the access goes beyond the top of the PMP region
|
||||
|
||||
// Only enforce PMP checking for S and U modes or in Machine mode when L bit is set in selected region
|
||||
assign EnforcePMP = (PrivilegeModeW != P.M_MODE) | MatchingL;
|
||||
|
||||
assign PMPCBOMAccessFault = EnforcePMP & (|CMOpM[2:0]) & ~MatchingR ; // checking R is sufficient because W implies R in PMP // exclusion-tag: immu-pmpcbom
|
||||
assign PMPCBOZAccessFault = EnforcePMP & CMOpM[3] & ~MatchingW ; // exclusion-tag: immu-pmpcboz
|
||||
assign PMPCMOAccessFault = PMPCBOZAccessFault | PMPCBOMAccessFault; // exclusion-tag: immu-pmpcboaccess
|
||||
|
||||
assign PMPInstrAccessFaultF = EnforcePMP & ExecuteAccessF & ~|(X & FirstMatch) ;
|
||||
assign PMPStoreAmoAccessFaultM = (EnforcePMP & WriteAccessM & ~|(W & FirstMatch)) | PMPCMOAccessFault; // exclusion-tag: immu-pmpstoreamoaccessfault
|
||||
assign PMPLoadAccessFaultM = EnforcePMP & ReadAccessM & ~WriteAccessM & ~|(R & FirstMatch) ;
|
||||
assign PMPInstrAccessFaultF = EnforcePMP & ExecuteAccessF & ~MatchingX ;
|
||||
assign PMPStoreAmoAccessFaultM = (EnforcePMP & WriteAccessM & ~MatchingW) | PMPCMOAccessFault; // exclusion-tag: immu-pmpstoreamoaccessfault
|
||||
assign PMPLoadAccessFaultM = EnforcePMP & ReadAccessM & ~WriteAccessM & ~MatchingR;
|
||||
endmodule
|
||||
|
Loading…
Reference in New Issue
Block a user