@@ -19,10 +19,15 @@
#else
/* 64-bit target, since QEMU isn't built to have TARGET_LONG_BITS over 64 */
# define TARGET_LONG_BITS 64
-# define TARGET_PHYS_ADDR_SPACE_BITS 56 /* 44-bit PPN */
-# define TARGET_VIRT_ADDR_SPACE_BITS 48 /* sv48 */
+# define TARGET_PHYS_ADDR_SPACE_BITS 64 /* 54-bit PPN */
+# define TARGET_VIRT_ADDR_SPACE_BITS 44 /* sv44 */
#endif
+
+#if defined(TARGET_RISCV32) || defined(TARGET_RISCV64)
#define TARGET_PAGE_BITS 12 /* 4 KiB Pages */
+#else
+#define TARGET_PAGE_BITS 14 /* 16 KiB pages for RV128 */
+#endif
/*
* The current MMU Modes are:
* - U mode 0b000
@@ -428,6 +428,11 @@
#define SATP64_ASID 0x0FFFF00000000000ULL
#define SATP64_PPN 0x00000FFFFFFFFFFFULL
+/* RV128 satp CSR field masks (H/L for high/low dword) */
+#define SATP128_HMODE 0xFF00000000000000ULL
+#define SATP128_HASID 0x00FFFFFFFF000000ULL
+#define SATP128_LPPN 0x0003FFFFFFFFFFFFULL
+
/* VM modes (mstatus.vm) privileged ISA 1.9.1 */
#define VM_1_09_MBARE 0
#define VM_1_09_MBB 1
@@ -443,6 +448,9 @@
#define VM_1_10_SV48 9
#define VM_1_10_SV57 10
#define VM_1_10_SV64 11
+#define VM_1_10_SV44 12
+#define VM_1_10_SV54 13
+
/* Page table entry (PTE) fields */
#define PTE_V 0x001 /* Valid */
@@ -460,6 +468,8 @@
/* Leaf page shift amount */
#define PGSHIFT 12
+/* For now, pages in RV128 are 16 KiB. */
+#define PGSHIFT128 14
/* Default Reset Vector adress */
#define DEFAULT_RSTVEC 0x1000
@@ -391,7 +391,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
*prot = 0;
hwaddr base;
- int levels, ptidxbits, ptesize, vm, sum, mxr, widened;
+ int levels, ptidxbits, ptesize, vm, sum, mxr, widened, pgshift;
if (first_stage == true) {
mxr = get_field(env->mstatus, MSTATUS_MXR);
@@ -404,17 +404,25 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
if (riscv_cpu_is_32bit(env)) {
base = (hwaddr)get_field(env->vsatp, SATP32_PPN) << PGSHIFT;
vm = get_field(env->vsatp, SATP32_MODE);
- } else {
+ } else if (riscv_cpu_is_64bit(env)) {
base = (hwaddr)get_field(env->vsatp, SATP64_PPN) << PGSHIFT;
vm = get_field(env->vsatp, SATP64_MODE);
+ } else {
+ /* TODO : Hypervisor extension not supported yet in RV128. */
+ g_assert_not_reached();
}
} else {
if (riscv_cpu_is_32bit(env)) {
base = (hwaddr)get_field(env->satp, SATP32_PPN) << PGSHIFT;
vm = get_field(env->satp, SATP32_MODE);
- } else {
+ } else if (riscv_cpu_is_64bit(env)) {
base = (hwaddr)get_field(env->satp, SATP64_PPN) << PGSHIFT;
vm = get_field(env->satp, SATP64_MODE);
+ } else if (riscv_cpu_is_128bit(env)) {
+ base = (hwaddr)get_field(env->satp, SATP128_LPPN) << PGSHIFT128;
+ vm = get_field(env->satph, SATP128_HMODE);
+ } else {
+ g_assert_not_reached();
}
}
widened = 0;
@@ -422,9 +430,15 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
if (riscv_cpu_is_32bit(env)) {
base = (hwaddr)get_field(env->hgatp, SATP32_PPN) << PGSHIFT;
vm = get_field(env->hgatp, SATP32_MODE);
- } else {
+ } else if (riscv_cpu_is_64bit(env)) {
base = (hwaddr)get_field(env->hgatp, SATP64_PPN) << PGSHIFT;
vm = get_field(env->hgatp, SATP64_MODE);
+ } else {
+ /*
+ * TODO : Hypervisor extension not supported yet in RV128,
+ * so there shouldn't be any two-stage address lookups.
+ */
+ g_assert_not_reached();
}
widened = 2;
}
@@ -432,13 +446,17 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
sum = get_field(env->mstatus, MSTATUS_SUM) || use_background || is_debug;
switch (vm) {
case VM_1_10_SV32:
- levels = 2; ptidxbits = 10; ptesize = 4; break;
+ levels = 2; ptidxbits = 10; ptesize = 4; pgshift = 12; break;
case VM_1_10_SV39:
- levels = 3; ptidxbits = 9; ptesize = 8; break;
+ levels = 3; ptidxbits = 9; ptesize = 8; pgshift = 12; break;
case VM_1_10_SV48:
- levels = 4; ptidxbits = 9; ptesize = 8; break;
+ levels = 4; ptidxbits = 9; ptesize = 8; pgshift = 12; break;
case VM_1_10_SV57:
- levels = 5; ptidxbits = 9; ptesize = 8; break;
+ levels = 5; ptidxbits = 9; ptesize = 8; pgshift = 12; break;
+ case VM_1_10_SV44:
+ levels = 3; ptidxbits = 10; ptesize = 16; pgshift = 14; break;
+ case VM_1_10_SV54:
+ levels = 4; ptidxbits = 10; ptesize = 16; pgshift = 14; break;
case VM_1_10_MBARE:
*physical = addr;
*prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
@@ -448,7 +466,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
}
CPUState *cs = env_cpu(env);
- int va_bits = PGSHIFT + levels * ptidxbits + widened;
+ int va_bits = pgshift + levels * ptidxbits + widened;
target_ulong mask, masked_msbs;
if (TARGET_LONG_BITS > (va_bits - 1)) {
@@ -463,6 +481,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
}
int ptshift = (levels - 1) * ptidxbits;
+ uint64_t pgoff_mask = (1ULL << pgshift) - 1;
int i;
#if !TCG_OVERSIZED_GUEST
@@ -471,10 +490,10 @@ restart:
for (i = 0; i < levels; i++, ptshift -= ptidxbits) {
target_ulong idx;
if (i == 0) {
- idx = (addr >> (PGSHIFT + ptshift)) &
+ idx = (addr >> (pgshift + ptshift)) &
((1 << (ptidxbits + widened)) - 1);
} else {
- idx = (addr >> (PGSHIFT + ptshift)) &
+ idx = (addr >> (pgshift + ptshift)) &
((1 << ptidxbits) - 1);
}
@@ -482,6 +501,7 @@ restart:
hwaddr pte_addr;
if (two_stage && first_stage) {
+ /* TODO : Two-stage translation for RV128 */
int vbase_prot;
hwaddr vbase;
@@ -515,6 +535,10 @@ restart:
if (riscv_cpu_is_32bit(env)) {
pte = address_space_ldl(cs->as, pte_addr, attrs, &res);
} else {
+ /*
+ * For RV128, load only lower 64 bits as only those
+ * are used for now
+ */
pte = address_space_ldq(cs->as, pte_addr, attrs, &res);
}
@@ -529,7 +553,7 @@ restart:
return TRANSLATE_FAIL;
} else if (!(pte & (PTE_R | PTE_W | PTE_X))) {
/* Inner PTE, continue walking */
- base = ppn << PGSHIFT;
+ base = ppn << pgshift;
} else if ((pte & (PTE_R | PTE_W | PTE_X)) == PTE_W) {
/* Reserved leaf PTE flags: PTE_W */
return TRANSLATE_FAIL;
@@ -601,9 +625,9 @@ restart:
/* for superpage mappings, make a fake leaf PTE for the TLB's
benefit. */
- target_ulong vpn = addr >> PGSHIFT;
- *physical = ((ppn | (vpn & ((1L << ptshift) - 1))) << PGSHIFT) |
- (addr & ~TARGET_PAGE_MASK);
+ target_ulong vpn = addr >> pgshift;
+ *physical = ((ppn | (vpn & ((1L << ptshift) - 1))) << pgshift) |
+ (addr & pgoff_mask);
/* set permissions on the TLB entry */
if ((pte & PTE_R) || ((pte & PTE_X) && mxr)) {
@@ -461,6 +461,12 @@ static const char valid_vm_1_10_64[16] = {
[VM_1_10_SV57] = 1
};
+static const bool valid_vm_1_10_128[16] = {
+ [VM_1_10_MBARE] = 1,
+ [VM_1_10_SV44] = 1,
+ [VM_1_10_SV54] = 1
+};
+
/* Machine Information Registers */
static RISCVException read_zero_i128(CPURISCVState *env, int csrno,
Int128 *val)
@@ -557,8 +563,12 @@ static int validate_vm(CPURISCVState *env, target_ulong vm)
{
if (riscv_cpu_is_32bit(env)) {
return valid_vm_1_10_32[vm & 0xf];
- } else {
+ } else if (riscv_cpu_is_64bit(env)) {
return valid_vm_1_10_64[vm & 0xf];
+ } else if (riscv_cpu_is_128bit(env)) {
+ return valid_vm_1_10_128[vm & 0xf];
+ } else {
+ return 0;
}
}
@@ -1090,6 +1100,67 @@ static RISCVException rmw_sip(CPURISCVState *env, int csrno,
}
/* Supervisor Protection and Translation */
+static RISCVException read_satp_i128(CPURISCVState *env, int csrno,
+ Int128 *val)
+{
+ if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
+ *val = int128_zero();
+ return RISCV_EXCP_NONE;
+ }
+
+ if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ } else {
+ *val = int128_make128(env->satp, env->satph);
+ }
+
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_satp_i128(CPURISCVState *env, int csrno,
+ Int128 val)
+{
+ uint32_t asid;
+ bool vm_ok;
+ Int128 mask;
+
+ if (!riscv_feature(env, RISCV_FEATURE_MMU)) {
+ return RISCV_EXCP_NONE;
+ }
+
+ if (riscv_cpu_is_32bit(env)) {
+ vm_ok = validate_vm(env, get_field(int128_getlo(val), SATP32_MODE));
+ mask = int128_make64((int128_getlo(val) ^ env->satp)
+ & (SATP32_MODE | SATP32_ASID | SATP32_PPN));
+ asid = (int128_getlo(val) ^ env->satp) & SATP32_ASID;
+ } else if (riscv_cpu_is_64bit(env)) {
+ vm_ok = validate_vm(env, get_field(int128_getlo(val), SATP64_MODE));
+ mask = int128_make64((int128_getlo(val) ^ env->satp)
+ & (SATP64_MODE | SATP64_ASID | SATP64_PPN));
+ asid = (int128_getlo(val) ^ env->satp) & SATP64_ASID;
+ } else {
+ vm_ok = validate_vm(env, get_field(int128_gethi(val), SATP128_HMODE));
+ mask = int128_and(
+ int128_xor(val, int128_make128(env->satp, env->satph)),
+ int128_make128(SATP128_LPPN, SATP128_HMODE | SATP128_HASID));
+ asid = (int128_gethi(val) ^ env->satph) & SATP128_HASID;
+ }
+
+
+ if (vm_ok && int128_nz(mask)) {
+ if (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_TVM)) {
+ return RISCV_EXCP_ILLEGAL_INST;
+ } else {
+ if (asid) {
+ tlb_flush(env_cpu(env));
+ }
+ env->satp = int128_getlo(val);
+ env->satph = int128_gethi(val);
+ }
+ }
+ return RISCV_EXCP_NONE;
+}
+
static RISCVException read_satp(CPURISCVState *env, int csrno,
target_ulong *val)
{
@@ -1624,7 +1695,7 @@ static inline RISCVException riscv_csrrw_check_i128(CPURISCVState *env,
/* check privileges and return -1 if check fails */
#if !defined(CONFIG_USER_ONLY)
int effective_priv = env->priv;
- int read_only = get_field(csrno, 0xc00) == 3;
+ int read_only = get_field(csrno, 0xC00) == 3;
if (riscv_has_ext(env, RVH) &&
env->priv == PRV_S &&
@@ -1765,7 +1836,7 @@ riscv_csr_operations128 csr_ops_128[CSR_TABLE_SIZE] = {
[CSR_MSCRATCH] = { read_mscratch_i128, write_mscratch_i128 },
[CSR_MEPC] = { read_mepc_i128, write_mepc_i128 },
- [CSR_SATP] = { read_zero_i128 },
+ [CSR_SATP] = { read_satp_i128, write_satp_i128 },
#endif
};
Support for a 128-bit satp. This is a bit more involved than necessary because we took the opportunity to increase the page size to 16kB, and change the page table geometry, which makes the page walk a bit more parametrizable (variables instead of defines). Note that is anyway a necessary step for the merging of the 32-bit and 64-bit riscv versions in a single executable. Signed-off-by: Frédéric Pétrot <frederic.petrot@univ-grenoble-alpes.fr> Co-authored-by: Fabien Portas <fabien.portas@grenoble-inp.org> --- target/riscv/cpu-param.h | 9 ++++- target/riscv/cpu_bits.h | 10 +++++ target/riscv/cpu_helper.c | 54 +++++++++++++++++++-------- target/riscv/csr.c | 77 +++++++++++++++++++++++++++++++++++++-- 4 files changed, 130 insertions(+), 20 deletions(-)