Skip to content

Commit

Permalink
riscv: Introduce satp mode hw capabilities
Browse files Browse the repository at this point in the history
Currently, the max satp mode is set with the only constraint that it must be
implemented in QEMU, i.e. set in valid_vm_1_10_[32|64].

But we actually need to add another level of constraint: what the hw is
actually capable of, because currently, a linux booting on a sifive-u54
boots in sv57 mode which is incompatible with the cpu's sv39 max
capability.

So add a new bitmap to RISCVSATPMap which contains this capability and
initialize it in every XXX_cpu_init.

Finally:
- valid_vm_1_10_[32|64] constrains which satp mode the CPU can use
- the CPU hw capabilities constrains what the user may select
- the user's selection then constrains what's available to the guest
  OS.

Signed-off-by: Alexandre Ghiti <alexghiti@rivosinc.com>
Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Bin Meng <bmeng@tinylab.org>
Reviewed-by: Frank Chang <frank.chang@sifive.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20230303131252.892893-5-alexghiti@rivosinc.com>
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
  • Loading branch information
Alexandre Ghiti authored and palmer-dabbelt committed Mar 6, 2023
1 parent 6f23aae commit 6df3747
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 26 deletions.
93 changes: 69 additions & 24 deletions target/riscv/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -313,17 +313,24 @@ const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit)
g_assert_not_reached();
}

/* Sets the satp mode to the max supported */
static void set_satp_mode_default_map(RISCVCPU *cpu)
static void set_satp_mode_max_supported(RISCVCPU *cpu,
uint8_t satp_mode)
{
bool rv32 = riscv_cpu_mxl(&cpu->env) == MXL_RV32;
const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64;

if (riscv_feature(&cpu->env, RISCV_FEATURE_MMU)) {
cpu->cfg.satp_mode.map |= (1 << (rv32 ? VM_1_10_SV32 : VM_1_10_SV57));
} else {
cpu->cfg.satp_mode.map |= (1 << VM_1_10_MBARE);
for (int i = 0; i <= satp_mode; ++i) {
if (valid_vm[i]) {
cpu->cfg.satp_mode.supported |= (1 << i);
}
}
}

/* Set the satp mode to the max supported */
static void set_satp_mode_default_map(RISCVCPU *cpu)
{
cpu->cfg.satp_mode.map = cpu->cfg.satp_mode.supported;
}
#endif

static void riscv_any_cpu_init(Object *obj)
Expand All @@ -334,6 +341,13 @@ static void riscv_any_cpu_init(Object *obj)
#elif defined(TARGET_RISCV64)
set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU);
#endif

#ifndef CONFIG_USER_ONLY
set_satp_mode_max_supported(RISCV_CPU(obj),
riscv_cpu_mxl(&RISCV_CPU(obj)->env) == MXL_RV32 ?
VM_1_10_SV32 : VM_1_10_SV57);
#endif

set_priv_version(env, PRIV_VERSION_1_12_0);
register_cpu_props(obj);
}
Expand All @@ -347,6 +361,9 @@ static void rv64_base_cpu_init(Object *obj)
register_cpu_props(obj);
/* Set latest version of privileged specification */
set_priv_version(env, PRIV_VERSION_1_12_0);
#ifndef CONFIG_USER_ONLY
set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV57);
#endif
}

static void rv64_sifive_u_cpu_init(Object *obj)
Expand All @@ -355,6 +372,9 @@ static void rv64_sifive_u_cpu_init(Object *obj)
set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
register_cpu_props(obj);
set_priv_version(env, PRIV_VERSION_1_10_0);
#ifndef CONFIG_USER_ONLY
set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV39);
#endif
}

static void rv64_sifive_e_cpu_init(Object *obj)
Expand All @@ -366,6 +386,9 @@ static void rv64_sifive_e_cpu_init(Object *obj)
register_cpu_props(obj);
set_priv_version(env, PRIV_VERSION_1_10_0);
cpu->cfg.mmu = false;
#ifndef CONFIG_USER_ONLY
set_satp_mode_max_supported(cpu, VM_1_10_MBARE);
#endif
}

static void rv64_thead_c906_cpu_init(Object *obj)
Expand Down Expand Up @@ -395,6 +418,9 @@ static void rv64_thead_c906_cpu_init(Object *obj)
cpu->cfg.ext_xtheadsync = true;

cpu->cfg.mvendorid = THEAD_VENDOR_ID;
#ifndef CONFIG_USER_ONLY
set_satp_mode_max_supported(cpu, VM_1_10_SV39);
#endif
}

static void rv128_base_cpu_init(Object *obj)
Expand All @@ -411,6 +437,9 @@ static void rv128_base_cpu_init(Object *obj)
register_cpu_props(obj);
/* Set latest version of privileged specification */
set_priv_version(env, PRIV_VERSION_1_12_0);
#ifndef CONFIG_USER_ONLY
set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV57);
#endif
}
#else
static void rv32_base_cpu_init(Object *obj)
Expand All @@ -421,6 +450,9 @@ static void rv32_base_cpu_init(Object *obj)
register_cpu_props(obj);
/* Set latest version of privileged specification */
set_priv_version(env, PRIV_VERSION_1_12_0);
#ifndef CONFIG_USER_ONLY
set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV32);
#endif
}

