mirror of https://gitee.com/openkylin/qemu.git
target/ppc: Use MMUAccessType in mmu-radix64.c
We must leave the 'int rwx' parameter to ppc_radix64_handle_mmu_fault for now, but will clean that up later. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-Id: <20210518201146.794854-3-richard.henderson@linaro.org> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
parent
182357dbb6
commit
13c5fdbac6
|
@ -75,71 +75,94 @@ static bool ppc_radix64_get_fully_qualified_addr(const CPUPPCState *env,
|
|||
return true;
|
||||
}
|
||||
|
||||
static void ppc_radix64_raise_segi(PowerPCCPU *cpu, int rwx, vaddr eaddr)
|
||||
static void ppc_radix64_raise_segi(PowerPCCPU *cpu, MMUAccessType access_type,
|
||||
vaddr eaddr)
|
||||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
if (rwx == 2) { /* Instruction Segment Interrupt */
|
||||
switch (access_type) {
|
||||
case MMU_INST_FETCH:
|
||||
/* Instruction Segment Interrupt */
|
||||
cs->exception_index = POWERPC_EXCP_ISEG;
|
||||
} else { /* Data Segment Interrupt */
|
||||
break;
|
||||
case MMU_DATA_STORE:
|
||||
case MMU_DATA_LOAD:
|
||||
/* Data Segment Interrupt */
|
||||
cs->exception_index = POWERPC_EXCP_DSEG;
|
||||
env->spr[SPR_DAR] = eaddr;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
env->error_code = 0;
|
||||
}
|
||||
|
||||
static void ppc_radix64_raise_si(PowerPCCPU *cpu, int rwx, vaddr eaddr,
|
||||
uint32_t cause)
|
||||
static void ppc_radix64_raise_si(PowerPCCPU *cpu, MMUAccessType access_type,
|
||||
vaddr eaddr, uint32_t cause)
|
||||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
if (rwx == 2) { /* Instruction Storage Interrupt */
|
||||
switch (access_type) {
|
||||
case MMU_INST_FETCH:
|
||||
/* Instruction Storage Interrupt */
|
||||
cs->exception_index = POWERPC_EXCP_ISI;
|
||||
env->error_code = cause;
|
||||
} else { /* Data Storage Interrupt */
|
||||
break;
|
||||
case MMU_DATA_STORE:
|
||||
cause |= DSISR_ISSTORE;
|
||||
/* fall through */
|
||||
case MMU_DATA_LOAD:
|
||||
/* Data Storage Interrupt */
|
||||
cs->exception_index = POWERPC_EXCP_DSI;
|
||||
if (rwx == 1) { /* Write -> Store */
|
||||
cause |= DSISR_ISSTORE;
|
||||
}
|
||||
env->spr[SPR_DSISR] = cause;
|
||||
env->spr[SPR_DAR] = eaddr;
|
||||
env->error_code = 0;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static void ppc_radix64_raise_hsi(PowerPCCPU *cpu, int rwx, vaddr eaddr,
|
||||
hwaddr g_raddr, uint32_t cause)
|
||||
static void ppc_radix64_raise_hsi(PowerPCCPU *cpu, MMUAccessType access_type,
|
||||
vaddr eaddr, hwaddr g_raddr, uint32_t cause)
|
||||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
if (rwx == 2) { /* H Instruction Storage Interrupt */
|
||||
switch (access_type) {
|
||||
case MMU_INST_FETCH:
|
||||
/* H Instruction Storage Interrupt */
|
||||
cs->exception_index = POWERPC_EXCP_HISI;
|
||||
env->spr[SPR_ASDR] = g_raddr;
|
||||
env->error_code = cause;
|
||||
} else { /* H Data Storage Interrupt */
|
||||
break;
|
||||
case MMU_DATA_STORE:
|
||||
cause |= DSISR_ISSTORE;
|
||||
/* fall through */
|
||||
case MMU_DATA_LOAD:
|
||||
/* H Data Storage Interrupt */
|
||||
cs->exception_index = POWERPC_EXCP_HDSI;
|
||||
if (rwx == 1) { /* Write -> Store */
|
||||
cause |= DSISR_ISSTORE;
|
||||
}
|
||||
env->spr[SPR_HDSISR] = cause;
|
||||
env->spr[SPR_HDAR] = eaddr;
|
||||
env->spr[SPR_ASDR] = g_raddr;
|
||||
env->error_code = 0;
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
static bool ppc_radix64_check_prot(PowerPCCPU *cpu, int rwx, uint64_t pte,
|
||||
int *fault_cause, int *prot,
|
||||
static bool ppc_radix64_check_prot(PowerPCCPU *cpu, MMUAccessType access_type,
|
||||
uint64_t pte, int *fault_cause, int *prot,
|
||||
bool partition_scoped)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
int need_prot;
|
||||
|
||||
/* Check Page Attributes (pte58:59) */
|
||||
if (((pte & R_PTE_ATT) == R_PTE_ATT_NI_IO) && (rwx == 2)) {
|
||||
if ((pte & R_PTE_ATT) == R_PTE_ATT_NI_IO && access_type == MMU_INST_FETCH) {
|
||||
/*
|
||||
* Radix PTE entries with the non-idempotent I/O attribute are treated
|
||||
* as guarded storage
|
||||
|
@ -159,7 +182,7 @@ static bool ppc_radix64_check_prot(PowerPCCPU *cpu, int rwx, uint64_t pte,
|
|||
}
|
||||
|
||||
/* Check if requested access type is allowed */
|
||||
need_prot = prot_for_access_type(rwx);
|
||||
need_prot = prot_for_access_type(access_type);
|
||||
if (need_prot & ~*prot) { /* Page Protected for that Access */
|
||||
*fault_cause |= DSISR_PROTFAULT;
|
||||
return true;
|
||||
|
@ -168,15 +191,15 @@ static bool ppc_radix64_check_prot(PowerPCCPU *cpu, int rwx, uint64_t pte,
|
|||
return false;
|
||||
}
|
||||
|
||||
static void ppc_radix64_set_rc(PowerPCCPU *cpu, int rwx, uint64_t pte,
|
||||
hwaddr pte_addr, int *prot)
|
||||
static void ppc_radix64_set_rc(PowerPCCPU *cpu, MMUAccessType access_type,
|
||||
uint64_t pte, hwaddr pte_addr, int *prot)
|
||||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
uint64_t npte;
|
||||
|
||||
npte = pte | R_PTE_R; /* Always set reference bit */
|
||||
|
||||
if (rwx == 1) { /* Store/Write */
|
||||
if (access_type == MMU_DATA_STORE) { /* Store/Write */
|
||||
npte |= R_PTE_C; /* Set change bit */
|
||||
} else {
|
||||
/*
|
||||
|
@ -271,7 +294,8 @@ static bool validate_pate(PowerPCCPU *cpu, uint64_t lpid, ppc_v3_pate_t *pate)
|
|||
return true;
|
||||
}
|
||||
|
||||
static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu, int rwx,
|
||||
static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu,
|
||||
MMUAccessType access_type,
|
||||
vaddr eaddr, hwaddr g_raddr,
|
||||
ppc_v3_pate_t pate,
|
||||
hwaddr *h_raddr, int *h_prot,
|
||||
|
@ -287,24 +311,25 @@ static int ppc_radix64_partition_scoped_xlate(PowerPCCPU *cpu, int rwx,
|
|||
if (ppc_radix64_walk_tree(CPU(cpu)->as, g_raddr, pate.dw0 & PRTBE_R_RPDB,
|
||||
pate.dw0 & PRTBE_R_RPDS, h_raddr, h_page_size,
|
||||
&pte, &fault_cause, &pte_addr) ||
|
||||
ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, h_prot, true)) {
|
||||
ppc_radix64_check_prot(cpu, access_type, pte, &fault_cause, h_prot, true)) {
|
||||
if (pde_addr) { /* address being translated was that of a guest pde */
|
||||
fault_cause |= DSISR_PRTABLE_FAULT;
|
||||
}
|
||||
if (guest_visible) {
|
||||
ppc_radix64_raise_hsi(cpu, rwx, eaddr, g_raddr, fault_cause);
|
||||
ppc_radix64_raise_hsi(cpu, access_type, eaddr, g_raddr, fault_cause);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (guest_visible) {
|
||||
ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, h_prot);
|
||||
ppc_radix64_set_rc(cpu, access_type, pte, pte_addr, h_prot);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
|
||||
static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu,
|
||||
MMUAccessType access_type,
|
||||
vaddr eaddr, uint64_t pid,
|
||||
ppc_v3_pate_t pate, hwaddr *g_raddr,
|
||||
int *g_prot, int *g_page_size,
|
||||
|
@ -323,7 +348,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
|
|||
if (offset >= size) {
|
||||
/* offset exceeds size of the process table */
|
||||
if (guest_visible) {
|
||||
ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE);
|
||||
ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_NOPTE);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -364,7 +389,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
|
|||
if (ret) {
|
||||
/* No valid PTE */
|
||||
if (guest_visible) {
|
||||
ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
|
||||
ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -393,7 +418,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
|
|||
if (ret) {
|
||||
/* No valid pte */
|
||||
if (guest_visible) {
|
||||
ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
|
||||
ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -407,16 +432,16 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
|
|||
*g_raddr = (rpn & ~mask) | (eaddr & mask);
|
||||
}
|
||||
|
||||
if (ppc_radix64_check_prot(cpu, rwx, pte, &fault_cause, g_prot, false)) {
|
||||
if (ppc_radix64_check_prot(cpu, access_type, pte, &fault_cause, g_prot, false)) {
|
||||
/* Access denied due to protection */
|
||||
if (guest_visible) {
|
||||
ppc_radix64_raise_si(cpu, rwx, eaddr, fault_cause);
|
||||
ppc_radix64_raise_si(cpu, access_type, eaddr, fault_cause);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (guest_visible) {
|
||||
ppc_radix64_set_rc(cpu, rwx, pte, pte_addr, g_prot);
|
||||
ppc_radix64_set_rc(cpu, access_type, pte, pte_addr, g_prot);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -439,7 +464,8 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu, int rwx,
|
|||
* | = On | Process Scoped | Scoped |
|
||||
* +-------------+----------------+---------------+
|
||||
*/
|
||||
static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
|
||||
static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr,
|
||||
MMUAccessType access_type,
|
||||
bool relocation,
|
||||
hwaddr *raddr, int *psizep, int *protp,
|
||||
bool guest_visible)
|
||||
|
@ -453,7 +479,7 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
|
|||
/* Virtual Mode Access - get the fully qualified address */
|
||||
if (!ppc_radix64_get_fully_qualified_addr(&cpu->env, eaddr, &lpid, &pid)) {
|
||||
if (guest_visible) {
|
||||
ppc_radix64_raise_segi(cpu, rwx, eaddr);
|
||||
ppc_radix64_raise_segi(cpu, access_type, eaddr);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -466,13 +492,13 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
|
|||
} else {
|
||||
if (!ppc64_v3_get_pate(cpu, lpid, &pate)) {
|
||||
if (guest_visible) {
|
||||
ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_NOPTE);
|
||||
ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_NOPTE);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (!validate_pate(cpu, lpid, &pate)) {
|
||||
if (guest_visible) {
|
||||
ppc_radix64_raise_si(cpu, rwx, eaddr, DSISR_R_BADCONFIG);
|
||||
ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_R_BADCONFIG);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -490,7 +516,7 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
|
|||
* - Translates an effective address to a guest real address.
|
||||
*/
|
||||
if (relocation) {
|
||||
int ret = ppc_radix64_process_scoped_xlate(cpu, rwx, eaddr, pid,
|
||||
int ret = ppc_radix64_process_scoped_xlate(cpu, access_type, eaddr, pid,
|
||||
pate, &g_raddr, &prot,
|
||||
&psize, guest_visible);
|
||||
if (ret) {
|
||||
|
@ -513,9 +539,10 @@ static int ppc_radix64_xlate(PowerPCCPU *cpu, vaddr eaddr, int rwx,
|
|||
if (lpid || !msr_hv) {
|
||||
int ret;
|
||||
|
||||
ret = ppc_radix64_partition_scoped_xlate(cpu, rwx, eaddr, g_raddr,
|
||||
pate, raddr, &prot, &psize,
|
||||
false, guest_visible);
|
||||
ret = ppc_radix64_partition_scoped_xlate(cpu, access_type, eaddr,
|
||||
g_raddr, pate, raddr,
|
||||
&prot, &psize, false,
|
||||
guest_visible);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
@ -536,12 +563,14 @@ int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
|
|||
CPUPPCState *env = &cpu->env;
|
||||
int page_size, prot;
|
||||
bool relocation;
|
||||
MMUAccessType access_type;
|
||||
hwaddr raddr;
|
||||
|
||||
assert(!(msr_hv && cpu->vhyp));
|
||||
assert((rwx == 0) || (rwx == 1) || (rwx == 2));
|
||||
access_type = rwx;
|
||||
|
||||
relocation = ((rwx == 2) && (msr_ir == 1)) || ((rwx != 2) && (msr_dr == 1));
|
||||
relocation = (access_type == MMU_INST_FETCH ? msr_ir : msr_dr);
|
||||
/* HV or virtual hypervisor Real Mode Access */
|
||||
if (!relocation && (msr_hv || cpu->vhyp)) {
|
||||
/* In real mode top 4 effective addr bits (mostly) ignored */
|
||||
|
@ -570,7 +599,7 @@ int ppc_radix64_handle_mmu_fault(PowerPCCPU *cpu, vaddr eaddr, int rwx,
|
|||
}
|
||||
|
||||
/* Translate eaddr to raddr (where raddr is addr qemu needs for access) */
|
||||
if (ppc_radix64_xlate(cpu, eaddr, rwx, relocation, &raddr,
|
||||
if (ppc_radix64_xlate(cpu, eaddr, access_type, relocation, &raddr,
|
||||
&page_size, &prot, true)) {
|
||||
return 1;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue