Commit 43cb39ad authored by Roman Kisel's avatar Roman Kisel Committed by Wei Liu
Browse files

arch/x86: Provide the CPU number in the wakeup AP callback



When starting APs, confidential guests and paravisor guests
need to know the CPU number, and the pattern of using the linear
search has emerged in several places. With N processors that leads
to the O(N^2) time complexity.

Provide the CPU number in the AP wake up callback so that one can
get the CPU number in constant time.

Suggested-by: default avatarMichael Kelley <mhklinux@outlook.com>
Signed-off-by: default avatarRoman Kisel <romank@linux.microsoft.com>
Reviewed-by: default avatarTom Lendacky <thomas.lendacky@amd.com>
Reviewed-by: default avatarThomas Gleixner <tglx@linutronix.de>
Reviewed-by: default avatarMichael Kelley <mhklinux@outlook.com>
Acked-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://lore.kernel.org/r/20250507182227.7421-3-romank@linux.microsoft.com


Signed-off-by: default avatarWei Liu <wei.liu@kernel.org>
Message-ID: <20250507182227.7421-3-romank@linux.microsoft.com>
parent 86c48271
Loading
Loading
Loading
Loading
+2 −11
Original line number Diff line number Diff line
@@ -1177,7 +1177,7 @@ static void snp_cleanup_vmsa(struct sev_es_save_area *vmsa, int apic_id)
		free_page((unsigned long)vmsa);
}

static int wakeup_cpu_via_vmgexit(u32 apic_id, unsigned long start_ip)
static int wakeup_cpu_via_vmgexit(u32 apic_id, unsigned long start_ip, unsigned int cpu)
{
	struct sev_es_save_area *cur_vmsa, *vmsa;
	struct ghcb_state state;
@@ -1185,7 +1185,7 @@ static int wakeup_cpu_via_vmgexit(u32 apic_id, unsigned long start_ip)
	unsigned long flags;
	struct ghcb *ghcb;
	u8 sipi_vector;
	int cpu, ret;
	int ret;
	u64 cr4;

	/*
@@ -1206,15 +1206,6 @@ static int wakeup_cpu_via_vmgexit(u32 apic_id, unsigned long start_ip)

	/* Override start_ip with known protected guest start IP */
	start_ip = real_mode_header->sev_es_trampoline_start;

	/* Find the logical CPU for the APIC ID */
	for_each_present_cpu(cpu) {
		if (arch_match_cpu_phys_id(cpu, apic_id))
			break;
	}
	if (cpu >= nr_cpu_ids)
		return -EINVAL;

	cur_vmsa = per_cpu(sev_vmsa, cpu);

	/*
+2 −10
Original line number Diff line number Diff line
@@ -211,17 +211,9 @@ static int hv_vtl_bringup_vcpu(u32 target_vp_index, int cpu, u64 eip_ignored)
	return ret;
}

static int hv_vtl_wakeup_secondary_cpu(u32 apicid, unsigned long start_eip)
static int hv_vtl_wakeup_secondary_cpu(u32 apicid, unsigned long start_eip, unsigned int cpu)
{
	int vp_index, cpu;

	/* Find the logical CPU for the APIC ID */
	for_each_present_cpu(cpu) {
		if (arch_match_cpu_phys_id(cpu, apicid))
			break;
	}
	if (cpu >= nr_cpu_ids)
		return -EINVAL;
	int vp_index;

	pr_debug("Bringing up CPU with APIC ID %d in VTL2...\n", apicid);
	vp_index = hv_apicid_to_vp_index(apicid);
+2 −13
Original line number Diff line number Diff line
@@ -289,7 +289,7 @@ static void snp_cleanup_vmsa(struct sev_es_save_area *vmsa)
		free_page((unsigned long)vmsa);
}

int hv_snp_boot_ap(u32 apic_id, unsigned long start_ip)
int hv_snp_boot_ap(u32 apic_id, unsigned long start_ip, unsigned int cpu)
{
	struct sev_es_save_area *vmsa = (struct sev_es_save_area *)
		__get_free_page(GFP_KERNEL | __GFP_ZERO);
@@ -298,7 +298,7 @@ int hv_snp_boot_ap(u32 apic_id, unsigned long start_ip)
	u64 ret, retry = 5;
	struct hv_enable_vp_vtl *start_vp_input;
	unsigned long flags;
	int cpu, vp_index;
	int vp_index;

	if (!vmsa)
		return -ENOMEM;
@@ -308,17 +308,6 @@ int hv_snp_boot_ap(u32 apic_id, unsigned long start_ip)
	if (vp_index < 0 || vp_index > ms_hyperv.max_vp_index)
		return -EINVAL;

	/*
	 * Find the Linux CPU number for addressing the per-CPU data, and it
	 * might not be the same as APIC ID.
	 */
	for_each_present_cpu(cpu) {
		if (arch_match_cpu_phys_id(cpu, apic_id))
			break;
	}
	if (cpu >= nr_cpu_ids)
		return -EINVAL;

	native_store_gdt(&gdtr);

	vmsa->gdtr.base = gdtr.address;
+4 −4
Original line number Diff line number Diff line
@@ -313,9 +313,9 @@ struct apic {
	u32	(*get_apic_id)(u32 id);

	/* wakeup_secondary_cpu */
	int	(*wakeup_secondary_cpu)(u32 apicid, unsigned long start_eip);
	int	(*wakeup_secondary_cpu)(u32 apicid, unsigned long start_eip, unsigned int cpu);
	/* wakeup secondary CPU using 64-bit wakeup point */
	int	(*wakeup_secondary_cpu_64)(u32 apicid, unsigned long start_eip);
	int	(*wakeup_secondary_cpu_64)(u32 apicid, unsigned long start_eip, unsigned int cpu);

	char	*name;
};
@@ -333,8 +333,8 @@ struct apic_override {
	void	(*send_IPI_self)(int vector);
	u64	(*icr_read)(void);
	void	(*icr_write)(u32 low, u32 high);
	int	(*wakeup_secondary_cpu)(u32 apicid, unsigned long start_eip);
	int	(*wakeup_secondary_cpu_64)(u32 apicid, unsigned long start_eip);
	int	(*wakeup_secondary_cpu)(u32 apicid, unsigned long start_eip, unsigned int cpu);
	int	(*wakeup_secondary_cpu_64)(u32 apicid, unsigned long start_eip, unsigned int cpu);
};

/*
+3 −2
Original line number Diff line number Diff line
@@ -268,11 +268,12 @@ int hv_unmap_ioapic_interrupt(int ioapic_id, struct hv_interrupt_entry *entry);
#ifdef CONFIG_AMD_MEM_ENCRYPT
bool hv_ghcb_negotiate_protocol(void);
void __noreturn hv_ghcb_terminate(unsigned int set, unsigned int reason);
int hv_snp_boot_ap(u32 apic_id, unsigned long start_ip);
int hv_snp_boot_ap(u32 apic_id, unsigned long start_ip, unsigned int cpu);
#else
static inline bool hv_ghcb_negotiate_protocol(void) { return false; }
static inline void hv_ghcb_terminate(unsigned int set, unsigned int reason) {}
static inline int hv_snp_boot_ap(u32 apic_id, unsigned long start_ip) { return 0; }
static inline int hv_snp_boot_ap(u32 apic_id, unsigned long start_ip,
		unsigned int cpu) { return 0; }
#endif

#if defined(CONFIG_AMD_MEM_ENCRYPT) || defined(CONFIG_INTEL_TDX_GUEST)
Loading