Skip to content

Commit

Permalink
x86, realmode: Move SMP trampoline to unified realmode code
Browse files Browse the repository at this point in the history
Migrated SMP trampoline code to the real mode blob.
SMP trampoline code is not yet removed from
.x86_trampoline because it is needed by the wakeup
code.

[ hpa: always enable compiling startup_32_smp in head_32.S... it is
  only a few instructions which go into .init on UP builds, and it makes
  the rest of the code less #ifdef ugly. ]

Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@intel.com>
Link: http://lkml.kernel.org/r/1336501366-28617-6-git-send-email-jarkko.sakkinen@intel.com
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
  • Loading branch information
Jarkko Sakkinen authored and H. Peter Anvin committed May 8, 2012
1 parent 5a8c9ae commit 48927bb
Show file tree
Hide file tree
Showing 9 changed files with 316 additions and 16 deletions.
18 changes: 18 additions & 0 deletions arch/x86/include/asm/realmode.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@ struct real_mode_header {
/* reboot */
#ifdef CONFIG_X86_32
u32 machine_real_restart_asm;
#endif
/* SMP trampoline */
u32 trampoline_data;
u32 trampoline_status;
#ifdef CONFIG_X86_32
u32 startup_32_smp;
u32 boot_gdt;
#else
u32 startup_64_smp;
u32 level3_ident_pgt;
u32 level3_kernel_pgt;
#endif
} __attribute__((__packed__));

Expand All @@ -25,6 +36,13 @@ extern unsigned long initial_gs;
extern unsigned char real_mode_blob[];
extern unsigned char real_mode_relocs[];

#ifdef CONFIG_X86_32
extern unsigned char startup_32_smp[];
extern unsigned char boot_gdt[];
#else
extern unsigned char secondary_startup_64[];
#endif

extern void __init setup_real_mode(void);

#endif /* _ARCH_X86_REALMODE_H */
5 changes: 1 addition & 4 deletions arch/x86/kernel/head_32.S
Original file line number Diff line number Diff line change
Expand Up @@ -273,10 +273,7 @@ num_subarch_entries = (. - subarch_entries) / 4
* If cpu hotplug is not supported then this code can go in init section
* which will be freed later
*/

__CPUINIT

#ifdef CONFIG_SMP
ENTRY(startup_32_smp)
cld
movl $(__BOOT_DS),%eax
Expand All @@ -287,7 +284,7 @@ ENTRY(startup_32_smp)
movl pa(stack_start),%ecx
movl %eax,%ss
leal -__PAGE_OFFSET(%ecx),%esp
#endif /* CONFIG_SMP */

default_entry:

/*
Expand Down
4 changes: 0 additions & 4 deletions arch/x86/kernel/head_64.S
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,6 @@ ident_complete:
/* Fixup phys_base */
addq %rbp, phys_base(%rip)

/* Fixup trampoline */
addq %rbp, trampoline_level4_pgt + 0(%rip)
addq %rbp, trampoline_level4_pgt + (511*8)(%rip)

/* Due to ENTRY(), sometimes the empty space gets filled with
* zeros. Better take a jmp than relying on empty space being
* filled with 0x90 (nop)
Expand Down
14 changes: 14 additions & 0 deletions arch/x86/kernel/realmode.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,20 @@ void __init setup_real_mode(void)
/* Copied header will contain relocated physical addresses. */
memcpy(&real_mode_header, real_mode_base,
sizeof(struct real_mode_header));

#ifdef CONFIG_X86_32
*((u32 *)__va(real_mode_header.startup_32_smp)) = __pa(startup_32_smp);
*((u32 *)__va(real_mode_header.boot_gdt)) = __pa(boot_gdt);
#else
*((u64 *) __va(real_mode_header.startup_64_smp)) =
(u64) __pa(secondary_startup_64);

*((u64 *) __va(real_mode_header.level3_ident_pgt)) =
__pa(level3_ident_pgt) + _KERNPG_TABLE;

*((u64 *) __va(real_mode_header.level3_kernel_pgt)) =
__pa(level3_kernel_pgt) + _KERNPG_TABLE;
#endif
}

/*
Expand Down
18 changes: 10 additions & 8 deletions arch/x86/kernel/smpboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
#include <asm/nmi.h>
#include <asm/irq.h>
#include <asm/idle.h>
#include <asm/trampoline.h>
#include <asm/realmode.h>
#include <asm/cpu.h>
#include <asm/numa.h>
#include <asm/pgtable.h>
Expand All @@ -73,6 +73,8 @@
#include <asm/smpboot_hooks.h>
#include <asm/i8259.h>

#include <asm/realmode.h>

/* State of each CPU */
DEFINE_PER_CPU(int, cpu_state) = { 0 };

