arch/x86/kernel/acpi/madt_wakeup.c
Source file repositories/reference/linux-study-clean/arch/x86/kernel/acpi/madt_wakeup.c
File Facts
- System
- Linux kernel
- Corpus path
arch/x86/kernel/acpi/madt_wakeup.c- Extension
.c- Size
- 8007 bytes
- Lines
- 266
- Domain
- Architecture Layer
- Bucket
- arch/x86
- Inferred role
- Architecture Layer: implementation source
- Status
- source implementation candidate
Why This File Exists
CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.
- CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/acpi.hlinux/cpu.hlinux/delay.hlinux/io.hlinux/kexec.hlinux/memblock.hlinux/pgtable.hlinux/sched/hotplug.hasm/apic.hasm/barrier.hasm/init.hasm/intel_pt.hasm/nmi.hasm/processor.hasm/reboot.h
Detected Declarations
function acpi_mp_stop_this_cpufunction acpi_mp_play_deadfunction acpi_mp_cpu_diefunction free_pgt_pagefunction acpi_mp_setup_resetfunction acpi_wakeup_cpufunction acpi_wakeup_cpufunction acpi_mp_disable_offliningfunction acpi_parse_mp_wakefunction acpi_setup_mp_wakeup_mailboxfunction acpi_get_mp_wakeup_mailbox_paddr
Annotated Snippet
if (kernel_ident_mapping_init(&info, pgd, mstart, mend)) {
kernel_ident_mapping_free(&info, pgd);
return -ENOMEM;
}
}
mstart = PAGE_ALIGN_DOWN(reset_vector);
mend = mstart + PAGE_SIZE;
if (kernel_ident_mapping_init(&info, pgd, mstart, mend)) {
kernel_ident_mapping_free(&info, pgd);
return -ENOMEM;
}
/*
* Make sure asm_acpi_mp_play_dead() is present in the identity mapping
* at the same place as in the kernel page tables.
* asm_acpi_mp_play_dead() switches to the identity mapping and the
* function must be present at the same spot in the virtual address space
* before and after switching page tables.
*/
info.offset = __START_KERNEL_map - phys_base;
mstart = PAGE_ALIGN_DOWN(__pa(asm_acpi_mp_play_dead));
mend = mstart + PAGE_SIZE;
if (kernel_ident_mapping_init(&info, pgd, mstart, mend)) {
kernel_ident_mapping_free(&info, pgd);
return -ENOMEM;
}
smp_ops.play_dead = acpi_mp_play_dead;
smp_ops.stop_this_cpu = acpi_mp_stop_this_cpu;
smp_ops.cpu_die = acpi_mp_cpu_die;
acpi_mp_reset_vector_paddr = reset_vector;
acpi_mp_pgd = __pa(pgd);
return 0;
}
static int acpi_wakeup_cpu(u32 apicid, unsigned long start_ip, unsigned int cpu)
{
if (!acpi_mp_wake_mailbox_paddr) {
pr_warn_once("No MADT mailbox: cannot bringup secondary CPUs. Booting with kexec?\n");
return -EOPNOTSUPP;
}
/*
* Remap mailbox memory only for the first call to acpi_wakeup_cpu().
*
* Wakeup of secondary CPUs is fully serialized in the core code.
* No need to protect acpi_mp_wake_mailbox from concurrent accesses.
*/
if (!acpi_mp_wake_mailbox) {
acpi_mp_wake_mailbox = memremap(acpi_mp_wake_mailbox_paddr,
sizeof(*acpi_mp_wake_mailbox),
MEMREMAP_WB);
}
/*
* Mailbox memory is shared between the firmware and OS. Firmware will
* listen on mailbox command address, and once it receives the wakeup
* command, the CPU associated with the given apicid will be booted.
*
* The value of 'apic_id' and 'wakeup_vector' must be visible to the
* firmware before the wakeup command is visible. smp_store_release()
* ensures ordering and visibility.
*/
acpi_mp_wake_mailbox->apic_id = apicid;
acpi_mp_wake_mailbox->wakeup_vector = start_ip;
smp_store_release(&acpi_mp_wake_mailbox->command,
ACPI_MP_WAKE_COMMAND_WAKEUP);
/*
* Wait for the CPU to wake up.
*
* The CPU being woken up is essentially in a spin loop waiting to be
* woken up. It should not take long for it wake up and acknowledge by
* zeroing out ->command.
*
* ACPI specification doesn't provide any guidance on how long kernel
* has to wait for a wake up acknowledgment. It also doesn't provide
* a way to cancel a wake up request if it takes too long.
*
* In TDX environment, the VMM has control over how long it takes to
* wake up secondary. It can postpone scheduling secondary vCPU
* indefinitely. Giving up on wake up request and reporting error opens
* possible attack vector for VMM: it can wake up a secondary CPU when
* kernel doesn't expect it. Wait until positive result of the wake up
* request.
*/
while (READ_ONCE(acpi_mp_wake_mailbox->command))
Annotation
- Immediate include surface: `linux/acpi.h`, `linux/cpu.h`, `linux/delay.h`, `linux/io.h`, `linux/kexec.h`, `linux/memblock.h`, `linux/pgtable.h`, `linux/sched/hotplug.h`.
- Detected declarations: `function acpi_mp_stop_this_cpu`, `function acpi_mp_play_dead`, `function acpi_mp_cpu_die`, `function free_pgt_page`, `function acpi_mp_setup_reset`, `function acpi_wakeup_cpu`, `function acpi_wakeup_cpu`, `function acpi_mp_disable_offlining`, `function acpi_parse_mp_wake`, `function acpi_setup_mp_wakeup_mailbox`.
- Atlas domain: Architecture Layer / arch/x86.
- Implementation status: source implementation candidate.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.