diff options
author | David Gibson <david@gibson.dropbear.id.au> | 2011-04-01 15:15:22 +1100 |
---|---|---|
committer | Alexander Graf <agraf@suse.de> | 2011-04-01 18:34:55 +0200 |
commit | f43e35255cffb6ac6230dd09d308f7909f823f96 (patch) | |
tree | 31985141441b01f223053a871f3ced77f0ff617f /hw/spapr.c | |
parent | 4040ab72379f75fe171c03f93ceb75efb48c14a5 (diff) |
Virtual hash page table handling on pSeries machine
On pSeries logical partitions, excepting the old POWER4-style full system
partitions, the guest does not have direct access to the hardware page
table. Instead, the pagetable exists in hypervisor memory, and the guest
must manipulate it with hypercalls.
However, our current pSeries emulation more closely resembles the old
style where the guest must set up and handle the pagetables itself. This
patch converts it to act like a modern partition.
This involves two things: first, the hash translation path is modified to
permit the has table to be stored externally to the emulated machine's
RAM. The pSeries machine init code configures the CPUs to use this mode.
Secondly, we emulate the PAPR hypercalls for manipulating the external
hashed page table.
Signed-off-by: David Gibson <dwg@au1.ibm.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'hw/spapr.c')
-rw-r--r-- | hw/spapr.c | 35 |
1 files changed, 31 insertions, 4 deletions
diff --git a/hw/spapr.c b/hw/spapr.c index c24c92b1a0..57140d231d 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -52,12 +52,15 @@ 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 *kernel_cmdline) + const char *kernel_cmdline, + long hash_shift) { 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); + uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)}; + char hypertas_prop[] = "hcall-pft\0hcall-term"; int i; char *modelname; int ret; @@ -145,6 +148,8 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, * 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(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))); @@ -160,6 +165,14 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize, _FDT((fdt_end_node(fdt))); + /* RTAS */ + _FDT((fdt_begin_node(fdt, "rtas"))); + + _FDT((fdt_property(fdt, "ibm,hypertas-functions", hypertas_prop, + sizeof(hypertas_prop)))); + + _FDT((fdt_end_node(fdt))); + /* vdevice */ _FDT((fdt_begin_node(fdt, "vdevice"))); @@ -208,12 +221,13 @@ static void ppc_spapr_init(ram_addr_t ram_size, const char *cpu_model) { CPUState *envs[MAX_CPUS]; - void *fdt; + void *fdt, *htab; int i; ram_addr_t ram_offset; target_phys_addr_t fdt_addr; uint32_t kernel_base, initrd_base; - long kernel_size, initrd_size; + long kernel_size, initrd_size, htab_size; + long pteg_shift = 17; int fdt_size; spapr = qemu_malloc(sizeof(*spapr)); @@ -250,6 +264,18 @@ static void ppc_spapr_init(ram_addr_t ram_size, ram_offset = qemu_ram_alloc(NULL, "ppc_spapr.ram", ram_size); cpu_register_physical_memory(0, ram_size, ram_offset); + /* allocate hash page table. For now we always make this 16mb, + * later we should probably make it scale to the size of guest + * RAM */ + htab_size = 1ULL << (pteg_shift + 7); + htab = qemu_mallocz(htab_size); + + for (i = 0; i < smp_cpus; i++) { + envs[i]->external_htab = htab; + envs[i]->htab_base = -1; + envs[i]->htab_mask = htab_size - 1; + } + spapr->vio_bus = spapr_vio_bus_init(); for (i = 0; i < MAX_SERIAL_PORTS; i++) { @@ -296,7 +322,8 @@ static void ppc_spapr_init(ram_addr_t ram_size, /* 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, kernel_cmdline, + pteg_shift + 7); assert(fdt != NULL); cpu_physical_memory_write(fdt_addr, fdt, fdt_size); |