ppc patch queue 2019-10-04

Here's the next batch of ppc and spapr patches.  Includes:
   * Fist part of a large cleanup to irq infrastructure
   * Recreate the full FDT at CAS time, instead of making a difficult
     to follow set of updates.  This will help us move towards
     eliminating CAS reboots altogether
   * No longer provide RTAS blob to SLOF - SLOF can include it just as
     well itself, since guests will generally need to relocate it with
     a call to instantiate-rtas
   * A number of DFP fixes and cleanups from Mark Cave-Ayland
   * Assorted bugfixes
   * Several new small devices for powernv
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEdfRlhq5hpmzETofcbDjKyiDZs5IFAl2XEn0ACgkQbDjKyiDZ
 s5I6bA/7B5sjY/QxuE8axm5KupoAnE8zf205hN8mbYASwtDfFwgaeNreVaOSJUpr
 fgcx/g9G3rAryGZv3O6i02+wcRgNw1DnJ3ynCthIrExZEcfbTYJiS4s9apwPEQy8
 HFmBNdPDqrhFI0aFvXEUauiOp1aapPUUklm34eFscs94lJXxphRUEfa3XT5uEhUh
 xrIZwYq20A+ih4UHwk3Onyx/cvFpl6BRB2nVEllQFqzwF5eTTfz9t8+JGTebxD/7
 8qqt8ti0KM3wxSDTQnmyMUmpgy+C1iCvNYvv6nWFg+07QuGs48EHlQUUVVni4r9j
 kUrDwKS2eC+8e8gP/xdIXEq3R2DsAMq+wFIswXZ3X6x4DoUV0OAJSHc9iMD4l+pr
 LyWnVpDprc6XhJHWKpuHZ5w9EuBnZFbIXdlZGFno+8UvXtusnbbuwAZzHTrRJRqe
 /AWVpFwGAoOF4KxIOFlPVBI8m4vFad/soVojC0vzIbRqaogOFZAjiL/yD5GwLmMa
 tywOEMBUJ/j2lgudTCyKn5uCa/Ew3DS1TSdenJjyqRi/gZM0IaORIhJhyFYW/eO1
 U7Uh8BnbC+4J11wwvFR5+W789dgM2+EEtAX9uI08VcE/R2ASabZlN4Zwrl0w4cb/
 VRybMT4bgmjzHRpfrqYPxpn8wqPcIw0BCeipSOjY3QU1Q25TEYQ=
 =PXXe
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-4.2-20191004' into staging

ppc patch queue 2019-10-04

Here's the next batch of ppc and spapr patches.  Includes:
  * Fist part of a large cleanup to irq infrastructure
  * Recreate the full FDT at CAS time, instead of making a difficult
    to follow set of updates.  This will help us move towards
    eliminating CAS reboots altogether
  * No longer provide RTAS blob to SLOF - SLOF can include it just as
    well itself, since guests will generally need to relocate it with
    a call to instantiate-rtas
  * A number of DFP fixes and cleanups from Mark Cave-Ayland
  * Assorted bugfixes
  * Several new small devices for powernv

# gpg: Signature made Fri 04 Oct 2019 10:35:57 BST
# gpg:                using RSA key 75F46586AE61A66CC44E87DC6C38CACA20D9B392
# gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>" [full]
# gpg:                 aka "David Gibson (Red Hat) <dgibson@redhat.com>" [full]
# gpg:                 aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>" [full]
# gpg:                 aka "David Gibson (kernel.org) <dwg@kernel.org>" [unknown]
# Primary key fingerprint: 75F4 6586 AE61 A66C C44E  87DC 6C38 CACA 20D9 B392

* remotes/dgibson/tags/ppc-for-4.2-20191004: (53 commits)
  ppc/pnv: Remove the XICSFabric Interface from the POWER9 machine
  spapr: Eliminate SpaprIrq::init hook
  spapr: Add return value to spapr_irq_check()
  spapr: Use less cryptic representation of which irq backends are supported
  xive: Improve irq claim/free path
  spapr, xics, xive: Better use of assert()s on irq claim/free paths
  spapr: Handle freeing of multiple irqs in frontend only
  spapr: Remove unhelpful tracepoints from spapr_irq_free_xics()
  spapr: Eliminate SpaprIrq:get_nodename method
  spapr: Simplify spapr_qirq() handling
  spapr: Fix indexing of XICS irqs
  spapr: Eliminate nr_irqs parameter to SpaprIrq::init
  spapr: Clarify and fix handling of nr_irqs
  spapr: Replace spapr_vio_qirq() helper with spapr_vio_irq_pulse() helper
  spapr: Fold spapr_phb_lsi_qirq() into its single caller
  xics: Create sPAPR specific ICS subtype
  xics: Merge TYPE_ICS_BASE and TYPE_ICS_SIMPLE classes
  xics: Eliminate reset hook
  xics: Rename misleading ics_simple_*() functions
  xics: Eliminate 'reject', 'resend' and 'eoi' class hooks
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2019-10-07 13:49:02 +01:00
commit 0f0b43868a
54 changed files with 1422 additions and 1094 deletions

View File

@ -1077,8 +1077,6 @@ F: hw/*/spapr*
F: include/hw/*/spapr* F: include/hw/*/spapr*
F: hw/*/xics* F: hw/*/xics*
F: include/hw/*/xics* F: include/hw/*/xics*
F: pc-bios/spapr-rtas/*
F: pc-bios/spapr-rtas.bin
F: pc-bios/slof.bin F: pc-bios/slof.bin
F: docs/specs/ppc-spapr-hcalls.txt F: docs/specs/ppc-spapr-hcalls.txt
F: docs/specs/ppc-spapr-hotplug.txt F: docs/specs/ppc-spapr-hotplug.txt

View File

@ -769,7 +769,7 @@ qemu-nsis.bmp \
bamboo.dtb canyonlands.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \ bamboo.dtb canyonlands.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
multiboot.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bin pvh.bin \ multiboot.bin linuxboot.bin linuxboot_dma.bin kvmvapic.bin pvh.bin \
s390-ccw.img s390-netboot.img \ s390-ccw.img s390-netboot.img \
spapr-rtas.bin slof.bin skiboot.lid \ slof.bin skiboot.lid \
palcode-clipper \ palcode-clipper \
u-boot.e500 u-boot-sam460-20100605.bin \ u-boot.e500 u-boot-sam460-20100605.bin \
qemu_vga.ndrv \ qemu_vga.ndrv \

6
configure vendored
View File

@ -6166,9 +6166,6 @@ if { test "$cpu" = "i386" || test "$cpu" = "x86_64"; } && \
fi fi
done done
fi fi
if test "$ARCH" = "ppc64" && test "$targetos" != "Darwin" ; then
roms="$roms spapr-rtas"
fi
# Only build s390-ccw bios if we're on s390x and the compiler has -march=z900 # Only build s390-ccw bios if we're on s390x and the compiler has -march=z900
if test "$cpu" = "s390x" ; then if test "$cpu" = "s390x" ; then
@ -7800,13 +7797,12 @@ fi
DIRS="tests tests/tcg tests/tcg/lm32 tests/libqos tests/qapi-schema tests/qemu-iotests tests/vm" DIRS="tests tests/tcg tests/tcg/lm32 tests/libqos tests/qapi-schema tests/qemu-iotests tests/vm"
DIRS="$DIRS tests/fp tests/qgraph" DIRS="$DIRS tests/fp tests/qgraph"
DIRS="$DIRS docs docs/interop fsdev scsi" DIRS="$DIRS docs docs/interop fsdev scsi"
DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas pc-bios/s390-ccw" DIRS="$DIRS pc-bios/optionrom pc-bios/s390-ccw"
DIRS="$DIRS roms/seabios roms/vgabios" DIRS="$DIRS roms/seabios roms/vgabios"
LINKS="Makefile" LINKS="Makefile"
LINKS="$LINKS tests/tcg/lm32/Makefile po/Makefile" LINKS="$LINKS tests/tcg/lm32/Makefile po/Makefile"
LINKS="$LINKS tests/tcg/Makefile.target tests/fp/Makefile" LINKS="$LINKS tests/tcg/Makefile.target tests/fp/Makefile"
LINKS="$LINKS pc-bios/optionrom/Makefile pc-bios/keymaps" LINKS="$LINKS pc-bios/optionrom/Makefile pc-bios/keymaps"
LINKS="$LINKS pc-bios/spapr-rtas/Makefile"
LINKS="$LINKS pc-bios/s390-ccw/Makefile" LINKS="$LINKS pc-bios/s390-ccw/Makefile"
LINKS="$LINKS roms/seabios/Makefile roms/vgabios/Makefile" LINKS="$LINKS roms/seabios/Makefile roms/vgabios/Makefile"
LINKS="$LINKS pc-bios/qemu-icon.bmp" LINKS="$LINKS pc-bios/qemu-icon.bmp"

View File

@ -5,7 +5,6 @@
#include "cpu.h" #include "cpu.h"
#include "migration/vmstate.h" #include "migration/vmstate.h"
#include "chardev/char-fe.h" #include "chardev/char-fe.h"
#include "hw/irq.h"
#include "hw/ppc/spapr.h" #include "hw/ppc/spapr.h"
#include "hw/ppc/spapr_vio.h" #include "hw/ppc/spapr_vio.h"
#include "hw/qdev-properties.h" #include "hw/qdev-properties.h"
@ -37,7 +36,7 @@ static void vty_receive(void *opaque, const uint8_t *buf, int size)
if ((dev->in == dev->out) && size) { if ((dev->in == dev->out) && size) {
/* toggle line to simulate edge interrupt */ /* toggle line to simulate edge interrupt */
qemu_irq_pulse(spapr_vio_qirq(&dev->sdev)); spapr_vio_irq_pulse(&dev->sdev);
} }
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
if (dev->in - dev->out >= VTERM_BUFSIZE) { if (dev->in - dev->out >= VTERM_BUFSIZE) {

View File

@ -528,12 +528,15 @@ static void spapr_xive_register_types(void)
type_init(spapr_xive_register_types) type_init(spapr_xive_register_types)
bool spapr_xive_irq_claim(SpaprXive *xive, uint32_t lisn, bool lsi) int spapr_xive_irq_claim(SpaprXive *xive, int lisn, bool lsi, Error **errp)
{ {
XiveSource *xsrc = &xive->source; XiveSource *xsrc = &xive->source;
if (lisn >= xive->nr_irqs) { assert(lisn < xive->nr_irqs);
return false;
if (xive_eas_is_valid(&xive->eat[lisn])) {
error_setg(errp, "IRQ %d is not free", lisn);
return -EBUSY;
} }
/* /*
@ -545,26 +548,17 @@ bool spapr_xive_irq_claim(SpaprXive *xive, uint32_t lisn, bool lsi)
} }
if (kvm_irqchip_in_kernel()) { if (kvm_irqchip_in_kernel()) {
Error *local_err = NULL; return kvmppc_xive_source_reset_one(xsrc, lisn, errp);
kvmppc_xive_source_reset_one(xsrc, lisn, &local_err);
if (local_err) {
error_report_err(local_err);
return false;
}
} }
return true; return 0;
} }
bool spapr_xive_irq_free(SpaprXive *xive, uint32_t lisn) void spapr_xive_irq_free(SpaprXive *xive, int lisn)
{ {
if (lisn >= xive->nr_irqs) { assert(lisn < xive->nr_irqs);
return false;
}
xive->eat[lisn].w &= cpu_to_be64(~EAS_VALID); xive->eat[lisn].w &= cpu_to_be64(~EAS_VALID);
return true;
} }
/* /*

View File

@ -232,14 +232,14 @@ void kvmppc_xive_sync_source(SpaprXive *xive, uint32_t lisn, Error **errp)
* only need to inform the KVM XIVE device about their type: LSI or * only need to inform the KVM XIVE device about their type: LSI or
* MSI. * MSI.
*/ */
void kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp) int kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp)
{ {
SpaprXive *xive = SPAPR_XIVE(xsrc->xive); SpaprXive *xive = SPAPR_XIVE(xsrc->xive);
uint64_t state = 0; uint64_t state = 0;
/* The KVM XIVE device is not in use */ /* The KVM XIVE device is not in use */
if (xive->fd == -1) { if (xive->fd == -1) {
return; return -ENODEV;
} }
if (xive_source_irq_is_lsi(xsrc, srcno)) { if (xive_source_irq_is_lsi(xsrc, srcno)) {
@ -249,17 +249,22 @@ void kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp)
} }
} }
kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_SOURCE, srcno, &state, return kvm_device_access(xive->fd, KVM_DEV_XIVE_GRP_SOURCE, srcno, &state,
true, errp); true, errp);
} }
static void kvmppc_xive_source_reset(XiveSource *xsrc, Error **errp) static void kvmppc_xive_source_reset(XiveSource *xsrc, Error **errp)
{ {
SpaprXive *xive = SPAPR_XIVE(xsrc->xive);
int i; int i;
for (i = 0; i < xsrc->nr_irqs; i++) { for (i = 0; i < xsrc->nr_irqs; i++) {
Error *local_err = NULL; Error *local_err = NULL;
if (!xive_eas_is_valid(&xive->eat[i])) {
continue;
}
kvmppc_xive_source_reset_one(xsrc, i, &local_err); kvmppc_xive_source_reset_one(xsrc, i, &local_err);
if (local_err) { if (local_err) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
@ -328,11 +333,18 @@ uint64_t kvmppc_xive_esb_rw(XiveSource *xsrc, int srcno, uint32_t offset,
static void kvmppc_xive_source_get_state(XiveSource *xsrc) static void kvmppc_xive_source_get_state(XiveSource *xsrc)
{ {
SpaprXive *xive = SPAPR_XIVE(xsrc->xive);
int i; int i;
for (i = 0; i < xsrc->nr_irqs; i++) { for (i = 0; i < xsrc->nr_irqs; i++) {
uint8_t pq;
if (!xive_eas_is_valid(&xive->eat[i])) {
continue;
}
/* Perform a load without side effect to retrieve the PQ bits */ /* Perform a load without side effect to retrieve the PQ bits */
uint8_t pq = xive_esb_read(xsrc, i, XIVE_ESB_GET); pq = xive_esb_read(xsrc, i, XIVE_ESB_GET);
/* and save PQ locally */ /* and save PQ locally */
xive_source_esb_set(xsrc, i, pq); xive_source_esb_set(xsrc, i, pq);
@ -521,9 +533,14 @@ static void kvmppc_xive_change_state_handler(void *opaque, int running,
*/ */
if (running) { if (running) {
for (i = 0; i < xsrc->nr_irqs; i++) { for (i = 0; i < xsrc->nr_irqs; i++) {
uint8_t pq = xive_source_esb_get(xsrc, i); uint8_t pq;
uint8_t old_pq; uint8_t old_pq;
if (!xive_eas_is_valid(&xive->eat[i])) {
continue;
}
pq = xive_source_esb_get(xsrc, i);
old_pq = xive_esb_read(xsrc, i, XIVE_ESB_SET_PQ_00 + (pq << 8)); old_pq = xive_esb_read(xsrc, i, XIVE_ESB_SET_PQ_00 + (pq << 8));
/* /*
@ -545,7 +562,13 @@ static void kvmppc_xive_change_state_handler(void *opaque, int running,
* migration is in progress. * migration is in progress.
*/ */
for (i = 0; i < xsrc->nr_irqs; i++) { for (i = 0; i < xsrc->nr_irqs; i++) {
uint8_t pq = xive_esb_read(xsrc, i, XIVE_ESB_GET); uint8_t pq;
if (!xive_eas_is_valid(&xive->eat[i])) {
continue;
}
pq = xive_esb_read(xsrc, i, XIVE_ESB_GET);
/* /*
* PQ is set to PENDING to possibly catch a triggered * PQ is set to PENDING to possibly catch a triggered
@ -655,6 +678,17 @@ int kvmppc_xive_post_load(SpaprXive *xive, int version_id)
continue; continue;
} }
/*
* We can only restore the source config if the source has been
* previously set in KVM. Since we don't do that for all interrupts
* at reset time anymore, let's do it now.
*/
kvmppc_xive_source_reset_one(&xive->source, i, &local_err);
if (local_err) {
error_report_err(local_err);
return -1;
}
kvmppc_xive_set_source_config(xive, i, &xive->eat[i], &local_err); kvmppc_xive_set_source_config(xive, i, &xive->eat[i], &local_err);
if (local_err) { if (local_err) {
error_report_err(local_err); error_report_err(local_err);

View File

@ -66,12 +66,12 @@ xics_icp_accept(uint32_t old_xirr, uint32_t new_xirr) "icp_accept: XIRR 0x%"PRIx
xics_icp_eoi(int server, uint32_t xirr, uint32_t new_xirr) "icp_eoi: server %d given XIRR 0x%"PRIx32" new XIRR 0x%"PRIx32 xics_icp_eoi(int server, uint32_t xirr, uint32_t new_xirr) "icp_eoi: server %d given XIRR 0x%"PRIx32" new XIRR 0x%"PRIx32
xics_icp_irq(int server, int nr, uint8_t priority) "cpu %d trying to deliver irq 0x%"PRIx32" priority 0x%x" xics_icp_irq(int server, int nr, uint8_t priority) "cpu %d trying to deliver irq 0x%"PRIx32" priority 0x%x"
xics_icp_raise(uint32_t xirr, uint8_t pending_priority) "raising IRQ new XIRR=0x%x new pending priority=0x%x" xics_icp_raise(uint32_t xirr, uint8_t pending_priority) "raising IRQ new XIRR=0x%x new pending priority=0x%x"
xics_ics_simple_set_irq_msi(int srcno, int nr) "set_irq_msi: srcno %d [irq 0x%x]" xics_ics_set_irq_msi(int srcno, int nr) "set_irq_msi: srcno %d [irq 0x%x]"
xics_masked_pending(void) "set_irq_msi: masked pending" xics_masked_pending(void) "set_irq_msi: masked pending"
xics_ics_simple_set_irq_lsi(int srcno, int nr) "set_irq_lsi: srcno %d [irq 0x%x]" xics_ics_set_irq_lsi(int srcno, int nr) "set_irq_lsi: srcno %d [irq 0x%x]"
xics_ics_simple_write_xive(int nr, int srcno, int server, uint8_t priority) "ics_write_xive: irq 0x%x [src %d] server 0x%x prio 0x%x" xics_ics_write_xive(int nr, int srcno, int server, uint8_t priority) "ics_write_xive: irq 0x%x [src %d] server 0x%x prio 0x%x"
xics_ics_simple_reject(int nr, int srcno) "reject irq 0x%x [src %d]" xics_ics_reject(int nr, int srcno) "reject irq 0x%x [src %d]"
xics_ics_simple_eoi(int nr) "ics_eoi: irq 0x%x" xics_ics_eoi(int nr) "ics_eoi: irq 0x%x"
# s390_flic_kvm.c # s390_flic_kvm.c
flic_create_device(int err) "flic: create device failed %d" flic_create_device(int err) "flic: create device failed %d"

View File

@ -98,32 +98,8 @@ void ics_pic_print_info(ICSState *ics, Monitor *mon)
#define XISR(icp) (((icp)->xirr) & XISR_MASK) #define XISR(icp) (((icp)->xirr) & XISR_MASK)
#define CPPR(icp) (((icp)->xirr) >> 24) #define CPPR(icp) (((icp)->xirr) >> 24)
static void ics_reject(ICSState *ics, uint32_t nr) static void ics_reject(ICSState *ics, uint32_t nr);
{ static void ics_eoi(ICSState *ics, uint32_t nr);
ICSStateClass *k = ICS_BASE_GET_CLASS(ics);
if (k->reject) {
k->reject(ics, nr);
}
}
void ics_resend(ICSState *ics)
{
ICSStateClass *k = ICS_BASE_GET_CLASS(ics);
if (k->resend) {
k->resend(ics);
}
}
static void ics_eoi(ICSState *ics, int nr)
{
ICSStateClass *k = ICS_BASE_GET_CLASS(ics);
if (k->eoi) {
k->eoi(ics, nr);
}
}
static void icp_check_ipi(ICPState *icp) static void icp_check_ipi(ICPState *icp)
{ {
@ -427,7 +403,7 @@ Object *icp_create(Object *cpu, const char *type, XICSFabric *xi, Error **errp)
/* /*
* ICS: Source layer * ICS: Source layer
*/ */
static void ics_simple_resend_msi(ICSState *ics, int srcno) static void ics_resend_msi(ICSState *ics, int srcno)
{ {
ICSIRQState *irq = ics->irqs + srcno; ICSIRQState *irq = ics->irqs + srcno;
@ -440,7 +416,7 @@ static void ics_simple_resend_msi(ICSState *ics, int srcno)
} }
} }
static void ics_simple_resend_lsi(ICSState *ics, int srcno) static void ics_resend_lsi(ICSState *ics, int srcno)
{ {
ICSIRQState *irq = ics->irqs + srcno; ICSIRQState *irq = ics->irqs + srcno;
@ -452,11 +428,11 @@ static void ics_simple_resend_lsi(ICSState *ics, int srcno)
} }
} }
static void ics_simple_set_irq_msi(ICSState *ics, int srcno, int val) static void ics_set_irq_msi(ICSState *ics, int srcno, int val)
{ {
ICSIRQState *irq = ics->irqs + srcno; ICSIRQState *irq = ics->irqs + srcno;
trace_xics_ics_simple_set_irq_msi(srcno, srcno + ics->offset); trace_xics_ics_set_irq_msi(srcno, srcno + ics->offset);
if (val) { if (val) {
if (irq->priority == 0xff) { if (irq->priority == 0xff) {
@ -468,20 +444,20 @@ static void ics_simple_set_irq_msi(ICSState *ics, int srcno, int val)
} }
} }
static void ics_simple_set_irq_lsi(ICSState *ics, int srcno, int val) static void ics_set_irq_lsi(ICSState *ics, int srcno, int val)
{ {
ICSIRQState *irq = ics->irqs + srcno; ICSIRQState *irq = ics->irqs + srcno;
trace_xics_ics_simple_set_irq_lsi(srcno, srcno + ics->offset); trace_xics_ics_set_irq_lsi(srcno, srcno + ics->offset);
if (val) { if (val) {
irq->status |= XICS_STATUS_ASSERTED; irq->status |= XICS_STATUS_ASSERTED;
} else { } else {
irq->status &= ~XICS_STATUS_ASSERTED; irq->status &= ~XICS_STATUS_ASSERTED;
} }
ics_simple_resend_lsi(ics, srcno); ics_resend_lsi(ics, srcno);
} }
void ics_simple_set_irq(void *opaque, int srcno, int val) void ics_set_irq(void *opaque, int srcno, int val)
{ {
ICSState *ics = (ICSState *)opaque; ICSState *ics = (ICSState *)opaque;
@ -491,13 +467,13 @@ void ics_simple_set_irq(void *opaque, int srcno, int val)
} }
if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) { if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
ics_simple_set_irq_lsi(ics, srcno, val); ics_set_irq_lsi(ics, srcno, val);
} else { } else {
ics_simple_set_irq_msi(ics, srcno, val); ics_set_irq_msi(ics, srcno, val);
} }
} }
static void ics_simple_write_xive_msi(ICSState *ics, int srcno) static void ics_write_xive_msi(ICSState *ics, int srcno)
{ {
ICSIRQState *irq = ics->irqs + srcno; ICSIRQState *irq = ics->irqs + srcno;
@ -510,13 +486,13 @@ static void ics_simple_write_xive_msi(ICSState *ics, int srcno)
icp_irq(ics, irq->server, srcno + ics->offset, irq->priority); icp_irq(ics, irq->server, srcno + ics->offset, irq->priority);
} }
static void ics_simple_write_xive_lsi(ICSState *ics, int srcno) static void ics_write_xive_lsi(ICSState *ics, int srcno)
{ {
ics_simple_resend_lsi(ics, srcno); ics_resend_lsi(ics, srcno);
} }
void ics_simple_write_xive(ICSState *ics, int srcno, int server, void ics_write_xive(ICSState *ics, int srcno, int server,
uint8_t priority, uint8_t saved_priority) uint8_t priority, uint8_t saved_priority)
{ {
ICSIRQState *irq = ics->irqs + srcno; ICSIRQState *irq = ics->irqs + srcno;
@ -524,21 +500,20 @@ void ics_simple_write_xive(ICSState *ics, int srcno, int server,
irq->priority = priority; irq->priority = priority;
irq->saved_priority = saved_priority; irq->saved_priority = saved_priority;
trace_xics_ics_simple_write_xive(ics->offset + srcno, srcno, server, trace_xics_ics_write_xive(ics->offset + srcno, srcno, server, priority);
priority);
if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) { if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
ics_simple_write_xive_lsi(ics, srcno); ics_write_xive_lsi(ics, srcno);
} else { } else {
ics_simple_write_xive_msi(ics, srcno); ics_write_xive_msi(ics, srcno);
} }
} }
static void ics_simple_reject(ICSState *ics, uint32_t nr) static void ics_reject(ICSState *ics, uint32_t nr)
{ {
ICSIRQState *irq = ics->irqs + nr - ics->offset; ICSIRQState *irq = ics->irqs + nr - ics->offset;
trace_xics_ics_simple_reject(nr, nr - ics->offset); trace_xics_ics_reject(nr, nr - ics->offset);
if (irq->flags & XICS_FLAGS_IRQ_MSI) { if (irq->flags & XICS_FLAGS_IRQ_MSI) {
irq->status |= XICS_STATUS_REJECTED; irq->status |= XICS_STATUS_REJECTED;
} else if (irq->flags & XICS_FLAGS_IRQ_LSI) { } else if (irq->flags & XICS_FLAGS_IRQ_LSI) {
@ -546,100 +521,41 @@ static void ics_simple_reject(ICSState *ics, uint32_t nr)
} }
} }
static void ics_simple_resend(ICSState *ics) void ics_resend(ICSState *ics)
{ {
int i; int i;
for (i = 0; i < ics->nr_irqs; i++) { for (i = 0; i < ics->nr_irqs; i++) {
/* FIXME: filter by server#? */ /* FIXME: filter by server#? */
if (ics->irqs[i].flags & XICS_FLAGS_IRQ_LSI) { if (ics->irqs[i].flags & XICS_FLAGS_IRQ_LSI) {
ics_simple_resend_lsi(ics, i); ics_resend_lsi(ics, i);
} else { } else {
ics_simple_resend_msi(ics, i); ics_resend_msi(ics, i);
} }
} }
} }
static void ics_simple_eoi(ICSState *ics, uint32_t nr) static void ics_eoi(ICSState *ics, uint32_t nr)
{ {
int srcno = nr - ics->offset; int srcno = nr - ics->offset;
ICSIRQState *irq = ics->irqs + srcno; ICSIRQState *irq = ics->irqs + srcno;
trace_xics_ics_simple_eoi(nr); trace_xics_ics_eoi(nr);
if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) { if (ics->irqs[srcno].flags & XICS_FLAGS_IRQ_LSI) {
irq->status &= ~XICS_STATUS_SENT; irq->status &= ~XICS_STATUS_SENT;
} }
} }
static void ics_simple_reset(DeviceState *dev)
{
ICSStateClass *icsc = ICS_BASE_GET_CLASS(dev);
icsc->parent_reset(dev);
if (kvm_irqchip_in_kernel()) {
Error *local_err = NULL;
ics_set_kvm_state(ICS_BASE(dev), &local_err);
if (local_err) {
error_report_err(local_err);
}
}
}
static void ics_simple_reset_handler(void *dev)
{
ics_simple_reset(dev);
}
static void ics_simple_realize(DeviceState *dev, Error **errp)
{
ICSState *ics = ICS_SIMPLE(dev);
ICSStateClass *icsc = ICS_BASE_GET_CLASS(ics);
Error *local_err = NULL;
icsc->parent_realize(dev, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
qemu_register_reset(ics_simple_reset_handler, ics);
}
static void ics_simple_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ICSStateClass *isc = ICS_BASE_CLASS(klass);
device_class_set_parent_realize(dc, ics_simple_realize,
&isc->parent_realize);
device_class_set_parent_reset(dc, ics_simple_reset,
&isc->parent_reset);
isc->reject = ics_simple_reject;
isc->resend = ics_simple_resend;
isc->eoi = ics_simple_eoi;
}
static const TypeInfo ics_simple_info = {
.name = TYPE_ICS_SIMPLE,
.parent = TYPE_ICS_BASE,
.instance_size = sizeof(ICSState),
.class_init = ics_simple_class_init,
.class_size = sizeof(ICSStateClass),
};
static void ics_reset_irq(ICSIRQState *irq) static void ics_reset_irq(ICSIRQState *irq)
{ {
irq->priority = 0xff; irq->priority = 0xff;
irq->saved_priority = 0xff; irq->saved_priority = 0xff;
} }
static void ics_base_reset(DeviceState *dev) static void ics_reset(DeviceState *dev)
{ {
ICSState *ics = ICS_BASE(dev); ICSState *ics = ICS(dev);
int i; int i;
uint8_t flags[ics->nr_irqs]; uint8_t flags[ics->nr_irqs];
@ -653,17 +569,31 @@ static void ics_base_reset(DeviceState *dev)
ics_reset_irq(ics->irqs + i); ics_reset_irq(ics->irqs + i);
ics->irqs[i].flags = flags[i]; ics->irqs[i].flags = flags[i];
} }
if (kvm_irqchip_in_kernel()) {
Error *local_err = NULL;
ics_set_kvm_state(ICS(dev), &local_err);
if (local_err) {
error_report_err(local_err);
}
}
} }
static void ics_base_realize(DeviceState *dev, Error **errp) static void ics_reset_handler(void *dev)
{ {
ICSState *ics = ICS_BASE(dev); ics_reset(dev);
Object *obj; }
Error *err = NULL;
obj = object_property_get_link(OBJECT(dev), ICS_PROP_XICS, &err); static void ics_realize(DeviceState *dev, Error **errp)
{
ICSState *ics = ICS(dev);
Error *local_err = NULL;
Object *obj;
obj = object_property_get_link(OBJECT(dev), ICS_PROP_XICS, &local_err);
if (!obj) { if (!obj) {
error_propagate_prepend(errp, err, error_propagate_prepend(errp, local_err,
"required link '" ICS_PROP_XICS "required link '" ICS_PROP_XICS
"' not found: "); "' not found: ");
return; return;
@ -675,16 +605,18 @@ static void ics_base_realize(DeviceState *dev, Error **errp)
return; return;
} }
ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState)); ics->irqs = g_malloc0(ics->nr_irqs * sizeof(ICSIRQState));
qemu_register_reset(ics_reset_handler, ics);
} }
static void ics_base_instance_init(Object *obj) static void ics_instance_init(Object *obj)
{ {
ICSState *ics = ICS_BASE(obj); ICSState *ics = ICS(obj);
ics->offset = XICS_IRQ_BASE; ics->offset = XICS_IRQ_BASE;
} }
static int ics_base_pre_save(void *opaque) static int ics_pre_save(void *opaque)
{ {
ICSState *ics = opaque; ICSState *ics = opaque;
@ -695,7 +627,7 @@ static int ics_base_pre_save(void *opaque)
return 0; return 0;
} }
static int ics_base_post_load(void *opaque, int version_id) static int ics_post_load(void *opaque, int version_id)
{ {
ICSState *ics = opaque; ICSState *ics = opaque;
@ -713,7 +645,7 @@ static int ics_base_post_load(void *opaque, int version_id)
return 0; return 0;
} }
static const VMStateDescription vmstate_ics_base_irq = { static const VMStateDescription vmstate_ics_irq = {
.name = "ics/irq", .name = "ics/irq",
.version_id = 2, .version_id = 2,
.minimum_version_id = 1, .minimum_version_id = 1,
@ -727,45 +659,44 @@ static const VMStateDescription vmstate_ics_base_irq = {
}, },
}; };
static const VMStateDescription vmstate_ics_base = { static const VMStateDescription vmstate_ics = {
.name = "ics", .name = "ics",
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.pre_save = ics_base_pre_save, .pre_save = ics_pre_save,
.post_load = ics_base_post_load, .post_load = ics_post_load,
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
/* Sanity check */ /* Sanity check */
VMSTATE_UINT32_EQUAL(nr_irqs, ICSState, NULL), VMSTATE_UINT32_EQUAL(nr_irqs, ICSState, NULL),
VMSTATE_STRUCT_VARRAY_POINTER_UINT32(irqs, ICSState, nr_irqs, VMSTATE_STRUCT_VARRAY_POINTER_UINT32(irqs, ICSState, nr_irqs,
vmstate_ics_base_irq, vmstate_ics_irq,
ICSIRQState), ICSIRQState),
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
}, },
}; };
static Property ics_base_properties[] = { static Property ics_properties[] = {
DEFINE_PROP_UINT32("nr-irqs", ICSState, nr_irqs, 0), DEFINE_PROP_UINT32("nr-irqs", ICSState, nr_irqs, 0),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };
static void ics_base_class_init(ObjectClass *klass, void *data) static void ics_class_init(ObjectClass *klass, void *data)
{ {
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = ics_base_realize; dc->realize = ics_realize;
dc->props = ics_base_properties; dc->props = ics_properties;
dc->reset = ics_base_reset; dc->reset = ics_reset;
dc->vmsd = &vmstate_ics_base; dc->vmsd = &vmstate_ics;
} }
static const TypeInfo ics_base_info = { static const TypeInfo ics_info = {
.name = TYPE_ICS_BASE, .name = TYPE_ICS,
.parent = TYPE_DEVICE, .parent = TYPE_DEVICE,
.abstract = true,
.instance_size = sizeof(ICSState), .instance_size = sizeof(ICSState),
.instance_init = ics_base_instance_init, .instance_init = ics_instance_init,
.class_init = ics_base_class_init, .class_init = ics_class_init,
.class_size = sizeof(ICSStateClass), .class_size = sizeof(ICSStateClass),
}; };
@ -805,8 +736,7 @@ void ics_set_irq_type(ICSState *ics, int srcno, bool lsi)
static void xics_register_types(void) static void xics_register_types(void)
{ {
type_register_static(&ics_simple_info); type_register_static(&ics_info);
type_register_static(&ics_base_info);
type_register_static(&icp_info); type_register_static(&icp_info);
type_register_static(&xics_fabric_info); type_register_static(&xics_fabric_info);
} }

View File

@ -190,6 +190,10 @@ void ics_get_kvm_state(ICSState *ics)
for (i = 0; i < ics->nr_irqs; i++) { for (i = 0; i < ics->nr_irqs; i++) {
ICSIRQState *irq = &ics->irqs[i]; ICSIRQState *irq = &ics->irqs[i];
if (ics_irq_free(ics, i)) {
continue;
}
kvm_device_access(kernel_xics_fd, KVM_DEV_XICS_GRP_SOURCES, kvm_device_access(kernel_xics_fd, KVM_DEV_XICS_GRP_SOURCES,
i + ics->offset, &state, false, &error_fatal); i + ics->offset, &state, false, &error_fatal);
@ -301,6 +305,10 @@ int ics_set_kvm_state(ICSState *ics, Error **errp)
Error *local_err = NULL; Error *local_err = NULL;
int ret; int ret;
if (ics_irq_free(ics, i)) {
continue;
}
ret = ics_set_kvm_state_one(ics, i, &local_err); ret = ics_set_kvm_state_one(ics, i, &local_err);
if (ret < 0) { if (ret < 0) {
error_propagate(errp, local_err); error_propagate(errp, local_err);

View File

@ -179,7 +179,7 @@ static void rtas_set_xive(PowerPCCPU *cpu, SpaprMachineState *spapr,
} }
srcno = nr - ics->offset; srcno = nr - ics->offset;
ics_simple_write_xive(ics, srcno, server, priority, priority); ics_write_xive(ics, srcno, server, priority, priority);
rtas_st(rets, 0, RTAS_OUT_SUCCESS); rtas_st(rets, 0, RTAS_OUT_SUCCESS);
} }
@ -243,8 +243,8 @@ static void rtas_int_off(PowerPCCPU *cpu, SpaprMachineState *spapr,
} }
srcno = nr - ics->offset; srcno = nr - ics->offset;
ics_simple_write_xive(ics, srcno, ics->irqs[srcno].server, 0xff, ics_write_xive(ics, srcno, ics->irqs[srcno].server, 0xff,
ics->irqs[srcno].priority); ics->irqs[srcno].priority);
rtas_st(rets, 0, RTAS_OUT_SUCCESS); rtas_st(rets, 0, RTAS_OUT_SUCCESS);
} }
@ -276,15 +276,25 @@ static void rtas_int_on(PowerPCCPU *cpu, SpaprMachineState *spapr,
} }
srcno = nr - ics->offset; srcno = nr - ics->offset;
ics_simple_write_xive(ics, srcno, ics->irqs[srcno].server, ics_write_xive(ics, srcno, ics->irqs[srcno].server,
ics->irqs[srcno].saved_priority, ics->irqs[srcno].saved_priority,
ics->irqs[srcno].saved_priority); ics->irqs[srcno].saved_priority);
rtas_st(rets, 0, RTAS_OUT_SUCCESS); rtas_st(rets, 0, RTAS_OUT_SUCCESS);
} }
void xics_spapr_init(SpaprMachineState *spapr) static void ics_spapr_realize(DeviceState *dev, Error **errp)
{ {
ICSState *ics = ICS_SPAPR(dev);
ICSStateClass *icsc = ICS_GET_CLASS(ics);
Error *local_err = NULL;
icsc->parent_realize(dev, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_set_xive); spapr_rtas_register(RTAS_IBM_SET_XIVE, "ibm,set-xive", rtas_set_xive);
spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_get_xive); spapr_rtas_register(RTAS_IBM_GET_XIVE, "ibm,get-xive", rtas_get_xive);
spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_int_off); spapr_rtas_register(RTAS_IBM_INT_OFF, "ibm,int-off", rtas_int_off);
@ -306,7 +316,7 @@ void spapr_dt_xics(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt,
}; };
int node; int node;
_FDT(node = fdt_add_subnode(fdt, 0, XICS_NODENAME)); _FDT(node = fdt_add_subnode(fdt, 0, "interrupt-controller"));
_FDT(fdt_setprop_string(fdt, node, "device_type", _FDT(fdt_setprop_string(fdt, node, "device_type",
"PowerPC-External-Interrupt-Presentation")); "PowerPC-External-Interrupt-Presentation"));
@ -319,3 +329,25 @@ void spapr_dt_xics(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt,
_FDT(fdt_setprop_cell(fdt, node, "linux,phandle", phandle)); _FDT(fdt_setprop_cell(fdt, node, "linux,phandle", phandle));
_FDT(fdt_setprop_cell(fdt, node, "phandle", phandle)); _FDT(fdt_setprop_cell(fdt, node, "phandle", phandle));
} }
static void ics_spapr_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ICSStateClass *isc = ICS_CLASS(klass);
device_class_set_parent_realize(dc, ics_spapr_realize,
&isc->parent_realize);
}
static const TypeInfo ics_spapr_info = {
.name = TYPE_ICS_SPAPR,
.parent = TYPE_ICS,
.class_init = ics_spapr_class_init,
};
static void xics_spapr_register_types(void)
{
type_register_static(&ics_spapr_info);
}
type_init(xics_spapr_register_types)

