ppc patch queue 2018-08-21

Here's my first ppc & spapr pull request for qemu-3.1.  This contains
 a bunch of things that have accumulated while 3.0 was in freeze.
 Highlights are:
     * SLOF firmware update
     * A number of floating point cleanups from Richard Henderson and
       Yasmin Beatriz
     * A new model for assigning irq numbers on spapr, this is an
       important preliminary step towards implementing the POWER9
       "XIVE" interrupt controller
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEdfRlhq5hpmzETofcbDjKyiDZs5IFAlt7lewACgkQbDjKyiDZ
 s5K+TA//QIMtlm59lR1G68Bwj656WEMgi/f+HN3FL419XtOZ/UkgprPmvBzWvoVP
 r7EgyktRw9qSyCsOe5OOST12rkP8s4RwyjxOPak8opRBEgXRFYk9q8micCCOv/94
 X7dtxh7sqDYvWVC4Gky1SvmNbrPtaFqSWAp7ZC/+OYnN5jOg9g+nQloPTko++GKp
 hNEKoS5I/5Q/OvtkaxGy6+G5oShi3in9gpC/nE5vtfJOnZ/ukIJcW5Niate6INpF
 WoKg5LPEF3/f0GGCDxumpoOQ7odVcBIFrtbeoeEDIK91f0l3H7+n75b8xgWE1Y51
 WelLNgdD2n0Z1pxhKwxUljIg5CnJamVSBhd6zELXDc5cx8CcOBLuNBSqtpriyRPn
 0Or3E4xfq3EbD+fNVcqHNVBC8M5mN18iplx+sOjmNTbBtwAiB/IGpVVfJkhc83Ed
 85Rlu4FxDdwBdeeE21PwdLhkRrRrtYpgobiWU2Mw0l20YYflhnQ20XS80AVQiVBa
 H/NflZbkEM93rqt/sKwenlx0bAUKt1HjZpE3mDuhSkLMRL4Sdg4hsulFEMT7QpPW
 QSZs+AntJpC6znRmZfE0Cavq1GNk5j4j9O5MBSKD8fbSNv7UR6Muu4SABIhjEZ0m
 7wG7qfqfLVEO/cnFph4nKgSAPnCE8mNiIyE0VowpkjhUWFSDTGE=
 =viH7
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-3.1-20180821' into staging

ppc patch queue 2018-08-21

Here's my first ppc & spapr pull request for qemu-3.1.  This contains
a bunch of things that have accumulated while 3.0 was in freeze.
Highlights are:
    * SLOF firmware update
    * A number of floating point cleanups from Richard Henderson and
      Yasmin Beatriz
    * A new model for assigning irq numbers on spapr, this is an
      important preliminary step towards implementing the POWER9
      "XIVE" interrupt controller

# gpg: Signature made Tue 21 Aug 2018 05:32:44 BST
# gpg:                using RSA key 6C38CACA20D9B392
# gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>"
# gpg:                 aka "David Gibson (Red Hat) <dgibson@redhat.com>"
# gpg:                 aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>"
# gpg:                 aka "David Gibson (kernel.org) <dwg@kernel.org>"
# Primary key fingerprint: 75F4 6586 AE61 A66C C44E  87DC 6C38 CACA 20D9 B392

* remotes/dgibson/tags/ppc-for-3.1-20180821: (26 commits)
  ppc: add DBCR based debugging
  spapr_pci: factorize the use of SPAPR_MACHINE_GET_CLASS()
  mac_newworld: don't use legacy fw_cfg_init_mem() function
  mac_oldworld: don't use legacy fw_cfg_init_mem() function
  40p: don't use legacy fw_cfg_init_mem() function
  qemu-doc: mark ppc/prep machine as deprecated
  hw/ppc: deprecate the machine type 'prep', replaced by '40p'
  spapr: introduce a IRQ controller backend to the machine
  hw/ppc/ppc405_uc: Convert away from old_mmio
  hw/ppc/ppc_boards: Don't use old_mmio for ref405ep_fpga
  hw/ppc/prep: Remove ifdeffed-out stub of XCSR code
  spapr: introduce a fixed IRQ number space
  spapr: Add a pseries-3.1 machine type
  target/ppc: simplify bcdadd/sub functions
  xics: don't include "target/ppc/cpu-qom.h" in "hw/ppc/xics.h"
  vfio/spapr: Allow backing bigger guest IOMMU pages with smaller physical pages
  target/ppc: bcdsub fix sign when result is zero
  target/ppc: Use non-arithmetic conversions for fp load/store
  target/ppc: Honor fpscr_ze semantics and tidy fre, fresqrt
  target/ppc: Tidy helper_fsqrt
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2018-08-21 13:27:11 +01:00
commit ee135aa042
31 changed files with 953 additions and 743 deletions

View File

@ -4,7 +4,7 @@ obj-y += ppc.o ppc_booke.o fdt.o
obj-$(CONFIG_PSERIES) += spapr.o spapr_caps.o spapr_vio.o spapr_events.o
obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o
obj-$(CONFIG_PSERIES) += spapr_pci.o spapr_rtc.o spapr_drc.o spapr_rng.o
obj-$(CONFIG_PSERIES) += spapr_cpu_core.o spapr_ovec.o
obj-$(CONFIG_PSERIES) += spapr_cpu_core.o spapr_ovec.o spapr_irq.o
# IBM PowerNV
obj-$(CONFIG_POWERNV) += pnv.o pnv_xscom.o pnv_core.o pnv_lpc.o pnv_psi.o pnv_occ.o pnv_bmc.o
ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)

View File

@ -454,7 +454,17 @@ static void ppc_core99_init(MachineState *machine)
pmac_format_nvram_partition(nvr, 0x2000);
/* No PCI init: the BIOS will do it */
fw_cfg = fw_cfg_init_mem(CFG_ADDR, CFG_ADDR + 2);
dev = qdev_create(NULL, TYPE_FW_CFG_MEM);
fw_cfg = FW_CFG(dev);
qdev_prop_set_uint32(dev, "data_width", 1);
qdev_prop_set_bit(dev, "dma_enabled", false);
object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG,
OBJECT(fw_cfg), NULL);
qdev_init_nofail(dev);
s = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(s, 0, CFG_ADDR);
sysbus_mmio_map(s, 1, CFG_ADDR + 2);
fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)smp_cpus);
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);

View File

@ -309,7 +309,17 @@ static void ppc_heathrow_init(MachineState *machine)
/* No PCI init: the BIOS will do it */
fw_cfg = fw_cfg_init_mem(CFG_ADDR, CFG_ADDR + 2);
dev = qdev_create(NULL, TYPE_FW_CFG_MEM);
fw_cfg = FW_CFG(dev);
qdev_prop_set_uint32(dev, "data_width", 1);
qdev_prop_set_bit(dev, "dma_enabled", false);
object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG,
OBJECT(fw_cfg), NULL);
qdev_init_nofail(dev);
s = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(s, 0, CFG_ADDR);
sysbus_mmio_map(s, 1, CFG_ADDR + 2);
fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, (uint16_t)smp_cpus);
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);

View File

@ -66,7 +66,7 @@ struct ref405ep_fpga_t {
uint8_t reg1;
};
static uint32_t ref405ep_fpga_readb (void *opaque, hwaddr addr)
static uint64_t ref405ep_fpga_readb(void *opaque, hwaddr addr, unsigned size)
{
ref405ep_fpga_t *fpga;
uint32_t ret;
@ -87,8 +87,8 @@ static uint32_t ref405ep_fpga_readb (void *opaque, hwaddr addr)
return ret;
}
static void ref405ep_fpga_writeb (void *opaque,
hwaddr addr, uint32_t value)
static void ref405ep_fpga_writeb(void *opaque, hwaddr addr, uint64_t value,
unsigned size)
{
ref405ep_fpga_t *fpga;
@ -105,54 +105,14 @@ static void ref405ep_fpga_writeb (void *opaque,
}
}
static uint32_t ref405ep_fpga_readw (void *opaque, hwaddr addr)
{
uint32_t ret;
ret = ref405ep_fpga_readb(opaque, addr) << 8;
ret |= ref405ep_fpga_readb(opaque, addr + 1);
return ret;
}
static void ref405ep_fpga_writew (void *opaque,
hwaddr addr, uint32_t value)
{
ref405ep_fpga_writeb(opaque, addr, (value >> 8) & 0xFF);
ref405ep_fpga_writeb(opaque, addr + 1, value & 0xFF);
}
static uint32_t ref405ep_fpga_readl (void *opaque, hwaddr addr)
{
uint32_t ret;
ret = ref405ep_fpga_readb(opaque, addr) << 24;
ret |= ref405ep_fpga_readb(opaque, addr + 1) << 16;
ret |= ref405ep_fpga_readb(opaque, addr + 2) << 8;
ret |= ref405ep_fpga_readb(opaque, addr + 3);
return ret;
}
static void ref405ep_fpga_writel (void *opaque,
hwaddr addr, uint32_t value)
{
ref405ep_fpga_writeb(opaque, addr, (value >> 24) & 0xFF);
ref405ep_fpga_writeb(opaque, addr + 1, (value >> 16) & 0xFF);
ref405ep_fpga_writeb(opaque, addr + 2, (value >> 8) & 0xFF);
ref405ep_fpga_writeb(opaque, addr + 3, value & 0xFF);
}
static const MemoryRegionOps ref405ep_fpga_ops = {
.old_mmio = {
.read = {
ref405ep_fpga_readb, ref405ep_fpga_readw, ref405ep_fpga_readl,
},
.write = {
ref405ep_fpga_writeb, ref405ep_fpga_writew, ref405ep_fpga_writel,
},
},
.endianness = DEVICE_NATIVE_ENDIAN,
.read = ref405ep_fpga_readb,
.write = ref405ep_fpga_writeb,
.impl.min_access_size = 1,
.impl.max_access_size = 1,
.valid.min_access_size = 1,
.valid.max_access_size = 4,
.endianness = DEVICE_BIG_ENDIAN,
};
static void ref405ep_fpga_reset (void *opaque)

View File

