Patch queue for ppc - 2015-01-07

New year's release. This time's highlights:
 
   - E500: More RAM support
   - pseries: New SLOF release
   - Migration fixes
   - Simplify USB spawning logic, removes support for explicit usb=off
   - TCG: Simple untansactional TM emulation
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.19 (GNU/Linux)
 
 iQIcBAABAgAGBQJUrU6JAAoJECszeR4D/txgclcQALbuKWkpj4O85zfC3MbbC/ld
 dORPmHFI0OChyN9YOU8UKtetIQK6FlbBB+ZA0VVOusEVpiQ/bmj+iGelTRf4R08a
 5pcqlF8yQPoWrIxH6JK+OJqg7rrNJSUSrlYnMQKsZudmvL6r1VzFCcGoL+lIzIi8
 uGoD+ngBHdEjUKRD+BxnOdkBwIm5K6FlbK1uynN1Cj9FLkYw9RsmVNqNPtd0vYSn
 2Qi4XPXZoLxwVM2x/M89d1HCW41eBeLhBr28KuXR4bphIS1eyZY5pBlS35LPPt9+
 KWo9xvkT2y+18T968vwKHLmQlqN62N0rotSFlNCpnvoo3bd6KexsSkjg497HsUR9
 eOHdgVOBOHReWmmqtjgECgjzBmI2hEY8fEHg8ktOdOJ0YupcGdbWui5+r0ObYbnp
 BKEvPiAo3/+XSASbW6NkAxcWvFt6DQx8nh5Y+9XFq1Q6Ge962SuCldzExzTo/8iQ
 kSxTeECsHZb5Ch0vPyrOICeWxeBFJYW6lWVl59qSS0NzHflBD/Nns9TBGO8LJxm6
 6NLmAu47Q7KW4xYZOXve6+I5Ze20szasiPF2v9BeV6TeKdSCd2krut1D8lUurPQM
 EdtRmAKOCRQnC3x/lzQrrRxszoCqa3OSStO9RZ5TaGeq+7zec5J3g/9iomgGtMyz
 t4Q8k66Mez8BhviG0SoS
 =28q1
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/agraf/tags/signed-ppc-for-upstream' into staging

Patch queue for ppc - 2015-01-07

New year's release. This time's highlights:

  - E500: More RAM support
  - pseries: New SLOF release
  - Migration fixes
  - Simplify USB spawning logic, removes support for explicit usb=off
  - TCG: Simple untansactional TM emulation

# gpg: Signature made Wed 07 Jan 2015 15:19:37 GMT using RSA key ID 03FEDC60
# gpg: Good signature from "Alexander Graf <agraf@suse.de>"
# gpg:                 aka "Alexander Graf <alex@csgraf.de>"

* remotes/agraf/tags/signed-ppc-for-upstream: (37 commits)
  hw/ppc/mac_newworld: simplify usb controller creation logic
  hw/ppc/spapr: simplify usb controller creation logic
  hw/ppc/mac_newworld: QOMified mac99 machines
  hw/usb: simplified usb_enabled
  hw/machine: added machine_usb wrapper
  hw/ppc: modified the condition for usb controllers to be created for some ppc machines
  target-ppc: Cast ssize_t to size_t before printing with %zx
  target-ppc: Mark SR() and gen_sync_exception() as !CONFIG_USER_ONLY
  PPC: e500: Fix GPIO controller interrupt number
  target-ppc: Introduce Privileged TM Noops
  target-ppc: Introduce tcheck
  target-ppc: Introduce TM Noops
  target-ppc: Introduce tbegin
  target-ppc: Introduce TEXASRU Bit Fields
  target-ppc: Power8 Supports Transactional Memory
  target-ppc: Introduce tm_enabled Bit to CPU State
  target-ppc: Introduce Feature Flag for Transactional Memory
  target-ppc: Introduce Instruction Type for Transactional Memory
  pseries: Update SLOF firmware image to 20141202
  PPC: Fix crash on spapr_tce_table_finalize()
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2015-01-10 19:50:21 +00:00
commit 97052d64e4
20 changed files with 538 additions and 156 deletions

View File

@ -324,6 +324,7 @@ int qemu_fdt_setprop_sized_cells_from_array(void *fdt,
uint64_t value; uint64_t value;
int cellnum, vnum, ncells; int cellnum, vnum, ncells;
uint32_t hival; uint32_t hival;
int ret;
propcells = g_new0(uint32_t, numvalues * 2); propcells = g_new0(uint32_t, numvalues * 2);
@ -331,18 +332,23 @@ int qemu_fdt_setprop_sized_cells_from_array(void *fdt,
for (vnum = 0; vnum < numvalues; vnum++) { for (vnum = 0; vnum < numvalues; vnum++) {
ncells = values[vnum * 2]; ncells = values[vnum * 2];
if (ncells != 1 && ncells != 2) { if (ncells != 1 && ncells != 2) {
return -1; ret = -1;
goto out;
} }
value = values[vnum * 2 + 1]; value = values[vnum * 2 + 1];
hival = cpu_to_be32(value >> 32); hival = cpu_to_be32(value >> 32);
if (ncells > 1) { if (ncells > 1) {
propcells[cellnum++] = hival; propcells[cellnum++] = hival;
} else if (hival != 0) { } else if (hival != 0) {
return -1; ret = -1;
goto out;
} }
propcells[cellnum++] = cpu_to_be32(value); propcells[cellnum++] = cpu_to_be32(value);
} }
return qemu_fdt_setprop(fdt, node_path, property, propcells, ret = qemu_fdt_setprop(fdt, node_path, property, propcells,
cellnum * sizeof(uint32_t)); cellnum * sizeof(uint32_t));
out:
g_free(propcells);
return ret;
} }

View File

