mirror of
https://github.com/memtest86plus/memtest86plus.git
synced 2025-02-25 18:55:23 -06:00
Properly protect the startup stack with a mutex.
Because we start the APs sequentially, it is unlikely they will coincide for the brief period that they use the temporary startup stack, but we should guard against it. This allows us to remove the mutex around the restart of each AP when relocating, which should improve test times.
This commit is contained in:
parent
17093a96f9
commit
4100a44b12
10
app/main.c
10
app/main.c
@ -126,9 +126,10 @@ static void run_at(uintptr_t addr, int my_pcpu)
|
|||||||
}
|
}
|
||||||
BARRIER(true);
|
BARRIER(true);
|
||||||
|
|
||||||
// We use a lock to ensure that only one CPU at a time jumps to
|
#ifndef __x86_64__
|
||||||
// the new code. Some of the startup stuff is not thread safe!
|
// The 32-bit startup code needs to know where it is located.
|
||||||
spin_lock(start_mutex);
|
__asm__ __volatile__("movl %0, %%edi" : : "r" (new_start_addr));
|
||||||
|
#endif
|
||||||
|
|
||||||
goto *new_start_addr;
|
goto *new_start_addr;
|
||||||
}
|
}
|
||||||
@ -384,9 +385,6 @@ void main(void)
|
|||||||
} else {
|
} else {
|
||||||
pcpu_state[my_pcpu] = CPU_STATE_RUNNING;
|
pcpu_state[my_pcpu] = CPU_STATE_RUNNING;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// Release the lock taken in run_at().
|
|
||||||
spin_unlock(start_mutex);
|
|
||||||
}
|
}
|
||||||
BARRIER(true);
|
BARRIER(true);
|
||||||
init_state = 2;
|
init_state = 2;
|
||||||
|
@ -49,6 +49,8 @@
|
|||||||
|
|
||||||
extern uint8_t _start[];
|
extern uint8_t _start[];
|
||||||
|
|
||||||
|
extern uint8_t startup32[];
|
||||||
|
|
||||||
extern uint8_t startup[];
|
extern uint8_t startup[];
|
||||||
|
|
||||||
extern uint64_t pml4[];
|
extern uint64_t pml4[];
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
// Copyright (C) 2020-2021 Martin Whitaker.
|
// Copyright (C) 2020-2022 Martin Whitaker.
|
||||||
//
|
//
|
||||||
// Derived from Linux 5.6 arch/x86/boot/compressed/eboot.c and extracts
|
// Derived from Linux 5.6 arch/x86/boot/compressed/eboot.c and extracts
|
||||||
// from drivers/firmware/efi/libstub:
|
// from drivers/firmware/efi/libstub:
|
||||||
@ -541,6 +541,8 @@ boot_params_t *efi_setup(efi_handle_t handle, efi_system_table_t *sys_table_arg,
|
|||||||
memset(boot_params, 0, sizeof(boot_params_t));
|
memset(boot_params, 0, sizeof(boot_params_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boot_params->code32_start = (uintptr_t)startup32;
|
||||||
|
|
||||||
status = set_screen_info(boot_params);
|
status = set_screen_info(boot_params);
|
||||||
if (status != EFI_SUCCESS) {
|
if (status != EFI_SUCCESS) {
|
||||||
print_string("set_screen_info() failed\n");
|
print_string("set_screen_info() failed\n");
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
startup32:
|
startup32:
|
||||||
cld
|
cld
|
||||||
cli
|
cli
|
||||||
jmp startup
|
jmp first_start
|
||||||
|
|
||||||
# The Linux 32-bit EFI handover point.
|
# The Linux 32-bit EFI handover point.
|
||||||
|
|
||||||
@ -62,18 +62,28 @@ efi_handover:
|
|||||||
call efi_setup
|
call efi_setup
|
||||||
|
|
||||||
# Fall though to the shared 32-bit entry point with the boot
|
# Fall though to the shared 32-bit entry point with the boot
|
||||||
# params pointer in %esi.
|
# params pointer in %esi...
|
||||||
|
|
||||||
movl %eax, %esi
|
movl %eax, %esi
|
||||||
|
|
||||||
|
# ...and with the startup address in %edi.
|
||||||
|
|
||||||
|
first_start:
|
||||||
|
movl 0x214(%esi), %ebx # bootparams.code32_start
|
||||||
|
leal (startup - startup32)(%ebx), %edi
|
||||||
|
|
||||||
# The 32-bit entry point for AP boot and for restart after relocation.
|
# The 32-bit entry point for AP boot and for restart after relocation.
|
||||||
|
|
||||||
.globl startup
|
.globl startup
|
||||||
startup:
|
startup:
|
||||||
# Use a temporary stack until we pick the correct one. We can
|
# Use the startup stack until we pick the correct one. We
|
||||||
# safely use the high address, even if we are loaded low.
|
# need to take the mutex to protect our use of the stack.
|
||||||
|
|
||||||
movl $(HIGH_LOAD_ADDR + startup_stack_top - startup32), %esp
|
leal (startup_stack_mutex - startup)(%edi), %eax
|
||||||
|
0: lock bts $0, (%eax)
|
||||||
|
jc 0b
|
||||||
|
|
||||||
|
leal (startup_stack_top - startup)(%edi), %esp
|
||||||
|
|
||||||
# Load the GOT pointer.
|
# Load the GOT pointer.
|
||||||
|
|
||||||
@ -98,6 +108,10 @@ startup:
|
|||||||
leal _end@GOTOFF(%ebx), %esp
|
leal _end@GOTOFF(%ebx), %esp
|
||||||
addl %eax, %esp
|
addl %eax, %esp
|
||||||
|
|
||||||
|
# Release the mutex that protects the startup stack.
|
||||||
|
|
||||||
|
movl $0, startup_stack_mutex@GOTOFF(%ebx)
|
||||||
|
|
||||||
# Initialise the GDT descriptor.
|
# Initialise the GDT descriptor.
|
||||||
|
|
||||||
leal gdt@GOTOFF(%ebx), %eax
|
leal gdt@GOTOFF(%ebx), %eax
|
||||||
@ -495,15 +509,15 @@ ap_trampoline:
|
|||||||
movw %cs, %ax
|
movw %cs, %ax
|
||||||
movw %ax, %ds
|
movw %ax, %ds
|
||||||
|
|
||||||
# Patch the jump address.
|
# Load the startup address and use it to patch the jump address.
|
||||||
|
|
||||||
movl (ap_startup_addr - ap_trampoline), %ebx
|
movl (ap_startup_addr - ap_trampoline), %edi
|
||||||
movl %ebx, (ap_jump - ap_trampoline + 2)
|
movl %edi, (ap_jump - ap_trampoline + 2)
|
||||||
|
|
||||||
# Patch and load the GDT descriptor. It should point to the main
|
# Patch and load the GDT descriptor. It should point to the main
|
||||||
# GDT descriptor, which has already been initialised by the BSP.
|
# GDT descriptor, which has already been initialised by the BSP.
|
||||||
|
|
||||||
movl %ebx, %eax
|
movl %edi, %eax
|
||||||
addl $(gdt - startup), %eax
|
addl $(gdt - startup), %eax
|
||||||
movl %eax, (ap_gdt_descr - ap_trampoline + 2)
|
movl %eax, (ap_gdt_descr - ap_trampoline + 2)
|
||||||
lgdt ap_gdt_descr - ap_trampoline
|
lgdt ap_gdt_descr - ap_trampoline
|
||||||
@ -544,11 +558,15 @@ ap_trampoline_end:
|
|||||||
# Variables.
|
# Variables.
|
||||||
|
|
||||||
.data
|
.data
|
||||||
|
.align 4
|
||||||
|
|
||||||
.globl boot_params_addr
|
.globl boot_params_addr
|
||||||
boot_params_addr:
|
boot_params_addr:
|
||||||
.long 0
|
.long 0
|
||||||
|
|
||||||
|
startup_stack_mutex:
|
||||||
|
.long 0
|
||||||
|
|
||||||
first_boot:
|
first_boot:
|
||||||
.long 1
|
.long 1
|
||||||
|
|
||||||
|
@ -32,19 +32,18 @@ startup32:
|
|||||||
cld
|
cld
|
||||||
cli
|
cli
|
||||||
|
|
||||||
# Use a temporary stack until we pick the correct one. We can
|
|
||||||
# safely use the high address, even if we are loaded low.
|
|
||||||
|
|
||||||
movl $(HIGH_LOAD_ADDR + startup_stack_top - startup32), %esp
|
|
||||||
|
|
||||||
# Get the load address.
|
# Get the load address.
|
||||||
|
|
||||||
movl 0x214(%esi), %ebx
|
movl 0x214(%esi), %ebx # bootparams.code32_start
|
||||||
|
|
||||||
# Save the boot params pointer.
|
# Save the boot params pointer.
|
||||||
|
|
||||||
movl %esi, (boot_params_addr - startup32)(%ebx)
|
movl %esi, (boot_params_addr - startup32)(%ebx)
|
||||||
|
|
||||||
|
# Use the startup stack until we pick the correct one.
|
||||||
|
|
||||||
|
leal (startup_stack_top - startup32)(%ebx), %esp
|
||||||
|
|
||||||
# Initialise the pml4 and pdp tables.
|
# Initialise the pml4 and pdp tables.
|
||||||
|
|
||||||
leal (pml4 - startup32)(%ebx), %ecx
|
leal (pml4 - startup32)(%ebx), %ecx
|
||||||
@ -143,8 +142,11 @@ efi_handover:
|
|||||||
|
|
||||||
.globl startup
|
.globl startup
|
||||||
startup:
|
startup:
|
||||||
# Use a temporary stack until we pick the correct one.
|
# Use the startup stack until we pick the correct one. We
|
||||||
|
# need to take a mutex to protect our use of the stack.
|
||||||
|
|
||||||
|
0: lock bts $0, startup_stack_mutex(%rip)
|
||||||
|
jc 0b
|
||||||
leaq startup_stack_top(%rip), %rsp
|
leaq startup_stack_top(%rip), %rsp
|
||||||
|
|
||||||
# Pick the correct stack. The stacks are allocated immediately
|
# Pick the correct stack. The stacks are allocated immediately
|
||||||
@ -158,6 +160,9 @@ startup:
|
|||||||
leaq _end(%rip), %rsp
|
leaq _end(%rip), %rsp
|
||||||
addq %rax, %rsp
|
addq %rax, %rsp
|
||||||
|
|
||||||
|
# Release the mutex that protects the startup stack.
|
||||||
|
movl $0, startup_stack_mutex(%rip)
|
||||||
|
|
||||||
# Initialise the pml4 and pdp tables.
|
# Initialise the pml4 and pdp tables.
|
||||||
|
|
||||||
leaq pml4(%rip), %rcx
|
leaq pml4(%rip), %rcx
|
||||||
@ -589,11 +594,15 @@ ap_trampoline_end:
|
|||||||
# Variables.
|
# Variables.
|
||||||
|
|
||||||
.data
|
.data
|
||||||
|
.align 4
|
||||||
|
|
||||||
.globl boot_params_addr
|
.globl boot_params_addr
|
||||||
boot_params_addr:
|
boot_params_addr:
|
||||||
.quad 0
|
.quad 0
|
||||||
|
|
||||||
|
startup_stack_mutex:
|
||||||
|
.long 0
|
||||||
|
|
||||||
first_boot:
|
first_boot:
|
||||||
.long 1
|
.long 1
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user