diff options
-rw-r--r-- | .gitmodules | 3 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | hw/spapr.c | 35 | ||||
-rw-r--r-- | hw/spapr_rtas.c | 78 | ||||
-rw-r--r-- | pc-bios/README | 5 | ||||
-rw-r--r-- | pc-bios/slof.bin | bin | 0 -> 579072 bytes | |||
m--------- | roms/SLOF | 0 |
7 files changed, 118 insertions, 5 deletions
diff --git a/.gitmodules b/.gitmodules index 5217ce7..44fdd1a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "roms/seabios"] path = roms/seabios url = git://git.qemu.org/seabios.git/ +[submodule "roms/SLOF"] + path = roms/SLOF + url = git://git.qemu.org/SLOF.git @@ -214,7 +214,7 @@ pxe-rtl8139.bin pxe-virtio.bin \ bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \ multiboot.bin linuxboot.bin \ s390-zipl.rom \ -spapr-rtas.bin +spapr-rtas.bin slof.bin else BLOBS= endif @@ -44,6 +44,10 @@ #define INITRD_LOAD_ADDR 0x02800000 #define FDT_MAX_SIZE 0x10000 #define RTAS_MAX_SIZE 0x10000 +#define FW_MAX_SIZE 0x400000 +#define FW_FILE_NAME "slof.bin" + +#define MIN_RAM_SLOF 512UL #define TIMEBASE_FREQ 512000000ULL @@ -57,6 +61,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, sPAPREnvironment *spapr, target_phys_addr_t initrd_base, target_phys_addr_t initrd_size, + const char *boot_device, const char *kernel_cmdline, target_phys_addr_t rtas_addr, target_phys_addr_t rtas_size, @@ -105,6 +110,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, &start_prop, sizeof(start_prop)))); _FDT((fdt_property(fdt, "linux,initrd-end", &end_prop, sizeof(end_prop)))); + _FDT((fdt_property_string(fdt, "qemu,boot-device", boot_device))); _FDT((fdt_end_node(fdt))); @@ -261,7 +267,7 @@ static void ppc_spapr_init(ram_addr_t ram_size, ram_addr_t ram_offset; target_phys_addr_t fdt_addr, rtas_addr; uint32_t kernel_base, initrd_base; - long kernel_size, initrd_size, htab_size, rtas_size; + long kernel_size, initrd_size, htab_size, rtas_size, fw_size; long pteg_shift = 17; int fdt_size; char *filename; @@ -392,13 +398,33 @@ static void ppc_spapr_init(ram_addr_t ram_size, initrd_size = 0; } } else { - fprintf(stderr, "pSeries machine needs -kernel for now"); - exit(1); + if (ram_size < (MIN_RAM_SLOF << 20)) { + fprintf(stderr, "qemu: pSeries SLOF firmware requires >= " + "%ldM guest RAM\n", MIN_RAM_SLOF); + exit(1); + } + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "slof.bin"); + fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE); + if (fw_size < 0) { + hw_error("qemu: could not load LPAR rtas '%s'\n", filename); + exit(1); + } + qemu_free(filename); + kernel_base = 0x100; + initrd_base = 0; + initrd_size = 0; + + /* SLOF will startup the secondary CPUs using RTAS, + rather than expecting a kexec() style entry */ + for (i = 0; i < smp_cpus; i++) { + envs[i]->halted = 1; + } } /* Prepare the device tree */ fdt = spapr_create_fdt(&fdt_size, ram_size, cpu_model, envs, spapr, - initrd_base, initrd_size, kernel_cmdline, + initrd_base, initrd_size, + boot_device, kernel_cmdline, rtas_addr, rtas_size, pteg_shift + 7); assert(fdt != NULL); @@ -409,6 +435,7 @@ static void ppc_spapr_init(ram_addr_t ram_size, envs[0]->gpr[3] = fdt_addr; envs[0]->gpr[5] = 0; envs[0]->hreset_vector = kernel_base; + envs[0]->halted = 0; } static QEMUMachine spapr_machine = { diff --git a/hw/spapr_rtas.c b/hw/spapr_rtas.c index 7226853..16b6542 100644 --- a/hw/spapr_rtas.c +++ b/hw/spapr_rtas.c @@ -90,6 +90,81 @@ static void rtas_power_off(sPAPREnvironment *spapr, rtas_st(rets, 0, 0); } +static void rtas_query_cpu_stopped_state(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + target_ulong id; + CPUState *env; + + if (nargs != 1 || nret != 2) { + rtas_st(rets, 0, -3); + return; + } + + id = rtas_ld(args, 0); + for (env = first_cpu; env; env = env->next_cpu) { + if (env->cpu_index != id) { + continue; + } + + if (env->halted) { + rtas_st(rets, 1, 0); + } else { + rtas_st(rets, 1, 2); + } + + rtas_st(rets, 0, 0); + return; + } + + /* Didn't find a matching cpu */ + rtas_st(rets, 0, -3); +} + +static void rtas_start_cpu(sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, + uint32_t nret, target_ulong rets) +{ + target_ulong id, start, r3; + CPUState *env; + + if (nargs != 3 || nret != 1) { + rtas_st(rets, 0, -3); + return; + } + + id = rtas_ld(args, 0); + start = rtas_ld(args, 1); + r3 = rtas_ld(args, 2); + + for (env = first_cpu; env; env = env->next_cpu) { + if (env->cpu_index != id) { + continue; + } + + if (!env->halted) { + rtas_st(rets, 0, -1); + return; + } + + env->msr = (1ULL << MSR_SF) | (1ULL << MSR_ME); + env->nip = start; + env->gpr[3] = r3; + env->halted = 0; + + qemu_cpu_kick(env); + + rtas_st(rets, 0, 0); + return; + } + + /* Didn't find a matching cpu */ + rtas_st(rets, 0, -3); +} + static struct rtas_call { const char *name; spapr_rtas_fn fn; @@ -196,5 +271,8 @@ static void register_core_rtas(void) spapr_rtas_register("display-character", rtas_display_character); spapr_rtas_register("get-time-of-day", rtas_get_time_of_day); spapr_rtas_register("power-off", rtas_power_off); + spapr_rtas_register("query-cpu-stopped-state", + rtas_query_cpu_stopped_state); + spapr_rtas_register("start-cpu", rtas_start_cpu); } device_init(register_core_rtas); diff --git a/pc-bios/README b/pc-bios/README index 3fc0944..646a31a 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -13,6 +13,11 @@ The included image for PowerPC (for 32 and 64 bit PPC CPUs), Sparc32 and Sparc64 are built from OpenBIOS SVN revision 1018. +- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware + implementation for certain IBM POWER hardware. The sources are at + https://github.com/dgibson/SLOF, and the image currently in qemu is + built from git tag qemu-slof-20110323. + - The PXE roms come from Rom-o-Matic gPXE 0.9.9 with BANNER_TIMEOUT=0 e1000 8086:100E diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin Binary files differnew file mode 100644 index 0000000..22c4c7f --- /dev/null +++ b/pc-bios/slof.bin diff --git a/roms/SLOF b/roms/SLOF new file mode 160000 +Subproject d1d6b53b713a2b7c2c25685268fa932d28a4b4c |