View File

@ -1396,6 +1396,14 @@ static bool xive_presenter_match(XiveRouter *xrtr, uint8_t format,
XiveTCTX *tctx = xive_router_get_tctx(xrtr, cs); XiveTCTX *tctx = xive_router_get_tctx(xrtr, cs);
int ring; int ring;
/*
* Skip partially initialized vCPUs. This can happen when
* vCPUs are hotplugged.
*/
if (!tctx) {
continue;
}
/* /*
* HW checks that the CPU is enabled in the Physical Thread * HW checks that the CPU is enabled in the Physical Thread
* Enable Register (PTER). * Enable Register (PTER).

View File

@ -27,7 +27,6 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "cpu.h" #include "cpu.h"
#include "hw/irq.h"
#include "qemu/log.h" #include "qemu/log.h"
#include "qemu/module.h" #include "qemu/module.h"
#include "net/net.h" #include "net/net.h"
@ -267,7 +266,7 @@ static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf,
} }
if (sdev->signal_state & 1) { if (sdev->signal_state & 1) {
qemu_irq_pulse(spapr_vio_qirq(sdev)); spapr_vio_irq_pulse(sdev);
} }
return size; return size;

View File

@ -9,6 +9,7 @@ obj-$(CONFIG_PSERIES) += spapr_tpm_proxy.o
obj-$(CONFIG_SPAPR_RNG) += spapr_rng.o obj-$(CONFIG_SPAPR_RNG) += spapr_rng.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
obj-$(CONFIG_POWERNV) += pnv_homer.o
ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy) ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy)
obj-y += spapr_pci_vfio.o spapr_pci_nvlink2.o obj-y += spapr_pci_vfio.o spapr_pci_nvlink2.o
endif endif

View File

@ -187,7 +187,8 @@ static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
_FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq))); _FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
_FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq))); _FDT((fdt_setprop_cell(fdt, offset, "clock-frequency", cpufreq)));
_FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size", cpu->hash64_opts->slb_size))); _FDT((fdt_setprop_cell(fdt, offset, "ibm,slb-size",
cpu->hash64_opts->slb_size)));
_FDT((fdt_setprop_string(fdt, offset, "status", "okay"))); _FDT((fdt_setprop_string(fdt, offset, "status", "okay")));
_FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0))); _FDT((fdt_setprop(fdt, offset, "64-bit", NULL, 0)));
@ -200,19 +201,23 @@ static void pnv_dt_core(PnvChip *chip, PnvCore *pc, void *fdt)
segs, sizeof(segs)))); segs, sizeof(segs))));
} }
/* Advertise VMX/VSX (vector extensions) if available /*
* Advertise VMX/VSX (vector extensions) if available
* 0 / no property == no vector extensions * 0 / no property == no vector extensions
* 1 == VMX / Altivec available * 1 == VMX / Altivec available
* 2 == VSX available */ * 2 == VSX available
*/
if (env->insns_flags & PPC_ALTIVEC) { if (env->insns_flags & PPC_ALTIVEC) {
uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1; uint32_t vmx = (env->insns_flags2 & PPC2_VSX) ? 2 : 1;
_FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx))); _FDT((fdt_setprop_cell(fdt, offset, "ibm,vmx", vmx)));
} }
/* Advertise DFP (Decimal Floating Point) if available /*
* Advertise DFP (Decimal Floating Point) if available
* 0 / no property == no DFP * 0 / no property == no DFP
* 1 == DFP available */ * 1 == DFP available
*/
if (env->insns_flags2 & PPC2_DFP) { if (env->insns_flags2 & PPC2_DFP) {
_FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1))); _FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
} }
@ -424,7 +429,8 @@ static int pnv_dt_isa_device(DeviceState *dev, void *opaque)
return 0; return 0;
} }
/* The default LPC bus of a multichip system is on chip 0. It's /*
* The default LPC bus of a multichip system is on chip 0. It's
* recognized by the firmware (skiboot) using a "primary" property. * recognized by the firmware (skiboot) using a "primary" property.
*/ */
static void pnv_dt_isa(PnvMachineState *pnv, void *fdt) static void pnv_dt_isa(PnvMachineState *pnv, void *fdt)
@ -442,8 +448,10 @@ static void pnv_dt_isa(PnvMachineState *pnv, void *fdt)
assert(phandle > 0); assert(phandle > 0);
_FDT((fdt_setprop_cell(fdt, isa_offset, "phandle", phandle))); _FDT((fdt_setprop_cell(fdt, isa_offset, "phandle", phandle)));
/* ISA devices are not necessarily parented to the ISA bus so we /*
* can not use object_child_foreach() */ * ISA devices are not necessarily parented to the ISA bus so we
* can not use object_child_foreach()
*/
qbus_walk_children(BUS(pnv->isa_bus), pnv_dt_isa_device, NULL, NULL, NULL, qbus_walk_children(BUS(pnv->isa_bus), pnv_dt_isa_device, NULL, NULL, NULL,
&args); &args);
} }
@ -545,7 +553,8 @@ static void pnv_reset(MachineState *machine)
qemu_devices_reset(); qemu_devices_reset();
/* OpenPOWER systems have a BMC, which can be defined on the /*
* OpenPOWER systems have a BMC, which can be defined on the
* command line with: * command line with:
* *
* -device ipmi-bmc-sim,id=bmc0 * -device ipmi-bmc-sim,id=bmc0
@ -705,7 +714,8 @@ static void pnv_init(MachineState *machine)
pnv->chips[i] = PNV_CHIP(chip); pnv->chips[i] = PNV_CHIP(chip);
/* TODO: put all the memory in one node on chip 0 until we find a /*
* TODO: put all the memory in one node on chip 0 until we find a
* way to specify different ranges for each chip * way to specify different ranges for each chip
*/ */
if (i == 0) { if (i == 0) {
@ -732,8 +742,10 @@ static void pnv_init(MachineState *machine)
/* Create an RTC ISA device too */ /* Create an RTC ISA device too */
mc146818_rtc_init(pnv->isa_bus, 2000, NULL); mc146818_rtc_init(pnv->isa_bus, 2000, NULL);
/* OpenPOWER systems use a IPMI SEL Event message to notify the /*
* host to powerdown */ * OpenPOWER systems use a IPMI SEL Event message to notify the
* host to powerdown
*/
pnv->powerdown_notifier.notify = pnv_powerdown_notify; pnv->powerdown_notifier.notify = pnv_powerdown_notify;
qemu_register_powerdown_notifier(&pnv->powerdown_notifier); qemu_register_powerdown_notifier(&pnv->powerdown_notifier);
} }
@ -803,7 +815,8 @@ static void pnv_chip_power9_intc_create(PnvChip *chip, PowerPCCPU *cpu,
pnv_cpu->intc = obj; pnv_cpu->intc = obj;
} }
/* Allowed core identifiers on a POWER8 Processor Chip : /*
* Allowed core identifiers on a POWER8 Processor Chip :
* *
* <EX0 reserved> * <EX0 reserved>
* EX1 - Venice only * EX1 - Venice only
@ -847,6 +860,11 @@ static void pnv_chip_power8_instance_init(Object *obj)
TYPE_PNV8_OCC, &error_abort, NULL); TYPE_PNV8_OCC, &error_abort, NULL);
object_property_add_const_link(OBJECT(&chip8->occ), "psi", object_property_add_const_link(OBJECT(&chip8->occ), "psi",
OBJECT(&chip8->psi), &error_abort); OBJECT(&chip8->psi), &error_abort);
object_initialize_child(obj, "homer", &chip8->homer, sizeof(chip8->homer),
TYPE_PNV8_HOMER, &error_abort, NULL);
object_property_add_const_link(OBJECT(&chip8->homer), "chip", obj,
&error_abort);
} }
static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp) static void pnv_chip_icp_realize(Pnv8Chip *chip8, Error **errp)
@ -923,8 +941,10 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp)
(uint64_t) PNV_XSCOM_BASE(chip), (uint64_t) PNV_XSCOM_BASE(chip),
PNV_XSCOM_LPC_BASE); PNV_XSCOM_LPC_BASE);
/* Interrupt Management Area. This is the memory region holding /*
* all the Interrupt Control Presenter (ICP) registers */ * Interrupt Management Area. This is the memory region holding
* all the Interrupt Control Presenter (ICP) registers
*/
pnv_chip_icp_realize(chip8, &local_err); pnv_chip_icp_realize(chip8, &local_err);
if (local_err) { if (local_err) {
error_propagate(errp, local_err); error_propagate(errp, local_err);
@ -938,6 +958,20 @@ static void pnv_chip_power8_realize(DeviceState *dev, Error **errp)
return; return;
} }
pnv_xscom_add_subregion(chip, PNV_XSCOM_OCC_BASE, &chip8->occ.xscom_regs); pnv_xscom_add_subregion(chip, PNV_XSCOM_OCC_BASE, &chip8->occ.xscom_regs);
/* OCC SRAM model */
memory_region_add_subregion(get_system_memory(), PNV_OCC_COMMON_AREA(chip),
&chip8->occ.sram_regs);
/* HOMER */
object_property_set_bool(OBJECT(&chip8->homer), true, "realized",
&local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
memory_region_add_subregion(get_system_memory(), PNV_HOMER_BASE(chip),
&chip8->homer.regs);
} }
static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data) static void pnv_chip_power8e_class_init(ObjectClass *klass, void *data)
@ -1020,6 +1054,11 @@ static void pnv_chip_power9_instance_init(Object *obj)
TYPE_PNV9_OCC, &error_abort, NULL); TYPE_PNV9_OCC, &error_abort, NULL);
object_property_add_const_link(OBJECT(&chip9->occ), "psi", object_property_add_const_link(OBJECT(&chip9->occ), "psi",
OBJECT(&chip9->psi), &error_abort); OBJECT(&chip9->psi), &error_abort);
object_initialize_child(obj, "homer", &chip9->homer, sizeof(chip9->homer),
TYPE_PNV9_HOMER, &error_abort, NULL);
object_property_add_const_link(OBJECT(&chip9->homer), "chip", obj,
&error_abort);
} }
static void pnv_chip_quad_realize(Pnv9Chip *chip9, Error **errp) static void pnv_chip_quad_realize(Pnv9Chip *chip9, Error **errp)
@ -1126,6 +1165,20 @@ static void pnv_chip_power9_realize(DeviceState *dev, Error **errp)
return; return;
} }
pnv_xscom_add_subregion(chip, PNV9_XSCOM_OCC_BASE, &chip9->occ.xscom_regs); pnv_xscom_add_subregion(chip, PNV9_XSCOM_OCC_BASE, &chip9->occ.xscom_regs);
/* OCC SRAM model */
memory_region_add_subregion(get_system_memory(), PNV9_OCC_COMMON_AREA(chip),
&chip9->occ.sram_regs);
/* HOMER */
object_property_set_bool(OBJECT(&chip9->homer), true, "realized",
&local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
memory_region_add_subregion(get_system_memory(), PNV9_HOMER_BASE(chip),
&chip9->homer.regs);
} }
static void pnv_chip_power9_class_init(ObjectClass *klass, void *data) static void pnv_chip_power9_class_init(ObjectClass *klass, void *data)
@ -1404,8 +1457,8 @@ static void pnv_machine_class_init(ObjectClass *oc, void *data)
mc->init = pnv_init; mc->init = pnv_init;
mc->reset = pnv_reset; mc->reset = pnv_reset;
mc->max_cpus = MAX_CPUS; mc->max_cpus = MAX_CPUS;
mc->block_default_type = IF_IDE; /* Pnv provides a AHCI device for /* Pnv provides a AHCI device for storage */
* storage */ mc->block_default_type = IF_IDE;
mc->no_parallel = 1; mc->no_parallel = 1;
mc->default_boot_order = NULL; mc->default_boot_order = NULL;
/* /*
@ -1432,23 +1485,21 @@ static void pnv_machine_class_init(ObjectClass *oc, void *data)
.parent = TYPE_PNV9_CHIP, \ .parent = TYPE_PNV9_CHIP, \
} }
#define DEFINE_PNV_MACHINE_TYPE(cpu, class_initfn) \
{ \
.name = MACHINE_TYPE_NAME(cpu), \
.parent = TYPE_PNV_MACHINE, \
.instance_size = sizeof(PnvMachineState), \
.instance_init = pnv_machine_instance_init, \
.class_init = class_initfn, \
.interfaces = (InterfaceInfo[]) { \
{ TYPE_XICS_FABRIC }, \
{ TYPE_INTERRUPT_STATS_PROVIDER }, \
{ }, \
}, \
}
static const TypeInfo types[] = { static const TypeInfo types[] = {
DEFINE_PNV_MACHINE_TYPE("powernv8", pnv_machine_power8_class_init), {
DEFINE_PNV_MACHINE_TYPE("powernv9", pnv_machine_power9_class_init), .name = MACHINE_TYPE_NAME("powernv9"),
.parent = TYPE_PNV_MACHINE,
.class_init = pnv_machine_power9_class_init,
},
{
.name = MACHINE_TYPE_NAME("powernv8"),
.parent = TYPE_PNV_MACHINE,
.class_init = pnv_machine_power8_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_XICS_FABRIC },
{ },
},
},
{ {
.name = TYPE_PNV_MACHINE, .name = TYPE_PNV_MACHINE,
.parent = TYPE_MACHINE, .parent = TYPE_MACHINE,
@ -1457,7 +1508,6 @@ static const TypeInfo types[] = {
.instance_init = pnv_machine_instance_init, .instance_init = pnv_machine_instance_init,
.class_init = pnv_machine_class_init, .class_init = pnv_machine_class_init,
.interfaces = (InterfaceInfo[]) { .interfaces = (InterfaceInfo[]) {
{ TYPE_XICS_FABRIC },
{ TYPE_INTERRUPT_STATS_PROVIDER }, { TYPE_INTERRUPT_STATS_PROVIDER },
{ }, { },
}, },

View File

@ -77,13 +77,10 @@ void pnv_dt_bmc_sensors(IPMIBmc *bmc, void *fdt)
const struct ipmi_sdr_compact *sdr; const struct ipmi_sdr_compact *sdr;
uint16_t nextrec; uint16_t nextrec;
offset = fdt_add_subnode(fdt, 0, "/bmc"); offset = fdt_add_subnode(fdt, 0, "bmc");
_FDT(offset); _FDT(offset);
_FDT((fdt_setprop_string(fdt, offset, "name", "bmc"))); _FDT((fdt_setprop_string(fdt, offset, "name", "bmc")));
_FDT((fdt_setprop_cell(fdt, offset, "#address-cells", 0x1)));
_FDT((fdt_setprop_cell(fdt, offset, "#size-cells", 0x0)));
offset = fdt_add_subnode(fdt, offset, "sensors"); offset = fdt_add_subnode(fdt, offset, "sensors");
_FDT(offset); _FDT(offset);

272
hw/ppc/pnv_homer.c Normal file
View File

@ -0,0 +1,272 @@
/*
* QEMU PowerPC PowerNV Emulation of a few HOMER related registers
*
* Copyright (c) 2019, IBM Corporation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "exec/hwaddr.h"
#include "exec/memory.h"
#include "sysemu/cpus.h"
#include "hw/qdev-core.h"
#include "hw/ppc/pnv.h"
#include "hw/ppc/pnv_homer.h"
static bool core_max_array(PnvHomer *homer, hwaddr addr)
{
int i;
PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer);
for (i = 0; i <= homer->chip->nr_cores; i++) {
if (addr == (hmrc->core_max_base + i)) {
return true;
}
}
return false;
}
/* P8 Pstate table */
#define PNV8_OCC_PSTATE_VERSION 0x1f8001
#define PNV8_OCC_PSTATE_MIN 0x1f8003
#define PNV8_OCC_PSTATE_VALID 0x1f8000
#define PNV8_OCC_PSTATE_THROTTLE 0x1f8002
#define PNV8_OCC_PSTATE_NOM 0x1f8004
#define PNV8_OCC_PSTATE_TURBO 0x1f8005
#define PNV8_OCC_PSTATE_ULTRA_TURBO 0x1f8006
#define PNV8_OCC_PSTATE_DATA 0x1f8008
#define PNV8_OCC_PSTATE_ID_ZERO 0x1f8010
#define PNV8_OCC_PSTATE_ID_ONE 0x1f8018
#define PNV8_OCC_PSTATE_ID_TWO 0x1f8020
#define PNV8_OCC_VDD_VOLTAGE_IDENTIFIER 0x1f8012
#define PNV8_OCC_VCS_VOLTAGE_IDENTIFIER 0x1f8013
#define PNV8_OCC_PSTATE_ZERO_FREQUENCY 0x1f8014
#define PNV8_OCC_PSTATE_ONE_FREQUENCY 0x1f801c
#define PNV8_OCC_PSTATE_TWO_FREQUENCY 0x1f8024
#define PNV8_CORE_MAX_BASE 0x1f8810
static uint64_t pnv_power8_homer_read(void *opaque, hwaddr addr,
unsigned size)
{
PnvHomer *homer = PNV_HOMER(opaque);
switch (addr) {
case PNV8_OCC_PSTATE_VERSION:
case PNV8_OCC_PSTATE_MIN:
case PNV8_OCC_PSTATE_ID_ZERO:
return 0;
case PNV8_OCC_PSTATE_VALID:
case PNV8_OCC_PSTATE_THROTTLE:
case PNV8_OCC_PSTATE_NOM:
case PNV8_OCC_PSTATE_TURBO:
case PNV8_OCC_PSTATE_ID_ONE:
case PNV8_OCC_VDD_VOLTAGE_IDENTIFIER:
case PNV8_OCC_VCS_VOLTAGE_IDENTIFIER:
return 1;
case PNV8_OCC_PSTATE_ULTRA_TURBO:
case PNV8_OCC_PSTATE_ID_TWO:
return 2;
case PNV8_OCC_PSTATE_DATA:
return 0x1000000000000000;
/* P8 frequency for 0, 1, and 2 pstates */
case PNV8_OCC_PSTATE_ZERO_FREQUENCY:
case PNV8_OCC_PSTATE_ONE_FREQUENCY:
case PNV8_OCC_PSTATE_TWO_FREQUENCY:
return 3000;
}
/* pstate table core max array */
if (core_max_array(homer, addr)) {
return 1;
}
return 0;
}
static void pnv_power8_homer_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
/* callback function defined to homer write */
return;
}
static const MemoryRegionOps pnv_power8_homer_ops = {
.read = pnv_power8_homer_read,
.write = pnv_power8_homer_write,
.valid.min_access_size = 1,
.valid.max_access_size = 8,
.impl.min_access_size = 1,
.impl.max_access_size = 8,
.endianness = DEVICE_BIG_ENDIAN,
};
static void pnv_homer_power8_class_init(ObjectClass *klass, void *data)
{
PnvHomerClass *homer = PNV_HOMER_CLASS(klass);
homer->homer_size = PNV_HOMER_SIZE;
homer->homer_ops = &pnv_power8_homer_ops;
homer->core_max_base = PNV8_CORE_MAX_BASE;
}
static const TypeInfo pnv_homer_power8_type_info = {
.name = TYPE_PNV8_HOMER,
.parent = TYPE_PNV_HOMER,
.instance_size = sizeof(PnvHomer),
.class_init = pnv_homer_power8_class_init,
};
/* P9 Pstate table */
#define PNV9_OCC_PSTATE_ID_ZERO 0xe2018
#define PNV9_OCC_PSTATE_ID_ONE 0xe2020
#define PNV9_OCC_PSTATE_ID_TWO 0xe2028
#define PNV9_OCC_PSTATE_DATA 0xe2000
#define PNV9_OCC_PSTATE_DATA_AREA 0xe2008
#define PNV9_OCC_PSTATE_MIN 0xe2003
#define PNV9_OCC_PSTATE_NOM 0xe2004
#define PNV9_OCC_PSTATE_TURBO 0xe2005
#define PNV9_OCC_PSTATE_ULTRA_TURBO 0xe2818
#define PNV9_OCC_MAX_PSTATE_ULTRA_TURBO 0xe2006
#define PNV9_OCC_PSTATE_MAJOR_VERSION 0xe2001
#define PNV9_OCC_OPAL_RUNTIME_DATA 0xe2b85
#define PNV9_CHIP_HOMER_IMAGE_POINTER 0x200008
#define PNV9_CHIP_HOMER_BASE 0x0
#define PNV9_OCC_PSTATE_ZERO_FREQUENCY 0xe201c
#define PNV9_OCC_PSTATE_ONE_FREQUENCY 0xe2024
#define PNV9_OCC_PSTATE_TWO_FREQUENCY 0xe202c
#define PNV9_OCC_ROLE_MASTER_OR_SLAVE 0xe2002
#define PNV9_CORE_MAX_BASE 0xe2819
static uint64_t pnv_power9_homer_read(void *opaque, hwaddr addr,
unsigned size)
{
PnvHomer *homer = PNV_HOMER(opaque);
switch (addr) {
case PNV9_OCC_MAX_PSTATE_ULTRA_TURBO:
case PNV9_OCC_PSTATE_ID_ZERO:
return 0;
case PNV9_OCC_PSTATE_DATA:
case PNV9_OCC_ROLE_MASTER_OR_SLAVE:
case PNV9_OCC_PSTATE_NOM:
case PNV9_OCC_PSTATE_TURBO:
case PNV9_OCC_PSTATE_ID_ONE:
case PNV9_OCC_PSTATE_ULTRA_TURBO:
case PNV9_OCC_OPAL_RUNTIME_DATA:
return 1;
case PNV9_OCC_PSTATE_MIN:
case PNV9_OCC_PSTATE_ID_TWO:
return 2;
/* 3000 khz frequency for 0, 1, and 2 pstates */
case PNV9_OCC_PSTATE_ZERO_FREQUENCY:
case PNV9_OCC_PSTATE_ONE_FREQUENCY:
case PNV9_OCC_PSTATE_TWO_FREQUENCY:
return 3000;
case PNV9_OCC_PSTATE_MAJOR_VERSION:
return 0x90;
case PNV9_CHIP_HOMER_BASE:
case PNV9_OCC_PSTATE_DATA_AREA:
case PNV9_CHIP_HOMER_IMAGE_POINTER:
return 0x1000000000000000;
}
/* pstate table core max array */
if (core_max_array(homer, addr)) {
return 1;
}
return 0;
}
static void pnv_power9_homer_write(void *opaque, hwaddr addr,
uint64_t val, unsigned size)
{
/* callback function defined to homer write */
return;
}
static const MemoryRegionOps pnv_power9_homer_ops = {
.read = pnv_power9_homer_read,
.write = pnv_power9_homer_write,
.valid.min_access_size = 1,
.valid.max_access_size = 8,
.impl.min_access_size = 1,
.impl.max_access_size = 8,
.endianness = DEVICE_BIG_ENDIAN,
};
static void pnv_homer_power9_class_init(ObjectClass *klass, void *data)
{
PnvHomerClass *homer = PNV_HOMER_CLASS(klass);
homer->homer_size = PNV9_HOMER_SIZE;
homer->homer_ops = &pnv_power9_homer_ops;
homer->core_max_base = PNV9_CORE_MAX_BASE;
}
static const TypeInfo pnv_homer_power9_type_info = {
.name = TYPE_PNV9_HOMER,
.parent = TYPE_PNV_HOMER,
.instance_size = sizeof(PnvHomer),
.class_init = pnv_homer_power9_class_init,
};
static void pnv_homer_realize(DeviceState *dev, Error **errp)
{
PnvHomer *homer = PNV_HOMER(dev);
PnvHomerClass *hmrc = PNV_HOMER_GET_CLASS(homer);
Object *obj;
Error *local_err = NULL;
obj = object_property_get_link(OBJECT(dev), "chip", &local_err);
if (!obj) {
error_propagate(errp, local_err);
error_prepend(errp, "required link 'chip' not found: ");
return;
}
homer->chip = PNV_CHIP(obj);
/* homer region */
memory_region_init_io(&homer->regs, OBJECT(dev),
hmrc->homer_ops, homer, "homer-main-memory",
hmrc->homer_size);
}
static void pnv_homer_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->realize = pnv_homer_realize;
dc->desc = "PowerNV HOMER Memory";
}
static const TypeInfo pnv_homer_type_info = {
.name = TYPE_PNV_HOMER,
.parent = TYPE_DEVICE,
.instance_size = sizeof(PnvHomer),
.class_init = pnv_homer_class_init,
.class_size = sizeof(PnvHomerClass),
.abstract = true,
};
static void pnv_homer_register_types(void)
{
type_register_static(&pnv_homer_type_info);
type_register_static(&pnv_homer_power8_type_info);
type_register_static(&pnv_homer_power9_type_info);
}
type_init(pnv_homer_register_types);

