From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37376) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Zzi02-0000mC-8d for qemu-devel@nongnu.org; Fri, 20 Nov 2015 04:29:01 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Zzhzy-0002h3-Vi for qemu-devel@nongnu.org; Fri, 20 Nov 2015 04:28:58 -0500 Date: Fri, 20 Nov 2015 19:21:58 +1100 From: David Gibson Message-ID: <20151120082158.GG7118@voom.redhat.com> References: <1447201710-10229-1-git-send-email-benh@kernel.crashing.org> <1447201710-10229-27-git-send-email-benh@kernel.crashing.org> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="sClP8c1IaQxyux9v" Content-Disposition: inline In-Reply-To: <1447201710-10229-27-git-send-email-benh@kernel.crashing.org> Subject: Re: [Qemu-devel] [Qemu-ppc] [PATCH 26/77] ppc/pnv: Add skeletton PowerNV platform List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Benjamin Herrenschmidt Cc: qemu-ppc@nongnu.org, qemu-devel@nongnu.org --sClP8c1IaQxyux9v Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Wed, Nov 11, 2015 at 11:27:39AM +1100, Benjamin Herrenschmidt wrote: > No devices yet, not even an interrupt controller, just to get > started. >=20 > Signed-off-by: Benjamin Herrenschmidt > --- > default-configs/ppc64-softmmu.mak | 1 + > hw/ppc/Makefile.objs | 2 + > hw/ppc/pnv.c | 600 ++++++++++++++++++++++++++++++++= ++++++ > include/hw/ppc/pnv.h | 36 +++ > 4 files changed, 639 insertions(+) > create mode 100644 hw/ppc/pnv.c > create mode 100644 include/hw/ppc/pnv.h Many of my comments below may be made irrelevant by later patches in the series. > diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-so= ftmmu.mak > index bb71b23..96574c8 100644 > --- a/default-configs/ppc64-softmmu.mak > +++ b/default-configs/ppc64-softmmu.mak > @@ -40,6 +40,7 @@ CONFIG_I8259=3Dy > CONFIG_XILINX=3Dy > CONFIG_XILINX_ETHLITE=3Dy > CONFIG_PSERIES=3Dy > +CONFIG_POWERNV=3Dy > CONFIG_PREP=3Dy > CONFIG_MAC=3Dy > CONFIG_E500=3Dy > diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs > index c1ffc77..cd74c96 100644 > --- a/hw/ppc/Makefile.objs > +++ b/hw/ppc/Makefile.objs > @@ -4,6 +4,8 @@ obj-y +=3D ppc.o ppc_booke.o > obj-$(CONFIG_PSERIES) +=3D spapr.o spapr_vio.o spapr_events.o > obj-$(CONFIG_PSERIES) +=3D spapr_hcall.o spapr_iommu.o spapr_rtas.o > obj-$(CONFIG_PSERIES) +=3D spapr_pci.o spapr_rtc.o spapr_drc.o spapr_rng= =2Eo > +# IBM PowerNV > +obj-$(CONFIG_POWERNV) +=3D pnv.o > ifeq ($(CONFIG_PCI)$(CONFIG_PSERIES)$(CONFIG_LINUX), yyy) > obj-y +=3D spapr_pci_vfio.o > endif > diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c > new file mode 100644 > index 0000000..e68c9b1 > --- /dev/null > +++ b/hw/ppc/pnv.c > @@ -0,0 +1,600 @@ > +/* > + * QEMU PowerPC PowerNV model > + * > + * 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 includ= ed in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRE= SS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILI= TY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHA= LL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR = OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISI= NG FROM, > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALING= S IN > + * THE SOFTWARE. > + * > + */ > +#include "sysemu/sysemu.h" > +#include "hw/hw.h" > +#include "hw/fw-path-provider.h" > +#include "elf.h" > +#include "net/net.h" > +#include "sysemu/block-backend.h" > +#include "sysemu/cpus.h" > +#include "sysemu/kvm.h" > +#include "sysemu/numa.h" > +#include "kvm_ppc.h" > +#include "mmu-hash64.h" > +#include "qom/cpu.h" > + > +#include "hw/boards.h" > +#include "hw/ppc/ppc.h" > +#include "hw/ppc/pnv.h" > +#include "hw/loader.h" > + > +#include "exec/address-spaces.h" > +#include "qemu/config-file.h" > +#include "qemu/error-report.h" > +#include "trace.h" > +#include "hw/nmi.h" > + > +#include "hw/compat.h" > + > +#include > + > +#define FDT_ADDR 0x01000000 > +#define FDT_MAX_SIZE 0x00100000 > +#define FW_MAX_SIZE 0x00400000 > +#define FW_FILE_NAME "skiboot.lid" > +#define KERNEL_FILE_NAME "skiroot.lid" > +#define KERNEL_LOAD_ADDR 0x20000000 > + > +#define TIMEBASE_FREQ 512000000ULL > + > +#define MAX_CPUS 255 > + > +#define PHANDLE_XICP 0x00001111 > + > +typedef struct sPowerNVMachineState sPowerNVMachineState; > + > +#define TYPE_POWERNV_MACHINE "powernv-machine" > +#define POWERNV_MACHINE(obj) \ > + OBJECT_CHECK(sPowerNVMachineState, (obj), TYPE_POWERNV_MACHINE) > + > +/** > + * sPowerNVMachineState: > + */ > +struct sPowerNVMachineState { > + /*< private >*/ > + MachineState parent_obj; > + PnvSystem sys; > +}; > + > +static size_t create_page_sizes_prop(CPUPPCState *env, uint32_t *prop, > + size_t maxsize) > +{ > + size_t maxcells =3D maxsize / sizeof(uint32_t); > + int i, j, count; > + uint32_t *p =3D prop; > + > + for (i =3D 0; i < PPC_PAGE_SIZES_MAX_SZ; i++) { > + struct ppc_one_seg_page_size *sps =3D &env->sps.sps[i]; > + > + if (!sps->page_shift) { > + break; > + } > + for (count =3D 0; count < PPC_PAGE_SIZES_MAX_SZ; count++) { > + if (sps->enc[count].page_shift =3D=3D 0) { > + break; > + } > + } > + if ((p - prop) >=3D (maxcells - 3 - count * 2)) { > + break; > + } > + *(p++) =3D cpu_to_be32(sps->page_shift); > + *(p++) =3D cpu_to_be32(sps->slb_enc); > + *(p++) =3D cpu_to_be32(count); > + for (j =3D 0; j < count; j++) { > + *(p++) =3D cpu_to_be32(sps->enc[j].page_shift); > + *(p++) =3D cpu_to_be32(sps->enc[j].pte_enc); > + } > + } > + > + return (p - prop) * sizeof(uint32_t); > +} > + > +#define _FDT(exp) \ > + do { \ > + int ret =3D (exp); \ > + if (ret < 0) { \ > + fprintf(stderr, "qemu: error creating device tree: %s: %s\n"= , \ > + #exp, fdt_strerror(ret)); \ > + exit(1); \ > + } \ > + } while (0) We should probably make a file where helper routines used by both spapr.c and pnv.c can live. > + > +static void powernv_populate_memory_node(void *fdt, int nodeid, hwaddr s= tart, > + hwaddr size) > +{ > + /* Probablly bogus, need to match with what's going on in CPU nodes = */ > + uint32_t chip_id[] =3D { > + cpu_to_be32(0x0), cpu_to_be32(nodeid) > + }; > + char *mem_name; > + uint64_t mem_reg_property[2]; > + > + mem_reg_property[0] =3D cpu_to_be64(start); > + mem_reg_property[1] =3D cpu_to_be64(size); > + > + mem_name =3D g_strdup_printf("memory@"TARGET_FMT_lx, start); > + _FDT((fdt_begin_node(fdt, mem_name))); > + g_free(mem_name); > + _FDT((fdt_property_string(fdt, "device_type", "memory"))); > + _FDT((fdt_property(fdt, "reg", mem_reg_property, > + sizeof(mem_reg_property)))); > + _FDT((fdt_property(fdt, "ibm,chip-id", chip_id, sizeof(chip_id)))); > + _FDT((fdt_end_node(fdt))); > +} > + > +static int powernv_populate_memory(void *fdt) > +{ > + hwaddr mem_start, node_size; > + int i, nb_nodes =3D nb_numa_nodes; > + NodeInfo *nodes =3D numa_info; > + NodeInfo ramnode; > + > + /* No NUMA nodes, assume there is just one node with whole RAM */ > + if (!nb_numa_nodes) { > + nb_nodes =3D 1; > + ramnode.node_mem =3D ram_size; > + nodes =3D &ramnode; > + } > + > + for (i =3D 0, mem_start =3D 0; i < nb_nodes; ++i) { > + if (!nodes[i].node_mem) { > + continue; > + } > + if (mem_start >=3D ram_size) { > + node_size =3D 0; > + } else { > + node_size =3D nodes[i].node_mem; > + if (node_size > ram_size - mem_start) { > + node_size =3D ram_size - mem_start; > + } > + } > + for ( ; node_size; ) { > + hwaddr sizetmp =3D pow2floor(node_size); > + > + /* mem_start !=3D 0 here */ > + if (ctzl(mem_start) < ctzl(sizetmp)) { > + sizetmp =3D 1ULL << ctzl(mem_start); > + } > + > + powernv_populate_memory_node(fdt, i, mem_start, sizetmp); > + node_size -=3D sizetmp; > + mem_start +=3D sizetmp; > + } > + } > + > + return 0; > +} > + > +static void powernv_create_cpu_node(void *fdt, CPUState *cs, int smt_thr= eads) > +{ > + PowerPCCPU *cpu =3D POWERPC_CPU(cs); > + CPUPPCState *env =3D &cpu->env; > + DeviceClass *dc =3D DEVICE_GET_CLASS(cs); > + PowerPCCPUClass *pcc =3D POWERPC_CPU_GET_CLASS(cs); > + uint32_t servers_prop[smt_threads]; > + uint32_t gservers_prop[smt_threads * 2]; > + int i, index =3D ppc_get_vcpu_dt_id(cpu); > + uint32_t segs[] =3D {cpu_to_be32(28), cpu_to_be32(40), > + 0xffffffff, 0xffffffff}; > + uint32_t tbfreq =3D kvm_enabled() ? kvmppc_get_tbfreq() : TIMEBASE_F= REQ; > + uint32_t cpufreq =3D kvm_enabled() ? kvmppc_get_clockfreq() : 100000= 0000; > + uint32_t page_sizes_prop[64]; > + size_t page_sizes_prop_size; > + char *nodename; > + > + if ((index % smt_threads) !=3D 0) { > + return; > + } > + > + nodename =3D g_strdup_printf("%s@%x", dc->fw_name, index); > + > + _FDT((fdt_begin_node(fdt, nodename))); > + > + g_free(nodename); > + > + _FDT((fdt_property_cell(fdt, "reg", index))); > + _FDT((fdt_property_string(fdt, "device_type", "cpu"))); > + > + _FDT((fdt_property_cell(fdt, "cpu-version", env->spr[SPR_PVR]))); > + _FDT((fdt_property_cell(fdt, "d-cache-block-size", > + env->dcache_line_size))); > + _FDT((fdt_property_cell(fdt, "d-cache-line-size", > + env->dcache_line_size))); > + _FDT((fdt_property_cell(fdt, "i-cache-block-size", > + env->icache_line_size))); > + _FDT((fdt_property_cell(fdt, "i-cache-line-size", > + env->icache_line_size))); > + > + if (pcc->l1_dcache_size) { > + _FDT((fdt_property_cell(fdt, "d-cache-size", pcc->l1_dcache_size= ))); > + } else { > + fprintf(stderr, "Warning: Unknown L1 dcache size for cpu\n"); Hmm (note to self) should probably change a bunch of these both in spapr.c and pnv.c from explicit fprintfs() to modern error_report() and similar. > + } > + if (pcc->l1_icache_size) { > + _FDT((fdt_property_cell(fdt, "i-cache-size", pcc->l1_icache_size= ))); > + } else { > + fprintf(stderr, "Warning: Unknown L1 icache size for cpu\n"); > + } > + > + _FDT((fdt_property_cell(fdt, "timebase-frequency", tbfreq))); > + _FDT((fdt_property_cell(fdt, "clock-frequency", cpufreq))); > + _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 (env->spr_cb[SPR_PURR].oea_read) { > + _FDT((fdt_property(fdt, "ibm,purr", NULL, 0))); > + } > + > + if (env->mmu_model & POWERPC_MMU_1TSEG) { > + _FDT((fdt_property(fdt, "ibm,processor-segment-sizes", > + segs, sizeof(segs)))); > + } > + > + /* Advertise VMX/VSX (vector extensions) if available > + * 0 / no property =3D=3D no vector extensions > + * 1 =3D=3D VMX / Altivec available > + * 2 =3D=3D VSX available */ > + if (env->insns_flags & PPC_ALTIVEC) { > + uint32_t vmx =3D (env->insns_flags2 & PPC2_VSX) ? 2 : 1; > + > + _FDT((fdt_property_cell(fdt, "ibm,vmx", vmx))); > + } > + > + /* Advertise DFP (Decimal Floating Point) if available > + * 0 / no property =3D=3D no DFP > + * 1 =3D=3D DFP available */ > + if (env->insns_flags2 & PPC2_DFP) { > + _FDT((fdt_property_cell(fdt, "ibm,dfp", 1))); > + } > + > + page_sizes_prop_size =3D create_page_sizes_prop(env, page_sizes_prop, > + sizeof(page_sizes_prop= )); > + if (page_sizes_prop_size) { > + _FDT((fdt_property(fdt, "ibm,segment-page-sizes", > + page_sizes_prop, page_sizes_prop_size))); > + } > + > + /* XXX Just a hack for now */ > + _FDT((fdt_property_cell(fdt, "ibm,chip-id", 0))); > + > + if (cpu->cpu_version) { > + _FDT((fdt_property_cell(fdt, "cpu-version", cpu->cpu_version))); > + } > + > + /* Build interrupt servers and gservers properties */ > + for (i =3D 0; i < smt_threads; i++) { > + servers_prop[i] =3D cpu_to_be32(index + i); > + /* Hack, direct the group queues back to cpu 0 */ > + gservers_prop[i*2] =3D cpu_to_be32(index + i); > + gservers_prop[i*2 + 1] =3D 0; > + } > + _FDT((fdt_property(fdt, "ibm,ppc-interrupt-server#s", > + servers_prop, sizeof(servers_prop)))); > + _FDT((fdt_property(fdt, "ibm,ppc-interrupt-gserver#s", > + gservers_prop, sizeof(gservers_prop)))); > + > + _FDT((fdt_end_node(fdt))); > +} > + > +static void *powernv_create_fdt(PnvSystem *sys, uint32_t initrd_base, ui= nt32_t initrd_size) > +{ So.. does it make sense for qemu to create a device tree for powernv, rather than leaving it to Opal? > + void *fdt; > + CPUState *cs; > + int smt =3D kvmppc_smt_threads(); > + uint32_t start_prop =3D cpu_to_be32(initrd_base); > + uint32_t end_prop =3D cpu_to_be32(initrd_base + initrd_size); > + char *buf; > + const char plat_compat[] =3D "qemu,powernv\0ibm,powernv"; > + > + fdt =3D g_malloc0(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, "model", "IBM PowerNV (emulated by qe= mu)"))); > + _FDT((fdt_property(fdt, "compatible", plat_compat, sizeof(plat_compa= t)))); > + > + /* > + * Add info to guest to indentify which host is it being run on > + * and what is the uuid of the guest > + */ > + if (kvmppc_get_host_model(&buf)) { > + _FDT((fdt_property_string(fdt, "host-model", buf))); > + g_free(buf); > + } > + if (kvmppc_get_host_serial(&buf)) { > + _FDT((fdt_property_string(fdt, "host-serial", buf))); > + g_free(buf); > + } Since you're emulating a "bare metal" machine, surely the host properties aren't relevant here. > + > + buf =3D g_strdup_printf(UUID_FMT, qemu_uuid[0], qemu_uuid[1], > + qemu_uuid[2], qemu_uuid[3], qemu_uuid[4], > + qemu_uuid[5], qemu_uuid[6], qemu_uuid[7], > + qemu_uuid[8], qemu_uuid[9], qemu_uuid[10], > + qemu_uuid[11], qemu_uuid[12], qemu_uuid[13], > + qemu_uuid[14], qemu_uuid[15]); > + > + _FDT((fdt_property_string(fdt, "vm,uuid", buf))); > + g_free(buf); > + > + _FDT((fdt_begin_node(fdt, "chosen"))); > + _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))); > + > + _FDT((fdt_property_cell(fdt, "#address-cells", 0x2))); > + _FDT((fdt_property_cell(fdt, "#size-cells", 0x2))); > + > + /* cpus */ > + _FDT((fdt_begin_node(fdt, "cpus"))); > + _FDT((fdt_property_cell(fdt, "#address-cells", 0x1))); > + _FDT((fdt_property_cell(fdt, "#size-cells", 0x0))); > + > + CPU_FOREACH(cs) { > + powernv_create_cpu_node(fdt, cs, smt); > + } > + > + _FDT((fdt_end_node(fdt))); > + > + /* Memory */ > + _FDT((powernv_populate_memory(fdt))); > + > + /* /hypervisor node */ > + if (kvm_enabled()) { > + uint8_t hypercall[16]; > + > + /* indicate KVM hypercall interface */ > + _FDT((fdt_begin_node(fdt, "hypervisor"))); > + _FDT((fdt_property_string(fdt, "compatible", "linux,kvm"))); > + if (kvmppc_has_cap_fixup_hcalls()) { > + /* > + * Older KVM versions with older guest kernels were broken w= ith the > + * magic page, don't allow the guest to map it. > + */ > + kvmppc_get_hypercall(first_cpu->env_ptr, hypercall, > + sizeof(hypercall)); > + _FDT((fdt_property(fdt, "hcall-instructions", hypercall, > + sizeof(hypercall)))); > + } > + _FDT((fdt_end_node(fdt))); > + } And a hypercall interface surely doesn't make sense for powernv. > + > + _FDT((fdt_end_node(fdt))); /* close root node */ > + _FDT((fdt_finish(fdt))); > + > + return fdt; > +} > + > +static void powernv_cpu_reset(void *opaque) > +{ > + PowerPCCPU *cpu =3D opaque; > + CPUState *cs =3D CPU(cpu); > + CPUPPCState *env =3D &cpu->env; > + > + cpu_reset(cs); > + > + env->spr[SPR_PIR] =3D ppc_get_vcpu_dt_id(cpu); > + env->spr[SPR_HIOR] =3D 0; > + env->gpr[3] =3D FDT_ADDR; > + env->nip =3D 0x10; > + env->msr |=3D MSR_HVB; > +} So, I believe the qemu-ishly correct way of doing this is to have the cpu initialization in the cpu code, rather than the platform code, as much as possible. On PAPR we kind of get away with initialization in the platform code on the grounds that it's a paravirt platform, but powernv doesn't have that excuse. But this may well be stuff that changes in later patches, so.. > +static const VMStateDescription vmstate_powernv =3D { > + .name =3D "powernv", > + .version_id =3D 1, > + .minimum_version_id =3D 1, > +}; It might be best to leave out the vmstate entirely until you're ready to implement migration, rather than having a partial, probably not working migration implementation. > + > +static void pnv_create_chip(PnvSystem *sys, unsigned int chip_no) > +{ > + PnvChip *chip =3D &sys->chips[chip_no]; > + > + if (chip_no >=3D PNV_MAX_CHIPS) { > + return; > + } > + > + /* XXX Improve chip numbering to better match HW */ > + chip->chip_id =3D chip_no; I think modern qemu conventions would suggest creating the chips as QOM objects rather than having a fixed array. > +} > + > +static void ppc_powernv_init(MachineState *machine) > +{ > + ram_addr_t ram_size =3D machine->ram_size; > + const char *cpu_model =3D machine->cpu_model; > + const char *kernel_filename =3D machine->kernel_filename; > + const char *initrd_filename =3D machine->initrd_filename; > + uint32_t initrd_base =3D 0; > + long initrd_size =3D 0; > + PowerPCCPU *cpu; > + CPUPPCState *env; > + MemoryRegion *sysmem =3D get_system_memory(); > + MemoryRegion *ram =3D g_new(MemoryRegion, 1); > + sPowerNVMachineState *pnv_machine =3D POWERNV_MACHINE(machine); > + PnvSystem *sys =3D &pnv_machine->sys; > + long fw_size; > + char *filename; > + void *fdt; > + int i; > + > + /* init CPUs */ > + if (cpu_model =3D=3D NULL) { > + cpu_model =3D kvm_enabled() ? "host" : "POWER8"; > + } > + > + for (i =3D 0; i < smp_cpus; i++) { > + cpu =3D cpu_ppc_init(cpu_model); > + if (cpu =3D=3D NULL) { > + fprintf(stderr, "Unable to find PowerPC CPU definition\n"); > + exit(1); > + } > + env =3D &cpu->env; > + > + /* Set time-base frequency to 512 MHz */ > + cpu_ppc_tb_init(env, TIMEBASE_FREQ); > + > + /* MSR[IP] doesn't exist nowadays */ > + env->msr_mask &=3D ~(1 << 6); > + > + qemu_register_reset(powernv_cpu_reset, cpu); > + } > + > + /* allocate RAM */ > + memory_region_allocate_system_memory(ram, NULL, "ppc_powernv.ram", r= am_size); > + memory_region_add_subregion(sysmem, 0, ram); > + > + /* XXX We should decide how many chips to create based on #cores and > + * Venice vs. Murano vs. Naples chip type etc..., for now, just crea= te > + * one chip. Also creation of the CPUs should be done per-chip > + */ > + sys->num_chips =3D 1; > + > + /* Create only one PHB for now until I figure out what's wrong > + * when I create more (resource assignment failures in Linux) > + */ > + pnv_create_chip(sys, 0); > + > + if (bios_name =3D=3D NULL) { > + bios_name =3D FW_FILE_NAME; > + } > + filename =3D qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); > + fw_size =3D load_image_targphys(filename, 0, FW_MAX_SIZE); > + if (fw_size < 0) { > + hw_error("qemu: could not load OPAL '%s'\n", filename); > + exit(1); > + } > + g_free(filename); > + > + > + if (kernel_filename =3D=3D NULL) { > + kernel_filename =3D KERNEL_FILE_NAME; > + } > + filename =3D qemu_find_file(QEMU_FILE_TYPE_BIOS, > kernel_filename); The commit withe Opal image should go in before this, no? > + fw_size =3D load_image_targphys(filename, 0x20000000, 0x2000000); > + if (fw_size < 0) { > + hw_error("qemu: could not load kernel'%s'\n", filename); > + exit(1); > + } > + g_free(filename); > + > + /* load initrd */ > + if (initrd_filename) { > + /* Try to locate the initrd in the gap between the kernel > + * and the firmware. Add a bit of space just in case > + */ > + initrd_base =3D 0x40000000; > + initrd_size =3D load_image_targphys(initrd_filename, initrd_= base, > + 0x10000000); // 128MB max > + if (initrd_size < 0) { > + fprintf(stderr, "qemu: could not load initial ram di= sk '%s'\n", > + initrd_filename); > + exit(1); > + } > + } else { > + initrd_base =3D 0; > + initrd_size =3D 0; > + } > + fdt =3D powernv_create_fdt(sys, initrd_base, initrd_size); > + cpu_physical_memory_write(FDT_ADDR, fdt, fdt_totalsize(fdt)); > +} > + > +static int powernv_kvm_type(const char *vm_type) > +{ > + /* Always force PR KVM */ > + return 2; > +} > + > +static void ppc_cpu_do_nmi_on_cpu(void *arg) > +{ > + CPUState *cs =3D arg; > + > + cpu_synchronize_state(cs); > + ppc_cpu_do_system_reset(cs); > +} > + > +static void powernv_nmi(NMIState *n, int cpu_index, Error **errp) > +{ > + CPUState *cs; > + > + CPU_FOREACH(cs) { > + async_run_on_cpu(cs, ppc_cpu_do_nmi_on_cpu, cs); > + } > +} > + > +static void powernv_machine_class_init(ObjectClass *oc, void *data) > +{ > + MachineClass *mc =3D MACHINE_CLASS(oc); > + NMIClass *nc =3D NMI_CLASS(oc); > + > + mc->init =3D ppc_powernv_init; > + mc->block_default_type =3D IF_SCSI; > + mc->max_cpus =3D MAX_CPUS; > + mc->no_parallel =3D 1; > + mc->default_boot_order =3D NULL; > + mc->kvm_type =3D powernv_kvm_type; > + > + nc->nmi_monitor_handler =3D powernv_nmi; > +} > + > +static const TypeInfo powernv_machine_info =3D { > + .name =3D TYPE_POWERNV_MACHINE, > + .parent =3D TYPE_MACHINE, > + .abstract =3D true, > + .instance_size =3D sizeof(sPowerNVMachineState), > + .class_init =3D powernv_machine_class_init, > + .interfaces =3D (InterfaceInfo[]) { > + { TYPE_NMI }, > + { } > + }, > +}; > + > +static void powernv_machine_2_5_class_init(ObjectClass *oc, void *data) > +{ > + MachineClass *mc =3D MACHINE_CLASS(oc); > + > + mc->name =3D "powernv-2.5"; > + mc->desc =3D "PowerNV v2.5"; > + mc->alias =3D "powernv"; > +} > + > +static const TypeInfo powernv_machine_2_5_info =3D { > + .name =3D MACHINE_TYPE_NAME("powernv-2.5"), > + .parent =3D TYPE_POWERNV_MACHINE, > + .class_init =3D powernv_machine_2_5_class_init, > +}; > + > +static void powernv_machine_register_types(void) > +{ > + type_register_static(&powernv_machine_info); > + type_register_static(&powernv_machine_2_5_info); > +} > + > +type_init(powernv_machine_register_types) > diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h > new file mode 100644 > index 0000000..9a48c16 > --- /dev/null > +++ b/include/hw/ppc/pnv.h > @@ -0,0 +1,36 @@ > +#ifndef _HW_LPC_H > +#define _HW_LPC_H > +/* > + * QEMU PowerNV various definitions > + * > + * Copyright (c) 2014 BenH > + * > + * This library is free software; you can redistribute it and/or > + * modify it under the terms of the GNU Lesser General Public > + * License as published by the Free Software Foundation; either > + * version 2 of the License, or (at your option) any later version. > + * > + * This library is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU > + * Lesser General Public License for more details. > + * > + * You should have received a copy of the GNU Lesser General Public > + * License along with this library; if not, see . > + */ > + > +#include "hw/hw.h" > + > +/* Should we turn that into a QOjb of some sort ? */ > +typedef struct PnvChip { > + uint32_t chip_id; > +} PnvChip; > + > +typedef struct PnvSystem { > + uint32_t num_chips; > +#define PNV_MAX_CHIPS 1 > + PnvChip chips[PNV_MAX_CHIPS]; > +} PnvSystem; > + > +#endif /* _HW_PNV_LPC_H */ > + --=20 David Gibson | I'll have my music baroque, and my code david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_ | _way_ _around_! http://www.ozlabs.org/~dgibson --sClP8c1IaQxyux9v Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAEBAgAGBQJWTtgmAAoJEGw4ysog2bOSauMP/ihcQSqVzblcf/BbUHGyYPEH U5utr3GDKulVkw145W46nhMm4zsaQLI2194T85gM+Hdqpx37C3yQWZSD/taerl0+ RvzosAPi9tqPPuFT2O1IpKha5gnsLXwM0UYw5C7sYZq1gJPwfobbdGZ50Tywwy6G vK/3ZAeLB5HiPG7VXywLWmezTti9kSJFlogUj8XxZvKBX45fiGX7DDlnmyjr9OCx FGou7/tp39kcetNlADRjPbU/M36+GLw1qZ2oExWu3JQnQpgQM/b8pxG8iYcaxKLQ rt4D23OlSceDCMga2zlNjNWgpN/nX/MNRNefRVjGSX0cxkFx/UmuzBldsVbG2Atz EDWfiolK8TrAOlqtM6uX39jW1Fy5sSGOChe4qhtdfF+I3Dh1UEbNScW3run0csrX SxZnYmvlhbo8XveiKyfUNkMrOH758+00+za22wX8aQkZOzAaUeZLqiXKvnVMBzja 0ybZccz4nZKVkNBYSnT6QWeOKDZGIK+kENFV+hGTQRfUZZ/yCgXCxaBy28rrh0oh F4rqGaJGEParfG6hSEaQWXWJXwrfpAFSYhQt50SKwxMBEo2kwNVM0JluAxdRgFUr r3fBsO5UJnaKSgtaXF874+1mXxXokniASifmFLOAvo2sbhr9lrR9LHAoO2h6XvJH WMiwbNDv5ock9CEnArAv =YgKv -----END PGP SIGNATURE----- --sClP8c1IaQxyux9v--