diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 3a925ef18a..68f936c4f8 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1288,8 +1288,8 @@ void spapr_free_hpt(sPAPRMachineState *spapr) close_htab_fd(spapr); } -static void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift, - Error **errp) +void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift, + Error **errp) { long rc; @@ -1337,9 +1337,17 @@ static void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift, void spapr_setup_hpt_and_vrma(sPAPRMachineState *spapr) { - spapr_reallocate_hpt(spapr, - spapr_hpt_shift_for_ramsize(MACHINE(spapr)->maxram_size), - &error_fatal); + int hpt_shift; + + if ((spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED) + || (spapr->cas_reboot + && !spapr_ovec_test(spapr->ov5_cas, OV5_HPT_RESIZE))) { + hpt_shift = spapr_hpt_shift_for_ramsize(MACHINE(spapr)->maxram_size); + } else { + hpt_shift = spapr_hpt_shift_for_ramsize(MACHINE(spapr)->ram_size); + } + spapr_reallocate_hpt(spapr, hpt_shift, &error_fatal); + if (spapr->vrma_adjust) { spapr->rma_size = kvmppc_rma_size(spapr_node0_size(), spapr->htab_shift); @@ -2254,6 +2262,11 @@ static void ppc_spapr_init(MachineState *machine) spapr_ovec_set(spapr->ov5, OV5_HP_EVT); } + /* advertise support for HPT resizing */ + if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) { + spapr_ovec_set(spapr->ov5, OV5_HPT_RESIZE); + } + /* init CPUs */ if (machine->cpu_model == NULL) { machine->cpu_model = kvm_enabled() ? "host" : smc->tcg_default_cpu; diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index f69ce4f60c..436f5e2b22 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -1473,6 +1473,35 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, guest_radix = spapr_ovec_test(ov5_guest, OV5_MMU_RADIX_300); spapr_ovec_clear(ov5_guest, OV5_MMU_RADIX_300); + /* + * HPT resizing is a bit of a special case, because when enabled + * we assume an HPT guest will support it until it says it + * doesn't, instead of assuming it won't support it until it says + * it does. Strictly speaking that approach could break for + * guests which don't make a CAS call, but those are so old we + * don't care about them. Without that assumption we'd have to + * make at least a temporary allocation of an HPT sized for max + * memory, which could be impossibly difficult under KVM HV if + * maxram is large. + */ + if (!guest_radix && !spapr_ovec_test(ov5_guest, OV5_HPT_RESIZE)) { + int maxshift = spapr_hpt_shift_for_ramsize(MACHINE(spapr)->maxram_size); + + if (spapr->resize_hpt == SPAPR_RESIZE_HPT_REQUIRED) { + error_report( + "h_client_architecture_support: Guest doesn't support HPT resizing, but resize-hpt=required"); + exit(1); + } + + if (spapr->htab_shift < maxshift) { + /* Guest doesn't know about HPT resizing, so we + * pre-emptively resize for the maximum permitted RAM. At + * the point this is called, nothing should have been + * entered into the existing HPT */ + spapr_reallocate_hpt(spapr, maxshift, &error_fatal); + } + } + /* NOTE: there are actually a number of ov5 bits where input from the * guest is always zero, and the platform/QEMU enables them independently * of guest input. To model these properly we'd want some sort of mask, diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 3dd62d81f6..2a303a705c 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -660,6 +660,8 @@ void spapr_hotplug_req_remove_by_count_indexed(sPAPRDRConnectorType drc_type, uint32_t count, uint32_t index); void spapr_cpu_parse_features(sPAPRMachineState *spapr); int spapr_hpt_shift_for_ramsize(uint64_t ramsize); +void spapr_reallocate_hpt(sPAPRMachineState *spapr, int shift, + Error **errp); /* CPU and LMB DRC release callbacks. */ void spapr_core_release(DeviceState *dev); diff --git a/include/hw/ppc/spapr_ovec.h b/include/hw/ppc/spapr_ovec.h index 0b464e22e7..9edfa5ff75 100644 --- a/include/hw/ppc/spapr_ovec.h +++ b/include/hw/ppc/spapr_ovec.h @@ -50,6 +50,7 @@ typedef struct sPAPROptionVector sPAPROptionVector; #define OV5_DRCONF_MEMORY OV_BIT(2, 2) #define OV5_FORM1_AFFINITY OV_BIT(5, 0) #define OV5_HP_EVT OV_BIT(6, 5) +#define OV5_HPT_RESIZE OV_BIT(6, 7) #define OV5_XIVE_EXPLOIT OV_BIT(23, 7) /* ISA 3.00 MMU features: */