qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] Re: [PATCH 27/27] Add SLOF-based partition firmware for pSe


From: Alexander Graf
Subject: [Qemu-devel] Re: [PATCH 27/27] Add SLOF-based partition firmware for pSeries machine, allowing more boot options
Date: Mon, 28 Mar 2011 12:30:58 +0200

On 25.03.2011, at 04:21, David Gibson wrote:

> 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 <address@hidden>
> Signed-off-by: Paul Mackerras <address@hidden>
> Signed-off-by: David Gibson <address@hidden>
> ---
> Makefile         |    2 +-
> hw/spapr.c       |   35 +++++++++++++++++++++---
> hw/spapr_rtas.c  |   78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> pc-bios/README   |    5 +++
> pc-bios/slof.bin |  Bin 0 -> 579072 bytes
> 5 files changed, 115 insertions(+), 5 deletions(-)
> create mode 100644 pc-bios/slof.bin
> 
> diff --git a/Makefile b/Makefile
> index e0b3fea..989622b 100644
> --- a/Makefile
> +++ b/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
> diff --git a/hw/spapr.c b/hw/spapr.c
> index 9d611a7..c6454e6 100644
> --- a/hw/spapr.c
> +++ b/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
> 
> @@ -56,6 +60,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,
> @@ -104,6 +109,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)));
> 
> @@ -260,7 +266,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

Is this a line removal?


Alex




reply via email to

[Prev in Thread] Current Thread [Next in Thread]