@@ -64,8 +64,16 @@ struct RISCVIOMMUContext {
64
64
uint64_t msiptp ; /* MSI redirection page table pointer */
65
65
};
66
66
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
+
67
74
/* Address translation cache entry */
68
75
struct RISCVIOMMUEntry {
76
+ RISCVIOMMUTransTag tag ; /* Translation Tag */
69
77
uint64_t iova :44 ; /* IOVA Page Number */
70
78
uint64_t pscid :20 ; /* Process Soft-Context identifier */
71
79
uint64_t phys :44 ; /* Physical Page Number */
@@ -1227,7 +1235,7 @@ static gboolean riscv_iommu_iot_equal(gconstpointer v1, gconstpointer v2)
1227
1235
RISCVIOMMUEntry * t1 = (RISCVIOMMUEntry * ) v1 ;
1228
1236
RISCVIOMMUEntry * t2 = (RISCVIOMMUEntry * ) v2 ;
1229
1237
return t1 -> gscid == t2 -> gscid && t1 -> pscid == t2 -> pscid &&
1230
- t1 -> iova == t2 -> iova ;
1238
+ t1 -> iova == t2 -> iova && t1 -> tag == t2 -> tag ;
1231
1239
}
1232
1240
1233
1241
static guint riscv_iommu_iot_hash (gconstpointer v )
@@ -1236,67 +1244,115 @@ static guint riscv_iommu_iot_hash(gconstpointer v)
1236
1244
return (guint )t -> iova ;
1237
1245
}
1238
1246
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 */
1240
1284
static void riscv_iommu_iot_inval_pscid_iova (gpointer key , gpointer value ,
1241
1285
gpointer data )
1242
1286
{
1243
1287
RISCVIOMMUEntry * iot = (RISCVIOMMUEntry * ) value ;
1244
1288
RISCVIOMMUEntry * arg = (RISCVIOMMUEntry * ) data ;
1245
- if (iot -> gscid == arg -> gscid &&
1289
+ if (iot -> tag == arg -> tag &&
1246
1290
iot -> pscid == arg -> pscid &&
1247
1291
iot -> iova == arg -> iova ) {
1248
1292
iot -> perm = IOMMU_NONE ;
1249
1293
}
1250
1294
}
1251
1295
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 )
1255
1300
{
1256
1301
RISCVIOMMUEntry * iot = (RISCVIOMMUEntry * ) value ;
1257
1302
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 ) {
1260
1305
iot -> perm = IOMMU_NONE ;
1261
1306
}
1262
1307
}
1263
1308
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 )
1267
1312
{
1268
1313
RISCVIOMMUEntry * iot = (RISCVIOMMUEntry * ) value ;
1269
1314
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 ) {
1272
1318
iot -> perm = IOMMU_NONE ;
1273
1319
}
1274
1320
}
1275
1321
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 )
1279
1326
{
1280
1327
RISCVIOMMUEntry * iot = (RISCVIOMMUEntry * ) value ;
1281
1328
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 ) {
1283
1332
iot -> perm = IOMMU_NONE ;
1284
1333
}
1285
1334
}
1286
1335
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 )
1290
1339
{
1291
1340
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
+ }
1293
1348
}
1294
1349
1295
1350
/* caller should keep ref-count for iot_cache object */
1296
1351
static RISCVIOMMUEntry * riscv_iommu_iot_lookup (RISCVIOMMUContext * ctx ,
1297
- GHashTable * iot_cache , hwaddr iova )
1352
+ GHashTable * iot_cache , hwaddr iova , RISCVIOMMUTransTag transtag )
1298
1353
{
1299
1354
RISCVIOMMUEntry key = {
1355
+ .tag = transtag ,
1300
1356
.gscid = get_field (ctx -> gatp , RISCV_IOMMU_DC_IOHGATP_GSCID ),
1301
1357
.pscid = get_field (ctx -> ta , RISCV_IOMMU_DC_TA_PSCID ),
1302
1358
.iova = PPN_DOWN (iova ),
@@ -1322,10 +1378,11 @@ static void riscv_iommu_iot_update(RISCVIOMMUState *s,
1322
1378
}
1323
1379
1324
1380
static 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 )
1326
1382
{
1327
1383
GHashTable * iot_cache ;
1328
1384
RISCVIOMMUEntry key = {
1385
+ .tag = transtag ,
1329
1386
.gscid = gscid ,
1330
1387
.pscid = pscid ,
1331
1388
.iova = PPN_DOWN (iova ),
@@ -1336,9 +1393,24 @@ static void riscv_iommu_iot_inval(RISCVIOMMUState *s, GHFunc func,
1336
1393
g_hash_table_unref (iot_cache );
1337
1394
}
1338
1395
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
+
1339
1410
static int riscv_iommu_translate (RISCVIOMMUState * s , RISCVIOMMUContext * ctx ,
1340
1411
IOMMUTLBEntry * iotlb , bool enable_cache )
1341
1412
{
1413
+ RISCVIOMMUTransTag transtag = riscv_iommu_get_transtag (ctx );
1342
1414
RISCVIOMMUEntry * iot ;
1343
1415
IOMMUAccessFlags perm ;
1344
1416
bool enable_pid ;
@@ -1364,7 +1436,7 @@ static int riscv_iommu_translate(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
1364
1436
}
1365
1437
}
1366
1438
1367
- iot = riscv_iommu_iot_lookup (ctx , iot_cache , iotlb -> iova );
1439
+ iot = riscv_iommu_iot_lookup (ctx , iot_cache , iotlb -> iova , transtag );
1368
1440
perm = iot ? iot -> perm : IOMMU_NONE ;
1369
1441
if (perm != IOMMU_NONE ) {
1370
1442
iotlb -> translated_addr = PPN_PHYS (iot -> phys );
@@ -1395,6 +1467,7 @@ static int riscv_iommu_translate(RISCVIOMMUState *s, RISCVIOMMUContext *ctx,
1395
1467
iot -> gscid = get_field (ctx -> gatp , RISCV_IOMMU_DC_IOHGATP_GSCID );
1396
1468
iot -> pscid = get_field (ctx -> ta , RISCV_IOMMU_DC_TA_PSCID );
1397
1469
iot -> perm = iotlb -> perm ;
1470
+ iot -> tag = transtag ;
1398
1471
riscv_iommu_iot_update (s , iot_cache , iot );
1399
1472
}
1400
1473
@@ -1602,44 +1675,72 @@ static void riscv_iommu_process_cq_tail(RISCVIOMMUState *s)
1602
1675
1603
1676
case RISCV_IOMMU_CMD (RISCV_IOMMU_CMD_IOTINVAL_FUNC_GVMA ,
1604
1677
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 ) {
1606
1689
/* illegal command arguments IOTINVAL.GVMA & PSCV == 1 */
1607
1690
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 ;
1617
1691
}
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 );
1621
1705
break ;
1706
+ }
1622
1707
1623
1708
case RISCV_IOMMU_CMD (RISCV_IOMMU_CMD_IOTINVAL_FUNC_VMA ,
1624
1709
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
+ }
1634
1730
} 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
+ }
1637
1739
}
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 );
1642
1742
break ;
1743
+ }
1643
1744
1644
1745
case RISCV_IOMMU_CMD (RISCV_IOMMU_CMD_IODIR_FUNC_INVAL_DDT ,
1645
1746
RISCV_IOMMU_CMD_IODIR_OPCODE ):
0 commit comments