On Sat, Feb 12, 2011 at 6:23 PM, Alexander Graf <ag...@suse.de> wrote:
>
> On 12.02.2011, at 15:54, David Gibson wrote:
>
>> This patch adds a "pseries" machine to qemu.  This aims to emulate a
>> logical partition on an IBM pSeries machine, compliant to the
>> "PowerPC Architecture Platform Requirements" (PAPR) document.
>>
>> This initial version is quite limited, it implements a basic machine
>> and PAPR hypercall emulation.  So far only one hypercall is present -
>> H_PUT_TERM_CHAR - so that a (write-only) console is available.
>>
>> The machine so far more resembles an old POWER4 style "full system
>> partition" rather than a modern LPAR, in that the guest manages the
>> page tables directly, rather than via hypercalls.
>>
>> The machine requires qemu to be configured with --enable-fdt.  The
>> machine can (so far) only be booted with -kernel - i.e. no partition
>> firmware is provided.
>>
>> Signed-off-by: David Gibson <d...@au1.ibm.com>
>> ---
>> Makefile.target  |    2 +
>> hw/spapr.c       |  279 
>> ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>> hw/spapr.h       |  240 ++++++++++++++++++++++++++++++++++++++++++++++
>> hw/spapr_hcall.c |   40 ++++++++
>> 4 files changed, 561 insertions(+), 0 deletions(-)
>> create mode 100644 hw/spapr.c
>> create mode 100644 hw/spapr.h
>> create mode 100644 hw/spapr_hcall.c
>>
>> diff --git a/Makefile.target b/Makefile.target
>> index 48e6c00..e0796ba 100644
>> --- a/Makefile.target
>> +++ b/Makefile.target
>> @@ -231,6 +231,8 @@ obj-ppc-y += ppc_prep.o
>> obj-ppc-y += ppc_oldworld.o
>> # NewWorld PowerMac
>> obj-ppc-y += ppc_newworld.o
>> +# IBM pSeries (sPAPR)
>> +obj-ppc-y += spapr.o spapr_hcall.o
>> # PowerPC 4xx boards
>> obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o
>> obj-ppc-y += ppc440.o ppc440_bamboo.o
>> diff --git a/hw/spapr.c b/hw/spapr.c
>> new file mode 100644
>> index 0000000..8aca4e0
>> --- /dev/null
>> +++ b/hw/spapr.c
>> @@ -0,0 +1,279 @@
>> +/*
>> + * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System 
>> Emulator
>> + *
>> + * Copyright (c) 2004-2007 Fabrice Bellard
>> + * Copyright (c) 2007 Jocelyn Mayer
>> + * Copyright (c) 2010 David Gibson, IBM Corporation.
>> + *
>> + * Permission is hereby granted, free of charge, to any person obtaining a 
>> copy
>> + * of this software and associated documentation files (the "Software"), to 
>> deal
>> + * in the Software without restriction, including without limitation the 
>> rights
>> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
>> + * copies of the Software, and to permit persons to whom the Software is
>> + * furnished to do so, subject to the following conditions:
>> + *
>> + * The above copyright notice and this permission notice shall be included 
>> in
>> + * all copies or substantial portions of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
>> OR
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 
>> OTHER
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
>> FROM,
>> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
>> + * THE SOFTWARE.
>> + *
>> + */
>> +#include "hw.h"
>> +#include "ppc.h"
>> +#include "pc.h"
>> +#include "sysemu.h"
>> +#include "boards.h"
>> +#include "fw_cfg.h"
>> +#include "loader.h"
>> +#include "elf.h"
>> +#include "kvm.h"
>> +#include "kvm_ppc.h"
>> +#include "net.h"
>> +#include "blockdev.h"
>> +#include "hw/spapr.h"
>> +
>> +#include <libfdt.h>
>> +
>> +#define KERNEL_LOAD_ADDR        0x00000000
>> +#define INITRD_LOAD_ADDR        0x02800000
>> +#define FDT_ADDR                0x0f000000
>> +#define FDT_MAX_SIZE            0x10000
>> +
>> +#define TIMEBASE_FREQ           512000000ULL
>> +
>> +static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
>> +                              const char *cpu_model, CPUState *envs[],
>> +                              target_phys_addr_t initrd_base,
>> +                              target_phys_addr_t initrd_size,
>> +                              const char *kernel_cmdline)
>> +{
>> +    void *fdt;
>> +    uint64_t mem_reg_property[] = { 0, cpu_to_be64(ramsize) };
>> +    uint32_t start_prop = cpu_to_be32(initrd_base);
>> +    uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
>> +    int i;
>> +    char *modelname;
>> +
>> +#define _FDT(exp) \
>> +    do { \
>> +        int ret = (exp);                                           \
>> +        if (ret < 0) {                                             \
>> +            hw_error("qemu: error creating device tree: %s: %s\n", \
>> +                     #exp, fdt_strerror(ret));                     \
>> +            return NULL;                                           \
>> +        }                                                          \
>> +    } while (0)
>> +
>> +    fdt = qemu_mallocz(FDT_MAX_SIZE);
>> +    _FDT((fdt_create(fdt, FDT_MAX_SIZE)));
>> +
>> +    _FDT((fdt_finish_reservemap(fdt)));
>> +
>> +    /* Root node */
>> +    _FDT((fdt_begin_node(fdt, "")));
>> +    _FDT((fdt_property_string(fdt, "device_type", "chrp")));
>> +    _FDT((fdt_property_string(fdt, "model", "qemu,emulated-pSeries-LPAR")));
>> +
>> +    _FDT((fdt_property_cell(fdt, "#address-cells", 0x2)));
>> +    _FDT((fdt_property_cell(fdt, "#size-cells", 0x2)));
>> +
>> +    /* /chosen */
>> +    _FDT((fdt_begin_node(fdt, "chosen")));
>> +
>> +    _FDT((fdt_property_string(fdt, "bootargs", kernel_cmdline)));
>> +    _FDT((fdt_property(fdt, "linux,initrd-start", &start_prop, 
>> sizeof(start_prop))));
>> +    _FDT((fdt_property(fdt, "linux,initrd-end", &end_prop, 
>> sizeof(end_prop))));
>> +
>> +    _FDT((fdt_end_node(fdt)));
>> +
>> +    /* memory node */
>> +    _FDT((fdt_begin_node(fdt, "memory@0")));
>> +
>> +    _FDT((fdt_property_string(fdt, "device_type", "memory")));
>> +    _FDT((fdt_property(fdt, "reg", mem_reg_property, 
>> sizeof(mem_reg_property))));
>> +
>> +    _FDT((fdt_end_node(fdt)));
>> +
>> +    /* cpus */
>> +    _FDT((fdt_begin_node(fdt, "cpus")));
>> +
>> +    _FDT((fdt_property_cell(fdt, "#address-cells", 0x1)));
>> +    _FDT((fdt_property_cell(fdt, "#size-cells", 0x0)));
>> +
>> +    modelname = qemu_strdup(cpu_model);
>> +
>> +    for (i = 0; i < strlen(modelname); i++)
>
> Braces
>
>> +        modelname[i] = toupper(modelname[i]);
>> +
>> +    for (i = 0; i < smp_cpus; i++) {
>> +        CPUState *env = envs[i];
>> +        char *nodename;
>> +        uint32_t segs[] = {cpu_to_be32(28), cpu_to_be32(40),
>> +                           0xffffffff, 0xffffffff};
>> +
>> +        if (asprintf(&nodename, "%s@%x", modelname, i) < 0) {
>> +            fprintf(stderr, "Allocation failure\n");
>> +            exit(1);
>> +        }
>> +
>> +        _FDT((fdt_begin_node(fdt, nodename)));
>> +
>> +        free(nodename);
>> +
>> +        _FDT((fdt_property_cell(fdt, "reg", i)));
>> +        _FDT((fdt_property_string(fdt, "device_type", "cpu")));
>> +
>> +        _FDT((fdt_property_cell(fdt, "cpu-version", env->spr[SPR_PVR])));
>> +        _FDT((fdt_property_cell(fdt, "dcache-block-size", 
>> env->dcache_line_size)));
>> +        _FDT((fdt_property_cell(fdt, "icache-block-size", 
>> env->icache_line_size)));
>> +        _FDT((fdt_property_cell(fdt, "timebase-frequency", TIMEBASE_FREQ)));
>> +        /* Hardcode CPU frequency for now.  It's kind of arbitrary on
>> +         * full emu, for kvm we should copy it from the host */
>> +        _FDT((fdt_property_cell(fdt, "clock-frequency", 1000000000)));
>> +        _FDT((fdt_property_cell(fdt, "ibm,slb-size", env->slb_nr)));
>> +        _FDT((fdt_property_string(fdt, "status", "okay")));
>> +        _FDT((fdt_property(fdt, "64-bit", NULL, 0)));
>> +
>> +        if (envs[i]->mmu_model & POWERPC_MMU_1TSEG)
>> +            _FDT((fdt_property(fdt, "ibm,processor-segment-sizes",
>> +                               segs, sizeof(segs))));
>> +
>> +        _FDT((fdt_end_node(fdt)));
>> +    }
>> +
>> +    qemu_free(modelname);
>> +
>> +    _FDT((fdt_end_node(fdt)));
>> +
>> +    _FDT((fdt_end_node(fdt))); /* close root node */
>> +    _FDT((fdt_finish(fdt)));
>> +
>> +    if (fdt_size)
>
> Braces
>
>> +        *fdt_size = fdt_totalsize(fdt);
>> +
>> +    return fdt;
>> +}
>> +
>> +static uint64_t translate_kernel_address(void *opaque, uint64_t addr)
>> +{
>> +    return (addr & 0x0fffffff) + KERNEL_LOAD_ADDR;
>> +}
>> +
>> +static void emulate_spapr_hypercall(CPUState *env, void *opaque)
>> +{
>> +    env->gpr[3] = spapr_hypercall(env, (sPAPREnvironment *)opaque,
>> +                                  env->gpr[3], &env->gpr[4]);
>> +}
>> +
>> +/* pSeries LPAR / sPAPR hardware init */
>> +static void ppc_spapr_init (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)
>> +{
>> +    CPUState *env = NULL;
>> +    void *fdt;
>> +    int i;
>> +    ram_addr_t ram_offset;
>> +    uint32_t kernel_base, initrd_base;
>> +    long kernel_size, initrd_size;
>> +    int fdt_size;
>> +    sPAPREnvironment *spapr;
>
> Not sure this complies with CODING_STYLE. I don't care - but Blue does care a 
> lot. So let's better ask him.

sPAPREnvironment has a certain aroma reminding of aHungarian
nNotation, but otherwise the bouquet is entirely passable.

Reply via email to