From b3266bd6ff52efb9e57c7fbfff4c8f7363dfaab3 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Tue, 8 May 2012 21:22:25 +0300 Subject: x86, realmode: realmode.bin infrastructure Create realmode.bin and realmode.relocs files. Piggy pack them into relocatable object that will be included into .init.data section of the main kernel image. The first file includes binary image of the real-mode code. The latter file includes all relocations. The layout of the binary image is specified in realmode.lds.S. The makefile generates pa_ prefixed symbols for each exported global. These are used in 32-bit code and in realmode header to define symbols that need to be relocated. Signed-off-by: Jarkko Sakkinen Link: http://lkml.kernel.org/r/1336501366-28617-3-git-send-email-jarkko.sakkinen@intel.com Originally-by: H. Peter Anvin Signed-off-by: H. Peter Anvin --- arch/x86/realmode/Makefile | 20 +++++++++++ arch/x86/realmode/rm/.gitignore | 3 ++ arch/x86/realmode/rm/Makefile | 63 ++++++++++++++++++++++++++++++++++ arch/x86/realmode/rm/header.S | 16 +++++++++ arch/x86/realmode/rm/realmode.lds.S | 68 +++++++++++++++++++++++++++++++++++++ arch/x86/realmode/rmpiggy.S | 18 ++++++++++ 6 files changed, 188 insertions(+) create mode 100644 arch/x86/realmode/Makefile create mode 100644 arch/x86/realmode/rm/.gitignore create mode 100644 arch/x86/realmode/rm/Makefile create mode 100644 arch/x86/realmode/rm/header.S create mode 100644 arch/x86/realmode/rm/realmode.lds.S create mode 100644 arch/x86/realmode/rmpiggy.S (limited to 'arch/x86/realmode') diff --git a/arch/x86/realmode/Makefile b/arch/x86/realmode/Makefile new file mode 100644 index 000000000000..f22a4f8d99d6 --- /dev/null +++ b/arch/x86/realmode/Makefile @@ -0,0 +1,20 @@ +# +# arch/x86/realmode/Makefile +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# + +subdir- := rm + +obj-y += rmpiggy.o + +$(obj)/rmpiggy.o: $(obj)/rm/realmode.relocs $(obj)/rm/realmode.bin + +$(obj)/rm/realmode.bin: FORCE + $(Q)$(MAKE) $(build)=$(obj)/rm $@ + +$(obj)/rm/realmode.relocs: FORCE + $(Q)$(MAKE) $(build)=$(obj)/rm $@ diff --git a/arch/x86/realmode/rm/.gitignore b/arch/x86/realmode/rm/.gitignore new file mode 100644 index 000000000000..b6ed3a2555cb --- /dev/null +++ b/arch/x86/realmode/rm/.gitignore @@ -0,0 +1,3 @@ +pasyms.h +realmode.lds +realmode.relocs diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile new file mode 100644 index 000000000000..7c3f202cbccf --- /dev/null +++ b/arch/x86/realmode/rm/Makefile @@ -0,0 +1,63 @@ +# +# arch/x86/realmode/Makefile +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# +# + +subdir- := wakeup + +always := realmode.bin + +realmode-y += header.o + +targets += $(realmode-y) + +REALMODE_OBJS = $(addprefix $(obj)/,$(realmode-y)) + +sed-pasyms := -n -r -e 's/^([0-9a-fA-F]+) [ABCDGRSTVW] (.+)$$/pa_\2 = \2;/p' + +quiet_cmd_pasyms = PASYMS $@ + cmd_pasyms = $(NM) $(filter-out FORCE,$^) | \ + sed $(sed-pasyms) | sort | uniq > $@ + +$(obj)/pasyms.h: $(REALMODE_OBJS) FORCE + $(call if_changed,pasyms) + +$(obj)/realmode.lds: $(obj)/pasyms.h + +LDFLAGS_realmode.elf := --emit-relocs -T +CPPFLAGS_realmode.lds += -P -C -I$(obj) + +$(obj)/realmode.elf: $(obj)/realmode.lds $(REALMODE_OBJS) FORCE + $(call if_changed,ld) + +OBJCOPYFLAGS_realmode.bin := -O binary + +$(obj)/realmode.bin: $(obj)/realmode.elf + $(call if_changed,objcopy) + +quiet_cmd_relocs = RELOCS $@ + cmd_relocs = scripts/x86-relocs --realmode $< > $@ +$(obj)/realmode.relocs: $(obj)/realmode.elf FORCE + $(call if_changed,relocs) + +# --------------------------------------------------------------------------- + +# How to compile the 16-bit code. Note we always compile for -march=i386, +# that way we can complain to the user if the CPU is insufficient. +KBUILD_CFLAGS := $(LINUXINCLUDE) -m32 -g -Os -D_SETUP -D__KERNEL__ \ + -DDISABLE_BRANCH_PROFILING \ + -Wall -Wstrict-prototypes \ + -march=i386 -mregparm=3 \ + -include $(srctree)/$(src)/../../boot/code16gcc.h \ + -fno-strict-aliasing -fomit-frame-pointer \ + $(call cc-option, -ffreestanding) \ + $(call cc-option, -fno-toplevel-reorder,\ + $(call cc-option, -fno-unit-at-a-time)) \ + $(call cc-option, -fno-stack-protector) \ + $(call cc-option, -mpreferred-stack-boundary=2) +KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ +GCOV_PROFILE := n diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S new file mode 100644 index 000000000000..7be17f2c65a3 --- /dev/null +++ b/arch/x86/realmode/rm/header.S @@ -0,0 +1,16 @@ +/* + * Real-mode blob header; this should match realmode.h and be + * readonly; for mutable data instead add pointers into the .data + * or .bss sections as appropriate. + */ + +#include +#include + + .section ".header", "a" + +ENTRY(real_mode_header) + .long pa_text_start + .long pa_ro_end + .long pa_end +END(real_mode_header) diff --git a/arch/x86/realmode/rm/realmode.lds.S b/arch/x86/realmode/rm/realmode.lds.S new file mode 100644 index 000000000000..c5b8a4f31ba3 --- /dev/null +++ b/arch/x86/realmode/rm/realmode.lds.S @@ -0,0 +1,68 @@ +/* + * realmode.lds.S + * + * Linker script for the real-mode code + */ + +#include + +#undef i386 + +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) + +SECTIONS +{ + real_mode_seg = 0; + + . = 0; + .header : { + pa_real_mode_base = .; + *(.header) + } + + . = ALIGN(4); + .rodata : { + *(.rodata) + *(.rodata.*) + } + + . = ALIGN(PAGE_SIZE); + .text : { + pa_text_start = .; + *(.text) + *(.text.*) + } + + .text32 : { + *(.text32) + *(.text32.*) + pa_ro_end = .; + } + + . = ALIGN(PAGE_SIZE); + .data : { + *(.data) + *(.data.*) + } + + . = ALIGN(128); + .bss : { + *(.bss*) + } + + /* End signature for integrity checking */ + . = ALIGN(4); + .signature : { + *(.signature) + pa_end = .; + } + + /DISCARD/ : { + *(.note*) + *(.debug*) + *(.eh_frame*) + } + +#include "pasyms.h" +} diff --git a/arch/x86/realmode/rmpiggy.S b/arch/x86/realmode/rmpiggy.S new file mode 100644 index 000000000000..6047d7f604cf --- /dev/null +++ b/arch/x86/realmode/rmpiggy.S @@ -0,0 +1,18 @@ +/* + * Wrapper script for the realmode binary as a transport object + * before copying to low memory. + */ +#include +#include + + .section ".init.data","aw" + + .balign PAGE_SIZE + +ENTRY(real_mode_blob) + .incbin "arch/x86/realmode/rm/realmode.bin" +END(real_mode_blob) + +ENTRY(real_mode_relocs) + .incbin "arch/x86/realmode/rm/realmode.relocs" +END(real_mode_relocs) -- cgit v1.2.3 From 5a8c9aebe04a78b069828d364798d5f24c5a42bd Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Tue, 8 May 2012 21:22:27 +0300 Subject: x86, realmode: Move reboot_32.S to unified realmode code Migrated reboot_32.S from x86_trampoline to the real-mode blob. Signed-off-by: Jarkko Sakkinen Link: http://lkml.kernel.org/r/1336501366-28617-5-git-send-email-jarkko.sakkinen@intel.com Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/realmode.h | 4 ++ arch/x86/kernel/Makefile | 1 - arch/x86/kernel/reboot.c | 25 +------- arch/x86/kernel/reboot_32.S | 135 --------------------------------------- arch/x86/realmode/rm/Makefile | 1 + arch/x86/realmode/rm/header.S | 3 + arch/x86/realmode/rm/reboot_32.S | 134 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 145 insertions(+), 158 deletions(-) delete mode 100644 arch/x86/kernel/reboot_32.S create mode 100644 arch/x86/realmode/rm/reboot_32.S (limited to 'arch/x86/realmode') diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h index dc1bba534c14..bf26b0681931 100644 --- a/arch/x86/include/asm/realmode.h +++ b/arch/x86/include/asm/realmode.h @@ -9,6 +9,10 @@ struct real_mode_header { u32 text_start; u32 ro_end; u32 end; + /* reboot */ +#ifdef CONFIG_X86_32 + u32 machine_real_restart_asm; +#endif } __attribute__((__packed__)); extern struct real_mode_header real_mode_header; diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index f9e19d4eb984..b71ef35c7d77 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -49,7 +49,6 @@ obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-y += cpu/ obj-y += acpi/ obj-y += reboot.o -obj-$(CONFIG_X86_32) += reboot_32.o obj-$(CONFIG_MCA) += mca_32.o obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_CPUID) += cpuid.o diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index d840e69a853c..050eff29a4bb 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -24,6 +24,7 @@ #ifdef CONFIG_X86_32 # include # include +# include #else # include #endif @@ -332,15 +333,10 @@ static int __init reboot_init(void) } core_initcall(reboot_init); -extern const unsigned char machine_real_restart_asm[]; -extern const u64 machine_real_restart_gdt[3]; - void machine_real_restart(unsigned int type) { - void *restart_va; - unsigned long restart_pa; - void (*restart_lowmem)(unsigned int); - u64 *lowmem_gdt; + void (*restart_lowmem)(unsigned int) = (void (*)(unsigned int)) + real_mode_header.machine_real_restart_asm; local_irq_disable(); @@ -369,21 +365,6 @@ void machine_real_restart(unsigned int type) too. */ *((unsigned short *)0x472) = reboot_mode; - /* Patch the GDT in the low memory trampoline */ - lowmem_gdt = TRAMPOLINE_SYM(machine_real_restart_gdt); - - restart_va = TRAMPOLINE_SYM(machine_real_restart_asm); - restart_pa = virt_to_phys(restart_va); - restart_lowmem = (void (*)(unsigned int))restart_pa; - - /* GDT[0]: GDT self-pointer */ - lowmem_gdt[0] = - (u64)(sizeof(machine_real_restart_gdt) - 1) + - ((u64)virt_to_phys(lowmem_gdt) << 16); - /* GDT[1]: 64K real mode code segment */ - lowmem_gdt[1] = - GDT_ENTRY(0x009b, restart_pa, 0xffff); - /* Jump to the identity-mapped low memory code */ restart_lowmem(type); } diff --git a/arch/x86/kernel/reboot_32.S b/arch/x86/kernel/reboot_32.S deleted file mode 100644 index 1d5c46df0d78..000000000000 --- a/arch/x86/kernel/reboot_32.S +++ /dev/null @@ -1,135 +0,0 @@ -#include -#include -#include -#include - -/* - * The following code and data reboots the machine by switching to real - * mode and jumping to the BIOS reset entry point, as if the CPU has - * really been reset. The previous version asked the keyboard - * controller to pulse the CPU reset line, which is more thorough, but - * doesn't work with at least one type of 486 motherboard. It is easy - * to stop this code working; hence the copious comments. - * - * This code is called with the restart type (0 = BIOS, 1 = APM) in %eax. - */ - .section ".x86_trampoline","a" - .balign 16 - .code32 -ENTRY(machine_real_restart_asm) -r_base = . - /* Get our own relocated address */ - call 1f -1: popl %ebx - subl $(1b - r_base), %ebx - - /* Compute the equivalent real-mode segment */ - movl %ebx, %ecx - shrl $4, %ecx - - /* Patch post-real-mode segment jump */ - movw (dispatch_table - r_base)(%ebx,%eax,2),%ax - movw %ax, (101f - r_base)(%ebx) - movw %cx, (102f - r_base)(%ebx) - - /* Set up the IDT for real mode. */ - lidtl (machine_real_restart_idt - r_base)(%ebx) - - /* - * Set up a GDT from which we can load segment descriptors for real - * mode. The GDT is not used in real mode; it is just needed here to - * prepare the descriptors. - */ - lgdtl (machine_real_restart_gdt - r_base)(%ebx) - - /* - * Load the data segment registers with 16-bit compatible values - */ - movl $16, %ecx - movl %ecx, %ds - movl %ecx, %es - movl %ecx, %fs - movl %ecx, %gs - movl %ecx, %ss - ljmpl $8, $1f - r_base - -/* - * This is 16-bit protected mode code to disable paging and the cache, - * switch to real mode and jump to the BIOS reset code. - * - * The instruction that switches to real mode by writing to CR0 must be - * followed immediately by a far jump instruction, which set CS to a - * valid value for real mode, and flushes the prefetch queue to avoid - * running instructions that have already been decoded in protected - * mode. - * - * Clears all the flags except ET, especially PG (paging), PE - * (protected-mode enable) and TS (task switch for coprocessor state - * save). Flushes the TLB after paging has been disabled. Sets CD and - * NW, to disable the cache on a 486, and invalidates the cache. This - * is more like the state of a 486 after reset. I don't know if - * something else should be done for other chips. - * - * More could be done here to set up the registers as if a CPU reset had - * occurred; hopefully real BIOSs don't assume much. This is not the - * actual BIOS entry point, anyway (that is at 0xfffffff0). - * - * Most of this work is probably excessive, but it is what is tested. - */ - .code16 -1: - xorl %ecx, %ecx - movl %cr0, %eax - andl $0x00000011, %eax - orl $0x60000000, %eax - movl %eax, %cr0 - movl %ecx, %cr3 - movl %cr0, %edx - andl $0x60000000, %edx /* If no cache bits -> no wbinvd */ - jz 2f - wbinvd -2: - andb $0x10, %al - movl %eax, %cr0 - .byte 0xea /* ljmpw */ -101: .word 0 /* Offset */ -102: .word 0 /* Segment */ - -bios: - ljmpw $0xf000, $0xfff0 - -apm: - movw $0x1000, %ax - movw %ax, %ss - movw $0xf000, %sp - movw $0x5307, %ax - movw $0x0001, %bx - movw $0x0003, %cx - int $0x15 - -END(machine_real_restart_asm) - - .balign 16 - /* These must match +#include +#include +#include + +/* + * The following code and data reboots the machine by switching to real + * mode and jumping to the BIOS reset entry point, as if the CPU has + * really been reset. The previous version asked the keyboard + * controller to pulse the CPU reset line, which is more thorough, but + * doesn't work with at least one type of 486 motherboard. It is easy + * to stop this code working; hence the copious comments. + * + * This code is called with the restart type (0 = BIOS, 1 = APM) in %eax. + */ + .section ".text32", "ax" + .code32 + .globl machine_real_restart_asm + + .balign 16 +machine_real_restart_asm: + /* Set up the IDT for real mode. */ + lidtl pa_machine_real_restart_idt + + /* + * Set up a GDT from which we can load segment descriptors for real + * mode. The GDT is not used in real mode; it is just needed here to + * prepare the descriptors. + */ + lgdtl pa_machine_real_restart_gdt + + /* + * Load the data segment registers with 16-bit compatible values + */ + movl $16, %ecx + movl %ecx, %ds + movl %ecx, %es + movl %ecx, %fs + movl %ecx, %gs + movl %ecx, %ss + ljmpw $8, $1f + +/* + * This is 16-bit protected mode code to disable paging and the cache, + * switch to real mode and jump to the BIOS reset code. + * + * The instruction that switches to real mode by writing to CR0 must be + * followed immediately by a far jump instruction, which set CS to a + * valid value for real mode, and flushes the prefetch queue to avoid + * running instructions that have already been decoded in protected + * mode. + * + * Clears all the flags except ET, especially PG (paging), PE + * (protected-mode enable) and TS (task switch for coprocessor state + * save). Flushes the TLB after paging has been disabled. Sets CD and + * NW, to disable the cache on a 486, and invalidates the cache. This + * is more like the state of a 486 after reset. I don't know if + * something else should be done for other chips. + * + * More could be done here to set up the registers as if a CPU reset had + * occurred; hopefully real BIOSs don't assume much. This is not the + * actual BIOS entry point, anyway (that is at 0xfffffff0). + * + * Most of this work is probably excessive, but it is what is tested. + */ + .text + .code16 + + .balign 16 +machine_real_restart_asm16: +1: + xorl %ecx, %ecx + movl %cr0, %edx + andl $0x00000011, %edx + orl $0x60000000, %edx + movl %edx, %cr0 + movl %ecx, %cr3 + movl %cr0, %edx + andl $0x60000000, %edx /* If no cache bits -> no wbinvd */ + jz 2f + wbinvd +2: + andb $0x10, %dl + movl %edx, %cr0 + .byte 0xea /* ljmpw */ + .word 3f /* Offset */ + .word real_mode_seg /* Segment */ + +3: + testb $0, %al + jz bios + +apm: + movw $0x1000, %ax + movw %ax, %ss + movw $0xf000, %sp + movw $0x5307, %ax + movw $0x0001, %bx + movw $0x0003, %cx + int $0x15 + /* This should never return... */ + +bios: + ljmpw $0xf000, $0xfff0 + + .section ".rodata", "a" + .globl machine_real_restart_idt, machine_real_restart_gdt + + .balign 16 +machine_real_restart_idt: + .word 0xffff /* Length - real mode default value */ + .long 0 /* Base - real mode default value */ + + .balign 16 +machine_real_restart_gdt: + /* Self-pointer */ + .word 0xffff /* Length - real mode default value */ + .long pa_machine_real_restart_gdt + .word 0 + + /* + * 16-bit code segment pointing to real_mode_seg + * Selector value 8 + */ + .word 0xffff /* Limit */ + .long 0x9b000000 + pa_real_mode_base + .word 0 + + /* + * 16-bit data segment with the selector value 16 = 0x10 and + * base value 0x100; since this is consistent with real mode + * semantics we don't have to reload the segments once CR0.PE = 0. + */ + .quad GDT_ENTRY(0x0093, 0x100, 0xffff) -- cgit v1.2.3 From 48927bbb97c7d4cf343c05827ab9ac30c60678cb Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Tue, 8 May 2012 21:22:28 +0300 Subject: x86, realmode: Move SMP trampoline to unified realmode code 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 Link: http://lkml.kernel.org/r/1336501366-28617-6-git-send-email-jarkko.sakkinen@intel.com Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/realmode.h | 18 ++++ arch/x86/kernel/head_32.S | 5 +- arch/x86/kernel/head_64.S | 4 - arch/x86/kernel/realmode.c | 14 +++ arch/x86/kernel/smpboot.c | 18 ++-- arch/x86/realmode/rm/Makefile | 1 + arch/x86/realmode/rm/header.S | 11 +++ arch/x86/realmode/rm/trampoline_32.S | 86 +++++++++++++++++ arch/x86/realmode/rm/trampoline_64.S | 175 +++++++++++++++++++++++++++++++++++ 9 files changed, 316 insertions(+), 16 deletions(-) create mode 100644 arch/x86/realmode/rm/trampoline_32.S create mode 100644 arch/x86/realmode/rm/trampoline_64.S (limited to 'arch/x86/realmode') diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h index bf26b0681931..9b4a5da5e22e 100644 --- a/arch/x86/include/asm/realmode.h +++ b/arch/x86/include/asm/realmode.h @@ -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__)); @@ -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 */ diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S index ce0be7cd085e..a3c2b4ffebc6 100644 --- a/arch/x86/kernel/head_32.S +++ b/arch/x86/kernel/head_32.S @@ -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 @@ -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: /* diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index 40f4eb3766d1..d70bc2eb202b 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S @@ -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) diff --git a/arch/x86/kernel/realmode.c b/arch/x86/kernel/realmode.c index 7415c42547ac..a465775b32f2 100644 --- a/arch/x86/kernel/realmode.c +++ b/arch/x86/kernel/realmode.c @@ -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 } /* diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 6e1e406038c2..c7971ea74bd0 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -57,7 +57,7 @@ #include #include #include -#include +#include #include #include #include @@ -73,6 +73,8 @@ #include #include +#include + /* State of each CPU */ DEFINE_PER_CPU(int, cpu_state) = { 0 }; @@ -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, @@ -713,9 +719,6 @@ do_rest: 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); @@ -778,8 +781,7 @@ do_rest: 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 @@ -805,7 +807,7 @@ do_rest: } /* 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) { /* diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile index 3f851c488593..56ec64f94e69 100644 --- a/arch/x86/realmode/rm/Makefile +++ b/arch/x86/realmode/rm/Makefile @@ -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) diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S index db21401c0c57..a97900409c61 100644 --- a/arch/x86/realmode/rm/header.S +++ b/arch/x86/realmode/rm/header.S @@ -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) diff --git a/arch/x86/realmode/rm/trampoline_32.S b/arch/x86/realmode/rm/trampoline_32.S new file mode 100644 index 000000000000..18cb7fc9fad4 --- /dev/null +++ b/arch/x86/realmode/rm/trampoline_32.S @@ -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 +#include +#include +#include + + .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 diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S new file mode 100644 index 000000000000..063da008d520 --- /dev/null +++ b/arch/x86/realmode/rm/trampoline_64.S @@ -0,0 +1,175 @@ +/* + * + * Trampoline.S Derived from Setup.S by Linus Torvalds + * + * 4 Jan 1997 Michael Chastain: changed to gnu as. + * 15 Sept 2005 Eric Biederman: 64bit PIC support + * + * 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. + * + * 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, data addresses need to be absolute + * (no relocation) and are taken with regard to r_base. + * + * With the addition of trampoline_level4_pgt this code can + * now enter a 64bit kernel that lives at arbitrary 64bit + * physical addresses. + * + * If you work on this file, check the object module with objdump + * --full-contents --reloc to make sure there are no relocation + * entries. + */ + +#include +#include +#include +#include +#include +#include +#include + + .text + .balign PAGE_SIZE + .code16 + +ENTRY(trampoline_data) + cli # We should be safe anyway + wbinvd + + .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 + mov %ax, %es + mov %ax, %ss + + movl $0xA5A5A5A5, trampoline_status + # write marker for master knows we're running + + # Setup stack + movw $trampoline_stack_end, %sp + + call verify_cpu # Verify the cpu supports long mode + testl %eax, %eax # Check for return code + jnz no_longmode + + /* + * 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 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 + + # flush prefetch and jump to startup_32 + ljmpl *(startup_32_vector) + +no_longmode: + hlt + jmp no_longmode +#include "../kernel/verify_cpu.S" + + .code32 + .balign 4 +ENTRY(startup_32) + movl $__KERNEL_DS, %eax # Initialize the %ds segment register + movl %eax, %ds + + 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 + movl %eax, %cr3 + + movl $MSR_EFER, %ecx + movl $(1 << _EFER_LME), %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 %eax, %cr0 + + /* + * At this point we're in long mode but in 32bit compatibility mode + * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn + * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use + * the new gdt/idt that has __KERNEL_CS with CS.L = 1. + */ + ljmpl *(pa_startup_64_vector) + + .code64 + .balign 4 +ENTRY(startup_64) + # Now jump into the kernel using virtual addresses + movl %edi, %eax + shlq $32, %rax + addl %esi, %eax + jmp *%rax + + # Careful these need to be in the same 64K segment as the above; +tidt: + .word 0 # idt limit = 0 + .word 0, 0 # idt base = 0L + + # Duplicate the global descriptor table + # so the kernel can live anywhere + .balign 4 + .globl tgdt +tgdt: + .short tgdt_end - tgdt # gdt limit + .long pa_tgdt + .short 0 + .quad 0x00cf9b000000ffff # __KERNEL32_CS + .quad 0x00af9b000000ffff # __KERNEL_CS + .quad 0x00cf93000000ffff # __KERNEL_DS +tgdt_end: + + .balign 4 +startup_32_vector: + .long pa_startup_32 + .word __KERNEL32_CS, 0 + + .balign 4 + .globl startup_64_vector +startup_64_vector: + .long pa_startup_64 + .word __KERNEL_CS, 0 + + .data + + .balign 4 +ENTRY(trampoline_status) + .long 0 + +trampoline_stack: + .org 0x1000 +trampoline_stack_end: + + .globl level3_ident_pgt + .globl level3_kernel_pgt +ENTRY(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 -- cgit v1.2.3 From c9b77ccb52a5c77233b0e557b7d4417b00ef4012 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Tue, 8 May 2012 21:22:29 +0300 Subject: x86, realmode: Move ACPI wakeup to unified realmode code Migrated ACPI wakeup code to the real-mode blob. Code existing in .x86_trampoline can be completely removed. Static descriptor table in wakeup_asm.S is courtesy of H. Peter Anvin. Signed-off-by: Jarkko Sakkinen Link: http://lkml.kernel.org/r/1336501366-28617-7-git-send-email-jarkko.sakkinen@intel.com Cc: Rafael J. Wysocki Cc: Len Brown Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/acpi.h | 2 - arch/x86/include/asm/realmode.h | 4 + arch/x86/include/asm/trampoline.h | 39 ------ arch/x86/kernel/Makefile | 1 - arch/x86/kernel/acpi/Makefile | 9 +- arch/x86/kernel/acpi/realmode/.gitignore | 3 - arch/x86/kernel/acpi/realmode/Makefile | 59 --------- arch/x86/kernel/acpi/realmode/bioscall.S | 1 - arch/x86/kernel/acpi/realmode/copy.S | 1 - arch/x86/kernel/acpi/realmode/regs.c | 1 - arch/x86/kernel/acpi/realmode/video-bios.c | 1 - arch/x86/kernel/acpi/realmode/video-mode.c | 1 - arch/x86/kernel/acpi/realmode/video-vesa.c | 1 - arch/x86/kernel/acpi/realmode/video-vga.c | 1 - arch/x86/kernel/acpi/realmode/wakemain.c | 81 ------------- arch/x86/kernel/acpi/realmode/wakeup.S | 170 -------------------------- arch/x86/kernel/acpi/realmode/wakeup.h | 48 -------- arch/x86/kernel/acpi/realmode/wakeup.lds.S | 62 ---------- arch/x86/kernel/acpi/sleep.c | 33 +---- arch/x86/kernel/acpi/sleep.h | 2 +- arch/x86/kernel/acpi/wakeup_rm.S | 12 -- arch/x86/kernel/head32.c | 1 - arch/x86/kernel/head64.c | 1 - arch/x86/kernel/mpparse.c | 1 - arch/x86/kernel/setup.c | 2 - arch/x86/kernel/tboot.c | 5 +- arch/x86/kernel/trampoline.c | 42 ------- arch/x86/kernel/trampoline_32.S | 83 ------------- arch/x86/kernel/trampoline_64.S | 171 -------------------------- arch/x86/kernel/vmlinux.lds.S | 12 -- arch/x86/realmode/rm/Makefile | 4 + arch/x86/realmode/rm/header.S | 5 + arch/x86/realmode/rm/realmode.lds.S | 4 + arch/x86/realmode/rm/wakeup/.gitignore | 3 + arch/x86/realmode/rm/wakeup/Makefile | 33 +++++ arch/x86/realmode/rm/wakeup/bioscall.S | 1 + arch/x86/realmode/rm/wakeup/copy.S | 1 + arch/x86/realmode/rm/wakeup/regs.c | 1 + arch/x86/realmode/rm/wakeup/video-bios.c | 1 + arch/x86/realmode/rm/wakeup/video-mode.c | 1 + arch/x86/realmode/rm/wakeup/video-vesa.c | 1 + arch/x86/realmode/rm/wakeup/video-vga.c | 1 + arch/x86/realmode/rm/wakeup/wakemain.c | 82 +++++++++++++ arch/x86/realmode/rm/wakeup/wakeup.h | 41 +++++++ arch/x86/realmode/rm/wakeup/wakeup_asm.S | 189 +++++++++++++++++++++++++++++ drivers/acpi/sleep.c | 8 +- 46 files changed, 386 insertions(+), 840 deletions(-) delete mode 100644 arch/x86/include/asm/trampoline.h delete mode 100644 arch/x86/kernel/acpi/realmode/.gitignore delete mode 100644 arch/x86/kernel/acpi/realmode/Makefile delete mode 100644 arch/x86/kernel/acpi/realmode/bioscall.S delete mode 100644 arch/x86/kernel/acpi/realmode/copy.S delete mode 100644 arch/x86/kernel/acpi/realmode/regs.c delete mode 100644 arch/x86/kernel/acpi/realmode/video-bios.c delete mode 100644 arch/x86/kernel/acpi/realmode/video-mode.c delete mode 100644 arch/x86/kernel/acpi/realmode/video-vesa.c delete mode 100644 arch/x86/kernel/acpi/realmode/video-vga.c delete mode 100644 arch/x86/kernel/acpi/realmode/wakemain.c delete mode 100644 arch/x86/kernel/acpi/realmode/wakeup.S delete mode 100644 arch/x86/kernel/acpi/realmode/wakeup.h delete mode 100644 arch/x86/kernel/acpi/realmode/wakeup.lds.S delete mode 100644 arch/x86/kernel/acpi/wakeup_rm.S delete mode 100644 arch/x86/kernel/trampoline.c delete mode 100644 arch/x86/kernel/trampoline_32.S delete mode 100644 arch/x86/kernel/trampoline_64.S create mode 100644 arch/x86/realmode/rm/wakeup/.gitignore create mode 100644 arch/x86/realmode/rm/wakeup/Makefile create mode 100644 arch/x86/realmode/rm/wakeup/bioscall.S create mode 100644 arch/x86/realmode/rm/wakeup/copy.S create mode 100644 arch/x86/realmode/rm/wakeup/regs.c create mode 100644 arch/x86/realmode/rm/wakeup/video-bios.c create mode 100644 arch/x86/realmode/rm/wakeup/video-mode.c create mode 100644 arch/x86/realmode/rm/wakeup/video-vesa.c create mode 100644 arch/x86/realmode/rm/wakeup/video-vga.c create mode 100644 arch/x86/realmode/rm/wakeup/wakemain.c create mode 100644 arch/x86/realmode/rm/wakeup/wakeup.h create mode 100644 arch/x86/realmode/rm/wakeup/wakeup_asm.S (limited to 'arch/x86/realmode') diff --git a/arch/x86/include/asm/acpi.h b/arch/x86/include/asm/acpi.h index 610001d385dd..724aa441de7d 100644 --- a/arch/x86/include/asm/acpi.h +++ b/arch/x86/include/asm/acpi.h @@ -29,7 +29,6 @@ #include #include #include -#include #define COMPILER_DEPENDENT_INT64 long long #define COMPILER_DEPENDENT_UINT64 unsigned long long @@ -118,7 +117,6 @@ static inline void acpi_disable_pci(void) extern int acpi_suspend_lowlevel(void); extern const unsigned char acpi_wakeup_code[]; -#define acpi_wakeup_address (__pa(TRAMPOLINE_SYM(acpi_wakeup_code))) /* early initialization routine */ extern void acpi_reserve_wakeup_memory(void); diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h index 9b4a5da5e22e..1bfc74d213a4 100644 --- a/arch/x86/include/asm/realmode.h +++ b/arch/x86/include/asm/realmode.h @@ -24,6 +24,10 @@ struct real_mode_header { u32 level3_ident_pgt; u32 level3_kernel_pgt; #endif +#ifdef CONFIG_ACPI_SLEEP + u32 wakeup_start; + u32 wakeup_header; +#endif } __attribute__((__packed__)); extern struct real_mode_header real_mode_header; diff --git a/arch/x86/include/asm/trampoline.h b/arch/x86/include/asm/trampoline.h deleted file mode 100644 index feca3118a73b..000000000000 --- a/arch/x86/include/asm/trampoline.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _ASM_X86_TRAMPOLINE_H -#define _ASM_X86_TRAMPOLINE_H - -#ifndef __ASSEMBLY__ - -#include -#include - -/* - * Trampoline 80x86 program as an array. These are in the init rodata - * segment, but that's okay, because we only care about the relative - * addresses of the symbols. - */ -extern const unsigned char x86_trampoline_start []; -extern const unsigned char x86_trampoline_end []; -extern unsigned char *x86_trampoline_base; - -extern unsigned long init_rsp; -extern unsigned long initial_code; -extern unsigned long initial_gs; - -extern void __init setup_trampolines(void); - -extern const unsigned char trampoline_data[]; -extern const unsigned char trampoline_status[]; - -#define TRAMPOLINE_SYM(x) \ - ((void *)(x86_trampoline_base + \ - ((const unsigned char *)(x) - x86_trampoline_start))) - -/* Address of the SMP trampoline */ -static inline unsigned long trampoline_address(void) -{ - return virt_to_phys(TRAMPOLINE_SYM(trampoline_data)); -} - -#endif /* __ASSEMBLY__ */ - -#endif /* _ASM_X86_TRAMPOLINE_H */ diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index b71ef35c7d77..4a20f4441ffe 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -35,7 +35,6 @@ obj-y += tsc.o io_delay.o rtc.o obj-y += pci-iommu_table.o obj-y += resource.o -obj-y += trampoline.o trampoline_$(BITS).o obj-y += realmode.o obj-y += process.o obj-y += i387.o xsave.o diff --git a/arch/x86/kernel/acpi/Makefile b/arch/x86/kernel/acpi/Makefile index 6f35260bb3ef..163b22581472 100644 --- a/arch/x86/kernel/acpi/Makefile +++ b/arch/x86/kernel/acpi/Makefile @@ -1,14 +1,7 @@ -subdir- := realmode - obj-$(CONFIG_ACPI) += boot.o -obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_rm.o wakeup_$(BITS).o +obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_$(BITS).o ifneq ($(CONFIG_ACPI_PROCESSOR),) obj-y += cstate.o endif -$(obj)/wakeup_rm.o: $(obj)/realmode/wakeup.bin - -$(obj)/realmode/wakeup.bin: FORCE - $(Q)$(MAKE) $(build)=$(obj)/realmode - diff --git a/arch/x86/kernel/acpi/realmode/.gitignore b/arch/x86/kernel/acpi/realmode/.gitignore deleted file mode 100644 index 58f1f48a58f8..000000000000 --- a/arch/x86/kernel/acpi/realmode/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -wakeup.bin -wakeup.elf -wakeup.lds diff --git a/arch/x86/kernel/acpi/realmode/Makefile b/arch/x86/kernel/acpi/realmode/Makefile deleted file mode 100644 index 6a564ac67ef5..000000000000 --- a/arch/x86/kernel/acpi/realmode/Makefile +++ /dev/null @@ -1,59 +0,0 @@ -# -# arch/x86/kernel/acpi/realmode/Makefile -# -# This file is subject to the terms and conditions of the GNU General Public -# License. See the file "COPYING" in the main directory of this archive -# for more details. -# - -always := wakeup.bin -targets := wakeup.elf wakeup.lds - -wakeup-y += wakeup.o wakemain.o video-mode.o copy.o bioscall.o regs.o - -# The link order of the video-*.o modules can matter. In particular, -# video-vga.o *must* be listed first, followed by video-vesa.o. -# Hardware-specific drivers should follow in the order they should be -# probed, and video-bios.o should typically be last. -wakeup-y += video-vga.o -wakeup-y += video-vesa.o -wakeup-y += video-bios.o - -targets += $(wakeup-y) - -bootsrc := $(src)/../../../boot - -# --------------------------------------------------------------------------- - -# How to compile the 16-bit code. Note we always compile for -march=i386, -# that way we can complain to the user if the CPU is insufficient. -# Compile with _SETUP since this is similar to the boot-time setup code. -KBUILD_CFLAGS := $(LINUXINCLUDE) -g -Os -D_SETUP -D_WAKEUP -D__KERNEL__ \ - -I$(srctree)/$(bootsrc) \ - $(cflags-y) \ - -Wall -Wstrict-prototypes \ - -march=i386 -mregparm=3 \ - -include $(srctree)/$(bootsrc)/code16gcc.h \ - -fno-strict-aliasing -fomit-frame-pointer \ - $(call cc-option, -ffreestanding) \ - $(call cc-option, -fno-toplevel-reorder,\ - $(call cc-option, -fno-unit-at-a-time)) \ - $(call cc-option, -fno-stack-protector) \ - $(call cc-option, -mpreferred-stack-boundary=2) -KBUILD_CFLAGS += $(call cc-option, -m32) -KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ -GCOV_PROFILE := n - -WAKEUP_OBJS = $(addprefix $(obj)/,$(wakeup-y)) - -LDFLAGS_wakeup.elf := -T - -CPPFLAGS_wakeup.lds += -P -C - -$(obj)/wakeup.elf: $(obj)/wakeup.lds $(WAKEUP_OBJS) FORCE - $(call if_changed,ld) - -OBJCOPYFLAGS_wakeup.bin := -O binary - -$(obj)/wakeup.bin: $(obj)/wakeup.elf FORCE - $(call if_changed,objcopy) diff --git a/arch/x86/kernel/acpi/realmode/bioscall.S b/arch/x86/kernel/acpi/realmode/bioscall.S deleted file mode 100644 index f51eb0bb56ce..000000000000 --- a/arch/x86/kernel/acpi/realmode/bioscall.S +++ /dev/null @@ -1 +0,0 @@ -#include "../../../boot/bioscall.S" diff --git a/arch/x86/kernel/acpi/realmode/copy.S b/arch/x86/kernel/acpi/realmode/copy.S deleted file mode 100644 index dc59ebee69d8..000000000000 --- a/arch/x86/kernel/acpi/realmode/copy.S +++ /dev/null @@ -1 +0,0 @@ -#include "../../../boot/copy.S" diff --git a/arch/x86/kernel/acpi/realmode/regs.c b/arch/x86/kernel/acpi/realmode/regs.c deleted file mode 100644 index 6206033ba202..000000000000 --- a/arch/x86/kernel/acpi/realmode/regs.c +++ /dev/null @@ -1 +0,0 @@ -#include "../../../boot/regs.c" diff --git a/arch/x86/kernel/acpi/realmode/video-bios.c b/arch/x86/kernel/acpi/realmode/video-bios.c deleted file mode 100644 index 7deabc144a27..000000000000 --- a/arch/x86/kernel/acpi/realmode/video-bios.c +++ /dev/null @@ -1 +0,0 @@ -#include "../../../boot/video-bios.c" diff --git a/arch/x86/kernel/acpi/realmode/video-mode.c b/arch/x86/kernel/acpi/realmode/video-mode.c deleted file mode 100644 index 328ad209f113..000000000000 --- a/arch/x86/kernel/acpi/realmode/video-mode.c +++ /dev/null @@ -1 +0,0 @@ -#include "../../../boot/video-mode.c" diff --git a/arch/x86/kernel/acpi/realmode/video-vesa.c b/arch/x86/kernel/acpi/realmode/video-vesa.c deleted file mode 100644 index 9dbb9672226a..000000000000 --- a/arch/x86/kernel/acpi/realmode/video-vesa.c +++ /dev/null @@ -1 +0,0 @@ -#include "../../../boot/video-vesa.c" diff --git a/arch/x86/kernel/acpi/realmode/video-vga.c b/arch/x86/kernel/acpi/realmode/video-vga.c deleted file mode 100644 index bcc81255f374..000000000000 --- a/arch/x86/kernel/acpi/realmode/video-vga.c +++ /dev/null @@ -1 +0,0 @@ -#include "../../../boot/video-vga.c" diff --git a/arch/x86/kernel/acpi/realmode/wakemain.c b/arch/x86/kernel/acpi/realmode/wakemain.c deleted file mode 100644 index 883962d9eef2..000000000000 --- a/arch/x86/kernel/acpi/realmode/wakemain.c +++ /dev/null @@ -1,81 +0,0 @@ -#include "wakeup.h" -#include "boot.h" - -static void udelay(int loops) -{ - while (loops--) - io_delay(); /* Approximately 1 us */ -} - -static void beep(unsigned int hz) -{ - u8 enable; - - if (!hz) { - enable = 0x00; /* Turn off speaker */ - } else { - u16 div = 1193181/hz; - - outb(0xb6, 0x43); /* Ctr 2, squarewave, load, binary */ - io_delay(); - outb(div, 0x42); /* LSB of counter */ - io_delay(); - outb(div >> 8, 0x42); /* MSB of counter */ - io_delay(); - - enable = 0x03; /* Turn on speaker */ - } - inb(0x61); /* Dummy read of System Control Port B */ - io_delay(); - outb(enable, 0x61); /* Enable timer 2 output to speaker */ - io_delay(); -} - -#define DOT_HZ 880 -#define DASH_HZ 587 -#define US_PER_DOT 125000 - -/* Okay, this is totally silly, but it's kind of fun. */ -static void send_morse(const char *pattern) -{ - char s; - - while ((s = *pattern++)) { - switch (s) { - case '.': - beep(DOT_HZ); - udelay(US_PER_DOT); - beep(0); - udelay(US_PER_DOT); - break; - case '-': - beep(DASH_HZ); - udelay(US_PER_DOT * 3); - beep(0); - udelay(US_PER_DOT); - break; - default: /* Assume it's a space */ - udelay(US_PER_DOT * 3); - break; - } - } -} - -void main(void) -{ - /* Kill machine if structures are wrong */ - if (wakeup_header.real_magic != 0x12345678) - while (1); - - if (wakeup_header.realmode_flags & 4) - send_morse("...-"); - - if (wakeup_header.realmode_flags & 1) - asm volatile("lcallw $0xc000,$3"); - - if (wakeup_header.realmode_flags & 2) { - /* Need to call BIOS */ - probe_cards(0); - set_mode(wakeup_header.video_mode); - } -} diff --git a/arch/x86/kernel/acpi/realmode/wakeup.S b/arch/x86/kernel/acpi/realmode/wakeup.S deleted file mode 100644 index b4fd836e4053..000000000000 --- a/arch/x86/kernel/acpi/realmode/wakeup.S +++ /dev/null @@ -1,170 +0,0 @@ -/* - * ACPI wakeup real mode startup stub - */ -#include -#include -#include -#include -#include -#include "wakeup.h" - - .code16 - .section ".jump", "ax" - .globl _start -_start: - cli - jmp wakeup_code - -/* This should match the structure in wakeup.h */ - .section ".header", "a" - .globl wakeup_header -wakeup_header: -video_mode: .short 0 /* Video mode number */ -pmode_return: .byte 0x66, 0xea /* ljmpl */ - .long 0 /* offset goes here */ - .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 -trampoline_segment: .word 0 -_pad1: .byte 0 -wakeup_jmp: .byte 0xea /* ljmpw */ -wakeup_jmp_off: .word 3f -wakeup_jmp_seg: .word 0 -wakeup_gdt: .quad 0, 0, 0 -signature: .long WAKEUP_HEADER_SIGNATURE - - .text - .code16 -wakeup_code: - cld - - /* Apparently some dimwit BIOS programmers don't know how to - program a PM to RM transition, and we might end up here with - junk in the data segment descriptor registers. The only way - to repair that is to go into PM and fix it ourselves... */ - movw $16, %cx - lgdtl %cs:wakeup_gdt - movl %cr0, %eax - orb $X86_CR0_PE, %al - movl %eax, %cr0 - jmp 1f -1: ljmpw $8, $2f -2: - movw %cx, %ds - movw %cx, %es - movw %cx, %ss - movw %cx, %fs - movw %cx, %gs - - andb $~X86_CR0_PE, %al - movl %eax, %cr0 - jmp wakeup_jmp -3: - /* Set up segments */ - movw %cs, %ax - movw %ax, %ds - movw %ax, %es - movw %ax, %ss - lidtl wakeup_idt - - movl $wakeup_stack_end, %esp - - /* Clear the EFLAGS */ - pushl $0 - popfl - - /* Check header signature... */ - movl signature, %eax - cmpl $WAKEUP_HEADER_SIGNATURE, %eax - jne bogus_real_magic - - /* Check we really have everything... */ - movl end_signature, %eax - cmpl $WAKEUP_END_SIGNATURE, %eax - jne bogus_real_magic - - /* Call the C code */ - calll main - - /* Restore MISC_ENABLE before entering protected mode, in case - BIOS decided to clear XD_DISABLE during S3. */ - movl pmode_behavior, %eax - btl $WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %eax - jnc 1f - - movl pmode_misc_en, %eax - movl pmode_misc_en + 4, %edx - movl $MSR_IA32_MISC_ENABLE, %ecx - wrmsr -1: - - /* Do any other stuff... */ - -#ifndef CONFIG_64BIT - /* This could also be done in C code... */ - movl pmode_cr3, %eax - movl %eax, %cr3 - - movl pmode_cr4, %ecx - jecxz 1f - movl %ecx, %cr4 -1: - movl pmode_efer, %eax - movl pmode_efer + 4, %edx - movl %eax, %ecx - orl %edx, %ecx - jz 1f - movl $MSR_EFER, %ecx - wrmsr -1: - - lgdtl pmode_gdt - - /* This really couldn't... */ - movl pmode_cr0, %eax - movl %eax, %cr0 - jmp pmode_return -#else - pushw $0 - pushw trampoline_segment - pushw $0 - lret -#endif - -bogus_real_magic: -1: - hlt - jmp 1b - - .data - .balign 8 - - /* This is the standard real-mode IDT */ -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: - - .section ".signature","a" -end_signature: - .long WAKEUP_END_SIGNATURE diff --git a/arch/x86/kernel/acpi/realmode/wakeup.h b/arch/x86/kernel/acpi/realmode/wakeup.h deleted file mode 100644 index 97a29e1430e3..000000000000 --- a/arch/x86/kernel/acpi/realmode/wakeup.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Definitions for the wakeup data structure at the head of the - * wakeup code. - */ - -#ifndef ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H -#define ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H - -#ifndef __ASSEMBLY__ -#include - -/* This must match data at wakeup.S */ -struct wakeup_header { - u16 video_mode; /* Video mode number */ - u16 _jmp1; /* ljmpl opcode, 32-bit only */ - u32 pmode_entry; /* Protected mode resume point, 32-bit only */ - u16 _jmp2; /* CS value, 32-bit only */ - u32 pmode_cr0; /* Protected mode cr0 */ - u32 pmode_cr3; /* Protected mode cr3 */ - u32 pmode_cr4; /* Protected mode cr4 */ - u32 pmode_efer_low; /* Protected mode EFER */ - u32 pmode_efer_high; - u64 pmode_gdt; - u32 pmode_misc_en_low; /* Protected mode MISC_ENABLE */ - u32 pmode_misc_en_high; - u32 pmode_behavior; /* Wakeup routine behavior flags */ - u32 realmode_flags; - u32 real_magic; - u16 trampoline_segment; /* segment with trampoline code, 64-bit only */ - u8 _pad1; - u8 wakeup_jmp; - u16 wakeup_jmp_off; - u16 wakeup_jmp_seg; - u64 wakeup_gdt[3]; - u32 signature; /* To check we have correct structure */ -} __attribute__((__packed__)); - -extern struct wakeup_header wakeup_header; -#endif - -#define WAKEUP_HEADER_OFFSET 8 -#define WAKEUP_HEADER_SIGNATURE 0x51ee1111 -#define WAKEUP_END_SIGNATURE 0x65a22c82 - -/* Wakeup behavior bits */ -#define WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE 0 - -#endif /* ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H */ diff --git a/arch/x86/kernel/acpi/realmode/wakeup.lds.S b/arch/x86/kernel/acpi/realmode/wakeup.lds.S deleted file mode 100644 index d4f8010a5b1b..000000000000 --- a/arch/x86/kernel/acpi/realmode/wakeup.lds.S +++ /dev/null @@ -1,62 +0,0 @@ -/* - * wakeup.ld - * - * Linker script for the real-mode wakeup code - */ -#undef i386 -#include "wakeup.h" - -OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") -OUTPUT_ARCH(i386) -ENTRY(_start) - -SECTIONS -{ - . = 0; - .jump : { - *(.jump) - } = 0x90909090 - - . = WAKEUP_HEADER_OFFSET; - .header : { - *(.header) - } - - . = ALIGN(16); - .text : { - *(.text*) - } = 0x90909090 - - . = ALIGN(16); - .rodata : { - *(.rodata*) - } - - .videocards : { - video_cards = .; - *(.videocards) - video_cards_end = .; - } - - . = ALIGN(16); - .data : { - *(.data*) - } - - . = ALIGN(16); - .bss : { - __bss_start = .; - *(.bss) - __bss_end = .; - } - - .signature : { - *(.signature) - } - - _end = .; - - /DISCARD/ : { - *(.note*) - } -} diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c index 146a49c763a4..d941b62da4b6 100644 --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c @@ -14,8 +14,9 @@ #include #include #include +#include -#include "realmode/wakeup.h" +#include "../../realmode/rm/wakeup/wakeup.h" #include "sleep.h" unsigned long acpi_realmode_flags; @@ -36,13 +37,9 @@ asmlinkage void acpi_enter_s3(void) */ int acpi_suspend_lowlevel(void) { - struct wakeup_header *header; - /* address in low memory of the wakeup routine. */ - char *acpi_realmode; + struct wakeup_header *header = + (struct wakeup_header *) __va(real_mode_header.wakeup_header); - acpi_realmode = TRAMPOLINE_SYM(acpi_wakeup_code); - - header = (struct wakeup_header *)(acpi_realmode + WAKEUP_HEADER_OFFSET); if (header->signature != WAKEUP_HEADER_SIGNATURE) { printk(KERN_ERR "wakeup header does not match\n"); return -EINVAL; @@ -50,27 +47,6 @@ int acpi_suspend_lowlevel(void) header->video_mode = saved_video_mode; - header->wakeup_jmp_seg = acpi_wakeup_address >> 4; - - /* - * Set up the wakeup GDT. We set these up as Big Real Mode, - * that is, with limits set to 4 GB. At least the Lenovo - * Thinkpad X61 is known to need this for the video BIOS - * initialization quirk to work; this is likely to also - * be the case for other laptops or integrated video devices. - */ - - /* GDT[0]: GDT self-pointer */ - header->wakeup_gdt[0] = - (u64)(sizeof(header->wakeup_gdt) - 1) + - ((u64)__pa(&header->wakeup_gdt) << 16); - /* GDT[1]: big real mode-like code segment */ - header->wakeup_gdt[1] = - GDT_ENTRY(0x809b, acpi_wakeup_address, 0xfffff); - /* GDT[2]: big real mode-like data segment */ - header->wakeup_gdt[2] = - GDT_ENTRY(0x8093, acpi_wakeup_address, 0xfffff); - #ifndef CONFIG_64BIT store_gdt((struct desc_ptr *)&header->pmode_gdt); @@ -95,7 +71,6 @@ int acpi_suspend_lowlevel(void) header->pmode_cr3 = (u32)__pa(&initial_page_table); saved_magic = 0x12345678; #else /* CONFIG_64BIT */ - header->trampoline_segment = trampoline_address() >> 4; #ifdef CONFIG_SMP stack_start = (unsigned long)temp_stack + sizeof(temp_stack); early_gdt_descr.address = diff --git a/arch/x86/kernel/acpi/sleep.h b/arch/x86/kernel/acpi/sleep.h index d68677a2a010..5653a5791ec9 100644 --- a/arch/x86/kernel/acpi/sleep.h +++ b/arch/x86/kernel/acpi/sleep.h @@ -2,8 +2,8 @@ * Variables and functions used by the code in sleep.c */ -#include #include +#include extern unsigned long saved_video_mode; extern long saved_magic; diff --git a/arch/x86/kernel/acpi/wakeup_rm.S b/arch/x86/kernel/acpi/wakeup_rm.S deleted file mode 100644 index 63b8ab524f2c..000000000000 --- a/arch/x86/kernel/acpi/wakeup_rm.S +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Wrapper script for the realmode binary as a transport object - * before copying to low memory. - */ -#include - - .section ".x86_trampoline","a" - .balign PAGE_SIZE - .globl acpi_wakeup_code -acpi_wakeup_code: - .incbin "arch/x86/kernel/acpi/realmode/wakeup.bin" - .size acpi_wakeup_code, .-acpi_wakeup_code diff --git a/arch/x86/kernel/head32.c b/arch/x86/kernel/head32.c index 51ff18616d50..c18f59d10101 100644 --- a/arch/x86/kernel/head32.c +++ b/arch/x86/kernel/head32.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c index 3a3b779f41d3..037df57a99ac 100644 --- a/arch/x86/kernel/head64.c +++ b/arch/x86/kernel/head64.c @@ -24,7 +24,6 @@ #include #include #include -#include #include static void __init zap_identity_mappings(void) diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c index ca470e4c92dc..f44d31157353 100644 --- a/arch/x86/kernel/mpparse.c +++ b/arch/x86/kernel/mpparse.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 56e41242a6b8..7a14fece9cfc 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -73,7 +73,6 @@ #include #include -#include #include #include #include @@ -918,7 +917,6 @@ void __init setup_arch(char **cmdline_p) printk(KERN_DEBUG "initial memory mapped : 0 - %08lx\n", max_pfn_mapped< #include -#include +#include #include #include #include @@ -201,7 +201,8 @@ static int tboot_setup_sleep(void) add_mac_region(e820.map[i].addr, e820.map[i].size); } - tboot->acpi_sinfo.kernel_s3_resume_vector = acpi_wakeup_address; + tboot->acpi_sinfo.kernel_s3_resume_vector = + real_mode_header.wakeup_start; return 0; } diff --git a/arch/x86/kernel/trampoline.c b/arch/x86/kernel/trampoline.c deleted file mode 100644 index a73b61055ad6..000000000000 --- a/arch/x86/kernel/trampoline.c +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include - -#include -#include -#include - -unsigned char *x86_trampoline_base; - -void __init setup_trampolines(void) -{ - phys_addr_t mem; - size_t size = PAGE_ALIGN(x86_trampoline_end - x86_trampoline_start); - - /* Has to be in very low memory so we can execute real-mode AP code. */ - mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE); - if (!mem) - panic("Cannot allocate trampoline\n"); - - x86_trampoline_base = __va(mem); - memblock_reserve(mem, size); - - printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n", - x86_trampoline_base, (unsigned long long)mem, size); - - memcpy(x86_trampoline_base, x86_trampoline_start, size); -} - -/* - * setup_trampolines() gets called very early, to guarantee the - * availability of low memory. This is before the proper kernel page - * tables are set up, so we cannot set page permissions in that - * function. Thus, we use an arch_initcall instead. - */ -static int __init configure_trampolines(void) -{ - size_t size = PAGE_ALIGN(x86_trampoline_end - x86_trampoline_start); - - set_memory_x((unsigned long)x86_trampoline_base, size >> PAGE_SHIFT); - return 0; -} -arch_initcall(configure_trampolines); diff --git a/arch/x86/kernel/trampoline_32.S b/arch/x86/kernel/trampoline_32.S deleted file mode 100644 index 451c0a7ef7fd..000000000000 --- a/arch/x86/kernel/trampoline_32.S +++ /dev/null @@ -1,83 +0,0 @@ -/* - * - * 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, data addresses need to be absolute - * (no relocation) and are taken with regard to r_base. - * - * If you work on this file, check the object module with - * objdump --reloc to make sure there are no relocation - * entries except for: - * - * TYPE VALUE - * R_386_32 startup_32_smp - * R_386_32 boot_gdt - */ - -#include -#include -#include -#include - -#ifdef CONFIG_SMP - - .section ".x86_trampoline","a" - .balign PAGE_SIZE - .code16 - -ENTRY(trampoline_data) -r_base = . - wbinvd # Needed for NUMA-Q should be harmless for others - mov %cs, %ax # Code and data in the same place - mov %ax, %ds - - cli # We should be safe anyway - - movl $0xA5A5A5A5, trampoline_status - r_base - # 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 - r_base # load idt with 0, 0 - lgdtl boot_gdt_descr - r_base # 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 $__BOOT_CS, $(startup_32_smp-__PAGE_OFFSET) - - # These need to be in the same 64K segment as the above; - # hence we don't use the boot_gdt_descr defined in head.S -boot_gdt_descr: - .word __BOOT_DS + 7 # gdt limit - .long boot_gdt - __PAGE_OFFSET # gdt base - -boot_idt_descr: - .word 0 # idt limit = 0 - .long 0 # idt base = 0L - -ENTRY(trampoline_status) - .long 0 - -.globl trampoline_end -trampoline_end: - -#endif /* CONFIG_SMP */ diff --git a/arch/x86/kernel/trampoline_64.S b/arch/x86/kernel/trampoline_64.S deleted file mode 100644 index 09ff51799e96..000000000000 --- a/arch/x86/kernel/trampoline_64.S +++ /dev/null @@ -1,171 +0,0 @@ -/* - * - * Trampoline.S Derived from Setup.S by Linus Torvalds - * - * 4 Jan 1997 Michael Chastain: changed to gnu as. - * 15 Sept 2005 Eric Biederman: 64bit PIC support - * - * 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. - * - * 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, data addresses need to be absolute - * (no relocation) and are taken with regard to r_base. - * - * With the addition of trampoline_level4_pgt this code can - * now enter a 64bit kernel that lives at arbitrary 64bit - * physical addresses. - * - * If you work on this file, check the object module with objdump - * --full-contents --reloc to make sure there are no relocation - * entries. - */ - -#include -#include -#include -#include -#include -#include -#include - - .section ".x86_trampoline","a" - .balign PAGE_SIZE - .code16 - -ENTRY(trampoline_data) -r_base = . - cli # We should be safe anyway - wbinvd - mov %cs, %ax # Code and data in the same place - mov %ax, %ds - mov %ax, %es - mov %ax, %ss - - - movl $0xA5A5A5A5, trampoline_status - r_base - # write marker for master knows we're running - - # Setup stack - movw $(trampoline_stack_end - r_base), %sp - - call verify_cpu # Verify the cpu supports long mode - testl %eax, %eax # Check for return code - jnz no_longmode - - mov %cs, %ax - movzx %ax, %esi # Find the 32bit trampoline location - shll $4, %esi - - # Fixup the absolute vectors - leal (startup_32 - r_base)(%esi), %eax - movl %eax, startup_32_vector - r_base - leal (startup_64 - r_base)(%esi), %eax - movl %eax, startup_64_vector - r_base - leal (tgdt - r_base)(%esi), %eax - movl %eax, (tgdt + 2 - r_base) - - /* - * 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 tidt - r_base # load idt with 0, 0 - lgdtl tgdt - r_base # load gdt with whatever is appropriate - - mov $X86_CR0_PE, %ax # protected mode (PE) bit - lmsw %ax # into protected mode - - # flush prefetch and jump to startup_32 - ljmpl *(startup_32_vector - r_base) - - .code32 - .balign 4 -startup_32: - movl $__KERNEL_DS, %eax # Initialize the %ds segment register - movl %eax, %ds - - movl $X86_CR4_PAE, %eax - movl %eax, %cr4 # Enable PAE mode - - # Setup trampoline 4 level pagetables - leal (trampoline_level4_pgt - r_base)(%esi), %eax - movl %eax, %cr3 - - movl $MSR_EFER, %ecx - movl $(1 << _EFER_LME), %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 %eax, %cr0 - - /* - * At this point we're in long mode but in 32bit compatibility mode - * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn - * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use - * the new gdt/idt that has __KERNEL_CS with CS.L = 1. - */ - ljmp *(startup_64_vector - r_base)(%esi) - - .code64 - .balign 4 -startup_64: - # Now jump into the kernel using virtual addresses - movq $secondary_startup_64, %rax - jmp *%rax - - .code16 -no_longmode: - hlt - jmp no_longmode -#include "verify_cpu.S" - - .balign 4 - # Careful these need to be in the same 64K segment as the above; -tidt: - .word 0 # idt limit = 0 - .word 0, 0 # idt base = 0L - - # Duplicate the global descriptor table - # so the kernel can live anywhere - .balign 4 -tgdt: - .short tgdt_end - tgdt # gdt limit - .long tgdt - r_base - .short 0 - .quad 0x00cf9b000000ffff # __KERNEL32_CS - .quad 0x00af9b000000ffff # __KERNEL_CS - .quad 0x00cf93000000ffff # __KERNEL_DS -tgdt_end: - - .balign 4 -startup_32_vector: - .long startup_32 - r_base - .word __KERNEL32_CS, 0 - - .balign 4 -startup_64_vector: - .long startup_64 - r_base - .word __KERNEL_CS, 0 - - .balign 4 -ENTRY(trampoline_status) - .long 0 - -trampoline_stack: - .org 0x1000 -trampoline_stack_end: -ENTRY(trampoline_level4_pgt) - .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE - .fill 510,8,0 - .quad level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE - -ENTRY(trampoline_end) diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index 0f703f10901a..22a1530146a8 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -197,18 +197,6 @@ SECTIONS INIT_DATA_SECTION(16) - /* - * Code and data for a variety of lowlevel trampolines, to be - * copied into base memory (< 1 MiB) during initialization. - * Since it is copied early, the main copy can be discarded - * afterwards. - */ - .x86_trampoline : AT(ADDR(.x86_trampoline) - LOAD_OFFSET) { - x86_trampoline_start = .; - *(.x86_trampoline) - x86_trampoline_end = .; - } - .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) { __x86_cpu_dev_start = .; *(.x86_cpu_dev.init) diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile index 56ec64f94e69..2432acb6b04f 100644 --- a/arch/x86/realmode/rm/Makefile +++ b/arch/x86/realmode/rm/Makefile @@ -14,9 +14,13 @@ always := realmode.bin realmode-y += header.o realmode-$(CONFIG_X86_32) += reboot_32.o realmode-y += trampoline_$(BITS).o +realmode-$(CONFIG_ACPI_SLEEP) += wakeup/wakeup.o targets += $(realmode-y) +$(obj)/wakeup/wakeup.o: FORCE + $(Q)$(MAKE) $(build)=$(obj)/wakeup $@ + REALMODE_OBJS = $(addprefix $(obj)/,$(realmode-y)) sed-pasyms := -n -r -e 's/^([0-9a-fA-F]+) [ABCDGRSTVW] (.+)$$/pa_\2 = \2;/p' diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S index a97900409c61..730b1316c099 100644 --- a/arch/x86/realmode/rm/header.S +++ b/arch/x86/realmode/rm/header.S @@ -26,5 +26,10 @@ ENTRY(real_mode_header) .long pa_startup_64_smp .long pa_level3_ident_pgt .long pa_level3_kernel_pgt +#endif + /* ACPI sleep */ +#ifdef CONFIG_ACPI_SLEEP + .long pa_wakeup_start + .long pa_wakeup_header #endif END(real_mode_header) diff --git a/arch/x86/realmode/rm/realmode.lds.S b/arch/x86/realmode/rm/realmode.lds.S index c5b8a4f31ba3..91b83ea55c37 100644 --- a/arch/x86/realmode/rm/realmode.lds.S +++ b/arch/x86/realmode/rm/realmode.lds.S @@ -25,6 +25,10 @@ SECTIONS .rodata : { *(.rodata) *(.rodata.*) + . = ALIGN(16); + video_cards = .; + *(.videocards) + video_cards_end = .; } . = ALIGN(PAGE_SIZE); diff --git a/arch/x86/realmode/rm/wakeup/.gitignore b/arch/x86/realmode/rm/wakeup/.gitignore new file mode 100644 index 000000000000..58f1f48a58f8 --- /dev/null +++ b/arch/x86/realmode/rm/wakeup/.gitignore @@ -0,0 +1,3 @@ +wakeup.bin +wakeup.elf +wakeup.lds diff --git a/arch/x86/realmode/rm/wakeup/Makefile b/arch/x86/realmode/rm/wakeup/Makefile new file mode 100644 index 000000000000..4c8533240cdd --- /dev/null +++ b/arch/x86/realmode/rm/wakeup/Makefile @@ -0,0 +1,33 @@ +# +# arch/x86/kernel/acpi/realmode/Makefile +# +# This file is subject to the terms and conditions of the GNU General Public +# License. See the file "COPYING" in the main directory of this archive +# for more details. +# + +always := wakeup.o + +wakeup-y += wakeup_asm.o wakemain.o video-mode.o +wakeup-y += copy.o bioscall.o regs.o + +# The link order of the video-*.o modules can matter. In particular, +# video-vga.o *must* be listed first, followed by video-vesa.o. +# Hardware-specific drivers should follow in the order they should be +# probed, and video-bios.o should typically be last. +wakeup-y += video-vga.o +wakeup-y += video-vesa.o +wakeup-y += video-bios.o + +targets += $(wakeup-y) + +WAKEUP_OBJS = $(addprefix $(obj)/,$(wakeup-y)) + +LDFLAGS_wakeup.o := -m elf_i386 -r +$(obj)/wakeup.o: $(WAKEUP_OBJS) FORCE + $(call if_changed,ld) + +bootsrc := $(src)/../../../boot + +ccflags-y += -D_WAKEUP -I$(srctree)/$(bootsrc) +asflags-y += -D_WAKEUP -I$(srctree)/$(bootsrc) diff --git a/arch/x86/realmode/rm/wakeup/bioscall.S b/arch/x86/realmode/rm/wakeup/bioscall.S new file mode 100644 index 000000000000..f51eb0bb56ce --- /dev/null +++ b/arch/x86/realmode/rm/wakeup/bioscall.S @@ -0,0 +1 @@ +#include "../../../boot/bioscall.S" diff --git a/arch/x86/realmode/rm/wakeup/copy.S b/arch/x86/realmode/rm/wakeup/copy.S new file mode 100644 index 000000000000..dc59ebee69d8 --- /dev/null +++ b/arch/x86/realmode/rm/wakeup/copy.S @@ -0,0 +1 @@ +#include "../../../boot/copy.S" diff --git a/arch/x86/realmode/rm/wakeup/regs.c b/arch/x86/realmode/rm/wakeup/regs.c new file mode 100644 index 000000000000..6206033ba202 --- /dev/null +++ b/arch/x86/realmode/rm/wakeup/regs.c @@ -0,0 +1 @@ +#include "../../../boot/regs.c" diff --git a/arch/x86/realmode/rm/wakeup/video-bios.c b/arch/x86/realmode/rm/wakeup/video-bios.c new file mode 100644 index 000000000000..7deabc144a27 --- /dev/null +++ b/arch/x86/realmode/rm/wakeup/video-bios.c @@ -0,0 +1 @@ +#include "../../../boot/video-bios.c" diff --git a/arch/x86/realmode/rm/wakeup/video-mode.c b/arch/x86/realmode/rm/wakeup/video-mode.c new file mode 100644 index 000000000000..328ad209f113 --- /dev/null +++ b/arch/x86/realmode/rm/wakeup/video-mode.c @@ -0,0 +1 @@ +#include "../../../boot/video-mode.c" diff --git a/arch/x86/realmode/rm/wakeup/video-vesa.c b/arch/x86/realmode/rm/wakeup/video-vesa.c new file mode 100644 index 000000000000..9dbb9672226a --- /dev/null +++ b/arch/x86/realmode/rm/wakeup/video-vesa.c @@ -0,0 +1 @@ +#include "../../../boot/video-vesa.c" diff --git a/arch/x86/realmode/rm/wakeup/video-vga.c b/arch/x86/realmode/rm/wakeup/video-vga.c new file mode 100644 index 000000000000..bcc81255f374 --- /dev/null +++ b/arch/x86/realmode/rm/wakeup/video-vga.c @@ -0,0 +1 @@ +#include "../../../boot/video-vga.c" diff --git a/arch/x86/realmode/rm/wakeup/wakemain.c b/arch/x86/realmode/rm/wakeup/wakemain.c new file mode 100644 index 000000000000..91405d515ec6 --- /dev/null +++ b/arch/x86/realmode/rm/wakeup/wakemain.c @@ -0,0 +1,82 @@ +#include "wakeup.h" +#include "boot.h" + +static void udelay(int loops) +{ + while (loops--) + io_delay(); /* Approximately 1 us */ +} + +static void beep(unsigned int hz) +{ + u8 enable; + + if (!hz) { + enable = 0x00; /* Turn off speaker */ + } else { + u16 div = 1193181/hz; + + outb(0xb6, 0x43); /* Ctr 2, squarewave, load, binary */ + io_delay(); + outb(div, 0x42); /* LSB of counter */ + io_delay(); + outb(div >> 8, 0x42); /* MSB of counter */ + io_delay(); + + enable = 0x03; /* Turn on speaker */ + } + inb(0x61); /* Dummy read of System Control Port B */ + io_delay(); + outb(enable, 0x61); /* Enable timer 2 output to speaker */ + io_delay(); +} + +#define DOT_HZ 880 +#define DASH_HZ 587 +#define US_PER_DOT 125000 + +/* Okay, this is totally silly, but it's kind of fun. */ +static void send_morse(const char *pattern) +{ + char s; + + while ((s = *pattern++)) { + switch (s) { + case '.': + beep(DOT_HZ); + udelay(US_PER_DOT); + beep(0); + udelay(US_PER_DOT); + break; + case '-': + beep(DASH_HZ); + udelay(US_PER_DOT * 3); + beep(0); + udelay(US_PER_DOT); + break; + default: /* Assume it's a space */ + udelay(US_PER_DOT * 3); + break; + } + } +} + +void main(void) +{ + /* Kill machine if structures are wrong */ + if (wakeup_header.real_magic != 0x12345678) + while (1) + ; + + if (wakeup_header.realmode_flags & 4) + send_morse("...-"); + + if (wakeup_header.realmode_flags & 1) + asm volatile("lcallw $0xc000,$3"); + + if (wakeup_header.realmode_flags & 2) { + /* Need to call BIOS */ + probe_cards(0); + set_mode(wakeup_header.video_mode); + } +} diff --git a/arch/x86/realmode/rm/wakeup/wakeup.h b/arch/x86/realmode/rm/wakeup/wakeup.h new file mode 100644 index 000000000000..2dfaf06b8af1 --- /dev/null +++ b/arch/x86/realmode/rm/wakeup/wakeup.h @@ -0,0 +1,41 @@ +/* + * Definitions for the wakeup data structure at the head of the + * wakeup code. + */ + +#ifndef ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H +#define ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H + +#ifndef __ASSEMBLY__ +#include + +/* This must match data at wakeup.S */ +struct wakeup_header { + u16 video_mode; /* Video mode number */ + u32 pmode_entry; /* Protected mode resume point, 32-bit only */ + u16 pmode_cs; + u32 pmode_cr0; /* Protected mode cr0 */ + u32 pmode_cr3; /* Protected mode cr3 */ + u32 pmode_cr4; /* Protected mode cr4 */ + u32 pmode_efer_low; /* Protected mode EFER */ + u32 pmode_efer_high; + u64 pmode_gdt; + u32 pmode_misc_en_low; /* Protected mode MISC_ENABLE */ + u32 pmode_misc_en_high; + u32 pmode_behavior; /* Wakeup routine behavior flags */ + u32 realmode_flags; + u32 real_magic; + u32 signature; /* To check we have correct structure */ +} __attribute__((__packed__)); + +extern struct wakeup_header wakeup_header; +#endif + +#define WAKEUP_HEADER_OFFSET 8 +#define WAKEUP_HEADER_SIGNATURE 0x51ee1111 +#define WAKEUP_END_SIGNATURE 0x65a22c82 + +/* Wakeup behavior bits */ +#define WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE 0 + +#endif /* ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H */ diff --git a/arch/x86/realmode/rm/wakeup/wakeup_asm.S b/arch/x86/realmode/rm/wakeup/wakeup_asm.S new file mode 100644 index 000000000000..b61126cb599e --- /dev/null +++ b/arch/x86/realmode/rm/wakeup/wakeup_asm.S @@ -0,0 +1,189 @@ +/* + * ACPI wakeup real mode startup stub + */ +#include +#include +#include +#include +#include +#include "wakeup.h" + + .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 + + .text + .code16 + .globl wakeup_start +wakeup_start: + cli + cld + + .byte 0xea /* ljmpw */ + .word 3f + .word real_mode_seg +3: + /* Apparently some dimwit BIOS programmers don't know how to + program a PM to RM transition, and we might end up here with + junk in the data segment descriptor registers. The only way + to repair that is to go into PM and fix it ourselves... */ + movw $16, %cx + lgdtl %cs:wakeup_gdt + movl %cr0, %eax + orb $X86_CR0_PE, %al + movl %eax, %cr0 + ljmpw $8, $2f +2: + movw %cx, %ds + movw %cx, %es + movw %cx, %ss + movw %cx, %fs + movw %cx, %gs + + andb $~X86_CR0_PE, %al + movl %eax, %cr0 + .byte 0xea /* ljmpw */ + .word 3f + .word real_mode_seg +3: + /* Set up segments */ + movw %cs, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + lidtl wakeup_idt + + movl $wakeup_stack_end, %esp + + /* Clear the EFLAGS */ + pushl $0 + popfl + + /* Check header signature... */ + movl signature, %eax + cmpl $WAKEUP_HEADER_SIGNATURE, %eax + jne bogus_real_magic + + /* Check we really have everything... */ + movl end_signature, %eax + cmpl $WAKEUP_END_SIGNATURE, %eax + jne bogus_real_magic + + /* Call the C code */ + calll main + + /* Restore MISC_ENABLE before entering protected mode, in case + BIOS decided to clear XD_DISABLE during S3. */ + movl pmode_behavior, %eax + btl $WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %eax + jnc 1f + + movl pmode_misc_en, %eax + movl pmode_misc_en + 4, %edx + movl $MSR_IA32_MISC_ENABLE, %ecx + wrmsr +1: + + /* Do any other stuff... */ + +#ifndef CONFIG_64BIT + /* This could also be done in C code... */ + movl pmode_cr3, %eax + movl %eax, %cr3 + + movl pmode_cr4, %ecx + jecxz 1f + movl %ecx, %cr4 +1: + movl pmode_efer, %eax + movl pmode_efer + 4, %edx + movl %eax, %ecx + orl %edx, %ecx + jz 1f + movl $MSR_EFER, %ecx + wrmsr +1: + + lgdtl pmode_gdt + + /* This really couldn't... */ + movl pmode_cr0, %eax + movl %eax, %cr0 + ljmpl *pmode_entry +#else + jmp trampoline_data +#endif + +bogus_real_magic: +1: + hlt + jmp 1b + + .section ".rodata","a" + + /* + * Set up the wakeup GDT. We set these up as Big Real Mode, + * that is, with limits set to 4 GB. At least the Lenovo + * Thinkpad X61 is known to need this for the video BIOS + * initialization quirk to work; this is likely to also + * be the case for other laptops or integrated video devices. + */ + + .globl wakeup_gdt + .balign 16 +wakeup_gdt: + .word 3*8-1 /* Self-descriptor */ + .long pa_wakeup_gdt + .word 0 + + .word 0xffff /* 16-bit code segment @ real_mode_base */ + .long 0x9b000000 + pa_real_mode_base + .word 0x008f /* big real mode */ + + .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 + + .data + .balign 8 + + /* This is the standard real-mode IDT */ +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: + + .section ".signature","a" +end_signature: + .long WAKEUP_END_SIGNATURE diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index eb6fd233764b..e77aa4a1c9f6 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -25,6 +25,8 @@ #include #include +#include + #include "internal.h" #include "sleep.h" @@ -91,13 +93,13 @@ static struct notifier_block tts_notifier = { static int acpi_sleep_prepare(u32 acpi_state) { #ifdef CONFIG_ACPI_SLEEP + unsigned long wakeup_pa = real_mode_header.wakeup_start; /* do we have a wakeup address for S2 and S3? */ if (acpi_state == ACPI_STATE_S3) { - if (!acpi_wakeup_address) { + if (!wakeup_pa) return -EFAULT; - } acpi_set_firmware_waking_vector( - (acpi_physical_address)acpi_wakeup_address); + (acpi_physical_address)wakeup_pa); } ACPI_FLUSH_CPU_CACHE(); -- cgit v1.2.3 From 487f50ffeb142d8f86fff6e43a8852ce3d46c173 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 8 May 2012 21:22:32 +0300 Subject: x86, realmode: Add .text64 section, make barrier symbols absolute Add a .text64 section. The purpose of this is to keep 16-, 32- and 64-bit code segregated into separate sections, mainly to keep disassembly sane. Move barrier symbols out of sections to avoid the "symbol in empty section" problem in some versions of GNU ld. Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/r/1336501366-28617-10-git-send-email-jarkko.sakkinen@intel.com --- arch/x86/realmode/rm/realmode.lds.S | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'arch/x86/realmode') diff --git a/arch/x86/realmode/rm/realmode.lds.S b/arch/x86/realmode/rm/realmode.lds.S index 91b83ea55c37..4d4afcaf5f02 100644 --- a/arch/x86/realmode/rm/realmode.lds.S +++ b/arch/x86/realmode/rm/realmode.lds.S @@ -32,8 +32,8 @@ SECTIONS } . = ALIGN(PAGE_SIZE); + pa_text_start = .; .text : { - pa_text_start = .; *(.text) *(.text.*) } @@ -41,9 +41,14 @@ SECTIONS .text32 : { *(.text32) *(.text32.*) - pa_ro_end = .; } + .text64 : { + *(.text64) + *(.text64.*) + } + pa_ro_end = .; + . = ALIGN(PAGE_SIZE); .data : { *(.data) @@ -59,8 +64,8 @@ SECTIONS . = ALIGN(4); .signature : { *(.signature) - pa_end = .; } + pa_end = .; /DISCARD/ : { *(.note*) -- cgit v1.2.3 From 024742861124ef26dae4cfc620250f8f47ac934a Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 8 May 2012 21:22:33 +0300 Subject: x86, realmode: Move bits to the proper sections in trampoline_64.S Move various bits to the sections they really belong in in trampoline_64.S. Use GLOBAL() rather than ENTRY() for data objects: ENTRY() should only be used with code and forces alignment to 16 bytes. Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/r/1336501366-28617-11-git-send-email-jarkko.sakkinen@intel.com --- arch/x86/realmode/rm/trampoline_64.S | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'arch/x86/realmode') diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S index 063da008d520..66c58cf15503 100644 --- a/arch/x86/realmode/rm/trampoline_64.S +++ b/arch/x86/realmode/rm/trampoline_64.S @@ -80,6 +80,7 @@ no_longmode: jmp no_longmode #include "../kernel/verify_cpu.S" + .section ".text32","ax" .code32 .balign 4 ENTRY(startup_32) @@ -114,6 +115,7 @@ ENTRY(startup_32) */ ljmpl *(pa_startup_64_vector) + .section ".text64","ax" .code64 .balign 4 ENTRY(startup_64) @@ -123,7 +125,8 @@ ENTRY(startup_64) addl %esi, %eax jmp *%rax - # Careful these need to be in the same 64K segment as the above; + .section ".rodata","a" + .balign 16 tidt: .word 0 # idt limit = 0 .word 0, 0 # idt base = 0L @@ -153,9 +156,8 @@ startup_64_vector: .word __KERNEL_CS, 0 .data - .balign 4 -ENTRY(trampoline_status) +GLOBAL(trampoline_status) .long 0 trampoline_stack: @@ -164,7 +166,7 @@ trampoline_stack_end: .globl level3_ident_pgt .globl level3_kernel_pgt -ENTRY(trampoline_level4_pgt) +GLOBAL(trampoline_level4_pgt) level3_ident_pgt: .quad 0 .fill 510,8,0 level3_kernel_pgt: .quad 0 -- cgit v1.2.3 From f7436a9da902922a48cccc208099763b87d6171f Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 8 May 2012 21:22:34 +0300 Subject: x86, realmode: Align .data section in trampoline_32.S Specify the alignment of the .data section in trampoline_32.S. Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/r/1336501366-28617-12-git-send-email-jarkko.sakkinen@intel.com --- arch/x86/realmode/rm/trampoline_32.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86/realmode') diff --git a/arch/x86/realmode/rm/trampoline_32.S b/arch/x86/realmode/rm/trampoline_32.S index 18cb7fc9fad4..1f9e3316f73d 100644 --- a/arch/x86/realmode/rm/trampoline_32.S +++ b/arch/x86/realmode/rm/trampoline_32.S @@ -68,7 +68,7 @@ trampoline_data: .data .globl startup_32_smp, boot_gdt, trampoline_status - + .balign 4 boot_gdt_descr: .word __BOOT_DS + 7 # gdt limit boot_gdt: -- cgit v1.2.3 From 056a43a6d3ab903a798d8ee4435ad67d6fccc3e6 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 8 May 2012 21:22:35 +0300 Subject: x86, realmode: Remove indirect jumps in trampoline_64.S Remove indirect jumps in trampoline_64.S which are no longer necessary: the realmode code can relocate the absolute jumps correctly from the start. Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/r/1336501366-28617-13-git-send-email-jarkko.sakkinen@intel.com --- arch/x86/realmode/rm/trampoline_64.S | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) (limited to 'arch/x86/realmode') diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S index 66c58cf15503..77b72b45d705 100644 --- a/arch/x86/realmode/rm/trampoline_64.S +++ b/arch/x86/realmode/rm/trampoline_64.S @@ -73,7 +73,7 @@ ENTRY(trampoline_data) lmsw %ax # into protected mode # flush prefetch and jump to startup_32 - ljmpl *(startup_32_vector) + ljmpl $__KERNEL32_CS, $pa_startup_32 no_longmode: hlt @@ -113,7 +113,7 @@ ENTRY(startup_32) * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use * the new gdt/idt that has __KERNEL_CS with CS.L = 1. */ - ljmpl *(pa_startup_64_vector) + ljmpl $__KERNEL_CS, $pa_startup_64 .section ".text64","ax" .code64 @@ -144,17 +144,6 @@ tgdt: .quad 0x00cf93000000ffff # __KERNEL_DS tgdt_end: - .balign 4 -startup_32_vector: - .long pa_startup_32 - .word __KERNEL32_CS, 0 - - .balign 4 - .globl startup_64_vector -startup_64_vector: - .long pa_startup_64 - .word __KERNEL_CS, 0 - .data .balign 4 GLOBAL(trampoline_status) -- cgit v1.2.3 From 968ff9ee56f1e3ed4ff4a6d10185865dc77d8f7e Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 8 May 2012 21:22:36 +0300 Subject: x86, realmode: Remove indirect jumps in trampoline_32 and wakeup_asm Remove indirect jumps in trampoline_32.S and the 32-bit part of wakeup_asm.S. There exist systems which are known to do weird things if an SMI comes in right after a mode switch, and the safest way to deal with it is to always follow with a simple absolute far jump. In the 64-bit code we then to a register indirect near jump; follow that pattern for the 32-bit code. Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/r/1336501366-28617-14-git-send-email-jarkko.sakkinen@intel.com --- arch/x86/realmode/rm/trampoline_32.S | 22 +++++++++++++--------- arch/x86/realmode/rm/wakeup/wakeup_asm.S | 8 +++++--- 2 files changed, 18 insertions(+), 12 deletions(-) (limited to 'arch/x86/realmode') diff --git a/arch/x86/realmode/rm/trampoline_32.S b/arch/x86/realmode/rm/trampoline_32.S index 1f9e3316f73d..1315ef48dbf1 100644 --- a/arch/x86/realmode/rm/trampoline_32.S +++ b/arch/x86/realmode/rm/trampoline_32.S @@ -47,24 +47,29 @@ trampoline_data: cli # We should be safe anyway + movl startup_32_smp, %eax # where we need to go + movl $0xA5A5A5A5, trampoline_status # write marker for master knows we're running - /* GDT tables in non default location kernel can be beyond 16MB and + /* + * 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 + movw $1, %dx # protected mode (PE) bit + lmsw %dx # into protected mode - # flush prefetch and jump to startup_32_smp in arch/i386/kernel/head.S - ljmpl *(startup_32_smp) + ljmpl $__BOOT_CS, $pa_startup_32 + + .section ".text32","ax" + .code32 +ENTRY(startup_32) # note: also used from wakeup_asm.S + jmp *%eax .data .globl startup_32_smp, boot_gdt, trampoline_status @@ -82,5 +87,4 @@ trampoline_status: .long 0 startup_32_smp: - .long 0x00000000 - .word __BOOT_CS, 0 + .long 0 diff --git a/arch/x86/realmode/rm/wakeup/wakeup_asm.S b/arch/x86/realmode/rm/wakeup/wakeup_asm.S index b61126cb599e..4c5c5f2bfbec 100644 --- a/arch/x86/realmode/rm/wakeup/wakeup_asm.S +++ b/arch/x86/realmode/rm/wakeup/wakeup_asm.S @@ -124,9 +124,11 @@ wakeup_start: lgdtl pmode_gdt /* This really couldn't... */ - movl pmode_cr0, %eax - movl %eax, %cr0 - ljmpl *pmode_entry + movl pmode_entry, %eax + movl pmode_cr0, %ecx + movl %ecx, %cr0 + ljmpl $__KERNEL_CS, $pa_startup_32 + /* -> jmp *%eax in trampoline_32.S */ #else jmp trampoline_data #endif -- cgit v1.2.3 From e5684ec438a094bec0f7d5c52652c0901b48b613 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 8 May 2012 21:22:37 +0300 Subject: x86, realmode: Replace open-coded ljmpw with a macro We cannot code an ljmpw to the real-mode segment directly, because gas refuses to assemble an ljmp with a symbolic segment. Instead of open-coding it everywhere, define a macro and use it for this case. This is specifically an ljmpw from a 16-bit segment. This is okay, as one should never enter real mode from a 32-bit segment: if one do, the CPU ends up in a bizarre (and useless) mode sometimes called "unreal mode" where segments behave like real mode but the default address and operand sizes is 32 bits. Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/r/1336501366-28617-15-git-send-email-jarkko.sakkinen@intel.com --- arch/x86/realmode/rm/realmode.h | 16 ++++++++++++++++ arch/x86/realmode/rm/reboot_32.S | 6 ++---- arch/x86/realmode/rm/trampoline_32.S | 5 ++--- arch/x86/realmode/rm/trampoline_64.S | 5 ++--- arch/x86/realmode/rm/wakeup/wakeup_asm.S | 9 +++------ 5 files changed, 25 insertions(+), 16 deletions(-) create mode 100644 arch/x86/realmode/rm/realmode.h (limited to 'arch/x86/realmode') diff --git a/arch/x86/realmode/rm/realmode.h b/arch/x86/realmode/rm/realmode.h new file mode 100644 index 000000000000..15ab6335f843 --- /dev/null +++ b/arch/x86/realmode/rm/realmode.h @@ -0,0 +1,16 @@ +#ifndef ARCH_X86_REALMODE_RM_REALMODE_H +#define ARCH_X86_REALMODE_RM_REALMODE_H + +#ifdef __ASSEMBLY__ + +/* + * 16-bit ljmpw to the real_mode_seg + * + * This must be open-coded since gas will choke on using a + * relocatable symbol for the segment portion. + */ +#define LJMPW_RM(to) .byte 0xea ; .word (to), real_mode_seg + +#endif /* __ASSEMBLY__ */ + +#endif /* ARCH_X86_REALMODE_RM_REALMODE_H */ diff --git a/arch/x86/realmode/rm/reboot_32.S b/arch/x86/realmode/rm/reboot_32.S index 83803c222b4a..e90f8c4bbae2 100644 --- a/arch/x86/realmode/rm/reboot_32.S +++ b/arch/x86/realmode/rm/reboot_32.S @@ -2,6 +2,7 @@ #include #include #include +#include "realmode.h" /* * The following code and data reboots the machine by switching to real @@ -82,10 +83,7 @@ machine_real_restart_asm16: 2: andb $0x10, %dl movl %edx, %cr0 - .byte 0xea /* ljmpw */ - .word 3f /* Offset */ - .word real_mode_seg /* Segment */ - + LJMPW_RM(3f) 3: testb $0, %al jz bios diff --git a/arch/x86/realmode/rm/trampoline_32.S b/arch/x86/realmode/rm/trampoline_32.S index 1315ef48dbf1..279f82ef7a9e 100644 --- a/arch/x86/realmode/rm/trampoline_32.S +++ b/arch/x86/realmode/rm/trampoline_32.S @@ -29,6 +29,7 @@ #include #include #include +#include "realmode.h" .text .code16 @@ -38,9 +39,7 @@ trampoline_data: wbinvd # Needed for NUMA-Q should be harmless for others - .byte 0xea # ljmpw - .word 1f # Offset - .word real_mode_seg # Segment + LJMPW_RM(1f) 1: mov %cs, %ax # Code and data in the same place mov %ax, %ds diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S index 77b72b45d705..7459c52f0c25 100644 --- a/arch/x86/realmode/rm/trampoline_64.S +++ b/arch/x86/realmode/rm/trampoline_64.S @@ -31,6 +31,7 @@ #include #include #include +#include "realmode.h" .text .balign PAGE_SIZE @@ -40,9 +41,7 @@ ENTRY(trampoline_data) cli # We should be safe anyway wbinvd - .byte 0xea # ljmpw - .word 1f # Offset - .word real_mode_seg # Segment + LJMPW_RM(1f) 1: mov %cs, %ax # Code and data in the same place mov %ax, %ds diff --git a/arch/x86/realmode/rm/wakeup/wakeup_asm.S b/arch/x86/realmode/rm/wakeup/wakeup_asm.S index 4c5c5f2bfbec..8064e1c3591b 100644 --- a/arch/x86/realmode/rm/wakeup/wakeup_asm.S +++ b/arch/x86/realmode/rm/wakeup/wakeup_asm.S @@ -6,6 +6,7 @@ #include #include #include +#include "../realmode.h" #include "wakeup.h" .code16 @@ -36,9 +37,7 @@ wakeup_start: cli cld - .byte 0xea /* ljmpw */ - .word 3f - .word real_mode_seg + LJMPW_RM(3f) 3: /* Apparently some dimwit BIOS programmers don't know how to program a PM to RM transition, and we might end up here with @@ -59,9 +58,7 @@ wakeup_start: andb $~X86_CR0_PE, %al movl %eax, %cr0 - .byte 0xea /* ljmpw */ - .word 3f - .word real_mode_seg + LJMPW_RM(3f) 3: /* Set up segments */ movw %cs, %ax -- cgit v1.2.3 From be60828920d23758da8124bed771404a0438f369 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 8 May 2012 21:22:38 +0300 Subject: x86, realmode: Move trampoline_*.S early in the link order Move trampoline_*.S earlier in the link order so it ends up being first in the text segment; since the SIPI vector requires 4K alignment it otherwise ends up padding the .text segment with that much completely unnecessarily. Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/r/1336501366-28617-16-git-send-email-jarkko.sakkinen@intel.com --- arch/x86/realmode/rm/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86/realmode') diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile index 2432acb6b04f..2423142b4da4 100644 --- a/arch/x86/realmode/rm/Makefile +++ b/arch/x86/realmode/rm/Makefile @@ -12,8 +12,8 @@ subdir- := wakeup always := realmode.bin realmode-y += header.o -realmode-$(CONFIG_X86_32) += reboot_32.o realmode-y += trampoline_$(BITS).o +realmode-$(CONFIG_X86_32) += reboot_32.o realmode-$(CONFIG_ACPI_SLEEP) += wakeup/wakeup.o targets += $(realmode-y) -- cgit v1.2.3 From 6feb592dceaed1a6cf26c9747b1180958d5156cd Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 8 May 2012 21:22:39 +0300 Subject: x86, realmode: Fix always-zero test in reboot_32.S A test instruction is an "and", and an and with zero is always zero. This would cause us to always take the BIOS path, not the APM path, in case anyone actually cares... Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/r/1336501366-28617-17-git-send-email-jarkko.sakkinen@intel.com --- arch/x86/realmode/rm/reboot_32.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86/realmode') diff --git a/arch/x86/realmode/rm/reboot_32.S b/arch/x86/realmode/rm/reboot_32.S index e90f8c4bbae2..50ba994ba921 100644 --- a/arch/x86/realmode/rm/reboot_32.S +++ b/arch/x86/realmode/rm/reboot_32.S @@ -85,7 +85,7 @@ machine_real_restart_asm16: movl %edx, %cr0 LJMPW_RM(3f) 3: - testb $0, %al + andw %ax, %ax jz bios apm: -- cgit v1.2.3 From 8e029fcdd8702719c9179317cae9ef84ebe7027e Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Tue, 8 May 2012 21:22:40 +0300 Subject: 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 Link: http://lkml.kernel.org/r/1336501366-28617-18-git-send-email-jarkko.sakkinen@intel.com Originally-by: H. Peter Anvin Cc: Rafael J. Wysocki Cc: Len Brown Signed-off-by: H. Peter Anvin --- arch/x86/kernel/realmode.c | 2 +- arch/x86/realmode/rm/Makefile | 1 + arch/x86/realmode/rm/header.S | 2 +- arch/x86/realmode/rm/reboot_32.S | 18 ++++---- arch/x86/realmode/rm/stack.S | 19 ++++++++ arch/x86/realmode/rm/trampoline_32.S | 29 ++++++------ arch/x86/realmode/rm/trampoline_64.S | 67 ++++++++++++---------------- arch/x86/realmode/rm/wakeup/wakeup_asm.S | 75 +++++++++++++++----------------- arch/x86/realmode/rmpiggy.S | 4 +- 9 files changed, 110 insertions(+), 107 deletions(-) create mode 100644 arch/x86/realmode/rm/stack.S (limited to 'arch/x86/realmode') diff --git a/arch/x86/kernel/realmode.c b/arch/x86/kernel/realmode.c index d85ac20bb4eb..e7bf82a409bf 100644 --- a/arch/x86/kernel/realmode.c +++ b/arch/x86/kernel/realmode.c @@ -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; diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile index 2423142b4da4..c2c27a41ab8f 100644 --- a/arch/x86/realmode/rm/Makefile +++ b/arch/x86/realmode/rm/Makefile @@ -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 diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S index 730b1316c099..a91ec8f6b15f 100644 --- a/arch/x86/realmode/rm/header.S +++ b/arch/x86/realmode/rm/header.S @@ -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 diff --git a/arch/x86/realmode/rm/reboot_32.S b/arch/x86/realmode/rm/reboot_32.S index 50ba994ba921..8d9bfd13a93e 100644 --- a/arch/x86/realmode/rm/reboot_32.S +++ b/arch/x86/realmode/rm/reboot_32.S @@ -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) diff --git a/arch/x86/realmode/rm/stack.S b/arch/x86/realmode/rm/stack.S new file mode 100644 index 000000000000..867ae87adfae --- /dev/null +++ b/arch/x86/realmode/rm/stack.S @@ -0,0 +1,19 @@ +/* + * Common heap and stack allocations + */ + +#include + + .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) diff --git a/arch/x86/realmode/rm/trampoline_32.S b/arch/x86/realmode/rm/trampoline_32.S index 279f82ef7a9e..1ecdbb59191b 100644 --- a/arch/x86/realmode/rm/trampoline_32.S +++ b/arch/x86/realmode/rm/trampoline_32.S @@ -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 diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S index 7459c52f0c25..f71ea0800d3d 100644 --- a/arch/x86/realmode/rm/trampoline_64.S +++ b/arch/x86/realmode/rm/trampoline_64.S @@ -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 - -trampoline_stack: - .org 0x1000 -trampoline_stack_end: - - .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 + .bss + + .balign PAGE_SIZE +GLOBAL(level3_ident_pgt) .space 511*8 +GLOBAL(level3_kernel_pgt) .space 8 + + .balign 8 +GLOBAL(startup_64_smp) .space 8 +GLOBAL(trampoline_status) .space 4 diff --git a/arch/x86/realmode/rm/wakeup/wakeup_asm.S b/arch/x86/realmode/rm/wakeup/wakeup_asm.S index 8064e1c3591b..f81c1cd99eaf 100644 --- a/arch/x86/realmode/rm/wakeup/wakeup_asm.S +++ b/arch/x86/realmode/rm/wakeup/wakeup_asm.S @@ -1,6 +1,7 @@ /* * ACPI wakeup real mode startup stub */ +#include #include #include #include @@ -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: diff --git a/arch/x86/realmode/rmpiggy.S b/arch/x86/realmode/rmpiggy.S index 6047d7f604cf..fd72a99d12ae 100644 --- a/arch/x86/realmode/rmpiggy.S +++ b/arch/x86/realmode/rmpiggy.S @@ -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) -- cgit v1.2.3 From b429dbf6e866bd6dadb56fae66f61f611cde57ff Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Tue, 8 May 2012 21:22:41 +0300 Subject: x86, realmode: don't copy real_mode_header Replaced copying of real_mode_header with a pointer to beginning of RM memory. Signed-off-by: Jarkko Sakkinen Link: http://lkml.kernel.org/r/1336501366-28617-19-git-send-email-jarkko.sakkinen@intel.com Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/realmode.h | 5 ++-- arch/x86/kernel/acpi/sleep.c | 2 +- arch/x86/kernel/realmode.c | 57 ++++++++++++++++--------------------- arch/x86/kernel/reboot.c | 2 +- arch/x86/kernel/smpboot.c | 4 +-- arch/x86/kernel/tboot.c | 2 +- arch/x86/realmode/rm/header.S | 1 - arch/x86/realmode/rm/realmode.lds.S | 1 - arch/x86/realmode/rmpiggy.S | 2 ++ drivers/acpi/sleep.c | 2 +- 10 files changed, 35 insertions(+), 43 deletions(-) (limited to 'arch/x86/realmode') diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h index 1bfc74d213a4..d3ae49f4c3ef 100644 --- a/arch/x86/include/asm/realmode.h +++ b/arch/x86/include/asm/realmode.h @@ -8,7 +8,6 @@ struct real_mode_header { u32 text_start; u32 ro_end; - u32 end; /* reboot */ #ifdef CONFIG_X86_32 u32 machine_real_restart_asm; @@ -30,8 +29,8 @@ struct real_mode_header { #endif } __attribute__((__packed__)); -extern struct real_mode_header real_mode_header; -extern unsigned char *real_mode_base; +extern struct real_mode_header *real_mode_header; +extern unsigned char real_mode_blob_end[]; extern unsigned long init_rsp; extern unsigned long initial_code; diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c index d941b62da4b6..6ca3f54ebe7d 100644 --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c @@ -38,7 +38,7 @@ asmlinkage void acpi_enter_s3(void) int acpi_suspend_lowlevel(void) { struct wakeup_header *header = - (struct wakeup_header *) __va(real_mode_header.wakeup_header); + (struct wakeup_header *) __va(real_mode_header->wakeup_header); if (header->signature != WAKEUP_HEADER_SIGNATURE) { printk(KERN_ERR "wakeup header does not match\n"); diff --git a/arch/x86/kernel/realmode.c b/arch/x86/kernel/realmode.c index e7bf82a409bf..632c810ec8ea 100644 --- a/arch/x86/kernel/realmode.c +++ b/arch/x86/kernel/realmode.c @@ -5,8 +5,7 @@ #include #include -unsigned char *real_mode_base; -struct real_mode_header real_mode_header; +struct real_mode_header *real_mode_header; void __init setup_real_mode(void) { @@ -17,33 +16,32 @@ void __init setup_real_mode(void) u32 *ptr; u16 *seg; int i; + unsigned char *base; - struct real_mode_header *header = - (struct real_mode_header *) real_mode_blob; - - size_t size = PAGE_ALIGN(header->end); + size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob); /* Has to be in very low memory so we can execute real-mode AP code. */ mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE); if (!mem) panic("Cannot allocate trampoline\n"); - real_mode_base = __va(mem); + base = __va(mem); memblock_reserve(mem, size); + real_mode_header = (struct real_mode_header *) base; printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n", - real_mode_base, (unsigned long long)mem, size); + base, (unsigned long long)mem, size); - memcpy(real_mode_base, real_mode_blob, size); + memcpy(base, real_mode_blob, size); - real_mode_seg = __pa(real_mode_base) >> 4; + real_mode_seg = __pa(base) >> 4; rel = (u32 *) real_mode_relocs; /* 16-bit segment relocations. */ count = rel[0]; rel = &rel[1]; for (i = 0; i < count; i++) { - seg = (u16 *) (real_mode_base + rel[i]); + seg = (u16 *) (base + rel[i]); *seg = real_mode_seg; } @@ -51,25 +49,21 @@ void __init setup_real_mode(void) count = rel[i]; rel = &rel[i + 1]; for (i = 0; i < count; i++) { - ptr = (u32 *) (real_mode_base + rel[i]); - *ptr += __pa(real_mode_base); + ptr = (u32 *) (base + rel[i]); + *ptr += __pa(base); } - /* 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); + *((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 *) __va(real_mode_header->startup_64_smp)) = (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; - *((u64 *) __va(real_mode_header.level3_kernel_pgt)) = + *((u64 *) __va(real_mode_header->level3_kernel_pgt)) = __pa(level3_kernel_pgt) + _KERNPG_TABLE; #endif } @@ -82,23 +76,22 @@ void __init setup_real_mode(void) */ static int __init set_real_mode_permissions(void) { - size_t all_size = - PAGE_ALIGN(real_mode_header.end) - - __pa(real_mode_base); + unsigned char *base = (unsigned char *) real_mode_header; + size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob); size_t ro_size = - PAGE_ALIGN(real_mode_header.ro_end) - - __pa(real_mode_base); + PAGE_ALIGN(real_mode_header->ro_end) - + __pa(base); size_t text_size = - PAGE_ALIGN(real_mode_header.ro_end) - - real_mode_header.text_start; + PAGE_ALIGN(real_mode_header->ro_end) - + real_mode_header->text_start; unsigned long text_start = - (unsigned long) __va(real_mode_header.text_start); + (unsigned long) __va(real_mode_header->text_start); - set_memory_nx((unsigned long) real_mode_base, all_size >> PAGE_SHIFT); - set_memory_ro((unsigned long) real_mode_base, ro_size >> PAGE_SHIFT); + set_memory_nx((unsigned long) base, size >> PAGE_SHIFT); + set_memory_ro((unsigned long) base, ro_size >> PAGE_SHIFT); set_memory_x((unsigned long) text_start, text_size >> PAGE_SHIFT); return 0; diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 050eff29a4bb..658f856f09a3 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -336,7 +336,7 @@ core_initcall(reboot_init); void machine_real_restart(unsigned int type) { void (*restart_lowmem)(unsigned int) = (void (*)(unsigned int)) - real_mode_header.machine_real_restart_asm; + real_mode_header->machine_real_restart_asm; local_irq_disable(); diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index c7971ea74bd0..b8c0661e2341 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -665,9 +665,9 @@ 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); + (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 start_ip = real_mode_header->trampoline_data; unsigned long boot_error = 0; int timeout; diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c index c136e2325062..65adda4fde93 100644 --- a/arch/x86/kernel/tboot.c +++ b/arch/x86/kernel/tboot.c @@ -202,7 +202,7 @@ static int tboot_setup_sleep(void) } tboot->acpi_sinfo.kernel_s3_resume_vector = - real_mode_header.wakeup_start; + real_mode_header->wakeup_start; return 0; } diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S index a91ec8f6b15f..c83005c4d455 100644 --- a/arch/x86/realmode/rm/header.S +++ b/arch/x86/realmode/rm/header.S @@ -12,7 +12,6 @@ GLOBAL(real_mode_header) .long pa_text_start .long pa_ro_end - .long pa_end #ifdef CONFIG_X86_32 .long pa_machine_real_restart_asm #endif diff --git a/arch/x86/realmode/rm/realmode.lds.S b/arch/x86/realmode/rm/realmode.lds.S index 4d4afcaf5f02..86b2e8d6b1f1 100644 --- a/arch/x86/realmode/rm/realmode.lds.S +++ b/arch/x86/realmode/rm/realmode.lds.S @@ -65,7 +65,6 @@ SECTIONS .signature : { *(.signature) } - pa_end = .; /DISCARD/ : { *(.note*) diff --git a/arch/x86/realmode/rmpiggy.S b/arch/x86/realmode/rmpiggy.S index fd72a99d12ae..204c6ece0e97 100644 --- a/arch/x86/realmode/rmpiggy.S +++ b/arch/x86/realmode/rmpiggy.S @@ -13,6 +13,8 @@ GLOBAL(real_mode_blob) .incbin "arch/x86/realmode/rm/realmode.bin" END(real_mode_blob) +GLOBAL(real_mode_blob_end); + GLOBAL(real_mode_relocs) .incbin "arch/x86/realmode/rm/realmode.relocs" END(real_mode_relocs) diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index e77aa4a1c9f6..06139005c4dd 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -93,7 +93,7 @@ static struct notifier_block tts_notifier = { static int acpi_sleep_prepare(u32 acpi_state) { #ifdef CONFIG_ACPI_SLEEP - unsigned long wakeup_pa = real_mode_header.wakeup_start; + unsigned long wakeup_pa = real_mode_header->wakeup_start; /* do we have a wakeup address for S2 and S3? */ if (acpi_state == ACPI_STATE_S3) { if (!wakeup_pa) -- cgit v1.2.3 From c4845474a01f699966272536e8416222e3f2d2cb Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Tue, 8 May 2012 21:22:42 +0300 Subject: x86, realmode: flattened rm hierachy Simplified hierarchy under rm directory to a flat directory because it is not anymore really justified to have own directory for wakeup code. It only adds more complexity. Signed-off-by: Jarkko Sakkinen Link: http://lkml.kernel.org/r/1336501366-28617-20-git-send-email-jarkko.sakkinen@intel.com Signed-off-by: H. Peter Anvin --- arch/x86/kernel/acpi/sleep.c | 2 +- arch/x86/realmode/rm/Makefile | 20 ++-- arch/x86/realmode/rm/bioscall.S | 1 + arch/x86/realmode/rm/copy.S | 1 + arch/x86/realmode/rm/regs.c | 1 + arch/x86/realmode/rm/video-bios.c | 1 + arch/x86/realmode/rm/video-mode.c | 1 + arch/x86/realmode/rm/video-vesa.c | 1 + arch/x86/realmode/rm/video-vga.c | 1 + arch/x86/realmode/rm/wakemain.c | 82 ++++++++++++++ arch/x86/realmode/rm/wakeup.h | 41 +++++++ arch/x86/realmode/rm/wakeup/.gitignore | 3 - arch/x86/realmode/rm/wakeup/Makefile | 33 ------ arch/x86/realmode/rm/wakeup/bioscall.S | 1 - arch/x86/realmode/rm/wakeup/copy.S | 1 - arch/x86/realmode/rm/wakeup/regs.c | 1 - arch/x86/realmode/rm/wakeup/video-bios.c | 1 - arch/x86/realmode/rm/wakeup/video-mode.c | 1 - arch/x86/realmode/rm/wakeup/video-vesa.c | 1 - arch/x86/realmode/rm/wakeup/video-vga.c | 1 - arch/x86/realmode/rm/wakeup/wakemain.c | 82 -------------- arch/x86/realmode/rm/wakeup/wakeup.h | 41 ------- arch/x86/realmode/rm/wakeup/wakeup_asm.S | 181 ------------------------------- arch/x86/realmode/rm/wakeup_asm.S | 181 +++++++++++++++++++++++++++++++ 24 files changed, 325 insertions(+), 355 deletions(-) create mode 100644 arch/x86/realmode/rm/bioscall.S create mode 100644 arch/x86/realmode/rm/copy.S create mode 100644 arch/x86/realmode/rm/regs.c create mode 100644 arch/x86/realmode/rm/video-bios.c create mode 100644 arch/x86/realmode/rm/video-mode.c create mode 100644 arch/x86/realmode/rm/video-vesa.c create mode 100644 arch/x86/realmode/rm/video-vga.c create mode 100644 arch/x86/realmode/rm/wakemain.c create mode 100644 arch/x86/realmode/rm/wakeup.h delete mode 100644 arch/x86/realmode/rm/wakeup/.gitignore delete mode 100644 arch/x86/realmode/rm/wakeup/Makefile delete mode 100644 arch/x86/realmode/rm/wakeup/bioscall.S delete mode 100644 arch/x86/realmode/rm/wakeup/copy.S delete mode 100644 arch/x86/realmode/rm/wakeup/regs.c delete mode 100644 arch/x86/realmode/rm/wakeup/video-bios.c delete mode 100644 arch/x86/realmode/rm/wakeup/video-mode.c delete mode 100644 arch/x86/realmode/rm/wakeup/video-vesa.c delete mode 100644 arch/x86/realmode/rm/wakeup/video-vga.c delete mode 100644 arch/x86/realmode/rm/wakeup/wakemain.c delete mode 100644 arch/x86/realmode/rm/wakeup/wakeup.h delete mode 100644 arch/x86/realmode/rm/wakeup/wakeup_asm.S create mode 100644 arch/x86/realmode/rm/wakeup_asm.S (limited to 'arch/x86/realmode') diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c index 6ca3f54ebe7d..95bf99de9058 100644 --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c @@ -16,7 +16,7 @@ #include #include -#include "../../realmode/rm/wakeup/wakeup.h" +#include "../../realmode/rm/wakeup.h" #include "sleep.h" unsigned long acpi_realmode_flags; diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile index c2c27a41ab8f..fc8854b09dfa 100644 --- a/arch/x86/realmode/rm/Makefile +++ b/arch/x86/realmode/rm/Makefile @@ -7,21 +7,26 @@ # # -subdir- := wakeup - 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 +realmode-$(CONFIG_ACPI_SLEEP) += $(wakeup-objs) + +wakeup-objs := wakeup_asm.o wakemain.o video-mode.o +wakeup-objs += copy.o bioscall.o regs.o +# The link order of the video-*.o modules can matter. In particular, +# video-vga.o *must* be listed first, followed by video-vesa.o. +# Hardware-specific drivers should follow in the order they should be +# probed, and video-bios.o should typically be last. +wakeup-objs += video-vga.o +wakeup-objs += video-vesa.o +wakeup-objs += video-bios.o targets += $(realmode-y) -$(obj)/wakeup/wakeup.o: FORCE - $(Q)$(MAKE) $(build)=$(obj)/wakeup $@ - REALMODE_OBJS = $(addprefix $(obj)/,$(realmode-y)) sed-pasyms := -n -r -e 's/^([0-9a-fA-F]+) [ABCDGRSTVW] (.+)$$/pa_\2 = \2;/p' @@ -55,7 +60,8 @@ $(obj)/realmode.relocs: $(obj)/realmode.elf FORCE # How to compile the 16-bit code. Note we always compile for -march=i386, # that way we can complain to the user if the CPU is insufficient. -KBUILD_CFLAGS := $(LINUXINCLUDE) -m32 -g -Os -D_SETUP -D__KERNEL__ \ +KBUILD_CFLAGS := $(LINUXINCLUDE) -m32 -g -Os -D_SETUP -D__KERNEL__ -D_WAKEUP \ + -I$(srctree)/arch/x86/boot \ -DDISABLE_BRANCH_PROFILING \ -Wall -Wstrict-prototypes \ -march=i386 -mregparm=3 \ diff --git a/arch/x86/realmode/rm/bioscall.S b/arch/x86/realmode/rm/bioscall.S new file mode 100644 index 000000000000..16162d197918 --- /dev/null +++ b/arch/x86/realmode/rm/bioscall.S @@ -0,0 +1 @@ +#include "../../boot/bioscall.S" diff --git a/arch/x86/realmode/rm/copy.S b/arch/x86/realmode/rm/copy.S new file mode 100644 index 000000000000..b785e6f38fdd --- /dev/null +++ b/arch/x86/realmode/rm/copy.S @@ -0,0 +1 @@ +#include "../../boot/copy.S" diff --git a/arch/x86/realmode/rm/regs.c b/arch/x86/realmode/rm/regs.c new file mode 100644 index 000000000000..fbb15b9f9ca9 --- /dev/null +++ b/arch/x86/realmode/rm/regs.c @@ -0,0 +1 @@ +#include "../../boot/regs.c" diff --git a/arch/x86/realmode/rm/video-bios.c b/arch/x86/realmode/rm/video-bios.c new file mode 100644 index 000000000000..848b25aaf11b --- /dev/null +++ b/arch/x86/realmode/rm/video-bios.c @@ -0,0 +1 @@ +#include "../../boot/video-bios.c" diff --git a/arch/x86/realmode/rm/video-mode.c b/arch/x86/realmode/rm/video-mode.c new file mode 100644 index 000000000000..2a98b7e2368b --- /dev/null +++ b/arch/x86/realmode/rm/video-mode.c @@ -0,0 +1 @@ +#include "../../boot/video-mode.c" diff --git a/arch/x86/realmode/rm/video-vesa.c b/arch/x86/realmode/rm/video-vesa.c new file mode 100644 index 000000000000..413edddb51e5 --- /dev/null +++ b/arch/x86/realmode/rm/video-vesa.c @@ -0,0 +1 @@ +#include "../../boot/video-vesa.c" diff --git a/arch/x86/realmode/rm/video-vga.c b/arch/x86/realmode/rm/video-vga.c new file mode 100644 index 000000000000..3085f5c9d288 --- /dev/null +++ b/arch/x86/realmode/rm/video-vga.c @@ -0,0 +1 @@ +#include "../../boot/video-vga.c" diff --git a/arch/x86/realmode/rm/wakemain.c b/arch/x86/realmode/rm/wakemain.c new file mode 100644 index 000000000000..91405d515ec6 --- /dev/null +++ b/arch/x86/realmode/rm/wakemain.c @@ -0,0 +1,82 @@ +#include "wakeup.h" +#include "boot.h" + +static void udelay(int loops) +{ + while (loops--) + io_delay(); /* Approximately 1 us */ +} + +static void beep(unsigned int hz) +{ + u8 enable; + + if (!hz) { + enable = 0x00; /* Turn off speaker */ + } else { + u16 div = 1193181/hz; + + outb(0xb6, 0x43); /* Ctr 2, squarewave, load, binary */ + io_delay(); + outb(div, 0x42); /* LSB of counter */ + io_delay(); + outb(div >> 8, 0x42); /* MSB of counter */ + io_delay(); + + enable = 0x03; /* Turn on speaker */ + } + inb(0x61); /* Dummy read of System Control Port B */ + io_delay(); + outb(enable, 0x61); /* Enable timer 2 output to speaker */ + io_delay(); +} + +#define DOT_HZ 880 +#define DASH_HZ 587 +#define US_PER_DOT 125000 + +/* Okay, this is totally silly, but it's kind of fun. */ +static void send_morse(const char *pattern) +{ + char s; + + while ((s = *pattern++)) { + switch (s) { + case '.': + beep(DOT_HZ); + udelay(US_PER_DOT); + beep(0); + udelay(US_PER_DOT); + break; + case '-': + beep(DASH_HZ); + udelay(US_PER_DOT * 3); + beep(0); + udelay(US_PER_DOT); + break; + default: /* Assume it's a space */ + udelay(US_PER_DOT * 3); + break; + } + } +} + +void main(void) +{ + /* Kill machine if structures are wrong */ + if (wakeup_header.real_magic != 0x12345678) + while (1) + ; + + if (wakeup_header.realmode_flags & 4) + send_morse("...-"); + + if (wakeup_header.realmode_flags & 1) + asm volatile("lcallw $0xc000,$3"); + + if (wakeup_header.realmode_flags & 2) { + /* Need to call BIOS */ + probe_cards(0); + set_mode(wakeup_header.video_mode); + } +} diff --git a/arch/x86/realmode/rm/wakeup.h b/arch/x86/realmode/rm/wakeup.h new file mode 100644 index 000000000000..2dfaf06b8af1 --- /dev/null +++ b/arch/x86/realmode/rm/wakeup.h @@ -0,0 +1,41 @@ +/* + * Definitions for the wakeup data structure at the head of the + * wakeup code. + */ + +#ifndef ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H +#define ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H + +#ifndef __ASSEMBLY__ +#include + +/* This must match data at wakeup.S */ +struct wakeup_header { + u16 video_mode; /* Video mode number */ + u32 pmode_entry; /* Protected mode resume point, 32-bit only */ + u16 pmode_cs; + u32 pmode_cr0; /* Protected mode cr0 */ + u32 pmode_cr3; /* Protected mode cr3 */ + u32 pmode_cr4; /* Protected mode cr4 */ + u32 pmode_efer_low; /* Protected mode EFER */ + u32 pmode_efer_high; + u64 pmode_gdt; + u32 pmode_misc_en_low; /* Protected mode MISC_ENABLE */ + u32 pmode_misc_en_high; + u32 pmode_behavior; /* Wakeup routine behavior flags */ + u32 realmode_flags; + u32 real_magic; + u32 signature; /* To check we have correct structure */ +} __attribute__((__packed__)); + +extern struct wakeup_header wakeup_header; +#endif + +#define WAKEUP_HEADER_OFFSET 8 +#define WAKEUP_HEADER_SIGNATURE 0x51ee1111 +#define WAKEUP_END_SIGNATURE 0x65a22c82 + +/* Wakeup behavior bits */ +#define WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE 0 + +#endif /* ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H */ diff --git a/arch/x86/realmode/rm/wakeup/.gitignore b/arch/x86/realmode/rm/wakeup/.gitignore deleted file mode 100644 index 58f1f48a58f8..000000000000 --- a/arch/x86/realmode/rm/wakeup/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -wakeup.bin -wakeup.elf -wakeup.lds diff --git a/arch/x86/realmode/rm/wakeup/Makefile b/arch/x86/realmode/rm/wakeup/Makefile deleted file mode 100644 index 4c8533240cdd..000000000000 --- a/arch/x86/realmode/rm/wakeup/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -# -# arch/x86/kernel/acpi/realmode/Makefile -# -# This file is subject to the terms and conditions of the GNU General Public -# License. See the file "COPYING" in the main directory of this archive -# for more details. -# - -always := wakeup.o - -wakeup-y += wakeup_asm.o wakemain.o video-mode.o -wakeup-y += copy.o bioscall.o regs.o - -# The link order of the video-*.o modules can matter. In particular, -# video-vga.o *must* be listed first, followed by video-vesa.o. -# Hardware-specific drivers should follow in the order they should be -# probed, and video-bios.o should typically be last. -wakeup-y += video-vga.o -wakeup-y += video-vesa.o -wakeup-y += video-bios.o - -targets += $(wakeup-y) - -WAKEUP_OBJS = $(addprefix $(obj)/,$(wakeup-y)) - -LDFLAGS_wakeup.o := -m elf_i386 -r -$(obj)/wakeup.o: $(WAKEUP_OBJS) FORCE - $(call if_changed,ld) - -bootsrc := $(src)/../../../boot - -ccflags-y += -D_WAKEUP -I$(srctree)/$(bootsrc) -asflags-y += -D_WAKEUP -I$(srctree)/$(bootsrc) diff --git a/arch/x86/realmode/rm/wakeup/bioscall.S b/arch/x86/realmode/rm/wakeup/bioscall.S deleted file mode 100644 index f51eb0bb56ce..000000000000 --- a/arch/x86/realmode/rm/wakeup/bioscall.S +++ /dev/null @@ -1 +0,0 @@ -#include "../../../boot/bioscall.S" diff --git a/arch/x86/realmode/rm/wakeup/copy.S b/arch/x86/realmode/rm/wakeup/copy.S deleted file mode 100644 index dc59ebee69d8..000000000000 --- a/arch/x86/realmode/rm/wakeup/copy.S +++ /dev/null @@ -1 +0,0 @@ -#include "../../../boot/copy.S" diff --git a/arch/x86/realmode/rm/wakeup/regs.c b/arch/x86/realmode/rm/wakeup/regs.c deleted file mode 100644 index 6206033ba202..000000000000 --- a/arch/x86/realmode/rm/wakeup/regs.c +++ /dev/null @@ -1 +0,0 @@ -#include "../../../boot/regs.c" diff --git a/arch/x86/realmode/rm/wakeup/video-bios.c b/arch/x86/realmode/rm/wakeup/video-bios.c deleted file mode 100644 index 7deabc144a27..000000000000 --- a/arch/x86/realmode/rm/wakeup/video-bios.c +++ /dev/null @@ -1 +0,0 @@ -#include "../../../boot/video-bios.c" diff --git a/arch/x86/realmode/rm/wakeup/video-mode.c b/arch/x86/realmode/rm/wakeup/video-mode.c deleted file mode 100644 index 328ad209f113..000000000000 --- a/arch/x86/realmode/rm/wakeup/video-mode.c +++ /dev/null @@ -1 +0,0 @@ -#include "../../../boot/video-mode.c" diff --git a/arch/x86/realmode/rm/wakeup/video-vesa.c b/arch/x86/realmode/rm/wakeup/video-vesa.c deleted file mode 100644 index 9dbb9672226a..000000000000 --- a/arch/x86/realmode/rm/wakeup/video-vesa.c +++ /dev/null @@ -1 +0,0 @@ -#include "../../../boot/video-vesa.c" diff --git a/arch/x86/realmode/rm/wakeup/video-vga.c b/arch/x86/realmode/rm/wakeup/video-vga.c deleted file mode 100644 index bcc81255f374..000000000000 --- a/arch/x86/realmode/rm/wakeup/video-vga.c +++ /dev/null @@ -1 +0,0 @@ -#include "../../../boot/video-vga.c" diff --git a/arch/x86/realmode/rm/wakeup/wakemain.c b/arch/x86/realmode/rm/wakeup/wakemain.c deleted file mode 100644 index 91405d515ec6..000000000000 --- a/arch/x86/realmode/rm/wakeup/wakemain.c +++ /dev/null @@ -1,82 +0,0 @@ -#include "wakeup.h" -#include "boot.h" - -static void udelay(int loops) -{ - while (loops--) - io_delay(); /* Approximately 1 us */ -} - -static void beep(unsigned int hz) -{ - u8 enable; - - if (!hz) { - enable = 0x00; /* Turn off speaker */ - } else { - u16 div = 1193181/hz; - - outb(0xb6, 0x43); /* Ctr 2, squarewave, load, binary */ - io_delay(); - outb(div, 0x42); /* LSB of counter */ - io_delay(); - outb(div >> 8, 0x42); /* MSB of counter */ - io_delay(); - - enable = 0x03; /* Turn on speaker */ - } - inb(0x61); /* Dummy read of System Control Port B */ - io_delay(); - outb(enable, 0x61); /* Enable timer 2 output to speaker */ - io_delay(); -} - -#define DOT_HZ 880 -#define DASH_HZ 587 -#define US_PER_DOT 125000 - -/* Okay, this is totally silly, but it's kind of fun. */ -static void send_morse(const char *pattern) -{ - char s; - - while ((s = *pattern++)) { - switch (s) { - case '.': - beep(DOT_HZ); - udelay(US_PER_DOT); - beep(0); - udelay(US_PER_DOT); - break; - case '-': - beep(DASH_HZ); - udelay(US_PER_DOT * 3); - beep(0); - udelay(US_PER_DOT); - break; - default: /* Assume it's a space */ - udelay(US_PER_DOT * 3); - break; - } - } -} - -void main(void) -{ - /* Kill machine if structures are wrong */ - if (wakeup_header.real_magic != 0x12345678) - while (1) - ; - - if (wakeup_header.realmode_flags & 4) - send_morse("...-"); - - if (wakeup_header.realmode_flags & 1) - asm volatile("lcallw $0xc000,$3"); - - if (wakeup_header.realmode_flags & 2) { - /* Need to call BIOS */ - probe_cards(0); - set_mode(wakeup_header.video_mode); - } -} diff --git a/arch/x86/realmode/rm/wakeup/wakeup.h b/arch/x86/realmode/rm/wakeup/wakeup.h deleted file mode 100644 index 2dfaf06b8af1..000000000000 --- a/arch/x86/realmode/rm/wakeup/wakeup.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Definitions for the wakeup data structure at the head of the - * wakeup code. - */ - -#ifndef ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H -#define ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H - -#ifndef __ASSEMBLY__ -#include - -/* This must match data at wakeup.S */ -struct wakeup_header { - u16 video_mode; /* Video mode number */ - u32 pmode_entry; /* Protected mode resume point, 32-bit only */ - u16 pmode_cs; - u32 pmode_cr0; /* Protected mode cr0 */ - u32 pmode_cr3; /* Protected mode cr3 */ - u32 pmode_cr4; /* Protected mode cr4 */ - u32 pmode_efer_low; /* Protected mode EFER */ - u32 pmode_efer_high; - u64 pmode_gdt; - u32 pmode_misc_en_low; /* Protected mode MISC_ENABLE */ - u32 pmode_misc_en_high; - u32 pmode_behavior; /* Wakeup routine behavior flags */ - u32 realmode_flags; - u32 real_magic; - u32 signature; /* To check we have correct structure */ -} __attribute__((__packed__)); - -extern struct wakeup_header wakeup_header; -#endif - -#define WAKEUP_HEADER_OFFSET 8 -#define WAKEUP_HEADER_SIGNATURE 0x51ee1111 -#define WAKEUP_END_SIGNATURE 0x65a22c82 - -/* Wakeup behavior bits */ -#define WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE 0 - -#endif /* ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H */ diff --git a/arch/x86/realmode/rm/wakeup/wakeup_asm.S b/arch/x86/realmode/rm/wakeup/wakeup_asm.S deleted file mode 100644 index f81c1cd99eaf..000000000000 --- a/arch/x86/realmode/rm/wakeup/wakeup_asm.S +++ /dev/null @@ -1,181 +0,0 @@ -/* - * ACPI wakeup real mode startup stub - */ -#include -#include -#include -#include -#include -#include -#include "../realmode.h" -#include "wakeup.h" - - .code16 - -/* This should match the structure in wakeup.h */ - .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 - - .balign 16 -ENTRY(wakeup_start) - cli - cld - - LJMPW_RM(3f) -3: - /* Apparently some dimwit BIOS programmers don't know how to - program a PM to RM transition, and we might end up here with - junk in the data segment descriptor registers. The only way - to repair that is to go into PM and fix it ourselves... */ - movw $16, %cx - lgdtl %cs:wakeup_gdt - movl %cr0, %eax - orb $X86_CR0_PE, %al - movl %eax, %cr0 - ljmpw $8, $2f -2: - movw %cx, %ds - movw %cx, %es - movw %cx, %ss - movw %cx, %fs - movw %cx, %gs - - andb $~X86_CR0_PE, %al - movl %eax, %cr0 - LJMPW_RM(3f) -3: - /* Set up segments */ - movw %cs, %ax - movw %ax, %ss - movl $rm_stack_end, %esp - movw %ax, %ds - movw %ax, %es - movw %ax, %fs - movw %ax, %gs - - lidtl wakeup_idt - - /* Clear the EFLAGS */ - pushl $0 - popfl - - /* Check header signature... */ - movl signature, %eax - cmpl $WAKEUP_HEADER_SIGNATURE, %eax - jne bogus_real_magic - - /* Check we really have everything... */ - movl end_signature, %eax - cmpl $WAKEUP_END_SIGNATURE, %eax - jne bogus_real_magic - - /* Call the C code */ - calll main - - /* Restore MISC_ENABLE before entering protected mode, in case - BIOS decided to clear XD_DISABLE during S3. */ - movl pmode_behavior, %eax - btl $WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %eax - jnc 1f - - movl pmode_misc_en, %eax - movl pmode_misc_en + 4, %edx - movl $MSR_IA32_MISC_ENABLE, %ecx - wrmsr -1: - - /* Do any other stuff... */ - -#ifndef CONFIG_64BIT - /* This could also be done in C code... */ - movl pmode_cr3, %eax - movl %eax, %cr3 - - movl pmode_cr4, %ecx - jecxz 1f - movl %ecx, %cr4 -1: - movl pmode_efer, %eax - movl pmode_efer + 4, %edx - movl %eax, %ecx - orl %edx, %ecx - jz 1f - movl $MSR_EFER, %ecx - wrmsr -1: - - lgdtl pmode_gdt - - /* This really couldn't... */ - movl pmode_entry, %eax - movl pmode_cr0, %ecx - movl %ecx, %cr0 - ljmpl $__KERNEL_CS, $pa_startup_32 - /* -> jmp *%eax in trampoline_32.S */ -#else - jmp trampoline_data -#endif - -bogus_real_magic: -1: - hlt - jmp 1b - - .section ".rodata","a" - - /* - * Set up the wakeup GDT. We set these up as Big Real Mode, - * that is, with limits set to 4 GB. At least the Lenovo - * Thinkpad X61 is known to need this for the video BIOS - * initialization quirk to work; this is likely to also - * be the case for other laptops or integrated video devices. - */ - - .balign 16 -GLOBAL(wakeup_gdt) - .word 3*8-1 /* Self-descriptor */ - .long pa_wakeup_gdt - .word 0 - - .word 0xffff /* 16-bit code segment @ real_mode_base */ - .long 0x9b000000 + pa_real_mode_base - .word 0x008f /* big real mode */ - - .word 0xffff /* 16-bit data segment @ real_mode_base */ - .long 0x93000000 + pa_real_mode_base - .word 0x008f /* big real mode */ -END(wakeup_gdt) - - .section ".rodata","a" - .balign 8 - - /* This is the standard real-mode IDT */ - .balign 16 -GLOBAL(wakeup_idt) - .word 0xffff /* limit */ - .long 0 /* address */ - .word 0 -END(wakeup_idt) - - .section ".signature","a" -end_signature: - .long WAKEUP_END_SIGNATURE diff --git a/arch/x86/realmode/rm/wakeup_asm.S b/arch/x86/realmode/rm/wakeup_asm.S new file mode 100644 index 000000000000..8a57c5a05fbc --- /dev/null +++ b/arch/x86/realmode/rm/wakeup_asm.S @@ -0,0 +1,181 @@ +/* + * ACPI wakeup real mode startup stub + */ +#include +#include +#include +#include +#include +#include +#include "realmode.h" +#include "wakeup.h" + + .code16 + +/* This should match the structure in wakeup.h */ + .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 + + .balign 16 +ENTRY(wakeup_start) + cli + cld + + LJMPW_RM(3f) +3: + /* Apparently some dimwit BIOS programmers don't know how to + program a PM to RM transition, and we might end up here with + junk in the data segment descriptor registers. The only way + to repair that is to go into PM and fix it ourselves... */ + movw $16, %cx + lgdtl %cs:wakeup_gdt + movl %cr0, %eax + orb $X86_CR0_PE, %al + movl %eax, %cr0 + ljmpw $8, $2f +2: + movw %cx, %ds + movw %cx, %es + movw %cx, %ss + movw %cx, %fs + movw %cx, %gs + + andb $~X86_CR0_PE, %al + movl %eax, %cr0 + LJMPW_RM(3f) +3: + /* Set up segments */ + movw %cs, %ax + movw %ax, %ss + movl $rm_stack_end, %esp + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + + lidtl wakeup_idt + + /* Clear the EFLAGS */ + pushl $0 + popfl + + /* Check header signature... */ + movl signature, %eax + cmpl $WAKEUP_HEADER_SIGNATURE, %eax + jne bogus_real_magic + + /* Check we really have everything... */ + movl end_signature, %eax + cmpl $WAKEUP_END_SIGNATURE, %eax + jne bogus_real_magic + + /* Call the C code */ + calll main + + /* Restore MISC_ENABLE before entering protected mode, in case + BIOS decided to clear XD_DISABLE during S3. */ + movl pmode_behavior, %eax + btl $WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %eax + jnc 1f + + movl pmode_misc_en, %eax + movl pmode_misc_en + 4, %edx + movl $MSR_IA32_MISC_ENABLE, %ecx + wrmsr +1: + + /* Do any other stuff... */ + +#ifndef CONFIG_64BIT + /* This could also be done in C code... */ + movl pmode_cr3, %eax + movl %eax, %cr3 + + movl pmode_cr4, %ecx + jecxz 1f + movl %ecx, %cr4 +1: + movl pmode_efer, %eax + movl pmode_efer + 4, %edx + movl %eax, %ecx + orl %edx, %ecx + jz 1f + movl $MSR_EFER, %ecx + wrmsr +1: + + lgdtl pmode_gdt + + /* This really couldn't... */ + movl pmode_entry, %eax + movl pmode_cr0, %ecx + movl %ecx, %cr0 + ljmpl $__KERNEL_CS, $pa_startup_32 + /* -> jmp *%eax in trampoline_32.S */ +#else + jmp trampoline_data +#endif + +bogus_real_magic: +1: + hlt + jmp 1b + + .section ".rodata","a" + + /* + * Set up the wakeup GDT. We set these up as Big Real Mode, + * that is, with limits set to 4 GB. At least the Lenovo + * Thinkpad X61 is known to need this for the video BIOS + * initialization quirk to work; this is likely to also + * be the case for other laptops or integrated video devices. + */ + + .balign 16 +GLOBAL(wakeup_gdt) + .word 3*8-1 /* Self-descriptor */ + .long pa_wakeup_gdt + .word 0 + + .word 0xffff /* 16-bit code segment @ real_mode_base */ + .long 0x9b000000 + pa_real_mode_base + .word 0x008f /* big real mode */ + + .word 0xffff /* 16-bit data segment @ real_mode_base */ + .long 0x93000000 + pa_real_mode_base + .word 0x008f /* big real mode */ +END(wakeup_gdt) + + .section ".rodata","a" + .balign 8 + + /* This is the standard real-mode IDT */ + .balign 16 +GLOBAL(wakeup_idt) + .word 0xffff /* limit */ + .long 0 /* address */ + .word 0 +END(wakeup_idt) + + .section ".signature","a" +end_signature: + .long WAKEUP_END_SIGNATURE -- cgit v1.2.3 From f37240f16bec91f15ce564515f70a6ca9715ce96 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Tue, 8 May 2012 21:22:43 +0300 Subject: x86, realmode: header for trampoline code Added header for trampoline code that can be used to supply input data to it. This makes interface between real mode code and kernel cleaner and simpler. Replaced two confusing pointers to level4 pgt in trampoline_64.S with a single pointer to the beginning of the page table. Signed-off-by: Jarkko Sakkinen Link: http://lkml.kernel.org/r/1336501366-28617-21-git-send-email-jarkko.sakkinen@intel.com Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/realmode.h | 32 +++++++++++++++++----------- arch/x86/kernel/realmode.c | 27 +++++++++++++----------- arch/x86/kernel/smpboot.c | 2 +- arch/x86/realmode/rm/header.S | 35 ++++++++++++++----------------- arch/x86/realmode/rm/trampoline_32.S | 36 ++++++-------------------------- arch/x86/realmode/rm/trampoline_64.S | 18 +++++----------- arch/x86/realmode/rm/trampoline_common.S | 23 ++++++++++++++++++++ arch/x86/realmode/rm/wakeup_asm.S | 2 +- 8 files changed, 87 insertions(+), 88 deletions(-) create mode 100644 arch/x86/realmode/rm/trampoline_common.S (limited to 'arch/x86/realmode') diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h index d3ae49f4c3ef..1421eed1c8e8 100644 --- a/arch/x86/include/asm/realmode.h +++ b/arch/x86/include/asm/realmode.h @@ -8,24 +8,32 @@ struct real_mode_header { u32 text_start; u32 ro_end; - /* reboot */ -#ifdef CONFIG_X86_32 - u32 machine_real_restart_asm; -#endif /* SMP trampoline */ - u32 trampoline_data; + u32 trampoline_start; 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; + u32 trampoline_header; +#ifdef CONFIG_X86_64 + u32 trampoline_pgd; #endif + /* ACPI S3 wakeup */ #ifdef CONFIG_ACPI_SLEEP u32 wakeup_start; u32 wakeup_header; +#endif + /* APM/BIOS reboot */ +#ifdef CONFIG_X86_32 + u32 machine_real_restart_asm; +#endif +} __attribute__((__packed__)); + +/* This must match data at trampoline_32/64.S */ +struct trampoline_header { +#ifdef CONFIG_X86_32 + u32 start; + u16 gdt_limit; + u32 gdt_base; +#else + u64 start; #endif } __attribute__((__packed__)); diff --git a/arch/x86/kernel/realmode.c b/arch/x86/kernel/realmode.c index 632c810ec8ea..712fba8fd774 100644 --- a/arch/x86/kernel/realmode.c +++ b/arch/x86/kernel/realmode.c @@ -17,8 +17,11 @@ void __init setup_real_mode(void) u16 *seg; int i; unsigned char *base; - + struct trampoline_header *trampoline_header; size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob); +#ifdef CONFIG_X86_64 + u64 *trampoline_pgd; +#endif /* Has to be in very low memory so we can execute real-mode AP code. */ mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE); @@ -28,7 +31,6 @@ void __init setup_real_mode(void) base = __va(mem); memblock_reserve(mem, size); real_mode_header = (struct real_mode_header *) base; - printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n", base, (unsigned long long)mem, size); @@ -53,18 +55,19 @@ void __init setup_real_mode(void) *ptr += __pa(base); } + /* Must be perfomed *after* relocation. */ + trampoline_header = (struct trampoline_header *) + __va(real_mode_header->trampoline_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); + trampoline_header->start = __pa(startup_32_smp); + trampoline_header->gdt_limit = __BOOT_DS + 7; + trampoline_header->gdt_base = __pa(boot_gdt); #else - *((u64 *) __va(real_mode_header->startup_64_smp)) = - (u64)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; + trampoline_header->start = (u64) secondary_startup_64; + trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd); + trampoline_pgd[0] = __pa(level3_ident_pgt) + _KERNPG_TABLE; + trampoline_pgd[511] = __pa(level3_kernel_pgt) + _KERNPG_TABLE; #endif } diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index b8c0661e2341..757c4b1d0a02 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c @@ -667,7 +667,7 @@ 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 start_ip = real_mode_header->trampoline_start; unsigned long boot_error = 0; int timeout; diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S index c83005c4d455..b4c32632bf16 100644 --- a/arch/x86/realmode/rm/header.S +++ b/arch/x86/realmode/rm/header.S @@ -7,28 +7,25 @@ #include #include - .section ".header", "a" + .section ".header", "a" GLOBAL(real_mode_header) - .long pa_text_start - .long pa_ro_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 + .long pa_text_start + .long pa_ro_end + /* SMP trampoline */ + .long pa_trampoline_start + .long pa_trampoline_status + .long pa_trampoline_header +#ifdef CONFIG_X86_64 + .long pa_trampoline_pgd; #endif - /* ACPI sleep */ + /* ACPI S3 wakeup */ #ifdef CONFIG_ACPI_SLEEP - .long pa_wakeup_start - .long pa_wakeup_header + .long pa_wakeup_start + .long pa_wakeup_header +#endif + /* APM/BIOS reboot */ +#ifdef CONFIG_X86_32 + .long pa_machine_real_restart_asm #endif END(real_mode_header) diff --git a/arch/x86/realmode/rm/trampoline_32.S b/arch/x86/realmode/rm/trampoline_32.S index 1ecdbb59191b..6fc064b4d2b9 100644 --- a/arch/x86/realmode/rm/trampoline_32.S +++ b/arch/x86/realmode/rm/trampoline_32.S @@ -13,16 +13,10 @@ * * We jump into arch/x86/kernel/head_32.S. * - * On entry to trampoline_data, the processor is in real mode + * On entry to trampoline_start, 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 @@ -35,7 +29,7 @@ .code16 .balign PAGE_SIZE -ENTRY(trampoline_data) +ENTRY(trampoline_start) wbinvd # Needed for NUMA-Q should be harmless for others LJMPW_RM(1f) @@ -45,7 +39,7 @@ ENTRY(trampoline_data) cli # We should be safe anyway - movl startup_32_smp, %eax # where we need to go + movl tr_start, %eax # where we need to go movl $0xA5A5A5A5, trampoline_status # write marker for master knows we're running @@ -56,8 +50,8 @@ ENTRY(trampoline_data) * 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 + lidtl tr_idt # load idt with 0, 0 + lgdtl tr_gdt # load gdt with whatever is appropriate movw $1, %dx # protected mode (PE) bit lmsw %dx # into protected mode @@ -69,22 +63,4 @@ ENTRY(trampoline_data) ENTRY(startup_32) # note: also used from wakeup_asm.S jmp *%eax - .section ".rodata","a" - - .balign 4 -boot_idt_descr: - .word 0 # idt limit = 0 - .long 0 # idt base = 0L - - .data - -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 +#include "trampoline_common.S" diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S index f71ea0800d3d..3f7293239365 100644 --- a/arch/x86/realmode/rm/trampoline_64.S +++ b/arch/x86/realmode/rm/trampoline_64.S @@ -10,7 +10,7 @@ * trampoline page to make our stack and everything else * is a mystery. * - * On entry to trampoline_data, the processor is in real mode + * On entry to trampoline_start, the processor is in real mode * with 16-bit addressing and 16-bit data. CS has some value * and IP is zero. Thus, data addresses need to be absolute * (no relocation) and are taken with regard to r_base. @@ -37,7 +37,7 @@ .balign PAGE_SIZE .code16 -ENTRY(trampoline_data) +ENTRY(trampoline_start) cli # We should be safe anyway wbinvd @@ -97,7 +97,7 @@ ENTRY(startup_32) movl %eax, %cr4 # Enable PAE mode # Setup trampoline 4 level pagetables - movl $pa_level3_ident_pgt, %eax + movl $pa_trampoline_pgd, %eax movl %eax, %cr3 movl $MSR_EFER, %ecx @@ -122,7 +122,7 @@ ENTRY(startup_32) .balign 4 ENTRY(startup_64) # Now jump into the kernel using virtual addresses - jmpq *startup_64_smp(%rip) + jmpq *tr_start(%rip) .section ".rodata","a" .balign 16 @@ -143,12 +143,4 @@ tgdt: .quad 0x00cf93000000ffff # __KERNEL_DS tgdt_end: - .bss - - .balign PAGE_SIZE -GLOBAL(level3_ident_pgt) .space 511*8 -GLOBAL(level3_kernel_pgt) .space 8 - - .balign 8 -GLOBAL(startup_64_smp) .space 8 -GLOBAL(trampoline_status) .space 4 +#include "trampoline_common.S" diff --git a/arch/x86/realmode/rm/trampoline_common.S b/arch/x86/realmode/rm/trampoline_common.S new file mode 100644 index 000000000000..c3f951c468c5 --- /dev/null +++ b/arch/x86/realmode/rm/trampoline_common.S @@ -0,0 +1,23 @@ + .section ".rodata","a" + + .balign 4 +tr_idt: .fill 1, 6, 0 + + .bss + + .balign 4 +GLOBAL(trampoline_status) .space 4 + +GLOBAL(trampoline_header) +#ifdef CONFIG_X86_32 + tr_start: .space 4 + tr_gdt: .space 6 +#else + tr_start: .space 8 +#endif +END(trampoline_header) + +#ifdef CONFIG_X86_64 + .balign PAGE_SIZE +GLOBAL(trampoline_pgd) .space PAGE_SIZE +#endif diff --git a/arch/x86/realmode/rm/wakeup_asm.S b/arch/x86/realmode/rm/wakeup_asm.S index 8a57c5a05fbc..46108f05e04e 100644 --- a/arch/x86/realmode/rm/wakeup_asm.S +++ b/arch/x86/realmode/rm/wakeup_asm.S @@ -132,7 +132,7 @@ ENTRY(wakeup_start) ljmpl $__KERNEL_CS, $pa_startup_32 /* -> jmp *%eax in trampoline_32.S */ #else - jmp trampoline_data + jmp trampoline_start #endif bogus_real_magic: -- cgit v1.2.3 From f2604c141a00c00b92b7fd2f9d2455517fdd6c15 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Tue, 8 May 2012 21:22:44 +0300 Subject: x86, realmode: move relocs from scripts/ to arch/x86/tools Moved relocs tool from scripts/ to arch/x86/tools because it is architecture specific script. Added new target archscripts that can be used to build scripts needed building an architecture. Signed-off-by: Jarkko Sakkinen Link: http://lkml.kernel.org/r/1336501366-28617-22-git-send-email-jarkko.sakkinen@intel.com Signed-off-by: H. Peter Anvin Cc: Sam Ravnborg Cc: Michal Marek --- Makefile | 9 +- arch/x86/Makefile | 3 + arch/x86/boot/compressed/Makefile | 4 +- arch/x86/realmode/rm/Makefile | 2 +- arch/x86/tools/.gitignore | 1 + arch/x86/tools/Makefile | 4 + arch/x86/tools/relocs.c | 804 ++++++++++++++++++++++++++++++++++++++ scripts/Makefile | 1 - scripts/x86-relocs.c | 804 -------------------------------------- 9 files changed, 821 insertions(+), 811 deletions(-) create mode 100644 arch/x86/tools/.gitignore create mode 100644 arch/x86/tools/relocs.c delete mode 100644 scripts/x86-relocs.c (limited to 'arch/x86/realmode') diff --git a/Makefile b/Makefile index 9e384ae6c403..ed1bd29dc03c 100644 --- a/Makefile +++ b/Makefile @@ -442,7 +442,7 @@ asm-generic: no-dot-config-targets := clean mrproper distclean \ cscope gtags TAGS tags help %docs check% coccicheck \ - include/linux/version.h headers_% archheaders \ + include/linux/version.h headers_% archheaders archscripts \ kernelversion %src-pkg config-targets := 0 @@ -979,7 +979,7 @@ prepare1: prepare2 include/linux/version.h include/generated/utsrelease.h \ include/config/auto.conf $(cmd_crmodverdir) -archprepare: archheaders prepare1 scripts_basic +archprepare: archheaders archscripts prepare1 scripts_basic prepare0: archprepare FORCE $(Q)$(MAKE) $(build)=. @@ -1049,8 +1049,11 @@ hdr-dst = $(if $(KBUILD_HEADERS), dst=include/asm-$(hdr-arch), dst=include/asm) PHONY += archheaders archheaders: +PHONY += archscripts +archscripts: + PHONY += __headers -__headers: include/linux/version.h scripts_basic asm-generic archheaders FORCE +__headers: include/linux/version.h scripts_basic asm-generic archheaders archscripts FORCE $(Q)$(MAKE) $(build)=scripts build_unifdef PHONY += headers_install_all diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 41a7237606a3..94e91e401da9 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -134,6 +134,9 @@ KBUILD_CFLAGS += $(call cc-option,-mno-avx,) KBUILD_CFLAGS += $(mflags-y) KBUILD_AFLAGS += $(mflags-y) +archscripts: + $(Q)$(MAKE) $(build)=arch/x86/tools relocs + ### # Syscall table generation diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 0435e8a2d20e..e398bb5d63bb 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -42,8 +42,8 @@ $(obj)/vmlinux.bin: vmlinux FORCE targets += vmlinux.bin.all vmlinux.relocs -CMD_RELOCS = scripts/x86-relocs -quiet_cmd_relocs = RELOCS $@ +CMD_RELOCS = arch/x86/tools/relocs +quiet_cmd_relocs = RELOCS $@ cmd_relocs = $(CMD_RELOCS) $< > $@;$(CMD_RELOCS) --abs-relocs $< $(obj)/vmlinux.relocs: vmlinux FORCE $(call if_changed,relocs) diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile index fc8854b09dfa..de40bc44b92f 100644 --- a/arch/x86/realmode/rm/Makefile +++ b/arch/x86/realmode/rm/Makefile @@ -52,7 +52,7 @@ $(obj)/realmode.bin: $(obj)/realmode.elf $(call if_changed,objcopy) quiet_cmd_relocs = RELOCS $@ - cmd_relocs = scripts/x86-relocs --realmode $< > $@ + cmd_relocs = arch/x86/tools/relocs --realmode $< > $@ $(obj)/realmode.relocs: $(obj)/realmode.elf FORCE $(call if_changed,relocs) diff --git a/arch/x86/tools/.gitignore b/arch/x86/tools/.gitignore new file mode 100644 index 000000000000..be0ed065249b --- /dev/null +++ b/arch/x86/tools/.gitignore @@ -0,0 +1 @@ +relocs diff --git a/arch/x86/tools/Makefile b/arch/x86/tools/Makefile index d511aa97533a..733057b435b0 100644 --- a/arch/x86/tools/Makefile +++ b/arch/x86/tools/Makefile @@ -36,3 +36,7 @@ HOSTCFLAGS_insn_sanity.o := -Wall -I$(objtree)/arch/x86/lib/ -I$(srctree)/arch/x $(obj)/test_get_len.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/inat.c $(srctree)/arch/x86/include/asm/inat_types.h $(srctree)/arch/x86/include/asm/inat.h $(srctree)/arch/x86/include/asm/insn.h $(objtree)/arch/x86/lib/inat-tables.c $(obj)/insn_sanity.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/inat.c $(srctree)/arch/x86/include/asm/inat_types.h $(srctree)/arch/x86/include/asm/inat.h $(srctree)/arch/x86/include/asm/insn.h $(objtree)/arch/x86/lib/inat-tables.c + +HOST_EXTRACFLAGS += -I$(srctree)/tools/include +hostprogs-y += relocs +relocs: $(obj)/relocs diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c new file mode 100644 index 000000000000..74e16bb15dc4 --- /dev/null +++ b/arch/x86/tools/relocs.c @@ -0,0 +1,804 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define USE_BSD +#include +#include +#include + +static void die(char *fmt, ...); + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +static Elf32_Ehdr ehdr; +static unsigned long reloc_count, reloc_idx; +static unsigned long *relocs; +static unsigned long reloc16_count, reloc16_idx; +static unsigned long *relocs16; + +struct section { + Elf32_Shdr shdr; + struct section *link; + Elf32_Sym *symtab; + Elf32_Rel *reltab; + char *strtab; +}; +static struct section *secs; + +enum symtype { + S_ABS, + S_REL, + S_SEG, + S_LIN, + S_NSYMTYPES +}; + +static const char * const sym_regex_kernel[S_NSYMTYPES] = { +/* + * Following symbols have been audited. There values are constant and do + * not change if bzImage is loaded at a different physical address than + * the address for which it has been compiled. Don't warn user about + * absolute relocations present w.r.t these symbols. + */ + [S_ABS] = + "^(xen_irq_disable_direct_reloc$|" + "xen_save_fl_direct_reloc$|" + "VDSO|" + "__crc_)", + +/* + * These symbols are known to be relative, even if the linker marks them + * as absolute (typically defined outside any section in the linker script.) + */ + [S_REL] = + "^_end$", +}; + + +static const char * const sym_regex_realmode[S_NSYMTYPES] = { +/* + * These symbols are known to be relative, even if the linker marks them + * as absolute (typically defined outside any section in the linker script.) + */ + [S_REL] = + "^pa_", + +/* + * These are 16-bit segment symbols when compiling 16-bit code. + */ + [S_SEG] = + "^real_mode_seg$", + +/* + * These are offsets belonging to segments, as opposed to linear addresses, + * when compiling 16-bit code. + */ + [S_LIN] = + "^pa_", +}; + +static const char * const *sym_regex; + +static regex_t sym_regex_c[S_NSYMTYPES]; +static int is_reloc(enum symtype type, const char *sym_name) +{ + return sym_regex[type] && + !regexec(&sym_regex_c[type], sym_name, 0, NULL, 0); +} + +static void regex_init(int use_real_mode) +{ + char errbuf[128]; + int err; + int i; + + if (use_real_mode) + sym_regex = sym_regex_realmode; + else + sym_regex = sym_regex_kernel; + + for (i = 0; i < S_NSYMTYPES; i++) { + if (!sym_regex[i]) + continue; + + err = regcomp(&sym_regex_c[i], sym_regex[i], + REG_EXTENDED|REG_NOSUB); + + if (err) { + regerror(err, &sym_regex_c[i], errbuf, sizeof errbuf); + die("%s", errbuf); + } + } +} + +static void die(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + exit(1); +} + +static const char *sym_type(unsigned type) +{ + static const char *type_name[] = { +#define SYM_TYPE(X) [X] = #X + SYM_TYPE(STT_NOTYPE), + SYM_TYPE(STT_OBJECT), + SYM_TYPE(STT_FUNC), + SYM_TYPE(STT_SECTION), + SYM_TYPE(STT_FILE), + SYM_TYPE(STT_COMMON), + SYM_TYPE(STT_TLS), +#undef SYM_TYPE + }; + const char *name = "unknown sym type name"; + if (type < ARRAY_SIZE(type_name)) { + name = type_name[type]; + } + return name; +} + +static const char *sym_bind(unsigned bind) +{ + static const char *bind_name[] = { +#define SYM_BIND(X) [X] = #X + SYM_BIND(STB_LOCAL), + SYM_BIND(STB_GLOBAL), + SYM_BIND(STB_WEAK), +#undef SYM_BIND + }; + const char *name = "unknown sym bind name"; + if (bind < ARRAY_SIZE(bind_name)) { + name = bind_name[bind]; + } + return name; +} + +static const char *sym_visibility(unsigned visibility) +{ + static const char *visibility_name[] = { +#define SYM_VISIBILITY(X) [X] = #X + SYM_VISIBILITY(STV_DEFAULT), + SYM_VISIBILITY(STV_INTERNAL), + SYM_VISIBILITY(STV_HIDDEN), + SYM_VISIBILITY(STV_PROTECTED), +#undef SYM_VISIBILITY + }; + const char *name = "unknown sym visibility name"; + if (visibility < ARRAY_SIZE(visibility_name)) { + name = visibility_name[visibility]; + } + return name; +} + +static const char *rel_type(unsigned type) +{ + static const char *type_name[] = { +#define REL_TYPE(X) [X] = #X + REL_TYPE(R_386_NONE), + REL_TYPE(R_386_32), + REL_TYPE(R_386_PC32), + REL_TYPE(R_386_GOT32), + REL_TYPE(R_386_PLT32), + REL_TYPE(R_386_COPY), + REL_TYPE(R_386_GLOB_DAT), + REL_TYPE(R_386_JMP_SLOT), + REL_TYPE(R_386_RELATIVE), + REL_TYPE(R_386_GOTOFF), + REL_TYPE(R_386_GOTPC), + REL_TYPE(R_386_8), + REL_TYPE(R_386_PC8), + REL_TYPE(R_386_16), + REL_TYPE(R_386_PC16), +#undef REL_TYPE + }; + const char *name = "unknown type rel type name"; + if (type < ARRAY_SIZE(type_name) && type_name[type]) { + name = type_name[type]; + } + return name; +} + +static const char *sec_name(unsigned shndx) +{ + const char *sec_strtab; + const char *name; + sec_strtab = secs[ehdr.e_shstrndx].strtab; + name = ""; + if (shndx < ehdr.e_shnum) { + name = sec_strtab + secs[shndx].shdr.sh_name; + } + else if (shndx == SHN_ABS) { + name = "ABSOLUTE"; + } + else if (shndx == SHN_COMMON) { + name = "COMMON"; + } + return name; +} + +static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym) +{ + const char *name; + name = ""; + if (sym->st_name) { + name = sym_strtab + sym->st_name; + } + else { + name = sec_name(sym->st_shndx); + } + return name; +} + + + +#if BYTE_ORDER == LITTLE_ENDIAN +#define le16_to_cpu(val) (val) +#define le32_to_cpu(val) (val) +#endif +#if BYTE_ORDER == BIG_ENDIAN +#define le16_to_cpu(val) bswap_16(val) +#define le32_to_cpu(val) bswap_32(val) +#endif + +static uint16_t elf16_to_cpu(uint16_t val) +{ + return le16_to_cpu(val); +} + +static uint32_t elf32_to_cpu(uint32_t val) +{ + return le32_to_cpu(val); +} + +static void read_ehdr(FILE *fp) +{ + if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) { + die("Cannot read ELF header: %s\n", + strerror(errno)); + } + if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) { + die("No ELF magic\n"); + } + if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) { + die("Not a 32 bit executable\n"); + } + if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) { + die("Not a LSB ELF executable\n"); + } + if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) { + die("Unknown ELF version\n"); + } + /* Convert the fields to native endian */ + ehdr.e_type = elf16_to_cpu(ehdr.e_type); + ehdr.e_machine = elf16_to_cpu(ehdr.e_machine); + ehdr.e_version = elf32_to_cpu(ehdr.e_version); + ehdr.e_entry = elf32_to_cpu(ehdr.e_entry); + ehdr.e_phoff = elf32_to_cpu(ehdr.e_phoff); + ehdr.e_shoff = elf32_to_cpu(ehdr.e_shoff); + ehdr.e_flags = elf32_to_cpu(ehdr.e_flags); + ehdr.e_ehsize = elf16_to_cpu(ehdr.e_ehsize); + ehdr.e_phentsize = elf16_to_cpu(ehdr.e_phentsize); + ehdr.e_phnum = elf16_to_cpu(ehdr.e_phnum); + ehdr.e_shentsize = elf16_to_cpu(ehdr.e_shentsize); + ehdr.e_shnum = elf16_to_cpu(ehdr.e_shnum); + ehdr.e_shstrndx = elf16_to_cpu(ehdr.e_shstrndx); + + if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) { + die("Unsupported ELF header type\n"); + } + if (ehdr.e_machine != EM_386) { + die("Not for x86\n"); + } + if (ehdr.e_version != EV_CURRENT) { + die("Unknown ELF version\n"); + } + if (ehdr.e_ehsize != sizeof(Elf32_Ehdr)) { + die("Bad Elf header size\n"); + } + if (ehdr.e_phentsize != sizeof(Elf32_Phdr)) { + die("Bad program header entry\n"); + } + if (ehdr.e_shentsize != sizeof(Elf32_Shdr)) { + die("Bad section header entry\n"); + } + if (ehdr.e_shstrndx >= ehdr.e_shnum) { + die("String table index out of bounds\n"); + } +} + +static void read_shdrs(FILE *fp) +{ + int i; + Elf32_Shdr shdr; + + secs = calloc(ehdr.e_shnum, sizeof(struct section)); + if (!secs) { + die("Unable to allocate %d section headers\n", + ehdr.e_shnum); + } + if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) { + die("Seek to %d failed: %s\n", + ehdr.e_shoff, strerror(errno)); + } + for (i = 0; i < ehdr.e_shnum; i++) { + struct section *sec = &secs[i]; + if (fread(&shdr, sizeof shdr, 1, fp) != 1) + die("Cannot read ELF section headers %d/%d: %s\n", + i, ehdr.e_shnum, strerror(errno)); + sec->shdr.sh_name = elf32_to_cpu(shdr.sh_name); + sec->shdr.sh_type = elf32_to_cpu(shdr.sh_type); + sec->shdr.sh_flags = elf32_to_cpu(shdr.sh_flags); + sec->shdr.sh_addr = elf32_to_cpu(shdr.sh_addr); + sec->shdr.sh_offset = elf32_to_cpu(shdr.sh_offset); + sec->shdr.sh_size = elf32_to_cpu(shdr.sh_size); + sec->shdr.sh_link = elf32_to_cpu(shdr.sh_link); + sec->shdr.sh_info = elf32_to_cpu(shdr.sh_info); + sec->shdr.sh_addralign = elf32_to_cpu(shdr.sh_addralign); + sec->shdr.sh_entsize = elf32_to_cpu(shdr.sh_entsize); + if (sec->shdr.sh_link < ehdr.e_shnum) + sec->link = &secs[sec->shdr.sh_link]; + } + +} + +static void read_strtabs(FILE *fp) +{ + int i; + for (i = 0; i < ehdr.e_shnum; i++) { + struct section *sec = &secs[i]; + if (sec->shdr.sh_type != SHT_STRTAB) { + continue; + } + sec->strtab = malloc(sec->shdr.sh_size); + if (!sec->strtab) { + die("malloc of %d bytes for strtab failed\n", + sec->shdr.sh_size); + } + if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) { + die("Seek to %d failed: %s\n", + sec->shdr.sh_offset, strerror(errno)); + } + if (fread(sec->strtab, 1, sec->shdr.sh_size, fp) + != sec->shdr.sh_size) { + die("Cannot read symbol table: %s\n", + strerror(errno)); + } + } +} + +static void read_symtabs(FILE *fp) +{ + int i,j; + for (i = 0; i < ehdr.e_shnum; i++) { + struct section *sec = &secs[i]; + if (sec->shdr.sh_type != SHT_SYMTAB) { + continue; + } + sec->symtab = malloc(sec->shdr.sh_size); + if (!sec->symtab) { + die("malloc of %d bytes for symtab failed\n", + sec->shdr.sh_size); + } + if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) { + die("Seek to %d failed: %s\n", + sec->shdr.sh_offset, strerror(errno)); + } + if (fread(sec->symtab, 1, sec->shdr.sh_size, fp) + != sec->shdr.sh_size) { + die("Cannot read symbol table: %s\n", + strerror(errno)); + } + for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) { + Elf32_Sym *sym = &sec->symtab[j]; + sym->st_name = elf32_to_cpu(sym->st_name); + sym->st_value = elf32_to_cpu(sym->st_value); + sym->st_size = elf32_to_cpu(sym->st_size); + sym->st_shndx = elf16_to_cpu(sym->st_shndx); + } + } +} + + +static void read_relocs(FILE *fp) +{ + int i,j; + for (i = 0; i < ehdr.e_shnum; i++) { + struct section *sec = &secs[i]; + if (sec->shdr.sh_type != SHT_REL) { + continue; + } + sec->reltab = malloc(sec->shdr.sh_size); + if (!sec->reltab) { + die("malloc of %d bytes for relocs failed\n", + sec->shdr.sh_size); + } + if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) { + die("Seek to %d failed: %s\n", + sec->shdr.sh_offset, strerror(errno)); + } + if (fread(sec->reltab, 1, sec->shdr.sh_size, fp) + != sec->shdr.sh_size) { + die("Cannot read symbol table: %s\n", + strerror(errno)); + } + for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) { + Elf32_Rel *rel = &sec->reltab[j]; + rel->r_offset = elf32_to_cpu(rel->r_offset); + rel->r_info = elf32_to_cpu(rel->r_info); + } + } +} + + +static void print_absolute_symbols(void) +{ + int i; + printf("Absolute symbols\n"); + printf(" Num: Value Size Type Bind Visibility Name\n"); + for (i = 0; i < ehdr.e_shnum; i++) { + struct section *sec = &secs[i]; + char *sym_strtab; + int j; + + if (sec->shdr.sh_type != SHT_SYMTAB) { + continue; + } + sym_strtab = sec->link->strtab; + for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) { + Elf32_Sym *sym; + const char *name; + sym = &sec->symtab[j]; + name = sym_name(sym_strtab, sym); + if (sym->st_shndx != SHN_ABS) { + continue; + } + printf("%5d %08x %5d %10s %10s %12s %s\n", + j, sym->st_value, sym->st_size, + sym_type(ELF32_ST_TYPE(sym->st_info)), + sym_bind(ELF32_ST_BIND(sym->st_info)), + sym_visibility(ELF32_ST_VISIBILITY(sym->st_other)), + name); + } + } + printf("\n"); +} + +static void print_absolute_relocs(void) +{ + int i, printed = 0; + + for (i = 0; i < ehdr.e_shnum; i++) { + struct section *sec = &secs[i]; + struct section *sec_applies, *sec_symtab; + char *sym_strtab; + Elf32_Sym *sh_symtab; + int j; + if (sec->shdr.sh_type != SHT_REL) { + continue; + } + sec_symtab = sec->link; + sec_applies = &secs[sec->shdr.sh_info]; + if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) { + continue; + } + sh_symtab = sec_symtab->symtab; + sym_strtab = sec_symtab->link->strtab; + for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) { + Elf32_Rel *rel; + Elf32_Sym *sym; + const char *name; + rel = &sec->reltab[j]; + sym = &sh_symtab[ELF32_R_SYM(rel->r_info)]; + name = sym_name(sym_strtab, sym); + if (sym->st_shndx != SHN_ABS) { + continue; + } + + /* Absolute symbols are not relocated if bzImage is + * loaded at a non-compiled address. Display a warning + * to user at compile time about the absolute + * relocations present. + * + * User need to audit the code to make sure + * some symbols which should have been section + * relative have not become absolute because of some + * linker optimization or wrong programming usage. + * + * Before warning check if this absolute symbol + * relocation is harmless. + */ + if (is_reloc(S_ABS, name) || is_reloc(S_REL, name)) + continue; + + if (!printed) { + printf("WARNING: Absolute relocations" + " present\n"); + printf("Offset Info Type Sym.Value " + "Sym.Name\n"); + printed = 1; + } + + printf("%08x %08x %10s %08x %s\n", + rel->r_offset, + rel->r_info, + rel_type(ELF32_R_TYPE(rel->r_info)), + sym->st_value, + name); + } + } + + if (printed) + printf("\n"); +} + +static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym), + int use_real_mode) +{ + int i; + /* Walk through the relocations */ + for (i = 0; i < ehdr.e_shnum; i++) { + char *sym_strtab; + Elf32_Sym *sh_symtab; + struct section *sec_applies, *sec_symtab; + int j; + struct section *sec = &secs[i]; + + if (sec->shdr.sh_type != SHT_REL) { + continue; + } + sec_symtab = sec->link; + sec_applies = &secs[sec->shdr.sh_info]; + if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) { + continue; + } + sh_symtab = sec_symtab->symtab; + sym_strtab = sec_symtab->link->strtab; + for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) { + Elf32_Rel *rel; + Elf32_Sym *sym; + unsigned r_type; + const char *symname; + rel = &sec->reltab[j]; + sym = &sh_symtab[ELF32_R_SYM(rel->r_info)]; + r_type = ELF32_R_TYPE(rel->r_info); + + switch (r_type) { + case R_386_NONE: + case R_386_PC32: + case R_386_PC16: + case R_386_PC8: + /* + * NONE can be ignored and and PC relative + * relocations don't need to be adjusted. + */ + break; + + case R_386_16: + symname = sym_name(sym_strtab, sym); + if (!use_real_mode) + goto bad; + if (sym->st_shndx == SHN_ABS) { + if (is_reloc(S_ABS, symname)) + break; + else if (!is_reloc(S_SEG, symname)) + goto bad; + } else { + if (is_reloc(S_LIN, symname)) + goto bad; + else + break; + } + visit(rel, sym); + break; + + case R_386_32: + symname = sym_name(sym_strtab, sym); + if (sym->st_shndx == SHN_ABS) { + if (is_reloc(S_ABS, symname)) + break; + else if (!is_reloc(S_REL, symname)) + goto bad; + } else { + if (use_real_mode && + !is_reloc(S_LIN, symname)) + break; + } + visit(rel, sym); + break; + default: + die("Unsupported relocation type: %s (%d)\n", + rel_type(r_type), r_type); + break; + bad: + symname = sym_name(sym_strtab, sym); + die("Invalid %s relocation: %s\n", + rel_type(r_type), symname); + } + } + } +} + +static void count_reloc(Elf32_Rel *rel, Elf32_Sym *sym) +{ + if (ELF32_R_TYPE(rel->r_info) == R_386_16) + reloc16_count++; + else + reloc_count++; +} + +static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym) +{ + /* Remember the address that needs to be adjusted. */ + if (ELF32_R_TYPE(rel->r_info) == R_386_16) + relocs16[reloc16_idx++] = rel->r_offset; + else + relocs[reloc_idx++] = rel->r_offset; +} + +static int cmp_relocs(const void *va, const void *vb) +{ + const unsigned long *a, *b; + a = va; b = vb; + return (*a == *b)? 0 : (*a > *b)? 1 : -1; +} + +static int write32(unsigned int v, FILE *f) +{ + unsigned char buf[4]; + + put_unaligned_le32(v, buf); + return fwrite(buf, 1, 4, f) == 4 ? 0 : -1; +} + +static void emit_relocs(int as_text, int use_real_mode) +{ + int i; + /* Count how many relocations I have and allocate space for them. */ + reloc_count = 0; + walk_relocs(count_reloc, use_real_mode); + relocs = malloc(reloc_count * sizeof(relocs[0])); + if (!relocs) { + die("malloc of %d entries for relocs failed\n", + reloc_count); + } + + relocs16 = malloc(reloc16_count * sizeof(relocs[0])); + if (!relocs16) { + die("malloc of %d entries for relocs16 failed\n", + reloc16_count); + } + /* Collect up the relocations */ + reloc_idx = 0; + walk_relocs(collect_reloc, use_real_mode); + + if (reloc16_count && !use_real_mode) + die("Segment relocations found but --realmode not specified\n"); + + /* Order the relocations for more efficient processing */ + qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs); + qsort(relocs16, reloc16_count, sizeof(relocs16[0]), cmp_relocs); + + /* Print the relocations */ + if (as_text) { + /* Print the relocations in a form suitable that + * gas will like. + */ + printf(".section \".data.reloc\",\"a\"\n"); + printf(".balign 4\n"); + if (use_real_mode) { + printf("\t.long %lu\n", reloc16_count); + for (i = 0; i < reloc16_count; i++) + printf("\t.long 0x%08lx\n", relocs16[i]); + printf("\t.long %lu\n", reloc_count); + for (i = 0; i < reloc_count; i++) { + printf("\t.long 0x%08lx\n", relocs[i]); + } + } else { + /* Print a stop */ + printf("\t.long 0x%08lx\n", (unsigned long)0); + for (i = 0; i < reloc_count; i++) { + printf("\t.long 0x%08lx\n", relocs[i]); + } + } + + printf("\n"); + } + else { + if (use_real_mode) { + write32(reloc16_count, stdout); + for (i = 0; i < reloc16_count; i++) + write32(relocs16[i], stdout); + write32(reloc_count, stdout); + + /* Now print each relocation */ + for (i = 0; i < reloc_count; i++) + write32(relocs[i], stdout); + } else { + /* Print a stop */ + write32(0, stdout); + + /* Now print each relocation */ + for (i = 0; i < reloc_count; i++) { + write32(relocs[i], stdout); + } + } + } +} + +static void usage(void) +{ + die("relocs [--abs-syms|--abs-relocs|--text|--realmode] vmlinux\n"); +} + +int main(int argc, char **argv) +{ + int show_absolute_syms, show_absolute_relocs; + int as_text, use_real_mode; + const char *fname; + FILE *fp; + int i; + + show_absolute_syms = 0; + show_absolute_relocs = 0; + as_text = 0; + use_real_mode = 0; + fname = NULL; + for (i = 1; i < argc; i++) { + char *arg = argv[i]; + if (*arg == '-') { + if (strcmp(arg, "--abs-syms") == 0) { + show_absolute_syms = 1; + continue; + } + if (strcmp(arg, "--abs-relocs") == 0) { + show_absolute_relocs = 1; + continue; + } + if (strcmp(arg, "--text") == 0) { + as_text = 1; + continue; + } + if (strcmp(arg, "--realmode") == 0) { + use_real_mode = 1; + continue; + } + } + else if (!fname) { + fname = arg; + continue; + } + usage(); + } + if (!fname) { + usage(); + } + regex_init(use_real_mode); + fp = fopen(fname, "r"); + if (!fp) { + die("Cannot open %s: %s\n", + fname, strerror(errno)); + } + read_ehdr(fp); + read_shdrs(fp); + read_strtabs(fp); + read_symtabs(fp); + read_relocs(fp); + if (show_absolute_syms) { + print_absolute_symbols(); + return 0; + } + if (show_absolute_relocs) { + print_absolute_relocs(); + return 0; + } + emit_relocs(as_text, use_real_mode); + return 0; +} diff --git a/scripts/Makefile b/scripts/Makefile index a241359d2c82..36266665dbcb 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -15,7 +15,6 @@ hostprogs-$(CONFIG_LOGO) += pnmtologo hostprogs-$(CONFIG_VT) += conmakehash hostprogs-$(CONFIG_IKCONFIG) += bin2c hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount -hostprogs-$(CONFIG_X86) += x86-relocs always := $(hostprogs-y) $(hostprogs-m) diff --git a/scripts/x86-relocs.c b/scripts/x86-relocs.c deleted file mode 100644 index 74e16bb15dc4..000000000000 --- a/scripts/x86-relocs.c +++ /dev/null @@ -1,804 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#define USE_BSD -#include -#include -#include - -static void die(char *fmt, ...); - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) -static Elf32_Ehdr ehdr; -static unsigned long reloc_count, reloc_idx; -static unsigned long *relocs; -static unsigned long reloc16_count, reloc16_idx; -static unsigned long *relocs16; - -struct section { - Elf32_Shdr shdr; - struct section *link; - Elf32_Sym *symtab; - Elf32_Rel *reltab; - char *strtab; -}; -static struct section *secs; - -enum symtype { - S_ABS, - S_REL, - S_SEG, - S_LIN, - S_NSYMTYPES -}; - -static const char * const sym_regex_kernel[S_NSYMTYPES] = { -/* - * Following symbols have been audited. There values are constant and do - * not change if bzImage is loaded at a different physical address than - * the address for which it has been compiled. Don't warn user about - * absolute relocations present w.r.t these symbols. - */ - [S_ABS] = - "^(xen_irq_disable_direct_reloc$|" - "xen_save_fl_direct_reloc$|" - "VDSO|" - "__crc_)", - -/* - * These symbols are known to be relative, even if the linker marks them - * as absolute (typically defined outside any section in the linker script.) - */ - [S_REL] = - "^_end$", -}; - - -static const char * const sym_regex_realmode[S_NSYMTYPES] = { -/* - * These symbols are known to be relative, even if the linker marks them - * as absolute (typically defined outside any section in the linker script.) - */ - [S_REL] = - "^pa_", - -/* - * These are 16-bit segment symbols when compiling 16-bit code. - */ - [S_SEG] = - "^real_mode_seg$", - -/* - * These are offsets belonging to segments, as opposed to linear addresses, - * when compiling 16-bit code. - */ - [S_LIN] = - "^pa_", -}; - -static const char * const *sym_regex; - -static regex_t sym_regex_c[S_NSYMTYPES]; -static int is_reloc(enum symtype type, const char *sym_name) -{ - return sym_regex[type] && - !regexec(&sym_regex_c[type], sym_name, 0, NULL, 0); -} - -static void regex_init(int use_real_mode) -{ - char errbuf[128]; - int err; - int i; - - if (use_real_mode) - sym_regex = sym_regex_realmode; - else - sym_regex = sym_regex_kernel; - - for (i = 0; i < S_NSYMTYPES; i++) { - if (!sym_regex[i]) - continue; - - err = regcomp(&sym_regex_c[i], sym_regex[i], - REG_EXTENDED|REG_NOSUB); - - if (err) { - regerror(err, &sym_regex_c[i], errbuf, sizeof errbuf); - die("%s", errbuf); - } - } -} - -static void die(char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - exit(1); -} - -static const char *sym_type(unsigned type) -{ - static const char *type_name[] = { -#define SYM_TYPE(X) [X] = #X - SYM_TYPE(STT_NOTYPE), - SYM_TYPE(STT_OBJECT), - SYM_TYPE(STT_FUNC), - SYM_TYPE(STT_SECTION), - SYM_TYPE(STT_FILE), - SYM_TYPE(STT_COMMON), - SYM_TYPE(STT_TLS), -#undef SYM_TYPE - }; - const char *name = "unknown sym type name"; - if (type < ARRAY_SIZE(type_name)) { - name = type_name[type]; - } - return name; -} - -static const char *sym_bind(unsigned bind) -{ - static const char *bind_name[] = { -#define SYM_BIND(X) [X] = #X - SYM_BIND(STB_LOCAL), - SYM_BIND(STB_GLOBAL), - SYM_BIND(STB_WEAK), -#undef SYM_BIND - }; - const char *name = "unknown sym bind name"; - if (bind < ARRAY_SIZE(bind_name)) { - name = bind_name[bind]; - } - return name; -} - -static const char *sym_visibility(unsigned visibility) -{ - static const char *visibility_name[] = { -#define SYM_VISIBILITY(X) [X] = #X - SYM_VISIBILITY(STV_DEFAULT), - SYM_VISIBILITY(STV_INTERNAL), - SYM_VISIBILITY(STV_HIDDEN), - SYM_VISIBILITY(STV_PROTECTED), -#undef SYM_VISIBILITY - }; - const char *name = "unknown sym visibility name"; - if (visibility < ARRAY_SIZE(visibility_name)) { - name = visibility_name[visibility]; - } - return name; -} - -static const char *rel_type(unsigned type) -{ - static const char *type_name[] = { -#define REL_TYPE(X) [X] = #X - REL_TYPE(R_386_NONE), - REL_TYPE(R_386_32), - REL_TYPE(R_386_PC32), - REL_TYPE(R_386_GOT32), - REL_TYPE(R_386_PLT32), - REL_TYPE(R_386_COPY), - REL_TYPE(R_386_GLOB_DAT), - REL_TYPE(R_386_JMP_SLOT), - REL_TYPE(R_386_RELATIVE), - REL_TYPE(R_386_GOTOFF), - REL_TYPE(R_386_GOTPC), - REL_TYPE(R_386_8), - REL_TYPE(R_386_PC8), - REL_TYPE(R_386_16), - REL_TYPE(R_386_PC16), -#undef REL_TYPE - }; - const char *name = "unknown type rel type name"; - if (type < ARRAY_SIZE(type_name) && type_name[type]) { - name = type_name[type]; - } - return name; -} - -static const char *sec_name(unsigned shndx) -{ - const char *sec_strtab; - const char *name; - sec_strtab = secs[ehdr.e_shstrndx].strtab; - name = ""; - if (shndx < ehdr.e_shnum) { - name = sec_strtab + secs[shndx].shdr.sh_name; - } - else if (shndx == SHN_ABS) { - name = "ABSOLUTE"; - } - else if (shndx == SHN_COMMON) { - name = "COMMON"; - } - return name; -} - -static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym) -{ - const char *name; - name = ""; - if (sym->st_name) { - name = sym_strtab + sym->st_name; - } - else { - name = sec_name(sym->st_shndx); - } - return name; -} - - - -#if BYTE_ORDER == LITTLE_ENDIAN -#define le16_to_cpu(val) (val) -#define le32_to_cpu(val) (val) -#endif -#if BYTE_ORDER == BIG_ENDIAN -#define le16_to_cpu(val) bswap_16(val) -#define le32_to_cpu(val) bswap_32(val) -#endif - -static uint16_t elf16_to_cpu(uint16_t val) -{ - return le16_to_cpu(val); -} - -static uint32_t elf32_to_cpu(uint32_t val) -{ - return le32_to_cpu(val); -} - -static void read_ehdr(FILE *fp) -{ - if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) { - die("Cannot read ELF header: %s\n", - strerror(errno)); - } - if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) { - die("No ELF magic\n"); - } - if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) { - die("Not a 32 bit executable\n"); - } - if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) { - die("Not a LSB ELF executable\n"); - } - if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) { - die("Unknown ELF version\n"); - } - /* Convert the fields to native endian */ - ehdr.e_type = elf16_to_cpu(ehdr.e_type); - ehdr.e_machine = elf16_to_cpu(ehdr.e_machine); - ehdr.e_version = elf32_to_cpu(ehdr.e_version); - ehdr.e_entry = elf32_to_cpu(ehdr.e_entry); - ehdr.e_phoff = elf32_to_cpu(ehdr.e_phoff); - ehdr.e_shoff = elf32_to_cpu(ehdr.e_shoff); - ehdr.e_flags = elf32_to_cpu(ehdr.e_flags); - ehdr.e_ehsize = elf16_to_cpu(ehdr.e_ehsize); - ehdr.e_phentsize = elf16_to_cpu(ehdr.e_phentsize); - ehdr.e_phnum = elf16_to_cpu(ehdr.e_phnum); - ehdr.e_shentsize = elf16_to_cpu(ehdr.e_shentsize); - ehdr.e_shnum = elf16_to_cpu(ehdr.e_shnum); - ehdr.e_shstrndx = elf16_to_cpu(ehdr.e_shstrndx); - - if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) { - die("Unsupported ELF header type\n"); - } - if (ehdr.e_machine != EM_386) { - die("Not for x86\n"); - } - if (ehdr.e_version != EV_CURRENT) { - die("Unknown ELF version\n"); - } - if (ehdr.e_ehsize != sizeof(Elf32_Ehdr)) { - die("Bad Elf header size\n"); - } - if (ehdr.e_phentsize != sizeof(Elf32_Phdr)) { - die("Bad program header entry\n"); - } - if (ehdr.e_shentsize != sizeof(Elf32_Shdr)) { - die("Bad section header entry\n"); - } - if (ehdr.e_shstrndx >= ehdr.e_shnum) { - die("String table index out of bounds\n"); - } -} - -static void read_shdrs(FILE *fp) -{ - int i; - Elf32_Shdr shdr; - - secs = calloc(ehdr.e_shnum, sizeof(struct section)); - if (!secs) { - die("Unable to allocate %d section headers\n", - ehdr.e_shnum); - } - if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) { - die("Seek to %d failed: %s\n", - ehdr.e_shoff, strerror(errno)); - } - for (i = 0; i < ehdr.e_shnum; i++) { - struct section *sec = &secs[i]; - if (fread(&shdr, sizeof shdr, 1, fp) != 1) - die("Cannot read ELF section headers %d/%d: %s\n", - i, ehdr.e_shnum, strerror(errno)); - sec->shdr.sh_name = elf32_to_cpu(shdr.sh_name); - sec->shdr.sh_type = elf32_to_cpu(shdr.sh_type); - sec->shdr.sh_flags = elf32_to_cpu(shdr.sh_flags); - sec->shdr.sh_addr = elf32_to_cpu(shdr.sh_addr); - sec->shdr.sh_offset = elf32_to_cpu(shdr.sh_offset); - sec->shdr.sh_size = elf32_to_cpu(shdr.sh_size); - sec->shdr.sh_link = elf32_to_cpu(shdr.sh_link); - sec->shdr.sh_info = elf32_to_cpu(shdr.sh_info); - sec->shdr.sh_addralign = elf32_to_cpu(shdr.sh_addralign); - sec->shdr.sh_entsize = elf32_to_cpu(shdr.sh_entsize); - if (sec->shdr.sh_link < ehdr.e_shnum) - sec->link = &secs[sec->shdr.sh_link]; - } - -} - -static void read_strtabs(FILE *fp) -{ - int i; - for (i = 0; i < ehdr.e_shnum; i++) { - struct section *sec = &secs[i]; - if (sec->shdr.sh_type != SHT_STRTAB) { - continue; - } - sec->strtab = malloc(sec->shdr.sh_size); - if (!sec->strtab) { - die("malloc of %d bytes for strtab failed\n", - sec->shdr.sh_size); - } - if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) { - die("Seek to %d failed: %s\n", - sec->shdr.sh_offset, strerror(errno)); - } - if (fread(sec->strtab, 1, sec->shdr.sh_size, fp) - != sec->shdr.sh_size) { - die("Cannot read symbol table: %s\n", - strerror(errno)); - } - } -} - -static void read_symtabs(FILE *fp) -{ - int i,j; - for (i = 0; i < ehdr.e_shnum; i++) { - struct section *sec = &secs[i]; - if (sec->shdr.sh_type != SHT_SYMTAB) { - continue; - } - sec->symtab = malloc(sec->shdr.sh_size); - if (!sec->symtab) { - die("malloc of %d bytes for symtab failed\n", - sec->shdr.sh_size); - } - if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) { - die("Seek to %d failed: %s\n", - sec->shdr.sh_offset, strerror(errno)); - } - if (fread(sec->symtab, 1, sec->shdr.sh_size, fp) - != sec->shdr.sh_size) { - die("Cannot read symbol table: %s\n", - strerror(errno)); - } - for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) { - Elf32_Sym *sym = &sec->symtab[j]; - sym->st_name = elf32_to_cpu(sym->st_name); - sym->st_value = elf32_to_cpu(sym->st_value); - sym->st_size = elf32_to_cpu(sym->st_size); - sym->st_shndx = elf16_to_cpu(sym->st_shndx); - } - } -} - - -static void read_relocs(FILE *fp) -{ - int i,j; - for (i = 0; i < ehdr.e_shnum; i++) { - struct section *sec = &secs[i]; - if (sec->shdr.sh_type != SHT_REL) { - continue; - } - sec->reltab = malloc(sec->shdr.sh_size); - if (!sec->reltab) { - die("malloc of %d bytes for relocs failed\n", - sec->shdr.sh_size); - } - if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) { - die("Seek to %d failed: %s\n", - sec->shdr.sh_offset, strerror(errno)); - } - if (fread(sec->reltab, 1, sec->shdr.sh_size, fp) - != sec->shdr.sh_size) { - die("Cannot read symbol table: %s\n", - strerror(errno)); - } - for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) { - Elf32_Rel *rel = &sec->reltab[j]; - rel->r_offset = elf32_to_cpu(rel->r_offset); - rel->r_info = elf32_to_cpu(rel->r_info); - } - } -} - - -static void print_absolute_symbols(void) -{ - int i; - printf("Absolute symbols\n"); - printf(" Num: Value Size Type Bind Visibility Name\n"); - for (i = 0; i < ehdr.e_shnum; i++) { - struct section *sec = &secs[i]; - char *sym_strtab; - int j; - - if (sec->shdr.sh_type != SHT_SYMTAB) { - continue; - } - sym_strtab = sec->link->strtab; - for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) { - Elf32_Sym *sym; - const char *name; - sym = &sec->symtab[j]; - name = sym_name(sym_strtab, sym); - if (sym->st_shndx != SHN_ABS) { - continue; - } - printf("%5d %08x %5d %10s %10s %12s %s\n", - j, sym->st_value, sym->st_size, - sym_type(ELF32_ST_TYPE(sym->st_info)), - sym_bind(ELF32_ST_BIND(sym->st_info)), - sym_visibility(ELF32_ST_VISIBILITY(sym->st_other)), - name); - } - } - printf("\n"); -} - -static void print_absolute_relocs(void) -{ - int i, printed = 0; - - for (i = 0; i < ehdr.e_shnum; i++) { - struct section *sec = &secs[i]; - struct section *sec_applies, *sec_symtab; - char *sym_strtab; - Elf32_Sym *sh_symtab; - int j; - if (sec->shdr.sh_type != SHT_REL) { - continue; - } - sec_symtab = sec->link; - sec_applies = &secs[sec->shdr.sh_info]; - if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) { - continue; - } - sh_symtab = sec_symtab->symtab; - sym_strtab = sec_symtab->link->strtab; - for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) { - Elf32_Rel *rel; - Elf32_Sym *sym; - const char *name; - rel = &sec->reltab[j]; - sym = &sh_symtab[ELF32_R_SYM(rel->r_info)]; - name = sym_name(sym_strtab, sym); - if (sym->st_shndx != SHN_ABS) { - continue; - } - - /* Absolute symbols are not relocated if bzImage is - * loaded at a non-compiled address. Display a warning - * to user at compile time about the absolute - * relocations present. - * - * User need to audit the code to make sure - * some symbols which should have been section - * relative have not become absolute because of some - * linker optimization or wrong programming usage. - * - * Before warning check if this absolute symbol - * relocation is harmless. - */ - if (is_reloc(S_ABS, name) || is_reloc(S_REL, name)) - continue; - - if (!printed) { - printf("WARNING: Absolute relocations" - " present\n"); - printf("Offset Info Type Sym.Value " - "Sym.Name\n"); - printed = 1; - } - - printf("%08x %08x %10s %08x %s\n", - rel->r_offset, - rel->r_info, - rel_type(ELF32_R_TYPE(rel->r_info)), - sym->st_value, - name); - } - } - - if (printed) - printf("\n"); -} - -static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym), - int use_real_mode) -{ - int i; - /* Walk through the relocations */ - for (i = 0; i < ehdr.e_shnum; i++) { - char *sym_strtab; - Elf32_Sym *sh_symtab; - struct section *sec_applies, *sec_symtab; - int j; - struct section *sec = &secs[i]; - - if (sec->shdr.sh_type != SHT_REL) { - continue; - } - sec_symtab = sec->link; - sec_applies = &secs[sec->shdr.sh_info]; - if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) { - continue; - } - sh_symtab = sec_symtab->symtab; - sym_strtab = sec_symtab->link->strtab; - for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) { - Elf32_Rel *rel; - Elf32_Sym *sym; - unsigned r_type; - const char *symname; - rel = &sec->reltab[j]; - sym = &sh_symtab[ELF32_R_SYM(rel->r_info)]; - r_type = ELF32_R_TYPE(rel->r_info); - - switch (r_type) { - case R_386_NONE: - case R_386_PC32: - case R_386_PC16: - case R_386_PC8: - /* - * NONE can be ignored and and PC relative - * relocations don't need to be adjusted. - */ - break; - - case R_386_16: - symname = sym_name(sym_strtab, sym); - if (!use_real_mode) - goto bad; - if (sym->st_shndx == SHN_ABS) { - if (is_reloc(S_ABS, symname)) - break; - else if (!is_reloc(S_SEG, symname)) - goto bad; - } else { - if (is_reloc(S_LIN, symname)) - goto bad; - else - break; - } - visit(rel, sym); - break; - - case R_386_32: - symname = sym_name(sym_strtab, sym); - if (sym->st_shndx == SHN_ABS) { - if (is_reloc(S_ABS, symname)) - break; - else if (!is_reloc(S_REL, symname)) - goto bad; - } else { - if (use_real_mode && - !is_reloc(S_LIN, symname)) - break; - } - visit(rel, sym); - break; - default: - die("Unsupported relocation type: %s (%d)\n", - rel_type(r_type), r_type); - break; - bad: - symname = sym_name(sym_strtab, sym); - die("Invalid %s relocation: %s\n", - rel_type(r_type), symname); - } - } - } -} - -static void count_reloc(Elf32_Rel *rel, Elf32_Sym *sym) -{ - if (ELF32_R_TYPE(rel->r_info) == R_386_16) - reloc16_count++; - else - reloc_count++; -} - -static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym) -{ - /* Remember the address that needs to be adjusted. */ - if (ELF32_R_TYPE(rel->r_info) == R_386_16) - relocs16[reloc16_idx++] = rel->r_offset; - else - relocs[reloc_idx++] = rel->r_offset; -} - -static int cmp_relocs(const void *va, const void *vb) -{ - const unsigned long *a, *b; - a = va; b = vb; - return (*a == *b)? 0 : (*a > *b)? 1 : -1; -} - -static int write32(unsigned int v, FILE *f) -{ - unsigned char buf[4]; - - put_unaligned_le32(v, buf); - return fwrite(buf, 1, 4, f) == 4 ? 0 : -1; -} - -static void emit_relocs(int as_text, int use_real_mode) -{ - int i; - /* Count how many relocations I have and allocate space for them. */ - reloc_count = 0; - walk_relocs(count_reloc, use_real_mode); - relocs = malloc(reloc_count * sizeof(relocs[0])); - if (!relocs) { - die("malloc of %d entries for relocs failed\n", - reloc_count); - } - - relocs16 = malloc(reloc16_count * sizeof(relocs[0])); - if (!relocs16) { - die("malloc of %d entries for relocs16 failed\n", - reloc16_count); - } - /* Collect up the relocations */ - reloc_idx = 0; - walk_relocs(collect_reloc, use_real_mode); - - if (reloc16_count && !use_real_mode) - die("Segment relocations found but --realmode not specified\n"); - - /* Order the relocations for more efficient processing */ - qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs); - qsort(relocs16, reloc16_count, sizeof(relocs16[0]), cmp_relocs); - - /* Print the relocations */ - if (as_text) { - /* Print the relocations in a form suitable that - * gas will like. - */ - printf(".section \".data.reloc\",\"a\"\n"); - printf(".balign 4\n"); - if (use_real_mode) { - printf("\t.long %lu\n", reloc16_count); - for (i = 0; i < reloc16_count; i++) - printf("\t.long 0x%08lx\n", relocs16[i]); - printf("\t.long %lu\n", reloc_count); - for (i = 0; i < reloc_count; i++) { - printf("\t.long 0x%08lx\n", relocs[i]); - } - } else { - /* Print a stop */ - printf("\t.long 0x%08lx\n", (unsigned long)0); - for (i = 0; i < reloc_count; i++) { - printf("\t.long 0x%08lx\n", relocs[i]); - } - } - - printf("\n"); - } - else { - if (use_real_mode) { - write32(reloc16_count, stdout); - for (i = 0; i < reloc16_count; i++) - write32(relocs16[i], stdout); - write32(reloc_count, stdout); - - /* Now print each relocation */ - for (i = 0; i < reloc_count; i++) - write32(relocs[i], stdout); - } else { - /* Print a stop */ - write32(0, stdout); - - /* Now print each relocation */ - for (i = 0; i < reloc_count; i++) { - write32(relocs[i], stdout); - } - } - } -} - -static void usage(void) -{ - die("relocs [--abs-syms|--abs-relocs|--text|--realmode] vmlinux\n"); -} - -int main(int argc, char **argv) -{ - int show_absolute_syms, show_absolute_relocs; - int as_text, use_real_mode; - const char *fname; - FILE *fp; - int i; - - show_absolute_syms = 0; - show_absolute_relocs = 0; - as_text = 0; - use_real_mode = 0; - fname = NULL; - for (i = 1; i < argc; i++) { - char *arg = argv[i]; - if (*arg == '-') { - if (strcmp(arg, "--abs-syms") == 0) { - show_absolute_syms = 1; - continue; - } - if (strcmp(arg, "--abs-relocs") == 0) { - show_absolute_relocs = 1; - continue; - } - if (strcmp(arg, "--text") == 0) { - as_text = 1; - continue; - } - if (strcmp(arg, "--realmode") == 0) { - use_real_mode = 1; - continue; - } - } - else if (!fname) { - fname = arg; - continue; - } - usage(); - } - if (!fname) { - usage(); - } - regex_init(use_real_mode); - fp = fopen(fname, "r"); - if (!fp) { - die("Cannot open %s: %s\n", - fname, strerror(errno)); - } - read_ehdr(fp); - read_shdrs(fp); - read_strtabs(fp); - read_symtabs(fp); - read_relocs(fp); - if (show_absolute_syms) { - print_absolute_symbols(); - return 0; - } - if (show_absolute_relocs) { - print_absolute_relocs(); - return 0; - } - emit_relocs(as_text, use_real_mode); - return 0; -} -- cgit v1.2.3 From cda846f101fb1396b6924f1d9b68ac3d42de5403 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Tue, 8 May 2012 21:22:46 +0300 Subject: x86, realmode: read cr4 and EFER from kernel for 64-bit trampoline This patch changes 64-bit trampoline so that CR4 and EFER are provided by the kernel instead of using fixed values. Signed-off-by: Jarkko Sakkinen Link: http://lkml.kernel.org/r/1336501366-28617-24-git-send-email-jarkko.sakkinen@intel.com Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/processor.h | 7 ++++++- arch/x86/include/asm/realmode.h | 8 ++++++-- arch/x86/kernel/realmode.c | 8 ++++++++ arch/x86/kernel/setup.c | 2 ++ arch/x86/realmode/rm/header.S | 1 + arch/x86/realmode/rm/trampoline_64.S | 32 +++++++------------------------- arch/x86/realmode/rm/trampoline_common.S | 19 +++++++++++++++++++ 7 files changed, 49 insertions(+), 28 deletions(-) (limited to 'arch/x86/realmode') diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 4fa7dcceb6c0..404583ccf0cf 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -544,13 +544,16 @@ static inline void load_sp0(struct tss_struct *tss, * enable), so that any CPU's that boot up * after us can get the correct flags. */ -extern unsigned long mmu_cr4_features; +extern unsigned long mmu_cr4_features; +extern u32 *trampoline_cr4_features; static inline void set_in_cr4(unsigned long mask) { unsigned long cr4; mmu_cr4_features |= mask; + if (trampoline_cr4_features) + *trampoline_cr4_features = mmu_cr4_features; cr4 = read_cr4(); cr4 |= mask; write_cr4(cr4); @@ -561,6 +564,8 @@ static inline void clear_in_cr4(unsigned long mask) unsigned long cr4; mmu_cr4_features &= ~mask; + if (trampoline_cr4_features) + *trampoline_cr4_features = mmu_cr4_features; cr4 = read_cr4(); cr4 &= ~mask; write_cr4(cr4); diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h index 1421eed1c8e8..937dc6071d76 100644 --- a/arch/x86/include/asm/realmode.h +++ b/arch/x86/include/asm/realmode.h @@ -24,18 +24,22 @@ struct real_mode_header { #ifdef CONFIG_X86_32 u32 machine_real_restart_asm; #endif -} __attribute__((__packed__)); +}; /* This must match data at trampoline_32/64.S */ struct trampoline_header { #ifdef CONFIG_X86_32 u32 start; + u16 gdt_pad; u16 gdt_limit; u32 gdt_base; #else u64 start; + u32 cr4; + u32 efer_low; + u32 efer_high; #endif -} __attribute__((__packed__)); +}; extern struct real_mode_header *real_mode_header; extern unsigned char real_mode_blob_end[]; diff --git a/arch/x86/kernel/realmode.c b/arch/x86/kernel/realmode.c index 712fba8fd774..66ac276cf361 100644 --- a/arch/x86/kernel/realmode.c +++ b/arch/x86/kernel/realmode.c @@ -6,6 +6,7 @@ #include struct real_mode_header *real_mode_header; +u32 *trampoline_cr4_features; void __init setup_real_mode(void) { @@ -64,7 +65,14 @@ void __init setup_real_mode(void) trampoline_header->gdt_limit = __BOOT_DS + 7; trampoline_header->gdt_base = __pa(boot_gdt); #else + if (rdmsr_safe(MSR_EFER, &trampoline_header->efer_low, + &trampoline_header->efer_high)) + BUG(); + trampoline_header->start = (u64) secondary_startup_64; + trampoline_cr4_features = &trampoline_header->cr4; + *trampoline_cr4_features = read_cr4(); + trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd); trampoline_pgd[0] = __pa(level3_ident_pgt) + _KERNPG_TABLE; trampoline_pgd[511] = __pa(level3_kernel_pgt) + _KERNPG_TABLE; diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 7a14fece9cfc..efcf305210a4 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -975,6 +975,8 @@ void __init setup_arch(char **cmdline_p) if (boot_cpu_data.cpuid_level >= 0) { /* A CPU has %cr4 if and only if it has CPUID */ mmu_cr4_features = read_cr4(); + if (trampoline_cr4_features) + *trampoline_cr4_features = mmu_cr4_features; } #ifdef CONFIG_X86_32 diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S index b4c32632bf16..4612d5382791 100644 --- a/arch/x86/realmode/rm/header.S +++ b/arch/x86/realmode/rm/header.S @@ -9,6 +9,7 @@ .section ".header", "a" + .balign 16 GLOBAL(real_mode_header) .long pa_text_start .long pa_ro_end diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S index 3f7293239365..66e26f088288 100644 --- a/arch/x86/realmode/rm/trampoline_64.S +++ b/arch/x86/realmode/rm/trampoline_64.S @@ -34,9 +34,9 @@ #include "realmode.h" .text - .balign PAGE_SIZE .code16 + .balign PAGE_SIZE ENTRY(trampoline_start) cli # We should be safe anyway wbinvd @@ -65,8 +65,8 @@ ENTRY(trampoline_start) * to 32 bit. */ - lidtl tidt # load idt with 0, 0 - lgdtl tgdt # load gdt with whatever is appropriate + lidtl tr_idt # load idt with 0, 0 + lgdtl tr_gdt # load gdt with whatever is appropriate movw $__KERNEL_DS, %dx # Data segment descriptor @@ -93,16 +93,17 @@ ENTRY(startup_32) movl %edx, %fs movl %edx, %gs - movl $X86_CR4_PAE, %eax + movl pa_tr_cr4, %eax movl %eax, %cr4 # Enable PAE mode # Setup trampoline 4 level pagetables movl $pa_trampoline_pgd, %eax movl %eax, %cr3 + # Set up EFER + movl pa_tr_efer, %eax + movl pa_tr_efer + 4, %edx movl $MSR_EFER, %ecx - movl $((1 << _EFER_LME) | (1 << _EFER_NX)), %eax # Enable Long Mode - xorl %edx, %edx wrmsr # Enable paging and in turn activate Long Mode @@ -124,23 +125,4 @@ ENTRY(startup_64) # Now jump into the kernel using virtual addresses jmpq *tr_start(%rip) - .section ".rodata","a" - .balign 16 -tidt: - .word 0 # idt limit = 0 - .word 0, 0 # idt base = 0L - - # Duplicate the global descriptor table - # so the kernel can live anywhere - .balign 16 - .globl tgdt -tgdt: - .short tgdt_end - tgdt - 1 # gdt limit - .long pa_tgdt - .short 0 - .quad 0x00cf9b000000ffff # __KERNEL32_CS - .quad 0x00af9b000000ffff # __KERNEL_CS - .quad 0x00cf93000000ffff # __KERNEL_DS -tgdt_end: - #include "trampoline_common.S" diff --git a/arch/x86/realmode/rm/trampoline_common.S b/arch/x86/realmode/rm/trampoline_common.S index c3f951c468c5..cac444b942f8 100644 --- a/arch/x86/realmode/rm/trampoline_common.S +++ b/arch/x86/realmode/rm/trampoline_common.S @@ -1,5 +1,20 @@ .section ".rodata","a" +#ifdef CONFIG_X86_64 + # Duplicate the global descriptor table + # so the kernel can live anywhere + .balign 16 + .globl tr_gdt +tr_gdt: + .short tr_gdt_end - tr_gdt - 1 # gdt limit + .long pa_tr_gdt + .short 0 + .quad 0x00cf9b000000ffff # __KERNEL32_CS + .quad 0x00af9b000000ffff # __KERNEL_CS + .quad 0x00cf93000000ffff # __KERNEL_DS +tr_gdt_end: +#endif + .balign 4 tr_idt: .fill 1, 6, 0 @@ -8,12 +23,16 @@ tr_idt: .fill 1, 6, 0 .balign 4 GLOBAL(trampoline_status) .space 4 + .balign 8 GLOBAL(trampoline_header) #ifdef CONFIG_X86_32 tr_start: .space 4 + tr_gdt_pad: .space 2 tr_gdt: .space 6 #else tr_start: .space 8 + GLOBAL(tr_cr4) .space 4 + GLOBAL(tr_efer) .space 8 #endif END(trampoline_header) -- cgit v1.2.3 From c5403aed044e23f8d1ecdf05d0ff120314186527 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Wed, 9 May 2012 23:25:06 +0300 Subject: x86, realmode: build fix: remove duplicate build Real-mode binary was built twice. This patch fixes the issue by making realmode.relocs as target for realmode.bin. [ hpa: removed the direct dependency on realmode.relocs in arch/x86/realmode/Makefile ] Signed-off-by: Jarkko Sakkinen Link: http://lkml.kernel.org/r/1336595106-21135-1-git-send-email-jarkko.sakkinen@intel.com Cc: Sam Ravnborg Cc: Michal Marek Signed-off-by: H. Peter Anvin --- arch/x86/realmode/Makefile | 5 +---- arch/x86/realmode/rm/Makefile | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'arch/x86/realmode') diff --git a/arch/x86/realmode/Makefile b/arch/x86/realmode/Makefile index f22a4f8d99d6..a05b3aca64ad 100644 --- a/arch/x86/realmode/Makefile +++ b/arch/x86/realmode/Makefile @@ -11,10 +11,7 @@ subdir- := rm obj-y += rmpiggy.o -$(obj)/rmpiggy.o: $(obj)/rm/realmode.relocs $(obj)/rm/realmode.bin +$(obj)/rmpiggy.o: $(obj)/rm/realmode.bin $(obj)/rm/realmode.bin: FORCE $(Q)$(MAKE) $(build)=$(obj)/rm $@ - -$(obj)/rm/realmode.relocs: FORCE - $(Q)$(MAKE) $(build)=$(obj)/rm $@ diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile index de40bc44b92f..1c1d3d3bbee4 100644 --- a/arch/x86/realmode/rm/Makefile +++ b/arch/x86/realmode/rm/Makefile @@ -48,7 +48,7 @@ $(obj)/realmode.elf: $(obj)/realmode.lds $(REALMODE_OBJS) FORCE OBJCOPYFLAGS_realmode.bin := -O binary -$(obj)/realmode.bin: $(obj)/realmode.elf +$(obj)/realmode.bin: $(obj)/realmode.elf $(obj)/realmode.relocs $(call if_changed,objcopy) quiet_cmd_relocs = RELOCS $@ -- cgit v1.2.3 From 0f6f11eb00830fa691c16084048f53d83c5c3a5d Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 9 May 2012 14:53:01 -0700 Subject: x86, realmode: Make sure all generated files are listed in targets Kbuild expects all generated files to be listed in the targets variable. If it isn't, weird things happen. Cc: Sam Ravnborg Cc: Michal Marek Signed-off-by: H. Peter Anvin Link: http://lkml.kernel.org/r/1336595106-21135-1-git-send-email-jarkko.sakkinen@intel.com --- arch/x86/realmode/rm/Makefile | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'arch/x86/realmode') diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile index 1c1d3d3bbee4..5b84a2d30888 100644 --- a/arch/x86/realmode/rm/Makefile +++ b/arch/x86/realmode/rm/Makefile @@ -7,13 +7,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-objs) +always := realmode.bin realmode.relocs wakeup-objs := wakeup_asm.o wakemain.o video-mode.o wakeup-objs += copy.o bioscall.o regs.o @@ -25,6 +19,12 @@ wakeup-objs += video-vga.o wakeup-objs += video-vesa.o wakeup-objs += video-bios.o +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-objs) + targets += $(realmode-y) REALMODE_OBJS = $(addprefix $(obj)/,$(realmode-y)) @@ -35,24 +35,30 @@ quiet_cmd_pasyms = PASYMS $@ cmd_pasyms = $(NM) $(filter-out FORCE,$^) | \ sed $(sed-pasyms) | sort | uniq > $@ +targets += pasyms.h $(obj)/pasyms.h: $(REALMODE_OBJS) FORCE $(call if_changed,pasyms) +targets += realmode.lds $(obj)/realmode.lds: $(obj)/pasyms.h LDFLAGS_realmode.elf := --emit-relocs -T CPPFLAGS_realmode.lds += -P -C -I$(obj) +targets += realmode.elf $(obj)/realmode.elf: $(obj)/realmode.lds $(REALMODE_OBJS) FORCE $(call if_changed,ld) OBJCOPYFLAGS_realmode.bin := -O binary +targets += realmode.bin $(obj)/realmode.bin: $(obj)/realmode.elf $(obj)/realmode.relocs $(call if_changed,objcopy) quiet_cmd_relocs = RELOCS $@ cmd_relocs = arch/x86/tools/relocs --realmode $< > $@ + +targets += realmode.relocs $(obj)/realmode.relocs: $(obj)/realmode.elf FORCE $(call if_changed,relocs) -- cgit v1.2.3 From 34d0b02e08470c56a411ba6da1f377bc6da02826 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Thu, 10 May 2012 10:11:38 +0300 Subject: x86, realmode: Fix no cache bits test in reboot_32.S Before the new real-mode code infrastructure %edx was used for testing CD and NW bits with andl in order to decide whether to flush the processor caches or not. The value of cr0 was also stored in %eax, which was later used to set cr0 after masking out lower byte (except TS bit) in order to enter real-mode. In the new real-mode code infrastructure we wanted to keep input parameter in %eax so we are using %edx for both cr0 cases. This has caused regression since andl overwrites the value of %edx. This patch fixes the issue by replacing andl with testl, which is essentially andl without writing result to the register. Special thanks to Paolo Bonzini for noting this and proposing a fix. Reported-and-tested-by: Paolo Bonzini Signed-off-by: Jarkko Sakkinen Link: http://lkml.kernel.org/r/1336633898-23743-1-git-send-email-jarkko.sakkinen@intel.com Signed-off-by: H. Peter Anvin --- arch/x86/realmode/rm/reboot_32.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/x86/realmode') diff --git a/arch/x86/realmode/rm/reboot_32.S b/arch/x86/realmode/rm/reboot_32.S index 8d9bfd13a93e..114044876b3d 100644 --- a/arch/x86/realmode/rm/reboot_32.S +++ b/arch/x86/realmode/rm/reboot_32.S @@ -76,7 +76,7 @@ machine_real_restart_asm16: movl %edx, %cr0 movl %ecx, %cr3 movl %cr0, %edx - andl $0x60000000, %edx /* If no cache bits -> no wbinvd */ + testl $0x60000000, %edx /* If no cache bits -> no wbinvd */ jz 2f wbinvd 2: -- cgit v1.2.3 From 51edbe6a2f47c78c6c6e529999ee0a044fe59a89 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 16 May 2012 13:44:10 -0700 Subject: x86, realmode: Move not-common bits out of trampoline_common.S Move the bits that aren't actually common out of trampoline_common.S and into the arch-specific files. Furthermore, make sure the page directory is first in the .bss section for trampoline_64.S in order to not waste an entire page of memory. Signed-off-by: H. Peter Anvin Cc: Jarkko Sakkinen --- arch/x86/realmode/rm/trampoline_32.S | 8 ++++++++ arch/x86/realmode/rm/trampoline_64.S | 25 +++++++++++++++++++++++ arch/x86/realmode/rm/trampoline_common.S | 35 -------------------------------- 3 files changed, 33 insertions(+), 35 deletions(-) (limited to 'arch/x86/realmode') diff --git a/arch/x86/realmode/rm/trampoline_32.S b/arch/x86/realmode/rm/trampoline_32.S index 6fc064b4d2b9..c1b2791183e7 100644 --- a/arch/x86/realmode/rm/trampoline_32.S +++ b/arch/x86/realmode/rm/trampoline_32.S @@ -63,4 +63,12 @@ ENTRY(trampoline_start) ENTRY(startup_32) # note: also used from wakeup_asm.S jmp *%eax + .bss + .balign 8 +GLOBAL(trampoline_header) + tr_start: .space 4 + tr_gdt_pad: .space 2 + tr_gdt: .space 6 +END(trampoline_header) + #include "trampoline_common.S" diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S index 66e26f088288..1b9e1bc1ac5e 100644 --- a/arch/x86/realmode/rm/trampoline_64.S +++ b/arch/x86/realmode/rm/trampoline_64.S @@ -125,4 +125,29 @@ ENTRY(startup_64) # Now jump into the kernel using virtual addresses jmpq *tr_start(%rip) + .section ".rodata","a" + # Duplicate the global descriptor table + # so the kernel can live anywhere + .balign 16 + .globl tr_gdt +tr_gdt: + .short tr_gdt_end - tr_gdt - 1 # gdt limit + .long pa_tr_gdt + .short 0 + .quad 0x00cf9b000000ffff # __KERNEL32_CS + .quad 0x00af9b000000ffff # __KERNEL_CS + .quad 0x00cf93000000ffff # __KERNEL_DS +tr_gdt_end: + + .bss + .balign PAGE_SIZE +GLOBAL(trampoline_pgd) .space PAGE_SIZE + + .balign 8 +GLOBAL(trampoline_header) + tr_start: .space 8 + GLOBAL(tr_cr4) .space 4 + GLOBAL(tr_efer) .space 8 +END(trampoline_header) + #include "trampoline_common.S" diff --git a/arch/x86/realmode/rm/trampoline_common.S b/arch/x86/realmode/rm/trampoline_common.S index cac444b942f8..b1ecdb9692ad 100644 --- a/arch/x86/realmode/rm/trampoline_common.S +++ b/arch/x86/realmode/rm/trampoline_common.S @@ -1,42 +1,7 @@ .section ".rodata","a" - -#ifdef CONFIG_X86_64 - # Duplicate the global descriptor table - # so the kernel can live anywhere .balign 16 - .globl tr_gdt -tr_gdt: - .short tr_gdt_end - tr_gdt - 1 # gdt limit - .long pa_tr_gdt - .short 0 - .quad 0x00cf9b000000ffff # __KERNEL32_CS - .quad 0x00af9b000000ffff # __KERNEL_CS - .quad 0x00cf93000000ffff # __KERNEL_DS -tr_gdt_end: -#endif - - .balign 4 tr_idt: .fill 1, 6, 0 .bss - .balign 4 GLOBAL(trampoline_status) .space 4 - - .balign 8 -GLOBAL(trampoline_header) -#ifdef CONFIG_X86_32 - tr_start: .space 4 - tr_gdt_pad: .space 2 - tr_gdt: .space 6 -#else - tr_start: .space 8 - GLOBAL(tr_cr4) .space 4 - GLOBAL(tr_efer) .space 8 -#endif -END(trampoline_header) - -#ifdef CONFIG_X86_64 - .balign PAGE_SIZE -GLOBAL(trampoline_pgd) .space PAGE_SIZE -#endif -- cgit v1.2.3 From 137127018812ec7fcccb9843156cfc0b5cfa31d5 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 16 May 2012 13:49:10 -0700 Subject: x86, realmode: Move kernel/realmode.c to realmode/init.c Keep all the realmode code together, including initialization (only the rm/ subdirectory is actually built as real-mode code, anyway.) Signed-off-by: H. Peter Anvin Cc: Jarkko Sakkinen --- arch/x86/kernel/Makefile | 1 - arch/x86/kernel/realmode.c | 116 --------------------------------------------- arch/x86/realmode/Makefile | 1 + arch/x86/realmode/init.c | 116 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 117 insertions(+), 117 deletions(-) delete mode 100644 arch/x86/kernel/realmode.c create mode 100644 arch/x86/realmode/init.c (limited to 'arch/x86/realmode') diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 4a20f4441ffe..08484332f329 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -35,7 +35,6 @@ obj-y += tsc.o io_delay.o rtc.o obj-y += pci-iommu_table.o obj-y += resource.o -obj-y += realmode.o obj-y += process.o obj-y += i387.o xsave.o obj-y += ptrace.o diff --git a/arch/x86/kernel/realmode.c b/arch/x86/kernel/realmode.c deleted file mode 100644 index 099277984b80..000000000000 --- a/arch/x86/kernel/realmode.c +++ /dev/null @@ -1,116 +0,0 @@ -#include -#include - -#include -#include -#include - -struct real_mode_header *real_mode_header; -u32 *trampoline_cr4_features; - -void __init setup_real_mode(void) -{ - phys_addr_t mem; - u16 real_mode_seg; - u32 *rel; - u32 count; - u32 *ptr; - u16 *seg; - int i; - unsigned char *base; - struct trampoline_header *trampoline_header; - size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob); -#ifdef CONFIG_X86_64 - u64 *trampoline_pgd; - u32 efer_low, efer_high; -#endif - - /* Has to be in very low memory so we can execute real-mode AP code. */ - mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE); - if (!mem) - panic("Cannot allocate trampoline\n"); - - base = __va(mem); - memblock_reserve(mem, size); - real_mode_header = (struct real_mode_header *) base; - printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n", - base, (unsigned long long)mem, size); - - memcpy(base, real_mode_blob, size); - - real_mode_seg = __pa(base) >> 4; - rel = (u32 *) real_mode_relocs; - - /* 16-bit segment relocations. */ - count = rel[0]; - rel = &rel[1]; - for (i = 0; i < count; i++) { - seg = (u16 *) (base + rel[i]); - *seg = real_mode_seg; - } - - /* 32-bit linear relocations. */ - count = rel[i]; - rel = &rel[i + 1]; - for (i = 0; i < count; i++) { - ptr = (u32 *) (base + rel[i]); - *ptr += __pa(base); - } - - /* Must be perfomed *after* relocation. */ - trampoline_header = (struct trampoline_header *) - __va(real_mode_header->trampoline_header); - -#ifdef CONFIG_X86_32 - trampoline_header->start = __pa(startup_32_smp); - trampoline_header->gdt_limit = __BOOT_DS + 7; - trampoline_header->gdt_base = __pa(boot_gdt); -#else - /* - * Some AMD processors will #GP(0) if EFER.LMA is set in WRMSR - * so we need to mask it out. - */ - rdmsr(MSR_EFER, efer_low, efer_high); - trampoline_header->efer_low = efer_low & ~EFER_LMA; - trampoline_header->efer_high = efer_high; - - trampoline_header->start = (u64) secondary_startup_64; - trampoline_cr4_features = &trampoline_header->cr4; - *trampoline_cr4_features = read_cr4(); - - trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd); - trampoline_pgd[0] = __pa(level3_ident_pgt) + _KERNPG_TABLE; - trampoline_pgd[511] = __pa(level3_kernel_pgt) + _KERNPG_TABLE; -#endif -} - -/* - * set_real_mode_permissions() gets called very early, to guarantee the - * availability of low memory. This is before the proper kernel page - * tables are set up, so we cannot set page permissions in that - * function. Thus, we use an arch_initcall instead. - */ -static int __init set_real_mode_permissions(void) -{ - unsigned char *base = (unsigned char *) real_mode_header; - size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob); - - size_t ro_size = - PAGE_ALIGN(real_mode_header->ro_end) - - __pa(base); - - size_t text_size = - PAGE_ALIGN(real_mode_header->ro_end) - - real_mode_header->text_start; - - unsigned long text_start = - (unsigned long) __va(real_mode_header->text_start); - - set_memory_nx((unsigned long) base, size >> PAGE_SHIFT); - set_memory_ro((unsigned long) base, ro_size >> PAGE_SHIFT); - set_memory_x((unsigned long) text_start, text_size >> PAGE_SHIFT); - - return 0; -} - -arch_initcall(set_real_mode_permissions); diff --git a/arch/x86/realmode/Makefile b/arch/x86/realmode/Makefile index a05b3aca64ad..94f7fbe97b08 100644 --- a/arch/x86/realmode/Makefile +++ b/arch/x86/realmode/Makefile @@ -9,6 +9,7 @@ subdir- := rm +obj-y += init.o obj-y += rmpiggy.o $(obj)/rmpiggy.o: $(obj)/rm/realmode.bin diff --git a/arch/x86/realmode/init.c b/arch/x86/realmode/init.c new file mode 100644 index 000000000000..099277984b80 --- /dev/null +++ b/arch/x86/realmode/init.c @@ -0,0 +1,116 @@ +#include +#include + +#include +#include +#include + +struct real_mode_header *real_mode_header; +u32 *trampoline_cr4_features; + +void __init setup_real_mode(void) +{ + phys_addr_t mem; + u16 real_mode_seg; + u32 *rel; + u32 count; + u32 *ptr; + u16 *seg; + int i; + unsigned char *base; + struct trampoline_header *trampoline_header; + size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob); +#ifdef CONFIG_X86_64 + u64 *trampoline_pgd; + u32 efer_low, efer_high; +#endif + + /* Has to be in very low memory so we can execute real-mode AP code. */ + mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE); + if (!mem) + panic("Cannot allocate trampoline\n"); + + base = __va(mem); + memblock_reserve(mem, size); + real_mode_header = (struct real_mode_header *) base; + printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n", + base, (unsigned long long)mem, size); + + memcpy(base, real_mode_blob, size); + + real_mode_seg = __pa(base) >> 4; + rel = (u32 *) real_mode_relocs; + + /* 16-bit segment relocations. */ + count = rel[0]; + rel = &rel[1]; + for (i = 0; i < count; i++) { + seg = (u16 *) (base + rel[i]); + *seg = real_mode_seg; + } + + /* 32-bit linear relocations. */ + count = rel[i]; + rel = &rel[i + 1]; + for (i = 0; i < count; i++) { + ptr = (u32 *) (base + rel[i]); + *ptr += __pa(base); + } + + /* Must be perfomed *after* relocation. */ + trampoline_header = (struct trampoline_header *) + __va(real_mode_header->trampoline_header); + +#ifdef CONFIG_X86_32 + trampoline_header->start = __pa(startup_32_smp); + trampoline_header->gdt_limit = __BOOT_DS + 7; + trampoline_header->gdt_base = __pa(boot_gdt); +#else + /* + * Some AMD processors will #GP(0) if EFER.LMA is set in WRMSR + * so we need to mask it out. + */ + rdmsr(MSR_EFER, efer_low, efer_high); + trampoline_header->efer_low = efer_low & ~EFER_LMA; + trampoline_header->efer_high = efer_high; + + trampoline_header->start = (u64) secondary_startup_64; + trampoline_cr4_features = &trampoline_header->cr4; + *trampoline_cr4_features = read_cr4(); + + trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd); + trampoline_pgd[0] = __pa(level3_ident_pgt) + _KERNPG_TABLE; + trampoline_pgd[511] = __pa(level3_kernel_pgt) + _KERNPG_TABLE; +#endif +} + +/* + * set_real_mode_permissions() gets called very early, to guarantee the + * availability of low memory. This is before the proper kernel page + * tables are set up, so we cannot set page permissions in that + * function. Thus, we use an arch_initcall instead. + */ +static int __init set_real_mode_permissions(void) +{ + unsigned char *base = (unsigned char *) real_mode_header; + size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob); + + size_t ro_size = + PAGE_ALIGN(real_mode_header->ro_end) - + __pa(base); + + size_t text_size = + PAGE_ALIGN(real_mode_header->ro_end) - + real_mode_header->text_start; + + unsigned long text_start = + (unsigned long) __va(real_mode_header->text_start); + + set_memory_nx((unsigned long) base, size >> PAGE_SHIFT); + set_memory_ro((unsigned long) base, ro_size >> PAGE_SHIFT); + set_memory_x((unsigned long) text_start, text_size >> PAGE_SHIFT); + + return 0; +} + +arch_initcall(set_real_mode_permissions); -- cgit v1.2.3 From 638d957b51c88852de72f15f7cd588d125e97dab Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 16 May 2012 14:02:05 -0700 Subject: x86, realmode: Change EFER to a single u64 field Change EFER to be a single u64 field instead of two u32 fields; change the order to maintain alignment. Note that on x86-64 cr4 is really also a 64-bit quantity, although we can only set the low 32 bits from the trampoline code since it is still executing in 32-bit mode at that point. Signed-off-by: H. Peter Anvin Cc: Jarkko Sakkinen --- arch/x86/include/asm/realmode.h | 3 +-- arch/x86/realmode/init.c | 7 +++---- arch/x86/realmode/rm/trampoline_64.S | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) (limited to 'arch/x86/realmode') diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h index 937dc6071d76..fce3f4ae5bd6 100644 --- a/arch/x86/include/asm/realmode.h +++ b/arch/x86/include/asm/realmode.h @@ -35,9 +35,8 @@ struct trampoline_header { u32 gdt_base; #else u64 start; + u64 efer; u32 cr4; - u32 efer_low; - u32 efer_high; #endif }; diff --git a/arch/x86/realmode/init.c b/arch/x86/realmode/init.c index 099277984b80..cbca565af5bd 100644 --- a/arch/x86/realmode/init.c +++ b/arch/x86/realmode/init.c @@ -22,7 +22,7 @@ void __init setup_real_mode(void) size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob); #ifdef CONFIG_X86_64 u64 *trampoline_pgd; - u32 efer_low, efer_high; + u64 efer; #endif /* Has to be in very low memory so we can execute real-mode AP code. */ @@ -70,9 +70,8 @@ void __init setup_real_mode(void) * Some AMD processors will #GP(0) if EFER.LMA is set in WRMSR * so we need to mask it out. */ - rdmsr(MSR_EFER, efer_low, efer_high); - trampoline_header->efer_low = efer_low & ~EFER_LMA; - trampoline_header->efer_high = efer_high; + rdmsrl(MSR_EFER, efer); + trampoline_header->efer = efer & ~EFER_LMA; trampoline_header->start = (u64) secondary_startup_64; trampoline_cr4_features = &trampoline_header->cr4; diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S index 1b9e1bc1ac5e..bb360dc39d21 100644 --- a/arch/x86/realmode/rm/trampoline_64.S +++ b/arch/x86/realmode/rm/trampoline_64.S @@ -146,8 +146,8 @@ GLOBAL(trampoline_pgd) .space PAGE_SIZE .balign 8 GLOBAL(trampoline_header) tr_start: .space 8 - GLOBAL(tr_cr4) .space 4 GLOBAL(tr_efer) .space 8 + GLOBAL(tr_cr4) .space 4 END(trampoline_header) #include "trampoline_common.S" -- cgit v1.2.3 From 61f5446169046c217a5479517edac3a890c3bee7 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Mon, 21 May 2012 00:02:45 -0700 Subject: x86, realmode: Move end signature into header.S The end signature was defined in wakeup_asm.S as it originally came from the ACPI wakeup code. However, we rely on the existence of the .signature section to expand .bss, otherwise we would have to include code to explicitly zero the .bss depending on the configuration. Since the expanded .bss is just in .init.data anyway, it's easier to always have it expanded. This fixes failures when compiled without CONFIG_ACPI_SLEEP. Reported-by: Ingo Molnar Signed-off-by: H. Peter Anvin Cc: Jarkko Sakkinen --- arch/x86/realmode/rm/header.S | 9 +++++++++ arch/x86/realmode/rm/realmode.h | 5 +++++ arch/x86/realmode/rm/wakeup.h | 1 - arch/x86/realmode/rm/wakeup_asm.S | 6 +----- 4 files changed, 15 insertions(+), 6 deletions(-) (limited to 'arch/x86/realmode') diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S index 4612d5382791..fadf48378ada 100644 --- a/arch/x86/realmode/rm/header.S +++ b/arch/x86/realmode/rm/header.S @@ -7,6 +7,8 @@ #include #include +#include "realmode.h" + .section ".header", "a" .balign 16 @@ -30,3 +32,10 @@ GLOBAL(real_mode_header) .long pa_machine_real_restart_asm #endif END(real_mode_header) + + /* End signature, used to verify integrity */ + .section ".signature","a" + .balign 4 +GLOBAL(end_signature) + .long REALMODE_END_SIGNATURE +END(end_signature) diff --git a/arch/x86/realmode/rm/realmode.h b/arch/x86/realmode/rm/realmode.h index 15ab6335f843..d74cff6350ed 100644 --- a/arch/x86/realmode/rm/realmode.h +++ b/arch/x86/realmode/rm/realmode.h @@ -13,4 +13,9 @@ #endif /* __ASSEMBLY__ */ +/* + * Signature at the end of the realmode region + */ +#define REALMODE_END_SIGNATURE 0x65a22c82 + #endif /* ARCH_X86_REALMODE_RM_REALMODE_H */ diff --git a/arch/x86/realmode/rm/wakeup.h b/arch/x86/realmode/rm/wakeup.h index 2dfaf06b8af1..9317e0042f24 100644 --- a/arch/x86/realmode/rm/wakeup.h +++ b/arch/x86/realmode/rm/wakeup.h @@ -33,7 +33,6 @@ extern struct wakeup_header wakeup_header; #define WAKEUP_HEADER_OFFSET 8 #define WAKEUP_HEADER_SIGNATURE 0x51ee1111 -#define WAKEUP_END_SIGNATURE 0x65a22c82 /* Wakeup behavior bits */ #define WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE 0 diff --git a/arch/x86/realmode/rm/wakeup_asm.S b/arch/x86/realmode/rm/wakeup_asm.S index 46108f05e04e..8905166b0bbb 100644 --- a/arch/x86/realmode/rm/wakeup_asm.S +++ b/arch/x86/realmode/rm/wakeup_asm.S @@ -85,7 +85,7 @@ ENTRY(wakeup_start) /* Check we really have everything... */ movl end_signature, %eax - cmpl $WAKEUP_END_SIGNATURE, %eax + cmpl $REALMODE_END_SIGNATURE, %eax jne bogus_real_magic /* Call the C code */ @@ -175,7 +175,3 @@ GLOBAL(wakeup_idt) .long 0 /* address */ .word 0 END(wakeup_idt) - - .section ".signature","a" -end_signature: - .long WAKEUP_END_SIGNATURE -- cgit v1.2.3