mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/dgibson/tags/ppc-for-2.8-20160907' into staging
ppc patch queue for 2016-Sep-7
This is my first pull request for the newly opened qemu-2.8 tree. It
contains a heap of things that were too late for 2.7 and have been
queued for a while. In particular:
* A number of preliminary patches for the powernv machine type
* A substantial cleanup of exception handling which will be
necessary to support running a TCG with hypervisor
facilities
* A start on support for POWER9
* Some TCG implementations for new POWER9 instructions
* Some TCG and related cleanups in preparation for POWER9
* Some assorted TCG optimizations
* An implementation of the H_CHANGE_LOGICAL_LAN_MAC hypercall
which allows the MAC address to be changed on the PAPR virtual
NIC.
* Add some extra test cases for several machines (this isn't
strictly in the ppc code, but is most value to ppc)
NOTE: This pull request supersedes ppc-for-2.8-20160906, which had
some problems. Changes:
* Dropped BenH's lmw/stmw speedups, which break for
qemu-system-ppc64 on BE hosts
* A small fix to Thomas' serial output test to avoid a warning on
the isapc machine type.
* Some trivial checkpatch fixes
Note that some of the patches in this series still have large numbers
of checkpatch warnings. This is because they're moving existing code
that predates most of the checkpatch style conventions.
# gpg: Signature made Wed 07 Sep 2016 07:09:27 BST
# gpg: using RSA key 0x6C38CACA20D9B392
# gpg: Good signature from "David Gibson <david@gibson.dropbear.id.au>"
# gpg: aka "David Gibson (Red Hat) <dgibson@redhat.com>"
# gpg: aka "David Gibson (ozlabs.org) <dgibson@ozlabs.org>"
# gpg: aka "David Gibson (kernel.org) <dwg@kernel.org>"
# Primary key fingerprint: 75F4 6586 AE61 A66C C44E 87DC 6C38 CACA 20D9 B392
* remotes/dgibson/tags/ppc-for-2.8-20160907: (64 commits)
tests: Check serial output of firmware boot of some machines
tests: Resort check-qtest entries in Makefile.include
spapr: implement H_CHANGE_LOGICAL_LAN_MAC h_call
ppc: Improve a few more helper flags
ppc: Improve the exception helpers flags
ppc: Improve flags for helpers loading/writing the time facilities
ppc: Don't generate dead code on unconditional branches
ppc: Stop dumping state on all exceptions in linux-user
ppc: Fix catching some segfaults in user mode
ppc: Fix macio ESCC legacy mapping
hw/ppc: add a ppc_create_page_sizes_prop() helper routine
hw/ppc: use error_report instead of fprintf
ppc: Rename #include'd .c files to .inc.c
target-ppc: add extswsli[.] instruction
target-ppc: add vsrv instruction
target-ppc: add vslv instruction
target-ppc: add vcmpnez[b,h,w][.] instructions
target-ppc: add vabsdu[b,h,w] instructions
target-ppc: add dtstsfi[q] instructions
target-ppc: implement branch-less divd[o][.]
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
+8
-12
@@ -329,6 +329,7 @@ static void xics_kvm_cpu_setup(XICSState *xics, PowerPCCPU *cpu)
|
||||
CPUState *cs;
|
||||
ICPState *ss;
|
||||
KVMXICSState *xicskvm = XICS_SPAPR_KVM(xics);
|
||||
int ret;
|
||||
|
||||
cs = CPU(cpu);
|
||||
ss = &xics->ss[cs->cpu_index];
|
||||
@@ -347,19 +348,14 @@ static void xics_kvm_cpu_setup(XICSState *xics, PowerPCCPU *cpu)
|
||||
return;
|
||||
}
|
||||
|
||||
if (xicskvm->kernel_xics_fd != -1) {
|
||||
int ret;
|
||||
|
||||
ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0,
|
||||
xicskvm->kernel_xics_fd,
|
||||
kvm_arch_vcpu_id(cs));
|
||||
if (ret < 0) {
|
||||
error_report("Unable to connect CPU%ld to kernel XICS: %s",
|
||||
kvm_arch_vcpu_id(cs), strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
ss->cap_irq_xics_enabled = true;
|
||||
ret = kvm_vcpu_enable_cap(cs, KVM_CAP_IRQ_XICS, 0, xicskvm->kernel_xics_fd,
|
||||
kvm_arch_vcpu_id(cs));
|
||||
if (ret < 0) {
|
||||
error_report("Unable to connect CPU%ld to kernel XICS: %s",
|
||||
kvm_arch_vcpu_id(cs), strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
ss->cap_irq_xics_enabled = true;
|
||||
}
|
||||
|
||||
static void xics_kvm_set_nr_irqs(XICSState *xics, uint32_t nr_irqs,
|
||||
|
||||
+10
-16
@@ -89,22 +89,16 @@ static void macio_escc_legacy_setup(MacIOState *macio_state)
|
||||
MemoryRegion *bar = &macio_state->bar;
|
||||
int i;
|
||||
static const int maps[] = {
|
||||
0x00, 0x00,
|
||||
0x02, 0x20,
|
||||
0x04, 0x10,
|
||||
0x06, 0x30,
|
||||
0x08, 0x40,
|
||||
0x0A, 0x50,
|
||||
0x60, 0x60,
|
||||
0x70, 0x70,
|
||||
0x80, 0x70,
|
||||
0x90, 0x80,
|
||||
0xA0, 0x90,
|
||||
0xB0, 0xA0,
|
||||
0xC0, 0xB0,
|
||||
0xD0, 0xC0,
|
||||
0xE0, 0xD0,
|
||||
0xF0, 0xE0,
|
||||
0x00, 0x00, /* Command B */
|
||||
0x02, 0x20, /* Command A */
|
||||
0x04, 0x10, /* Data B */
|
||||
0x06, 0x30, /* Data A */
|
||||
0x08, 0x40, /* Enhancement B */
|
||||
0x0A, 0x50, /* Enhancement A */
|
||||
0x80, 0x80, /* Recovery count */
|
||||
0x90, 0x90, /* Start A */
|
||||
0xa0, 0xa0, /* Start B */
|
||||
0xb0, 0xb0, /* Detect AB */
|
||||
};
|
||||
|
||||
memory_region_init(escc_legacy, OBJECT(macio_state), "escc-legacy", 256);
|
||||
|
||||
@@ -106,6 +106,7 @@ typedef struct VIOsPAPRVLANDevice {
|
||||
VIOsPAPRDevice sdev;
|
||||
NICConf nicconf;
|
||||
NICState *nic;
|
||||
MACAddr perm_mac;
|
||||
bool isopen;
|
||||
hwaddr buf_list;
|
||||
uint32_t add_buf_ptr, use_buf_ptr, rx_bufs;
|
||||
@@ -316,6 +317,10 @@ static void spapr_vlan_reset(VIOsPAPRDevice *sdev)
|
||||
spapr_vlan_reset_rx_pool(dev->rx_pool[i]);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&dev->nicconf.macaddr.a, &dev->perm_mac.a,
|
||||
sizeof(dev->nicconf.macaddr.a));
|
||||
qemu_format_nic_info_str(qemu_get_queue(dev->nic), dev->nicconf.macaddr.a);
|
||||
}
|
||||
|
||||
static void spapr_vlan_realize(VIOsPAPRDevice *sdev, Error **errp)
|
||||
@@ -324,6 +329,8 @@ static void spapr_vlan_realize(VIOsPAPRDevice *sdev, Error **errp)
|
||||
|
||||
qemu_macaddr_default_if_unset(&dev->nicconf.macaddr);
|
||||
|
||||
memcpy(&dev->perm_mac.a, &dev->nicconf.macaddr.a, sizeof(dev->perm_mac.a));
|
||||
|
||||
dev->nic = qemu_new_nic(&net_spapr_vlan_info, &dev->nicconf,
|
||||
object_get_typename(OBJECT(sdev)), sdev->qdev.id, dev);
|
||||
qemu_format_nic_info_str(qemu_get_queue(dev->nic), dev->nicconf.macaddr.a);
|
||||
@@ -756,6 +763,27 @@ static target_ulong h_multicast_ctrl(PowerPCCPU *cpu, sPAPRMachineState *spapr,
|
||||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static target_ulong h_change_logical_lan_mac(PowerPCCPU *cpu,
|
||||
sPAPRMachineState *spapr,
|
||||
target_ulong opcode,
|
||||
target_ulong *args)
|
||||
{
|
||||
target_ulong reg = args[0];
|
||||
target_ulong macaddr = args[1];
|
||||
VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
|
||||
VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ETH_ALEN; i++) {
|
||||
dev->nicconf.macaddr.a[ETH_ALEN - i - 1] = macaddr & 0xff;
|
||||
macaddr >>= 8;
|
||||
}
|
||||
|
||||
qemu_format_nic_info_str(qemu_get_queue(dev->nic), dev->nicconf.macaddr.a);
|
||||
|
||||
return H_SUCCESS;
|
||||
}
|
||||
|
||||
static Property spapr_vlan_properties[] = {
|
||||
DEFINE_SPAPR_PROPERTIES(VIOsPAPRVLANDevice, sdev),
|
||||
DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf),
|
||||
@@ -854,6 +882,8 @@ static void spapr_vlan_register_types(void)
|
||||
spapr_register_hypercall(H_ADD_LOGICAL_LAN_BUFFER,
|
||||
h_add_logical_lan_buffer);
|
||||
spapr_register_hypercall(H_MULTICAST_CTRL, h_multicast_ctrl);
|
||||
spapr_register_hypercall(H_CHANGE_LOGICAL_LAN_MAC,
|
||||
h_change_logical_lan_mac);
|
||||
type_register_static(&spapr_vlan_info);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# shared objects
|
||||
obj-y += ppc.o ppc_booke.o
|
||||
obj-y += ppc.o ppc_booke.o fdt.o
|
||||
# IBM pSeries (sPAPR)
|
||||
obj-$(CONFIG_PSERIES) += spapr.o spapr_vio.o spapr_events.o
|
||||
obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* QEMU PowerPC helper routines for the device tree.
|
||||
*
|
||||
* Copyright (C) 2016 IBM Corp.
|
||||
*
|
||||
* This code is licensed under the GPL version 2 or later. See the
|
||||
* COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "target-ppc/cpu.h"
|
||||
|
||||
#include "hw/ppc/fdt.h"
|
||||
|
||||
#if defined(TARGET_PPC64)
|
||||
size_t ppc_create_page_sizes_prop(CPUPPCState *env, uint32_t *prop,
|
||||
size_t maxsize)
|
||||
{
|
||||
size_t maxcells = maxsize / sizeof(uint32_t);
|
||||
int i, j, count;
|
||||
uint32_t *p = prop;
|
||||
|
||||
for (i = 0; i < PPC_PAGE_SIZES_MAX_SZ; i++) {
|
||||
struct ppc_one_seg_page_size *sps = &env->sps.sps[i];
|
||||
|
||||
if (!sps->page_shift) {
|
||||
break;
|
||||
}
|
||||
for (count = 0; count < PPC_PAGE_SIZES_MAX_SZ; count++) {
|
||||
if (sps->enc[count].page_shift == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((p - prop) >= (maxcells - 3 - count * 2)) {
|
||||
break;
|
||||
}
|
||||
*(p++) = cpu_to_be32(sps->page_shift);
|
||||
*(p++) = cpu_to_be32(sps->slb_enc);
|
||||
*(p++) = cpu_to_be32(count);
|
||||
for (j = 0; j < count; j++) {
|
||||
*(p++) = cpu_to_be32(sps->enc[j].page_shift);
|
||||
*(p++) = cpu_to_be32(sps->enc[j].pte_enc);
|
||||
}
|
||||
}
|
||||
|
||||
return (p - prop) * sizeof(uint32_t);
|
||||
}
|
||||
#endif
|
||||
+8
-51
@@ -47,6 +47,7 @@
|
||||
#include "hw/ppc/ppc.h"
|
||||
#include "hw/loader.h"
|
||||
|
||||
#include "hw/ppc/fdt.h"
|
||||
#include "hw/ppc/spapr.h"
|
||||
#include "hw/ppc/spapr_vio.h"
|
||||
#include "hw/pci-host/spapr.h"
|
||||
@@ -249,40 +250,6 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPRMachineState *spapr)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static size_t create_page_sizes_prop(CPUPPCState *env, uint32_t *prop,
|
||||
size_t maxsize)
|
||||
{
|
||||
size_t maxcells = maxsize / sizeof(uint32_t);
|
||||
int i, j, count;
|
||||
uint32_t *p = prop;
|
||||
|
||||
for (i = 0; i < PPC_PAGE_SIZES_MAX_SZ; i++) {
|
||||
struct ppc_one_seg_page_size *sps = &env->sps.sps[i];
|
||||
|
||||
if (!sps->page_shift) {
|
||||
break;
|
||||
}
|
||||
for (count = 0; count < PPC_PAGE_SIZES_MAX_SZ; count++) {
|
||||
if (sps->enc[count].page_shift == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((p - prop) >= (maxcells - 3 - count * 2)) {
|
||||
break;
|
||||
}
|
||||
*(p++) = cpu_to_be32(sps->page_shift);
|
||||
*(p++) = cpu_to_be32(sps->slb_enc);
|
||||
*(p++) = cpu_to_be32(count);
|
||||
for (j = 0; j < count; j++) {
|
||||
*(p++) = cpu_to_be32(sps->enc[j].page_shift);
|
||||
*(p++) = cpu_to_be32(sps->enc[j].pte_enc);
|
||||
}
|
||||
}
|
||||
|
||||
return (p - prop) * sizeof(uint32_t);
|
||||
}
|
||||
|
||||
static hwaddr spapr_node0_size(void)
|
||||
{
|
||||
MachineState *machine = MACHINE(qdev_get_machine());
|
||||
@@ -299,16 +266,6 @@ static hwaddr spapr_node0_size(void)
|
||||
return machine->ram_size;
|
||||
}
|
||||
|
||||
#define _FDT(exp) \
|
||||
do { \
|
||||
int ret = (exp); \
|
||||
if (ret < 0) { \
|
||||
fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \
|
||||
#exp, fdt_strerror(ret)); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static void add_str(GString *s, const gchar *s1)
|
||||
{
|
||||
g_string_append_len(s, s1, strlen(s1) + 1);
|
||||
@@ -656,13 +613,13 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "d-cache-size",
|
||||
pcc->l1_dcache_size)));
|
||||
} else {
|
||||
fprintf(stderr, "Warning: Unknown L1 dcache size for cpu\n");
|
||||
error_report("Warning: Unknown L1 dcache size for cpu");
|
||||
}
|
||||
if (pcc->l1_icache_size) {
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "i-cache-size",
|
||||
pcc->l1_icache_size)));
|
||||
} else {
|
||||
fprintf(stderr, "Warning: Unknown L1 icache size for cpu\n");
|
||||
error_report("Warning: Unknown L1 icache size for cpu");
|
||||
}
|
||||
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "timebase-frequency", tbfreq)));
|
||||
@@ -698,7 +655,7 @@ static void spapr_populate_cpu_dt(CPUState *cs, void *fdt, int offset,
|
||||
_FDT((fdt_setprop_cell(fdt, offset, "ibm,dfp", 1)));
|
||||
}
|
||||
|
||||
page_sizes_prop_size = create_page_sizes_prop(env, page_sizes_prop,
|
||||
page_sizes_prop_size = ppc_create_page_sizes_prop(env, page_sizes_prop,
|
||||
sizeof(page_sizes_prop));
|
||||
if (page_sizes_prop_size) {
|
||||
_FDT((fdt_setprop(fdt, offset, "ibm,segment-page-sizes",
|
||||
@@ -954,20 +911,20 @@ static void spapr_finalize_fdt(sPAPRMachineState *spapr,
|
||||
|
||||
ret = spapr_populate_memory(spapr, fdt);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "couldn't setup memory nodes in fdt\n");
|
||||
error_report("couldn't setup memory nodes in fdt");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = spapr_populate_vdevice(spapr->vio_bus, fdt);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "couldn't setup vio devices in fdt\n");
|
||||
error_report("couldn't setup vio devices in fdt");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (object_resolve_path_type("", TYPE_SPAPR_RNG, NULL)) {
|
||||
ret = spapr_rng_populate_dt(fdt);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "could not set up rng device in the fdt\n");
|
||||
error_report("could not set up rng device in the fdt");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
@@ -983,7 +940,7 @@ static void spapr_finalize_fdt(sPAPRMachineState *spapr,
|
||||
/* RTAS */
|
||||
ret = spapr_rtas_device_tree_setup(fdt, rtas_addr, rtas_size);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Couldn't set up RTAS device tree properties\n");
|
||||
error_report("Couldn't set up RTAS device tree properties");
|
||||
}
|
||||
|
||||
/* cpus */
|
||||
|
||||
+4
-4
@@ -816,7 +816,7 @@ int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner,
|
||||
drc_indexes->data,
|
||||
drc_indexes->len * sizeof(uint32_t));
|
||||
if (ret) {
|
||||
fprintf(stderr, "Couldn't create ibm,drc-indexes property\n");
|
||||
error_report("Couldn't create ibm,drc-indexes property");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -824,21 +824,21 @@ int spapr_drc_populate_dt(void *fdt, int fdt_offset, Object *owner,
|
||||
drc_power_domains->data,
|
||||
drc_power_domains->len * sizeof(uint32_t));
|
||||
if (ret) {
|
||||
fprintf(stderr, "Couldn't finalize ibm,drc-power-domains property\n");
|
||||
error_report("Couldn't finalize ibm,drc-power-domains property");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = fdt_setprop(fdt, fdt_offset, "ibm,drc-names",
|
||||
drc_names->str, drc_names->len);
|
||||
if (ret) {
|
||||
fprintf(stderr, "Couldn't finalize ibm,drc-names property\n");
|
||||
error_report("Couldn't finalize ibm,drc-names property");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = fdt_setprop(fdt, fdt_offset, "ibm,drc-types",
|
||||
drc_types->str, drc_types->len);
|
||||
if (ret) {
|
||||
fprintf(stderr, "Couldn't finalize ibm,drc-types property\n");
|
||||
error_report("Couldn't finalize ibm,drc-types property");
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
+1
-10
@@ -32,6 +32,7 @@
|
||||
#include "hw/qdev.h"
|
||||
#include "sysemu/device_tree.h"
|
||||
|
||||
#include "hw/ppc/fdt.h"
|
||||
#include "hw/ppc/spapr.h"
|
||||
#include "hw/ppc/spapr_vio.h"
|
||||
#include "hw/pci/pci.h"
|
||||
@@ -210,16 +211,6 @@ struct hp_log_full {
|
||||
#define EVENT_MASK_HOTPLUG 0x10000000
|
||||
#define EVENT_MASK_IO 0x08000000
|
||||
|
||||
#define _FDT(exp) \
|
||||
do { \
|
||||
int ret = (exp); \
|
||||
if (ret < 0) { \
|
||||
fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \
|
||||
#exp, fdt_strerror(ret)); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
void spapr_events_fdt_skel(void *fdt, uint32_t check_exception_irq)
|
||||
{
|
||||
uint32_t irq_ranges[] = {cpu_to_be32(check_exception_irq), cpu_to_be32(1)};
|
||||
|
||||
@@ -310,8 +310,8 @@ sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn)
|
||||
char tmp[32];
|
||||
|
||||
if (spapr_tce_find_by_liobn(liobn)) {
|
||||
fprintf(stderr, "Attempted to create TCE table with duplicate"
|
||||
" LIOBN 0x%x\n", liobn);
|
||||
error_report("Attempted to create TCE table with duplicate"
|
||||
" LIOBN 0x%x", liobn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
+7
-6
@@ -27,6 +27,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "cpu.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/char.h"
|
||||
#include "hw/qdev.h"
|
||||
@@ -716,7 +717,7 @@ int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr,
|
||||
|
||||
ret = fdt_add_mem_rsv(fdt, rtas_addr, rtas_size);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Couldn't add RTAS reserve entry: %s\n",
|
||||
error_report("Couldn't add RTAS reserve entry: %s",
|
||||
fdt_strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
@@ -724,7 +725,7 @@ int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr,
|
||||
ret = qemu_fdt_setprop_cell(fdt, "/rtas", "linux,rtas-base",
|
||||
rtas_addr);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Couldn't add linux,rtas-base property: %s\n",
|
||||
error_report("Couldn't add linux,rtas-base property: %s",
|
||||
fdt_strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
@@ -732,7 +733,7 @@ int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr,
|
||||
ret = qemu_fdt_setprop_cell(fdt, "/rtas", "linux,rtas-entry",
|
||||
rtas_addr);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Couldn't add linux,rtas-entry property: %s\n",
|
||||
error_report("Couldn't add linux,rtas-entry property: %s",
|
||||
fdt_strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
@@ -740,7 +741,7 @@ int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr,
|
||||
ret = qemu_fdt_setprop_cell(fdt, "/rtas", "rtas-size",
|
||||
rtas_size);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Couldn't add rtas-size property: %s\n",
|
||||
error_report("Couldn't add rtas-size property: %s",
|
||||
fdt_strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
@@ -755,7 +756,7 @@ int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr,
|
||||
ret = qemu_fdt_setprop_cell(fdt, "/rtas", call->name,
|
||||
i + RTAS_TOKEN_BASE);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Couldn't add rtas token for %s: %s\n",
|
||||
error_report("Couldn't add rtas token for %s: %s",
|
||||
call->name, fdt_strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
@@ -770,7 +771,7 @@ int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr,
|
||||
ret = qemu_fdt_setprop(fdt, "/rtas", "ibm,lrdr-capacity", lrdr_capacity,
|
||||
sizeof(lrdr_capacity));
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "Couldn't add ibm,lrdr-capacity rtas property\n");
|
||||
error_report("Couldn't add ibm,lrdr-capacity rtas property");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/hw.h"
|
||||
#include "qemu/log.h"
|
||||
@@ -276,7 +277,7 @@ int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq)
|
||||
uint8_t byte;
|
||||
|
||||
if (!dev->crq.qsize) {
|
||||
fprintf(stderr, "spapr_vio_send_creq on uninitialized queue\n");
|
||||
error_report("spapr_vio_send_creq on uninitialized queue");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* QEMU PowerPC helper routines for the device tree.
|
||||
*
|
||||
* Copyright (C) 2016 IBM Corp.
|
||||
*
|
||||
* This code is licensed under the GPL version 2 or later. See the
|
||||
* COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#ifndef PPC_FDT_H
|
||||
#define PPC_FDT_H
|
||||
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
typedef struct CPUPPCState CPUPPCState;
|
||||
|
||||
#define _FDT(exp) \
|
||||
do { \
|
||||
int ret = (exp); \
|
||||
if (ret < 0) { \
|
||||
error_report("error creating device tree: %s: %s", \
|
||||
#exp, fdt_strerror(ret)); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
size_t ppc_create_page_sizes_prop(CPUPPCState *env, uint32_t *prop,
|
||||
size_t maxsize);
|
||||
|
||||
#endif /* PPC_FDT_H */
|
||||
+7
-18
@@ -1651,11 +1651,10 @@ void cpu_loop(CPUPPCState *env)
|
||||
"Aborting\n");
|
||||
break;
|
||||
case POWERPC_EXCP_DSI: /* Data storage exception */
|
||||
EXCP_DUMP(env, "Invalid data memory access: 0x" TARGET_FMT_lx "\n",
|
||||
env->spr[SPR_DAR]);
|
||||
/* XXX: check this. Seems bugged */
|
||||
switch (env->error_code & 0xFF000000) {
|
||||
case 0x40000000:
|
||||
case 0x42000000:
|
||||
info.si_signo = TARGET_SIGSEGV;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_SEGV_MAPERR;
|
||||
@@ -1683,8 +1682,6 @@ void cpu_loop(CPUPPCState *env)
|
||||
queue_signal(env, info.si_signo, &info);
|
||||
break;
|
||||
case POWERPC_EXCP_ISI: /* Instruction storage exception */
|
||||
EXCP_DUMP(env, "Invalid instruction fetch: 0x\n" TARGET_FMT_lx
|
||||
"\n", env->spr[SPR_SRR0]);
|
||||
/* XXX: check this */
|
||||
switch (env->error_code & 0xFF000000) {
|
||||
case 0x40000000:
|
||||
@@ -1715,7 +1712,6 @@ void cpu_loop(CPUPPCState *env)
|
||||
"Aborting\n");
|
||||
break;
|
||||
case POWERPC_EXCP_ALIGN: /* Alignment exception */
|
||||
EXCP_DUMP(env, "Unaligned memory access\n");
|
||||
/* XXX: check this */
|
||||
info.si_signo = TARGET_SIGBUS;
|
||||
info.si_errno = 0;
|
||||
@@ -1728,7 +1724,6 @@ void cpu_loop(CPUPPCState *env)
|
||||
/* XXX: check this */
|
||||
switch (env->error_code & ~0xF) {
|
||||
case POWERPC_EXCP_FP:
|
||||
EXCP_DUMP(env, "Floating point program exception\n");
|
||||
info.si_signo = TARGET_SIGFPE;
|
||||
info.si_errno = 0;
|
||||
switch (env->error_code & 0xF) {
|
||||
@@ -1764,7 +1759,6 @@ void cpu_loop(CPUPPCState *env)
|
||||
}
|
||||
break;
|
||||
case POWERPC_EXCP_INVAL:
|
||||
EXCP_DUMP(env, "Invalid instruction\n");
|
||||
info.si_signo = TARGET_SIGILL;
|
||||
info.si_errno = 0;
|
||||
switch (env->error_code & 0xF) {
|
||||
@@ -1788,7 +1782,6 @@ void cpu_loop(CPUPPCState *env)
|
||||
}
|
||||
break;
|
||||
case POWERPC_EXCP_PRIV:
|
||||
EXCP_DUMP(env, "Privilege violation\n");
|
||||
info.si_signo = TARGET_SIGILL;
|
||||
info.si_errno = 0;
|
||||
switch (env->error_code & 0xF) {
|
||||
@@ -1814,15 +1807,14 @@ void cpu_loop(CPUPPCState *env)
|
||||
env->error_code);
|
||||
break;
|
||||
}
|
||||
info._sifields._sigfault._addr = env->nip - 4;
|
||||
info._sifields._sigfault._addr = env->nip;
|
||||
queue_signal(env, info.si_signo, &info);
|
||||
break;
|
||||
case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
|
||||
EXCP_DUMP(env, "No floating point allowed\n");
|
||||
info.si_signo = TARGET_SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_COPROC;
|
||||
info._sifields._sigfault._addr = env->nip - 4;
|
||||
info._sifields._sigfault._addr = env->nip;
|
||||
queue_signal(env, info.si_signo, &info);
|
||||
break;
|
||||
case POWERPC_EXCP_SYSCALL: /* System call exception */
|
||||
@@ -1830,11 +1822,10 @@ void cpu_loop(CPUPPCState *env)
|
||||
"Aborting\n");
|
||||
break;
|
||||
case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
|
||||
EXCP_DUMP(env, "No APU instruction allowed\n");
|
||||
info.si_signo = TARGET_SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_COPROC;
|
||||
info._sifields._sigfault._addr = env->nip - 4;
|
||||
info._sifields._sigfault._addr = env->nip;
|
||||
queue_signal(env, info.si_signo, &info);
|
||||
break;
|
||||
case POWERPC_EXCP_DECR: /* Decrementer exception */
|
||||
@@ -1858,11 +1849,10 @@ void cpu_loop(CPUPPCState *env)
|
||||
"Aborting\n");
|
||||
break;
|
||||
case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavail. */
|
||||
EXCP_DUMP(env, "No SPE/floating-point instruction allowed\n");
|
||||
info.si_signo = TARGET_SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_COPROC;
|
||||
info._sifields._sigfault._addr = env->nip - 4;
|
||||
info._sifields._sigfault._addr = env->nip;
|
||||
queue_signal(env, info.si_signo, &info);
|
||||
break;
|
||||
case POWERPC_EXCP_EFPDI: /* Embedded floating-point data IRQ */
|
||||
@@ -1922,11 +1912,10 @@ void cpu_loop(CPUPPCState *env)
|
||||
"while in user mode. Aborting\n");
|
||||
break;
|
||||
case POWERPC_EXCP_VPU: /* Vector unavailable exception */
|
||||
EXCP_DUMP(env, "No Altivec instructions allowed\n");
|
||||
info.si_signo = TARGET_SIGILL;
|
||||
info.si_errno = 0;
|
||||
info.si_code = TARGET_ILL_COPROC;
|
||||
info._sifields._sigfault._addr = env->nip - 4;
|
||||
info._sifields._sigfault._addr = env->nip;
|
||||
queue_signal(env, info.si_signo, &info);
|
||||
break;
|
||||
case POWERPC_EXCP_PIT: /* Programmable interval timer IRQ */
|
||||
@@ -2001,9 +1990,9 @@ void cpu_loop(CPUPPCState *env)
|
||||
env->gpr[5], env->gpr[6], env->gpr[7],
|
||||
env->gpr[8], 0, 0);
|
||||
if (ret == -TARGET_ERESTARTSYS) {
|
||||
env->nip -= 4;
|
||||
break;
|
||||
}
|
||||
env->nip += 4;
|
||||
if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
|
||||
/* Returning from a successful sigreturn syscall.
|
||||
Avoid corrupting register state. */
|
||||
|
||||
@@ -1147,6 +1147,10 @@
|
||||
"POWER8NVL v1.0")
|
||||
POWERPC_DEF("970_v2.2", CPU_POWERPC_970_v22, 970,
|
||||
"PowerPC 970 v2.2")
|
||||
|
||||
POWERPC_DEF("POWER9_v1.0", CPU_POWERPC_POWER9_BASE, POWER9,
|
||||
"POWER9 v1.0")
|
||||
|
||||
POWERPC_DEF("970fx_v1.0", CPU_POWERPC_970FX_v10, 970,
|
||||
"PowerPC 970FX v1.0 (G5)")
|
||||
POWERPC_DEF("970fx_v2.0", CPU_POWERPC_970FX_v20, 970,
|
||||
@@ -1395,6 +1399,7 @@ PowerPCCPUAlias ppc_cpu_aliases[] = {
|
||||
{ "POWER8E", "POWER8E_v2.1" },
|
||||
{ "POWER8", "POWER8_v2.0" },
|
||||
{ "POWER8NVL", "POWER8NVL_v1.0" },
|
||||
{ "POWER9", "POWER9_v1.0" },
|
||||
{ "970", "970_v2.2" },
|
||||
{ "970fx", "970fx_v3.1" },
|
||||
{ "970mp", "970mp_v1.1" },
|
||||
|
||||
@@ -562,6 +562,7 @@ enum {
|
||||
CPU_POWERPC_POWER8_v20 = 0x004D0200,
|
||||
CPU_POWERPC_POWER8NVL_BASE = 0x004C0000,
|
||||
CPU_POWERPC_POWER8NVL_v10 = 0x004C0100,
|
||||
CPU_POWERPC_POWER9_BASE = 0x004E0000,
|
||||
CPU_POWERPC_970_v22 = 0x00390202,
|
||||
CPU_POWERPC_970FX_v10 = 0x00391100,
|
||||
CPU_POWERPC_970FX_v20 = 0x003C0200,
|
||||
|
||||
@@ -86,6 +86,7 @@ enum powerpc_mmu_t {
|
||||
POWERPC_MMU_2_07 = POWERPC_MMU_64 | POWERPC_MMU_1TSEG
|
||||
| POWERPC_MMU_64K
|
||||
| POWERPC_MMU_AMR | 0x00000004,
|
||||
/* FIXME Add POWERPC_MMU_3_OO defines */
|
||||
/* Architecture 2.07 "degraded" (no 1T segments) */
|
||||
POWERPC_MMU_2_07a = POWERPC_MMU_64 | POWERPC_MMU_AMR
|
||||
| 0x00000004,
|
||||
|
||||
+12
-2
@@ -1202,7 +1202,6 @@ extern const struct VMStateDescription vmstate_ppc_cpu;
|
||||
PowerPCCPU *cpu_ppc_init(const char *cpu_model);
|
||||
void ppc_translate_init(void);
|
||||
const char *ppc_cpu_lookup_alias(const char *alias);
|
||||
void gen_update_current_nip(void *opaque);
|
||||
/* you can call this signal handler from your SIGBUS and SIGSEGV
|
||||
signal handlers to inform the virtual CPU of exceptions. non zero
|
||||
is returned if the signal was handled by the virtual CPU. */
|
||||
@@ -2095,6 +2094,8 @@ enum {
|
||||
PPC2_TM = 0x0000000000020000ULL,
|
||||
/* Server PM instructgions (ISA 2.06, Book III) */
|
||||
PPC2_PM_ISA206 = 0x0000000000040000ULL,
|
||||
/* POWER ISA 3.0 */
|
||||
PPC2_ISA300 = 0x0000000000080000ULL,
|
||||
|
||||
#define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_VSX | PPC2_PRCNTL | PPC2_DBRX | \
|
||||
PPC2_ISA205 | PPC2_VSX207 | PPC2_PERM_ISA206 | \
|
||||
@@ -2102,7 +2103,8 @@ enum {
|
||||
PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | \
|
||||
PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | \
|
||||
PPC2_ALTIVEC_207 | PPC2_ISA207S | PPC2_DFP | \
|
||||
PPC2_FP_CVT_S64 | PPC2_TM | PPC2_PM_ISA206)
|
||||
PPC2_FP_CVT_S64 | PPC2_TM | PPC2_PM_ISA206 | \
|
||||
PPC2_ISA300)
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -2296,6 +2298,14 @@ static inline void cpu_get_tb_cpu_state(CPUPPCState *env, target_ulong *pc,
|
||||
*flags = env->hflags;
|
||||
}
|
||||
|
||||
void QEMU_NORETURN raise_exception(CPUPPCState *env, uint32_t exception);
|
||||
void QEMU_NORETURN raise_exception_ra(CPUPPCState *env, uint32_t exception,
|
||||
uintptr_t raddr);
|
||||
void QEMU_NORETURN raise_exception_err(CPUPPCState *env, uint32_t exception,
|
||||
uint32_t error_code);
|
||||
void QEMU_NORETURN raise_exception_err_ra(CPUPPCState *env, uint32_t exception,
|
||||
uint32_t error_code, uintptr_t raddr);
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
static inline int booke206_tlbm_id(CPUPPCState *env, ppcmas_tlb_t *tlbm)
|
||||
{
|
||||
|
||||
@@ -647,6 +647,41 @@ uint32_t helper_##op(CPUPPCState *env, uint64_t *a, uint64_t *b) \
|
||||
DFP_HELPER_TSTSF(dtstsf, 64)
|
||||
DFP_HELPER_TSTSF(dtstsfq, 128)
|
||||
|
||||
#define DFP_HELPER_TSTSFI(op, size) \
|
||||
uint32_t helper_##op(CPUPPCState *env, uint32_t a, uint64_t *b) \
|
||||
{ \
|
||||
struct PPC_DFP dfp; \
|
||||
unsigned uim; \
|
||||
\
|
||||
dfp_prepare_decimal##size(&dfp, 0, b, env); \
|
||||
\
|
||||
uim = a & 0x3F; \
|
||||
\
|
||||
if (unlikely(decNumberIsSpecial(&dfp.b))) { \
|
||||
dfp.crbf = 1; \
|
||||
} else if (uim == 0) { \
|
||||
dfp.crbf = 4; \
|
||||
} else if (unlikely(decNumberIsZero(&dfp.b))) { \
|
||||
/* Zero has no sig digits */ \
|
||||
dfp.crbf = 4; \
|
||||
} else { \
|
||||
unsigned nsd = dfp.b.digits; \
|
||||
if (uim < nsd) { \
|
||||
dfp.crbf = 8; \
|
||||
} else if (uim > nsd) { \
|
||||
dfp.crbf = 4; \
|
||||
} else { \
|
||||
dfp.crbf = 2; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
dfp_set_FPCC_from_CRBF(&dfp); \
|
||||
return dfp.crbf; \
|
||||
}
|
||||
|
||||
DFP_HELPER_TSTSFI(dtstsfi, 64)
|
||||
DFP_HELPER_TSTSFI(dtstsfiq, 128)
|
||||
|
||||
static void QUA_PPs(struct PPC_DFP *dfp)
|
||||
{
|
||||
dfp_set_FPRF_from_FRT(dfp);
|
||||
|
||||
+97
-106
@@ -198,7 +198,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||
default:
|
||||
goto excp_invalid;
|
||||
}
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_MCHECK: /* Machine check exception */
|
||||
if (msr_me == 0) {
|
||||
/* Machine check exception is not enabled.
|
||||
@@ -235,16 +235,16 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_DSI: /* Data storage exception */
|
||||
LOG_EXCP("DSI exception: DSISR=" TARGET_FMT_lx" DAR=" TARGET_FMT_lx
|
||||
"\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_ISI: /* Instruction storage exception */
|
||||
LOG_EXCP("ISI exception: msr=" TARGET_FMT_lx ", nip=" TARGET_FMT_lx
|
||||
"\n", msr, env->nip);
|
||||
msr |= env->error_code;
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_EXTERNAL: /* External input */
|
||||
cs = CPU(cpu);
|
||||
|
||||
@@ -258,13 +258,15 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||
/* IACK the IRQ on delivery */
|
||||
env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
|
||||
}
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_ALIGN: /* Alignment exception */
|
||||
/* XXX: this is false */
|
||||
/* Get rS/rD and rA from faulting opcode */
|
||||
env->spr[SPR_DSISR] |= (cpu_ldl_code(env, (env->nip - 4))
|
||||
& 0x03FF0000) >> 16;
|
||||
goto store_next;
|
||||
/* Note: the opcode fields will not be set properly for a direct
|
||||
* store load/store, but nobody cares as nobody actually uses
|
||||
* direct store segments.
|
||||
*/
|
||||
env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
|
||||
break;
|
||||
case POWERPC_EXCP_PROGRAM: /* Program exception */
|
||||
switch (env->error_code & ~0xF) {
|
||||
case POWERPC_EXCP_FP:
|
||||
@@ -274,11 +276,12 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||
env->error_code = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* FP exceptions always have NIP pointing to the faulting
|
||||
* instruction, so always use store_next and claim we are
|
||||
* precise in the MSR.
|
||||
*/
|
||||
msr |= 0x00100000;
|
||||
if (msr_fe0 == msr_fe1) {
|
||||
goto store_next;
|
||||
}
|
||||
msr |= 0x00010000;
|
||||
break;
|
||||
case POWERPC_EXCP_INVAL:
|
||||
LOG_EXCP("Invalid instruction at " TARGET_FMT_lx "\n", env->nip);
|
||||
@@ -299,19 +302,16 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||
env->error_code);
|
||||
break;
|
||||
}
|
||||
goto store_current;
|
||||
case POWERPC_EXCP_HV_EMU:
|
||||
srr0 = SPR_HSRR0;
|
||||
srr1 = SPR_HSRR1;
|
||||
new_msr |= (target_ulong)MSR_HVB;
|
||||
new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
|
||||
goto store_current;
|
||||
case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
|
||||
goto store_current;
|
||||
break;
|
||||
case POWERPC_EXCP_SYSCALL: /* System call exception */
|
||||
dump_syscall(env);
|
||||
lev = env->error_code;
|
||||
|
||||
/* We need to correct the NIP which in this case is supposed
|
||||
* to point to the next instruction
|
||||
*/
|
||||
env->nip += 4;
|
||||
|
||||
/* "PAPR mode" built-in hypercall emulation */
|
||||
if ((lev == 1) && cpu_ppc_hypercall) {
|
||||
cpu_ppc_hypercall(cpu);
|
||||
@@ -320,15 +320,15 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||
if (lev == 1) {
|
||||
new_msr |= (target_ulong)MSR_HVB;
|
||||
}
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
|
||||
case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
|
||||
goto store_current;
|
||||
case POWERPC_EXCP_DECR: /* Decrementer exception */
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
|
||||
/* FIT on 4xx */
|
||||
LOG_EXCP("FIT exception\n");
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
|
||||
LOG_EXCP("WDT exception\n");
|
||||
switch (excp_model) {
|
||||
@@ -339,11 +339,10 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_DTLB: /* Data TLB error */
|
||||
goto store_next;
|
||||
case POWERPC_EXCP_ITLB: /* Instruction TLB error */
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_DEBUG: /* Debug interrupt */
|
||||
switch (excp_model) {
|
||||
case POWERPC_EXCP_BOOKE:
|
||||
@@ -358,33 +357,33 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||
}
|
||||
/* XXX: TODO */
|
||||
cpu_abort(cs, "Debug exception is not implemented yet !\n");
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */
|
||||
env->spr[SPR_BOOKE_ESR] = ESR_SPV;
|
||||
goto store_current;
|
||||
break;
|
||||
case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */
|
||||
/* XXX: TODO */
|
||||
cpu_abort(cs, "Embedded floating point data exception "
|
||||
"is not implemented yet !\n");
|
||||
env->spr[SPR_BOOKE_ESR] = ESR_SPV;
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */
|
||||
/* XXX: TODO */
|
||||
cpu_abort(cs, "Embedded floating point round exception "
|
||||
"is not implemented yet !\n");
|
||||
env->spr[SPR_BOOKE_ESR] = ESR_SPV;
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */
|
||||
/* XXX: TODO */
|
||||
cpu_abort(cs,
|
||||
"Performance counter exception is not implemented yet !\n");
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
|
||||
srr0 = SPR_BOOKE_CSRR0;
|
||||
srr1 = SPR_BOOKE_CSRR1;
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_RESET: /* System reset exception */
|
||||
if (msr_pow) {
|
||||
/* indicate that we resumed from power save mode */
|
||||
@@ -395,65 +394,42 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||
|
||||
new_msr |= (target_ulong)MSR_HVB;
|
||||
ail = 0;
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_DSEG: /* Data segment exception */
|
||||
goto store_next;
|
||||
case POWERPC_EXCP_ISEG: /* Instruction segment exception */
|
||||
goto store_next;
|
||||
case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
|
||||
srr0 = SPR_HSRR0;
|
||||
srr1 = SPR_HSRR1;
|
||||
new_msr |= (target_ulong)MSR_HVB;
|
||||
new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
|
||||
goto store_next;
|
||||
case POWERPC_EXCP_TRACE: /* Trace exception */
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
|
||||
case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
|
||||
srr0 = SPR_HSRR0;
|
||||
srr1 = SPR_HSRR1;
|
||||
new_msr |= (target_ulong)MSR_HVB;
|
||||
new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
|
||||
goto store_next;
|
||||
case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */
|
||||
srr0 = SPR_HSRR0;
|
||||
srr1 = SPR_HSRR1;
|
||||
new_msr |= (target_ulong)MSR_HVB;
|
||||
new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
|
||||
goto store_next;
|
||||
case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */
|
||||
srr0 = SPR_HSRR0;
|
||||
srr1 = SPR_HSRR1;
|
||||
new_msr |= (target_ulong)MSR_HVB;
|
||||
new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
|
||||
goto store_next;
|
||||
case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */
|
||||
case POWERPC_EXCP_HV_EMU:
|
||||
srr0 = SPR_HSRR0;
|
||||
srr1 = SPR_HSRR1;
|
||||
new_msr |= (target_ulong)MSR_HVB;
|
||||
new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_VPU: /* Vector unavailable exception */
|
||||
goto store_current;
|
||||
case POWERPC_EXCP_VSXU: /* VSX unavailable exception */
|
||||
goto store_current;
|
||||
case POWERPC_EXCP_FU: /* Facility unavailable exception */
|
||||
goto store_current;
|
||||
break;
|
||||
case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
|
||||
LOG_EXCP("PIT exception\n");
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_IO: /* IO error exception */
|
||||
/* XXX: TODO */
|
||||
cpu_abort(cs, "601 IO error exception is not implemented yet !\n");
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_RUNM: /* Run mode exception */
|
||||
/* XXX: TODO */
|
||||
cpu_abort(cs, "601 run mode exception is not implemented yet !\n");
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_EMUL: /* Emulation trap exception */
|
||||
/* XXX: TODO */
|
||||
cpu_abort(cs, "602 emulation trap exception "
|
||||
"is not implemented yet !\n");
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
|
||||
switch (excp_model) {
|
||||
case POWERPC_EXCP_602:
|
||||
@@ -568,71 +544,67 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
||||
cpu_abort(cs, "Invalid data store TLB miss exception\n");
|
||||
break;
|
||||
}
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_FPA: /* Floating-point assist exception */
|
||||
/* XXX: TODO */
|
||||
cpu_abort(cs, "Floating point assist exception "
|
||||
"is not implemented yet !\n");
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_DABR: /* Data address breakpoint */
|
||||
/* XXX: TODO */
|
||||
cpu_abort(cs, "DABR exception is not implemented yet !\n");
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
|
||||
/* XXX: TODO */
|
||||
cpu_abort(cs, "IABR exception is not implemented yet !\n");
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_SMI: /* System management interrupt */
|
||||
/* XXX: TODO */
|
||||
cpu_abort(cs, "SMI exception is not implemented yet !\n");
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_THERM: /* Thermal interrupt */
|
||||
/* XXX: TODO */
|
||||
cpu_abort(cs, "Thermal management exception "
|
||||
"is not implemented yet !\n");
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
|
||||
/* XXX: TODO */
|
||||
cpu_abort(cs,
|
||||
"Performance counter exception is not implemented yet !\n");
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_VPUA: /* Vector assist exception */
|
||||
/* XXX: TODO */
|
||||
cpu_abort(cs, "VPU assist exception is not implemented yet !\n");
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_SOFTP: /* Soft patch exception */
|
||||
/* XXX: TODO */
|
||||
cpu_abort(cs,
|
||||
"970 soft-patch exception is not implemented yet !\n");
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_MAINT: /* Maintenance exception */
|
||||
/* XXX: TODO */
|
||||
cpu_abort(cs,
|
||||
"970 maintenance exception is not implemented yet !\n");
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */
|
||||
/* XXX: TODO */
|
||||
cpu_abort(cs, "Maskable external exception "
|
||||
"is not implemented yet !\n");
|
||||
goto store_next;
|
||||
break;
|
||||
case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */
|
||||
/* XXX: TODO */
|
||||
cpu_abort(cs, "Non maskable external exception "
|
||||
"is not implemented yet !\n");
|
||||
goto store_next;
|
||||
break;
|
||||
default:
|
||||
excp_invalid:
|
||||
cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
|
||||
break;
|
||||
store_current:
|
||||
/* save current instruction location */
|
||||
env->spr[srr0] = env->nip - 4;
|
||||
break;
|
||||
store_next:
|
||||
/* save next instruction location */
|
||||
env->spr[srr0] = env->nip;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Save PC */
|
||||
env->spr[srr0] = env->nip;
|
||||
|
||||
/* Save MSR */
|
||||
env->spr[srr1] = msr;
|
||||
|
||||
@@ -898,34 +870,53 @@ static void cpu_dump_rfi(target_ulong RA, target_ulong msr)
|
||||
/*****************************************************************************/
|
||||
/* Exceptions processing helpers */
|
||||
|
||||
void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
|
||||
uint32_t error_code)
|
||||
void raise_exception_err_ra(CPUPPCState *env, uint32_t exception,
|
||||
uint32_t error_code, uintptr_t raddr)
|
||||
{
|
||||
CPUState *cs = CPU(ppc_env_get_cpu(env));
|
||||
|
||||
#if 0
|
||||
printf("Raise exception %3x code : %d\n", exception, error_code);
|
||||
#endif
|
||||
cs->exception_index = exception;
|
||||
env->error_code = error_code;
|
||||
cpu_loop_exit(cs);
|
||||
cpu_loop_exit_restore(cs, raddr);
|
||||
}
|
||||
|
||||
void raise_exception_err(CPUPPCState *env, uint32_t exception,
|
||||
uint32_t error_code)
|
||||
{
|
||||
raise_exception_err_ra(env, exception, error_code, 0);
|
||||
}
|
||||
|
||||
void raise_exception(CPUPPCState *env, uint32_t exception)
|
||||
{
|
||||
raise_exception_err_ra(env, exception, 0, 0);
|
||||
}
|
||||
|
||||
void raise_exception_ra(CPUPPCState *env, uint32_t exception,
|
||||
uintptr_t raddr)
|
||||
{
|
||||
raise_exception_err_ra(env, exception, 0, raddr);
|
||||
}
|
||||
|
||||
void helper_raise_exception_err(CPUPPCState *env, uint32_t exception,
|
||||
uint32_t error_code)
|
||||
{
|
||||
raise_exception_err_ra(env, exception, error_code, 0);
|
||||
}
|
||||
|
||||
void helper_raise_exception(CPUPPCState *env, uint32_t exception)
|
||||
{
|
||||
helper_raise_exception_err(env, exception, 0);
|
||||
raise_exception_err_ra(env, exception, 0, 0);
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
void helper_store_msr(CPUPPCState *env, target_ulong val)
|
||||
{
|
||||
CPUState *cs;
|
||||
uint32_t excp = hreg_store_msr(env, val, 0);
|
||||
|
||||
val = hreg_store_msr(env, val, 0);
|
||||
if (val != 0) {
|
||||
cs = CPU(ppc_env_get_cpu(env));
|
||||
if (excp != 0) {
|
||||
CPUState *cs = CPU(ppc_env_get_cpu(env));
|
||||
cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
|
||||
helper_raise_exception(env, val);
|
||||
raise_exception(env, excp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -951,7 +942,7 @@ void helper_pminsn(CPUPPCState *env, powerpc_pm_insn_t insn)
|
||||
* but this doesn't seem to be a problem.
|
||||
*/
|
||||
env->msr |= (1ull << MSR_EE);
|
||||
helper_raise_exception(env, EXCP_HLT);
|
||||
raise_exception(env, EXCP_HLT);
|
||||
}
|
||||
#endif /* defined(TARGET_PPC64) */
|
||||
|
||||
@@ -1041,8 +1032,8 @@ void helper_tw(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
|
||||
((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
|
||||
((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
|
||||
((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
|
||||
helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
|
||||
POWERPC_EXCP_TRAP);
|
||||
raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
|
||||
POWERPC_EXCP_TRAP, GETPC());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1055,8 +1046,8 @@ void helper_td(CPUPPCState *env, target_ulong arg1, target_ulong arg2,
|
||||
((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
|
||||
((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
|
||||
((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01))))) {
|
||||
helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
|
||||
POWERPC_EXCP_TRAP);
|
||||
raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM,
|
||||
POWERPC_EXCP_TRAP, GETPC());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
+104
-89
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user