From 0ddb2f2222c96a3b6d4a54d2340529832320af93 Mon Sep 17 00:00:00 2001 From: Ved Shanbhogue Date: Thu, 26 Sep 2024 12:49:22 -0500 Subject: [PATCH 1/2] Refactor H/W A/D update for implicit walk --- iommu_ref_model/libiommu/include/iommu_translate.h | 4 ++-- .../libiommu/src/iommu_process_context.c | 4 ++-- .../libiommu/src/iommu_second_stage_trans.c | 13 +++++++++---- iommu_ref_model/libiommu/src/iommu_translate.c | 4 ++-- .../libiommu/src/iommu_two_stage_trans.c | 14 ++++++++++---- 5 files changed, 25 insertions(+), 14 deletions(-) diff --git a/iommu_ref_model/libiommu/include/iommu_translate.h b/iommu_ref_model/libiommu/include/iommu_translate.h index 4d6fa37b..d0c36e30 100644 --- a/iommu_ref_model/libiommu/include/iommu_translate.h +++ b/iommu_ref_model/libiommu/include/iommu_translate.h @@ -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 diff --git a/iommu_ref_model/libiommu/src/iommu_process_context.c b/iommu_ref_model/libiommu/src/iommu_process_context.c index b3afbe6b..659331e2 100644 --- a/iommu_ref_model/libiommu/src/iommu_process_context.c +++ b/iommu_ref_model/libiommu/src/iommu_process_context.c @@ -80,9 +80,9 @@ 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, + if ( ( gst_fault = second_stage_address_translation(a, 1, device_id, 1, 0, 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, + 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 diff --git a/iommu_ref_model/libiommu/src/iommu_second_stage_trans.c b/iommu_ref_model/libiommu/src/iommu_second_stage_trans.c index 8ed5e790..cc97849a 100644 --- a/iommu_ref_model/libiommu/src/iommu_second_stage_trans.c +++ b/iommu_ref_model/libiommu/src/iommu_second_stage_trans.c @@ -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]; @@ -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. @@ -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; diff --git a/iommu_ref_model/libiommu/src/iommu_translate.c b/iommu_ref_model/libiommu/src/iommu_translate.c index 88505a07..99fde3ad 100644 --- a/iommu_ref_model/libiommu/src/iommu_translate.c +++ b/iommu_ref_model/libiommu/src/iommu_translate.c @@ -311,8 +311,8 @@ iommu_translate_iova( // transaction. If a fault is detected by the address translation process then // stop and report the fault. 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, 0, 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; diff --git a/iommu_ref_model/libiommu/src/iommu_two_stage_trans.c b/iommu_ref_model/libiommu/src/iommu_two_stage_trans.c index 015fe9f3..b69437f2 100644 --- a/iommu_ref_model/libiommu/src/iommu_two_stage_trans.c +++ b/iommu_ref_model/libiommu/src/iommu_two_stage_trans.c @@ -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; @@ -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; @@ -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. @@ -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; From f300f1f47447199d3537a86b78f9bbb7f2c3808e Mon Sep 17 00:00:00 2001 From: Ved Shanbhogue Date: Thu, 26 Sep 2024 12:53:26 -0500 Subject: [PATCH 2/2] Refactor H/W A/D update for implicit walk --- iommu_ref_model/libiommu/src/iommu_process_context.c | 12 ++++++++---- iommu_ref_model/libiommu/src/iommu_translate.c | 5 +++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/iommu_ref_model/libiommu/src/iommu_process_context.c b/iommu_ref_model/libiommu/src/iommu_process_context.c index 659331e2..1d93590f 100644 --- a/iommu_ref_model/libiommu/src/iommu_process_context.c +++ b/iommu_ref_model/libiommu/src/iommu_process_context.c @@ -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 @@ -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, 0, 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) ) ) { + 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); diff --git a/iommu_ref_model/libiommu/src/iommu_translate.c b/iommu_ref_model/libiommu/src/iommu_translate.c index 99fde3ad..ea8953e6 100644 --- a/iommu_ref_model/libiommu/src/iommu_translate.c +++ b/iommu_ref_model/libiommu/src/iommu_translate.c @@ -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 @@ -310,8 +310,9 @@ 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, 0, PV, PID, PSCV, PSCID, GV, GSCID, + 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;