View File

@ -30,6 +30,24 @@
#define OCB_OCI_OCCMISC_AND 0x4021 #define OCB_OCI_OCCMISC_AND 0x4021
#define OCB_OCI_OCCMISC_OR 0x4022 #define OCB_OCI_OCCMISC_OR 0x4022
/* OCC sensors */
#define OCC_SENSOR_DATA_BLOCK_OFFSET 0x580000
#define OCC_SENSOR_DATA_VALID 0x580001
#define OCC_SENSOR_DATA_VERSION 0x580002
#define OCC_SENSOR_DATA_READING_VERSION 0x580004
#define OCC_SENSOR_DATA_NR_SENSORS 0x580008
#define OCC_SENSOR_DATA_NAMES_OFFSET 0x580010
#define OCC_SENSOR_DATA_READING_PING_OFFSET 0x580014
#define OCC_SENSOR_DATA_READING_PONG_OFFSET 0x58000c
#define OCC_SENSOR_DATA_NAME_LENGTH 0x58000d
#define OCC_SENSOR_NAME_STRUCTURE_TYPE 0x580023
#define OCC_SENSOR_LOC_CORE 0x580022
#define OCC_SENSOR_LOC_GPU 0x580020
#define OCC_SENSOR_TYPE_POWER 0x580003
#define OCC_SENSOR_NAME 0x580005
#define HWMON_SENSORS_MASK 0x58001e
#define SLW_IMAGE_BASE 0x0
static void pnv_occ_set_misc(PnvOCC *occ, uint64_t val) static void pnv_occ_set_misc(PnvOCC *occ, uint64_t val)
{ {
bool irq_state; bool irq_state;
@ -82,6 +100,48 @@ static void pnv_occ_power8_xscom_write(void *opaque, hwaddr addr,
} }
} }
static uint64_t pnv_occ_common_area_read(void *opaque, hwaddr addr,
unsigned width)
{
switch (addr) {
/*
* occ-sensor sanity check that asserts the sensor
* header block
*/
case OCC_SENSOR_DATA_BLOCK_OFFSET:
case OCC_SENSOR_DATA_VALID:
case OCC_SENSOR_DATA_VERSION:
case OCC_SENSOR_DATA_READING_VERSION:
case OCC_SENSOR_DATA_NR_SENSORS:
case OCC_SENSOR_DATA_NAMES_OFFSET:
case OCC_SENSOR_DATA_READING_PING_OFFSET:
case OCC_SENSOR_DATA_READING_PONG_OFFSET:
case OCC_SENSOR_NAME_STRUCTURE_TYPE:
return 1;
case OCC_SENSOR_DATA_NAME_LENGTH:
return 0x30;
case OCC_SENSOR_LOC_CORE:
return 0x0040;
case OCC_SENSOR_TYPE_POWER:
return 0x0080;
case OCC_SENSOR_NAME:
return 0x1000;
case HWMON_SENSORS_MASK:
case OCC_SENSOR_LOC_GPU:
return 0x8e00;
case SLW_IMAGE_BASE:
return 0x1000000000000000;
}
return 0;
}
static void pnv_occ_common_area_write(void *opaque, hwaddr addr,
uint64_t val, unsigned width)
{
/* callback function defined to occ common area write */
return;
}
static const MemoryRegionOps pnv_occ_power8_xscom_ops = { static const MemoryRegionOps pnv_occ_power8_xscom_ops = {
.read = pnv_occ_power8_xscom_read, .read = pnv_occ_power8_xscom_read,
.write = pnv_occ_power8_xscom_write, .write = pnv_occ_power8_xscom_write,
@ -92,12 +152,24 @@ static const MemoryRegionOps pnv_occ_power8_xscom_ops = {
.endianness = DEVICE_BIG_ENDIAN, .endianness = DEVICE_BIG_ENDIAN,
}; };
const MemoryRegionOps pnv_occ_sram_ops = {
.read = pnv_occ_common_area_read,
.write = pnv_occ_common_area_write,
.valid.min_access_size = 1,
.valid.max_access_size = 8,
.impl.min_access_size = 1,
.impl.max_access_size = 8,
.endianness = DEVICE_BIG_ENDIAN,
};
static void pnv_occ_power8_class_init(ObjectClass *klass, void *data) static void pnv_occ_power8_class_init(ObjectClass *klass, void *data)
{ {
PnvOCCClass *poc = PNV_OCC_CLASS(klass); PnvOCCClass *poc = PNV_OCC_CLASS(klass);
poc->xscom_size = PNV_XSCOM_OCC_SIZE; poc->xscom_size = PNV_XSCOM_OCC_SIZE;
poc->sram_size = PNV_OCC_COMMON_AREA_SIZE;
poc->xscom_ops = &pnv_occ_power8_xscom_ops; poc->xscom_ops = &pnv_occ_power8_xscom_ops;
poc->sram_ops = &pnv_occ_sram_ops;
poc->psi_irq = PSIHB_IRQ_OCC; poc->psi_irq = PSIHB_IRQ_OCC;
} }
@ -168,7 +240,9 @@ static void pnv_occ_power9_class_init(ObjectClass *klass, void *data)
PnvOCCClass *poc = PNV_OCC_CLASS(klass); PnvOCCClass *poc = PNV_OCC_CLASS(klass);
poc->xscom_size = PNV9_XSCOM_OCC_SIZE; poc->xscom_size = PNV9_XSCOM_OCC_SIZE;
poc->sram_size = PNV9_OCC_COMMON_AREA_SIZE;
poc->xscom_ops = &pnv_occ_power9_xscom_ops; poc->xscom_ops = &pnv_occ_power9_xscom_ops;
poc->sram_ops = &pnv_occ_sram_ops;
poc->psi_irq = PSIHB9_IRQ_OCC; poc->psi_irq = PSIHB9_IRQ_OCC;
} }
@ -199,6 +273,10 @@ static void pnv_occ_realize(DeviceState *dev, Error **errp)
/* XScom region for OCC registers */ /* XScom region for OCC registers */
pnv_xscom_region_init(&occ->xscom_regs, OBJECT(dev), poc->xscom_ops, pnv_xscom_region_init(&occ->xscom_regs, OBJECT(dev), poc->xscom_ops,
occ, "xscom-occ", poc->xscom_size); occ, "xscom-occ", poc->xscom_size);
/* XScom region for OCC SRAM registers */
pnv_xscom_region_init(&occ->sram_regs, OBJECT(dev), poc->sram_ops,
occ, "occ-common-area", poc->sram_size);
} }
static void pnv_occ_class_init(ObjectClass *klass, void *data) static void pnv_occ_class_init(ObjectClass *klass, void *data)

View File

