mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2024-12-23 08:15:37 +00:00
target/riscv: Support the v0.6 Hypervisor extension CRSs
Backports 83028098f45a08da209799aeea4801c362d0afeb
This commit is contained in:
parent
8e3d241d2c
commit
dd9f854edb
|
@ -244,9 +244,12 @@
|
||||||
#define CSR_HIDELEG 0x603
|
#define CSR_HIDELEG 0x603
|
||||||
#define CSR_HIE 0x604
|
#define CSR_HIE 0x604
|
||||||
#define CSR_HCOUNTEREN 0x606
|
#define CSR_HCOUNTEREN 0x606
|
||||||
|
#define CSR_HGEIE 0x607
|
||||||
#define CSR_HTVAL 0x643
|
#define CSR_HTVAL 0x643
|
||||||
|
#define CSR_HVIP 0x645
|
||||||
#define CSR_HIP 0x644
|
#define CSR_HIP 0x644
|
||||||
#define CSR_HTINST 0x64A
|
#define CSR_HTINST 0x64A
|
||||||
|
#define CSR_HGEIP 0xE12
|
||||||
#define CSR_HGATP 0x680
|
#define CSR_HGATP 0x680
|
||||||
#define CSR_HTIMEDELTA 0x605
|
#define CSR_HTIMEDELTA 0x605
|
||||||
#define CSR_HTIMEDELTAH 0x615
|
#define CSR_HTIMEDELTAH 0x615
|
||||||
|
|
|
@ -334,22 +334,13 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
|
||||||
* was called. Background registers will be used if the guest has
|
* was called. Background registers will be used if the guest has
|
||||||
* forced a two stage translation to be on (in HS or M mode).
|
* forced a two stage translation to be on (in HS or M mode).
|
||||||
*/
|
*/
|
||||||
|
if (riscv_cpu_two_stage_lookup(env) && access_type != MMU_INST_FETCH) {
|
||||||
|
use_background = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (mode == PRV_M && access_type != MMU_INST_FETCH) {
|
if (mode == PRV_M && access_type != MMU_INST_FETCH) {
|
||||||
if (get_field(env->mstatus, MSTATUS_MPRV)) {
|
if (get_field(env->mstatus, MSTATUS_MPRV)) {
|
||||||
mode = get_field(env->mstatus, MSTATUS_MPP);
|
mode = get_field(env->mstatus, MSTATUS_MPP);
|
||||||
|
|
||||||
if (riscv_has_ext(env, RVH) &&
|
|
||||||
MSTATUS_MPV_ISSET(env)) {
|
|
||||||
use_background = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode == PRV_S && access_type != MMU_INST_FETCH &&
|
|
||||||
riscv_has_ext(env, RVH) && !riscv_cpu_virt_enabled(env)) {
|
|
||||||
if (get_field(env->hstatus, HSTATUS_SPRV)) {
|
|
||||||
mode = get_field(env->mstatus, SSTATUS_SPP);
|
|
||||||
use_background = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -602,7 +593,8 @@ static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MMU_DATA_LOAD:
|
case MMU_DATA_LOAD:
|
||||||
if (riscv_cpu_virt_enabled(env) && !first_stage) {
|
if ((riscv_cpu_virt_enabled(env) || riscv_cpu_two_stage_lookup(env)) &&
|
||||||
|
!first_stage) {
|
||||||
cs->exception_index = RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT;
|
cs->exception_index = RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT;
|
||||||
} else {
|
} else {
|
||||||
cs->exception_index = page_fault_exceptions ?
|
cs->exception_index = page_fault_exceptions ?
|
||||||
|
@ -610,7 +602,8 @@ static void raise_mmu_exception(CPURISCVState *env, target_ulong address,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MMU_DATA_STORE:
|
case MMU_DATA_STORE:
|
||||||
if (riscv_cpu_virt_enabled(env) && !first_stage) {
|
if ((riscv_cpu_virt_enabled(env) || riscv_cpu_two_stage_lookup(env)) &&
|
||||||
|
!first_stage) {
|
||||||
cs->exception_index = RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT;
|
cs->exception_index = RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT;
|
||||||
} else {
|
} else {
|
||||||
cs->exception_index = page_fault_exceptions ?
|
cs->exception_index = page_fault_exceptions ?
|
||||||
|
@ -697,8 +690,6 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||||
hwaddr pa = 0;
|
hwaddr pa = 0;
|
||||||
int prot, prot2;
|
int prot, prot2;
|
||||||
bool pmp_violation = false;
|
bool pmp_violation = false;
|
||||||
bool m_mode_two_stage = false;
|
|
||||||
bool hs_mode_two_stage = false;
|
|
||||||
bool first_stage_error = true;
|
bool first_stage_error = true;
|
||||||
int ret = TRANSLATE_FAIL;
|
int ret = TRANSLATE_FAIL;
|
||||||
int mode = mmu_idx;
|
int mode = mmu_idx;
|
||||||
|
@ -709,30 +700,21 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||||
qemu_log_mask(CPU_LOG_MMU, "%s ad %" VADDR_PRIx " rw %d mmu_idx %d\n",
|
qemu_log_mask(CPU_LOG_MMU, "%s ad %" VADDR_PRIx " rw %d mmu_idx %d\n",
|
||||||
__func__, address, access_type, mmu_idx);
|
__func__, address, access_type, mmu_idx);
|
||||||
|
|
||||||
/*
|
|
||||||
* Determine if we are in M mode and MPRV is set or in HS mode and SPRV is
|
|
||||||
* set and we want to access a virtulisation address.
|
|
||||||
*/
|
|
||||||
if (riscv_has_ext(env, RVH)) {
|
|
||||||
m_mode_two_stage = env->priv == PRV_M &&
|
|
||||||
access_type != MMU_INST_FETCH &&
|
|
||||||
get_field(env->mstatus, MSTATUS_MPRV) &&
|
|
||||||
MSTATUS_MPV_ISSET(env);
|
|
||||||
|
|
||||||
hs_mode_two_stage = env->priv == PRV_S &&
|
|
||||||
!riscv_cpu_virt_enabled(env) &&
|
|
||||||
access_type != MMU_INST_FETCH &&
|
|
||||||
get_field(env->hstatus, HSTATUS_SPRV) &&
|
|
||||||
get_field(env->hstatus, HSTATUS_SPV);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode == PRV_M && access_type != MMU_INST_FETCH) {
|
if (mode == PRV_M && access_type != MMU_INST_FETCH) {
|
||||||
if (get_field(env->mstatus, MSTATUS_MPRV)) {
|
if (get_field(env->mstatus, MSTATUS_MPRV)) {
|
||||||
mode = get_field(env->mstatus, MSTATUS_MPP);
|
mode = get_field(env->mstatus, MSTATUS_MPP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (riscv_cpu_virt_enabled(env) || m_mode_two_stage || hs_mode_two_stage) {
|
if (riscv_has_ext(env, RVH) && env->priv == PRV_M &&
|
||||||
|
access_type != MMU_INST_FETCH &&
|
||||||
|
get_field(env->mstatus, MSTATUS_MPRV) &&
|
||||||
|
MSTATUS_MPV_ISSET(env)) {
|
||||||
|
riscv_cpu_set_two_stage_lookup(env, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (riscv_cpu_virt_enabled(env) ||
|
||||||
|
(riscv_cpu_two_stage_lookup(env) && access_type != MMU_INST_FETCH)) {
|
||||||
/* Two stage lookup */
|
/* Two stage lookup */
|
||||||
ret = get_physical_address(env, &pa, &prot, address, access_type,
|
ret = get_physical_address(env, &pa, &prot, address, access_type,
|
||||||
mmu_idx, true, true);
|
mmu_idx, true, true);
|
||||||
|
@ -784,6 +766,14 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
|
||||||
__func__, address, ret, pa, prot);
|
__func__, address, ret, pa, prot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We did the two stage lookup based on MPRV, unset the lookup */
|
||||||
|
if (riscv_has_ext(env, RVH) && env->priv == PRV_M &&
|
||||||
|
access_type != MMU_INST_FETCH &&
|
||||||
|
get_field(env->mstatus, MSTATUS_MPRV) &&
|
||||||
|
MSTATUS_MPV_ISSET(env)) {
|
||||||
|
riscv_cpu_set_two_stage_lookup(env, false);
|
||||||
|
}
|
||||||
|
|
||||||
if (riscv_feature(env, RISCV_FEATURE_PMP) &&
|
if (riscv_feature(env, RISCV_FEATURE_PMP) &&
|
||||||
(ret == TRANSLATE_SUCCESS) &&
|
(ret == TRANSLATE_SUCCESS) &&
|
||||||
!pmp_hart_has_privs(env, pa, size, 1 << access_type, mode)) {
|
!pmp_hart_has_privs(env, pa, size, 1 << access_type, mode)) {
|
||||||
|
|
|
@ -886,12 +886,25 @@ static int write_hideleg(CPURISCVState *env, int csrno, target_ulong val)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rmw_hvip(CPURISCVState *env, int csrno, target_ulong *ret_value,
|
||||||
|
target_ulong new_value, target_ulong write_mask)
|
||||||
|
{
|
||||||
|
int ret = rmw_mip(env, 0, ret_value, new_value,
|
||||||
|
write_mask & hip_writable_mask);
|
||||||
|
|
||||||
|
*ret_value &= hip_writable_mask;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int rmw_hip(CPURISCVState *env, int csrno, target_ulong *ret_value,
|
static int rmw_hip(CPURISCVState *env, int csrno, target_ulong *ret_value,
|
||||||
target_ulong new_value, target_ulong write_mask)
|
target_ulong new_value, target_ulong write_mask)
|
||||||
{
|
{
|
||||||
int ret = rmw_mip(env, 0, ret_value, new_value,
|
int ret = rmw_mip(env, 0, ret_value, new_value,
|
||||||
write_mask & hip_writable_mask);
|
write_mask & hip_writable_mask);
|
||||||
|
|
||||||
|
*ret_value &= hip_writable_mask;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -919,6 +932,18 @@ static int write_hcounteren(CPURISCVState *env, int csrno, target_ulong val)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int read_hgeie(CPURISCVState *env, int csrno, target_ulong *val)
|
||||||
|
{
|
||||||
|
qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int write_hgeie(CPURISCVState *env, int csrno, target_ulong val)
|
||||||
|
{
|
||||||
|
qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int read_htval(CPURISCVState *env, int csrno, target_ulong *val)
|
static int read_htval(CPURISCVState *env, int csrno, target_ulong *val)
|
||||||
{
|
{
|
||||||
*val = env->htval;
|
*val = env->htval;
|
||||||
|
@ -942,6 +967,18 @@ static int write_htinst(CPURISCVState *env, int csrno, target_ulong val)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int read_hgeip(CPURISCVState *env, int csrno, target_ulong *val)
|
||||||
|
{
|
||||||
|
qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int write_hgeip(CPURISCVState *env, int csrno, target_ulong val)
|
||||||
|
{
|
||||||
|
qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int read_hgatp(CPURISCVState *env, int csrno, target_ulong *val)
|
static int read_hgatp(CPURISCVState *env, int csrno, target_ulong *val)
|
||||||
{
|
{
|
||||||
*val = env->hgatp;
|
*val = env->hgatp;
|
||||||
|
@ -1344,11 +1381,14 @@ static riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
|
||||||
[CSR_HSTATUS] = { hmode, read_hstatus, write_hstatus },
|
[CSR_HSTATUS] = { hmode, read_hstatus, write_hstatus },
|
||||||
[CSR_HEDELEG] = { hmode, read_hedeleg, write_hedeleg },
|
[CSR_HEDELEG] = { hmode, read_hedeleg, write_hedeleg },
|
||||||
[CSR_HIDELEG] = { hmode, read_hideleg, write_hideleg },
|
[CSR_HIDELEG] = { hmode, read_hideleg, write_hideleg },
|
||||||
|
[CSR_HVIP] = { hmode, NULL, NULL, rmw_hvip },
|
||||||
[CSR_HIP] = { hmode, NULL, NULL, rmw_hip },
|
[CSR_HIP] = { hmode, NULL, NULL, rmw_hip },
|
||||||
[CSR_HIE] = { hmode, read_hie, write_hie },
|
[CSR_HIE] = { hmode, read_hie, write_hie },
|
||||||
[CSR_HCOUNTEREN] = { hmode, read_hcounteren, write_hcounteren },
|
[CSR_HCOUNTEREN] = { hmode, read_hcounteren, write_hcounteren },
|
||||||
|
[CSR_HGEIE] = { hmode, read_hgeie, write_hgeie },
|
||||||
[CSR_HTVAL] = { hmode, read_htval, write_htval },
|
[CSR_HTVAL] = { hmode, read_htval, write_htval },
|
||||||
[CSR_HTINST] = { hmode, read_htinst, write_htinst },
|
[CSR_HTINST] = { hmode, read_htinst, write_htinst },
|
||||||
|
[CSR_HGEIP] = { hmode, read_hgeip, write_hgeip },
|
||||||
[CSR_HGATP] = { hmode, read_hgatp, write_hgatp },
|
[CSR_HGATP] = { hmode, read_hgatp, write_hgatp },
|
||||||
[CSR_HTIMEDELTA] = { hmode, read_htimedelta, write_htimedelta },
|
[CSR_HTIMEDELTA] = { hmode, read_htimedelta, write_htimedelta },
|
||||||
#if defined(TARGET_RISCV32)
|
#if defined(TARGET_RISCV32)
|
||||||
|
|
Loading…
Reference in a new issue