@ -283,7 +283,7 @@ struct ppc4xx_opba_t {
uint8_t pr;
};
static uint32_t opba_readb (void *opaque, hwaddr addr)
static uint64_t opba_readb(void *opaque, hwaddr addr, unsigned size)
{
ppc4xx_opba_t *opba;
uint32_t ret;
@ -307,8 +307,8 @@ static uint32_t opba_readb (void *opaque, hwaddr addr)
return ret;
}
static void opba_writeb (void *opaque,
hwaddr addr, uint32_t value)
static void opba_writeb(void *opaque, hwaddr addr, uint64_t value,
unsigned size)
{
ppc4xx_opba_t *opba;
@ -328,61 +328,14 @@ static void opba_writeb (void *opaque,
break;
}
}
static uint32_t opba_readw (void *opaque, hwaddr addr)
{
uint32_t ret;
#ifdef DEBUG_OPBA
printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
#endif
ret = opba_readb(opaque, addr) << 8;
ret |= opba_readb(opaque, addr + 1);
return ret;
}
static void opba_writew (void *opaque,
hwaddr addr, uint32_t value)
{
#ifdef DEBUG_OPBA
printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
value);
#endif
opba_writeb(opaque, addr, value >> 8);
opba_writeb(opaque, addr + 1, value);
}
static uint32_t opba_readl (void *opaque, hwaddr addr)
{
uint32_t ret;
#ifdef DEBUG_OPBA
printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
#endif
ret = opba_readb(opaque, addr) << 24;
ret |= opba_readb(opaque, addr + 1) << 16;
return ret;
}
static void opba_writel (void *opaque,
hwaddr addr, uint32_t value)
{
#ifdef DEBUG_OPBA
printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
value);
#endif
opba_writeb(opaque, addr, value >> 24);
opba_writeb(opaque, addr + 1, value >> 16);
}
static const MemoryRegionOps opba_ops = {
.old_mmio = {
.read = { opba_readb, opba_readw, opba_readl, },
.write = { opba_writeb, opba_writew, opba_writel, },
},
.endianness = DEVICE_NATIVE_ENDIAN,
.read = opba_readb,
.write = opba_writeb,
.impl.min_access_size = 1,
.impl.max_access_size = 1,
.valid.min_access_size = 1,
.valid.max_access_size = 4,
.endianness = DEVICE_BIG_ENDIAN,
};
static void ppc4xx_opba_reset (void *opaque)
@ -750,65 +703,27 @@ struct ppc405_gpio_t {
uint32_t isr1l;
};
static uint32_t ppc405_gpio_readb (void *opaque, hwaddr addr)
static uint64_t ppc405_gpio_read(void *opaque, hwaddr addr, unsigned size)
{
#ifdef DEBUG_GPIO
printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
printf("%s: addr " TARGET_FMT_plx " size %d\n", __func__, addr, size);
#endif
return 0;
}
static void ppc405_gpio_writeb (void *opaque,
hwaddr addr, uint32_t value)
static void ppc405_gpio_write(void *opaque, hwaddr addr, uint64_t value,
unsigned size)
{
#ifdef DEBUG_GPIO
printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
value);
#endif
}
static uint32_t ppc405_gpio_readw (void *opaque, hwaddr addr)
{
#ifdef DEBUG_GPIO
printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
#endif
return 0;
}
static void ppc405_gpio_writew (void *opaque,
hwaddr addr, uint32_t value)
{
#ifdef DEBUG_GPIO
printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
value);
#endif
}
static uint32_t ppc405_gpio_readl (void *opaque, hwaddr addr)
{
#ifdef DEBUG_GPIO
printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
#endif
return 0;
}
static void ppc405_gpio_writel (void *opaque,
hwaddr addr, uint32_t value)
{
#ifdef DEBUG_GPIO
printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
value);
printf("%s: addr " TARGET_FMT_plx " size %d val %08" PRIx32 "\n",
__func__, addr, size, value);
#endif
}
static const MemoryRegionOps ppc405_gpio_ops = {
.old_mmio = {
.read = { ppc405_gpio_readb, ppc405_gpio_readw, ppc405_gpio_readl, },
.write = { ppc405_gpio_writeb, ppc405_gpio_writew, ppc405_gpio_writel, },
},
.read = ppc405_gpio_read,
.write = ppc405_gpio_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};
@ -1017,44 +932,6 @@ struct ppc4xx_gpt_t {
uint32_t mask[5];
};
static uint32_t ppc4xx_gpt_readb (void *opaque, hwaddr addr)
{
#ifdef DEBUG_GPT
printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
#endif
/* XXX: generate a bus fault */
return -1;
}
static void ppc4xx_gpt_writeb (void *opaque,
hwaddr addr, uint32_t value)
{
#ifdef DEBUG_I2C
printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
value);
#endif
/* XXX: generate a bus fault */
}
static uint32_t ppc4xx_gpt_readw (void *opaque, hwaddr addr)
{
#ifdef DEBUG_GPT
printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
#endif
/* XXX: generate a bus fault */
return -1;
}
static void ppc4xx_gpt_writew (void *opaque,
hwaddr addr, uint32_t value)
{
#ifdef DEBUG_I2C
printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr,
value);
#endif
/* XXX: generate a bus fault */
}
static int ppc4xx_gpt_compare (ppc4xx_gpt_t *gpt, int n)
{
/* XXX: TODO */
@ -1107,7 +984,7 @@ static void ppc4xx_gpt_compute_timer (ppc4xx_gpt_t *gpt)
/* XXX: TODO */
}
static uint32_t ppc4xx_gpt_readl (void *opaque, hwaddr addr)
static uint64_t ppc4xx_gpt_read(void *opaque, hwaddr addr, unsigned size)
{
ppc4xx_gpt_t *gpt;
uint32_t ret;
@ -1162,8 +1039,8 @@ static uint32_t ppc4xx_gpt_readl (void *opaque, hwaddr addr)
return ret;
}
static void ppc4xx_gpt_writel (void *opaque,
hwaddr addr, uint32_t value)
static void ppc4xx_gpt_write(void *opaque, hwaddr addr, uint64_t value,
unsigned size)
{
ppc4xx_gpt_t *gpt;
int idx;
@ -1225,10 +1102,10 @@ static void ppc4xx_gpt_writel (void *opaque,
}
static const MemoryRegionOps gpt_ops = {
.old_mmio = {
.read = { ppc4xx_gpt_readb, ppc4xx_gpt_readw, ppc4xx_gpt_readl, },
.write = { ppc4xx_gpt_writeb, ppc4xx_gpt_writew, ppc4xx_gpt_writel, },
},
.read = ppc4xx_gpt_read,
.write = ppc4xx_gpt_write,
.valid.min_access_size = 4,
.valid.max_access_size = 4,
.endianness = DEVICE_NATIVE_ENDIAN,
};

View File

@ -78,94 +78,6 @@ static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
/* ISA IO ports bridge */
#define PPC_IO_BASE 0x80000000
/* PowerPC control and status registers */
#if 0 // Not used
static struct {
/* IDs */
uint32_t veni_devi;
uint32_t revi;
/* Control and status */
uint32_t gcsr;
uint32_t xcfr;
uint32_t ct32;
uint32_t mcsr;
/* General purpose registers */
uint32_t gprg[6];
/* Exceptions */
uint32_t feen;
uint32_t fest;
uint32_t fema;
uint32_t fecl;
uint32_t eeen;
uint32_t eest;
uint32_t eecl;
uint32_t eeint;
uint32_t eemck0;
uint32_t eemck1;
/* Error diagnostic */
} XCSR;
static void PPC_XCSR_writeb (void *opaque,
hwaddr addr, uint32_t value)
{
printf("%s: 0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", __func__, addr,
value);
}
static void PPC_XCSR_writew (void *opaque,
hwaddr addr, uint32_t value)
{
printf("%s: 0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", __func__, addr,
value);
}
static void PPC_XCSR_writel (void *opaque,
hwaddr addr, uint32_t value)
{
printf("%s: 0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", __func__, addr,
value);
}
static uint32_t PPC_XCSR_readb (void *opaque, hwaddr addr)
{
uint32_t retval = 0;
printf("%s: 0x" TARGET_FMT_plx " <= %08" PRIx32 "\n", __func__, addr,
retval);
return retval;
}
static uint32_t PPC_XCSR_readw (void *opaque, hwaddr addr)
{
uint32_t retval = 0;
printf("%s: 0x" TARGET_FMT_plx " <= %08" PRIx32 "\n", __func__, addr,
retval);
return retval;
}
static uint32_t PPC_XCSR_readl (void *opaque, hwaddr addr)
{
uint32_t retval = 0;
printf("%s: 0x" TARGET_FMT_plx " <= %08" PRIx32 "\n", __func__, addr,
retval);
return retval;
}
static const MemoryRegionOps PPC_XCSR_ops = {
.old_mmio = {
.read = { PPC_XCSR_readb, PPC_XCSR_readw, PPC_XCSR_readl, },
.write = { PPC_XCSR_writeb, PPC_XCSR_writew, PPC_XCSR_writel, },
},
.endianness = DEVICE_LITTLE_ENDIAN,
};
#endif
/* Fake super-io ports for PREP platform (Intel 82378ZB) */
typedef struct sysctrl_t {
qemu_irq reset_irq;
@ -648,11 +560,10 @@ static void ppc_prep_init(MachineState *machine)
portio_list_init(&prep_port_list, NULL, prep_portio_list, sysctrl, "prep");
portio_list_add(&prep_port_list, isa_address_space_io(isa), 0x0);
/* PowerPC control and status register group */
#if 0
memory_region_init_io(xcsr, NULL, &PPC_XCSR_ops, NULL, "ppc-xcsr", 0x1000);
memory_region_add_subregion(sysmem, 0xFEFF0000, xcsr);
#endif
/*
* PowerPC control and status register group: unimplemented,
* would be at address 0xFEFF0000.
*/
if (machine_usb(machine)) {
pci_create_simple(pci_bus, -1, "pci-ohci");
@ -676,6 +587,7 @@ static void ppc_prep_init(MachineState *machine)
static void prep_machine_init(MachineClass *mc)
{
mc->deprecation_reason = "use 40p machine type instead";
mc->desc = "PowerPC PREP platform";
mc->init = ppc_prep_init;
mc->block_default_type = IF_IDE;
@ -706,7 +618,7 @@ static void ibm_40p_init(MachineState *machine)
uint16_t cmos_checksum;
PowerPCCPU *cpu;
DeviceState *dev;
SysBusDevice *pcihost;
SysBusDevice *pcihost, *s;
Nvram *m48t59 = NULL;
PCIBus *pci_bus;
ISABus *isa_bus;
@ -799,7 +711,16 @@ static void ibm_40p_init(MachineState *machine)
}
/* Prepare firmware configuration for OpenBIOS */
fw_cfg = fw_cfg_init_mem(CFG_ADDR, CFG_ADDR + 2);
dev = qdev_create(NULL, TYPE_FW_CFG_MEM);
fw_cfg = FW_CFG(dev);
qdev_prop_set_uint32(dev, "data_width", 1);
qdev_prop_set_bit(dev, "dma_enabled", false);
object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG,
OBJECT(fw_cfg), NULL);
qdev_init_nofail(dev);
s = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(s, 0, CFG_ADDR);
sysbus_mmio_map(s, 1, CFG_ADDR + 2);
if (machine->kernel_filename) {
/* load kernel */

View File

@ -54,7 +54,6 @@
#include "hw/ppc/spapr.h"
#include "hw/ppc/spapr_vio.h"
#include "hw/pci-host/spapr.h"
#include "hw/ppc/xics.h"
#include "hw/pci/msi.h"
#include "hw/pci/pci.h"
@ -117,33 +116,6 @@ static bool spapr_is_thread0_in_vcore(sPAPRMachineState *spapr,
return spapr_get_vcpu_id(cpu) % spapr->vsmt == 0;
}
static ICSState *spapr_ics_create(sPAPRMachineState *spapr,
const char *type_ics,
int nr_irqs, Error **errp)
{
Error *local_err = NULL;
Object *obj;
obj = object_new(type_ics);
object_property_add_child(OBJECT(spapr), "ics", obj, &error_abort);
object_property_add_const_link(obj, ICS_PROP_XICS, OBJECT(spapr),
&error_abort);
object_property_set_int(obj, nr_irqs, "nr-irqs", &local_err);
if (local_err) {
goto error;
}
object_property_set_bool(obj, true, "realized", &local_err);
if (local_err) {
goto error;
}
return ICS_BASE(obj);
error:
error_propagate(errp, local_err);
return NULL;
}
static bool pre_2_10_vmstate_dummy_icp_needed(void *opaque)
{
/* Dummy entries correspond to unused ICPState objects in older QEMUs,
@ -184,38 +156,6 @@ static int xics_max_server_number(sPAPRMachineState *spapr)
return DIV_ROUND_UP(max_cpus * spapr->vsmt, smp_threads);
}
static void xics_system_init(MachineState *machine, int nr_irqs, Error **errp)
{
sPAPRMachineState *spapr = SPAPR_MACHINE(machine);
Error *local_err = NULL;
if (kvm_enabled()) {
if (machine_kernel_irqchip_allowed(machine) &&
!xics_kvm_init(spapr, &local_err)) {
spapr->icp_type = TYPE_KVM_ICP;
spapr->ics = spapr_ics_create(spapr, TYPE_ICS_KVM, nr_irqs,
&local_err);
}
if (machine_kernel_irqchip_required(machine) && !spapr->ics) {
error_prepend(&local_err,
"kernel_irqchip requested but unavailable: ");
goto error;
}
error_free(local_err);
local_err = NULL;
}
if (!spapr->ics) {
xics_spapr_init(spapr);
spapr->icp_type = TYPE_ICP;
spapr->ics = spapr_ics_create(spapr, TYPE_ICS_SIMPLE, nr_irqs,
&local_err);
}
error:
error_propagate(errp, local_err);
}
static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
int smt_threads)
{
@ -1636,6 +1576,10 @@ static void spapr_machine_reset(void)
ppc_set_compat(first_ppc_cpu, spapr->max_compat_pvr, &error_fatal);
}
if (!SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
spapr_irq_msi_reset(spapr);
}
qemu_devices_reset();
/* DRC reset may cause a device to be unplugged. This will cause troubles
@ -1910,6 +1854,24 @@ static const VMStateDescription vmstate_spapr_patb_entry = {
},
};
static bool spapr_irq_map_needed(void *opaque)
{
sPAPRMachineState *spapr = opaque;
return spapr->irq_map && !bitmap_empty(spapr->irq_map, spapr->irq_map_nr);
}
static const VMStateDescription vmstate_spapr_irq_map = {
.name = "spapr_irq_map",
.version_id = 1,
.minimum_version_id = 1,
.needed = spapr_irq_map_needed,
.fields = (VMStateField[]) {
VMSTATE_BITMAP(irq_map, sPAPRMachineState, 0, irq_map_nr),
VMSTATE_END_OF_LIST()
},
};
static const VMStateDescription vmstate_spapr = {
.name = "spapr",
.version_id = 3,
@ -1937,6 +1899,7 @@ static const VMStateDescription vmstate_spapr = {
&vmstate_spapr_cap_cfpc,
&vmstate_spapr_cap_sbbc,
&vmstate_spapr_cap_ibs,
&vmstate_spapr_irq_map,
NULL
}
};
@ -2590,7 +2553,7 @@ static void spapr_machine_init(MachineState *machine)
load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD;
/* Set up Interrupt Controller before we create the VCPUs */
xics_system_init(machine, XICS_IRQS_SPAPR, &error_fatal);
smc->irq->init(spapr, &error_fatal);
/* Set up containers for ibm,client-architecture-support negotiated options
*/
@ -3782,121 +3745,13 @@ static ICPState *spapr_icp_get(XICSFabric *xi, int vcpu_id)
return cpu ? ICP(cpu->intc) : NULL;
}
#define ICS_IRQ_FREE(ics, srcno) \
(!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK)))
static int ics_find_free_block(ICSState *ics, int num, int alignnum)
{
int first, i;
for (first = 0; first < ics->nr_irqs; first += alignnum) {
if (num > (ics->nr_irqs - first)) {
return -1;
}
for (i = first; i < first + num; ++i) {
if (!ICS_IRQ_FREE(ics, i)) {
break;
}
}
if (i == (first + num)) {
return first;
}
}
return -1;
}
int spapr_irq_find(sPAPRMachineState *spapr, int num, bool align, Error **errp)
{
ICSState *ics = spapr->ics;
int first = -1;
assert(ics);
/*
* MSIMesage::data is used for storing VIRQ so
* it has to be aligned to num to support multiple
* MSI vectors. MSI-X is not affected by this.
* The hint is used for the first IRQ, the rest should
* be allocated continuously.
*/
if (align) {
assert((num == 1) || (num == 2) || (num == 4) ||
(num == 8) || (num == 16) || (num == 32));
first = ics_find_free_block(ics, num, num);
} else {
first = ics_find_free_block(ics, num, 1);
}
if (first < 0) {
error_setg(errp, "can't find a free %d-IRQ block", num);
return -1;
}
return first + ics->offset;
}
int spapr_irq_claim(sPAPRMachineState *spapr, int irq, bool lsi, Error **errp)
{
ICSState *ics = spapr->ics;
assert(ics);
if (!ics_valid_irq(ics, irq)) {
error_setg(errp, "IRQ %d is invalid", irq);
return -1;
}
if (!ICS_IRQ_FREE(ics, irq - ics->offset)) {
error_setg(errp, "IRQ %d is not free", irq);
return -1;
}
ics_set_irq_type(ics, irq - ics->offset, lsi);
return 0;
}
void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num)
{
ICSState *ics = spapr->ics;
int srcno = irq - ics->offset;
int i;
if (ics_valid_irq(ics, irq)) {
trace_spapr_irq_free(0, irq, num);
for (i = srcno; i < srcno + num; ++i) {
if (ICS_IRQ_FREE(ics, i)) {
trace_spapr_irq_free_warn(0, i + ics->offset);
}
memset(&ics->irqs[i], 0, sizeof(ICSIRQState));
}
}
}
qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq)
{
ICSState *ics = spapr->ics;
if (ics_valid_irq(ics, irq)) {
return ics->qirqs[irq - ics->offset];
}
return NULL;
}
static void spapr_pic_print_info(InterruptStatsProvider *obj,
Monitor *mon)
{
sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
CPUState *cs;
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
CPU_FOREACH(cs) {
PowerPCCPU *cpu = POWERPC_CPU(cs);
icp_pic_print_info(ICP(cpu->intc), mon);
}
ics_pic_print_info(spapr->ics, mon);
smc->irq->print_info(spapr, mon);
}
int spapr_get_vcpu_id(PowerPCCPU *cpu)
@ -4009,6 +3864,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data)
smc->default_caps.caps[SPAPR_CAP_IBS] = SPAPR_CAP_BROKEN;
smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 16; /* 64kiB */
spapr_caps_add_properties(smc, &error_abort);
smc->irq = &spapr_irq_xics;
}
static const TypeInfo spapr_machine_info = {
@ -4059,19 +3915,42 @@ static const TypeInfo spapr_machine_info = {
} \
type_init(spapr_machine_register_##suffix)
/*
* pseries-3.0
/*
* pseries-3.1
*/
static void spapr_machine_3_0_instance_options(MachineState *machine)
static void spapr_machine_3_1_instance_options(MachineState *machine)
{
}
static void spapr_machine_3_0_class_options(MachineClass *mc)
static void spapr_machine_3_1_class_options(MachineClass *mc)
{
/* Defaults for the latest behaviour inherited from the base class */
}
DEFINE_SPAPR_MACHINE(3_0, "3.0", true);
DEFINE_SPAPR_MACHINE(3_1, "3.1", true);
/*
* pseries-3.0
*/
#define SPAPR_COMPAT_3_0 \
HW_COMPAT_3_0
static void spapr_machine_3_0_instance_options(MachineState *machine)
{
spapr_machine_3_1_instance_options(machine);
}
static void spapr_machine_3_0_class_options(MachineClass *mc)
{
sPAPRMachineClass *smc = SPAPR_MACHINE_CLASS(mc);
spapr_machine_3_1_class_options(mc);
SET_MACHINE_COMPAT(mc, SPAPR_COMPAT_3_0);
smc->legacy_irq_allocation = true;
}
DEFINE_SPAPR_MACHINE(3_0, "3.0", false);
/*
* pseries-2.12

View File

@ -11,6 +11,7 @@
#include "hw/ppc/spapr_cpu_core.h"
#include "target/ppc/cpu.h"
#include "hw/ppc/spapr.h"
#include "hw/ppc/xics.h" /* for icp_create() - to be removed */
#include "hw/boards.h"
#include "qapi/error.h"
#include "sysemu/cpus.h"
@ -113,26 +114,6 @@ const char *spapr_get_cpu_core_type(const char *cpu_type)
return object_class_get_name(oc);
}
static void spapr_unrealize_vcpu(PowerPCCPU *cpu)
{
qemu_unregister_reset(spapr_cpu_reset, cpu);
object_unparent(cpu->intc);
cpu_remove_sync(CPU(cpu));
object_unparent(OBJECT(cpu));
}
static void spapr_cpu_core_unrealize(DeviceState *dev, Error **errp)
{
sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
CPUCore *cc = CPU_CORE(dev);
int i;
for (i = 0; i < cc->nr_threads; i++) {
spapr_unrealize_vcpu(sc->threads[i]);
}
g_free(sc->threads);
}
static bool slb_shadow_needed(void *opaque)
{
sPAPRCPUState *spapr_cpu = opaque;
@ -207,10 +188,34 @@ static const VMStateDescription vmstate_spapr_cpu_state = {
}
};
static void spapr_unrealize_vcpu(PowerPCCPU *cpu, sPAPRCPUCore *sc)
{
if (!sc->pre_3_0_migration) {
vmstate_unregister(NULL, &vmstate_spapr_cpu_state, cpu->machine_data);
}
qemu_unregister_reset(spapr_cpu_reset, cpu);
object_unparent(cpu->intc);
cpu_remove_sync(CPU(cpu));
object_unparent(OBJECT(cpu));
}
static void spapr_cpu_core_unrealize(DeviceState *dev, Error **errp)
{
sPAPRCPUCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
CPUCore *cc = CPU_CORE(dev);
int i;
for (i = 0; i < cc->nr_threads; i++) {
spapr_unrealize_vcpu(sc->threads[i], sc);
}
g_free(sc->threads);
}
static void spapr_realize_vcpu(PowerPCCPU *cpu, sPAPRMachineState *spapr,
Error **errp)
sPAPRCPUCore *sc, Error **errp)
{
CPUPPCState *env = &cpu->env;
CPUState *cs = CPU(cpu);
Error *local_err = NULL;
object_property_set_bool(OBJECT(cpu), true, "realized", &local_err);
@ -233,6 +238,11 @@ static void spapr_realize_vcpu(PowerPCCPU *cpu, sPAPRMachineState *spapr,
goto error_unregister;
}
if (!sc->pre_3_0_migration) {
vmstate_register(NULL, cs->cpu_index, &vmstate_spapr_cpu_state,
cpu->machine_data);
}
return;
error_unregister:
@ -272,10 +282,6 @@ static PowerPCCPU *spapr_create_vcpu(sPAPRCPUCore *sc, int i, Error **errp)
}
cpu->machine_data = g_new0(sPAPRCPUState, 1);
if (!sc->pre_3_0_migration) {
vmstate_register(NULL, cs->cpu_index, &vmstate_spapr_cpu_state,
cpu->machine_data);
}
object_unref(obj);
return cpu;
@ -290,9 +296,6 @@ static void spapr_delete_vcpu(PowerPCCPU *cpu, sPAPRCPUCore *sc)
{
sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu);
if (!sc->pre_3_0_migration) {
vmstate_unregister(NULL, &vmstate_spapr_cpu_state, cpu->machine_data);
}
cpu->machine_data = NULL;
g_free(spapr_cpu);
object_unparent(OBJECT(cpu));
@ -325,7 +328,7 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
}
for (j = 0; j < cc->nr_threads; j++) {
spapr_realize_vcpu(sc->threads[j], spapr, &local_err);
spapr_realize_vcpu(sc->threads[j], spapr, sc, &local_err);
if (local_err) {
goto err_unrealize;
}
@ -334,7 +337,7 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
err_unrealize:
while (--j >= 0) {
spapr_unrealize_vcpu(sc->threads[j]);
spapr_unrealize_vcpu(sc->threads[j], sc);
}
err:
while (--i >= 0) {

View File

@ -707,9 +707,11 @@ void spapr_clear_pending_events(sPAPRMachineState *spapr)
void spapr_events_init(sPAPRMachineState *spapr)
{
int epow_irq;
int epow_irq = SPAPR_IRQ_EPOW;
epow_irq = spapr_irq_findone(spapr, &error_fatal);
if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
epow_irq = spapr_irq_findone(spapr, &error_fatal);
}
spapr_irq_claim(spapr, epow_irq, false, &error_fatal);
@ -729,9 +731,11 @@ void spapr_events_init(sPAPRMachineState *spapr)
* checking that it's enabled.
*/
if (spapr->use_hotplug_event_source) {
int hp_irq;
int hp_irq = SPAPR_IRQ_HOTPLUG;
hp_irq = spapr_irq_findone(spapr, &error_fatal);
if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
hp_irq = spapr_irq_findone(spapr, &error_fatal);
}
spapr_irq_claim(spapr, hp_irq, false, &error_fatal);

286
hw/ppc/spapr_irq.c Normal file
View File

@ -0,0 +1,286 @@
/*
* QEMU PowerPC sPAPR IRQ interface
*
* Copyright (c) 2018, IBM Corporation.
*
* This code is licensed under the GPL version 2 or later. See the
* COPYING file in the top-level directory.
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/error-report.h"
#include "qapi/error.h"
#include "hw/ppc/spapr.h"
#include "hw/ppc/xics.h"
#include "sysemu/kvm.h"
#include "trace.h"
void spapr_irq_msi_init(sPAPRMachineState *spapr, uint32_t nr_msis)
{
spapr->irq_map_nr = nr_msis;
spapr->irq_map = bitmap_new(spapr->irq_map_nr);
}
int spapr_irq_msi_alloc(sPAPRMachineState *spapr, uint32_t num, bool align,
Error **errp)
{
int irq;
/*
* The 'align_mask' parameter of bitmap_find_next_zero_area()
* should be one less than a power of 2; 0 means no
* alignment. Adapt the 'align' value of the former allocator
* to fit the requirements of bitmap_find_next_zero_area()
*/
align -= 1;
irq = bitmap_find_next_zero_area(spapr->irq_map, spapr->irq_map_nr, 0, num,
align);
if (irq == spapr->irq_map_nr) {
error_setg(errp, "can't find a free %d-IRQ block", num);
return -1;
}
bitmap_set(spapr->irq_map, irq, num);
return irq + SPAPR_IRQ_MSI;
}
void spapr_irq_msi_free(sPAPRMachineState *spapr, int irq, uint32_t num)
{
bitmap_clear(spapr->irq_map, irq - SPAPR_IRQ_MSI, num);
}
void spapr_irq_msi_reset(sPAPRMachineState *spapr)
{
bitmap_clear(spapr->irq_map, 0, spapr->irq_map_nr);
}
/*
* XICS IRQ backend.
*/
static ICSState *spapr_ics_create(sPAPRMachineState *spapr,
const char *type_ics,
int nr_irqs, Error **errp)
{
Error *local_err = NULL;
Object *obj;
obj = object_new(type_ics);
object_property_add_child(OBJECT(spapr), "ics", obj, &error_abort);
object_property_add_const_link(obj, ICS_PROP_XICS, OBJECT(spapr),
&error_abort);
object_property_set_int(obj, nr_irqs, "nr-irqs", &local_err);
if (local_err) {
goto error;
}
object_property_set_bool(obj, true, "realized", &local_err);
if (local_err) {
goto error;
}
return ICS_BASE(obj);
error:
error_propagate(errp, local_err);
return NULL;
}
static void spapr_irq_init_xics(sPAPRMachineState *spapr, Error **errp)
{
MachineState *machine = MACHINE(spapr);
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
int nr_irqs = smc->irq->nr_irqs;
Error *local_err = NULL;
/* Initialize the MSI IRQ allocator. */
if (!SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
spapr_irq_msi_init(spapr, XICS_IRQ_BASE + nr_irqs - SPAPR_IRQ_MSI);
}
if (kvm_enabled()) {
if (machine_kernel_irqchip_allowed(machine) &&
!xics_kvm_init(spapr, &local_err)) {
spapr->icp_type = TYPE_KVM_ICP;
spapr->ics = spapr_ics_create(spapr, TYPE_ICS_KVM, nr_irqs,
&local_err);
}
if (machine_kernel_irqchip_required(machine) && !spapr->ics) {
error_prepend(&local_err,
"kernel_irqchip requested but unavailable: ");
goto error;
}
error_free(local_err);
local_err = NULL;
}
if (!spapr->ics) {
xics_spapr_init(spapr);
spapr->icp_type = TYPE_ICP;
spapr->ics = spapr_ics_create(spapr, TYPE_ICS_SIMPLE, nr_irqs,
&local_err);
}
error:
error_propagate(errp, local_err);
}
#define ICS_IRQ_FREE(ics, srcno) \
(!((ics)->irqs[(srcno)].flags & (XICS_FLAGS_IRQ_MASK)))
static int spapr_irq_claim_xics(sPAPRMachineState *spapr, int irq, bool lsi,
Error **errp)
{
ICSState *ics = spapr->ics;
assert(ics);
if (!ics_valid_irq(ics, irq)) {
error_setg(errp, "IRQ %d is invalid", irq);
return -1;
}
if (!ICS_IRQ_FREE(ics, irq - ics->offset)) {
error_setg(errp, "IRQ %d is not free", irq);
return -1;
}
ics_set_irq_type(ics, irq - ics->offset, lsi);
return 0;
}
static void spapr_irq_free_xics(sPAPRMachineState *spapr, int irq, int num)
{
ICSState *ics = spapr->ics;
uint32_t srcno = irq - ics->offset;
int i;
if (ics_valid_irq(ics, irq)) {
trace_spapr_irq_free(0, irq, num);
for (i = srcno; i < srcno + num; ++i) {
if (ICS_IRQ_FREE(ics, i)) {
trace_spapr_irq_free_warn(0, i);
}
memset(&ics->irqs[i], 0, sizeof(ICSIRQState));
}
}
}
static qemu_irq spapr_qirq_xics(sPAPRMachineState *spapr, int irq)
{
ICSState *ics = spapr->ics;
uint32_t srcno = irq - ics->offset;
if (ics_valid_irq(ics, irq)) {
return ics->qirqs[srcno];
}
return NULL;
}
static void spapr_irq_print_info_xics(sPAPRMachineState *spapr, Monitor *mon)
{
CPUState *cs;
CPU_FOREACH(cs) {
PowerPCCPU *cpu = POWERPC_CPU(cs);
icp_pic_print_info(ICP(cpu->intc), mon);
}
ics_pic_print_info(spapr->ics, mon);
}
sPAPRIrq spapr_irq_xics = {
.nr_irqs = XICS_IRQS_SPAPR,
.init = spapr_irq_init_xics,
.claim = spapr_irq_claim_xics,
.free = spapr_irq_free_xics,
.qirq = spapr_qirq_xics,
.print_info = spapr_irq_print_info_xics,
};
/*
* sPAPR IRQ frontend routines for devices
*/
int spapr_irq_claim(sPAPRMachineState *spapr, int irq, bool lsi, Error **errp)
{
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
return smc->irq->claim(spapr, irq, lsi, errp);
}
void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num)
{
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
smc->irq->free(spapr, irq, num);
}
qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq)
{
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
return smc->irq->qirq(spapr, irq);
}
/*
* XICS legacy routines - to deprecate one day
*/
static int ics_find_free_block(ICSState *ics, int num, int alignnum)
{
int first, i;
for (first = 0; first < ics->nr_irqs; first += alignnum) {
if (num > (ics->nr_irqs - first)) {
return -1;
}
for (i = first; i < first + num; ++i) {
if (!ICS_IRQ_FREE(ics, i)) {
break;
}
}
if (i == (first + num)) {
return first;
}
}
return -1;
}
int spapr_irq_find(sPAPRMachineState *spapr, int num, bool align, Error **errp)
{
ICSState *ics = spapr->ics;
int first = -1;
assert(ics);
/*
* MSIMesage::data is used for storing VIRQ so
* it has to be aligned to num to support multiple
* MSI vectors. MSI-X is not affected by this.
* The hint is used for the first IRQ, the rest should
* be allocated continuously.
*/
if (align) {
assert((num == 1) || (num == 2) || (num == 4) ||
(num == 8) || (num == 16) || (num == 32));
first = ics_find_free_block(ics, num, num);
} else {
first = ics_find_free_block(ics, num, 1);
}
if (first < 0) {
error_setg(errp, "can't find a free %d-IRQ block", num);
return -1;
}
return first + ics->offset;
}

