continue;
}
drc = SPAPR_DR_CONNECTOR(object_property_get_link(drc_container,
- prop->name, NULL));
+ prop->name,
+ &error_abort));
if (spapr_drc_transient(drc)) {
spapr_drc_reset(drc);
spapr_clear_pending_hotplug_events(spapr);
}
-static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
- SpaprMachineState *spapr,
- target_ulong opcode,
- target_ulong *args)
+target_ulong do_client_architecture_support(PowerPCCPU *cpu,
+ SpaprMachineState *spapr,
+ target_ulong vec,
+ target_ulong fdt_bufsize)
{
- /* Working address in data buffer */
- target_ulong addr = ppc64_phys_to_real(args[0]);
- target_ulong fdt_buf = args[1];
- target_ulong fdt_bufsize = args[2];
- target_ulong ov_table;
+ target_ulong ov_table; /* Working address in data buffer */
uint32_t cas_pvr;
- SpaprOptionVector *ov1_guest, *ov5_guest, *ov5_cas_old;
+ SpaprOptionVector *ov1_guest, *ov5_guest;
bool guest_radix;
Error *local_err = NULL;
bool raw_mode_supported = false;
bool guest_xive;
CPUState *cs;
+ void *fdt;
/* CAS is supposed to be called early when only the boot vCPU is active. */
CPU_FOREACH(cs) {
}
}
- cas_pvr = cas_check_pvr(spapr, cpu, &addr, &raw_mode_supported, &local_err);
+ cas_pvr = cas_check_pvr(spapr, cpu, &vec, &raw_mode_supported, &local_err);
if (local_err) {
error_report_err(local_err);
return H_HARDWARE;
}
/* For the future use: here @ov_table points to the first option vector */
- ov_table = addr;
+ ov_table = vec;
ov1_guest = spapr_ovec_parse_vector(ov_table, 1);
if (!ov1_guest) {
}
ov5_guest = spapr_ovec_parse_vector(ov_table, 5);
if (!ov5_guest) {
+ spapr_ovec_cleanup(ov1_guest);
warn_report("guest didn't provide option vector 5");
return H_PARAMETER;
}
exit(EXIT_FAILURE);
}
- /* The radix/hash bit in byte 24 requires special handling: */
guest_radix = spapr_ovec_test(ov5_guest, OV5_MMU_RADIX_300);
- spapr_ovec_clear(ov5_guest, OV5_MMU_RADIX_300);
guest_xive = spapr_ovec_test(ov5_guest, OV5_XIVE_EXPLOIT);
* by LoPAPR 1.1, 14.5.4.8, which QEMU doesn't implement, we don't need
* to worry about this for now.
*/
- ov5_cas_old = spapr_ovec_clone(spapr->ov5_cas);
-
- /* also clear the radix/hash bit from the current ov5_cas bits to
- * be in sync with the newly ov5 bits. Else the radix bit will be
- * seen as being removed and this will generate a reset loop
- */
- spapr_ovec_clear(ov5_cas_old, OV5_MMU_RADIX_300);
/* full range of negotiated ov5 capabilities */
spapr_ovec_intersect(spapr->ov5_cas, spapr->ov5, ov5_guest);
spapr_ovec_cleanup(ov5_guest);
- /* capabilities that have been added since CAS-generated guest reset.
- * if capabilities have since been removed, generate another reset
- */
- spapr->cas_reboot = !spapr_ovec_subset(ov5_cas_old, spapr->ov5_cas);
- spapr_ovec_cleanup(ov5_cas_old);
- /* Now that processing is finished, set the radix/hash bit for the
- * guest if it requested a valid mode; otherwise terminate the boot. */
+
if (guest_radix) {
if (kvm_enabled() && !kvmppc_has_cap_mmu_radix()) {
error_report("Guest requested unavailable MMU mode (radix).");
exit(EXIT_FAILURE);
}
- spapr_ovec_set(spapr->ov5_cas, OV5_MMU_RADIX_300);
} else {
if (kvm_enabled() && kvmppc_has_cap_mmu_radix()
&& !kvmppc_has_cap_mmu_hash_v3()) {
spapr_handle_transient_dev_before_cas(spapr);
- if (!spapr->cas_reboot) {
- void *fdt;
- SpaprDeviceTreeUpdateHeader hdr = { .version_id = 1 };
+ /*
+ * If spapr_machine_reset() did not set up a HPT but one is necessary
+ * (because the guest isn't going to use radix) then set it up here.
+ */
+ if ((spapr->patb_entry & PATE1_GR) && !guest_radix) {
+ /* legacy hash or new hash: */
+ spapr_setup_hpt(spapr);
+ }
- /* If spapr_machine_reset() did not set up a HPT but one is necessary
- * (because the guest isn't going to use radix) then set it up here. */
- if ((spapr->patb_entry & PATE1_GR) && !guest_radix) {
- /* legacy hash or new hash: */
- spapr_setup_hpt(spapr);
- }
+ fdt = spapr_build_fdt(spapr, false, fdt_bufsize);
- if (fdt_bufsize < sizeof(hdr)) {
- error_report("SLOF provided insufficient CAS buffer "
- TARGET_FMT_lu " (min: %zu)", fdt_bufsize, sizeof(hdr));
- exit(EXIT_FAILURE);
- }
+ g_free(spapr->fdt_blob);
+ spapr->fdt_size = fdt_totalsize(fdt);
+ spapr->fdt_initial_size = spapr->fdt_size;
+ spapr->fdt_blob = fdt;
- fdt_bufsize -= sizeof(hdr);
+ return H_SUCCESS;
+}
+
+static target_ulong h_client_architecture_support(PowerPCCPU *cpu,
+ SpaprMachineState *spapr,
+ target_ulong opcode,
+ target_ulong *args)
+{
+ target_ulong vec = ppc64_phys_to_real(args[0]);
+ target_ulong fdt_buf = args[1];
+ target_ulong fdt_bufsize = args[2];
+ target_ulong ret;
+ SpaprDeviceTreeUpdateHeader hdr = { .version_id = 1 };
- fdt = spapr_build_fdt(spapr, false, fdt_bufsize);
- _FDT((fdt_pack(fdt)));
+ if (fdt_bufsize < sizeof(hdr)) {
+ error_report("SLOF provided insufficient CAS buffer "
+ TARGET_FMT_lu " (min: %zu)", fdt_bufsize, sizeof(hdr));
+ exit(EXIT_FAILURE);
+ }
- cpu_physical_memory_write(fdt_buf, &hdr, sizeof(hdr));
- cpu_physical_memory_write(fdt_buf + sizeof(hdr), fdt,
- fdt_totalsize(fdt));
- trace_spapr_cas_continue(fdt_totalsize(fdt) + sizeof(hdr));
+ fdt_bufsize -= sizeof(hdr);
- g_free(spapr->fdt_blob);
- spapr->fdt_size = fdt_totalsize(fdt);
+ ret = do_client_architecture_support(cpu, spapr, vec, fdt_bufsize);
+ if (ret == H_SUCCESS) {
+ _FDT((fdt_pack(spapr->fdt_blob)));
+ spapr->fdt_size = fdt_totalsize(spapr->fdt_blob);
spapr->fdt_initial_size = spapr->fdt_size;
- spapr->fdt_blob = fdt;
- }
- if (spapr->cas_reboot) {
- qemu_system_reset_request(SHUTDOWN_CAUSE_SUBSYSTEM_RESET);
+ cpu_physical_memory_write(fdt_buf, &hdr, sizeof(hdr));
+ cpu_physical_memory_write(fdt_buf + sizeof(hdr), spapr->fdt_blob,
+ spapr->fdt_size);
+ trace_spapr_cas_continue(spapr->fdt_size + sizeof(hdr));
}
- return H_SUCCESS;
+ return ret;
}
static target_ulong h_home_node_associativity(PowerPCCPU *cpu,