static void rv32_sifive_u_cpu_init(Object *obj)
Expand All @@ -429,6 +461,9 @@ static void rv32_sifive_u_cpu_init(Object *obj)
set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
register_cpu_props(obj);
set_priv_version(env, PRIV_VERSION_1_10_0);
#ifndef CONFIG_USER_ONLY
set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV32);
#endif
}

static void rv32_sifive_e_cpu_init(Object *obj)
Expand All @@ -440,6 +475,9 @@ static void rv32_sifive_e_cpu_init(Object *obj)
register_cpu_props(obj);
set_priv_version(env, PRIV_VERSION_1_10_0);
cpu->cfg.mmu = false;
#ifndef CONFIG_USER_ONLY
set_satp_mode_max_supported(cpu, VM_1_10_MBARE);
#endif
}

static void rv32_ibex_cpu_init(Object *obj)
Expand All @@ -451,6 +489,9 @@ static void rv32_ibex_cpu_init(Object *obj)
register_cpu_props(obj);
set_priv_version(env, PRIV_VERSION_1_11_0);
cpu->cfg.mmu = false;
#ifndef CONFIG_USER_ONLY
set_satp_mode_max_supported(cpu, VM_1_10_MBARE);
#endif
cpu->cfg.epmp = true;
}

Expand All @@ -463,6 +504,9 @@ static void rv32_imafcu_nommu_cpu_init(Object *obj)
register_cpu_props(obj);
set_priv_version(env, PRIV_VERSION_1_10_0);
cpu->cfg.mmu = false;
#ifndef CONFIG_USER_ONLY
set_satp_mode_max_supported(cpu, VM_1_10_MBARE);
#endif
}
#endif

Expand Down Expand Up @@ -999,8 +1043,9 @@ static void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
{
bool rv32 = riscv_cpu_mxl(&cpu->env) == MXL_RV32;
const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64;
uint8_t satp_mode_max;
uint8_t satp_mode_map_max;
uint8_t satp_mode_supported_max =
satp_mode_max_from_map(cpu->cfg.satp_mode.supported);

if (cpu->cfg.satp_mode.map == 0) {
if (cpu->cfg.satp_mode.init == 0) {
Expand All @@ -1013,9 +1058,10 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
* valid_vm_1_10_32/64.
*/
for (int i = 1; i < 16; ++i) {
if ((cpu->cfg.satp_mode.init & (1 << i)) && valid_vm[i]) {
if ((cpu->cfg.satp_mode.init & (1 << i)) &&
(cpu->cfg.satp_mode.supported & (1 << i))) {
for (int j = i - 1; j >= 0; --j) {
if (valid_vm[j]) {
if (cpu->cfg.satp_mode.supported & (1 << j)) {
cpu->cfg.satp_mode.map |= (1 << j);
break;
}
Expand All @@ -1026,37 +1072,36 @@ static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
}
}

/* Make sure the configuration asked is supported by qemu */
for (int i = 0; i < 16; ++i) {
if ((cpu->cfg.satp_mode.map & (1 << i)) && !valid_vm[i]) {
error_setg(errp, "satp_mode %s is not valid",
satp_mode_str(i, rv32));
return;
}
satp_mode_map_max = satp_mode_max_from_map(cpu->cfg.satp_mode.map);

/* Make sure the user asked for a supported configuration (HW and qemu) */
if (satp_mode_map_max > satp_mode_supported_max) {
error_setg(errp, "satp_mode %s is higher than hw max capability %s",
satp_mode_str(satp_mode_map_max, rv32),
satp_mode_str(satp_mode_supported_max, rv32));
return;
}

/*
* Make sure the user did not ask for an invalid configuration as per
* the specification.
*/
satp_mode_max = satp_mode_max_from_map(cpu->cfg.satp_mode.map);

if (!rv32) {
for (int i = satp_mode_max - 1; i >= 0; --i) {
for (int i = satp_mode_map_max - 1; i >= 0; --i) {
if (!(cpu->cfg.satp_mode.map & (1 << i)) &&
(cpu->cfg.satp_mode.init & (1 << i)) &&
valid_vm[i]) {
(cpu->cfg.satp_mode.supported & (1 << i))) {
error_setg(errp, "cannot disable %s satp mode if %s "
"is enabled", satp_mode_str(i, false),
satp_mode_str(satp_mode_max, false));
satp_mode_str(satp_mode_map_max, false));
return;
}
}
}

/* Finally expand the map so that all valid modes are set */
for (int i = satp_mode_max - 1; i >= 0; --i) {
if (valid_vm[i]) {
for (int i = satp_mode_map_max - 1; i >= 0; --i) {
if (cpu->cfg.satp_mode.supported & (1 << i)) {
cpu->cfg.satp_mode.map |= (1 << i);
}
}
Expand Down
8 changes: 6 additions & 2 deletions target/riscv/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -404,13 +404,17 @@ struct RISCVCPUClass {

/*
* map is a 16-bit bitmap: the most significant set bit in map is the maximum
* satp mode that is supported.
* satp mode that is supported. It may be chosen by the user and must respect
* what qemu implements (valid_1_10_32/64) and what the hw is capable of
* (supported bitmap below).
*
* init is a 16-bit bitmap used to make sure the user selected a correct
* configuration as per the specification.
*
* supported is a 16-bit bitmap used to reflect the hw capabilities.
*/
typedef struct {
uint16_t map, init;
uint16_t map, init, supported;
} RISCVSATPMap;

struct RISCVCPUConfig {
Expand Down

0 comments on commit 6df3747

Please sign in to comment.