mirror of
https://github.com/qemu/qemu.git
synced 2024-11-30 15:23:34 +08:00
Add SLOF-based partition firmware for pSeries machine, allowing more boot options
Currently, the emulated pSeries machine requires the use of the -kernel parameter in order to explicitly load a guest kernel. This means booting from the virtual disk, cdrom or network is not possible. This patch addresses this limitation by inserting a within-partition firmware image (derived from the "SLOF" free Open Firmware project). If -kernel is not specified, qemu will now load the SLOF image, which has access to the qemu boot device list through the device tree, and can boot from any of the usual virtual devices. In order to support the new firmware, an extension to the emulated machine/hypervisor is necessary. Unlike Linux, which expects multi-CPU entry to be handled kexec() style, the SLOF firmware expects only one CPU to be active at entry, and to use a hypervisor RTAS method to enable the other CPUs one by one. This patch also implements this 'start-cpu' method, so that SLOF can start the secondary CPUs and marshal them into the kexec() holding pattern ready for entry into the guest OS. Linux should, and in the future might directly use the start-cpu method to enable initially disabled CPUs, but for now it does require kexec() entry. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: David Gibson <dwg@au1.ibm.com> Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
parent
ed120055c7
commit
a9f8ad8f2a
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -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
|
||||
|
2
Makefile
2
Makefile
@ -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
|
||||
|
33
hw/spapr.c
33
hw/spapr.c
@ -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");
|
||||
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 = {
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
BIN
pc-bios/slof.bin
Normal file
BIN
pc-bios/slof.bin
Normal file
Binary file not shown.
1
roms/SLOF
Submodule
1
roms/SLOF
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit d1d6b53b713a2b7c2c25685268fa932d28a4b4c0
|
Loading…
Reference in New Issue
Block a user