View File

@ -267,6 +267,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong args, uint32_t nret,
target_ulong rets)
{
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
uint32_t config_addr = rtas_ld(args, 0);
uint64_t buid = rtas_ldq(args, 1);
unsigned int func = rtas_ld(args, 3);
@ -334,6 +335,9 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return;
}
if (!smc->legacy_irq_allocation) {
spapr_irq_msi_free(spapr, msi->first_irq, msi->num);
}
spapr_irq_free(spapr, msi->first_irq, msi->num);
if (msi_present(pdev)) {
spapr_msi_setmsg(pdev, 0, false, 0, 0);
@ -372,7 +376,13 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
}
/* Allocate MSIs */
irq = spapr_irq_find(spapr, req_num, ret_intr_type == RTAS_TYPE_MSI, &err);
if (smc->legacy_irq_allocation) {
irq = spapr_irq_find(spapr, req_num, ret_intr_type == RTAS_TYPE_MSI,
&err);
} else {
irq = spapr_irq_msi_alloc(spapr, req_num,
ret_intr_type == RTAS_TYPE_MSI, &err);
}
if (err) {
error_reportf_err(err, "Can't allocate MSIs for device %x: ",
config_addr);
@ -392,6 +402,9 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
/* Release previous MSIs */
if (msi) {
if (!smc->legacy_irq_allocation) {
spapr_irq_msi_free(spapr, msi->first_irq, msi->num);
}
spapr_irq_free(spapr, msi->first_irq, msi->num);
g_hash_table_remove(phb->msi, &config_addr);
}
@ -1546,6 +1559,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
sPAPRMachineState *spapr =
(sPAPRMachineState *) object_dynamic_cast(qdev_get_machine(),
TYPE_SPAPR_MACHINE);
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
SysBusDevice *s = SYS_BUS_DEVICE(dev);
sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s);
PCIHostState *phb = PCI_HOST_BRIDGE(s);
@ -1563,7 +1577,6 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
}
if (sphb->index != (uint32_t)-1) {
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
Error *local_err = NULL;
smc->phb_placement(spapr, sphb->index,
@ -1705,14 +1718,16 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
/* Initialize the LSI table */
for (i = 0; i < PCI_NUM_PINS; i++) {
uint32_t irq;
uint32_t irq = SPAPR_IRQ_PCI_LSI + sphb->index * PCI_NUM_PINS + i;
Error *local_err = NULL;
irq = spapr_irq_findone(spapr, &local_err);
if (local_err) {
error_propagate(errp, local_err);
error_prepend(errp, "can't allocate LSIs: ");
return;
if (smc->legacy_irq_allocation) {
irq = spapr_irq_findone(spapr, &local_err);
if (local_err) {
error_propagate(errp, local_err);
error_prepend(errp, "can't allocate LSIs: ");
return;
}
}
spapr_irq_claim(spapr, irq, true, &local_err);
@ -2123,6 +2138,7 @@ int spapr_populate_pci_dt(sPAPRPHBState *phb,
_FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof_ranges));
_FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg)));
_FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pci-config-space-type", 0x1));
/* TODO: fine tune the total count of allocatable MSIs per PHB */
_FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pe-total-#msi", XICS_IRQS_SPAPR));
/* Dynamic DMA window */

