diff --git a/usr.sbin/bhyve/aarch64/bhyve_machdep.h b/usr.sbin/bhyve/aarch64/bhyve_machdep.h --- a/usr.sbin/bhyve/aarch64/bhyve_machdep.h +++ b/usr.sbin/bhyve/aarch64/bhyve_machdep.h @@ -7,6 +7,7 @@ #ifndef _BHYVE_MACHDEP_H_ #define _BHYVE_MACHDEP_H_ +extern uint64_t *cpu_to_mpidr; extern cpuset_t running_cpumask; #endif /* _BHYVE_MACHDEP_H_ */ diff --git a/usr.sbin/bhyve/aarch64/bhyverun_machdep.c b/usr.sbin/bhyve/aarch64/bhyverun_machdep.c --- a/usr.sbin/bhyve/aarch64/bhyverun_machdep.c +++ b/usr.sbin/bhyve/aarch64/bhyverun_machdep.c @@ -30,6 +30,8 @@ #include #include +#include + #include #include #include @@ -74,6 +76,8 @@ #define PCIE_INTC 36 #define PCIE_INTD 37 +uint64_t *cpu_to_mpidr; + void bhyve_init_config(void) { @@ -364,6 +368,23 @@ int error; int pcie_intrs[4] = {PCIE_INTA, PCIE_INTB, PCIE_INTC, PCIE_INTD}; + cpu_to_mpidr = calloc(guest_ncpus, sizeof(*cpu_to_mpidr)); + if (cpu_to_mpidr == NULL) { + warnx("unable to allocate space for mpidr list"); + return (ENOMEM); + } + + for (uint64_t cpu = 0; cpu < (uint64_t)guest_ncpus; cpu++) { + uint64_t mpidr; + + error = vm_get_register(fbsdrun_vcpu(cpu), VM_REG_GUEST_MPIDR_EL1, + &mpidr); + assert(error == 0); +#define MPIDR_AFF_MASK (MPIDR_AFF0_MASK | MPIDR_AFF1_MASK | MPIDR_AFF2_MASK | MPIDR_AFF3_MASK) + cpu_to_mpidr[cpu] = mpidr & MPIDR_AFF_MASK; +#undef MPIDR_AFF_MASK + } + bootrom = get_config_value("bootrom"); if (bootrom == NULL) { warnx("no bootrom specified"); diff --git a/usr.sbin/bhyve/aarch64/fdt.c b/usr.sbin/bhyve/aarch64/fdt.c --- a/usr.sbin/bhyve/aarch64/fdt.c +++ b/usr.sbin/bhyve/aarch64/fdt.c @@ -39,6 +39,7 @@ #include #include "config.h" +#include "bhyve_machdep.h" #include "bhyverun.h" #include "fdt.h" @@ -92,7 +93,7 @@ fdt_begin_node(fdt, node_name); fdt_property_string(fdt, "device_type", "cpu"); fdt_property_string(fdt, "compatible", "arm,armv8"); - fdt_property_u64(fdt, "reg", cpuid); + fdt_property_u64(fdt, "reg", cpu_to_mpidr[cpuid]); fdt_property_string(fdt, "enable-method", "psci"); fdt_end_node(fdt); } diff --git a/usr.sbin/bhyve/aarch64/vmexit.c b/usr.sbin/bhyve/aarch64/vmexit.c --- a/usr.sbin/bhyve/aarch64/vmexit.c +++ b/usr.sbin/bhyve/aarch64/vmexit.c @@ -152,7 +152,7 @@ static uint64_t smccc_affinity_info(uint64_t target_affinity, uint32_t lowest_affinity_level) { - uint64_t cpu_aff, mask = 0; + uint64_t mask = 0; switch (lowest_affinity_level) { case 0: @@ -172,13 +172,7 @@ } for (int vcpu = 0; vcpu < guest_ncpus; vcpu++) { - /* TODO: We should get this from the kernel */ - cpu_aff = (vcpu & 0xf) << MPIDR_AFF0_SHIFT | - ((vcpu >> 4) & 0xff) << MPIDR_AFF1_SHIFT | - ((vcpu >> 12) & 0xff) << MPIDR_AFF2_SHIFT | - (uint64_t)((vcpu >> 20) & 0xff) << MPIDR_AFF3_SHIFT; - - if ((cpu_aff & mask) == (target_affinity & mask) && + if ((cpu_to_mpidr[vcpu] & mask) == (target_affinity & mask) && CPU_ISSET(vcpu, &running_cpumask)) { /* Return ON if any CPUs are on */ return (PSCI_AFFINITY_INFO_ON); @@ -194,9 +188,9 @@ { struct vcpu *newvcpu; struct vm_exit *vme; - uint64_t newcpu, smccc_rv; + uint64_t mpidr, smccc_rv; enum vm_suspend_how how; - int error; + int error, newcpu; /* Return the Unknown Function Identifier by default */ smccc_rv = SMCCC_RET_NOT_SUPPORTED; @@ -211,8 +205,13 @@ case PSCI_FNID_CPU_OFF: break; case PSCI_FNID_CPU_ON: - newcpu = vme->u.smccc_call.args[0]; - if (newcpu > (uint64_t)guest_ncpus) { + mpidr = vme->u.smccc_call.args[0]; + for (newcpu = 0; newcpu < guest_ncpus; newcpu++) { + if (cpu_to_mpidr[newcpu] == mpidr) + break; + } + + if (newcpu == guest_ncpus) { smccc_rv = PSCI_RETVAL_INVALID_PARAMS; break; }