From 048706d971c1830d7813052ca027ae00c519e894 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Sep 2012 16:57:10 +0000 Subject: pseries: Fix and cleanup CPU initialization and reset MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current pseries machine init function iterates over the CPUs at several points, doing various bits of initialization. This is messy; these can and should be merged into a single iteration doing all the necessary per cpu initialization. Worse, some of these initializations were setting up state which should be set on every reset, not just at machine init time. A few of the initializations simply weren't necessary at all. This patch, therefore, moves those things that need to be to the per-cpu reset handler, and combines the remainder into two loops over the cpus (which also creates them). The second loop is for setting up hash table information, and will be removed in a subsequent patch also making other fixes to the hash table setup. This exposes a bug in our start-cpu RTAS routine (called by the guest to start up CPUs other than CPU0) under kvm. Previously, this function did not make a call to ensure that it's changes to the new cpu's state were pushed into KVM in-kernel state. We sort-of got away with this because some of the initializations had already placed the secondary CPUs into the right starting state for the sorts of Linux guests we've been running. Nonetheless the start-cpu RTAS call's behaviour was not correct and could easily have been broken by guest changes. This patch also fixes it. Signed-off-by: David Gibson Reviewed-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/spapr.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) (limited to 'hw/spapr.c') diff --git a/hw/spapr.c b/hw/spapr.c index c34b767c6e..d88525aadd 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -581,8 +581,16 @@ static void spapr_reset(void *opaque) static void spapr_cpu_reset(void *opaque) { PowerPCCPU *cpu = opaque; + CPUPPCState *env = &cpu->env; cpu_reset(CPU(cpu)); + + /* All CPUs start halted. CPU0 is unhalted from the machine level + * reset code and the rest are explicitly started up by the guest + * using an RTAS call */ + env->halted = 1; + + env->spr[SPR_HIOR] = 0; } /* Returns whether we want to use VGA or not */ @@ -665,11 +673,16 @@ static void ppc_spapr_init(ram_addr_t ram_size, /* Set time-base frequency to 512 MHz */ cpu_ppc_tb_init(env, TIMEBASE_FREQ); - qemu_register_reset(spapr_cpu_reset, cpu); - env->hreset_vector = 0x60; + /* PAPR always has exception vectors in RAM not ROM */ env->hreset_excp_prefix = 0; - env->gpr[3] = env->cpu_index; + + /* Tell KVM that we're in PAPR mode */ + if (kvm_enabled()) { + kvmppc_set_papr(env); + } + + qemu_register_reset(spapr_cpu_reset, cpu); } /* allocate RAM */ @@ -685,7 +698,10 @@ static void ppc_spapr_init(ram_addr_t ram_size, /* allocate hash page table. For now we always make this 16mb, * later we should probably make it scale to the size of guest - * RAM */ + * RAM. FIXME: setting the htab information in the CPU env really + * belongs at CPU reset time, but we can get away with it for now + * because the PAPR guest is not permitted to write SDR1 so in + * fact these settings will never change during the run */ spapr->htab_size = 1ULL << (pteg_shift + 7); spapr->htab = qemu_memalign(spapr->htab_size, spapr->htab_size); @@ -697,11 +713,6 @@ static void ppc_spapr_init(ram_addr_t ram_size, /* Tell KVM that we're in PAPR mode */ env->spr[SPR_SDR1] = (unsigned long)spapr->htab | ((pteg_shift + 7) - 18); - env->spr[SPR_HIOR] = 0; - - if (kvm_enabled()) { - kvmppc_set_papr(env); - } } filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin"); @@ -827,11 +838,6 @@ static void ppc_spapr_init(ram_addr_t ram_size, spapr->entry_point = 0x100; - /* SLOF will startup the secondary CPUs using RTAS */ - for (env = first_cpu; env != NULL; env = env->next_cpu) { - env->halted = 1; - } - /* Prepare the device tree */ spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, rma_size, initrd_base, initrd_size, -- cgit v1.2.1 From c8787ad477f3be5a971b877dcb1bae5752c5796a Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Sep 2012 16:57:11 +0000 Subject: pseries: Use new method to correct reset sequence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A number of things need to occur during reset of the PAPR paravirtualized platform in a specific order. For example, the hash table needs to be cleared before the CPUs are reset, so that they initialize their register state correctly, and the CPUs need to have their main reset called before we set up the entry point state on the boot cpu. We also need to have the main qdev reset happen before the creation and installation of the device tree for the new boot, because we need the state of the devices settled to correctly construct the device tree. We currently do the pseries once-per-reset initializations done from a reset handler. However we can't adequately control when this handler is called during the reset - in particular we can't guarantee it happens after all the qdev resets (since qdevs might be registered after the machine init function has executed). This patch uses the new QEMUMachine reset method to to fix this problem, ensuring the various order dependent reset steps happen in the correct order. Signed-off-by: David Gibson Reviewed-by: Andreas Färber Signed-off-by: Alexander Graf --- hw/spapr.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'hw/spapr.c') diff --git a/hw/spapr.c b/hw/spapr.c index d88525aadd..68542e89b6 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -559,13 +559,13 @@ static void emulate_spapr_hypercall(CPUPPCState *env) env->gpr[3] = spapr_hypercall(env, env->gpr[3], &env->gpr[4]); } -static void spapr_reset(void *opaque) +static void ppc_spapr_reset(void) { - sPAPREnvironment *spapr = (sPAPREnvironment *)opaque; - /* flush out the hash table */ memset(spapr->htab, 0, spapr->htab_size); + qemu_devices_reset(); + /* Load the fdt */ spapr_finalize_fdt(spapr, spapr->fdt_addr, spapr->rtas_addr, spapr->rtas_size); @@ -845,14 +845,13 @@ static void ppc_spapr_init(ram_addr_t ram_size, boot_device, kernel_cmdline, pteg_shift + 7); assert(spapr->fdt_skel != NULL); - - qemu_register_reset(spapr_reset, spapr); } static QEMUMachine spapr_machine = { .name = "pseries", .desc = "pSeries Logical Partition (PAPR compliant)", .init = ppc_spapr_init, + .reset = ppc_spapr_reset, .max_cpus = MAX_CPUS, .no_parallel = 1, .use_scsi = 1, -- cgit v1.2.1 From 7f763a5d994bbddb50705d2e50decdf52937521f Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Sep 2012 16:57:12 +0000 Subject: pseries: Add support for new KVM hash table control call This adds support for then new "reset htab" ioctl which allows qemu to properly cleanup the MMU hash table when the guest is reset. With the corresponding kernel support, reset of a guest now works properly. This also paves the way for indicating a different size hash table to the kernel and for the kernel to be able to impose limits on the requested size. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr.c | 274 ++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 162 insertions(+), 112 deletions(-) (limited to 'hw/spapr.c') diff --git a/hw/spapr.c b/hw/spapr.c index 68542e89b6..0a0e9cddc6 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -85,6 +85,8 @@ #define PHANDLE_XICP 0x00001111 +#define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift)) + sPAPREnvironment *spapr; int spapr_allocate_irq(int hint, enum xics_irq_type type) @@ -134,12 +136,13 @@ int spapr_allocate_irq_block(int num, enum xics_irq_type type) return first; } -static int spapr_set_associativity(void *fdt, sPAPREnvironment *spapr) +static int spapr_fixup_cpu_dt(void *fdt, sPAPREnvironment *spapr) { int ret = 0, offset; CPUPPCState *env; char cpu_model[32]; int smt = kvmppc_smt_threads(); + uint32_t pft_size_prop[] = {0, cpu_to_be32(spapr->htab_shift)}; assert(spapr->cpu_model); @@ -163,8 +166,16 @@ static int spapr_set_associativity(void *fdt, sPAPREnvironment *spapr) return offset; } - ret = fdt_setprop(fdt, offset, "ibm,associativity", associativity, - sizeof(associativity)); + if (nb_numa_nodes > 1) { + ret = fdt_setprop(fdt, offset, "ibm,associativity", associativity, + sizeof(associativity)); + if (ret < 0) { + return ret; + } + } + + ret = fdt_setprop(fdt, offset, "ibm,pft-size", + pft_size_prop, sizeof(pft_size_prop)); if (ret < 0) { return ret; } @@ -206,45 +217,36 @@ static size_t create_page_sizes_prop(CPUPPCState *env, uint32_t *prop, return (p - prop) * sizeof(uint32_t); } +#define _FDT(exp) \ + do { \ + int ret = (exp); \ + if (ret < 0) { \ + fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \ + #exp, fdt_strerror(ret)); \ + exit(1); \ + } \ + } while (0) + + static void *spapr_create_fdt_skel(const char *cpu_model, - target_phys_addr_t rma_size, target_phys_addr_t initrd_base, target_phys_addr_t initrd_size, target_phys_addr_t kernel_size, const char *boot_device, - const char *kernel_cmdline, - long hash_shift) + const char *kernel_cmdline) { void *fdt; CPUPPCState *env; - uint64_t mem_reg_property[2]; uint32_t start_prop = cpu_to_be32(initrd_base); uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size); - uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)}; char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt" "\0hcall-tce\0hcall-vio\0hcall-splpar\0hcall-bulk"; char qemu_hypertas_prop[] = "hcall-memop1"; + uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)}; uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)}; - int i; char *modelname; - int smt = kvmppc_smt_threads(); + int i, smt = kvmppc_smt_threads(); unsigned char vec5[] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x80}; - uint32_t refpoints[] = {cpu_to_be32(0x4), cpu_to_be32(0x4)}; - uint32_t associativity[] = {cpu_to_be32(0x4), cpu_to_be32(0x0), - cpu_to_be32(0x0), cpu_to_be32(0x0), - cpu_to_be32(0x0)}; - char mem_name[32]; - target_phys_addr_t node0_size, mem_start; - -#define _FDT(exp) \ - do { \ - int ret = (exp); \ - if (ret < 0) { \ - fprintf(stderr, "qemu: error creating device tree: %s: %s\n", \ - #exp, fdt_strerror(ret)); \ - exit(1); \ - } \ - } while (0) fdt = g_malloc0(FDT_MAX_SIZE); _FDT((fdt_create(fdt, FDT_MAX_SIZE))); @@ -289,55 +291,6 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _FDT((fdt_end_node(fdt))); - /* memory node(s) */ - node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size; - if (rma_size > node0_size) { - rma_size = node0_size; - } - - /* RMA */ - mem_reg_property[0] = 0; - mem_reg_property[1] = cpu_to_be64(rma_size); - _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_property(fdt, "ibm,associativity", associativity, - sizeof(associativity)))); - _FDT((fdt_end_node(fdt))); - - /* RAM: Node 0 */ - if (node0_size > rma_size) { - mem_reg_property[0] = cpu_to_be64(rma_size); - mem_reg_property[1] = cpu_to_be64(node0_size - rma_size); - - sprintf(mem_name, "memory@" TARGET_FMT_lx, rma_size); - _FDT((fdt_begin_node(fdt, 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,associativity", associativity, - sizeof(associativity)))); - _FDT((fdt_end_node(fdt))); - } - - /* RAM: Node 1 and beyond */ - mem_start = node0_size; - for (i = 1; i < nb_numa_nodes; i++) { - mem_reg_property[0] = cpu_to_be64(mem_start); - mem_reg_property[1] = cpu_to_be64(node_mem[i]); - associativity[3] = associativity[4] = cpu_to_be32(i); - sprintf(mem_name, "memory@" TARGET_FMT_lx, mem_start); - _FDT((fdt_begin_node(fdt, 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,associativity", associativity, - sizeof(associativity)))); - _FDT((fdt_end_node(fdt))); - mem_start += node_mem[i]; - } - /* cpus */ _FDT((fdt_begin_node(fdt, "cpus"))); @@ -389,8 +342,6 @@ static void *spapr_create_fdt_skel(const char *cpu_model, _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(fdt, "ibm,pft-size", - pft_size_prop, sizeof(pft_size_prop)))); _FDT((fdt_property_string(fdt, "status", "okay"))); _FDT((fdt_property(fdt, "64-bit", NULL, 0))); @@ -489,6 +440,68 @@ static void *spapr_create_fdt_skel(const char *cpu_model, return fdt; } +static int spapr_populate_memory(sPAPREnvironment *spapr, void *fdt) +{ + uint32_t associativity[] = {cpu_to_be32(0x4), cpu_to_be32(0x0), + cpu_to_be32(0x0), cpu_to_be32(0x0), + cpu_to_be32(0x0)}; + char mem_name[32]; + target_phys_addr_t node0_size, mem_start; + uint64_t mem_reg_property[2]; + int i, off; + + /* memory node(s) */ + node0_size = (nb_numa_nodes > 1) ? node_mem[0] : ram_size; + if (spapr->rma_size > node0_size) { + spapr->rma_size = node0_size; + } + + /* RMA */ + mem_reg_property[0] = 0; + mem_reg_property[1] = cpu_to_be64(spapr->rma_size); + off = fdt_add_subnode(fdt, 0, "memory@0"); + _FDT(off); + _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); + _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property, + sizeof(mem_reg_property)))); + _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity, + sizeof(associativity)))); + + /* RAM: Node 0 */ + if (node0_size > spapr->rma_size) { + mem_reg_property[0] = cpu_to_be64(spapr->rma_size); + mem_reg_property[1] = cpu_to_be64(node0_size - spapr->rma_size); + + sprintf(mem_name, "memory@" TARGET_FMT_lx, spapr->rma_size); + off = fdt_add_subnode(fdt, 0, mem_name); + _FDT(off); + _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); + _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property, + sizeof(mem_reg_property)))); + _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity, + sizeof(associativity)))); + } + + /* RAM: Node 1 and beyond */ + mem_start = node0_size; + for (i = 1; i < nb_numa_nodes; i++) { + mem_reg_property[0] = cpu_to_be64(mem_start); + mem_reg_property[1] = cpu_to_be64(node_mem[i]); + associativity[3] = associativity[4] = cpu_to_be32(i); + sprintf(mem_name, "memory@" TARGET_FMT_lx, mem_start); + off = fdt_add_subnode(fdt, 0, mem_name); + _FDT(off); + _FDT((fdt_setprop_string(fdt, off, "device_type", "memory"))); + _FDT((fdt_setprop(fdt, off, "reg", mem_reg_property, + sizeof(mem_reg_property)))); + _FDT((fdt_setprop(fdt, off, "ibm,associativity", associativity, + sizeof(associativity)))); + mem_start += node_mem[i]; + } + + return 0; +} + static void spapr_finalize_fdt(sPAPREnvironment *spapr, target_phys_addr_t fdt_addr, target_phys_addr_t rtas_addr, @@ -503,6 +516,12 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr, /* open out the base tree into a temp buffer for the final tweaks */ _FDT((fdt_open_into(spapr->fdt_skel, fdt, FDT_MAX_SIZE))); + ret = spapr_populate_memory(spapr, fdt); + if (ret < 0) { + fprintf(stderr, "couldn't setup memory nodes in fdt\n"); + exit(1); + } + ret = spapr_populate_vdevice(spapr->vio_bus, fdt); if (ret < 0) { fprintf(stderr, "couldn't setup vio devices in fdt\n"); @@ -525,11 +544,9 @@ static void spapr_finalize_fdt(sPAPREnvironment *spapr, } /* Advertise NUMA via ibm,associativity */ - if (nb_numa_nodes > 1) { - ret = spapr_set_associativity(fdt, spapr); - if (ret < 0) { - fprintf(stderr, "Couldn't set up NUMA device tree properties\n"); - } + ret = spapr_fixup_cpu_dt(fdt, spapr); + if (ret < 0) { + fprintf(stderr, "Couldn't finalize CPU device tree properties\n"); } if (!spapr->has_graphics) { @@ -559,10 +576,39 @@ static void emulate_spapr_hypercall(CPUPPCState *env) env->gpr[3] = spapr_hypercall(env, env->gpr[3], &env->gpr[4]); } +static void spapr_reset_htab(sPAPREnvironment *spapr) +{ + long shift; + + /* allocate hash page table. For now we always make this 16mb, + * later we should probably make it scale to the size of guest + * RAM */ + + shift = kvmppc_reset_htab(spapr->htab_shift); + + if (shift > 0) { + /* Kernel handles htab, we don't need to allocate one */ + spapr->htab_shift = shift; + } else { + if (!spapr->htab) { + /* Allocate an htab if we don't yet have one */ + spapr->htab = qemu_memalign(HTAB_SIZE(spapr), HTAB_SIZE(spapr)); + } + + /* And clear it */ + memset(spapr->htab, 0, HTAB_SIZE(spapr)); + } + + /* Update the RMA size if necessary */ + if (spapr->vrma_adjust) { + spapr->rma_size = kvmppc_rma_size(ram_size, spapr->htab_shift); + } +} + static void ppc_spapr_reset(void) { - /* flush out the hash table */ - memset(spapr->htab, 0, spapr->htab_size); + /* Reset the hash table & recalc the RMA */ + spapr_reset_htab(spapr); qemu_devices_reset(); @@ -591,6 +637,12 @@ static void spapr_cpu_reset(void *opaque) env->halted = 1; env->spr[SPR_HIOR] = 0; + + env->external_htab = spapr->htab; + env->htab_base = -1; + env->htab_mask = HTAB_SIZE(spapr) - 1; + env->spr[SPR_SDR1] = (unsigned long)spapr->htab | + (spapr->htab_shift - 18); } /* Returns whether we want to use VGA or not */ @@ -624,11 +676,10 @@ static void ppc_spapr_init(ram_addr_t ram_size, int i; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); - target_phys_addr_t rma_alloc_size, rma_size; + target_phys_addr_t rma_alloc_size; uint32_t initrd_base = 0; long kernel_size = 0, initrd_size = 0; long load_limit, rtas_limit, fw_size; - long pteg_shift = 17; char *filename; msi_supported = true; @@ -645,20 +696,39 @@ static void ppc_spapr_init(ram_addr_t ram_size, hw_error("qemu: Unable to create RMA\n"); exit(1); } + if (rma_alloc_size && (rma_alloc_size < ram_size)) { - rma_size = rma_alloc_size; + spapr->rma_size = rma_alloc_size; } else { - rma_size = ram_size; + spapr->rma_size = ram_size; + + /* With KVM, we don't actually know whether KVM supports an + * unbounded RMA (PR KVM) or is limited by the hash table size + * (HV KVM using VRMA), so we always assume the latter + * + * In that case, we also limit the initial allocations for RTAS + * etc... to 256M since we have no way to know what the VRMA size + * is going to be as it depends on the size of the hash table + * isn't determined yet. + */ + if (kvm_enabled()) { + spapr->vrma_adjust = 1; + spapr->rma_size = MIN(spapr->rma_size, 0x10000000); + } } /* We place the device tree and RTAS just below either the top of the RMA, * or just below 2GB, whichever is lowere, so that it can be * processed with 32-bit real mode code if necessary */ - rtas_limit = MIN(rma_size, 0x80000000); + rtas_limit = MIN(spapr->rma_size, 0x80000000); spapr->rtas_addr = rtas_limit - RTAS_MAX_SIZE; spapr->fdt_addr = spapr->rtas_addr - FDT_MAX_SIZE; load_limit = spapr->fdt_addr - FW_OVERHEAD; + /* For now, always aim for a 16MB hash table */ + /* FIXME: we should change this default based on RAM size */ + spapr->htab_shift = 24; + /* init CPUs */ if (cpu_model == NULL) { cpu_model = kvm_enabled() ? "host" : "POWER7"; @@ -696,25 +766,6 @@ static void ppc_spapr_init(ram_addr_t ram_size, memory_region_add_subregion(sysmem, nonrma_base, ram); } - /* allocate hash page table. For now we always make this 16mb, - * later we should probably make it scale to the size of guest - * RAM. FIXME: setting the htab information in the CPU env really - * belongs at CPU reset time, but we can get away with it for now - * because the PAPR guest is not permitted to write SDR1 so in - * fact these settings will never change during the run */ - spapr->htab_size = 1ULL << (pteg_shift + 7); - spapr->htab = qemu_memalign(spapr->htab_size, spapr->htab_size); - - for (env = first_cpu; env != NULL; env = env->next_cpu) { - env->external_htab = spapr->htab; - env->htab_base = -1; - env->htab_mask = spapr->htab_size - 1; - - /* Tell KVM that we're in PAPR mode */ - env->spr[SPR_SDR1] = (unsigned long)spapr->htab | - ((pteg_shift + 7) - 18); - } - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "spapr-rtas.bin"); spapr->rtas_size = load_image_targphys(filename, spapr->rtas_addr, rtas_limit - spapr->rtas_addr); @@ -787,7 +838,7 @@ static void ppc_spapr_init(ram_addr_t ram_size, } } - if (rma_size < (MIN_RMA_SLOF << 20)) { + if (spapr->rma_size < (MIN_RMA_SLOF << 20)) { fprintf(stderr, "qemu: pSeries SLOF firmware requires >= " "%ldM guest RMA (Real Mode Area memory)\n", MIN_RMA_SLOF); exit(1); @@ -839,11 +890,10 @@ static void ppc_spapr_init(ram_addr_t ram_size, spapr->entry_point = 0x100; /* Prepare the device tree */ - spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, rma_size, + spapr->fdt_skel = spapr_create_fdt_skel(cpu_model, initrd_base, initrd_size, kernel_size, - boot_device, kernel_cmdline, - pteg_shift + 7); + boot_device, kernel_cmdline); assert(spapr->fdt_skel != NULL); } -- cgit v1.2.1 From ff9d2afa618acd81d926c9c213b4ff5f7163db1d Mon Sep 17 00:00:00 2001 From: David Gibson Date: Wed, 12 Sep 2012 16:57:18 +0000 Subject: pseries: Remove XICS irq type enum type Currently the XICS interrupt controller emulation uses a custom enum to specify whether a given interrupt is level-sensitive or message-triggered. This enum makes life awkward for saving the state, and isn't particularly useful since there are only two possibilities. This patch replaces the enum with a simple bool. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'hw/spapr.c') diff --git a/hw/spapr.c b/hw/spapr.c index 0a0e9cddc6..1177efaa98 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -89,7 +89,7 @@ sPAPREnvironment *spapr; -int spapr_allocate_irq(int hint, enum xics_irq_type type) +int spapr_allocate_irq(int hint, bool lsi) { int irq; @@ -105,13 +105,13 @@ int spapr_allocate_irq(int hint, enum xics_irq_type type) return 0; } - xics_set_irq_type(spapr->icp, irq, type); + xics_set_irq_type(spapr->icp, irq, lsi); return irq; } /* Allocate block of consequtive IRQs, returns a number of the first */ -int spapr_allocate_irq_block(int num, enum xics_irq_type type) +int spapr_allocate_irq_block(int num, bool lsi) { int first = -1; int i; @@ -119,7 +119,7 @@ int spapr_allocate_irq_block(int num, enum xics_irq_type type) for (i = 0; i < num; ++i) { int irq; - irq = spapr_allocate_irq(0, type); + irq = spapr_allocate_irq(0, lsi); if (!irq) { return -1; } -- cgit v1.2.1 From 382be75df77142cf6bdc7f5852738029eeb9e23a Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 20 Sep 2012 17:42:27 +0000 Subject: pseries: Set hash table size based on RAM size Currently the pseries machine code always attempts to set the size of the guests's hash page table to 16MB. However, because of the way the POWER MMU works, a suitable hash page table size should really depend on memory size. 16MB will be excessive for guests with <1GB and RAM, and may not be enough for guests with >2GB of RAM (depending on guest page size and other factors). The usual given rule of thumb is that the hash table should be 1/64 of the size of memory, but in fact the Linux guests we are aiming at don't really need that much. This patch, therefore, changes the hash table allocation code to aim for 1/128 of the size of RAM (rounding up). When using KVM, this size may still be adjusted by the host kernel if it is unable to allocate a suitable (contiguous) table. Signed-off-by: David Gibson Signed-off-by: Alexander Graf --- hw/spapr.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'hw/spapr.c') diff --git a/hw/spapr.c b/hw/spapr.c index 1177efaa98..a8bd3c1ae6 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -725,9 +725,16 @@ static void ppc_spapr_init(ram_addr_t ram_size, spapr->fdt_addr = spapr->rtas_addr - FDT_MAX_SIZE; load_limit = spapr->fdt_addr - FW_OVERHEAD; - /* For now, always aim for a 16MB hash table */ - /* FIXME: we should change this default based on RAM size */ - spapr->htab_shift = 24; + /* We aim for a hash table of size 1/128 the size of RAM. The + * normal rule of thumb is 1/64 the size of RAM, but that's much + * more than needed for the Linux guests we support. */ + spapr->htab_shift = 18; /* Minimum architected size */ + while (spapr->htab_shift <= 46) { + if ((1ULL << (spapr->htab_shift + 7)) >= ram_size) { + break; + } + spapr->htab_shift++; + } /* init CPUs */ if (cpu_model == NULL) { -- cgit v1.2.1 From efcb9383b974114e5f682e531346006f8f2466c0 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Tue, 25 Sep 2012 17:12:20 +0000 Subject: pseries: Don't test for MSR_PR for hypercalls under KVM PAPR hypercalls should only be invoked from the guest kernel, not guest user programs, that is, with MSR[PR]=0. Currently we check this in spapr_hypercall, returning H_PRIVILEGE if MSR[PR]=1. However, under KVM the state of MSR[PR] is already checked by the host kernel before passing the hypercall to qemu, making this check redundant. Worse, however, we don't generally synchronize KVM and qemu state on the hypercall path, meaning that qemu could incorrectly reject a hypercall because it has a stale MSR value. This patch fixes the problem by moving the privilege test exclusively to the TCG hypercall path. Signed-off-by: David Gibson CC: qemu-stable@nongnu.org Signed-off-by: Alexander Graf --- hw/spapr.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'hw/spapr.c') diff --git a/hw/spapr.c b/hw/spapr.c index a8bd3c1ae6..ab227a0093 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -573,7 +573,12 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr) static void emulate_spapr_hypercall(CPUPPCState *env) { - env->gpr[3] = spapr_hypercall(env, env->gpr[3], &env->gpr[4]); + if (msr_pr) { + hcall_dprintf("Hypercall made with MSR[PR]=1\n"); + env->gpr[3] = H_PRIVILEGE; + } else { + env->gpr[3] = spapr_hypercall(env, env->gpr[3], &env->gpr[4]); + } } static void spapr_reset_htab(sPAPREnvironment *spapr) -- cgit v1.2.1