View File

@ -37,12 +37,13 @@
#include "hw/ppc/spapr.h"
#include "hw/ppc/spapr_vio.h"
#include "hw/ppc/xics.h"
#include "hw/ppc/fdt.h"
#include "trace.h"
#include <libfdt.h>
#define SPAPR_VIO_REG_BASE 0x71000000
static void spapr_vio_get_irq(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
@ -445,6 +446,55 @@ static void spapr_vio_busdev_reset(DeviceState *qdev)
}
}
/*
* The register property of a VIO device is defined in livirt using
* 0x1000 as a base register number plus a 0x1000 increment. For the
* VIO tty device, the base number is changed to 0x30000000. QEMU uses
* a base register number of 0x71000000 and then a simple increment.
*
* The formula below tries to compute a unique index number from the
* register value that will be used to define the IRQ number of the
* VIO device.
*
* A maximum of 256 VIO devices is covered. Collisions are possible
* but they will be detected when the IRQ is claimed.
*/
static inline uint32_t spapr_vio_reg_to_irq(uint32_t reg)
{
uint32_t irq;
if (reg >= SPAPR_VIO_REG_BASE) {
/*
* VIO device register values when allocated by QEMU. For
* these, we simply mask the high bits to fit the overall
* range: [0x00 - 0xff].
*
* The nvram VIO device (reg=0x71000000) is a static device of
* the pseries machine and so is always allocated by QEMU. Its
* IRQ number is 0x0.
*/
irq = reg & 0xff;
} else if (reg >= 0x30000000) {
/*
* VIO tty devices register values, when allocated by livirt,
* are mapped in range [0xf0 - 0xff], gives us a maximum of 16
* vtys.
*/
irq = 0xf0 | ((reg >> 12) & 0xf);
} else {
/*
* Other VIO devices register values, when allocated by
* livirt, should be mapped in range [0x00 - 0xef]. Conflicts
* will be detected when IRQ is claimed.
*/
irq = (reg >> 12) & 0xff;
}
return SPAPR_IRQ_VIO | irq;
}
static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp)
{
sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
@ -485,10 +535,14 @@ static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp)
}
if (!dev->irq) {
dev->irq = spapr_irq_findone(spapr, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
dev->irq = spapr_vio_reg_to_irq(dev->reg);
if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
dev->irq = spapr_irq_findone(spapr, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
}
}
@ -557,7 +611,7 @@ VIOsPAPRBus *spapr_vio_bus_init(void)
/* Create bus on bridge device */
qbus = qbus_create(TYPE_SPAPR_VIO_BUS, dev, "spapr-vio");
bus = SPAPR_VIO_BUS(qbus);
bus->next_reg = 0x71000000;
bus->next_reg = SPAPR_VIO_REG_BASE;
/* hcall-vio */
spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal);

