Skip to content
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

Add Non-leaf PTE Invalidation and Address Range Invalidation Extensions to model #514

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions iommu_ref_model/libiommu/include/iommu_command_queue.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@ typedef union {

uint64_t pscv:1;
uint64_t gv:1;
uint64_t rsvd1:10;
uint64_t nl:1;
uint64_t rsvd1:9;
uint64_t gscid:16;
uint64_t rsvd2:4;

uint64_t rsvd3:10;
uint64_t rsvd3:9;
uint64_t s:1;
uint64_t addr_63_12:52;
uint64_t rsvd4:2;
} iotinval;
Expand Down Expand Up @@ -94,8 +96,10 @@ typedef union {

void do_inval_ddt(uint8_t DV, uint32_t DID);
void do_inval_pdt(uint32_t DID, uint32_t PID);
void do_iotinval_vma(uint8_t GV, uint8_t AV, uint8_t PSCV, uint32_t GSCID, uint32_t PSCID, uint64_t ADDR);
void do_iotinval_gvma(uint8_t GV, uint8_t AV, uint32_t GSCID, uint64_t ADDR);
void do_iotinval_vma(uint8_t GV, uint8_t AV, uint8_t NL, uint8_t PSCV, uint32_t
GSCID, uint32_t PSCID, uint64_t ADDR, uint8_t S);
void do_iotinval_gvma(uint8_t GV, uint8_t AV, uint8_t NL, uint32_t GSCID,
uint64_t ADDR, uint8_t S);
void do_ats_msg( uint8_t MSGCODE, uint8_t TAG, uint8_t DSV, uint8_t DSEG, uint16_t RID,
uint8_t PV, uint32_t PID, uint64_t PAYLOAD);
uint8_t do_iofence_c(uint8_t PR, uint8_t PW, uint8_t AV, uint8_t WIS_BIT, uint64_t ADDR, uint32_t DATA);
Expand Down
4 changes: 3 additions & 1 deletion iommu_ref_model/libiommu/include/iommu_registers.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ typedef union {
uint64_t pd17 : 1; // Two level PDT with 17-bit process_id supported.
uint64_t pd20 : 1; // Three level PDT with 20-bit process_id supported.
uint64_t qosid : 1; // Associating QoS IDs with requests is supported.
uint64_t rsvd3 : 14; // Reserved for standard use
uint64_t nl : 1; // Non-leaf PTE invalidation extension is supported.
uint64_t s : 1; // Address range invalidation extension is supported.
uint64_t rsvd3 : 12; // Reserved for standard use
uint64_t custom : 8; // _Designated for custom use_
};
uint64_t raw;
Expand Down
2 changes: 1 addition & 1 deletion iommu_ref_model/libiommu/include/iommu_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@
#define __IOMMU_UTILS_H__
#define get_bits(__MS_BIT, __LS_BIT, __FIELD)\
((__FIELD >> __LS_BIT) & (((uint64_t)1 << (((__MS_BIT - __LS_BIT) + 1))) - 1))
extern uint8_t match_address_range( uint64_t ADDR, uint64_t PPN, uint8_t S);
extern uint8_t match_address_range( uint64_t ADDR, uint8_t ADDR_S, uint64_t PPN, uint8_t S);
#endif // __IOMMU_UTILS_H__
2 changes: 1 addition & 1 deletion iommu_ref_model/libiommu/src/iommu_atc.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ lookup_ioatc_iotlb(
if ( tlb[i].valid == 1 &&
tlb[i].GV == GV && tlb[i].GSCID == GSCID &&
tlb[i].PSCV == PSCV && tlb[i].PSCID == PSCID &&
match_address_range(vpn, tlb[i].vpn, tlb[i].S) ) {
match_address_range(vpn, 0, tlb[i].vpn, tlb[i].S) ) {
hit = i;
break;
}
Expand Down
112 changes: 104 additions & 8 deletions iommu_ref_model/libiommu/src/iommu_command_queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,20 +90,35 @@ process_commands(
// implemented as determined by the IOMMU capabilities register.
switch ( command.any.opcode ) {
case IOTINVAL:
// The non-leaf PTE invalidation extension is implemented if the
// capabilities.NL (bit 42) is 1. When the capabilities.NL bit is 1, a
// non-leaf (NL) field is defined at bit 34 in the IOTINVAL.VMA and
// IOTINVAL.GVMA commands by this extension. When the capabilities.NL
// bit is 0, bit 34 remains reserved.
// The address range invalidation extension is implemented if
// `capabilities.S` (bit 43) is 1. When `capabilities.S` is 1, a
// range-size (`S`) operand is defined at bit 73 in the `IOTINVAL.VMA` and
// `IOTINVAL.GVMA` commands by this extension. When the `capabilities.S`
// bit is 0, bit 73 remains reserved.
if ( command.iotinval.rsvd != 0 || command.iotinval.rsvd1 != 0 ||
command.iotinval.rsvd2 != 0 || command.iotinval.rsvd3 != 0 ||
command.iotinval.rsvd4 != 0 ) goto command_illegal;
command.iotinval.rsvd4 != 0 ||
(g_reg_file.capabilities.nl == 0 && command.iotinval.nl != 0) ||
(g_reg_file.capabilities.s == 0 && command.iotinval.s != 0) )
goto command_illegal;
switch ( command.any.func3 ) {
case VMA:
do_iotinval_vma(command.iotinval.gv, command.iotinval.av,
command.iotinval.pscv, command.iotinval.gscid,
command.iotinval.pscid, command.iotinval.addr_63_12);
command.iotinval.nl, command.iotinval.pscv,
command.iotinval.gscid, command.iotinval.pscid,
command.iotinval.addr_63_12, command.iotinval.s);
break;
case GVMA:
// Setting PSCV to 1 with IOTINVAL.GVMA is illegal.
if ( command.iotinval.pscv != 0 ) goto command_illegal;
do_iotinval_gvma(command.iotinval.gv, command.iotinval.av,
command.iotinval.gscid, command.iotinval.addr_63_12);
command.iotinval.nl, command.iotinval.gscid,
command.iotinval.addr_63_12, command.iotinval.s);
break;
default: goto command_illegal;
}
Expand Down Expand Up @@ -283,7 +298,8 @@ do_inval_pdt(

void
do_iotinval_vma(
uint8_t GV, uint8_t AV, uint8_t PSCV, uint32_t GSCID, uint32_t PSCID, uint64_t ADDR_63_12) {
uint8_t GV, uint8_t AV, uint8_t NL, uint8_t PSCV, uint32_t GSCID,
uint32_t PSCID, uint64_t ADDR_63_12, uint8_t S) {

// IOMMU operations cause implicit reads to PDT, first-stage and second-stage
// page tables. To reduce latency of such reads, the IOMMU may cache entries
Expand Down Expand Up @@ -339,6 +355,21 @@ do_iotinval_vma(

uint8_t i, gscid_match, pscid_match, addr_match, global_match;

// The address range invalidation extension adds the S bit.
// When the AV operand is 0, the S operand is ignored in both the IOTINVAL.VMA and
// IOTINVAL.GVMA commands. When the S operand is ignored or set to 0, the operations of
// the IOTINVAL.VMA and IOTINVAL.GVMA commands are as specified in the RISC-V IOMMU
// Version 1.0 specification.
// When the S operand is not ignored and is 1, the ADDR operand represents a NAPOT
// range encoded in the operand itself. Starting from bit position 0 of the ADDR operand,
// if the first 0 bit is at position X, the range size is 2(X+1) * 4 KiB. When X is 0,
// the size of the range is 8 KiB. If the S operand is not ignored and is 1 and all bits
// of the ADDR operand are 1, the behavior is UNSPECIFIED.
// * The model treats this unspecified behavior as matching the entire address space.
// If the S operand is not ignored and is 1 and the most significant bit of the ADDR
// operand is 0 while all other bits are 1, the specified address range covers the entire
// address space

for ( i = 0; i < TLB_SIZE; i++ ) {
gscid_match = pscid_match = addr_match = global_match = 0;
if ( (GV == 0 && tlb[i].GV == 0 ) ||
Expand All @@ -351,16 +382,44 @@ do_iotinval_vma(
(PSCV == 1 && tlb[i].G == 0) )
global_match = 1;
if ( (AV == 0) ||
(AV == 1 && match_address_range(ADDR_63_12, tlb[i].vpn, tlb[i].S)) )
(AV == 1 && match_address_range(ADDR_63_12, S, tlb[i].vpn, tlb[i].S)) )
addr_match = 1;
if ( gscid_match && pscid_match && addr_match && global_match )
tlb[i].valid = 0;
}
// This model implementation does not have non-leaf PTE caches. This
// information is for documentation only.
// * When the `AV` operand is 0, the `NL` operand is ignored and the `IOTINVAL.VMA`
// command operations are as specified in RISC-V IOMMU Version 1.0 specification.
// * When the `AV` operand is 1 and the `NL` operand is 0, the `IOTINVAL.VMA`
// command operations are as specified in RISC-V IOMMU Version 1.0 specification.
// * When both the `AV` and `NL` operands are 1, the `IOTINVAL.VMA` command
// performs the following operations:
// ** When `GV=0` and `PSCV=0`: Invalidates information cached from all levels of
// first-stage page table entries corresponding to the IOVA in the `ADDR`
// operand for all host address spaces, including entries containing global
// mappings.
// ** When `GV=0` and `PSCV=1`: Invalidates information cached from all levels of
// first-stage page table entries corresponding to the IOVA in the `ADDR`
// operand and the host address space identified by the `PSCID` operand, except
// for entries containing global mappings.
// ** When `GV=1` and `PSCV=0`: Invalidates information cached from all levels of
// first-stage page table entries corresponding to the IOVA in the `ADDR`
// operand for all VM address spaces associated with the `GSCID` operand,
// including entries that contain global mappings.
// ** When `GV=1` and `PSCV=1`: Invalidates information cached from all levels of
// first-stage page table entries corresponding to the IOVA in the `ADDR`
// operand and the VM address space identified by the `PSCID` and `GSCID`
// operands, except for entries containing global mappings.
//
// if (AV == 1 && NL == 1) {
// invalidate_vs_stage_nl_pte_caches(GV, AV, NL, PSCV, GSCID, PSCID, ADDR_63_12);
// }
return;
}
void
do_iotinval_gvma(
uint8_t GV, uint8_t AV, uint32_t GSCID, uint64_t ADDR_63_12) {
uint8_t GV, uint8_t AV, uint8_t NL, uint32_t GSCID, uint64_t ADDR_63_12, uint8_t S) {

uint8_t i, gscid_match, addr_match;
// Conceptually, an implementation might contain two address-translation
Expand Down Expand Up @@ -393,6 +452,23 @@ do_iotinval_gvma(
// table entries corresponding to the guest-physical-address in
// `ADDR` operand, for only for VM address spaces identified
// `GSCID` operand.
//
// The address range invalidation extension adds the S bit.
// When the GV operand is 0, both the AV and S operands are ignored by the
// IOTINVAL.GVMA command.
// When the AV operand is 0, the S operand is ignored in both the IOTINVAL.VMA and
// IOTINVAL.GVMA commands. When the S operand is ignored or set to 0, the operations of
// the IOTINVAL.VMA and IOTINVAL.GVMA commands are as specified in the RISC-V IOMMU
// Version 1.0 specification.
// When the S operand is not ignored and is 1, the ADDR operand represents a NAPOT
// range encoded in the operand itself. Starting from bit position 0 of the ADDR operand,
// if the first 0 bit is at position X, the range size is 2(X+1) * 4 KiB. When X is 0,
// the size of the range is 8 KiB. If the S operand is not ignored and is 1 and all bits
// of the ADDR operand are 1, the behavior is UNSPECIFIED.
// * The model treats this unspecified behavior as matching the entire address space.
// If the S operand is not ignored and is 1 and the most significant bit of the ADDR
// operand is 0 while all other bits are 1, the specified address range covers the entire
// address space
for ( i = 0; i < TLB_SIZE; i++ ) {
if ( tlb[i].valid == 0 ) continue;
if ( (GV == 0 && tlb[i].GV == 1) ||
Expand All @@ -402,11 +478,31 @@ do_iotinval_gvma(
// it. If PSCV is 0 then it holds a GPA. If AV is 0 then all entries are
// eligible else match the address
if ( (tlb[i].PSCV == 1) || (AV == 0) ||
(tlb[i].PSCV == 0 && AV == 1 && match_address_range(ADDR_63_12, tlb[i].vpn, tlb[i].S)) )
(tlb[i].PSCV == 0 && AV == 1 && match_address_range(ADDR_63_12, S, tlb[i].vpn, tlb[i].S)) )
addr_match = 1;
if ( gscid_match && addr_match )
tlb[i].valid = 0;
}
// This model implementation does not have non-leaf PTE caches. This
// information is for documentation only.
// * When the `GV` operand is 0, both the `AV` and `NL` operands are ignored and
// the `IOTINVAL.GVMA` command operations are as specified in RISC-V IOMMU
// Version 1.0 specification.
// * When the `GV` operand is 1 and the `AV` operand is 0, the `NL` operand is
// ignored and the `IOTINVAL.GVMA` command operations are as specified in
// RISC-V IOMMU Version 1.0 specification.
// * When the `GV` and `AV` operands are 1 and the `NL` operand is 0, the
// `IOTINVAL.GVMA` command operations are as specified in RISC-V IOMMU Version
// 1.0 specification.
// * When `GV`, `AV`, and `NL` are all 1, the `IOTINVAL.GVMA` command performs the
// following operations:
// ** Invalidates information cached from all levels of second-stage page table
// entries corresponding to the guest-physical address in the `ADDR` operand and
// the VM address spaces identified by the `GSCID` operand.
//
// if (GV == 1 && AV == 1 && NL == 1) {
// invalidate_g_stage_NL_pte_caches(GV, AV, NL, GSCID, ADDR_63_12);
// }
return;
}
void
Expand Down
8 changes: 5 additions & 3 deletions iommu_ref_model/libiommu/src/iommu_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
// Match address to a NAPOT range
uint8_t
match_address_range(
uint64_t VPN, uint64_t BASE_PN, uint8_t S) {
uint64_t VPN, uint8_t VPN_S, uint64_t BASE_PN, uint8_t S) {

uint64_t RANGE_MASK;

uint64_t VPN_RANGE_MASK;
VPN_RANGE_MASK = (VPN_S == 0) ? ~0UL : ~((VPN) ^ (VPN + 1));
RANGE_MASK = (S == 0) ? ~0UL : ~((BASE_PN) ^ (BASE_PN + 1));
return ((VPN & RANGE_MASK) == (BASE_PN & RANGE_MASK)) ? 1 : 0;
return ((VPN & RANGE_MASK & VPN_RANGE_MASK) ==
(BASE_PN & RANGE_MASK & VPN_RANGE_MASK)) ? 1 : 0;
}
5 changes: 3 additions & 2 deletions iommu_ref_model/test/test_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -3702,8 +3702,10 @@ main(void) {
cmd.iotinval.rsvd2 == 0 &&
cmd.iotinval.rsvd3 == 0 &&
cmd.iotinval.rsvd4 == 0 ) {
if ( temp == 0 )
if ( temp == 0 ) {
cmd.iotinval.s = 0;
cmd.iotinval.func3 = 0x7;
}
if ( temp == 1 )
cmd.iotinval.rsvd = 1;
if ( temp == 2 )
Expand Down Expand Up @@ -4323,7 +4325,6 @@ main(void) {
g_reg_file.capabilities.ats = 1;
write_register(ICVEC_OFFSET, 8, 0x0000000000005555);
fail_if( ( read_register(ICVEC_OFFSET, 8) != 0x0000000000005555) );

// test iommu_qosid
g_reg_file.capabilities.qosid = 1;
g_iommu_qosid_mask = 0x00FF00FF;
Expand Down
Loading