summaryrefslogtreecommitdiff
path: root/hw/ppc
diff options
context:
space:
mode:
authorChanho Park <chanho61.park@samsung.com>2014-06-26 20:28:10 +0900
committerChanho Park <chanho61.park@samsung.com>2014-07-07 16:25:44 +0900
commita15119db2ff5c2fdfdeb913b297bf8aa3399132e (patch)
tree7d6f779408bb772b11c029ab88000fc01856b599 /hw/ppc
parent340f06c9eaee097e626c251bf7a013350649c091 (diff)
downloadqemu-a15119db2ff5c2fdfdeb913b297bf8aa3399132e.tar.gz
qemu-a15119db2ff5c2fdfdeb913b297bf8aa3399132e.tar.bz2
qemu-a15119db2ff5c2fdfdeb913b297bf8aa3399132e.zip
Imported Upstream version 2.0.0upstream/2.0.0
Change-Id: I081766c4314e7893f54fec80b920b1638d15021f
Diffstat (limited to 'hw/ppc')
-rw-r--r--hw/ppc/Makefile.objs6
-rw-r--r--hw/ppc/e500.c306
-rw-r--r--hw/ppc/e500.h13
-rw-r--r--hw/ppc/e500plat.c21
-rw-r--r--hw/ppc/mac.h1
-rw-r--r--hw/ppc/mac_newworld.c4
-rw-r--r--hw/ppc/mac_oldworld.c4
-rw-r--r--hw/ppc/mpc8544ds.c21
-rw-r--r--hw/ppc/ppc.c186
-rw-r--r--hw/ppc/ppc405_boards.c41
-rw-r--r--hw/ppc/ppc405_uc.c71
-rw-r--r--hw/ppc/ppc440_bamboo.c32
-rw-r--r--hw/ppc/ppc4xx_devs.c4
-rw-r--r--hw/ppc/ppc4xx_pci.c5
-rw-r--r--hw/ppc/ppc_booke.c87
-rw-r--r--hw/ppc/ppce500_spin.c8
-rw-r--r--hw/ppc/prep.c155
-rw-r--r--hw/ppc/spapr.c331
-rw-r--r--hw/ppc/spapr_events.c6
-rw-r--r--hw/ppc/spapr_hcall.c221
-rw-r--r--hw/ppc/spapr_iommu.c108
-rw-r--r--hw/ppc/spapr_pci.c232
-rw-r--r--hw/ppc/spapr_rtas.c134
-rw-r--r--hw/ppc/spapr_vio.c17
-rw-r--r--hw/ppc/virtex_ml507.c97
25 files changed, 1259 insertions, 852 deletions
diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs
index 7a1cd5d89..ea747f0a2 100644
--- a/hw/ppc/Makefile.objs
+++ b/hw/ppc/Makefile.objs
@@ -8,11 +8,11 @@ obj-$(CONFIG_PSERIES) += spapr_pci.o
obj-y += ppc405_boards.o ppc4xx_devs.o ppc405_uc.o ppc440_bamboo.o
obj-y += ppc4xx_pci.o
# PReP
-obj-y += prep.o
+obj-$(CONFIG_PREP) += prep.o
# OldWorld PowerMac
-obj-y += mac_oldworld.o
+obj-$(CONFIG_MAC) += mac_oldworld.o
# NewWorld PowerMac
-obj-y += mac_newworld.o
+obj-$(CONFIG_MAC) += mac_newworld.o
# e500
obj-$(CONFIG_E500) += e500.o mpc8544ds.o e500plat.o
obj-$(CONFIG_E500) += mpc8544_guts.o ppce500_spin.o
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index f00a62a1c..f984b3e9a 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -108,29 +108,31 @@ static void dt_serial_create(void *fdt, unsigned long long offset,
char ser[128];
snprintf(ser, sizeof(ser), "%s/serial@%llx", soc, offset);
- qemu_devtree_add_subnode(fdt, ser);
- qemu_devtree_setprop_string(fdt, ser, "device_type", "serial");
- qemu_devtree_setprop_string(fdt, ser, "compatible", "ns16550");
- qemu_devtree_setprop_cells(fdt, ser, "reg", offset, 0x100);
- qemu_devtree_setprop_cell(fdt, ser, "cell-index", idx);
- qemu_devtree_setprop_cell(fdt, ser, "clock-frequency", 0);
- qemu_devtree_setprop_cells(fdt, ser, "interrupts", 42, 2);
- qemu_devtree_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
- qemu_devtree_setprop_string(fdt, "/aliases", alias, ser);
+ qemu_fdt_add_subnode(fdt, ser);
+ qemu_fdt_setprop_string(fdt, ser, "device_type", "serial");
+ qemu_fdt_setprop_string(fdt, ser, "compatible", "ns16550");
+ qemu_fdt_setprop_cells(fdt, ser, "reg", offset, 0x100);
+ qemu_fdt_setprop_cell(fdt, ser, "cell-index", idx);
+ qemu_fdt_setprop_cell(fdt, ser, "clock-frequency", 0);
+ qemu_fdt_setprop_cells(fdt, ser, "interrupts", 42, 2);
+ qemu_fdt_setprop_phandle(fdt, ser, "interrupt-parent", mpic);
+ qemu_fdt_setprop_string(fdt, "/aliases", alias, ser);
if (defcon) {
- qemu_devtree_setprop_string(fdt, "/chosen", "linux,stdout-path", ser);
+ qemu_fdt_setprop_string(fdt, "/chosen", "linux,stdout-path", ser);
}
}
-static int ppce500_load_device_tree(CPUPPCState *env,
+static int ppce500_load_device_tree(QEMUMachineInitArgs *args,
PPCE500Params *params,
hwaddr addr,
hwaddr initrd_base,
- hwaddr initrd_size)
+ hwaddr initrd_size,
+ bool dry_run)
{
+ CPUPPCState *env = first_cpu->env_ptr;
int ret = -1;
- uint64_t mem_reg_property[] = { 0, cpu_to_be64(params->ram_size) };
+ uint64_t mem_reg_property[] = { 0, cpu_to_be64(args->ram_size) };
int fdt_size;
void *fdt;
uint8_t hypercall[16];
@@ -181,31 +183,31 @@ static int ppce500_load_device_tree(CPUPPCState *env,
}
/* Manipulate device tree in memory. */
- qemu_devtree_setprop_cell(fdt, "/", "#address-cells", 2);
- qemu_devtree_setprop_cell(fdt, "/", "#size-cells", 2);
+ qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 2);
+ qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 2);
- qemu_devtree_add_subnode(fdt, "/memory");
- qemu_devtree_setprop_string(fdt, "/memory", "device_type", "memory");
- qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
- sizeof(mem_reg_property));
+ qemu_fdt_add_subnode(fdt, "/memory");
+ qemu_fdt_setprop_string(fdt, "/memory", "device_type", "memory");
+ qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
+ sizeof(mem_reg_property));
- qemu_devtree_add_subnode(fdt, "/chosen");
+ qemu_fdt_add_subnode(fdt, "/chosen");
if (initrd_size) {
- ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
- initrd_base);
+ ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
+ initrd_base);
if (ret < 0) {
fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
}
- ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
- (initrd_base + initrd_size));
+ ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
+ (initrd_base + initrd_size));
if (ret < 0) {
fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
}
}
- ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
- params->kernel_cmdline);
+ ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
+ args->kernel_cmdline);
if (ret < 0)
fprintf(stderr, "couldn't set /chosen/bootargs\n");
@@ -215,27 +217,28 @@ static int ppce500_load_device_tree(CPUPPCState *env,
tb_freq = kvmppc_get_tbfreq();
/* indicate KVM hypercall interface */
- qemu_devtree_add_subnode(fdt, "/hypervisor");
- qemu_devtree_setprop_string(fdt, "/hypervisor", "compatible",
- "linux,kvm");
+ qemu_fdt_add_subnode(fdt, "/hypervisor");
+ qemu_fdt_setprop_string(fdt, "/hypervisor", "compatible",
+ "linux,kvm");
kvmppc_get_hypercall(env, hypercall, sizeof(hypercall));
- qemu_devtree_setprop(fdt, "/hypervisor", "hcall-instructions",
- hypercall, sizeof(hypercall));
+ qemu_fdt_setprop(fdt, "/hypervisor", "hcall-instructions",
+ hypercall, sizeof(hypercall));
/* if KVM supports the idle hcall, set property indicating this */
if (kvmppc_get_hasidle(env)) {
- qemu_devtree_setprop(fdt, "/hypervisor", "has-idle", NULL, 0);
+ qemu_fdt_setprop(fdt, "/hypervisor", "has-idle", NULL, 0);
}
}
/* Create CPU nodes */
- qemu_devtree_add_subnode(fdt, "/cpus");
- qemu_devtree_setprop_cell(fdt, "/cpus", "#address-cells", 1);
- qemu_devtree_setprop_cell(fdt, "/cpus", "#size-cells", 0);
+ qemu_fdt_add_subnode(fdt, "/cpus");
+ qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 1);
+ qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0);
/* We need to generate the cpu nodes in reverse order, so Linux can pick
the first node as boot node and be happy */
for (i = smp_cpus - 1; i >= 0; i--) {
CPUState *cpu;
+ PowerPCCPU *pcpu;
char cpu_name[128];
uint64_t cpu_release_addr = MPC8544_SPIN_BASE + (i * 0x20);
@@ -244,58 +247,61 @@ static int ppce500_load_device_tree(CPUPPCState *env,
continue;
}
env = cpu->env_ptr;
+ pcpu = POWERPC_CPU(cpu);
snprintf(cpu_name, sizeof(cpu_name), "/cpus/PowerPC,8544@%x",
- cpu->cpu_index);
- qemu_devtree_add_subnode(fdt, cpu_name);
- qemu_devtree_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
- qemu_devtree_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
- qemu_devtree_setprop_string(fdt, cpu_name, "device_type", "cpu");
- qemu_devtree_setprop_cell(fdt, cpu_name, "reg", cpu->cpu_index);
- qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-line-size",
- env->dcache_line_size);
- qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-line-size",
- env->icache_line_size);
- qemu_devtree_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000);
- qemu_devtree_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000);
- qemu_devtree_setprop_cell(fdt, cpu_name, "bus-frequency", 0);
+ ppc_get_vcpu_dt_id(pcpu));
+ qemu_fdt_add_subnode(fdt, cpu_name);
+ qemu_fdt_setprop_cell(fdt, cpu_name, "clock-frequency", clock_freq);
+ qemu_fdt_setprop_cell(fdt, cpu_name, "timebase-frequency", tb_freq);
+ qemu_fdt_setprop_string(fdt, cpu_name, "device_type", "cpu");
+ qemu_fdt_setprop_cell(fdt, cpu_name, "reg",
+ ppc_get_vcpu_dt_id(pcpu));
+ qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-line-size",
+ env->dcache_line_size);
+ qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-line-size",
+ env->icache_line_size);
+ qemu_fdt_setprop_cell(fdt, cpu_name, "d-cache-size", 0x8000);
+ qemu_fdt_setprop_cell(fdt, cpu_name, "i-cache-size", 0x8000);
+ qemu_fdt_setprop_cell(fdt, cpu_name, "bus-frequency", 0);
if (cpu->cpu_index) {
- qemu_devtree_setprop_string(fdt, cpu_name, "status", "disabled");
- qemu_devtree_setprop_string(fdt, cpu_name, "enable-method", "spin-table");
- qemu_devtree_setprop_u64(fdt, cpu_name, "cpu-release-addr",
- cpu_release_addr);
+ qemu_fdt_setprop_string(fdt, cpu_name, "status", "disabled");
+ qemu_fdt_setprop_string(fdt, cpu_name, "enable-method",
+ "spin-table");
+ qemu_fdt_setprop_u64(fdt, cpu_name, "cpu-release-addr",
+ cpu_release_addr);
} else {
- qemu_devtree_setprop_string(fdt, cpu_name, "status", "okay");
+ qemu_fdt_setprop_string(fdt, cpu_name, "status", "okay");
}
}
- qemu_devtree_add_subnode(fdt, "/aliases");
+ qemu_fdt_add_subnode(fdt, "/aliases");
/* XXX These should go into their respective devices' code */
snprintf(soc, sizeof(soc), "/soc@%llx", MPC8544_CCSRBAR_BASE);
- qemu_devtree_add_subnode(fdt, soc);
- qemu_devtree_setprop_string(fdt, soc, "device_type", "soc");
- qemu_devtree_setprop(fdt, soc, "compatible", compatible_sb,
- sizeof(compatible_sb));
- qemu_devtree_setprop_cell(fdt, soc, "#address-cells", 1);
- qemu_devtree_setprop_cell(fdt, soc, "#size-cells", 1);
- qemu_devtree_setprop_cells(fdt, soc, "ranges", 0x0,
- MPC8544_CCSRBAR_BASE >> 32, MPC8544_CCSRBAR_BASE,
- MPC8544_CCSRBAR_SIZE);
+ qemu_fdt_add_subnode(fdt, soc);
+ qemu_fdt_setprop_string(fdt, soc, "device_type", "soc");
+ qemu_fdt_setprop(fdt, soc, "compatible", compatible_sb,
+ sizeof(compatible_sb));
+ qemu_fdt_setprop_cell(fdt, soc, "#address-cells", 1);
+ qemu_fdt_setprop_cell(fdt, soc, "#size-cells", 1);
+ qemu_fdt_setprop_cells(fdt, soc, "ranges", 0x0,
+ MPC8544_CCSRBAR_BASE >> 32, MPC8544_CCSRBAR_BASE,
+ MPC8544_CCSRBAR_SIZE);
/* XXX should contain a reasonable value */
- qemu_devtree_setprop_cell(fdt, soc, "bus-frequency", 0);
+ qemu_fdt_setprop_cell(fdt, soc, "bus-frequency", 0);
snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET);
- qemu_devtree_add_subnode(fdt, mpic);
- qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic");
- qemu_devtree_setprop_string(fdt, mpic, "compatible", "fsl,mpic");
- qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET,
- 0x40000);
- qemu_devtree_setprop_cell(fdt, mpic, "#address-cells", 0);
- qemu_devtree_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
- mpic_ph = qemu_devtree_alloc_phandle(fdt);
- qemu_devtree_setprop_cell(fdt, mpic, "phandle", mpic_ph);
- qemu_devtree_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
- qemu_devtree_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
+ qemu_fdt_add_subnode(fdt, mpic);
+ qemu_fdt_setprop_string(fdt, mpic, "device_type", "open-pic");
+ qemu_fdt_setprop_string(fdt, mpic, "compatible", "fsl,mpic");
+ qemu_fdt_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET,
+ 0x40000);
+ qemu_fdt_setprop_cell(fdt, mpic, "#address-cells", 0);
+ qemu_fdt_setprop_cell(fdt, mpic, "#interrupt-cells", 2);
+ mpic_ph = qemu_fdt_alloc_phandle(fdt);
+ qemu_fdt_setprop_cell(fdt, mpic, "phandle", mpic_ph);
+ qemu_fdt_setprop_cell(fdt, mpic, "linux,phandle", mpic_ph);
+ qemu_fdt_setprop(fdt, mpic, "interrupt-controller", NULL, 0);
/*
* We have to generate ser1 first, because Linux takes the first
@@ -309,19 +315,19 @@ static int ppce500_load_device_tree(CPUPPCState *env,
snprintf(gutil, sizeof(gutil), "%s/global-utilities@%llx", soc,
MPC8544_UTIL_OFFSET);
- qemu_devtree_add_subnode(fdt, gutil);
- qemu_devtree_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
- qemu_devtree_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000);
- qemu_devtree_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
+ qemu_fdt_add_subnode(fdt, gutil);
+ qemu_fdt_setprop_string(fdt, gutil, "compatible", "fsl,mpc8544-guts");
+ qemu_fdt_setprop_cells(fdt, gutil, "reg", MPC8544_UTIL_OFFSET, 0x1000);
+ qemu_fdt_setprop(fdt, gutil, "fsl,has-rstcr", NULL, 0);
snprintf(msi, sizeof(msi), "/%s/msi@%llx", soc, MPC8544_MSI_REGS_OFFSET);
- qemu_devtree_add_subnode(fdt, msi);
- qemu_devtree_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi");
- qemu_devtree_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200);
- msi_ph = qemu_devtree_alloc_phandle(fdt);
- qemu_devtree_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100);
- qemu_devtree_setprop_phandle(fdt, msi, "interrupt-parent", mpic);
- qemu_devtree_setprop_cells(fdt, msi, "interrupts",
+ qemu_fdt_add_subnode(fdt, msi);
+ qemu_fdt_setprop_string(fdt, msi, "compatible", "fsl,mpic-msi");
+ qemu_fdt_setprop_cells(fdt, msi, "reg", MPC8544_MSI_REGS_OFFSET, 0x200);
+ msi_ph = qemu_fdt_alloc_phandle(fdt);
+ qemu_fdt_setprop_cells(fdt, msi, "msi-available-ranges", 0x0, 0x100);
+ qemu_fdt_setprop_phandle(fdt, msi, "interrupt-parent", mpic);
+ qemu_fdt_setprop_cells(fdt, msi, "interrupts",
0xe0, 0x0,
0xe1, 0x0,
0xe2, 0x0,
@@ -330,50 +336,48 @@ static int ppce500_load_device_tree(CPUPPCState *env,
0xe5, 0x0,
0xe6, 0x0,
0xe7, 0x0);
- qemu_devtree_setprop_cell(fdt, msi, "phandle", msi_ph);
- qemu_devtree_setprop_cell(fdt, msi, "linux,phandle", msi_ph);
+ qemu_fdt_setprop_cell(fdt, msi, "phandle", msi_ph);
+ qemu_fdt_setprop_cell(fdt, msi, "linux,phandle", msi_ph);
snprintf(pci, sizeof(pci), "/pci@%llx", MPC8544_PCI_REGS_BASE);
- qemu_devtree_add_subnode(fdt, pci);
- qemu_devtree_setprop_cell(fdt, pci, "cell-index", 0);
- qemu_devtree_setprop_string(fdt, pci, "compatible", "fsl,mpc8540-pci");
- qemu_devtree_setprop_string(fdt, pci, "device_type", "pci");
- qemu_devtree_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,
- 0x0, 0x7);
- pci_map = pci_map_create(fdt, qemu_devtree_get_phandle(fdt, mpic),
+ qemu_fdt_add_subnode(fdt, pci);
+ 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, "device_type", "pci");
+ qemu_fdt_setprop_cells(fdt, pci, "interrupt-map-mask", 0xf800, 0x0,
+ 0x0, 0x7);
+ pci_map = pci_map_create(fdt, qemu_fdt_get_phandle(fdt, mpic),
params->pci_first_slot, params->pci_nr_slots,
&len);
- qemu_devtree_setprop(fdt, pci, "interrupt-map", pci_map, len);
- qemu_devtree_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
- qemu_devtree_setprop_cells(fdt, pci, "interrupts", 24, 2);
- qemu_devtree_setprop_cells(fdt, pci, "bus-range", 0, 255);
+ qemu_fdt_setprop(fdt, pci, "interrupt-map", pci_map, len);
+ qemu_fdt_setprop_phandle(fdt, pci, "interrupt-parent", mpic);
+ qemu_fdt_setprop_cells(fdt, pci, "interrupts", 24, 2);
+ qemu_fdt_setprop_cells(fdt, pci, "bus-range", 0, 255);
for (i = 0; i < 14; i++) {
pci_ranges[i] = cpu_to_be32(pci_ranges[i]);
}
- qemu_devtree_setprop_cell(fdt, pci, "fsl,msi", msi_ph);
- qemu_devtree_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
- qemu_devtree_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32,
- MPC8544_PCI_REGS_BASE, 0, 0x1000);
- qemu_devtree_setprop_cell(fdt, pci, "clock-frequency", 66666666);
- qemu_devtree_setprop_cell(fdt, pci, "#interrupt-cells", 1);
- qemu_devtree_setprop_cell(fdt, pci, "#size-cells", 2);
- qemu_devtree_setprop_cell(fdt, pci, "#address-cells", 3);
- qemu_devtree_setprop_string(fdt, "/aliases", "pci0", pci);
+ qemu_fdt_setprop_cell(fdt, pci, "fsl,msi", msi_ph);
+ qemu_fdt_setprop(fdt, pci, "ranges", pci_ranges, sizeof(pci_ranges));
+ qemu_fdt_setprop_cells(fdt, pci, "reg", MPC8544_PCI_REGS_BASE >> 32,
+ MPC8544_PCI_REGS_BASE, 0, 0x1000);
+ qemu_fdt_setprop_cell(fdt, pci, "clock-frequency", 66666666);
+ qemu_fdt_setprop_cell(fdt, pci, "#interrupt-cells", 1);
+ qemu_fdt_setprop_cell(fdt, pci, "#size-cells", 2);
+ qemu_fdt_setprop_cell(fdt, pci, "#address-cells", 3);
+ qemu_fdt_setprop_string(fdt, "/aliases", "pci0", pci);
params->fixup_devtree(params, fdt);
if (toplevel_compat) {
- qemu_devtree_setprop(fdt, "/", "compatible", toplevel_compat,
- strlen(toplevel_compat) + 1);
+ qemu_fdt_setprop(fdt, "/", "compatible", toplevel_compat,
+ strlen(toplevel_compat) + 1);
}
done:
- qemu_devtree_dumpdtb(fdt, fdt_size);
- ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
- if (ret < 0) {
- goto out;
+ if (!dry_run) {
+ qemu_fdt_dumpdtb(fdt, fdt_size);
+ cpu_physical_memory_write(addr, fdt, fdt_size);
}
- g_free(fdt);
ret = fdt_size;
out:
@@ -382,6 +386,41 @@ out:
return ret;
}
+typedef struct DeviceTreeParams {
+ QEMUMachineInitArgs args;
+ PPCE500Params params;
+ hwaddr addr;
+ hwaddr initrd_base;
+ hwaddr initrd_size;
+} DeviceTreeParams;
+
+static void ppce500_reset_device_tree(void *opaque)
+{
+ DeviceTreeParams *p = opaque;
+ ppce500_load_device_tree(&p->args, &p->params, p->addr, p->initrd_base,
+ p->initrd_size, false);
+}
+
+static int ppce500_prep_device_tree(QEMUMachineInitArgs *args,
+ PPCE500Params *params,
+ hwaddr addr,
+ hwaddr initrd_base,
+ hwaddr initrd_size)
+{
+ DeviceTreeParams *p = g_new(DeviceTreeParams, 1);
+ p->args = *args;
+ p->params = *params;
+ p->addr = addr;
+ p->initrd_base = initrd_base;
+ p->initrd_size = initrd_size;
+
+ qemu_register_reset(ppce500_reset_device_tree, p);
+
+ /* Issue the device tree loader once, so that we get the size of the blob */
+ return ppce500_load_device_tree(args, params, addr, initrd_base,
+ initrd_size, true);
+}
+
/* Create -kernel TLB entries for BookE. */
static inline hwaddr booke206_page_size_to_tlb(uint64_t size)
{
@@ -433,14 +472,13 @@ static void ppce500_cpu_reset_sec(void *opaque)
{
PowerPCCPU *cpu = opaque;
CPUState *cs = CPU(cpu);
- CPUPPCState *env = &cpu->env;
cpu_reset(cs);
/* Secondary CPU starts in halted state for now. Needs to change when
implementing non-kernel boot. */
cs->halted = 1;
- env->exception_index = EXCP_HLT;
+ cs->exception_index = EXCP_HLT;
}
static void ppce500_cpu_reset(void *opaque)
@@ -505,7 +543,7 @@ static DeviceState *ppce500_init_mpic_kvm(PPCE500Params *params,
return NULL;
}
- for (cs = first_cpu; cs != NULL; cs = cs->next_cpu) {
+ CPU_FOREACH(cs) {
if (kvm_openpic_connect_vcpu(dev, cs)) {
fprintf(stderr, "%s: failed to connect vcpu to irqchip\n",
__func__);
@@ -559,7 +597,7 @@ static qemu_irq *ppce500_init_mpic(PPCE500Params *params, MemoryRegion *ccsr,
return mpic;
}
-void ppce500_init(PPCE500Params *params)
+void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params)
{
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *ram = g_new(MemoryRegion, 1);
@@ -584,8 +622,8 @@ void ppce500_init(PPCE500Params *params)
PPCE500CCSRState *ccsr;
/* Setup CPUs */
- if (params->cpu_model == NULL) {
- params->cpu_model = "e500v2_v30";
+ if (args->cpu_model == NULL) {
+ args->cpu_model = "e500v2_v30";
}
irqs = g_malloc0(smp_cpus * sizeof(qemu_irq *));
@@ -595,7 +633,7 @@ void ppce500_init(PPCE500Params *params)
CPUState *cs;
qemu_irq *input;
- cpu = cpu_ppc_init(params->cpu_model);
+ cpu = cpu_ppc_init(args->cpu_model);
if (cpu == NULL) {
fprintf(stderr, "Unable to initialize CPU!\n");
exit(1);
@@ -611,7 +649,7 @@ void ppce500_init(PPCE500Params *params)
input = (qemu_irq *)env->irq_inputs;
irqs[i][OPENPIC_OUTPUT_INT] = input[PPCE500_INPUT_INT];
irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT];
- env->spr[SPR_BOOKE_PIR] = cs->cpu_index = i;
+ env->spr_cb[SPR_BOOKE_PIR].default_value = cs->cpu_index = i;
env->mpic_iack = MPC8544_CCSRBAR_BASE +
MPC8544_MPIC_REGS_OFFSET + 0xa0;
@@ -634,7 +672,7 @@ void ppce500_init(PPCE500Params *params)
/* Fixup Memory size on a alignment boundary */
ram_size &= ~(RAM_SIZES_ALIGN - 1);
- params->ram_size = ram_size;
+ args->ram_size = ram_size;
/* Register Memory */
memory_region_init_ram(ram, NULL, "mpc8544ds.ram", ram_size);
@@ -701,11 +739,11 @@ void ppce500_init(PPCE500Params *params)
sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL);
/* Load kernel. */
- if (params->kernel_filename) {
- kernel_size = load_uimage(params->kernel_filename, &entry,
+ if (args->kernel_filename) {
+ kernel_size = load_uimage(args->kernel_filename, &entry,
&loadaddr, NULL);
if (kernel_size < 0) {
- kernel_size = load_elf(params->kernel_filename, NULL, NULL,
+ kernel_size = load_elf(args->kernel_filename, NULL, NULL,
&elf_entry, &elf_lowaddr, NULL, 1,
ELF_MACHINE, 0);
entry = elf_entry;
@@ -714,7 +752,7 @@ void ppce500_init(PPCE500Params *params)
/* XXX try again as binary */
if (kernel_size < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
- params->kernel_filename);
+ args->kernel_filename);
exit(1);
}
@@ -726,14 +764,14 @@ void ppce500_init(PPCE500Params *params)
}
/* Load initrd. */
- if (params->initrd_filename) {
+ if (args->initrd_filename) {
initrd_base = (cur_base + INITRD_LOAD_PAD) & ~INITRD_PAD_MASK;
- initrd_size = load_image_targphys(params->initrd_filename, initrd_base,
+ initrd_size = load_image_targphys(args->initrd_filename, initrd_base,
ram_size - initrd_base);
if (initrd_size < 0) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
- params->initrd_filename);
+ args->initrd_filename);
exit(1);
}
@@ -741,12 +779,12 @@ void ppce500_init(PPCE500Params *params)
}
/* If we're loading a kernel directly, we must load the device tree too. */
- if (params->kernel_filename) {
+ if (args->kernel_filename) {
struct boot_info *boot_info;
int dt_size;
- dt_size = ppce500_load_device_tree(env, params, dt_base, initrd_base,
- initrd_size);
+ dt_size = ppce500_prep_device_tree(args, params, dt_base,
+ initrd_base, initrd_size);
if (dt_size < 0) {
fprintf(stderr, "couldn't load device tree\n");
exit(1);
diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h
index 226c93d24..52726a2ec 100644
--- a/hw/ppc/e500.h
+++ b/hw/ppc/e500.h
@@ -1,25 +1,18 @@
#ifndef PPCE500_H
#define PPCE500_H
+#include "hw/boards.h"
+
typedef struct PPCE500Params {
- /* Standard QEMU machine init params */
- ram_addr_t ram_size;
- const char *boot_device;
- const char *kernel_filename;
- const char *kernel_cmdline;
- const char *initrd_filename;
- const char *cpu_model;
int pci_first_slot;
int pci_nr_slots;
- /* e500-specific params */
-
/* required -- must at least add toplevel board compatible */
void (*fixup_devtree)(struct PPCE500Params *params, void *fdt);
int mpic_version;
} PPCE500Params;
-void ppce500_init(PPCE500Params *params);
+void ppce500_init(QEMUMachineInitArgs *args, PPCE500Params *params);
#endif
diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c
index c85299588..7d5357e83 100644
--- a/hw/ppc/e500plat.c
+++ b/hw/ppc/e500plat.c
@@ -23,26 +23,14 @@ static void e500plat_fixup_devtree(PPCE500Params *params, void *fdt)
const char model[] = "QEMU ppce500";
const char compatible[] = "fsl,qemu-e500";
- qemu_devtree_setprop(fdt, "/", "model", model, sizeof(model));
- qemu_devtree_setprop(fdt, "/", "compatible", compatible,
- sizeof(compatible));
+ qemu_fdt_setprop(fdt, "/", "model", model, sizeof(model));
+ qemu_fdt_setprop(fdt, "/", "compatible", compatible,
+ sizeof(compatible));
}
static void e500plat_init(QEMUMachineInitArgs *args)
{
- ram_addr_t ram_size = args->ram_size;
- const char *boot_device = args->boot_device;
- const char *cpu_model = args->cpu_model;
- const char *kernel_filename = args->kernel_filename;
- const char *kernel_cmdline = args->kernel_cmdline;
- const char *initrd_filename = args->initrd_filename;
PPCE500Params params = {
- .ram_size = ram_size,
- .boot_device = boot_device,
- .kernel_filename = kernel_filename,
- .kernel_cmdline = kernel_cmdline,
- .initrd_filename = initrd_filename,
- .cpu_model = cpu_model,
.pci_first_slot = 0x1,
.pci_nr_slots = PCI_SLOT_MAX - 1,
.fixup_devtree = e500plat_fixup_devtree,
@@ -55,7 +43,7 @@ static void e500plat_init(QEMUMachineInitArgs *args)
params.mpic_version = OPENPIC_MODEL_FSL_MPIC_20;
}
- ppce500_init(&params);
+ ppce500_init(args, &params);
}
static QEMUMachine e500plat_machine = {
@@ -63,7 +51,6 @@ static QEMUMachine e500plat_machine = {
.desc = "generic paravirt e500 platform",
.init = e500plat_init,
.max_cpus = 32,
- DEFAULT_MACHINE_OPTIONS,
};
static void e500plat_machine_init(void)
diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h
index 1e578dd59..c1faf9ce2 100644
--- a/hw/ppc/mac.h
+++ b/hw/ppc/mac.h
@@ -34,7 +34,6 @@
#define MAX_CPUS 1
#define BIOS_SIZE (1024 * 1024)
-#define BIOS_FILENAME "ppc_rom.bin"
#define NVRAM_SIZE 0x2000
#define PROM_FILENAME "openbios-ppc"
#define PROM_ADDR 0xfff00000
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index 7ef806ef7..5e7957516 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -147,7 +147,7 @@ static void ppc_core99_init(QEMUMachineInitArgs *args)
const char *kernel_filename = args->kernel_filename;
const char *kernel_cmdline = args->kernel_cmdline;
const char *initrd_filename = args->initrd_filename;
- const char *boot_device = args->boot_device;
+ const char *boot_device = args->boot_order;
PowerPCCPU *cpu = NULL;
CPUPPCState *env = NULL;
char *filename;
@@ -477,7 +477,7 @@ static QEMUMachine core99_machine = {
.desc = "Mac99 based PowerMAC",
.init = ppc_core99_init,
.max_cpus = MAX_CPUS,
- DEFAULT_MACHINE_OPTIONS,
+ .default_boot_order = "cd",
};
static void core99_machine_init(void)
diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c
index 42bb9d55c..2f27754c6 100644
--- a/hw/ppc/mac_oldworld.c
+++ b/hw/ppc/mac_oldworld.c
@@ -78,7 +78,7 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args)
const char *kernel_filename = args->kernel_filename;
const char *kernel_cmdline = args->kernel_cmdline;
const char *initrd_filename = args->initrd_filename;
- const char *boot_device = args->boot_device;
+ const char *boot_device = args->boot_order;
MemoryRegion *sysmem = get_system_memory();
PowerPCCPU *cpu = NULL;
CPUPPCState *env = NULL;
@@ -350,7 +350,7 @@ static QEMUMachine heathrow_machine = {
#ifndef TARGET_PPC64
.is_default = 1,
#endif
- DEFAULT_MACHINE_OPTIONS,
+ .default_boot_order = "cd", /* TOFIX "cad" when Mac floppy is implemented */
};
static void heathrow_machine_init(void)
diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c
index 444da0246..292c70953 100644
--- a/hw/ppc/mpc8544ds.c
+++ b/hw/ppc/mpc8544ds.c
@@ -21,33 +21,21 @@ static void mpc8544ds_fixup_devtree(PPCE500Params *params, void *fdt)
const char model[] = "MPC8544DS";
const char compatible[] = "MPC8544DS\0MPC85xxDS";
- qemu_devtree_setprop(fdt, "/", "model", model, sizeof(model));
- qemu_devtree_setprop(fdt, "/", "compatible", compatible,
- sizeof(compatible));
+ qemu_fdt_setprop(fdt, "/", "model", model, sizeof(model));
+ qemu_fdt_setprop(fdt, "/", "compatible", compatible,
+ sizeof(compatible));
}
static void mpc8544ds_init(QEMUMachineInitArgs *args)
{
- ram_addr_t ram_size = args->ram_size;
- const char *boot_device = args->boot_device;
- const char *cpu_model = args->cpu_model;
- const char *kernel_filename = args->kernel_filename;
- const char *kernel_cmdline = args->kernel_cmdline;
- const char *initrd_filename = args->initrd_filename;
PPCE500Params params = {
- .ram_size = ram_size,
- .boot_device = boot_device,
- .kernel_filename = kernel_filename,
- .kernel_cmdline = kernel_cmdline,
- .initrd_filename = initrd_filename,
- .cpu_model = cpu_model,
.pci_first_slot = 0x11,
.pci_nr_slots = 2,
.fixup_devtree = mpc8544ds_fixup_devtree,
.mpic_version = OPENPIC_MODEL_FSL_MPIC_20,
};
- ppce500_init(&params);
+ ppce500_init(args, &params);
}
@@ -56,7 +44,6 @@ static QEMUMachine ppce500_machine = {
.desc = "mpc8544ds",
.init = mpc8544ds_init,
.max_cpus = 15,
- DEFAULT_MACHINE_OPTIONS,
};
static void ppce500_machine_init(void)
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index e1c095c7e..71df47174 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -26,6 +26,7 @@
#include "hw/ppc/ppc_e500.h"
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
+#include "sysemu/cpus.h"
#include "hw/timer/m48t59.h"
#include "qemu/log.h"
#include "hw/loader.h"
@@ -443,7 +444,7 @@ void ppce500_set_mpic_proxy(bool enabled)
{
CPUState *cs;
- for (cs = first_cpu; cs != NULL; cs = cs->next_cpu) {
+ CPU_FOREACH(cs) {
PowerPCCPU *cpu = POWERPC_CPU(cs);
cpu->env.mpic_proxy = enabled;
@@ -471,7 +472,7 @@ uint64_t cpu_ppc_load_tbl (CPUPPCState *env)
return env->spr[SPR_TBL];
}
- tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset);
+ tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset);
LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
return tb;
@@ -482,7 +483,7 @@ static inline uint32_t _cpu_ppc_load_tbu(CPUPPCState *env)
ppc_tb_t *tb_env = env->tb_env;
uint64_t tb;
- tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset);
+ tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset);
LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
return tb >> 32;
@@ -510,9 +511,9 @@ void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value)
ppc_tb_t *tb_env = env->tb_env;
uint64_t tb;
- tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset);
+ tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset);
tb &= 0xFFFFFFFF00000000ULL;
- cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock),
+ cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
&tb_env->tb_offset, tb | (uint64_t)value);
}
@@ -521,9 +522,9 @@ static inline void _cpu_ppc_store_tbu(CPUPPCState *env, uint32_t value)
ppc_tb_t *tb_env = env->tb_env;
uint64_t tb;
- tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->tb_offset);
+ tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->tb_offset);
tb &= 0x00000000FFFFFFFFULL;
- cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock),
+ cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
&tb_env->tb_offset, ((uint64_t)value << 32) | tb);
}
@@ -537,7 +538,7 @@ uint64_t cpu_ppc_load_atbl (CPUPPCState *env)
ppc_tb_t *tb_env = env->tb_env;
uint64_t tb;
- tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset);
+ tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset);
LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
return tb;
@@ -548,7 +549,7 @@ uint32_t cpu_ppc_load_atbu (CPUPPCState *env)
ppc_tb_t *tb_env = env->tb_env;
uint64_t tb;
- tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset);
+ tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset);
LOG_TB("%s: tb %016" PRIx64 "\n", __func__, tb);
return tb >> 32;
@@ -559,9 +560,9 @@ void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value)
ppc_tb_t *tb_env = env->tb_env;
uint64_t tb;
- tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset);
+ tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset);
tb &= 0xFFFFFFFF00000000ULL;
- cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock),
+ cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
&tb_env->atb_offset, tb | (uint64_t)value);
}
@@ -570,9 +571,9 @@ void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value)
ppc_tb_t *tb_env = env->tb_env;
uint64_t tb;
- tb = cpu_ppc_get_tb(tb_env, qemu_get_clock_ns(vm_clock), tb_env->atb_offset);
+ tb = cpu_ppc_get_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), tb_env->atb_offset);
tb &= 0x00000000FFFFFFFFULL;
- cpu_ppc_store_tb(tb_env, qemu_get_clock_ns(vm_clock),
+ cpu_ppc_store_tb(tb_env, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
&tb_env->atb_offset, ((uint64_t)value << 32) | tb);
}
@@ -583,7 +584,7 @@ static void cpu_ppc_tb_stop (CPUPPCState *env)
/* If the time base is already frozen, do nothing */
if (tb_env->tb_freq != 0) {
- vmclk = qemu_get_clock_ns(vm_clock);
+ vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
/* Get the time base */
tb = cpu_ppc_get_tb(tb_env, vmclk, tb_env->tb_offset);
/* Get the alternate time base */
@@ -605,7 +606,7 @@ static void cpu_ppc_tb_start (CPUPPCState *env)
/* If the time base is not frozen, do nothing */
if (tb_env->tb_freq == 0) {
- vmclk = qemu_get_clock_ns(vm_clock);
+ vmclk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
/* Get the time base from tb_offset */
tb = tb_env->tb_offset;
/* Get the alternate time base from atb_offset */
@@ -619,13 +620,20 @@ static void cpu_ppc_tb_start (CPUPPCState *env)
}
}
+bool ppc_decr_clear_on_delivery(CPUPPCState *env)
+{
+ ppc_tb_t *tb_env = env->tb_env;
+ int flags = PPC_DECR_UNDERFLOW_TRIGGERED | PPC_DECR_UNDERFLOW_LEVEL;
+ return ((tb_env->flags & flags) == PPC_DECR_UNDERFLOW_TRIGGERED);
+}
+
static inline uint32_t _cpu_ppc_load_decr(CPUPPCState *env, uint64_t next)
{
ppc_tb_t *tb_env = env->tb_env;
uint32_t decr;
int64_t diff;
- diff = next - qemu_get_clock_ns(vm_clock);
+ diff = next - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
if (diff >= 0) {
decr = muldiv64(diff, tb_env->decr_freq, get_ticks_per_sec());
} else if (tb_env->flags & PPC_TIMER_BOOKE) {
@@ -661,7 +669,7 @@ uint64_t cpu_ppc_load_purr (CPUPPCState *env)
ppc_tb_t *tb_env = env->tb_env;
uint64_t diff;
- diff = qemu_get_clock_ns(vm_clock) - tb_env->purr_start;
+ diff = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - tb_env->purr_start;
return tb_env->purr_load + muldiv64(diff, tb_env->tb_freq, get_ticks_per_sec());
}
@@ -676,6 +684,11 @@ static inline void cpu_ppc_decr_excp(PowerPCCPU *cpu)
ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 1);
}
+static inline void cpu_ppc_decr_lower(PowerPCCPU *cpu)
+{
+ ppc_set_irq(cpu, PPC_INTERRUPT_DECR, 0);
+}
+
static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu)
{
/* Raise it */
@@ -683,11 +696,16 @@ static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu)
ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 1);
}
+static inline void cpu_ppc_hdecr_lower(PowerPCCPU *cpu)
+{
+ ppc_set_irq(cpu, PPC_INTERRUPT_HDECR, 0);
+}
+
static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
- struct QEMUTimer *timer,
- void (*raise_excp)(PowerPCCPU *),
- uint32_t decr, uint32_t value,
- int is_excp)
+ QEMUTimer *timer,
+ void (*raise_excp)(void *),
+ void (*lower_excp)(PowerPCCPU *),
+ uint32_t decr, uint32_t value)
{
CPUPPCState *env = &cpu->env;
ppc_tb_t *tb_env = env->tb_env;
@@ -701,59 +719,74 @@ static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp,
return;
}
- now = qemu_get_clock_ns(vm_clock);
- next = now + muldiv64(value, get_ticks_per_sec(), tb_env->decr_freq);
- if (is_excp) {
- next += *nextp - now;
+ /*
+ * Going from 2 -> 1, 1 -> 0 or 0 -> -1 is the event to generate a DEC
+ * interrupt.
+ *
+ * If we get a really small DEC value, we can assume that by the time we
+ * handled it we should inject an interrupt already.
+ *
+ * On MSB level based DEC implementations the MSB always means the interrupt
+ * is pending, so raise it on those.
+ *
+ * On MSB edge based DEC implementations the MSB going from 0 -> 1 triggers
+ * an edge interrupt, so raise it here too.
+ */
+ if ((value < 3) ||
+ ((tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL) && (value & 0x80000000)) ||
+ ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED) && (value & 0x80000000)
+ && !(decr & 0x80000000))) {
+ (*raise_excp)(cpu);
+ return;
}
- if (next == now) {
- next++;
+
+ /* On MSB level based systems a 0 for the MSB stops interrupt delivery */
+ if (!(value & 0x80000000) && (tb_env->flags & PPC_DECR_UNDERFLOW_LEVEL)) {
+ (*lower_excp)(cpu);
}
+
+ /* Calculate the next timer event */
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ next = now + muldiv64(value, get_ticks_per_sec(), tb_env->decr_freq);
*nextp = next;
- /* Adjust timer */
- qemu_mod_timer(timer, next);
- /* If we set a negative value and the decrementer was positive, raise an
- * exception.
- */
- if ((tb_env->flags & PPC_DECR_UNDERFLOW_TRIGGERED)
- && (value & 0x80000000)
- && !(decr & 0x80000000)) {
- (*raise_excp)(cpu);
- }
+ /* Adjust timer */
+ timer_mod(timer, next);
}
static inline void _cpu_ppc_store_decr(PowerPCCPU *cpu, uint32_t decr,
- uint32_t value, int is_excp)
+ uint32_t value)
{
ppc_tb_t *tb_env = cpu->env.tb_env;
__cpu_ppc_store_decr(cpu, &tb_env->decr_next, tb_env->decr_timer,
- &cpu_ppc_decr_excp, decr, value, is_excp);
+ tb_env->decr_timer->cb, &cpu_ppc_decr_lower, decr,
+ value);
}
void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value)
{
PowerPCCPU *cpu = ppc_env_get_cpu(env);
- _cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value, 0);
+ _cpu_ppc_store_decr(cpu, cpu_ppc_load_decr(env), value);
}
static void cpu_ppc_decr_cb(void *opaque)
{
PowerPCCPU *cpu = opaque;
- _cpu_ppc_store_decr(cpu, 0x00000000, 0xFFFFFFFF, 1);
+ cpu_ppc_decr_excp(cpu);
}
static inline void _cpu_ppc_store_hdecr(PowerPCCPU *cpu, uint32_t hdecr,
- uint32_t value, int is_excp)
+ uint32_t value)
{
ppc_tb_t *tb_env = cpu->env.tb_env;
if (tb_env->hdecr_timer != NULL) {
__cpu_ppc_store_decr(cpu, &tb_env->hdecr_next, tb_env->hdecr_timer,
- &cpu_ppc_hdecr_excp, hdecr, value, is_excp);
+ tb_env->hdecr_timer->cb, &cpu_ppc_hdecr_lower,
+ hdecr, value);
}
}
@@ -761,14 +794,14 @@ void cpu_ppc_store_hdecr (CPUPPCState *env, uint32_t value)
{
PowerPCCPU *cpu = ppc_env_get_cpu(env);
- _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value, 0);
+ _cpu_ppc_store_hdecr(cpu, cpu_ppc_load_hdecr(env), value);
}
static void cpu_ppc_hdecr_cb(void *opaque)
{
PowerPCCPU *cpu = opaque;
- _cpu_ppc_store_hdecr(cpu, 0x00000000, 0xFFFFFFFF, 1);
+ cpu_ppc_hdecr_excp(cpu);
}
static void cpu_ppc_store_purr(PowerPCCPU *cpu, uint64_t value)
@@ -776,7 +809,7 @@ static void cpu_ppc_store_purr(PowerPCCPU *cpu, uint64_t value)
ppc_tb_t *tb_env = cpu->env.tb_env;
tb_env->purr_load = value;
- tb_env->purr_start = qemu_get_clock_ns(vm_clock);
+ tb_env->purr_start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
}
static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
@@ -791,8 +824,8 @@ static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
* if a decrementer exception is pending when it enables msr_ee at startup,
* it's not ready to handle it...
*/
- _cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 0);
- _cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF, 0);
+ _cpu_ppc_store_decr(cpu, 0xFFFFFFFF, 0xFFFFFFFF);
+ _cpu_ppc_store_hdecr(cpu, 0xFFFFFFFF, 0xFFFFFFFF);
cpu_ppc_store_purr(cpu, 0x0000000000000000ULL);
}
@@ -805,12 +838,16 @@ clk_setup_cb cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq)
tb_env = g_malloc0(sizeof(ppc_tb_t));
env->tb_env = tb_env;
tb_env->flags = PPC_DECR_UNDERFLOW_TRIGGERED;
+ if (env->insns_flags & PPC_SEGMENT_64B) {
+ /* All Book3S 64bit CPUs implement level based DEC logic */
+ tb_env->flags |= PPC_DECR_UNDERFLOW_LEVEL;
+ }
/* Create new timer */
- tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_decr_cb, cpu);
+ tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_decr_cb, cpu);
if (0) {
/* XXX: find a suitable condition to enable the hypervisor decrementer
*/
- tb_env->hdecr_timer = qemu_new_timer_ns(vm_clock, &cpu_ppc_hdecr_cb,
+ tb_env->hdecr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_ppc_hdecr_cb,
cpu);
} else {
tb_env->hdecr_timer = NULL;
@@ -856,9 +893,9 @@ typedef struct ppc40x_timer_t ppc40x_timer_t;
struct ppc40x_timer_t {
uint64_t pit_reload; /* PIT auto-reload value */
uint64_t fit_next; /* Tick for next FIT interrupt */
- struct QEMUTimer *fit_timer;
+ QEMUTimer *fit_timer;
uint64_t wdt_next; /* Tick for next WDT interrupt */
- struct QEMUTimer *wdt_timer;
+ QEMUTimer *wdt_timer;
/* 405 have the PIT, 440 have a DECR. */
unsigned int decr_excp;
@@ -877,7 +914,7 @@ static void cpu_4xx_fit_cb (void *opaque)
cpu = ppc_env_get_cpu(env);
tb_env = env->tb_env;
ppc40x_timer = tb_env->opaque;
- now = qemu_get_clock_ns(vm_clock);
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) {
case 0:
next = 1 << 9;
@@ -898,7 +935,7 @@ static void cpu_4xx_fit_cb (void *opaque)
next = now + muldiv64(next, get_ticks_per_sec(), tb_env->tb_freq);
if (next == now)
next++;
- qemu_mod_timer(ppc40x_timer->fit_timer, next);
+ timer_mod(ppc40x_timer->fit_timer, next);
env->spr[SPR_40x_TSR] |= 1 << 26;
if ((env->spr[SPR_40x_TCR] >> 23) & 0x1) {
ppc_set_irq(cpu, PPC_INTERRUPT_FIT, 1);
@@ -920,18 +957,18 @@ static void start_stop_pit (CPUPPCState *env, ppc_tb_t *tb_env, int is_excp)
(is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) {
/* Stop PIT */
LOG_TB("%s: stop PIT\n", __func__);
- qemu_del_timer(tb_env->decr_timer);
+ timer_del(tb_env->decr_timer);
} else {
LOG_TB("%s: start PIT %016" PRIx64 "\n",
__func__, ppc40x_timer->pit_reload);
- now = qemu_get_clock_ns(vm_clock);
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
next = now + muldiv64(ppc40x_timer->pit_reload,
get_ticks_per_sec(), tb_env->decr_freq);
if (is_excp)
next += tb_env->decr_next - now;
if (next == now)
next++;
- qemu_mod_timer(tb_env->decr_timer, next);
+ timer_mod(tb_env->decr_timer, next);
tb_env->decr_next = next;
}
}
@@ -973,7 +1010,7 @@ static void cpu_4xx_wdt_cb (void *opaque)
cpu = ppc_env_get_cpu(env);
tb_env = env->tb_env;
ppc40x_timer = tb_env->opaque;
- now = qemu_get_clock_ns(vm_clock);
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) {
case 0:
next = 1 << 17;
@@ -999,12 +1036,12 @@ static void cpu_4xx_wdt_cb (void *opaque)
switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
case 0x0:
case 0x1:
- qemu_mod_timer(ppc40x_timer->wdt_timer, next);
+ timer_mod(ppc40x_timer->wdt_timer, next);
ppc40x_timer->wdt_next = next;
- env->spr[SPR_40x_TSR] |= 1 << 31;
+ env->spr[SPR_40x_TSR] |= 1U << 31;
break;
case 0x2:
- qemu_mod_timer(ppc40x_timer->wdt_timer, next);
+ timer_mod(ppc40x_timer->wdt_timer, next);
ppc40x_timer->wdt_next = next;
env->spr[SPR_40x_TSR] |= 1 << 30;
if ((env->spr[SPR_40x_TCR] >> 27) & 0x1) {
@@ -1076,11 +1113,11 @@ clk_setup_cb ppc_40x_timers_init (CPUPPCState *env, uint32_t freq,
LOG_TB("%s freq %" PRIu32 "\n", __func__, freq);
if (ppc40x_timer != NULL) {
/* We use decr timer for PIT */
- tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &cpu_4xx_pit_cb, env);
+ tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_pit_cb, env);
ppc40x_timer->fit_timer =
- qemu_new_timer_ns(vm_clock, &cpu_4xx_fit_cb, env);
+ timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_fit_cb, env);
ppc40x_timer->wdt_timer =
- qemu_new_timer_ns(vm_clock, &cpu_4xx_wdt_cb, env);
+ timer_new_ns(QEMU_CLOCK_VIRTUAL, &cpu_4xx_wdt_cb, env);
ppc40x_timer->decr_excp = decr_excp;
}
@@ -1362,3 +1399,24 @@ int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size,
return 0;
}
+
+/* CPU device-tree ID helpers */
+int ppc_get_vcpu_dt_id(PowerPCCPU *cpu)
+{
+ return cpu->cpu_dt_id;
+}
+
+PowerPCCPU *ppc_get_vcpu_by_dt_id(int cpu_dt_id)
+{
+ CPUState *cs;
+
+ CPU_FOREACH(cs) {
+ PowerPCCPU *cpu = POWERPC_CPU(cs);
+
+ if (cpu->cpu_dt_id == cpu_dt_id) {
+ return cpu;
+ }
+ }
+
+ return NULL;
+}
diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c
index f74e5e52c..f1a8f6734 100644
--- a/hw/ppc/ppc405_boards.c
+++ b/hw/ppc/ppc405_boards.c
@@ -27,9 +27,11 @@
#include "hw/timer/m48t59.h"
#include "hw/block/flash.h"
#include "sysemu/sysemu.h"
+#include "sysemu/qtest.h"
#include "block/block.h"
#include "hw/boards.h"
#include "qemu/log.h"
+#include "qemu/error-report.h"
#include "hw/loader.h"
#include "sysemu/blockdev.h"
#include "exec/address-spaces.h"
@@ -42,7 +44,7 @@
#define USE_FLASH_BIOS
-#define DEBUG_BOARD_INIT
+//#define DEBUG_BOARD_INIT
/*****************************************************************************/
/* PPC405EP reference board (IBM) */
@@ -252,17 +254,20 @@ static void ref405ep_init(QEMUMachineInitArgs *args)
if (filename) {
bios_size = load_image(filename, memory_region_get_ram_ptr(bios));
g_free(filename);
+ if (bios_size < 0 || bios_size > BIOS_SIZE) {
+ error_report("Could not load PowerPC BIOS '%s'", bios_name);
+ exit(1);
+ }
+ bios_size = (bios_size + 0xfff) & ~0xfff;
+ memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
+ } else if (!qtest_enabled() || kernel_filename != NULL) {
+ error_report("Could not load PowerPC BIOS '%s'", bios_name);
+ exit(1);
} else {
+ /* Avoid an uninitialized variable warning */
bios_size = -1;
}
- if (bios_size < 0 || bios_size > BIOS_SIZE) {
- fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n",
- bios_name);
- exit(1);
- }
- bios_size = (bios_size + 0xfff) & ~0xfff;
memory_region_set_readonly(bios, true);
- memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
}
/* Register FPGA */
#ifdef DEBUG_BOARD_INIT
@@ -353,16 +358,15 @@ static void ref405ep_init(QEMUMachineInitArgs *args)
bdloc = 0;
}
#ifdef DEBUG_BOARD_INIT
+ printf("bdloc " RAM_ADDR_FMT "\n", bdloc);
printf("%s: Done\n", __func__);
#endif
- printf("bdloc " RAM_ADDR_FMT "\n", bdloc);
}
static QEMUMachine ref405ep_machine = {
.name = "ref405ep",
.desc = "ref405ep",
.init = ref405ep_init,
- DEFAULT_MACHINE_OPTIONS,
};
/*****************************************************************************/
@@ -569,17 +573,17 @@ static void taihu_405ep_init(QEMUMachineInitArgs *args)
if (filename) {
bios_size = load_image(filename, memory_region_get_ram_ptr(bios));
g_free(filename);
- } else {
- bios_size = -1;
- }
- if (bios_size < 0 || bios_size > BIOS_SIZE) {
- fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n",
- bios_name);
+ if (bios_size < 0 || bios_size > BIOS_SIZE) {
+ error_report("Could not load PowerPC BIOS '%s'", bios_name);
+ exit(1);
+ }
+ bios_size = (bios_size + 0xfff) & ~0xfff;
+ memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
+ } else if (!qtest_enabled()) {
+ error_report("Could not load PowerPC BIOS '%s'", bios_name);
exit(1);
}
- bios_size = (bios_size + 0xfff) & ~0xfff;
memory_region_set_readonly(bios, true);
- memory_region_add_subregion(sysmem, (uint32_t)(-bios_size), bios);
}
/* Register Linux flash */
dinfo = drive_get(IF_PFLASH, 0, fl_idx);
@@ -650,7 +654,6 @@ static QEMUMachine taihu_machine = {
.name = "taihu",
.desc = "taihu",
.init = taihu_405ep_init,
- DEFAULT_MACHINE_OPTIONS,
};
static void ppc405_machine_init(void)
diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c
index 290f71ab6..54ba59e73 100644
--- a/hw/ppc/ppc405_uc.c
+++ b/hw/ppc/ppc405_uc.c
@@ -30,20 +30,21 @@
#include "qemu/log.h"
#include "exec/address-spaces.h"
-#define DEBUG_OPBA
-#define DEBUG_SDRAM
-#define DEBUG_GPIO
-#define DEBUG_SERIAL
-#define DEBUG_OCM
+//#define DEBUG_OPBA
+//#define DEBUG_SDRAM
+//#define DEBUG_GPIO
+//#define DEBUG_SERIAL
+//#define DEBUG_OCM
//#define DEBUG_I2C
-#define DEBUG_GPT
-#define DEBUG_MAL
-#define DEBUG_CLOCKS
+//#define DEBUG_GPT
+//#define DEBUG_MAL
+//#define DEBUG_CLOCKS
//#define DEBUG_CLOCKS_LL
ram_addr_t ppc405_set_bootinfo (CPUPPCState *env, ppc4xx_bd_info_t *bd,
uint32_t flags)
{
+ CPUState *cs = CPU(ppc_env_get_cpu(env));
ram_addr_t bdloc;
int i, n;
@@ -52,42 +53,42 @@ ram_addr_t ppc405_set_bootinfo (CPUPPCState *env, ppc4xx_bd_info_t *bd,
bdloc = 0x01000000UL - sizeof(struct ppc4xx_bd_info_t);
else
bdloc = bd->bi_memsize - sizeof(struct ppc4xx_bd_info_t);
- stl_be_phys(bdloc + 0x00, bd->bi_memstart);
- stl_be_phys(bdloc + 0x04, bd->bi_memsize);
- stl_be_phys(bdloc + 0x08, bd->bi_flashstart);
- stl_be_phys(bdloc + 0x0C, bd->bi_flashsize);
- stl_be_phys(bdloc + 0x10, bd->bi_flashoffset);
- stl_be_phys(bdloc + 0x14, bd->bi_sramstart);
- stl_be_phys(bdloc + 0x18, bd->bi_sramsize);
- stl_be_phys(bdloc + 0x1C, bd->bi_bootflags);
- stl_be_phys(bdloc + 0x20, bd->bi_ipaddr);
+ stl_be_phys(cs->as, bdloc + 0x00, bd->bi_memstart);
+ stl_be_phys(cs->as, bdloc + 0x04, bd->bi_memsize);
+ stl_be_phys(cs->as, bdloc + 0x08, bd->bi_flashstart);
+ stl_be_phys(cs->as, bdloc + 0x0C, bd->bi_flashsize);
+ stl_be_phys(cs->as, bdloc + 0x10, bd->bi_flashoffset);
+ stl_be_phys(cs->as, bdloc + 0x14, bd->bi_sramstart);
+ stl_be_phys(cs->as, bdloc + 0x18, bd->bi_sramsize);
+ stl_be_phys(cs->as, bdloc + 0x1C, bd->bi_bootflags);
+ stl_be_phys(cs->as, bdloc + 0x20, bd->bi_ipaddr);
for (i = 0; i < 6; i++) {
- stb_phys(bdloc + 0x24 + i, bd->bi_enetaddr[i]);
+ stb_phys(cs->as, bdloc + 0x24 + i, bd->bi_enetaddr[i]);
}
- stw_be_phys(bdloc + 0x2A, bd->bi_ethspeed);
- stl_be_phys(bdloc + 0x2C, bd->bi_intfreq);
- stl_be_phys(bdloc + 0x30, bd->bi_busfreq);
- stl_be_phys(bdloc + 0x34, bd->bi_baudrate);
+ stw_be_phys(cs->as, bdloc + 0x2A, bd->bi_ethspeed);
+ stl_be_phys(cs->as, bdloc + 0x2C, bd->bi_intfreq);
+ stl_be_phys(cs->as, bdloc + 0x30, bd->bi_busfreq);
+ stl_be_phys(cs->as, bdloc + 0x34, bd->bi_baudrate);
for (i = 0; i < 4; i++) {
- stb_phys(bdloc + 0x38 + i, bd->bi_s_version[i]);
+ stb_phys(cs->as, bdloc + 0x38 + i, bd->bi_s_version[i]);
}
for (i = 0; i < 32; i++) {
- stb_phys(bdloc + 0x3C + i, bd->bi_r_version[i]);
+ stb_phys(cs->as, bdloc + 0x3C + i, bd->bi_r_version[i]);
}
- stl_be_phys(bdloc + 0x5C, bd->bi_plb_busfreq);
- stl_be_phys(bdloc + 0x60, bd->bi_pci_busfreq);
+ stl_be_phys(cs->as, bdloc + 0x5C, bd->bi_plb_busfreq);
+ stl_be_phys(cs->as, bdloc + 0x60, bd->bi_pci_busfreq);
for (i = 0; i < 6; i++) {
- stb_phys(bdloc + 0x64 + i, bd->bi_pci_enetaddr[i]);
+ stb_phys(cs->as, bdloc + 0x64 + i, bd->bi_pci_enetaddr[i]);
}
n = 0x6A;
if (flags & 0x00000001) {
for (i = 0; i < 6; i++)
- stb_phys(bdloc + n++, bd->bi_pci_enetaddr2[i]);
+ stb_phys(cs->as, bdloc + n++, bd->bi_pci_enetaddr2[i]);
}
- stl_be_phys(bdloc + n, bd->bi_opbfreq);
+ stl_be_phys(cs->as, bdloc + n, bd->bi_opbfreq);
n += 4;
for (i = 0; i < 2; i++) {
- stl_be_phys(bdloc + n, bd->bi_iic_fast[i]);
+ stl_be_phys(cs->as, bdloc + n, bd->bi_iic_fast[i]);
n += 4;
}
@@ -1234,7 +1235,7 @@ struct ppc4xx_gpt_t {
MemoryRegion iomem;
int64_t tb_offset;
uint32_t tb_freq;
- struct QEMUTimer *timer;
+ QEMUTimer *timer;
qemu_irq irqs[5];
uint32_t oe;
uint32_t ol;
@@ -1348,7 +1349,7 @@ static uint32_t ppc4xx_gpt_readl (void *opaque, hwaddr addr)
switch (addr) {
case 0x00:
/* Time base counter */
- ret = muldiv64(qemu_get_clock_ns(vm_clock) + gpt->tb_offset,
+ ret = muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + gpt->tb_offset,
gpt->tb_freq, get_ticks_per_sec());
break;
case 0x10:
@@ -1405,7 +1406,7 @@ static void ppc4xx_gpt_writel (void *opaque,
case 0x00:
/* Time base counter */
gpt->tb_offset = muldiv64(value, get_ticks_per_sec(), gpt->tb_freq)
- - qemu_get_clock_ns(vm_clock);
+ - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
ppc4xx_gpt_compute_timer(gpt);
break;
case 0x10:
@@ -1476,7 +1477,7 @@ static void ppc4xx_gpt_reset (void *opaque)
int i;
gpt = opaque;
- qemu_del_timer(gpt->timer);
+ timer_del(gpt->timer);
gpt->oe = 0x00000000;
gpt->ol = 0x00000000;
gpt->im = 0x00000000;
@@ -1497,7 +1498,7 @@ static void ppc4xx_gpt_init(hwaddr base, qemu_irq irqs[5])
for (i = 0; i < 5; i++) {
gpt->irqs[i] = irqs[i];
}
- gpt->timer = qemu_new_timer_ns(vm_clock, &ppc4xx_gpt_cb, gpt);
+ gpt->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &ppc4xx_gpt_cb, gpt);
#ifdef DEBUG_GPT
printf("%s: offset " TARGET_FMT_plx "\n", __func__, base);
#endif
diff --git a/hw/ppc/ppc440_bamboo.c b/hw/ppc/ppc440_bamboo.c
index 369ab9e26..2ddc2ed4b 100644
--- a/hw/ppc/ppc440_bamboo.c
+++ b/hw/ppc/ppc440_bamboo.c
@@ -77,23 +77,23 @@ static int bamboo_load_device_tree(hwaddr addr,
/* Manipulate device tree in memory. */
- ret = qemu_devtree_setprop(fdt, "/memory", "reg", mem_reg_property,
- sizeof(mem_reg_property));
+ ret = qemu_fdt_setprop(fdt, "/memory", "reg", mem_reg_property,
+ sizeof(mem_reg_property));
if (ret < 0)
fprintf(stderr, "couldn't set /memory/reg\n");
- ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-start",
- initrd_base);
+ ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
+ initrd_base);
if (ret < 0)
fprintf(stderr, "couldn't set /chosen/linux,initrd-start\n");
- ret = qemu_devtree_setprop_cell(fdt, "/chosen", "linux,initrd-end",
- (initrd_base + initrd_size));
+ ret = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
+ (initrd_base + initrd_size));
if (ret < 0)
fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
- ret = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs",
- kernel_cmdline);
+ ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
+ kernel_cmdline);
if (ret < 0)
fprintf(stderr, "couldn't set /chosen/bootargs\n");
@@ -105,13 +105,14 @@ static int bamboo_load_device_tree(hwaddr addr,
clock_freq = kvmppc_get_clockfreq();
}
- qemu_devtree_setprop_cell(fdt, "/cpus/cpu@0", "clock-frequency",
- clock_freq);
- qemu_devtree_setprop_cell(fdt, "/cpus/cpu@0", "timebase-frequency",
- tb_freq);
+ qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "clock-frequency",
+ clock_freq);
+ qemu_fdt_setprop_cell(fdt, "/cpus/cpu@0", "timebase-frequency",
+ tb_freq);
- ret = rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
+ rom_add_blob_fixed(BINARY_DEVICE_TREE_FILE, fdt, fdt_size, addr);
g_free(fdt);
+ return 0;
out:
@@ -127,7 +128,7 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env,
tlb->attr = 0;
tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
- tlb->size = 1 << 31; /* up to 0x80000000 */
+ tlb->size = 1U << 31; /* up to 0x80000000 */
tlb->EPN = va & TARGET_PAGE_MASK;
tlb->RPN = pa & TARGET_PAGE_MASK;
tlb->PID = 0;
@@ -135,7 +136,7 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env,
tlb = &env->tlb.tlbe[1];
tlb->attr = 0;
tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
- tlb->size = 1 << 31; /* up to 0xffffffff */
+ tlb->size = 1U << 31; /* up to 0xffffffff */
tlb->EPN = 0x80000000 & TARGET_PAGE_MASK;
tlb->RPN = 0x80000000 & TARGET_PAGE_MASK;
tlb->PID = 0;
@@ -296,7 +297,6 @@ static QEMUMachine bamboo_machine = {
.name = "bamboo",
.desc = "bamboo",
.init = bamboo_init,
- DEFAULT_MACHINE_OPTIONS,
};
static void bamboo_machine_init(void)
diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c
index 239aada19..8a43111a5 100644
--- a/hw/ppc/ppc4xx_devs.c
+++ b/hw/ppc/ppc4xx_devs.c
@@ -27,8 +27,6 @@
#include "qemu/log.h"
#include "exec/address-spaces.h"
-//#define DEBUG_MMIO
-//#define DEBUG_UNASSIGNED
#define DEBUG_UIC
@@ -163,7 +161,7 @@ static void ppcuic_set_irq (void *opaque, int irq_num, int level)
uint32_t mask, sr;
uic = opaque;
- mask = 1 << (31-irq_num);
+ mask = 1U << (31-irq_num);
LOG_UIC("%s: irq %d level %d uicsr %08" PRIx32
" mask %08" PRIx32 " => %08" PRIx32 " %08" PRIx32 "\n",
__func__, irq_num, level,
diff --git a/hw/ppc/ppc4xx_pci.c b/hw/ppc/ppc4xx_pci.c
index d2d6f65e6..4cb78518a 100644
--- a/hw/ppc/ppc4xx_pci.c
+++ b/hw/ppc/ppc4xx_pci.c
@@ -380,6 +380,11 @@ static void ppc4xx_host_bridge_class_init(ObjectClass *klass, void *data)
k->vendor_id = PCI_VENDOR_ID_IBM;
k->device_id = PCI_DEVICE_ID_IBM_440GX;
k->class_id = PCI_CLASS_BRIDGE_OTHER;
+ /*
+ * PCI-facing part of the host bridge, not usable without the
+ * host-facing part, which can't be device_add'ed, yet.
+ */
+ dc->cannot_instantiate_with_device_add_yet = true;
}
static const TypeInfo ppc4xx_host_bridge_info = {
diff --git a/hw/ppc/ppc_booke.c b/hw/ppc/ppc_booke.c
index 000c27f2e..8b94da6b0 100644
--- a/hw/ppc/ppc_booke.c
+++ b/hw/ppc/ppc_booke.c
@@ -34,15 +34,15 @@
/* Timer Control Register */
#define TCR_WP_SHIFT 30 /* Watchdog Timer Period */
-#define TCR_WP_MASK (0x3 << TCR_WP_SHIFT)
+#define TCR_WP_MASK (0x3U << TCR_WP_SHIFT)
#define TCR_WRC_SHIFT 28 /* Watchdog Timer Reset Control */
-#define TCR_WRC_MASK (0x3 << TCR_WRC_SHIFT)
-#define TCR_WIE (1 << 27) /* Watchdog Timer Interrupt Enable */
-#define TCR_DIE (1 << 26) /* Decrementer Interrupt Enable */
+#define TCR_WRC_MASK (0x3U << TCR_WRC_SHIFT)
+#define TCR_WIE (1U << 27) /* Watchdog Timer Interrupt Enable */
+#define TCR_DIE (1U << 26) /* Decrementer Interrupt Enable */
#define TCR_FP_SHIFT 24 /* Fixed-Interval Timer Period */
-#define TCR_FP_MASK (0x3 << TCR_FP_SHIFT)
-#define TCR_FIE (1 << 23) /* Fixed-Interval Timer Interrupt Enable */
-#define TCR_ARE (1 << 22) /* Auto-Reload Enable */
+#define TCR_FP_MASK (0x3U << TCR_FP_SHIFT)
+#define TCR_FIE (1U << 23) /* Fixed-Interval Timer Interrupt Enable */
+#define TCR_ARE (1U << 22) /* Auto-Reload Enable */
/* Timer Control Register (e500 specific fields) */
@@ -53,21 +53,21 @@
/* Timer Status Register */
-#define TSR_FIS (1 << 26) /* Fixed-Interval Timer Interrupt Status */
-#define TSR_DIS (1 << 27) /* Decrementer Interrupt Status */
+#define TSR_FIS (1U << 26) /* Fixed-Interval Timer Interrupt Status */
+#define TSR_DIS (1U << 27) /* Decrementer Interrupt Status */
#define TSR_WRS_SHIFT 28 /* Watchdog Timer Reset Status */
-#define TSR_WRS_MASK (0x3 << TSR_WRS_SHIFT)
-#define TSR_WIS (1 << 30) /* Watchdog Timer Interrupt Status */
-#define TSR_ENW (1 << 31) /* Enable Next Watchdog Timer */
+#define TSR_WRS_MASK (0x3U << TSR_WRS_SHIFT)
+#define TSR_WIS (1U << 30) /* Watchdog Timer Interrupt Status */
+#define TSR_ENW (1U << 31) /* Enable Next Watchdog Timer */
typedef struct booke_timer_t booke_timer_t;
struct booke_timer_t {
uint64_t fit_next;
- struct QEMUTimer *fit_timer;
+ QEMUTimer *fit_timer;
uint64_t wdt_next;
- struct QEMUTimer *wdt_timer;
+ QEMUTimer *wdt_timer;
uint32_t flags;
};
@@ -128,7 +128,8 @@ static uint8_t booke_get_wdt_target(CPUPPCState *env, ppc_tb_t *tb_env)
static void booke_update_fixed_timer(CPUPPCState *env,
uint8_t target_bit,
uint64_t *next,
- struct QEMUTimer *timer)
+ QEMUTimer *timer,
+ int tsr_bit)
{
ppc_tb_t *tb_env = env->tb_env;
uint64_t delta_tick, ticks = 0;
@@ -136,7 +137,15 @@ static void booke_update_fixed_timer(CPUPPCState *env,
uint64_t period;
uint64_t now;
- now = qemu_get_clock_ns(vm_clock);
+ if (!(env->spr[SPR_BOOKE_TSR] & tsr_bit)) {
+ /*
+ * Don't arm the timer again when the guest has the current
+ * interrupt still pending. Wait for it to ack it.
+ */
+ return;
+ }
+
+ now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
tb = cpu_ppc_get_tb(tb_env, now, tb_env->tb_offset);
period = 1ULL << target_bit;
delta_tick = period - (tb & (period - 1));
@@ -165,9 +174,16 @@ static void booke_update_fixed_timer(CPUPPCState *env,
if (*next == now) {
(*next)++;
+ } else {
+ /*
+ * There's no point to fake any granularity that's more fine grained
+ * than milliseconds. Anything beyond that just overloads the system.
+ */
+ *next = MAX(*next, now + SCALE_MS);
}
- qemu_mod_timer(timer, *next);
+ /* Fire the next timer */
+ timer_mod(timer, *next);
}
static void booke_decr_cb(void *opaque)
@@ -200,7 +216,8 @@ static void booke_fit_cb(void *opaque)
booke_update_fixed_timer(env,
booke_get_fit_target(env, tb_env),
&booke_timer->fit_next,
- booke_timer->fit_timer);
+ booke_timer->fit_timer,
+ TSR_FIS);
}
static void booke_wdt_cb(void *opaque)
@@ -220,15 +237,35 @@ static void booke_wdt_cb(void *opaque)
booke_update_fixed_timer(env,
booke_get_wdt_target(env, tb_env),
&booke_timer->wdt_next,
- booke_timer->wdt_timer);
+ booke_timer->wdt_timer,
+ TSR_WIS);
}
void store_booke_tsr(CPUPPCState *env, target_ulong val)
{
PowerPCCPU *cpu = ppc_env_get_cpu(env);
+ ppc_tb_t *tb_env = env->tb_env;
+ booke_timer_t *booke_timer = tb_env->opaque;
env->spr[SPR_BOOKE_TSR] &= ~val;
kvmppc_clear_tsr_bits(cpu, val);
+
+ if (val & TSR_FIS) {
+ booke_update_fixed_timer(env,
+ booke_get_fit_target(env, tb_env),
+ &booke_timer->fit_next,
+ booke_timer->fit_timer,
+ TSR_FIS);
+ }
+
+ if (val & TSR_WIS) {
+ booke_update_fixed_timer(env,
+ booke_get_wdt_target(env, tb_env),
+ &booke_timer->wdt_next,
+ booke_timer->wdt_timer,
+ TSR_WIS);
+ }
+
booke_update_irq(cpu);
}
@@ -247,12 +284,14 @@ void store_booke_tcr(CPUPPCState *env, target_ulong val)
booke_update_fixed_timer(env,
booke_get_fit_target(env, tb_env),
&booke_timer->fit_next,
- booke_timer->fit_timer);
+ booke_timer->fit_timer,
+ TSR_FIS);
booke_update_fixed_timer(env,
booke_get_wdt_target(env, tb_env),
&booke_timer->wdt_next,
- booke_timer->wdt_timer);
+ booke_timer->wdt_timer,
+ TSR_WIS);
}
static void ppc_booke_timer_reset_handle(void *opaque)
@@ -303,12 +342,12 @@ void ppc_booke_timers_init(PowerPCCPU *cpu, uint32_t freq, uint32_t flags)
tb_env->tb_freq = freq;
tb_env->decr_freq = freq;
tb_env->opaque = booke_timer;
- tb_env->decr_timer = qemu_new_timer_ns(vm_clock, &booke_decr_cb, cpu);
+ tb_env->decr_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, &booke_decr_cb, cpu);
booke_timer->fit_timer =
- qemu_new_timer_ns(vm_clock, &booke_fit_cb, cpu);
+ timer_new_ns(QEMU_CLOCK_VIRTUAL, &booke_fit_cb, cpu);
booke_timer->wdt_timer =
- qemu_new_timer_ns(vm_clock, &booke_wdt_cb, cpu);
+ timer_new_ns(QEMU_CLOCK_VIRTUAL, &booke_wdt_cb, cpu);
ret = kvmppc_booke_watchdog_enable(cpu);
diff --git a/hw/ppc/ppce500_spin.c b/hw/ppc/ppce500_spin.c
index 78b23fa59..d49f2b880 100644
--- a/hw/ppc/ppce500_spin.c
+++ b/hw/ppc/ppce500_spin.c
@@ -65,9 +65,9 @@ static void spin_reset(void *opaque)
for (i = 0; i < MAX_CPUS; i++) {
SpinInfo *info = &s->spin[i];
- info->pir = i;
- info->r3 = i;
- info->addr = 1;
+ stl_p(&info->pir, i);
+ stq_p(&info->r3, i);
+ stq_p(&info->addr, 1);
}
}
@@ -117,7 +117,7 @@ static void spin_kick(void *data)
mmubooke_create_initial_mapping(env, 0, map_start, map_size);
cpu->halted = 0;
- env->exception_index = -1;
+ cpu->exception_index = -1;
cpu->stopped = false;
qemu_cpu_kick(cpu);
}
diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c
index 7e04b1ac8..e2436512f 100644
--- a/hw/ppc/prep.c
+++ b/hw/ppc/prep.c
@@ -185,6 +185,7 @@ typedef struct sysctrl_t {
uint8_t state;
uint8_t syscontrol;
int contiguous_map;
+ qemu_irq contiguous_map_irq;
int endian;
} sysctrl_t;
@@ -253,6 +254,7 @@ static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val)
case 0x0850:
/* I/O map type register */
sysctrl->contiguous_map = val & 0x01;
+ qemu_set_irq(sysctrl->contiguous_map_irq, sysctrl->contiguous_map);
break;
default:
printf("ERROR: unaffected IO port write: %04" PRIx32
@@ -327,91 +329,6 @@ static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr)
return retval;
}
-static inline hwaddr prep_IO_address(sysctrl_t *sysctrl,
- hwaddr addr)
-{
- if (sysctrl->contiguous_map == 0) {
- /* 64 KB contiguous space for IOs */
- addr &= 0xFFFF;
- } else {
- /* 8 MB non-contiguous space for IOs */
- addr = (addr & 0x1F) | ((addr & 0x007FFF000) >> 7);
- }
-
- return addr;
-}
-
-static void PPC_prep_io_writeb (void *opaque, hwaddr addr,
- uint32_t value)
-{
- sysctrl_t *sysctrl = opaque;
-
- addr = prep_IO_address(sysctrl, addr);
- cpu_outb(addr, value);
-}
-
-static uint32_t PPC_prep_io_readb (void *opaque, hwaddr addr)
-{
- sysctrl_t *sysctrl = opaque;
- uint32_t ret;
-
- addr = prep_IO_address(sysctrl, addr);
- ret = cpu_inb(addr);
-
- return ret;
-}
-
-static void PPC_prep_io_writew (void *opaque, hwaddr addr,
- uint32_t value)
-{
- sysctrl_t *sysctrl = opaque;
-
- addr = prep_IO_address(sysctrl, addr);
- PPC_IO_DPRINTF("0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", addr, value);
- cpu_outw(addr, value);
-}
-
-static uint32_t PPC_prep_io_readw (void *opaque, hwaddr addr)
-{
- sysctrl_t *sysctrl = opaque;
- uint32_t ret;
-
- addr = prep_IO_address(sysctrl, addr);
- ret = cpu_inw(addr);
- PPC_IO_DPRINTF("0x" TARGET_FMT_plx " <= 0x%08" PRIx32 "\n", addr, ret);
-
- return ret;
-}
-
-static void PPC_prep_io_writel (void *opaque, hwaddr addr,
- uint32_t value)
-{
- sysctrl_t *sysctrl = opaque;
-
- addr = prep_IO_address(sysctrl, addr);
- PPC_IO_DPRINTF("0x" TARGET_FMT_plx " => 0x%08" PRIx32 "\n", addr, value);
- cpu_outl(addr, value);
-}
-
-static uint32_t PPC_prep_io_readl (void *opaque, hwaddr addr)
-{
- sysctrl_t *sysctrl = opaque;
- uint32_t ret;
-
- addr = prep_IO_address(sysctrl, addr);
- ret = cpu_inl(addr);
- PPC_IO_DPRINTF("0x" TARGET_FMT_plx " <= 0x%08" PRIx32 "\n", addr, ret);
-
- return ret;
-}
-
-static const MemoryRegionOps PPC_prep_io_ops = {
- .old_mmio = {
- .read = { PPC_prep_io_readb, PPC_prep_io_readw, PPC_prep_io_readl },
- .write = { PPC_prep_io_writeb, PPC_prep_io_writew, PPC_prep_io_writel },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
#define NVRAM_SIZE 0x2000
@@ -452,21 +369,19 @@ static void ppc_prep_init(QEMUMachineInitArgs *args)
const char *kernel_filename = args->kernel_filename;
const char *kernel_cmdline = args->kernel_cmdline;
const char *initrd_filename = args->initrd_filename;
- const char *boot_device = args->boot_device;
+ const char *boot_device = args->boot_order;
MemoryRegion *sysmem = get_system_memory();
PowerPCCPU *cpu = NULL;
CPUPPCState *env = NULL;
- char *filename;
nvram_t nvram;
M48t59State *m48t59;
- MemoryRegion *PPC_io_memory = g_new(MemoryRegion, 1);
PortioList *port_list = g_new(PortioList, 1);
#if 0
MemoryRegion *xcsr = g_new(MemoryRegion, 1);
#endif
- int linux_boot, i, nb_nics1, bios_size;
+ int linux_boot, i, nb_nics1;
MemoryRegion *ram = g_new(MemoryRegion, 1);
- MemoryRegion *bios = g_new(MemoryRegion, 1);
+ MemoryRegion *vga = g_new(MemoryRegion, 1);
uint32_t kernel_base, initrd_base;
long kernel_size, initrd_size;
DeviceState *dev;
@@ -509,43 +424,6 @@ static void ppc_prep_init(QEMUMachineInitArgs *args)
vmstate_register_ram_global(ram);
memory_region_add_subregion(sysmem, 0, ram);
- /* allocate and load BIOS */
- memory_region_init_ram(bios, NULL, "ppc_prep.bios", BIOS_SIZE);
- memory_region_set_readonly(bios, true);
- memory_region_add_subregion(sysmem, (uint32_t)(-BIOS_SIZE), bios);
- vmstate_register_ram_global(bios);
- if (bios_name == NULL)
- bios_name = BIOS_FILENAME;
- filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
- if (filename) {
- bios_size = load_elf(filename, NULL, NULL, NULL,
- NULL, NULL, 1, ELF_MACHINE, 0);
- if (bios_size < 0) {
- bios_size = get_image_size(filename);
- if (bios_size > 0 && bios_size <= BIOS_SIZE) {
- hwaddr bios_addr;
- bios_size = (bios_size + 0xfff) & ~0xfff;
- bios_addr = (uint32_t)(-bios_size);
- bios_size = load_image_targphys(filename, bios_addr, bios_size);
- }
- if (bios_size > BIOS_SIZE) {
- fprintf(stderr, "qemu: PReP bios '%s' is too large (0x%x)\n",
- bios_name, bios_size);
- exit(1);
- }
- }
- } else {
- bios_size = -1;
- }
- if (bios_size < 0 && !qtest_enabled()) {
- fprintf(stderr, "qemu: could not load PPC PReP bios '%s'\n",
- bios_name);
- exit(1);
- }
- if (filename) {
- g_free(filename);
- }
-
if (linux_boot) {
kernel_base = KERNEL_LOAD_ADDR;
/* now we can load the kernel */
@@ -593,6 +471,11 @@ static void ppc_prep_init(QEMUMachineInitArgs *args)
}
dev = qdev_create(NULL, "raven-pcihost");
+ if (bios_name == NULL) {
+ bios_name = BIOS_FILENAME;
+ }
+ qdev_prop_set_string(dev, "bios-name", bios_name);
+ qdev_prop_set_uint32(dev, "elf-machine", ELF_MACHINE);
pcihost = PCI_HOST_BRIDGE(dev);
object_property_add_child(qdev_get_machine(), "raven", OBJECT(dev), NULL);
qdev_init_nofail(dev);
@@ -601,6 +484,7 @@ static void ppc_prep_init(QEMUMachineInitArgs *args)
fprintf(stderr, "Couldn't create PCI host controller.\n");
exit(1);
}
+ sysctrl->contiguous_map_irq = qdev_get_gpio_in(dev, 0);
/* PCI -> ISA bridge */
pci = pci_create_simple(pci_bus, PCI_DEVFN(1, 0), "i82378");
@@ -621,13 +505,16 @@ static void ppc_prep_init(QEMUMachineInitArgs *args)
qdev_prop_set_uint8(dev, "config", 13); /* fdc, ser0, ser1, par0 */
qdev_init_nofail(dev);
- /* Register 8 MB of ISA IO space (needed for non-contiguous map) */
- memory_region_init_io(PPC_io_memory, NULL, &PPC_prep_io_ops, sysctrl,
- "ppc-io", 0x00800000);
- memory_region_add_subregion(sysmem, 0x80000000, PPC_io_memory);
-
/* init basic PC hardware */
pci_vga_init(pci_bus);
+ /* Open Hack'Ware hack: PCI BAR#0 is programmed to 0xf0000000.
+ * While bios will access framebuffer at 0xf0000000, real physical
+ * address is 0xf0000000 + 0xc0000000 (PCI memory base).
+ * Alias the wrong memory accesses to the right place.
+ */
+ memory_region_init_alias(vga, NULL, "vga-alias", pci_address_space(pci),
+ 0xf0000000, 0x1000000);
+ memory_region_add_subregion_overlap(sysmem, 0xf0000000, vga, 10);
nb_nics1 = nb_nics;
if (nb_nics1 > NE2000_NB_MAX)
@@ -656,7 +543,7 @@ static void ppc_prep_init(QEMUMachineInitArgs *args)
sysctrl->reset_irq = cpu->env.irq_inputs[PPC6xx_INPUT_HRESET];
portio_list_init(port_list, NULL, prep_portio_list, sysctrl, "prep");
- portio_list_add(port_list, get_system_io(), 0x0);
+ portio_list_add(port_list, isa_address_space_io(isa), 0x0);
/* PowerPC control and status register group */
#if 0
@@ -691,7 +578,7 @@ static QEMUMachine prep_machine = {
.desc = "PowerPC PREP platform",
.init = ppc_prep_init,
.max_cpus = MAX_CPUS,
- DEFAULT_MACHINE_OPTIONS,
+ .default_boot_order = "cad",
};
static void prep_machine_init(void)
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 16bfab90b..a11e1217b 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -26,6 +26,7 @@
*/
#include "sysemu/sysemu.h"
#include "hw/hw.h"
+#include "hw/fw-path-provider.h"
#include "elf.h"
#include "net/net.h"
#include "sysemu/blockdev.h"
@@ -45,10 +46,13 @@
#include "hw/pci/msi.h"
#include "hw/pci/pci.h"
+#include "hw/scsi/scsi.h"
+#include "hw/virtio/virtio-scsi.h"
#include "exec/address-spaces.h"
#include "hw/usb.h"
#include "qemu/config-file.h"
+#include "qemu/error-report.h"
#include <libfdt.h>
@@ -62,7 +66,7 @@
*
* We load our kernel at 4M, leaving space for SLOF initial image
*/
-#define FDT_MAX_SIZE 0x10000
+#define FDT_MAX_SIZE 0x40000
#define RTAS_MAX_SIZE 0x10000
#define FW_MAX_SIZE 0x400000
#define FW_FILE_NAME "slof.bin"
@@ -80,6 +84,8 @@
#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift))
+#define TYPE_SPAPR_MACHINE "spapr-machine"
+
sPAPREnvironment *spapr;
int spapr_allocate_irq(int hint, bool lsi)
@@ -88,6 +94,9 @@ int spapr_allocate_irq(int hint, bool lsi)
if (hint) {
irq = hint;
+ if (hint >= spapr->next_irq) {
+ spapr->next_irq = hint + 1;
+ }
/* FIXME: we should probably check for collisions somehow */
} else {
irq = spapr->next_irq++;
@@ -103,22 +112,39 @@ int spapr_allocate_irq(int hint, bool lsi)
return irq;
}
-/* Allocate block of consequtive IRQs, returns a number of the first */
-int spapr_allocate_irq_block(int num, bool lsi)
+/*
+ * Allocate block of consequtive IRQs, returns a number of the first.
+ * If msi==true, aligns the first IRQ number to num.
+ */
+int spapr_allocate_irq_block(int num, bool lsi, bool msi)
{
int first = -1;
- int i;
+ int i, hint = 0;
+
+ /*
+ * MSIMesage::data is used for storing VIRQ so
+ * it has to be aligned to num to support multiple
+ * MSI vectors. MSI-X is not affected by this.
+ * The hint is used for the first IRQ, the rest should
+ * be allocated continuously.
+ */
+ if (msi) {
+ assert((num == 1) || (num == 2) || (num == 4) ||
+ (num == 8) || (num == 16) || (num == 32));
+ hint = (spapr->next_irq + num - 1) & ~(num - 1);
+ }
for (i = 0; i < num; ++i) {
int irq;
- irq = spapr_allocate_irq(0, lsi);
+ irq = spapr_allocate_irq(hint, lsi);
if (!irq) {
return -1;
}
if (0 == i) {
first = irq;
+ hint = 0;
}
/* If the above doesn't create a consecutive block then that's
@@ -141,14 +167,33 @@ static XICSState *try_create_xics(const char *type, int nr_servers,
return NULL;
}
- return XICS(dev);
+ return XICS_COMMON(dev);
}
static XICSState *xics_system_init(int nr_servers, int nr_irqs)
{
XICSState *icp = NULL;
- icp = try_create_xics(TYPE_XICS, nr_servers, nr_irqs);
+ if (kvm_enabled()) {
+ QemuOpts *machine_opts = qemu_get_machine_opts();
+ bool irqchip_allowed = qemu_opt_get_bool(machine_opts,
+ "kernel_irqchip", true);
+ bool irqchip_required = qemu_opt_get_bool(machine_opts,
+ "kernel_irqchip", false);
+ if (irqchip_allowed) {
+ icp = try_create_xics(TYPE_KVM_XICS, nr_servers, nr_irqs);
+ }
+
+ if (irqchip_required && !icp) {
+ perror("Failed to create in-kernel XICS\n");
+ abort();
+ }
+ }
+
+ if (!icp) {
+ icp = try_create_xics(TYPE_XICS, nr_servers, nr_irqs);
+ }
+
if (!icp) {
perror("Failed to create XICS\n");
abort();
@@ -165,22 +210,22 @@ static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr)
int smt = kvmppc_smt_threads();
uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)};
- assert(spapr->cpu_model);
-
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
+ DeviceClass *dc = DEVICE_GET_CLASS(cpu);
+ int index = ppc_get_vcpu_dt_id(POWERPC_CPU(cpu));
uint32_t associativity[] = {cpu_to_be32(0x5),
cpu_to_be32(0x0),
cpu_to_be32(0x0),
cpu_to_be32(0x0),
cpu_to_be32(cpu->numa_node),
- cpu_to_be32(cpu->cpu_index)};
+ cpu_to_be32(index)};
- if ((cpu->cpu_index % smt) != 0) {
+ if ((index % smt) != 0) {
continue;
}
- snprintf(cpu_model, 32, "/cpus/%s@%x", spapr->cpu_model,
- cpu->cpu_index);
+ snprintf(cpu_model, 32, "/cpus/%s@%x", dc->fw_name,
+ index);
offset = fdt_path_offset(fdt, cpu_model);
if (offset < 0) {
@@ -249,10 +294,10 @@ static size_t create_page_sizes_prop(CPUPPCState *env, uint32_t *prop,
} while (0)
-static void *spapr_create_fdt_skel(const char *cpu_model,
- hwaddr initrd_base,
+static void *spapr_create_fdt_skel(hwaddr initrd_base,
hwaddr initrd_size,
hwaddr kernel_size,
+ bool little_endian,
const char *boot_device,
const char *kernel_cmdline,
uint32_t epow_irq)
@@ -262,11 +307,10 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
uint32_t start_prop = cpu_to_be32(initrd_base);
uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt"
- "\0hcall-tce\0hcall-vio\0hcall-splpar\0hcall-bulk";
+ "\0hcall-tce\0hcall-vio\0hcall-splpar\0hcall-bulk\0hcall-set-mode";
char qemu_hypertas_prop[] = "hcall-memop1";
uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)};
uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
- char *modelname;
int i, smt = kvmppc_smt_threads();
unsigned char vec5[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x80};
@@ -306,6 +350,9 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
cpu_to_be64(kernel_size) };
_FDT((fdt_property(fdt, "qemu,boot-kernel", &kprop, sizeof(kprop))));
+ if (little_endian) {
+ _FDT((fdt_property(fdt, "qemu,boot-kernel-le", NULL, 0)));
+ }
}
if (boot_device) {
_FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device)));
@@ -322,20 +369,12 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
_FDT((fdt_property_cell(fdt, "#address-cells", 0x1)));
_FDT((fdt_property_cell(fdt, "#size-cells", 0x0)));
- modelname = g_strdup(cpu_model);
-
- for (i = 0; i < strlen(modelname); i++) {
- modelname[i] = toupper(modelname[i]);
- }
-
- /* This is needed during FDT finalization */
- spapr->cpu_model = g_strdup(modelname);
-
- for (cs = first_cpu; cs != NULL; cs = cs->next_cpu) {
+ CPU_FOREACH(cs) {
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *env = &cpu->env;
+ DeviceClass *dc = DEVICE_GET_CLASS(cs);
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
- int index = cs->cpu_index;
+ int index = ppc_get_vcpu_dt_id(cpu);
uint32_t servers_prop[smp_threads];
uint32_t gservers_prop[smp_threads * 2];
char *nodename;
@@ -350,7 +389,7 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
continue;
}
- nodename = g_strdup_printf("%s@%x", modelname, index);
+ nodename = g_strdup_printf("%s@%x", dc->fw_name, index);
_FDT((fdt_begin_node(fdt, nodename)));
@@ -398,6 +437,10 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
_FDT((fdt_property(fdt, "ibm,ppc-interrupt-gserver#s",
gservers_prop, sizeof(gservers_prop))));
+ if (env->spr_cb[SPR_PURR].oea_read) {
+ _FDT((fdt_property(fdt, "ibm,purr", NULL, 0)));
+ }
+
if (env->mmu_model & POWERPC_MMU_1TSEG) {
_FDT((fdt_property(fdt, "ibm,processor-segment-sizes",
segs, sizeof(segs))));
@@ -430,8 +473,6 @@ static void *spapr_create_fdt_skel(const char *cpu_model,
_FDT((fdt_end_node(fdt)));
}
- g_free(modelname);
-
_FDT((fdt_end_node(fdt)));
/* RTAS */
@@ -492,14 +533,15 @@ static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt)
cpu_to_be32(0x0), cpu_to_be32(0x0),
cpu_to_be32(0x0)};
char mem_name[32];
- hwaddr node0_size, mem_start;
+ hwaddr node0_size, mem_start, node_size;
uint64_t mem_reg_property[2];
int i, off;
/* memory node(s) */
- node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size;
- if (spapr->rma_size > node0_size) {
- spapr->rma_size = node0_size;
+ if (nb_numa_nodes > 1 && node_mem[0] < ram_size) {
+ node0_size = node_mem[0];
+ } else {
+ node0_size = ram_size;
}
/* RMA */
@@ -532,7 +574,15 @@ static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt)
mem_start = node0_size;
for (i = 1; i < nb_numa_nodes; i++) {
mem_reg_property[0] = cpu_to_be64(mem_start);
- mem_reg_property[1] = cpu_to_be64(node_mem[i]);
+ if (mem_start >= ram_size) {
+ node_size = 0;
+ } else {
+ node_size = node_mem[i];
+ if (node_size > ram_size - mem_start) {
+ node_size = ram_size - mem_start;
+ }
+ }
+ mem_reg_property[1] = cpu_to_be64(node_size);
associativity[3] = associativity[4] = cpu_to_be32(i);
sprintf(mem_name, "memory@" TARGET_FMT_lx, mem_start);
off = fdt_add_subnode(fdt, 0, mem_name);
@@ -542,7 +592,7 @@ static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt)
sizeof(mem_reg_property))));
_FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity,
sizeof(associativity))));
- mem_start += node_mem[i];
+ mem_start += node_size;
}
return 0;
@@ -553,7 +603,9 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr,
hwaddr rtas_addr,
hwaddr rtas_size)
{
- int ret;
+ int ret, i;
+ size_t cb = 0;
+ char *bootlist;
void *fdt;
sPAPRPHBState *phb;
@@ -595,6 +647,21 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr,
fprintf(stderr, "Couldn't finalize CPU device tree properties\n");
}
+ bootlist = get_boot_devices_list(&cb, true);
+ if (cb && bootlist) {
+ int offset = fdt_path_offset(fdt, "/chosen");
+ if (offset < 0) {
+ exit(1);
+ }
+ for (i = 0; i < cb; i++) {
+ if (bootlist[i] == '\n') {
+ bootlist[i] = ' ';
+ }
+
+ }
+ ret = fdt_setprop_string(fdt, offset, "qemu,boot-list", bootlist);
+ }
+
if (!spapr->has_graphics) {
spapr_populate_chosen_stdout(fdt, spapr->vio_bus);
}
@@ -642,6 +709,7 @@ static void spapr_reset_htab(sPAPREnvironment *spapr)
if (shift > 0) {
/* Kernel handles htab, we don't need to allocate one */
spapr->htab_shift = shift;
+ kvmppc_kern_htab = true;
} else {
if (!spapr->htab) {
/* Allocate an htab if we don't yet have one */
@@ -654,7 +722,8 @@ static void spapr_reset_htab(sPAPREnvironment *spapr)
/* Update the RMA size if necessary */
if (spapr->vrma_adjust) {
- spapr->rma_size = kvmppc_rma_size(ram_size, spapr->htab_shift);
+ hwaddr node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size;
+ spapr->rma_size = kvmppc_rma_size(node0_size, spapr->htab_shift);
}
}
@@ -696,8 +765,21 @@ static void spapr_cpu_reset(void *opaque)
env->spr[SPR_HIOR] = 0;
env->external_htab = (uint8_t *)spapr->htab;
+ if (kvm_enabled() && !env->external_htab) {
+ /*
+ * HV KVM, set external_htab to 1 so our ppc_hash64_load_hpte*
+ * functions do the right thing.
+ */
+ env->external_htab = (void *)1;
+ }
env->htab_base = -1;
- env->htab_mask = HTAB_SIZE(spapr) - 1;
+ /*
+ * htab_mask is the mask used to normalize hash value to PTEG index.
+ * htab_shift is log2 of hash table size.
+ * We have 8 hpte per group, and each hpte is 16 bytes.
+ * ie have 128 bytes per hpte entry.
+ */
+ env->htab_mask = (1ULL << ((spapr)->htab_shift - 7)) - 1;
env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab |
(spapr->htab_shift - 18);
}
@@ -705,18 +787,10 @@ static void spapr_cpu_reset(void *opaque)
static void spapr_create_nvram(sPAPREnvironment *spapr)
{
DeviceState *dev = qdev_create(&spapr->vio_bus->bus, "spapr-nvram");
- const char *drivename = qemu_opt_get(qemu_get_machine_opts(), "nvram");
+ DriveInfo *dinfo = drive_get(IF_PFLASH, 0, 0);
- if (drivename) {
- BlockDriverState *bs;
-
- bs = bdrv_find(drivename);
- if (!bs) {
- fprintf(stderr, "No such block device \"%s\" for nvram\n",
- drivename);
- exit(1);
- }
- qdev_prop_set_drive_nofail(dev, "drive", bs);
+ if (dinfo) {
+ qdev_prop_set_drive_nofail(dev, "drive", dinfo->bdrv);
}
qdev_init_nofail(dev);
@@ -729,13 +803,15 @@ static int spapr_vga_init(PCIBus *pci_bus)
{
switch (vga_interface_type) {
case VGA_NONE:
+ return false;
+ case VGA_DEVICE:
+ return true;
case VGA_STD:
return pci_vga_init(pci_bus) != NULL;
default:
fprintf(stderr, "This vga model is not supported,"
"currently it only supports -vga std\n");
exit(0);
- break;
}
}
@@ -789,7 +865,7 @@ static void htab_save_first_pass(QEMUFile *f, sPAPREnvironment *spapr,
{
int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
int index = spapr->htab_save_index;
- int64_t starttime = qemu_get_clock_ns(rt_clock);
+ int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
assert(spapr->htab_first_pass);
@@ -820,7 +896,7 @@ static void htab_save_first_pass(QEMUFile *f, sPAPREnvironment *spapr,
qemu_put_buffer(f, HPTE(spapr->htab, chunkstart),
HASH_PTE_SIZE_64 * n_valid);
- if ((qemu_get_clock_ns(rt_clock) - starttime) > max_ns) {
+ if ((qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
break;
}
}
@@ -841,7 +917,7 @@ static int htab_save_later_pass(QEMUFile *f, sPAPREnvironment *spapr,
int htabslots = HTAB_SIZE(spapr) / HASH_PTE_SIZE_64;
int examined = 0, sent = 0;
int index = spapr->htab_save_index;
- int64_t starttime = qemu_get_clock_ns(rt_clock);
+ int64_t starttime = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
assert(!spapr->htab_first_pass);
@@ -886,7 +962,7 @@ static int htab_save_later_pass(QEMUFile *f, sPAPREnvironment *spapr,
HASH_PTE_SIZE_64 * n_valid);
sent += index - chunkstart;
- if (!final && (qemu_get_clock_ns(rt_clock) - starttime) > max_ns) {
+ if (!final && (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) {
break;
}
}
@@ -1071,7 +1147,7 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
const char *kernel_filename = args->kernel_filename;
const char *kernel_cmdline = args->kernel_cmdline;
const char *initrd_filename = args->initrd_filename;
- const char *boot_device = args->boot_device;
+ const char *boot_device = args->boot_order;
PowerPCCPU *cpu;
CPUPPCState *env;
PCIHostState *phb;
@@ -1079,9 +1155,11 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
MemoryRegion *sysmem = get_system_memory();
MemoryRegion *ram = g_new(MemoryRegion, 1);
hwaddr rma_alloc_size;
+ hwaddr node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size;
uint32_t initrd_base = 0;
long kernel_size = 0, initrd_size = 0;
long load_limit, rtas_limit, fw_size;
+ bool kernel_le = false;
char *filename;
msi_supported = true;
@@ -1099,10 +1177,10 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
exit(1);
}
- if (rma_alloc_size && (rma_alloc_size < ram_size)) {
+ if (rma_alloc_size && (rma_alloc_size < node0_size)) {
spapr->rma_size = rma_alloc_size;
} else {
- spapr->rma_size = ram_size;
+ spapr->rma_size = node0_size;
/* With KVM, we don't actually know whether KVM supports an
* unbounded RMA (PR KVM) or is limited by the hash table size
@@ -1119,6 +1197,12 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
}
}
+ if (spapr->rma_size > node0_size) {
+ fprintf(stderr, "Error: Numa node 0 has to span the RMA (%#08"HWADDR_PRIx")\n",
+ spapr->rma_size);
+ exit(1);
+ }
+
/* We place the device tree and RTAS just below either the top of the RMA,
* or just below 2GB, whichever is lowere, so that it can be
* processed with 32-bit real mode code if necessary */
@@ -1155,8 +1239,6 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
}
env = &cpu->env;
- xics_cpu_setup(spapr->icp, cpu);
-
/* Set time-base frequency to 512 MHz */
cpu_ppc_tb_init(env, TIMEBASE_FREQ);
@@ -1170,6 +1252,8 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
kvmppc_set_papr(cpu);
}
+ xics_cpu_setup(spapr->icp, cpu);
+
qemu_register_reset(spapr_cpu_reset, cpu);
}
@@ -1214,6 +1298,7 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
spapr_create_nvram(spapr);
/* Set up PCI */
+ spapr_pci_msi_init(spapr, SPAPR_PCI_MSI_WINDOW);
spapr_pci_rtas_init();
phb = spapr_create_phb(spapr, 0);
@@ -1260,14 +1345,15 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
NULL, &lowaddr, NULL, 1, ELF_MACHINE, 0);
- if (kernel_size < 0) {
- kernel_size = load_image_targphys(kernel_filename,
- KERNEL_LOAD_ADDR,
- load_limit - KERNEL_LOAD_ADDR);
+ if (kernel_size == ELF_LOAD_WRONG_ENDIAN) {
+ kernel_size = load_elf(kernel_filename,
+ translate_kernel_address, NULL,
+ NULL, &lowaddr, NULL, 0, ELF_MACHINE, 0);
+ kernel_le = kernel_size > 0;
}
if (kernel_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- kernel_filename);
+ fprintf(stderr, "qemu: error loading %s: %s\n",
+ kernel_filename, load_elf_strerror(kernel_size));
exit(1);
}
@@ -1308,14 +1394,31 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
&savevm_htab_handlers, spapr);
/* Prepare the device tree */
- spapr->fdt_skel = spapr_create_fdt_skel(cpu_model,
- initrd_base, initrd_size,
- kernel_size,
+ spapr->fdt_skel = spapr_create_fdt_skel(initrd_base, initrd_size,
+ kernel_size, kernel_le,
boot_device, kernel_cmdline,
spapr->epow_irq);
assert(spapr->fdt_skel != NULL);
}
+static int spapr_kvm_type(const char *vm_type)
+{
+ if (!vm_type) {
+ return 0;
+ }
+
+ if (!strcmp(vm_type, "HV")) {
+ return 1;
+ }
+
+ if (!strcmp(vm_type, "PR")) {
+ return 2;
+ }
+
+ error_report("Unknown kvm-type specified '%s'", vm_type);
+ exit(1);
+}
+
static QEMUMachine spapr_machine = {
.name = "pseries",
.desc = "pSeries Logical Partition (PAPR compliant)",
@@ -1325,12 +1428,90 @@ static QEMUMachine spapr_machine = {
.block_default_type = IF_SCSI,
.max_cpus = MAX_CPUS,
.no_parallel = 1,
- .boot_order = NULL,
+ .default_boot_order = NULL,
+ .kvm_type = spapr_kvm_type,
+};
+
+/*
+ * Implementation of an interface to adjust firmware patch
+ * for the bootindex property handling.
+ */
+static char *spapr_get_fw_dev_path(FWPathProvider *p, BusState *bus,
+ DeviceState *dev)
+{
+#define CAST(type, obj, name) \
+ ((type *)object_dynamic_cast(OBJECT(obj), (name)))
+ SCSIDevice *d = CAST(SCSIDevice, dev, TYPE_SCSI_DEVICE);
+ sPAPRPHBState *phb = CAST(sPAPRPHBState, dev, TYPE_SPAPR_PCI_HOST_BRIDGE);
+
+ if (d) {
+ void *spapr = CAST(void, bus->parent, "spapr-vscsi");
+ VirtIOSCSI *virtio = CAST(VirtIOSCSI, bus->parent, TYPE_VIRTIO_SCSI);
+ USBDevice *usb = CAST(USBDevice, bus->parent, TYPE_USB_DEVICE);
+
+ if (spapr) {
+ /*
+ * Replace "channel@0/disk@0,0" with "disk@8000000000000000":
+ * We use SRP luns of the form 8000 | (bus << 8) | (id << 5) | lun
+ * in the top 16 bits of the 64-bit LUN
+ */
+ unsigned id = 0x8000 | (d->id << 8) | d->lun;
+ return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
+ (uint64_t)id << 48);
+ } else if (virtio) {
+ /*
+ * We use SRP luns of the form 01000000 | (target << 8) | lun
+ * in the top 32 bits of the 64-bit LUN
+ * Note: the quote above is from SLOF and it is wrong,
+ * the actual binding is:
+ * swap 0100 or 10 << or 20 << ( target lun-id -- srplun )
+ */
+ unsigned id = 0x1000000 | (d->id << 16) | d->lun;
+ return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
+ (uint64_t)id << 32);
+ } else if (usb) {
+ /*
+ * We use SRP luns of the form 01000000 | (usb-port << 16) | lun
+ * in the top 32 bits of the 64-bit LUN
+ */
+ unsigned usb_port = atoi(usb->port->path);
+ unsigned id = 0x1000000 | (usb_port << 16) | d->lun;
+ return g_strdup_printf("%s@%"PRIX64, qdev_fw_name(dev),
+ (uint64_t)id << 32);
+ }
+ }
+
+ if (phb) {
+ /* Replace "pci" with "pci@800000020000000" */
+ return g_strdup_printf("pci@%"PRIX64, phb->buid);
+ }
+
+ return NULL;
+}
+
+static void spapr_machine_class_init(ObjectClass *oc, void *data)
+{
+ MachineClass *mc = MACHINE_CLASS(oc);
+ FWPathProviderClass *fwc = FW_PATH_PROVIDER_CLASS(oc);
+
+ mc->qemu_machine = data;
+ fwc->get_dev_path = spapr_get_fw_dev_path;
+}
+
+static const TypeInfo spapr_machine_info = {
+ .name = TYPE_SPAPR_MACHINE,
+ .parent = TYPE_MACHINE,
+ .class_init = spapr_machine_class_init,
+ .class_data = &spapr_machine,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_FW_PATH_PROVIDER },
+ { }
+ },
};
-static void spapr_machine_init(void)
+static void spapr_machine_register_types(void)
{
- qemu_register_machine(&spapr_machine);
+ type_register_static(&spapr_machine_info);
}
-machine_init(spapr_machine_init);
+type_init(spapr_machine_register_types)
diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c
index a69390e54..16fa49e88 100644
--- a/hw/ppc/spapr_events.c
+++ b/hw/ppc/spapr_events.c
@@ -286,7 +286,7 @@ static void check_exception(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint64_t xinfo;
if ((nargs < 6) || (nargs > 7) || nret != 1) {
- rtas_st(rets, 0, -3);
+ rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return;
}
@@ -306,9 +306,9 @@ static void check_exception(PowerPCCPU *cpu, sPAPREnvironment *spapr,
cpu_physical_memory_write(buf, pending_epow, len);
g_free(pending_epow);
pending_epow = NULL;
- rtas_st(rets, 0, 0);
+ rtas_st(rets, 0, RTAS_OUT_SUCCESS);
} else {
- rtas_st(rets, 0, 1);
+ rtas_st(rets, 0, RTAS_OUT_NO_ERRORS_FOUND);
}
}
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 67d6cd91d..0bae0535e 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -4,6 +4,36 @@
#include "hw/ppc/spapr.h"
#include "mmu-hash64.h"
+struct SPRSyncState {
+ CPUState *cs;
+ int spr;
+ target_ulong value;
+ target_ulong mask;
+};
+
+static void do_spr_sync(void *arg)
+{
+ struct SPRSyncState *s = arg;
+ PowerPCCPU *cpu = POWERPC_CPU(s->cs);
+ CPUPPCState *env = &cpu->env;
+
+ cpu_synchronize_state(s->cs);
+ env->spr[s->spr] &= ~s->mask;
+ env->spr[s->spr] |= s->value;
+}
+
+static void set_spr(CPUState *cs, int spr, target_ulong value,
+ target_ulong mask)
+{
+ struct SPRSyncState s = {
+ .cs = cs,
+ .spr = spr,
+ .value = value,
+ .mask = mask
+ };
+ run_on_cpu(cs, do_spr_sync, &s);
+}
+
static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
target_ulong pte_index)
{
@@ -40,6 +70,17 @@ static target_ulong compute_tlbie_rb(target_ulong v, target_ulong r,
return rb;
}
+static inline bool valid_pte_index(CPUPPCState *env, target_ulong pte_index)
+{
+ /*
+ * hash value/pteg group index is normalized by htab_mask
+ */
+ if (((pte_index & ~7ULL) / HPTES_PER_GROUP) & ~env->htab_mask) {
+ return false;
+ }
+ return true;
+}
+
static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong opcode, target_ulong *args)
{
@@ -50,8 +91,8 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong ptel = args[3];
target_ulong page_shift = 12;
target_ulong raddr;
- target_ulong i;
- hwaddr hpte;
+ target_ulong index;
+ uint64_t token;
/* only handle 4k and 16M pages for now */
if (pteh & HPTE64_V_LARGE) {
@@ -91,33 +132,36 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr,
pteh &= ~0x60ULL;
- if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+ if (!valid_pte_index(env, pte_index)) {
return H_PARAMETER;
}
+
+ index = 0;
if (likely((flags & H_EXACT) == 0)) {
pte_index &= ~7ULL;
- hpte = pte_index * HASH_PTE_SIZE_64;
- for (i = 0; ; ++i) {
- if (i == 8) {
- return H_PTEG_FULL;
- }
- if ((ppc_hash64_load_hpte0(env, hpte) & HPTE64_V_VALID) == 0) {
+ token = ppc_hash64_start_access(cpu, pte_index);
+ for (; index < 8; index++) {
+ if ((ppc_hash64_load_hpte0(env, token, index) & HPTE64_V_VALID) == 0) {
break;
}
- hpte += HASH_PTE_SIZE_64;
+ }
+ ppc_hash64_stop_access(token);
+ if (index == 8) {
+ return H_PTEG_FULL;
}
} else {
- i = 0;
- hpte = pte_index * HASH_PTE_SIZE_64;
- if (ppc_hash64_load_hpte0(env, hpte) & HPTE64_V_VALID) {
+ token = ppc_hash64_start_access(cpu, pte_index);
+ if (ppc_hash64_load_hpte0(env, token, 0) & HPTE64_V_VALID) {
+ ppc_hash64_stop_access(token);
return H_PTEG_FULL;
}
+ ppc_hash64_stop_access(token);
}
- ppc_hash64_store_hpte1(env, hpte, ptel);
- /* eieio(); FIXME: need some sort of barrier for smp? */
- ppc_hash64_store_hpte0(env, hpte, pteh | HPTE64_V_HPTE_DIRTY);
- args[0] = pte_index + i;
+ ppc_hash64_store_hpte(env, pte_index + index,
+ pteh | HPTE64_V_HPTE_DIRTY, ptel);
+
+ args[0] = pte_index + index;
return H_SUCCESS;
}
@@ -133,17 +177,17 @@ static RemoveResult remove_hpte(CPUPPCState *env, target_ulong ptex,
target_ulong flags,
target_ulong *vp, target_ulong *rp)
{
- hwaddr hpte;
+ uint64_t token;
target_ulong v, r, rb;
- if ((ptex * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+ if (!valid_pte_index(env, ptex)) {
return REMOVE_PARM;
}
- hpte = ptex * HASH_PTE_SIZE_64;
-
- v = ppc_hash64_load_hpte0(env, hpte);
- r = ppc_hash64_load_hpte1(env, hpte);
+ token = ppc_hash64_start_access(ppc_env_get_cpu(env), ptex);
+ v = ppc_hash64_load_hpte0(env, token, 0);
+ r = ppc_hash64_load_hpte1(env, token, 0);
+ ppc_hash64_stop_access(token);
if ((v & HPTE64_V_VALID) == 0 ||
((flags & H_AVPN) && (v & ~0x7fULL) != avpn) ||
@@ -152,7 +196,7 @@ static RemoveResult remove_hpte(CPUPPCState *env, target_ulong ptex,
}
*vp = v;
*rp = r;
- ppc_hash64_store_hpte0(env, hpte, HPTE64_V_HPTE_DIRTY);
+ ppc_hash64_store_hpte(env, ptex, HPTE64_V_HPTE_DIRTY, 0);
rb = compute_tlbie_rb(v, r, ptex);
ppc_tlb_invalidate_one(env, rb);
return REMOVE_SUCCESS;
@@ -259,17 +303,17 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong flags = args[0];
target_ulong pte_index = args[1];
target_ulong avpn = args[2];
- hwaddr hpte;
+ uint64_t token;
target_ulong v, r, rb;
- if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+ if (!valid_pte_index(env, pte_index)) {
return H_PARAMETER;
}
- hpte = pte_index * HASH_PTE_SIZE_64;
-
- v = ppc_hash64_load_hpte0(env, hpte);
- r = ppc_hash64_load_hpte1(env, hpte);
+ token = ppc_hash64_start_access(cpu, pte_index);
+ v = ppc_hash64_load_hpte0(env, token, 0);
+ r = ppc_hash64_load_hpte1(env, token, 0);
+ ppc_hash64_stop_access(token);
if ((v & HPTE64_V_VALID) == 0 ||
((flags & H_AVPN) && (v & ~0x7fULL) != avpn)) {
@@ -282,11 +326,11 @@ static target_ulong h_protect(PowerPCCPU *cpu, sPAPREnvironment *spapr,
r |= (flags << 48) & HPTE64_R_KEY_HI;
r |= flags & (HPTE64_R_PP | HPTE64_R_N | HPTE64_R_KEY_LO);
rb = compute_tlbie_rb(v, r, pte_index);
- ppc_hash64_store_hpte0(env, hpte, (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY);
+ ppc_hash64_store_hpte(env, pte_index,
+ (v & ~HPTE64_V_VALID) | HPTE64_V_HPTE_DIRTY, 0);
ppc_tlb_invalidate_one(env, rb);
- ppc_hash64_store_hpte1(env, hpte, r);
/* Don't need a memory barrier, due to qemu's global lock */
- ppc_hash64_store_hpte0(env, hpte, v | HPTE64_V_HPTE_DIRTY);
+ ppc_hash64_store_hpte(env, pte_index, v | HPTE64_V_HPTE_DIRTY, r);
return H_SUCCESS;
}
@@ -299,7 +343,7 @@ static target_ulong h_read(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint8_t *hpte;
int i, ridx, n_entries = 1;
- if ((pte_index * HASH_PTE_SIZE_64) & ~env->htab_mask) {
+ if (!valid_pte_index(env, pte_index)) {
return H_PARAMETER;
}
@@ -341,6 +385,7 @@ static target_ulong h_set_dabr(PowerPCCPU *cpu, sPAPREnvironment *spapr,
static target_ulong register_vpa(CPUPPCState *env, target_ulong vpa)
{
+ CPUState *cs = CPU(ppc_env_get_cpu(env));
uint16_t size;
uint8_t tmp;
@@ -354,7 +399,7 @@ static target_ulong register_vpa(CPUPPCState *env, target_ulong vpa)
}
/* FIXME: bounds check the address */
- size = lduw_be_phys(vpa + 0x4);
+ size = lduw_be_phys(cs->as, vpa + 0x4);
if (size < VPA_MIN_SIZE) {
return H_PARAMETER;
@@ -367,9 +412,9 @@ static target_ulong register_vpa(CPUPPCState *env, target_ulong vpa)
env->vpa_addr = vpa;
- tmp = ldub_phys(env->vpa_addr + VPA_SHARED_PROC_OFFSET);
+ tmp = ldub_phys(cs->as, env->vpa_addr + VPA_SHARED_PROC_OFFSET);
tmp |= VPA_SHARED_PROC_VAL;
- stb_phys(env->vpa_addr + VPA_SHARED_PROC_OFFSET, tmp);
+ stb_phys(cs->as, env->vpa_addr + VPA_SHARED_PROC_OFFSET, tmp);
return H_SUCCESS;
}
@@ -390,6 +435,7 @@ static target_ulong deregister_vpa(CPUPPCState *env, target_ulong vpa)
static target_ulong register_slb_shadow(CPUPPCState *env, target_ulong addr)
{
+ CPUState *cs = CPU(ppc_env_get_cpu(env));
uint32_t size;
if (addr == 0) {
@@ -397,7 +443,7 @@ static target_ulong register_slb_shadow(CPUPPCState *env, target_ulong addr)
return H_HARDWARE;
}
- size = ldl_be_phys(addr + 0x4);
+ size = ldl_be_phys(cs->as, addr + 0x4);
if (size < 0x8) {
return H_PARAMETER;
}
@@ -425,6 +471,7 @@ static target_ulong deregister_slb_shadow(CPUPPCState *env, target_ulong addr)
static target_ulong register_dtl(CPUPPCState *env, target_ulong addr)
{
+ CPUState *cs = CPU(ppc_env_get_cpu(env));
uint32_t size;
if (addr == 0) {
@@ -432,7 +479,7 @@ static target_ulong register_dtl(CPUPPCState *env, target_ulong addr)
return H_HARDWARE;
}
- size = ldl_be_phys(addr + 0x4);
+ size = ldl_be_phys(cs->as, addr + 0x4);
if (size < 48) {
return H_PARAMETER;
@@ -464,13 +511,13 @@ static target_ulong h_register_vpa(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong vpa = args[2];
target_ulong ret = H_PARAMETER;
CPUPPCState *tenv;
- CPUState *tcpu;
+ PowerPCCPU *tcpu;
- tcpu = qemu_get_cpu(procno);
+ tcpu = ppc_get_vcpu_by_dt_id(procno);
if (!tcpu) {
return H_PARAMETER;
}
- tenv = tcpu->env_ptr;
+ tenv = &tcpu->env;
switch (flags) {
case FLAGS_REGISTER_VPA:
@@ -511,7 +558,7 @@ static target_ulong h_cede(PowerPCCPU *cpu, sPAPREnvironment *spapr,
hreg_compute_hflags(env);
if (!cpu_has_work(cs)) {
cs->halted = 1;
- env->exception_index = EXCP_HLT;
+ cs->exception_index = EXCP_HLT;
cs->exit_request = 1;
}
return H_SUCCESS;
@@ -521,9 +568,9 @@ static target_ulong h_rtas(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong opcode, target_ulong *args)
{
target_ulong rtas_r3 = args[0];
- uint32_t token = ldl_be_phys(rtas_r3);
- uint32_t nargs = ldl_be_phys(rtas_r3 + 4);
- uint32_t nret = ldl_be_phys(rtas_r3 + 8);
+ uint32_t token = rtas_ld(rtas_r3, 0);
+ uint32_t nargs = rtas_ld(rtas_r3, 1);
+ uint32_t nret = rtas_ld(rtas_r3, 2);
return spapr_rtas_call(cpu, spapr, token, nargs, rtas_r3 + 12,
nret, rtas_r3 + 12 + 4*nargs);
@@ -532,21 +579,22 @@ static target_ulong h_rtas(PowerPCCPU *cpu, sPAPREnvironment *spapr,
static target_ulong h_logical_load(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong opcode, target_ulong *args)
{
+ CPUState *cs = CPU(cpu);
target_ulong size = args[0];
target_ulong addr = args[1];
switch (size) {
case 1:
- args[0] = ldub_phys(addr);
+ args[0] = ldub_phys(cs->as, addr);
return H_SUCCESS;
case 2:
- args[0] = lduw_phys(addr);
+ args[0] = lduw_phys(cs->as, addr);
return H_SUCCESS;
case 4:
- args[0] = ldl_phys(addr);
+ args[0] = ldl_phys(cs->as, addr);
return H_SUCCESS;
case 8:
- args[0] = ldq_phys(addr);
+ args[0] = ldq_phys(cs->as, addr);
return H_SUCCESS;
}
return H_PARAMETER;
@@ -555,22 +603,24 @@ static target_ulong h_logical_load(PowerPCCPU *cpu, sPAPREnvironment *spapr,
static target_ulong h_logical_store(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong opcode, target_ulong *args)
{
+ CPUState *cs = CPU(cpu);
+
target_ulong size = args[0];
target_ulong addr = args[1];
target_ulong val = args[2];
switch (size) {
case 1:
- stb_phys(addr, val);
+ stb_phys(cs->as, addr, val);
return H_SUCCESS;
case 2:
- stw_phys(addr, val);
+ stw_phys(cs->as, addr, val);
return H_SUCCESS;
case 4:
- stl_phys(addr, val);
+ stl_phys(cs->as, addr, val);
return H_SUCCESS;
case 8:
- stq_phys(addr, val);
+ stq_phys(cs->as, addr, val);
return H_SUCCESS;
}
return H_PARAMETER;
@@ -579,6 +629,8 @@ static target_ulong h_logical_store(PowerPCCPU *cpu, sPAPREnvironment *spapr,
static target_ulong h_logical_memop(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong opcode, target_ulong *args)
{
+ CPUState *cs = CPU(cpu);
+
target_ulong dst = args[0]; /* Destination address */
target_ulong src = args[1]; /* Source address */
target_ulong esize = args[2]; /* Element size (0=1,1=2,2=4,3=8) */
@@ -605,16 +657,16 @@ static target_ulong h_logical_memop(PowerPCCPU *cpu, sPAPREnvironment *spapr,
while (count--) {
switch (esize) {
case 0:
- tmp = ldub_phys(src);
+ tmp = ldub_phys(cs->as, src);
break;
case 1:
- tmp = lduw_phys(src);
+ tmp = lduw_phys(cs->as, src);
break;
case 2:
- tmp = ldl_phys(src);
+ tmp = ldl_phys(cs->as, src);
break;
case 3:
- tmp = ldq_phys(src);
+ tmp = ldq_phys(cs->as, src);
break;
default:
return H_PARAMETER;
@@ -624,16 +676,16 @@ static target_ulong h_logical_memop(PowerPCCPU *cpu, sPAPREnvironment *spapr,
}
switch (esize) {
case 0:
- stb_phys(dst, tmp);
+ stb_phys(cs->as, dst, tmp);
break;
case 1:
- stw_phys(dst, tmp);
+ stw_phys(cs->as, dst, tmp);
break;
case 2:
- stl_phys(dst, tmp);
+ stl_phys(cs->as, dst, tmp);
break;
case 3:
- stq_phys(dst, tmp);
+ stq_phys(cs->as, dst, tmp);
break;
}
dst = dst + step;
@@ -657,6 +709,49 @@ static target_ulong h_logical_dcbf(PowerPCCPU *cpu, sPAPREnvironment *spapr,
return H_SUCCESS;
}
+static target_ulong h_set_mode(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ CPUState *cs;
+ target_ulong mflags = args[0];
+ target_ulong resource = args[1];
+ target_ulong value1 = args[2];
+ target_ulong value2 = args[3];
+ target_ulong ret = H_P2;
+
+ if (resource == H_SET_MODE_RESOURCE_LE) {
+ if (value1) {
+ ret = H_P3;
+ goto out;
+ }
+ if (value2) {
+ ret = H_P4;
+ goto out;
+ }
+ switch (mflags) {
+ case H_SET_MODE_ENDIAN_BIG:
+ CPU_FOREACH(cs) {
+ set_spr(cs, SPR_LPCR, 0, LPCR_ILE);
+ }
+ ret = H_SUCCESS;
+ break;
+
+ case H_SET_MODE_ENDIAN_LITTLE:
+ CPU_FOREACH(cs) {
+ set_spr(cs, SPR_LPCR, LPCR_ILE, LPCR_ILE);
+ }
+ ret = H_SUCCESS;
+ break;
+
+ default:
+ ret = H_UNSUPPORTED_FLAG;
+ }
+ }
+
+out:
+ return ret;
+}
+
static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX - KVMPPC_HCALL_BASE + 1];
@@ -734,6 +829,8 @@ static void hypercall_register_types(void)
/* qemu/KVM-PPC specific hcalls */
spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
+
+ spapr_register_hypercall(H_SET_MODE, h_set_mode);
}
type_init(hypercall_register_types)
diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
index 3d4a1fcfe..d9fe94681 100644
--- a/hw/ppc/spapr_iommu.c
+++ b/hw/ppc/spapr_iommu.c
@@ -22,13 +22,12 @@
#include "kvm_ppc.h"
#include "sysemu/dma.h"
#include "exec/address-spaces.h"
+#include "trace.h"
#include "hw/ppc/spapr.h"
#include <libfdt.h>
-/* #define DEBUG_TCE */
-
enum sPAPRTCEAccess {
SPAPR_TCE_FAULT = 0,
SPAPR_TCE_RO = 1,
@@ -61,44 +60,28 @@ static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr)
{
sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu);
uint64_t tce;
-
-#ifdef DEBUG_TCE
- fprintf(stderr, "spapr_tce_translate liobn=0x%" PRIx32 " addr=0x"
- DMA_ADDR_FMT "\n", tcet->liobn, addr);
-#endif
+ IOMMUTLBEntry ret = {
+ .target_as = &address_space_memory,
+ .iova = 0,
+ .translated_addr = 0,
+ .addr_mask = ~(hwaddr)0,
+ .perm = IOMMU_NONE,
+ };
if (tcet->bypass) {
- return (IOMMUTLBEntry) {
- .target_as = &address_space_memory,
- .iova = 0,
- .translated_addr = 0,
- .addr_mask = ~(hwaddr)0,
- .perm = IOMMU_RW,
- };
+ ret.perm = IOMMU_RW;
+ } else if (addr < tcet->window_size) {
+ /* Check if we are in bound */
+ tce = tcet->table[addr >> SPAPR_TCE_PAGE_SHIFT];
+ ret.iova = addr & ~SPAPR_TCE_PAGE_MASK;
+ ret.translated_addr = tce & ~SPAPR_TCE_PAGE_MASK;
+ ret.addr_mask = SPAPR_TCE_PAGE_MASK;
+ ret.perm = tce;
}
+ trace_spapr_iommu_xlate(tcet->liobn, addr, ret.iova, ret.perm,
+ ret.addr_mask);
- /* Check if we are in bound */
- if (addr >= tcet->window_size) {
-#ifdef DEBUG_TCE
- fprintf(stderr, "spapr_tce_translate out of bounds\n");
-#endif
- return (IOMMUTLBEntry) { .perm = IOMMU_NONE };
- }
-
- tce = tcet->table[addr >> SPAPR_TCE_PAGE_SHIFT];
-
-#ifdef DEBUG_TCE
- fprintf(stderr, " -> *paddr=0x%llx, *len=0x%llx\n",
- (tce & ~SPAPR_TCE_PAGE_MASK), SPAPR_TCE_PAGE_MASK + 1);
-#endif
-
- return (IOMMUTLBEntry) {
- .target_as = &address_space_memory,
- .iova = addr & ~SPAPR_TCE_PAGE_MASK,
- .translated_addr = tce & ~SPAPR_TCE_PAGE_MASK,
- .addr_mask = SPAPR_TCE_PAGE_MASK,
- .perm = tce,
- };
+ return ret;
}
static int spapr_tce_table_pre_load(void *opaque)
@@ -150,10 +133,7 @@ static int spapr_tce_table_realize(DeviceState *dev)
}
tcet->nb_table = tcet->window_size >> SPAPR_TCE_PAGE_SHIFT;
-#ifdef DEBUG_TCE
- fprintf(stderr, "spapr_iommu: New TCE table @ %p, liobn=0x%x, "
- "table @ %p, fd=%d\n", tcet, liobn, tcet->table, tcet->fd);
-#endif
+ trace_spapr_iommu_new_table(tcet->liobn, tcet, tcet->table, tcet->fd);
memory_region_init_iommu(&tcet->iommu, OBJECT(dev), &spapr_iommu_ops,
"iommu-spapr", UINT64_MAX);
@@ -250,20 +230,53 @@ static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong liobn = args[0];
target_ulong ioba = args[1];
target_ulong tce = args[2];
+ target_ulong ret = H_PARAMETER;
+ sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
+
+ ioba &= ~(SPAPR_TCE_PAGE_SIZE - 1);
+
+ if (tcet) {
+ ret = put_tce_emu(tcet, ioba, tce);
+ }
+ trace_spapr_iommu_put(liobn, ioba, tce, ret);
+
+ return ret;
+}
+
+static target_ulong get_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
+ target_ulong *tce)
+{
+ if (ioba >= tcet->window_size) {
+ hcall_dprintf("spapr_iommu_get_tce on out-of-bounds IOBA 0x"
+ TARGET_FMT_lx "\n", ioba);
+ return H_PARAMETER;
+ }
+
+ *tce = tcet->table[ioba >> SPAPR_TCE_PAGE_SHIFT];
+
+ return H_SUCCESS;
+}
+
+static target_ulong h_get_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ target_ulong liobn = args[0];
+ target_ulong ioba = args[1];
+ target_ulong tce = 0;
+ target_ulong ret = H_PARAMETER;
sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
ioba &= ~(SPAPR_TCE_PAGE_SIZE - 1);
if (tcet) {
- return put_tce_emu(tcet, ioba, tce);
+ ret = get_tce_emu(tcet, ioba, &tce);
+ if (!ret) {
+ args[0] = tce;
+ }
}
-#ifdef DEBUG_TCE
- fprintf(stderr, "%s on liobn=" TARGET_FMT_lx /*%s*/
- " ioba 0x" TARGET_FMT_lx " TCE 0x" TARGET_FMT_lx "\n",
- __func__, liobn, /*dev->qdev.id, */ioba, tce);
-#endif
+ trace_spapr_iommu_get(liobn, ioba, ret, tce);
- return H_PARAMETER;
+ return ret;
}
int spapr_dma_dt(void *fdt, int node_off, const char *propname,
@@ -318,6 +331,7 @@ static void spapr_tce_table_class_init(ObjectClass *klass, void *data)
/* hcall-tce */
spapr_register_hypercall(H_PUT_TCE, h_put_tce);
+ spapr_register_hypercall(H_GET_TCE, h_get_tce);
}
static TypeInfo spapr_tce_table_info = {
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index 1ca35a0a7..cbef09593 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -32,6 +32,7 @@
#include "exec/address-spaces.h"
#include <libfdt.h>
#include "trace.h"
+#include "qemu/error-report.h"
#include "hw/pci/pci_bus.h"
@@ -65,22 +66,14 @@ static PCIDevice *find_dev(sPAPREnvironment *spapr, uint64_t buid,
{
sPAPRPHBState *sphb = find_phb(spapr, buid);
PCIHostState *phb = PCI_HOST_BRIDGE(sphb);
- BusState *bus = BUS(phb->bus);
- BusChild *kid;
+ int bus_num = (config_addr >> 16) & 0xFF;
int devfn = (config_addr >> 8) & 0xFF;
if (!phb) {
return NULL;
}
- QTAILQ_FOREACH(kid, &bus->children, sibling) {
- PCIDevice *dev = (PCIDevice *)kid->child;
- if (dev->devfn == devfn) {
- return dev;
- }
- }
-
- return NULL;
+ return pci_find_device(phb->bus, bus_num, devfn);
}
static uint32_t rtas_pci_cfgaddr(uint32_t arg)
@@ -98,7 +91,7 @@ static void finish_read_pci_config(sPAPREnvironment *spapr, uint64_t buid,
if ((size != 1) && (size != 2) && (size != 4)) {
/* access must be 1, 2 or 4 bytes */
- rtas_st(rets, 0, -1);
+ rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
return;
}
@@ -108,14 +101,14 @@ static void finish_read_pci_config(sPAPREnvironment *spapr, uint64_t buid,
if (!pci_dev || (addr % size) || (addr >= pci_config_size(pci_dev))) {
/* Access must be to a valid device, within bounds and
* naturally aligned */
- rtas_st(rets, 0, -1);
+ rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
return;
}
val = pci_host_config_read_common(pci_dev, addr,
pci_config_size(pci_dev), size);
- rtas_st(rets, 0, 0);
+ rtas_st(rets, 0, RTAS_OUT_SUCCESS);
rtas_st(rets, 1, val);
}
@@ -128,7 +121,7 @@ static void rtas_ibm_read_pci_config(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint32_t size, addr;
if ((nargs != 4) || (nret != 2)) {
- rtas_st(rets, 0, -1);
+ rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
return;
}
@@ -147,7 +140,7 @@ static void rtas_read_pci_config(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint32_t size, addr;
if ((nargs != 2) || (nret != 2)) {
- rtas_st(rets, 0, -1);
+ rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
return;
}
@@ -165,7 +158,7 @@ static void finish_write_pci_config(sPAPREnvironment *spapr, uint64_t buid,
if ((size != 1) && (size != 2) && (size != 4)) {
/* access must be 1, 2 or 4 bytes */
- rtas_st(rets, 0, -1);
+ rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
return;
}
@@ -175,14 +168,14 @@ static void finish_write_pci_config(sPAPREnvironment *spapr, uint64_t buid,
if (!pci_dev || (addr % size) || (addr >= pci_config_size(pci_dev))) {
/* Access must be to a valid device, within bounds and
* naturally aligned */
- rtas_st(rets, 0, -1);
+ rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
return;
}
pci_host_config_write_common(pci_dev, addr, pci_config_size(pci_dev),
val, size);
- rtas_st(rets, 0, 0);
+ rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
static void rtas_ibm_write_pci_config(PowerPCCPU *cpu, sPAPREnvironment *spapr,
@@ -194,7 +187,7 @@ static void rtas_ibm_write_pci_config(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint32_t val, size, addr;
if ((nargs != 5) || (nret != 1)) {
- rtas_st(rets, 0, -1);
+ rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
return;
}
@@ -214,7 +207,7 @@ static void rtas_write_pci_config(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint32_t val, size, addr;
if ((nargs != 3) || (nret != 1)) {
- rtas_st(rets, 0, -1);
+ rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
return;
}
@@ -258,11 +251,11 @@ static int spapr_msicfg_find(sPAPRPHBState *phb, uint32_t config_addr,
* This is required for msi_notify()/msix_notify() which
* will write at the addresses via spapr_msi_write().
*/
-static void spapr_msi_setmsg(PCIDevice *pdev, hwaddr addr,
- bool msix, unsigned req_num)
+static void spapr_msi_setmsg(PCIDevice *pdev, hwaddr addr, bool msix,
+ unsigned first_irq, unsigned req_num)
{
unsigned i;
- MSIMessage msg = { .address = addr, .data = 0 };
+ MSIMessage msg = { .address = addr, .data = first_irq };
if (!msix) {
msi_set_message(pdev, msg);
@@ -270,8 +263,7 @@ static void spapr_msi_setmsg(PCIDevice *pdev, hwaddr addr,
return;
}
- for (i = 0; i < req_num; ++i) {
- msg.address = addr | (i << 2);
+ for (i = 0; i < req_num; ++i, ++msg.data) {
msix_set_message(pdev, i, msg);
trace_spapr_pci_msi_setup(pdev->name, i, msg.address);
}
@@ -301,8 +293,8 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
ret_intr_type = RTAS_TYPE_MSIX;
break;
default:
- fprintf(stderr, "rtas_ibm_change_msi(%u) is not implemented\n", func);
- rtas_st(rets, 0, -3); /* Parameter error */
+ error_report("rtas_ibm_change_msi(%u) is not implemented", func);
+ rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return;
}
@@ -312,7 +304,7 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
pdev = find_dev(spapr, buid, config_addr);
}
if (!phb || !pdev) {
- rtas_st(rets, 0, -3); /* Parameter error */
+ rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return;
}
@@ -321,11 +313,11 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
ndev = spapr_msicfg_find(phb, config_addr, false);
if (ndev < 0) {
trace_spapr_pci_msi("MSI has not been enabled", -1, config_addr);
- rtas_st(rets, 0, -1); /* Hardware error */
+ rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
return;
}
trace_spapr_pci_msi("Released MSIs", ndev, config_addr);
- rtas_st(rets, 0, 0);
+ rtas_st(rets, 0, RTAS_OUT_SUCCESS);
rtas_st(rets, 1, 0);
return;
}
@@ -335,8 +327,8 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
/* Find a device number in the map to add or reuse the existing one */
ndev = spapr_msicfg_find(phb, config_addr, true);
if (ndev >= SPAPR_MSIX_MAX_DEVS || ndev < 0) {
- fprintf(stderr, "No free entry for a new MSI device\n");
- rtas_st(rets, 0, -1); /* Hardware error */
+ error_report("No free entry for a new MSI device");
+ rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
return;
}
trace_spapr_pci_msi("Configuring MSI", ndev, config_addr);
@@ -344,17 +336,18 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
/* Check if there is an old config and MSI number has not changed */
if (phb->msi_table[ndev].nvec && (req_num != phb->msi_table[ndev].nvec)) {
/* Unexpected behaviour */
- fprintf(stderr, "Cannot reuse MSI config for device#%d", ndev);
- rtas_st(rets, 0, -1); /* Hardware error */
+ error_report("Cannot reuse MSI config for device#%d", ndev);
+ rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
return;
}
/* There is no cached config, allocate MSIs */
if (!phb->msi_table[ndev].nvec) {
- irq = spapr_allocate_irq_block(req_num, false);
+ irq = spapr_allocate_irq_block(req_num, false,
+ ret_intr_type == RTAS_TYPE_MSI);
if (irq < 0) {
- fprintf(stderr, "Cannot allocate MSIs for device#%d", ndev);
- rtas_st(rets, 0, -1); /* Hardware error */
+ error_report("Cannot allocate MSIs for device#%d", ndev);
+ rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
return;
}
phb->msi_table[ndev].irq = irq;
@@ -363,10 +356,10 @@ static void rtas_ibm_change_msi(PowerPCCPU *cpu, sPAPREnvironment *spapr,
}
/* Setup MSI/MSIX vectors in the device (via cfgspace or MSIX BAR) */
- spapr_msi_setmsg(pdev, phb->msi_win_addr | (ndev << 16),
- ret_intr_type == RTAS_TYPE_MSIX, req_num);
+ spapr_msi_setmsg(pdev, spapr->msi_win_addr, ret_intr_type == RTAS_TYPE_MSIX,
+ phb->msi_table[ndev].irq, req_num);
- rtas_st(rets, 0, 0);
+ rtas_st(rets, 0, RTAS_OUT_SUCCESS);
rtas_st(rets, 1, req_num);
rtas_st(rets, 2, ++seq_num);
rtas_st(rets, 3, ret_intr_type);
@@ -391,7 +384,7 @@ static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu,
/* Fins sPAPRPHBState */
phb = find_phb(spapr, buid);
if (!phb) {
- rtas_st(rets, 0, -3); /* Parameter error */
+ rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return;
}
@@ -399,7 +392,7 @@ static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu,
ndev = spapr_msicfg_find(phb, config_addr, false);
if (ndev < 0) {
trace_spapr_pci_msi("MSI has not been enabled", -1, config_addr);
- rtas_st(rets, 0, -1); /* Hardware error */
+ rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
return;
}
@@ -407,7 +400,7 @@ static void rtas_ibm_query_interrupt_source_number(PowerPCCPU *cpu,
trace_spapr_pci_rtas_ibm_query_interrupt_source_number(ioa_intr_num,
intr_src_num);
- rtas_st(rets, 0, 0);
+ rtas_st(rets, 0, RTAS_OUT_SUCCESS);
rtas_st(rets, 1, intr_src_num);
rtas_st(rets, 2, 1);/* 0 == level; 1 == edge */
}
@@ -440,6 +433,17 @@ static void pci_spapr_set_irq(void *opaque, int irq_num, int level)
qemu_set_irq(spapr_phb_lsi_qirq(phb, irq_num), level);
}
+static PCIINTxRoute spapr_route_intx_pin_to_irq(void *opaque, int pin)
+{
+ sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(opaque);
+ PCIINTxRoute route;
+
+ route.mode = PCI_INTX_ENABLED;
+ route.irq = sphb->lsi_table[pin].irq;
+
+ return route;
+}
+
/*
* MSI/MSIX memory region implementation.
* The handler handles both MSI and MSIX.
@@ -450,10 +454,7 @@ static void pci_spapr_set_irq(void *opaque, int irq_num, int level)
static void spapr_msi_write(void *opaque, hwaddr addr,
uint64_t data, unsigned size)
{
- sPAPRPHBState *phb = opaque;
- int ndev = addr >> 16;
- int vec = ((addr & 0xFFFF) >> 2) | data;
- uint32_t irq = phb->msi_table[ndev].irq + vec;
+ uint32_t irq = data;
trace_spapr_pci_msi_write(addr, data, irq);
@@ -467,6 +468,34 @@ static const MemoryRegionOps spapr_msi_ops = {
.endianness = DEVICE_LITTLE_ENDIAN
};
+void spapr_pci_msi_init(sPAPREnvironment *spapr, hwaddr addr)
+{
+ uint64_t window_size = 4096;
+
+ /*
+ * As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors,
+ * we need to allocate some memory to catch those writes coming
+ * from msi_notify()/msix_notify().
+ * As MSIMessage:addr is going to be the same and MSIMessage:data
+ * is going to be a VIRQ number, 4 bytes of the MSI MR will only
+ * be used.
+ *
+ * For KVM we want to ensure that this memory is a full page so that
+ * our memory slot is of page size granularity.
+ */
+#ifdef CONFIG_KVM
+ if (kvm_enabled()) {
+ window_size = getpagesize();
+ }
+#endif
+
+ spapr->msi_win_addr = addr;
+ memory_region_init_io(&spapr->msiwindow, NULL, &spapr_msi_ops, spapr,
+ "msi", window_size);
+ memory_region_add_subregion(get_system_memory(), spapr->msi_win_addr,
+ &spapr->msiwindow);
+}
+
/*
* PHB PCI device
*/
@@ -477,12 +506,11 @@ static AddressSpace *spapr_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn)
return &phb->iommu_as;
}
-static int spapr_phb_init(SysBusDevice *s)
+static void spapr_phb_realize(DeviceState *dev, Error **errp)
{
- DeviceState *dev = DEVICE(s);
+ SysBusDevice *s = SYS_BUS_DEVICE(dev);
sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s);
PCIHostState *phb = PCI_HOST_BRIDGE(s);
- const char *busname;
char *namebuf;
int i;
PCIBus *bus;
@@ -492,11 +520,10 @@ static int spapr_phb_init(SysBusDevice *s)
if ((sphb->buid != -1) || (sphb->dma_liobn != -1)
|| (sphb->mem_win_addr != -1)
- || (sphb->io_win_addr != -1)
- || (sphb->msi_win_addr != -1)) {
- fprintf(stderr, "Either \"index\" or other parameters must"
- " be specified for PAPR PHB, not both\n");
- return -1;
+ || (sphb->io_win_addr != -1)) {
+ error_setg(errp, "Either \"index\" or other parameters must"
+ " be specified for PAPR PHB, not both");
+ return;
}
sphb->buid = SPAPR_PCI_BASE_BUID + sphb->index;
@@ -506,37 +533,31 @@ static int spapr_phb_init(SysBusDevice *s)
+ sphb->index * SPAPR_PCI_WINDOW_SPACING;
sphb->mem_win_addr = windows_base + SPAPR_PCI_MMIO_WIN_OFF;
sphb->io_win_addr = windows_base + SPAPR_PCI_IO_WIN_OFF;
- sphb->msi_win_addr = windows_base + SPAPR_PCI_MSI_WIN_OFF;
}
if (sphb->buid == -1) {
- fprintf(stderr, "BUID not specified for PHB\n");
- return -1;
+ error_setg(errp, "BUID not specified for PHB");
+ return;
}
if (sphb->dma_liobn == -1) {
- fprintf(stderr, "LIOBN not specified for PHB\n");
- return -1;
+ error_setg(errp, "LIOBN not specified for PHB");
+ return;
}
if (sphb->mem_win_addr == -1) {
- fprintf(stderr, "Memory window address not specified for PHB\n");
- return -1;
+ error_setg(errp, "Memory window address not specified for PHB");
+ return;
}
if (sphb->io_win_addr == -1) {
- fprintf(stderr, "IO window address not specified for PHB\n");
- return -1;
- }
-
- if (sphb->msi_win_addr == -1) {
- fprintf(stderr, "MSI window address not specified for PHB\n");
- return -1;
+ error_setg(errp, "IO window address not specified for PHB");
+ return;
}
if (find_phb(spapr, sphb->buid)) {
- fprintf(stderr, "PCI host bridges must have unique BUIDs\n");
- return -1;
+ error_setg(errp, "PCI host bridges must have unique BUIDs");
+ return;
}
sphb->dtbusname = g_strdup_printf("pci@%" PRIx64, sphb->buid);
@@ -545,7 +566,7 @@ static int spapr_phb_init(SysBusDevice *s)
/* Initialize memory regions */
sprintf(namebuf, "%s.mmio", sphb->dtbusname);
- memory_region_init(&sphb->memspace, OBJECT(sphb), namebuf, INT64_MAX);
+ memory_region_init(&sphb->memspace, OBJECT(sphb), namebuf, UINT64_MAX);
sprintf(namebuf, "%s.mmio-alias", sphb->dtbusname);
memory_region_init_alias(&sphb->memwindow, OBJECT(sphb),
@@ -574,37 +595,7 @@ static int spapr_phb_init(SysBusDevice *s)
memory_region_add_subregion(get_system_memory(), sphb->io_win_addr,
&sphb->iowindow);
- /* As MSI/MSIX interrupts trigger by writing at MSI/MSIX vectors,
- * we need to allocate some memory to catch those writes coming
- * from msi_notify()/msix_notify() */
- if (msi_supported) {
- sprintf(namebuf, "%s.msi", sphb->dtbusname);
- memory_region_init_io(&sphb->msiwindow, OBJECT(sphb), &spapr_msi_ops, sphb,
- namebuf, SPAPR_MSIX_MAX_DEVS * 0x10000);
- memory_region_add_subregion(get_system_memory(), sphb->msi_win_addr,
- &sphb->msiwindow);
- }
-
- /*
- * Selecting a busname is more complex than you'd think, due to
- * interacting constraints. If the user has specified an id
- * explicitly for the phb , then we want to use the qdev default
- * of naming the bus based on the bridge device (so the user can
- * then assign devices to it in the way they expect). For the
- * first / default PCI bus (index=0) we want to use just "pci"
- * because libvirt expects there to be a bus called, simply,
- * "pci". Otherwise, we use the same name as in the device tree,
- * since it's unique by construction, and makes the guest visible
- * BUID clear.
- */
- if (dev->id) {
- busname = NULL;
- } else if (sphb->index == 0) {
- busname = "pci";
- } else {
- busname = sphb->dtbusname;
- }
- bus = pci_register_bus(dev, busname,
+ bus = pci_register_bus(dev, NULL,
pci_spapr_set_irq, pci_spapr_map_irq, sphb,
&sphb->memspace, &sphb->iospace,
PCI_DEVFN(0, 0), PCI_NUM_PINS, TYPE_PCI_BUS);
@@ -615,14 +606,17 @@ static int spapr_phb_init(SysBusDevice *s)
sphb->tcet = spapr_tce_new_table(dev, sphb->dma_liobn,
sphb->dma_window_size);
if (!sphb->tcet) {
- fprintf(stderr, "Unable to create TCE table for %s\n", sphb->dtbusname);
- return -1;
+ error_setg(errp, "Unable to create TCE table for %s",
+ sphb->dtbusname);
+ return;
}
address_space_init(&sphb->iommu_as, spapr_tce_get_iommu(sphb->tcet),
sphb->dtbusname);
pci_setup_iommu(bus, spapr_pci_dma_iommu, sphb);
+ pci_bus_set_route_irq_fn(bus, spapr_route_intx_pin_to_irq);
+
QLIST_INSERT_HEAD(&spapr->phbs, sphb, list);
/* Initialize the LSI table */
@@ -631,13 +625,12 @@ static int spapr_phb_init(SysBusDevice *s)
irq = spapr_allocate_lsi(0);
if (!irq) {
- return -1;
+ error_setg(errp, "spapr_allocate_lsi failed");
+ return;
}
sphb->lsi_table[i].irq = irq;
}
-
- return 0;
}
static void spapr_phb_reset(DeviceState *qdev)
@@ -651,15 +644,14 @@ static void spapr_phb_reset(DeviceState *qdev)
static Property spapr_phb_properties[] = {
DEFINE_PROP_INT32("index", sPAPRPHBState, index, -1),
- DEFINE_PROP_HEX64("buid", sPAPRPHBState, buid, -1),
- DEFINE_PROP_HEX32("liobn", sPAPRPHBState, dma_liobn, -1),
- DEFINE_PROP_HEX64("mem_win_addr", sPAPRPHBState, mem_win_addr, -1),
- DEFINE_PROP_HEX64("mem_win_size", sPAPRPHBState, mem_win_size,
- SPAPR_PCI_MMIO_WIN_SIZE),
- DEFINE_PROP_HEX64("io_win_addr", sPAPRPHBState, io_win_addr, -1),
- DEFINE_PROP_HEX64("io_win_size", sPAPRPHBState, io_win_size,
- SPAPR_PCI_IO_WIN_SIZE),
- DEFINE_PROP_HEX64("msi_win_addr", sPAPRPHBState, msi_win_addr, -1),
+ DEFINE_PROP_UINT64("buid", sPAPRPHBState, buid, -1),
+ DEFINE_PROP_UINT32("liobn", sPAPRPHBState, dma_liobn, -1),
+ DEFINE_PROP_UINT64("mem_win_addr", sPAPRPHBState, mem_win_addr, -1),
+ DEFINE_PROP_UINT64("mem_win_size", sPAPRPHBState, mem_win_size,
+ SPAPR_PCI_MMIO_WIN_SIZE),
+ DEFINE_PROP_UINT64("io_win_addr", sPAPRPHBState, io_win_addr, -1),
+ DEFINE_PROP_UINT64("io_win_size", sPAPRPHBState, io_win_size,
+ SPAPR_PCI_IO_WIN_SIZE),
DEFINE_PROP_END_OF_LIST(),
};
@@ -701,7 +693,6 @@ static const VMStateDescription vmstate_spapr_pci = {
VMSTATE_UINT64_EQUAL(mem_win_size, sPAPRPHBState),
VMSTATE_UINT64_EQUAL(io_win_addr, sPAPRPHBState),
VMSTATE_UINT64_EQUAL(io_win_size, sPAPRPHBState),
- VMSTATE_UINT64_EQUAL(msi_win_addr, sPAPRPHBState),
VMSTATE_STRUCT_ARRAY(lsi_table, sPAPRPHBState, PCI_NUM_PINS, 0,
vmstate_spapr_pci_lsi, struct spapr_pci_lsi),
VMSTATE_STRUCT_ARRAY(msi_table, sPAPRPHBState, SPAPR_MSIX_MAX_DEVS, 0,
@@ -722,14 +713,15 @@ static const char *spapr_phb_root_bus_path(PCIHostState *host_bridge,
static void spapr_phb_class_init(ObjectClass *klass, void *data)
{
PCIHostBridgeClass *hc = PCI_HOST_BRIDGE_CLASS(klass);
- SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
hc->root_bus_path = spapr_phb_root_bus_path;
- sdc->init = spapr_phb_init;
+ dc->realize = spapr_phb_realize;
dc->props = spapr_phb_properties;
dc->reset = spapr_phb_reset;
dc->vmsd = &vmstate_spapr_pci;
+ set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+ dc->cannot_instantiate_with_device_add_yet = false;
}
static const TypeInfo spapr_phb_info = {
diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index 394ce05ba..73860d048 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -47,10 +47,10 @@ static void rtas_display_character(PowerPCCPU *cpu, sPAPREnvironment *spapr,
VIOsPAPRDevice *sdev = vty_lookup(spapr, 0);
if (!sdev) {
- rtas_st(rets, 0, -1);
+ rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
} else {
vty_putchars(sdev, &c, sizeof(c));
- rtas_st(rets, 0, 0);
+ rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
}
@@ -62,13 +62,13 @@ static void rtas_get_time_of_day(PowerPCCPU *cpu, sPAPREnvironment *spapr,
struct tm tm;
if (nret != 8) {
- rtas_st(rets, 0, -3);
+ rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return;
}
qemu_get_timedate(&tm, spapr->rtc_offset);
- rtas_st(rets, 0, 0); /* Success */
+ rtas_st(rets, 0, RTAS_OUT_SUCCESS);
rtas_st(rets, 1, tm.tm_year + 1900);
rtas_st(rets, 2, tm.tm_mon + 1);
rtas_st(rets, 3, tm.tm_mday);
@@ -96,7 +96,7 @@ static void rtas_set_time_of_day(PowerPCCPU *cpu, sPAPREnvironment *spapr,
rtc_change_mon_event(&tm);
spapr->rtc_offset = qemu_timedate_diff(&tm);
- rtas_st(rets, 0, 0); /* Success */
+ rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
static void rtas_power_off(PowerPCCPU *cpu, sPAPREnvironment *spapr,
@@ -104,11 +104,11 @@ static void rtas_power_off(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint32_t nret, target_ulong rets)
{
if (nargs != 2 || nret != 1) {
- rtas_st(rets, 0, -3);
+ rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return;
}
qemu_system_shutdown_request();
- rtas_st(rets, 0, 0);
+ rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
static void rtas_system_reboot(PowerPCCPU *cpu, sPAPREnvironment *spapr,
@@ -117,11 +117,11 @@ static void rtas_system_reboot(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint32_t nret, target_ulong rets)
{
if (nargs != 0 || nret != 1) {
- rtas_st(rets, 0, -3);
+ rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return;
}
qemu_system_reset_request();
- rtas_st(rets, 0, 0);
+ rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_,
@@ -131,28 +131,28 @@ static void rtas_query_cpu_stopped_state(PowerPCCPU *cpu_,
uint32_t nret, target_ulong rets)
{
target_ulong id;
- CPUState *cpu;
+ PowerPCCPU *cpu;
if (nargs != 1 || nret != 2) {
- rtas_st(rets, 0, -3);
+ rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return;
}
id = rtas_ld(args, 0);
- cpu = qemu_get_cpu(id);
+ cpu = ppc_get_vcpu_by_dt_id(id);
if (cpu != NULL) {
- if (cpu->halted) {
+ if (CPU(cpu)->halted) {
rtas_st(rets, 1, 0);
} else {
rtas_st(rets, 1, 2);
}
- rtas_st(rets, 0, 0);
+ rtas_st(rets, 0, RTAS_OUT_SUCCESS);
return;
}
/* Didn't find a matching cpu */
- rtas_st(rets, 0, -3);
+ rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
}
static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPREnvironment *spapr,
@@ -161,10 +161,10 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPREnvironment *spapr,
uint32_t nret, target_ulong rets)
{
target_ulong id, start, r3;
- CPUState *cs;
+ PowerPCCPU *cpu;
if (nargs != 3 || nret != 1) {
- rtas_st(rets, 0, -3);
+ rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return;
}
@@ -172,13 +172,13 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPREnvironment *spapr,
start = rtas_ld(args, 1);
r3 = rtas_ld(args, 2);
- cs = qemu_get_cpu(id);
- if (cs != NULL) {
- PowerPCCPU *cpu = POWERPC_CPU(cs);
+ cpu = ppc_get_vcpu_by_dt_id(id);
+ if (cpu != NULL) {
+ CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
if (!cs->halted) {
- rtas_st(rets, 0, -1);
+ rtas_st(rets, 0, RTAS_OUT_HW_ERROR);
return;
}
@@ -194,12 +194,77 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPREnvironment *spapr,
qemu_cpu_kick(cs);
- rtas_st(rets, 0, 0);
+ rtas_st(rets, 0, RTAS_OUT_SUCCESS);
return;
}
/* Didn't find a matching cpu */
- rtas_st(rets, 0, -3);
+ rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
+}
+
+static void rtas_stop_self(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+ uint32_t token, uint32_t nargs,
+ target_ulong args,
+ uint32_t nret, target_ulong rets)
+{
+ CPUState *cs = CPU(cpu);
+ CPUPPCState *env = &cpu->env;
+
+ cs->halted = 1;
+ cpu_exit(cs);
+ /*
+ * While stopping a CPU, the guest calls H_CPPR which
+ * effectively disables interrupts on XICS level.
+ * However decrementer interrupts in TCG can still
+ * wake the CPU up so here we disable interrupts in MSR
+ * as well.
+ * As rtas_start_cpu() resets the whole MSR anyway, there is
+ * no need to bother with specific bits, we just clear it.
+ */
+ env->msr = 0;
+}
+
+#define DIAGNOSTICS_RUN_MODE 42
+
+static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu,
+ sPAPREnvironment *spapr,
+ uint32_t token, uint32_t nargs,
+ target_ulong args,
+ uint32_t nret, target_ulong rets)
+{
+ target_ulong parameter = rtas_ld(args, 0);
+ target_ulong buffer = rtas_ld(args, 1);
+ target_ulong length = rtas_ld(args, 2);
+ target_ulong ret = RTAS_OUT_NOT_SUPPORTED;
+
+ switch (parameter) {
+ case DIAGNOSTICS_RUN_MODE:
+ if (length == 1) {
+ rtas_st(buffer, 0, 0);
+ ret = RTAS_OUT_SUCCESS;
+ }
+ break;
+ }
+
+ rtas_st(rets, 0, ret);
+}
+
+static void rtas_ibm_set_system_parameter(PowerPCCPU *cpu,
+ sPAPREnvironment *spapr,
+ uint32_t token, uint32_t nargs,
+ target_ulong args,
+ uint32_t nret, target_ulong rets)
+{
+ target_ulong parameter = rtas_ld(args, 0);
+ target_ulong ret = RTAS_OUT_NOT_SUPPORTED;
+
+ switch (parameter) {
+ case DIAGNOSTICS_RUN_MODE:
+ ret = RTAS_OUT_NOT_AUTHORIZED;
+ break;
+ }
+
+ rtas_st(rets, 0, ret);
}
static struct rtas_call {
@@ -233,7 +298,7 @@ target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPREnvironment *spapr,
}
hcall_dprintf("Unknown RTAS token 0x%x\n", token);
- rtas_st(rets, 0, -3);
+ rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return H_PARAMETER;
}
@@ -269,24 +334,24 @@ int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr,
return ret;
}
- ret = qemu_devtree_setprop_cell(fdt, "/rtas", "linux,rtas-base",
- rtas_addr);
+ ret = qemu_fdt_setprop_cell(fdt, "/rtas", "linux,rtas-base",
+ rtas_addr);
if (ret < 0) {
fprintf(stderr, "Couldn't add linux,rtas-base property: %s\n",
fdt_strerror(ret));
return ret;
}
- ret = qemu_devtree_setprop_cell(fdt, "/rtas", "linux,rtas-entry",
- rtas_addr);
+ ret = qemu_fdt_setprop_cell(fdt, "/rtas", "linux,rtas-entry",
+ rtas_addr);
if (ret < 0) {
fprintf(stderr, "Couldn't add linux,rtas-entry property: %s\n",
fdt_strerror(ret));
return ret;
}
- ret = qemu_devtree_setprop_cell(fdt, "/rtas", "rtas-size",
- rtas_size);
+ ret = qemu_fdt_setprop_cell(fdt, "/rtas", "rtas-size",
+ rtas_size);
if (ret < 0) {
fprintf(stderr, "Couldn't add rtas-size property: %s\n",
fdt_strerror(ret));
@@ -300,8 +365,8 @@ int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr,
continue;
}
- ret = qemu_devtree_setprop_cell(fdt, "/rtas", call->name,
- i + TOKEN_BASE);
+ ret = qemu_fdt_setprop_cell(fdt, "/rtas", call->name,
+ i + TOKEN_BASE);
if (ret < 0) {
fprintf(stderr, "Couldn't add rtas token for %s: %s\n",
call->name, fdt_strerror(ret));
@@ -322,6 +387,11 @@ static void core_rtas_register_types(void)
spapr_rtas_register("query-cpu-stopped-state",
rtas_query_cpu_stopped_state);
spapr_rtas_register("start-cpu", rtas_start_cpu);
+ spapr_rtas_register("stop-self", rtas_stop_self);
+ spapr_rtas_register("ibm,get-system-parameter",
+ rtas_ibm_get_system_parameter);
+ spapr_rtas_register("ibm,set-system-parameter",
+ rtas_ibm_set_system_parameter);
}
type_init(core_rtas_register_types)
diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c
index a6a0a5113..2ae06a335 100644
--- a/hw/ppc/spapr_vio.c
+++ b/hw/ppc/spapr_vio.c
@@ -68,6 +68,7 @@ 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;
+ k->get_fw_dev_path = spapr_vio_get_dev_name;
}
static const TypeInfo spapr_vio_bus_info = {
@@ -331,25 +332,25 @@ static void rtas_set_tce_bypass(PowerPCCPU *cpu, sPAPREnvironment *spapr,
uint32_t unit, enable;
if (nargs != 2) {
- rtas_st(rets, 0, -3);
+ rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return;
}
unit = rtas_ld(args, 0);
enable = rtas_ld(args, 1);
dev = spapr_vio_find_by_reg(bus, unit);
if (!dev) {
- rtas_st(rets, 0, -3);
+ rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return;
}
if (!dev->tcet) {
- rtas_st(rets, 0, -3);
+ rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return;
}
spapr_tce_set_bypass(dev->tcet, !!enable);
- rtas_st(rets, 0, 0);
+ rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
static void rtas_quiesce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
@@ -362,7 +363,7 @@ static void rtas_quiesce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
VIOsPAPRDevice *dev = NULL;
if (nargs != 0) {
- rtas_st(rets, 0, -3);
+ rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR);
return;
}
@@ -371,7 +372,7 @@ static void rtas_quiesce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
spapr_vio_quiesce_one(dev);
}
- rtas_st(rets, 0, 0);
+ rtas_st(rets, 0, RTAS_OUT_SUCCESS);
}
static VIOsPAPRDevice *reg_conflict(VIOsPAPRDevice *dev)
@@ -528,11 +529,11 @@ static int spapr_vio_bridge_init(SysBusDevice *dev)
static void spapr_vio_bridge_class_init(ObjectClass *klass, void *data)
{
- DeviceClass *dc = DEVICE_CLASS(klass);
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ dc->fw_name = "vdevice";
k->init = spapr_vio_bridge_init;
- dc->no_user = 1;
}
static const TypeInfo spapr_vio_bridge_info = {
diff --git a/hw/ppc/virtex_ml507.c b/hw/ppc/virtex_ml507.c
index 08e77fbef..3e3569d4b 100644
--- a/hw/ppc/virtex_ml507.c
+++ b/hw/ppc/virtex_ml507.c
@@ -40,11 +40,19 @@
#include "ppc405.h"
#include "sysemu/blockdev.h"
-#include "hw/xilinx.h"
+#include "qapi/qmp/qerror.h"
#define EPAPR_MAGIC (0x45504150)
#define FLASH_SIZE (16 * 1024 * 1024)
+#define INTC_BASEADDR 0x81800000
+#define UART16550_BASEADDR 0x83e01003
+#define TIMER_BASEADDR 0x83c00000
+#define PFLASH_BASEADDR 0xfc000000
+
+#define TIMER_IRQ 3
+#define UART16550_IRQ 9
+
static struct boot_info
{
uint32_t bootstrap_pc;
@@ -63,7 +71,7 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env,
tlb->attr = 0;
tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
- tlb->size = 1 << 31; /* up to 0x80000000 */
+ tlb->size = 1U << 31; /* up to 0x80000000 */
tlb->EPN = va & TARGET_PAGE_MASK;
tlb->RPN = pa & TARGET_PAGE_MASK;
tlb->PID = 0;
@@ -71,7 +79,7 @@ static void mmubooke_create_initial_mapping(CPUPPCState *env,
tlb = &env->tlb.tlbe[1];
tlb->attr = 0;
tlb->prot = PAGE_VALID | ((PAGE_READ | PAGE_WRITE | PAGE_EXEC) << 4);
- tlb->size = 1 << 31; /* up to 0xffffffff */
+ tlb->size = 1U << 31; /* up to 0xffffffff */
tlb->EPN = 0x80000000 & TARGET_PAGE_MASK;
tlb->RPN = 0x80000000 & TARGET_PAGE_MASK;
tlb->PID = 0;
@@ -141,23 +149,45 @@ static int xilinx_load_device_tree(hwaddr addr,
{
char *path;
int fdt_size;
- void *fdt;
+ void *fdt = NULL;
int r;
+ const char *dtb_filename;
- /* Try the local "ppc.dtb" override. */
- fdt = load_device_tree("ppc.dtb", &fdt_size);
- if (!fdt) {
- path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
- if (path) {
- fdt = load_device_tree(path, &fdt_size);
- g_free(path);
+ dtb_filename = qemu_opt_get(qemu_get_machine_opts(), "dtb");
+ if (dtb_filename) {
+ fdt = load_device_tree(dtb_filename, &fdt_size);
+ if (!fdt) {
+ error_report("Error while loading device tree file '%s'",
+ dtb_filename);
}
+ } else {
+ /* Try the local "ppc.dtb" override. */
+ fdt = load_device_tree("ppc.dtb", &fdt_size);
if (!fdt) {
- return 0;
+ path = qemu_find_file(QEMU_FILE_TYPE_BIOS, BINARY_DEVICE_TREE_FILE);
+ if (path) {
+ fdt = load_device_tree(path, &fdt_size);
+ g_free(path);
+ }
}
}
+ if (!fdt) {
+ return 0;
+ }
- r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline);
+ r = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start",
+ initrd_base);
+ if (r < 0) {
+ error_report("couldn't set /chosen/linux,initrd-start");
+ }
+
+ r = qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end",
+ (initrd_base + initrd_size));
+ if (r < 0) {
+ error_report("couldn't set /chosen/linux,initrd-end");
+ }
+
+ r = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline);
if (r < 0)
fprintf(stderr, "couldn't set /chosen/bootargs\n");
cpu_physical_memory_write(addr, fdt, fdt_size);
@@ -170,6 +200,8 @@ static void virtex_init(QEMUMachineInitArgs *args)
const char *cpu_model = args->cpu_model;
const char *kernel_filename = args->kernel_filename;
const char *kernel_cmdline = args->kernel_cmdline;
+ hwaddr initrd_base = 0;
+ int initrd_size = 0;
MemoryRegion *address_space_mem = get_system_memory();
DeviceState *dev;
PowerPCCPU *cpu;
@@ -195,22 +227,31 @@ static void virtex_init(QEMUMachineInitArgs *args)
memory_region_add_subregion(address_space_mem, ram_base, phys_ram);
dinfo = drive_get(IF_PFLASH, 0, 0);
- pflash_cfi01_register(0xfc000000, NULL, "virtex.flash", FLASH_SIZE,
+ pflash_cfi01_register(PFLASH_BASEADDR, NULL, "virtex.flash", FLASH_SIZE,
dinfo ? dinfo->bdrv : NULL, (64 * 1024),
FLASH_SIZE >> 16,
1, 0x89, 0x18, 0x0000, 0x0, 1);
cpu_irq = (qemu_irq *) &env->irq_inputs[PPC40x_INPUT_INT];
- dev = xilinx_intc_create(0x81800000, cpu_irq[0], 0);
+ dev = qdev_create(NULL, "xlnx.xps-intc");
+ qdev_prop_set_uint32(dev, "kind-of-intr", 0);
+ qdev_init_nofail(dev);
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, INTC_BASEADDR);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irq[0]);
for (i = 0; i < 32; i++) {
irq[i] = qdev_get_gpio_in(dev, i);
}
- serial_mm_init(address_space_mem, 0x83e01003ULL, 2, irq[9], 115200,
- serial_hds[0], DEVICE_LITTLE_ENDIAN);
+ serial_mm_init(address_space_mem, UART16550_BASEADDR, 2, irq[UART16550_IRQ],
+ 115200, serial_hds[0], DEVICE_LITTLE_ENDIAN);
/* 2 timers at irq 2 @ 62 Mhz. */
- xilinx_timer_create(0x83c00000, irq[3], 0, 62 * 1000000);
+ dev = qdev_create(NULL, "xlnx.xps-timer");
+ qdev_prop_set_uint32(dev, "one-timer-only", 0);
+ qdev_prop_set_uint32(dev, "clock-frequency", 62 * 1000000);
+ qdev_init_nofail(dev);
+ sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, TIMER_BASEADDR);
+ sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[TIMER_IRQ]);
if (kernel_filename) {
uint64_t entry, low, high;
@@ -233,10 +274,27 @@ static void virtex_init(QEMUMachineInitArgs *args)
boot_info.ima_size = kernel_size;
+ /* Load initrd. */
+ if (args->initrd_filename) {
+ initrd_base = high = ROUND_UP(high, 4);
+ initrd_size = load_image_targphys(args->initrd_filename,
+ high, ram_size - high);
+
+ if (initrd_size < 0) {
+ error_report("couldn't load ram disk '%s'",
+ args->initrd_filename);
+ exit(1);
+ }
+ high = ROUND_UP(high + initrd_size, 4);
+ }
+
/* Provide a device-tree. */
boot_info.fdt = high + (8192 * 2);
boot_info.fdt &= ~8191;
- xilinx_load_device_tree(boot_info.fdt, ram_size, 0, 0, kernel_cmdline);
+
+ xilinx_load_device_tree(boot_info.fdt, ram_size,
+ initrd_base, initrd_size,
+ kernel_cmdline);
}
env->load_info = &boot_info;
}
@@ -245,7 +303,6 @@ static QEMUMachine virtex_machine = {
.name = "virtex-ml507",
.desc = "Xilinx Virtex ML507 reference design",
.init = virtex_init,
- DEFAULT_MACHINE_OPTIONS,
};
static void virtex_machine_init(void)