@ -311,7 +311,7 @@ static void pnv_psi_set_xivr(PnvPsi *psi, uint32_t reg, uint64_t val)
* do for now but a more accurate implementation would instead * do for now but a more accurate implementation would instead
* use a fixed server/prio and a remapper of the generated irq. * use a fixed server/prio and a remapper of the generated irq.
*/ */
ics_simple_write_xive(ics, src, server, prio, prio); ics_write_xive(ics, src, server, prio, prio);
} }
static uint64_t pnv_psi_reg_read(PnvPsi *psi, uint32_t offset, bool mmio) static uint64_t pnv_psi_reg_read(PnvPsi *psi, uint32_t offset, bool mmio)
@ -469,7 +469,7 @@ static void pnv_psi_power8_instance_init(Object *obj)
Pnv8Psi *psi8 = PNV8_PSI(obj); Pnv8Psi *psi8 = PNV8_PSI(obj);
object_initialize_child(obj, "ics-psi", &psi8->ics, sizeof(psi8->ics), object_initialize_child(obj, "ics-psi", &psi8->ics, sizeof(psi8->ics),
TYPE_ICS_SIMPLE, &error_abort, NULL); TYPE_ICS, &error_abort, NULL);
} }
static const uint8_t irq_to_xivr[] = { static const uint8_t irq_to_xivr[] = {
@ -514,7 +514,7 @@ static void pnv_psi_power8_realize(DeviceState *dev, Error **errp)
ics_set_irq_type(ics, i, true); ics_set_irq_type(ics, i, true);
} }
psi->qirqs = qemu_allocate_irqs(ics_simple_set_irq, ics, ics->nr_irqs); psi->qirqs = qemu_allocate_irqs(ics_set_irq, ics, ics->nr_irqs);
/* XSCOM region for PSI registers */ /* XSCOM region for PSI registers */
pnv_xscom_region_init(&psi->xscom_regs, OBJECT(dev), &pnv_psi_xscom_ops, pnv_xscom_region_init(&psi->xscom_regs, OBJECT(dev), &pnv_psi_xscom_ops,

View File

@ -36,6 +36,16 @@
#define PRD_P9_IPOLL_REG_MASK 0x000F0033 #define PRD_P9_IPOLL_REG_MASK 0x000F0033
#define PRD_P9_IPOLL_REG_STATUS 0x000F0034 #define PRD_P9_IPOLL_REG_STATUS 0x000F0034
/* PBA BARs */
#define P8_PBA_BAR0 0x2013f00
#define P8_PBA_BAR2 0x2013f02
#define P8_PBA_BARMASK0 0x2013f04
#define P8_PBA_BARMASK2 0x2013f06
#define P9_PBA_BAR0 0x5012b00
#define P9_PBA_BAR2 0x5012b02
#define P9_PBA_BARMASK0 0x5012b04
#define P9_PBA_BARMASK2 0x5012b06
static void xscom_complete(CPUState *cs, uint64_t hmer_bits) static void xscom_complete(CPUState *cs, uint64_t hmer_bits)
{ {
/* /*
@ -74,6 +84,26 @@ static uint64_t xscom_read_default(PnvChip *chip, uint32_t pcba)
case 0x18002: /* ECID2 */ case 0x18002: /* ECID2 */
return 0; return 0;
case P9_PBA_BAR0:
return PNV9_HOMER_BASE(chip);
case P8_PBA_BAR0:
return PNV_HOMER_BASE(chip);
case P9_PBA_BARMASK0: /* P9 homer region size */
return PNV9_HOMER_SIZE;
case P8_PBA_BARMASK0: /* P8 homer region size */
return PNV_HOMER_SIZE;
case P9_PBA_BAR2: /* P9 occ common area */
return PNV9_OCC_COMMON_AREA(chip);
case P8_PBA_BAR2: /* P8 occ common area */
return PNV_OCC_COMMON_AREA(chip);
case P9_PBA_BARMASK2: /* P9 occ common area size */
return PNV9_OCC_COMMON_AREA_SIZE;
case P8_PBA_BARMASK2: /* P8 occ common area size */
return PNV_OCC_COMMON_AREA_SIZE;
case 0x1010c00: /* PIBAM FIR */ case 0x1010c00: /* PIBAM FIR */
case 0x1010c03: /* PIBAM FIR MASK */ case 0x1010c03: /* PIBAM FIR MASK */
@ -93,13 +123,9 @@ static uint64_t xscom_read_default(PnvChip *chip, uint32_t pcba)
case 0x2020009: /* ADU stuff, error register */ case 0x2020009: /* ADU stuff, error register */
case 0x202000f: /* ADU stuff, receive status register*/ case 0x202000f: /* ADU stuff, receive status register*/
return 0; return 0;
case 0x2013f00: /* PBA stuff */
case 0x2013f01: /* PBA stuff */ case 0x2013f01: /* PBA stuff */
case 0x2013f02: /* PBA stuff */
case 0x2013f03: /* PBA stuff */ case 0x2013f03: /* PBA stuff */
case 0x2013f04: /* PBA stuff */
case 0x2013f05: /* PBA stuff */ case 0x2013f05: /* PBA stuff */
case 0x2013f06: /* PBA stuff */
case 0x2013f07: /* PBA stuff */ case 0x2013f07: /* PBA stuff */
return 0; return 0;
case 0x2013028: /* CAPP stuff */ case 0x2013028: /* CAPP stuff */

View File

@ -81,6 +81,8 @@
#include "hw/mem/memory-device.h" #include "hw/mem/memory-device.h"
#include "hw/ppc/spapr_tpm_proxy.h" #include "hw/ppc/spapr_tpm_proxy.h"
#include "monitor/monitor.h"
#include <libfdt.h> #include <libfdt.h>
/* SLOF memory layout: /* SLOF memory layout:
@ -94,7 +96,6 @@
* We load our kernel at 4M, leaving space for SLOF initial image * We load our kernel at 4M, leaving space for SLOF initial image
*/ */
#define FDT_MAX_SIZE 0x100000 #define FDT_MAX_SIZE 0x100000
#define RTAS_MAX_SIZE 0x10000
#define RTAS_MAX_ADDR 0x80000000 /* RTAS must stay below that */ #define RTAS_MAX_ADDR 0x80000000 /* RTAS must stay below that */
#define FW_MAX_SIZE 0x400000 #define FW_MAX_SIZE 0x400000
#define FW_FILE_NAME "slof.bin" #define FW_FILE_NAME "slof.bin"
@ -218,8 +219,7 @@ static int spapr_fixup_cpu_numa_dt(void *fdt, int offset, PowerPCCPU *cpu)
/* Populate the "ibm,pa-features" property */ /* Populate the "ibm,pa-features" property */
static void spapr_populate_pa_features(SpaprMachineState *spapr, static void spapr_populate_pa_features(SpaprMachineState *spapr,
PowerPCCPU *cpu, PowerPCCPU *cpu,
void *fdt, int offset, void *fdt, int offset)
bool legacy_guest)
{ {
uint8_t pa_features_206[] = { 6, 0, uint8_t pa_features_206[] = { 6, 0,
0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 }; 0xf6, 0x1f, 0xc7, 0x00, 0x80, 0xc0 };
@ -285,7 +285,7 @@ static void spapr_populate_pa_features(SpaprMachineState *spapr,
if ((spapr_get_cap(spapr, SPAPR_CAP_HTM) != 0) && pa_size > 24) { if ((spapr_get_cap(spapr, SPAPR_CAP_HTM) != 0) && pa_size > 24) {
pa_features[24] |= 0x80; /* Transactional memory support */ pa_features[24] |= 0x80; /* Transactional memory support */
} }
if (legacy_guest && pa_size > 40) { if (spapr->cas_pre_isa3_guest && pa_size > 40) {
/* Workaround for broken kernels that attempt (guest) radix /* Workaround for broken kernels that attempt (guest) radix
* mode when they can't handle it, if they see the radix bit set * mode when they can't handle it, if they see the radix bit set
* in pa-features. So hide it from them. */ * in pa-features. So hide it from them. */
@ -295,65 +295,6 @@ static void spapr_populate_pa_features(SpaprMachineState *spapr,
_FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size))); _FDT((fdt_setprop(fdt, offset, "ibm,pa-features", pa_features, pa_size)));
} }
static int spapr_fixup_cpu_dt(void *fdt, SpaprMachineState *spapr)
{
MachineState *ms = MACHINE(spapr);
int ret = 0, offset, cpus_offset;
CPUState *cs;
char cpu_model[32];
uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
CPU_FOREACH(cs) {
PowerPCCPU *cpu = POWERPC_CPU(cs);
DeviceClass *dc = DEVICE_GET_CLASS(cs);
int index = spapr_get_vcpu_id(cpu);
int compat_smt = MIN(ms->smp.threads, ppc_compat_max_vthreads(cpu));
if (!spapr_is_thread0_in_vcore(spapr, cpu)) {
continue;
}
snprintf(cpu_model, 32, "%s@%x", dc->fw_name, index);
cpus_offset = fdt_path_offset(fdt, "/cpus");
if (cpus_offset < 0) {
cpus_offset = fdt_add_subnode(fdt, 0, "cpus");
if (cpus_offset < 0) {
return cpus_offset;
}
}
offset = fdt_subnode_offset(fdt, cpus_offset, cpu_model);
if (offset < 0) {
offset = fdt_add_subnode(fdt, cpus_offset, cpu_model);
if (offset < 0) {
return offset;
}
}
ret = fdt_setprop(fdt, offset, "ibm,pft-size",
pft_size_prop, sizeof(pft_size_prop));
if (ret < 0) {
return ret;
}
if (ms->numa_state->num_nodes > 1) {
ret = spapr_fixup_cpu_numa_dt(fdt, offset, cpu);
if (ret < 0) {
return ret;
}
}
ret = spapr_fixup_cpu_smt_dt(fdt, offset, cpu, compat_smt);
if (ret < 0) {
return ret;
}
spapr_populate_pa_features(spapr, cpu, fdt, offset,
spapr->cas_legacy_guest_workaround);
}
return ret;
}
static hwaddr spapr_node0_size(MachineState *machine) static hwaddr spapr_node0_size(MachineState *machine)
{ {
if (machine->numa_state->num_nodes) { if (machine->numa_state->num_nodes) {
@ -388,7 +329,7 @@ static int spapr_populate_memory_node(void *fdt, int nodeid, hwaddr start,
mem_reg_property[0] = cpu_to_be64(start); mem_reg_property[0] = cpu_to_be64(start);
mem_reg_property[1] = cpu_to_be64(size); mem_reg_property[1] = cpu_to_be64(size);
sprintf(mem_name, "memory@" TARGET_FMT_lx, start); sprintf(mem_name, "memory@%" HWADDR_PRIx, start);
off = fdt_add_subnode(fdt, 0, mem_name); off = fdt_add_subnode(fdt, 0, mem_name);
_FDT(off); _FDT(off);
_FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); _FDT((fdt_setprop_string(fdt, off, "device_type", "memory")));
@ -551,7 +492,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
page_sizes_prop, page_sizes_prop_size))); page_sizes_prop, page_sizes_prop_size)));
} }
spapr_populate_pa_features(spapr, cpu, fdt, offset, false); spapr_populate_pa_features(spapr, cpu, fdt, offset);
_FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id", _FDT((fdt_setprop_cell(fdt, offset, "ibm,chip-id",
cs->cpu_index / vcpus_per_socket))); cs->cpu_index / vcpus_per_socket)));
@ -984,11 +925,13 @@ static bool spapr_hotplugged_dev_before_cas(void)
return false; return false;
} }
static void *spapr_build_fdt(SpaprMachineState *spapr);
int spapr_h_cas_compose_response(SpaprMachineState *spapr, int spapr_h_cas_compose_response(SpaprMachineState *spapr,
target_ulong addr, target_ulong size, target_ulong addr, target_ulong size,
SpaprOptionVector *ov5_updates) SpaprOptionVector *ov5_updates)
{ {
void *fdt, *fdt_skel; void *fdt;
SpaprDeviceTreeUpdateHeader hdr = { .version_id = 1 }; SpaprDeviceTreeUpdateHeader hdr = { .version_id = 1 };
if (spapr_hotplugged_dev_before_cas()) { if (spapr_hotplugged_dev_before_cas()) {
@ -1004,28 +947,11 @@ int spapr_h_cas_compose_response(SpaprMachineState *spapr,
size -= sizeof(hdr); size -= sizeof(hdr);
/* Create skeleton */ fdt = spapr_build_fdt(spapr);
fdt_skel = g_malloc0(size);
_FDT((fdt_create(fdt_skel, size)));
_FDT((fdt_finish_reservemap(fdt_skel)));
_FDT((fdt_begin_node(fdt_skel, "")));
_FDT((fdt_end_node(fdt_skel)));
_FDT((fdt_finish(fdt_skel)));
fdt = g_malloc0(size);
_FDT((fdt_open_into(fdt_skel, fdt, size)));
g_free(fdt_skel);
/* Fixup cpu nodes */
_FDT((spapr_fixup_cpu_dt(fdt, spapr)));
if (spapr_dt_cas_updates(spapr, fdt, ov5_updates)) {
return -1;
}
/* Pack resulting tree */
_FDT((fdt_pack(fdt))); _FDT((fdt_pack(fdt)));
if (fdt_totalsize(fdt) + sizeof(hdr) > size) { if (fdt_totalsize(fdt) + sizeof(hdr) > size) {
g_free(fdt);
trace_spapr_cas_failed(size); trace_spapr_cas_failed(size);
return -1; return -1;
} }
@ -1033,7 +959,11 @@ int spapr_h_cas_compose_response(SpaprMachineState *spapr,
cpu_physical_memory_write(addr, &hdr, sizeof(hdr)); cpu_physical_memory_write(addr, &hdr, sizeof(hdr));
cpu_physical_memory_write(addr + sizeof(hdr), fdt, fdt_totalsize(fdt)); cpu_physical_memory_write(addr + sizeof(hdr), fdt, fdt_totalsize(fdt));
trace_spapr_cas_continue(fdt_totalsize(fdt) + sizeof(hdr)); trace_spapr_cas_continue(fdt_totalsize(fdt) + sizeof(hdr));
g_free(fdt);
g_free(spapr->fdt_blob);
spapr->fdt_size = fdt_totalsize(fdt);
spapr->fdt_initial_size = spapr->fdt_size;
spapr->fdt_blob = fdt;
return 0; return 0;
} }
@ -1136,19 +1066,28 @@ static void spapr_dt_ov5_platform_support(SpaprMachineState *spapr, void *fdt,
PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu); PowerPCCPU *first_ppc_cpu = POWERPC_CPU(first_cpu);
char val[2 * 4] = { char val[2 * 4] = {
23, spapr->irq->ov5, /* Xive mode. */ 23, 0x00, /* XICS / XIVE mode */
24, 0x00, /* Hash/Radix, filled in below. */ 24, 0x00, /* Hash/Radix, filled in below. */
25, 0x00, /* Hash options: Segment Tables == no, GTSE == no. */ 25, 0x00, /* Hash options: Segment Tables == no, GTSE == no. */
26, 0x40, /* Radix options: GTSE == yes. */ 26, 0x40, /* Radix options: GTSE == yes. */
}; };
if (spapr->irq->xics && spapr->irq->xive) {
val[1] = SPAPR_OV5_XIVE_BOTH;
} else if (spapr->irq->xive) {
val[1] = SPAPR_OV5_XIVE_EXPLOIT;
} else {
assert(spapr->irq->xics);
val[1] = SPAPR_OV5_XIVE_LEGACY;
}
if (!ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0, if (!ppc_check_compat(first_ppc_cpu, CPU_POWERPC_LOGICAL_3_00, 0,
first_ppc_cpu->compat_pvr)) { first_ppc_cpu->compat_pvr)) {
/* /*
* If we're in a pre POWER9 compat mode then the guest should * If we're in a pre POWER9 compat mode then the guest should
* do hash and use the legacy interrupt mode * do hash and use the legacy interrupt mode
*/ */
val[1] = 0x00; /* XICS */ val[1] = SPAPR_OV5_XIVE_LEGACY; /* XICS */
val[3] = 0x00; /* Hash */ val[3] = 0x00; /* Hash */
} else if (kvm_enabled()) { } else if (kvm_enabled()) {
if (kvmppc_has_cap_mmu_radix() && kvmppc_has_cap_mmu_hash_v3()) { if (kvmppc_has_cap_mmu_radix() && kvmppc_has_cap_mmu_hash_v3()) {
@ -1178,11 +1117,16 @@ static void spapr_dt_chosen(SpaprMachineState *spapr, void *fdt)
_FDT(chosen = fdt_add_subnode(fdt, 0, "chosen")); _FDT(chosen = fdt_add_subnode(fdt, 0, "chosen"));
_FDT(fdt_setprop_string(fdt, chosen, "bootargs", machine->kernel_cmdline)); if (machine->kernel_cmdline && machine->kernel_cmdline[0]) {
_FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-start", _FDT(fdt_setprop_string(fdt, chosen, "bootargs",
spapr->initrd_base)); machine->kernel_cmdline));
_FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-end", }
spapr->initrd_base + spapr->initrd_size)); if (spapr->initrd_size) {
_FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-start",
spapr->initrd_base));
_FDT(fdt_setprop_cell(fdt, chosen, "linux,initrd-end",
spapr->initrd_base + spapr->initrd_size));
}
if (spapr->kernel_size) { if (spapr->kernel_size) {
uint64_t kprop[2] = { cpu_to_be64(KERNEL_LOAD_ADDR), uint64_t kprop[2] = { cpu_to_be64(KERNEL_LOAD_ADDR),
@ -1717,8 +1661,7 @@ static void spapr_machine_reset(MachineState *machine)
{ {
SpaprMachineState *spapr = SPAPR_MACHINE(machine); SpaprMachineState *spapr = SPAPR_MACHINE(machine);
PowerPCCPU *first_ppc_cpu; PowerPCCPU *first_ppc_cpu;
uint32_t rtas_limit; hwaddr fdt_addr;
hwaddr rtas_addr, fdt_addr;
void *fdt; void *fdt;
int rc; int rc;
@ -1739,16 +1682,6 @@ static void spapr_machine_reset(MachineState *machine)
spapr_setup_hpt_and_vrma(spapr); spapr_setup_hpt_and_vrma(spapr);
} }
/*
* NVLink2-connected GPU RAM needs to be placed on a separate NUMA node.
* We assign a new numa ID per GPU in spapr_pci_collect_nvgpu() which is
* called from vPHB reset handler so we initialize the counter here.
* If no NUMA is configured from the QEMU side, we start from 1 as GPU RAM
* must be equally distant from any other node.
* The final value of spapr->gpu_numa_id is going to be written to
* max-associativity-domains in spapr_build_fdt().
*/
spapr->gpu_numa_id = MAX(1, machine->numa_state->num_nodes);
qemu_devices_reset(); qemu_devices_reset();
/* /*
@ -1792,14 +1725,10 @@ static void spapr_machine_reset(MachineState *machine)
* or just below 2GB, whichever is lower, so that it can be * or just below 2GB, whichever is lower, so that it can be
* processed with 32-bit real mode code if necessary * processed with 32-bit real mode code if necessary
*/ */
rtas_limit = MIN(spapr->rma_size, RTAS_MAX_ADDR); fdt_addr = MIN(spapr->rma_size, RTAS_MAX_ADDR) - FDT_MAX_SIZE;
rtas_addr = rtas_limit - RTAS_MAX_SIZE;
fdt_addr = rtas_addr - FDT_MAX_SIZE;
fdt = spapr_build_fdt(spapr); fdt = spapr_build_fdt(spapr);
spapr_load_rtas(spapr, fdt, rtas_addr);
rc = fdt_pack(fdt); rc = fdt_pack(fdt);
/* Should only fail if we've built a corrupted tree */ /* Should only fail if we've built a corrupted tree */
@ -2847,13 +2776,57 @@ static void spapr_machine_init(MachineState *machine)
spapr_ovec_set(spapr->ov5, OV5_DRMEM_V2); spapr_ovec_set(spapr->ov5, OV5_DRMEM_V2);
/* advertise XIVE on POWER9 machines */ /* advertise XIVE on POWER9 machines */
if (spapr->irq->ov5 & (SPAPR_OV5_XIVE_EXPLOIT | SPAPR_OV5_XIVE_BOTH)) { if (spapr->irq->xive) {
spapr_ovec_set(spapr->ov5, OV5_XIVE_EXPLOIT); spapr_ovec_set(spapr->ov5, OV5_XIVE_EXPLOIT);
} }
/* init CPUs */ /* init CPUs */
spapr_init_cpus(spapr); spapr_init_cpus(spapr);
/*
* check we don't have a memory-less/cpu-less NUMA node
* Firmware relies on the existing memory/cpu topology to provide the
* NUMA topology to the kernel.
* And the linux kernel needs to know the NUMA topology at start
* to be able to hotplug CPUs later.
*/
if (machine->numa_state->num_nodes) {
for (i = 0; i < machine->numa_state->num_nodes; ++i) {
/* check for memory-less node */
if (machine->numa_state->nodes[i].node_mem == 0) {
CPUState *cs;
int found = 0;
/* check for cpu-less node */
CPU_FOREACH(cs) {
PowerPCCPU *cpu = POWERPC_CPU(cs);
if (cpu->node_id == i) {
found = 1;
break;
}
}
/* memory-less and cpu-less node */
if (!found) {
error_report(
"Memory-less/cpu-less nodes are not supported (node %d)",
i);
exit(1);
}
}
}
}
/*
* NVLink2-connected GPU RAM needs to be placed on a separate NUMA node.
* We assign a new numa ID per GPU in spapr_pci_collect_nvgpu() which is
* called from vPHB reset handler so we initialize the counter here.
* If no NUMA is configured from the QEMU side, we start from 1 as GPU RAM
* must be equally distant from any other node.
* The final value of spapr->gpu_numa_id is going to be written to
* max-associativity-domains in spapr_build_fdt().
*/
spapr->gpu_numa_id = MAX(1, machine->numa_state->num_nodes);
if ((!kvm_enabled() || kvmppc_has_cap_mmu_radix()) && if ((!kvm_enabled() || kvmppc_has_cap_mmu_radix()) &&
ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0, ppc_type_check_compat(machine->cpu_type, CPU_POWERPC_LOGICAL_3_00, 0,
spapr->max_compat_pvr)) { spapr->max_compat_pvr)) {
@ -2915,28 +2888,6 @@ static void spapr_machine_init(MachineState *machine)
spapr_create_lmb_dr_connectors(spapr); spapr_create_lmb_dr_connectors(spapr);
} }
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin");
if (!filename) {
error_report("Could not find LPAR rtas '%s'", "spapr-rtas.bin");
exit(1);
}
spapr->rtas_size = get_image_size(filename);
if (spapr->rtas_size < 0) {
error_report("Could not get size of LPAR rtas '%s'", filename);
exit(1);
}
spapr->rtas_blob = g_malloc(spapr->rtas_size);
if (load_image_size(filename, spapr->rtas_blob, spapr->rtas_size) < 0) {
error_report("Could not load LPAR rtas '%s'", filename);
exit(1);
}
if (spapr->rtas_size > RTAS_MAX_SIZE) {
error_report("RTAS too big ! 0x%zx bytes (max is 0x%x)",
(size_t)spapr->rtas_size, RTAS_MAX_SIZE);
exit(1);
}
g_free(filename);
/* Set up RTAS event infrastructure */ /* Set up RTAS event infrastructure */
spapr_events_init(spapr); spapr_events_init(spapr);
@ -4321,6 +4272,8 @@ static void spapr_pic_print_info(InterruptStatsProvider *obj,
SpaprMachineState *spapr = SPAPR_MACHINE(obj); SpaprMachineState *spapr = SPAPR_MACHINE(obj);
spapr->irq->print_info(spapr, mon); spapr->irq->print_info(spapr, mon);
monitor_printf(mon, "irqchip: %s\n",
kvm_irqchip_in_kernel() ? "in-kernel" : "emulated");
} }
int spapr_get_vcpu_id(PowerPCCPU *cpu) int spapr_get_vcpu_id(PowerPCCPU *cpu)

View File

@ -1765,8 +1765,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} }
spapr->cas_legacy_guest_workaround = !spapr_ovec_test(ov1_guest, spapr->cas_pre_isa3_guest = !spapr_ovec_test(ov1_guest, OV1_PPC_3_00);
OV1_PPC_3_00);
spapr_ovec_cleanup(ov1_guest); spapr_ovec_cleanup(ov1_guest);
if (!spapr->cas_reboot) { if (!spapr->cas_reboot) {
/* If spapr_machine_reset() did not set up a HPT but one is necessary /* If spapr_machine_reset() did not set up a HPT but one is necessary
@ -1785,13 +1784,13 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
* terminate the boot. * terminate the boot.
*/ */
if (guest_xive) { if (guest_xive) {
if (spapr->irq->ov5 == SPAPR_OV5_XIVE_LEGACY) { if (!spapr->irq->xive) {
error_report( error_report(
"Guest requested unavailable interrupt mode (XIVE), try the ic-mode=xive or ic-mode=dual machine property"); "Guest requested unavailable interrupt mode (XIVE), try the ic-mode=xive or ic-mode=dual machine property");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} else { } else {
if (spapr->irq->ov5 == SPAPR_OV5_XIVE_EXPLOIT) { if (!spapr->irq->xics) {
error_report( error_report(
"Guest requested unavailable interrupt mode (XICS), either don't set the ic-mode machine property or try ic-mode=xics or ic-mode=dual"); "Guest requested unavailable interrupt mode (XICS), either don't set the ic-mode machine property or try ic-mode=xics or ic-mode=dual");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@ -1805,7 +1804,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
*/ */
if (!spapr->cas_reboot) { if (!spapr->cas_reboot) {
spapr->cas_reboot = spapr_ovec_test(ov5_updates, OV5_XIVE_EXPLOIT) spapr->cas_reboot = spapr_ovec_test(ov5_updates, OV5_XIVE_EXPLOIT)
&& spapr->irq->ov5 & SPAPR_OV5_XIVE_BOTH; && spapr->irq->xics && spapr->irq->xive;
} }
spapr_ovec_cleanup(ov5_updates); spapr_ovec_cleanup(ov5_updates);

View File

@ -92,44 +92,15 @@ static void spapr_irq_init_kvm(SpaprMachineState *spapr,
* XICS IRQ backend. * XICS IRQ backend.
*/ */
static void spapr_irq_init_xics(SpaprMachineState *spapr, int nr_irqs,
Error **errp)
{
Object *obj;
Error *local_err = NULL;
obj = object_new(TYPE_ICS_SIMPLE);
object_property_add_child(OBJECT(spapr), "ics", obj, &error_abort);
object_property_add_const_link(obj, ICS_PROP_XICS, OBJECT(spapr),
&error_fatal);
object_property_set_int(obj, nr_irqs, "nr-irqs", &error_fatal);
object_property_set_bool(obj, true, "realized", &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
spapr->ics = ICS_BASE(obj);
xics_spapr_init(spapr);
}
#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, static int spapr_irq_claim_xics(SpaprMachineState *spapr, int irq, bool lsi,
Error **errp) Error **errp)
{ {
ICSState *ics = spapr->ics; ICSState *ics = spapr->ics;
assert(ics); assert(ics);
assert(ics_valid_irq(ics, irq));
if (!ics_valid_irq(ics, irq)) { if (!ics_irq_free(ics, irq - ics->offset)) {
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); error_setg(errp, "IRQ %d is not free", irq);
return -1; return -1;
} }
@ -138,33 +109,14 @@ static int spapr_irq_claim_xics(SpaprMachineState *spapr, int irq, bool lsi,
return 0; return 0;
} }
static void spapr_irq_free_xics(SpaprMachineState *spapr, int irq, int num) static void spapr_irq_free_xics(SpaprMachineState *spapr, int irq)
{
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; ICSState *ics = spapr->ics;
uint32_t srcno = irq - ics->offset; uint32_t srcno = irq - ics->offset;
if (ics_valid_irq(ics, irq)) { assert(ics_valid_irq(ics, irq));
return spapr->qirqs[srcno];
}
return NULL; memset(&ics->irqs[srcno], 0, sizeof(ICSIRQState));
} }
static void spapr_irq_print_info_xics(SpaprMachineState *spapr, Monitor *mon) static void spapr_irq_print_info_xics(SpaprMachineState *spapr, Monitor *mon)
@ -209,11 +161,12 @@ static int spapr_irq_post_load_xics(SpaprMachineState *spapr, int version_id)
return 0; return 0;
} }
static void spapr_irq_set_irq_xics(void *opaque, int srcno, int val) static void spapr_irq_set_irq_xics(void *opaque, int irq, int val)
{ {
SpaprMachineState *spapr = opaque; SpaprMachineState *spapr = opaque;
uint32_t srcno = irq - spapr->ics->offset;
ics_simple_set_irq(spapr->ics, srcno, val); ics_set_irq(spapr->ics, srcno, val);
} }
static void spapr_irq_reset_xics(SpaprMachineState *spapr, Error **errp) static void spapr_irq_reset_xics(SpaprMachineState *spapr, Error **errp)
@ -227,11 +180,6 @@ static void spapr_irq_reset_xics(SpaprMachineState *spapr, Error **errp)
} }
} }
static const char *spapr_irq_get_nodename_xics(SpaprMachineState *spapr)
{
return XICS_NODENAME;
}
static void spapr_irq_init_kvm_xics(SpaprMachineState *spapr, Error **errp) static void spapr_irq_init_kvm_xics(SpaprMachineState *spapr, Error **errp)
{ {
if (kvm_enabled()) { if (kvm_enabled()) {
@ -239,88 +187,36 @@ static void spapr_irq_init_kvm_xics(SpaprMachineState *spapr, Error **errp)
} }
} }
#define SPAPR_IRQ_XICS_NR_IRQS 0x1000
#define SPAPR_IRQ_XICS_NR_MSIS \
(XICS_IRQ_BASE + SPAPR_IRQ_XICS_NR_IRQS - SPAPR_IRQ_MSI)
SpaprIrq spapr_irq_xics = { SpaprIrq spapr_irq_xics = {
.nr_irqs = SPAPR_IRQ_XICS_NR_IRQS, .nr_xirqs = SPAPR_NR_XIRQS,
.nr_msis = SPAPR_IRQ_XICS_NR_MSIS, .nr_msis = SPAPR_NR_MSIS,
.ov5 = SPAPR_OV5_XIVE_LEGACY, .xics = true,
.xive = false,
.init = spapr_irq_init_xics,
.claim = spapr_irq_claim_xics, .claim = spapr_irq_claim_xics,
.free = spapr_irq_free_xics, .free = spapr_irq_free_xics,
.qirq = spapr_qirq_xics,
.print_info = spapr_irq_print_info_xics, .print_info = spapr_irq_print_info_xics,
.dt_populate = spapr_dt_xics, .dt_populate = spapr_dt_xics,
.cpu_intc_create = spapr_irq_cpu_intc_create_xics, .cpu_intc_create = spapr_irq_cpu_intc_create_xics,
.post_load = spapr_irq_post_load_xics, .post_load = spapr_irq_post_load_xics,
.reset = spapr_irq_reset_xics, .reset = spapr_irq_reset_xics,
.set_irq = spapr_irq_set_irq_xics, .set_irq = spapr_irq_set_irq_xics,
.get_nodename = spapr_irq_get_nodename_xics,
.init_kvm = spapr_irq_init_kvm_xics, .init_kvm = spapr_irq_init_kvm_xics,
}; };
/* /*
* XIVE IRQ backend. * XIVE IRQ backend.
*/ */
static void spapr_irq_init_xive(SpaprMachineState *spapr, int nr_irqs,
Error **errp)
{
uint32_t nr_servers = spapr_max_server_number(spapr);
DeviceState *dev;
int i;
dev = qdev_create(NULL, TYPE_SPAPR_XIVE);
qdev_prop_set_uint32(dev, "nr-irqs", nr_irqs);
/*
* 8 XIVE END structures per CPU. One for each available priority
*/
qdev_prop_set_uint32(dev, "nr-ends", nr_servers << 3);
qdev_init_nofail(dev);
spapr->xive = SPAPR_XIVE(dev);
/* Enable the CPU IPIs */
for (i = 0; i < nr_servers; ++i) {
spapr_xive_irq_claim(spapr->xive, SPAPR_IRQ_IPI + i, false);
}
spapr_xive_hcall_init(spapr);
}
static int spapr_irq_claim_xive(SpaprMachineState *spapr, int irq, bool lsi, static int spapr_irq_claim_xive(SpaprMachineState *spapr, int irq, bool lsi,
Error **errp) Error **errp)
{ {
if (!spapr_xive_irq_claim(spapr->xive, irq, lsi)) { return spapr_xive_irq_claim(spapr->xive, irq, lsi, errp);
error_setg(errp, "IRQ %d is invalid", irq);
return -1;
}
return 0;
} }
static void spapr_irq_free_xive(SpaprMachineState *spapr, int irq, int num) static void spapr_irq_free_xive(SpaprMachineState *spapr, int irq)
{ {
int i; spapr_xive_irq_free(spapr->xive, irq);
for (i = irq; i < irq + num; ++i) {
spapr_xive_irq_free(spapr->xive, i);
}
}
static qemu_irq spapr_qirq_xive(SpaprMachineState *spapr, int irq)
{
SpaprXive *xive = spapr->xive;
if (irq >= xive->nr_irqs) {
return NULL;
}
/* The sPAPR machine/device should have claimed the IRQ before */
assert(xive_eas_is_valid(&xive->eat[irq]));
return spapr->qirqs[irq];
} }
static void spapr_irq_print_info_xive(SpaprMachineState *spapr, static void spapr_irq_print_info_xive(SpaprMachineState *spapr,
@ -386,22 +282,17 @@ static void spapr_irq_reset_xive(SpaprMachineState *spapr, Error **errp)
spapr_xive_mmio_set_enabled(spapr->xive, true); spapr_xive_mmio_set_enabled(spapr->xive, true);
} }
static void spapr_irq_set_irq_xive(void *opaque, int srcno, int val) static void spapr_irq_set_irq_xive(void *opaque, int irq, int val)
{ {
SpaprMachineState *spapr = opaque; SpaprMachineState *spapr = opaque;
if (kvm_irqchip_in_kernel()) { if (kvm_irqchip_in_kernel()) {
kvmppc_xive_source_set_irq(&spapr->xive->source, srcno, val); kvmppc_xive_source_set_irq(&spapr->xive->source, irq, val);
} else { } else {
xive_source_set_irq(&spapr->xive->source, srcno, val); xive_source_set_irq(&spapr->xive->source, irq, val);
} }
} }
static const char *spapr_irq_get_nodename_xive(SpaprMachineState *spapr)
{
return spapr->xive->nodename;
}
static void spapr_irq_init_kvm_xive(SpaprMachineState *spapr, Error **errp) static void spapr_irq_init_kvm_xive(SpaprMachineState *spapr, Error **errp)
{ {
if (kvm_enabled()) { if (kvm_enabled()) {
@ -409,30 +300,20 @@ static void spapr_irq_init_kvm_xive(SpaprMachineState *spapr, Error **errp)
} }
} }
/*
* XIVE uses the full IRQ number space. Set it to 8K to be compatible
* with XICS.
*/
#define SPAPR_IRQ_XIVE_NR_IRQS 0x2000
#define SPAPR_IRQ_XIVE_NR_MSIS (SPAPR_IRQ_XIVE_NR_IRQS - SPAPR_IRQ_MSI)
SpaprIrq spapr_irq_xive = { SpaprIrq spapr_irq_xive = {
.nr_irqs = SPAPR_IRQ_XIVE_NR_IRQS, .nr_xirqs = SPAPR_NR_XIRQS,
.nr_msis = SPAPR_IRQ_XIVE_NR_MSIS, .nr_msis = SPAPR_NR_MSIS,
.ov5 = SPAPR_OV5_XIVE_EXPLOIT, .xics = false,
.xive = true,
.init = spapr_irq_init_xive,
.claim = spapr_irq_claim_xive, .claim = spapr_irq_claim_xive,
.free = spapr_irq_free_xive, .free = spapr_irq_free_xive,
.qirq = spapr_qirq_xive,
.print_info = spapr_irq_print_info_xive, .print_info = spapr_irq_print_info_xive,
.dt_populate = spapr_dt_xive, .dt_populate = spapr_dt_xive,
.cpu_intc_create = spapr_irq_cpu_intc_create_xive, .cpu_intc_create = spapr_irq_cpu_intc_create_xive,
.post_load = spapr_irq_post_load_xive, .post_load = spapr_irq_post_load_xive,
.reset = spapr_irq_reset_xive, .reset = spapr_irq_reset_xive,
.set_irq = spapr_irq_set_irq_xive, .set_irq = spapr_irq_set_irq_xive,
.get_nodename = spapr_irq_get_nodename_xive,
.init_kvm = spapr_irq_init_kvm_xive, .init_kvm = spapr_irq_init_kvm_xive,
}; };
@ -455,24 +336,6 @@ static SpaprIrq *spapr_irq_current(SpaprMachineState *spapr)
&spapr_irq_xive : &spapr_irq_xics; &spapr_irq_xive : &spapr_irq_xics;
} }
static void spapr_irq_init_dual(SpaprMachineState *spapr, int nr_irqs,
Error **errp)
{
Error *local_err = NULL;
spapr_irq_xics.init(spapr, spapr_irq_xics.nr_irqs, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
spapr_irq_xive.init(spapr, spapr_irq_xive.nr_irqs, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
}
static int spapr_irq_claim_dual(SpaprMachineState *spapr, int irq, bool lsi, static int spapr_irq_claim_dual(SpaprMachineState *spapr, int irq, bool lsi,
Error **errp) Error **errp)
{ {
@ -494,15 +357,10 @@ static int spapr_irq_claim_dual(SpaprMachineState *spapr, int irq, bool lsi,
return ret; return ret;
} }
static void spapr_irq_free_dual(SpaprMachineState *spapr, int irq, int num) static void spapr_irq_free_dual(SpaprMachineState *spapr, int irq)
{ {
spapr_irq_xics.free(spapr, irq, num); spapr_irq_xics.free(spapr, irq);
spapr_irq_xive.free(spapr, irq, num); spapr_irq_xive.free(spapr, irq);
}
static qemu_irq spapr_qirq_dual(SpaprMachineState *spapr, int irq)
{
return spapr_irq_current(spapr)->qirq(spapr, irq);
} }
static void spapr_irq_print_info_dual(SpaprMachineState *spapr, Monitor *mon) static void spapr_irq_print_info_dual(SpaprMachineState *spapr, Monitor *mon)
@ -576,45 +434,35 @@ static void spapr_irq_reset_dual(SpaprMachineState *spapr, Error **errp)
spapr_irq_current(spapr)->reset(spapr, errp); spapr_irq_current(spapr)->reset(spapr, errp);
} }
static void spapr_irq_set_irq_dual(void *opaque, int srcno, int val) static void spapr_irq_set_irq_dual(void *opaque, int irq, int val)
{ {
SpaprMachineState *spapr = opaque; SpaprMachineState *spapr = opaque;
spapr_irq_current(spapr)->set_irq(spapr, srcno, val); spapr_irq_current(spapr)->set_irq(spapr, irq, val);
}
static const char *spapr_irq_get_nodename_dual(SpaprMachineState *spapr)
{
return spapr_irq_current(spapr)->get_nodename(spapr);
} }
/* /*
* Define values in sync with the XIVE and XICS backend * Define values in sync with the XIVE and XICS backend
*/ */
#define SPAPR_IRQ_DUAL_NR_IRQS 0x2000
#define SPAPR_IRQ_DUAL_NR_MSIS (SPAPR_IRQ_DUAL_NR_IRQS - SPAPR_IRQ_MSI)
SpaprIrq spapr_irq_dual = { SpaprIrq spapr_irq_dual = {
.nr_irqs = SPAPR_IRQ_DUAL_NR_IRQS, .nr_xirqs = SPAPR_NR_XIRQS,
.nr_msis = SPAPR_IRQ_DUAL_NR_MSIS, .nr_msis = SPAPR_NR_MSIS,
.ov5 = SPAPR_OV5_XIVE_BOTH, .xics = true,
.xive = true,
.init = spapr_irq_init_dual,
.claim = spapr_irq_claim_dual, .claim = spapr_irq_claim_dual,
.free = spapr_irq_free_dual, .free = spapr_irq_free_dual,
.qirq = spapr_qirq_dual,
.print_info = spapr_irq_print_info_dual, .print_info = spapr_irq_print_info_dual,
.dt_populate = spapr_irq_dt_populate_dual, .dt_populate = spapr_irq_dt_populate_dual,
.cpu_intc_create = spapr_irq_cpu_intc_create_dual, .cpu_intc_create = spapr_irq_cpu_intc_create_dual,
.post_load = spapr_irq_post_load_dual, .post_load = spapr_irq_post_load_dual,
.reset = spapr_irq_reset_dual, .reset = spapr_irq_reset_dual,
.set_irq = spapr_irq_set_irq_dual, .set_irq = spapr_irq_set_irq_dual,
.get_nodename = spapr_irq_get_nodename_dual,
.init_kvm = NULL, /* should not be used */ .init_kvm = NULL, /* should not be used */
}; };
static void spapr_irq_check(SpaprMachineState *spapr, Error **errp) static int spapr_irq_check(SpaprMachineState *spapr, Error **errp)
{ {
MachineState *machine = MACHINE(spapr); MachineState *machine = MACHINE(spapr);
@ -630,7 +478,7 @@ static void spapr_irq_check(SpaprMachineState *spapr, Error **errp)
*/ */
if (spapr->irq == &spapr_irq_dual) { if (spapr->irq == &spapr_irq_dual) {
spapr->irq = &spapr_irq_xics; spapr->irq = &spapr_irq_xics;
return; return 0;
} }
/* /*
@ -650,7 +498,7 @@ static void spapr_irq_check(SpaprMachineState *spapr, Error **errp)
*/ */
if (spapr->irq == &spapr_irq_xive) { if (spapr->irq == &spapr_irq_xive) {
error_setg(errp, "XIVE-only machines require a POWER9 CPU"); error_setg(errp, "XIVE-only machines require a POWER9 CPU");
return; return -1;
} }
} }
@ -664,8 +512,10 @@ static void spapr_irq_check(SpaprMachineState *spapr, Error **errp)
machine_kernel_irqchip_required(machine) && machine_kernel_irqchip_required(machine) &&
xics_kvm_has_broken_disconnect(spapr)) { xics_kvm_has_broken_disconnect(spapr)) {
error_setg(errp, "KVM is too old to support ic-mode=dual,kernel-irqchip=on"); error_setg(errp, "KVM is too old to support ic-mode=dual,kernel-irqchip=on");
return; return -1;
} }
return 0;
} }
/* /*
@ -674,7 +524,6 @@ static void spapr_irq_check(SpaprMachineState *spapr, Error **errp)
void spapr_irq_init(SpaprMachineState *spapr, Error **errp) void spapr_irq_init(SpaprMachineState *spapr, Error **errp)
{ {
MachineState *machine = MACHINE(spapr); MachineState *machine = MACHINE(spapr);
Error *local_err = NULL;
if (machine_kernel_irqchip_split(machine)) { if (machine_kernel_irqchip_split(machine)) {
error_setg(errp, "kernel_irqchip split mode not supported on pseries"); error_setg(errp, "kernel_irqchip split mode not supported on pseries");
@ -687,9 +536,7 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp)
return; return;
} }
spapr_irq_check(spapr, &local_err); if (spapr_irq_check(spapr, errp) < 0) {
if (local_err) {
error_propagate(errp, local_err);
return; return;
} }
@ -698,25 +545,113 @@ void spapr_irq_init(SpaprMachineState *spapr, Error **errp)
spapr_irq_msi_init(spapr, spapr->irq->nr_msis); spapr_irq_msi_init(spapr, spapr->irq->nr_msis);
} }
spapr->irq->init(spapr, spapr->irq->nr_irqs, errp); if (spapr->irq->xics) {
Error *local_err = NULL;
Object *obj;
obj = object_new(TYPE_ICS_SPAPR);
object_property_add_child(OBJECT(spapr), "ics", obj, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
object_property_add_const_link(obj, ICS_PROP_XICS, OBJECT(spapr),
&local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
object_property_set_int(obj, spapr->irq->nr_xirqs, "nr-irqs",
&local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
object_property_set_bool(obj, true, "realized", &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
spapr->ics = ICS_SPAPR(obj);
}
if (spapr->irq->xive) {
uint32_t nr_servers = spapr_max_server_number(spapr);
DeviceState *dev;
int i;
dev = qdev_create(NULL, TYPE_SPAPR_XIVE);
qdev_prop_set_uint32(dev, "nr-irqs",
spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE);
/*
* 8 XIVE END structures per CPU. One for each available
* priority
*/
qdev_prop_set_uint32(dev, "nr-ends", nr_servers << 3);
qdev_init_nofail(dev);
spapr->xive = SPAPR_XIVE(dev);
/* Enable the CPU IPIs */
for (i = 0; i < nr_servers; ++i) {
if (spapr_xive_irq_claim(spapr->xive, SPAPR_IRQ_IPI + i,
false, errp) < 0) {
return;
}
}
spapr_xive_hcall_init(spapr);
}
spapr->qirqs = qemu_allocate_irqs(spapr->irq->set_irq, spapr, spapr->qirqs = qemu_allocate_irqs(spapr->irq->set_irq, spapr,
spapr->irq->nr_irqs); spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE);
} }
int spapr_irq_claim(SpaprMachineState *spapr, int irq, bool lsi, Error **errp) int spapr_irq_claim(SpaprMachineState *spapr, int irq, bool lsi, Error **errp)
{ {
assert(irq >= SPAPR_XIRQ_BASE);
assert(irq < (spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE));
return spapr->irq->claim(spapr, irq, lsi, errp); return spapr->irq->claim(spapr, irq, lsi, errp);
} }
void spapr_irq_free(SpaprMachineState *spapr, int irq, int num) void spapr_irq_free(SpaprMachineState *spapr, int irq, int num)
{ {
spapr->irq->free(spapr, irq, num); int i;
assert(irq >= SPAPR_XIRQ_BASE);
assert((irq + num) <= (spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE));
for (i = irq; i < (irq + num); i++) {
spapr->irq->free(spapr, i);
}
} }
qemu_irq spapr_qirq(SpaprMachineState *spapr, int irq) qemu_irq spapr_qirq(SpaprMachineState *spapr, int irq)
{ {
return spapr->irq->qirq(spapr, irq); /*
* This interface is basically for VIO and PHB devices to find the
* right qemu_irq to manipulate, so we only allow access to the
* external irqs for now. Currently anything which needs to
* access the IPIs most naturally gets there via the guest side
* interfaces, we can change this if we need to in future.
*/
assert(irq >= SPAPR_XIRQ_BASE);
assert(irq < (spapr->irq->nr_xirqs + SPAPR_XIRQ_BASE));
if (spapr->ics) {
assert(ics_valid_irq(spapr->ics, irq));
}
if (spapr->xive) {
assert(irq < spapr->xive->nr_irqs);
assert(xive_eas_is_valid(&spapr->xive->eat[irq]));
}
return spapr->qirqs[irq];
} }
int spapr_irq_post_load(SpaprMachineState *spapr, int version_id) int spapr_irq_post_load(SpaprMachineState *spapr, int version_id)
@ -735,13 +670,13 @@ void spapr_irq_reset(SpaprMachineState *spapr, Error **errp)
int spapr_irq_get_phandle(SpaprMachineState *spapr, void *fdt, Error **errp) int spapr_irq_get_phandle(SpaprMachineState *spapr, void *fdt, Error **errp)
{ {
const char *nodename = spapr->irq->get_nodename(spapr); const char *nodename = "interrupt-controller";
int offset, phandle; int offset, phandle;
offset = fdt_subnode_offset(fdt, 0, nodename); offset = fdt_subnode_offset(fdt, 0, nodename);
if (offset < 0) { if (offset < 0) {
error_setg(errp, "Can't find node \"%s\": %s", nodename, error_setg(errp, "Can't find node \"%s\": %s",
fdt_strerror(offset)); nodename, fdt_strerror(offset));
return -1; return -1;
} }
@ -767,7 +702,7 @@ static int ics_find_free_block(ICSState *ics, int num, int alignnum)
return -1; return -1;
} }
for (i = first; i < first + num; ++i) { for (i = first; i < first + num; ++i) {
if (!ICS_IRQ_FREE(ics, i)) { if (!ics_irq_free(ics, i)) {
break; break;
} }
} }
@ -809,23 +744,21 @@ int spapr_irq_find(SpaprMachineState *spapr, int num, bool align, Error **errp)
return first + ics->offset; return first + ics->offset;
} }
#define SPAPR_IRQ_XICS_LEGACY_NR_IRQS 0x400 #define SPAPR_IRQ_XICS_LEGACY_NR_XIRQS 0x400
SpaprIrq spapr_irq_xics_legacy = { SpaprIrq spapr_irq_xics_legacy = {
.nr_irqs = SPAPR_IRQ_XICS_LEGACY_NR_IRQS, .nr_xirqs = SPAPR_IRQ_XICS_LEGACY_NR_XIRQS,
.nr_msis = SPAPR_IRQ_XICS_LEGACY_NR_IRQS, .nr_msis = SPAPR_IRQ_XICS_LEGACY_NR_XIRQS,
.ov5 = SPAPR_OV5_XIVE_LEGACY, .xics = true,
.xive = false,
.init = spapr_irq_init_xics,
.claim = spapr_irq_claim_xics, .claim = spapr_irq_claim_xics,
.free = spapr_irq_free_xics, .free = spapr_irq_free_xics,
.qirq = spapr_qirq_xics,
.print_info = spapr_irq_print_info_xics, .print_info = spapr_irq_print_info_xics,
.dt_populate = spapr_dt_xics, .dt_populate = spapr_dt_xics,
.cpu_intc_create = spapr_irq_cpu_intc_create_xics, .cpu_intc_create = spapr_irq_cpu_intc_create_xics,
.post_load = spapr_irq_post_load_xics, .post_load = spapr_irq_post_load_xics,
.reset = spapr_irq_reset_xics, .reset = spapr_irq_reset_xics,
.set_irq = spapr_irq_set_irq_xics, .set_irq = spapr_irq_set_irq_xics,
.get_nodename = spapr_irq_get_nodename_xics,
.init_kvm = spapr_irq_init_kvm_xics, .init_kvm = spapr_irq_init_kvm_xics,
}; };

