mirror of https://github.com/xemu-project/xemu.git
ppc patch queue for 2022-07-18:
This is the last ppc patch queue before the soft freeze. It contains new TCG instructions and changes, a tricky bug fix in kvmppc_find_cpu_dt() and other enhancements/fixes. - tcg and target/ppc: - move instructions to decodetree - check for bad Radix configs - ISA 3.00 tlbie[l] - fix gen_*_exception error codes - check fortb_env != 0 when printing TBU/TBL/DECR - fix kvmppc_find_cpu_dt() returning the wrong CPU DT path when there's a 'clock-frequency' property in the root node - spapr, e500: pass a random seed in /chosen/rng-seed - all boards: allocate IRQ lines with qdev_init_gpio_in() -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQQX6/+ZI9AYAK8oOBk82cqW3gMxZAUCYtWWPgAKCRA82cqW3gMx ZOOwAQCNnCvmSP9pehzEeWGxu7JfPs75NlF7dwSYHBpYUxfz1wD+Lii9mhF4RYKv epHEh+sMfzUf28uijIq6uRVuDfehjgM= =VYC3 -----END PGP SIGNATURE----- Merge tag 'pull-ppc-20220718' of https://gitlab.com/danielhb/qemu into staging ppc patch queue for 2022-07-18: This is the last ppc patch queue before the soft freeze. It contains new TCG instructions and changes, a tricky bug fix in kvmppc_find_cpu_dt() and other enhancements/fixes. - tcg and target/ppc: - move instructions to decodetree - check for bad Radix configs - ISA 3.00 tlbie[l] - fix gen_*_exception error codes - check fortb_env != 0 when printing TBU/TBL/DECR - fix kvmppc_find_cpu_dt() returning the wrong CPU DT path when there's a 'clock-frequency' property in the root node - spapr, e500: pass a random seed in /chosen/rng-seed - all boards: allocate IRQ lines with qdev_init_gpio_in() # gpg: Signature made Mon 18 Jul 2022 18:19:58 BST # gpg: using EDDSA key 17EBFF9923D01800AF2838193CD9CA96DE033164 # gpg: Good signature from "Daniel Henrique Barboza <danielhb413@gmail.com>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 17EB FF99 23D0 1800 AF28 3819 3CD9 CA96 DE03 3164 * tag 'pull-ppc-20220718' of https://gitlab.com/danielhb/qemu: (30 commits) target/ppc: Check page dir/table base alignment target/ppc: Improve Radix xlate level validation ppc: Check partition and process table alignment target/ppc: check tb_env != 0 before printing TBU/TBL/DECR target/ppc: Implement slbiag target/ppc: Move slbsync to decodetree target/ppc: Move slbfee to decodetree target/ppc: Move slbmfee to decodetree target/ppc: Move slbmfev to decodetree target/ppc: Move slbmte to decodetree target/ppc: Move slbia to decodetree target/ppc: Move slbieg to decodetree target/ppc: Move slbie to decodetree target/ppc: add macros to check privilege level target/ppc: receive DisasContext explicitly in GEN_PRIV target/ppc: Implement ISA 3.00 tlbie[l] target/ppc: Move tlbie[l] to decode tree target/ppc: fix exception error code in spr_write_excp_vector target/ppc: fix PMU Group A register read/write exceptions target/ppc: fix exception error code in helper_{load, store}_dcr ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
b8bb9bbf46
|
@ -301,23 +301,25 @@ void icp_reset(ICPState *icp)
|
|||
static void icp_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
ICPState *icp = ICP(dev);
|
||||
PowerPCCPU *cpu;
|
||||
CPUPPCState *env;
|
||||
Error *err = NULL;
|
||||
|
||||
assert(icp->xics);
|
||||
assert(icp->cs);
|
||||
|
||||
env = &POWERPC_CPU(icp->cs)->env;
|
||||
cpu = POWERPC_CPU(icp->cs);
|
||||
env = &cpu->env;
|
||||
switch (PPC_INPUT(env)) {
|
||||
case PPC_FLAGS_INPUT_POWER7:
|
||||
icp->output = env->irq_inputs[POWER7_INPUT_INT];
|
||||
icp->output = qdev_get_gpio_in(DEVICE(cpu), POWER7_INPUT_INT);
|
||||
break;
|
||||
case PPC_FLAGS_INPUT_POWER9: /* For SPAPR xics emulation */
|
||||
icp->output = env->irq_inputs[POWER9_INPUT_INT];
|
||||
icp->output = qdev_get_gpio_in(DEVICE(cpu), POWER9_INPUT_INT);
|
||||
break;
|
||||
|
||||
case PPC_FLAGS_INPUT_970:
|
||||
icp->output = env->irq_inputs[PPC970_INPUT_INT];
|
||||
icp->output = qdev_get_gpio_in(DEVICE(cpu), PPC970_INPUT_INT);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -695,8 +695,8 @@ static void xive_tctx_realize(DeviceState *dev, Error **errp)
|
|||
env = &cpu->env;
|
||||
switch (PPC_INPUT(env)) {
|
||||
case PPC_FLAGS_INPUT_POWER9:
|
||||
tctx->hv_output = env->irq_inputs[POWER9_INPUT_HINT];
|
||||
tctx->os_output = env->irq_inputs[POWER9_INPUT_INT];
|
||||
tctx->hv_output = qdev_get_gpio_in(DEVICE(cpu), POWER9_INPUT_HINT);
|
||||
tctx->os_output = qdev_get_gpio_in(DEVICE(cpu), POWER9_INPUT_INT);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "qemu/datadir.h"
|
||||
#include "qemu/units.h"
|
||||
#include "qemu/guest-random.h"
|
||||
#include "qapi/error.h"
|
||||
#include "e500.h"
|
||||
#include "e500-ccsr.h"
|
||||
|
@ -346,6 +347,7 @@ static int ppce500_load_device_tree(PPCE500MachineState *pms,
|
|||
};
|
||||
const char *dtb_file = machine->dtb;
|
||||
const char *toplevel_compat = machine->dt_compatible;
|
||||
uint8_t rng_seed[32];
|
||||
|
||||
if (dtb_file) {
|
||||
char *filename;
|
||||
|
@ -403,6 +405,9 @@ static int ppce500_load_device_tree(PPCE500MachineState *pms,
|
|||
if (ret < 0)
|
||||
fprintf(stderr, "couldn't set /chosen/bootargs\n");
|
||||
|
||||
qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed));
|
||||
qemu_fdt_setprop(fdt, "/chosen", "rng-seed", rng_seed, sizeof(rng_seed));
|
||||
|
||||
if (kvm_enabled()) {
|
||||
/* Read out host's frequencies */
|
||||
clock_freq = kvmppc_get_clockfreq();
|
||||
|
@ -861,7 +866,6 @@ void ppce500_init(MachineState *machine)
|
|||
for (i = 0; i < smp_cpus; i++) {
|
||||
PowerPCCPU *cpu;
|
||||
CPUState *cs;
|
||||
qemu_irq *input;
|
||||
|
||||
cpu = POWERPC_CPU(object_new(machine->cpu_type));
|
||||
env = &cpu->env;
|
||||
|
@ -885,9 +889,10 @@ void ppce500_init(MachineState *machine)
|
|||
firstenv = env;
|
||||
}
|
||||
|
||||
input = (qemu_irq *)env->irq_inputs;
|
||||
irqs[i].irq[OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
|
||||
irqs[i].irq[OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
|
||||
irqs[i].irq[OPENPIC_OUTPUT_INT] =
|
||||
qdev_get_gpio_in(DEVICE(cpu), PPCE500_INPUT_INT);
|
||||
irqs[i].irq[OPENPIC_OUTPUT_CINT] =
|
||||
qdev_get_gpio_in(DEVICE(cpu), PPCE500_INPUT_CINT);
|
||||
env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
|
||||
env->mpic_iack = pmc->ccsrbar_base + MPC8544_MPIC_REGS_OFFSET + 0xa0;
|
||||
|
||||
|
|
|
@ -262,30 +262,30 @@ static void ppc_core99_init(MachineState *machine)
|
|||
switch (PPC_INPUT(env)) {
|
||||
case PPC_FLAGS_INPUT_6xx:
|
||||
openpic_irqs[i].irq[OPENPIC_OUTPUT_INT] =
|
||||
((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT];
|
||||
qdev_get_gpio_in(DEVICE(cpu), PPC6xx_INPUT_INT);
|
||||
openpic_irqs[i].irq[OPENPIC_OUTPUT_CINT] =
|
||||
((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT];
|
||||
qdev_get_gpio_in(DEVICE(cpu), PPC6xx_INPUT_INT);
|
||||
openpic_irqs[i].irq[OPENPIC_OUTPUT_MCK] =
|
||||
((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_MCP];
|
||||
qdev_get_gpio_in(DEVICE(cpu), PPC6xx_INPUT_MCP);
|
||||
/* Not connected ? */
|
||||
openpic_irqs[i].irq[OPENPIC_OUTPUT_DEBUG] = NULL;
|
||||
/* Check this */
|
||||
openpic_irqs[i].irq[OPENPIC_OUTPUT_RESET] =
|
||||
((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_HRESET];
|
||||
qdev_get_gpio_in(DEVICE(cpu), PPC6xx_INPUT_HRESET);
|
||||
break;
|
||||
#if defined(TARGET_PPC64)
|
||||
case PPC_FLAGS_INPUT_970:
|
||||
openpic_irqs[i].irq[OPENPIC_OUTPUT_INT] =
|
||||
((qemu_irq *)env->irq_inputs)[PPC970_INPUT_INT];
|
||||
qdev_get_gpio_in(DEVICE(cpu), PPC970_INPUT_INT);
|
||||
openpic_irqs[i].irq[OPENPIC_OUTPUT_CINT] =
|
||||
((qemu_irq *)env->irq_inputs)[PPC970_INPUT_INT];
|
||||
qdev_get_gpio_in(DEVICE(cpu), PPC970_INPUT_INT);
|
||||
openpic_irqs[i].irq[OPENPIC_OUTPUT_MCK] =
|
||||
((qemu_irq *)env->irq_inputs)[PPC970_INPUT_MCP];
|
||||
qdev_get_gpio_in(DEVICE(cpu), PPC970_INPUT_MCP);
|
||||
/* Not connected ? */
|
||||
openpic_irqs[i].irq[OPENPIC_OUTPUT_DEBUG] = NULL;
|
||||
/* Check this */
|
||||
openpic_irqs[i].irq[OPENPIC_OUTPUT_RESET] =
|
||||
((qemu_irq *)env->irq_inputs)[PPC970_INPUT_HRESET];
|
||||
qdev_get_gpio_in(DEVICE(cpu), PPC970_INPUT_HRESET);
|
||||
break;
|
||||
#endif /* defined(TARGET_PPC64) */
|
||||
default:
|
||||
|
|
|
@ -271,7 +271,7 @@ static void ppc_heathrow_init(MachineState *machine)
|
|||
case PPC_FLAGS_INPUT_6xx:
|
||||
/* XXX: we register only 1 output pin for heathrow PIC */
|
||||
qdev_connect_gpio_out(pic_dev, 0,
|
||||
((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT]);
|
||||
qdev_get_gpio_in(DEVICE(cpu), PPC6xx_INPUT_INT));
|
||||
break;
|
||||
default:
|
||||
error_report("Bus model not supported on OldWorld Mac machine");
|
||||
|
|
|
@ -155,7 +155,7 @@ static void pegasos2_init(MachineState *machine)
|
|||
|
||||
/* Marvell Discovery II system controller */
|
||||
pm->mv = DEVICE(sysbus_create_simple(TYPE_MV64361, -1,
|
||||
((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT]));
|
||||
qdev_get_gpio_in(DEVICE(pm->cpu), PPC6xx_INPUT_INT)));
|
||||
pci_bus = mv64361_get_pci_bus(pm->mv, 1);
|
||||
|
||||
/* VIA VT8231 South Bridge (multifunction PCI device) */
|
||||
|
|
30
hw/ppc/ppc.c
30
hw/ppc/ppc.c
|
@ -154,10 +154,7 @@ static void ppc6xx_set_irq(void *opaque, int pin, int level)
|
|||
|
||||
void ppc6xx_irq_init(PowerPCCPU *cpu)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, cpu,
|
||||
PPC6xx_INPUT_NB);
|
||||
qdev_init_gpio_in(DEVICE(cpu), ppc6xx_set_irq, PPC6xx_INPUT_NB);
|
||||
}
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
|
@ -234,10 +231,7 @@ static void ppc970_set_irq(void *opaque, int pin, int level)
|
|||
|
||||
void ppc970_irq_init(PowerPCCPU *cpu)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, cpu,
|
||||
PPC970_INPUT_NB);
|
||||
qdev_init_gpio_in(DEVICE(cpu), ppc970_set_irq, PPC970_INPUT_NB);
|
||||
}
|
||||
|
||||
/* POWER7 internal IRQ controller */
|
||||
|
@ -260,10 +254,7 @@ static void power7_set_irq(void *opaque, int pin, int level)
|
|||
|
||||
void ppcPOWER7_irq_init(PowerPCCPU *cpu)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
env->irq_inputs = (void **)qemu_allocate_irqs(&power7_set_irq, cpu,
|
||||
POWER7_INPUT_NB);
|
||||
qdev_init_gpio_in(DEVICE(cpu), power7_set_irq, POWER7_INPUT_NB);
|
||||
}
|
||||
|
||||
/* POWER9 internal IRQ controller */
|
||||
|
@ -292,10 +283,7 @@ static void power9_set_irq(void *opaque, int pin, int level)
|
|||
|
||||
void ppcPOWER9_irq_init(PowerPCCPU *cpu)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
env->irq_inputs = (void **)qemu_allocate_irqs(&power9_set_irq, cpu,
|
||||
POWER9_INPUT_NB);
|
||||
qdev_init_gpio_in(DEVICE(cpu), power9_set_irq, POWER9_INPUT_NB);
|
||||
}
|
||||
#endif /* defined(TARGET_PPC64) */
|
||||
|
||||
|
@ -431,10 +419,7 @@ static void ppc40x_set_irq(void *opaque, int pin, int level)
|
|||
|
||||
void ppc40x_irq_init(PowerPCCPU *cpu)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq,
|
||||
cpu, PPC40x_INPUT_NB);
|
||||
qdev_init_gpio_in(DEVICE(cpu), ppc40x_set_irq, PPC40x_INPUT_NB);
|
||||
}
|
||||
|
||||
/* PowerPC E500 internal IRQ controller */
|
||||
|
@ -489,10 +474,7 @@ static void ppce500_set_irq(void *opaque, int pin, int level)
|
|||
|
||||
void ppce500_irq_init(PowerPCCPU *cpu)
|
||||
{
|
||||
CPUPPCState *env = &cpu->env;
|
||||
|
||||
env->irq_inputs = (void **)qemu_allocate_irqs(&ppce500_set_irq,
|
||||
cpu, PPCE500_INPUT_NB);
|
||||
qdev_init_gpio_in(DEVICE(cpu), ppce500_set_irq, PPCE500_INPUT_NB);
|
||||
}
|
||||
|
||||
/* Enable or Disable the E500 EPR capability */
|
||||
|
|
|
@ -1470,9 +1470,9 @@ PowerPCCPU *ppc405ep_init(MemoryRegion *address_space_mem,
|
|||
sysbus_realize_and_unref(uicsbd, &error_fatal);
|
||||
|
||||
sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT,
|
||||
((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]);
|
||||
qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_INT));
|
||||
sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT,
|
||||
((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]);
|
||||
qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_CINT));
|
||||
|
||||
*uicdevp = uicdev;
|
||||
|
||||
|
|
|
@ -200,9 +200,9 @@ static void bamboo_init(MachineState *machine)
|
|||
sysbus_realize_and_unref(uicsbd, &error_fatal);
|
||||
|
||||
sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT,
|
||||
((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]);
|
||||
qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_INT));
|
||||
sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT,
|
||||
((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]);
|
||||
qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_CINT));
|
||||
|
||||
/* SDRAM controller */
|
||||
memset(ram_bases, 0, sizeof(ram_bases));
|
||||
|
|
|
@ -275,7 +275,7 @@ static void ibm_40p_init(MachineState *machine)
|
|||
/* PCI -> ISA bridge */
|
||||
i82378_dev = DEVICE(pci_create_simple(pci_bus, PCI_DEVFN(11, 0), "i82378"));
|
||||
qdev_connect_gpio_out(i82378_dev, 0,
|
||||
cpu->env.irq_inputs[PPC6xx_INPUT_INT]);
|
||||
qdev_get_gpio_in(DEVICE(cpu), PPC6xx_INPUT_INT));
|
||||
sysbus_connect_irq(pcihost, 0, qdev_get_gpio_in(i82378_dev, 15));
|
||||
isa_bus = ISA_BUS(qdev_get_child_bus(i82378_dev, "isa.0"));
|
||||
|
||||
|
|
|
@ -262,7 +262,7 @@ static void prep_systemio_realize(DeviceState *dev, Error **errp)
|
|||
qemu_set_irq(s->non_contiguous_io_map_irq,
|
||||
s->iomap_type & PORT0850_IOMAP_NONCONTIGUOUS);
|
||||
cpu = POWERPC_CPU(first_cpu);
|
||||
s->softreset_irq = cpu->env.irq_inputs[PPC6xx_INPUT_HRESET];
|
||||
s->softreset_irq = qdev_get_gpio_in(DEVICE(cpu), PPC6xx_INPUT_HRESET);
|
||||
|
||||
isa_register_portio_list(isa, &s->portio, 0x0, ppc_io800_port_list, s,
|
||||
"systemio800");
|
||||
|
|
|
@ -334,9 +334,9 @@ static void sam460ex_init(MachineState *machine)
|
|||
|
||||
if (i == 0) {
|
||||
sysbus_connect_irq(sbd, PPCUIC_OUTPUT_INT,
|
||||
((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]);
|
||||
qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_INT));
|
||||
sysbus_connect_irq(sbd, PPCUIC_OUTPUT_CINT,
|
||||
((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]);
|
||||
qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_CINT));
|
||||
} else {
|
||||
sysbus_connect_irq(sbd, PPCUIC_OUTPUT_INT,
|
||||
qdev_get_gpio_in(uic[0], input_ints[i]));
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "qemu/datadir.h"
|
||||
#include "qemu/memalign.h"
|
||||
#include "qemu/guest-random.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qapi-events-machine.h"
|
||||
#include "qapi/qapi-events-qdev.h"
|
||||
|
@ -1014,6 +1015,7 @@ static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt, bool reset)
|
|||
{
|
||||
MachineState *machine = MACHINE(spapr);
|
||||
SpaprMachineClass *smc = SPAPR_MACHINE_GET_CLASS(machine);
|
||||
uint8_t rng_seed[32];
|
||||
int chosen;
|
||||
|
||||
_FDT(chosen = fdt_add_subnode(fdt, 0, "chosen"));
|
||||
|
@ -1091,6 +1093,9 @@ static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt, bool reset)
|
|||
spapr_dt_ov5_platform_support(spapr, fdt, chosen);
|
||||
}
|
||||
|
||||
qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed));
|
||||
_FDT(fdt_setprop(fdt, chosen, "rng-seed", rng_seed, sizeof(rng_seed)));
|
||||
|
||||
_FDT(spapr_dt_ovec(fdt, chosen, spapr->ov5_cas, "ibm,architecture-vec-5"));
|
||||
}
|
||||
|
||||
|
@ -1331,6 +1336,11 @@ static bool spapr_get_pate(PPCVirtualHypervisor *vhyp, PowerPCCPU *cpu,
|
|||
patb = spapr->nested_ptcr & PTCR_PATB;
|
||||
pats = spapr->nested_ptcr & PTCR_PATS;
|
||||
|
||||
/* Check if partition table is properly aligned */
|
||||
if (patb & MAKE_64BIT_MASK(0, pats + 12)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Calculate number of entries */
|
||||
pats = 1ull << (pats + 12 - 4);
|
||||
if (pats <= lpid) {
|
||||
|
|
|
@ -920,6 +920,7 @@ static target_ulong h_register_process_table(PowerPCCPU *cpu,
|
|||
target_ulong page_size = args[2];
|
||||
target_ulong table_size = args[3];
|
||||
target_ulong update_lpcr = 0;
|
||||
target_ulong table_byte_size;
|
||||
uint64_t cproc;
|
||||
|
||||
if (flags & ~FLAGS_MASK) { /* Check no reserved bits are set */
|
||||
|
@ -927,6 +928,14 @@ static target_ulong h_register_process_table(PowerPCCPU *cpu,
|
|||
}
|
||||
if (flags & FLAG_MODIFY) {
|
||||
if (flags & FLAG_REGISTER) {
|
||||
/* Check process table alignment */
|
||||
table_byte_size = 1ULL << (table_size + 12);
|
||||
if (proc_tbl & (table_byte_size - 1)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: process table not properly aligned: proc_tbl 0x"
|
||||
TARGET_FMT_lx" proc_tbl_size 0x"TARGET_FMT_lx"\n",
|
||||
__func__, proc_tbl, table_byte_size);
|
||||
}
|
||||
if (flags & FLAG_RADIX) { /* Register new RADIX process table */
|
||||
if (proc_tbl & 0xfff || proc_tbl >> 60) {
|
||||
return H_P2;
|
||||
|
|
|
@ -111,9 +111,9 @@ static PowerPCCPU *ppc440_init_xilinx(const char *cpu_type, uint32_t sysclk)
|
|||
sysbus_realize_and_unref(uicsbd, &error_fatal);
|
||||
|
||||
sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_INT,
|
||||
((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT]);
|
||||
qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_INT));
|
||||
sysbus_connect_irq(uicsbd, PPCUIC_OUTPUT_CINT,
|
||||
((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT]);
|
||||
qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_CINT));
|
||||
|
||||
/* This board doesn't wire anything up to the inputs of the UIC. */
|
||||
return cpu;
|
||||
|
@ -213,7 +213,7 @@ static void virtex_init(MachineState *machine)
|
|||
CPUPPCState *env;
|
||||
hwaddr ram_base = 0;
|
||||
DriveInfo *dinfo;
|
||||
qemu_irq irq[32], *cpu_irq;
|
||||
qemu_irq irq[32], cpu_irq;
|
||||
int kernel_size;
|
||||
int i;
|
||||
|
||||
|
@ -236,12 +236,12 @@ static void virtex_init(MachineState *machine)
|
|||
dinfo ? blk_by_legacy_dinfo(dinfo) : NULL,
|
||||
64 * KiB, 1, 0x89, 0x18, 0x0000, 0x0, 1);
|
||||
|
||||
cpu_irq = (qemu_irq *) &env->irq_inputs[PPC40x_INPUT_INT];
|
||||
cpu_irq = qdev_get_gpio_in(DEVICE(cpu), PPC40x_INPUT_INT);
|
||||
dev = qdev_new("xlnx.xps-intc");
|
||||
qdev_prop_set_uint32(dev, "kind-of-intr", 0);
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, INTC_BASEADDR);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irq[0]);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irq);
|
||||
for (i = 0; i < 32; i++) {
|
||||
irq[i] = qdev_get_gpio_in(dev, i);
|
||||
}
|
||||
|
|
|
@ -1184,7 +1184,6 @@ struct CPUArchState {
|
|||
* by recent Book3s compatible CPUs (POWER7 and newer).
|
||||
*/
|
||||
uint32_t irq_input_state;
|
||||
void **irq_inputs;
|
||||
|
||||
target_ulong excp_vectors[POWERPC_EXCP_NB]; /* Exception vectors */
|
||||
target_ulong excp_prefix;
|
||||
|
@ -2215,8 +2214,6 @@ enum {
|
|||
PPC_DCR = 0x1000000000000000ULL,
|
||||
/* DCR extended accesse */
|
||||
PPC_DCRX = 0x2000000000000000ULL,
|
||||
/* user-mode DCR access, implemented in PowerPC 460 */
|
||||
PPC_DCRUX = 0x4000000000000000ULL,
|
||||
/* popcntw and popcntd instructions */
|
||||
PPC_POPCNTWD = 0x8000000000000000ULL,
|
||||
|
||||
|
@ -2240,8 +2237,8 @@ enum {
|
|||
| PPC_405_MAC | PPC_440_SPEC | PPC_BOOKE \
|
||||
| PPC_MFAPIDI | PPC_TLBIVA | PPC_TLBIVAX \
|
||||
| PPC_4xx_COMMON | PPC_40x_ICBT | PPC_RFMCI \
|
||||
| PPC_RFDI | PPC_DCR | PPC_DCRX | PPC_DCRUX \
|
||||
| PPC_POPCNTWD | PPC_CILDST)
|
||||
| PPC_RFDI | PPC_DCR | PPC_DCRX | PPC_POPCNTWD \
|
||||
| PPC_CILDST)
|
||||
|
||||
/* extended type values */
|
||||
|
||||
|
|
|
@ -6373,7 +6373,7 @@ POWERPC_FAMILY(POWER9)(ObjectClass *oc, void *data)
|
|||
PPC_FLOAT_EXT |
|
||||
PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO |
|
||||
PPC_MEM_TLBSYNC |
|
||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |
|
||||
PPC_64B | PPC_64H | PPC_64BX | PPC_ALTIVEC |
|
||||
PPC_SEGMENT_64B | PPC_SLBI |
|
||||
PPC_POPCNTB | PPC_POPCNTWD |
|
||||
|
@ -6591,7 +6591,7 @@ POWERPC_FAMILY(POWER10)(ObjectClass *oc, void *data)
|
|||
PPC_FLOAT_EXT |
|
||||
PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |
|
||||
PPC_MEM_SYNC | PPC_MEM_EIEIO |
|
||||
PPC_MEM_TLBSYNC |
|
||||
PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |
|
||||
PPC_64B | PPC_64H | PPC_64BX | PPC_ALTIVEC |
|
||||
PPC_SEGMENT_64B | PPC_SLBI |
|
||||
PPC_POPCNTB | PPC_POPCNTWD |
|
||||
|
@ -6678,7 +6678,6 @@ static void init_ppc_proc(PowerPCCPU *cpu)
|
|||
#if !defined(CONFIG_USER_ONLY)
|
||||
int i;
|
||||
|
||||
env->irq_inputs = NULL;
|
||||
/* Set all exception vectors to an invalid address */
|
||||
for (i = 0; i < POWERPC_EXCP_NB; i++) {
|
||||
env->excp_vectors[i] = (target_ulong)(-1ULL);
|
||||
|
@ -6808,10 +6807,6 @@ static void init_ppc_proc(PowerPCCPU *cpu)
|
|||
/* Pre-compute some useful values */
|
||||
env->tlb_per_way = env->nb_tlb / env->nb_ways;
|
||||
}
|
||||
if (env->irq_inputs == NULL) {
|
||||
warn_report("no internal IRQ controller registered."
|
||||
" Attempt QEMU to crash very soon !");
|
||||
}
|
||||
#endif
|
||||
if (env->check_pow == NULL) {
|
||||
warn_report("no power management check handler registered."
|
||||
|
@ -7476,17 +7471,15 @@ void ppc_cpu_dump_state(CPUState *cs, FILE *f, int flags)
|
|||
"%08x iidx %d didx %d\n",
|
||||
env->msr, env->spr[SPR_HID0], env->hflags,
|
||||
cpu_mmu_index(env, true), cpu_mmu_index(env, false));
|
||||
#if !defined(NO_TIMER_DUMP)
|
||||
qemu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
" DECR " TARGET_FMT_lu
|
||||
#endif
|
||||
"\n",
|
||||
cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env)
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
, cpu_ppc_load_decr(env)
|
||||
#endif
|
||||
);
|
||||
if (env->tb_env) {
|
||||
qemu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64
|
||||
" DECR " TARGET_FMT_lu "\n", cpu_ppc_load_tbu(env),
|
||||
cpu_ppc_load_tbl(env), cpu_ppc_load_decr(env));
|
||||
}
|
||||
#else
|
||||
qemu_fprintf(f, "TB %08" PRIu32 " %08" PRIu64 "\n", cpu_ppc_load_tbu(env),
|
||||
cpu_ppc_load_tbl(env));
|
||||
#endif
|
||||
for (i = 0; i < 32; i++) {
|
||||
if ((i & (RGPL - 1)) == 0) {
|
||||
|
|
|
@ -674,13 +674,16 @@ DEF_HELPER_FLAGS_1(tlbia, TCG_CALL_NO_RWG, void, env)
|
|||
DEF_HELPER_FLAGS_2(tlbie, TCG_CALL_NO_RWG, void, env, tl)
|
||||
DEF_HELPER_FLAGS_2(tlbiva, TCG_CALL_NO_RWG, void, env, tl)
|
||||
#if defined(TARGET_PPC64)
|
||||
DEF_HELPER_FLAGS_3(store_slb, TCG_CALL_NO_RWG, void, env, tl, tl)
|
||||
DEF_HELPER_2(load_slb_esid, tl, env, tl)
|
||||
DEF_HELPER_2(load_slb_vsid, tl, env, tl)
|
||||
DEF_HELPER_2(find_slb_vsid, tl, env, tl)
|
||||
DEF_HELPER_FLAGS_2(slbia, TCG_CALL_NO_RWG, void, env, i32)
|
||||
DEF_HELPER_FLAGS_2(slbie, TCG_CALL_NO_RWG, void, env, tl)
|
||||
DEF_HELPER_FLAGS_2(slbieg, TCG_CALL_NO_RWG, void, env, tl)
|
||||
DEF_HELPER_FLAGS_4(tlbie_isa300, TCG_CALL_NO_WG, void, \
|
||||
env, tl, tl, i32)
|
||||
DEF_HELPER_FLAGS_3(SLBMTE, TCG_CALL_NO_RWG, void, env, tl, tl)
|
||||
DEF_HELPER_2(SLBMFEE, tl, env, tl)
|
||||
DEF_HELPER_2(SLBMFEV, tl, env, tl)
|
||||
DEF_HELPER_2(SLBFEE, tl, env, tl)
|
||||
DEF_HELPER_FLAGS_2(SLBIA, TCG_CALL_NO_RWG, void, env, i32)
|
||||
DEF_HELPER_FLAGS_3(SLBIAG, TCG_CALL_NO_RWG, void, env, tl, i32)
|
||||
DEF_HELPER_FLAGS_2(SLBIE, TCG_CALL_NO_RWG, void, env, tl)
|
||||
DEF_HELPER_FLAGS_2(SLBIEG, TCG_CALL_NO_RWG, void, env, tl)
|
||||
#endif
|
||||
DEF_HELPER_FLAGS_2(load_sr, TCG_CALL_NO_RWG, tl, env, tl)
|
||||
DEF_HELPER_FLAGS_3(store_sr, TCG_CALL_NO_RWG, void, env, tl, tl)
|
||||
|
@ -694,10 +697,10 @@ DEF_HELPER_2(book3s_msgclr, void, env, tl)
|
|||
DEF_HELPER_4(dlmzb, tl, env, tl, tl, i32)
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
DEF_HELPER_2(rac, tl, env, tl)
|
||||
#endif
|
||||
|
||||
DEF_HELPER_2(load_dcr, tl, env, tl)
|
||||
DEF_HELPER_3(store_dcr, void, env, tl, tl)
|
||||
#endif
|
||||
|
||||
DEF_HELPER_2(load_dump_spr, void, env, i32)
|
||||
DEF_HELPER_2(store_dump_spr, void, env, i32)
|
||||
|
|
|
@ -146,6 +146,15 @@
|
|||
&X_imm8 xt imm:uint8_t
|
||||
@X_imm8 ...... ..... .. imm:8 .......... . &X_imm8 xt=%x_xt
|
||||
|
||||
&X_ih ih:uint8_t
|
||||
@X_ih ...... .. ih:3 ..... ..... .......... . &X_ih
|
||||
|
||||
&X_rb rb
|
||||
@X_rb ...... ..... ..... rb:5 .......... . &X_rb
|
||||
|
||||
&X_rs_l rs l:bool
|
||||
@X_rs_l ...... rs:5 .... l:1 ..... .......... . &X_rs_l
|
||||
|
||||
&X_uim5 xt uim:uint8_t
|
||||
@X_uim5 ...... ..... ..... uim:5 .......... . &X_uim5 xt=%x_xt
|
||||
|
||||
|
@ -856,3 +865,28 @@ VMODSD 000100 ..... ..... ..... 11111001011 @VX
|
|||
VMODUD 000100 ..... ..... ..... 11011001011 @VX
|
||||
VMODSQ 000100 ..... ..... ..... 11100001011 @VX
|
||||
VMODUQ 000100 ..... ..... ..... 11000001011 @VX
|
||||
|
||||
## SLB Management Instructions
|
||||
|
||||
SLBIE 011111 ----- ----- ..... 0110110010 - @X_rb
|
||||
SLBIEG 011111 ..... ----- ..... 0111010010 - @X_tb
|
||||
|
||||
SLBIA 011111 --... ----- ----- 0111110010 - @X_ih
|
||||
SLBIAG 011111 ..... ----. ----- 1101010010 - @X_rs_l
|
||||
|
||||
SLBMTE 011111 ..... ----- ..... 0110010010 - @X_tb
|
||||
|
||||
SLBMFEV 011111 ..... ----- ..... 1101010011 - @X_tb
|
||||
SLBMFEE 011111 ..... ----- ..... 1110010011 - @X_tb
|
||||
|
||||
SLBFEE 011111 ..... ----- ..... 1111010011 1 @X_tb
|
||||
|
||||
SLBSYNC 011111 ----- ----- ----- 0101010010 -
|
||||
|
||||
## TLB Management Instructions
|
||||
|
||||
&X_tlbie rb rs ric prs:bool r:bool
|
||||
@X_tlbie ...... rs:5 - ric:2 prs:1 r:1 rb:5 .......... - &X_tlbie
|
||||
|
||||
TLBIE 011111 ..... - .. . . ..... 0100110010 - @X_tlbie
|
||||
TLBIEL 011111 ..... - .. . . ..... 0100010010 - @X_tlbie
|
||||
|
|
|
@ -1877,6 +1877,12 @@ static int kvmppc_find_cpu_dt(char *buf, int buf_len)
|
|||
buf[0] = '\0';
|
||||
while ((dirp = readdir(dp)) != NULL) {
|
||||
FILE *f;
|
||||
|
||||
/* Don't accidentally read from the current and parent directories */
|
||||
if (strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
snprintf(buf, buf_len, "%s%s/clock-frequency", PROC_DEVTREE_CPU,
|
||||
dirp->d_name);
|
||||
f = fopen(buf, "r");
|
||||
|
|
|
@ -28,6 +28,11 @@ bool ppc64_v3_get_pate(PowerPCCPU *cpu, target_ulong lpid, ppc_v3_pate_t *entry)
|
|||
uint64_t patb = cpu->env.spr[SPR_PTCR] & PTCR_PATB;
|
||||
uint64_t pats = cpu->env.spr[SPR_PTCR] & PTCR_PATS;
|
||||
|
||||
/* Check if partition table is properly aligned */
|
||||
if (patb & MAKE_64BIT_MASK(0, pats + 12)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Calculate number of entries */
|
||||
pats = 1ull << (pats + 12 - 4);
|
||||
if (pats <= lpid) {
|
||||
|
|
|
@ -50,6 +50,21 @@ struct prtb_entry {
|
|||
|
||||
#ifdef TARGET_PPC64
|
||||
|
||||
/*
|
||||
* tlbie[l] helper flags
|
||||
*
|
||||
* RIC, PRS, R and local are passed as flags in the last argument.
|
||||
*/
|
||||
#define TLBIE_F_RIC_SHIFT 0
|
||||
#define TLBIE_F_PRS_SHIFT 2
|
||||
#define TLBIE_F_R_SHIFT 3
|
||||
#define TLBIE_F_LOCAL_SHIFT 4
|
||||
|
||||
#define TLBIE_F_RIC_MASK (3 << TLBIE_F_RIC_SHIFT)
|
||||
#define TLBIE_F_PRS (1 << TLBIE_F_PRS_SHIFT)
|
||||
#define TLBIE_F_R (1 << TLBIE_F_R_SHIFT)
|
||||
#define TLBIE_F_LOCAL (1 << TLBIE_F_LOCAL_SHIFT)
|
||||
|
||||
static inline bool ppc64_use_proc_tbl(PowerPCCPU *cpu)
|
||||
{
|
||||
return !!(cpu->env.spr[SPR_LPCR] & LPCR_UPRT);
|
||||
|
|
|
@ -101,7 +101,7 @@ void dump_slb(PowerPCCPU *cpu)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_TCG
|
||||
void helper_slbia(CPUPPCState *env, uint32_t ih)
|
||||
void helper_SLBIA(CPUPPCState *env, uint32_t ih)
|
||||
{
|
||||
PowerPCCPU *cpu = env_archcpu(env);
|
||||
int starting_entry;
|
||||
|
@ -173,6 +173,33 @@ void helper_slbia(CPUPPCState *env, uint32_t ih)
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
void helper_SLBIAG(CPUPPCState *env, target_ulong rs, uint32_t l)
|
||||
{
|
||||
PowerPCCPU *cpu = env_archcpu(env);
|
||||
int n;
|
||||
|
||||
/*
|
||||
* slbiag must always flush all TLB (which is equivalent to ERAT in ppc
|
||||
* architecture). Matching on SLB_ESID_V is not good enough, because slbmte
|
||||
* can overwrite a valid SLB without flushing its lookaside information.
|
||||
*
|
||||
* It would be possible to keep the TLB in synch with the SLB by flushing
|
||||
* when a valid entry is overwritten by slbmte, and therefore slbiag would
|
||||
* not have to flush unless it evicts a valid SLB entry. However it is
|
||||
* expected that slbmte is more common than slbiag, and slbiag is usually
|
||||
* going to evict valid SLB entries, so that tradeoff is unlikely to be a
|
||||
* good one.
|
||||
*/
|
||||
env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
|
||||
|
||||
for (n = 0; n < cpu->hash64_opts->slb_size; n++) {
|
||||
ppc_slb_t *slb = &env->slb[n];
|
||||
slb->esid &= ~SLB_ESID_V;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void __helper_slbie(CPUPPCState *env, target_ulong addr,
|
||||
target_ulong global)
|
||||
{
|
||||
|
@ -197,12 +224,12 @@ static void __helper_slbie(CPUPPCState *env, target_ulong addr,
|
|||
}
|
||||
}
|
||||
|
||||
void helper_slbie(CPUPPCState *env, target_ulong addr)
|
||||
void helper_SLBIE(CPUPPCState *env, target_ulong addr)
|
||||
{
|
||||
__helper_slbie(env, addr, false);
|
||||
}
|
||||
|
||||
void helper_slbieg(CPUPPCState *env, target_ulong addr)
|
||||
void helper_SLBIEG(CPUPPCState *env, target_ulong addr)
|
||||
{
|
||||
__helper_slbie(env, addr, true);
|
||||
}
|
||||
|
@ -309,7 +336,7 @@ static int ppc_find_slb_vsid(PowerPCCPU *cpu, target_ulong rb,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
|
||||
void helper_SLBMTE(CPUPPCState *env, target_ulong rb, target_ulong rs)
|
||||
{
|
||||
PowerPCCPU *cpu = env_archcpu(env);
|
||||
|
||||
|
@ -319,7 +346,7 @@ void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
|
|||
}
|
||||
}
|
||||
|
||||
target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb)
|
||||
target_ulong helper_SLBMFEE(CPUPPCState *env, target_ulong rb)
|
||||
{
|
||||
PowerPCCPU *cpu = env_archcpu(env);
|
||||
target_ulong rt = 0;
|
||||
|
@ -331,7 +358,7 @@ target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb)
|
|||
return rt;
|
||||
}
|
||||
|
||||
target_ulong helper_find_slb_vsid(CPUPPCState *env, target_ulong rb)
|
||||
target_ulong helper_SLBFEE(CPUPPCState *env, target_ulong rb)
|
||||
{
|
||||
PowerPCCPU *cpu = env_archcpu(env);
|
||||
target_ulong rt = 0;
|
||||
|
@ -343,7 +370,7 @@ target_ulong helper_find_slb_vsid(CPUPPCState *env, target_ulong rb)
|
|||
return rt;
|
||||
}
|
||||
|
||||
target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
|
||||
target_ulong helper_SLBMFEV(CPUPPCState *env, target_ulong rb)
|
||||
{
|
||||
PowerPCCPU *cpu = env_archcpu(env);
|
||||
target_ulong rt = 0;
|
||||
|
|
|
@ -236,16 +236,36 @@ static void ppc_radix64_set_rc(PowerPCCPU *cpu, MMUAccessType access_type,
|
|||
}
|
||||
}
|
||||
|
||||
static bool ppc_radix64_is_valid_level(int level, int psize, uint64_t nls)
|
||||
{
|
||||
/*
|
||||
* Check if this is a valid level, according to POWER9 and POWER10
|
||||
* Processor User's Manuals, sections 4.10.4.1 and 5.10.6.1, respectively:
|
||||
* Supported Radix Tree Configurations and Resulting Page Sizes.
|
||||
*
|
||||
* Note: these checks are specific to POWER9 and POWER10 CPUs. Any future
|
||||
* CPUs that supports a different Radix MMU configuration will need their
|
||||
* own implementation.
|
||||
*/
|
||||
switch (level) {
|
||||
case 0: /* Root Page Dir */
|
||||
return psize == 52 && nls == 13;
|
||||
case 1:
|
||||
case 2:
|
||||
return nls == 9;
|
||||
case 3:
|
||||
return nls == 9 || nls == 5;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "invalid radix level: %d\n", level);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int ppc_radix64_next_level(AddressSpace *as, vaddr eaddr,
|
||||
uint64_t *pte_addr, uint64_t *nls,
|
||||
int *psize, uint64_t *pte, int *fault_cause)
|
||||
{
|
||||
uint64_t index, pde;
|
||||
|
||||
if (*nls < 5) { /* Directory maps less than 2**5 entries */
|
||||
*fault_cause |= DSISR_R_BADCONFIG;
|
||||
return 1;
|
||||
}
|
||||
uint64_t index, mask, nlb, pde;
|
||||
|
||||
/* Read page <directory/table> entry from guest address space */
|
||||
pde = ldq_phys(as, *pte_addr);
|
||||
|
@ -260,7 +280,17 @@ static int ppc_radix64_next_level(AddressSpace *as, vaddr eaddr,
|
|||
*nls = pde & R_PDE_NLS;
|
||||
index = eaddr >> (*psize - *nls); /* Shift */
|
||||
index &= ((1UL << *nls) - 1); /* Mask */
|
||||
*pte_addr = (pde & R_PDE_NLB) + (index * sizeof(pde));
|
||||
nlb = pde & R_PDE_NLB;
|
||||
mask = MAKE_64BIT_MASK(0, *nls + 3);
|
||||
|
||||
if (nlb & mask) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: misaligned page dir/table base: 0x"TARGET_FMT_lx
|
||||
" page dir size: 0x"TARGET_FMT_lx"\n",
|
||||
__func__, nlb, mask + 1);
|
||||
nlb &= ~mask;
|
||||
}
|
||||
*pte_addr = nlb + index * sizeof(pde);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -270,19 +300,30 @@ static int ppc_radix64_walk_tree(AddressSpace *as, vaddr eaddr,
|
|||
hwaddr *raddr, int *psize, uint64_t *pte,
|
||||
int *fault_cause, hwaddr *pte_addr)
|
||||
{
|
||||
uint64_t index, pde, rpn , mask;
|
||||
|
||||
if (nls < 5) { /* Directory maps less than 2**5 entries */
|
||||
*fault_cause |= DSISR_R_BADCONFIG;
|
||||
return 1;
|
||||
}
|
||||
uint64_t index, pde, rpn, mask;
|
||||
int level = 0;
|
||||
|
||||
index = eaddr >> (*psize - nls); /* Shift */
|
||||
index &= ((1UL << nls) - 1); /* Mask */
|
||||
*pte_addr = base_addr + (index * sizeof(pde));
|
||||
index &= ((1UL << nls) - 1); /* Mask */
|
||||
mask = MAKE_64BIT_MASK(0, nls + 3);
|
||||
|
||||
if (base_addr & mask) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: misaligned page dir base: 0x"TARGET_FMT_lx
|
||||
" page dir size: 0x"TARGET_FMT_lx"\n",
|
||||
__func__, base_addr, mask + 1);
|
||||
base_addr &= ~mask;
|
||||
}
|
||||
*pte_addr = base_addr + index * sizeof(pde);
|
||||
|
||||
do {
|
||||
int ret;
|
||||
|
||||
if (!ppc_radix64_is_valid_level(level++, *psize, nls)) {
|
||||
*fault_cause |= DSISR_R_BADCONFIG;
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = ppc_radix64_next_level(as, eaddr, pte_addr, &nls, psize, &pde,
|
||||
fault_cause);
|
||||
if (ret) {
|
||||
|
@ -383,7 +424,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu,
|
|||
{
|
||||
CPUState *cs = CPU(cpu);
|
||||
CPUPPCState *env = &cpu->env;
|
||||
uint64_t offset, size, prtbe_addr, prtbe0, base_addr, nls, index, pte;
|
||||
uint64_t offset, size, prtb, prtbe_addr, prtbe0, base_addr, nls, index, pte;
|
||||
int fault_cause = 0, h_page_size, h_prot;
|
||||
hwaddr h_raddr, pte_addr;
|
||||
int ret;
|
||||
|
@ -393,9 +434,18 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu,
|
|||
__func__, access_str(access_type),
|
||||
eaddr, mmu_idx, pid);
|
||||
|
||||
prtb = (pate.dw1 & PATE1_R_PRTB);
|
||||
size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12);
|
||||
if (prtb & (size - 1)) {
|
||||
/* Process Table not properly aligned */
|
||||
if (guest_visible) {
|
||||
ppc_radix64_raise_si(cpu, access_type, eaddr, DSISR_R_BADCONFIG);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Index Process Table by PID to Find Corresponding Process Table Entry */
|
||||
offset = pid * sizeof(struct prtb_entry);
|
||||
size = 1ULL << ((pate.dw1 & PATE1_R_PRTS) + 12);
|
||||
if (offset >= size) {
|
||||
/* offset exceeds size of the process table */
|
||||
if (guest_visible) {
|
||||
|
@ -403,7 +453,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu,
|
|||
}
|
||||
return 1;
|
||||
}
|
||||
prtbe_addr = (pate.dw1 & PATE1_R_PRTB) + offset;
|
||||
prtbe_addr = prtb + offset;
|
||||
|
||||
if (vhyp_flat_addressing(cpu)) {
|
||||
prtbe0 = ldq_phys(cs->as, prtbe_addr);
|
||||
|
@ -447,6 +497,7 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu,
|
|||
}
|
||||
} else {
|
||||
uint64_t rpn, mask;
|
||||
int level = 0;
|
||||
|
||||
index = (eaddr & R_EADDR_MASK) >> (*g_page_size - nls); /* Shift */
|
||||
index &= ((1UL << nls) - 1); /* Mask */
|
||||
|
@ -466,6 +517,11 @@ static int ppc_radix64_process_scoped_xlate(PowerPCCPU *cpu,
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (!ppc_radix64_is_valid_level(level++, *g_page_size, nls)) {
|
||||
fault_cause |= DSISR_R_BADCONFIG;
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = ppc_radix64_next_level(cs->as, eaddr & R_EADDR_MASK, &h_raddr,
|
||||
&nls, g_page_size, &pte, &fault_cause);
|
||||
if (ret) {
|
||||
|
@ -568,7 +624,7 @@ static bool ppc_radix64_xlate_impl(PowerPCCPU *cpu, vaddr eaddr,
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Get Process Table */
|
||||
/* Get Partition Table */
|
||||
if (cpu->vhyp) {
|
||||
PPCVirtualHypervisorClass *vhc;
|
||||
vhc = PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
|
||||
|
|
|
@ -429,6 +429,160 @@ void helper_tlbie(CPUPPCState *env, target_ulong addr)
|
|||
ppc_tlb_invalidate_one(env, addr);
|
||||
}
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
|
||||
/* Invalidation Selector */
|
||||
#define TLBIE_IS_VA 0
|
||||
#define TLBIE_IS_PID 1
|
||||
#define TLBIE_IS_LPID 2
|
||||
#define TLBIE_IS_ALL 3
|
||||
|
||||
/* Radix Invalidation Control */
|
||||
#define TLBIE_RIC_TLB 0
|
||||
#define TLBIE_RIC_PWC 1
|
||||
#define TLBIE_RIC_ALL 2
|
||||
#define TLBIE_RIC_GRP 3
|
||||
|
||||
/* Radix Actual Page sizes */
|
||||
#define TLBIE_R_AP_4K 0
|
||||
#define TLBIE_R_AP_64K 5
|
||||
#define TLBIE_R_AP_2M 1
|
||||
#define TLBIE_R_AP_1G 2
|
||||
|
||||
/* RB field masks */
|
||||
#define TLBIE_RB_EPN_MASK PPC_BITMASK(0, 51)
|
||||
#define TLBIE_RB_IS_MASK PPC_BITMASK(52, 53)
|
||||
#define TLBIE_RB_AP_MASK PPC_BITMASK(56, 58)
|
||||
|
||||
void helper_tlbie_isa300(CPUPPCState *env, target_ulong rb, target_ulong rs,
|
||||
uint32_t flags)
|
||||
{
|
||||
unsigned ric = (flags & TLBIE_F_RIC_MASK) >> TLBIE_F_RIC_SHIFT;
|
||||
/*
|
||||
* With the exception of the checks for invalid instruction forms,
|
||||
* PRS is currently ignored, because we don't know if a given TLB entry
|
||||
* is process or partition scoped.
|
||||
*/
|
||||
bool prs = flags & TLBIE_F_PRS;
|
||||
bool r = flags & TLBIE_F_R;
|
||||
bool local = flags & TLBIE_F_LOCAL;
|
||||
bool effR;
|
||||
unsigned is = extract64(rb, PPC_BIT_NR(53), 2);
|
||||
unsigned ap; /* actual page size */
|
||||
target_ulong addr, pgoffs_mask;
|
||||
|
||||
qemu_log_mask(CPU_LOG_MMU,
|
||||
"%s: local=%d addr=" TARGET_FMT_lx " ric=%u prs=%d r=%d is=%u\n",
|
||||
__func__, local, rb & TARGET_PAGE_MASK, ric, prs, r, is);
|
||||
|
||||
effR = FIELD_EX64(env->msr, MSR, HV) ? r : env->spr[SPR_LPCR] & LPCR_HR;
|
||||
|
||||
/* Partial TLB invalidation is supported for Radix only for now. */
|
||||
if (!effR) {
|
||||
goto inval_all;
|
||||
}
|
||||
|
||||
/* Check for invalid instruction forms (effR=1). */
|
||||
if (unlikely(ric == TLBIE_RIC_GRP ||
|
||||
((ric == TLBIE_RIC_PWC || ric == TLBIE_RIC_ALL) &&
|
||||
is == TLBIE_IS_VA) ||
|
||||
(!prs && is == TLBIE_IS_PID))) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: invalid instruction form: ric=%u prs=%d r=%d is=%u\n",
|
||||
__func__, ric, prs, r, is);
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
/* We don't cache Page Walks. */
|
||||
if (ric == TLBIE_RIC_PWC) {
|
||||
if (local) {
|
||||
unsigned set = extract64(rb, PPC_BIT_NR(51), 12);
|
||||
if (set != 0) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid set: %d\n",
|
||||
__func__, set);
|
||||
goto invalid;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Invalidation by LPID or PID is not supported, so fallback
|
||||
* to full TLB flush in these cases.
|
||||
*/
|
||||
if (is != TLBIE_IS_VA) {
|
||||
goto inval_all;
|
||||
}
|
||||
|
||||
/*
|
||||
* The results of an attempt to invalidate a translation outside of
|
||||
* quadrant 0 for Radix Tree translation (effR=1, RIC=0, PRS=1, IS=0,
|
||||
* and EA 0:1 != 0b00) are boundedly undefined.
|
||||
*/
|
||||
if (unlikely(ric == TLBIE_RIC_TLB && prs && is == TLBIE_IS_VA &&
|
||||
(rb & R_EADDR_QUADRANT) != R_EADDR_QUADRANT0)) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: attempt to invalidate a translation outside of quadrant 0\n",
|
||||
__func__);
|
||||
goto inval_all;
|
||||
}
|
||||
|
||||
assert(is == TLBIE_IS_VA);
|
||||
assert(ric == TLBIE_RIC_TLB || ric == TLBIE_RIC_ALL);
|
||||
|
||||
ap = extract64(rb, PPC_BIT_NR(58), 3);
|
||||
switch (ap) {
|
||||
case TLBIE_R_AP_4K:
|
||||
pgoffs_mask = 0xfffull;
|
||||
break;
|
||||
|
||||
case TLBIE_R_AP_64K:
|
||||
pgoffs_mask = 0xffffull;
|
||||
break;
|
||||
|
||||
case TLBIE_R_AP_2M:
|
||||
pgoffs_mask = 0x1fffffull;
|
||||
break;
|
||||
|
||||
case TLBIE_R_AP_1G:
|
||||
pgoffs_mask = 0x3fffffffull;
|
||||
break;
|
||||
|
||||
default:
|
||||
/*
|
||||
* If the value specified in RS 0:31, RS 32:63, RB 54:55, RB 56:58,
|
||||
* RB 44:51, or RB 56:63, when it is needed to perform the specified
|
||||
* operation, is not supported by the implementation, the instruction
|
||||
* is treated as if the instruction form were invalid.
|
||||
*/
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid AP: %d\n", __func__, ap);
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
addr = rb & TLBIE_RB_EPN_MASK & ~pgoffs_mask;
|
||||
|
||||
if (local) {
|
||||
tlb_flush_page(env_cpu(env), addr);
|
||||
} else {
|
||||
tlb_flush_page_all_cpus(env_cpu(env), addr);
|
||||
}
|
||||
return;
|
||||
|
||||
inval_all:
|
||||
env->tlb_need_flush |= TLB_NEED_LOCAL_FLUSH;
|
||||
if (!local) {
|
||||
env->tlb_need_flush |= TLB_NEED_GLOBAL_FLUSH;
|
||||
}
|
||||
return;
|
||||
|
||||
invalid:
|
||||
raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
|
||||
POWERPC_EXCP_INVAL |
|
||||
POWERPC_EXCP_INVAL_INVAL, GETPC());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void helper_tlbiva(CPUPPCState *env, target_ulong addr)
|
||||
{
|
||||
/* tlbiva instruction only exists on BookE */
|
||||
|
|
|
@ -55,6 +55,9 @@ static target_long monitor_get_decr(Monitor *mon, const struct MonitorDef *md,
|
|||
int val)
|
||||
{
|
||||
CPUArchState *env = mon_get_cpu_env(mon);
|
||||
if (!env->tb_env) {
|
||||
return 0;
|
||||
}
|
||||
return cpu_ppc_load_decr(env);
|
||||
}
|
||||
|
||||
|
@ -62,6 +65,9 @@ static target_long monitor_get_tbu(Monitor *mon, const struct MonitorDef *md,
|
|||
int val)
|
||||
{
|
||||
CPUArchState *env = mon_get_cpu_env(mon);
|
||||
if (!env->tb_env) {
|
||||
return 0;
|
||||
}
|
||||
return cpu_ppc_load_tbu(env);
|
||||
}
|
||||
|
||||
|
@ -69,6 +75,9 @@ static target_long monitor_get_tbl(Monitor *mon, const struct MonitorDef *md,
|
|||
int val)
|
||||
{
|
||||
CPUArchState *env = mon_get_cpu_env(mon);
|
||||
if (!env->tb_env) {
|
||||
return 0;
|
||||
}
|
||||
return cpu_ppc_load_tbl(env);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
static bool spr_groupA_read_allowed(DisasContext *ctx)
|
||||
{
|
||||
if (!ctx->mmcr0_pmcc0 && ctx->mmcr0_pmcc1) {
|
||||
gen_hvpriv_exception(ctx, POWERPC_EXCP_FU);
|
||||
gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_PMU);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -46,10 +46,10 @@ static bool spr_groupA_write_allowed(DisasContext *ctx)
|
|||
|
||||
if (ctx->mmcr0_pmcc1) {
|
||||
/* PMCC = 0b01 */
|
||||
gen_hvpriv_exception(ctx, POWERPC_EXCP_FU);
|
||||
gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_PMU);
|
||||
} else {
|
||||
/* PMCC = 0b00 */
|
||||
gen_hvpriv_exception(ctx, POWERPC_EXCP_INVAL_SPR);
|
||||
gen_hvpriv_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -214,7 +214,7 @@ void spr_read_PMC56_ureg(DisasContext *ctx, int gprn, int sprn)
|
|||
* Interrupt.
|
||||
*/
|
||||
if (ctx->mmcr0_pmcc0 && ctx->mmcr0_pmcc1) {
|
||||
gen_hvpriv_exception(ctx, POWERPC_EXCP_FU);
|
||||
gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_PMU);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -249,7 +249,7 @@ void spr_write_PMC56_ureg(DisasContext *ctx, int sprn, int gprn)
|
|||
* Interrupt.
|
||||
*/
|
||||
if (ctx->mmcr0_pmcc0 && ctx->mmcr0_pmcc1) {
|
||||
gen_hvpriv_exception(ctx, POWERPC_EXCP_FU);
|
||||
gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_PMU);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -143,7 +143,6 @@ void helper_store_booke_tsr(CPUPPCState *env, target_ulong val)
|
|||
{
|
||||
store_booke_tsr(env, val);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Embedded PowerPC specific helpers */
|
||||
|
@ -169,7 +168,7 @@ target_ulong helper_load_dcr(CPUPPCState *env, target_ulong dcrn)
|
|||
(uint32_t)dcrn, (uint32_t)dcrn);
|
||||
raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
|
||||
POWERPC_EXCP_INVAL |
|
||||
POWERPC_EXCP_PRIV_REG, GETPC());
|
||||
POWERPC_EXCP_INVAL_INVAL, GETPC());
|
||||
}
|
||||
}
|
||||
return val;
|
||||
|
@ -192,7 +191,8 @@ void helper_store_dcr(CPUPPCState *env, target_ulong dcrn, target_ulong val)
|
|||
(uint32_t)dcrn, (uint32_t)dcrn);
|
||||
raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
|
||||
POWERPC_EXCP_INVAL |
|
||||
POWERPC_EXCP_PRIV_REG, GETPC());
|
||||
POWERPC_EXCP_INVAL_INVAL, GETPC());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -79,11 +79,8 @@ static bool do_ldst_quad(DisasContext *ctx, arg_D *a, bool store, bool prefixed)
|
|||
REQUIRE_INSNS_FLAGS(ctx, 64BX);
|
||||
|
||||
if (!prefixed && !(ctx->insns_flags2 & PPC2_LSQ_ISA207)) {
|
||||
if (ctx->pr) {
|
||||
/* lq and stq were privileged prior to V. 2.07 */
|
||||
gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||
return true;
|
||||
}
|
||||
/* lq and stq were privileged prior to V. 2.07 */
|
||||
REQUIRE_SV(ctx);
|
||||
|
||||
if (ctx->le_mode) {
|
||||
gen_align_no_le(ctx);
|
||||
|
|
|
@ -901,7 +901,7 @@ static void gen_lfdepx(DisasContext *ctx)
|
|||
{
|
||||
TCGv EA;
|
||||
TCGv_i64 t0;
|
||||
CHK_SV;
|
||||
CHK_SV(ctx);
|
||||
if (unlikely(!ctx->fpu_enabled)) {
|
||||
gen_exception(ctx, POWERPC_EXCP_FPU);
|
||||
return;
|
||||
|
@ -1058,7 +1058,7 @@ static void gen_stfdepx(DisasContext *ctx)
|
|||
{
|
||||
TCGv EA;
|
||||
TCGv_i64 t0;
|
||||
CHK_SV;
|
||||
CHK_SV(ctx);
|
||||
if (unlikely(!ctx->fpu_enabled)) {
|
||||
gen_exception(ctx, POWERPC_EXCP_FPU);
|
||||
return;
|
||||
|
|
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* Power ISA decode for Storage Control instructions
|
||||
*
|
||||
* Copyright (c) 2022 Instituto de Pesquisas Eldorado (eldorado.org.br)
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Store Control Instructions
|
||||
*/
|
||||
|
||||
#include "mmu-book3s-v3.h"
|
||||
|
||||
static bool trans_SLBIE(DisasContext *ctx, arg_SLBIE *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_INSNS_FLAGS(ctx, SLBI);
|
||||
REQUIRE_SV(ctx);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64)
|
||||
gen_helper_SLBIE(cpu_env, cpu_gpr[a->rb]);
|
||||
#else
|
||||
qemu_build_not_reached();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_SLBIEG(DisasContext *ctx, arg_SLBIEG *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_INSNS_FLAGS2(ctx, ISA300);
|
||||
REQUIRE_SV(ctx);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64)
|
||||
gen_helper_SLBIEG(cpu_env, cpu_gpr[a->rb]);
|
||||
#else
|
||||
qemu_build_not_reached();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_SLBIA(DisasContext *ctx, arg_SLBIA *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_INSNS_FLAGS(ctx, SLBI);
|
||||
REQUIRE_SV(ctx);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64)
|
||||
gen_helper_SLBIA(cpu_env, tcg_constant_i32(a->ih));
|
||||
#else
|
||||
qemu_build_not_reached();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_SLBIAG(DisasContext *ctx, arg_SLBIAG *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_INSNS_FLAGS2(ctx, ISA300);
|
||||
REQUIRE_SV(ctx);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64)
|
||||
gen_helper_SLBIAG(cpu_env, cpu_gpr[a->rs], tcg_constant_i32(a->l));
|
||||
#else
|
||||
qemu_build_not_reached();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_SLBMTE(DisasContext *ctx, arg_SLBMTE *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_INSNS_FLAGS(ctx, SEGMENT_64B);
|
||||
REQUIRE_SV(ctx);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64)
|
||||
gen_helper_SLBMTE(cpu_env, cpu_gpr[a->rb], cpu_gpr[a->rt]);
|
||||
#else
|
||||
qemu_build_not_reached();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_SLBMFEV(DisasContext *ctx, arg_SLBMFEV *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_INSNS_FLAGS(ctx, SEGMENT_64B);
|
||||
REQUIRE_SV(ctx);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64)
|
||||
gen_helper_SLBMFEV(cpu_gpr[a->rt], cpu_env, cpu_gpr[a->rb]);
|
||||
#else
|
||||
qemu_build_not_reached();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_SLBMFEE(DisasContext *ctx, arg_SLBMFEE *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_INSNS_FLAGS(ctx, SEGMENT_64B);
|
||||
REQUIRE_SV(ctx);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64)
|
||||
gen_helper_SLBMFEE(cpu_gpr[a->rt], cpu_env, cpu_gpr[a->rb]);
|
||||
#else
|
||||
qemu_build_not_reached();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_SLBFEE(DisasContext *ctx, arg_SLBFEE *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_INSNS_FLAGS(ctx, SEGMENT_64B);
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||
#else
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
TCGLabel *l1, *l2;
|
||||
|
||||
if (unlikely(ctx->pr)) {
|
||||
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_REG);
|
||||
return true;
|
||||
}
|
||||
gen_helper_SLBFEE(cpu_gpr[a->rt], cpu_env,
|
||||
cpu_gpr[a->rb]);
|
||||
l1 = gen_new_label();
|
||||
l2 = gen_new_label();
|
||||
tcg_gen_trunc_tl_i32(cpu_crf[0], cpu_so);
|
||||
tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_gpr[a->rt], -1, l1);
|
||||
tcg_gen_ori_i32(cpu_crf[0], cpu_crf[0], CRF_EQ);
|
||||
tcg_gen_br(l2);
|
||||
gen_set_label(l1);
|
||||
tcg_gen_movi_tl(cpu_gpr[a->rt], 0);
|
||||
gen_set_label(l2);
|
||||
#else
|
||||
qemu_build_not_reached();
|
||||
#endif
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_SLBSYNC(DisasContext *ctx, arg_SLBSYNC *a)
|
||||
{
|
||||
REQUIRE_64BIT(ctx);
|
||||
REQUIRE_INSNS_FLAGS2(ctx, ISA300);
|
||||
REQUIRE_SV(ctx);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64)
|
||||
gen_check_tlb_flush(ctx, true);
|
||||
#else
|
||||
qemu_build_not_reached();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool do_tlbie(DisasContext *ctx, arg_X_tlbie *a, bool local)
|
||||
{
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||
return true;
|
||||
#else
|
||||
TCGv_i32 t1;
|
||||
int rb;
|
||||
|
||||
rb = a->rb;
|
||||
|
||||
if ((ctx->insns_flags2 & PPC2_ISA300) == 0) {
|
||||
/*
|
||||
* Before Power ISA 3.0, the corresponding bits of RIC, PRS, and R
|
||||
* (and RS for tlbiel) were reserved fields and should be ignored.
|
||||
*/
|
||||
a->ric = 0;
|
||||
a->prs = false;
|
||||
a->r = false;
|
||||
if (local) {
|
||||
a->rs = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->pr) {
|
||||
/* tlbie[l] is privileged... */
|
||||
gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||
return true;
|
||||
} else if (!ctx->hv) {
|
||||
if ((!a->prs && ctx->hr) || (!local && !ctx->gtse)) {
|
||||
/*
|
||||
* ... except when PRS=0 and HR=1, or when GTSE=0 for tlbie,
|
||||
* making it hypervisor privileged.
|
||||
*/
|
||||
gen_priv_exception(ctx, POWERPC_EXCP_PRIV_OPC);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!local && NARROW_MODE(ctx)) {
|
||||
TCGv t0 = tcg_temp_new();
|
||||
tcg_gen_ext32u_tl(t0, cpu_gpr[rb]);
|
||||
gen_helper_tlbie(cpu_env, t0);
|
||||
tcg_temp_free(t0);
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
/*
|
||||
* ISA 3.1B says that MSR SF must be 1 when this instruction is executed;
|
||||
* otherwise the results are undefined.
|
||||
*/
|
||||
} else if (a->r) {
|
||||
gen_helper_tlbie_isa300(cpu_env, cpu_gpr[rb], cpu_gpr[a->rs],
|
||||
tcg_constant_i32(a->ric << TLBIE_F_RIC_SHIFT |
|
||||
a->prs << TLBIE_F_PRS_SHIFT |
|
||||
a->r << TLBIE_F_R_SHIFT |
|
||||
local << TLBIE_F_LOCAL_SHIFT));
|
||||
return true;
|
||||
#endif
|
||||
|
||||
} else {
|
||||
gen_helper_tlbie(cpu_env, cpu_gpr[rb]);
|
||||
}
|
||||
|
||||
if (local) {
|
||||
return true;
|
||||
}
|
||||
|
||||
t1 = tcg_temp_new_i32();
|
||||
tcg_gen_ld_i32(t1, cpu_env, offsetof(CPUPPCState, tlb_need_flush));
|
||||
tcg_gen_ori_i32(t1, t1, TLB_NEED_GLOBAL_FLUSH);
|
||||
tcg_gen_st_i32(t1, cpu_env, offsetof(CPUPPCState, tlb_need_flush));
|
||||
tcg_temp_free_i32(t1);
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
TRANS_FLAGS(MEM_TLBIE, TLBIE, do_tlbie, false)
|
||||
TRANS_FLAGS(MEM_TLBIE, TLBIEL, do_tlbie, true)
|
Loading…
Reference in New Issue