mirror of https://github.com/xemu-project/xemu.git
ppc patch queue 2021-10-21
Here's the next batch of ppc target related patches for qemu-6.2. Highlights are: * Some fixes and minimal tests for old embedded ppc platforms * The beginnings of PMU emulation in TCG from Daniel Barboza * Some improvements to the pegasos2 platform * A number of TCG bugfixes from the folks at the El Dorado Institute * A few other assorted bugfixes and cleanups -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEdfRlhq5hpmzETofcbDjKyiDZs5IFAmFw6jgACgkQbDjKyiDZ s5Kn+Q//bxrE9GjUA6XzPjB1DJiDgWzmDALlT8ATsFVFDZv/+ABr/RNcqFKRfjKC +YANtBKgwTFdgjjysQhSnawQkqOiMN4XRmTf7msLAHP0FD8RIZI3C0YpXFCZfeIp cjZgK3WzJ9fb29YGfrD85QlklDXfGLWnu0HuTjvPYmBWHWlexLmxSZGrj6HvCCjl N4otpaLSCXte1BneLmJSEkRE9SAFWfSysdB2u7wNJhpxgvfLIe1gRgl8JstrxokO MFnnYWPjMom0khsziTEAQ6Db5RXTdsKdma6uKtWXbz5IVIqlj99v12qL3zXc20uG LxYjwxb1UMvj0W44p8XiTwupOAmAd0vjgPBJy3hv71iQfO52nfoozHRwvepG29J3 CN7REEGp1u/8ycoNu6ZzUu2FarmWLiF3Wp4jil36FqYoPrDMjOA0kyOyTRG+t3jB PvrBsuxaykz/1/EvC9GlzYgA5OTXb+/Szu81D8It1DCsLOPvC6zVqbuTYicT2O1N rA3MXCTvW77XcJ1ymhrq3r1uSrd1bGwTwr6DGFI90HnnOLeUVqPnJfC1SfkdE16l SCJCi5lM7Kkkzx7sCm2fWBNm5PkKBV0Uj7pej+U9hi85tD8glIVbAYdLk/Y7DhTW WIwjDMpMqgwWuUzHSEb08JL5vs80AlokUS9kKFF7VL/y/X+yqz4= =wrQy -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-6.2-20211021' into staging ppc patch queue 2021-10-21 Here's the next batch of ppc target related patches for qemu-6.2. Highlights are: * Some fixes and minimal tests for old embedded ppc platforms * The beginnings of PMU emulation in TCG from Daniel Barboza * Some improvements to the pegasos2 platform * A number of TCG bugfixes from the folks at the El Dorado Institute * A few other assorted bugfixes and cleanups # gpg: Signature made Wed 20 Oct 2021 09:19:04 PM PDT # gpg: using RSA key 75F46586AE61A66CC44E87DC6C38CACA20D9B392 # gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>" [full] # gpg: aka "David Gibson (kernel.org) <dwg@kernel.org>" [unknown] # gpg: aka "David Gibson (Red Hat) <dgibson@redhat.com>" [full] # gpg: aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>" [full] * remotes/dgibson/tags/ppc-for-6.2-20211021: (25 commits) hw/ppc/ppc4xx_pci: Fix ppc4xx_pci_map_irq() for recent Linux kernels target/ppc: adding user read/write functions for PMCs target/ppc: add user read/write functions for MMCR2 target/ppc: add user read/write functions for MMCR0 target/ppc: add MMCR0 PMCC bits to hflags target/ppc: Filter mtmsr[d] input before setting MSR tests/acceptance: Add a test for the bamboo ppc board ppc/pegasos2: Implement power-off RTAS function with VOF ppc/pegasos2: Add constants for PCI config addresses ppc/pegasos2: Access MV64361 registers via their memory region ppc/pegasos2: Implement get-time-of-day RTAS function with VOF ppc/pegasos2: Warn when using VOF but no kernel is specified ppc/pegasos2: Restrict memory to 2 gigabytes target/ppc: Fix XER access in monitor linux-user: Fix XER access in ppc version of elf_core_copy_regs target/ppc: Fix XER access in gdbstub linux-user/ppc: Fix XER access in save/restore_user_regs tests/acceptance: Add tests for the ppc405 boards hw/ppc: Fix iothread locking in the 405 code spapr/xive: Use xive_esb_rw() to trigger interrupts ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
e016b58f6e
|
@ -1245,6 +1245,7 @@ Bamboo
|
|||
L: qemu-ppc@nongnu.org
|
||||
S: Orphan
|
||||
F: hw/ppc/ppc440_bamboo.c
|
||||
F: tests/acceptance/ppc_bamboo.py
|
||||
|
||||
e500
|
||||
L: qemu-ppc@nongnu.org
|
||||
|
|
|
@ -185,7 +185,7 @@ static void spapr_xive_pic_print_info(SpaprXive *xive, Monitor *mon)
|
|||
xive_source_irq_is_lsi(xsrc, i) ? "LSI" : "MSI",
|
||||
pq & XIVE_ESB_VAL_P ? 'P' : '-',
|
||||
pq & XIVE_ESB_VAL_Q ? 'Q' : '-',
|
||||
xsrc->status[i] & XIVE_STATUS_ASSERTED ? 'A' : ' ',
|
||||
xive_source_is_asserted(xsrc, i) ? 'A' : ' ',
|
||||
xive_eas_is_masked(eas) ? "M" : " ",
|
||||
(int) xive_get_field64(EAS_END_DATA, eas->w));
|
||||
|
||||
|
|
|
@ -242,7 +242,7 @@ int kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp)
|
|||
|
||||
if (xive_source_irq_is_lsi(xsrc, srcno)) {
|
||||
state |= KVM_XIVE_LEVEL_SENSITIVE;
|
||||
if (xsrc->status[srcno] & XIVE_STATUS_ASSERTED) {
|
||||
if (xive_source_is_asserted(xsrc, srcno)) {
|
||||
state |= KVM_XIVE_LEVEL_ASSERTED;
|
||||
}
|
||||
}
|
||||
|
@ -301,9 +301,7 @@ static uint8_t xive_esb_read(XiveSource *xsrc, int srcno, uint32_t offset)
|
|||
|
||||
static void kvmppc_xive_esb_trigger(XiveSource *xsrc, int srcno)
|
||||
{
|
||||
uint64_t *addr = xsrc->esb_mmap + xive_source_esb_page(xsrc, srcno);
|
||||
|
||||
*addr = 0x0;
|
||||
xive_esb_rw(xsrc, srcno, 0, 0, true);
|
||||
}
|
||||
|
||||
uint64_t kvmppc_xive_esb_rw(XiveSource *xsrc, int srcno, uint32_t offset,
|
||||
|
@ -321,7 +319,7 @@ uint64_t kvmppc_xive_esb_rw(XiveSource *xsrc, int srcno, uint32_t offset,
|
|||
if (xive_source_irq_is_lsi(xsrc, srcno) &&
|
||||
offset == XIVE_ESB_LOAD_EOI) {
|
||||
xive_esb_read(xsrc, srcno, XIVE_ESB_SET_PQ_00);
|
||||
if (xsrc->status[srcno] & XIVE_STATUS_ASSERTED) {
|
||||
if (xive_source_is_asserted(xsrc, srcno)) {
|
||||
kvmppc_xive_esb_trigger(xsrc, srcno);
|
||||
}
|
||||
return 0;
|
||||
|
@ -359,11 +357,7 @@ void kvmppc_xive_source_set_irq(void *opaque, int srcno, int val)
|
|||
return;
|
||||
}
|
||||
} else {
|
||||
if (val) {
|
||||
xsrc->status[srcno] |= XIVE_STATUS_ASSERTED;
|
||||
} else {
|
||||
xsrc->status[srcno] &= ~XIVE_STATUS_ASSERTED;
|
||||
}
|
||||
xive_source_set_asserted(xsrc, srcno, val);
|
||||
}
|
||||
|
||||
kvmppc_xive_esb_trigger(xsrc, srcno);
|
||||
|
|
|
@ -875,7 +875,7 @@ static bool xive_source_lsi_trigger(XiveSource *xsrc, uint32_t srcno)
|
|||
{
|
||||
uint8_t old_pq = xive_source_esb_get(xsrc, srcno);
|
||||
|
||||
xsrc->status[srcno] |= XIVE_STATUS_ASSERTED;
|
||||
xive_source_set_asserted(xsrc, srcno, true);
|
||||
|
||||
switch (old_pq) {
|
||||
case XIVE_ESB_RESET:
|
||||
|
@ -923,7 +923,7 @@ static bool xive_source_esb_eoi(XiveSource *xsrc, uint32_t srcno)
|
|||
* notification
|
||||
*/
|
||||
if (xive_source_irq_is_lsi(xsrc, srcno) &&
|
||||
xsrc->status[srcno] & XIVE_STATUS_ASSERTED) {
|
||||
xive_source_is_asserted(xsrc, srcno)) {
|
||||
ret = xive_source_lsi_trigger(xsrc, srcno);
|
||||
}
|
||||
|
||||
|
@ -1104,7 +1104,7 @@ void xive_source_set_irq(void *opaque, int srcno, int val)
|
|||
if (val) {
|
||||
notify = xive_source_lsi_trigger(xsrc, srcno);
|
||||
} else {
|
||||
xsrc->status[srcno] &= ~XIVE_STATUS_ASSERTED;
|
||||
xive_source_set_asserted(xsrc, srcno, false);
|
||||
}
|
||||
} else {
|
||||
if (val) {
|
||||
|
@ -1133,7 +1133,7 @@ void xive_source_pic_print_info(XiveSource *xsrc, uint32_t offset, Monitor *mon)
|
|||
xive_source_irq_is_lsi(xsrc, i) ? "LSI" : "MSI",
|
||||
pq & XIVE_ESB_VAL_P ? 'P' : '-',
|
||||
pq & XIVE_ESB_VAL_Q ? 'Q' : '-',
|
||||
xsrc->status[i] & XIVE_STATUS_ASSERTED ? 'A' : ' ');
|
||||
xive_source_is_asserted(xsrc, i) ? 'A' : ' ');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -869,6 +869,7 @@ static void mv64361_realize(DeviceState *dev, Error **errp)
|
|||
s->base_addr_enable = 0x1fffff;
|
||||
memory_region_init_io(&s->regs, OBJECT(s), &mv64361_ops, s,
|
||||
TYPE_MV64361, 0x10000);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->regs);
|
||||
for (i = 0; i < 2; i++) {
|
||||
g_autofree char *name = g_strdup_printf("pcihost%d", i);
|
||||
object_initialize_child(OBJECT(dev), name, &s->pci[i],
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "hw/i2c/smbus_eeprom.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "sysemu/reset.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/loader.h"
|
||||
#include "hw/fw-path-provider.h"
|
||||
|
@ -31,6 +32,8 @@
|
|||
#include "sysemu/kvm.h"
|
||||
#include "kvm_ppc.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "qom/qom-qobject.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "trace.h"
|
||||
#include "qemu/datadir.h"
|
||||
#include "sysemu/device_tree.h"
|
||||
|
@ -52,11 +55,13 @@
|
|||
|
||||
#define BUS_FREQ_HZ 133333333
|
||||
|
||||
#define PCI0_CFG_ADDR 0xcf8
|
||||
#define PCI0_MEM_BASE 0xc0000000
|
||||
#define PCI0_MEM_SIZE 0x20000000
|
||||
#define PCI0_IO_BASE 0xf8000000
|
||||
#define PCI0_IO_SIZE 0x10000
|
||||
|
||||
#define PCI1_CFG_ADDR 0xc78
|
||||
#define PCI1_MEM_BASE 0x80000000
|
||||
#define PCI1_MEM_SIZE 0x40000000
|
||||
#define PCI1_IO_BASE 0xfe000000
|
||||
|
@ -117,6 +122,10 @@ static void pegasos2_init(MachineState *machine)
|
|||
qemu_register_reset(pegasos2_cpu_reset, pm->cpu);
|
||||
|
||||
/* RAM */
|
||||
if (machine->ram_size > 2 * GiB) {
|
||||
error_report("RAM size more than 2 GiB is not supported");
|
||||
exit(1);
|
||||
}
|
||||
memory_region_add_subregion(get_system_memory(), 0, machine->ram);
|
||||
|
||||
/* allocate and load firmware */
|
||||
|
@ -190,62 +199,58 @@ static void pegasos2_init(MachineState *machine)
|
|||
if (!pm->vof) {
|
||||
warn_report("Option -kernel may be ineffective with -bios.");
|
||||
}
|
||||
} else if (pm->vof) {
|
||||
warn_report("Using Virtual OpenFirmware but no -kernel option.");
|
||||
}
|
||||
|
||||
if (!pm->vof && machine->kernel_cmdline && machine->kernel_cmdline[0]) {
|
||||
warn_report("Option -append may be ineffective with -bios.");
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t pegasos2_pci_config_read(AddressSpace *as, int bus,
|
||||
static uint32_t pegasos2_mv_reg_read(Pegasos2MachineState *pm,
|
||||
uint32_t addr, uint32_t len)
|
||||
{
|
||||
MemoryRegion *r = sysbus_mmio_get_region(SYS_BUS_DEVICE(pm->mv), 0);
|
||||
uint64_t val = 0xffffffffULL;
|
||||
memory_region_dispatch_read(r, addr, &val, size_memop(len) | MO_LE,
|
||||
MEMTXATTRS_UNSPECIFIED);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void pegasos2_mv_reg_write(Pegasos2MachineState *pm, uint32_t addr,
|
||||
uint32_t len, uint32_t val)
|
||||
{
|
||||
MemoryRegion *r = sysbus_mmio_get_region(SYS_BUS_DEVICE(pm->mv), 0);
|
||||
memory_region_dispatch_write(r, addr, val, size_memop(len) | MO_LE,
|
||||
MEMTXATTRS_UNSPECIFIED);
|
||||
}
|
||||
|
||||
static uint32_t pegasos2_pci_config_read(Pegasos2MachineState *pm, int bus,
|
||||
uint32_t addr, uint32_t len)
|
||||
{
|
||||
hwaddr pcicfg = (bus ? 0xf1000c78 : 0xf1000cf8);
|
||||
uint32_t val = 0xffffffff;
|
||||
hwaddr pcicfg = bus ? PCI1_CFG_ADDR : PCI0_CFG_ADDR;
|
||||
uint64_t val = 0xffffffffULL;
|
||||
|
||||
stl_le_phys(as, pcicfg, addr | BIT(31));
|
||||
switch (len) {
|
||||
case 4:
|
||||
val = ldl_le_phys(as, pcicfg + 4);
|
||||
break;
|
||||
case 2:
|
||||
val = lduw_le_phys(as, pcicfg + 4);
|
||||
break;
|
||||
case 1:
|
||||
val = ldub_phys(as, pcicfg + 4);
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid length\n", __func__);
|
||||
break;
|
||||
if (len <= 4) {
|
||||
pegasos2_mv_reg_write(pm, pcicfg, 4, addr | BIT(31));
|
||||
val = pegasos2_mv_reg_read(pm, pcicfg + 4, len);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static void pegasos2_pci_config_write(AddressSpace *as, int bus, uint32_t addr,
|
||||
uint32_t len, uint32_t val)
|
||||
static void pegasos2_pci_config_write(Pegasos2MachineState *pm, int bus,
|
||||
uint32_t addr, uint32_t len, uint32_t val)
|
||||
{
|
||||
hwaddr pcicfg = (bus ? 0xf1000c78 : 0xf1000cf8);
|
||||
hwaddr pcicfg = bus ? PCI1_CFG_ADDR : PCI0_CFG_ADDR;
|
||||
|
||||
stl_le_phys(as, pcicfg, addr | BIT(31));
|
||||
switch (len) {
|
||||
case 4:
|
||||
stl_le_phys(as, pcicfg + 4, val);
|
||||
break;
|
||||
case 2:
|
||||
stw_le_phys(as, pcicfg + 4, val);
|
||||
break;
|
||||
case 1:
|
||||
stb_phys(as, pcicfg + 4, val);
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid length\n", __func__);
|
||||
break;
|
||||
}
|
||||
pegasos2_mv_reg_write(pm, pcicfg, 4, addr | BIT(31));
|
||||
pegasos2_mv_reg_write(pm, pcicfg + 4, len, val);
|
||||
}
|
||||
|
||||
static void pegasos2_machine_reset(MachineState *machine)
|
||||
{
|
||||
Pegasos2MachineState *pm = PEGASOS2_MACHINE(machine);
|
||||
AddressSpace *as = CPU(pm->cpu)->as;
|
||||
void *fdt;
|
||||
uint64_t d[2];
|
||||
int sz;
|
||||
|
@ -256,51 +261,51 @@ static void pegasos2_machine_reset(MachineState *machine)
|
|||
}
|
||||
|
||||
/* Otherwise, set up devices that board firmware would normally do */
|
||||
stl_le_phys(as, 0xf1000000, 0x28020ff);
|
||||
stl_le_phys(as, 0xf1000278, 0xa31fc);
|
||||
stl_le_phys(as, 0xf100f300, 0x11ff0400);
|
||||
stl_le_phys(as, 0xf100f10c, 0x80000000);
|
||||
stl_le_phys(as, 0xf100001c, 0x8000000);
|
||||
pegasos2_pci_config_write(as, 0, PCI_COMMAND, 2, PCI_COMMAND_IO |
|
||||
pegasos2_mv_reg_write(pm, 0, 4, 0x28020ff);
|
||||
pegasos2_mv_reg_write(pm, 0x278, 4, 0xa31fc);
|
||||
pegasos2_mv_reg_write(pm, 0xf300, 4, 0x11ff0400);
|
||||
pegasos2_mv_reg_write(pm, 0xf10c, 4, 0x80000000);
|
||||
pegasos2_mv_reg_write(pm, 0x1c, 4, 0x8000000);
|
||||
pegasos2_pci_config_write(pm, 0, PCI_COMMAND, 2, PCI_COMMAND_IO |
|
||||
PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
|
||||
pegasos2_pci_config_write(as, 1, PCI_COMMAND, 2, PCI_COMMAND_IO |
|
||||
pegasos2_pci_config_write(pm, 1, PCI_COMMAND, 2, PCI_COMMAND_IO |
|
||||
PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
|
||||
|
||||
pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 0) << 8) |
|
||||
pegasos2_pci_config_write(pm, 1, (PCI_DEVFN(12, 0) << 8) |
|
||||
PCI_INTERRUPT_LINE, 2, 0x9);
|
||||
pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 0) << 8) |
|
||||
pegasos2_pci_config_write(pm, 1, (PCI_DEVFN(12, 0) << 8) |
|
||||
0x50, 1, 0x2);
|
||||
|
||||
pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 1) << 8) |
|
||||
pegasos2_pci_config_write(pm, 1, (PCI_DEVFN(12, 1) << 8) |
|
||||
PCI_INTERRUPT_LINE, 2, 0x109);
|
||||
pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 1) << 8) |
|
||||
pegasos2_pci_config_write(pm, 1, (PCI_DEVFN(12, 1) << 8) |
|
||||
PCI_CLASS_PROG, 1, 0xf);
|
||||
pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 1) << 8) |
|
||||
pegasos2_pci_config_write(pm, 1, (PCI_DEVFN(12, 1) << 8) |
|
||||
0x40, 1, 0xb);
|
||||
pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 1) << 8) |
|
||||
pegasos2_pci_config_write(pm, 1, (PCI_DEVFN(12, 1) << 8) |
|
||||
0x50, 4, 0x17171717);
|
||||
pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 1) << 8) |
|
||||
pegasos2_pci_config_write(pm, 1, (PCI_DEVFN(12, 1) << 8) |
|
||||
PCI_COMMAND, 2, 0x87);
|
||||
|
||||
pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 2) << 8) |
|
||||
pegasos2_pci_config_write(pm, 1, (PCI_DEVFN(12, 2) << 8) |
|
||||
PCI_INTERRUPT_LINE, 2, 0x409);
|
||||
|
||||
pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 3) << 8) |
|
||||
pegasos2_pci_config_write(pm, 1, (PCI_DEVFN(12, 3) << 8) |
|
||||
PCI_INTERRUPT_LINE, 2, 0x409);
|
||||
|
||||
pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 4) << 8) |
|
||||
pegasos2_pci_config_write(pm, 1, (PCI_DEVFN(12, 4) << 8) |
|
||||
PCI_INTERRUPT_LINE, 2, 0x9);
|
||||
pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 4) << 8) |
|
||||
pegasos2_pci_config_write(pm, 1, (PCI_DEVFN(12, 4) << 8) |
|
||||
0x48, 4, 0xf00);
|
||||
pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 4) << 8) |
|
||||
pegasos2_pci_config_write(pm, 1, (PCI_DEVFN(12, 4) << 8) |
|
||||
0x40, 4, 0x558020);
|
||||
pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 4) << 8) |
|
||||
pegasos2_pci_config_write(pm, 1, (PCI_DEVFN(12, 4) << 8) |
|
||||
0x90, 4, 0xd00);
|
||||
|
||||
pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 5) << 8) |
|
||||
pegasos2_pci_config_write(pm, 1, (PCI_DEVFN(12, 5) << 8) |
|
||||
PCI_INTERRUPT_LINE, 2, 0x309);
|
||||
|
||||
pegasos2_pci_config_write(as, 1, (PCI_DEVFN(12, 6) << 8) |
|
||||
pegasos2_pci_config_write(pm, 1, (PCI_DEVFN(12, 6) << 8) |
|
||||
PCI_INTERRUPT_LINE, 2, 0x309);
|
||||
|
||||
/* Device tree and VOF set up */
|
||||
|
@ -362,6 +367,29 @@ static target_ulong pegasos2_rtas(PowerPCCPU *cpu, Pegasos2MachineState *pm,
|
|||
return H_PARAMETER;
|
||||
}
|
||||
switch (token) {
|
||||
case RTAS_GET_TIME_OF_DAY:
|
||||
{
|
||||
QObject *qo = object_property_get_qobject(qdev_get_machine(),
|
||||
"rtc-time", &error_fatal);
|
||||
QDict *qd = qobject_to(QDict, qo);
|
||||
|
||||
if (nargs != 0 || nrets != 8 || !qd) {
|
||||
stl_be_phys(as, rets, -1);
|
||||
qobject_unref(qo);
|
||||
return H_PARAMETER;
|
||||
}
|
||||
|
||||
stl_be_phys(as, rets, 0);
|
||||
stl_be_phys(as, rets + 4, qdict_get_int(qd, "tm_year") + 1900);
|
||||
stl_be_phys(as, rets + 8, qdict_get_int(qd, "tm_mon") + 1);
|
||||
stl_be_phys(as, rets + 12, qdict_get_int(qd, "tm_mday"));
|
||||
stl_be_phys(as, rets + 16, qdict_get_int(qd, "tm_hour"));
|
||||
stl_be_phys(as, rets + 20, qdict_get_int(qd, "tm_min"));
|
||||
stl_be_phys(as, rets + 24, qdict_get_int(qd, "tm_sec"));
|
||||
stl_be_phys(as, rets + 28, 0);
|
||||
qobject_unref(qo);
|
||||
return H_SUCCESS;
|
||||
}
|
||||
case RTAS_READ_PCI_CONFIG:
|
||||
{
|
||||
uint32_t addr, len, val;
|
||||
|
@ -372,7 +400,7 @@ static target_ulong pegasos2_rtas(PowerPCCPU *cpu, Pegasos2MachineState *pm,
|
|||
}
|
||||
addr = ldl_be_phys(as, args);
|
||||
len = ldl_be_phys(as, args + 4);
|
||||
val = pegasos2_pci_config_read(as, !(addr >> 24),
|
||||
val = pegasos2_pci_config_read(pm, !(addr >> 24),
|
||||
addr & 0x0fffffff, len);
|
||||
stl_be_phys(as, rets, 0);
|
||||
stl_be_phys(as, rets + 4, val);
|
||||
|
@ -389,7 +417,7 @@ static target_ulong pegasos2_rtas(PowerPCCPU *cpu, Pegasos2MachineState *pm,
|
|||
addr = ldl_be_phys(as, args);
|
||||
len = ldl_be_phys(as, args + 4);
|
||||
val = ldl_be_phys(as, args + 8);
|
||||
pegasos2_pci_config_write(as, !(addr >> 24),
|
||||
pegasos2_pci_config_write(pm, !(addr >> 24),
|
||||
addr & 0x0fffffff, len, val);
|
||||
stl_be_phys(as, rets, 0);
|
||||
return H_SUCCESS;
|
||||
|
@ -402,6 +430,16 @@ static target_ulong pegasos2_rtas(PowerPCCPU *cpu, Pegasos2MachineState *pm,
|
|||
qemu_log_mask(LOG_UNIMP, "%c", ldl_be_phys(as, args));
|
||||
stl_be_phys(as, rets, 0);
|
||||
return H_SUCCESS;
|
||||
case RTAS_POWER_OFF:
|
||||
{
|
||||
if (nargs != 2 || nrets != 1) {
|
||||
stl_be_phys(as, rets, -1);
|
||||
return H_PARAMETER;
|
||||
}
|
||||
qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
|
||||
stl_be_phys(as, rets, 0);
|
||||
return H_SUCCESS;
|
||||
}
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "Unknown RTAS token %u (args=%u, rets=%u)\n",
|
||||
token, nargs, nrets);
|
||||
|
|
|
@ -336,6 +336,8 @@ void store_40x_dbcr0(CPUPPCState *env, uint32_t val)
|
|||
{
|
||||
PowerPCCPU *cpu = env_archcpu(env);
|
||||
|
||||
qemu_mutex_lock_iothread();
|
||||
|
||||
switch ((val >> 28) & 0x3) {
|
||||
case 0x0:
|
||||
/* No action */
|
||||
|
@ -353,6 +355,8 @@ void store_40x_dbcr0(CPUPPCState *env, uint32_t val)
|
|||
ppc40x_system_reset(cpu);
|
||||
break;
|
||||
}
|
||||
|
||||
qemu_mutex_unlock_iothread();
|
||||
}
|
||||
|
||||
/* PowerPC 40x internal IRQ controller */
|
||||
|
@ -848,7 +852,7 @@ static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
|
|||
* On MSB edge based DEC implementations the MSB going from 0 -> 1 triggers
|
||||
* an edge interrupt, so raise it here too.
|
||||
*/
|
||||
if ((signed_value < 3) ||
|
||||
if ((value < 3) ||
|
||||
((tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL) && signed_value < 0) ||
|
||||
((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED) && signed_value < 0
|
||||
&& signed_decr >= 0)) {
|
||||
|
|
|
@ -48,12 +48,14 @@ OBJECT_DECLARE_SIMPLE_TYPE(PPC4xxPCIState, PPC4xx_PCI_HOST_BRIDGE)
|
|||
#define PPC4xx_PCI_NR_PMMS 3
|
||||
#define PPC4xx_PCI_NR_PTMS 2
|
||||
|
||||
#define PPC4xx_PCI_NUM_DEVS 5
|
||||
|
||||
struct PPC4xxPCIState {
|
||||
PCIHostState parent_obj;
|
||||
|
||||
struct PCIMasterMap pmm[PPC4xx_PCI_NR_PMMS];
|
||||
struct PCITargetMap ptm[PPC4xx_PCI_NR_PTMS];
|
||||
qemu_irq irq[PCI_NUM_PINS];
|
||||
qemu_irq irq[PPC4xx_PCI_NUM_DEVS];
|
||||
|
||||
MemoryRegion container;
|
||||
MemoryRegion iomem;
|
||||
|
@ -246,7 +248,7 @@ static int ppc4xx_pci_map_irq(PCIDevice *pci_dev, int irq_num)
|
|||
|
||||
trace_ppc4xx_pci_map_irq(pci_dev->devfn, irq_num, slot);
|
||||
|
||||
return slot - 1;
|
||||
return slot > 0 ? slot - 1 : PPC4xx_PCI_NUM_DEVS - 1;
|
||||
}
|
||||
|
||||
static void ppc4xx_pci_set_irq(void *opaque, int irq_num, int level)
|
||||
|
@ -254,7 +256,7 @@ static void ppc4xx_pci_set_irq(void *opaque, int irq_num, int level)
|
|||
qemu_irq *pci_irqs = opaque;
|
||||
|
||||
trace_ppc4xx_pci_set_irq(irq_num);
|
||||
assert(irq_num >= 0);
|
||||
assert(irq_num >= 0 && irq_num < PPC4xx_PCI_NUM_DEVS);
|
||||
qemu_set_irq(pci_irqs[irq_num], level);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,25 +1,10 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qapi/error.h"
|
||||
#include "sysemu/hw_accel.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "cpu.h"
|
||||
#include "exec/exec-all.h"
|
||||
#include "helper_regs.h"
|
||||
#include "hw/ppc/spapr.h"
|
||||
#include "hw/ppc/spapr_cpu_core.h"
|
||||
#include "mmu-hash64.h"
|
||||
#include "cpu-models.h"
|
||||
#include "trace.h"
|
||||
#include "kvm_ppc.h"
|
||||
#include "hw/ppc/fdt.h"
|
||||
#include "hw/ppc/spapr_ovec.h"
|
||||
#include "mmu-book3s-v3.h"
|
||||
#include "hw/mem/memory-device.h"
|
||||
|
||||
static inline bool valid_ptex(PowerPCCPU *cpu, target_ulong ptex)
|
||||
{
|
||||
|
|
|
@ -286,6 +286,30 @@ uint8_t xive_esb_set(uint8_t *pq, uint8_t value);
|
|||
uint8_t xive_source_esb_get(XiveSource *xsrc, uint32_t srcno);
|
||||
uint8_t xive_source_esb_set(XiveSource *xsrc, uint32_t srcno, uint8_t pq);
|
||||
|
||||
/*
|
||||
* Source status helpers
|
||||
*/
|
||||
static inline void xive_source_set_status(XiveSource *xsrc, uint32_t srcno,
|
||||
uint8_t status, bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
xsrc->status[srcno] |= status;
|
||||
} else {
|
||||
xsrc->status[srcno] &= ~status;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void xive_source_set_asserted(XiveSource *xsrc, uint32_t srcno,
|
||||
bool enable)
|
||||
{
|
||||
xive_source_set_status(xsrc, srcno, XIVE_STATUS_ASSERTED, enable);
|
||||
}
|
||||
|
||||
static inline bool xive_source_is_asserted(XiveSource *xsrc, uint32_t srcno)
|
||||
{
|
||||
return xsrc->status[srcno] & XIVE_STATUS_ASSERTED;
|
||||
}
|
||||
|
||||
void xive_source_pic_print_info(XiveSource *xsrc, uint32_t offset,
|
||||
Monitor *mon);
|
||||
|
||||
|
|
|
@ -901,7 +901,7 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUPPCState *en
|
|||
(*regs)[33] = tswapreg(env->msr);
|
||||
(*regs)[35] = tswapreg(env->ctr);
|
||||
(*regs)[36] = tswapreg(env->lr);
|
||||
(*regs)[37] = tswapreg(env->xer);
|
||||
(*regs)[37] = tswapreg(cpu_read_xer(env));
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
|
||||
ccr |= env->crf[i] << (32 - ((i + 1) * 4));
|
||||
|
|
|
@ -242,7 +242,7 @@ static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame)
|
|||
__put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]);
|
||||
__put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]);
|
||||
__put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]);
|
||||
__put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]);
|
||||
__put_user(cpu_read_xer(env), &frame->mc_gregs[TARGET_PT_XER]);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
|
||||
ccr |= env->crf[i] << (32 - ((i + 1) * 4));
|
||||
|
@ -315,6 +315,7 @@ static void restore_user_regs(CPUPPCState *env,
|
|||
{
|
||||
target_ulong save_r2 = 0;
|
||||
target_ulong msr;
|
||||
target_ulong xer;
|
||||
target_ulong ccr;
|
||||
|
||||
int i;
|
||||
|
@ -330,9 +331,11 @@ static void restore_user_regs(CPUPPCState *env,
|
|||
__get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP]);
|
||||
__get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR]);
|
||||
__get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK]);
|
||||
__get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]);
|
||||
__get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
|
||||
|
||||
__get_user(xer, &frame->mc_gregs[TARGET_PT_XER]);
|
||||
cpu_write_xer(env, xer);
|
||||
|
||||
__get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
|
||||
for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
|
||||
env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include "helper_regs.h"
|
||||
#include "sysemu/tcg.h"
|
||||
|
||||
target_ulong cpu_read_xer(CPUPPCState *env)
|
||||
target_ulong cpu_read_xer(const CPUPPCState *env)
|
||||
{
|
||||
if (is_isa300(env)) {
|
||||
return env->xer | (env->so << XER_SO) |
|
||||
|
|
|
@ -314,6 +314,7 @@ typedef struct ppc_v3_pate_t {
|
|||
#define MSR_AP 23 /* Access privilege state on 602 hflags */
|
||||
#define MSR_VSX 23 /* Vector Scalar Extension (ISA 2.06 and later) x hflags */
|
||||
#define MSR_SA 22 /* Supervisor access mode on 602 hflags */
|
||||
#define MSR_S 22 /* Secure state */
|
||||
#define MSR_KEY 19 /* key bit on 603e */
|
||||
#define MSR_POW 18 /* Power management */
|
||||
#define MSR_TGPR 17 /* TGPR usage on 602/603 x */
|
||||
|
@ -342,6 +343,26 @@ typedef struct ppc_v3_pate_t {
|
|||
#define MSR_RI 1 /* Recoverable interrupt 1 */
|
||||
#define MSR_LE 0 /* Little-endian mode 1 hflags */
|
||||
|
||||
/* PMU bits */
|
||||
#define MMCR0_FC PPC_BIT(32) /* Freeze Counters */
|
||||
#define MMCR0_PMAO PPC_BIT(56) /* Perf Monitor Alert Ocurred */
|
||||
#define MMCR0_PMAE PPC_BIT(37) /* Perf Monitor Alert Enable */
|
||||
#define MMCR0_EBE PPC_BIT(43) /* Perf Monitor EBB Enable */
|
||||
#define MMCR0_FCECE PPC_BIT(38) /* FC on Enabled Cond or Event */
|
||||
#define MMCR0_PMCC0 PPC_BIT(44) /* PMC Control bit 0 */
|
||||
#define MMCR0_PMCC1 PPC_BIT(45) /* PMC Control bit 1 */
|
||||
/* MMCR0 userspace r/w mask */
|
||||
#define MMCR0_UREG_MASK (MMCR0_FC | MMCR0_PMAO | MMCR0_PMAE)
|
||||
/* MMCR2 userspace r/w mask */
|
||||
#define MMCR2_FC1P0 PPC_BIT(1) /* MMCR2 FCnP0 for PMC1 */
|
||||
#define MMCR2_FC2P0 PPC_BIT(10) /* MMCR2 FCnP0 for PMC2 */
|
||||
#define MMCR2_FC3P0 PPC_BIT(19) /* MMCR2 FCnP0 for PMC3 */
|
||||
#define MMCR2_FC4P0 PPC_BIT(28) /* MMCR2 FCnP0 for PMC4 */
|
||||
#define MMCR2_FC5P0 PPC_BIT(37) /* MMCR2 FCnP0 for PMC5 */
|
||||
#define MMCR2_FC6P0 PPC_BIT(46) /* MMCR2 FCnP0 for PMC6 */
|
||||
#define MMCR2_UREG_MASK (MMCR2_FC1P0 | MMCR2_FC2P0 | MMCR2_FC3P0 | \
|
||||
MMCR2_FC4P0 | MMCR2_FC5P0 | MMCR2_FC6P0)
|
||||
|
||||
/* LPCR bits */
|
||||
#define LPCR_VPM0 PPC_BIT(0)
|
||||
#define LPCR_VPM1 PPC_BIT(1)
|
||||
|
@ -607,6 +628,8 @@ enum {
|
|||
HFLAGS_SE = 10, /* MSR_SE -- from elsewhere on embedded ppc */
|
||||
HFLAGS_FP = 13, /* MSR_FP */
|
||||
HFLAGS_PR = 14, /* MSR_PR */
|
||||
HFLAGS_PMCC0 = 15, /* MMCR0 PMCC bit 0 */
|
||||
HFLAGS_PMCC1 = 16, /* MMCR0 PMCC bit 1 */
|
||||
HFLAGS_VSX = 23, /* MSR_VSX if cpu has VSX */
|
||||
HFLAGS_VR = 25, /* MSR_VR if cpu has VRE */
|
||||
|
||||
|
@ -2412,7 +2435,7 @@ enum {
|
|||
/*****************************************************************************/
|
||||
|
||||
#define is_isa300(ctx) (!!(ctx->insns_flags2 & PPC2_ISA300))
|
||||
target_ulong cpu_read_xer(CPUPPCState *env);
|
||||
target_ulong cpu_read_xer(const CPUPPCState *env);
|
||||
void cpu_write_xer(CPUPPCState *env, target_ulong xer);
|
||||
|
||||
/*
|
||||
|
|
|
@ -6867,7 +6867,7 @@ static void register_book3s_pmu_sup_sprs(CPUPPCState *env)
|
|||
static void register_book3s_pmu_user_sprs(CPUPPCState *env)
|
||||
{
|
||||
spr_register(env, SPR_POWER_UMMCR0, "UMMCR0",
|
||||
&spr_read_ureg, SPR_NOACCESS,
|
||||
&spr_read_MMCR0_ureg, &spr_write_MMCR0_ureg,
|
||||
&spr_read_ureg, &spr_write_ureg,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_POWER_UMMCR1, "UMMCR1",
|
||||
|
@ -6879,27 +6879,27 @@ static void register_book3s_pmu_user_sprs(CPUPPCState *env)
|
|||
&spr_read_ureg, &spr_write_ureg,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_POWER_UPMC1, "UPMC1",
|
||||
&spr_read_ureg, SPR_NOACCESS,
|
||||
&spr_read_PMC14_ureg, &spr_write_PMC14_ureg,
|
||||
&spr_read_ureg, &spr_write_ureg,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_POWER_UPMC2, "UPMC2",
|
||||
&spr_read_ureg, SPR_NOACCESS,
|
||||
&spr_read_PMC14_ureg, &spr_write_PMC14_ureg,
|
||||
&spr_read_ureg, &spr_write_ureg,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_POWER_UPMC3, "UPMC3",
|
||||
&spr_read_ureg, SPR_NOACCESS,
|
||||
&spr_read_PMC14_ureg, &spr_write_PMC14_ureg,
|
||||
&spr_read_ureg, &spr_write_ureg,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_POWER_UPMC4, "UPMC4",
|
||||
&spr_read_ureg, SPR_NOACCESS,
|
||||
&spr_read_PMC14_ureg, &spr_write_PMC14_ureg,
|
||||
&spr_read_ureg, &spr_write_ureg,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_POWER_UPMC5, "UPMC5",
|
||||
&spr_read_ureg, SPR_NOACCESS,
|
||||
&spr_read_PMC56_ureg, &spr_write_PMC56_ureg,
|
||||
&spr_read_ureg, &spr_write_ureg,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_POWER_UPMC6, "UPMC6",
|
||||
&spr_read_ureg, SPR_NOACCESS,
|
||||
&spr_read_PMC56_ureg, &spr_write_PMC56_ureg,
|
||||
&spr_read_ureg, &spr_write_ureg,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_POWER_USIAR, "USIAR",
|
||||
|
@ -6975,7 +6975,7 @@ static void register_power8_pmu_sup_sprs(CPUPPCState *env)
|
|||
static void register_power8_pmu_user_sprs(CPUPPCState *env)
|
||||
{
|
||||
spr_register(env, SPR_POWER_UMMCR2, "UMMCR2",
|
||||
&spr_read_ureg, SPR_NOACCESS,
|
||||
&spr_read_MMCR2_ureg, &spr_write_MMCR2_ureg,
|
||||
&spr_read_ureg, &spr_write_ureg,
|
||||
0x00000000);
|
||||
spr_register(env, SPR_POWER_USIER, "USIER",
|
||||
|
|
|
@ -159,7 +159,7 @@ int ppc_cpu_gdb_read_register(CPUState *cs, GByteArray *buf, int n)
|
|||
gdb_get_regl(buf, env->ctr);
|
||||
break;
|
||||
case 69:
|
||||
gdb_get_reg32(buf, env->xer);
|
||||
gdb_get_reg32(buf, cpu_read_xer(env));
|
||||
break;
|
||||
case 70:
|
||||
gdb_get_reg32(buf, env->fpscr);
|
||||
|
@ -217,7 +217,7 @@ int ppc_cpu_gdb_read_register_apple(CPUState *cs, GByteArray *buf, int n)
|
|||
gdb_get_reg64(buf, env->ctr);
|
||||
break;
|
||||
case 69 + 32:
|
||||
gdb_get_reg32(buf, env->xer);
|
||||
gdb_get_reg32(buf, cpu_read_xer(env));
|
||||
break;
|
||||
case 70 + 32:
|
||||
gdb_get_reg64(buf, env->fpscr);
|
||||
|
@ -269,7 +269,7 @@ int ppc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
|
|||
env->ctr = ldtul_p(mem_buf);
|
||||
break;
|
||||
case 69:
|
||||
env->xer = ldl_p(mem_buf);
|
||||
cpu_write_xer(env, ldl_p(mem_buf));
|
||||
break;
|
||||
case 70:
|
||||
/* fpscr */
|
||||
|
@ -319,7 +319,7 @@ int ppc_cpu_gdb_write_register_apple(CPUState *cs, uint8_t *mem_buf, int n)
|
|||
env->ctr = ldq_p(mem_buf);
|
||||
break;
|
||||
case 69 + 32:
|
||||
env->xer = ldl_p(mem_buf);
|
||||
cpu_write_xer(env, ldl_p(mem_buf));
|
||||
break;
|
||||
case 70 + 32:
|
||||
/* fpscr */
|
||||
|
|
|
@ -109,6 +109,12 @@ static uint32_t hreg_compute_hflags_value(CPUPPCState *env)
|
|||
if (env->spr[SPR_LPCR] & LPCR_HR) {
|
||||
hflags |= 1 << HFLAGS_HR;
|
||||
}
|
||||
if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCC0) {
|
||||
hflags |= 1 << HFLAGS_PMCC0;
|
||||
}
|
||||
if (env->spr[SPR_POWER_MMCR0] & MMCR0_PMCC1) {
|
||||
hflags |= 1 << HFLAGS_PMCC1;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
if (!env->has_hv_mode || (msr & (1ull << MSR_HV))) {
|
||||
|
|
|
@ -44,6 +44,13 @@ static target_long monitor_get_ccr(Monitor *mon, const struct MonitorDef *md,
|
|||
return u;
|
||||
}
|
||||
|
||||
static target_long monitor_get_xer(Monitor *mon, const struct MonitorDef *md,
|
||||
int val)
|
||||
{
|
||||
CPUArchState *env = mon_get_cpu_env(mon);
|
||||
return cpu_read_xer(env);
|
||||
}
|
||||
|
||||
static target_long monitor_get_decr(Monitor *mon, const struct MonitorDef *md,
|
||||
int val)
|
||||
{
|
||||
|
@ -85,7 +92,7 @@ const MonitorDef monitor_defs[] = {
|
|||
{ "decr", 0, &monitor_get_decr, },
|
||||
{ "ccr|cr", 0, &monitor_get_ccr, },
|
||||
/* Machine state register */
|
||||
{ "xer", offsetof(CPUPPCState, xer) },
|
||||
{ "xer", 0, &monitor_get_xer },
|
||||
{ "msr", offsetof(CPUPPCState, msr) },
|
||||
{ "tbu", 0, &monitor_get_tbu, },
|
||||
{ "tbl", 0, &monitor_get_tbl, },
|
||||
|
|
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
* PMU register read/write functions for TCG IBM POWER chips
|
||||
*
|
||||
* Copyright IBM Corp. 2021
|
||||
*
|
||||
* Authors:
|
||||
* Daniel Henrique Barboza <danielhb413@gmail.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
|
||||
|
||||
/*
|
||||
* Checks whether the Group A SPR (MMCR0, MMCR2, MMCRA, and the
|
||||
* PMCs) has problem state read access.
|
||||
*
|
||||
* Read acccess is granted for all PMCC values but 0b01, where a
|
||||
* Facility Unavailable Interrupt will occur.
|
||||
*/
|
||||
static bool spr_groupA_read_allowed(DisasContext *ctx)
|
||||
{
|
||||
if (!ctx->mmcr0_pmcc0 && ctx->mmcr0_pmcc1) {
|
||||
gen_hvpriv_exception(ctx, POWERPC_EXCP_FU);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks whether the Group A SPR (MMCR0, MMCR2, MMCRA, and the
|
||||
* PMCs) has problem state write access.
|
||||
*
|
||||
* Write acccess is granted for PMCC values 0b10 and 0b11. Userspace
|
||||
* writing with PMCC 0b00 will generate a Hypervisor Emulation
|
||||
* Assistance Interrupt. Userspace writing with PMCC 0b01 will
|
||||
* generate a Facility Unavailable Interrupt.
|
||||
*/
|
||||
static bool spr_groupA_write_allowed(DisasContext *ctx)
|
||||
{
|
||||
if (ctx->mmcr0_pmcc0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ctx->mmcr0_pmcc1) {
|
||||
/* PMCC = 0b01 */
|
||||
gen_hvpriv_exception(ctx, POWERPC_EXCP_FU);
|
||||
} else {
|
||||
/* PMCC = 0b00 */
|
||||
gen_hvpriv_exception(ctx, POWERPC_EXCP_INVAL_SPR);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function to avoid code repetition between MMCR0 and
|
||||
* MMCR2 problem state write functions.
|
||||
*
|
||||
* 'ret' must be tcg_temp_freed() by the caller.
|
||||
*/
|
||||
static TCGv masked_gprn_for_spr_write(int gprn, int sprn,
|
||||
uint64_t spr_mask)
|
||||
{
|
||||
TCGv ret = tcg_temp_new();
|
||||
TCGv t0 = tcg_temp_new();
|
||||
|
||||
/* 'ret' starts with all mask bits cleared */
|
||||
gen_load_spr(ret, sprn);
|
||||
tcg_gen_andi_tl(ret, ret, ~(spr_mask));
|
||||
|
||||
/* Apply the mask into 'gprn' in a temp var */
|
||||
tcg_gen_andi_tl(t0, cpu_gpr[gprn], spr_mask);
|
||||
|
||||
/* Add the masked gprn bits into 'ret' */
|
||||
tcg_gen_or_tl(ret, ret, t0);
|
||||
|
||||
tcg_temp_free(t0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void spr_read_MMCR0_ureg(DisasContext *ctx, int gprn, int sprn)
|
||||
{
|
||||
TCGv t0;
|
||||
|
||||
if (!spr_groupA_read_allowed(ctx)) {
|
||||
return;
|
||||
}
|
||||
|
||||
t0 = tcg_temp_new();
|
||||
|
||||
/*
|
||||
* Filter out all bits but FC, PMAO, and PMAE, according
|
||||
* to ISA v3.1, in 10.4.4 Monitor Mode Control Register 0,
|
||||
* fourth paragraph.
|
||||
*/
|
||||
gen_load_spr(t0, SPR_POWER_MMCR0);
|
||||
tcg_gen_andi_tl(t0, t0, MMCR0_UREG_MASK);
|
||||
tcg_gen_mov_tl(cpu_gpr[gprn], t0);
|
||||
|
||||
tcg_temp_free(t0);
|
||||
}
|
||||
|
||||
void spr_write_MMCR0_ureg(DisasContext *ctx, int sprn, int gprn)
|
||||
{
|
||||
TCGv masked_gprn;
|
||||
|
||||
if (!spr_groupA_write_allowed(ctx)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Filter out all bits but FC, PMAO, and PMAE, according
|
||||
* to ISA v3.1, in 10.4.4 Monitor Mode Control Register 0,
|
||||
* fourth paragraph.
|
||||
*/
|
||||
masked_gprn = masked_gprn_for_spr_write(gprn, SPR_POWER_MMCR0,
|
||||
MMCR0_UREG_MASK);
|
||||
gen_store_spr(SPR_POWER_MMCR0, masked_gprn);
|
||||
|
||||
tcg_temp_free(masked_gprn);
|
||||
}
|
||||
|
||||
void spr_read_MMCR2_ureg(DisasContext *ctx, int gprn, int sprn)
|
||||
{
|
||||
TCGv t0;
|
||||
|
||||
if (!spr_groupA_read_allowed(ctx)) {
|
||||
return;
|
||||
}
|
||||
|
||||
t0 = tcg_temp_new();
|
||||
|
||||
/*
|
||||
* On read, filter out all bits that are not FCnP0 bits.
|
||||
* When MMCR0[PMCC] is set to 0b10 or 0b11, providing
|
||||
* problem state programs read/write access to MMCR2,
|
||||
* only the FCnP0 bits can be accessed. All other bits are
|
||||
* not changed when mtspr is executed in problem state, and
|
||||
* all other bits return 0s when mfspr is executed in problem
|
||||
* state, according to ISA v3.1, section 10.4.6 Monitor Mode
|
||||
* Control Register 2, p. 1316, third paragraph.
|
||||
*/
|
||||
gen_load_spr(t0, SPR_POWER_MMCR2);
|
||||
tcg_gen_andi_tl(t0, t0, MMCR2_UREG_MASK);
|
||||
tcg_gen_mov_tl(cpu_gpr[gprn], t0);
|
||||
|
||||
tcg_temp_free(t0);
|
||||
}
|
||||
|
||||
void spr_write_MMCR2_ureg(DisasContext *ctx, int sprn, int gprn)
|
||||
{
|
||||
TCGv masked_gprn;
|
||||
|
||||
if (!spr_groupA_write_allowed(ctx)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Filter the bits that can be written using MMCR2_UREG_MASK,
|
||||
* similar to what is done in spr_write_MMCR0_ureg().
|
||||
*/
|
||||
masked_gprn = masked_gprn_for_spr_write(gprn, SPR_POWER_MMCR2,
|
||||
MMCR2_UREG_MASK);
|
||||
gen_store_spr(SPR_POWER_MMCR2, masked_gprn);
|
||||
|
||||
tcg_temp_free(masked_gprn);
|
||||
}
|
||||
|
||||
void spr_read_PMC14_ureg(DisasContext *ctx, int gprn, int sprn)
|
||||
{
|
||||
if (!spr_groupA_read_allowed(ctx)) {
|
||||
return;
|
||||
}
|
||||
|
||||
spr_read_ureg(ctx, gprn, sprn);
|
||||
}
|
||||
|
||||
void spr_read_PMC56_ureg(DisasContext *ctx, int gprn, int sprn)
|
||||
{
|
||||
/*
|
||||
* If PMCC = 0b11, PMC5 and PMC6 aren't included in the Performance
|
||||
* Monitor, and a read attempt results in a Facility Unavailable
|
||||
* Interrupt.
|
||||
*/
|
||||
if (ctx->mmcr0_pmcc0 && ctx->mmcr0_pmcc1) {
|
||||
gen_hvpriv_exception(ctx, POWERPC_EXCP_FU);
|
||||
return;
|
||||
}
|
||||
|
||||
/* The remaining steps are similar to PMCs 1-4 userspace read */
|
||||
spr_read_PMC14_ureg(ctx, gprn, sprn);
|
||||
}
|
||||
|
||||
void spr_write_PMC14_ureg(DisasContext *ctx, int sprn, int gprn)
|
||||
{
|
||||
if (!spr_groupA_write_allowed(ctx)) {
|
||||
return;
|
||||
}
|
||||
|
||||
spr_write_ureg(ctx, sprn, gprn);
|
||||
}
|
||||
|
||||
void spr_write_PMC56_ureg(DisasContext *ctx, int sprn, int gprn)
|
||||
{
|
||||
/*
|
||||
* If PMCC = 0b11, PMC5 and PMC6 aren't included in the Performance
|
||||
* Monitor, and a write attempt results in a Facility Unavailable
|
||||
* Interrupt.
|
||||
*/
|
||||
if (ctx->mmcr0_pmcc0 && ctx->mmcr0_pmcc1) {
|
||||
gen_hvpriv_exception(ctx, POWERPC_EXCP_FU);
|
||||
return;
|
||||
}
|
||||
|
||||
/* The remaining steps are similar to PMCs 1-4 userspace write */
|
||||
spr_write_PMC14_ureg(ctx, sprn, gprn);
|
||||
}
|
||||
#else
|
||||
void spr_read_MMCR0_ureg(DisasContext *ctx, int gprn, int sprn)
|
||||
{
|
||||
spr_read_ureg(ctx, gprn, sprn);
|
||||
}
|
||||
|
||||
void spr_write_MMCR0_ureg(DisasContext *ctx, int sprn, int gprn)
|
||||
{
|
||||
spr_noaccess(ctx, gprn, sprn);
|
||||
}
|
||||
|
||||
void spr_read_MMCR2_ureg(DisasContext *ctx, int gprn, int sprn)
|
||||
{
|
||||
spr_read_ureg(ctx, gprn, sprn);
|
||||
}
|
||||
|
||||
void spr_write_MMCR2_ureg(DisasContext *ctx, int sprn, int gprn)
|
||||
{
|
||||
spr_noaccess(ctx, gprn, sprn);
|
||||
}
|
||||
|
||||
void spr_read_PMC14_ureg(DisasContext *ctx, int gprn, int sprn)
|
||||
{
|
||||
spr_read_ureg(ctx, gprn, sprn);
|
||||
}
|
||||
|
||||
void spr_read_PMC56_ureg(DisasContext *ctx, int gprn, int sprn)
|
||||
{
|
||||
spr_read_ureg(ctx, gprn, sprn);
|
||||
}
|
||||
|
||||
void spr_write_PMC14_ureg(DisasContext *ctx, int sprn, int gprn)
|
||||
{
|
||||
spr_noaccess(ctx, gprn, sprn);
|
||||
}
|
||||
|
||||
void spr_write_PMC56_ureg(DisasContext *ctx, int sprn, int gprn)
|
||||
{
|
||||
spr_noaccess(ctx, gprn, sprn);
|
||||
}
|
||||
#endif /* defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY) */
|
|
@ -32,6 +32,10 @@ void spr_write_lr(DisasContext *ctx, int sprn, int gprn);
|
|||
void spr_read_ctr(DisasContext *ctx, int gprn, int sprn);
|
||||
void spr_write_ctr(DisasContext *ctx, int sprn, int gprn);
|
||||
void spr_read_ureg(DisasContext *ctx, int gprn, int sprn);
|
||||
void spr_read_MMCR0_ureg(DisasContext *ctx, int gprn, int sprn);
|
||||
void spr_read_MMCR2_ureg(DisasContext *ctx, int gprn, int sprn);
|
||||
void spr_read_PMC14_ureg(DisasContext *ctx, int gprn, int sprn);
|
||||
void spr_read_PMC56_ureg(DisasContext *ctx, int gprn, int sprn);
|
||||
void spr_read_tbl(DisasContext *ctx, int gprn, int sprn);
|
||||
void spr_read_tbu(DisasContext *ctx, int gprn, int sprn);
|
||||
void spr_read_atbl(DisasContext *ctx, int gprn, int sprn);
|
||||
|
@ -40,6 +44,10 @@ void spr_read_601_rtcl(DisasContext *ctx, int gprn, int sprn);
|
|||
void spr_read_601_rtcu(DisasContext *ctx, int gprn, int sprn);
|
||||
void spr_read_spefscr(DisasContext *ctx, int gprn, int sprn);
|
||||
void spr_write_spefscr(DisasContext *ctx, int sprn, int gprn);
|
||||
void spr_write_MMCR0_ureg(DisasContext *ctx, int sprn, int gprn);
|
||||
void spr_write_MMCR2_ureg(DisasContext *ctx, int sprn, int gprn);
|
||||
void spr_write_PMC14_ureg(DisasContext *ctx, int sprn, int gprn);
|
||||
void spr_write_PMC56_ureg(DisasContext *ctx, int sprn, int gprn);
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
void spr_write_generic32(DisasContext *ctx, int sprn, int gprn);
|
||||
|
|
|
@ -175,6 +175,8 @@ struct DisasContext {
|
|||
bool tm_enabled;
|
||||
bool gtse;
|
||||
bool hr;
|
||||
bool mmcr0_pmcc0;
|
||||
bool mmcr0_pmcc1;
|
||||
ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
|
||||
int singlestep_enabled;
|
||||
uint32_t flags;
|
||||
|
@ -4934,32 +4936,40 @@ static void gen_mtmsrd(DisasContext *ctx)
|
|||
CHK_SV;
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
TCGv t0, t1;
|
||||
target_ulong mask;
|
||||
|
||||
t0 = tcg_temp_new();
|
||||
t1 = tcg_temp_new();
|
||||
|
||||
gen_icount_io_start(ctx);
|
||||
|
||||
if (ctx->opcode & 0x00010000) {
|
||||
/* L=1 form only updates EE and RI */
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)],
|
||||
(1 << MSR_RI) | (1 << MSR_EE));
|
||||
tcg_gen_andi_tl(t1, cpu_msr,
|
||||
~(target_ulong)((1 << MSR_RI) | (1 << MSR_EE)));
|
||||
tcg_gen_or_tl(t1, t1, t0);
|
||||
|
||||
gen_helper_store_msr(cpu_env, t1);
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
|
||||
mask = (1ULL << MSR_RI) | (1ULL << MSR_EE);
|
||||
} else {
|
||||
/* mtmsrd does not alter HV, S, ME, or LE */
|
||||
mask = ~((1ULL << MSR_LE) | (1ULL << MSR_ME) | (1ULL << MSR_S) |
|
||||
(1ULL << MSR_HV));
|
||||
/*
|
||||
* XXX: we need to update nip before the store if we enter
|
||||
* power saving mode, we will exit the loop directly from
|
||||
* ppc_store_msr
|
||||
*/
|
||||
gen_update_nip(ctx, ctx->base.pc_next);
|
||||
gen_helper_store_msr(cpu_env, cpu_gpr[rS(ctx->opcode)]);
|
||||
}
|
||||
|
||||
tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], mask);
|
||||
tcg_gen_andi_tl(t1, cpu_msr, ~mask);
|
||||
tcg_gen_or_tl(t0, t0, t1);
|
||||
|
||||
gen_helper_store_msr(cpu_env, t0);
|
||||
|
||||
/* Must stop the translation as machine state (may have) changed */
|
||||
ctx->base.is_jmp = DISAS_EXIT_UPDATE;
|
||||
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
#endif /* !defined(CONFIG_USER_ONLY) */
|
||||
}
|
||||
#endif /* defined(TARGET_PPC64) */
|
||||
|
@ -4969,23 +4979,19 @@ static void gen_mtmsr(DisasContext *ctx)
|
|||
CHK_SV;
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
TCGv t0, t1;
|
||||
target_ulong mask = 0xFFFFFFFF;
|
||||
|
||||
t0 = tcg_temp_new();
|
||||
t1 = tcg_temp_new();
|
||||
|
||||
gen_icount_io_start(ctx);
|
||||
if (ctx->opcode & 0x00010000) {
|
||||
/* L=1 form only updates EE and RI */
|
||||
TCGv t0 = tcg_temp_new();
|
||||
TCGv t1 = tcg_temp_new();
|
||||
tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)],
|
||||
(1 << MSR_RI) | (1 << MSR_EE));
|
||||
tcg_gen_andi_tl(t1, cpu_msr,
|
||||
~(target_ulong)((1 << MSR_RI) | (1 << MSR_EE)));
|
||||
tcg_gen_or_tl(t1, t1, t0);
|
||||
|
||||
gen_helper_store_msr(cpu_env, t1);
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
|
||||
mask &= (1ULL << MSR_RI) | (1ULL << MSR_EE);
|
||||
} else {
|
||||
TCGv msr = tcg_temp_new();
|
||||
/* mtmsr does not alter S, ME, or LE */
|
||||
mask &= ~((1ULL << MSR_LE) | (1ULL << MSR_ME) | (1ULL << MSR_S));
|
||||
|
||||
/*
|
||||
* XXX: we need to update nip before the store if we enter
|
||||
|
@ -4993,16 +4999,19 @@ static void gen_mtmsr(DisasContext *ctx)
|
|||
* ppc_store_msr
|
||||
*/
|
||||
gen_update_nip(ctx, ctx->base.pc_next);
|
||||
#if defined(TARGET_PPC64)
|
||||
tcg_gen_deposit_tl(msr, cpu_msr, cpu_gpr[rS(ctx->opcode)], 0, 32);
|
||||
#else
|
||||
tcg_gen_mov_tl(msr, cpu_gpr[rS(ctx->opcode)]);
|
||||
#endif
|
||||
gen_helper_store_msr(cpu_env, msr);
|
||||
tcg_temp_free(msr);
|
||||
}
|
||||
|
||||
tcg_gen_andi_tl(t0, cpu_gpr[rS(ctx->opcode)], mask);
|
||||
tcg_gen_andi_tl(t1, cpu_msr, ~mask);
|
||||
tcg_gen_or_tl(t0, t0, t1);
|
||||
|
||||
gen_helper_store_msr(cpu_env, t0);
|
||||
|
||||
/* Must stop the translation as machine state (may have) changed */
|
||||
ctx->base.is_jmp = DISAS_EXIT_UPDATE;
|
||||
|
||||
tcg_temp_free(t0);
|
||||
tcg_temp_free(t1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -5068,19 +5077,15 @@ static void gen_mtspr(DisasContext *ctx)
|
|||
static void gen_setb(DisasContext *ctx)
|
||||
{
|
||||
TCGv_i32 t0 = tcg_temp_new_i32();
|
||||
TCGv_i32 t8 = tcg_temp_new_i32();
|
||||
TCGv_i32 tm1 = tcg_temp_new_i32();
|
||||
TCGv_i32 t8 = tcg_constant_i32(8);
|
||||
TCGv_i32 tm1 = tcg_constant_i32(-1);
|
||||
int crf = crfS(ctx->opcode);
|
||||
|
||||
tcg_gen_setcondi_i32(TCG_COND_GEU, t0, cpu_crf[crf], 4);
|
||||
tcg_gen_movi_i32(t8, 8);
|
||||
tcg_gen_movi_i32(tm1, -1);
|
||||
tcg_gen_movcond_i32(TCG_COND_GEU, t0, cpu_crf[crf], t8, tm1, t0);
|
||||
tcg_gen_ext_i32_tl(cpu_gpr[rD(ctx->opcode)], t0);
|
||||
|
||||
tcg_temp_free_i32(t0);
|
||||
tcg_temp_free_i32(t8);
|
||||
tcg_temp_free_i32(tm1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -7481,6 +7486,8 @@ static int times_4(DisasContext *ctx, int x)
|
|||
|
||||
#include "decode-insn32.c.inc"
|
||||
#include "decode-insn64.c.inc"
|
||||
#include "power8-pmu-regs.c.inc"
|
||||
|
||||
#include "translate/fixedpoint-impl.c.inc"
|
||||
|
||||
#include "translate/fp-impl.c.inc"
|
||||
|
@ -7573,18 +7580,16 @@ static void gen_brw(DisasContext *ctx)
|
|||
/* brh */
|
||||
static void gen_brh(DisasContext *ctx)
|
||||
{
|
||||
TCGv_i64 t0 = tcg_temp_new_i64();
|
||||
TCGv_i64 mask = tcg_constant_i64(0x00ff00ff00ff00ffull);
|
||||
TCGv_i64 t1 = tcg_temp_new_i64();
|
||||
TCGv_i64 t2 = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_movi_i64(t0, 0x00ff00ff00ff00ffull);
|
||||
tcg_gen_shri_i64(t1, cpu_gpr[rS(ctx->opcode)], 8);
|
||||
tcg_gen_and_i64(t2, t1, t0);
|
||||
tcg_gen_and_i64(t1, cpu_gpr[rS(ctx->opcode)], t0);
|
||||
tcg_gen_and_i64(t2, t1, mask);
|
||||
tcg_gen_and_i64(t1, cpu_gpr[rS(ctx->opcode)], mask);
|
||||
tcg_gen_shli_i64(t1, t1, 8);
|
||||
tcg_gen_or_i64(cpu_gpr[rA(ctx->opcode)], t1, t2);
|
||||
|
||||
tcg_temp_free_i64(t0);
|
||||
tcg_temp_free_i64(t1);
|
||||
tcg_temp_free_i64(t2);
|
||||
}
|
||||
|
@ -8551,6 +8556,8 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
|
|||
ctx->tm_enabled = (hflags >> HFLAGS_TM) & 1;
|
||||
ctx->gtse = (hflags >> HFLAGS_GTSE) & 1;
|
||||
ctx->hr = (hflags >> HFLAGS_HR) & 1;
|
||||
ctx->mmcr0_pmcc0 = (hflags >> HFLAGS_PMCC0) & 1;
|
||||
ctx->mmcr0_pmcc1 = (hflags >> HFLAGS_PMCC1) & 1;
|
||||
|
||||
ctx->singlestep_enabled = 0;
|
||||
if ((hflags >> HFLAGS_SE) & 1) {
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
# Test that the U-Boot firmware boots on ppc 405 machines and check the console
|
||||
#
|
||||
# Copyright (c) 2021 Red Hat, Inc.
|
||||
#
|
||||
# This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
# later. See the COPYING file in the top-level directory.
|
||||
|
||||
from avocado.utils import archive
|
||||
from avocado_qemu import Test
|
||||
from avocado_qemu import wait_for_console_pattern
|
||||
from avocado_qemu import exec_command_and_wait_for_pattern
|
||||
|
||||
class Ppc405Machine(Test):
|
||||
|
||||
timeout = 90
|
||||
|
||||
def do_test_ppc405(self):
|
||||
uboot_url = ('https://gitlab.com/huth/u-boot/-/raw/'
|
||||
'taihu-2021-10-09/u-boot-taihu.bin')
|
||||
uboot_hash = ('3208940e908a5edc7c03eab072c60f0dcfadc2ab');
|
||||
file_path = self.fetch_asset(uboot_url, asset_hash=uboot_hash)
|
||||
self.vm.set_console(console_index=1)
|
||||
self.vm.add_args('-bios', file_path)
|
||||
self.vm.launch()
|
||||
wait_for_console_pattern(self, 'AMCC PPC405EP Evaluation Board')
|
||||
exec_command_and_wait_for_pattern(self, 'reset', 'AMCC PowerPC 405EP')
|
||||
|
||||
def test_ppc_taihu(self):
|
||||
"""
|
||||
:avocado: tags=arch:ppc
|
||||
:avocado: tags=machine:taihu
|
||||
:avocado: tags=cpu:405ep
|
||||
"""
|
||||
self.do_test_ppc405()
|
||||
|
||||
def test_ppc_ref405ep(self):
|
||||
"""
|
||||
:avocado: tags=arch:ppc
|
||||
:avocado: tags=machine:ref405ep
|
||||
:avocado: tags=cpu:405ep
|
||||
"""
|
||||
self.do_test_ppc405()
|
|
@ -0,0 +1,39 @@
|
|||
# Test that Linux kernel boots on the ppc bamboo board and check the console
|
||||
#
|
||||
# Copyright (c) 2021 Red Hat
|
||||
#
|
||||
# This work is licensed under the terms of the GNU GPL, version 2 or
|
||||
# later. See the COPYING file in the top-level directory.
|
||||
|
||||
from avocado.utils import archive
|
||||
from avocado_qemu import Test
|
||||
from avocado_qemu import wait_for_console_pattern
|
||||
from avocado_qemu import exec_command_and_wait_for_pattern
|
||||
|
||||
class BambooMachine(Test):
|
||||
|
||||
timeout = 90
|
||||
|
||||
def test_ppc_bamboo(self):
|
||||
"""
|
||||
:avocado: tags=arch:ppc
|
||||
:avocado: tags=machine:bamboo
|
||||
:avocado: tags=cpu:440epb
|
||||
:avocado: tags=device:rtl8139
|
||||
"""
|
||||
tar_url = ('http://landley.net/aboriginal/downloads/binaries/'
|
||||
'system-image-powerpc-440fp.tar.gz')
|
||||
tar_hash = '53e5f16414b195b82d2c70272f81c2eedb39bad9'
|
||||
file_path = self.fetch_asset(tar_url, asset_hash=tar_hash)
|
||||
archive.extract(file_path, self.workdir)
|
||||
self.vm.set_console()
|
||||
self.vm.add_args('-kernel', self.workdir +
|
||||
'/system-image-powerpc-440fp/linux',
|
||||
'-initrd', self.workdir +
|
||||
'/system-image-powerpc-440fp/rootfs.cpio.gz',
|
||||
'-nic', 'user,model=rtl8139,restrict=on')
|
||||
self.vm.launch()
|
||||
wait_for_console_pattern(self, 'Type exit when done')
|
||||
exec_command_and_wait_for_pattern(self, 'ping 10.0.2.2',
|
||||
'10.0.2.2 is alive!')
|
||||
exec_command_and_wait_for_pattern(self, 'halt', 'System Halted')
|
|
@ -23,4 +23,6 @@ run-plugin-byte_reverse-with-%:
|
|||
$(call skip-test, "RUN of byte_reverse ($*)", "not built")
|
||||
endif
|
||||
|
||||
PPC64_TESTS += signal_save_restore_xer
|
||||
|
||||
TESTS += $(PPC64_TESTS)
|
||||
|
|
|
@ -22,4 +22,6 @@ run-plugin-byte_reverse-with-%:
|
|||
$(call skip-test, "RUN of byte_reverse ($*)", "not built")
|
||||
endif
|
||||
|
||||
PPC64LE_TESTS += signal_save_restore_xer
|
||||
|
||||
TESTS += $(PPC64LE_TESTS)
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <signal.h>
|
||||
#include <sys/user.h>
|
||||
|
||||
#define XER_SO (1 << 31)
|
||||
#define XER_OV (1 << 30)
|
||||
#define XER_CA (1 << 29)
|
||||
#define XER_OV32 (1 << 19)
|
||||
#define XER_CA32 (1 << 18)
|
||||
|
||||
uint64_t saved;
|
||||
|
||||
void sigill_handler(int sig, siginfo_t *si, void *ucontext)
|
||||
{
|
||||
ucontext_t *uc = ucontext;
|
||||
uc->uc_mcontext.regs->nip += 4;
|
||||
saved = uc->uc_mcontext.regs->xer;
|
||||
uc->uc_mcontext.regs->xer |= XER_OV | XER_OV32;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
uint64_t initial = XER_CA | XER_CA32, restored;
|
||||
struct sigaction sa = {
|
||||
.sa_sigaction = sigill_handler,
|
||||
.sa_flags = SA_SIGINFO
|
||||
};
|
||||
|
||||
sigaction(SIGILL, &sa, NULL);
|
||||
|
||||
asm("mtspr 1, %1\n\t"
|
||||
".long 0x0\n\t"
|
||||
"mfspr %0, 1\n\t"
|
||||
: "=r" (restored)
|
||||
: "r" (initial));
|
||||
|
||||
assert(saved == initial);
|
||||
assert(restored == (XER_OV | XER_OV32 | XER_CA | XER_CA32));
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue