提交 076bfd7c 编写于 作者: A Aurelien Jarno

Merge branch 'ppc-for-upstream' of git://github.com/agraf/qemu

* 'ppc-for-upstream' of git://github.com/agraf/qemu: (30 commits)
  target-ppc: add support for extended mtfsf/mtfsfi forms
  target-ppc: emulate store doubleword pair instructions
  target-ppc: emulate load doubleword pair instructions
  target-ppc: emulate lfiwax instruction
  target-ppc: emulate fcpsgn instruction
  target-ppc: emulate prtyw and prtyd instructions
  target-ppc: emulate cmpb instruction
  target-ppc: add instruction flags for Book I 2.05
  disas: Disassemble all ppc insns for the guest
  target-ppc: optimize fabs, fnabs, fneg
  PPC: Fix dcbz for linux-user on 970
  powerpc: correctly handle fpu exceptions.
  pseries: Generate device paths for VIO devices
  pseries: Convert VIO code to QOM style type safe(ish) casts
  target-ppc: Synchronize VPA state with KVM
  pseries: Fix some small errors in XICS logic
  target-ppc: Add more stubs for POWER7 PMU registers
  pseries: Fixes and enhancements to L1 cache properties
  pseries: Fix incorrect calculation of RMA size in certain configurations
  PPC: Fix compile with profiling enabled
  ...
...@@ -227,6 +227,7 @@ void target_disas(FILE *out, CPUArchState *env, target_ulong code, ...@@ -227,6 +227,7 @@ void target_disas(FILE *out, CPUArchState *env, target_ulong code,
s.info.mach = bfd_mach_ppc; s.info.mach = bfd_mach_ppc;
#endif #endif
} }
s.info.disassembler_options = (char *)"any";
print_insn = print_insn_ppc; print_insn = print_insn_ppc;
#elif defined(TARGET_M68K) #elif defined(TARGET_M68K)
print_insn = print_insn_m68k; print_insn = print_insn_m68k;
......
...@@ -12,16 +12,20 @@ typedef struct VIOsPAPRVTYDevice { ...@@ -12,16 +12,20 @@ typedef struct VIOsPAPRVTYDevice {
uint8_t buf[VTERM_BUFSIZE]; uint8_t buf[VTERM_BUFSIZE];
} VIOsPAPRVTYDevice; } VIOsPAPRVTYDevice;
#define TYPE_VIO_SPAPR_VTY_DEVICE "spapr-vty"
#define VIO_SPAPR_VTY_DEVICE(obj) \
OBJECT_CHECK(VIOsPAPRVTYDevice, (obj), TYPE_VIO_SPAPR_VTY_DEVICE)
static int vty_can_receive(void *opaque) static int vty_can_receive(void *opaque)
{ {
VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque; VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(opaque);
return (dev->in - dev->out) < VTERM_BUFSIZE; return (dev->in - dev->out) < VTERM_BUFSIZE;
} }
static void vty_receive(void *opaque, const uint8_t *buf, int size) static void vty_receive(void *opaque, const uint8_t *buf, int size)
{ {
VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque; VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(opaque);
int i; int i;
if ((dev->in == dev->out) && size) { if ((dev->in == dev->out) && size) {
...@@ -36,7 +40,7 @@ static void vty_receive(void *opaque, const uint8_t *buf, int size) ...@@ -36,7 +40,7 @@ static void vty_receive(void *opaque, const uint8_t *buf, int size)
static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max) static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max)
{ {
VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev; VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(sdev);
int n = 0; int n = 0;
while ((n < max) && (dev->out != dev->in)) { while ((n < max) && (dev->out != dev->in)) {
...@@ -48,7 +52,7 @@ static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max) ...@@ -48,7 +52,7 @@ static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max)
void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len) void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len)
{ {
VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev; VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(sdev);
/* FIXME: should check the qemu_chr_fe_write() return value */ /* FIXME: should check the qemu_chr_fe_write() return value */
qemu_chr_fe_write(dev->chardev, buf, len); qemu_chr_fe_write(dev->chardev, buf, len);
...@@ -56,7 +60,7 @@ void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len) ...@@ -56,7 +60,7 @@ void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len)
static int spapr_vty_init(VIOsPAPRDevice *sdev) static int spapr_vty_init(VIOsPAPRDevice *sdev)
{ {
VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev; VIOsPAPRVTYDevice *dev = VIO_SPAPR_VTY_DEVICE(sdev);
if (!dev->chardev) { if (!dev->chardev) {
fprintf(stderr, "spapr-vty: Can't create vty without a chardev!\n"); fprintf(stderr, "spapr-vty: Can't create vty without a chardev!\n");
...@@ -151,7 +155,7 @@ static void spapr_vty_class_init(ObjectClass *klass, void *data) ...@@ -151,7 +155,7 @@ static void spapr_vty_class_init(ObjectClass *klass, void *data)
} }
static const TypeInfo spapr_vty_info = { static const TypeInfo spapr_vty_info = {
.name = "spapr-vty", .name = TYPE_VIO_SPAPR_VTY_DEVICE,
.parent = TYPE_VIO_SPAPR_DEVICE, .parent = TYPE_VIO_SPAPR_DEVICE,
.instance_size = sizeof(VIOsPAPRVTYDevice), .instance_size = sizeof(VIOsPAPRVTYDevice),
.class_init = spapr_vty_class_init, .class_init = spapr_vty_class_init,
...@@ -177,7 +181,7 @@ VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus) ...@@ -177,7 +181,7 @@ VIOsPAPRDevice *spapr_vty_get_default(VIOsPAPRBus *bus)
continue; continue;
} }
sdev = DO_UPCAST(VIOsPAPRDevice, qdev, iter); sdev = VIO_SPAPR_DEVICE(iter);
/* First VTY we've found, so it is selected for now */ /* First VTY we've found, so it is selected for now */
if (!selected) { if (!selected) {
......
...@@ -73,6 +73,10 @@ typedef uint64_t vlan_bd_t; ...@@ -73,6 +73,10 @@ typedef uint64_t vlan_bd_t;
#define VLAN_RX_BDS_OFF 16 #define VLAN_RX_BDS_OFF 16
#define VLAN_MAX_BUFS ((SPAPR_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF) / 8) #define VLAN_MAX_BUFS ((SPAPR_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF) / 8)
#define TYPE_VIO_SPAPR_VLAN_DEVICE "spapr-vlan"
#define VIO_SPAPR_VLAN_DEVICE(obj) \
OBJECT_CHECK(VIOsPAPRVLANDevice, (obj), TYPE_VIO_SPAPR_VLAN_DEVICE)
typedef struct VIOsPAPRVLANDevice { typedef struct VIOsPAPRVLANDevice {
VIOsPAPRDevice sdev; VIOsPAPRDevice sdev;
NICConf nicconf; NICConf nicconf;
...@@ -93,8 +97,8 @@ static int spapr_vlan_can_receive(NetClientState *nc) ...@@ -93,8 +97,8 @@ static int spapr_vlan_can_receive(NetClientState *nc)
static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf, static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf,
size_t size) size_t size)
{ {
VIOsPAPRDevice *sdev = qemu_get_nic_opaque(nc); VIOsPAPRVLANDevice *dev = qemu_get_nic_opaque(nc);
VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev; VIOsPAPRDevice *sdev = VIO_SPAPR_DEVICE(dev);
vlan_bd_t rxq_bd = vio_ldq(sdev, dev->buf_list + VLAN_RXQ_BD_OFF); vlan_bd_t rxq_bd = vio_ldq(sdev, dev->buf_list + VLAN_RXQ_BD_OFF);
vlan_bd_t bd; vlan_bd_t bd;
int buf_ptr = dev->use_buf_ptr; int buf_ptr = dev->use_buf_ptr;
...@@ -192,7 +196,7 @@ static NetClientInfo net_spapr_vlan_info = { ...@@ -192,7 +196,7 @@ static NetClientInfo net_spapr_vlan_info = {
static void spapr_vlan_reset(VIOsPAPRDevice *sdev) static void spapr_vlan_reset(VIOsPAPRDevice *sdev)
{ {
VIOsPAPRVLANDevice *dev = DO_UPCAST(VIOsPAPRVLANDevice, sdev, sdev); VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
dev->buf_list = 0; dev->buf_list = 0;
dev->rx_bufs = 0; dev->rx_bufs = 0;
...@@ -201,7 +205,7 @@ static void spapr_vlan_reset(VIOsPAPRDevice *sdev) ...@@ -201,7 +205,7 @@ static void spapr_vlan_reset(VIOsPAPRDevice *sdev)
static int spapr_vlan_init(VIOsPAPRDevice *sdev) static int spapr_vlan_init(VIOsPAPRDevice *sdev)
{ {
VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev; VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
qemu_macaddr_default_if_unset(&dev->nicconf.macaddr); qemu_macaddr_default_if_unset(&dev->nicconf.macaddr);
...@@ -225,7 +229,7 @@ void spapr_vlan_create(VIOsPAPRBus *bus, NICInfo *nd) ...@@ -225,7 +229,7 @@ void spapr_vlan_create(VIOsPAPRBus *bus, NICInfo *nd)
static int spapr_vlan_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off) static int spapr_vlan_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
{ {
VIOsPAPRVLANDevice *vdev = (VIOsPAPRVLANDevice *)dev; VIOsPAPRVLANDevice *vdev = VIO_SPAPR_VLAN_DEVICE(dev);
uint8_t padded_mac[8] = {0, 0}; uint8_t padded_mac[8] = {0, 0};
int ret; int ret;
...@@ -282,7 +286,7 @@ static target_ulong h_register_logical_lan(PowerPCCPU *cpu, ...@@ -282,7 +286,7 @@ static target_ulong h_register_logical_lan(PowerPCCPU *cpu,
target_ulong rec_queue = args[2]; target_ulong rec_queue = args[2];
target_ulong filter_list = args[3]; target_ulong filter_list = args[3];
VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev; VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
vlan_bd_t filter_list_bd; vlan_bd_t filter_list_bd;
if (!dev) { if (!dev) {
...@@ -341,7 +345,7 @@ static target_ulong h_free_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr, ...@@ -341,7 +345,7 @@ static target_ulong h_free_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr,
{ {
target_ulong reg = args[0]; target_ulong reg = args[0];
VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev; VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
if (!dev) { if (!dev) {
return H_PARAMETER; return H_PARAMETER;
...@@ -365,7 +369,7 @@ static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu, ...@@ -365,7 +369,7 @@ static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu,
target_ulong reg = args[0]; target_ulong reg = args[0];
target_ulong buf = args[1]; target_ulong buf = args[1];
VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev; VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
vlan_bd_t bd; vlan_bd_t bd;
dprintf("H_ADD_LOGICAL_LAN_BUFFER(0x" TARGET_FMT_lx dprintf("H_ADD_LOGICAL_LAN_BUFFER(0x" TARGET_FMT_lx
...@@ -413,7 +417,7 @@ static target_ulong h_send_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr, ...@@ -413,7 +417,7 @@ static target_ulong h_send_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong *bufs = args + 1; target_ulong *bufs = args + 1;
target_ulong continue_token = args[7]; target_ulong continue_token = args[7];
VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg); VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev; VIOsPAPRVLANDevice *dev = VIO_SPAPR_VLAN_DEVICE(sdev);
unsigned total_len; unsigned total_len;
uint8_t *lbuf, *p; uint8_t *lbuf, *p;
int i, nbufs; int i, nbufs;
...@@ -511,7 +515,7 @@ static void spapr_vlan_class_init(ObjectClass *klass, void *data) ...@@ -511,7 +515,7 @@ static void spapr_vlan_class_init(ObjectClass *klass, void *data)
} }
static const TypeInfo spapr_vlan_info = { static const TypeInfo spapr_vlan_info = {
.name = "spapr-vlan", .name = TYPE_VIO_SPAPR_VLAN_DEVICE,
.parent = TYPE_VIO_SPAPR_DEVICE, .parent = TYPE_VIO_SPAPR_DEVICE,
.instance_size = sizeof(VIOsPAPRVLANDevice), .instance_size = sizeof(VIOsPAPRVLANDevice),
.class_init = spapr_vlan_class_init, .class_init = spapr_vlan_class_init,
......
...@@ -36,6 +36,10 @@ typedef struct sPAPRNVRAM { ...@@ -36,6 +36,10 @@ typedef struct sPAPRNVRAM {
BlockDriverState *drive; BlockDriverState *drive;
} sPAPRNVRAM; } sPAPRNVRAM;
#define TYPE_VIO_SPAPR_NVRAM "spapr-nvram"
#define VIO_SPAPR_NVRAM(obj) \
OBJECT_CHECK(sPAPRNVRAM, (obj), TYPE_VIO_SPAPR_NVRAM)
#define MIN_NVRAM_SIZE 8192 #define MIN_NVRAM_SIZE 8192
#define DEFAULT_NVRAM_SIZE 65536 #define DEFAULT_NVRAM_SIZE 65536
#define MAX_NVRAM_SIZE (UINT16_MAX * 16) #define MAX_NVRAM_SIZE (UINT16_MAX * 16)
...@@ -134,7 +138,7 @@ static void rtas_nvram_store(sPAPREnvironment *spapr, ...@@ -134,7 +138,7 @@ static void rtas_nvram_store(sPAPREnvironment *spapr,
static int spapr_nvram_init(VIOsPAPRDevice *dev) static int spapr_nvram_init(VIOsPAPRDevice *dev)
{ {
sPAPRNVRAM *nvram = (sPAPRNVRAM *)dev; sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(dev);
if (nvram->drive) { if (nvram->drive) {
nvram->size = bdrv_getlength(nvram->drive); nvram->size = bdrv_getlength(nvram->drive);
...@@ -157,7 +161,7 @@ static int spapr_nvram_init(VIOsPAPRDevice *dev) ...@@ -157,7 +161,7 @@ static int spapr_nvram_init(VIOsPAPRDevice *dev)
static int spapr_nvram_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off) static int spapr_nvram_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
{ {
sPAPRNVRAM *nvram = (sPAPRNVRAM *)dev; sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(dev);
return fdt_setprop_cell(fdt, node_off, "#bytes", nvram->size); return fdt_setprop_cell(fdt, node_off, "#bytes", nvram->size);
} }
...@@ -182,7 +186,7 @@ static void spapr_nvram_class_init(ObjectClass *klass, void *data) ...@@ -182,7 +186,7 @@ static void spapr_nvram_class_init(ObjectClass *klass, void *data)
} }
static const TypeInfo spapr_nvram_type_info = { static const TypeInfo spapr_nvram_type_info = {
.name = "spapr-nvram", .name = TYPE_VIO_SPAPR_NVRAM,
.parent = TYPE_VIO_SPAPR_DEVICE, .parent = TYPE_VIO_SPAPR_DEVICE,
.instance_size = sizeof(sPAPRNVRAM), .instance_size = sizeof(sPAPRNVRAM),
.class_init = spapr_nvram_class_init, .class_init = spapr_nvram_class_init,
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "sysemu/device_tree.h" #include "sysemu/device_tree.h"
#include "hw/pci/pci.h" #include "hw/pci/pci.h"
#include "hw/ppc/openpic.h" #include "hw/ppc/openpic.h"
#include "kvm_ppc.h"
static void e500plat_fixup_devtree(PPCE500Params *params, void *fdt) static void e500plat_fixup_devtree(PPCE500Params *params, void *fdt)
{ {
...@@ -48,6 +49,12 @@ static void e500plat_init(QEMUMachineInitArgs *args) ...@@ -48,6 +49,12 @@ static void e500plat_init(QEMUMachineInitArgs *args)
.mpic_version = OPENPIC_MODEL_FSL_MPIC_42, .mpic_version = OPENPIC_MODEL_FSL_MPIC_42,
}; };
/* Older KVM versions don't support EPR which breaks guests when we announce
MPIC variants that support EPR. Revert to an older one for those */
if (kvm_enabled() && !kvmppc_has_cap_epr()) {
params.mpic_version = OPENPIC_MODEL_FSL_MPIC_20;
}
ppce500_init(&params); ppce500_init(&params);
} }
......
...@@ -126,6 +126,8 @@ static void ppc_core99_reset(void *opaque) ...@@ -126,6 +126,8 @@ static void ppc_core99_reset(void *opaque)
PowerPCCPU *cpu = opaque; PowerPCCPU *cpu = opaque;
cpu_reset(CPU(cpu)); cpu_reset(CPU(cpu));
/* 970 CPUs want to get their initial IP as part of their boot protocol */
cpu->env.nip = PROM_ADDR + 0x100;
} }
/* PowerPC Mac99 hardware initialisation */ /* PowerPC Mac99 hardware initialisation */
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "hw/timer/m48t59.h" #include "hw/timer/m48t59.h"
#include "qemu/log.h" #include "qemu/log.h"
#include "hw/loader.h" #include "hw/loader.h"
#include "kvm_ppc.h"
/* Timer Control Register */ /* Timer Control Register */
...@@ -211,6 +212,7 @@ void store_booke_tsr(CPUPPCState *env, target_ulong val) ...@@ -211,6 +212,7 @@ void store_booke_tsr(CPUPPCState *env, target_ulong val)
PowerPCCPU *cpu = ppc_env_get_cpu(env); PowerPCCPU *cpu = ppc_env_get_cpu(env);
env->spr[SPR_BOOKE_TSR] &= ~val; env->spr[SPR_BOOKE_TSR] &= ~val;
kvmppc_clear_tsr_bits(cpu, val);
booke_update_irq(cpu); booke_update_irq(cpu);
} }
...@@ -222,6 +224,7 @@ void store_booke_tcr(CPUPPCState *env, target_ulong val) ...@@ -222,6 +224,7 @@ void store_booke_tcr(CPUPPCState *env, target_ulong val)
tb_env = env->tb_env; tb_env = env->tb_env;
env->spr[SPR_BOOKE_TCR] = val; env->spr[SPR_BOOKE_TCR] = val;
kvmppc_set_tcr(cpu);
booke_update_irq(cpu); booke_update_irq(cpu);
...@@ -234,7 +237,6 @@ void store_booke_tcr(CPUPPCState *env, target_ulong val) ...@@ -234,7 +237,6 @@ void store_booke_tcr(CPUPPCState *env, target_ulong val)
booke_get_wdt_target(env, tb_env), booke_get_wdt_target(env, tb_env),
&booke_timer->wdt_next, &booke_timer->wdt_next,
booke_timer->wdt_timer); booke_timer->wdt_timer);
} }
static void ppc_booke_timer_reset_handle(void *opaque) static void ppc_booke_timer_reset_handle(void *opaque)
...@@ -242,16 +244,39 @@ static void ppc_booke_timer_reset_handle(void *opaque) ...@@ -242,16 +244,39 @@ static void ppc_booke_timer_reset_handle(void *opaque)
PowerPCCPU *cpu = opaque; PowerPCCPU *cpu = opaque;
CPUPPCState *env = &cpu->env; CPUPPCState *env = &cpu->env;
env->spr[SPR_BOOKE_TSR] = 0; store_booke_tcr(env, 0);
env->spr[SPR_BOOKE_TCR] = 0; store_booke_tsr(env, -1);
}
booke_update_irq(cpu); /*
* This function will be called whenever the CPU state changes.
* CPU states are defined "typedef enum RunState".
* Regarding timer, When CPU state changes to running after debug halt
* or similar cases which takes time then in between final watchdog
* expiry happenes. This will cause exit to QEMU and configured watchdog
* action will be taken. To avoid this we always clear the watchdog state when
* state changes to running.
*/
static void cpu_state_change_handler(void *opaque, int running, RunState state)
{
PowerPCCPU *cpu = opaque;
CPUPPCState *env = &cpu->env;
if (!running) {
return;
}
/*
* Clear watchdog interrupt condition by clearing TSR.
*/
store_booke_tsr(env, TSR_ENW | TSR_WIS | TSR_WRS_MASK);
} }
void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags) void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags)
{ {
ppc_tb_t *tb_env; ppc_tb_t *tb_env;
booke_timer_t *booke_timer; booke_timer_t *booke_timer;
int ret = 0;
tb_env = g_malloc0(sizeof(ppc_tb_t)); tb_env = g_malloc0(sizeof(ppc_tb_t));
booke_timer = g_malloc0(sizeof(booke_timer_t)); booke_timer = g_malloc0(sizeof(booke_timer_t));
...@@ -269,5 +294,17 @@ void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags) ...@@ -269,5 +294,17 @@ void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags)
booke_timer->wdt_timer = booke_timer->wdt_timer =
qemu_new_timer_ns(vm_clock, &booke_wdt_cb, cpu); qemu_new_timer_ns(vm_clock, &booke_wdt_cb, cpu);
ret = kvmppc_booke_watchdog_enable(cpu);
if (ret) {
/* TODO: Start the QEMU emulated watchdog if not running on KVM.
* Also start the QEMU emulated watchdog if KVM does not support
* emulated watchdog or somehow it is not enabled (supported but
* not enabled is though some bug and requires debugging :)).
*/
}
qemu_add_vm_change_state_handler(cpu_state_change_handler, cpu);
qemu_register_reset(ppc_booke_timer_reset_handle, cpu); qemu_register_reset(ppc_booke_timer_reset_handle, cpu);
} }
...@@ -308,6 +308,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model, ...@@ -308,6 +308,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
for (env = first_cpu; env != NULL; env = env->next_cpu) { for (env = first_cpu; env != NULL; env = env->next_cpu) {
CPUState *cpu = CPU(ppc_env_get_cpu(env)); CPUState *cpu = CPU(ppc_env_get_cpu(env));
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
int index = cpu->cpu_index; int index = cpu->cpu_index;
uint32_t servers_prop[smp_threads]; uint32_t servers_prop[smp_threads];
uint32_t gservers_prop[smp_threads * 2]; uint32_t gservers_prop[smp_threads * 2];
...@@ -333,10 +334,26 @@ static void *spapr_create_fdt_skel(const char *cpu_model, ...@@ -333,10 +334,26 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
_FDT((fdt_property_string(fdt, "device_type", "cpu"))); _FDT((fdt_property_string(fdt, "device_type", "cpu")));
_FDT((fdt_property_cell(fdt, "cpu-version", env->spr[SPR_PVR]))); _FDT((fdt_property_cell(fdt, "cpu-version", env->spr[SPR_PVR])));
_FDT((fdt_property_cell(fdt, "dcache-block-size", _FDT((fdt_property_cell(fdt, "d-cache-block-size",
env->dcache_line_size))); env->dcache_line_size)));
_FDT((fdt_property_cell(fdt, "icache-block-size", _FDT((fdt_property_cell(fdt, "d-cache-line-size",
env->dcache_line_size)));
_FDT((fdt_property_cell(fdt, "i-cache-block-size",
env->icache_line_size)));
_FDT((fdt_property_cell(fdt, "i-cache-line-size",
env->icache_line_size))); env->icache_line_size)));
if (pcc->l1_dcache_size) {
_FDT((fdt_property_cell(fdt, "d-cache-size", pcc->l1_dcache_size)));
} else {
fprintf(stderr, "Warning: Unknown L1 dcache size for cpu\n");
}
if (pcc->l1_icache_size) {
_FDT((fdt_property_cell(fdt, "i-cache-size", pcc->l1_icache_size)));
} else {
fprintf(stderr, "Warning: Unknown L1 icache size for cpu\n");
}
_FDT((fdt_property_cell(fdt, "timebase-frequency", tbfreq))); _FDT((fdt_property_cell(fdt, "timebase-frequency", tbfreq)));
_FDT((fdt_property_cell(fdt, "clock-frequency", cpufreq))); _FDT((fdt_property_cell(fdt, "clock-frequency", cpufreq)));
_FDT((fdt_property_cell(fdt, "ibm,slb-size", env->slb_nr))); _FDT((fdt_property_cell(fdt, "ibm,slb-size", env->slb_nr)));
...@@ -801,8 +818,10 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) ...@@ -801,8 +818,10 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
/* Set time-base frequency to 512 MHz */ /* Set time-base frequency to 512 MHz */
cpu_ppc_tb_init(env, TIMEBASE_FREQ); cpu_ppc_tb_init(env, TIMEBASE_FREQ);
/* PAPR always has exception vectors in RAM not ROM */ /* PAPR always has exception vectors in RAM not ROM. To ensure this,
env->hreset_excp_prefix = 0; * MSR[IP] should never be set.
*/
env->msr_mask &= ~(1 << 6);
/* Tell KVM that we're in PAPR mode */ /* Tell KVM that we're in PAPR mode */
if (kvm_enabled()) { if (kvm_enabled()) {
......
...@@ -53,9 +53,29 @@ static Property spapr_vio_props[] = { ...@@ -53,9 +53,29 @@ static Property spapr_vio_props[] = {
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };
static char *spapr_vio_get_dev_name(DeviceState *qdev)
{
VIOsPAPRDevice *dev = VIO_SPAPR_DEVICE(qdev);
VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
char *name;
/* Device tree style name device@reg */
name = g_strdup_printf("%s@%x", pc->dt_name, dev->reg);
return name;
}
static void spapr_vio_bus_class_init(ObjectClass *klass, void *data)
{
BusClass *k = BUS_CLASS(klass);
k->get_dev_path = spapr_vio_get_dev_name;
}
static const TypeInfo spapr_vio_bus_info = { static const TypeInfo spapr_vio_bus_info = {
.name = TYPE_SPAPR_VIO_BUS, .name = TYPE_SPAPR_VIO_BUS,
.parent = TYPE_BUS, .parent = TYPE_BUS,
.class_init = spapr_vio_bus_class_init,
.instance_size = sizeof(VIOsPAPRBus), .instance_size = sizeof(VIOsPAPRBus),
}; };
...@@ -74,17 +94,6 @@ VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg) ...@@ -74,17 +94,6 @@ VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg)
return NULL; return NULL;
} }
static char *vio_format_dev_name(VIOsPAPRDevice *dev)
{
VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
char *name;
/* Device tree style name device@reg */
name = g_strdup_printf("%s@%x", pc->dt_name, dev->reg);
return name;
}
#ifdef CONFIG_FDT #ifdef CONFIG_FDT
static int vio_make_devnode(VIOsPAPRDevice *dev, static int vio_make_devnode(VIOsPAPRDevice *dev,
void *fdt) void *fdt)
...@@ -98,7 +107,7 @@ static int vio_make_devnode(VIOsPAPRDevice *dev, ...@@ -98,7 +107,7 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
return vdevice_off; return vdevice_off;
} }
dt_name = vio_format_dev_name(dev); dt_name = spapr_vio_get_dev_name(DEVICE(dev));
node_off = fdt_add_subnode(fdt, vdevice_off, dt_name); node_off = fdt_add_subnode(fdt, vdevice_off, dt_name);
g_free(dt_name); g_free(dt_name);
if (node_off < 0) { if (node_off < 0) {
...@@ -379,7 +388,7 @@ static VIOsPAPRDevice *reg_conflict(VIOsPAPRDevice *dev) ...@@ -379,7 +388,7 @@ static VIOsPAPRDevice *reg_conflict(VIOsPAPRDevice *dev)
* the given dev might already be in the list. * the given dev might already be in the list.
*/ */
QTAILQ_FOREACH(kid, &bus->bus.children, sibling) { QTAILQ_FOREACH(kid, &bus->bus.children, sibling) {
other = DO_UPCAST(VIOsPAPRDevice, qdev, kid->child); other = VIO_SPAPR_DEVICE(kid->child);
if (other != dev && other->reg == dev->reg) { if (other != dev && other->reg == dev->reg) {
return other; return other;
...@@ -391,7 +400,7 @@ static VIOsPAPRDevice *reg_conflict(VIOsPAPRDevice *dev) ...@@ -391,7 +400,7 @@ static VIOsPAPRDevice *reg_conflict(VIOsPAPRDevice *dev)
static void spapr_vio_busdev_reset(DeviceState *qdev) static void spapr_vio_busdev_reset(DeviceState *qdev)
{ {
VIOsPAPRDevice *dev = DO_UPCAST(VIOsPAPRDevice, qdev, qdev); VIOsPAPRDevice *dev = VIO_SPAPR_DEVICE(qdev);
VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); VIOsPAPRDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev);
/* Shut down the request queue and TCEs if necessary */ /* Shut down the request queue and TCEs if necessary */
...@@ -437,7 +446,7 @@ static int spapr_vio_busdev_init(DeviceState *qdev) ...@@ -437,7 +446,7 @@ static int spapr_vio_busdev_init(DeviceState *qdev)
/* Don't overwrite ids assigned on the command line */ /* Don't overwrite ids assigned on the command line */
if (!dev->qdev.id) { if (!dev->qdev.id) {
id = vio_format_dev_name(dev); id = spapr_vio_get_dev_name(DEVICE(dev));
dev->qdev.id = id; dev->qdev.id = id;
} }
...@@ -636,7 +645,7 @@ int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus) ...@@ -636,7 +645,7 @@ int spapr_populate_chosen_stdout(void *fdt, VIOsPAPRBus *bus)
return offset; return offset;
} }
name = vio_format_dev_name(dev); name = spapr_vio_get_dev_name(DEVICE(dev));
path = g_strdup_printf("/vdevice/%s", name); path = g_strdup_printf("/vdevice/%s", name);
ret = fdt_setprop_string(fdt, offset, "linux,stdout-path", path); ret = fdt_setprop_string(fdt, offset, "linux,stdout-path", path);
......
...@@ -101,6 +101,7 @@ static void icp_set_cppr(struct icp_state *icp, int server, uint8_t cppr) ...@@ -101,6 +101,7 @@ static void icp_set_cppr(struct icp_state *icp, int server, uint8_t cppr)
if (XISR(ss) && (cppr <= ss->pending_priority)) { if (XISR(ss) && (cppr <= ss->pending_priority)) {
old_xisr = XISR(ss); old_xisr = XISR(ss);
ss->xirr &= ~XISR_MASK; /* Clear XISR */ ss->xirr &= ~XISR_MASK; /* Clear XISR */
ss->pending_priority = 0xff;
qemu_irq_lower(ss->output); qemu_irq_lower(ss->output);
ics_reject(icp->ics, old_xisr); ics_reject(icp->ics, old_xisr);
} }
...@@ -127,6 +128,7 @@ static uint32_t icp_accept(struct icp_server_state *ss) ...@@ -127,6 +128,7 @@ static uint32_t icp_accept(struct icp_server_state *ss)
qemu_irq_lower(ss->output); qemu_irq_lower(ss->output);
ss->xirr = ss->pending_priority << 24; ss->xirr = ss->pending_priority << 24;
ss->pending_priority = 0xff;
trace_xics_icp_accept(xirr, ss->xirr); trace_xics_icp_accept(xirr, ss->xirr);
......
...@@ -91,6 +91,9 @@ typedef struct vscsi_req { ...@@ -91,6 +91,9 @@ typedef struct vscsi_req {
int total_desc; int total_desc;
} vscsi_req; } vscsi_req;
#define TYPE_VIO_SPAPR_VSCSI_DEVICE "spapr-vscsi"
#define VIO_SPAPR_VSCSI_DEVICE(obj) \
OBJECT_CHECK(VSCSIState, (obj), TYPE_VIO_SPAPR_VSCSI_DEVICE)
typedef struct { typedef struct {
VIOsPAPRDevice vdev; VIOsPAPRDevice vdev;
...@@ -461,7 +464,7 @@ static int vscsi_preprocess_desc(vscsi_req *req) ...@@ -461,7 +464,7 @@ static int vscsi_preprocess_desc(vscsi_req *req)
/* Callback to indicate that the SCSI layer has completed a transfer. */ /* Callback to indicate that the SCSI layer has completed a transfer. */
static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len) static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len)
{ {
VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent); VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(sreq->bus->qbus.parent);
vscsi_req *req = sreq->hba_private; vscsi_req *req = sreq->hba_private;
uint8_t *buf; uint8_t *buf;
int rc = 0; int rc = 0;
...@@ -492,7 +495,7 @@ static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len) ...@@ -492,7 +495,7 @@ static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len)
/* Callback to indicate that the SCSI layer has completed a transfer. */ /* Callback to indicate that the SCSI layer has completed a transfer. */
static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status, size_t resid) static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status, size_t resid)
{ {
VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent); VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(sreq->bus->qbus.parent);
vscsi_req *req = sreq->hba_private; vscsi_req *req = sreq->hba_private;
int32_t res_in = 0, res_out = 0; int32_t res_in = 0, res_out = 0;
...@@ -827,7 +830,7 @@ static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq) ...@@ -827,7 +830,7 @@ static void vscsi_got_payload(VSCSIState *s, vscsi_crq *crq)
static int vscsi_do_crq(struct VIOsPAPRDevice *dev, uint8_t *crq_data) static int vscsi_do_crq(struct VIOsPAPRDevice *dev, uint8_t *crq_data)
{ {
VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev); VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(dev);
vscsi_crq crq; vscsi_crq crq;
memcpy(crq.raw, crq_data, 16); memcpy(crq.raw, crq_data, 16);
...@@ -897,7 +900,7 @@ static const struct SCSIBusInfo vscsi_scsi_info = { ...@@ -897,7 +900,7 @@ static const struct SCSIBusInfo vscsi_scsi_info = {
static void spapr_vscsi_reset(VIOsPAPRDevice *dev) static void spapr_vscsi_reset(VIOsPAPRDevice *dev)
{ {
VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev); VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(dev);
int i; int i;
memset(s->reqs, 0, sizeof(s->reqs)); memset(s->reqs, 0, sizeof(s->reqs));
...@@ -908,7 +911,7 @@ static void spapr_vscsi_reset(VIOsPAPRDevice *dev) ...@@ -908,7 +911,7 @@ static void spapr_vscsi_reset(VIOsPAPRDevice *dev)
static int spapr_vscsi_init(VIOsPAPRDevice *dev) static int spapr_vscsi_init(VIOsPAPRDevice *dev)
{ {
VSCSIState *s = DO_UPCAST(VSCSIState, vdev, dev); VSCSIState *s = VIO_SPAPR_VSCSI_DEVICE(dev);
dev->crq.SendFunc = vscsi_do_crq; dev->crq.SendFunc = vscsi_do_crq;
...@@ -968,7 +971,7 @@ static void spapr_vscsi_class_init(ObjectClass *klass, void *data) ...@@ -968,7 +971,7 @@ static void spapr_vscsi_class_init(ObjectClass *klass, void *data)
} }
static const TypeInfo spapr_vscsi_info = { static const TypeInfo spapr_vscsi_info = {
.name = "spapr-vscsi", .name = TYPE_VIO_SPAPR_VSCSI_DEVICE,
.parent = TYPE_VIO_SPAPR_DEVICE, .parent = TYPE_VIO_SPAPR_DEVICE,
.instance_size = sizeof(VSCSIState), .instance_size = sizeof(VSCSIState),
.class_init = spapr_vscsi_class_init, .class_init = spapr_vscsi_class_init,
......
...@@ -417,4 +417,9 @@ struct kvm_get_htab_header { ...@@ -417,4 +417,9 @@ struct kvm_get_htab_header {
#define KVM_REG_PPC_EPCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x85) #define KVM_REG_PPC_EPCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x85)
#define KVM_REG_PPC_EPR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x86) #define KVM_REG_PPC_EPR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x86)
/* Timer Status Register OR/CLEAR interface */
#define KVM_REG_PPC_OR_TSR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x87)
#define KVM_REG_PPC_CLEAR_TSR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x88)
#define KVM_REG_PPC_TCR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x89)
#define KVM_REG_PPC_TSR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0x8a)
#endif /* __LINUX_KVM_POWERPC_H */ #endif /* __LINUX_KVM_POWERPC_H */
...@@ -449,12 +449,15 @@ enum { ...@@ -449,12 +449,15 @@ enum {
kvm_ioeventfd_flag_nr_datamatch, kvm_ioeventfd_flag_nr_datamatch,
kvm_ioeventfd_flag_nr_pio, kvm_ioeventfd_flag_nr_pio,
kvm_ioeventfd_flag_nr_deassign, kvm_ioeventfd_flag_nr_deassign,
kvm_ioeventfd_flag_nr_virtio_ccw_notify,
kvm_ioeventfd_flag_nr_max, kvm_ioeventfd_flag_nr_max,
}; };
#define KVM_IOEVENTFD_FLAG_DATAMATCH (1 << kvm_ioeventfd_flag_nr_datamatch) #define KVM_IOEVENTFD_FLAG_DATAMATCH (1 << kvm_ioeventfd_flag_nr_datamatch)
#define KVM_IOEVENTFD_FLAG_PIO (1 << kvm_ioeventfd_flag_nr_pio) #define KVM_IOEVENTFD_FLAG_PIO (1 << kvm_ioeventfd_flag_nr_pio)
#define KVM_IOEVENTFD_FLAG_DEASSIGN (1 << kvm_ioeventfd_flag_nr_deassign) #define KVM_IOEVENTFD_FLAG_DEASSIGN (1 << kvm_ioeventfd_flag_nr_deassign)
#define KVM_IOEVENTFD_FLAG_VIRTIO_CCW_NOTIFY \
(1 << kvm_ioeventfd_flag_nr_virtio_ccw_notify)
#define KVM_IOEVENTFD_VALID_FLAG_MASK ((1 << kvm_ioeventfd_flag_nr_max) - 1) #define KVM_IOEVENTFD_VALID_FLAG_MASK ((1 << kvm_ioeventfd_flag_nr_max) - 1)
......
...@@ -63,6 +63,7 @@ typedef struct PowerPCCPUClass { ...@@ -63,6 +63,7 @@ typedef struct PowerPCCPUClass {
powerpc_input_t bus_model; powerpc_input_t bus_model;
uint32_t flags; uint32_t flags;
int bfd_mach; int bfd_mach;
uint32_t l1_dcache_size, l1_icache_size;
#if defined(TARGET_PPC64) #if defined(TARGET_PPC64)
const struct ppc_segment_page_sizes *sps; const struct ppc_segment_page_sizes *sps;
#endif #endif
......
...@@ -1026,7 +1026,6 @@ struct CPUPPCState { ...@@ -1026,7 +1026,6 @@ struct CPUPPCState {
/* Exception vectors */ /* Exception vectors */
target_ulong excp_vectors[POWERPC_EXCP_NB]; target_ulong excp_vectors[POWERPC_EXCP_NB];
target_ulong excp_prefix; target_ulong excp_prefix;
target_ulong hreset_excp_prefix;
target_ulong ivor_mask; target_ulong ivor_mask;
target_ulong ivpr_mask; target_ulong ivpr_mask;
target_ulong hreset_vector; target_ulong hreset_vector;
...@@ -1446,6 +1445,7 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp) ...@@ -1446,6 +1445,7 @@ static inline void cpu_clone_regs(CPUPPCState *env, target_ulong newsp)
#define SPR_PERF2 (0x302) #define SPR_PERF2 (0x302)
#define SPR_RCPU_MI_RBA2 (0x302) #define SPR_RCPU_MI_RBA2 (0x302)
#define SPR_MPC_MI_AP (0x302) #define SPR_MPC_MI_AP (0x302)
#define SPR_MMCRA (0x302)
#define SPR_PERF3 (0x303) #define SPR_PERF3 (0x303)
#define SPR_RCPU_MI_RBA3 (0x303) #define SPR_RCPU_MI_RBA3 (0x303)
#define SPR_MPC_MI_EPN (0x303) #define SPR_MPC_MI_EPN (0x303)
...@@ -1870,8 +1870,10 @@ enum { ...@@ -1870,8 +1870,10 @@ enum {
PPC2_PRCNTL = 0x0000000000000008ULL, PPC2_PRCNTL = 0x0000000000000008ULL,
/* Byte-reversed, indexed, double-word load and store */ /* Byte-reversed, indexed, double-word load and store */
PPC2_DBRX = 0x0000000000000010ULL, PPC2_DBRX = 0x0000000000000010ULL,
/* Book I 2.05 PowerPC specification */
PPC2_ISA205 = 0x0000000000000020ULL,
#define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_PRCNTL | PPC2_DBRX) #define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_PRCNTL | PPC2_DBRX | PPC2_ISA205)
}; };
/*****************************************************************************/ /*****************************************************************************/
......
...@@ -430,20 +430,17 @@ void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit) ...@@ -430,20 +430,17 @@ void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit)
void helper_store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask) void helper_store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
{ {
/* target_ulong prev, new;
* We use only the 32 LSB of the incoming fpr
*/
uint32_t prev, new;
int i; int i;
prev = env->fpscr; prev = env->fpscr;
new = (uint32_t)arg; new = (target_ulong)arg;
new &= ~0x60000000; new &= ~0x60000000LL;
new |= prev & 0x60000000; new |= prev & 0x60000000LL;
for (i = 0; i < 8; i++) { for (i = 0; i < sizeof(target_ulong) * 2; i++) {
if (mask & (1 << i)) { if (mask & (1 << i)) {
env->fpscr &= ~(0xF << (4 * i)); env->fpscr &= ~(0xFLL << (4 * i));
env->fpscr |= new & (0xF << (4 * i)); env->fpscr |= new & (0xFLL << (4 * i));
} }
} }
/* Update VX and FEX */ /* Update VX and FEX */
...@@ -470,6 +467,18 @@ void store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask) ...@@ -470,6 +467,18 @@ void store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
void helper_float_check_status(CPUPPCState *env) void helper_float_check_status(CPUPPCState *env)
{ {
int status = get_float_exception_flags(&env->fp_status);
if (status & float_flag_divbyzero) {
float_zero_divide_excp(env);
} else if (status & float_flag_overflow) {
float_overflow_excp(env);
} else if (status & float_flag_underflow) {
float_underflow_excp(env);
} else if (status & float_flag_inexact) {
float_inexact_excp(env);
}
if (env->exception_index == POWERPC_EXCP_PROGRAM && if (env->exception_index == POWERPC_EXCP_PROGRAM &&
(env->error_code & POWERPC_EXCP_FP)) { (env->error_code & POWERPC_EXCP_FP)) {
/* Differred floating-point exception after target FPR update */ /* Differred floating-point exception after target FPR update */
...@@ -477,17 +486,6 @@ void helper_float_check_status(CPUPPCState *env) ...@@ -477,17 +486,6 @@ void helper_float_check_status(CPUPPCState *env)
helper_raise_exception_err(env, env->exception_index, helper_raise_exception_err(env, env->exception_index,
env->error_code); env->error_code);
} }
} else {
int status = get_float_exception_flags(&env->fp_status);
if (status & float_flag_divbyzero) {
float_zero_divide_excp(env);
} else if (status & float_flag_overflow) {
float_overflow_excp(env);
} else if (status & float_flag_underflow) {
float_underflow_excp(env);
} else if (status & float_flag_inexact) {
float_inexact_excp(env);
}
} }
} }
...@@ -595,37 +593,6 @@ uint64_t helper_fdiv(CPUPPCState *env, uint64_t arg1, uint64_t arg2) ...@@ -595,37 +593,6 @@ uint64_t helper_fdiv(CPUPPCState *env, uint64_t arg1, uint64_t arg2)
return farg1.ll; return farg1.ll;
} }
/* fabs */
uint64_t helper_fabs(CPUPPCState *env, uint64_t arg)
{
CPU_DoubleU farg;
farg.ll = arg;
farg.d = float64_abs(farg.d);
return farg.ll;
}
/* fnabs */
uint64_t helper_fnabs(CPUPPCState *env, uint64_t arg)
{
CPU_DoubleU farg;
farg.ll = arg;
farg.d = float64_abs(farg.d);
farg.d = float64_chs(farg.d);
return farg.ll;
}
/* fneg */
uint64_t helper_fneg(CPUPPCState *env, uint64_t arg)
{
CPU_DoubleU farg;
farg.ll = arg;
farg.d = float64_chs(farg.d);
return farg.ll;
}
/* fctiw - fctiw. */ /* fctiw - fctiw. */
uint64_t helper_fctiw(CPUPPCState *env, uint64_t arg) uint64_t helper_fctiw(CPUPPCState *env, uint64_t arg)
{ {
......
...@@ -36,6 +36,7 @@ DEF_HELPER_3(mulldo, i64, env, i64, i64) ...@@ -36,6 +36,7 @@ DEF_HELPER_3(mulldo, i64, env, i64, i64)
DEF_HELPER_FLAGS_1(cntlzw, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_1(cntlzw, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(popcntb, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_1(popcntb, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_1(popcntw, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_1(popcntw, TCG_CALL_NO_RWG_SE, tl, tl)
DEF_HELPER_FLAGS_2(cmpb, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_3(sraw, tl, env, tl, tl) DEF_HELPER_3(sraw, tl, env, tl, tl)
#if defined(TARGET_PPC64) #if defined(TARGET_PPC64)
DEF_HELPER_FLAGS_1(cntlzd, TCG_CALL_NO_RWG_SE, tl, tl) DEF_HELPER_FLAGS_1(cntlzd, TCG_CALL_NO_RWG_SE, tl, tl)
...@@ -80,9 +81,6 @@ DEF_HELPER_4(fmadd, i64, env, i64, i64, i64) ...@@ -80,9 +81,6 @@ DEF_HELPER_4(fmadd, i64, env, i64, i64, i64)
DEF_HELPER_4(fmsub, i64, env, i64, i64, i64) DEF_HELPER_4(fmsub, i64, env, i64, i64, i64)
DEF_HELPER_4(fnmadd, i64, env, i64, i64, i64) DEF_HELPER_4(fnmadd, i64, env, i64, i64, i64)
DEF_HELPER_4(fnmsub, i64, env, i64, i64, i64) DEF_HELPER_4(fnmsub, i64, env, i64, i64, i64)
DEF_HELPER_2(fabs, i64, env, i64)
DEF_HELPER_2(fnabs, i64, env, i64)
DEF_HELPER_2(fneg, i64, env, i64)
DEF_HELPER_2(fsqrt, i64, env, i64) DEF_HELPER_2(fsqrt, i64, env, i64)
DEF_HELPER_2(fre, i64, env, i64) DEF_HELPER_2(fre, i64, env, i64)
DEF_HELPER_2(fres, i64, env, i64) DEF_HELPER_2(fres, i64, env, i64)
......
...@@ -53,6 +53,21 @@ target_ulong helper_cntlzd(target_ulong t) ...@@ -53,6 +53,21 @@ target_ulong helper_cntlzd(target_ulong t)
} }
#endif #endif
target_ulong helper_cmpb(target_ulong rs, target_ulong rb)
{
target_ulong mask = 0xff;
target_ulong ra = 0;
int i;
for (i = 0; i < sizeof(target_ulong); i++) {
if ((rs & mask) == (rb & mask)) {
ra |= mask;
}
mask <<= 8;
}
return ra;
}
/* shift right arithmetic helper */ /* shift right arithmetic helper */
target_ulong helper_sraw(CPUPPCState *env, target_ulong value, target_ulong helper_sraw(CPUPPCState *env, target_ulong value,
target_ulong shift) target_ulong shift)
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "hw/ppc/spapr.h" #include "hw/ppc/spapr.h"
#include "hw/ppc/spapr_vio.h" #include "hw/ppc/spapr_vio.h"
#include "sysemu/watchdog.h"
//#define DEBUG_KVM //#define DEBUG_KVM
...@@ -63,6 +64,9 @@ static int cap_ppc_rma; ...@@ -63,6 +64,9 @@ static int cap_ppc_rma;
static int cap_spapr_tce; static int cap_spapr_tce;
static int cap_hior; static int cap_hior;
static int cap_one_reg; static int cap_one_reg;
static int cap_epr;
static int cap_ppc_watchdog;
static int cap_papr;
/* XXX We have a race condition where we actually have a level triggered /* XXX We have a race condition where we actually have a level triggered
* interrupt, but the infrastructure can't expose that yet, so the guest * interrupt, but the infrastructure can't expose that yet, so the guest
...@@ -95,6 +99,10 @@ int kvm_arch_init(KVMState *s) ...@@ -95,6 +99,10 @@ int kvm_arch_init(KVMState *s)
cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE); cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE);
cap_one_reg = kvm_check_extension(s, KVM_CAP_ONE_REG); cap_one_reg = kvm_check_extension(s, KVM_CAP_ONE_REG);
cap_hior = kvm_check_extension(s, KVM_CAP_PPC_HIOR); cap_hior = kvm_check_extension(s, KVM_CAP_PPC_HIOR);
cap_epr = kvm_check_extension(s, KVM_CAP_PPC_EPR);
cap_ppc_watchdog = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_WATCHDOG);
/* Note: we don't set cap_papr here, because this capability is
* only activated after this by kvmppc_set_papr() */
if (!cap_interrupt_level) { if (!cap_interrupt_level) {
fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the " fprintf(stderr, "KVM: Couldn't find level irq capability. Expect the "
...@@ -652,6 +660,103 @@ static int kvm_get_fp(CPUState *cs) ...@@ -652,6 +660,103 @@ static int kvm_get_fp(CPUState *cs)
return 0; return 0;
} }
#if defined(TARGET_PPC64)
static int kvm_get_vpa(CPUState *cs)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *env = &cpu->env;
struct kvm_one_reg reg;
int ret;
reg.id = KVM_REG_PPC_VPA_ADDR;
reg.addr = (uintptr_t)&env->vpa_addr;
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
if (ret < 0) {
dprintf("Unable to get VPA address from KVM: %s\n", strerror(errno));
return ret;
}
assert((uintptr_t)&env->slb_shadow_size
== ((uintptr_t)&env->slb_shadow_addr + 8));
reg.id = KVM_REG_PPC_VPA_SLB;
reg.addr = (uintptr_t)&env->slb_shadow_addr;
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
if (ret < 0) {
dprintf("Unable to get SLB shadow state from KVM: %s\n",
strerror(errno));
return ret;
}
assert((uintptr_t)&env->dtl_size == ((uintptr_t)&env->dtl_addr + 8));
reg.id = KVM_REG_PPC_VPA_DTL;
reg.addr = (uintptr_t)&env->dtl_addr;
ret = kvm_vcpu_ioctl(cs, KVM_GET_ONE_REG, &reg);
if (ret < 0) {
dprintf("Unable to get dispatch trace log state from KVM: %s\n",
strerror(errno));
return ret;
}
return 0;
}
static int kvm_put_vpa(CPUState *cs)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *env = &cpu->env;
struct kvm_one_reg reg;
int ret;
/* SLB shadow or DTL can't be registered unless a master VPA is
* registered. That means when restoring state, if a VPA *is*
* registered, we need to set that up first. If not, we need to
* deregister the others before deregistering the master VPA */
assert(env->vpa_addr || !(env->slb_shadow_addr || env->dtl_addr));
if (env->vpa_addr) {
reg.id = KVM_REG_PPC_VPA_ADDR;
reg.addr = (uintptr_t)&env->vpa_addr;
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
if (ret < 0) {
dprintf("Unable to set VPA address to KVM: %s\n", strerror(errno));
return ret;
}
}
assert((uintptr_t)&env->slb_shadow_size
== ((uintptr_t)&env->slb_shadow_addr + 8));
reg.id = KVM_REG_PPC_VPA_SLB;
reg.addr = (uintptr_t)&env->slb_shadow_addr;
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
if (ret < 0) {
dprintf("Unable to set SLB shadow state to KVM: %s\n", strerror(errno));
return ret;
}
assert((uintptr_t)&env->dtl_size == ((uintptr_t)&env->dtl_addr + 8));
reg.id = KVM_REG_PPC_VPA_DTL;
reg.addr = (uintptr_t)&env->dtl_addr;
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
if (ret < 0) {
dprintf("Unable to set dispatch trace log state to KVM: %s\n",
strerror(errno));
return ret;
}
if (!env->vpa_addr) {
reg.id = KVM_REG_PPC_VPA_ADDR;
reg.addr = (uintptr_t)&env->vpa_addr;
ret = kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
if (ret < 0) {
dprintf("Unable to set VPA address to KVM: %s\n", strerror(errno));
return ret;
}
}
return 0;
}
#endif /* TARGET_PPC64 */
int kvm_arch_put_registers(CPUState *cs, int level) int kvm_arch_put_registers(CPUState *cs, int level)
{ {
PowerPCCPU *cpu = POWERPC_CPU(cs); PowerPCCPU *cpu = POWERPC_CPU(cs);
...@@ -752,6 +857,14 @@ int kvm_arch_put_registers(CPUState *cs, int level) ...@@ -752,6 +857,14 @@ int kvm_arch_put_registers(CPUState *cs, int level)
kvm_put_one_spr(cs, id, i); kvm_put_one_spr(cs, id, i);
} }
} }
#ifdef TARGET_PPC64
if (cap_papr) {
if (kvm_put_vpa(cs) < 0) {
dprintf("Warning: Unable to set VPA information to KVM\n");
}
}
#endif /* TARGET_PPC64 */
} }
return ret; return ret;
...@@ -953,6 +1066,14 @@ int kvm_arch_get_registers(CPUState *cs) ...@@ -953,6 +1066,14 @@ int kvm_arch_get_registers(CPUState *cs)
kvm_get_one_spr(cs, id, i); kvm_get_one_spr(cs, id, i);
} }
} }
#ifdef TARGET_PPC64
if (cap_papr) {
if (kvm_get_vpa(cs) < 0) {
dprintf("Warning: Unable to get VPA information from KVM\n");
}
}
#endif
} }
return 0; return 0;
...@@ -1092,6 +1213,12 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) ...@@ -1092,6 +1213,12 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
run->epr.epr = ldl_phys(env->mpic_iack); run->epr.epr = ldl_phys(env->mpic_iack);
ret = 0; ret = 0;
break; break;
case KVM_EXIT_WATCHDOG:
dprintf("handle watchdog expiry\n");
watchdog_perform_action();
ret = 0;
break;
default: default:
fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason); fprintf(stderr, "KVM: unknown exit reason %d\n", run->exit_reason);
ret = -1; ret = -1;
...@@ -1101,6 +1228,71 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) ...@@ -1101,6 +1228,71 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run)
return ret; return ret;
} }
int kvmppc_or_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits)
{
CPUState *cs = CPU(cpu);
uint32_t bits = tsr_bits;
struct kvm_one_reg reg = {
.id = KVM_REG_PPC_OR_TSR,
.addr = (uintptr_t) &bits,
};
return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
}
int kvmppc_clear_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits)
{
CPUState *cs = CPU(cpu);
uint32_t bits = tsr_bits;
struct kvm_one_reg reg = {
.id = KVM_REG_PPC_CLEAR_TSR,
.addr = (uintptr_t) &bits,
};
return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
}
int kvmppc_set_tcr(PowerPCCPU *cpu)
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
uint32_t tcr = env->spr[SPR_BOOKE_TCR];
struct kvm_one_reg reg = {
.id = KVM_REG_PPC_TCR,
.addr = (uintptr_t) &tcr,
};
return kvm_vcpu_ioctl(cs, KVM_SET_ONE_REG, &reg);
}
int kvmppc_booke_watchdog_enable(PowerPCCPU *cpu)
{
CPUState *cs = CPU(cpu);
struct kvm_enable_cap encap = {};
int ret;
if (!kvm_enabled()) {
return -1;
}
if (!cap_ppc_watchdog) {
printf("warning: KVM does not support watchdog");
return -1;
}
encap.cap = KVM_CAP_PPC_BOOKE_WATCHDOG;
ret = kvm_vcpu_ioctl(cs, KVM_ENABLE_CAP, &encap);
if (ret < 0) {
fprintf(stderr, "%s: couldn't enable KVM_CAP_PPC_BOOKE_WATCHDOG: %s\n",
__func__, strerror(-ret));
return ret;
}
return ret;
}
static int read_cpuinfo(const char *field, char *value, int len) static int read_cpuinfo(const char *field, char *value, int len)
{ {
FILE *f; FILE *f;
...@@ -1301,6 +1493,10 @@ void kvmppc_set_papr(PowerPCCPU *cpu) ...@@ -1301,6 +1493,10 @@ void kvmppc_set_papr(PowerPCCPU *cpu)
if (ret) { if (ret) {
cpu_abort(env, "This KVM version does not support PAPR\n"); cpu_abort(env, "This KVM version does not support PAPR\n");
} }
/* Update the capability flag so we sync the right information
* with kvm */
cap_papr = 1;
} }
void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy) void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy)
...@@ -1370,11 +1566,35 @@ off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem) ...@@ -1370,11 +1566,35 @@ off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem)
uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift) uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift)
{ {
struct kvm_ppc_smmu_info info;
long rampagesize, best_page_shift;
int i;
if (cap_ppc_rma >= 2) { if (cap_ppc_rma >= 2) {
return current_size; return current_size;
} }
/* Find the largest hardware supported page size that's less than
* or equal to the (logical) backing page size of guest RAM */
kvm_get_smmu_info(ppc_env_get_cpu(first_cpu), &info);
rampagesize = getrampagesize();
best_page_shift = 0;
for (i = 0; i < KVM_PPC_PAGE_SIZES_MAX_SZ; i++) {
struct kvm_ppc_one_seg_page_size *sps = &info.sps[i];
if (!sps->page_shift) {
continue;
}
if ((sps->page_shift > best_page_shift)
&& ((1UL << sps->page_shift) <= rampagesize)) {
best_page_shift = sps->page_shift;
}
}
return MIN(current_size, return MIN(current_size,
getrampagesize() << (hash_shift - 7)); 1ULL << (best_page_shift + hash_shift - 7));
} }
#endif #endif
...@@ -1503,6 +1723,8 @@ static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data) ...@@ -1503,6 +1723,8 @@ static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data)
PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
uint32_t vmx = kvmppc_get_vmx(); uint32_t vmx = kvmppc_get_vmx();
uint32_t dfp = kvmppc_get_dfp(); uint32_t dfp = kvmppc_get_dfp();
uint32_t dcache_size = kvmppc_read_int_cpu_dt("d-cache-size");
uint32_t icache_size = kvmppc_read_int_cpu_dt("i-cache-size");
/* Now fix up the class with information we can query from the host */ /* Now fix up the class with information we can query from the host */
...@@ -1515,6 +1737,14 @@ static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data) ...@@ -1515,6 +1737,14 @@ static void kvmppc_host_cpu_class_init(ObjectClass *oc, void *data)
/* Only override when we know what the host supports */ /* Only override when we know what the host supports */
alter_insns(&pcc->insns_flags2, PPC2_DFP, dfp); alter_insns(&pcc->insns_flags2, PPC2_DFP, dfp);
} }
if (dcache_size != -1) {
pcc->l1_dcache_size = dcache_size;
}
if (icache_size != -1) {
pcc->l1_icache_size = icache_size;
}
} }
int kvmppc_fixup_cpu(PowerPCCPU *cpu) int kvmppc_fixup_cpu(PowerPCCPU *cpu)
...@@ -1530,6 +1760,11 @@ int kvmppc_fixup_cpu(PowerPCCPU *cpu) ...@@ -1530,6 +1760,11 @@ int kvmppc_fixup_cpu(PowerPCCPU *cpu)
return 0; return 0;
} }
bool kvmppc_has_cap_epr(void)
{
return cap_epr;
}
static int kvm_ppc_register_host_cpu_type(void) static int kvm_ppc_register_host_cpu_type(void)
{ {
TypeInfo type_info = { TypeInfo type_info = {
......
...@@ -25,6 +25,10 @@ int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level); ...@@ -25,6 +25,10 @@ int kvmppc_set_interrupt(PowerPCCPU *cpu, int irq, int level);
void kvmppc_set_papr(PowerPCCPU *cpu); void kvmppc_set_papr(PowerPCCPU *cpu);
void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy); void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy);
int kvmppc_smt_threads(void); int kvmppc_smt_threads(void);
int kvmppc_clear_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits);
int kvmppc_or_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits);
int kvmppc_set_tcr(PowerPCCPU *cpu);
int kvmppc_booke_watchdog_enable(PowerPCCPU *cpu);
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem); off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem);
void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd); void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd);
...@@ -33,6 +37,7 @@ int kvmppc_reset_htab(int shift_hint); ...@@ -33,6 +37,7 @@ int kvmppc_reset_htab(int shift_hint);
uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift); uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift);
#endif /* !CONFIG_USER_ONLY */ #endif /* !CONFIG_USER_ONLY */
int kvmppc_fixup_cpu(PowerPCCPU *cpu); int kvmppc_fixup_cpu(PowerPCCPU *cpu);
bool kvmppc_has_cap_epr(void);
#else #else
...@@ -89,6 +94,26 @@ static inline int kvmppc_smt_threads(void) ...@@ -89,6 +94,26 @@ static inline int kvmppc_smt_threads(void)
return 1; return 1;
} }
static inline int kvmppc_or_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits)
{
return 0;
}
static inline int kvmppc_clear_tsr_bits(PowerPCCPU *cpu, uint32_t tsr_bits)
{
return 0;
}
static inline int kvmppc_set_tcr(PowerPCCPU *cpu)
{
return 0;
}
static inline int kvmppc_booke_watchdog_enable(PowerPCCPU *cpu)
{
return -1;
}
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
static inline off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem) static inline off_t kvmppc_alloc_rma(const char *name, MemoryRegion *sysmem)
{ {
...@@ -129,6 +154,11 @@ static inline int kvmppc_fixup_cpu(PowerPCCPU *cpu) ...@@ -129,6 +154,11 @@ static inline int kvmppc_fixup_cpu(PowerPCCPU *cpu)
{ {
return -1; return -1;
} }
static inline bool kvmppc_has_cap_epr(void)
{
return false;
}
#endif #endif
#ifndef CONFIG_KVM #ifndef CONFIG_KVM
......
...@@ -78,7 +78,6 @@ void cpu_save(QEMUFile *f, void *opaque) ...@@ -78,7 +78,6 @@ void cpu_save(QEMUFile *f, void *opaque)
for (i = 0; i < POWERPC_EXCP_NB; i++) for (i = 0; i < POWERPC_EXCP_NB; i++)
qemu_put_betls(f, &env->excp_vectors[i]); qemu_put_betls(f, &env->excp_vectors[i]);
qemu_put_betls(f, &env->excp_prefix); qemu_put_betls(f, &env->excp_prefix);
qemu_put_betls(f, &env->hreset_excp_prefix);
qemu_put_betls(f, &env->ivor_mask); qemu_put_betls(f, &env->ivor_mask);
qemu_put_betls(f, &env->ivpr_mask); qemu_put_betls(f, &env->ivpr_mask);
qemu_put_betls(f, &env->hreset_vector); qemu_put_betls(f, &env->hreset_vector);
...@@ -167,7 +166,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) ...@@ -167,7 +166,6 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
for (i = 0; i < POWERPC_EXCP_NB; i++) for (i = 0; i < POWERPC_EXCP_NB; i++)
qemu_get_betls(f, &env->excp_vectors[i]); qemu_get_betls(f, &env->excp_vectors[i]);
qemu_get_betls(f, &env->excp_prefix); qemu_get_betls(f, &env->excp_prefix);
qemu_get_betls(f, &env->hreset_excp_prefix);
qemu_get_betls(f, &env->ivor_mask); qemu_get_betls(f, &env->ivor_mask);
qemu_get_betls(f, &env->ivpr_mask); qemu_get_betls(f, &env->ivpr_mask);
qemu_get_betls(f, &env->hreset_vector); qemu_get_betls(f, &env->hreset_vector);
......
...@@ -140,7 +140,7 @@ void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t is_dcbzl) ...@@ -140,7 +140,7 @@ void helper_dcbz(CPUPPCState *env, target_ulong addr, uint32_t is_dcbzl)
{ {
int dcbz_size = env->dcache_line_size; int dcbz_size = env->dcache_line_size;
#if !defined(CONFIG_USER_ONLY) && defined(TARGET_PPC64) #if defined(TARGET_PPC64)
if (!is_dcbzl && if (!is_dcbzl &&
(env->excp_model == POWERPC_EXCP_970) && (env->excp_model == POWERPC_EXCP_970) &&
((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) { ((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1) {
......
...@@ -202,6 +202,8 @@ typedef struct DisasContext { ...@@ -202,6 +202,8 @@ typedef struct DisasContext {
int spe_enabled; int spe_enabled;
ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */ ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
int singlestep_enabled; int singlestep_enabled;
uint64_t insns_flags;
uint64_t insns_flags2;
} DisasContext; } DisasContext;
/* True when active word size < size of target_long. */ /* True when active word size < size of target_long. */
...@@ -423,9 +425,14 @@ EXTRACT_HELPER(ME, 1, 5); ...@@ -423,9 +425,14 @@ EXTRACT_HELPER(ME, 1, 5);
EXTRACT_HELPER(TO, 21, 5); EXTRACT_HELPER(TO, 21, 5);
EXTRACT_HELPER(CRM, 12, 8); EXTRACT_HELPER(CRM, 12, 8);
EXTRACT_HELPER(FM, 17, 8);
EXTRACT_HELPER(SR, 16, 4); EXTRACT_HELPER(SR, 16, 4);
/* mtfsf/mtfsfi */
EXTRACT_HELPER(FPBF, 19, 3);
EXTRACT_HELPER(FPIMM, 12, 4); EXTRACT_HELPER(FPIMM, 12, 4);
EXTRACT_HELPER(FPL, 21, 1);
EXTRACT_HELPER(FPFLM, 17, 8);
EXTRACT_HELPER(FPW, 16, 1);
/*** Jump target decoding ***/ /*** Jump target decoding ***/
/* Displacement */ /* Displacement */
...@@ -739,6 +746,13 @@ static void gen_isel(DisasContext *ctx) ...@@ -739,6 +746,13 @@ static void gen_isel(DisasContext *ctx)
tcg_temp_free_i32(t0); tcg_temp_free_i32(t0);
} }
/* cmpb: PowerPC 2.05 specification */
static void gen_cmpb(DisasContext *ctx)
{
gen_helper_cmpb(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)],
cpu_gpr[rB(ctx->opcode)]);
}
/*** Integer arithmetic ***/ /*** Integer arithmetic ***/
static inline void gen_op_arith_compute_ov(DisasContext *ctx, TCGv arg0, static inline void gen_op_arith_compute_ov(DisasContext *ctx, TCGv arg0,
...@@ -746,7 +760,7 @@ static inline void gen_op_arith_compute_ov(DisasContext *ctx, TCGv arg0, ...@@ -746,7 +760,7 @@ static inline void gen_op_arith_compute_ov(DisasContext *ctx, TCGv arg0,
{ {
TCGv t0 = tcg_temp_new(); TCGv t0 = tcg_temp_new();
tcg_gen_xor_tl(cpu_ov, arg0, arg1); tcg_gen_xor_tl(cpu_ov, arg0, arg2);
tcg_gen_xor_tl(t0, arg1, arg2); tcg_gen_xor_tl(t0, arg1, arg2);
if (sub) { if (sub) {
tcg_gen_and_tl(cpu_ov, cpu_ov, t0); tcg_gen_and_tl(cpu_ov, cpu_ov, t0);
...@@ -768,22 +782,25 @@ static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1, ...@@ -768,22 +782,25 @@ static inline void gen_op_arith_add(DisasContext *ctx, TCGv ret, TCGv arg1,
{ {
TCGv t0 = ret; TCGv t0 = ret;
if (((compute_ca && add_ca) || compute_ov) if (compute_ca || compute_ov) {
&& (TCGV_EQUAL(ret, arg1) || TCGV_EQUAL(ret, arg2))) {
t0 = tcg_temp_new(); t0 = tcg_temp_new();
} }
if (compute_ca) { if (compute_ca) {
if (NARROW_MODE(ctx)) { if (NARROW_MODE(ctx)) {
/* Caution: a non-obvious corner case of the spec is that we
must produce the *entire* 64-bit addition, but produce the
carry into bit 32. */
TCGv t1 = tcg_temp_new(); TCGv t1 = tcg_temp_new();
tcg_gen_ext32u_tl(t1, arg2); tcg_gen_xor_tl(t1, arg1, arg2); /* add without carry */
tcg_gen_ext32u_tl(t0, arg1); tcg_gen_add_tl(t0, arg1, arg2);
tcg_gen_add_tl(t0, t0, t1);
tcg_temp_free(t1);
if (add_ca) { if (add_ca) {
tcg_gen_add_tl(t0, t0, cpu_ca); tcg_gen_add_tl(t0, t0, cpu_ca);
} }
tcg_gen_shri_tl(cpu_ca, t0, 32); tcg_gen_xor_tl(cpu_ca, t0, t1); /* bits changed w/ carry */
tcg_temp_free(t1);
tcg_gen_shri_tl(cpu_ca, cpu_ca, 32); /* extract bit 32 */
tcg_gen_andi_tl(cpu_ca, cpu_ca, 1);
} else { } else {
TCGv zero = tcg_const_tl(0); TCGv zero = tcg_const_tl(0);
if (add_ca) { if (add_ca) {
...@@ -1122,24 +1139,30 @@ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1, ...@@ -1122,24 +1139,30 @@ static inline void gen_op_arith_subf(DisasContext *ctx, TCGv ret, TCGv arg1,
{ {
TCGv t0 = ret; TCGv t0 = ret;
if (compute_ov && (TCGV_EQUAL(ret, arg1) || TCGV_EQUAL(ret, arg2))) { if (compute_ca || compute_ov) {
t0 = tcg_temp_new(); t0 = tcg_temp_new();
} }
if (compute_ca) { if (compute_ca) {
/* dest = ~arg1 + arg2 [+ ca]. */ /* dest = ~arg1 + arg2 [+ ca]. */
if (NARROW_MODE(ctx)) { if (NARROW_MODE(ctx)) {
/* Caution: a non-obvious corner case of the spec is that we
must produce the *entire* 64-bit addition, but produce the
carry into bit 32. */
TCGv inv1 = tcg_temp_new(); TCGv inv1 = tcg_temp_new();
TCGv t1 = tcg_temp_new();
tcg_gen_not_tl(inv1, arg1); tcg_gen_not_tl(inv1, arg1);
tcg_gen_ext32u_tl(t0, arg2);
tcg_gen_ext32u_tl(inv1, inv1);
if (add_ca) { if (add_ca) {
tcg_gen_add_tl(t0, t0, cpu_ca); tcg_gen_add_tl(t0, arg2, cpu_ca);
} else { } else {
tcg_gen_addi_tl(t0, t0, 1); tcg_gen_addi_tl(t0, arg2, 1);
} }
tcg_gen_xor_tl(t1, arg2, inv1); /* add without carry */
tcg_gen_add_tl(t0, t0, inv1); tcg_gen_add_tl(t0, t0, inv1);
tcg_gen_shri_tl(cpu_ca, t0, 32); tcg_gen_xor_tl(cpu_ca, t0, t1); /* bits changes w/ carry */
tcg_temp_free(t1);
tcg_gen_shri_tl(cpu_ca, cpu_ca, 32); /* extract bit 32 */
tcg_gen_andi_tl(cpu_ca, cpu_ca, 1);
} else if (add_ca) { } else if (add_ca) {
TCGv zero, inv1 = tcg_temp_new(); TCGv zero, inv1 = tcg_temp_new();
tcg_gen_not_tl(inv1, arg1); tcg_gen_not_tl(inv1, arg1);
...@@ -1451,6 +1474,38 @@ static void gen_popcntd(DisasContext *ctx) ...@@ -1451,6 +1474,38 @@ static void gen_popcntd(DisasContext *ctx)
} }
#endif #endif
/* prtyw: PowerPC 2.05 specification */
static void gen_prtyw(DisasContext *ctx)
{
TCGv ra = cpu_gpr[rA(ctx->opcode)];
TCGv rs = cpu_gpr[rS(ctx->opcode)];
TCGv t0 = tcg_temp_new();
tcg_gen_shri_tl(t0, rs, 16);
tcg_gen_xor_tl(ra, rs, t0);
tcg_gen_shri_tl(t0, ra, 8);
tcg_gen_xor_tl(ra, ra, t0);
tcg_gen_andi_tl(ra, ra, (target_ulong)0x100000001ULL);
tcg_temp_free(t0);
}
#if defined(TARGET_PPC64)
/* prtyd: PowerPC 2.05 specification */
static void gen_prtyd(DisasContext *ctx)
{
TCGv ra = cpu_gpr[rA(ctx->opcode)];
TCGv rs = cpu_gpr[rS(ctx->opcode)];
TCGv t0 = tcg_temp_new();
tcg_gen_shri_tl(t0, rs, 32);
tcg_gen_xor_tl(ra, rs, t0);
tcg_gen_shri_tl(t0, ra, 16);
tcg_gen_xor_tl(ra, ra, t0);
tcg_gen_shri_tl(t0, ra, 8);
tcg_gen_xor_tl(ra, ra, t0);
tcg_gen_andi_tl(ra, ra, 1);
tcg_temp_free(t0);
}
#endif
#if defined(TARGET_PPC64) #if defined(TARGET_PPC64)
/* extsw & extsw. */ /* extsw & extsw. */
GEN_LOGICAL1(extsw, tcg_gen_ext32s_tl, 0x1E, PPC_64B); GEN_LOGICAL1(extsw, tcg_gen_ext32s_tl, 0x1E, PPC_64B);
...@@ -2161,7 +2216,16 @@ static void gen_fcmpu(DisasContext *ctx) ...@@ -2161,7 +2216,16 @@ static void gen_fcmpu(DisasContext *ctx)
/*** Floating-point move ***/ /*** Floating-point move ***/
/* fabs */ /* fabs */
/* XXX: beware that fabs never checks for NaNs nor update FPSCR */ /* XXX: beware that fabs never checks for NaNs nor update FPSCR */
GEN_FLOAT_B(abs, 0x08, 0x08, 0, PPC_FLOAT); static void gen_fabs(DisasContext *ctx)
{
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
tcg_gen_andi_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)],
~(1ULL << 63));
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 0, Rc(ctx->opcode) != 0);
}
/* fmr - fmr. */ /* fmr - fmr. */
/* XXX: beware that fmr never checks for NaNs nor update FPSCR */ /* XXX: beware that fmr never checks for NaNs nor update FPSCR */
...@@ -2177,10 +2241,42 @@ static void gen_fmr(DisasContext *ctx) ...@@ -2177,10 +2241,42 @@ static void gen_fmr(DisasContext *ctx)
/* fnabs */ /* fnabs */
/* XXX: beware that fnabs never checks for NaNs nor update FPSCR */ /* XXX: beware that fnabs never checks for NaNs nor update FPSCR */
GEN_FLOAT_B(nabs, 0x08, 0x04, 0, PPC_FLOAT); static void gen_fnabs(DisasContext *ctx)
{
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
tcg_gen_ori_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)],
1ULL << 63);
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 0, Rc(ctx->opcode) != 0);
}
/* fneg */ /* fneg */
/* XXX: beware that fneg never checks for NaNs nor update FPSCR */ /* XXX: beware that fneg never checks for NaNs nor update FPSCR */
GEN_FLOAT_B(neg, 0x08, 0x01, 0, PPC_FLOAT); static void gen_fneg(DisasContext *ctx)
{
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
tcg_gen_xori_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)],
1ULL << 63);
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 0, Rc(ctx->opcode) != 0);
}
/* fcpsgn: PowerPC 2.05 specification */
/* XXX: beware that fcpsgn never checks for NaNs nor update FPSCR */
static void gen_fcpsgn(DisasContext *ctx)
{
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
tcg_gen_deposit_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],
cpu_fpr[rB(ctx->opcode)], 0, 63);
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 0, Rc(ctx->opcode) != 0);
}
/*** Floating-Point status & ctrl register ***/ /*** Floating-Point status & ctrl register ***/
...@@ -2271,19 +2367,27 @@ static void gen_mtfsb1(DisasContext *ctx) ...@@ -2271,19 +2367,27 @@ static void gen_mtfsb1(DisasContext *ctx)
static void gen_mtfsf(DisasContext *ctx) static void gen_mtfsf(DisasContext *ctx)
{ {
TCGv_i32 t0; TCGv_i32 t0;
int L = ctx->opcode & 0x02000000; int flm, l, w;
if (unlikely(!ctx->fpu_enabled)) { if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU); gen_exception(ctx, POWERPC_EXCP_FPU);
return; return;
} }
flm = FPFLM(ctx->opcode);
l = FPL(ctx->opcode);
w = FPW(ctx->opcode);
if (unlikely(w & !(ctx->insns_flags2 & PPC2_ISA205))) {
gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
return;
}
/* NIP cannot be restored if the memory exception comes from an helper */ /* NIP cannot be restored if the memory exception comes from an helper */
gen_update_nip(ctx, ctx->nip - 4); gen_update_nip(ctx, ctx->nip - 4);
gen_reset_fpstatus(); gen_reset_fpstatus();
if (L) if (l) {
t0 = tcg_const_i32(0xff); t0 = tcg_const_i32((ctx->insns_flags2 & PPC2_ISA205) ? 0xffff : 0xff);
else } else {
t0 = tcg_const_i32(FM(ctx->opcode)); t0 = tcg_const_i32(flm << (w * 8));
}
gen_helper_store_fpscr(cpu_env, cpu_fpr[rB(ctx->opcode)], t0); gen_helper_store_fpscr(cpu_env, cpu_fpr[rB(ctx->opcode)], t0);
tcg_temp_free_i32(t0); tcg_temp_free_i32(t0);
if (unlikely(Rc(ctx->opcode) != 0)) { if (unlikely(Rc(ctx->opcode) != 0)) {
...@@ -2297,7 +2401,7 @@ static void gen_mtfsf(DisasContext *ctx) ...@@ -2297,7 +2401,7 @@ static void gen_mtfsf(DisasContext *ctx)
/* mtfsfi */ /* mtfsfi */
static void gen_mtfsfi(DisasContext *ctx) static void gen_mtfsfi(DisasContext *ctx)
{ {
int bf, sh; int bf, sh, w;
TCGv_i64 t0; TCGv_i64 t0;
TCGv_i32 t1; TCGv_i32 t1;
...@@ -2305,12 +2409,17 @@ static void gen_mtfsfi(DisasContext *ctx) ...@@ -2305,12 +2409,17 @@ static void gen_mtfsfi(DisasContext *ctx)
gen_exception(ctx, POWERPC_EXCP_FPU); gen_exception(ctx, POWERPC_EXCP_FPU);
return; return;
} }
bf = crbD(ctx->opcode) >> 2; w = FPW(ctx->opcode);
sh = 7 - bf; bf = FPBF(ctx->opcode);
if (unlikely(w & !(ctx->insns_flags2 & PPC2_ISA205))) {
gen_inval_exception(ctx, POWERPC_EXCP_INVAL_INVAL);
return;
}
sh = (8 * w) + 7 - bf;
/* NIP cannot be restored if the memory exception comes from an helper */ /* NIP cannot be restored if the memory exception comes from an helper */
gen_update_nip(ctx, ctx->nip - 4); gen_update_nip(ctx, ctx->nip - 4);
gen_reset_fpstatus(); gen_reset_fpstatus();
t0 = tcg_const_i64(FPIMM(ctx->opcode) << (4 * sh)); t0 = tcg_const_i64(((uint64_t)FPIMM(ctx->opcode)) << (4 * sh));
t1 = tcg_const_i32(1 << sh); t1 = tcg_const_i32(1 << sh);
gen_helper_store_fpscr(cpu_env, t0, t1); gen_helper_store_fpscr(cpu_env, t0, t1);
tcg_temp_free_i64(t0); tcg_temp_free_i64(t0);
...@@ -3211,6 +3320,72 @@ GEN_LDFS(lfd, ld64, 0x12, PPC_FLOAT); ...@@ -3211,6 +3320,72 @@ GEN_LDFS(lfd, ld64, 0x12, PPC_FLOAT);
/* lfs lfsu lfsux lfsx */ /* lfs lfsu lfsux lfsx */
GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT); GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT);
/* lfdp */
static void gen_lfdp(DisasContext *ctx)
{
TCGv EA;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
gen_set_access_type(ctx, ACCESS_FLOAT);
EA = tcg_temp_new();
gen_addr_imm_index(ctx, EA, 0); \
if (unlikely(ctx->le_mode)) {
gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
tcg_gen_addi_tl(EA, EA, 8);
gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
} else {
gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
tcg_gen_addi_tl(EA, EA, 8);
gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
}
tcg_temp_free(EA);
}
/* lfdpx */
static void gen_lfdpx(DisasContext *ctx)
{
TCGv EA;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
gen_set_access_type(ctx, ACCESS_FLOAT);
EA = tcg_temp_new();
gen_addr_reg_index(ctx, EA);
if (unlikely(ctx->le_mode)) {
gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
tcg_gen_addi_tl(EA, EA, 8);
gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
} else {
gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
tcg_gen_addi_tl(EA, EA, 8);
gen_qemu_ld64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
}
tcg_temp_free(EA);
}
/* lfiwax */
static void gen_lfiwax(DisasContext *ctx)
{
TCGv EA;
TCGv t0;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
gen_set_access_type(ctx, ACCESS_FLOAT);
EA = tcg_temp_new();
t0 = tcg_temp_new();
gen_addr_reg_index(ctx, EA);
gen_qemu_ld32u(ctx, t0, EA);
tcg_gen_ext_tl_i64(cpu_fpr[rD(ctx->opcode)], t0);
tcg_gen_ext32s_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rD(ctx->opcode)]);
tcg_temp_free(EA);
tcg_temp_free(t0);
}
/*** Floating-point store ***/ /*** Floating-point store ***/
#define GEN_STF(name, stop, opc, type) \ #define GEN_STF(name, stop, opc, type) \
static void glue(gen_, name)(DisasContext *ctx) \ static void glue(gen_, name)(DisasContext *ctx) \
...@@ -3304,6 +3479,52 @@ GEN_STFS(stfd, st64, 0x16, PPC_FLOAT); ...@@ -3304,6 +3479,52 @@ GEN_STFS(stfd, st64, 0x16, PPC_FLOAT);
/* stfs stfsu stfsux stfsx */ /* stfs stfsu stfsux stfsx */
GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT); GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT);
/* stfdp */
static void gen_stfdp(DisasContext *ctx)
{
TCGv EA;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
gen_set_access_type(ctx, ACCESS_FLOAT);
EA = tcg_temp_new();
gen_addr_imm_index(ctx, EA, 0); \
if (unlikely(ctx->le_mode)) {
gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
tcg_gen_addi_tl(EA, EA, 8);
gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
} else {
gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
tcg_gen_addi_tl(EA, EA, 8);
gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
}
tcg_temp_free(EA);
}
/* stfdpx */
static void gen_stfdpx(DisasContext *ctx)
{
TCGv EA;
if (unlikely(!ctx->fpu_enabled)) {
gen_exception(ctx, POWERPC_EXCP_FPU);
return;
}
gen_set_access_type(ctx, ACCESS_FLOAT);
EA = tcg_temp_new();
gen_addr_reg_index(ctx, EA);
if (unlikely(ctx->le_mode)) {
gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
tcg_gen_addi_tl(EA, EA, 8);
gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
} else {
gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode)], EA);
tcg_gen_addi_tl(EA, EA, 8);
gen_qemu_st64(ctx, cpu_fpr[rD(ctx->opcode) + 1], EA);
}
tcg_temp_free(EA);
}
/* Optional: */ /* Optional: */
static inline void gen_qemu_st32fiw(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2) static inline void gen_qemu_st32fiw(DisasContext *ctx, TCGv_i64 arg1, TCGv arg2)
{ {
...@@ -8426,6 +8647,7 @@ GEN_HANDLER(cmp, 0x1F, 0x00, 0x00, 0x00400000, PPC_INTEGER), ...@@ -8426,6 +8647,7 @@ GEN_HANDLER(cmp, 0x1F, 0x00, 0x00, 0x00400000, PPC_INTEGER),
GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER), GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER),
GEN_HANDLER(cmpl, 0x1F, 0x00, 0x01, 0x00400000, PPC_INTEGER), GEN_HANDLER(cmpl, 0x1F, 0x00, 0x01, 0x00400000, PPC_INTEGER),
GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER), GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER),
GEN_HANDLER_E(cmpb, 0x1F, 0x1C, 0x0F, 0x00000001, PPC_NONE, PPC2_ISA205),
GEN_HANDLER(isel, 0x1F, 0x0F, 0xFF, 0x00000001, PPC_ISEL), GEN_HANDLER(isel, 0x1F, 0x0F, 0xFF, 0x00000001, PPC_ISEL),
GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
...@@ -8453,9 +8675,11 @@ GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), ...@@ -8453,9 +8675,11 @@ GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
GEN_HANDLER(popcntb, 0x1F, 0x03, 0x03, 0x0000F801, PPC_POPCNTB), GEN_HANDLER(popcntb, 0x1F, 0x03, 0x03, 0x0000F801, PPC_POPCNTB),
GEN_HANDLER(popcntw, 0x1F, 0x1A, 0x0b, 0x0000F801, PPC_POPCNTWD), GEN_HANDLER(popcntw, 0x1F, 0x1A, 0x0b, 0x0000F801, PPC_POPCNTWD),
GEN_HANDLER_E(prtyw, 0x1F, 0x1A, 0x04, 0x0000F801, PPC_NONE, PPC2_ISA205),
#if defined(TARGET_PPC64) #if defined(TARGET_PPC64)
GEN_HANDLER(popcntd, 0x1F, 0x1A, 0x0F, 0x0000F801, PPC_POPCNTWD), GEN_HANDLER(popcntd, 0x1F, 0x1A, 0x0F, 0x0000F801, PPC_POPCNTWD),
GEN_HANDLER(cntlzd, 0x1F, 0x1A, 0x01, 0x00000000, PPC_64B), GEN_HANDLER(cntlzd, 0x1F, 0x1A, 0x01, 0x00000000, PPC_64B),
GEN_HANDLER_E(prtyd, 0x1F, 0x1A, 0x05, 0x0000F801, PPC_NONE, PPC2_ISA205),
#endif #endif
GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER), GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER),
...@@ -8476,13 +8700,17 @@ GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT), ...@@ -8476,13 +8700,17 @@ GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT),
GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT), GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT),
GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT), GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT),
GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT), GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT),
GEN_HANDLER(fabs, 0x3F, 0x08, 0x08, 0x001F0000, PPC_FLOAT),
GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT), GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT),
GEN_HANDLER(fnabs, 0x3F, 0x08, 0x04, 0x001F0000, PPC_FLOAT),
GEN_HANDLER(fneg, 0x3F, 0x08, 0x01, 0x001F0000, PPC_FLOAT),
GEN_HANDLER_E(fcpsgn, 0x3F, 0x08, 0x00, 0x00000000, PPC_NONE, PPC2_ISA205),
GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT), GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT),
GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT), GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT),
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, 0x00010000, PPC_FLOAT), GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x00000000, PPC_FLOAT),
GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT), GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006e0800, PPC_FLOAT),
#if defined(TARGET_PPC64) #if defined(TARGET_PPC64)
GEN_HANDLER(ld, 0x3A, 0xFF, 0xFF, 0x00000000, PPC_64B), GEN_HANDLER(ld, 0x3A, 0xFF, 0xFF, 0x00000000, PPC_64B),
GEN_HANDLER(lq, 0x38, 0xFF, 0xFF, 0x00000000, PPC_64BX), GEN_HANDLER(lq, 0x38, 0xFF, 0xFF, 0x00000000, PPC_64BX),
...@@ -8833,9 +9061,6 @@ GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT), ...@@ -8833,9 +9061,6 @@ GEN_FLOAT_B(rin, 0x08, 0x0C, 1, PPC_FLOAT_EXT),
GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT), GEN_FLOAT_B(riz, 0x08, 0x0D, 1, PPC_FLOAT_EXT),
GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT), GEN_FLOAT_B(rip, 0x08, 0x0E, 1, PPC_FLOAT_EXT),
GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT), GEN_FLOAT_B(rim, 0x08, 0x0F, 1, PPC_FLOAT_EXT),
GEN_FLOAT_B(abs, 0x08, 0x08, 0, PPC_FLOAT),
GEN_FLOAT_B(nabs, 0x08, 0x04, 0, PPC_FLOAT),
GEN_FLOAT_B(neg, 0x08, 0x01, 0, PPC_FLOAT),
#undef GEN_LD #undef GEN_LD
#undef GEN_LDU #undef GEN_LDU
...@@ -8921,6 +9146,9 @@ GEN_LDXF(name, ldop, 0x17, op | 0x00, type) ...@@ -8921,6 +9146,9 @@ GEN_LDXF(name, ldop, 0x17, op | 0x00, type)
GEN_LDFS(lfd, ld64, 0x12, PPC_FLOAT) GEN_LDFS(lfd, ld64, 0x12, PPC_FLOAT)
GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT) GEN_LDFS(lfs, ld32fs, 0x10, PPC_FLOAT)
GEN_HANDLER_E(lfiwax, 0x1f, 0x17, 0x1a, 0x00000001, PPC_NONE, PPC2_ISA205),
GEN_HANDLER_E(lfdp, 0x39, 0xFF, 0xFF, 0x00200003, PPC_NONE, PPC2_ISA205),
GEN_HANDLER_E(lfdpx, 0x1F, 0x17, 0x18, 0x00200001, PPC_NONE, PPC2_ISA205),
#undef GEN_STF #undef GEN_STF
#undef GEN_STUF #undef GEN_STUF
...@@ -8944,6 +9172,8 @@ GEN_STXF(name, stop, 0x17, op | 0x00, type) ...@@ -8944,6 +9172,8 @@ GEN_STXF(name, stop, 0x17, op | 0x00, type)
GEN_STFS(stfd, st64, 0x16, PPC_FLOAT) GEN_STFS(stfd, st64, 0x16, PPC_FLOAT)
GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT) GEN_STFS(stfs, st32fs, 0x14, PPC_FLOAT)
GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX) GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX)
GEN_HANDLER_E(stfdp, 0x3D, 0xFF, 0xFF, 0x00200003, PPC_NONE, PPC2_ISA205),
GEN_HANDLER_E(stfdpx, 0x1F, 0x17, 0x1C, 0x00200001, PPC_NONE, PPC2_ISA205),
#undef GEN_CRLOGIC #undef GEN_CRLOGIC
#define GEN_CRLOGIC(name, tcg_op, opc) \ #define GEN_CRLOGIC(name, tcg_op, opc) \
...@@ -9518,6 +9748,8 @@ static inline void gen_intermediate_code_internal(CPUPPCState *env, ...@@ -9518,6 +9748,8 @@ static inline void gen_intermediate_code_internal(CPUPPCState *env,
ctx.exception = POWERPC_EXCP_NONE; ctx.exception = POWERPC_EXCP_NONE;
ctx.spr_cb = env->spr_cb; ctx.spr_cb = env->spr_cb;
ctx.mem_idx = env->mmu_idx; ctx.mem_idx = env->mmu_idx;
ctx.insns_flags = env->insns_flags;
ctx.insns_flags2 = env->insns_flags2;
ctx.access_type = -1; ctx.access_type = -1;
ctx.le_mode = env->hflags & (1 << MSR_LE) ? 1 : 0; ctx.le_mode = env->hflags & (1 << MSR_LE) ? 1 : 0;
#if defined(TARGET_PPC64) #if defined(TARGET_PPC64)
......
...@@ -1149,6 +1149,13 @@ static void gen_spr_603 (CPUPPCState *env) ...@@ -1149,6 +1149,13 @@ static void gen_spr_603 (CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_generic,
0x00000000); 0x00000000);
/* Breakpoints */
/* XXX : not implemented */
spr_register(env, SPR_IABR, "IABR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
} }
/* SPR specific to PowerPC G2 implementation */ /* SPR specific to PowerPC G2 implementation */
...@@ -2593,7 +2600,6 @@ static void init_excp_4xx_real (CPUPPCState *env) ...@@ -2593,7 +2600,6 @@ static void init_excp_4xx_real (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_FIT] = 0x00001010; env->excp_vectors[POWERPC_EXCP_FIT] = 0x00001010;
env->excp_vectors[POWERPC_EXCP_WDT] = 0x00001020; env->excp_vectors[POWERPC_EXCP_WDT] = 0x00001020;
env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00002000; env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00002000;
env->hreset_excp_prefix = 0x00000000UL;
env->ivor_mask = 0x0000FFF0UL; env->ivor_mask = 0x0000FFF0UL;
env->ivpr_mask = 0xFFFF0000UL; env->ivpr_mask = 0xFFFF0000UL;
/* Hardware reset vector */ /* Hardware reset vector */
...@@ -2618,7 +2624,6 @@ static void init_excp_4xx_softmmu (CPUPPCState *env) ...@@ -2618,7 +2624,6 @@ static void init_excp_4xx_softmmu (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_DTLB] = 0x00001100; env->excp_vectors[POWERPC_EXCP_DTLB] = 0x00001100;
env->excp_vectors[POWERPC_EXCP_ITLB] = 0x00001200; env->excp_vectors[POWERPC_EXCP_ITLB] = 0x00001200;
env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00002000; env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00002000;
env->hreset_excp_prefix = 0x00000000UL;
env->ivor_mask = 0x0000FFF0UL; env->ivor_mask = 0x0000FFF0UL;
env->ivpr_mask = 0xFFFF0000UL; env->ivpr_mask = 0xFFFF0000UL;
/* Hardware reset vector */ /* Hardware reset vector */
...@@ -2644,11 +2649,10 @@ static void init_excp_MPC5xx (CPUPPCState *env) ...@@ -2644,11 +2649,10 @@ static void init_excp_MPC5xx (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001C00; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001C00;
env->excp_vectors[POWERPC_EXCP_MEXTBR] = 0x00001E00; env->excp_vectors[POWERPC_EXCP_MEXTBR] = 0x00001E00;
env->excp_vectors[POWERPC_EXCP_NMEXTBR] = 0x00001F00; env->excp_vectors[POWERPC_EXCP_NMEXTBR] = 0x00001F00;
env->hreset_excp_prefix = 0x00000000UL;
env->ivor_mask = 0x0000FFF0UL; env->ivor_mask = 0x0000FFF0UL;
env->ivpr_mask = 0xFFFF0000UL; env->ivpr_mask = 0xFFFF0000UL;
/* Hardware reset vector */ /* Hardware reset vector */
env->hreset_vector = 0xFFFFFFFCUL; env->hreset_vector = 0x00000100UL;
#endif #endif
} }
...@@ -2676,11 +2680,10 @@ static void init_excp_MPC8xx (CPUPPCState *env) ...@@ -2676,11 +2680,10 @@ static void init_excp_MPC8xx (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001C00; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001C00;
env->excp_vectors[POWERPC_EXCP_MEXTBR] = 0x00001E00; env->excp_vectors[POWERPC_EXCP_MEXTBR] = 0x00001E00;
env->excp_vectors[POWERPC_EXCP_NMEXTBR] = 0x00001F00; env->excp_vectors[POWERPC_EXCP_NMEXTBR] = 0x00001F00;
env->hreset_excp_prefix = 0x00000000UL;
env->ivor_mask = 0x0000FFF0UL; env->ivor_mask = 0x0000FFF0UL;
env->ivpr_mask = 0xFFFF0000UL; env->ivpr_mask = 0xFFFF0000UL;
/* Hardware reset vector */ /* Hardware reset vector */
env->hreset_vector = 0xFFFFFFFCUL; env->hreset_vector = 0x00000100UL;
#endif #endif
} }
...@@ -2704,9 +2707,8 @@ static void init_excp_G2 (CPUPPCState *env) ...@@ -2704,9 +2707,8 @@ static void init_excp_G2 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200; env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200;
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
env->hreset_excp_prefix = 0x00000000UL;
/* Hardware reset vector */ /* Hardware reset vector */
env->hreset_vector = 0xFFFFFFFCUL; env->hreset_vector = 0x00000100UL;
#endif #endif
} }
...@@ -2733,7 +2735,6 @@ static void init_excp_e200(CPUPPCState *env, target_ulong ivpr_mask) ...@@ -2733,7 +2735,6 @@ static void init_excp_e200(CPUPPCState *env, target_ulong ivpr_mask)
env->excp_vectors[POWERPC_EXCP_SPEU] = 0x00000000; env->excp_vectors[POWERPC_EXCP_SPEU] = 0x00000000;
env->excp_vectors[POWERPC_EXCP_EFPDI] = 0x00000000; env->excp_vectors[POWERPC_EXCP_EFPDI] = 0x00000000;
env->excp_vectors[POWERPC_EXCP_EFPRI] = 0x00000000; env->excp_vectors[POWERPC_EXCP_EFPRI] = 0x00000000;
env->hreset_excp_prefix = 0x00000000UL;
env->ivor_mask = 0x0000FFF7UL; env->ivor_mask = 0x0000FFF7UL;
env->ivpr_mask = ivpr_mask; env->ivpr_mask = ivpr_mask;
/* Hardware reset vector */ /* Hardware reset vector */
...@@ -2760,7 +2761,6 @@ static void init_excp_BookE (CPUPPCState *env) ...@@ -2760,7 +2761,6 @@ static void init_excp_BookE (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_DTLB] = 0x00000000; env->excp_vectors[POWERPC_EXCP_DTLB] = 0x00000000;
env->excp_vectors[POWERPC_EXCP_ITLB] = 0x00000000; env->excp_vectors[POWERPC_EXCP_ITLB] = 0x00000000;
env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00000000; env->excp_vectors[POWERPC_EXCP_DEBUG] = 0x00000000;
env->hreset_excp_prefix = 0x00000000UL;
env->ivor_mask = 0x0000FFE0UL; env->ivor_mask = 0x0000FFE0UL;
env->ivpr_mask = 0xFFFF0000UL; env->ivpr_mask = 0xFFFF0000UL;
/* Hardware reset vector */ /* Hardware reset vector */
...@@ -2783,7 +2783,6 @@ static void init_excp_601 (CPUPPCState *env) ...@@ -2783,7 +2783,6 @@ static void init_excp_601 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_IO] = 0x00000A00; env->excp_vectors[POWERPC_EXCP_IO] = 0x00000A00;
env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00; env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00;
env->excp_vectors[POWERPC_EXCP_RUNM] = 0x00002000; env->excp_vectors[POWERPC_EXCP_RUNM] = 0x00002000;
env->hreset_excp_prefix = 0xFFF00000UL;
/* Hardware reset vector */ /* Hardware reset vector */
env->hreset_vector = 0x00000100UL; env->hreset_vector = 0x00000100UL;
#endif #endif
...@@ -2811,9 +2810,8 @@ static void init_excp_602 (CPUPPCState *env) ...@@ -2811,9 +2810,8 @@ static void init_excp_602 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
env->excp_vectors[POWERPC_EXCP_WDT] = 0x00001500; env->excp_vectors[POWERPC_EXCP_WDT] = 0x00001500;
env->excp_vectors[POWERPC_EXCP_EMUL] = 0x00001600; env->excp_vectors[POWERPC_EXCP_EMUL] = 0x00001600;
env->hreset_excp_prefix = 0xFFF00000UL;
/* Hardware reset vector */ /* Hardware reset vector */
env->hreset_vector = 0xFFFFFFFCUL; env->hreset_vector = 0x00000100UL;
#endif #endif
} }
...@@ -2836,9 +2834,8 @@ static void init_excp_603 (CPUPPCState *env) ...@@ -2836,9 +2834,8 @@ static void init_excp_603 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200; env->excp_vectors[POWERPC_EXCP_DSTLB] = 0x00001200;
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
env->hreset_excp_prefix = 0x00000000UL;
/* Hardware reset vector */ /* Hardware reset vector */
env->hreset_vector = 0xFFFFFFFCUL; env->hreset_vector = 0x00000100UL;
#endif #endif
} }
...@@ -2859,7 +2856,6 @@ static void init_excp_604 (CPUPPCState *env) ...@@ -2859,7 +2856,6 @@ static void init_excp_604 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00;
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
env->hreset_excp_prefix = 0xFFF00000UL;
/* Hardware reset vector */ /* Hardware reset vector */
env->hreset_vector = 0x00000100UL; env->hreset_vector = 0x00000100UL;
#endif #endif
...@@ -2883,9 +2879,8 @@ static void init_excp_7x0 (CPUPPCState *env) ...@@ -2883,9 +2879,8 @@ static void init_excp_7x0 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700; env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700;
env->hreset_excp_prefix = 0x00000000UL;
/* Hardware reset vector */ /* Hardware reset vector */
env->hreset_vector = 0xFFFFFFFCUL; env->hreset_vector = 0x00000100UL;
#endif #endif
} }
...@@ -2906,9 +2901,8 @@ static void init_excp_750cl (CPUPPCState *env) ...@@ -2906,9 +2901,8 @@ static void init_excp_750cl (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00;
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
env->hreset_excp_prefix = 0x00000000UL;
/* Hardware reset vector */ /* Hardware reset vector */
env->hreset_vector = 0xFFFFFFFCUL; env->hreset_vector = 0x00000100UL;
#endif #endif
} }
...@@ -2929,9 +2923,8 @@ static void init_excp_750cx (CPUPPCState *env) ...@@ -2929,9 +2923,8 @@ static void init_excp_750cx (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00; env->excp_vectors[POWERPC_EXCP_PERFM] = 0x00000F00;
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700; env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700;
env->hreset_excp_prefix = 0x00000000UL;
/* Hardware reset vector */ /* Hardware reset vector */
env->hreset_vector = 0xFFFFFFFCUL; env->hreset_vector = 0x00000100UL;
#endif #endif
} }
...@@ -2957,9 +2950,8 @@ static void init_excp_7x5 (CPUPPCState *env) ...@@ -2957,9 +2950,8 @@ static void init_excp_7x5 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700; env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700;
env->hreset_excp_prefix = 0x00000000UL;
/* Hardware reset vector */ /* Hardware reset vector */
env->hreset_vector = 0xFFFFFFFCUL; env->hreset_vector = 0x00000100UL;
#endif #endif
} }
...@@ -2983,9 +2975,8 @@ static void init_excp_7400 (CPUPPCState *env) ...@@ -2983,9 +2975,8 @@ static void init_excp_7400 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001600; env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001600;
env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700; env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001700;
env->hreset_excp_prefix = 0x00000000UL;
/* Hardware reset vector */ /* Hardware reset vector */
env->hreset_vector = 0xFFFFFFFCUL; env->hreset_vector = 0x00000100UL;
#endif #endif
} }
...@@ -3011,9 +3002,8 @@ static void init_excp_7450 (CPUPPCState *env) ...@@ -3011,9 +3002,8 @@ static void init_excp_7450 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300; env->excp_vectors[POWERPC_EXCP_IABR] = 0x00001300;
env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400; env->excp_vectors[POWERPC_EXCP_SMI] = 0x00001400;
env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001600; env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001600;
env->hreset_excp_prefix = 0x00000000UL;
/* Hardware reset vector */ /* Hardware reset vector */
env->hreset_vector = 0xFFFFFFFCUL; env->hreset_vector = 0x00000100UL;
#endif #endif
} }
...@@ -3041,7 +3031,6 @@ static void init_excp_970 (CPUPPCState *env) ...@@ -3041,7 +3031,6 @@ static void init_excp_970 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_MAINT] = 0x00001600; env->excp_vectors[POWERPC_EXCP_MAINT] = 0x00001600;
env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001700; env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001700;
env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001800; env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001800;
env->hreset_excp_prefix = 0x00000000FFF00000ULL;
/* Hardware reset vector */ /* Hardware reset vector */
env->hreset_vector = 0x0000000000000100ULL; env->hreset_vector = 0x0000000000000100ULL;
#endif #endif
...@@ -3070,7 +3059,6 @@ static void init_excp_POWER7 (CPUPPCState *env) ...@@ -3070,7 +3059,6 @@ static void init_excp_POWER7 (CPUPPCState *env)
env->excp_vectors[POWERPC_EXCP_MAINT] = 0x00001600; env->excp_vectors[POWERPC_EXCP_MAINT] = 0x00001600;
env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001700; env->excp_vectors[POWERPC_EXCP_VPUA] = 0x00001700;
env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001800; env->excp_vectors[POWERPC_EXCP_THERM] = 0x00001800;
env->hreset_excp_prefix = 0;
/* Hardware reset vector */ /* Hardware reset vector */
env->hreset_vector = 0x0000000000000100ULL; env->hreset_vector = 0x0000000000000100ULL;
#endif #endif
...@@ -4157,6 +4145,33 @@ static void init_proc_G2LE (CPUPPCState *env) ...@@ -4157,6 +4145,33 @@ static void init_proc_G2LE (CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_generic,
0x00000000); 0x00000000);
/* Breakpoints */
/* XXX : not implemented */
spr_register(env, SPR_DABR, "DABR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_DABR2, "DABR2",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_IABR2, "IABR2",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_IBCR, "IBCR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_DBCR, "DBCR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* Memory management */ /* Memory management */
gen_low_BATs(env); gen_low_BATs(env);
gen_high_BATs(env); gen_high_BATs(env);
...@@ -6962,6 +6977,18 @@ static void init_proc_POWER7 (CPUPPCState *env) ...@@ -6962,6 +6977,18 @@ static void init_proc_POWER7 (CPUPPCState *env)
SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic, &spr_read_generic, &spr_write_generic,
KVM_REG_PPC_DSCR, 0x00000000); KVM_REG_PPC_DSCR, 0x00000000);
spr_register_kvm(env, SPR_MMCRA, "SPR_MMCRA",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
KVM_REG_PPC_MMCRA, 0x00000000);
spr_register_kvm(env, SPR_PMC5, "SPR_PMC5",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
KVM_REG_PPC_PMC5, 0x00000000);
spr_register_kvm(env, SPR_PMC6, "SPR_PMC6",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
KVM_REG_PPC_PMC6, 0x00000000);
#endif /* !CONFIG_USER_ONLY */ #endif /* !CONFIG_USER_ONLY */
/* Memory management */ /* Memory management */
/* XXX : not implemented */ /* XXX : not implemented */
...@@ -6989,6 +7016,7 @@ static void init_proc_POWER7 (CPUPPCState *env) ...@@ -6989,6 +7016,7 @@ static void init_proc_POWER7 (CPUPPCState *env)
init_excp_POWER7(env); init_excp_POWER7(env);
env->dcache_line_size = 128; env->dcache_line_size = 128;
env->icache_line_size = 128; env->icache_line_size = 128;
/* Allocate hardware IRQ controller */ /* Allocate hardware IRQ controller */
ppcPOWER7_irq_init(env); ppcPOWER7_irq_init(env);
/* Can't find information on what this should be on reset. This /* Can't find information on what this should be on reset. This
...@@ -7004,7 +7032,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) ...@@ -7004,7 +7032,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
dc->desc = "POWER7"; dc->desc = "POWER7";
pcc->init_proc = init_proc_POWER7; pcc->init_proc = init_proc_POWER7;
pcc->check_pow = check_pow_nocheck; pcc->check_pow = check_pow_nocheck;
pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |
PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |
PPC_FLOAT_STFIWX | PPC_FLOAT_STFIWX |
...@@ -7014,7 +7042,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) ...@@ -7014,7 +7042,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
PPC_64B | PPC_ALTIVEC | PPC_64B | PPC_ALTIVEC |
PPC_SEGMENT_64B | PPC_SLBI | PPC_SEGMENT_64B | PPC_SLBI |
PPC_POPCNTB | PPC_POPCNTWD; PPC_POPCNTB | PPC_POPCNTWD;
pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX; pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX | PPC2_ISA205;
pcc->msr_mask = 0x800000000204FF36ULL; pcc->msr_mask = 0x800000000204FF36ULL;
pcc->mmu_model = POWERPC_MMU_2_06; pcc->mmu_model = POWERPC_MMU_2_06;
#if defined(CONFIG_SOFTMMU) #if defined(CONFIG_SOFTMMU)
...@@ -7026,6 +7054,8 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) ...@@ -7026,6 +7054,8 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE |
POWERPC_FLAG_BE | POWERPC_FLAG_PMM | POWERPC_FLAG_BE | POWERPC_FLAG_PMM |
POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR; POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR;
pcc->l1_dcache_size = 0x8000;
pcc->l1_icache_size = 0x8000;
} }
#endif /* defined (TARGET_PPC64) */ #endif /* defined (TARGET_PPC64) */
...@@ -7043,7 +7073,6 @@ static void init_ppc_proc(PowerPCCPU *cpu) ...@@ -7043,7 +7073,6 @@ static void init_ppc_proc(PowerPCCPU *cpu)
/* Set all exception vectors to an invalid address */ /* Set all exception vectors to an invalid address */
for (i = 0; i < POWERPC_EXCP_NB; i++) for (i = 0; i < POWERPC_EXCP_NB; i++)
env->excp_vectors[i] = (target_ulong)(-1ULL); env->excp_vectors[i] = (target_ulong)(-1ULL);
env->hreset_excp_prefix = 0x00000000;
env->ivor_mask = 0x00000000; env->ivor_mask = 0x00000000;
env->ivpr_mask = 0x00000000; env->ivpr_mask = 0x00000000;
/* Default MMU definitions */ /* Default MMU definitions */
...@@ -7080,9 +7109,7 @@ static void init_ppc_proc(PowerPCCPU *cpu) ...@@ -7080,9 +7109,7 @@ static void init_ppc_proc(PowerPCCPU *cpu)
} }
/* PowerPC implementation specific initialisations (SPRs, timers, ...) */ /* PowerPC implementation specific initialisations (SPRs, timers, ...) */
(*pcc->init_proc)(env); (*pcc->init_proc)(env);
#if !defined(CONFIG_USER_ONLY)
env->excp_prefix = env->hreset_excp_prefix;
#endif
/* MSR bits & flags consistency checks */ /* MSR bits & flags consistency checks */
if (env->msr_mask & (1 << 25)) { if (env->msr_mask & (1 << 25)) {
switch (env->flags & (POWERPC_FLAG_SPE | POWERPC_FLAG_VRE)) { switch (env->flags & (POWERPC_FLAG_SPE | POWERPC_FLAG_VRE)) {
...@@ -8182,19 +8209,23 @@ static void ppc_cpu_reset(CPUState *s) ...@@ -8182,19 +8209,23 @@ static void ppc_cpu_reset(CPUState *s)
msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */ msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */
msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */ msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */
msr |= (target_ulong)1 << MSR_PR; msr |= (target_ulong)1 << MSR_PR;
#else
env->excp_prefix = env->hreset_excp_prefix;
env->nip = env->hreset_vector | env->excp_prefix;
if (env->mmu_model != POWERPC_MMU_REAL) {
ppc_tlb_invalidate_all(env);
}
#endif #endif
env->msr = msr & env->msr_mask;
#if defined(TARGET_PPC64) #if defined(TARGET_PPC64)
if (env->mmu_model & POWERPC_MMU_64) { if (env->mmu_model & POWERPC_MMU_64) {
env->msr |= (1ULL << MSR_SF); env->msr |= (1ULL << MSR_SF);
} }
#endif #endif
hreg_store_msr(env, msr, 1);
#if !defined(CONFIG_USER_ONLY)
env->nip = env->hreset_vector | env->excp_prefix;
if (env->mmu_model != POWERPC_MMU_REAL) {
ppc_tlb_invalidate_all(env);
}
#endif
hreg_compute_hflags(env); hreg_compute_hflags(env);
env->reserve_addr = (target_ulong)-1ULL; env->reserve_addr = (target_ulong)-1ULL;
/* Be sure no exception or interrupt is pending */ /* Be sure no exception or interrupt is pending */
......
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
#else #else
#include "exec/address-spaces.h" #include "exec/address-spaces.h"
#endif #endif
#include "qemu/timer.h"
#include "exec/cputlb.h" #include "exec/cputlb.h"
#include "translate-all.h" #include "translate-all.h"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册