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.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_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_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 # 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 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) 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); pmac_format_nvram_partition(nvr, 0x2000);
/* No PCI init: the BIOS will do it */ /* 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_NB_CPUS, (uint16_t)smp_cpus);
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_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); 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 */ /* 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_NB_CPUS, (uint16_t)smp_cpus);
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_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); 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; 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; ref405ep_fpga_t *fpga;
uint32_t ret; uint32_t ret;
@ -87,8 +87,8 @@ static uint32_t ref405ep_fpga_readb (void *opaque, hwaddr addr)
return ret; return ret;
} }
static void ref405ep_fpga_writeb (void *opaque, static void ref405ep_fpga_writeb(void *opaque, hwaddr addr, uint64_t value,
hwaddr addr, uint32_t value) unsigned size)
{ {
ref405ep_fpga_t *fpga; 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 = { static const MemoryRegionOps ref405ep_fpga_ops = {
.old_mmio = { .read = ref405ep_fpga_readb,
.read = { .write = ref405ep_fpga_writeb,
ref405ep_fpga_readb, ref405ep_fpga_readw, ref405ep_fpga_readl, .impl.min_access_size = 1,
}, .impl.max_access_size = 1,
.write = { .valid.min_access_size = 1,
ref405ep_fpga_writeb, ref405ep_fpga_writew, ref405ep_fpga_writel, .valid.max_access_size = 4,
}, .endianness = DEVICE_BIG_ENDIAN,
},
.endianness = DEVICE_NATIVE_ENDIAN,
}; };
static void ref405ep_fpga_reset (void *opaque) static void ref405ep_fpga_reset (void *opaque)

View file

@ -283,7 +283,7 @@ struct ppc4xx_opba_t {
uint8_t pr; 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; ppc4xx_opba_t *opba;
uint32_t ret; uint32_t ret;
@ -307,8 +307,8 @@ static uint32_t opba_readb (void *opaque, hwaddr addr)
return ret; return ret;
} }
static void opba_writeb (void *opaque, static void opba_writeb(void *opaque, hwaddr addr, uint64_t value,
hwaddr addr, uint32_t value) unsigned size)
{ {
ppc4xx_opba_t *opba; ppc4xx_opba_t *opba;
@ -328,61 +328,14 @@ static void opba_writeb (void *opaque,
break; 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 = { static const MemoryRegionOps opba_ops = {
.old_mmio = { .read = opba_readb,
.read = { opba_readb, opba_readw, opba_readl, }, .write = opba_writeb,
.write = { opba_writeb, opba_writew, opba_writel, }, .impl.min_access_size = 1,
}, .impl.max_access_size = 1,
.endianness = DEVICE_NATIVE_ENDIAN, .valid.min_access_size = 1,
.valid.max_access_size = 4,
.endianness = DEVICE_BIG_ENDIAN,
}; };
static void ppc4xx_opba_reset (void *opaque) static void ppc4xx_opba_reset (void *opaque)
@ -750,65 +703,27 @@ struct ppc405_gpio_t {
uint32_t isr1l; 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 #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 #endif
return 0; return 0;
} }
static void ppc405_gpio_writeb (void *opaque, static void ppc405_gpio_write(void *opaque, hwaddr addr, uint64_t value,
hwaddr addr, uint32_t value) unsigned size)
{ {
#ifdef DEBUG_GPIO #ifdef DEBUG_GPIO
printf("%s: addr " TARGET_FMT_plx " val %08" PRIx32 "\n", __func__, addr, printf("%s: addr " TARGET_FMT_plx " size %d val %08" PRIx32 "\n",
value); __func__, addr, size, 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);
#endif #endif
} }
static const MemoryRegionOps ppc405_gpio_ops = { static const MemoryRegionOps ppc405_gpio_ops = {
.old_mmio = { .read = ppc405_gpio_read,
.read = { ppc405_gpio_readb, ppc405_gpio_readw, ppc405_gpio_readl, }, .write = ppc405_gpio_write,
.write = { ppc405_gpio_writeb, ppc405_gpio_writew, ppc405_gpio_writel, },
},
.endianness = DEVICE_NATIVE_ENDIAN, .endianness = DEVICE_NATIVE_ENDIAN,
}; };
@ -1017,44 +932,6 @@ struct ppc4xx_gpt_t {
uint32_t mask[5]; 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) static int ppc4xx_gpt_compare (ppc4xx_gpt_t *gpt, int n)
{ {
/* XXX: TODO */ /* XXX: TODO */
@ -1107,7 +984,7 @@ static void ppc4xx_gpt_compute_timer (ppc4xx_gpt_t *gpt)
/* XXX: TODO */ /* 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; ppc4xx_gpt_t *gpt;
uint32_t ret; uint32_t ret;
@ -1162,8 +1039,8 @@ static uint32_t ppc4xx_gpt_readl (void *opaque, hwaddr addr)
return ret; return ret;
} }
static void ppc4xx_gpt_writel (void *opaque, static void ppc4xx_gpt_write(void *opaque, hwaddr addr, uint64_t value,
hwaddr addr, uint32_t value) unsigned size)
{ {
ppc4xx_gpt_t *gpt; ppc4xx_gpt_t *gpt;
int idx; int idx;
@ -1225,10 +1102,10 @@ static void ppc4xx_gpt_writel (void *opaque,
} }
static const MemoryRegionOps gpt_ops = { static const MemoryRegionOps gpt_ops = {
.old_mmio = { .read = ppc4xx_gpt_read,
.read = { ppc4xx_gpt_readb, ppc4xx_gpt_readw, ppc4xx_gpt_readl, }, .write = ppc4xx_gpt_write,
.write = { ppc4xx_gpt_writeb, ppc4xx_gpt_writew, ppc4xx_gpt_writel, }, .valid.min_access_size = 4,
}, .valid.max_access_size = 4,
.endianness = DEVICE_NATIVE_ENDIAN, .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 */ /* ISA IO ports bridge */
#define PPC_IO_BASE 0x80000000 #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) */ /* Fake super-io ports for PREP platform (Intel 82378ZB) */
typedef struct sysctrl_t { typedef struct sysctrl_t {
qemu_irq reset_irq; 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_init(&prep_port_list, NULL, prep_portio_list, sysctrl, "prep");
portio_list_add(&prep_port_list, isa_address_space_io(isa), 0x0); portio_list_add(&prep_port_list, isa_address_space_io(isa), 0x0);
/* PowerPC control and status register group */ /*
#if 0 * PowerPC control and status register group: unimplemented,
memory_region_init_io(xcsr, NULL, &PPC_XCSR_ops, NULL, "ppc-xcsr", 0x1000); * would be at address 0xFEFF0000.
memory_region_add_subregion(sysmem, 0xFEFF0000, xcsr); */
#endif
if (machine_usb(machine)) { if (machine_usb(machine)) {
pci_create_simple(pci_bus, -1, "pci-ohci"); 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) static void prep_machine_init(MachineClass *mc)
{ {
mc->deprecation_reason = "use 40p machine type instead";
mc->desc = "PowerPC PREP platform"; mc->desc = "PowerPC PREP platform";
mc->init = ppc_prep_init; mc->init = ppc_prep_init;
mc->block_default_type = IF_IDE; mc->block_default_type = IF_IDE;
@ -706,7 +618,7 @@ static void ibm_40p_init(MachineState *machine)
uint16_t cmos_checksum; uint16_t cmos_checksum;
PowerPCCPU *cpu; PowerPCCPU *cpu;
DeviceState *dev; DeviceState *dev;
SysBusDevice *pcihost; SysBusDevice *pcihost, *s;
Nvram *m48t59 = NULL; Nvram *m48t59 = NULL;
PCIBus *pci_bus; PCIBus *pci_bus;
ISABus *isa_bus; ISABus *isa_bus;
@ -799,7 +711,16 @@ static void ibm_40p_init(MachineState *machine)
} }
/* Prepare firmware configuration for OpenBIOS */ /* 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) { if (machine->kernel_filename) {
/* load kernel */ /* load kernel */

View file

@ -54,7 +54,6 @@
#include "hw/ppc/spapr.h" #include "hw/ppc/spapr.h"
#include "hw/ppc/spapr_vio.h" #include "hw/ppc/spapr_vio.h"
#include "hw/pci-host/spapr.h" #include "hw/pci-host/spapr.h"
#include "hw/ppc/xics.h"
#include "hw/pci/msi.h" #include "hw/pci/msi.h"
#include "hw/pci/pci.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; 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) static bool pre_2_10_vmstate_dummy_icp_needed(void *opaque)
{ {
/* Dummy entries correspond to unused ICPState objects in older QEMUs, /* 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); 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, static int spapr_fixup_cpu_smt_dt(void *fdt, int offset, PowerPCCPU *cpu,
int smt_threads) 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); 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(); qemu_devices_reset();
/* DRC reset may cause a device to be unplugged. This will cause troubles /* 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 = { static const VMStateDescription vmstate_spapr = {
.name = "spapr", .name = "spapr",
.version_id = 3, .version_id = 3,
@ -1937,6 +1899,7 @@ static const VMStateDescription vmstate_spapr = {
&vmstate_spapr_cap_cfpc, &vmstate_spapr_cap_cfpc,
&vmstate_spapr_cap_sbbc, &vmstate_spapr_cap_sbbc,
&vmstate_spapr_cap_ibs, &vmstate_spapr_cap_ibs,
&vmstate_spapr_irq_map,
NULL NULL
} }
}; };
@ -2590,7 +2553,7 @@ static void spapr_machine_init(MachineState *machine)
load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD; load_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FW_OVERHEAD;
/* Set up Interrupt Controller before we create the VCPUs */ /* 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 /* 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; 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, static void spapr_pic_print_info(InterruptStatsProvider *obj,
Monitor *mon) Monitor *mon)
{ {
sPAPRMachineState *spapr = SPAPR_MACHINE(obj); sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
CPUState *cs; sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
CPU_FOREACH(cs) { smc->irq->print_info(spapr, mon);
PowerPCCPU *cpu = POWERPC_CPU(cs);
icp_pic_print_info(ICP(cpu->intc), mon);
}
ics_pic_print_info(spapr->ics, mon);
} }
int spapr_get_vcpu_id(PowerPCCPU *cpu) 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_IBS] = SPAPR_CAP_BROKEN;
smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 16; /* 64kiB */ smc->default_caps.caps[SPAPR_CAP_HPT_MAXPAGESIZE] = 16; /* 64kiB */
spapr_caps_add_properties(smc, &error_abort); spapr_caps_add_properties(smc, &error_abort);
smc->irq = &spapr_irq_xics;
} }
static const TypeInfo spapr_machine_info = { static const TypeInfo spapr_machine_info = {
@ -4060,18 +3916,41 @@ static const TypeInfo spapr_machine_info = {
type_init(spapr_machine_register_##suffix) 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 */ /* 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 * pseries-2.12

View file

@ -11,6 +11,7 @@
#include "hw/ppc/spapr_cpu_core.h" #include "hw/ppc/spapr_cpu_core.h"
#include "target/ppc/cpu.h" #include "target/ppc/cpu.h"
#include "hw/ppc/spapr.h" #include "hw/ppc/spapr.h"
#include "hw/ppc/xics.h" /* for icp_create() - to be removed */
#include "hw/boards.h" #include "hw/boards.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "sysemu/cpus.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); 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) static bool slb_shadow_needed(void *opaque)
{ {
sPAPRCPUState *spapr_cpu = 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, static void spapr_realize_vcpu(PowerPCCPU *cpu, sPAPRMachineState *spapr,
Error **errp) sPAPRCPUCore *sc, Error **errp)
{ {
CPUPPCState *env = &cpu->env; CPUPPCState *env = &cpu->env;
CPUState *cs = CPU(cpu);
Error *local_err = NULL; Error *local_err = NULL;
object_property_set_bool(OBJECT(cpu), true, "realized", &local_err); 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; goto error_unregister;
} }
if (!sc->pre_3_0_migration) {
vmstate_register(NULL, cs->cpu_index, &vmstate_spapr_cpu_state,
cpu->machine_data);
}
return; return;
error_unregister: error_unregister:
@ -272,10 +282,6 @@ static PowerPCCPU *spapr_create_vcpu(sPAPRCPUCore *sc, int i, Error **errp)
} }
cpu->machine_data = g_new0(sPAPRCPUState, 1); 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); object_unref(obj);
return cpu; return cpu;
@ -290,9 +296,6 @@ static void spapr_delete_vcpu(PowerPCCPU *cpu, sPAPRCPUCore *sc)
{ {
sPAPRCPUState *spapr_cpu = spapr_cpu_state(cpu); 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; cpu->machine_data = NULL;
g_free(spapr_cpu); g_free(spapr_cpu);
object_unparent(OBJECT(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++) { 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) { if (local_err) {
goto err_unrealize; goto err_unrealize;
} }
@ -334,7 +337,7 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
err_unrealize: err_unrealize:
while (--j >= 0) { while (--j >= 0) {
spapr_unrealize_vcpu(sc->threads[j]); spapr_unrealize_vcpu(sc->threads[j], sc);
} }
err: err:
while (--i >= 0) { while (--i >= 0) {

View file

@ -707,9 +707,11 @@ void spapr_clear_pending_events(sPAPRMachineState *spapr)
void spapr_events_init(sPAPRMachineState *spapr) void spapr_events_init(sPAPRMachineState *spapr)
{ {
int epow_irq; int epow_irq = SPAPR_IRQ_EPOW;
if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
epow_irq = spapr_irq_findone(spapr, &error_fatal); epow_irq = spapr_irq_findone(spapr, &error_fatal);
}
spapr_irq_claim(spapr, epow_irq, false, &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. * checking that it's enabled.
*/ */
if (spapr->use_hotplug_event_source) { if (spapr->use_hotplug_event_source) {
int hp_irq; int hp_irq = SPAPR_IRQ_HOTPLUG;
if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) {
hp_irq = spapr_irq_findone(spapr, &error_fatal); hp_irq = spapr_irq_findone(spapr, &error_fatal);
}
spapr_irq_claim(spapr, hp_irq, false, &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 args, uint32_t nret,
target_ulong rets) target_ulong rets)
{ {
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
uint32_t config_addr = rtas_ld(args, 0); uint32_t config_addr = rtas_ld(args, 0);
uint64_t buid = rtas_ldq(args, 1); uint64_t buid = rtas_ldq(args, 1);
unsigned int func = rtas_ld(args, 3); unsigned int func = rtas_ld(args, 3);
@ -334,6 +335,9 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return; 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); spapr_irq_free(spapr, msi->first_irq, msi->num);
if (msi_present(pdev)) { if (msi_present(pdev)) {
spapr_msi_setmsg(pdev, 0, false, 0, 0); spapr_msi_setmsg(pdev, 0, false, 0, 0);
@ -372,7 +376,13 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
} }
/* Allocate MSIs */ /* 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) { if (err) {
error_reportf_err(err, "Can't allocate MSIs for device %x: ", error_reportf_err(err, "Can't allocate MSIs for device %x: ",
config_addr); config_addr);
@ -392,6 +402,9 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPRMachineState *spapr,
/* Release previous MSIs */ /* Release previous MSIs */
if (msi) { 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); spapr_irq_free(spapr, msi->first_irq, msi->num);
g_hash_table_remove(phb->msi, &config_addr); g_hash_table_remove(phb->msi, &config_addr);
} }
@ -1546,6 +1559,7 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
sPAPRMachineState *spapr = sPAPRMachineState *spapr =
(sPAPRMachineState *) object_dynamic_cast(qdev_get_machine(), (sPAPRMachineState *) object_dynamic_cast(qdev_get_machine(),
TYPE_SPAPR_MACHINE); TYPE_SPAPR_MACHINE);
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
SysBusDevice *s = SYS_BUS_DEVICE(dev); SysBusDevice *s = SYS_BUS_DEVICE(dev);
sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s); sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s);
PCIHostState *phb = 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) { if (sphb->index != (uint32_t)-1) {
sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr);
Error *local_err = NULL; Error *local_err = NULL;
smc->phb_placement(spapr, sphb->index, smc->phb_placement(spapr, sphb->index,
@ -1705,15 +1718,17 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp)
/* Initialize the LSI table */ /* Initialize the LSI table */
for (i = 0; i < PCI_NUM_PINS; i++) { 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; Error *local_err = NULL;
if (smc->legacy_irq_allocation) {
irq = spapr_irq_findone(spapr, &local_err); irq = spapr_irq_findone(spapr, &local_err);
if (local_err) { if (local_err) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
error_prepend(errp, "can't allocate LSIs: "); error_prepend(errp, "can't allocate LSIs: ");
return; return;
} }
}
spapr_irq_claim(spapr, irq, true, &local_err); spapr_irq_claim(spapr, irq, true, &local_err);
if (local_err) { if (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, "ranges", &ranges, sizeof_ranges));
_FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg))); _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)); _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)); _FDT(fdt_setprop_cell(fdt, bus_off, "ibm,pe-total-#msi", XICS_IRQS_SPAPR));
/* Dynamic DMA window */ /* Dynamic DMA window */

View file

@ -37,12 +37,13 @@
#include "hw/ppc/spapr.h" #include "hw/ppc/spapr.h"
#include "hw/ppc/spapr_vio.h" #include "hw/ppc/spapr_vio.h"
#include "hw/ppc/xics.h"
#include "hw/ppc/fdt.h" #include "hw/ppc/fdt.h"
#include "trace.h" #include "trace.h"
#include <libfdt.h> #include <libfdt.h>
#define SPAPR_VIO_REG_BASE 0x71000000
static void spapr_vio_get_irq(Object *obj, Visitor *v, const char *name, static void spapr_vio_get_irq(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp) 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) static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp)
{ {
sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
@ -485,12 +535,16 @@ static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp)
} }
if (!dev->irq) { if (!dev->irq) {
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); dev->irq = spapr_irq_findone(spapr, &local_err);
if (local_err) { if (local_err) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
return; return;
} }
} }
}
spapr_irq_claim(spapr, dev->irq, false, &local_err); spapr_irq_claim(spapr, dev->irq, false, &local_err);
if (local_err) { if (local_err) {
@ -557,7 +611,7 @@ VIOsPAPRBus *spapr_vio_bus_init(void)
/* Create bus on bridge device */ /* Create bus on bridge device */
qbus = qbus_create(TYPE_SPAPR_VIO_BUS, dev, "spapr-vio"); qbus = qbus_create(TYPE_SPAPR_VIO_BUS, dev, "spapr-vio");
bus = SPAPR_VIO_BUS(qbus); bus = SPAPR_VIO_BUS(qbus);
bus->next_reg = 0x71000000; bus->next_reg = SPAPR_VIO_REG_BASE;
/* hcall-vio */ /* hcall-vio */
spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal); 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; info.iova_pgsizes = 4096;
} }
vfio_host_win_add(container, 0, (hwaddr)-1, info.iova_pgsizes); 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) || } else if (ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_SPAPR_TCE_IOMMU) ||
ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_SPAPR_TCE_v2_IOMMU)) { ioctl(fd, VFIO_CHECK_EXTENSION, VFIO_SPAPR_TCE_v2_IOMMU)) {
struct vfio_iommu_spapr_tce_info info; struct vfio_iommu_spapr_tce_info info;
@ -1200,6 +1201,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as,
} }
if (v2) { if (v2) {
container->pgsizes = info.ddw.pgsizes;
/* /*
* There is a default window in just created container. * There is a default window in just created container.
* To make region_add/del simpler, we better remove this * To make region_add/del simpler, we better remove this
@ -1214,6 +1216,7 @@ static int vfio_connect_container(VFIOGroup *group, AddressSpace *as,
} }
} else { } else {
/* The default table uses 4K pages */ /* The default table uses 4K pages */
container->pgsizes = 0x1000;
vfio_host_win_add(container, info.dma32_window_start, vfio_host_win_add(container, info.dma32_window_start,
info.dma32_window_start + info.dma32_window_start +
info.dma32_window_size - 1, info.dma32_window_size - 1,

View file

@ -15,6 +15,7 @@
#include "hw/vfio/vfio-common.h" #include "hw/vfio/vfio-common.h"
#include "hw/hw.h" #include "hw/hw.h"
#include "exec/ram_addr.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "trace.h" #include "trace.h"
@ -144,9 +145,27 @@ int vfio_spapr_create_window(VFIOContainer *container,
{ {
int ret; int ret;
IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr); 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; unsigned entries, pages;
struct vfio_iommu_spapr_tce_create create = { .argsz = sizeof(create) }; 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 * FIXME: For VFIO iommu types which have KVM acceleration to

View file

@ -4,10 +4,10 @@
#include "qemu/units.h" #include "qemu/units.h"
#include "sysemu/dma.h" #include "sysemu/dma.h"
#include "hw/boards.h" #include "hw/boards.h"
#include "hw/ppc/xics.h"
#include "hw/ppc/spapr_drc.h" #include "hw/ppc/spapr_drc.h"
#include "hw/mem/pc-dimm.h" #include "hw/mem/pc-dimm.h"
#include "hw/ppc/spapr_ovec.h" #include "hw/ppc/spapr_ovec.h"
#include "hw/ppc/spapr_irq.h"
struct VIOsPAPRBus; struct VIOsPAPRBus;
struct sPAPRPHBState; struct sPAPRPHBState;
@ -15,6 +15,7 @@ struct sPAPRNVRAM;
typedef struct sPAPREventLogEntry sPAPREventLogEntry; typedef struct sPAPREventLogEntry sPAPREventLogEntry;
typedef struct sPAPREventSource sPAPREventSource; typedef struct sPAPREventSource sPAPREventSource;
typedef struct sPAPRPendingHPT sPAPRPendingHPT; typedef struct sPAPRPendingHPT sPAPRPendingHPT;
typedef struct ICSState ICSState;
#define HPTE64_V_HPTE_DIRTY 0x0000000000000040ULL #define HPTE64_V_HPTE_DIRTY 0x0000000000000040ULL
#define SPAPR_ENTRY_POINT 0x100 #define SPAPR_ENTRY_POINT 0x100
@ -101,12 +102,15 @@ struct sPAPRMachineClass {
bool dr_lmb_enabled; /* enable dynamic-reconfig/hotplug of LMBs */ bool dr_lmb_enabled; /* enable dynamic-reconfig/hotplug of LMBs */
bool use_ohci_by_default; /* use USB-OHCI instead of XHCI */ bool use_ohci_by_default; /* use USB-OHCI instead of XHCI */
bool pre_2_10_has_unused_icps; bool pre_2_10_has_unused_icps;
bool legacy_irq_allocation;
void (*phb_placement)(sPAPRMachineState *spapr, uint32_t index, void (*phb_placement)(sPAPRMachineState *spapr, uint32_t index,
uint64_t *buid, hwaddr *pio, uint64_t *buid, hwaddr *pio,
hwaddr *mmio32, hwaddr *mmio64, hwaddr *mmio32, hwaddr *mmio64,
unsigned n_dma, uint32_t *liobns, Error **errp); unsigned n_dma, uint32_t *liobns, Error **errp);
sPAPRResizeHPT resize_hpt_default; sPAPRResizeHPT resize_hpt_default;
sPAPRCapabilities default_caps; sPAPRCapabilities default_caps;
sPAPRIrq *irq;
}; };
/** /**
@ -167,6 +171,8 @@ struct sPAPRMachineState {
char *kvm_type; char *kvm_type;
const char *icp_type; const char *icp_type;
int32_t irq_map_nr;
unsigned long *irq_map;
bool cmd_line_caps[SPAPR_CAP_NUM]; bool cmd_line_caps[SPAPR_CAP_NUM];
sPAPRCapabilities def, eff, mig; 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); void spapr_set_vcpu_id(PowerPCCPU *cpu, int cpu_index, Error **errp);
PowerPCCPU *spapr_find_cpu(int vcpu_id); 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_load(void *opaque);
int spapr_caps_pre_save(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 #define XICS_H
#include "hw/qdev.h" #include "hw/qdev.h"
#include "target/ppc/cpu-qom.h"
#define XICS_IPI 0x2 #define XICS_IPI 0x2
#define XICS_BUID 0x1 #define XICS_BUID 0x1

View file

@ -73,6 +73,7 @@ typedef struct VFIOContainer {
unsigned iommu_type; unsigned iommu_type;
int error; int error;
bool initialized; bool initialized;
unsigned long pgsizes;
/* /*
* This assumes the host IOMMU can support only a single * This assumes the host IOMMU can support only a single
* contiguous IOVA window. We may need to generalize that in * 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 - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
implementation for certain IBM POWER hardware. The sources are at implementation for certain IBM POWER hardware. The sources are at
https://github.com/aik/SLOF, and the image currently in qemu is 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 - sgabios (the Serial Graphics Adapter option ROM) provides a means for
legacy x86 software to communicate with an attached serial console as 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 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. 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 @section Device options
@subsection Block 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_ts ((env->msr >> MSR_TS1) & 3)
#define msr_tm ((env->msr >> MSR_TM) & 1) #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 */ /* Hypervisor bit is more specific */
#if defined(TARGET_PPC64) #if defined(TARGET_PPC64)
#define MSR_HVB (1ULL << MSR_SHV) #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 */ case POWERPC_EXCP_ITLB: /* Instruction TLB error */
break; break;
case POWERPC_EXCP_DEBUG: /* Debug interrupt */ case POWERPC_EXCP_DEBUG: /* Debug interrupt */
switch (excp_model) { if (env->flags & POWERPC_FLAG_DE) {
case POWERPC_EXCP_BOOKE:
/* FIXME: choose one or the other based on CPU type */ /* FIXME: choose one or the other based on CPU type */
srr0 = SPR_BOOKE_DSRR0; srr0 = SPR_BOOKE_DSRR0;
srr1 = SPR_BOOKE_DSRR1; srr1 = SPR_BOOKE_DSRR1;
asrr0 = SPR_BOOKE_CSRR0; asrr0 = SPR_BOOKE_CSRR0;
asrr1 = SPR_BOOKE_CSRR1; asrr1 = SPR_BOOKE_CSRR1;
break; /* DBSR already modified by caller */
default: } else {
break; cpu_abort(cs, "Debug exception triggered on unsupported model\n");
} }
/* XXX: TODO */
cpu_abort(cs, "Debug exception is not implemented yet !\n");
break; break;
case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */ case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */
env->spr[SPR_BOOKE_ESR] = ESR_SPV; 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 float32_snan_to_qnan(x) ((x) | 0x00400000)
#define float16_snan_to_qnan(x) ((x) | 0x0200) #define float16_snan_to_qnan(x) ((x) | 0x0200)
/*****************************************************************************/ static inline bool fp_exceptions_enabled(CPUPPCState *env)
/* Floating point operations helpers */
uint64_t helper_float32_to_float64(CPUPPCState *env, uint32_t arg)
{ {
CPU_FloatU f; #ifdef CONFIG_USER_ONLY
CPU_DoubleU d; return true;
#else
f.l = arg; return (env->msr & ((1U << MSR_FE0) | (1U << MSR_FE1))) != 0;
d.d = float32_to_float64(f.f, &env->fp_status); #endif
return d.ll;
} }
uint32_t helper_float64_to_float32(CPUPPCState *env, uint64_t arg) /*****************************************************************************/
{ /* Floating point operations helpers */
CPU_FloatU f;
CPU_DoubleU d;
d.ll = arg; /*
f.f = float64_to_float32(d.d, &env->fp_status); * This is the non-arithmatic conversion that happens e.g. on loads.
return f.l; * 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) 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) { if (ve != 0) {
/* Update the floating-point enabled exception summary */ /* Update the floating-point enabled exception summary */
env->fpscr |= 1 << FPSCR_FEX; env->fpscr |= 1 << FPSCR_FEX;
if (msr_fe0 != 0 || msr_fe1 != 0) { if (fp_exceptions_enabled(env)) {
/* GETPC() works here because this is inline */ /* GETPC() works here because this is inline */
raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
POWERPC_EXCP_FP | op, GETPC()); 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) { if (fpscr_ze != 0) {
/* Update the floating-point enabled exception summary */ /* Update the floating-point enabled exception summary */
env->fpscr |= 1 << FPSCR_FEX; 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, raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX, POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX,
raddr); 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); int status = get_float_exception_flags(&env->fp_status);
bool inexact_happened = false; bool inexact_happened = false;
if (status & float_flag_divbyzero) { if (status & float_flag_overflow) {
float_zero_divide_excp(env, raddr);
} else if (status & float_flag_overflow) {
float_overflow_excp(env); float_overflow_excp(env);
} else if (status & float_flag_underflow) { } else if (status & float_flag_underflow) {
float_underflow_excp(env); 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 && if (cs->exception_index == POWERPC_EXCP_PROGRAM &&
(env->error_code & POWERPC_EXCP_FP)) { (env->error_code & POWERPC_EXCP_FP)) {
/* Differred floating-point exception after target FPR update */ /* 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, raise_exception_err_ra(env, cs->exception_index,
env->error_code, raddr); env->error_code, raddr);
} }
@ -580,102 +624,93 @@ void helper_reset_fpstatus(CPUPPCState *env)
} }
/* fadd - fadd. */ /* 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; if (unlikely(status & float_flag_invalid)) {
farg2.ll = arg2; if (float64_is_infinity(arg1) && float64_is_infinity(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 */ /* Magnitude subtraction of infinities */
farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
} else { } else if (float64_is_signaling_nan(arg1, &env->fp_status) ||
if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) || float64_is_signaling_nan(arg2, &env->fp_status)) {
float64_is_signaling_nan(farg2.d, &env->fp_status))) {
/* sNaN addition */ /* sNaN addition */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); 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. */ /* 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; if (unlikely(status & float_flag_invalid)) {
farg2.ll = arg2; if (float64_is_infinity(arg1) && float64_is_infinity(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 */ /* Magnitude subtraction of infinities */
farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1); float_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
} else { } else if (float64_is_signaling_nan(arg1, &env->fp_status) ||
if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) || float64_is_signaling_nan(arg2, &env->fp_status)) {
float64_is_signaling_nan(farg2.d, &env->fp_status))) { /* sNaN addition */
/* sNaN subtraction */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); 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. */ /* 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; if (unlikely(status & float_flag_invalid)) {
farg2.ll = arg2; if ((float64_is_infinity(arg1) && float64_is_zero(arg2)) ||
(float64_is_zero(arg1) && float64_is_infinity(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 */ /* Multiplication of zero by infinity */
farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1); float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
} else { } else if (float64_is_signaling_nan(arg1, &env->fp_status) ||
if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) || float64_is_signaling_nan(arg2, &env->fp_status)) {
float64_is_signaling_nan(farg2.d, &env->fp_status))) {
/* sNaN multiplication */ /* sNaN multiplication */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); 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. */ /* 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; if (unlikely(status)) {
farg2.ll = arg2; if (status & float_flag_invalid) {
/* Determine what kind of invalid operation was seen. */
if (unlikely(float64_is_infinity(farg1.d) && if (float64_is_infinity(arg1) && float64_is_infinity(arg2)) {
float64_is_infinity(farg2.d))) {
/* Division of infinity by infinity */ /* Division of infinity by infinity */
farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1); float_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1);
} else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) { } else if (float64_is_zero(arg1) && float64_is_zero(arg2)) {
/* Division of zero by zero */ /* Division of zero by zero */
farg1.ll = float_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1); float_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1);
} else { } else if (float64_is_signaling_nan(arg1, &env->fp_status) ||
if (unlikely(float64_is_signaling_nan(farg1.d, &env->fp_status) || float64_is_signaling_nan(arg2, &env->fp_status)) {
float64_is_signaling_nan(farg2.d, &env->fp_status))) {
/* sNaN division */ /* sNaN division */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
} }
farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status); }
if (status & float_flag_divbyzero) {
float_zero_divide_excp(env, GETPC());
}
} }
return farg1.ll; return ret;
} }
@ -860,40 +895,48 @@ uint64_t helper_frsp(CPUPPCState *env, uint64_t arg)
} }
/* fsqrt - fsqrt. */ /* 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(status & float_flag_invalid)) {
if (unlikely(float64_is_any_nan(arg))) {
if (unlikely(float64_is_any_nan(farg.d))) { if (unlikely(float64_is_signaling_nan(arg, &env->fp_status))) {
if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) { /* sNaN square root */
/* sNaN reciprocal square root */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
farg.ll = float64_snan_to_qnan(farg.ll);
} }
} 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 { } else {
farg.d = float64_sqrt(farg.d, &env->fp_status); /* Square root of a negative nonzero number */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
} }
return farg.ll; }
return ret;
} }
/* fre - fre. */ /* 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(status)) {
if (status & float_flag_invalid) {
if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) { if (float64_is_signaling_nan(arg, &env->fp_status)) {
/* sNaN reciprocal */ /* sNaN reciprocal */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
} }
farg.d = float64_div(float64_one, farg.d, &env->fp_status); }
return farg.d; 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));
}
}
return ret;
} }
/* fres - fres. */ /* fres - fres. */
@ -916,27 +959,30 @@ uint64_t helper_fres(CPUPPCState *env, uint64_t arg)
} }
/* frsqrte - frsqrte. */ /* 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(status)) {
if (status & float_flag_invalid) {
if (unlikely(float64_is_any_nan(farg.d))) { if (float64_is_signaling_nan(arg, &env->fp_status)) {
if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) { /* sNaN reciprocal */
/* sNaN reciprocal square root */
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
farg.ll = float64_snan_to_qnan(farg.ll);
}
} 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 { } else {
farg.d = float64_sqrt(farg.d, &env->fp_status); /* Square root of a negative nonzero number */
farg.d = float64_div(float64_one, farg.d, &env->fp_status); 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());
}
} }
return farg.ll; return retd;
} }
/* fsel - fsel. */ /* fsel - fsel. */
@ -1919,6 +1965,9 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
tp##_is_signaling_nan(xb.fld, &tstat)) { \ tp##_is_signaling_nan(xb.fld, &tstat)) { \
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ 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) { \ if (r2sp) { \
@ -1969,6 +2018,9 @@ void helper_xsdivqp(CPUPPCState *env, uint32_t opcode)
float_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); 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); helper_compute_fprf_float128(env, xt.f128);
putVSR(rD(opcode) + 32, &xt, env); 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_3(store_fpscr, void, env, i64, i32)
DEF_HELPER_2(fpscr_clrbit, void, env, i32) DEF_HELPER_2(fpscr_clrbit, void, env, i32)
DEF_HELPER_2(fpscr_setbit, void, env, i32) DEF_HELPER_2(fpscr_setbit, void, env, i32)
DEF_HELPER_2(float64_to_float32, i32, env, i64) DEF_HELPER_FLAGS_1(todouble, TCG_CALL_NO_RWG_SE, i64, i32)
DEF_HELPER_2(float32_to_float64, i64, env, 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(fcmpo, void, env, i64, i64, i32)
DEF_HELPER_4(fcmpu, 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(frip, i64, env, i64)
DEF_HELPER_2(frim, i64, env, i64) DEF_HELPER_2(frim, i64, env, i64)
DEF_HELPER_3(fadd, i64, env, i64, i64) DEF_HELPER_3(fadd, f64, env, f64, f64)
DEF_HELPER_3(fsub, i64, env, i64, i64) DEF_HELPER_3(fsub, f64, env, f64, f64)
DEF_HELPER_3(fmul, i64, env, i64, i64) DEF_HELPER_3(fmul, f64, env, f64, f64)
DEF_HELPER_3(fdiv, i64, env, i64, i64) DEF_HELPER_3(fdiv, f64, env, f64, f64)
DEF_HELPER_4(fmadd, i64, env, i64, i64, i64) DEF_HELPER_4(fmadd, i64, env, i64, i64, i64)
DEF_HELPER_4(fmsub, 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(fnmadd, i64, env, i64, i64, i64)
DEF_HELPER_4(fnmsub, 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(fre, i64, env, i64)
DEF_HELPER_2(fres, i64, env, i64) DEF_HELPER_2(fres, i64, env, i64)
DEF_HELPER_2(frsqrte, 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; 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 *overflow)
{ {
int carry = 0; int carry = 0;
int i; int i;
int is_zero = 1;
for (i = 1; i <= 31; i++) { for (i = 1; i <= 31; i++) {
uint8_t digit = bcd_get_digit(a, i, invalid) + uint8_t digit = bcd_get_digit(a, i, invalid) +
bcd_get_digit(b, i, invalid) + carry; bcd_get_digit(b, i, invalid) + carry;
is_zero &= (digit == 0);
if (digit > 9) { if (digit > 9) {
carry = 1; carry = 1;
digit -= 10; 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); bcd_put_digit(t, digit, i);
if (unlikely(*invalid)) {
return -1;
}
} }
*overflow = carry; *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 *overflow)
{ {
int carry = 0; int carry = 0;
int i; int i;
int is_zero = 1;
for (i = 1; i <= 31; i++) { for (i = 1; i <= 31; i++) {
uint8_t digit = bcd_get_digit(a, i, invalid) - uint8_t digit = bcd_get_digit(a, i, invalid) -
bcd_get_digit(b, i, invalid) + carry; bcd_get_digit(b, i, invalid) + carry;
is_zero &= (digit == 0);
if (digit & 0x80) { if (digit & 0x80) {
carry = -1; carry = -1;
digit += 10; 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); bcd_put_digit(t, digit, i);
if (unlikely(*invalid)) {
return -1;
}
} }
*overflow = carry; *overflow = carry;
return is_zero;
} }
uint32_t helper_bcdadd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps) 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 sgnb = bcd_get_sgn(b);
int invalid = (sgna == 0) || (sgnb == 0); int invalid = (sgna == 0) || (sgnb == 0);
int overflow = 0; int overflow = 0;
int zero = 0;
uint32_t cr = 0; uint32_t cr = 0;
ppc_avr_t result = { .u64 = { 0, 0 } }; ppc_avr_t result = { .u64 = { 0, 0 } };
if (!invalid) { if (!invalid) {
if (sgna == sgnb) { if (sgna == sgnb) {
result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgna, ps); result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgna, ps);
zero = bcd_add_mag(&result, a, b, &invalid, &overflow); bcd_add_mag(&result, a, b, &invalid, &overflow);
cr = (sgna > 0) ? CRF_GT : CRF_LT; cr = bcd_cmp_zero(&result);
} 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;
} else { } else {
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); result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgnb, ps);
zero = bcd_sub_mag(&result, b, a, &invalid, &overflow); bcd_sub_mag(&result, b, a, &invalid, &overflow);
cr = (sgnb > 0) ? CRF_GT : CRF_LT; 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; cr = CRF_SO;
} else if (overflow) { } else if (overflow) {
cr |= CRF_SO; cr |= CRF_SO;
} else if (zero) {
cr = CRF_EQ;
} }
*r = result; *r = result;

View file

@ -211,6 +211,7 @@ struct DisasContext {
bool gtse; bool gtse;
ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */ ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
int singlestep_enabled; int singlestep_enabled;
uint32_t flags;
uint64_t insns_flags; uint64_t insns_flags;
uint64_t insns_flags2; uint64_t insns_flags2;
}; };
@ -251,6 +252,17 @@ struct opc_handler_t {
#endif #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) static inline void gen_set_access_type(DisasContext *ctx, int access_type)
{ {
if (ctx->need_access_type && ctx->access_type != 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); 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) static void gen_debug_exception(DisasContext *ctx)
{ {
TCGv_i32 t0; TCGv_i32 t0;
@ -575,17 +619,6 @@ typedef struct opcode_t {
} }
#endif #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 */ /* Invalid instruction */
static void gen_invalid(DisasContext *ctx) static void gen_invalid(DisasContext *ctx)
{ {
@ -3602,6 +3635,24 @@ static inline bool use_goto_tb(DisasContext *ctx, target_ulong dest)
#endif #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 ***/ /*** Branch ***/
static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) 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); tcg_gen_exit_tb(ctx->base.tb, n);
} else { } else {
tcg_gen_movi_tl(cpu_nip, dest & ~3); tcg_gen_movi_tl(cpu_nip, dest & ~3);
if (unlikely(ctx->singlestep_enabled)) { gen_lookup_and_goto_ptr(ctx);
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();
} }
} }
@ -3668,8 +3708,8 @@ static void gen_bcond(DisasContext *ctx, int type)
uint32_t bo = BO(ctx->opcode); uint32_t bo = BO(ctx->opcode);
TCGLabel *l1; TCGLabel *l1;
TCGv target; TCGv target;
ctx->exception = POWERPC_EXCP_BRANCH; ctx->exception = POWERPC_EXCP_BRANCH;
if (type == BCOND_LR || type == BCOND_CTR || type == BCOND_TAR) { if (type == BCOND_LR || type == BCOND_CTR || type == BCOND_TAR) {
target = tcg_temp_local_new(); target = tcg_temp_local_new();
if (type == BCOND_CTR) if (type == BCOND_CTR)
@ -3733,10 +3773,11 @@ static void gen_bcond(DisasContext *ctx, int type)
} else { } else {
tcg_gen_andi_tl(cpu_nip, target, ~3); tcg_gen_andi_tl(cpu_nip, target, ~3);
} }
tcg_gen_lookup_and_goto_ptr(); gen_lookup_and_goto_ptr(ctx);
tcg_temp_free(target); tcg_temp_free(target);
} }
if ((bo & 0x14) != 0x14) { if ((bo & 0x14) != 0x14) {
/* fallthrough case */
gen_set_label(l1); gen_set_label(l1);
gen_goto_tb(ctx, 1, ctx->base.pc_next); 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->need_access_type = !(env->mmu_model & POWERPC_MMU_64B);
ctx->le_mode = !!(env->hflags & (1 << MSR_LE)); ctx->le_mode = !!(env->hflags & (1 << MSR_LE));
ctx->default_tcg_memop_mask = ctx->le_mode ? MO_LE : MO_BE; ctx->default_tcg_memop_mask = ctx->le_mode ? MO_LE : MO_BE;
ctx->flags = env->flags;
#if defined(TARGET_PPC64) #if defined(TARGET_PPC64)
ctx->sf_mode = msr_is_64bit(env, env->msr); ctx->sf_mode = msr_is_64bit(env, env->msr);
ctx->has_cfar = !!(env->flags & POWERPC_FLAG_CFAR); 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; ctx->singlestep_enabled = 0;
if ((env->flags & POWERPC_FLAG_BE) && msr_be) if ((env->flags & POWERPC_FLAG_BE) && msr_be)
ctx->singlestep_enabled |= CPU_BRANCH_STEP; 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)) { if (unlikely(ctx->base.singlestep_enabled)) {
ctx->singlestep_enabled |= GDBSTUB_SINGLE_STEP; 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_SYSCALL &&
ctx->exception != POWERPC_EXCP_TRAP && ctx->exception != POWERPC_EXCP_TRAP &&
ctx->exception != POWERPC_EXCP_BRANCH)) { 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()) { 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_LDUXF(name, ldop, op | 0x01, type); \
GEN_LDXF(name, ldop, 0x17, op | 0x00, 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 tmp = tcg_temp_new_i32();
TCGv_i32 t1 = tcg_temp_new_i32(); tcg_gen_qemu_ld_i32(tmp, addr, ctx->mem_idx, DEF_MEMOP(MO_UL));
gen_qemu_ld32u(ctx, t0, arg2); gen_helper_todouble(dest, tmp);
tcg_gen_trunc_tl_i32(t1, t0); tcg_temp_free_i32(tmp);
tcg_temp_free(t0);
gen_helper_float32_to_float64(arg1, cpu_env, t1);
tcg_temp_free_i32(t1);
} }
/* lfd lfdu lfdux lfdx */ /* lfd lfdu lfdux lfdx */
@ -836,15 +833,12 @@ GEN_STUF(name, stop, op | 0x21, type); \
GEN_STUXF(name, stop, op | 0x01, type); \ GEN_STUXF(name, stop, op | 0x01, type); \
GEN_STXF(name, stop, 0x17, op | 0x00, 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_i32 tmp = tcg_temp_new_i32();
TCGv t1 = tcg_temp_new(); gen_helper_tosingle(tmp, src);
gen_helper_float64_to_float32(t0, cpu_env, arg1); tcg_gen_qemu_st_i32(tmp, addr, ctx->mem_idx, DEF_MEMOP(MO_UL));
tcg_gen_extu_i32_tl(t1, t0); tcg_temp_free_i32(tmp);
tcg_temp_free_i32(t0);
gen_qemu_st32(ctx, t1, arg2);
tcg_temp_free(t1);
} }
/* stfd stfdu stfdux stfdx */ /* 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) 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]); gen_helper_store_40x_dbcr0(cpu_env, cpu_gpr[gprn]);
/* We must stop translation as we may have rebooted */ /* We must stop translation as we may have rebooted */
gen_stop_exception(ctx); gen_stop_exception(ctx);
@ -1769,6 +1770,14 @@ static void gen_spr_BookE(CPUPPCState *env, uint64_t ivor_mask)
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_generic,
0x00000000); 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 */ /* XXX : not implemented */
spr_register(env, SPR_BOOKE_DBSR, "DBSR", spr_register(env, SPR_BOOKE_DBSR, "DBSR",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
@ -1841,6 +1850,14 @@ static void gen_spr_BookE(CPUPPCState *env, uint64_t ivor_mask)
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_generic,
0x00000000); 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, static inline uint32_t gen_tlbncfg(uint32_t assoc, uint32_t minsize,
@ -10278,6 +10295,8 @@ static void ppc_cpu_reset(CPUState *s)
#endif #endif
#if defined(CONFIG_USER_ONLY) #if defined(CONFIG_USER_ONLY)
msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */ 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_VR; /* Allow altivec usage */
msr |= (target_ulong)1 << MSR_VSX; /* Allow VSX usage */ msr |= (target_ulong)1 << MSR_VSX; /* Allow VSX usage */
msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */ msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */

View file

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