From 428eb4f42ae3985875d731c9fa3cb4ffeb17f04a Mon Sep 17 00:00:00 2001 From: Ved Shanbhogue Date: Sun, 21 Apr 2024 12:17:51 -0500 Subject: [PATCH 1/2] Shadow Stack page type (Zicfiss) remains reserved --- iommu.bib | 4 ++++ iommu_data_structures.adoc | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/iommu.bib b/iommu.bib index 55e462c3..15691803 100644 --- a/iommu.bib +++ b/iommu.bib @@ -17,3 +17,7 @@ @electronic{AIA title = {RISC-V Advanced Interrupt Architecture}, url = {https://github.com/riscv/riscv-aia} } +@electronic{CFI, + title = {RISC-V Shadow Stacks and Landing Pads}, + url = {https://github.com/riscv/riscv-cfi} +} diff --git a/iommu_data_structures.adoc b/iommu_data_structures.adoc index 68d926eb..b80c0169 100644 --- a/iommu_data_structures.adoc +++ b/iommu_data_structures.adoc @@ -991,7 +991,9 @@ The process to translate an `IOVA` is as follows: . Translation process is complete When checking the `U` bit in a second-stage PTE, the transaction is treated as -not requesting supervisor privilege. +not requesting supervisor privilege. The `pte.xwr=010` encoding, as specified by +the Zicfiss cite:[CFI] extension for the Shadow Stack page type in single-stage +and VS-stage page tables, remains a reserved encoding for IO transactions. When the translation process reports a fault, and the request is an Untranslated request or a Translated request, the IOMMU requests the IO bridge to abort the From b32f9536a55700efaa421916c4ec40b1ffd571a0 Mon Sep 17 00:00:00 2001 From: Ved Shanbhogue Date: Tue, 23 Apr 2024 09:05:40 -0500 Subject: [PATCH 2/2] update *en behavior to latest spec --- iommu_ref_model/libiommu/src/iommu_reg.c | 98 ++++++++++++------------ iommu_ref_model/test/test_app.c | 30 +++++--- 2 files changed, 69 insertions(+), 59 deletions(-) diff --git a/iommu_ref_model/libiommu/src/iommu_reg.c b/iommu_ref_model/libiommu/src/iommu_reg.c index 2abe27eb..4a42be7e 100644 --- a/iommu_ref_model/libiommu/src/iommu_reg.c +++ b/iommu_ref_model/libiommu/src/iommu_reg.c @@ -215,6 +215,11 @@ write_register( return; g_reg_file.cqb.ppn = cqb_temp.ppn & ppn_mask; g_reg_file.cqb.log2szm1 = cqb_temp.log2szm1; + // The status of bits 31:cqb.LOG2SZ in cqt following a write to cqb + // is 0 and the bits cqb.LOG2SZ-1:0 in cqt assume a valid but + // otherwise UNSPECIFIED value. + // The reference model sets all bits to 0. + g_reg_file.cqt.index = 0; break; case CQH_OFFSET: // This register is read only @@ -236,6 +241,11 @@ write_register( return; g_reg_file.fqb.ppn = fqb_temp.ppn & ppn_mask; g_reg_file.fqb.log2szm1 = fqb_temp.log2szm1; + // The status of bits 31:fqb.LOG2SZ in fqh following a write to fqb + // is 0 and the bits fqb.LOG2SZ-1:0 in fqh assume a valid but + // otherwise UNSPECIFIED value. + // The reference model sets all bits to 0. + g_reg_file.fqh.index = 0; break; case FQH_OFFSET: g_reg_file.fqh.index = fqh_temp.index & @@ -260,6 +270,11 @@ write_register( return; g_reg_file.pqb.ppn = pqb_temp.ppn & ppn_mask; g_reg_file.pqb.log2szm1 = pqb_temp.log2szm1; + // The status of bits 31:pqb.LOG2SZ in pqh following a write to pqb + // is 0 and the bits pqb.LOG2SZ-1:0 in pqh assume a valid but + // otherwise UNSPECIFIED value. + // The reference model sets all bits to 0. + g_reg_file.pqh.index = 0; break; case PQH_OFFSET: // This register is read-only 0 if capabilities.ATS is 0. @@ -296,18 +311,18 @@ write_register( g_reg_file.cqcsr.busy = 1; // The command-queue-enable bit enables the command- // queue when set to 1. Changing `cqen` from 0 to 1 - // sets the `cqh` and `cqt` to 0. The command-queue - // may take some time to be active following setting - // the `cqen` to 1. When the command queue is active, - // the `cqon` bit reads 1. + // sets the `cqh` register and the `cqcsr` bits + // `cmd_ill`,`cmd_to`, `cqmf`, `fence_w_ip` to 0. + // The command-queue may take some time to be active + // following setting the `cqen` to 1. During + // this delay the `busy` bit is 1. When the command + // queue is active, the `cqon` bit reads 1. // When `cqen` is changed from 1 to 0, the command // queue may stay active till the commands already // fetched from the command-queue are being processed // and/or there are outstanding implicit loads from // the command-queue. When the command-queue turns - // off, the `cqon` bit reads 0, `cqh` is set to 0, - // `cqt` is set to 0 and the `cqcsr` bits `cmd_ill`, - // `cmd_to`, `cqmf`, `fence_w_ip` are set to 0. + // off, the `cqon` bit reads 0. // When the `cqon` bit reads 0, the IOMMU guarantees // that no implicit memory accesses to the command // queue are in-flight and the command-queue will not @@ -316,18 +331,15 @@ write_register( // cqen going from 0->1 or 1->0 if ( cqcsr_temp.cqen == 1 ) { g_reg_file.cqh.index = 0; - g_reg_file.cqt.index = 0; + g_reg_file.cqcsr.cmd_ill = 0; + g_reg_file.cqcsr.cmd_to = 0; + g_reg_file.cqcsr.cqmf = 0; + g_reg_file.cqcsr.fence_w_ip = 0; // mark queue as being on g_reg_file.cqcsr.cqen = 1; g_reg_file.cqcsr.cqon = 1; } if ( cqcsr_temp.cqen == 0 ) { - g_reg_file.cqh.index = 0; - g_reg_file.cqt.index = 0; - g_reg_file.cqcsr.cmd_ill = 0; - g_reg_file.cqcsr.cmd_to = 0; - g_reg_file.cqcsr.cqmf = 0; - g_reg_file.cqcsr.fence_w_ip = 0; // mark queue as being off g_reg_file.cqcsr.cqon = 0; g_reg_file.cqcsr.cqen = 0; @@ -361,19 +373,18 @@ write_register( // before writing to the `fqcsr`. // An IOMMU that can complete controls synchronously // may hard-wire this bit to 0. - if ( g_reg_file.fqcsr.busy ) { + if ( g_reg_file.fqcsr.busy ) return; - } // First set the busy bit g_reg_file.fqcsr.busy = 1; // The fault-queue enable bit enables the fault-queue // when set to 1. - // Changing `fqen` from 0 to 1, resets the `fqh` and - // `fqt` to 0 and clears `fqcsr` bits `fqmf` and `fqof`. - // The fault-queue may take some time to be active - // following setting the `fqen` to 1. When the fault - // queue is active, the `fqon` bit reads 1. - + // Changing `fqen` from 0 to 1 sets the `fqt` register + // and the `fqcsr` bits `fqof` and `fqmf` to 0. The + // fault-queue may take some time to be active following + // setting the `fqen` to 1. During this delay the `busy` + // bit is 1. When the fault queue is active, the `fqon` + // bit reads 1. // When `fqen` is changed from 1 to 0, the fault-queue // may stay active till in-flight fault-recording is // completed. When the fault-queue is off, the `fqon` @@ -384,17 +395,14 @@ write_register( if ( g_reg_file.fqcsr.fqen != fqcsr_temp.fqen ) { // fqen going from 0->1 or 1->0 if ( fqcsr_temp.fqen == 1 ) { - g_reg_file.fqh.index = 0; g_reg_file.fqt.index = 0; + g_reg_file.fqcsr.fqof = 0; + g_reg_file.fqcsr.fqmf = 0; // mark queue as being on g_reg_file.fqcsr.fqon = 1; g_reg_file.fqcsr.fqen = 1; } if ( fqcsr_temp.fqen == 0 ) { - g_reg_file.fqh.index = 0; - g_reg_file.fqt.index = 0; - g_reg_file.fqcsr.fqof = 0; - g_reg_file.fqcsr.fqmf = 0; // mark queue as being off g_reg_file.fqcsr.fqon = 0; g_reg_file.fqcsr.fqen = 0; @@ -433,22 +441,19 @@ write_register( g_reg_file.pqcsr.busy = 1; // The page-request-enable bit enables the // page-request-queue when set to 1. - // Changing `pqen` from 0 to 1, resets the `pqh` - // and `pqt` to 0 and clears `pqcsr` bits `pqmf` and - // `pqof` to 0. The page-request-queue may take - // some time to be active following setting the - // `pqen` to 1. When the page-request-queue is - // active, the `pqon` bit reads 1. - // When `pqen` is changed from 1 to 0, the - // page-request-queue may stay active till in-flight - // page-request writes are completed. When the - // page-request-queue turns off, the `pqon` bit - // reads 0, `pqh` is set to 0, `pqt` is set to 0 and - // the `pqcsr` bits `pqof`, and `pqmf` are set to 0. - // When `pqon` reads 0, the IOMMU guarantees that - // there are no older in-flight implicit writes to - // the queue memory and no further implicit writes - // will be generated to the queue memory. + // Changing `pqen` from 0 to 1, sets the `pqt` register and + // the `pqcsr` bits `pqmf` and `pqof` to 0. The + // page-request-queue may take some time to be active following + // setting the `pqen` to 1. During this delay the `busy` bit is + // 1. When the page-request-queue is active, the `pqon` bit + // reads 1. + // When `pqen` is changed from 1 to 0, the page-request-queue may + // stay active (with `busy` asserted) until in-flight + // page-request writes are completed. When the page-request-queue + // turns off, the `pqon` bit reads 0. + // When `pqon` reads 0, the IOMMU guarantees that there are no + // older in-flight implicit writes to the queue memory and no + // further implicit writes will be generated to the queue memory // The IOMMU may respond to “Page Request” messages // received when page-request-queue is off or in // the process of being turned off, as having @@ -457,17 +462,14 @@ write_register( if ( g_reg_file.pqcsr.pqen != pqcsr_temp.pqen ) { // fqen going from 0->1 or 1->0 if ( pqcsr_temp.pqen == 1 ) { - g_reg_file.pqh.index = 0; g_reg_file.pqt.index = 0; + g_reg_file.pqcsr.pqof = 0; + g_reg_file.pqcsr.pqmf = 0; // mark queue as being on g_reg_file.pqcsr.pqon = 1; g_reg_file.pqcsr.pqen = 1; } if ( pqcsr_temp.pqen == 0 ) { - g_reg_file.pqh.index = 0; - g_reg_file.pqt.index = 0; - g_reg_file.pqcsr.pqof = 0; - g_reg_file.pqcsr.pqmf = 0; // mark queue as being off g_reg_file.pqcsr.pqon = 0; g_reg_file.pqcsr.pqen = 0; diff --git a/iommu_ref_model/test/test_app.c b/iommu_ref_model/test/test_app.c index b3fa0cdc..a1bc9a57 100644 --- a/iommu_ref_model/test/test_app.c +++ b/iommu_ref_model/test/test_app.c @@ -294,14 +294,11 @@ main(void) { fqcsr.raw = read_register(FQCSR_OFFSET, 4); fqcsr.fqen = 0; write_register(FQCSR_OFFSET, 4, fqcsr.raw); + write_register(FQH_OFFSET, 4, 0); fqcsr.raw = read_register(FQCSR_OFFSET, 4); fail_if( (fqcsr.fqen == 1) ); fail_if( (fqcsr.fqon == 1) ); fail_if( (fqcsr.busy == 1) ); - fail_if( (fqcsr.fqmf == 1) ); - fail_if( (fqcsr.fqof == 1) ); - fail_if( ( ((read_register(FQH_OFFSET, 4)) != read_register(FQT_OFFSET, 4)) ) ); - fail_if( ( (read_register(FQH_OFFSET, 4) != 0) ) ); // Clear IPSR ipsr.raw = read_register(IPSR_OFFSET, 4); @@ -318,6 +315,8 @@ main(void) { fail_if( (fqcsr.busy == 1) ); fail_if( (fqcsr.fqmf == 1) ); fail_if( (fqcsr.fqof == 1) ); + fail_if( ( ((read_register(FQH_OFFSET, 4)) != read_register(FQT_OFFSET, 4)) ) ); + fail_if( ( (read_register(FQH_OFFSET, 4) != 0) ) ); // Create a memory fault fqb.raw = read_register(FQB_OFFSET, 8); @@ -1065,13 +1064,11 @@ main(void) { fail_if( ( (read_register(CQH_OFFSET, 4) + 1) != read_register(CQT_OFFSET, 4) ) ); cqcsr.cqen = 0; write_register(CQCSR_OFFSET, 4, cqcsr.raw); + write_register(CQT_OFFSET, 4, 0); cqcsr.raw = read_register(CQCSR_OFFSET, 4); fail_if( ( cqcsr.cqen == 1 ) ); fail_if( ( cqcsr.cqon == 1 ) ); - fail_if( ( cqcsr.cqmf == 1 ) ); fail_if( ( cqcsr.busy == 1 ) ); - fail_if( ( cqcsr.cmd_ill == 1 ) ); - fail_if( ( cqcsr.cmd_to == 1 ) ); cqcsr.cqen = 1; write_register(CQCSR_OFFSET, 4, cqcsr.raw); cqcsr.raw = read_register(CQCSR_OFFSET, 4); @@ -1095,6 +1092,7 @@ main(void) { fail_if( ( ipsr.cip != 0 ) ); cqcsr.cqen = 0; write_register(CQCSR_OFFSET, 4, cqcsr.raw); + write_register(CQT_OFFSET, 4, 0); cqcsr.cqen = 1; cqcsr.cie = 1; write_register(CQCSR_OFFSET, 4, cqcsr.raw); @@ -1108,10 +1106,13 @@ main(void) { write_register(DDTP_OFFSET, 8, ddtp.raw); cqcsr.cqen = 0; write_register(CQCSR_OFFSET, 4, cqcsr.raw); + write_register(CQT_OFFSET, 4, 0); fqcsr.fqen = 0; write_register(FQCSR_OFFSET, 4, fqcsr.raw); + write_register(FQH_OFFSET, 4, 0); pqcsr.pqen = 0; write_register(PQCSR_OFFSET, 4, pqcsr.raw); + write_register(PQH_OFFSET, 4, 0); fctl.raw = read_register(FCTRL_OFFSET, 4); fctl.wsi = 1; @@ -1154,10 +1155,13 @@ main(void) { write_register(DDTP_OFFSET, 8, ddtp.raw); cqcsr.cqen = 0; write_register(CQCSR_OFFSET, 4, cqcsr.raw); + write_register(CQT_OFFSET, 4, 0); fqcsr.fqen = 0; write_register(FQCSR_OFFSET, 4, fqcsr.raw); + write_register(FQH_OFFSET, 4, 0); pqcsr.pqen = 0; write_register(PQCSR_OFFSET, 4, pqcsr.raw); + write_register(PQH_OFFSET, 4, 0); fctl.wsi = 0; write_register(FCTRL_OFFSET, 4, fctl.raw); @@ -1572,6 +1576,7 @@ main(void) { fail_if( ( cqcsr.cmd_ill != 1 ) ); cqcsr.cqen = 0; write_register(CQCSR_OFFSET, 4, cqcsr.raw); + write_register(CQT_OFFSET, 4, 0); cqcsr.cqen = 1; write_register(CQCSR_OFFSET, 4, cqcsr.raw); @@ -3412,6 +3417,7 @@ main(void) { fail_if( ( cqcsr.cmd_ill != 1 ) ); cqcsr.cqen = 0; write_register(CQCSR_OFFSET, 4, cqcsr.raw); + write_register(CQT_OFFSET, 4, 0); cqcsr.cqen = 1; write_register(CQCSR_OFFSET, 4, cqcsr.raw); cqcsr.raw = read_register(CQCSR_OFFSET, 4); @@ -3498,6 +3504,7 @@ main(void) { fail_if( ( cqcsr.cmd_ill != 1 ) ); cqcsr.cqen = 0; write_register(CQCSR_OFFSET, 4, cqcsr.raw); + write_register(CQT_OFFSET, 4, 0); cqcsr.cqen = 1; write_register(CQCSR_OFFSET, 4, cqcsr.raw); cqcsr.raw = read_register(CQCSR_OFFSET, 4); @@ -3514,6 +3521,7 @@ main(void) { fail_if( ( cqcsr.cmd_ill != 1 ) ); cqcsr.cqen = 0; write_register(CQCSR_OFFSET, 4, cqcsr.raw); + write_register(CQT_OFFSET, 4, 0); cqcsr.cqen = 1; write_register(CQCSR_OFFSET, 4, cqcsr.raw); cqcsr.raw = read_register(CQCSR_OFFSET, 4); @@ -3527,6 +3535,7 @@ main(void) { fail_if( ( cqcsr.cmd_ill != 1 ) ); cqcsr.cqen = 0; write_register(CQCSR_OFFSET, 4, cqcsr.raw); + write_register(CQT_OFFSET, 4, 0); cqcsr.cqen = 1; write_register(CQCSR_OFFSET, 4, cqcsr.raw); cqcsr.raw = read_register(CQCSR_OFFSET, 4); @@ -3541,6 +3550,7 @@ main(void) { fail_if( ( cqcsr.cmd_ill != 1 ) ); cqcsr.cqen = 0; write_register(CQCSR_OFFSET, 4, cqcsr.raw); + write_register(CQT_OFFSET, 4, 0); cqcsr.cqen = 1; write_register(CQCSR_OFFSET, 4, cqcsr.raw); cqcsr.raw = read_register(CQCSR_OFFSET, 4); @@ -3552,6 +3562,7 @@ main(void) { fail_if( ( cqcsr.cmd_ill != 1 ) ); cqcsr.cqen = 0; write_register(CQCSR_OFFSET, 4, cqcsr.raw); + write_register(CQT_OFFSET, 4, 0); cqcsr.cqen = 1; write_register(CQCSR_OFFSET, 4, cqcsr.raw); cqcsr.raw = read_register(CQCSR_OFFSET, 4); @@ -3563,10 +3574,6 @@ main(void) { cqcsr.raw = read_register(CQCSR_OFFSET, 4); fail_if( ( cqcsr.cmd_ill != 0 ) ); - - - - // idle process_commands(); @@ -3705,6 +3712,7 @@ main(void) { cqcsr.raw = read_register(CQCSR_OFFSET, 4); cqcsr.cqen = 0; write_register(CQCSR_OFFSET, 4, cqcsr.raw); + write_register(CQT_OFFSET, 4, 0); write_register(i, 4, fctl.raw); fctl.raw = read_register(i, 4); fail_if( ( fctl.be != 1 ) );