diff --git a/iommu_ref_model/libiommu/include/iommu_registers.h b/iommu_ref_model/libiommu/include/iommu_registers.h index ec16d30..3848fd1 100644 --- a/iommu_ref_model/libiommu/include/iommu_registers.h +++ b/iommu_ref_model/libiommu/include/iommu_registers.h @@ -790,6 +790,7 @@ extern uint8_t offset_to_size[4096]; extern uint8_t g_max_iommu_mode; extern uint8_t g_fill_ats_trans_in_ioatc; extern uint32_t g_max_devid_mask; +extern uint8_t g_trans_for_debug; extern void process_commands(void); #endif //_IOMMU_REGS_H_ diff --git a/iommu_ref_model/libiommu/src/iommu_process_context.c b/iommu_ref_model/libiommu/src/iommu_process_context.c index 1d93590..646692d 100644 --- a/iommu_ref_model/libiommu/src/iommu_process_context.c +++ b/iommu_ref_model/libiommu/src/iommu_process_context.c @@ -84,7 +84,7 @@ locate_process_context( 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, + 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) ) ) { diff --git a/iommu_ref_model/libiommu/src/iommu_reg.c b/iommu_ref_model/libiommu/src/iommu_reg.c index 279c520..45b1273 100644 --- a/iommu_ref_model/libiommu/src/iommu_reg.c +++ b/iommu_ref_model/libiommu/src/iommu_reg.c @@ -20,6 +20,7 @@ uint8_t g_max_iommu_mode; uint8_t g_fill_ats_trans_in_ioatc; uint32_t g_max_devid_mask; extern uint8_t g_iofence_wait_pending_inv; +uint8_t g_trans_for_debug; uint8_t is_access_valid( @@ -703,7 +704,9 @@ write_register( req.tr.length = 1; req.tr.read_writeAMO = (g_reg_file.tr_req_ctrl.NW == 1) ? READ : WRITE; + g_trans_for_debug = 1; iommu_translate_iova(&req, &rsp); + g_trans_for_debug = 0; // The value in PBMT, S< and PPN are UNSPECIFIED if // fault is 1. Model sets them to 0. diff --git a/iommu_ref_model/libiommu/src/iommu_translate.c b/iommu_ref_model/libiommu/src/iommu_translate.c index ea8953e..533542f 100644 --- a/iommu_ref_model/libiommu/src/iommu_translate.c +++ b/iommu_ref_model/libiommu/src/iommu_translate.c @@ -303,6 +303,14 @@ iommu_translate_iova( if ( msi_address_translation(gpa, is_exec, &DC, &is_msi, &is_mrif, &mrif_nid, &dest_mrif_addr, &cause, &iotval2, &pa, &gst_page_sz, &g_pte, check_access_perms) ) goto stop_and_report_fault; + + // Chapter 5: If the IOVA is determined to be that of a virtual interrupt file + // (Section 3.1.3.6) and the corresponding MSI PTE is in MRIF mode, then the process + // stops and reports a "Transaction type disallowed" (cause = 260) fault. + if ( is_msi && is_mrif && g_trans_for_debug) { + cause = 260; // "Transaction type disallowed" + goto stop_and_report_fault; + } if ( is_msi == 1 ) goto skip_gpa_trans; // 19. Use the second-stage address translation process specified in Section diff --git a/iommu_ref_model/test/test_app.c b/iommu_ref_model/test/test_app.c index dfa5993..a97d0a4 100644 --- a/iommu_ref_model/test/test_app.c +++ b/iommu_ref_model/test/test_app.c @@ -154,7 +154,7 @@ main(void) { exp_msg.PAYLOAD = (0x1234UL << 48UL) | (RESPONSE_FAILURE << 44UL); handle_page_request(&pr); fail_if( ( exp_msg_received == 0 ) ); - fail_if( ( check_msg_faults(256, pr.PV, pr.PID, pr.PRIV, 0x431234, PAGE_REQ_MSG_CODE) < 0 ) ); + fail_if( ( check_faults(256, pr.PV, pr.PID, pr.PRIV, 0x431234, PAGE_REQ_MSG_CODE, PCIE_MESSAGE_REQUEST, 0) < 0 ) ); END_TEST(); START_TEST("Bare mode tests"); @@ -195,7 +195,7 @@ main(void) { exp_msg.PAYLOAD = (0x1234UL << 48UL) | (INVALID_REQUEST << 44UL); handle_page_request(&pr); fail_if( ( exp_msg_received == 0 ) ); - fail_if( ( check_msg_faults(260, pr.PV, pr.PID, pr.PRIV, 0x431234, PAGE_REQ_MSG_CODE) < 0 ) ); + fail_if( ( check_faults(260, pr.PV, pr.PID, pr.PRIV, 0x431234, PAGE_REQ_MSG_CODE, PCIE_MESSAGE_REQUEST, 0) < 0 ) ); // Turn it off fail_if( ( enable_iommu(Off) < 0 ) ); END_TEST(); @@ -227,7 +227,7 @@ main(void) { exp_msg.PAYLOAD = (0x1234UL << 48UL) | (INVALID_REQUEST << 44UL); handle_page_request(&pr); fail_if( ( exp_msg_received == 0 ) ); - fail_if( ( check_msg_faults(260, pr.PV, pr.PID, pr.PRIV, 0x431234, PAGE_REQ_MSG_CODE) < 0 ) ); + fail_if( ( check_faults(260, pr.PV, pr.PID, pr.PRIV, 0x431234, PAGE_REQ_MSG_CODE, PCIE_MESSAGE_REQUEST, 0) < 0 ) ); fail_if( ( enable_iommu(DDT_2LVL) == 0 ) ); fail_if( ( enable_iommu(Off) < 0 ) ); @@ -258,7 +258,7 @@ main(void) { exp_msg.PAYLOAD = (0x1234UL << 48UL) | (INVALID_REQUEST << 44UL); handle_page_request(&pr); fail_if( ( exp_msg_received == 0 ) ); - fail_if( ( check_msg_faults(260, pr.PV, pr.PID, pr.PRIV, 0x431234, PAGE_REQ_MSG_CODE) < 0 ) ); + fail_if( ( check_faults(260, pr.PV, pr.PID, pr.PRIV, 0x431234, PAGE_REQ_MSG_CODE, PCIE_MESSAGE_REQUEST, 0) < 0 ) ); // Change to MSI flat mode g_reg_file.capabilities.msi_flat = 0; @@ -284,7 +284,7 @@ main(void) { exp_msg.PAYLOAD = (0x1234UL << 48UL) | (INVALID_REQUEST << 44UL); handle_page_request(&pr); fail_if( ( exp_msg_received == 0 ) ); - fail_if( ( check_msg_faults(260, pr.PV, pr.PID, pr.PRIV, 0x431234, PAGE_REQ_MSG_CODE) < 0 ) ); + fail_if( ( check_faults(260, pr.PV, pr.PID, pr.PRIV, 0x431234, PAGE_REQ_MSG_CODE, PCIE_MESSAGE_REQUEST, 0) < 0 ) ); g_reg_file.capabilities.msi_flat = 1; END_TEST(); @@ -3024,7 +3024,7 @@ main(void) { exp_msg.PAYLOAD = (0x1234UL << 48UL) | (RESPONSE_FAILURE << 44UL); handle_page_request(&pr); fail_if( ( exp_msg_received == 0 ) ); - fail_if( ( check_msg_faults(258, pr.PV, pr.PID, pr.PRIV, 0x431234, PAGE_REQ_MSG_CODE) < 0 ) ); + fail_if( ( check_faults(258, pr.PV, pr.PID, pr.PRIV, 0x431234, PAGE_REQ_MSG_CODE, PCIE_MESSAGE_REQUEST, 0) < 0 ) ); // ATS disabled pr.RID = 0x2233; @@ -3040,7 +3040,7 @@ main(void) { exp_msg.PAYLOAD = (0x2233UL << 48UL) | (INVALID_REQUEST << 44UL); handle_page_request(&pr); fail_if( ( exp_msg_received == 0 ) ); - fail_if( ( check_msg_faults(260, pr.PV, pr.PID, pr.PRIV, 0x112233, PAGE_REQ_MSG_CODE) < 0 ) ); + fail_if( ( check_faults(260, pr.PV, pr.PID, pr.PRIV, 0x112233, PAGE_REQ_MSG_CODE, PCIE_MESSAGE_REQUEST, 0) < 0 ) ); // ATS enabled PRI disabled pr.RID = 0x2233; @@ -3056,7 +3056,7 @@ main(void) { exp_msg.PAYLOAD = (0x2233UL << 48UL) | (INVALID_REQUEST << 44UL); handle_page_request(&pr); fail_if( ( exp_msg_received == 0 ) ); - fail_if( ( check_msg_faults(260, pr.PV, pr.PID, pr.PRIV, 0x112233, PAGE_REQ_MSG_CODE) < 0 ) ); + fail_if( ( check_faults(260, pr.PV, pr.PID, pr.PRIV, 0x112233, PAGE_REQ_MSG_CODE, PCIE_MESSAGE_REQUEST, 0) < 0 ) ); // ATS, PRI enabled - Page request queue disabled @@ -3647,6 +3647,27 @@ main(void) { fail_if( ( rsp.trsp.mrif_nid != 0x412 ) ); fail_if( ( rsp.trsp.dest_mrif_addr != (msipte.mrif.MRIF_ADDR_55_9 * 512)) ); + req.device_id = 0x121679; + req.pid_valid = 0; + req.is_cxl_dev = 0; + req.tr.at = ADDR_TYPE_UNTRANSLATED; + req.tr.length = 64; + req.tr.read_writeAMO = READ; + req.tr.iova = gpa; + + tr_req_ctrl.DID = 0x121679; + tr_req_ctrl.PV = 0; + tr_req_ctrl.PID = 0; + tr_req_ctrl.Priv = 0; + tr_req_ctrl.NW = 1; + tr_req_ctrl.go_busy = 1; + tr_req_iova.raw = gpa; + write_register(TR_REQ_IOVA_OFFSET, 8, tr_req_iova.raw); + write_register(TR_REQ_CTRL_OFFSET, 8, tr_req_ctrl.raw); + tr_response.raw = read_register(TR_RESPONSE_OFFSET, 8); + fail_if( ( tr_response.fault == 0 ) ); + fail_if( ( check_faults(260, tr_req_ctrl.PV, tr_req_ctrl.PID, tr_req_ctrl.Priv, 0x121679, gpa, UNTRANSLATED_READ_TRANSACTION, 0) < 0 ) ); + END_TEST(); START_TEST("Illegal commands and CQ mem faults"); diff --git a/iommu_ref_model/test/test_app.h b/iommu_ref_model/test/test_app.h index f08db59..2bb1aa2 100644 --- a/iommu_ref_model/test/test_app.h +++ b/iommu_ref_model/test/test_app.h @@ -20,8 +20,8 @@ extern void send_translation_request(uint32_t did, uint8_t pid_valid, uint32_t p hb_to_iommu_req_t *req, iommu_to_hb_rsp_t *rsp); extern int8_t check_rsp_and_faults(hb_to_iommu_req_t *req, iommu_to_hb_rsp_t *rsp, status_t status, uint16_t cause, uint64_t exp_iotval2); -extern int8_t check_msg_faults(uint16_t cause, uint8_t exp_PV, uint32_t exp_PID, - uint8_t exp_PRIV, uint32_t exp_DID, uint64_t exp_iotval); +extern int8_t check_faults(uint16_t cause, uint8_t exp_PV, uint32_t exp_PID, + uint8_t exp_PRIV, uint32_t exp_DID, uint64_t exp_iotval, uint8_t ttyp, uint64_t exp_iotval2); extern int8_t check_exp_pq_rec(uint32_t DID, uint32_t PID, uint8_t PV, uint8_t PRIV, uint8_t EXEC, uint16_t reserved0, uint8_t reserved1, uint64_t PAYLOAD); extern uint64_t get_free_gppn(uint64_t num_gppn, iohgatp_t iohgatp); diff --git a/iommu_ref_model/test/test_utils.c b/iommu_ref_model/test/test_utils.c index f087167..8377101 100644 --- a/iommu_ref_model/test/test_utils.c +++ b/iommu_ref_model/test/test_utils.c @@ -207,9 +207,9 @@ check_exp_pq_rec(uint32_t DID, uint32_t PID, uint8_t PV, uint8_t PRIV, uint8_t E return 0; } int8_t -check_msg_faults( +check_faults( uint16_t cause, uint8_t exp_PV, uint32_t exp_PID, uint8_t exp_PRIV, - uint32_t exp_DID, uint64_t exp_iotval) { + uint32_t exp_DID, uint64_t exp_iotval, uint8_t ttyp, uint64_t exp_iotval2) { fault_rec_t fault_rec; fqb_t fqb; fqh_t fqh; @@ -233,8 +233,8 @@ check_msg_faults( if ( fault_rec.CAUSE != cause || fault_rec.DID != exp_DID || fault_rec.iotval != exp_iotval || - fault_rec.iotval2 != 0 || - fault_rec.TTYP != PCIE_MESSAGE_REQUEST || + fault_rec.iotval2 != exp_iotval2 || + fault_rec.TTYP != ttyp || fault_rec.reserved != 0 ) { printf("Bad fault record\n"); return -1; @@ -255,8 +255,6 @@ check_rsp_and_faults( uint16_t cause, uint64_t exp_iotval2) { - fault_rec_t fault_rec; - fqb_t fqb; fqh_t fqh; uint8_t EXP_TTYP; @@ -292,29 +290,8 @@ check_rsp_and_faults( } if ( cause == 0 ) return 0; - - fqb.raw = read_register(FQB_OFFSET, 8); - read_memory(((fqb.ppn * PAGESIZE) | (fqh.index * FQ_ENTRY_SZ)), FQ_ENTRY_SZ, (char *)&fault_rec); - - // pop the fault record - fqh.index++; - write_register(FQH_OFFSET, 4, fqh.raw); - - if ( fault_rec.CAUSE != cause || fault_rec.DID != req->device_id || - fault_rec.iotval != req->tr.iova || - fault_rec.iotval2 != exp_iotval2 || - fault_rec.TTYP != EXP_TTYP || - fault_rec.reserved != 0 ) { - printf("Bad fault record\n"); - return -1; - } - if ( (req->pid_valid != fault_rec.PV) || - (req->pid_valid && ((fault_rec.PID != req->process_id) || - (fault_rec.PRIV != req->priv_req))) ) { - printf("Bad fault record\n"); - return -1; - } - return 0; + return check_faults(cause, req->pid_valid, req->process_id, req->priv_req, + req->device_id, req->tr.iova, EXP_TTYP, exp_iotval2); } uint64_t add_device(uint32_t device_id, uint32_t gscid, uint8_t en_ats, uint8_t en_pri, uint8_t t2gpa,