View File

@ -721,9 +721,10 @@ static void pci_spapr_set_irq(void *opaque, int irq_num, int level)
* corresponding qemu_irq. * corresponding qemu_irq.
*/ */
SpaprPhbState *phb = opaque; SpaprPhbState *phb = opaque;
SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
trace_spapr_pci_lsi_set(phb->dtbusname, irq_num, phb->lsi_table[irq_num].irq); trace_spapr_pci_lsi_set(phb->dtbusname, irq_num, phb->lsi_table[irq_num].irq);
qemu_set_irq(spapr_phb_lsi_qirq(phb, irq_num), level); qemu_set_irq(spapr_qirq(spapr, phb->lsi_table[irq_num].irq), level);
} }
static PCIINTxRoute spapr_route_intx_pin_to_irq(void *opaque, int pin) static PCIINTxRoute spapr_route_intx_pin_to_irq(void *opaque, int pin)
@ -835,7 +836,7 @@ static char *spapr_phb_get_loc_code(SpaprPhbState *sphb, PCIDevice *pdev)
#define b_fff(x) b_x((x), 8, 3) /* function number */ #define b_fff(x) b_x((x), 8, 3) /* function number */
#define b_rrrrrrrr(x) b_x((x), 0, 8) /* register number */ #define b_rrrrrrrr(x) b_x((x), 0, 8) /* register number */
/* for 'reg'/'assigned-addresses' OF properties */ /* for 'reg' OF properties */
#define RESOURCE_CELLS_SIZE 2 #define RESOURCE_CELLS_SIZE 2
#define RESOURCE_CELLS_ADDRESS 3 #define RESOURCE_CELLS_ADDRESS 3
@ -849,17 +850,14 @@ typedef struct ResourceFields {
typedef struct ResourceProps { typedef struct ResourceProps {
ResourceFields reg[8]; ResourceFields reg[8];
ResourceFields assigned[7];
uint32_t reg_len; uint32_t reg_len;
uint32_t assigned_len;
} ResourceProps; } ResourceProps;
/* fill in the 'reg'/'assigned-resources' OF properties for /* fill in the 'reg' OF properties for
* a PCI device. 'reg' describes resource requirements for a * a PCI device. 'reg' describes resource requirements for a
* device's IO/MEM regions, 'assigned-addresses' describes the * device's IO/MEM regions.
* actual resource assignments.
* *
* the properties are arrays of ('phys-addr', 'size') pairs describing * the property is an array of ('phys-addr', 'size') pairs describing
* the addressable regions of the PCI device, where 'phys-addr' is a * the addressable regions of the PCI device, where 'phys-addr' is a
* RESOURCE_CELLS_ADDRESS-tuple of 32-bit integers corresponding to * RESOURCE_CELLS_ADDRESS-tuple of 32-bit integers corresponding to
* (phys.hi, phys.mid, phys.lo), and 'size' is a * (phys.hi, phys.mid, phys.lo), and 'size' is a
@ -888,18 +886,7 @@ typedef struct ResourceProps {
* phys.mid and phys.lo correspond respectively to the hi/lo portions * phys.mid and phys.lo correspond respectively to the hi/lo portions
* of the actual address of the region. * of the actual address of the region.
* *
* how the phys-addr/size values are used differ slightly between * note also that addresses defined in this property are, at least
* 'reg' and 'assigned-addresses' properties. namely, 'reg' has
* an additional description for the config space region of the
* device, and in the case of QEMU has n=0 and phys.mid=phys.lo=0
* to describe the region as relocatable, with an address-mapping
* that corresponds directly to the PHB's address space for the
* resource. 'assigned-addresses' always has n=1 set with an absolute
* address assigned for the resource. in general, 'assigned-addresses'
* won't be populated, since addresses for PCI devices are generally
* unmapped initially and left to the guest to assign.
*
* note also that addresses defined in these properties are, at least
* for PAPR guests, relative to the PHBs IO/MEM windows, and * for PAPR guests, relative to the PHBs IO/MEM windows, and
* correspond directly to the addresses in the BARs. * correspond directly to the addresses in the BARs.
* *
@ -913,8 +900,8 @@ static void populate_resource_props(PCIDevice *d, ResourceProps *rp)
uint32_t dev_id = (b_bbbbbbbb(bus_num) | uint32_t dev_id = (b_bbbbbbbb(bus_num) |
b_ddddd(PCI_SLOT(d->devfn)) | b_ddddd(PCI_SLOT(d->devfn)) |
b_fff(PCI_FUNC(d->devfn))); b_fff(PCI_FUNC(d->devfn)));
ResourceFields *reg, *assigned; ResourceFields *reg;
int i, reg_idx = 0, assigned_idx = 0; int i, reg_idx = 0;
/* config space region */ /* config space region */
reg = &rp->reg[reg_idx++]; reg = &rp->reg[reg_idx++];
@ -943,21 +930,9 @@ static void populate_resource_props(PCIDevice *d, ResourceProps *rp)
reg->phys_lo = 0; reg->phys_lo = 0;
reg->size_hi = cpu_to_be32(d->io_regions[i].size >> 32); reg->size_hi = cpu_to_be32(d->io_regions[i].size >> 32);
reg->size_lo = cpu_to_be32(d->io_regions[i].size); reg->size_lo = cpu_to_be32(d->io_regions[i].size);
if (d->io_regions[i].addr == PCI_BAR_UNMAPPED) {
continue;
}
assigned = &rp->assigned[assigned_idx++];
assigned->phys_hi = cpu_to_be32(be32_to_cpu(reg->phys_hi) | b_n(1));
assigned->phys_mid = cpu_to_be32(d->io_regions[i].addr >> 32);
assigned->phys_lo = cpu_to_be32(d->io_regions[i].addr);
assigned->size_hi = reg->size_hi;
assigned->size_lo = reg->size_lo;
} }
rp->reg_len = reg_idx * sizeof(ResourceFields); rp->reg_len = reg_idx * sizeof(ResourceFields);
rp->assigned_len = assigned_idx * sizeof(ResourceFields);
} }
typedef struct PCIClass PCIClass; typedef struct PCIClass PCIClass;
@ -1471,8 +1446,6 @@ static int spapr_dt_pci_device(SpaprPhbState *sphb, PCIDevice *dev,
populate_resource_props(dev, &rp); populate_resource_props(dev, &rp);
_FDT(fdt_setprop(fdt, offset, "reg", (uint8_t *)rp.reg, rp.reg_len)); _FDT(fdt_setprop(fdt, offset, "reg", (uint8_t *)rp.reg, rp.reg_len));
_FDT(fdt_setprop(fdt, offset, "assigned-addresses",
(uint8_t *)rp.assigned, rp.assigned_len));
if (sphb->pcie_ecs && pci_is_express(dev)) { if (sphb->pcie_ecs && pci_is_express(dev)) {
_FDT(fdt_setprop_cell(fdt, offset, "ibm,pci-config-space-type", 0x1)); _FDT(fdt_setprop_cell(fdt, offset, "ibm,pci-config-space-type", 0x1));

View File

@ -477,47 +477,6 @@ void spapr_dt_rtas_tokens(void *fdt, int rtas)
} }
} }
void spapr_load_rtas(SpaprMachineState *spapr, void *fdt, hwaddr addr)
{
int rtas_node;
int ret;
/* Copy RTAS blob into guest RAM */
cpu_physical_memory_write(addr, spapr->rtas_blob, spapr->rtas_size);
ret = fdt_add_mem_rsv(fdt, addr, spapr->rtas_size);
if (ret < 0) {
error_report("Couldn't add RTAS reserve entry: %s",
fdt_strerror(ret));
exit(1);
}
/* Update the device tree with the blob's location */
rtas_node = fdt_path_offset(fdt, "/rtas");
assert(rtas_node >= 0);
ret = fdt_setprop_cell(fdt, rtas_node, "linux,rtas-base", addr);
if (ret < 0) {
error_report("Couldn't add linux,rtas-base property: %s",
fdt_strerror(ret));
exit(1);
}
ret = fdt_setprop_cell(fdt, rtas_node, "linux,rtas-entry", addr);
if (ret < 0) {
error_report("Couldn't add linux,rtas-entry property: %s",
fdt_strerror(ret));
exit(1);
}
ret = fdt_setprop_cell(fdt, rtas_node, "rtas-size", spapr->rtas_size);
if (ret < 0) {
error_report("Couldn't add rtas-size property: %s",
fdt_strerror(ret));
exit(1);
}
}
static void core_rtas_register_types(void) static void core_rtas_register_types(void)
{ {
spapr_rtas_register(RTAS_DISPLAY_CHARACTER, "display-character", spapr_rtas_register(RTAS_DISPLAY_CHARACTER, "display-character",

View File

@ -114,7 +114,7 @@ static target_ulong h_tpm_comm(PowerPCCPU *cpu,
return H_FUNCTION; return H_FUNCTION;
} }
trace_spapr_h_tpm_comm(tpm_proxy->host_path ?: "null", op); trace_spapr_h_tpm_comm(tpm_proxy->host_path, op);
switch (op) { switch (op) {
case TPM_COMM_OP_EXECUTE: case TPM_COMM_OP_EXECUTE:

View File

@ -23,7 +23,6 @@
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qapi/visitor.h" #include "qapi/visitor.h"
#include "hw/irq.h"
#include "qemu/log.h" #include "qemu/log.h"
#include "hw/loader.h" #include "hw/loader.h"
#include "elf.h" #include "elf.h"
@ -294,7 +293,7 @@ int spapr_vio_send_crq(SpaprVioDevice *dev, uint8_t *crq)
dev->crq.qnext = (dev->crq.qnext + 16) % dev->crq.qsize; dev->crq.qnext = (dev->crq.qnext + 16) % dev->crq.qsize;
if (dev->signal_state & 1) { if (dev->signal_state & 1) {
qemu_irq_pulse(spapr_vio_qirq(dev)); spapr_vio_irq_pulse(dev);
} }
return 0; return 0;

View File

@ -13,10 +13,6 @@ spapr_pci_msi_retry(unsigned config_addr, unsigned req_num, unsigned max_irqs) "
spapr_cas_failed(unsigned long n) "DT diff buffer is too small: %ld bytes" spapr_cas_failed(unsigned long n) "DT diff buffer is too small: %ld bytes"
spapr_cas_continue(unsigned long n) "Copy changes to the guest: %ld bytes" spapr_cas_continue(unsigned long n) "Copy changes to the guest: %ld bytes"
# spapr_irq.c
spapr_irq_free(int src, int irq, int num) "Source#%d, first irq %d, %d irqs"
spapr_irq_free_warn(int src, int irq) "Source#%d, irq %d is already free"
# spapr_hcall.c # spapr_hcall.c
spapr_cas_pvr(uint32_t cur_pvr, bool explicit_match, uint32_t new_pvr) "current=0x%x, explicit_match=%u, new=0x%x" spapr_cas_pvr(uint32_t cur_pvr, bool explicit_match, uint32_t new_pvr) "current=0x%x, explicit_match=%u, new=0x%x"
spapr_h_resize_hpt_prepare(uint64_t flags, uint64_t shift) "flags=0x%"PRIx64", shift=%"PRIu64 spapr_h_resize_hpt_prepare(uint64_t flags, uint64_t shift) "flags=0x%"PRIx64", shift=%"PRIu64

View File

@ -128,13 +128,6 @@ struct SpaprPhbState {
#define SPAPR_PCI_NV2ATSD_WIN_SIZE (NVGPU_MAX_NUM * NVGPU_MAX_LINKS * \ #define SPAPR_PCI_NV2ATSD_WIN_SIZE (NVGPU_MAX_NUM * NVGPU_MAX_LINKS * \
64 * KiB) 64 * KiB)
static inline qemu_irq spapr_phb_lsi_qirq(struct SpaprPhbState *phb, int pin)
{
SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
return spapr_qirq(spapr, phb->lsi_table[pin].irq);
}
int spapr_dt_phb(SpaprPhbState *phb, uint32_t intc_phandle, void *fdt, int spapr_dt_phb(SpaprPhbState *phb, uint32_t intc_phandle, void *fdt,
uint32_t nr_msis, int *node_offset); uint32_t nr_msis, int *node_offset);

View File

@ -26,6 +26,7 @@
#include "hw/ppc/pnv_lpc.h" #include "hw/ppc/pnv_lpc.h"
#include "hw/ppc/pnv_psi.h" #include "hw/ppc/pnv_psi.h"
#include "hw/ppc/pnv_occ.h" #include "hw/ppc/pnv_occ.h"
#include "hw/ppc/pnv_homer.h"
#include "hw/ppc/pnv_xive.h" #include "hw/ppc/pnv_xive.h"
#include "hw/ppc/pnv_core.h" #include "hw/ppc/pnv_core.h"
@ -76,6 +77,7 @@ typedef struct Pnv8Chip {
PnvLpcController lpc; PnvLpcController lpc;
Pnv8Psi psi; Pnv8Psi psi;
PnvOCC occ; PnvOCC occ;
PnvHomer homer;
} Pnv8Chip; } Pnv8Chip;
#define TYPE_PNV9_CHIP "pnv9-chip" #define TYPE_PNV9_CHIP "pnv9-chip"
@ -90,6 +92,7 @@ typedef struct Pnv9Chip {
Pnv9Psi psi; Pnv9Psi psi;
PnvLpcController lpc; PnvLpcController lpc;
PnvOCC occ; PnvOCC occ;
PnvHomer homer;
uint32_t nr_quads; uint32_t nr_quads;
PnvQuad *quads; PnvQuad *quads;
@ -198,6 +201,16 @@ void pnv_bmc_powerdown(IPMIBmc *bmc);
#define PNV_XSCOM_BASE(chip) \ #define PNV_XSCOM_BASE(chip) \
(0x0003fc0000000000ull + ((uint64_t)(chip)->chip_id) * PNV_XSCOM_SIZE) (0x0003fc0000000000ull + ((uint64_t)(chip)->chip_id) * PNV_XSCOM_SIZE)
#define PNV_OCC_COMMON_AREA_SIZE 0x0000000000700000ull
#define PNV_OCC_COMMON_AREA(chip) \
(0x7fff800000ull + ((uint64_t)PNV_CHIP_INDEX(chip) * \
PNV_OCC_COMMON_AREA_SIZE))
#define PNV_HOMER_SIZE 0x0000000000300000ull
#define PNV_HOMER_BASE(chip) \
(0x7ffd800000ull + ((uint64_t)PNV_CHIP_INDEX(chip)) * PNV_HOMER_SIZE)
/* /*
* XSCOM 0x20109CA defines the ICP BAR: * XSCOM 0x20109CA defines the ICP BAR:
* *
@ -256,4 +269,12 @@ void pnv_bmc_powerdown(IPMIBmc *bmc);
#define PNV9_XSCOM_SIZE 0x0000000400000000ull #define PNV9_XSCOM_SIZE 0x0000000400000000ull
#define PNV9_XSCOM_BASE(chip) PNV9_CHIP_BASE(chip, 0x00603fc00000000ull) #define PNV9_XSCOM_BASE(chip) PNV9_CHIP_BASE(chip, 0x00603fc00000000ull)
#define PNV9_OCC_COMMON_AREA_SIZE 0x0000000000700000ull
#define PNV9_OCC_COMMON_AREA(chip) \
(0x203fff800000ull + ((uint64_t)PNV_CHIP_INDEX(chip) * \
PNV9_OCC_COMMON_AREA_SIZE))
#define PNV9_HOMER_SIZE 0x0000000000300000ull
#define PNV9_HOMER_BASE(chip) \
(0x203ffd800000ull + ((uint64_t)PNV_CHIP_INDEX(chip)) * PNV9_HOMER_SIZE)
#endif /* PPC_PNV_H */ #endif /* PPC_PNV_H */

View File

@ -0,0 +1,53 @@
/*
* QEMU PowerPC PowerNV Emulation of a few HOMER related registers
*
* Copyright (c) 2019, IBM Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PPC_PNV_HOMER_H
#define PPC_PNV_HOMER_H
#include "hw/ppc/pnv.h"
#define TYPE_PNV_HOMER "pnv-homer"
#define PNV_HOMER(obj) OBJECT_CHECK(PnvHomer, (obj), TYPE_PNV_HOMER)
#define TYPE_PNV8_HOMER TYPE_PNV_HOMER "-POWER8"
#define PNV8_HOMER(obj) OBJECT_CHECK(PnvHomer, (obj), TYPE_PNV8_HOMER)
#define TYPE_PNV9_HOMER TYPE_PNV_HOMER "-POWER9"
#define PNV9_HOMER(obj) OBJECT_CHECK(PnvHomer, (obj), TYPE_PNV9_HOMER)
typedef struct PnvHomer {
DeviceState parent;
struct PnvChip *chip;
MemoryRegion regs;
} PnvHomer;
#define PNV_HOMER_CLASS(klass) \
OBJECT_CLASS_CHECK(PnvHomerClass, (klass), TYPE_PNV_HOMER)
#define PNV_HOMER_GET_CLASS(obj) \
OBJECT_GET_CLASS(PnvHomerClass, (obj), TYPE_PNV_HOMER)
typedef struct PnvHomerClass {
DeviceClass parent_class;
int homer_size;
const MemoryRegionOps *homer_ops;
hwaddr core_max_base;
} PnvHomerClass;
#endif /* PPC_PNV_HOMER_H */

View File

@ -38,6 +38,7 @@ typedef struct PnvOCC {
PnvPsi *psi; PnvPsi *psi;
MemoryRegion xscom_regs; MemoryRegion xscom_regs;
MemoryRegion sram_regs;
} PnvOCC; } PnvOCC;
#define PNV_OCC_CLASS(klass) \ #define PNV_OCC_CLASS(klass) \
@ -49,7 +50,9 @@ typedef struct PnvOCCClass {
DeviceClass parent_class; DeviceClass parent_class;
int xscom_size; int xscom_size;
int sram_size;
const MemoryRegionOps *xscom_ops; const MemoryRegionOps *xscom_ops;
const MemoryRegionOps *sram_ops;
int psi_irq; int psi_irq;
} PnvOCCClass; } PnvOCCClass;

View File

@ -154,8 +154,6 @@ struct SpaprMachineState {
hwaddr rma_size; hwaddr rma_size;
int vrma_adjust; int vrma_adjust;
ssize_t rtas_size;
void *rtas_blob;
uint32_t fdt_size; uint32_t fdt_size;
uint32_t fdt_initial_size; uint32_t fdt_initial_size;
void *fdt_blob; void *fdt_blob;
@ -175,7 +173,7 @@ struct SpaprMachineState {
/* ibm,client-architecture-support option negotiation */ /* ibm,client-architecture-support option negotiation */
bool cas_reboot; bool cas_reboot;
bool cas_legacy_guest_workaround; bool cas_pre_isa3_guest;
SpaprOptionVector *ov5; /* QEMU-supported option vectors */ SpaprOptionVector *ov5; /* QEMU-supported option vectors */
SpaprOptionVector *ov5_cas; /* negotiated (via CAS) option vectors */ SpaprOptionVector *ov5_cas; /* negotiated (via CAS) option vectors */
uint32_t max_compat_pvr; uint32_t max_compat_pvr;

View File

@ -16,13 +16,18 @@
* IRQ range offsets per device type * IRQ range offsets per device type
*/ */
#define SPAPR_IRQ_IPI 0x0 #define SPAPR_IRQ_IPI 0x0
#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 #define SPAPR_XIRQ_BASE XICS_IRQ_BASE /* 0x1000 */
* by the bitmap allocator */ #define SPAPR_IRQ_EPOW (SPAPR_XIRQ_BASE + 0x0000)
#define SPAPR_IRQ_HOTPLUG (SPAPR_XIRQ_BASE + 0x0001)
#define SPAPR_IRQ_VIO (SPAPR_XIRQ_BASE + 0x0100) /* 256 VIO devices */
#define SPAPR_IRQ_PCI_LSI (SPAPR_XIRQ_BASE + 0x0200) /* 32+ PHBs devices */
/* Offset of the dynamic range covered by the bitmap allocator */
#define SPAPR_IRQ_MSI (SPAPR_XIRQ_BASE + 0x0300)
#define SPAPR_NR_XIRQS 0x1000
#define SPAPR_NR_MSIS (SPAPR_XIRQ_BASE + SPAPR_NR_XIRQS - SPAPR_IRQ_MSI)
typedef struct SpaprMachineState SpaprMachineState; typedef struct SpaprMachineState SpaprMachineState;
@ -32,14 +37,13 @@ int spapr_irq_msi_alloc(SpaprMachineState *spapr, uint32_t num, bool align,
void spapr_irq_msi_free(SpaprMachineState *spapr, int irq, uint32_t num); void spapr_irq_msi_free(SpaprMachineState *spapr, int irq, uint32_t num);
typedef struct SpaprIrq { typedef struct SpaprIrq {
uint32_t nr_irqs; uint32_t nr_xirqs;
uint32_t nr_msis; uint32_t nr_msis;
uint8_t ov5; bool xics;
bool xive;
void (*init)(SpaprMachineState *spapr, int nr_irqs, Error **errp);
int (*claim)(SpaprMachineState *spapr, int irq, bool lsi, Error **errp); int (*claim)(SpaprMachineState *spapr, int irq, bool lsi, Error **errp);
void (*free)(SpaprMachineState *spapr, int irq, int num); void (*free)(SpaprMachineState *spapr, int irq);
qemu_irq (*qirq)(SpaprMachineState *spapr, int irq);
void (*print_info)(SpaprMachineState *spapr, Monitor *mon); void (*print_info)(SpaprMachineState *spapr, Monitor *mon);
void (*dt_populate)(SpaprMachineState *spapr, uint32_t nr_servers, void (*dt_populate)(SpaprMachineState *spapr, uint32_t nr_servers,
void *fdt, uint32_t phandle); void *fdt, uint32_t phandle);
@ -48,7 +52,6 @@ typedef struct SpaprIrq {
int (*post_load)(SpaprMachineState *spapr, int version_id); int (*post_load)(SpaprMachineState *spapr, int version_id);
void (*reset)(SpaprMachineState *spapr, Error **errp); void (*reset)(SpaprMachineState *spapr, Error **errp);
void (*set_irq)(void *opaque, int srcno, int val); void (*set_irq)(void *opaque, int srcno, int val);
const char *(*get_nodename)(SpaprMachineState *spapr);
void (*init_kvm)(SpaprMachineState *spapr, Error **errp); void (*init_kvm)(SpaprMachineState *spapr, Error **errp);
} SpaprIrq; } SpaprIrq;

View File

@ -24,6 +24,7 @@
#include "hw/ppc/spapr.h" #include "hw/ppc/spapr.h"
#include "sysemu/dma.h" #include "sysemu/dma.h"
#include "hw/irq.h"
#define TYPE_VIO_SPAPR_DEVICE "vio-spapr-device" #define TYPE_VIO_SPAPR_DEVICE "vio-spapr-device"
#define VIO_SPAPR_DEVICE(obj) \ #define VIO_SPAPR_DEVICE(obj) \
@ -84,11 +85,11 @@ extern SpaprVioDevice *spapr_vio_find_by_reg(SpaprVioBus *bus, uint32_t reg);
void spapr_dt_vdevice(SpaprVioBus *bus, void *fdt); void spapr_dt_vdevice(SpaprVioBus *bus, void *fdt);
extern gchar *spapr_vio_stdout_path(SpaprVioBus *bus); extern gchar *spapr_vio_stdout_path(SpaprVioBus *bus);
static inline qemu_irq spapr_vio_qirq(SpaprVioDevice *dev) static inline void spapr_vio_irq_pulse(SpaprVioDevice *dev)
{ {
SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); SpaprMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
return spapr_qirq(spapr, dev->irq); qemu_irq_pulse(spapr_qirq(spapr, dev->irq));
} }
static inline bool spapr_vio_dma_valid(SpaprVioDevice *dev, uint64_t taddr, static inline bool spapr_vio_dma_valid(SpaprVioDevice *dev, uint64_t taddr,

View File

@ -54,8 +54,8 @@ typedef struct SpaprXive {
*/ */
#define SPAPR_XIVE_BLOCK_ID 0x0 #define SPAPR_XIVE_BLOCK_ID 0x0
bool spapr_xive_irq_claim(SpaprXive *xive, uint32_t lisn, bool lsi); int spapr_xive_irq_claim(SpaprXive *xive, int lisn, bool lsi, Error **errp);
bool spapr_xive_irq_free(SpaprXive *xive, uint32_t lisn); void spapr_xive_irq_free(SpaprXive *xive, int lisn);
void spapr_xive_pic_print_info(SpaprXive *xive, Monitor *mon); void spapr_xive_pic_print_info(SpaprXive *xive, Monitor *mon);
int spapr_xive_post_load(SpaprXive *xive, int version_id); int spapr_xive_post_load(SpaprXive *xive, int version_id);

View File

@ -89,27 +89,18 @@ struct PnvICPState {
uint32_t links[3]; uint32_t links[3];
}; };
#define TYPE_ICS_BASE "ics-base" #define TYPE_ICS "ics"
#define ICS_BASE(obj) OBJECT_CHECK(ICSState, (obj), TYPE_ICS_BASE) #define ICS(obj) OBJECT_CHECK(ICSState, (obj), TYPE_ICS)
/* Retain ics for sPAPR for migration from existing sPAPR guests */ #define ICS_CLASS(klass) \
#define TYPE_ICS_SIMPLE "ics" OBJECT_CLASS_CHECK(ICSStateClass, (klass), TYPE_ICS)
#define ICS_SIMPLE(obj) OBJECT_CHECK(ICSState, (obj), TYPE_ICS_SIMPLE) #define ICS_GET_CLASS(obj) \
OBJECT_GET_CLASS(ICSStateClass, (obj), TYPE_ICS)
#define ICS_BASE_CLASS(klass) \
OBJECT_CLASS_CHECK(ICSStateClass, (klass), TYPE_ICS_BASE)
#define ICS_BASE_GET_CLASS(obj) \
OBJECT_GET_CLASS(ICSStateClass, (obj), TYPE_ICS_BASE)
struct ICSStateClass { struct ICSStateClass {
DeviceClass parent_class; DeviceClass parent_class;
DeviceRealize parent_realize; DeviceRealize parent_realize;
DeviceReset parent_reset;
void (*reject)(ICSState *s, uint32_t irq);
void (*resend)(ICSState *s);
void (*eoi)(ICSState *s, uint32_t irq);
}; };
struct ICSState { struct ICSState {
@ -147,13 +138,9 @@ struct ICSIRQState {
uint8_t flags; uint8_t flags;
}; };
struct XICSFabric {
Object parent;
};
#define TYPE_XICS_FABRIC "xics-fabric" #define TYPE_XICS_FABRIC "xics-fabric"
#define XICS_FABRIC(obj) \ #define XICS_FABRIC(obj) \
OBJECT_CHECK(XICSFabric, (obj), TYPE_XICS_FABRIC) INTERFACE_CHECK(XICSFabric, (obj), TYPE_XICS_FABRIC)
#define XICS_FABRIC_CLASS(klass) \ #define XICS_FABRIC_CLASS(klass) \
OBJECT_CLASS_CHECK(XICSFabricClass, (klass), TYPE_XICS_FABRIC) OBJECT_CLASS_CHECK(XICSFabricClass, (klass), TYPE_XICS_FABRIC)
#define XICS_FABRIC_GET_CLASS(obj) \ #define XICS_FABRIC_GET_CLASS(obj) \
@ -175,9 +162,14 @@ uint32_t icp_accept(ICPState *ss);
uint32_t icp_ipoll(ICPState *ss, uint32_t *mfrr); uint32_t icp_ipoll(ICPState *ss, uint32_t *mfrr);
void icp_eoi(ICPState *icp, uint32_t xirr); void icp_eoi(ICPState *icp, uint32_t xirr);
void ics_simple_write_xive(ICSState *ics, int nr, int server, void ics_write_xive(ICSState *ics, int nr, int server,
uint8_t priority, uint8_t saved_priority); uint8_t priority, uint8_t saved_priority);
void ics_simple_set_irq(void *opaque, int srcno, int val); void ics_set_irq(void *opaque, int srcno, int val);
static inline bool ics_irq_free(ICSState *ics, uint32_t srcno)
{
return !(ics->irqs[srcno].flags & XICS_FLAGS_IRQ_MASK);
}
void ics_set_irq_type(ICSState *ics, int srcno, bool lsi); void ics_set_irq_type(ICSState *ics, int srcno, bool lsi);
void icp_pic_print_info(ICPState *icp, Monitor *mon); void icp_pic_print_info(ICPState *icp, Monitor *mon);

View File

@ -29,13 +29,13 @@
#include "hw/ppc/spapr.h" #include "hw/ppc/spapr.h"
#define XICS_NODENAME "interrupt-controller" #define TYPE_ICS_SPAPR "ics-spapr"
#define ICS_SPAPR(obj) OBJECT_CHECK(ICSState, (obj), TYPE_ICS_SPAPR)
void spapr_dt_xics(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt, void spapr_dt_xics(SpaprMachineState *spapr, uint32_t nr_servers, void *fdt,
uint32_t phandle); uint32_t phandle);
int xics_kvm_connect(SpaprMachineState *spapr, Error **errp); int xics_kvm_connect(SpaprMachineState *spapr, Error **errp);
void xics_kvm_disconnect(SpaprMachineState *spapr, Error **errp); void xics_kvm_disconnect(SpaprMachineState *spapr, Error **errp);
bool xics_kvm_has_broken_disconnect(SpaprMachineState *spapr); bool xics_kvm_has_broken_disconnect(SpaprMachineState *spapr);
void xics_spapr_init(SpaprMachineState *spapr);
#endif /* XICS_SPAPR_H */ #endif /* XICS_SPAPR_H */

View File

@ -425,7 +425,7 @@ static inline uint32_t xive_nvt_cam_line(uint8_t nvt_blk, uint32_t nvt_idx)
* KVM XIVE device helpers * KVM XIVE device helpers
*/ */
void kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp); int kvmppc_xive_source_reset_one(XiveSource *xsrc, int srcno, Error **errp);
void kvmppc_xive_source_set_irq(void *opaque, int srcno, int val); void kvmppc_xive_source_set_irq(void *opaque, int srcno, int val);
void kvmppc_xive_cpu_connect(XiveTCTX *tctx, Error **errp); void kvmppc_xive_cpu_connect(XiveTCTX *tctx, Error **errp);
void kvmppc_xive_cpu_synchronize_state(XiveTCTX *tctx, Error **errp); void kvmppc_xive_cpu_synchronize_state(XiveTCTX *tctx, Error **errp);

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-20190827. built from git tag qemu-slof-20190911.
- 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.

Binary file not shown.

View File

@ -1,27 +0,0 @@
all: build-all
# Dummy command so that make thinks it has done something
@true
include ../../config-host.mak
include $(SRC_PATH)/rules.mak
$(call set-vpath, $(SRC_PATH)/pc-bios/spapr-rtas)
.PHONY : all clean build-all
#CFLAGS += -I$(SRC_PATH)
#QEMU_CFLAGS = $(CFLAGS)
build-all: spapr-rtas.bin
%.o: %.S
$(call quiet-command,$(CCAS) -mbig -c -o $@ $<,"CCAS","$(TARGET_DIR)$@")
%.img: %.o
$(call quiet-command,$(CC) -nostdlib -mbig -o $@ $<,"Building","$(TARGET_DIR)$@")
%.bin: %.img
$(call quiet-command,$(OBJCOPY) -O binary -j .text $< $@,"Building","$(TARGET_DIR)$@")
clean:
rm -f *.o *.d *.img *.bin *~

View File

@ -1,37 +0,0 @@
/*
* QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
*
* Trivial in-partition RTAS implementation, based on a hypercall
*
* Copyright (c) 2010,2011 David Gibson, IBM Corporation.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#define KVMPPC_HCALL_BASE 0xf000
#define KVMPPC_H_RTAS (KVMPPC_HCALL_BASE + 0x0)
.globl _start
_start:
mr 4,3
lis 3,KVMPPC_H_RTAS@h
ori 3,3,KVMPPC_H_RTAS@l
sc 1
blr

@ -1 +1 @@
Subproject commit ea221600a116883137ef90b2b7ab7d2472bc4f10 Subproject commit bcc3c4e5c21a015f4680894c4ec978a90d4a2d69

View File

@ -235,6 +235,7 @@ typedef union _ppc_vsr_t {
} ppc_vsr_t; } ppc_vsr_t;
typedef ppc_vsr_t ppc_avr_t; typedef ppc_vsr_t ppc_avr_t;
typedef ppc_vsr_t ppc_fprp_t;
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
/* Software TLB cache */ /* Software TLB cache */
@ -559,6 +560,9 @@ enum {
/*****************************************************************************/ /*****************************************************************************/
/* Floating point status and control register */ /* Floating point status and control register */
#define FPSCR_DRN2 34 /* Decimal Floating-Point rounding control */
#define FPSCR_DRN1 33 /* Decimal Floating-Point rounding control */
#define FPSCR_DRN0 32 /* Decimal Floating-Point rounding control */
#define FPSCR_FX 31 /* Floating-point exception summary */ #define FPSCR_FX 31 /* Floating-point exception summary */
#define FPSCR_FEX 30 /* Floating-point enabled exception summary */ #define FPSCR_FEX 30 /* Floating-point enabled exception summary */
#define FPSCR_VX 29 /* Floating-point invalid operation exception summ. */ #define FPSCR_VX 29 /* Floating-point invalid operation exception summ. */
@ -592,6 +596,7 @@ enum {
#define FPSCR_NI 2 /* Floating-point non-IEEE mode */ #define FPSCR_NI 2 /* Floating-point non-IEEE mode */
#define FPSCR_RN1 1 #define FPSCR_RN1 1
#define FPSCR_RN0 0 /* Floating-point rounding control */ #define FPSCR_RN0 0 /* Floating-point rounding control */
#define fpscr_drn (((env->fpscr) & FP_DRN) >> FPSCR_DRN0)
#define fpscr_fex (((env->fpscr) >> FPSCR_FEX) & 0x1) #define fpscr_fex (((env->fpscr) >> FPSCR_FEX) & 0x1)
#define fpscr_vx (((env->fpscr) >> FPSCR_VX) & 0x1) #define fpscr_vx (((env->fpscr) >> FPSCR_VX) & 0x1)
#define fpscr_ox (((env->fpscr) >> FPSCR_OX) & 0x1) #define fpscr_ox (((env->fpscr) >> FPSCR_OX) & 0x1)
@ -627,6 +632,10 @@ enum {
#define fpscr_eex (((env->fpscr) >> FPSCR_XX) & ((env->fpscr) >> FPSCR_XE) & \ #define fpscr_eex (((env->fpscr) >> FPSCR_XX) & ((env->fpscr) >> FPSCR_XE) & \
0x1F) 0x1F)
#define FP_DRN2 (1ull << FPSCR_DRN2)
#define FP_DRN1 (1ull << FPSCR_DRN1)
#define FP_DRN0 (1ull << FPSCR_DRN0)
#define FP_DRN (FP_DRN2 | FP_DRN1 | FP_DRN0)
#define FP_FX (1ull << FPSCR_FX) #define FP_FX (1ull << FPSCR_FX)
#define FP_FEX (1ull << FPSCR_FEX) #define FP_FEX (1ull << FPSCR_FEX)
#define FP_VX (1ull << FPSCR_VX) #define FP_VX (1ull << FPSCR_VX)
@ -662,7 +671,6 @@ enum {
#define FP_RN0 (1ull << FPSCR_RN0) #define FP_RN0 (1ull << FPSCR_RN0)
#define FP_RN (FP_RN1 | FP_RN0) #define FP_RN (FP_RN1 | FP_RN0)
#define FP_MODE FP_RN
#define FP_ENABLES (FP_VE | FP_OE | FP_UE | FP_ZE | FP_XE) #define FP_ENABLES (FP_VE | FP_OE | FP_UE | FP_ZE | FP_XE)
#define FP_STATUS (FP_FR | FP_FI | FP_FPRF) #define FP_STATUS (FP_FR | FP_FI | FP_FPRF)

View File

@ -28,17 +28,32 @@
#include "libdecnumber/dpd/decimal64.h" #include "libdecnumber/dpd/decimal64.h"
#include "libdecnumber/dpd/decimal128.h" #include "libdecnumber/dpd/decimal128.h"
#if defined(HOST_WORDS_BIGENDIAN)
#define HI_IDX 0 static void get_dfp64(ppc_vsr_t *dst, ppc_fprp_t *dfp)
#define LO_IDX 1 {
#else dst->VsrD(1) = dfp->VsrD(0);
#define HI_IDX 1 }
#define LO_IDX 0
#endif static void get_dfp128(ppc_vsr_t *dst, ppc_fprp_t *dfp)
{
dst->VsrD(0) = dfp[0].VsrD(0);
dst->VsrD(1) = dfp[1].VsrD(0);
}
static void set_dfp64(ppc_fprp_t *dfp, ppc_vsr_t *src)
{
dfp->VsrD(0) = src->VsrD(1);
}
static void set_dfp128(ppc_fprp_t *dfp, ppc_vsr_t *src)
{
dfp[0].VsrD(0) = src->VsrD(0);
dfp[1].VsrD(0) = src->VsrD(1);
}
struct PPC_DFP { struct PPC_DFP {
CPUPPCState *env; CPUPPCState *env;
uint64_t t64[2], a64[2], b64[2]; ppc_vsr_t vt, va, vb;
decNumber t, a, b; decNumber t, a, b;
decContext context; decContext context;
uint8_t crbf; uint8_t crbf;
@ -48,7 +63,7 @@ static void dfp_prepare_rounding_mode(decContext *context, uint64_t fpscr)
{ {
enum rounding rnd; enum rounding rnd;
switch ((fpscr >> 32) & 0x7) { switch ((fpscr & FP_DRN) >> FPSCR_DRN0) {
case 0: case 0:
rnd = DEC_ROUND_HALF_EVEN; rnd = DEC_ROUND_HALF_EVEN;
break; break;
@ -121,56 +136,64 @@ static void dfp_set_round_mode_from_immediate(uint8_t r, uint8_t rmc,
decContextSetRounding(&dfp->context, rnd); decContextSetRounding(&dfp->context, rnd);
} }
static void dfp_prepare_decimal64(struct PPC_DFP *dfp, uint64_t *a, static void dfp_prepare_decimal64(struct PPC_DFP *dfp, ppc_fprp_t *a,
uint64_t *b, CPUPPCState *env) ppc_fprp_t *b, CPUPPCState *env)
{ {
decContextDefault(&dfp->context, DEC_INIT_DECIMAL64); decContextDefault(&dfp->context, DEC_INIT_DECIMAL64);
dfp_prepare_rounding_mode(&dfp->context, env->fpscr); dfp_prepare_rounding_mode(&dfp->context, env->fpscr);
dfp->env = env; dfp->env = env;
if (a) { if (a) {
dfp->a64[0] = *a; get_dfp64(&dfp->va, a);
decimal64ToNumber((decimal64 *)dfp->a64, &dfp->a); decimal64ToNumber((decimal64 *)&dfp->va.VsrD(1), &dfp->a);
} else { } else {
dfp->a64[0] = 0; dfp->va.VsrD(1) = 0;
decNumberZero(&dfp->a); decNumberZero(&dfp->a);
} }
if (b) { if (b) {
dfp->b64[0] = *b; get_dfp64(&dfp->vb, b);
decimal64ToNumber((decimal64 *)dfp->b64, &dfp->b); decimal64ToNumber((decimal64 *)&dfp->vb.VsrD(1), &dfp->b);
} else { } else {
dfp->b64[0] = 0; dfp->vb.VsrD(1) = 0;
decNumberZero(&dfp->b); decNumberZero(&dfp->b);
} }
} }
static void dfp_prepare_decimal128(struct PPC_DFP *dfp, uint64_t *a, static void dfp_prepare_decimal128(struct PPC_DFP *dfp, ppc_fprp_t *a,
uint64_t *b, CPUPPCState *env) ppc_fprp_t *b, CPUPPCState *env)
{ {
decContextDefault(&dfp->context, DEC_INIT_DECIMAL128); decContextDefault(&dfp->context, DEC_INIT_DECIMAL128);
dfp_prepare_rounding_mode(&dfp->context, env->fpscr); dfp_prepare_rounding_mode(&dfp->context, env->fpscr);
dfp->env = env; dfp->env = env;
if (a) { if (a) {
dfp->a64[0] = a[HI_IDX]; get_dfp128(&dfp->va, a);
dfp->a64[1] = a[LO_IDX]; decimal128ToNumber((decimal128 *)&dfp->va, &dfp->a);
decimal128ToNumber((decimal128 *)dfp->a64, &dfp->a);
} else { } else {
dfp->a64[0] = dfp->a64[1] = 0; dfp->va.VsrD(0) = dfp->va.VsrD(1) = 0;
decNumberZero(&dfp->a); decNumberZero(&dfp->a);
} }
if (b) { if (b) {
dfp->b64[0] = b[HI_IDX]; get_dfp128(&dfp->vb, b);
dfp->b64[1] = b[LO_IDX]; decimal128ToNumber((decimal128 *)&dfp->vb, &dfp->b);
decimal128ToNumber((decimal128 *)dfp->b64, &dfp->b);
} else { } else {
dfp->b64[0] = dfp->b64[1] = 0; dfp->vb.VsrD(0) = dfp->vb.VsrD(1) = 0;
decNumberZero(&dfp->b); decNumberZero(&dfp->b);
} }
} }
static void dfp_finalize_decimal64(struct PPC_DFP *dfp)
{
decimal64FromNumber((decimal64 *)&dfp->vt.VsrD(1), &dfp->t, &dfp->context);
}
static void dfp_finalize_decimal128(struct PPC_DFP *dfp)
{
decimal128FromNumber((decimal128 *)&dfp->vt, &dfp->t, &dfp->context);
}
static void dfp_set_FPSCR_flag(struct PPC_DFP *dfp, uint64_t flag, static void dfp_set_FPSCR_flag(struct PPC_DFP *dfp, uint64_t flag,
uint64_t enabled) uint64_t enabled)
{ {
@ -220,8 +243,8 @@ static void dfp_set_FPRF_from_FRT_with_context(struct PPC_DFP *dfp,
default: default:
assert(0); /* should never get here */ assert(0); /* should never get here */
} }
dfp->env->fpscr &= ~(0x1F << 12); dfp->env->fpscr &= ~FP_FPRF;
dfp->env->fpscr |= (fprf << 12); dfp->env->fpscr |= (fprf << FPSCR_FPRF);
} }
static void dfp_set_FPRF_from_FRT(struct PPC_DFP *dfp) static void dfp_set_FPRF_from_FRT(struct PPC_DFP *dfp)
@ -369,8 +392,8 @@ static void dfp_set_CRBF_from_T(struct PPC_DFP *dfp)
static void dfp_set_FPCC_from_CRBF(struct PPC_DFP *dfp) static void dfp_set_FPCC_from_CRBF(struct PPC_DFP *dfp)
{ {
dfp->env->fpscr &= ~(0xF << 12); dfp->env->fpscr &= ~FP_FPCC;
dfp->env->fpscr |= (dfp->crbf << 12); dfp->env->fpscr |= (dfp->crbf << FPSCR_FPCC);
} }
static inline void dfp_makeQNaN(decNumber *dn) static inline void dfp_makeQNaN(decNumber *dn)
@ -396,19 +419,15 @@ static inline int dfp_get_digit(decNumber *dn, int n)
} }
#define DFP_HELPER_TAB(op, dnop, postprocs, size) \ #define DFP_HELPER_TAB(op, dnop, postprocs, size) \
void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, uint64_t *b) \ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \
ppc_fprp_t *b) \
{ \ { \
struct PPC_DFP dfp; \ struct PPC_DFP dfp; \
dfp_prepare_decimal##size(&dfp, a, b, env); \ dfp_prepare_decimal##size(&dfp, a, b, env); \
dnop(&dfp.t, &dfp.a, &dfp.b, &dfp.context); \ dnop(&dfp.t, &dfp.a, &dfp.b, &dfp.context); \
decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \ dfp_finalize_decimal##size(&dfp); \
postprocs(&dfp); \ postprocs(&dfp); \
if (size == 64) { \ set_dfp##size(t, &dfp.vt); \
t[0] = dfp.t64[0]; \
} else if (size == 128) { \
t[0] = dfp.t64[HI_IDX]; \
t[1] = dfp.t64[LO_IDX]; \
} \
} }
static void ADD_PPs(struct PPC_DFP *dfp) static void ADD_PPs(struct PPC_DFP *dfp)
@ -466,12 +485,12 @@ DFP_HELPER_TAB(ddiv, decNumberDivide, DIV_PPs, 64)
DFP_HELPER_TAB(ddivq, decNumberDivide, DIV_PPs, 128) DFP_HELPER_TAB(ddivq, decNumberDivide, DIV_PPs, 128)
#define DFP_HELPER_BF_AB(op, dnop, postprocs, size) \ #define DFP_HELPER_BF_AB(op, dnop, postprocs, size) \
uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint64_t *b) \ uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, ppc_fprp_t *b) \
{ \ { \
struct PPC_DFP dfp; \ struct PPC_DFP dfp; \
dfp_prepare_decimal##size(&dfp, a, b, env); \ dfp_prepare_decimal##size(&dfp, a, b, env); \
dnop(&dfp.t, &dfp.a, &dfp.b, &dfp.context); \ dnop(&dfp.t, &dfp.a, &dfp.b, &dfp.context); \
decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \ dfp_finalize_decimal##size(&dfp); \
postprocs(&dfp); \ postprocs(&dfp); \
return dfp.crbf; \ return dfp.crbf; \
} }
@ -498,7 +517,7 @@ DFP_HELPER_BF_AB(dcmpo, decNumberCompare, CMPO_PPs, 64)
DFP_HELPER_BF_AB(dcmpoq, decNumberCompare, CMPO_PPs, 128) DFP_HELPER_BF_AB(dcmpoq, decNumberCompare, CMPO_PPs, 128)
#define DFP_HELPER_TSTDC(op, size) \ #define DFP_HELPER_TSTDC(op, size) \
uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint32_t dcm) \ uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, uint32_t dcm) \
{ \ { \
struct PPC_DFP dfp; \ struct PPC_DFP dfp; \
int match = 0; \ int match = 0; \
@ -526,7 +545,7 @@ DFP_HELPER_TSTDC(dtstdc, 64)
DFP_HELPER_TSTDC(dtstdcq, 128) DFP_HELPER_TSTDC(dtstdcq, 128)
#define DFP_HELPER_TSTDG(op, size) \ #define DFP_HELPER_TSTDG(op, size) \
uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint32_t dcm) \ uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, uint32_t dcm) \
{ \ { \
struct PPC_DFP dfp; \ struct PPC_DFP dfp; \
int minexp, maxexp, nzero_digits, nzero_idx, is_negative, is_zero, \ int minexp, maxexp, nzero_digits, nzero_idx, is_negative, is_zero, \
@ -581,7 +600,7 @@ DFP_HELPER_TSTDG(dtstdg, 64)
DFP_HELPER_TSTDG(dtstdgq, 128) DFP_HELPER_TSTDG(dtstdgq, 128)
#define DFP_HELPER_TSTEX(op, size) \ #define DFP_HELPER_TSTEX(op, size) \
uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint64_t *b) \ uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, ppc_fprp_t *b) \
{ \ { \
struct PPC_DFP dfp; \ struct PPC_DFP dfp; \
int expa, expb, a_is_special, b_is_special; \ int expa, expb, a_is_special, b_is_special; \
@ -613,14 +632,16 @@ DFP_HELPER_TSTEX(dtstex, 64)
DFP_HELPER_TSTEX(dtstexq, 128) DFP_HELPER_TSTEX(dtstexq, 128)
#define DFP_HELPER_TSTSF(op, size) \ #define DFP_HELPER_TSTSF(op, size) \
uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint64_t *b) \ uint32_t helper_##op(CPUPPCState *env, ppc_fprp_t *a, ppc_fprp_t *b) \
{ \ { \
struct PPC_DFP dfp; \ struct PPC_DFP dfp; \
unsigned k; \ unsigned k; \
ppc_vsr_t va; \
\ \
dfp_prepare_decimal##size(&dfp, 0, b, env); \ dfp_prepare_decimal##size(&dfp, 0, b, env); \
\ \
k = *a & 0x3F; \ get_dfp64(&va, a); \
k = va.VsrD(1) & 0x3F; \
\ \
if (unlikely(decNumberIsSpecial(&dfp.b))) { \ if (unlikely(decNumberIsSpecial(&dfp.b))) { \
dfp.crbf = 1; \ dfp.crbf = 1; \
@ -648,7 +669,7 @@ DFP_HELPER_TSTSF(dtstsf, 64)
DFP_HELPER_TSTSF(dtstsfq, 128) DFP_HELPER_TSTSF(dtstsfq, 128)
#define DFP_HELPER_TSTSFI(op, size) \ #define DFP_HELPER_TSTSFI(op, size) \
uint32_t helper_##op(CPUPPCState *env, uint32_t a, uint64_t *b) \ uint32_t helper_##op(CPUPPCState *env, uint32_t a, ppc_fprp_t *b) \
{ \ { \
struct PPC_DFP dfp; \ struct PPC_DFP dfp; \
unsigned uim; \ unsigned uim; \
@ -708,7 +729,7 @@ static void dfp_quantize(uint8_t rmc, struct PPC_DFP *dfp)
} }
#define DFP_HELPER_QUAI(op, size) \ #define DFP_HELPER_QUAI(op, size) \
void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, \ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \
uint32_t te, uint32_t rmc) \ uint32_t te, uint32_t rmc) \
{ \ { \
struct PPC_DFP dfp; \ struct PPC_DFP dfp; \
@ -719,40 +740,28 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, \
dfp.a.exponent = (int32_t)((int8_t)(te << 3) >> 3); \ dfp.a.exponent = (int32_t)((int8_t)(te << 3) >> 3); \
\ \
dfp_quantize(rmc, &dfp); \ dfp_quantize(rmc, &dfp); \
decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ dfp_finalize_decimal##size(&dfp); \
&dfp.context); \
QUA_PPs(&dfp); \ QUA_PPs(&dfp); \
\ \
if (size == 64) { \ set_dfp##size(t, &dfp.vt); \
t[0] = dfp.t64[0]; \
} else if (size == 128) { \
t[0] = dfp.t64[HI_IDX]; \
t[1] = dfp.t64[LO_IDX]; \
} \
} }
DFP_HELPER_QUAI(dquai, 64) DFP_HELPER_QUAI(dquai, 64)
DFP_HELPER_QUAI(dquaiq, 128) DFP_HELPER_QUAI(dquaiq, 128)
#define DFP_HELPER_QUA(op, size) \ #define DFP_HELPER_QUA(op, size) \
void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, \ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \
uint64_t *b, uint32_t rmc) \ ppc_fprp_t *b, uint32_t rmc) \
{ \ { \
struct PPC_DFP dfp; \ struct PPC_DFP dfp; \
\ \
dfp_prepare_decimal##size(&dfp, a, b, env); \ dfp_prepare_decimal##size(&dfp, a, b, env); \
\ \
dfp_quantize(rmc, &dfp); \ dfp_quantize(rmc, &dfp); \
decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ dfp_finalize_decimal##size(&dfp); \
&dfp.context); \
QUA_PPs(&dfp); \ QUA_PPs(&dfp); \
\ \
if (size == 64) { \ set_dfp##size(t, &dfp.vt); \
t[0] = dfp.t64[0]; \
} else if (size == 128) { \
t[0] = dfp.t64[HI_IDX]; \
t[1] = dfp.t64[LO_IDX]; \
} \
} }
DFP_HELPER_QUA(dqua, 64) DFP_HELPER_QUA(dqua, 64)
@ -813,33 +822,31 @@ static void _dfp_reround(uint8_t rmc, int32_t ref_sig, int32_t xmax,
} }
#define DFP_HELPER_RRND(op, size) \ #define DFP_HELPER_RRND(op, size) \
void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, \ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \
uint64_t *b, uint32_t rmc) \ ppc_fprp_t *b, uint32_t rmc) \
{ \ { \
struct PPC_DFP dfp; \ struct PPC_DFP dfp; \
int32_t ref_sig = *a & 0x3F; \ ppc_vsr_t va; \
int32_t ref_sig; \
int32_t xmax = ((size) == 64) ? 369 : 6111; \ int32_t xmax = ((size) == 64) ? 369 : 6111; \
\ \
dfp_prepare_decimal##size(&dfp, 0, b, env); \ dfp_prepare_decimal##size(&dfp, 0, b, env); \
\ \
get_dfp64(&va, a); \
ref_sig = va.VsrD(1) & 0x3f; \
\
_dfp_reround(rmc, ref_sig, xmax, &dfp); \ _dfp_reround(rmc, ref_sig, xmax, &dfp); \
decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ dfp_finalize_decimal##size(&dfp); \
&dfp.context); \
QUA_PPs(&dfp); \ QUA_PPs(&dfp); \
\ \
if (size == 64) { \ set_dfp##size(t, &dfp.vt); \
t[0] = dfp.t64[0]; \
} else if (size == 128) { \
t[0] = dfp.t64[HI_IDX]; \
t[1] = dfp.t64[LO_IDX]; \
} \
} }
DFP_HELPER_RRND(drrnd, 64) DFP_HELPER_RRND(drrnd, 64)
DFP_HELPER_RRND(drrndq, 128) DFP_HELPER_RRND(drrndq, 128)
#define DFP_HELPER_RINT(op, postprocs, size) \ #define DFP_HELPER_RINT(op, postprocs, size) \
void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, \ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \
uint32_t r, uint32_t rmc) \ uint32_t r, uint32_t rmc) \
{ \ { \
struct PPC_DFP dfp; \ struct PPC_DFP dfp; \
@ -848,15 +855,10 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, \
\ \
dfp_set_round_mode_from_immediate(r, rmc, &dfp); \ dfp_set_round_mode_from_immediate(r, rmc, &dfp); \
decNumberToIntegralExact(&dfp.t, &dfp.b, &dfp.context); \ decNumberToIntegralExact(&dfp.t, &dfp.b, &dfp.context); \
decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \ dfp_finalize_decimal##size(&dfp); \
postprocs(&dfp); \ postprocs(&dfp); \
\ \
if (size == 64) { \ set_dfp##size(t, &dfp.vt); \
t[0] = dfp.t64[0]; \
} else if (size == 128) { \
t[0] = dfp.t64[HI_IDX]; \
t[1] = dfp.t64[LO_IDX]; \
} \
} }
static void RINTX_PPs(struct PPC_DFP *dfp) static void RINTX_PPs(struct PPC_DFP *dfp)
@ -878,34 +880,42 @@ static void RINTN_PPs(struct PPC_DFP *dfp)
DFP_HELPER_RINT(drintn, RINTN_PPs, 64) DFP_HELPER_RINT(drintn, RINTN_PPs, 64)
DFP_HELPER_RINT(drintnq, RINTN_PPs, 128) DFP_HELPER_RINT(drintnq, RINTN_PPs, 128)
void helper_dctdp(CPUPPCState *env, uint64_t *t, uint64_t *b) void helper_dctdp(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b)
{ {
struct PPC_DFP dfp; struct PPC_DFP dfp;
uint32_t b_short = *b; ppc_vsr_t vb;
uint32_t b_short;
get_dfp64(&vb, b);
b_short = (uint32_t)vb.VsrD(1);
dfp_prepare_decimal64(&dfp, 0, 0, env); dfp_prepare_decimal64(&dfp, 0, 0, env);
decimal32ToNumber((decimal32 *)&b_short, &dfp.t); decimal32ToNumber((decimal32 *)&b_short, &dfp.t);
decimal64FromNumber((decimal64 *)t, &dfp.t, &dfp.context); dfp_finalize_decimal64(&dfp);
set_dfp64(t, &dfp.vt);
dfp_set_FPRF_from_FRT(&dfp); dfp_set_FPRF_from_FRT(&dfp);
} }
void helper_dctqpq(CPUPPCState *env, uint64_t *t, uint64_t *b) void helper_dctqpq(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b)
{ {
struct PPC_DFP dfp; struct PPC_DFP dfp;
ppc_vsr_t vb;
dfp_prepare_decimal128(&dfp, 0, 0, env); dfp_prepare_decimal128(&dfp, 0, 0, env);
decimal64ToNumber((decimal64 *)b, &dfp.t); get_dfp64(&vb, b);
decimal64ToNumber((decimal64 *)&vb.VsrD(1), &dfp.t);
dfp_check_for_VXSNAN_and_convert_to_QNaN(&dfp); dfp_check_for_VXSNAN_and_convert_to_QNaN(&dfp);
dfp_set_FPRF_from_FRT(&dfp); dfp_set_FPRF_from_FRT(&dfp);
decimal128FromNumber((decimal128 *)&dfp.t64, &dfp.t, &dfp.context); dfp_finalize_decimal128(&dfp);
t[0] = dfp.t64[HI_IDX]; set_dfp128(t, &dfp.vt);
t[1] = dfp.t64[LO_IDX];
} }
void helper_drsp(CPUPPCState *env, uint64_t *t, uint64_t *b) void helper_drsp(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b)
{ {
struct PPC_DFP dfp; struct PPC_DFP dfp;
uint32_t t_short = 0; uint32_t t_short = 0;
ppc_vsr_t vt;
dfp_prepare_decimal64(&dfp, 0, b, env); dfp_prepare_decimal64(&dfp, 0, b, env);
decimal32FromNumber((decimal32 *)&t_short, &dfp.b, &dfp.context); decimal32FromNumber((decimal32 *)&t_short, &dfp.b, &dfp.context);
decimal32ToNumber((decimal32 *)&t_short, &dfp.t); decimal32ToNumber((decimal32 *)&t_short, &dfp.t);
@ -915,15 +925,16 @@ void helper_drsp(CPUPPCState *env, uint64_t *t, uint64_t *b)
dfp_check_for_UX(&dfp); dfp_check_for_UX(&dfp);
dfp_check_for_XX(&dfp); dfp_check_for_XX(&dfp);
*t = t_short; vt.VsrD(1) = (uint64_t)t_short;
set_dfp64(t, &vt);
} }
void helper_drdpq(CPUPPCState *env, uint64_t *t, uint64_t *b) void helper_drdpq(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b)
{ {
struct PPC_DFP dfp; struct PPC_DFP dfp;
dfp_prepare_decimal128(&dfp, 0, b, env); dfp_prepare_decimal128(&dfp, 0, b, env);
decimal64FromNumber((decimal64 *)&dfp.t64, &dfp.b, &dfp.context); decimal64FromNumber((decimal64 *)&dfp.vt.VsrD(1), &dfp.b, &dfp.context);
decimal64ToNumber((decimal64 *)&dfp.t64, &dfp.t); decimal64ToNumber((decimal64 *)&dfp.vt.VsrD(1), &dfp.t);
dfp_check_for_VXSNAN_and_convert_to_QNaN(&dfp); dfp_check_for_VXSNAN_and_convert_to_QNaN(&dfp);
dfp_set_FPRF_from_FRT_long(&dfp); dfp_set_FPRF_from_FRT_long(&dfp);
@ -931,26 +942,23 @@ void helper_drdpq(CPUPPCState *env, uint64_t *t, uint64_t *b)
dfp_check_for_UX(&dfp); dfp_check_for_UX(&dfp);
dfp_check_for_XX(&dfp); dfp_check_for_XX(&dfp);
decimal64FromNumber((decimal64 *)dfp.t64, &dfp.t, &dfp.context); dfp.vt.VsrD(0) = dfp.vt.VsrD(1) = 0;
t[0] = dfp.t64[0]; dfp_finalize_decimal64(&dfp);
t[1] = 0; set_dfp128(t, &dfp.vt);
} }
#define DFP_HELPER_CFFIX(op, size) \ #define DFP_HELPER_CFFIX(op, size) \
void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b) \ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) \
{ \ { \
struct PPC_DFP dfp; \ struct PPC_DFP dfp; \
ppc_vsr_t vb; \
dfp_prepare_decimal##size(&dfp, 0, b, env); \ dfp_prepare_decimal##size(&dfp, 0, b, env); \
decNumberFromInt64(&dfp.t, (int64_t)(*b)); \ get_dfp64(&vb, b); \
decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, &dfp.context); \ decNumberFromInt64(&dfp.t, (int64_t)vb.VsrD(1)); \
dfp_finalize_decimal##size(&dfp); \
CFFIX_PPs(&dfp); \ CFFIX_PPs(&dfp); \
\ \
if (size == 64) { \ set_dfp##size(t, &dfp.vt); \
t[0] = dfp.t64[0]; \
} else if (size == 128) { \
t[0] = dfp.t64[HI_IDX]; \
t[1] = dfp.t64[LO_IDX]; \
} \
} }
static void CFFIX_PPs(struct PPC_DFP *dfp) static void CFFIX_PPs(struct PPC_DFP *dfp)
@ -963,7 +971,7 @@ DFP_HELPER_CFFIX(dcffix, 64)
DFP_HELPER_CFFIX(dcffixq, 128) DFP_HELPER_CFFIX(dcffixq, 128)
#define DFP_HELPER_CTFIX(op, size) \ #define DFP_HELPER_CTFIX(op, size) \
void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b) \ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) \
{ \ { \
struct PPC_DFP dfp; \ struct PPC_DFP dfp; \
dfp_prepare_decimal##size(&dfp, 0, b, env); \ dfp_prepare_decimal##size(&dfp, 0, b, env); \
@ -971,62 +979,65 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b) \
if (unlikely(decNumberIsSpecial(&dfp.b))) { \ if (unlikely(decNumberIsSpecial(&dfp.b))) { \
uint64_t invalid_flags = FP_VX | FP_VXCVI; \ uint64_t invalid_flags = FP_VX | FP_VXCVI; \
if (decNumberIsInfinite(&dfp.b)) { \ if (decNumberIsInfinite(&dfp.b)) { \
dfp.t64[0] = decNumberIsNegative(&dfp.b) ? INT64_MIN : INT64_MAX; \ dfp.vt.VsrD(1) = decNumberIsNegative(&dfp.b) ? INT64_MIN : \
INT64_MAX; \
} else { /* NaN */ \ } else { /* NaN */ \
dfp.t64[0] = INT64_MIN; \ dfp.vt.VsrD(1) = INT64_MIN; \
if (decNumberIsSNaN(&dfp.b)) { \ if (decNumberIsSNaN(&dfp.b)) { \
invalid_flags |= FP_VXSNAN; \ invalid_flags |= FP_VXSNAN; \
} \ } \
} \ } \
dfp_set_FPSCR_flag(&dfp, invalid_flags, FP_VE); \ dfp_set_FPSCR_flag(&dfp, invalid_flags, FP_VE); \
} else if (unlikely(decNumberIsZero(&dfp.b))) { \ } else if (unlikely(decNumberIsZero(&dfp.b))) { \
dfp.t64[0] = 0; \ dfp.vt.VsrD(1) = 0; \
} else { \ } else { \
decNumberToIntegralExact(&dfp.b, &dfp.b, &dfp.context); \ decNumberToIntegralExact(&dfp.b, &dfp.b, &dfp.context); \
dfp.t64[0] = decNumberIntegralToInt64(&dfp.b, &dfp.context); \ dfp.vt.VsrD(1) = decNumberIntegralToInt64(&dfp.b, &dfp.context); \
if (decContextTestStatus(&dfp.context, DEC_Invalid_operation)) { \ if (decContextTestStatus(&dfp.context, DEC_Invalid_operation)) { \
dfp.t64[0] = decNumberIsNegative(&dfp.b) ? INT64_MIN : INT64_MAX; \ dfp.vt.VsrD(1) = decNumberIsNegative(&dfp.b) ? INT64_MIN : \
INT64_MAX; \
dfp_set_FPSCR_flag(&dfp, FP_VX | FP_VXCVI, FP_VE); \ dfp_set_FPSCR_flag(&dfp, FP_VX | FP_VXCVI, FP_VE); \
} else { \ } else { \
dfp_check_for_XX(&dfp); \ dfp_check_for_XX(&dfp); \
} \ } \
} \ } \
\ \
*t = dfp.t64[0]; \ set_dfp64(t, &dfp.vt); \
} }
DFP_HELPER_CTFIX(dctfix, 64) DFP_HELPER_CTFIX(dctfix, 64)
DFP_HELPER_CTFIX(dctfixq, 128) DFP_HELPER_CTFIX(dctfixq, 128)
static inline void dfp_set_bcd_digit_64(uint64_t *t, uint8_t digit, static inline void dfp_set_bcd_digit_64(ppc_vsr_t *t, uint8_t digit,
unsigned n) unsigned n)
{ {
*t |= ((uint64_t)(digit & 0xF) << (n << 2)); t->VsrD(1) |= ((uint64_t)(digit & 0xF) << (n << 2));
} }
static inline void dfp_set_bcd_digit_128(uint64_t *t, uint8_t digit, static inline void dfp_set_bcd_digit_128(ppc_vsr_t *t, uint8_t digit,
unsigned n) unsigned n)
{ {
t[(n & 0x10) ? HI_IDX : LO_IDX] |= t->VsrD((n & 0x10) ? 0 : 1) |=
((uint64_t)(digit & 0xF) << ((n & 15) << 2)); ((uint64_t)(digit & 0xF) << ((n & 15) << 2));
} }
static inline void dfp_set_sign_64(uint64_t *t, uint8_t sgn) static inline void dfp_set_sign_64(ppc_vsr_t *t, uint8_t sgn)
{ {
*t <<= 4; t->VsrD(1) <<= 4;
*t |= (sgn & 0xF); t->VsrD(1) |= (sgn & 0xF);
} }
static inline void dfp_set_sign_128(uint64_t *t, uint8_t sgn) static inline void dfp_set_sign_128(ppc_vsr_t *t, uint8_t sgn)
{ {
t[HI_IDX] <<= 4; t->VsrD(0) <<= 4;
t[HI_IDX] |= (t[LO_IDX] >> 60); t->VsrD(0) |= (t->VsrD(1) >> 60);
t[LO_IDX] <<= 4; t->VsrD(1) <<= 4;
t[LO_IDX] |= (sgn & 0xF); t->VsrD(1) |= (sgn & 0xF);
} }
#define DFP_HELPER_DEDPD(op, size) \ #define DFP_HELPER_DEDPD(op, size) \
void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t sp) \ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \
uint32_t sp) \
{ \ { \
struct PPC_DFP dfp; \ struct PPC_DFP dfp; \
uint8_t digits[34]; \ uint8_t digits[34]; \
@ -1035,11 +1046,11 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t sp) \
dfp_prepare_decimal##size(&dfp, 0, b, env); \ dfp_prepare_decimal##size(&dfp, 0, b, env); \
\ \
decNumberGetBCD(&dfp.b, digits); \ decNumberGetBCD(&dfp.b, digits); \
dfp.t64[0] = dfp.t64[1] = 0; \ dfp.vt.VsrD(0) = dfp.vt.VsrD(1) = 0; \
N = dfp.b.digits; \ N = dfp.b.digits; \
\ \
for (i = 0; (i < N) && (i < (size)/4); i++) { \ for (i = 0; (i < N) && (i < (size)/4); i++) { \
dfp_set_bcd_digit_##size(dfp.t64, digits[N-i-1], i); \ dfp_set_bcd_digit_##size(&dfp.vt, digits[N - i - 1], i); \
} \ } \
\ \
if (sp & 2) { \ if (sp & 2) { \
@ -1050,32 +1061,28 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t sp) \
} else { \ } else { \
sgn = ((sp & 1) ? 0xF : 0xC); \ sgn = ((sp & 1) ? 0xF : 0xC); \
} \ } \
dfp_set_sign_##size(dfp.t64, sgn); \ dfp_set_sign_##size(&dfp.vt, sgn); \
} \ } \
\ \
if (size == 64) { \ set_dfp##size(t, &dfp.vt); \
t[0] = dfp.t64[0]; \
} else if (size == 128) { \
t[0] = dfp.t64[HI_IDX]; \
t[1] = dfp.t64[LO_IDX]; \
} \
} }
DFP_HELPER_DEDPD(ddedpd, 64) DFP_HELPER_DEDPD(ddedpd, 64)
DFP_HELPER_DEDPD(ddedpdq, 128) DFP_HELPER_DEDPD(ddedpdq, 128)
static inline uint8_t dfp_get_bcd_digit_64(uint64_t *t, unsigned n) static inline uint8_t dfp_get_bcd_digit_64(ppc_vsr_t *t, unsigned n)
{ {
return *t >> ((n << 2) & 63) & 15; return t->VsrD(1) >> ((n << 2) & 63) & 15;
} }
static inline uint8_t dfp_get_bcd_digit_128(uint64_t *t, unsigned n) static inline uint8_t dfp_get_bcd_digit_128(ppc_vsr_t *t, unsigned n)
{ {
return t[(n & 0x10) ? HI_IDX : LO_IDX] >> ((n << 2) & 63) & 15; return t->VsrD((n & 0x10) ? 0 : 1) >> ((n << 2) & 63) & 15;
} }
#define DFP_HELPER_ENBCD(op, size) \ #define DFP_HELPER_ENBCD(op, size) \
void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t s) \ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b, \
uint32_t s) \
{ \ { \
struct PPC_DFP dfp; \ struct PPC_DFP dfp; \
uint8_t digits[32]; \ uint8_t digits[32]; \
@ -1086,7 +1093,7 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t s) \
decNumberZero(&dfp.t); \ decNumberZero(&dfp.t); \
\ \
if (s) { \ if (s) { \
uint8_t sgnNibble = dfp_get_bcd_digit_##size(dfp.b64, offset++); \ uint8_t sgnNibble = dfp_get_bcd_digit_##size(&dfp.vb, offset++); \
switch (sgnNibble) { \ switch (sgnNibble) { \
case 0xD: \ case 0xD: \
case 0xB: \ case 0xB: \
@ -1106,7 +1113,8 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t s) \
\ \
while (offset < (size) / 4) { \ while (offset < (size) / 4) { \
n++; \ n++; \
digits[(size) / 4 - n] = dfp_get_bcd_digit_##size(dfp.b64, offset++); \ digits[(size) / 4 - n] = dfp_get_bcd_digit_##size(&dfp.vb, \
offset++); \
if (digits[(size) / 4 - n] > 10) { \ if (digits[(size) / 4 - n] > 10) { \
dfp_set_FPSCR_flag(&dfp, FP_VX | FP_VXCVI, FPSCR_VE); \ dfp_set_FPSCR_flag(&dfp, FP_VX | FP_VXCVI, FPSCR_VE); \
return; \ return; \
@ -1122,71 +1130,72 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b, uint32_t s) \
if (s && sgn) { \ if (s && sgn) { \
dfp.t.bits |= DECNEG; \ dfp.t.bits |= DECNEG; \
} \ } \
decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ dfp_finalize_decimal##size(&dfp); \
&dfp.context); \
dfp_set_FPRF_from_FRT(&dfp); \ dfp_set_FPRF_from_FRT(&dfp); \
if ((size) == 64) { \ set_dfp##size(t, &dfp.vt); \
t[0] = dfp.t64[0]; \
} else if ((size) == 128) { \
t[0] = dfp.t64[HI_IDX]; \
t[1] = dfp.t64[LO_IDX]; \
} \
} }
DFP_HELPER_ENBCD(denbcd, 64) DFP_HELPER_ENBCD(denbcd, 64)
DFP_HELPER_ENBCD(denbcdq, 128) DFP_HELPER_ENBCD(denbcdq, 128)
#define DFP_HELPER_XEX(op, size) \ #define DFP_HELPER_XEX(op, size) \
void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *b) \ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *b) \
{ \ { \
struct PPC_DFP dfp; \ struct PPC_DFP dfp; \
ppc_vsr_t vt; \
\ \
dfp_prepare_decimal##size(&dfp, 0, b, env); \ dfp_prepare_decimal##size(&dfp, 0, b, env); \
\ \
if (unlikely(decNumberIsSpecial(&dfp.b))) { \ if (unlikely(decNumberIsSpecial(&dfp.b))) { \
if (decNumberIsInfinite(&dfp.b)) { \ if (decNumberIsInfinite(&dfp.b)) { \
*t = -1; \ vt.VsrD(1) = -1; \
} else if (decNumberIsSNaN(&dfp.b)) { \ } else if (decNumberIsSNaN(&dfp.b)) { \
*t = -3; \ vt.VsrD(1) = -3; \
} else if (decNumberIsQNaN(&dfp.b)) { \ } else if (decNumberIsQNaN(&dfp.b)) { \
*t = -2; \ vt.VsrD(1) = -2; \
} else { \ } else { \
assert(0); \ assert(0); \
} \ } \
set_dfp64(t, &vt); \
} else { \ } else { \
if ((size) == 64) { \ if ((size) == 64) { \
*t = dfp.b.exponent + 398; \ vt.VsrD(1) = dfp.b.exponent + 398; \
} else if ((size) == 128) { \ } else if ((size) == 128) { \
*t = dfp.b.exponent + 6176; \ vt.VsrD(1) = dfp.b.exponent + 6176; \
} else { \ } else { \
assert(0); \ assert(0); \
} \ } \
set_dfp64(t, &vt); \
} \ } \
} }
DFP_HELPER_XEX(dxex, 64) DFP_HELPER_XEX(dxex, 64)
DFP_HELPER_XEX(dxexq, 128) DFP_HELPER_XEX(dxexq, 128)
static void dfp_set_raw_exp_64(uint64_t *t, uint64_t raw) static void dfp_set_raw_exp_64(ppc_vsr_t *t, uint64_t raw)
{ {
*t &= 0x8003ffffffffffffULL; t->VsrD(1) &= 0x8003ffffffffffffULL;
*t |= (raw << (63 - 13)); t->VsrD(1) |= (raw << (63 - 13));
} }
static void dfp_set_raw_exp_128(uint64_t *t, uint64_t raw) static void dfp_set_raw_exp_128(ppc_vsr_t *t, uint64_t raw)
{ {
t[HI_IDX] &= 0x80003fffffffffffULL; t->VsrD(0) &= 0x80003fffffffffffULL;
t[HI_IDX] |= (raw << (63 - 17)); t->VsrD(0) |= (raw << (63 - 17));
} }
#define DFP_HELPER_IEX(op, size) \ #define DFP_HELPER_IEX(op, size) \
void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, uint64_t *b) \ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \
ppc_fprp_t *b) \
{ \ { \
struct PPC_DFP dfp; \ struct PPC_DFP dfp; \
uint64_t raw_qnan, raw_snan, raw_inf, max_exp; \ uint64_t raw_qnan, raw_snan, raw_inf, max_exp; \
ppc_vsr_t va; \
int bias; \ int bias; \
int64_t exp = *((int64_t *)a); \ int64_t exp; \
\ \
get_dfp64(&va, a); \
exp = (int64_t)va.VsrD(1); \
dfp_prepare_decimal##size(&dfp, 0, b, env); \ dfp_prepare_decimal##size(&dfp, 0, b, env); \
\ \
if ((size) == 64) { \ if ((size) == 64) { \
@ -1206,14 +1215,14 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, uint64_t *b) \
} \ } \
\ \
if (unlikely((exp < 0) || (exp > max_exp))) { \ if (unlikely((exp < 0) || (exp > max_exp))) { \
dfp.t64[0] = dfp.b64[0]; \ dfp.vt.VsrD(0) = dfp.vb.VsrD(0); \
dfp.t64[1] = dfp.b64[1]; \ dfp.vt.VsrD(1) = dfp.vb.VsrD(1); \
if (exp == -1) { \ if (exp == -1) { \
dfp_set_raw_exp_##size(dfp.t64, raw_inf); \ dfp_set_raw_exp_##size(&dfp.vt, raw_inf); \
} else if (exp == -3) { \ } else if (exp == -3) { \
dfp_set_raw_exp_##size(dfp.t64, raw_snan); \ dfp_set_raw_exp_##size(&dfp.vt, raw_snan); \
} else { \ } else { \
dfp_set_raw_exp_##size(dfp.t64, raw_qnan); \ dfp_set_raw_exp_##size(&dfp.vt, raw_qnan); \
} \ } \
} else { \ } else { \
dfp.t = dfp.b; \ dfp.t = dfp.b; \
@ -1221,15 +1230,9 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, uint64_t *b) \
dfp.t.bits &= ~DECSPECIAL; \ dfp.t.bits &= ~DECSPECIAL; \
} \ } \
dfp.t.exponent = exp - bias; \ dfp.t.exponent = exp - bias; \
decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ dfp_finalize_decimal##size(&dfp); \
&dfp.context); \
} \
if (size == 64) { \
t[0] = dfp.t64[0]; \
} else if (size == 128) { \
t[0] = dfp.t64[HI_IDX]; \
t[1] = dfp.t64[LO_IDX]; \
} \ } \
set_dfp##size(t, &dfp.vt); \
} }
DFP_HELPER_IEX(diex, 64) DFP_HELPER_IEX(diex, 64)
@ -1276,7 +1279,7 @@ static void dfp_clear_lmd_from_g5msb(uint64_t *t)
} }
#define DFP_HELPER_SHIFT(op, size, shift_left) \ #define DFP_HELPER_SHIFT(op, size, shift_left) \
void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, \ void helper_##op(CPUPPCState *env, ppc_fprp_t *t, ppc_fprp_t *a, \
uint32_t sh) \ uint32_t sh) \
{ \ { \
struct PPC_DFP dfp; \ struct PPC_DFP dfp; \
@ -1303,26 +1306,21 @@ void helper_##op(CPUPPCState *env, uint64_t *t, uint64_t *a, \
dfp.t.digits = max_digits - 1; \ dfp.t.digits = max_digits - 1; \
} \ } \
\ \
decimal##size##FromNumber((decimal##size *)dfp.t64, &dfp.t, \ dfp_finalize_decimal##size(&dfp); \
&dfp.context); \
} else { \ } else { \
if ((size) == 64) { \ if ((size) == 64) { \
dfp.t64[0] = dfp.a64[0] & 0xFFFC000000000000ULL; \ dfp.vt.VsrD(1) = dfp.va.VsrD(1) & \
dfp_clear_lmd_from_g5msb(dfp.t64); \ 0xFFFC000000000000ULL; \
dfp_clear_lmd_from_g5msb(&dfp.vt.VsrD(1)); \
} else { \ } else { \
dfp.t64[HI_IDX] = dfp.a64[HI_IDX] & \ dfp.vt.VsrD(0) = dfp.va.VsrD(0) & \
0xFFFFC00000000000ULL; \ 0xFFFFC00000000000ULL; \
dfp_clear_lmd_from_g5msb(dfp.t64 + HI_IDX); \ dfp_clear_lmd_from_g5msb(&dfp.vt.VsrD(0)); \
dfp.t64[LO_IDX] = 0; \ dfp.vt.VsrD(1) = 0; \
} \ } \
} \ } \
\ \
if ((size) == 64) { \ set_dfp##size(t, &dfp.vt); \
t[0] = dfp.t64[0]; \
} else { \
t[0] = dfp.t64[HI_IDX]; \
t[1] = dfp.t64[LO_IDX]; \
} \
} }
DFP_HELPER_SHIFT(dscli, 64, 1) DFP_HELPER_SHIFT(dscli, 64, 1)

