Skip to content

Commit 2b5e22a

Browse files
kirylbp3tk0v
authored andcommitted
x86/acpi: Extract ACPI MADT wakeup code into a separate file
In order to prepare for the expansion of support for the ACPI MADT wakeup method, move the relevant code into a separate file. Introduce a new configuration option to clearly indicate dependencies without the use of ifdefs. There have been no functional changes. Signed-off-by: Kirill A. Shutemov <[email protected]> Signed-off-by: Borislav Petkov (AMD) <[email protected]> Reviewed-by: Baoquan He <[email protected]> Reviewed-by: Kuppuswamy Sathyanarayanan <[email protected]> Reviewed-by: Thomas Gleixner <[email protected]> Acked-by: Borislav Petkov (AMD) <[email protected]> Acked-by: Kai Huang <[email protected]> Acked-by: Rafael J. Wysocki <[email protected]> Tested-by: Tao Liu <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 54183d1 commit 2b5e22a

File tree

5 files changed

+96
-85
lines changed

5 files changed

+96
-85
lines changed

arch/x86/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,13 @@ config X86_LOCAL_APIC
11181118
depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC || PCI_MSI
11191119
select IRQ_DOMAIN_HIERARCHY
11201120

1121+
config ACPI_MADT_WAKEUP
1122+
def_bool y
1123+
depends on X86_64
1124+
depends on ACPI
1125+
depends on SMP
1126+
depends on X86_LOCAL_APIC
1127+
11211128
config X86_IO_APIC
11221129
def_bool y
11231130
depends on X86_LOCAL_APIC || X86_UP_IOAPIC

arch/x86/include/asm/acpi.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ static inline bool acpi_skip_set_wakeup_address(void)
7878

7979
#define acpi_skip_set_wakeup_address acpi_skip_set_wakeup_address
8080

81+
union acpi_subtable_headers;
82+
83+
int __init acpi_parse_mp_wake(union acpi_subtable_headers *header,
84+
const unsigned long end);
85+
8186
/*
8287
* Check if the CPU can handle C2 and deeper
8388
*/

arch/x86/kernel/acpi/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ obj-$(CONFIG_ACPI) += boot.o
44
obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_$(BITS).o
55
obj-$(CONFIG_ACPI_APEI) += apei.o
66
obj-$(CONFIG_ACPI_CPPC_LIB) += cppc.o
7+
obj-$(CONFIG_ACPI_MADT_WAKEUP) += madt_wakeup.o
78

89
ifneq ($(CONFIG_ACPI_PROCESSOR),)
910
obj-y += cstate.o

arch/x86/kernel/acpi/boot.c

Lines changed: 1 addition & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,6 @@ static bool has_lapic_cpus __initdata;
6767
static bool acpi_support_online_capable;
6868
#endif
6969

70-
#ifdef CONFIG_X86_64
71-
/* Physical address of the Multiprocessor Wakeup Structure mailbox */
72-
static u64 acpi_mp_wake_mailbox_paddr;
73-
/* Virtual address of the Multiprocessor Wakeup Structure mailbox */
74-
static struct acpi_madt_multiproc_wakeup_mailbox *acpi_mp_wake_mailbox;
75-
#endif
76-
7770
#ifdef CONFIG_X86_IO_APIC
7871
/*
7972
* Locks related to IOAPIC hotplug
@@ -341,60 +334,6 @@ acpi_parse_lapic_nmi(union acpi_subtable_headers * header, const unsigned long e
341334

342335
return 0;
343336
}
344-
345-
#ifdef CONFIG_X86_64
346-
static int acpi_wakeup_cpu(u32 apicid, unsigned long start_ip)
347-
{
348-
/*
349-
* Remap mailbox memory only for the first call to acpi_wakeup_cpu().
350-
*
351-
* Wakeup of secondary CPUs is fully serialized in the core code.
352-
* No need to protect acpi_mp_wake_mailbox from concurrent accesses.
353-
*/
354-
if (!acpi_mp_wake_mailbox) {
355-
acpi_mp_wake_mailbox = memremap(acpi_mp_wake_mailbox_paddr,
356-
sizeof(*acpi_mp_wake_mailbox),
357-
MEMREMAP_WB);
358-
}
359-
360-
/*
361-
* Mailbox memory is shared between the firmware and OS. Firmware will
362-
* listen on mailbox command address, and once it receives the wakeup
363-
* command, the CPU associated with the given apicid will be booted.
364-
*
365-
* The value of 'apic_id' and 'wakeup_vector' must be visible to the
366-
* firmware before the wakeup command is visible. smp_store_release()
367-
* ensures ordering and visibility.
368-
*/
369-
acpi_mp_wake_mailbox->apic_id = apicid;
370-
acpi_mp_wake_mailbox->wakeup_vector = start_ip;
371-
smp_store_release(&acpi_mp_wake_mailbox->command,
372-
ACPI_MP_WAKE_COMMAND_WAKEUP);
373-
374-
/*
375-
* Wait for the CPU to wake up.
376-
*
377-
* The CPU being woken up is essentially in a spin loop waiting to be
378-
* woken up. It should not take long for it wake up and acknowledge by
379-
* zeroing out ->command.
380-
*
381-
* ACPI specification doesn't provide any guidance on how long kernel
382-
* has to wait for a wake up acknowledgement. It also doesn't provide
383-
* a way to cancel a wake up request if it takes too long.
384-
*
385-
* In TDX environment, the VMM has control over how long it takes to
386-
* wake up secondary. It can postpone scheduling secondary vCPU
387-
* indefinitely. Giving up on wake up request and reporting error opens
388-
* possible attack vector for VMM: it can wake up a secondary CPU when
389-
* kernel doesn't expect it. Wait until positive result of the wake up
390-
* request.
391-
*/
392-
while (READ_ONCE(acpi_mp_wake_mailbox->command))
393-
cpu_relax();
394-
395-
return 0;
396-
}
397-
#endif /* CONFIG_X86_64 */
398337
#endif /* CONFIG_X86_LOCAL_APIC */
399338

