mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
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>
This commit is contained in:
parent
6feb592dce
commit
8e029fcdd8
@ -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
|
|||||||
|
|
||||||
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 @@
|
|||||||
|
|
||||||
.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 @@
|
|||||||
*/
|
*/
|
||||||
.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:
|
|||||||
.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:
|
|||||||
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:
|
|||||||
* 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)
|
||||||
|
19
arch/x86/realmode/rm/stack.S
Normal file
19
arch/x86/realmode/rm/stack.S
Normal 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)
|
@ -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:
|
|||||||
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)
|
|||||||
# 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)
|
|||||||
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:
|
|||||||
.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)
|
|||||||
.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:
|
|||||||
|
|
||||||
# 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:
|
|||||||
.quad 0x00cf93000000ffff # __KERNEL_DS
|
.quad 0x00cf93000000ffff # __KERNEL_DS
|
||||||
tgdt_end:
|
tgdt_end:
|
||||||
|
|
||||||
.data
|
.bss
|
||||||
.balign 4
|
|
||||||
GLOBAL(trampoline_status)
|
|
||||||
.long 0
|
|
||||||
|
|
||||||
trampoline_stack:
|
.balign PAGE_SIZE
|
||||||
.org 0x1000
|
GLOBAL(level3_ident_pgt) .space 511*8
|
||||||
trampoline_stack_end:
|
GLOBAL(level3_kernel_pgt) .space 8
|
||||||
|
|
||||||
.globl level3_ident_pgt
|
.balign 8
|
||||||
.globl level3_kernel_pgt
|
GLOBAL(startup_64_smp) .space 8
|
||||||
GLOBAL(trampoline_level4_pgt)
|
GLOBAL(trampoline_status) .space 4
|
||||||
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
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* 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 @@
|
|||||||
#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:
|
|||||||
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:
|
|||||||
* 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:
|
|||||||
.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 @@
|
|||||||
|
|
||||||
.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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user