View File

@ -180,7 +180,7 @@ static void set_fprf_from_class(CPUPPCState *env, int class)
}; };
bool isneg = class & is_neg; bool isneg = class & is_neg;
env->fpscr &= ~(0x1F << FPSCR_FPRF); env->fpscr &= ~FP_FPRF;
env->fpscr |= fprf[ctz32(class)][isneg] << FPSCR_FPRF; env->fpscr |= fprf[ctz32(class)][isneg] << FPSCR_FPRF;
} }
@ -199,12 +199,12 @@ COMPUTE_FPRF(float128)
static void finish_invalid_op_excp(CPUPPCState *env, int op, uintptr_t retaddr) static void finish_invalid_op_excp(CPUPPCState *env, int op, uintptr_t retaddr)
{ {
/* Update the floating-point invalid operation summary */ /* Update the floating-point invalid operation summary */
env->fpscr |= 1 << FPSCR_VX; env->fpscr |= FP_VX;
/* Update the floating-point exception summary */ /* Update the floating-point exception summary */
env->fpscr |= FP_FX; env->fpscr |= FP_FX;
if (fpscr_ve != 0) { if (fpscr_ve != 0) {
/* Update the floating-point enabled exception summary */ /* Update the floating-point enabled exception summary */
env->fpscr |= 1 << FPSCR_FEX; env->fpscr |= FP_FEX;
if (fp_exceptions_enabled(env)) { if (fp_exceptions_enabled(env)) {
raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
POWERPC_EXCP_FP | op, retaddr); POWERPC_EXCP_FP | op, retaddr);
@ -215,11 +215,11 @@ static void finish_invalid_op_excp(CPUPPCState *env, int op, uintptr_t retaddr)
static void finish_invalid_op_arith(CPUPPCState *env, int op, static void finish_invalid_op_arith(CPUPPCState *env, int op,
bool set_fpcc, uintptr_t retaddr) bool set_fpcc, uintptr_t retaddr)
{ {
env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); env->fpscr &= ~(FP_FR | FP_FI);
if (fpscr_ve == 0) { if (fpscr_ve == 0) {
if (set_fpcc) { if (set_fpcc) {
env->fpscr &= ~(0xF << FPSCR_FPCC); env->fpscr &= ~FP_FPCC;
env->fpscr |= 0x11 << FPSCR_FPCC; env->fpscr |= (FP_C | FP_FU);
} }
} }
finish_invalid_op_excp(env, op, retaddr); finish_invalid_op_excp(env, op, retaddr);
@ -228,7 +228,7 @@ static void finish_invalid_op_arith(CPUPPCState *env, int op,
/* Signalling NaN */ /* Signalling NaN */
static void float_invalid_op_vxsnan(CPUPPCState *env, uintptr_t retaddr) static void float_invalid_op_vxsnan(CPUPPCState *env, uintptr_t retaddr)
{ {
env->fpscr |= 1 << FPSCR_VXSNAN; env->fpscr |= FP_VXSNAN;
finish_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, retaddr); finish_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, retaddr);
} }
@ -236,7 +236,7 @@ static void float_invalid_op_vxsnan(CPUPPCState *env, uintptr_t retaddr)
static void float_invalid_op_vxisi(CPUPPCState *env, bool set_fpcc, static void float_invalid_op_vxisi(CPUPPCState *env, bool set_fpcc,
uintptr_t retaddr) uintptr_t retaddr)
{ {
env->fpscr |= 1 << FPSCR_VXISI; env->fpscr |= FP_VXISI;
finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXISI, set_fpcc, retaddr); finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXISI, set_fpcc, retaddr);
} }
@ -244,7 +244,7 @@ static void float_invalid_op_vxisi(CPUPPCState *env, bool set_fpcc,
static void float_invalid_op_vxidi(CPUPPCState *env, bool set_fpcc, static void float_invalid_op_vxidi(CPUPPCState *env, bool set_fpcc,
uintptr_t retaddr) uintptr_t retaddr)
{ {
env->fpscr |= 1 << FPSCR_VXIDI; env->fpscr |= FP_VXIDI;
finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXIDI, set_fpcc, retaddr); finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXIDI, set_fpcc, retaddr);
} }
@ -252,7 +252,7 @@ static void float_invalid_op_vxidi(CPUPPCState *env, bool set_fpcc,
static void float_invalid_op_vxzdz(CPUPPCState *env, bool set_fpcc, static void float_invalid_op_vxzdz(CPUPPCState *env, bool set_fpcc,
uintptr_t retaddr) uintptr_t retaddr)
{ {
env->fpscr |= 1 << FPSCR_VXZDZ; env->fpscr |= FP_VXZDZ;
finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXZDZ, set_fpcc, retaddr); finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXZDZ, set_fpcc, retaddr);
} }
@ -260,7 +260,7 @@ static void float_invalid_op_vxzdz(CPUPPCState *env, bool set_fpcc,
static void float_invalid_op_vximz(CPUPPCState *env, bool set_fpcc, static void float_invalid_op_vximz(CPUPPCState *env, bool set_fpcc,
uintptr_t retaddr) uintptr_t retaddr)
{ {
env->fpscr |= 1 << FPSCR_VXIMZ; env->fpscr |= FP_VXIMZ;
finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXIMZ, set_fpcc, retaddr); finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXIMZ, set_fpcc, retaddr);
} }
@ -268,7 +268,7 @@ static void float_invalid_op_vximz(CPUPPCState *env, bool set_fpcc,
static void float_invalid_op_vxsqrt(CPUPPCState *env, bool set_fpcc, static void float_invalid_op_vxsqrt(CPUPPCState *env, bool set_fpcc,
uintptr_t retaddr) uintptr_t retaddr)
{ {
env->fpscr |= 1 << FPSCR_VXSQRT; env->fpscr |= FP_VXSQRT;
finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXSQRT, set_fpcc, retaddr); finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXSQRT, set_fpcc, retaddr);
} }
@ -276,13 +276,13 @@ static void float_invalid_op_vxsqrt(CPUPPCState *env, bool set_fpcc,
static void float_invalid_op_vxvc(CPUPPCState *env, bool set_fpcc, static void float_invalid_op_vxvc(CPUPPCState *env, bool set_fpcc,
uintptr_t retaddr) uintptr_t retaddr)
{ {
env->fpscr |= 1 << FPSCR_VXVC; env->fpscr |= FP_VXVC;
if (set_fpcc) { if (set_fpcc) {
env->fpscr &= ~(0xF << FPSCR_FPCC); env->fpscr &= ~FP_FPCC;
env->fpscr |= 0x11 << FPSCR_FPCC; env->fpscr |= (FP_C | FP_FU);
} }
/* Update the floating-point invalid operation summary */ /* Update the floating-point invalid operation summary */
env->fpscr |= 1 << FPSCR_VX; env->fpscr |= FP_VX;
/* Update the floating-point exception summary */ /* Update the floating-point exception summary */
env->fpscr |= FP_FX; env->fpscr |= FP_FX;
/* We must update the target FPR before raising the exception */ /* We must update the target FPR before raising the exception */
@ -292,7 +292,7 @@ static void float_invalid_op_vxvc(CPUPPCState *env, bool set_fpcc,
cs->exception_index = POWERPC_EXCP_PROGRAM; cs->exception_index = POWERPC_EXCP_PROGRAM;
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC; env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
/* Update the floating-point enabled exception summary */ /* Update the floating-point enabled exception summary */
env->fpscr |= 1 << FPSCR_FEX; env->fpscr |= FP_FEX;
/* Exception is differed */ /* Exception is differed */
} }
} }
@ -301,12 +301,12 @@ static void float_invalid_op_vxvc(CPUPPCState *env, bool set_fpcc,
static void float_invalid_op_vxcvi(CPUPPCState *env, bool set_fpcc, static void float_invalid_op_vxcvi(CPUPPCState *env, bool set_fpcc,
uintptr_t retaddr) uintptr_t retaddr)
{ {
env->fpscr |= 1 << FPSCR_VXCVI; env->fpscr |= FP_VXCVI;
env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); env->fpscr &= ~(FP_FR | FP_FI);
if (fpscr_ve == 0) { if (fpscr_ve == 0) {
if (set_fpcc) { if (set_fpcc) {
env->fpscr &= ~(0xF << FPSCR_FPCC); env->fpscr &= ~FP_FPCC;
env->fpscr |= 0x11 << FPSCR_FPCC; env->fpscr |= (FP_C | FP_FU);
} }
} }
finish_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, retaddr); finish_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, retaddr);
@ -314,13 +314,13 @@ static void float_invalid_op_vxcvi(CPUPPCState *env, bool set_fpcc,
static inline void float_zero_divide_excp(CPUPPCState *env, uintptr_t raddr) static inline void float_zero_divide_excp(CPUPPCState *env, uintptr_t raddr)
{ {
env->fpscr |= 1 << FPSCR_ZX; env->fpscr |= FP_ZX;
env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); env->fpscr &= ~(FP_FR | FP_FI);
/* Update the floating-point exception summary */ /* Update the floating-point exception summary */
env->fpscr |= FP_FX; env->fpscr |= FP_FX;
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 |= FP_FEX;
if (fp_exceptions_enabled(env)) { 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,
@ -333,19 +333,19 @@ static inline void float_overflow_excp(CPUPPCState *env)
{ {
CPUState *cs = env_cpu(env); CPUState *cs = env_cpu(env);
env->fpscr |= 1 << FPSCR_OX; env->fpscr |= FP_OX;
/* Update the floating-point exception summary */ /* Update the floating-point exception summary */
env->fpscr |= FP_FX; env->fpscr |= FP_FX;
if (fpscr_oe != 0) { if (fpscr_oe != 0) {
/* XXX: should adjust the result */ /* XXX: should adjust the result */
/* Update the floating-point enabled exception summary */ /* Update the floating-point enabled exception summary */
env->fpscr |= 1 << FPSCR_FEX; env->fpscr |= FP_FEX;
/* We must update the target FPR before raising the exception */ /* We must update the target FPR before raising the exception */
cs->exception_index = POWERPC_EXCP_PROGRAM; cs->exception_index = POWERPC_EXCP_PROGRAM;
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX; env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
} else { } else {
env->fpscr |= 1 << FPSCR_XX; env->fpscr |= FP_XX;
env->fpscr |= 1 << FPSCR_FI; env->fpscr |= FP_FI;
} }
} }
@ -353,13 +353,13 @@ static inline void float_underflow_excp(CPUPPCState *env)
{ {
CPUState *cs = env_cpu(env); CPUState *cs = env_cpu(env);
env->fpscr |= 1 << FPSCR_UX; env->fpscr |= FP_UX;
/* Update the floating-point exception summary */ /* Update the floating-point exception summary */
env->fpscr |= FP_FX; env->fpscr |= FP_FX;
if (fpscr_ue != 0) { if (fpscr_ue != 0) {
/* XXX: should adjust the result */ /* XXX: should adjust the result */
/* Update the floating-point enabled exception summary */ /* Update the floating-point enabled exception summary */
env->fpscr |= 1 << FPSCR_FEX; env->fpscr |= FP_FEX;
/* We must update the target FPR before raising the exception */ /* We must update the target FPR before raising the exception */
cs->exception_index = POWERPC_EXCP_PROGRAM; cs->exception_index = POWERPC_EXCP_PROGRAM;
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX; env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
@ -370,13 +370,13 @@ static inline void float_inexact_excp(CPUPPCState *env)
{ {
CPUState *cs = env_cpu(env); CPUState *cs = env_cpu(env);
env->fpscr |= 1 << FPSCR_FI; env->fpscr |= FP_FI;
env->fpscr |= 1 << FPSCR_XX; env->fpscr |= FP_XX;
/* Update the floating-point exception summary */ /* Update the floating-point exception summary */
env->fpscr |= FP_FX; env->fpscr |= FP_FX;
if (fpscr_xe != 0) { if (fpscr_xe != 0) {
/* Update the floating-point enabled exception summary */ /* Update the floating-point enabled exception summary */
env->fpscr |= 1 << FPSCR_FEX; env->fpscr |= FP_FEX;
/* We must update the target FPR before raising the exception */ /* We must update the target FPR before raising the exception */
cs->exception_index = POWERPC_EXCP_PROGRAM; cs->exception_index = POWERPC_EXCP_PROGRAM;
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX; env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
@ -433,7 +433,7 @@ void helper_fpscr_clrbit(CPUPPCState *env, uint32_t bit)
case FPSCR_VXCVI: case FPSCR_VXCVI:
if (!fpscr_ix) { if (!fpscr_ix) {
/* Set VX bit to zero */ /* Set VX bit to zero */
env->fpscr &= ~(1 << FPSCR_VX); env->fpscr &= ~FP_VX;
} }
break; break;
case FPSCR_OX: case FPSCR_OX:
@ -447,7 +447,7 @@ void helper_fpscr_clrbit(CPUPPCState *env, uint32_t bit)
case FPSCR_XE: case FPSCR_XE:
if (!fpscr_eex) { if (!fpscr_eex) {
/* Set the FEX bit */ /* Set the FEX bit */
env->fpscr &= ~(1 << FPSCR_FEX); env->fpscr &= ~FP_FEX;
} }
break; break;
default: default:
@ -504,7 +504,7 @@ void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit)
case FPSCR_VXSOFT: case FPSCR_VXSOFT:
case FPSCR_VXSQRT: case FPSCR_VXSQRT:
case FPSCR_VXCVI: case FPSCR_VXCVI:
env->fpscr |= 1 << FPSCR_VX; env->fpscr |= FP_VX;
env->fpscr |= FP_FX; env->fpscr |= FP_FX;
if (fpscr_ve != 0) { if (fpscr_ve != 0) {
goto raise_ve; goto raise_ve;
@ -580,7 +580,7 @@ void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit)
break; break;
raise_excp: raise_excp:
/* Update the floating-point enabled exception summary */ /* Update the floating-point enabled exception summary */
env->fpscr |= 1 << FPSCR_FEX; env->fpscr |= FP_FEX;
/* We have to update Rc1 before raising the exception */ /* We have to update Rc1 before raising the exception */
cs->exception_index = POWERPC_EXCP_PROGRAM; cs->exception_index = POWERPC_EXCP_PROGRAM;
break; break;
@ -596,8 +596,8 @@ void helper_store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
prev = env->fpscr; prev = env->fpscr;
new = (target_ulong)arg; new = (target_ulong)arg;
new &= ~0x60000000LL; new &= ~(FP_FEX | FP_VX);
new |= prev & 0x60000000LL; new |= prev & (FP_FEX | FP_VX);
for (i = 0; i < sizeof(target_ulong) * 2; i++) { for (i = 0; i < sizeof(target_ulong) * 2; i++) {
if (mask & (1 << i)) { if (mask & (1 << i)) {
env->fpscr &= ~(0xFLL << (4 * i)); env->fpscr &= ~(0xFLL << (4 * i));
@ -606,17 +606,17 @@ void helper_store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
} }
/* Update VX and FEX */ /* Update VX and FEX */
if (fpscr_ix != 0) { if (fpscr_ix != 0) {
env->fpscr |= 1 << FPSCR_VX; env->fpscr |= FP_VX;
} else { } else {
env->fpscr &= ~(1 << FPSCR_VX); env->fpscr &= ~FP_VX;
} }
if ((fpscr_ex & fpscr_eex) != 0) { if ((fpscr_ex & fpscr_eex) != 0) {
env->fpscr |= 1 << FPSCR_FEX; env->fpscr |= FP_FEX;
cs->exception_index = POWERPC_EXCP_PROGRAM; cs->exception_index = POWERPC_EXCP_PROGRAM;
/* XXX: we should compute it properly */ /* XXX: we should compute it properly */
env->error_code = POWERPC_EXCP_FP; env->error_code = POWERPC_EXCP_FP;
} else { } else {
env->fpscr &= ~(1 << FPSCR_FEX); env->fpscr &= ~FP_FEX;
} }
fpscr_set_rounding_mode(env); fpscr_set_rounding_mode(env);
} }
@ -639,7 +639,7 @@ static void do_float_check_status(CPUPPCState *env, uintptr_t raddr)
if (status & float_flag_inexact) { if (status & float_flag_inexact) {
float_inexact_excp(env); float_inexact_excp(env);
} else { } else {
env->fpscr &= ~(1 << FPSCR_FI); /* clear the FPSCR[FI] bit */ env->fpscr &= ~FP_FI; /* clear the FPSCR[FI] bit */
} }
if (cs->exception_index == POWERPC_EXCP_PROGRAM && if (cs->exception_index == POWERPC_EXCP_PROGRAM &&
@ -1138,8 +1138,8 @@ void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
ret = 0x02UL; ret = 0x02UL;
} }
env->fpscr &= ~(0x0F << FPSCR_FPRF); env->fpscr &= ~FP_FPCC;
env->fpscr |= ret << FPSCR_FPRF; env->fpscr |= ret << FPSCR_FPCC;
env->crf[crfD] = ret; env->crf[crfD] = ret;
if (unlikely(ret == 0x01UL if (unlikely(ret == 0x01UL
&& (float64_is_signaling_nan(farg1.d, &env->fp_status) || && (float64_is_signaling_nan(farg1.d, &env->fp_status) ||
@ -1169,9 +1169,9 @@ void helper_fcmpo(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
ret = 0x02UL; ret = 0x02UL;
} }
env->fpscr &= ~(0x0F << FPSCR_FPRF); env->fpscr &= ~FP_FPCC;
env->fpscr |= ret << FPSCR_FPRF; env->fpscr |= ret << FPSCR_FPCC;
env->crf[crfD] = ret; env->crf[crfD] = (uint32_t) ret;
if (unlikely(ret == 0x01UL)) { if (unlikely(ret == 0x01UL)) {
float_invalid_op_vxvc(env, 1, GETPC()); float_invalid_op_vxvc(env, 1, GETPC());
if (float64_is_signaling_nan(farg1.d, &env->fp_status) || if (float64_is_signaling_nan(farg1.d, &env->fp_status) ||
@ -2431,8 +2431,8 @@ void helper_xscmpexpdp(CPUPPCState *env, uint32_t opcode,
} }
} }
env->fpscr &= ~(0x0F << FPSCR_FPRF); env->fpscr &= ~FP_FPCC;
env->fpscr |= cc << FPSCR_FPRF; env->fpscr |= cc << FPSCR_FPCC;
env->crf[BF(opcode)] = cc; env->crf[BF(opcode)] = cc;
do_float_check_status(env, GETPC()); do_float_check_status(env, GETPC());
@ -2460,8 +2460,8 @@ void helper_xscmpexpqp(CPUPPCState *env, uint32_t opcode,
} }
} }
env->fpscr &= ~(0x0F << FPSCR_FPRF); env->fpscr &= ~FP_FPCC;
env->fpscr |= cc << FPSCR_FPRF; env->fpscr |= cc << FPSCR_FPCC;
env->crf[BF(opcode)] = cc; env->crf[BF(opcode)] = cc;
do_float_check_status(env, GETPC()); do_float_check_status(env, GETPC());
@ -2505,8 +2505,8 @@ void helper_##op(CPUPPCState *env, uint32_t opcode, \
cc |= CRF_EQ; \ cc |= CRF_EQ; \
} \ } \
\ \
env->fpscr &= ~(0x0F << FPSCR_FPRF); \ env->fpscr &= ~FP_FPCC; \
env->fpscr |= cc << FPSCR_FPRF; \ env->fpscr |= cc << FPSCR_FPCC; \
env->crf[BF(opcode)] = cc; \ env->crf[BF(opcode)] = cc; \
\ \
do_float_check_status(env, GETPC()); \ do_float_check_status(env, GETPC()); \
@ -2553,8 +2553,8 @@ void helper_##op(CPUPPCState *env, uint32_t opcode, \
cc |= CRF_EQ; \ cc |= CRF_EQ; \
} \ } \
\ \
env->fpscr &= ~(0x0F << FPSCR_FPRF); \ env->fpscr &= ~FP_FPCC; \
env->fpscr |= cc << FPSCR_FPRF; \ env->fpscr |= cc << FPSCR_FPCC; \
env->crf[BF(opcode)] = cc; \ env->crf[BF(opcode)] = cc; \
\ \
do_float_check_status(env, GETPC()); \ do_float_check_status(env, GETPC()); \
@ -3242,8 +3242,8 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
\ \
if (scrf) { \ if (scrf) { \
cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT; \ cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT; \
env->fpscr &= ~(0x0F << FPSCR_FPRF); \ env->fpscr &= ~FP_FPCC; \
env->fpscr |= cc << FPSCR_FPRF; \ env->fpscr |= cc << FPSCR_FPCC; \
env->crf[BF(opcode)] = cc; \ env->crf[BF(opcode)] = cc; \
} else { \ } else { \
t.tfld = match ? fld_max : 0; \ t.tfld = match ? fld_max : 0; \
@ -3286,8 +3286,8 @@ void helper_xststdcsp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xb)
&env->fp_status), &env->fp_status); &env->fp_status), &env->fp_status);
cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT | not_sp << CRF_SO_BIT; cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT | not_sp << CRF_SO_BIT;
env->fpscr &= ~(0x0F << FPSCR_FPRF); env->fpscr &= ~FP_FPCC;
env->fpscr |= cc << FPSCR_FPRF; env->fpscr |= cc << FPSCR_FPCC;
env->crf[BF(opcode)] = cc; env->crf[BF(opcode)] = cc;
} }

View File

@ -686,7 +686,7 @@ DEF_HELPER_3(store_601_batu, void, env, i32, tl)
#endif #endif
#define dh_alias_fprp ptr #define dh_alias_fprp ptr
#define dh_ctype_fprp uint64_t * #define dh_ctype_fprp ppc_fprp_t *
#define dh_is_signed_fprp dh_is_signed_ptr #define dh_is_signed_fprp dh_is_signed_ptr
DEF_HELPER_4(dadd, void, env, fprp, fprp, fprp) DEF_HELPER_4(dadd, void, env, fprp, fprp, fprp)

View File

@ -2052,15 +2052,11 @@ void helper_vsubecuq(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
#define NATIONAL_PLUS 0x2B #define NATIONAL_PLUS 0x2B
#define NATIONAL_NEG 0x2D #define NATIONAL_NEG 0x2D
#if defined(HOST_WORDS_BIGENDIAN)
#define BCD_DIG_BYTE(n) (15 - ((n) / 2)) #define BCD_DIG_BYTE(n) (15 - ((n) / 2))
#else
#define BCD_DIG_BYTE(n) ((n) / 2)
#endif
static int bcd_get_sgn(ppc_avr_t *bcd) static int bcd_get_sgn(ppc_avr_t *bcd)
{ {
switch (bcd->u8[BCD_DIG_BYTE(0)] & 0xF) { switch (bcd->VsrB(BCD_DIG_BYTE(0)) & 0xF) {
case BCD_PLUS_PREF_1: case BCD_PLUS_PREF_1:
case BCD_PLUS_PREF_2: case BCD_PLUS_PREF_2:
case BCD_PLUS_ALT_1: case BCD_PLUS_ALT_1:
@ -2095,9 +2091,9 @@ static uint8_t bcd_get_digit(ppc_avr_t *bcd, int n, int *invalid)
{ {
uint8_t result; uint8_t result;
if (n & 1) { if (n & 1) {
result = bcd->u8[BCD_DIG_BYTE(n)] >> 4; result = bcd->VsrB(BCD_DIG_BYTE(n)) >> 4;
} else { } else {
result = bcd->u8[BCD_DIG_BYTE(n)] & 0xF; result = bcd->VsrB(BCD_DIG_BYTE(n)) & 0xF;
} }
if (unlikely(result > 9)) { if (unlikely(result > 9)) {
@ -2109,11 +2105,11 @@ static uint8_t bcd_get_digit(ppc_avr_t *bcd, int n, int *invalid)
static void bcd_put_digit(ppc_avr_t *bcd, uint8_t digit, int n) static void bcd_put_digit(ppc_avr_t *bcd, uint8_t digit, int n)
{ {
if (n & 1) { if (n & 1) {
bcd->u8[BCD_DIG_BYTE(n)] &= 0x0F; bcd->VsrB(BCD_DIG_BYTE(n)) &= 0x0F;
bcd->u8[BCD_DIG_BYTE(n)] |= (digit << 4); bcd->VsrB(BCD_DIG_BYTE(n)) |= (digit << 4);
} else { } else {
bcd->u8[BCD_DIG_BYTE(n)] &= 0xF0; bcd->VsrB(BCD_DIG_BYTE(n)) &= 0xF0;
bcd->u8[BCD_DIG_BYTE(n)] |= digit; bcd->VsrB(BCD_DIG_BYTE(n)) |= digit;
} }
} }
@ -2228,21 +2224,21 @@ uint32_t helper_bcdadd(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
if (!invalid) { if (!invalid) {
if (sgna == sgnb) { if (sgna == sgnb) {
result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgna, ps); result.VsrB(BCD_DIG_BYTE(0)) = bcd_preferred_sgn(sgna, ps);
bcd_add_mag(&result, a, b, &invalid, &overflow); bcd_add_mag(&result, a, b, &invalid, &overflow);
cr = bcd_cmp_zero(&result); cr = bcd_cmp_zero(&result);
} else { } else {
int magnitude = bcd_cmp_mag(a, b); int magnitude = bcd_cmp_mag(a, b);
if (magnitude > 0) { if (magnitude > 0) {
result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgna, ps); result.VsrB(BCD_DIG_BYTE(0)) = bcd_preferred_sgn(sgna, ps);
bcd_sub_mag(&result, a, b, &invalid, &overflow); bcd_sub_mag(&result, a, b, &invalid, &overflow);
cr = (sgna > 0) ? CRF_GT : CRF_LT; cr = (sgna > 0) ? CRF_GT : CRF_LT;
} else if (magnitude < 0) { } else if (magnitude < 0) {
result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(sgnb, ps); result.VsrB(BCD_DIG_BYTE(0)) = bcd_preferred_sgn(sgnb, ps);
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 { } else {
result.u8[BCD_DIG_BYTE(0)] = bcd_preferred_sgn(0, ps); result.VsrB(BCD_DIG_BYTE(0)) = bcd_preferred_sgn(0, ps);
cr = CRF_EQ; cr = CRF_EQ;
} }
} }
@ -2353,15 +2349,15 @@ uint32_t helper_bcdcfz(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
int zone_lead = ps ? 0xF : 0x3; int zone_lead = ps ? 0xF : 0x3;
int digit = 0; int digit = 0;
ppc_avr_t ret = { .u64 = { 0, 0 } }; ppc_avr_t ret = { .u64 = { 0, 0 } };
int sgnb = b->u8[BCD_DIG_BYTE(0)] >> 4; int sgnb = b->VsrB(BCD_DIG_BYTE(0)) >> 4;
if (unlikely((sgnb < 0xA) && ps)) { if (unlikely((sgnb < 0xA) && ps)) {
invalid = 1; invalid = 1;
} }
for (i = 0; i < 16; i++) { for (i = 0; i < 16; i++) {
zone_digit = i ? b->u8[BCD_DIG_BYTE(i * 2)] >> 4 : zone_lead; zone_digit = i ? b->VsrB(BCD_DIG_BYTE(i * 2)) >> 4 : zone_lead;
digit = b->u8[BCD_DIG_BYTE(i * 2)] & 0xF; digit = b->VsrB(BCD_DIG_BYTE(i * 2)) & 0xF;
if (unlikely(zone_digit != zone_lead || digit > 0x9)) { if (unlikely(zone_digit != zone_lead || digit > 0x9)) {
invalid = 1; invalid = 1;
break; break;
@ -2407,7 +2403,7 @@ uint32_t helper_bcdctz(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
break; break;
} }
ret.u8[BCD_DIG_BYTE(i * 2)] = zone_lead + digit; ret.VsrB(BCD_DIG_BYTE(i * 2)) = zone_lead + digit;
} }
if (ps) { if (ps) {
@ -2519,7 +2515,7 @@ uint32_t helper_bcdcpsgn(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
} }
*r = *a; *r = *a;
bcd_put_digit(r, b->u8[BCD_DIG_BYTE(0)] & 0xF, 0); bcd_put_digit(r, b->VsrB(BCD_DIG_BYTE(0)) & 0xF, 0);
for (i = 1; i < 32; i++) { for (i = 1; i < 32; i++) {
bcd_get_digit(a, i, &invalid); bcd_get_digit(a, i, &invalid);
@ -2549,11 +2545,7 @@ uint32_t helper_bcdsetsgn(ppc_avr_t *r, ppc_avr_t *b, uint32_t ps)
uint32_t helper_bcds(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps) uint32_t helper_bcds(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
{ {
int cr; int cr;
#if defined(HOST_WORDS_BIGENDIAN) int i = a->VsrSB(7);
int i = a->s8[7];
#else
int i = a->s8[8];
#endif
bool ox_flag = false; bool ox_flag = false;
int sgnb = bcd_get_sgn(b); int sgnb = bcd_get_sgn(b);
ppc_avr_t ret = *b; ppc_avr_t ret = *b;
@ -2602,11 +2594,7 @@ uint32_t helper_bcdus(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
} }
} }
#if defined(HOST_WORDS_BIGENDIAN) i = a->VsrSB(7);
i = a->s8[7];
#else
i = a->s8[8];
#endif
if (i >= 32) { if (i >= 32) {
ox_flag = true; ox_flag = true;
ret.VsrD(1) = ret.VsrD(0) = 0; ret.VsrD(1) = ret.VsrD(0) = 0;
@ -2637,13 +2625,11 @@ uint32_t helper_bcdsr(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
ppc_avr_t ret = *b; ppc_avr_t ret = *b;
ret.VsrD(1) &= ~0xf; ret.VsrD(1) &= ~0xf;
#if defined(HOST_WORDS_BIGENDIAN) int i = a->VsrSB(7);
int i = a->s8[7]; ppc_avr_t bcd_one;
ppc_avr_t bcd_one = { .u64 = { 0, 0x10 } };
#else bcd_one.VsrD(0) = 0;
int i = a->s8[8]; bcd_one.VsrD(1) = 0x10;
ppc_avr_t bcd_one = { .u64 = { 0x10, 0 } };
#endif
if (bcd_is_valid(b) == false) { if (bcd_is_valid(b) == false) {
return CRF_SO; return CRF_SO;
@ -2679,11 +2665,7 @@ uint32_t helper_bcdtrunc(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
{ {
uint64_t mask; uint64_t mask;
uint32_t ox_flag = 0; uint32_t ox_flag = 0;
#if defined(HOST_WORDS_BIGENDIAN) int i = a->VsrSH(3) + 1;
int i = a->s16[3] + 1;
#else
int i = a->s16[4] + 1;
#endif
ppc_avr_t ret = *b; ppc_avr_t ret = *b;
if (bcd_is_valid(b) == false) { if (bcd_is_valid(b) == false) {
@ -2728,11 +2710,7 @@ uint32_t helper_bcdutrunc(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t ps)
} }
} }
#if defined(HOST_WORDS_BIGENDIAN) i = a->VsrSH(3);
i = a->s16[3];
#else
i = a->s16[4];
#endif
if (i > 16 && i < 33) { if (i > 16 && i < 33) {
mask = (uint64_t)-1 >> (128 - i * 4); mask = (uint64_t)-1 >> (128 - i * 4);
if (ret.VsrD(0) & ~mask) { if (ret.VsrD(0) & ~mask) {

View File

@ -157,6 +157,9 @@ EXTRACT_HELPER(FPL, 25, 1);
EXTRACT_HELPER(FPFLM, 17, 8); EXTRACT_HELPER(FPFLM, 17, 8);
EXTRACT_HELPER(FPW, 16, 1); EXTRACT_HELPER(FPW, 16, 1);
/* mffscrni */
EXTRACT_HELPER(RM, 11, 2);
/* addpcis */ /* addpcis */
EXTRACT_HELPER_SPLIT_3(DX, 10, 6, 6, 5, 16, 1, 1, 0, 0) EXTRACT_HELPER_SPLIT_3(DX, 10, 6, 6, 5, 16, 1, 1, 0, 0)
#if defined(TARGET_PPC64) #if defined(TARGET_PPC64)

View File

@ -993,6 +993,10 @@ int kvm_arch_put_registers(CPUState *cs, int level)
} }
kvm_set_one_reg(cs, KVM_REG_PPC_TB_OFFSET, &env->tb_env->tb_offset); kvm_set_one_reg(cs, KVM_REG_PPC_TB_OFFSET, &env->tb_env->tb_offset);
if (level > KVM_PUT_RUNTIME_STATE) {
kvm_put_one_spr(cs, KVM_REG_PPC_DPDES, SPR_DPDES);
}
#endif /* TARGET_PPC64 */ #endif /* TARGET_PPC64 */
} }
@ -1297,6 +1301,7 @@ int kvm_arch_get_registers(CPUState *cs)
} }
kvm_get_one_reg(cs, KVM_REG_PPC_TB_OFFSET, &env->tb_env->tb_offset); kvm_get_one_reg(cs, KVM_REG_PPC_TB_OFFSET, &env->tb_env->tb_offset);
kvm_get_one_spr(cs, KVM_REG_PPC_DPDES, SPR_DPDES);
#endif #endif
} }

View File

@ -634,11 +634,108 @@ static void gen_mffsl(DisasContext *ctx)
gen_reset_fpstatus(); gen_reset_fpstatus();
tcg_gen_extu_tl_i64(t0, cpu_fpscr); tcg_gen_extu_tl_i64(t0, cpu_fpscr);
/* Mask everything except mode, status, and enables. */ /* Mask everything except mode, status, and enables. */
tcg_gen_andi_i64(t0, t0, FP_MODE | FP_STATUS | FP_ENABLES); tcg_gen_andi_i64(t0, t0, FP_DRN | FP_STATUS | FP_ENABLES | FP_RN);
set_fpr(rD(ctx->opcode), t0); set_fpr(rD(ctx->opcode), t0);
tcg_temp_free_i64(t0); tcg_temp_free_i64(t0);
} }
/* mffsce */
static void gen_mffsce(DisasContext *ctx)
{
TCGv_i64 t0;
TCGv_i32 mask;
if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) {
return gen_mffs(ctx);
}
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
t0 = tcg_temp_new_i64();
gen_reset_fpstatus();
tcg_gen_extu_tl_i64(t0, cpu_fpscr);
set_fpr(rD(ctx->opcode), t0);
/* Clear exception enable bits in the FPSCR. */
tcg_gen_andi_i64(t0, t0, ~FP_ENABLES);
mask = tcg_const_i32(0x0003);
gen_helper_store_fpscr(cpu_env, t0, mask);
tcg_temp_free_i32(mask);
tcg_temp_free_i64(t0);
}
static void gen_helper_mffscrn(DisasContext *ctx, TCGv_i64 t1)
{
TCGv_i64 t0 = tcg_temp_new_i64();
TCGv_i32 mask = tcg_const_i32(0x0001);
gen_reset_fpstatus();
tcg_gen_extu_tl_i64(t0, cpu_fpscr);
tcg_gen_andi_i64(t0, t0, FP_DRN | FP_ENABLES | FP_RN);
set_fpr(rD(ctx->opcode), t0);
/* Mask FPSCR value to clear RN. */
tcg_gen_andi_i64(t0, t0, ~FP_RN);
/* Merge RN into FPSCR value. */
tcg_gen_or_i64(t0, t0, t1);
gen_helper_store_fpscr(cpu_env, t0, mask);
tcg_temp_free_i32(mask);
tcg_temp_free_i64(t0);
}
/* mffscrn */
static void gen_mffscrn(DisasContext *ctx)
{
TCGv_i64 t1;
if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) {
return gen_mffs(ctx);
}
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
t1 = tcg_temp_new_i64();
get_fpr(t1, rB(ctx->opcode));
/* Mask FRB to get just RN. */
tcg_gen_andi_i64(t1, t1, FP_RN);
gen_helper_mffscrn(ctx, t1);
tcg_temp_free_i64(t1);
}
/* mffscrni */
static void gen_mffscrni(DisasContext *ctx)
{
TCGv_i64 t1;
if (unlikely(!(ctx->insns_flags2 & PPC2_ISA300))) {
return gen_mffs(ctx);
}
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
t1 = tcg_const_i64((uint64_t)RM(ctx->opcode));
gen_helper_mffscrn(ctx, t1);
tcg_temp_free_i64(t1);
}
/* mtfsb0 */ /* mtfsb0 */
static void gen_mtfsb0(DisasContext *ctx) static void gen_mtfsb0(DisasContext *ctx)
{ {

View File

@ -105,8 +105,14 @@ GEN_HANDLER_E(fmrgew, 0x3F, 0x06, 0x1E, 0x00000001, PPC_NONE, PPC2_VSX207),
GEN_HANDLER_E(fmrgow, 0x3F, 0x06, 0x1A, 0x00000001, PPC_NONE, PPC2_VSX207), GEN_HANDLER_E(fmrgow, 0x3F, 0x06, 0x1A, 0x00000001, PPC_NONE, PPC2_VSX207),
GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT), GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT),
GEN_HANDLER_E_2(mffs, 0x3F, 0x07, 0x12, 0x00, 0x00000000, PPC_FLOAT, PPC_NONE), GEN_HANDLER_E_2(mffs, 0x3F, 0x07, 0x12, 0x00, 0x00000000, PPC_FLOAT, PPC_NONE),
GEN_HANDLER_E_2(mffsce, 0x3F, 0x07, 0x12, 0x01, 0x00000000, PPC_FLOAT,
PPC2_ISA300),
GEN_HANDLER_E_2(mffsl, 0x3F, 0x07, 0x12, 0x18, 0x00000000, PPC_FLOAT, GEN_HANDLER_E_2(mffsl, 0x3F, 0x07, 0x12, 0x18, 0x00000000, PPC_FLOAT,
PPC2_ISA300), PPC2_ISA300),
GEN_HANDLER_E_2(mffscrn, 0x3F, 0x07, 0x12, 0x16, 0x00000000, PPC_FLOAT,
PPC_NONE),
GEN_HANDLER_E_2(mffscrni, 0x3F, 0x07, 0x12, 0x17, 0x00000000, PPC_FLOAT,
PPC_NONE),
GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT), GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT),
GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT), GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT),
GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x00000000, PPC_FLOAT), GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x00000000, PPC_FLOAT),

View File

@ -8200,11 +8200,10 @@ static void gen_spr_power8_dpdes(CPUPPCState *env)
{ {
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
/* Directed Privileged Door-bell Exception State, used for IPI */ /* Directed Privileged Door-bell Exception State, used for IPI */
spr_register_kvm_hv(env, SPR_DPDES, "DPDES", spr_register(env, SPR_DPDES, "DPDES",
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS, &spr_read_generic, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic, 0x00000000);
KVM_REG_PPC_DPDES, 0x00000000);
#endif #endif
} }