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.