Skip to content

Commit

Permalink
Merge pull request #431 from ved-rivos/0926
Browse files Browse the repository at this point in the history
Refactor H/W A/D update for implicit walk
  • Loading branch information
ved-rivos authored Sep 26, 2024
2 parents 3e005fd + f300f1f commit 4d7fad2
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 17 deletions.
4 changes: 2 additions & 2 deletions iommu_ref_model/libiommu/include/iommu_translate.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ two_stage_address_translation(
extern uint8_t
second_stage_address_translation(
uint64_t gpa, uint8_t check_access_perms, uint32_t DID,
uint8_t is_read, uint8_t is_write, uint8_t is_exec,
uint8_t is_read, uint8_t is_write, uint8_t is_exec, uint8_t is_implicit,
uint8_t PV, uint32_t PID, uint8_t PSCV, uint32_t PSCID,
uint8_t GV, uint32_t GSCID, iohgatp_t iohgatp, uint8_t GADE, uint8_t SXL,
uint8_t GV, uint32_t GSCID, iohgatp_t iohgatp, uint8_t GADE, uint8_t SADE, uint8_t SXL,
uint64_t *pa, uint64_t *gst_page_sz, gpte_t *gpte);

extern uint8_t
Expand Down
12 changes: 8 additions & 4 deletions iommu_ref_model/libiommu/src/iommu_process_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ locate_process_context(
gpte_t g_pte;
pdte_t pdte;
uint16_t PDI[3];
uint8_t is_implicit, is_read, is_write, is_exec;

// The device-context provides the PDT root page PPN (pdtp.ppn).
// When DC.iohgatp.mode is not Bare, pdtp.PPN as well as pdte.PPN
Expand Down Expand Up @@ -80,10 +81,13 @@ locate_process_context(
// occur during G-stage address translation of `a` then stop and the fault
// detected by the G-stage address translation process. The translated `a`
// is used in subsequent steps.
if ( ( gst_fault = second_stage_address_translation(a, 1, device_id, 1, 0, 0, 1, process_id,
0, 0, ((DC->iohgatp.MODE == IOHGATP_Bare) ? 0 : 1),
DC->iohgatp.GSCID, DC->iohgatp, DC->tc.GADE, DC->tc.SXL, &a,
&gst_page_sz, &g_pte) ) ) {
is_read = 1;
is_write = is_exec = is_implicit = 0;
if ( ( gst_fault = second_stage_address_translation(a, 1, device_id, is_read, is_write,
is_exec, is_implicit, 1, process_id, 0, 0,
((DC->iohgatp.MODE == IOHGATP_Bare) ? 0 : 1),
DC->iohgatp.GSCID, DC->iohgatp, DC->tc.GADE, DC->tc.SADE,
DC->tc.SXL, &a, &gst_page_sz, &g_pte) ) ) {
if ( gst_fault == GST_PAGE_FAULT ) {
*cause = 21; // Read guest page fault
*iotval2 = (a & ~0x3);
Expand Down
13 changes: 9 additions & 4 deletions iommu_ref_model/libiommu/src/iommu_second_stage_trans.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
uint8_t
second_stage_address_translation(
uint64_t gpa, uint8_t check_access_perms, uint32_t DID,
uint8_t is_read, uint8_t is_write, uint8_t is_exec,
uint8_t is_read, uint8_t is_write, uint8_t is_exec, uint8_t is_implicit,
uint8_t PV, uint32_t PID, uint8_t PSCV, uint32_t PSCID,
uint8_t GV, uint32_t GSCID, iohgatp_t iohgatp, uint8_t GADE, uint8_t SXL,
uint64_t *pa, uint64_t *gst_page_sz, gpte_t *gpte) {
uint8_t GV, uint32_t GSCID, iohgatp_t iohgatp, uint8_t GADE, uint8_t SADE,
uint8_t SXL, uint64_t *pa, uint64_t *gst_page_sz, gpte_t *gpte) {

uint16_t vpn[5];
uint16_t ppn[5];
Expand Down Expand Up @@ -259,6 +259,10 @@ second_stage_address_translation(
// If `GADE` is 1, the IOMMU updates A and D bits in G-stage PTEs atomically. If
// `GADE` is 0, the IOMMU causes a guest-page-fault corresponding to the original
// access type if A bit is 0 or if the memory access is a store and the D bit is 0.
// If the G-stage was invoked for a implicit walk then set D bit if its
// not already 0, if HW A/D updating for first stage is enabled (SADE is 1),
// HW A/D updating for G-stage is enabled (GADE is 1), and PTE provides
// write permission.
// For IOMMU updating of A/D bits the following steps are performed:
// - If a store to pte would violate a PMA or PMP check, raise an access-fault exception
// corresponding to the original access type.
Expand All @@ -267,7 +271,8 @@ second_stage_address_translation(
// – If the values match, set pte.a to 1 and, if the original memory access is a store,
// also set pte.d to 1.
// – If the comparison fails, return to step 2
if ( (gpte->A == 1) && ( (gpte->D == 1) || (is_write == 0) || (gpte->W == 0) ) ) goto step_8;
if ( (gpte->A == 1) && (gpte->D == 1 || is_write == 0) &&
(gpte->D == 1 || is_implicit == 0 || gpte->W == 0 || GADE == 0 || SADE == 0) ) goto step_8;

// A and/or D bit update needed
if ( GADE == 0 ) return GST_PAGE_FAULT;
Expand Down
7 changes: 4 additions & 3 deletions iommu_ref_model/libiommu/src/iommu_translate.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ iommu_translate_iova(
uint32_t DID, PID, GSCID, PSCID;
pte_t vs_pte;
gpte_t g_pte;
uint8_t ioatc_status, gst_fault;
uint8_t ioatc_status, gst_fault, is_implicit;
uint64_t napot_ppn, napot_iova, napot_gpa;

// Classify transaction type
Expand Down Expand Up @@ -310,9 +310,10 @@ iommu_translate_iova(
// cite:[PRIV] to translate the GPA `A` to determine the SPA accessed by the
// transaction. If a fault is detected by the address translation process then
// stop and report the fault.
is_implicit = 0;
if ( (gst_fault = second_stage_address_translation(gpa, check_access_perms, DID,
is_read, is_write, is_exec, PV, PID, PSCV, PSCID, GV, GSCID,
iohgatp, DC.tc.GADE, DC.tc.SXL, &pa, &gst_page_sz, &g_pte) ) ) {
is_read, is_write, is_exec, is_implicit, PV, PID, PSCV, PSCID, GV, GSCID,
iohgatp, DC.tc.GADE, DC.tc.SADE, DC.tc.SXL, &pa, &gst_page_sz, &g_pte) ) ) {
if ( gst_fault == GST_PAGE_FAULT ) goto guest_page_fault;
if ( gst_fault == GST_ACCESS_FAULT ) goto access_fault;
goto data_corruption;
Expand Down
14 changes: 10 additions & 4 deletions iommu_ref_model/libiommu/src/iommu_two_stage_trans.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ two_stage_address_translation(
pte_t amo_pte;
gpte_t gpte;
uint8_t NL_G = 0;
uint8_t is_implicit;
uint8_t PTESIZE, LEVELS, status, pte_changed, gst_fault;
int8_t i;
uint64_t a, masked_upper_bits, mask;
Expand Down Expand Up @@ -119,9 +120,9 @@ two_stage_address_translation(
// If IOMMU HW A/D bit update are enabled the implicit accesses are treated
// as writes. This avoids the IOMMU needing to go back in time to set D bit
// in G-stage page tables if A or D bit needs to be set in VS stage.
// If SADE is 1, then its a implicit write else its a implicit read
if ( ( gst_fault = second_stage_address_translation(a, 1, DID, 1, SADE, 0,
PV, PID, PSCV, PSCID, GV, GSCID, iohgatp, GADE, SXL,
is_implicit = 1;
if ( ( gst_fault = second_stage_address_translation(a, 1, DID, 1, 0, 0, is_implicit,
PV, PID, PSCV, PSCID, GV, GSCID, iohgatp, GADE, SADE, SXL,
&a, &gst_page_sz, &gpte) ) ) {
if ( gst_fault == GST_PAGE_FAULT ) goto guest_page_fault;
if ( gst_fault == GST_ACCESS_FAULT ) goto access_fault;
Expand Down Expand Up @@ -288,7 +289,9 @@ two_stage_address_translation(

// 7. If pte.a = 0, or if the original memory access is a store and pte.d = 0,
// If SADE is 1, the IOMMU updates A and D bits in first-stage PTEs atomically. If
// SADE is 0, the IOMMU causes a page-fault corresponding to the original access type
// SADE is 0, the IOMMU causes a page-fault corresponding to the original access type.
// To set A or D bit in first-stage PTE, the G-stage PTE that provides
// its translation must have write permission else a guest page fault occurs.
// if the A bit is 0 or if the memory access is a store and the D bit is 0.
// - If a store to pte would violate a PMA or PMP check, raise an access-fault exception
// corresponding to the original access type.
Expand All @@ -299,6 +302,9 @@ two_stage_address_translation(
// – If the comparison fails, return to step 2
if ( (pte->A == 1) && ( (pte->D == 1) || (is_write == 0) || (pte->W == 0) ) ) goto step_8;

// If G-stage does not provide write permission then cause guest page fault
if ( gpte.W == 0 ) goto guest_page_fault;

// A and/or D bit update needed
if ( SADE == 0 ) goto page_fault;

Expand Down

0 comments on commit 4d7fad2

Please sign in to comment.