@@ -64,8 +64,16 @@ struct RISCVIOMMUContext {
6464 uint64_t msiptp ; /* MSI redirection page table pointer */
6565};
6666
67+ typedef enum RISCVIOMMUTransTag {
68+ RISCV_IOMMU_TRANS_TAG_BY , /* Bypass */
69+ RISCV_IOMMU_TRANS_TAG_SS , /* Single Stage */
70+ RISCV_IOMMU_TRANS_TAG_VG , /* G-stage only */
71+ RISCV_IOMMU_TRANS_TAG_VN , /* Nested translation */
72+ } RISCVIOMMUTransTag ;
73+
6774/* Address translation cache entry */
6875struct RISCVIOMMUEntry {
76+ RISCVIOMMUTransTag tag ; /* Translation Tag */
6977 uint64_t iova :44 ; /* IOVA Page Number */
7078 uint64_t pscid :20 ; /* Process Soft-Context identifier */
7179 uint64_t phys :44 ; /* Physical Page Number */
@@ -1227,7 +1235,7 @@ static gboolean riscv_iommu_iot_equal(gconstpointer v1, gconstpointer v2)
12271235 RISCVIOMMUEntry * t1 = (RISCVIOMMUEntry * ) v1 ;
12281236 RISCVIOMMUEntry * t2 = (RISCVIOMMUEntry * ) v2 ;
12291237 return t1 -> gscid == t2 -> gscid && t1 -> pscid == t2 -> pscid &&
1230- t1 -> iova == t2 -> iova ;
1238+ t1 -> iova == t2 -> iova && t1 -> tag == t2 -> tag ;
12311239}
12321240
12331241static guint riscv_iommu_iot_hash (gconstpointer v )
@@ -1236,67 +1244,115 @@ static guint riscv_iommu_iot_hash(gconstpointer v)
12361244 return (guint )t -> iova ;
12371245}
12381246
1239- /* GV: 1 PSCV: 1 AV: 1 */
1247+ /* GV: 0 AV: 0 PSCV: 0 GVMA: 0 */
1248+ /* GV: 0 AV: 0 GVMA: 1 */
1249+ static
1250+ void riscv_iommu_iot_inval_all (gpointer key , gpointer value , gpointer data )
1251+ {
1252+ RISCVIOMMUEntry * iot = (RISCVIOMMUEntry * ) value ;
1253+ RISCVIOMMUEntry * arg = (RISCVIOMMUEntry * ) data ;
1254+ if (iot -> tag == arg -> tag ) {
1255+ iot -> perm = IOMMU_NONE ;
1256+ }
1257+ }
1258+
1259+ /* GV: 0 AV: 0 PSCV: 1 GVMA: 0 */
1260+ static
1261+ void riscv_iommu_iot_inval_pscid (gpointer key , gpointer value , gpointer data )
1262+ {
1263+ RISCVIOMMUEntry * iot = (RISCVIOMMUEntry * ) value ;
1264+ RISCVIOMMUEntry * arg = (RISCVIOMMUEntry * ) data ;
1265+ if (iot -> tag == arg -> tag &&
1266+ iot -> pscid == arg -> pscid ) {
1267+ iot -> perm = IOMMU_NONE ;
1268+ }
1269+ }
1270+
1271+ /* GV: 0 AV: 1 PSCV: 0 GVMA: 0 */
1272+ static
1273+ void riscv_iommu_iot_inval_iova (gpointer key , gpointer value , gpointer data )
1274+ {
1275+ RISCVIOMMUEntry * iot = (RISCVIOMMUEntry * ) value ;
1276+ RISCVIOMMUEntry * arg = (RISCVIOMMUEntry * ) data ;
1277+ if (iot -> tag == arg -> tag &&
1278+ iot -> iova == arg -> iova ) {
1279+ iot -> perm = IOMMU_NONE ;
1280+ }
1281+ }
1282+
1283+ /* GV: 0 AV: 1 PSCV: 1 GVMA: 0 */
12401284static void riscv_iommu_iot_inval_pscid_iova (gpointer key , gpointer value ,
12411285 gpointer data )
12421286{
12431287 RISCVIOMMUEntry * iot = (RISCVIOMMUEntry * ) value ;
12441288 RISCVIOMMUEntry * arg = (RISCVIOMMUEntry * ) data ;
1245- if (iot -> gscid == arg -> gscid &&
1289+ if (iot -> tag == arg -> tag &&
12461290 iot -> pscid == arg -> pscid &&
12471291 iot -> iova == arg -> iova ) {
12481292 iot -> perm = IOMMU_NONE ;
12491293 }
12501294}
12511295
1252- /* GV: 1 PSCV: 1 AV: 0 */
1253- static void riscv_iommu_iot_inval_pscid (gpointer key , gpointer value ,
1254- gpointer data )
1296+ /* GV: 1 AV: 0 PSCV: 0 GVMA: 0 */
1297+ /* GV: 1 AV: 0 GVMA: 1 */
1298+ static
1299+ void riscv_iommu_iot_inval_gscid (gpointer key , gpointer value , gpointer data )
12551300{
12561301 RISCVIOMMUEntry * iot = (RISCVIOMMUEntry * ) value ;
12571302 RISCVIOMMUEntry * arg = (RISCVIOMMUEntry * ) data ;
1258- if (iot -> gscid == arg -> gscid &&
1259- iot -> pscid == arg -> pscid ) {
1303+ if (iot -> tag == arg -> tag &&
1304+ iot -> gscid == arg -> gscid ) {
12601305 iot -> perm = IOMMU_NONE ;
12611306 }
12621307}
12631308
1264- /* GV: 1 GVMA: 1 */
1265- static void riscv_iommu_iot_inval_gscid_gpa (gpointer key , gpointer value ,
1266- gpointer data )
1309+ /* GV: 1 AV: 0 PSCV: 1 GVMA: 0 */
1310+ static void riscv_iommu_iot_inval_gscid_pscid (gpointer key , gpointer value ,
1311+ gpointer data )
12671312{
12681313 RISCVIOMMUEntry * iot = (RISCVIOMMUEntry * ) value ;
12691314 RISCVIOMMUEntry * arg = (RISCVIOMMUEntry * ) data ;
1270- if (iot -> gscid == arg -> gscid ) {
1271- /* simplified cache, no GPA matching */
1315+ if (iot -> tag == arg -> tag &&
1316+ iot -> gscid == arg -> gscid &&
1317+ iot -> pscid == arg -> pscid ) {
12721318 iot -> perm = IOMMU_NONE ;
12731319 }
12741320}
12751321
1276- /* GV: 1 GVMA: 0 */
1277- static void riscv_iommu_iot_inval_gscid (gpointer key , gpointer value ,
1278- gpointer data )
1322+ /* GV: 1 AV: 1 PSCV: 0 GVMA: 0 */
1323+ /* GV: 1 AV: 1 GVMA: 1 */
1324+ static void riscv_iommu_iot_inval_gscid_iova (gpointer key , gpointer value ,
1325+ gpointer data )
12791326{
12801327 RISCVIOMMUEntry * iot = (RISCVIOMMUEntry * ) value ;
12811328 RISCVIOMMUEntry * arg = (RISCVIOMMUEntry * ) data ;
1282- if (iot -> gscid == arg -> gscid ) {
1329+ if (iot -> tag == arg -> tag &&
1330+ iot -> gscid == arg -> gscid &&
1331+ iot -> iova == arg -> iova ) {
12831332 iot -> perm = IOMMU_NONE ;
12841333 }
12851334}
12861335
1287- /* GV: 0 */
1288- static void riscv_iommu_iot_inval_all (gpointer key , gpointer value ,
1289- gpointer data )
1336+ /* GV: 1 AV: 1 PSCV: 1 GVMA: 0 */
1337+ static void riscv_iommu_iot_inval_gscid_pscid_iova (gpointer key , gpointer value ,
1338+ gpointer data )
12901339{
12911340 RISCVIOMMUEntry * iot = (RISCVIOMMUEntry * ) value ;
1292- iot -> perm = IOMMU_NONE ;
1341+ RISCVIOMMUEntry * arg = (RISCVIOMMUEntry * ) data ;
1342+ if (iot -> tag == arg -> tag &&
1343+ iot -> gscid == arg -> gscid &&
1344+ iot -> pscid == arg -> pscid &&
1345+ iot -> iova == arg -> iova ) {
1346+ iot -> perm = IOMMU_NONE ;
1347+ }
12931348}
12941349
12951350/* caller should keep ref-count for iot_cache object */
12961351static RISCVIOMMUEntry * riscv_iommu_iot_lookup (RISCVIOMMUContext * ctx ,
1297- GHashTable * iot_cache , hwaddr iova )
1352+ GHashTable * iot_cache , hwaddr iova , RISCVIOMMUTransTag transtag )
12981353{
12991354 RISCVIOMMUEntry key = {
1355+ .tag = transtag ,
13001356 .gscid = get_field (ctx -> gatp , RISCV_IOMMU_DC_IOHGATP_GSCID ),
13011357 .pscid = get_field (ctx -> ta , RISCV_IOMMU_DC_TA_PSCID ),
13021358 .iova = PPN_DOWN (iova ),
@@ -1322,10 +1378,11 @@ static void riscv_iommu_iot_update(RISCVIOMMUState *s,
13221378}
13231379
13241380static void riscv_iommu_iot_inval (RISCVIOMMUState * s , GHFunc func ,
1325- uint32_t gscid , uint32_t pscid , hwaddr iova )
1381+ uint32_t gscid , uint32_t pscid , hwaddr iova , RISCVIOMMUTransTag transtag )
13261382{
13271383 GHashTable * iot_cache ;
13281384 RISCVIOMMUEntry key = {
1385+ .tag = transtag ,
13291386 .gscid = gscid ,
13301387 .pscid = pscid ,
13311388 .iova = PPN_DOWN (iova ),
@@ -1336,9 +1393,24 @@ static void riscv_iommu_iot_inval(RISCVIOMMUState *s, GHFunc func,
13361393 g_hash_table_unref (iot_cache );
13371394}
13381395
1396+ static RISCVIOMMUTransTag riscv_iommu_get_transtag (RISCVIOMMUContext * ctx )
1397+ {
1398+ uint64_t satp = get_field (ctx -> satp , RISCV_IOMMU_ATP_MODE_FIELD );
1399+ uint64_t gatp = get_field (ctx -> gatp , RISCV_IOMMU_ATP_MODE_FIELD );
1400+
1401+ if (satp == RISCV_IOMMU_DC_FSC_MODE_BARE ) {
1402+ return (gatp == RISCV_IOMMU_DC_IOHGATP_MODE_BARE ) ?
1403+ RISCV_IOMMU_TRANS_TAG_BY : RISCV_IOMMU_TRANS_TAG_VG ;
1404+ } else {
1405+ return (gatp == RISCV_IOMMU_DC_IOHGATP_MODE_BARE ) ?
1406+ RISCV_IOMMU_TRANS_TAG_SS : RISCV_IOMMU_TRANS_TAG_VN ;
1407+ }
1408+ }
1409+
13391410static int riscv_iommu_translate (RISCVIOMMUState * s , RISCVIOMMUContext * ctx ,
13401411 IOMMUTLBEntry * iotlb , bool enable_cache )
13411412{
1413+ RISCVIOMMUTransTag transtag = riscv_iommu_get_transtag (ctx );
13421414 RISCVIOMMUEntry * iot ;
13431415 IOMMUAccessFlags perm ;
13441416 bool enable_pid ;
@@ -1364,7 +1436,7 @@ static int riscv_iommu_translate(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
13641436 }
13651437 }
13661438
1367- iot = riscv_iommu_iot_lookup (ctx , iot_cache , iotlb -> iova );
1439+ iot = riscv_iommu_iot_lookup (ctx , iot_cache , iotlb -> iova , transtag );
13681440 perm = iot ? iot -> perm : IOMMU_NONE ;
13691441 if (perm != IOMMU_NONE ) {
13701442 iotlb -> translated_addr = PPN_PHYS (iot -> phys );
@@ -1395,6 +1467,7 @@ static int riscv_iommu_translate(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
13951467 iot -> gscid = get_field (ctx -> gatp , RISCV_IOMMU_DC_IOHGATP_GSCID );
13961468 iot -> pscid = get_field (ctx -> ta , RISCV_IOMMU_DC_TA_PSCID );
13971469 iot -> perm = iotlb -> perm ;
1470+ iot -> tag = transtag ;
13981471 riscv_iommu_iot_update (s , iot_cache , iot );
13991472 }
14001473
@@ -1602,44 +1675,72 @@ static void riscv_iommu_process_cq_tail(RISCVIOMMUState *s)
16021675
16031676 case RISCV_IOMMU_CMD (RISCV_IOMMU_CMD_IOTINVAL_FUNC_GVMA ,
16041677 RISCV_IOMMU_CMD_IOTINVAL_OPCODE ):
1605- if (cmd .dword0 & RISCV_IOMMU_CMD_IOTINVAL_PSCV ) {
1678+ {
1679+ bool gv = !!(cmd .dword0 & RISCV_IOMMU_CMD_IOTINVAL_GV );
1680+ bool av = !!(cmd .dword0 & RISCV_IOMMU_CMD_IOTINVAL_AV );
1681+ bool pscv = !!(cmd .dword0 & RISCV_IOMMU_CMD_IOTINVAL_PSCV );
1682+ uint32_t gscid = get_field (cmd .dword0 ,
1683+ RISCV_IOMMU_CMD_IOTINVAL_GSCID );
1684+ uint32_t pscid = get_field (cmd .dword0 ,
1685+ RISCV_IOMMU_CMD_IOTINVAL_PSCID );
1686+ hwaddr iova = (cmd .dword1 << 2 ) & TARGET_PAGE_MASK ;
1687+
1688+ if (pscv ) {
16061689 /* illegal command arguments IOTINVAL.GVMA & PSCV == 1 */
16071690 goto cmd_ill ;
1608- } else if (!(cmd .dword0 & RISCV_IOMMU_CMD_IOTINVAL_GV )) {
1609- /* invalidate all cache mappings */
1610- func = riscv_iommu_iot_inval_all ;
1611- } else if (!(cmd .dword0 & RISCV_IOMMU_CMD_IOTINVAL_AV )) {
1612- /* invalidate cache matching GSCID */
1613- func = riscv_iommu_iot_inval_gscid ;
1614- } else {
1615- /* invalidate cache matching GSCID and ADDR (GPA) */
1616- func = riscv_iommu_iot_inval_gscid_gpa ;
16171691 }
1618- riscv_iommu_iot_inval (s , func ,
1619- get_field (cmd .dword0 , RISCV_IOMMU_CMD_IOTINVAL_GSCID ), 0 ,
1620- cmd .dword1 << 2 & TARGET_PAGE_MASK );
1692+
1693+ func = riscv_iommu_iot_inval_all ;
1694+
1695+ if (gv ) {
1696+ func = (av ) ? riscv_iommu_iot_inval_gscid_iova :
1697+ riscv_iommu_iot_inval_gscid ;
1698+ }
1699+
1700+ riscv_iommu_iot_inval (
1701+ s , func , gscid , pscid , iova , RISCV_IOMMU_TRANS_TAG_VG );
1702+
1703+ riscv_iommu_iot_inval (
1704+ s , func , gscid , pscid , iova , RISCV_IOMMU_TRANS_TAG_VN );
16211705 break ;
1706+ }
16221707
16231708 case RISCV_IOMMU_CMD (RISCV_IOMMU_CMD_IOTINVAL_FUNC_VMA ,
16241709 RISCV_IOMMU_CMD_IOTINVAL_OPCODE ):
1625- if (!(cmd .dword0 & RISCV_IOMMU_CMD_IOTINVAL_GV )) {
1626- /* invalidate all cache mappings, simplified model */
1627- func = riscv_iommu_iot_inval_all ;
1628- } else if (!(cmd .dword0 & RISCV_IOMMU_CMD_IOTINVAL_PSCV )) {
1629- /* invalidate cache matching GSCID, simplified model */
1630- func = riscv_iommu_iot_inval_gscid ;
1631- } else if (!(cmd .dword0 & RISCV_IOMMU_CMD_IOTINVAL_AV )) {
1632- /* invalidate cache matching GSCID and PSCID */
1633- func = riscv_iommu_iot_inval_pscid ;
1710+ {
1711+ bool gv = !!(cmd .dword0 & RISCV_IOMMU_CMD_IOTINVAL_GV );
1712+ bool av = !!(cmd .dword0 & RISCV_IOMMU_CMD_IOTINVAL_AV );
1713+ bool pscv = !!(cmd .dword0 & RISCV_IOMMU_CMD_IOTINVAL_PSCV );
1714+ uint32_t gscid = get_field (cmd .dword0 ,
1715+ RISCV_IOMMU_CMD_IOTINVAL_GSCID );
1716+ uint32_t pscid = get_field (cmd .dword0 ,
1717+ RISCV_IOMMU_CMD_IOTINVAL_PSCID );
1718+ hwaddr iova = (cmd .dword1 << 2 ) & TARGET_PAGE_MASK ;
1719+ RISCVIOMMUTransTag transtag ;
1720+
1721+ if (gv ) {
1722+ transtag = RISCV_IOMMU_TRANS_TAG_VN ;
1723+ if (pscv ) {
1724+ func = (av ) ? riscv_iommu_iot_inval_gscid_pscid_iova :
1725+ riscv_iommu_iot_inval_gscid_pscid ;
1726+ } else {
1727+ func = (av ) ? riscv_iommu_iot_inval_gscid_iova :
1728+ riscv_iommu_iot_inval_gscid ;
1729+ }
16341730 } else {
1635- /* invalidate cache matching GSCID and PSCID and ADDR (IOVA) */
1636- func = riscv_iommu_iot_inval_pscid_iova ;
1731+ transtag = RISCV_IOMMU_TRANS_TAG_SS ;
1732+ if (pscv ) {
1733+ func = (av ) ? riscv_iommu_iot_inval_pscid_iova :
1734+ riscv_iommu_iot_inval_pscid ;
1735+ } else {
1736+ func = (av ) ? riscv_iommu_iot_inval_iova :
1737+ riscv_iommu_iot_inval_all ;
1738+ }
16371739 }
1638- riscv_iommu_iot_inval (s , func ,
1639- get_field (cmd .dword0 , RISCV_IOMMU_CMD_IOTINVAL_GSCID ),
1640- get_field (cmd .dword0 , RISCV_IOMMU_CMD_IOTINVAL_PSCID ),
1641- cmd .dword1 << 2 & TARGET_PAGE_MASK );
1740+
1741+ riscv_iommu_iot_inval (s , func , gscid , pscid , iova , transtag );
16421742 break ;
1743+ }
16431744
16441745 case RISCV_IOMMU_CMD (RISCV_IOMMU_CMD_IODIR_FUNC_INVAL_DDT ,
16451746 RISCV_IOMMU_CMD_IODIR_OPCODE ):
0 commit comments