@@ -317,6 +317,7 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
const char *kernel_cmdline,
uint32_t epow_irq)
{
+ sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
void *fdt;
uint32_t start_prop = cpu_to_be32(initrd_base);
uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
@@ -336,6 +337,9 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
add_str(hypertas, "hcall-splpar");
add_str(hypertas, "hcall-bulk");
add_str(hypertas, "hcall-set-mode");
+ if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) {
+ add_str(hypertas, "hcall-hpt-resize");
+ }
add_str(qemu_hypertas, "hcall-memop1");
fdt = g_malloc0(FDT_MAX_SIZE);
@@ -2100,6 +2104,36 @@ static void spapr_set_kvm_type(Object *obj, const char *value, Error **errp)
spapr->kvm_type = g_strdup(value);
}
+static char *spapr_get_resize_hpt(Object *obj, Error **errp)
+{
+ sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+
+ switch (spapr->resize_hpt) {
+ case SPAPR_RESIZE_HPT_DISABLED:
+ return g_strdup("disabled");
+ case SPAPR_RESIZE_HPT_ENABLED:
+ return g_strdup("enabled");
+ case SPAPR_RESIZE_HPT_REQUIRED:
+ return g_strdup("required");
+ }
+ assert(0);
+}
+
+static void spapr_set_resize_hpt(Object *obj, const char *value, Error **errp)
+{
+ sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
+
+ if (strcmp(value, "disabled") == 0) {
+ spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED;
+ } else if (strcmp(value, "enabled") == 0) {
+ spapr->resize_hpt = SPAPR_RESIZE_HPT_ENABLED;
+ } else if (strcmp(value, "required") == 0) {
+ spapr->resize_hpt = SPAPR_RESIZE_HPT_REQUIRED;
+ } else {
+ error_setg(errp, "Bad value for \"resize-hpt\" property");
+ }
+}
+
static void spapr_machine_initfn(Object *obj)
{
sPAPRMachineState *spapr = SPAPR_MACHINE(obj);
@@ -2110,6 +2144,12 @@ static void spapr_machine_initfn(Object *obj)
object_property_set_description(obj, "kvm-type",
"Specifies the KVM virtualization mode (HV, PR)",
NULL);
+
+ object_property_add_str(obj, "resize-hpt",
+ spapr_get_resize_hpt, spapr_set_resize_hpt, NULL);
+ object_property_set_description(obj, "resize-hpt",
+ "Resizing of the Hash Page Table (enabled, disabled, required)",
+ NULL);
}
static void spapr_machine_finalizefn(Object *obj)
@@ -331,6 +331,38 @@ static target_ulong h_read(PowerPCCPU *cpu, sPAPRMachineState *spapr,
return H_SUCCESS;
}
+static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu,
+ sPAPRMachineState *spapr,
+ target_ulong opcode,
+ target_ulong *args)
+{
+ target_ulong flags = args[0];
+ target_ulong shift = args[1];
+
+ if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED) {
+ return H_AUTHORITY;
+ }
+
+ trace_spapr_h_resize_hpt_prepare(flags, shift);
+ return H_HARDWARE;
+}
+
+static target_ulong h_resize_hpt_commit(PowerPCCPU *cpu,
+ sPAPRMachineState *spapr,
+ target_ulong opcode,
+ target_ulong *args)
+{
+ target_ulong flags = args[0];
+ target_ulong shift = args[1];
+
+ if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED) {
+ return H_AUTHORITY;
+ }
+
+ trace_spapr_h_resize_hpt_commit(flags, shift);
+ return H_HARDWARE;
+}
+
static target_ulong h_set_dabr(PowerPCCPU *cpu, sPAPRMachineState *spapr,
target_ulong opcode, target_ulong *args)
{
@@ -989,6 +1021,11 @@ static void hypercall_register_types(void)
/* hcall-bulk */
spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove);
+ /* hcall-hpt-resize */
+ spapr_register_hypercall(KVMPPC_H_RESIZE_HPT_PREPARE,
+ h_resize_hpt_prepare);
+ spapr_register_hypercall(KVMPPC_H_RESIZE_HPT_COMMIT, h_resize_hpt_commit);
+
/* hcall-dabr */
spapr_register_hypercall(H_SET_DABR, h_set_dabr);
@@ -42,6 +42,12 @@ struct sPAPRMachineClass {
/**
* sPAPRMachineState:
*/
+typedef enum {
+ SPAPR_RESIZE_HPT_DISABLED = 0,
+ SPAPR_RESIZE_HPT_ENABLED,
+ SPAPR_RESIZE_HPT_REQUIRED,
+} sPAPRResizeHPT;
+
struct sPAPRMachineState {
/*< private >*/
MachineState parent_obj;
@@ -52,6 +58,7 @@ struct sPAPRMachineState {
XICSState *icp;
DeviceState *rtc;
+ sPAPRResizeHPT resize_hpt;
void *htab;
uint32_t htab_shift;
hwaddr rma_size;
@@ -351,7 +358,9 @@ struct sPAPRMachineState {
#define KVMPPC_H_LOGICAL_MEMOP (KVMPPC_HCALL_BASE + 0x1)
/* Client Architecture support */
#define KVMPPC_H_CAS (KVMPPC_HCALL_BASE + 0x2)
-#define KVMPPC_HCALL_MAX KVMPPC_H_CAS
+#define KVMPPC_H_RESIZE_HPT_PREPARE (KVMPPC_HCALL_BASE + 0x3)
+#define KVMPPC_H_RESIZE_HPT_COMMIT (KVMPPC_HCALL_BASE + 0x4)
+#define KVMPPC_HCALL_MAX KVMPPC_H_RESIZE_HPT_COMMIT
typedef struct sPAPRDeviceTreeUpdateHeader {
uint32_t version_id;
@@ -1403,6 +1403,8 @@ spapr_cas_continue(unsigned long n) "Copy changes to the guest: %ld bytes"
# hw/ppc/spapr_hcall.c
spapr_cas_pvr_try(uint32_t pvr) "%x"
spapr_cas_pvr(uint32_t cur_pvr, bool cpu_match, uint32_t new_pvr, uint64_t pcr) "current=%x, cpu_match=%u, new=%x, compat flags=%"PRIx64
+spapr_h_resize_hpt_prepare(uint64_t flags, uint64_t shift) "flags=0x%"PRIx64", shift=%"PRIu64
+spapr_h_resize_hpt_commit(uint64_t flags, uint64_t shift) "flags=0x%"PRIx64", shift=%"PRIu64
# hw/ppc/spapr_iommu.c
spapr_iommu_put(uint64_t liobn, uint64_t ioba, uint64_t tce, uint64_t ret) "liobn=%"PRIx64" ioba=0x%"PRIx64" tce=0x%"PRIx64" ret=%"PRId64
This introduces stub implementations of the H_RESIZE_HPT_PREPARE and H_RESIZE_HPT_COMMIT hypercalls which we hope to add in a PAPR extension to allow run time resizing of a guest's hash page table. It also adds a new machine property for controlling whether this new facility is available. Finally, it adds a new string to the hypertas property in the device tree, advertising to the guest the availability of the HPT resizing hypercalls. This is a tentative suggested value, and would need to be standardized by PAPR before being merged. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> --- hw/ppc/spapr.c | 40 ++++++++++++++++++++++++++++++++++++++++ hw/ppc/spapr_hcall.c | 37 +++++++++++++++++++++++++++++++++++++ include/hw/ppc/spapr.h | 11 ++++++++++- trace-events | 2 ++ 4 files changed, 89 insertions(+), 1 deletion(-)