Expand Down Expand Up @@ -662,8 +664,12 @@ static void __cpuinit announce_cpu(int cpu, int apicid)
*/
static int __cpuinit do_boot_cpu(int apicid, int cpu)
{
volatile u32 *trampoline_status =
(volatile u32 *) __va(real_mode_header.trampoline_status);
/* start_ip had better be page-aligned! */
unsigned long start_ip = real_mode_header.trampoline_data;

unsigned long boot_error = 0;
unsigned long start_ip;
int timeout;
struct create_idle c_idle = {
.cpu = cpu,
Expand Down Expand Up @@ -713,9 +719,6 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu)
initial_code = (unsigned long)start_secondary;
stack_start = c_idle.idle->thread.sp;

/* start_ip had better be page-aligned! */
start_ip = trampoline_address();

/* So we see what's up */
announce_cpu(cpu, apicid);

Expand Down Expand Up @@ -778,8 +781,7 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu)
pr_debug("CPU%d: has booted.\n", cpu);
} else {
boot_error = 1;
if (*(volatile u32 *)TRAMPOLINE_SYM(trampoline_status)
== 0xA5A5A5A5)
if (*trampoline_status == 0xA5A5A5A5)
/* trampoline started but...? */
pr_err("CPU%d: Stuck ??\n", cpu);
else
Expand All @@ -805,7 +807,7 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu)
}

/* mark "stuck" area as not stuck */
*(volatile u32 *)TRAMPOLINE_SYM(trampoline_status) = 0;
*trampoline_status = 0;

if (get_uv_system_type() != UV_NON_UNIQUE_APIC) {
/*
Expand Down
1 change: 1 addition & 0 deletions arch/x86/realmode/rm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ always := realmode.bin

realmode-y += header.o
realmode-$(CONFIG_X86_32) += reboot_32.o
realmode-y += trampoline_$(BITS).o

targets += $(realmode-y)

Expand Down
11 changes: 11 additions & 0 deletions arch/x86/realmode/rm/header.S
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,16 @@ ENTRY(real_mode_header)
.long pa_end
#ifdef CONFIG_X86_32
.long pa_machine_real_restart_asm
#endif
/* SMP trampoline */
.long pa_trampoline_data
.long pa_trampoline_status
#ifdef CONFIG_X86_32
.long pa_startup_32_smp
.long pa_boot_gdt
#else
.long pa_startup_64_smp
.long pa_level3_ident_pgt
.long pa_level3_kernel_pgt
#endif
END(real_mode_header)
86 changes: 86 additions & 0 deletions arch/x86/realmode/rm/trampoline_32.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
*
* Trampoline.S Derived from Setup.S by Linus Torvalds
*
* 4 Jan 1997 Michael Chastain: changed to gnu as.
*
* This is only used for booting secondary CPUs in SMP machine
*
* Entry: CS:IP point to the start of our code, we are
* in real mode with no stack, but the rest of the
* trampoline page to make our stack and everything else
* is a mystery.
*
* We jump into arch/x86/kernel/head_32.S.
*
* On entry to trampoline_data, the processor is in real mode
* with 16-bit addressing and 16-bit data. CS has some value
* and IP is zero. Thus, we load CS to the physical segment
* of the real mode code before doing anything further.
*
* The structure real_mode_header includes entries that need
* to be set up before executing this code:
*
* startup_32_smp
* boot_gdt
*/

#include <linux/linkage.h>
#include <linux/init.h>
#include <asm/segment.h>
#include <asm/page_types.h>

.text
.code16
.globl trampoline_data

.balign PAGE_SIZE
trampoline_data:
wbinvd # Needed for NUMA-Q should be harmless for others

.byte 0xea # ljmpw
.word 1f # Offset
.word real_mode_seg # Segment
1:
mov %cs, %ax # Code and data in the same place
mov %ax, %ds

cli # We should be safe anyway

movl $0xA5A5A5A5, trampoline_status
# write marker for master knows we're running

/* GDT tables in non default location kernel can be beyond 16MB and
* lgdt will not be able to load the address as in real mode default
* operand size is 16bit. Use lgdtl instead to force operand size
* to 32 bit.
*/

lidtl boot_idt_descr # load idt with 0, 0
lgdtl boot_gdt_descr # load gdt with whatever is appropriate

xor %ax, %ax
inc %ax # protected mode (PE) bit
lmsw %ax # into protected mode

# flush prefetch and jump to startup_32_smp in arch/i386/kernel/head.S
ljmpl *(startup_32_smp)

.data
.globl startup_32_smp, boot_gdt, trampoline_status

boot_gdt_descr:
.word __BOOT_DS + 7 # gdt limit
boot_gdt:
.long 0 # gdt base

boot_idt_descr:
.word 0 # idt limit = 0
.long 0 # idt base = 0L

trampoline_status:
.long 0

startup_32_smp:
.long 0x00000000
.word __BOOT_CS, 0
Loading

0 comments on commit 48927bb

Please sign in to comment.