aboutsummaryrefslogtreecommitdiff
path: root/hw/spapr.c
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2011-04-01 15:15:22 +1100
committerAlexander Graf <agraf@suse.de>2011-04-01 18:34:55 +0200
commitf43e35255cffb6ac6230dd09d308f7909f823f96 (patch)
tree31985141441b01f223053a871f3ced77f0ff617f /hw/spapr.c
parent4040ab72379f75fe171c03f93ceb75efb48c14a5 (diff)
downloadqemu-f43e35255cffb6ac6230dd09d308f7909f823f96.zip
qemu-f43e35255cffb6ac6230dd09d308f7909f823f96.tar.gz
qemu-f43e35255cffb6ac6230dd09d308f7909f823f96.tar.bz2
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.c35
1 files changed, 31 insertions, 4 deletions
diff --git a/hw/spapr.c b/hw/spapr.c
index c24c92b..57140d2 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);