400339
#ifdef CONFIG_X86_IO_APIC
@@ -1124,29 +1063,6 @@ static int __init acpi_parse_madt_lapic_entries(void)
11241063
}
11251064
return 0;
11261065
}
1127-
1128-
#ifdef CONFIG_X86_64
1129-
static int __init acpi_parse_mp_wake(union acpi_subtable_headers *header,
1130-
const unsigned long end)
1131-
{
1132-
struct acpi_madt_multiproc_wakeup *mp_wake;
1133-
1134-
if (!IS_ENABLED(CONFIG_SMP))
1135-
return -ENODEV;
1136-
1137-
mp_wake = (struct acpi_madt_multiproc_wakeup *)header;
1138-
if (BAD_MADT_ENTRY(mp_wake, end))
1139-
return -EINVAL;
1140-
1141-
acpi_table_print_madt_entry(&header->common);
1142-
1143-
acpi_mp_wake_mailbox_paddr = mp_wake->base_address;
1144-
1145-
apic_update_callback(wakeup_secondary_cpu_64, acpi_wakeup_cpu);
1146-
1147-
return 0;
1148-
}
1149-
#endif /* CONFIG_X86_64 */
11501066
#endif /* CONFIG_X86_LOCAL_APIC */
11511067

11521068
#ifdef CONFIG_X86_IO_APIC
@@ -1343,7 +1259,7 @@ static void __init acpi_process_madt(void)
13431259
smp_found_config = 1;
13441260
}
13451261

1346-
#ifdef CONFIG_X86_64
1262+
#ifdef CONFIG_ACPI_MADT_WAKEUP
13471263
/*
13481264
* Parse MADT MP Wake entry.
13491265
*/

arch/x86/kernel/acpi/madt_wakeup.c

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
#include <linux/acpi.h>
3+
#include <linux/io.h>
4+
#include <asm/apic.h>
5+
#include <asm/barrier.h>
6+
#include <asm/processor.h>
7+
8+
/* Physical address of the Multiprocessor Wakeup Structure mailbox */
9+
static u64 acpi_mp_wake_mailbox_paddr;
10+
11+
/* Virtual address of the Multiprocessor Wakeup Structure mailbox */
12+
static struct acpi_madt_multiproc_wakeup_mailbox *acpi_mp_wake_mailbox;
13+
14+
static int acpi_wakeup_cpu(u32 apicid, unsigned long start_ip)
15+
{
16+
/*
17+
* Remap mailbox memory only for the first call to acpi_wakeup_cpu().
18+
*
19+
* Wakeup of secondary CPUs is fully serialized in the core code.
20+
* No need to protect acpi_mp_wake_mailbox from concurrent accesses.
21+
*/
22+
if (!acpi_mp_wake_mailbox) {
23+
acpi_mp_wake_mailbox = memremap(acpi_mp_wake_mailbox_paddr,
24+
sizeof(*acpi_mp_wake_mailbox),
25+
MEMREMAP_WB);
26+
}
27+
28+
/*
29+
* Mailbox memory is shared between the firmware and OS. Firmware will
30+
* listen on mailbox command address, and once it receives the wakeup
31+
* command, the CPU associated with the given apicid will be booted.
32+
*
33+
* The value of 'apic_id' and 'wakeup_vector' must be visible to the
34+
* firmware before the wakeup command is visible. smp_store_release()
35+
* ensures ordering and visibility.
36+
*/
37+
acpi_mp_wake_mailbox->apic_id = apicid;
38+
acpi_mp_wake_mailbox->wakeup_vector = start_ip;
39+
smp_store_release(&acpi_mp_wake_mailbox->command,
40+
ACPI_MP_WAKE_COMMAND_WAKEUP);
41+
42+
/*
43+
* Wait for the CPU to wake up.
44+
*
45+
* The CPU being woken up is essentially in a spin loop waiting to be
46+
* woken up. It should not take long for it wake up and acknowledge by
47+
* zeroing out ->command.
48+
*
49+
* ACPI specification doesn't provide any guidance on how long kernel
50+
* has to wait for a wake up acknowledgment. It also doesn't provide
51+
* a way to cancel a wake up request if it takes too long.
52+
*
53+
* In TDX environment, the VMM has control over how long it takes to
54+
* wake up secondary. It can postpone scheduling secondary vCPU
55+
* indefinitely. Giving up on wake up request and reporting error opens
56+
* possible attack vector for VMM: it can wake up a secondary CPU when
57+
* kernel doesn't expect it. Wait until positive result of the wake up
58+
* request.
59+
*/
60+
while (READ_ONCE(acpi_mp_wake_mailbox->command))
61+
cpu_relax();
62+
63+
return 0;
64+
}
65+
66+
int __init acpi_parse_mp_wake(union acpi_subtable_headers *header,
67+
const unsigned long end)
68+
{
69+
struct acpi_madt_multiproc_wakeup *mp_wake;
70+
71+
mp_wake = (struct acpi_madt_multiproc_wakeup *)header;
72+
if (BAD_MADT_ENTRY(mp_wake, end))
73+
return -EINVAL;
74+
75+
acpi_table_print_madt_entry(&header->common);
76+
77+
acpi_mp_wake_mailbox_paddr = mp_wake->base_address;
78+
79+
apic_update_callback(wakeup_secondary_cpu_64, acpi_wakeup_cpu);
80+
81+
return 0;
82+
}

0 commit comments

Comments
 (0)