View File

@ -1136,6 +1136,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as,
info.iova_pgsizes = 4096;
}
vfio_host_win_add(container, 0, (hwaddr)-1, info.iova_pgsizes);
container->pgsizes = info.iova_pgsizes;
} else if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_SPAPR_TCE_IOMMU) ||
ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_SPAPR_TCE_v2_IOMMU)) {
struct vfio_iommu_spapr_tce_info info;
@ -1200,6 +1201,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as,
}
if (v2) {
container->pgsizes = info.ddw.pgsizes;
/*
* There is a default window in just created container.
* To make region_add/del simpler, we better remove this
@ -1214,6 +1216,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as,
}
} else {
/* The default table uses 4K pages */
container->pgsizes = 0x1000;
vfio_host_win_add(container, info.dma32_window_start,
info.dma32_window_start +
info.dma32_window_size - 1,

View File

@ -15,6 +15,7 @@
#include "hw/vfio/vfio-common.h"
#include "hw/hw.h"
#include "exec/ram_addr.h"
#include "qemu/error-report.h"
#include "trace.h"
@ -144,9 +145,27 @@ int vfio_spapr_create_window(VFIOContainer *container,
{
int ret;
IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr);
unsigned pagesize = memory_region_iommu_get_min_page_size(iommu_mr);
uint64_t pagesize = memory_region_iommu_get_min_page_size(iommu_mr);
unsigned entries, pages;
struct vfio_iommu_spapr_tce_create create = { .argsz = sizeof(create) };
long systempagesize = qemu_getrampagesize();
/*
* The host might not support the guest supported IOMMU page size,
* so we will use smaller physical IOMMU pages to back them.
*/
if (pagesize > systempagesize) {
pagesize = systempagesize;
}
pagesize = 1ULL << (63 - clz64(container->pgsizes &
(pagesize | (pagesize - 1))));
if (!pagesize) {
error_report("Host doesn't support page size 0x%"PRIx64
", the supported mask is 0x%lx",
memory_region_iommu_get_min_page_size(iommu_mr),
container->pgsizes);
return -EINVAL;
}
/*
* FIXME: For VFIO iommu types which have KVM acceleration to

View File

@ -4,10 +4,10 @@
#include "qemu/units.h"
#include "sysemu/dma.h"
#include "hw/boards.h"
#include "hw/ppc/xics.h"
#include "hw/ppc/spapr_drc.h"
#include "hw/mem/pc-dimm.h"
#include "hw/ppc/spapr_ovec.h"
#include "hw/ppc/spapr_irq.h"
struct VIOsPAPRBus;
struct sPAPRPHBState;
@ -15,6 +15,7 @@ struct sPAPRNVRAM;
typedef struct sPAPREventLogEntry sPAPREventLogEntry;
typedef struct sPAPREventSource sPAPREventSource;
typedef struct sPAPRPendingHPT sPAPRPendingHPT;
typedef struct ICSState ICSState;
#define HPTE64_V_HPTE_DIRTY 0x0000000000000040ULL
#define SPAPR_ENTRY_POINT 0x100
@ -101,12 +102,15 @@ struct sPAPRMachineClass {
bool dr_lmb_enabled; /* enable dynamic-reconfig/hotplug of LMBs */
bool use_ohci_by_default; /* use USB-OHCI instead of XHCI */
bool pre_2_10_has_unused_icps;
bool legacy_irq_allocation;
void (*phb_placement)(sPAPRMachineState *spapr, uint32_t index,
uint64_t *buid, hwaddr *pio,
hwaddr *mmio32, hwaddr *mmio64,
unsigned n_dma, uint32_t *liobns, Error **errp);
sPAPRResizeHPT resize_hpt_default;
sPAPRCapabilities default_caps;
sPAPRIrq *irq;
};
/**
@ -167,6 +171,8 @@ struct sPAPRMachineState {
char *kvm_type;
const char *icp_type;
int32_t irq_map_nr;
unsigned long *irq_map;
bool cmd_line_caps[SPAPR_CAP_NUM];
sPAPRCapabilities def, eff, mig;
@ -775,14 +781,6 @@ int spapr_get_vcpu_id(PowerPCCPU *cpu);
void spapr_set_vcpu_id(PowerPCCPU *cpu, int cpu_index, Error **errp);
PowerPCCPU *spapr_find_cpu(int vcpu_id);
int spapr_irq_find(sPAPRMachineState *spapr, int num, bool align,
Error **errp);
#define spapr_irq_findone(spapr, errp) spapr_irq_find(spapr, 1, false, errp)
int spapr_irq_claim(sPAPRMachineState *spapr, int irq, bool lsi, Error **errp);
void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num);
qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq);
int spapr_caps_pre_load(void *opaque);
int spapr_caps_pre_save(void *opaque);

View File

@ -0,0 +1,54 @@
/*
* QEMU PowerPC sPAPR IRQ backend definitions
*
* Copyright (c) 2018, IBM Corporation.
*
* This code is licensed under the GPL version 2 or later. See the
* COPYING file in the top-level directory.
*/
#ifndef HW_SPAPR_IRQ_H
#define HW_SPAPR_IRQ_H
/*
* IRQ range offsets per device type
*/
#define SPAPR_IRQ_EPOW 0x1000 /* XICS_IRQ_BASE offset */
#define SPAPR_IRQ_HOTPLUG 0x1001
#define SPAPR_IRQ_VIO 0x1100 /* 256 VIO devices */
#define SPAPR_IRQ_PCI_LSI 0x1200 /* 32+ PHBs devices */
#define SPAPR_IRQ_MSI 0x1300 /* Offset of the dynamic range covered
* by the bitmap allocator */
typedef struct sPAPRMachineState sPAPRMachineState;
void spapr_irq_msi_init(sPAPRMachineState *spapr, uint32_t nr_msis);
int spapr_irq_msi_alloc(sPAPRMachineState *spapr, uint32_t num, bool align,
Error **errp);
void spapr_irq_msi_free(sPAPRMachineState *spapr, int irq, uint32_t num);
void spapr_irq_msi_reset(sPAPRMachineState *spapr);
typedef struct sPAPRIrq {
uint32_t nr_irqs;
void (*init)(sPAPRMachineState *spapr, Error **errp);
int (*claim)(sPAPRMachineState *spapr, int irq, bool lsi, Error **errp);
void (*free)(sPAPRMachineState *spapr, int irq, int num);
qemu_irq (*qirq)(sPAPRMachineState *spapr, int irq);
void (*print_info)(sPAPRMachineState *spapr, Monitor *mon);
} sPAPRIrq;
extern sPAPRIrq spapr_irq_xics;
int spapr_irq_claim(sPAPRMachineState *spapr, int irq, bool lsi, Error **errp);
void spapr_irq_free(sPAPRMachineState *spapr, int irq, int num);
qemu_irq spapr_qirq(sPAPRMachineState *spapr, int irq);
/*
* XICS legacy routines
*/
int spapr_irq_find(sPAPRMachineState *spapr, int num, bool align, Error **errp);
#define spapr_irq_findone(spapr, errp) spapr_irq_find(spapr, 1, false, errp)
#endif

View File

@ -29,7 +29,6 @@
#define XICS_H
#include "hw/qdev.h"
#include "target/ppc/cpu-qom.h"
#define XICS_IPI 0x2
#define XICS_BUID 0x1

View File

@ -73,6 +73,7 @@ typedef struct VFIOContainer {
unsigned iommu_type;
int error;
bool initialized;
unsigned long pgsizes;
/*
* This assumes the host IOMMU can support only a single
* contiguous IOVA window. We may need to generalize that in

View File

@ -17,7 +17,7 @@
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
implementation for certain IBM POWER hardware. The sources are at
https://github.com/aik/SLOF, and the image currently in qemu is
built from git tag qemu-slof-20180621.
built from git tag qemu-slof-20180702.
- sgabios (the Serial Graphics Adapter option ROM) provides a means for
legacy x86 software to communicate with an attached serial console as

Binary file not shown.

View File

@ -195,6 +195,12 @@ support page sizes < 4096 any longer.
These machine types are very old and likely can not be used for live migration
from old QEMU versions anymore. A newer machine type should be used instead.
@subsection prep (PowerPC) (since 3.1)
This machine type uses an unmaintained firmware, broken in lots of ways,
and unable to start post-2004 operating systems. 40p machine type should be
used instead.
@section Device options
@subsection Block device options

@ -1 +1 @@
Subproject commit 7d37babcfa48a6eb08e726a8d13b745cb2eebe1c
Subproject commit 9b7ab2fa020341dee8bf9df6c9cf40003e0136df

View File

@ -481,6 +481,11 @@ struct ppc_slb_t {
#define msr_ts ((env->msr >> MSR_TS1) & 3)
#define msr_tm ((env->msr >> MSR_TM) & 1)
#define DBCR0_ICMP (1 << 27)
#define DBCR0_BRT (1 << 26)
#define DBSR_ICMP (1 << 27)
#define DBSR_BRT (1 << 26)
/* Hypervisor bit is more specific */
#if defined(TARGET_PPC64)
#define MSR_HVB (1ULL << MSR_SHV)

View File

@ -348,19 +348,16 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
case POWERPC_EXCP_ITLB: /* Instruction TLB error */
break;
case POWERPC_EXCP_DEBUG: /* Debug interrupt */
switch (excp_model) {
case POWERPC_EXCP_BOOKE:
if (env->flags & POWERPC_FLAG_DE) {
/* FIXME: choose one or the other based on CPU type */
srr0 = SPR_BOOKE_DSRR0;
srr1 = SPR_BOOKE_DSRR1;
asrr0 = SPR_BOOKE_CSRR0;
asrr1 = SPR_BOOKE_CSRR1;
break;
default:
break;
/* DBSR already modified by caller */
} else {
cpu_abort(cs, "Debug exception triggered on unsupported model\n");
}
/* XXX: TODO */
cpu_abort(cs, "Debug exception is not implemented yet !\n");
break;
case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */
env->spr[SPR_BOOKE_ESR] = ESR_SPV;

View File

@ -36,26 +36,72 @@ static inline float128 float128_snan_to_qnan(float128 x)
#define float32_snan_to_qnan(x) ((x) | 0x00400000)
#define float16_snan_to_qnan(x) ((x) | 0x0200)
/*****************************************************************************/
/* Floating point operations helpers */
uint64_t helper_float32_to_float64(CPUPPCState *env, uint32_t arg)
static inline bool fp_exceptions_enabled(CPUPPCState *env)
{
CPU_FloatU f;
CPU_DoubleU d;
f.l = arg;
d.d = float32_to_float64(f.f, &env->fp_status);
return d.ll;
#ifdef CONFIG_USER_ONLY
return true;
#else
return (env->msr & ((1U << MSR_FE0) | (1U << MSR_FE1))) != 0;
#endif
}
uint32_t helper_float64_to_float32(CPUPPCState *env, uint64_t arg)
{
CPU_FloatU f;
CPU_DoubleU d;
/*****************************************************************************/
/* Floating point operations helpers */
d.ll = arg;
f.f = float64_to_float32(d.d, &env->fp_status);
return f.l;
/*
* This is the non-arithmatic conversion that happens e.g. on loads.
* In the Power ISA pseudocode, this is called DOUBLE.
*/
uint64_t helper_todouble(uint32_t arg)
{
uint32_t abs_arg = arg & 0x7fffffff;
uint64_t ret;
if (likely(abs_arg >= 0x00800000)) {
/* Normalized operand, or Inf, or NaN. */
ret = (uint64_t)extract32(arg, 30, 2) << 62;
ret |= ((extract32(arg, 30, 1) ^ 1) * (uint64_t)7) << 59;
ret |= (uint64_t)extract32(arg, 0, 30) << 29;
} else {
/* Zero or Denormalized operand. */
ret = (uint64_t)extract32(arg, 31, 1) << 63;
if (unlikely(abs_arg != 0)) {
/* Denormalized operand. */
int shift = clz32(abs_arg) - 9;
int exp = -126 - shift + 1023;
ret |= (uint64_t)exp << 52;
ret |= abs_arg << (shift + 29);
}
}
return ret;
}
/*
* This is the non-arithmatic conversion that happens e.g. on stores.
* In the Power ISA pseudocode, this is called SINGLE.
*/
uint32_t helper_tosingle(uint64_t arg)
{
int exp = extract64(arg, 52, 11);
uint32_t ret;
if (likely(exp > 896)) {
/* No denormalization required (includes Inf, NaN). */
ret = extract64(arg, 62, 2) << 30;
ret |= extract64(arg, 29, 30);
} else {
/* Zero or Denormal result. If the exponent is in bounds for
* a single-precision denormal result, extract the proper bits.
* If the input is not zero, and the exponent is out of bounds,
* then the result is undefined; this underflows to zero.
*/
ret = extract64(arg, 63, 1) << 31;
if (unlikely(exp >= 874)) {
/* Denormal result. */
ret |= ((1ULL << 52) | extract64(arg, 0, 52)) >> (896 + 30 - exp);
}
}
return ret;
}
static inline int ppc_float32_get_unbiased_exp(float32 f)
@ -207,7 +253,7 @@ uint64_t float_invalid_op_excp(CPUPPCState *env, int op, int set_fpcc)
if (ve != 0) {
/* Update the floating-point enabled exception summary */
env->fpscr |= 1 << FPSCR_FEX;
if (msr_fe0 != 0 || msr_fe1 != 0) {
if (fp_exceptions_enabled(env)) {
/* GETPC() works here because this is inline */
raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
POWERPC_EXCP_FP | op, GETPC());
@ -225,7 +271,7 @@ static inline void float_zero_divide_excp(CPUPPCState *env, uintptr_t raddr)
if (fpscr_ze != 0) {
/* Update the floating-point enabled exception summary */
env->fpscr |= 1 << FPSCR_FEX;
if (msr_fe0 != 0 || msr_fe1 != 0) {
if (fp_exceptions_enabled(env)) {
raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX,
raddr);
@ -536,9 +582,7 @@ static void do_float_check_status(CPUPPCState *env, uintptr_t raddr)
int status = get_float_exception_flags(&env->fp_status);
bool inexact_happened = false;
if (status & float_flag_divbyzero) {
float_zero_divide_excp(env, raddr);
} else if (status & float_flag_overflow) {
if (status & float_flag_overflow) {
float_overflow_excp(env);
} else if (status & float_flag_underflow) {
float_underflow_excp(env);
@ -555,7 +599,7 @@ static void do_float_check_status(CPUPPCState *env, uintptr_t raddr)
if (cs->exception_index == POWERPC_EXCP_PROGRAM &&
(env->error_code & POWERPC_EXCP_FP)) {
/* Differred floating-point exception after target FPR update */
if (msr_fe0 != 0 || msr_fe1 != 0) {
if (fp_exceptions_enabled(env)) {
raise_exception_err_ra(env, cs->exception_index,
env->error_code, raddr);
}
@ -580,102 +624,93 @@ void helper_reset_fpstatus(CPUPPCState *env)
}
/* fadd - fadd. */
uint64_t helper_fadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
float64 helper_fadd(CPUPPCState *env, float64 arg1, float64 arg2)
{
CPU_DoubleU farg1, farg2;
float64 ret = float64_add(arg1, arg2, &env->fp_status);
int status = get_float_exception_flags(&env->fp_status);
farg1.ll = arg1;
farg2.ll = arg2;
if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
/* Magnitude subtraction of infinities */
farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
float64_is_signaling_nan(farg2.d, &env->fp_status))) {
if (unlikely(status & float_flag_invalid)) {
if (float64_is_infinity(arg1) && float64_is_infinity(arg2)) {
/* Magnitude subtraction of infinities */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
} else if (float64_is_signaling_nan(arg1, &env->fp_status) ||
float64_is_signaling_nan(arg2, &env->fp_status)) {
/* sNaN addition */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
}
return farg1.ll;
return ret;
}
/* fsub - fsub. */
uint64_t helper_fsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
float64 helper_fsub(CPUPPCState *env, float64 arg1, float64 arg2)
{
CPU_DoubleU farg1, farg2;
float64 ret = float64_sub(arg1, arg2, &env->fp_status);
int status = get_float_exception_flags(&env->fp_status);
farg1.ll = arg1;
farg2.ll = arg2;
if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
/* Magnitude subtraction of infinities */
farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
float64_is_signaling_nan(farg2.d, &env->fp_status))) {
/* sNaN subtraction */
if (unlikely(status & float_flag_invalid)) {
if (float64_is_infinity(arg1) && float64_is_infinity(arg2)) {
/* Magnitude subtraction of infinities */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
} else if (float64_is_signaling_nan(arg1, &env->fp_status) ||
float64_is_signaling_nan(arg2, &env->fp_status)) {
/* sNaN addition */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
}
return farg1.ll;
return ret;
}
/* fmul - fmul. */
uint64_t helper_fmul(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
float64 helper_fmul(CPUPPCState *env, float64 arg1, float64 arg2)
{
CPU_DoubleU farg1, farg2;
float64 ret = float64_mul(arg1, arg2, &env->fp_status);
int status = get_float_exception_flags(&env->fp_status);
farg1.ll = arg1;
farg2.ll = arg2;
if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
(float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
/* Multiplication of zero by infinity */
farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
float64_is_signaling_nan(farg2.d, &env->fp_status))) {
if (unlikely(status & float_flag_invalid)) {
if ((float64_is_infinity(arg1) && float64_is_zero(arg2)) ||
(float64_is_zero(arg1) && float64_is_infinity(arg2))) {
/* Multiplication of zero by infinity */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
} else if (float64_is_signaling_nan(arg1, &env->fp_status) ||
float64_is_signaling_nan(arg2, &env->fp_status)) {
/* sNaN multiplication */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
}
return farg1.ll;
return ret;
}
/* fdiv - fdiv. */
uint64_t helper_fdiv(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
float64 helper_fdiv(CPUPPCState *env, float64 arg1, float64 arg2)
{
CPU_DoubleU farg1, farg2;
float64 ret = float64_div(arg1, arg2, &env->fp_status);
int status = get_float_exception_flags(&env->fp_status);
farg1.ll = arg1;
farg2.ll = arg2;
if (unlikely(float64_is_infinity(farg1.d) &&
float64_is_infinity(farg2.d))) {
/* Division of infinity by infinity */
farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1);
} else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
/* Division of zero by zero */
farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1);
} else {
if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) ||
float64_is_signaling_nan(farg2.d, &env->fp_status))) {
/* sNaN division */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
if (unlikely(status)) {
if (status & float_flag_invalid) {
/* Determine what kind of invalid operation was seen. */
if (float64_is_infinity(arg1) && float64_is_infinity(arg2)) {
/* Division of infinity by infinity */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1);
} else if (float64_is_zero(arg1) && float64_is_zero(arg2)) {
/* Division of zero by zero */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1);
} else if (float64_is_signaling_nan(arg1, &env->fp_status) ||
float64_is_signaling_nan(arg2, &env->fp_status)) {
/* sNaN division */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
}
if (status & float_flag_divbyzero) {
float_zero_divide_excp(env, GETPC());
}
farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
}
return farg1.ll;
return ret;
}
@ -860,40 +895,48 @@ uint64_t helper_frsp(CPUPPCState *env, uint64_t arg)
}
/* fsqrt - fsqrt. */
uint64_t helper_fsqrt(CPUPPCState *env, uint64_t arg)
float64 helper_fsqrt(CPUPPCState *env, float64 arg)
{
CPU_DoubleU farg;
float64 ret = float64_sqrt(arg, &env->fp_status);
int status = get_float_exception_flags(&env->fp_status);
farg.ll = arg;
if (unlikely(float64_is_any_nan(farg.d))) {
if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
/* sNaN reciprocal square root */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
farg.ll = float64_snan_to_qnan(farg.ll);
if (unlikely(status & float_flag_invalid)) {
if (unlikely(float64_is_any_nan(arg))) {
if (unlikely(float64_is_signaling_nan(arg, &env->fp_status))) {
/* sNaN square root */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
} else {
/* Square root of a negative nonzero number */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
}
} else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
/* Square root of a negative nonzero number */
farg.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
} else {
farg.d = float64_sqrt(farg.d, &env->fp_status);
}
return farg.ll;
return ret;
}
/* fre - fre. */
uint64_t helper_fre(CPUPPCState *env, uint64_t arg)
float64 helper_fre(CPUPPCState *env, float64 arg)
{
CPU_DoubleU farg;
/* "Estimate" the reciprocal with actual division. */
float64 ret = float64_div(float64_one, arg, &env->fp_status);
int status = get_float_exception_flags(&env->fp_status);
farg.ll = arg;
if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
/* sNaN reciprocal */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
if (unlikely(status)) {
if (status & float_flag_invalid) {
if (float64_is_signaling_nan(arg, &env->fp_status)) {
/* sNaN reciprocal */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
}
if (status & float_flag_divbyzero) {
float_zero_divide_excp(env, GETPC());
/* For FPSCR.ZE == 0, the result is 1/2. */
ret = float64_set_sign(float64_half, float64_is_neg(arg));
}
}
farg.d = float64_div(float64_one, farg.d, &env->fp_status);
return farg.d;
return ret;
}
/* fres - fres. */
@ -916,27 +959,30 @@ uint64_t helper_fres(CPUPPCState *env, uint64_t arg)
}
/* frsqrte - frsqrte. */
uint64_t helper_frsqrte(CPUPPCState *env, uint64_t arg)
float64 helper_frsqrte(CPUPPCState *env, float64 arg)
{
CPU_DoubleU farg;
/* "Estimate" the reciprocal with actual division. */
float64 rets = float64_sqrt(arg, &env->fp_status);
float64 retd = float64_div(float64_one, rets, &env->fp_status);
int status = get_float_exception_flags(&env->fp_status);
farg.ll = arg;
if (unlikely(float64_is_any_nan(farg.d))) {
if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) {
/* sNaN reciprocal square root */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
farg.ll = float64_snan_to_qnan(farg.ll);
if (unlikely(status)) {
if (status & float_flag_invalid) {
if (float64_is_signaling_nan(arg, &env->fp_status)) {
/* sNaN reciprocal */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
} else {
/* Square root of a negative nonzero number */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
}
}
if (status & float_flag_divbyzero) {
/* Reciprocal of (square root of) zero. */
float_zero_divide_excp(env, GETPC());
}
} else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
/* Reciprocal square root of a negative nonzero number */
farg.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
} else {
farg.d = float64_sqrt(farg.d, &env->fp_status);
farg.d = float64_div(float64_one, farg.d, &env->fp_status);
}
return farg.ll;
return retd;
}
/* fsel - fsel. */
@ -1919,6 +1965,9 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
tp##_is_signaling_nan(xb.fld, &tstat)) { \
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \
} \
} \
if (unlikely(tstat.float_exception_flags & float_flag_divbyzero)) { \
float_zero_divide_excp(env, GETPC()); \
} \
\
if (r2sp) { \
@ -1969,6 +2018,9 @@ void helper_xsdivqp(CPUPPCState *env, uint32_t opcode)
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
}
if (unlikely(tstat.float_exception_flags & float_flag_divbyzero)) {
float_zero_divide_excp(env, GETPC());
}
helper_compute_fprf_float128(env, xt.f128);
putVSR(rD(opcode) + 32, &xt, env);

View File

@ -61,8 +61,8 @@ DEF_HELPER_2(compute_fprf_float64, void, env, i64)
DEF_HELPER_3(store_fpscr, void, env, i64, i32)
DEF_HELPER_2(fpscr_clrbit, void, env, i32)
DEF_HELPER_2(fpscr_setbit, void, env, i32)
DEF_HELPER_2(float64_to_float32, i32, env, i64)
DEF_HELPER_2(float32_to_float64, i64, env, i32)
DEF_HELPER_FLAGS_1(todouble, TCG_CALL_NO_RWG_SE, i64, i32)
DEF_HELPER_FLAGS_1(tosingle, TCG_CALL_NO_RWG_SE, i32, i64)
DEF_HELPER_4(fcmpo, void, env, i64, i64, i32)
DEF_HELPER_4(fcmpu, void, env, i64, i64, i32)
@ -85,15 +85,15 @@ DEF_HELPER_2(friz, i64, env, i64)
DEF_HELPER_2(frip, i64, env, i64)
DEF_HELPER_2(frim, i64, env, i64)
DEF_HELPER_3(fadd, i64, env, i64, i64)
DEF_HELPER_3(fsub, i64, env, i64, i64)
DEF_HELPER_3(fmul, i64, env, i64, i64)
DEF_HELPER_3(fdiv, i64, env, i64, i64)
DEF_HELPER_3(fadd, f64, env, f64, f64)
DEF_HELPER_3(fsub, f64, env, f64, f64)
DEF_HELPER_3(fmul, f64, env, f64, f64)
DEF_HELPER_3(fdiv, f64, env, f64, f64)
DEF_HELPER_4(fmadd, i64, env, i64, i64, i64)
DEF_HELPER_4(fmsub, i64, env, i64, i64, i64)
DEF_HELPER_4(fnmadd, i64, env, i64, i64, i64)
DEF_HELPER_4(fnmsub, i64, env, i64, i64, i64)
DEF_HELPER_2(fsqrt, i64, env, i64)
DEF_HELPER_2(fsqrt, f64, env, f64)
DEF_HELPER_2(fre, i64, env, i64)
DEF_HELPER_2(fres, i64, env, i64)
DEF_HELPER_2(frsqrte, i64, env, i64)

View File

@ -2671,16 +2671,14 @@ static int bcd_cmp_mag(ppc_avr_t *a, ppc_avr_t *b)
return 0;
}
static int bcd_add_mag(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b, int *invalid,
static void bcd_add_mag(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b, int *invalid,
int *overflow)
{
int carry = 0;
int i;
int is_zero = 1;
for (i = 1; i <= 31; i++) {
uint8_t digit = bcd_get_digit(a, i, invalid) +
bcd_get_digit(b, i, invalid) + carry;
is_zero &= (digit == 0);
if (digit > 9) {
carry = 1;
digit -= 10;
@ -2689,26 +2687,20 @@ static int bcd_add_mag(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b, int *invalid,
}
bcd_put_digit(t, digit, i);
if (unlikely(*invalid)) {
return -1;
}
}
*overflow = carry;
return is_zero;
}
static int bcd_sub_mag(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b, int *invalid,
static void bcd_sub_mag(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b, int *invalid,
int *overflow)
{
int carry = 0;
int i;
int is_zero = 1;
for (i = 1; i <= 31; i++) {
uint8_t digit = bcd_get_digit(a, i, invalid) -
bcd_get_digit(b, i, invalid) + carry;
is_zero &= (digit == 0);
if (digit & 0x80) {
carry = -1;
digit += 10;
@ -2717,14 +2709,9 @@ static int bcd_sub_mag(ppc_avr_t *t, ppc_avr_t *a, ppc_avr_t *b, int *invalid,
}
bcd_put_digit(t, digit, i);
if (unlikely(*invalid)) {
return -1;
}
}
*overflow = carry;
return is_zero;
}
uint32_t helper_bcdadd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
@ -2734,23 +2721,28 @@ uint32_t helper_bcdadd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
int sgnb = bcd_get_sgn(b);
int invalid = (sgna == 0) || (sgnb == 0);
int overflow = 0;
int zero = 0;
uint32_t cr = 0;
ppc_avr_t result = { .u64 = { 0, 0 } };
if (!invalid) {
if (sgna == sgnb) {
result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgna, ps);
zero = bcd_add_mag(&result, a, b, &invalid, &overflow);
cr = (sgna > 0) ? CRF_GT : CRF_LT;
} else if (bcd_cmp_mag(a, b) > 0) {
result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgna, ps);
zero = bcd_sub_mag(&result, a, b, &invalid, &overflow);
cr = (sgna > 0) ? CRF_GT : CRF_LT;
bcd_add_mag(&result, a, b, &invalid, &overflow);
cr = bcd_cmp_zero(&result);
} else {
result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgnb, ps);
zero = bcd_sub_mag(&result, b, a, &invalid, &overflow);
cr = (sgnb > 0) ? CRF_GT : CRF_LT;
int magnitude = bcd_cmp_mag(a, b);
if (magnitude > 0) {
result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgna, ps);
bcd_sub_mag(&result, a, b, &invalid, &overflow);
cr = (sgna > 0) ? CRF_GT : CRF_LT;
} else if (magnitude < 0) {
result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgnb, ps);
bcd_sub_mag(&result, b, a, &invalid, &overflow);
cr = (sgnb > 0) ? CRF_GT : CRF_LT;
} else {
result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(0, ps);
cr = CRF_EQ;
}
}
}
@ -2759,8 +2751,6 @@ uint32_t helper_bcdadd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
cr = CRF_SO;
} else if (overflow) {
cr |= CRF_SO;
} else if (zero) {
cr = CRF_EQ;
}
*r = result;

View File

@ -211,6 +211,7 @@ struct DisasContext {
bool gtse;
ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
int singlestep_enabled;
uint32_t flags;
uint64_t insns_flags;
uint64_t insns_flags2;
};
@ -251,6 +252,17 @@ struct opc_handler_t {
#endif
};
/* SPR load/store helpers */
static inline void gen_load_spr(TCGv t, int reg)
{
tcg_gen_ld_tl(t, cpu_env, offsetof(CPUPPCState, spr[reg]));
}
static inline void gen_store_spr(int reg, TCGv t)
{
tcg_gen_st_tl(t, cpu_env, offsetof(CPUPPCState, spr[reg]));
}
static inline void gen_set_access_type(DisasContext *ctx, int access_type)
{
if (ctx->need_access_type && ctx->access_type != access_type) {
@ -313,6 +325,38 @@ static void gen_exception_nip(DisasContext *ctx, uint32_t excp,
ctx->exception = (excp);
}
/* Translates the EXCP_TRACE/BRANCH exceptions used on most PowerPCs to
* EXCP_DEBUG, if we are running on cores using the debug enable bit (e.g.
* BookE).
*/
static uint32_t gen_prep_dbgex(DisasContext *ctx, uint32_t excp)
{
if ((ctx->singlestep_enabled & CPU_SINGLE_STEP)
&& (excp == POWERPC_EXCP_BRANCH)) {
/* Trace excpt. has priority */
excp = POWERPC_EXCP_TRACE;
}
if (ctx->flags & POWERPC_FLAG_DE) {
target_ulong dbsr = 0;
switch (excp) {
case POWERPC_EXCP_TRACE:
dbsr = DBCR0_ICMP;
break;
case POWERPC_EXCP_BRANCH:
dbsr = DBCR0_BRT;
break;
}
TCGv t0 = tcg_temp_new();
gen_load_spr(t0, SPR_BOOKE_DBSR);
tcg_gen_ori_tl(t0, t0, dbsr);
gen_store_spr(SPR_BOOKE_DBSR, t0);
tcg_temp_free(t0);
return POWERPC_EXCP_DEBUG;
} else {
return excp;
}
}
static void gen_debug_exception(DisasContext *ctx)
{
TCGv_i32 t0;
@ -575,17 +619,6 @@ typedef struct opcode_t {
}
#endif
/* SPR load/store helpers */
static inline void gen_load_spr(TCGv t, int reg)
{
tcg_gen_ld_tl(t, cpu_env, offsetof(CPUPPCState, spr[reg]));
}
static inline void gen_store_spr(int reg, TCGv t)
{
tcg_gen_st_tl(t, cpu_env, offsetof(CPUPPCState, spr[reg]));
}
/* Invalid instruction */
static void gen_invalid(DisasContext *ctx)
{
@ -3602,6 +3635,24 @@ static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest)
#endif
}
static void gen_lookup_and_goto_ptr(DisasContext *ctx)
{
int sse = ctx->singlestep_enabled;
if (unlikely(sse)) {
if (sse & GDBSTUB_SINGLE_STEP) {
gen_debug_exception(ctx);
} else if (sse & (CPU_SINGLE_STEP | CPU_BRANCH_STEP)) {
uint32_t excp = gen_prep_dbgex(ctx, POWERPC_EXCP_BRANCH);
if (excp != POWERPC_EXCP_NONE) {
gen_exception(ctx, excp);
}
}
tcg_gen_exit_tb(NULL, 0);
} else {
tcg_gen_lookup_and_goto_ptr();
}
}
/*** Branch ***/
static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
{
@ -3614,18 +3665,7 @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
tcg_gen_exit_tb(ctx->base.tb, n);
} else {
tcg_gen_movi_tl(cpu_nip, dest & ~3);
if (unlikely(ctx->singlestep_enabled)) {
if ((ctx->singlestep_enabled &
(CPU_BRANCH_STEP | CPU_SINGLE_STEP)) &&
(ctx->exception == POWERPC_EXCP_BRANCH ||
ctx->exception == POWERPC_EXCP_TRACE)) {
gen_exception_nip(ctx, POWERPC_EXCP_TRACE, dest);
}
if (ctx->singlestep_enabled & GDBSTUB_SINGLE_STEP) {
gen_debug_exception(ctx);
}
}
tcg_gen_lookup_and_goto_ptr();
gen_lookup_and_goto_ptr(ctx);
}
}
@ -3668,8 +3708,8 @@ static void gen_bcond(DisasContext *ctx, int type)
uint32_t bo = BO(ctx->opcode);
TCGLabel *l1;
TCGv target;
ctx->exception = POWERPC_EXCP_BRANCH;
if (type == BCOND_LR || type == BCOND_CTR || type == BCOND_TAR) {
target = tcg_temp_local_new();
if (type == BCOND_CTR)
@ -3733,10 +3773,11 @@ static void gen_bcond(DisasContext *ctx, int type)
} else {
tcg_gen_andi_tl(cpu_nip, target, ~3);
}
tcg_gen_lookup_and_goto_ptr();
gen_lookup_and_goto_ptr(ctx);
tcg_temp_free(target);
}
if ((bo & 0x14) != 0x14) {
/* fallthrough case */
gen_set_label(l1);
gen_goto_tb(ctx, 1, ctx->base.pc_next);
}
@ -7419,6 +7460,7 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
ctx->need_access_type = !(env->mmu_model & POWERPC_MMU_64B);
ctx->le_mode = !!(env->hflags & (1 << MSR_LE));
ctx->default_tcg_memop_mask = ctx->le_mode ? MO_LE : MO_BE;
ctx->flags = env->flags;
#if defined(TARGET_PPC64)
ctx->sf_mode = msr_is_64bit(env, env->msr);
ctx->has_cfar = !!(env->flags & POWERPC_FLAG_CFAR);
@ -7455,6 +7497,17 @@ static void ppc_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
ctx->singlestep_enabled = 0;
if ((env->flags & POWERPC_FLAG_BE) && msr_be)
ctx->singlestep_enabled |= CPU_BRANCH_STEP;
if ((env->flags & POWERPC_FLAG_DE) && msr_de) {
ctx->singlestep_enabled = 0;
target_ulong dbcr0 = env->spr[SPR_BOOKE_DBCR0];
if (dbcr0 & DBCR0_ICMP) {
ctx->singlestep_enabled |= CPU_SINGLE_STEP;
}
if (dbcr0 & DBCR0_BRT) {
ctx->singlestep_enabled |= CPU_BRANCH_STEP;
}
}
if (unlikely(ctx->base.singlestep_enabled)) {
ctx->singlestep_enabled |= GDBSTUB_SINGLE_STEP;
}
@ -7565,7 +7618,9 @@ static void ppc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
ctx->exception != POWERPC_SYSCALL &&
ctx->exception != POWERPC_EXCP_TRAP &&
ctx->exception != POWERPC_EXCP_BRANCH)) {
gen_exception_nip(ctx, POWERPC_EXCP_TRACE, ctx->base.pc_next);
uint32_t excp = gen_prep_dbgex(ctx, POWERPC_EXCP_TRACE);
if (excp != POWERPC_EXCP_NONE)
gen_exception_nip(ctx, excp, ctx->base.pc_next);
}
if (tcg_check_temp_count()) {

View File

@ -660,15 +660,12 @@ GEN_LDUF(name, ldop, op | 0x21, type); \
GEN_LDUXF(name, ldop, op | 0x01, type); \
GEN_LDXF(name, ldop, 0x17, op | 0x00, type)
static inline void gen_qemu_ld32fs(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
static void gen_qemu_ld32fs(DisasContext *ctx, TCGv_i64 dest, TCGv addr)
{
TCGv t0 = tcg_temp_new();
TCGv_i32 t1 = tcg_temp_new_i32();
gen_qemu_ld32u(ctx, t0, arg2);
tcg_gen_trunc_tl_i32(t1, t0);
tcg_temp_free(t0);
gen_helper_float32_to_float64(arg1, cpu_env, t1);
tcg_temp_free_i32(t1);
TCGv_i32 tmp = tcg_temp_new_i32();
tcg_gen_qemu_ld_i32(tmp, addr, ctx->mem_idx, DEF_MEMOP(MO_UL));
gen_helper_todouble(dest, tmp);
tcg_temp_free_i32(tmp);
}
/* lfd lfdu lfdux lfdx */
@ -836,15 +833,12 @@ GEN_STUF(name, stop, op | 0x21, type); \
GEN_STUXF(name, stop, op | 0x01, type); \
GEN_STXF(name, stop, 0x17, op | 0x00, type)
static inline void gen_qemu_st32fs(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
static void gen_qemu_st32fs(DisasContext *ctx, TCGv_i64 src, TCGv addr)
{
TCGv_i32 t0 = tcg_temp_new_i32();
TCGv t1 = tcg_temp_new();
gen_helper_float64_to_float32(t0, cpu_env, arg1);
tcg_gen_extu_i32_tl(t1, t0);
tcg_temp_free_i32(t0);
gen_qemu_st32(ctx, t1, arg2);
tcg_temp_free(t1);
TCGv_i32 tmp = tcg_temp_new_i32();
gen_helper_tosingle(tmp, src);
tcg_gen_qemu_st_i32(tmp, addr, ctx->mem_idx, DEF_MEMOP(MO_UL));
tcg_temp_free_i32(tmp);
}
/* stfd stfdu stfdux stfdx */

View File

@ -498,6 +498,7 @@ static void spr_write_40x_pit(DisasContext *ctx, int sprn, int gprn)
static void spr_write_40x_dbcr0(DisasContext *ctx, int sprn, int gprn)
{
gen_store_spr(sprn, cpu_gpr[gprn]);
gen_helper_store_40x_dbcr0(cpu_env, cpu_gpr[gprn]);
/* We must stop translation as we may have rebooted */
gen_stop_exception(ctx);
@ -1769,6 +1770,14 @@ static void gen_spr_BookE(CPUPPCState *env, uint64_t ivor_mask)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
spr_register(env, SPR_BOOKE_DSRR0, "DSRR0",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
spr_register(env, SPR_BOOKE_DSRR1, "DSRR1",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_BOOKE_DBSR, "DBSR",
SPR_NOACCESS, SPR_NOACCESS,
@ -1841,6 +1850,14 @@ static void gen_spr_BookE(CPUPPCState *env, uint64_t ivor_mask)
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
spr_register(env, SPR_BOOKE_SPRG8, "SPRG8",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
spr_register(env, SPR_BOOKE_SPRG9, "SPRG9",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
}
static inline uint32_t gen_tlbncfg(uint32_t assoc, uint32_t minsize,
@ -10278,6 +10295,8 @@ static void ppc_cpu_reset(CPUState *s)
#endif
#if defined(CONFIG_USER_ONLY)
msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */
msr |= (target_ulong)1 << MSR_FE0; /* Allow floating point exceptions */
msr |= (target_ulong)1 << MSR_FE1;
msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */
msr |= (target_ulong)1 << MSR_VSX; /* Allow VSX usage */
msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */

View File

@ -75,13 +75,11 @@ typedef struct testdef {
static testdef_t tests[] = {
{ "alpha", "clipper", "", "PCI:" },
{ "ppc", "ppce500", "", "U-Boot" },
{ "ppc", "prep", "-m 96", "Memory size: 96 MB" },
{ "ppc", "40p", "-boot d", "Booting from device d" },
{ "ppc", "g3beige", "", "PowerPC,750" },
{ "ppc", "mac99", "", "PowerPC,G4" },
{ "ppc", "sam460ex", "-m 256", "DRAM: 256 MiB" },
{ "ppc64", "ppce500", "", "U-Boot" },
{ "ppc64", "prep", "-boot e", "Booting from device e" },
{ "ppc64", "40p", "-m 192", "Memory size: 192 MB" },
{ "ppc64", "mac99", "", "PowerPC,970FX" },
{ "ppc64", "pseries", "", "Open Firmware" },