@ -62,11 +62,19 @@
#define PPCE500_PCI_NR_POBS 5 #define PPCE500_PCI_NR_POBS 5
#define PPCE500_PCI_NR_PIBS 3 #define PPCE500_PCI_NR_PIBS 3
#define PIWAR_EN 0x80000000 /* Enable */
#define PIWAR_PF 0x20000000 /* prefetch */
#define PIWAR_TGI_LOCAL 0x00f00000 /* target - local memory */
#define PIWAR_READ_SNOOP 0x00050000
#define PIWAR_WRITE_SNOOP 0x00005000
#define PIWAR_SZ_MASK 0x0000003f
struct pci_outbound { struct pci_outbound {
uint32_t potar; uint32_t potar;
uint32_t potear; uint32_t potear;
uint32_t powbar; uint32_t powbar;
uint32_t powar; uint32_t powar;
MemoryRegion mem;
}; };
struct pci_inbound { struct pci_inbound {
@ -74,6 +82,7 @@ struct pci_inbound {
uint32_t piwbar; uint32_t piwbar;
uint32_t piwbear; uint32_t piwbear;
uint32_t piwar; uint32_t piwar;
MemoryRegion mem;
}; };
#define TYPE_PPC_E500_PCI_HOST_BRIDGE "e500-pcihost" #define TYPE_PPC_E500_PCI_HOST_BRIDGE "e500-pcihost"
@ -91,10 +100,13 @@ struct PPCE500PCIState {
uint32_t irq_num[PCI_NUM_PINS]; uint32_t irq_num[PCI_NUM_PINS];
uint32_t first_slot; uint32_t first_slot;
uint32_t first_pin_irq; uint32_t first_pin_irq;
AddressSpace bm_as;
MemoryRegion bm;
/* mmio maps */ /* mmio maps */
MemoryRegion container; MemoryRegion container;
MemoryRegion iomem; MemoryRegion iomem;
MemoryRegion pio; MemoryRegion pio;
MemoryRegion busmem;
}; };
#define TYPE_PPC_E500_PCI_BRIDGE "e500-host-bridge" #define TYPE_PPC_E500_PCI_BRIDGE "e500-host-bridge"
@ -181,6 +193,71 @@ static uint64_t pci_reg_read4(void *opaque, hwaddr addr,
return value; return value;
} }
/* DMA mapping */
static void e500_update_piw(PPCE500PCIState *pci, int idx)
{
uint64_t tar = ((uint64_t)pci->pib[idx].pitar) << 12;
uint64_t wbar = ((uint64_t)pci->pib[idx].piwbar) << 12;
uint64_t war = pci->pib[idx].piwar;
uint64_t size = 2ULL << (war & PIWAR_SZ_MASK);
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *mem = &pci->pib[idx].mem;
MemoryRegion *bm = &pci->bm;
char *name;
if (memory_region_is_mapped(mem)) {
/* Before we modify anything, unmap and destroy the region */
memory_region_del_subregion(bm, mem);
object_unparent(OBJECT(mem));
}
if (!(war & PIWAR_EN)) {
/* Not enabled, nothing to do */
return;
}
name = g_strdup_printf("PCI Inbound Window %d", idx);
memory_region_init_alias(mem, OBJECT(pci), name, address_space_mem, tar,
size);
memory_region_add_subregion_overlap(bm, wbar, mem, -1);
g_free(name);
pci_debug("%s: Added window of size=%#lx from PCI=%#lx to CPU=%#lx\n",
__func__, size, wbar, tar);
}
/* BAR mapping */
static void e500_update_pow(PPCE500PCIState *pci, int idx)
{
uint64_t tar = ((uint64_t)pci->pob[idx].potar) << 12;
uint64_t wbar = ((uint64_t)pci->pob[idx].powbar) << 12;
uint64_t war = pci->pob[idx].powar;
uint64_t size = 2ULL << (war & PIWAR_SZ_MASK);
MemoryRegion *mem = &pci->pob[idx].mem;
MemoryRegion *address_space_mem = get_system_memory();
char *name;
if (memory_region_is_mapped(mem)) {
/* Before we modify anything, unmap and destroy the region */
memory_region_del_subregion(address_space_mem, mem);
object_unparent(OBJECT(mem));
}
if (!(war & PIWAR_EN)) {
/* Not enabled, nothing to do */
return;
}
name = g_strdup_printf("PCI Outbound Window %d", idx);
memory_region_init_alias(mem, OBJECT(pci), name, &pci->busmem, tar,
size);
memory_region_add_subregion(address_space_mem, wbar, mem);
g_free(name);
pci_debug("%s: Added window of size=%#lx from CPU=%#lx to PCI=%#lx\n",
__func__, size, wbar, tar);
}
static void pci_reg_write4(void *opaque, hwaddr addr, static void pci_reg_write4(void *opaque, hwaddr addr,
uint64_t value, unsigned size) uint64_t value, unsigned size)
{ {
@ -199,18 +276,22 @@ static void pci_reg_write4(void *opaque, hwaddr addr,
case PPCE500_PCI_OW3: case PPCE500_PCI_OW3:
case PPCE500_PCI_OW4: case PPCE500_PCI_OW4:
idx = (addr >> 5) & 0x7; idx = (addr >> 5) & 0x7;
switch (addr & 0xC) { switch (addr & 0x1F) {
case PCI_POTAR: case PCI_POTAR:
pci->pob[idx].potar = value; pci->pob[idx].potar = value;
e500_update_pow(pci, idx);
break; break;
case PCI_POTEAR: case PCI_POTEAR:
pci->pob[idx].potear = value; pci->pob[idx].potear = value;
e500_update_pow(pci, idx);
break; break;
case PCI_POWBAR: case PCI_POWBAR:
pci->pob[idx].powbar = value; pci->pob[idx].powbar = value;
e500_update_pow(pci, idx);
break; break;
case PCI_POWAR: case PCI_POWAR:
pci->pob[idx].powar = value; pci->pob[idx].powar = value;
e500_update_pow(pci, idx);
break; break;
default: default:
break; break;
@ -221,18 +302,22 @@ static void pci_reg_write4(void *opaque, hwaddr addr,
case PPCE500_PCI_IW2: case PPCE500_PCI_IW2:
case PPCE500_PCI_IW1: case PPCE500_PCI_IW1:
idx = ((addr >> 5) & 0x3) - 1; idx = ((addr >> 5) & 0x3) - 1;
switch (addr & 0xC) { switch (addr & 0x1F) {
case PCI_PITAR: case PCI_PITAR:
pci->pib[idx].pitar = value; pci->pib[idx].pitar = value;
e500_update_piw(pci, idx);
break; break;
case PCI_PIWBAR: case PCI_PIWBAR:
pci->pib[idx].piwbar = value; pci->pib[idx].piwbar = value;
e500_update_piw(pci, idx);
break; break;
case PCI_PIWBEAR: case PCI_PIWBEAR:
pci->pib[idx].piwbear = value; pci->pib[idx].piwbear = value;
e500_update_piw(pci, idx);
break; break;
case PCI_PIWAR: case PCI_PIWAR:
pci->pib[idx].piwar = value; pci->pib[idx].piwar = value;
e500_update_piw(pci, idx);
break; break;
default: default:
break; break;
@ -349,13 +434,20 @@ static int e500_pcihost_bridge_initfn(PCIDevice *d)
return 0; return 0;
} }
static AddressSpace *e500_pcihost_set_iommu(PCIBus *bus, void *opaque,
int devfn)
{
PPCE500PCIState *s = opaque;
return &s->bm_as;
}
static int e500_pcihost_initfn(SysBusDevice *dev) static int e500_pcihost_initfn(SysBusDevice *dev)
{ {
PCIHostState *h; PCIHostState *h;
PPCE500PCIState *s; PPCE500PCIState *s;
PCIBus *b; PCIBus *b;
int i; int i;
MemoryRegion *address_space_mem = get_system_memory();
h = PCI_HOST_BRIDGE(dev); h = PCI_HOST_BRIDGE(dev);
s = PPC_E500_PCI_HOST_BRIDGE(dev); s = PPC_E500_PCI_HOST_BRIDGE(dev);
@ -369,12 +461,22 @@ static int e500_pcihost_initfn(SysBusDevice *dev)
} }
memory_region_init(&s->pio, OBJECT(s), "pci-pio", PCIE500_PCI_IOLEN); memory_region_init(&s->pio, OBJECT(s), "pci-pio", PCIE500_PCI_IOLEN);
memory_region_init(&s->busmem, OBJECT(s), "pci bus memory", UINT64_MAX);
/* PIO lives at the bottom of our bus space */
memory_region_add_subregion_overlap(&s->busmem, 0, &s->pio, -2);
b = pci_register_bus(DEVICE(dev), NULL, mpc85xx_pci_set_irq, b = pci_register_bus(DEVICE(dev), NULL, mpc85xx_pci_set_irq,
mpc85xx_pci_map_irq, s, address_space_mem, mpc85xx_pci_map_irq, s, &s->busmem, &s->pio,
&s->pio, PCI_DEVFN(s->first_slot, 0), 4, TYPE_PCI_BUS); PCI_DEVFN(s->first_slot, 0), 4, TYPE_PCI_BUS);
h->bus = b; h->bus = b;
/* Set up PCI view of memory */
memory_region_init(&s->bm, OBJECT(s), "bm-e500", UINT64_MAX);
memory_region_add_subregion(&s->bm, 0x0, &s->busmem);
address_space_init(&s->bm_as, &s->bm, "pci-bm");
pci_setup_iommu(b, e500_pcihost_set_iommu, s);
pci_create_simple(b, 0, "e500-host-bridge"); pci_create_simple(b, 0, "e500-host-bridge");
memory_region_init(&s->container, OBJECT(h), "pci-container", PCIE500_ALL_SIZE); memory_region_init(&s->container, OBJECT(h), "pci-container", PCIE500_ALL_SIZE);
@ -388,7 +490,6 @@ static int e500_pcihost_initfn(SysBusDevice *dev)
memory_region_add_subregion(&s->container, PCIE500_CFGDATA, &h->data_mem); memory_region_add_subregion(&s->container, PCIE500_CFGDATA, &h->data_mem);
memory_region_add_subregion(&s->container, PCIE500_REG_BASE, &s->iomem); memory_region_add_subregion(&s->container, PCIE500_REG_BASE, &s->iomem);
sysbus_init_mmio(dev, &s->container); sysbus_init_mmio(dev, &s->container);
sysbus_init_mmio(dev, &s->pio);
pci_bus_set_route_irq_fn(b, e500_route_intx_pin_to_irq); pci_bus_set_route_irq_fn(b, e500_route_intx_pin_to_irq);
return 0; return 0;

View File

@ -51,21 +51,16 @@
#define RAM_SIZES_ALIGN (64UL << 20) #define RAM_SIZES_ALIGN (64UL << 20)
/* TODO: parameterize */ /* TODO: parameterize */
#define MPC8544_CCSRBAR_BASE 0xE0000000ULL
#define MPC8544_CCSRBAR_SIZE 0x00100000ULL #define MPC8544_CCSRBAR_SIZE 0x00100000ULL
#define MPC8544_MPIC_REGS_OFFSET 0x40000ULL #define MPC8544_MPIC_REGS_OFFSET 0x40000ULL
#define MPC8544_MSI_REGS_OFFSET 0x41600ULL #define MPC8544_MSI_REGS_OFFSET 0x41600ULL
#define MPC8544_SERIAL0_REGS_OFFSET 0x4500ULL #define MPC8544_SERIAL0_REGS_OFFSET 0x4500ULL
#define MPC8544_SERIAL1_REGS_OFFSET 0x4600ULL #define MPC8544_SERIAL1_REGS_OFFSET 0x4600ULL
#define MPC8544_PCI_REGS_OFFSET 0x8000ULL #define MPC8544_PCI_REGS_OFFSET 0x8000ULL
#define MPC8544_PCI_REGS_BASE (MPC8544_CCSRBAR_BASE + \
MPC8544_PCI_REGS_OFFSET)
#define MPC8544_PCI_REGS_SIZE 0x1000ULL #define MPC8544_PCI_REGS_SIZE 0x1000ULL
#define MPC8544_PCI_IO 0xE1000000ULL
#define MPC8544_UTIL_OFFSET 0xe0000ULL #define MPC8544_UTIL_OFFSET 0xe0000ULL
#define MPC8544_SPIN_BASE 0xEF000000ULL
#define MPC8XXX_GPIO_OFFSET 0x000FF000ULL #define MPC8XXX_GPIO_OFFSET 0x000FF000ULL
#define MPC8XXX_GPIO_IRQ 43 #define MPC8XXX_GPIO_IRQ 47
struct boot_info struct boot_info
{ {
@ -293,12 +288,12 @@ static int ppce500_load_device_tree(MachineState *machine,
int len; int len;
uint32_t pci_ranges[14] = uint32_t pci_ranges[14] =
{ {
0x2000000, 0x0, 0xc0000000, 0x2000000, 0x0, params->pci_mmio_bus_base,
0x0, 0xc0000000, params->pci_mmio_base >> 32, params->pci_mmio_base,
0x0, 0x20000000, 0x0, 0x20000000,
0x1000000, 0x0, 0x0, 0x1000000, 0x0, 0x0,
0x0, 0xe1000000, params->pci_pio_base >> 32, params->pci_pio_base,
0x0, 0x10000, 0x0, 0x10000,
}; };
QemuOpts *machine_opts = qemu_get_machine_opts(); QemuOpts *machine_opts = qemu_get_machine_opts();
@ -389,7 +384,7 @@ static int ppce500_load_device_tree(MachineState *machine,
CPUState *cpu; CPUState *cpu;
PowerPCCPU *pcpu; PowerPCCPU *pcpu;
char cpu_name[128]; char cpu_name[128];
uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20); uint64_t cpu_release_addr = params->spin_base + (i * 0x20);
cpu = qemu_get_cpu(i); cpu = qemu_get_cpu(i);
if (cpu == NULL) { if (cpu == NULL) {
@ -426,7 +421,7 @@ static int ppce500_load_device_tree(MachineState *machine,
qemu_fdt_add_subnode(fdt, "/aliases"); qemu_fdt_add_subnode(fdt, "/aliases");
/* XXX These should go into their respective devices' code */ /* XXX These should go into their respective devices' code */
snprintf(soc, sizeof(soc), "/soc@%llx", MPC8544_CCSRBAR_BASE); snprintf(soc, sizeof(soc), "/soc@%"PRIx64, params->ccsrbar_base);
qemu_fdt_add_subnode(fdt, soc); qemu_fdt_add_subnode(fdt, soc);
qemu_fdt_setprop_string(fdt, soc, "device_type", "soc"); qemu_fdt_setprop_string(fdt, soc, "device_type", "soc");
qemu_fdt_setprop(fdt, soc, "compatible", compatible_sb, qemu_fdt_setprop(fdt, soc, "compatible", compatible_sb,
@ -434,7 +429,7 @@ static int ppce500_load_device_tree(MachineState *machine,
qemu_fdt_setprop_cell(fdt, soc, "#address-cells", 1); qemu_fdt_setprop_cell(fdt, soc, "#address-cells", 1);
qemu_fdt_setprop_cell(fdt, soc, "#size-cells", 1); qemu_fdt_setprop_cell(fdt, soc, "#size-cells", 1);
qemu_fdt_setprop_cells(fdt, soc, "ranges", 0x0, qemu_fdt_setprop_cells(fdt, soc, "ranges", 0x0,
MPC8544_CCSRBAR_BASE >> 32, MPC8544_CCSRBAR_BASE, params->ccsrbar_base >> 32, params->ccsrbar_base,
MPC8544_CCSRBAR_SIZE); MPC8544_CCSRBAR_SIZE);
/* XXX should contain a reasonable value */ /* XXX should contain a reasonable value */
qemu_fdt_setprop_cell(fdt, soc, "bus-frequency", 0); qemu_fdt_setprop_cell(fdt, soc, "bus-frequency", 0);
@ -493,7 +488,8 @@ static int ppce500_load_device_tree(MachineState *machine,
qemu_fdt_setprop_cell(fdt, msi, "phandle", msi_ph); qemu_fdt_setprop_cell(fdt, msi, "phandle", msi_ph);
qemu_fdt_setprop_cell(fdt, msi, "linux,phandle", msi_ph); qemu_fdt_setprop_cell(fdt, msi, "linux,phandle", msi_ph);
snprintf(pci, sizeof(pci), "/pci@%llx", MPC8544_PCI_REGS_BASE); snprintf(pci, sizeof(pci), "/pci@%llx",
params->ccsrbar_base + MPC8544_PCI_REGS_OFFSET);
qemu_fdt_add_subnode(fdt, pci); qemu_fdt_add_subnode(fdt, pci);
qemu_fdt_setprop_cell(fdt, pci, "cell-index", 0); qemu_fdt_setprop_cell(fdt, pci, "cell-index", 0);
qemu_fdt_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci"); qemu_fdt_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci");
@ -512,8 +508,10 @@ static int ppce500_load_device_tree(MachineState *machine,
} }
qemu_fdt_setprop_cell(fdt, pci, "fsl,msi", msi_ph); qemu_fdt_setprop_cell(fdt, pci, "fsl,msi", msi_ph);
qemu_fdt_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges)); qemu_fdt_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
qemu_fdt_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32, qemu_fdt_setprop_cells(fdt, pci, "reg",
MPC8544_PCI_REGS_BASE, 0, 0x1000); (params->ccsrbar_base + MPC8544_PCI_REGS_OFFSET) >> 32,
(params->ccsrbar_base + MPC8544_PCI_REGS_OFFSET),
0, 0x1000);
qemu_fdt_setprop_cell(fdt, pci, "clock-frequency", 66666666); qemu_fdt_setprop_cell(fdt, pci, "clock-frequency", 66666666);
qemu_fdt_setprop_cell(fdt, pci, "#interrupt-cells", 1); qemu_fdt_setprop_cell(fdt, pci, "#interrupt-cells", 1);
qemu_fdt_setprop_cell(fdt, pci, "#size-cells", 2); qemu_fdt_setprop_cell(fdt, pci, "#size-cells", 2);
@ -841,7 +839,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT]; irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT]; irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i; env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
env->mpic_iack = MPC8544_CCSRBAR_BASE + env->mpic_iack = params->ccsrbar_base +
MPC8544_MPIC_REGS_OFFSET + 0xa0; MPC8544_MPIC_REGS_OFFSET + 0xa0;
ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500); ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500);
@ -875,7 +873,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
qdev_init_nofail(dev); qdev_init_nofail(dev);
ccsr = CCSR(dev); ccsr = CCSR(dev);
ccsr_addr_space = &ccsr->ccsr_space; ccsr_addr_space = &ccsr->ccsr_space;
memory_region_add_subregion(address_space_mem, MPC8544_CCSRBAR_BASE, memory_region_add_subregion(address_space_mem, params->ccsrbar_base,
ccsr_addr_space); ccsr_addr_space);
mpic = ppce500_init_mpic(params, ccsr_addr_space, irqs); mpic = ppce500_init_mpic(params, ccsr_addr_space, irqs);
@ -917,8 +915,6 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
if (!pci_bus) if (!pci_bus)
printf("couldn't create PCI controller!\n"); printf("couldn't create PCI controller!\n");
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1, MPC8544_PCI_IO);
if (pci_bus) { if (pci_bus) {
/* Register network interfaces. */ /* Register network interfaces. */
for (i = 0; i < nb_nics; i++) { for (i = 0; i < nb_nics; i++) {
@ -927,7 +923,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
} }
/* Register spinning region */ /* Register spinning region */
sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL); sysbus_create_simple("e500-spin", params->spin_base, NULL);
if (cur_base < (32 * 1024 * 1024)) { if (cur_base < (32 * 1024 * 1024)) {
/* u-boot occupies memory up to 32MB, so load blobs above */ /* u-boot occupies memory up to 32MB, so load blobs above */

View File

@ -17,6 +17,11 @@ typedef struct PPCE500Params {
hwaddr platform_bus_size; hwaddr platform_bus_size;
int platform_bus_first_irq; int platform_bus_first_irq;
int platform_bus_num_irqs; int platform_bus_num_irqs;
hwaddr ccsrbar_base;
hwaddr pci_pio_base;
hwaddr pci_mmio_base;
hwaddr pci_mmio_bus_base;
hwaddr spin_base;
} PPCE500Params; } PPCE500Params;
void ppce500_init(MachineState *machine, PPCE500Params *params); void ppce500_init(MachineState *machine, PPCE500Params *params);

View File

@ -41,6 +41,11 @@ static void e500plat_init(MachineState *machine)
.platform_bus_size = (128ULL * 1024 * 1024), .platform_bus_size = (128ULL * 1024 * 1024),
.platform_bus_first_irq = 5, .platform_bus_first_irq = 5,
.platform_bus_num_irqs = 10, .platform_bus_num_irqs = 10,
.ccsrbar_base = 0xFE0000000ULL,
.pci_pio_base = 0xFE1000000ULL,
.pci_mmio_base = 0xC00000000ULL,
.pci_mmio_bus_base = 0xE0000000ULL,
.spin_base = 0xFEF000000ULL,
}; };
/* Older KVM versions don't support EPR which breaks guests when we announce /* Older KVM versions don't support EPR which breaks guests when we announce

View File

@ -15,6 +15,7 @@
#include "hw/boards.h" #include "hw/boards.h"
#include "sysemu/device_tree.h" #include "sysemu/device_tree.h"
#include "hw/ppc/openpic.h" #include "hw/ppc/openpic.h"
#include "qemu/error-report.h"
static void mpc8544ds_fixup_devtree(PPCE500Params *params, void *fdt) static void mpc8544ds_fixup_devtree(PPCE500Params *params, void *fdt)
{ {
@ -33,8 +34,18 @@ static void mpc8544ds_init(MachineState *machine)
.pci_nr_slots = 2, .pci_nr_slots = 2,
.fixup_devtree = mpc8544ds_fixup_devtree, .fixup_devtree = mpc8544ds_fixup_devtree,
.mpic_version = OPENPIC_MODEL_FSL_MPIC_20, .mpic_version = OPENPIC_MODEL_FSL_MPIC_20,
.ccsrbar_base = 0xE0000000ULL,
.pci_mmio_base = 0xC0000000ULL,
.pci_mmio_bus_base = 0xC0000000ULL,
.pci_pio_base = 0xE1000000ULL,
.spin_base = 0xEF000000ULL,
}; };
if (machine->ram_size > 0xc0000000) {
error_report("The MPC8544DS board only supports up to 3GB of RAM");
exit(1);
}
ppce500_init(machine, &params); ppce500_init(machine, &params);
} }

View File

@ -844,7 +844,7 @@ static void timebase_pre_save(void *opaque)
return; return;
} }
tb->time_of_the_day_ns = get_clock_realtime(); tb->time_of_the_day_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST);
/* /*
* tb_offset is only expected to be changed by migration so * tb_offset is only expected to be changed by migration so
* there is no need to update it from KVM here * there is no need to update it from KVM here
@ -873,7 +873,7 @@ static int timebase_post_load(void *opaque, int version_id)
* We try to adjust timebase by downtime if host clocks are not * We try to adjust timebase by downtime if host clocks are not
* too much out of sync (1 second for now). * too much out of sync (1 second for now).
*/ */
host_ns = get_clock_realtime(); host_ns = qemu_clock_get_ns(QEMU_CLOCK_HOST);
ns_diff = MAX(0, host_ns - tb_remote->time_of_the_day_ns); ns_diff = MAX(0, host_ns - tb_remote->time_of_the_day_ns);
migration_duration_ns = MIN(NSEC_PER_SEC, ns_diff); migration_duration_ns = MIN(NSEC_PER_SEC, ns_diff);
migration_duration_tb = muldiv64(migration_duration_ns, freq, NSEC_PER_SEC); migration_duration_tb = muldiv64(migration_duration_ns, freq, NSEC_PER_SEC);

View File

@ -819,9 +819,16 @@ static void emulate_spapr_hypercall(PowerPCCPU *cpu)
} }
} }
#define HPTE(_table, _i) (void *)(((uint64_t *)(_table)) + ((_i) * 2))
#define HPTE_VALID(_hpte) (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_VALID)
#define HPTE_DIRTY(_hpte) (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_HPTE_DIRTY)
#define CLEAN_HPTE(_hpte) ((*(uint64_t *)(_hpte)) &= tswap64(~HPTE64_V_HPTE_DIRTY))
#define DIRTY_HPTE(_hpte) ((*(uint64_t *)(_hpte)) |= tswap64(HPTE64_V_HPTE_DIRTY))
static void spapr_reset_htab(sPAPREnvironment *spapr) static void spapr_reset_htab(sPAPREnvironment *spapr)
{ {
long shift; long shift;
int index;
/* allocate hash page table. For now we always make this 16mb, /* allocate hash page table. For now we always make this 16mb,
* later we should probably make it scale to the size of guest * later we should probably make it scale to the size of guest
@ -833,6 +840,11 @@ static void spapr_reset_htab(sPAPREnvironment *spapr)
/* Kernel handles htab, we don't need to allocate one */ /* Kernel handles htab, we don't need to allocate one */
spapr->htab_shift = shift; spapr->htab_shift = shift;
kvmppc_kern_htab = true; kvmppc_kern_htab = true;
/* Tell readers to update their file descriptor */
if (spapr->htab_fd >= 0) {
spapr->htab_fd_stale = true;
}
} else { } else {
if (!spapr->htab) { if (!spapr->htab) {
/* Allocate an htab if we don't yet have one */ /* Allocate an htab if we don't yet have one */
@ -841,6 +853,10 @@ static void spapr_reset_htab(sPAPREnvironment *spapr)
/* And clear it */ /* And clear it */
memset(spapr->htab, 0, HTAB_SIZE(spapr)); memset(spapr->htab, 0, HTAB_SIZE(spapr));
for (index = 0; index < HTAB_SIZE(spapr) / HASH_PTE_SIZE_64; index++) {
DIRTY_HPTE(HPTE(spapr->htab, index));
}
} }
/* Update the RMA size if necessary */ /* Update the RMA size if necessary */
@ -867,6 +883,28 @@ static int find_unknown_sysbus_device(SysBusDevice *sbdev, void *opaque)
return 0; return 0;
} }
/*
* A guest reset will cause spapr->htab_fd to become stale if being used.
* Reopen the file descriptor to make sure the whole HTAB is properly read.
*/
static int spapr_check_htab_fd(sPAPREnvironment *spapr)
{
int rc = 0;
if (spapr->htab_fd_stale) {
close(spapr->htab_fd);
spapr->htab_fd = kvmppc_get_htab_fd(false);
if (spapr->htab_fd < 0) {
error_report("Unable to open fd for reading hash table from KVM: "
"%s", strerror(errno));
rc = -1;
}
spapr->htab_fd_stale = false;
}
return rc;
}
static void ppc_spapr_reset(void) static void ppc_spapr_reset(void)
{ {
PowerPCCPU *first_ppc_cpu; PowerPCCPU *first_ppc_cpu;
@ -986,11 +1024,6 @@ static const VMStateDescription vmstate_spapr = {
}, },
}; };
#define HPTE(_table, _i) (void *)(((uint64_t *)(_table)) + ((_i) * 2))
#define HPTE_VALID(_hpte) (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_VALID)
#define HPTE_DIRTY(_hpte) (tswap64(*((uint64_t *)(_hpte))) & HPTE64_V_HPTE_DIRTY)
#define CLEAN_HPTE(_hpte) ((*(uint64_t *)(_hpte)) &= tswap64(~HPTE64_V_HPTE_DIRTY))
static int htab_save_setup(QEMUFile *f, void *opaque) static int htab_save_setup(QEMUFile *f, void *opaque)
{ {
sPAPREnvironment *spapr = opaque; sPAPREnvironment *spapr = opaque;
@ -1005,6 +1038,7 @@ static int htab_save_setup(QEMUFile *f, void *opaque)
assert(kvm_enabled()); assert(kvm_enabled());
spapr->htab_fd = kvmppc_get_htab_fd(false); spapr->htab_fd = kvmppc_get_htab_fd(false);
spapr->htab_fd_stale = false;
if (spapr->htab_fd < 0) { if (spapr->htab_fd < 0) {
fprintf(stderr, "Unable to open fd for reading hash table from KVM: %s\n", fprintf(stderr, "Unable to open fd for reading hash table from KVM: %s\n",
strerror(errno)); strerror(errno));
@ -1037,7 +1071,7 @@ static void htab_save_first_pass(QEMUFile *f, sPAPREnvironment *spapr,
/* Consume valid HPTEs */ /* Consume valid HPTEs */
chunkstart = index; chunkstart = index;
while ((index < htabslots) while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
&& HPTE_VALID(HPTE(spapr->htab, index))) { && HPTE_VALID(HPTE(spapr->htab, index))) {
index++; index++;
CLEAN_HPTE(HPTE(spapr->htab, index)); CLEAN_HPTE(HPTE(spapr->htab, index));
@ -1089,7 +1123,7 @@ static int htab_save_later_pass(QEMUFile *f, sPAPREnvironment *spapr,
chunkstart = index; chunkstart = index;
/* Consume valid dirty HPTEs */ /* Consume valid dirty HPTEs */
while ((index < htabslots) while ((index < htabslots) && (index - chunkstart < USHRT_MAX)
&& HPTE_DIRTY(HPTE(spapr->htab, index)) && HPTE_DIRTY(HPTE(spapr->htab, index))
&& HPTE_VALID(HPTE(spapr->htab, index))) { && HPTE_VALID(HPTE(spapr->htab, index))) {
CLEAN_HPTE(HPTE(spapr->htab, index)); CLEAN_HPTE(HPTE(spapr->htab, index));
@ -1099,7 +1133,7 @@ static int htab_save_later_pass(QEMUFile *f, sPAPREnvironment *spapr,
invalidstart = index; invalidstart = index;
/* Consume invalid dirty HPTEs */ /* Consume invalid dirty HPTEs */
while ((index < htabslots) while ((index < htabslots) && (index - invalidstart < USHRT_MAX)
&& HPTE_DIRTY(HPTE(spapr->htab, index)) && HPTE_DIRTY(HPTE(spapr->htab, index))
&& !HPTE_VALID(HPTE(spapr->htab, index))) { && !HPTE_VALID(HPTE(spapr->htab, index))) {
CLEAN_HPTE(HPTE(spapr->htab, index)); CLEAN_HPTE(HPTE(spapr->htab, index));
@ -1157,6 +1191,11 @@ static int htab_save_iterate(QEMUFile *f, void *opaque)
if (!spapr->htab) { if (!spapr->htab) {
assert(kvm_enabled()); assert(kvm_enabled());
rc = spapr_check_htab_fd(spapr);
if (rc < 0) {
return rc;
}
rc = kvmppc_save_htab(f, spapr->htab_fd, rc = kvmppc_save_htab(f, spapr->htab_fd,
MAX_KVM_BUF_SIZE, MAX_ITERATION_NS); MAX_KVM_BUF_SIZE, MAX_ITERATION_NS);
if (rc < 0) { if (rc < 0) {
@ -1188,6 +1227,11 @@ static int htab_save_complete(QEMUFile *f, void *opaque)
assert(kvm_enabled()); assert(kvm_enabled());
rc = spapr_check_htab_fd(spapr);
if (rc < 0) {
return rc;
}
rc = kvmppc_save_htab(f, spapr->htab_fd, MAX_KVM_BUF_SIZE, -1); rc = kvmppc_save_htab(f, spapr->htab_fd, MAX_KVM_BUF_SIZE, -1);
if (rc < 0) { if (rc < 0) {
return rc; return rc;
@ -1438,7 +1482,7 @@ static void ppc_spapr_init(MachineState *machine)
} }
if (spapr->rtas_size > RTAS_MAX_SIZE) { if (spapr->rtas_size > RTAS_MAX_SIZE) {
hw_error("RTAS too big ! 0x%zx bytes (max is 0x%x)\n", hw_error("RTAS too big ! 0x%zx bytes (max is 0x%x)\n",
spapr->rtas_size, RTAS_MAX_SIZE); (size_t)spapr->rtas_size, RTAS_MAX_SIZE);
exit(1); exit(1);
} }
g_free(filename); g_free(filename);

View File

@ -173,9 +173,9 @@ sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn,
return tcet; return tcet;
} }
static void spapr_tce_table_finalize(Object *obj) static void spapr_tce_table_unrealize(DeviceState *dev, Error **errp)
{ {
sPAPRTCETable *tcet = SPAPR_TCE_TABLE(obj); sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev);
QLIST_REMOVE(tcet, list); QLIST_REMOVE(tcet, list);
@ -420,6 +420,7 @@ static void spapr_tce_table_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass); DeviceClass *dc = DEVICE_CLASS(klass);
dc->init = spapr_tce_table_realize; dc->init = spapr_tce_table_realize;
dc->reset = spapr_tce_reset; dc->reset = spapr_tce_reset;
dc->unrealize = spapr_tce_table_unrealize;
QLIST_INIT(&spapr_tce_tables); QLIST_INIT(&spapr_tce_tables);
@ -435,7 +436,6 @@ static TypeInfo spapr_tce_table_info = {
.parent = TYPE_DEVICE, .parent = TYPE_DEVICE,
.instance_size = sizeof(sPAPRTCETable), .instance_size = sizeof(sPAPRTCETable),
.class_init = spapr_tce_table_class_init, .class_init = spapr_tce_table_class_init,
.instance_finalize = spapr_tce_table_finalize,
}; };
static void register_types(void) static void register_types(void)

View File

@ -37,6 +37,7 @@ typedef struct sPAPREnvironment {
int htab_save_index; int htab_save_index;
bool htab_first_pass; bool htab_first_pass;
int htab_fd; int htab_fd;
bool htab_fd_stale;
} sPAPREnvironment; } sPAPREnvironment;
#define H_SUCCESS 0 #define H_SUCCESS 0

View File

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

Binary file not shown.

@ -1 +1 @@
Subproject commit f284ab3f03ae69a20e1ae966f6ddf76da33cbf72 Subproject commit a70dbda2e21f6e438b3617c44ff180c3418dc30f

View File

@ -559,6 +559,26 @@ struct ppc_slb_t {
#define ESR_VLEMI (1 << (63 - 58)) /* VLE operation */ #define ESR_VLEMI (1 << (63 - 58)) /* VLE operation */
#define ESR_MIF (1 << (63 - 62)) /* Misaligned instruction (VLE) */ #define ESR_MIF (1 << (63 - 62)) /* Misaligned instruction (VLE) */
/* Transaction EXception And Summary Register bits */
#define TEXASR_FAILURE_PERSISTENT (63 - 7)
#define TEXASR_DISALLOWED (63 - 8)
#define TEXASR_NESTING_OVERFLOW (63 - 9)
#define TEXASR_FOOTPRINT_OVERFLOW (63 - 10)
#define TEXASR_SELF_INDUCED_CONFLICT (63 - 11)
#define TEXASR_NON_TRANSACTIONAL_CONFLICT (63 - 12)
#define TEXASR_TRANSACTION_CONFLICT (63 - 13)
#define TEXASR_TRANSLATION_INVALIDATION_CONFLICT (63 - 14)
#define TEXASR_IMPLEMENTATION_SPECIFIC (63 - 15)
#define TEXASR_INSTRUCTION_FETCH_CONFLICT (63 - 16)
#define TEXASR_ABORT (63 - 31)
#define TEXASR_SUSPENDED (63 - 32)
#define TEXASR_PRIVILEGE_HV (63 - 34)
#define TEXASR_PRIVILEGE_PR (63 - 35)
#define TEXASR_FAILURE_SUMMARY (63 - 36)
#define TEXASR_TFIAR_EXACT (63 - 37)
#define TEXASR_ROT (63 - 38)
#define TEXASR_TRANSACTION_LEVEL (63 - 52) /* 12 bits */
enum { enum {
POWERPC_FLAG_NONE = 0x00000000, POWERPC_FLAG_NONE = 0x00000000,
/* Flag for MSR bit 25 signification (VRE/SPE) */ /* Flag for MSR bit 25 signification (VRE/SPE) */
@ -585,6 +605,8 @@ enum {
POWERPC_FLAG_CFAR = 0x00040000, POWERPC_FLAG_CFAR = 0x00040000,
/* Has VSX */ /* Has VSX */
POWERPC_FLAG_VSX = 0x00080000, POWERPC_FLAG_VSX = 0x00080000,
/* Has Transaction Memory (ISA 2.07) */
POWERPC_FLAG_TM = 0x00100000,
}; };
/*****************************************************************************/ /*****************************************************************************/
@ -2011,6 +2033,8 @@ enum {
PPC2_ISA207S = 0x0000000000008000ULL, PPC2_ISA207S = 0x0000000000008000ULL,
/* Double precision floating point conversion for signed integer 64 */ /* Double precision floating point conversion for signed integer 64 */
PPC2_FP_CVT_S64 = 0x0000000000010000ULL, PPC2_FP_CVT_S64 = 0x0000000000010000ULL,
/* Transactional Memory (ISA 2.07, Book II) */
PPC2_TM = 0x0000000000020000ULL,
#define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_VSX | PPC2_PRCNTL | PPC2_DBRX | \ #define PPC_TCG_INSNS2 (PPC2_BOOKE206 | PPC2_VSX | PPC2_PRCNTL | PPC2_DBRX | \
PPC2_ISA205 | PPC2_VSX207 | PPC2_PERM_ISA206 | \ PPC2_ISA205 | PPC2_VSX207 | PPC2_PERM_ISA206 | \
@ -2018,7 +2042,7 @@ enum {
PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | \ PPC2_FP_CVT_ISA206 | PPC2_FP_TST_ISA206 | \
PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | \ PPC2_BCTAR_ISA207 | PPC2_LSQ_ISA207 | \
PPC2_ALTIVEC_207 | PPC2_ISA207S | PPC2_DFP | \ PPC2_ALTIVEC_207 | PPC2_ISA207S | PPC2_DFP | \
PPC2_FP_CVT_S64) PPC2_FP_CVT_S64 | PPC2_TM)
}; };
/*****************************************************************************/ /*****************************************************************************/

View File

@ -19,6 +19,9 @@
#include "cpu.h" #include "cpu.h"
#include "exec/helper-proto.h" #include "exec/helper-proto.h"
#define float64_snan_to_qnan(x) ((x) | 0x0008000000000000ULL)
#define float32_snan_to_qnan(x) ((x) | 0x00400000)
/*****************************************************************************/ /*****************************************************************************/
/* Floating point operations helpers */ /* Floating point operations helpers */
uint64_t helper_float32_to_float64(CPUPPCState *env, uint32_t arg) uint64_t helper_float32_to_float64(CPUPPCState *env, uint32_t arg)
@ -60,59 +63,55 @@ static inline int ppc_float64_get_unbiased_exp(float64 f)
return ((f >> 52) & 0x7FF) - 1023; return ((f >> 52) & 0x7FF) - 1023;
} }
uint32_t helper_compute_fprf(CPUPPCState *env, uint64_t arg, uint32_t set_fprf) void helper_compute_fprf(CPUPPCState *env, uint64_t arg)
{ {
CPU_DoubleU farg; CPU_DoubleU farg;
int isneg; int isneg;
int ret; int fprf;
farg.ll = arg; farg.ll = arg;
isneg = float64_is_neg(farg.d); isneg = float64_is_neg(farg.d);
if (unlikely(float64_is_any_nan(farg.d))) { if (unlikely(float64_is_any_nan(farg.d))) {
if (float64_is_signaling_nan(farg.d)) { if (float64_is_signaling_nan(farg.d)) {
/* Signaling NaN: flags are undefined */ /* Signaling NaN: flags are undefined */
ret = 0x00; fprf = 0x00;
} else { } else {
/* Quiet NaN */ /* Quiet NaN */
ret = 0x11; fprf = 0x11;
} }
} else if (unlikely(float64_is_infinity(farg.d))) { } else if (unlikely(float64_is_infinity(farg.d))) {
/* +/- infinity */ /* +/- infinity */
if (isneg) { if (isneg) {
ret = 0x09; fprf = 0x09;
} else { } else {
ret = 0x05; fprf = 0x05;
} }
} else { } else {
if (float64_is_zero(farg.d)) { if (float64_is_zero(farg.d)) {
/* +/- zero */ /* +/- zero */
if (isneg) { if (isneg) {
ret = 0x12; fprf = 0x12;
} else { } else {
ret = 0x02; fprf = 0x02;
} }
} else { } else {
if (isden(farg.d)) { if (isden(farg.d)) {
/* Denormalized numbers */ /* Denormalized numbers */
ret = 0x10; fprf = 0x10;
} else { } else {
/* Normalized numbers */ /* Normalized numbers */
ret = 0x00; fprf = 0x00;
} }
if (isneg) { if (isneg) {
ret |= 0x08; fprf |= 0x08;
} else { } else {
ret |= 0x04; fprf |= 0x04;
} }
} }
} }
if (set_fprf) { /* We update FPSCR_FPRF */
/* We update FPSCR_FPRF */ env->fpscr &= ~(0x1F << FPSCR_FPRF);
env->fpscr &= ~(0x1F << FPSCR_FPRF); env->fpscr |= fprf << FPSCR_FPRF;
env->fpscr |= ret << FPSCR_FPRF;
}
/* We just need fpcc to update Rc1 */
return ret & 0xF;
} }
/* Floating-point invalid operations exception */ /* Floating-point invalid operations exception */
@ -920,14 +919,16 @@ uint64_t helper_fsqrt(CPUPPCState *env, uint64_t arg)
farg.ll = arg; farg.ll = arg;
if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) { if (unlikely(float64_is_any_nan(farg.d))) {
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN reciprocal square root */
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
farg.ll = float64_snan_to_qnan(farg.ll);
}
} else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
/* Square root of a negative nonzero number */ /* Square root of a negative nonzero number */
farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1); farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
} else { } else {
if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN square root */
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
}
farg.d = float64_sqrt(farg.d, &env->fp_status); farg.d = float64_sqrt(farg.d, &env->fp_status);
} }
return farg.ll; return farg.ll;
@ -974,17 +975,20 @@ uint64_t helper_frsqrte(CPUPPCState *env, uint64_t arg)
farg.ll = arg; farg.ll = arg;
if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) { if (unlikely(float64_is_any_nan(farg.d))) {
/* Reciprocal square root of a negative nonzero number */
farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
} else {
if (unlikely(float64_is_signaling_nan(farg.d))) { if (unlikely(float64_is_signaling_nan(farg.d))) {
/* sNaN reciprocal square root */ /* sNaN reciprocal square root */
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
farg.ll = float64_snan_to_qnan(farg.ll);
} }
} else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
/* Reciprocal square root of a negative nonzero number */
farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
} else {
farg.d = float64_sqrt(farg.d, &env->fp_status); farg.d = float64_sqrt(farg.d, &env->fp_status);
farg.d = float64_div(float64_one, farg.d, &env->fp_status); farg.d = float64_div(float64_one, farg.d, &env->fp_status);
} }
return farg.ll; return farg.ll;
} }
@ -1845,7 +1849,7 @@ void helper_##name(CPUPPCState *env, uint32_t opcode) \
} \ } \
\ \
if (sfprf) { \ if (sfprf) { \
helper_compute_fprf(env, xt.fld, sfprf); \ helper_compute_fprf(env, xt.fld); \
} \ } \
} \ } \
putVSR(xT(opcode), &xt, env); \ putVSR(xT(opcode), &xt, env); \
@ -1900,7 +1904,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
} \ } \
\ \
if (sfprf) { \ if (sfprf) { \
helper_compute_fprf(env, xt.fld, sfprf); \ helper_compute_fprf(env, xt.fld); \
} \ } \
} \ } \
\ \
@ -1954,7 +1958,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
} \ } \
\ \
if (sfprf) { \ if (sfprf) { \
helper_compute_fprf(env, xt.fld, sfprf); \ helper_compute_fprf(env, xt.fld); \
} \ } \
} \ } \
\ \
@ -1995,7 +1999,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
} \ } \
\ \
if (sfprf) { \ if (sfprf) { \
helper_compute_fprf(env, xt.fld, sfprf); \ helper_compute_fprf(env, xt.fld); \
} \ } \
} \ } \
\ \
@ -2044,7 +2048,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
} \ } \
\ \
if (sfprf) { \ if (sfprf) { \
helper_compute_fprf(env, xt.fld, sfprf); \ helper_compute_fprf(env, xt.fld); \
} \ } \
} \ } \
\ \
@ -2094,7 +2098,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
} \ } \
\ \
if (sfprf) { \ if (sfprf) { \
helper_compute_fprf(env, xt.fld, sfprf); \ helper_compute_fprf(env, xt.fld); \
} \ } \
} \ } \
\ \
@ -2294,7 +2298,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
} \ } \
\ \
if (sfprf) { \ if (sfprf) { \
helper_compute_fprf(env, xt_out.fld, sfprf); \ helper_compute_fprf(env, xt_out.fld); \
} \ } \
} \ } \
putVSR(xT(opcode), &xt_out, env); \ putVSR(xT(opcode), &xt_out, env); \
@ -2382,9 +2386,6 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
VSX_SCALAR_CMP(xscmpodp, 1) VSX_SCALAR_CMP(xscmpodp, 1)
VSX_SCALAR_CMP(xscmpudp, 0) VSX_SCALAR_CMP(xscmpudp, 0)
#define float64_snan_to_qnan(x) ((x) | 0x0008000000000000ULL)
#define float32_snan_to_qnan(x) ((x) | 0x00400000)
/* VSX_MAX_MIN - VSX floating point maximum/minimum /* VSX_MAX_MIN - VSX floating point maximum/minimum
* name - instruction mnemonic * name - instruction mnemonic
* op - operation (max or min) * op - operation (max or min)
@ -2504,7 +2505,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
} \ } \
if (sfprf) { \ if (sfprf) { \
helper_compute_fprf(env, ttp##_to_float64(xt.tfld, \ helper_compute_fprf(env, ttp##_to_float64(xt.tfld, \
&env->fp_status), sfprf); \ &env->fp_status)); \
} \ } \
} \ } \
\ \
@ -2614,7 +2615,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
xt.tfld = helper_frsp(env, xt.tfld); \ xt.tfld = helper_frsp(env, xt.tfld); \
} \ } \
if (sfprf) { \ if (sfprf) { \
helper_compute_fprf(env, xt.tfld, sfprf); \ helper_compute_fprf(env, xt.tfld); \
} \ } \
} \ } \
\ \
@ -2669,7 +2670,7 @@ void helper_##op(CPUPPCState *env, uint32_t opcode) \
xt.fld = tp##_round_to_int(xb.fld, &env->fp_status); \ xt.fld = tp##_round_to_int(xb.fld, &env->fp_status); \
} \ } \
if (sfprf) { \ if (sfprf) { \
helper_compute_fprf(env, xt.fld, sfprf); \ helper_compute_fprf(env, xt.fld); \
} \ } \
} \ } \
\ \
@ -2709,7 +2710,7 @@ uint64_t helper_xsrsp(CPUPPCState *env, uint64_t xb)
uint64_t xt = helper_frsp(env, xb); uint64_t xt = helper_frsp(env, xb);
helper_compute_fprf(env, xt, 1); helper_compute_fprf(env, xt);
helper_float_check_status(env); helper_float_check_status(env);
return xt; return xt;
} }

View File

@ -52,7 +52,7 @@ DEF_HELPER_FLAGS_2(brinc, TCG_CALL_NO_RWG_SE, tl, tl, tl)
DEF_HELPER_1(float_check_status, void, env) DEF_HELPER_1(float_check_status, void, env)
DEF_HELPER_1(reset_fpstatus, void, env) DEF_HELPER_1(reset_fpstatus, void, env)
DEF_HELPER_3(compute_fprf, i32, env, i64, i32) DEF_HELPER_2(compute_fprf, void, env, i64)
DEF_HELPER_3(store_fpscr, void, env, i64, i32) DEF_HELPER_3(store_fpscr, void, env, i64, i32)
DEF_HELPER_2(fpscr_clrbit, void, env, i32) DEF_HELPER_2(fpscr_clrbit, void, env, i32)
DEF_HELPER_2(fpscr_setbit, void, env, i32) DEF_HELPER_2(fpscr_setbit, void, env, i32)
@ -665,3 +665,5 @@ DEF_HELPER_4(dscri, void, env, fprp, fprp, i32)
DEF_HELPER_4(dscriq, void, env, fprp, fprp, i32) DEF_HELPER_4(dscriq, void, env, fprp, fprp, i32)
DEF_HELPER_4(dscli, void, env, fprp, fprp, i32) DEF_HELPER_4(dscli, void, env, fprp, fprp, i32)
DEF_HELPER_4(dscliq, void, env, fprp, fprp, i32) DEF_HELPER_4(dscliq, void, env, fprp, fprp, i32)
DEF_HELPER_1(tbegin, void, env)

View File

@ -2246,8 +2246,23 @@ int kvmppc_save_htab(QEMUFile *f, int fd, size_t bufsize, int64_t max_ns)
strerror(errno)); strerror(errno));
return rc; return rc;
} else if (rc) { } else if (rc) {
/* Kernel already retuns data in BE format for the file */ uint8_t *buffer = buf;
qemu_put_buffer(f, buf, rc); ssize_t n = rc;
while (n) {
struct kvm_get_htab_header *head =
(struct kvm_get_htab_header *) buffer;
size_t chunksize = sizeof(*head) +
HASH_PTE_SIZE_64 * head->n_valid;
qemu_put_be32(f, head->index);
qemu_put_be16(f, head->n_valid);
qemu_put_be16(f, head->n_invalid);
qemu_put_buffer(f, (void *)(head + 1),
HASH_PTE_SIZE_64 * head->n_valid);
buffer += chunksize;
n -= chunksize;
}
} }
} while ((rc != 0) } while ((rc != 0)
&& ((max_ns < 0) && ((max_ns < 0)
@ -2264,7 +2279,6 @@ int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index,
ssize_t rc; ssize_t rc;
buf = alloca(chunksize); buf = alloca(chunksize);
/* This is KVM on ppc, so this is all big-endian */
buf->index = index; buf->index = index;
buf->n_valid = n_valid; buf->n_valid = n_valid;
buf->n_invalid = n_invalid; buf->n_invalid = n_invalid;

View File

@ -269,3 +269,25 @@ STVE(stvewx, cpu_stl_data, bswap32, u32)
#undef HI_IDX #undef HI_IDX
#undef LO_IDX #undef LO_IDX
void helper_tbegin(CPUPPCState *env)
{
/* As a degenerate implementation, always fail tbegin. The reason
* given is "Nesting overflow". The "persistent" bit is set,
* providing a hint to the error handler to not retry. The TFIAR
* captures the address of the failure, which is this tbegin
* instruction. Instruction execution will continue with the
* next instruction in memory, which is precisely what we want.
*/
env->spr[SPR_TEXASR] =
(1ULL << TEXASR_FAILURE_PERSISTENT) |
(1ULL << TEXASR_NESTING_OVERFLOW) |
(msr_hv << TEXASR_PRIVILEGE_HV) |
(msr_pr << TEXASR_PRIVILEGE_PR) |
(1ULL << TEXASR_FAILURE_SUMMARY) |
(1ULL << TEXASR_TFIAR_EXACT);
env->spr[SPR_TFIAR] = env->nip | (msr_hv << 1) | msr_pr;
env->spr[SPR_TFHAR] = env->nip + 4;
env->crf[0] = 0xB; /* 0b1010 = transaction failure */
}

View File

@ -203,6 +203,7 @@ struct DisasContext {
int altivec_enabled; int altivec_enabled;
int vsx_enabled; int vsx_enabled;
int spe_enabled; int spe_enabled;
int tm_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_flags;
@ -250,26 +251,10 @@ static inline void gen_reset_fpstatus(void)
gen_helper_reset_fpstatus(cpu_env); gen_helper_reset_fpstatus(cpu_env);
} }
static inline void gen_compute_fprf(TCGv_i64 arg, int set_fprf, int set_rc) static inline void gen_compute_fprf(TCGv_i64 arg)
{ {
TCGv_i32 t0 = tcg_temp_new_i32(); gen_helper_compute_fprf(cpu_env, arg);
gen_helper_float_check_status(cpu_env);
if (set_fprf != 0) {
/* This case might be optimized later */
tcg_gen_movi_i32(t0, 1);
gen_helper_compute_fprf(t0, cpu_env, arg, t0);
if (unlikely(set_rc)) {
tcg_gen_mov_i32(cpu_crf[1], t0);
}
gen_helper_float_check_status(cpu_env);
} else if (unlikely(set_rc)) {
/* We always need to compute fpcc */
tcg_gen_movi_i32(t0, 0);
gen_helper_compute_fprf(t0, cpu_env, arg, t0);
tcg_gen_mov_i32(cpu_crf[1], t0);
}
tcg_temp_free_i32(t0);
} }
static inline void gen_set_access_type(DisasContext *ctx, int access_type) static inline void gen_set_access_type(DisasContext *ctx, int access_type)
@ -346,11 +331,13 @@ static inline void gen_stop_exception(DisasContext *ctx)
ctx->exception = POWERPC_EXCP_STOP; ctx->exception = POWERPC_EXCP_STOP;
} }
#ifndef CONFIG_USER_ONLY
/* No need to update nip here, as execution flow will change */ /* No need to update nip here, as execution flow will change */
static inline void gen_sync_exception(DisasContext *ctx) static inline void gen_sync_exception(DisasContext *ctx)
{ {
ctx->exception = POWERPC_EXCP_SYNC; ctx->exception = POWERPC_EXCP_SYNC;
} }
#endif
#define GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \ #define GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \
GEN_OPCODE(name, opc1, opc2, opc3, inval, type, PPC_NONE) GEN_OPCODE(name, opc1, opc2, opc3, inval, type, PPC_NONE)
@ -452,7 +439,10 @@ 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);
#ifndef CONFIG_USER_ONLY
EXTRACT_HELPER(SR, 16, 4); EXTRACT_HELPER(SR, 16, 4);
#endif
/* mtfsf/mtfsfi */ /* mtfsf/mtfsfi */
EXTRACT_HELPER(FPBF, 23, 3); EXTRACT_HELPER(FPBF, 23, 3);
@ -2077,6 +2067,21 @@ static void gen_srd(DisasContext *ctx)
} }
#endif #endif
#if defined(TARGET_PPC64)
static void gen_set_cr1_from_fpscr(DisasContext *ctx)
{
TCGv_i32 tmp = tcg_temp_new_i32();
tcg_gen_trunc_tl_i32(tmp, cpu_fpscr);
tcg_gen_shri_i32(cpu_crf[1], tmp, 28);
tcg_temp_free_i32(tmp);
}
#else
static void gen_set_cr1_from_fpscr(DisasContext *ctx)
{
tcg_gen_shri_tl(cpu_crf[1], cpu_fpscr, 28);
}
#endif
/*** Floating-Point arithmetic ***/ /*** Floating-Point arithmetic ***/
#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, set_fprf, type) \ #define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, set_fprf, type) \
static void gen_f##name(DisasContext *ctx) \ static void gen_f##name(DisasContext *ctx) \
@ -2095,8 +2100,12 @@ static void gen_f##name(DisasContext *ctx) \
gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \ gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \
cpu_fpr[rD(ctx->opcode)]); \ cpu_fpr[rD(ctx->opcode)]); \
} \ } \
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], set_fprf, \ if (set_fprf) { \
Rc(ctx->opcode) != 0); \ gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); \
} \
if (unlikely(Rc(ctx->opcode) != 0)) { \
gen_set_cr1_from_fpscr(ctx); \
} \
} }
#define GEN_FLOAT_ACB(name, op2, set_fprf, type) \ #define GEN_FLOAT_ACB(name, op2, set_fprf, type) \
@ -2120,8 +2129,12 @@ static void gen_f##name(DisasContext *ctx) \
gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \ gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \
cpu_fpr[rD(ctx->opcode)]); \ cpu_fpr[rD(ctx->opcode)]); \
} \ } \
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], \ if (set_fprf) { \
set_fprf, Rc(ctx->opcode) != 0); \ gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); \
} \
if (unlikely(Rc(ctx->opcode) != 0)) { \
gen_set_cr1_from_fpscr(ctx); \
} \
} }
#define GEN_FLOAT_AB(name, op2, inval, set_fprf, type) \ #define GEN_FLOAT_AB(name, op2, inval, set_fprf, type) \
_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0, set_fprf, type); \ _GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0, set_fprf, type); \
@ -2144,8 +2157,12 @@ static void gen_f##name(DisasContext *ctx) \
gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \ gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, \
cpu_fpr[rD(ctx->opcode)]); \ cpu_fpr[rD(ctx->opcode)]); \
} \ } \
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], \ if (set_fprf) { \
set_fprf, Rc(ctx->opcode) != 0); \ gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); \
} \
if (unlikely(Rc(ctx->opcode) != 0)) { \
gen_set_cr1_from_fpscr(ctx); \
} \
} }
#define GEN_FLOAT_AC(name, op2, inval, set_fprf, type) \ #define GEN_FLOAT_AC(name, op2, inval, set_fprf, type) \
_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0, set_fprf, type); \ _GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0, set_fprf, type); \
@ -2163,8 +2180,12 @@ static void gen_f##name(DisasContext *ctx) \
gen_reset_fpstatus(); \ gen_reset_fpstatus(); \
gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env, \ gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env, \
cpu_fpr[rB(ctx->opcode)]); \ cpu_fpr[rB(ctx->opcode)]); \
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], \ if (set_fprf) { \
set_fprf, Rc(ctx->opcode) != 0); \ gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); \
} \
if (unlikely(Rc(ctx->opcode) != 0)) { \
gen_set_cr1_from_fpscr(ctx); \
} \
} }
#define GEN_FLOAT_BS(name, op1, op2, set_fprf, type) \ #define GEN_FLOAT_BS(name, op1, op2, set_fprf, type) \
@ -2179,8 +2200,12 @@ static void gen_f##name(DisasContext *ctx) \
gen_reset_fpstatus(); \ gen_reset_fpstatus(); \
gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env, \ gen_helper_f##name(cpu_fpr[rD(ctx->opcode)], cpu_env, \
cpu_fpr[rB(ctx->opcode)]); \ cpu_fpr[rB(ctx->opcode)]); \
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], \ if (set_fprf) { \
set_fprf, Rc(ctx->opcode) != 0); \ gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]); \
} \
if (unlikely(Rc(ctx->opcode) != 0)) { \
gen_set_cr1_from_fpscr(ctx); \
} \
} }
/* fadd - fadds */ /* fadd - fadds */
@ -2213,7 +2238,10 @@ static void gen_frsqrtes(DisasContext *ctx)
cpu_fpr[rB(ctx->opcode)]); cpu_fpr[rB(ctx->opcode)]);
gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env,
cpu_fpr[rD(ctx->opcode)]); cpu_fpr[rD(ctx->opcode)]);
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 1, Rc(ctx->opcode) != 0); gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]);
if (unlikely(Rc(ctx->opcode) != 0)) {
gen_set_cr1_from_fpscr(ctx);
}
} }
/* fsel */ /* fsel */
@ -2234,7 +2262,10 @@ static void gen_fsqrt(DisasContext *ctx)
gen_reset_fpstatus(); gen_reset_fpstatus();
gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env, gen_helper_fsqrt(cpu_fpr[rD(ctx->opcode)], cpu_env,
cpu_fpr[rB(ctx->opcode)]); cpu_fpr[rB(ctx->opcode)]);
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 1, Rc(ctx->opcode) != 0); gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]);
if (unlikely(Rc(ctx->opcode) != 0)) {
gen_set_cr1_from_fpscr(ctx);
}
} }
static void gen_fsqrts(DisasContext *ctx) static void gen_fsqrts(DisasContext *ctx)
@ -2250,7 +2281,10 @@ static void gen_fsqrts(DisasContext *ctx)
cpu_fpr[rB(ctx->opcode)]); cpu_fpr[rB(ctx->opcode)]);
gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env, gen_helper_frsp(cpu_fpr[rD(ctx->opcode)], cpu_env,
cpu_fpr[rD(ctx->opcode)]); cpu_fpr[rD(ctx->opcode)]);
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 1, Rc(ctx->opcode) != 0); gen_compute_fprf(cpu_fpr[rD(ctx->opcode)]);
if (unlikely(Rc(ctx->opcode) != 0)) {
gen_set_cr1_from_fpscr(ctx);
}
} }
/*** Floating-Point multiply-and-add ***/ /*** Floating-Point multiply-and-add ***/
@ -2370,7 +2404,9 @@ static void gen_fabs(DisasContext *ctx)
} }
tcg_gen_andi_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)], tcg_gen_andi_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)],
~(1ULL << 63)); ~(1ULL << 63));
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 0, Rc(ctx->opcode) != 0); if (unlikely(Rc(ctx->opcode))) {
gen_set_cr1_from_fpscr(ctx);
}
} }
/* fmr - fmr. */ /* fmr - fmr. */
@ -2382,7 +2418,9 @@ static void gen_fmr(DisasContext *ctx)
return; return;
} }
tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]); tcg_gen_mov_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)]);
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 0, Rc(ctx->opcode) != 0); if (unlikely(Rc(ctx->opcode))) {
gen_set_cr1_from_fpscr(ctx);
}
} }
/* fnabs */ /* fnabs */
@ -2395,7 +2433,9 @@ static void gen_fnabs(DisasContext *ctx)
} }
tcg_gen_ori_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)], tcg_gen_ori_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)],
1ULL << 63); 1ULL << 63);
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 0, Rc(ctx->opcode) != 0); if (unlikely(Rc(ctx->opcode))) {
gen_set_cr1_from_fpscr(ctx);
}
} }
/* fneg */ /* fneg */
@ -2408,7 +2448,9 @@ static void gen_fneg(DisasContext *ctx)
} }
tcg_gen_xori_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)], tcg_gen_xori_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rB(ctx->opcode)],
1ULL << 63); 1ULL << 63);
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 0, Rc(ctx->opcode) != 0); if (unlikely(Rc(ctx->opcode))) {
gen_set_cr1_from_fpscr(ctx);
}
} }
/* fcpsgn: PowerPC 2.05 specification */ /* fcpsgn: PowerPC 2.05 specification */
@ -2421,7 +2463,9 @@ static void gen_fcpsgn(DisasContext *ctx)
} }
tcg_gen_deposit_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)], tcg_gen_deposit_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpr[rA(ctx->opcode)],
cpu_fpr[rB(ctx->opcode)], 0, 63); cpu_fpr[rB(ctx->opcode)], 0, 63);
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 0, Rc(ctx->opcode) != 0); if (unlikely(Rc(ctx->opcode))) {
gen_set_cr1_from_fpscr(ctx);
}
} }
static void gen_fmrgew(DisasContext *ctx) static void gen_fmrgew(DisasContext *ctx)
@ -2479,7 +2523,9 @@ static void gen_mffs(DisasContext *ctx)
} }
gen_reset_fpstatus(); gen_reset_fpstatus();
tcg_gen_extu_tl_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpscr); tcg_gen_extu_tl_i64(cpu_fpr[rD(ctx->opcode)], cpu_fpscr);
gen_compute_fprf(cpu_fpr[rD(ctx->opcode)], 0, Rc(ctx->opcode) != 0); if (unlikely(Rc(ctx->opcode))) {
gen_set_cr1_from_fpscr(ctx);
}
} }
/* mtfsb0 */ /* mtfsb0 */
@ -6743,7 +6789,7 @@ static void gen_st##name(DisasContext *ctx) \
tcg_temp_free(EA); \ tcg_temp_free(EA); \
} }
#define GEN_VR_LVE(name, opc2, opc3) \ #define GEN_VR_LVE(name, opc2, opc3, size) \
static void gen_lve##name(DisasContext *ctx) \ static void gen_lve##name(DisasContext *ctx) \
{ \ { \
TCGv EA; \ TCGv EA; \
@ -6755,13 +6801,16 @@ static void gen_lve##name(DisasContext *ctx) \
gen_set_access_type(ctx, ACCESS_INT); \ gen_set_access_type(ctx, ACCESS_INT); \
EA = tcg_temp_new(); \ EA = tcg_temp_new(); \
gen_addr_reg_index(ctx, EA); \ gen_addr_reg_index(ctx, EA); \
if (size > 1) { \
tcg_gen_andi_tl(EA, EA, ~(size - 1)); \
} \
rs = gen_avr_ptr(rS(ctx->opcode)); \ rs = gen_avr_ptr(rS(ctx->opcode)); \
gen_helper_lve##name(cpu_env, rs, EA); \ gen_helper_lve##name(cpu_env, rs, EA); \
tcg_temp_free(EA); \ tcg_temp_free(EA); \
tcg_temp_free_ptr(rs); \ tcg_temp_free_ptr(rs); \
} }
#define GEN_VR_STVE(name, opc2, opc3) \ #define GEN_VR_STVE(name, opc2, opc3, size) \
static void gen_stve##name(DisasContext *ctx) \ static void gen_stve##name(DisasContext *ctx) \
{ \ { \
TCGv EA; \ TCGv EA; \
@ -6773,6 +6822,9 @@ static void gen_stve##name(DisasContext *ctx) \
gen_set_access_type(ctx, ACCESS_INT); \ gen_set_access_type(ctx, ACCESS_INT); \
EA = tcg_temp_new(); \ EA = tcg_temp_new(); \
gen_addr_reg_index(ctx, EA); \ gen_addr_reg_index(ctx, EA); \
if (size > 1) { \
tcg_gen_andi_tl(EA, EA, ~(size - 1)); \
} \
rs = gen_avr_ptr(rS(ctx->opcode)); \ rs = gen_avr_ptr(rS(ctx->opcode)); \
gen_helper_stve##name(cpu_env, rs, EA); \ gen_helper_stve##name(cpu_env, rs, EA); \
tcg_temp_free(EA); \ tcg_temp_free(EA); \
@ -6783,17 +6835,17 @@ GEN_VR_LDX(lvx, 0x07, 0x03);
/* As we don't emulate the cache, lvxl is stricly equivalent to lvx */ /* As we don't emulate the cache, lvxl is stricly equivalent to lvx */
GEN_VR_LDX(lvxl, 0x07, 0x0B); GEN_VR_LDX(lvxl, 0x07, 0x0B);
GEN_VR_LVE(bx, 0x07, 0x00); GEN_VR_LVE(bx, 0x07, 0x00, 1);
GEN_VR_LVE(hx, 0x07, 0x01); GEN_VR_LVE(hx, 0x07, 0x01, 2);
GEN_VR_LVE(wx, 0x07, 0x02); GEN_VR_LVE(wx, 0x07, 0x02, 4);
GEN_VR_STX(svx, 0x07, 0x07); GEN_VR_STX(svx, 0x07, 0x07);
/* As we don't emulate the cache, stvxl is stricly equivalent to stvx */ /* As we don't emulate the cache, stvxl is stricly equivalent to stvx */
GEN_VR_STX(svxl, 0x07, 0x0F); GEN_VR_STX(svxl, 0x07, 0x0F);
GEN_VR_STVE(bx, 0x07, 0x04); GEN_VR_STVE(bx, 0x07, 0x04, 1);
GEN_VR_STVE(hx, 0x07, 0x05); GEN_VR_STVE(hx, 0x07, 0x05, 2);
GEN_VR_STVE(wx, 0x07, 0x06); GEN_VR_STVE(wx, 0x07, 0x06, 4);
static void gen_lvsl(DisasContext *ctx) static void gen_lvsl(DisasContext *ctx)
{ {
@ -8205,21 +8257,6 @@ static inline TCGv_ptr gen_fprp_ptr(int reg)
return r; return r;
} }
#if defined(TARGET_PPC64)
static void gen_set_cr1_from_fpscr(DisasContext *ctx)
{
TCGv_i32 tmp = tcg_temp_new_i32();
tcg_gen_trunc_tl_i32(tmp, cpu_fpscr);
tcg_gen_shri_i32(cpu_crf[1], tmp, 28);
tcg_temp_free_i32(tmp);
}
#else
static void gen_set_cr1_from_fpscr(DisasContext *ctx)
{
tcg_gen_shri_tl(cpu_crf[1], cpu_fpscr, 28);
}
#endif
#define GEN_DFP_T_A_B_Rc(name) \ #define GEN_DFP_T_A_B_Rc(name) \
static void gen_##name(DisasContext *ctx) \ static void gen_##name(DisasContext *ctx) \
{ \ { \
@ -9642,6 +9679,88 @@ GEN_SPE(efdctsiz, speundef, 0x1D, 0x0B, 0x00180000, 0xFFFFFFFF, PPC_SPE_DOUBLE
GEN_SPE(efdtstgt, efdtstlt, 0x1E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE); // GEN_SPE(efdtstgt, efdtstlt, 0x1E, 0x0B, 0x00600000, 0x00600000, PPC_SPE_DOUBLE); //
GEN_SPE(efdtsteq, speundef, 0x1F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_DOUBLE); // GEN_SPE(efdtsteq, speundef, 0x1F, 0x0B, 0x00600000, 0xFFFFFFFF, PPC_SPE_DOUBLE); //
static void gen_tbegin(DisasContext *ctx)
{
if (unlikely(!ctx->tm_enabled)) {
gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_TM);
return;
}
gen_helper_tbegin(cpu_env);
}
#define GEN_TM_NOOP(name) \
static inline void gen_##name(DisasContext *ctx) \
{ \
if (unlikely(!ctx->tm_enabled)) { \
gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_TM); \
return; \
} \
/* Because tbegin always fails in QEMU, these user \
* space instructions all have a simple implementation: \
* \
* CR[0] = 0b0 || MSR[TS] || 0b0 \
* = 0b0 || 0b00 || 0b0 \
*/ \
tcg_gen_movi_i32(cpu_crf[0], 0); \
}
GEN_TM_NOOP(tend);
GEN_TM_NOOP(tabort);
GEN_TM_NOOP(tabortwc);
GEN_TM_NOOP(tabortwci);
GEN_TM_NOOP(tabortdc);
GEN_TM_NOOP(tabortdci);
GEN_TM_NOOP(tsr);
static void gen_tcheck(DisasContext *ctx)
{
if (unlikely(!ctx->tm_enabled)) {
gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_TM);
return;
}
/* Because tbegin always fails, the tcheck implementation
* is simple:
*
* CR[CRF] = TDOOMED || MSR[TS] || 0b0
* = 0b1 || 0b00 || 0b0
*/
tcg_gen_movi_i32(cpu_crf[crfD(ctx->opcode)], 0x8);
}
#if defined(CONFIG_USER_ONLY)
#define GEN_TM_PRIV_NOOP(name) \
static inline void gen_##name(DisasContext *ctx) \
{ \
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); \
}
#else
#define GEN_TM_PRIV_NOOP(name) \
static inline void gen_##name(DisasContext *ctx) \
{ \
if (unlikely(ctx->pr)) { \
gen_inval_exception(ctx, POWERPC_EXCP_PRIV_OPC); \
return; \
} \
if (unlikely(!ctx->tm_enabled)) { \
gen_exception_err(ctx, POWERPC_EXCP_FU, FSCR_IC_TM); \
return; \
} \
/* Because tbegin always fails, the implementation is \
* simple: \
* \
* CR[0] = 0b0 || MSR[TS] || 0b0 \
* = 0b0 || 0b00 | 0b0 \
*/ \
tcg_gen_movi_i32(cpu_crf[0], 0); \
}
#endif
GEN_TM_PRIV_NOOP(treclaim);
GEN_TM_PRIV_NOOP(trechkpt);
static opcode_t opcodes[] = { static opcode_t opcodes[] = {
GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE), GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE),
GEN_HANDLER(cmp, 0x1F, 0x00, 0x00, 0x00400000, PPC_INTEGER), GEN_HANDLER(cmp, 0x1F, 0x00, 0x00, 0x00400000, PPC_INTEGER),
@ -11054,6 +11173,29 @@ GEN_SPEOP_LDST(evstwhe, 0x18, 2),
GEN_SPEOP_LDST(evstwho, 0x1A, 2), GEN_SPEOP_LDST(evstwho, 0x1A, 2),
GEN_SPEOP_LDST(evstwwe, 0x1C, 2), GEN_SPEOP_LDST(evstwwe, 0x1C, 2),
GEN_SPEOP_LDST(evstwwo, 0x1E, 2), GEN_SPEOP_LDST(evstwwo, 0x1E, 2),
GEN_HANDLER2_E(tbegin, "tbegin", 0x1F, 0x0E, 0x14, 0x01DFF800, \
PPC_NONE, PPC2_TM),
GEN_HANDLER2_E(tend, "tend", 0x1F, 0x0E, 0x15, 0x01FFF800, \
PPC_NONE, PPC2_TM),
GEN_HANDLER2_E(tabort, "tabort", 0x1F, 0x0E, 0x1C, 0x03E0F800, \
PPC_NONE, PPC2_TM),
GEN_HANDLER2_E(tabortwc, "tabortwc", 0x1F, 0x0E, 0x18, 0x00000000, \
PPC_NONE, PPC2_TM),
GEN_HANDLER2_E(tabortwci, "tabortwci", 0x1F, 0x0E, 0x1A, 0x00000000, \
PPC_NONE, PPC2_TM),
GEN_HANDLER2_E(tabortdc, "tabortdc", 0x1F, 0x0E, 0x19, 0x00000000, \
PPC_NONE, PPC2_TM),
GEN_HANDLER2_E(tabortdci, "tabortdci", 0x1F, 0x0E, 0x1B, 0x00000000, \
PPC_NONE, PPC2_TM),
GEN_HANDLER2_E(tsr, "tsr", 0x1F, 0x0E, 0x17, 0x03DFF800, \
PPC_NONE, PPC2_TM),
GEN_HANDLER2_E(tcheck, "tcheck", 0x1F, 0x0E, 0x16, 0x007FF800, \
PPC_NONE, PPC2_TM),
GEN_HANDLER2_E(treclaim, "treclaim", 0x1F, 0x0E, 0x1D, 0x03E0F800, \
PPC_NONE, PPC2_TM),
GEN_HANDLER2_E(trechkpt, "trechkpt", 0x1F, 0x0E, 0x1F, 0x03FFF800, \
PPC_NONE, PPC2_TM),
}; };
#include "helper_regs.h" #include "helper_regs.h"
@ -11311,6 +11453,13 @@ static inline void gen_intermediate_code_internal(PowerPCCPU *cpu,
} else { } else {
ctx.vsx_enabled = 0; ctx.vsx_enabled = 0;
} }
#if defined(TARGET_PPC64)
if ((env->flags & POWERPC_FLAG_TM) && msr_tm) {
ctx.tm_enabled = msr_tm;
} else {
ctx.tm_enabled = 0;
}
#endif
if ((env->flags & POWERPC_FLAG_SE) && msr_se) if ((env->flags & POWERPC_FLAG_SE) && msr_se)
ctx.singlestep_enabled = CPU_SINGLE_STEP; ctx.singlestep_enabled = CPU_SINGLE_STEP;
else else

View File

@ -8214,7 +8214,8 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 | PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 |
PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 | PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 |
PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 | PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 |
PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64; PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 |
PPC2_TM;
pcc->msr_mask = (1ull << MSR_SF) | pcc->msr_mask = (1ull << MSR_SF) |
(1ull << MSR_TM) | (1ull << MSR_TM) |
(1ull << MSR_VR) | (1ull << MSR_VR) |
@ -8242,7 +8243,7 @@ POWERPC_FAMILY(POWER8)(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 |
POWERPC_FLAG_VSX; POWERPC_FLAG_VSX | POWERPC_FLAG_TM;
pcc->l1_dcache_size = 0x8000; pcc->l1_dcache_size = 0x8000;
pcc->l1_icache_size = 0x8000; pcc->l1_icache_size = 0x8000;
pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr; pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;