aboutsummaryrefslogtreecommitdiff
path: root/hw/ppc/e500.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/ppc/e500.c')
-rw-r--r--hw/ppc/e500.c147
1 files changed, 100 insertions, 47 deletions
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 223bab9eea..a973c18d88 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -39,7 +39,6 @@
#define EPAPR_MAGIC (0x45504150)
#define BINARY_DEVICE_TREE_FILE "mpc8544ds.dtb"
-#define UIMAGE_LOAD_BASE 0
#define DTC_LOAD_PAD 0x1800000
#define DTC_PAD_MASK 0xFFFFF
#define DTB_MAX_SIZE (8 * 1024 * 1024)
@@ -128,6 +127,8 @@ static int ppce500_load_device_tree(MachineState *machine,
hwaddr addr,
hwaddr initrd_base,
hwaddr initrd_size,
+ hwaddr kernel_base,
+ hwaddr kernel_size,
bool dry_run)
{
CPUPPCState *env = first_cpu->env_ptr;
@@ -204,6 +205,13 @@ static int ppce500_load_device_tree(MachineState *machine,
if (ret < 0) {
fprintf(stderr, "couldn't set /chosen/linux,initrd-end\n");
}
+
+ }
+
+ if (kernel_base != -1ULL) {
+ qemu_fdt_setprop_cells(fdt, "/chosen", "qemu,boot-kernel",
+ kernel_base >> 32, kernel_base,
+ kernel_size >> 32, kernel_size);
}
ret = qemu_fdt_setprop_string(fdt, "/chosen", "bootargs",
@@ -392,20 +400,25 @@ typedef struct DeviceTreeParams {
hwaddr addr;
hwaddr initrd_base;
hwaddr initrd_size;
+ hwaddr kernel_base;
+ hwaddr kernel_size;
} DeviceTreeParams;
static void ppce500_reset_device_tree(void *opaque)
{
DeviceTreeParams *p = opaque;
ppce500_load_device_tree(p->machine, &p->params, p->addr, p->initrd_base,
- p->initrd_size, false);
+ p->initrd_size, p->kernel_base, p->kernel_size,
+ false);
}
static int ppce500_prep_device_tree(MachineState *machine,
PPCE500Params *params,
hwaddr addr,
hwaddr initrd_base,
- hwaddr initrd_size)
+ hwaddr initrd_size,
+ hwaddr kernel_base,
+ hwaddr kernel_size)
{
DeviceTreeParams *p = g_new(DeviceTreeParams, 1);
p->machine = machine;
@@ -413,12 +426,15 @@ static int ppce500_prep_device_tree(MachineState *machine,
p->addr = addr;
p->initrd_base = initrd_base;
p->initrd_size = initrd_size;
+ p->kernel_base = kernel_base;
+ p->kernel_size = kernel_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(machine, params, addr, initrd_base,
- initrd_size, true);
+ initrd_size, kernel_base, kernel_size,
+ true);
}
/* Create -kernel TLB entries for BookE. */
@@ -603,17 +619,22 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
MemoryRegion *ram = g_new(MemoryRegion, 1);
PCIBus *pci_bus;
CPUPPCState *env = NULL;
- uint64_t elf_entry;
- uint64_t elf_lowaddr;
- hwaddr entry=0;
- hwaddr loadaddr=UIMAGE_LOAD_BASE;
- target_long kernel_size=0;
- target_ulong dt_base = 0;
- target_ulong initrd_base = 0;
- target_long initrd_size = 0;
- target_ulong cur_base = 0;
+ uint64_t loadaddr;
+ hwaddr kernel_base = -1LL;
+ int kernel_size = 0;
+ hwaddr dt_base = 0;
+ hwaddr initrd_base = 0;
+ int initrd_size = 0;
+ hwaddr cur_base = 0;
+ char *filename;
+ hwaddr bios_entry = 0;
+ target_long bios_size;
+ struct boot_info *boot_info;
+ int dt_size;
int i;
- unsigned int pci_irq_nrs[4] = {1, 2, 3, 4};
+ /* irq num for pin INTA, INTB, INTC and INTD is 1, 2, 3 and
+ * 4 respectively */
+ unsigned int pci_irq_nrs[PCI_NUM_PINS] = {1, 2, 3, 4};
qemu_irq **irqs, *mpic;
DeviceState *dev;
CPUPPCState *firstenv = NULL;
@@ -713,12 +734,13 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
/* PCI */
dev = qdev_create(NULL, "e500-pcihost");
qdev_prop_set_uint32(dev, "first_slot", params->pci_first_slot);
+ qdev_prop_set_uint32(dev, "first_pin_irq", pci_irq_nrs[0]);
qdev_init_nofail(dev);
s = SYS_BUS_DEVICE(dev);
- sysbus_connect_irq(s, 0, mpic[pci_irq_nrs[0]]);
- sysbus_connect_irq(s, 1, mpic[pci_irq_nrs[1]]);
- sysbus_connect_irq(s, 2, mpic[pci_irq_nrs[2]]);
- sysbus_connect_irq(s, 3, mpic[pci_irq_nrs[3]]);
+ for (i = 0; i < PCI_NUM_PINS; i++) {
+ sysbus_connect_irq(s, i, mpic[pci_irq_nrs[i]]);
+ }
+
memory_region_add_subregion(ccsr_addr_space, MPC8544_PCI_REGS_OFFSET,
sysbus_mmio_get_region(s, 0));
@@ -738,29 +760,24 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
/* Register spinning region */
sysbus_create_simple("e500-spin", MPC8544_SPIN_BASE, NULL);
+ if (cur_base < (32 * 1024 * 1024)) {
+ /* u-boot occupies memory up to 32MB, so load blobs above */
+ cur_base = (32 * 1024 * 1024);
+ }
+
/* Load kernel. */
if (machine->kernel_filename) {
- kernel_size = load_uimage(machine->kernel_filename, &entry,
- &loadaddr, NULL);
- if (kernel_size < 0) {
- kernel_size = load_elf(machine->kernel_filename, NULL, NULL,
- &elf_entry, &elf_lowaddr, NULL, 1,
- ELF_MACHINE, 0);
- entry = elf_entry;
- loadaddr = elf_lowaddr;
- }
- /* XXX try again as binary */
+ kernel_base = cur_base;
+ kernel_size = load_image_targphys(machine->kernel_filename,
+ cur_base,
+ ram_size - cur_base);
if (kernel_size < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
machine->kernel_filename);
exit(1);
}
- cur_base = loadaddr + kernel_size;
-
- /* Reserve space for dtb */
- dt_base = (cur_base + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
- cur_base += DTB_MAX_SIZE;
+ cur_base += kernel_size;
}
/* Load initrd. */
@@ -778,24 +795,60 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
cur_base = initrd_base + initrd_size;
}
- /* If we're loading a kernel directly, we must load the device tree too. */
- if (machine->kernel_filename) {
- struct boot_info *boot_info;
- int dt_size;
-
- dt_size = ppce500_prep_device_tree(machine, params, dt_base,
- initrd_base, initrd_size);
- if (dt_size < 0) {
- fprintf(stderr, "couldn't load device tree\n");
+ /*
+ * Smart firmware defaults ahead!
+ *
+ * We follow the following table to select which payload we execute.
+ *
+ * -kernel | -bios | payload
+ * ---------+-------+---------
+ * N | Y | u-boot
+ * N | N | u-boot
+ * Y | Y | u-boot
+ * Y | N | kernel
+ *
+ * This ensures backwards compatibility with how we used to expose
+ * -kernel to users but allows them to run through u-boot as well.
+ */
+ if (bios_name == NULL) {
+ if (machine->kernel_filename) {
+ bios_name = machine->kernel_filename;
+ } else {
+ bios_name = "u-boot.e500";
+ }
+ }
+ filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
+
+ bios_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
+ 1, ELF_MACHINE, 0);
+ if (bios_size < 0) {
+ /*
+ * Hrm. No ELF image? Try a uImage, maybe someone is giving us an
+ * ePAPR compliant kernel
+ */
+ kernel_size = load_uimage(filename, &bios_entry, &loadaddr, NULL);
+ if (kernel_size < 0) {
+ fprintf(stderr, "qemu: could not load firmware '%s'\n", filename);
exit(1);
}
- assert(dt_size < DTB_MAX_SIZE);
+ }
- boot_info = env->load_info;
- boot_info->entry = entry;
- boot_info->dt_base = dt_base;
- boot_info->dt_size = dt_size;
+ /* Reserve space for dtb */
+ dt_base = (loadaddr + bios_size + DTC_LOAD_PAD) & ~DTC_PAD_MASK;
+
+ dt_size = ppce500_prep_device_tree(machine, params, dt_base,
+ initrd_base, initrd_size,
+ kernel_base, kernel_size);
+ if (dt_size < 0) {
+ fprintf(stderr, "couldn't load device tree\n");
+ exit(1);
}
+ assert(dt_size < DTB_MAX_SIZE);
+
+ boot_info = env->load_info;
+ boot_info->entry = bios_entry;
+ boot_info->dt_base = dt_base;
+ boot_info->dt_size = dt_size;
if (kvm_enabled()) {
kvmppc_init();