1
0
Fork 0

x86, realmode: fix 64-bit wakeup sequence

There were number of issues in wakeup sequence:

- Wakeup stack was placed in hardcoded address.
- NX bit in EFER was not enabled.
- Initialization incorrectly set physical address
of secondary_startup_64.
- Some alignment issues.

This patch fixes these issues and in addition:

- Unifies coding conventions in .S files.
- Sets alignments of code and data right.

Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@intel.com>
Link: http://lkml.kernel.org/r/1336501366-28617-18-git-send-email-jarkko.sakkinen@intel.com
Originally-by: H. Peter Anvin <hpa@linux.intel.com>
Cc: Rafael J. Wysocki <rjw@sisk.pl>
Cc: Len Brown <len.brown@intel.com>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
hifive-unleashed-5.1
Jarkko Sakkinen 2012-05-08 21:22:40 +03:00 committed by H. Peter Anvin
parent 6feb592dce
commit 8e029fcdd8
9 changed files with 108 additions and 105 deletions

View File

@ -64,7 +64,7 @@ void __init setup_real_mode(void)
*((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)secondary_startup_64;
*((u64 *) __va(real_mode_header.level3_ident_pgt)) =
__pa(level3_ident_pgt) + _KERNPG_TABLE;

View File

@ -13,6 +13,7 @@ always := realmode.bin
realmode-y += header.o
realmode-y += trampoline_$(BITS).o
realmode-y += stack.o
realmode-$(CONFIG_X86_32) += reboot_32.o
realmode-$(CONFIG_ACPI_SLEEP) += wakeup/wakeup.o

View File

@ -9,7 +9,7 @@
.section ".header", "a"
ENTRY(real_mode_header)
GLOBAL(real_mode_header)
.long pa_text_start
.long pa_ro_end
.long pa_end

View File

@ -16,10 +16,9 @@
*/
.section ".text32", "ax"
.code32
.globl machine_real_restart_asm
.balign 16
machine_real_restart_asm:
.balign 16
ENTRY(machine_real_restart_asm)
/* Set up the IDT for real mode. */
lidtl pa_machine_real_restart_idt
@ -67,7 +66,7 @@ machine_real_restart_asm:
.text
.code16
.balign 16
.balign 16
machine_real_restart_asm16:
1:
xorl %ecx, %ecx
@ -102,15 +101,15 @@ bios:
ljmpw $0xf000, $0xfff0
.section ".rodata", "a"
.globl machine_real_restart_idt, machine_real_restart_gdt
.balign 16
machine_real_restart_idt:
.balign 16
GLOBAL(machine_real_restart_idt)
.word 0xffff /* Length - real mode default value */
.long 0 /* Base - real mode default value */
END(machine_real_restart_idt)
.balign 16
machine_real_restart_gdt:
.balign 16
GLOBAL(machine_real_restart_gdt)
/* Self-pointer */
.word 0xffff /* Length - real mode default value */
.long pa_machine_real_restart_gdt
@ -130,3 +129,4 @@ machine_real_restart_gdt:
* semantics we don't have to reload the segments once CR0.PE = 0.
*/
.quad GDT_ENTRY(0x0093, 0x100, 0xffff)
END(machine_real_restart_gdt)

View File

@ -0,0 +1,19 @@
/*
* Common heap and stack allocations
*/
#include <linux/linkage.h>
.data
GLOBAL(HEAP)
.long rm_heap
GLOBAL(heap_end)
.long rm_stack
.bss
.balign 16
GLOBAL(rm_heap)
.space 2048
GLOBAL(rm_stack)
.space 2048
GLOBAL(rm_stack_end)

View File

@ -33,10 +33,9 @@
.text
.code16
.globl trampoline_data
.balign PAGE_SIZE
trampoline_data:
.balign PAGE_SIZE
ENTRY(trampoline_data)
wbinvd # Needed for NUMA-Q should be harmless for others
LJMPW_RM(1f)
@ -70,20 +69,22 @@ trampoline_data:
ENTRY(startup_32) # note: also used from wakeup_asm.S
jmp *%eax
.data
.globl startup_32_smp, boot_gdt, trampoline_status
.balign 4
boot_gdt_descr:
.word __BOOT_DS + 7 # gdt limit
boot_gdt:
.long 0 # gdt base
.section ".rodata","a"
.balign 4
boot_idt_descr:
.word 0 # idt limit = 0
.long 0 # idt base = 0L
trampoline_status:
.long 0
.data
startup_32_smp:
.long 0
boot_gdt_descr:
.word __BOOT_DS + 7 # gdt limit
GLOBAL(boot_gdt)
.long 0 # gdt base
.bss
.balign 4
GLOBAL(trampoline_status) .space 4
GLOBAL(startup_32_smp) .space 4

View File

@ -52,7 +52,7 @@ ENTRY(trampoline_data)
# write marker for master knows we're running
# Setup stack
movw $trampoline_stack_end, %sp
movl $rm_stack_end, %esp
call verify_cpu # Verify the cpu supports long mode
testl %eax, %eax # Check for return code
@ -68,8 +68,11 @@ ENTRY(trampoline_data)
lidtl tidt # load idt with 0, 0
lgdtl tgdt # load gdt with whatever is appropriate
mov $X86_CR0_PE, %ax # protected mode (PE) bit
lmsw %ax # into protected mode
movw $__KERNEL_DS, %dx # Data segment descriptor
# Enable protected mode
movl $X86_CR0_PE, %eax # protected mode (PE) bit
movl %eax, %cr0 # into protected mode
# flush prefetch and jump to startup_32
ljmpl $__KERNEL32_CS, $pa_startup_32
@ -83,27 +86,27 @@ no_longmode:
.code32
.balign 4
ENTRY(startup_32)
movl $__KERNEL_DS, %eax # Initialize the %ds segment register
movl %eax, %ds
movl %edx, %ss
addl $pa_real_mode_base, %esp
movl %edx, %ds
movl %edx, %es
movl %edx, %fs
movl %edx, %gs
movl $X86_CR4_PAE, %eax
movl %eax, %cr4 # Enable PAE mode
movl pa_startup_64_smp, %esi
movl pa_startup_64_smp_high, %edi
# Setup trampoline 4 level pagetables
leal pa_trampoline_level4_pgt, %eax
# Setup trampoline 4 level pagetables
movl $pa_level3_ident_pgt, %eax
movl %eax, %cr3
movl $MSR_EFER, %ecx
movl $(1 << _EFER_LME), %eax # Enable Long Mode
movl $((1 << _EFER_LME) | (1 << _EFER_NX)), %eax # Enable Long Mode
xorl %edx, %edx
wrmsr
# Enable paging and in turn activate Long Mode
# Enable protected mode
movl $(X86_CR0_PG | X86_CR0_PE), %eax
movl $(X86_CR0_PG | X86_CR0_WP | X86_CR0_PE), %eax
movl %eax, %cr0
/*
@ -119,10 +122,7 @@ ENTRY(startup_32)
.balign 4
ENTRY(startup_64)
# Now jump into the kernel using virtual addresses
movl %edi, %eax
shlq $32, %rax
addl %esi, %eax
jmp *%rax
jmpq *startup_64_smp(%rip)
.section ".rodata","a"
.balign 16
@ -132,10 +132,10 @@ tidt:
# Duplicate the global descriptor table
# so the kernel can live anywhere
.balign 4
.balign 16
.globl tgdt
tgdt:
.short tgdt_end - tgdt # gdt limit
.short tgdt_end - tgdt - 1 # gdt limit
.long pa_tgdt
.short 0
.quad 0x00cf9b000000ffff # __KERNEL32_CS
@ -143,23 +143,12 @@ tgdt:
.quad 0x00cf93000000ffff # __KERNEL_DS
tgdt_end:
.data
.balign 4
GLOBAL(trampoline_status)
.long 0
.bss
trampoline_stack:
.org 0x1000
trampoline_stack_end:
.balign PAGE_SIZE
GLOBAL(level3_ident_pgt) .space 511*8
GLOBAL(level3_kernel_pgt) .space 8
.globl level3_ident_pgt
.globl level3_kernel_pgt
GLOBAL(trampoline_level4_pgt)
level3_ident_pgt: .quad 0
.fill 510,8,0
level3_kernel_pgt: .quad 0
.globl startup_64_smp
.globl startup_64_smp_high
startup_64_smp: .long 0
startup_64_smp_high: .long 0
.balign 8
GLOBAL(startup_64_smp) .space 8
GLOBAL(trampoline_status) .space 4

View File

@ -1,6 +1,7 @@
/*
* ACPI wakeup real mode startup stub
*/
#include <linux/linkage.h>
#include <asm/segment.h>
#include <asm/msr-index.h>
#include <asm/page_types.h>
@ -9,31 +10,33 @@
#include "../realmode.h"
#include "wakeup.h"
.code16
.code16
/* This should match the structure in wakeup.h */
.section ".data", "aw"
.globl wakeup_header
wakeup_header:
video_mode: .short 0 /* Video mode number */
pmode_entry: .long 0
pmode_cs: .short __KERNEL_CS
pmode_cr0: .long 0 /* Saved %cr0 */
pmode_cr3: .long 0 /* Saved %cr3 */
pmode_cr4: .long 0 /* Saved %cr4 */
pmode_efer: .quad 0 /* Saved EFER */
pmode_gdt: .quad 0
pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */
pmode_behavior: .long 0 /* Wakeup behavior flags */
realmode_flags: .long 0
real_magic: .long 0
signature: .long WAKEUP_HEADER_SIGNATURE
.size wakeup_header, .-wakeup_header
.section ".data", "aw"
.balign 16
GLOBAL(wakeup_header)
video_mode: .short 0 /* Video mode number */
pmode_entry: .long 0
pmode_cs: .short __KERNEL_CS
pmode_cr0: .long 0 /* Saved %cr0 */
pmode_cr3: .long 0 /* Saved %cr3 */
pmode_cr4: .long 0 /* Saved %cr4 */
pmode_efer: .quad 0 /* Saved EFER */
pmode_gdt: .quad 0
pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */
pmode_behavior: .long 0 /* Wakeup behavior flags */
realmode_flags: .long 0
real_magic: .long 0
signature: .long WAKEUP_HEADER_SIGNATURE
END(wakeup_header)
.text
.code16
.globl wakeup_start
wakeup_start:
.balign 16
ENTRY(wakeup_start)
cli
cld
@ -62,12 +65,14 @@ wakeup_start:
3:
/* Set up segments */
movw %cs, %ax
movw %ax, %ss
movl $rm_stack_end, %esp
movw %ax, %ds
movw %ax, %es
movw %ax, %ss
lidtl wakeup_idt
movw %ax, %fs
movw %ax, %gs
movl $wakeup_stack_end, %esp
lidtl wakeup_idt
/* Clear the EFLAGS */
pushl $0
@ -145,9 +150,8 @@ bogus_real_magic:
* be the case for other laptops or integrated video devices.
*/
.globl wakeup_gdt
.balign 16
wakeup_gdt:
GLOBAL(wakeup_gdt)
.word 3*8-1 /* Self-descriptor */
.long pa_wakeup_gdt
.word 0
@ -159,29 +163,18 @@ wakeup_gdt:
.word 0xffff /* 16-bit data segment @ real_mode_base */
.long 0x93000000 + pa_real_mode_base
.word 0x008f /* big real mode */
.size wakeup_gdt, .-wakeup_gdt
END(wakeup_gdt)
.data
.section ".rodata","a"
.balign 8
/* This is the standard real-mode IDT */
wakeup_idt:
.balign 16
GLOBAL(wakeup_idt)
.word 0xffff /* limit */
.long 0 /* address */
.word 0
.globl HEAP, heap_end
HEAP:
.long wakeup_heap
heap_end:
.long wakeup_stack
.bss
wakeup_heap:
.space 2048
wakeup_stack:
.space 2048
wakeup_stack_end:
END(wakeup_idt)
.section ".signature","a"
end_signature:

View File

@ -9,10 +9,10 @@
.balign PAGE_SIZE
ENTRY(real_mode_blob)
GLOBAL(real_mode_blob)
.incbin "arch/x86/realmode/rm/realmode.bin"
END(real_mode_blob)
ENTRY(real_mode_relocs)
GLOBAL(real_mode_relocs)
.incbin "arch/x86/realmode/rm/realmode.relocs"
END(real_mode_relocs)