Commit 8e029fcd authored by Jarkko Sakkinen's avatar Jarkko Sakkinen Committed by H. Peter Anvin

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: default avatarJarkko Sakkinen <jarkko.sakkinen@intel.com>
Link: http://lkml.kernel.org/r/1336501366-28617-18-git-send-email-jarkko.sakkinen@intel.comOriginally-by: default avatarH. Peter Anvin <hpa@linux.intel.com>
Cc: Rafael J. Wysocki <rjw@sisk.pl>
Cc: Len Brown <len.brown@intel.com>
Signed-off-by: default avatarH. Peter Anvin <hpa@linux.intel.com>
parent 6feb592d
...@@ -64,7 +64,7 @@ void __init setup_real_mode(void) ...@@ -64,7 +64,7 @@ void __init setup_real_mode(void)
*((u32 *)__va(real_mode_header.boot_gdt)) = __pa(boot_gdt); *((u32 *)__va(real_mode_header.boot_gdt)) = __pa(boot_gdt);
#else #else
*((u64 *) __va(real_mode_header.startup_64_smp)) = *((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)) = *((u64 *) __va(real_mode_header.level3_ident_pgt)) =
__pa(level3_ident_pgt) + _KERNPG_TABLE; __pa(level3_ident_pgt) + _KERNPG_TABLE;
......
...@@ -13,6 +13,7 @@ always := realmode.bin ...@@ -13,6 +13,7 @@ always := realmode.bin
realmode-y += header.o realmode-y += header.o
realmode-y += trampoline_$(BITS).o realmode-y += trampoline_$(BITS).o
realmode-y += stack.o
realmode-$(CONFIG_X86_32) += reboot_32.o realmode-$(CONFIG_X86_32) += reboot_32.o
realmode-$(CONFIG_ACPI_SLEEP) += wakeup/wakeup.o realmode-$(CONFIG_ACPI_SLEEP) += wakeup/wakeup.o
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
.section ".header", "a" .section ".header", "a"
ENTRY(real_mode_header) GLOBAL(real_mode_header)
.long pa_text_start .long pa_text_start
.long pa_ro_end .long pa_ro_end
.long pa_end .long pa_end
......
...@@ -16,10 +16,9 @@ ...@@ -16,10 +16,9 @@
*/ */
.section ".text32", "ax" .section ".text32", "ax"
.code32 .code32
.globl machine_real_restart_asm
.balign 16 .balign 16
machine_real_restart_asm: ENTRY(machine_real_restart_asm)
/* Set up the IDT for real mode. */ /* Set up the IDT for real mode. */
lidtl pa_machine_real_restart_idt lidtl pa_machine_real_restart_idt
...@@ -67,7 +66,7 @@ machine_real_restart_asm: ...@@ -67,7 +66,7 @@ machine_real_restart_asm:
.text .text
.code16 .code16
.balign 16 .balign 16
machine_real_restart_asm16: machine_real_restart_asm16:
1: 1:
xorl %ecx, %ecx xorl %ecx, %ecx
...@@ -102,15 +101,15 @@ bios: ...@@ -102,15 +101,15 @@ bios:
ljmpw $0xf000, $0xfff0 ljmpw $0xf000, $0xfff0
.section ".rodata", "a" .section ".rodata", "a"
.globl machine_real_restart_idt, machine_real_restart_gdt
.balign 16 .balign 16
machine_real_restart_idt: GLOBAL(machine_real_restart_idt)
.word 0xffff /* Length - real mode default value */ .word 0xffff /* Length - real mode default value */
.long 0 /* Base - real mode default value */ .long 0 /* Base - real mode default value */
END(machine_real_restart_idt)
.balign 16 .balign 16
machine_real_restart_gdt: GLOBAL(machine_real_restart_gdt)
/* Self-pointer */ /* Self-pointer */
.word 0xffff /* Length - real mode default value */ .word 0xffff /* Length - real mode default value */
.long pa_machine_real_restart_gdt .long pa_machine_real_restart_gdt
...@@ -130,3 +129,4 @@ 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. * semantics we don't have to reload the segments once CR0.PE = 0.
*/ */
.quad GDT_ENTRY(0x0093, 0x100, 0xffff) .quad GDT_ENTRY(0x0093, 0x100, 0xffff)
END(machine_real_restart_gdt)
/*
* 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)
...@@ -33,10 +33,9 @@ ...@@ -33,10 +33,9 @@
.text .text
.code16 .code16
.globl trampoline_data
.balign PAGE_SIZE .balign PAGE_SIZE
trampoline_data: ENTRY(trampoline_data)
wbinvd # Needed for NUMA-Q should be harmless for others wbinvd # Needed for NUMA-Q should be harmless for others
LJMPW_RM(1f) LJMPW_RM(1f)
...@@ -70,20 +69,22 @@ trampoline_data: ...@@ -70,20 +69,22 @@ trampoline_data:
ENTRY(startup_32) # note: also used from wakeup_asm.S ENTRY(startup_32) # note: also used from wakeup_asm.S
jmp *%eax jmp *%eax
.data .section ".rodata","a"
.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
.balign 4
boot_idt_descr: boot_idt_descr:
.word 0 # idt limit = 0 .word 0 # idt limit = 0
.long 0 # idt base = 0L .long 0 # idt base = 0L
trampoline_status: .data
.long 0
startup_32_smp: boot_gdt_descr:
.long 0 .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
...@@ -52,7 +52,7 @@ ENTRY(trampoline_data) ...@@ -52,7 +52,7 @@ ENTRY(trampoline_data)
# write marker for master knows we're running # write marker for master knows we're running
# Setup stack # Setup stack
movw $trampoline_stack_end, %sp movl $rm_stack_end, %esp
call verify_cpu # Verify the cpu supports long mode call verify_cpu # Verify the cpu supports long mode
testl %eax, %eax # Check for return code testl %eax, %eax # Check for return code
...@@ -68,8 +68,11 @@ ENTRY(trampoline_data) ...@@ -68,8 +68,11 @@ ENTRY(trampoline_data)
lidtl tidt # load idt with 0, 0 lidtl tidt # load idt with 0, 0
lgdtl tgdt # load gdt with whatever is appropriate lgdtl tgdt # load gdt with whatever is appropriate
mov $X86_CR0_PE, %ax # protected mode (PE) bit movw $__KERNEL_DS, %dx # Data segment descriptor
lmsw %ax # into protected mode
# 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 # flush prefetch and jump to startup_32
ljmpl $__KERNEL32_CS, $pa_startup_32 ljmpl $__KERNEL32_CS, $pa_startup_32
...@@ -83,27 +86,27 @@ no_longmode: ...@@ -83,27 +86,27 @@ no_longmode:
.code32 .code32
.balign 4 .balign 4
ENTRY(startup_32) ENTRY(startup_32)
movl $__KERNEL_DS, %eax # Initialize the %ds segment register movl %edx, %ss
movl %eax, %ds addl $pa_real_mode_base, %esp
movl %edx, %ds
movl %edx, %es
movl %edx, %fs
movl %edx, %gs
movl $X86_CR4_PAE, %eax movl $X86_CR4_PAE, %eax
movl %eax, %cr4 # Enable PAE mode movl %eax, %cr4 # Enable PAE mode
movl pa_startup_64_smp, %esi # Setup trampoline 4 level pagetables
movl pa_startup_64_smp_high, %edi movl $pa_level3_ident_pgt, %eax
# Setup trampoline 4 level pagetables
leal pa_trampoline_level4_pgt, %eax
movl %eax, %cr3 movl %eax, %cr3
movl $MSR_EFER, %ecx 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 xorl %edx, %edx
wrmsr wrmsr
# Enable paging and in turn activate Long Mode # Enable paging and in turn activate Long Mode
# Enable protected mode movl $(X86_CR0_PG | X86_CR0_WP | X86_CR0_PE), %eax
movl $(X86_CR0_PG | X86_CR0_PE), %eax
movl %eax, %cr0 movl %eax, %cr0
/* /*
...@@ -119,10 +122,7 @@ ENTRY(startup_32) ...@@ -119,10 +122,7 @@ ENTRY(startup_32)
.balign 4 .balign 4
ENTRY(startup_64) ENTRY(startup_64)
# Now jump into the kernel using virtual addresses # Now jump into the kernel using virtual addresses
movl %edi, %eax jmpq *startup_64_smp(%rip)
shlq $32, %rax
addl %esi, %eax
jmp *%rax
.section ".rodata","a" .section ".rodata","a"
.balign 16 .balign 16
...@@ -132,10 +132,10 @@ tidt: ...@@ -132,10 +132,10 @@ tidt:
# Duplicate the global descriptor table # Duplicate the global descriptor table
# so the kernel can live anywhere # so the kernel can live anywhere
.balign 4 .balign 16
.globl tgdt .globl tgdt
tgdt: tgdt:
.short tgdt_end - tgdt # gdt limit .short tgdt_end - tgdt - 1 # gdt limit
.long pa_tgdt .long pa_tgdt
.short 0 .short 0
.quad 0x00cf9b000000ffff # __KERNEL32_CS .quad 0x00cf9b000000ffff # __KERNEL32_CS
...@@ -143,23 +143,12 @@ tgdt: ...@@ -143,23 +143,12 @@ tgdt:
.quad 0x00cf93000000ffff # __KERNEL_DS .quad 0x00cf93000000ffff # __KERNEL_DS
tgdt_end: tgdt_end:
.data .bss
.balign 4
GLOBAL(trampoline_status) .balign PAGE_SIZE
.long 0 GLOBAL(level3_ident_pgt) .space 511*8
GLOBAL(level3_kernel_pgt) .space 8
trampoline_stack:
.org 0x1000 .balign 8
trampoline_stack_end: GLOBAL(startup_64_smp) .space 8
GLOBAL(trampoline_status) .space 4
.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
/* /*
* ACPI wakeup real mode startup stub * ACPI wakeup real mode startup stub
*/ */
#include <linux/linkage.h>
#include <asm/segment.h> #include <asm/segment.h>
#include <asm/msr-index.h> #include <asm/msr-index.h>
#include <asm/page_types.h> #include <asm/page_types.h>
...@@ -9,31 +10,33 @@ ...@@ -9,31 +10,33 @@
#include "../realmode.h" #include "../realmode.h"
#include "wakeup.h" #include "wakeup.h"
.code16 .code16
/* This should match the structure in wakeup.h */ /* This should match the structure in wakeup.h */
.section ".data", "aw" .section ".data", "aw"
.globl wakeup_header
wakeup_header: .balign 16
video_mode: .short 0 /* Video mode number */ GLOBAL(wakeup_header)
pmode_entry: .long 0 video_mode: .short 0 /* Video mode number */
pmode_cs: .short __KERNEL_CS pmode_entry: .long 0
pmode_cr0: .long 0 /* Saved %cr0 */ pmode_cs: .short __KERNEL_CS
pmode_cr3: .long 0 /* Saved %cr3 */ pmode_cr0: .long 0 /* Saved %cr0 */
pmode_cr4: .long 0 /* Saved %cr4 */ pmode_cr3: .long 0 /* Saved %cr3 */
pmode_efer: .quad 0 /* Saved EFER */ pmode_cr4: .long 0 /* Saved %cr4 */
pmode_gdt: .quad 0 pmode_efer: .quad 0 /* Saved EFER */
pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */ pmode_gdt: .quad 0
pmode_behavior: .long 0 /* Wakeup behavior flags */ pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */
realmode_flags: .long 0 pmode_behavior: .long 0 /* Wakeup behavior flags */
real_magic: .long 0 realmode_flags: .long 0
signature: .long WAKEUP_HEADER_SIGNATURE real_magic: .long 0
.size wakeup_header, .-wakeup_header signature: .long WAKEUP_HEADER_SIGNATURE
END(wakeup_header)
.text .text
.code16 .code16
.globl wakeup_start
wakeup_start: .balign 16
ENTRY(wakeup_start)
cli cli
cld cld
...@@ -62,12 +65,14 @@ wakeup_start: ...@@ -62,12 +65,14 @@ wakeup_start:
3: 3:
/* Set up segments */ /* Set up segments */
movw %cs, %ax movw %cs, %ax
movw %ax, %ss
movl $rm_stack_end, %esp
movw %ax, %ds movw %ax, %ds
movw %ax, %es movw %ax, %es
movw %ax, %ss movw %ax, %fs
lidtl wakeup_idt movw %ax, %gs
movl $wakeup_stack_end, %esp lidtl wakeup_idt
/* Clear the EFLAGS */ /* Clear the EFLAGS */
pushl $0 pushl $0
...@@ -145,9 +150,8 @@ bogus_real_magic: ...@@ -145,9 +150,8 @@ bogus_real_magic:
* be the case for other laptops or integrated video devices. * be the case for other laptops or integrated video devices.
*/ */
.globl wakeup_gdt
.balign 16 .balign 16
wakeup_gdt: GLOBAL(wakeup_gdt)
.word 3*8-1 /* Self-descriptor */ .word 3*8-1 /* Self-descriptor */
.long pa_wakeup_gdt .long pa_wakeup_gdt
.word 0 .word 0
...@@ -159,29 +163,18 @@ wakeup_gdt: ...@@ -159,29 +163,18 @@ wakeup_gdt:
.word 0xffff /* 16-bit data segment @ real_mode_base */ .word 0xffff /* 16-bit data segment @ real_mode_base */
.long 0x93000000 + pa_real_mode_base .long 0x93000000 + pa_real_mode_base
.word 0x008f /* big real mode */ .word 0x008f /* big real mode */
.size wakeup_gdt, .-wakeup_gdt END(wakeup_gdt)
.data .section ".rodata","a"
.balign 8 .balign 8
/* This is the standard real-mode IDT */ /* This is the standard real-mode IDT */
wakeup_idt: .balign 16
GLOBAL(wakeup_idt)
.word 0xffff /* limit */ .word 0xffff /* limit */
.long 0 /* address */ .long 0 /* address */
.word 0 .word 0
END(wakeup_idt)
.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:
.section ".signature","a" .section ".signature","a"
end_signature: end_signature:
......
...@@ -9,10 +9,10 @@ ...@@ -9,10 +9,10 @@
.balign PAGE_SIZE .balign PAGE_SIZE
ENTRY(real_mode_blob) GLOBAL(real_mode_blob)
.incbin "arch/x86/realmode/rm/realmode.bin" .incbin "arch/x86/realmode/rm/realmode.bin"
END(real_mode_blob) END(real_mode_blob)
ENTRY(real_mode_relocs) GLOBAL(real_mode_relocs)
.incbin "arch/x86/realmode/rm/realmode.relocs" .incbin "arch/x86/realmode/rm/realmode.relocs"
END(real_mode_relocs) END(real_mode_relocs)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment