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:
Peter Maydell 2022-07-18 19:27:25 +01:00
commit b8bb9bbf46
32 changed files with 850 additions and 473 deletions

View File

@ -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:

View File

@ -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:

View File

@ -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;

View File

@ -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:

View File

@ -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");

View File

@ -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) */

View File

@ -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 */

View File

@ -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;

View File

@ -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));

View File

@ -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"));

View File

@ -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");

View File

@ -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]));

View File

@ -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) {

View File

@ -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;

View File

@ -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);
}

View File

@ -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 */

View File

@ -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) {

View File

@ -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)

View File

@ -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

View File

@ -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");

View File

@ -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) {

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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 */

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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)