Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'x86-trampoline-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 trampoline rework from H. Peter Anvin:
"This code reworks all the "trampoline"/"realmode" code (various bits
that need to live in the first megabyte of memory, most but not all of
which runs in real mode at some point) in the kernel into a single
object. The main reason for doing this is that it eliminates the last
place in the kernel where we needed pages to be mapped RWX. This code
separates all that code into proper R/RW/RX pages."

Fix up conflicts in arch/x86/kernel/Makefile (mca removed next to reboot
code), and arch/x86/kernel/reboot.c (reboot code moved around in one
branch, modified in this one), and arch/x86/tools/relocs.c (mostly same
code came in earlier due to working around the ld bugs just before the
3.4 release).

Also remove stale x86-relocs entry from scripts/.gitignore as per Peter
Anvin.

* commit '61f5446169046c217a5479517edac3a890c3bee7': (36 commits)
x86, realmode: Move end signature into header.S
x86, relocs: When printing an error, say relative or absolute
x86, relocs: More relocations which may end up as absolute
x86, relocs: Workaround for binutils 2.22.52.0.1 section bug
xen-acpi-processor: Add missing #include <xen/xen.h>
acpi, bgrd: Add missing <linux/io.h> to drivers/acpi/bgrt.c
x86, realmode: Change EFER to a single u64 field
x86, realmode: Move kernel/realmode.c to realmode/init.c
x86, realmode: Move not-common bits out of trampoline_common.S
x86, realmode: Mask out EFER.LMA when saving trampoline EFER
x86, realmode: Fix no cache bits test in reboot_32.S
x86, realmode: Make sure all generated files are listed in targets
x86, realmode: build fix: remove duplicate build
x86, realmode: read cr4 and EFER from kernel for 64-bit trampoline
x86, realmode: fixes compilation issue in tboot.c
x86, realmode: move relocs from scripts/ to arch/x86/tools
x86, realmode: header for trampoline code
x86, realmode: flattened rm hierachy
x86, realmode: don't copy real_mode_header
x86, realmode: fix 64-bit wakeup sequence
...

+862 -701
+1 -1
arch/x86/Kbuild
··· 1 - 2 1 obj-$(CONFIG_KVM) += kvm/ 3 2 4 3 # Xen paravirtualization support ··· 6 7 # lguest paravirtualization support 7 8 obj-$(CONFIG_LGUEST_GUEST) += lguest/ 8 9 10 + obj-y += realmode/ 9 11 obj-y += kernel/ 10 12 obj-y += mm/ 11 13
-2
arch/x86/include/asm/acpi.h
··· 29 29 #include <asm/processor.h> 30 30 #include <asm/mmu.h> 31 31 #include <asm/mpspec.h> 32 - #include <asm/trampoline.h> 33 32 34 33 #define COMPILER_DEPENDENT_INT64 long long 35 34 #define COMPILER_DEPENDENT_UINT64 unsigned long long ··· 117 118 extern int acpi_suspend_lowlevel(void); 118 119 119 120 extern const unsigned char acpi_wakeup_code[]; 120 - #define acpi_wakeup_address (__pa(TRAMPOLINE_SYM(acpi_wakeup_code))) 121 121 122 122 /* early initialization routine */ 123 123 extern void acpi_reserve_wakeup_memory(void);
+6 -1
arch/x86/include/asm/processor.h
··· 544 544 * enable), so that any CPU's that boot up 545 545 * after us can get the correct flags. 546 546 */ 547 - extern unsigned long mmu_cr4_features; 547 + extern unsigned long mmu_cr4_features; 548 + extern u32 *trampoline_cr4_features; 548 549 549 550 static inline void set_in_cr4(unsigned long mask) 550 551 { 551 552 unsigned long cr4; 552 553 553 554 mmu_cr4_features |= mask; 555 + if (trampoline_cr4_features) 556 + *trampoline_cr4_features = mmu_cr4_features; 554 557 cr4 = read_cr4(); 555 558 cr4 |= mask; 556 559 write_cr4(cr4); ··· 564 561 unsigned long cr4; 565 562 566 563 mmu_cr4_features &= ~mask; 564 + if (trampoline_cr4_features) 565 + *trampoline_cr4_features = mmu_cr4_features; 567 566 cr4 = read_cr4(); 568 567 cr4 &= ~mask; 569 568 write_cr4(cr4);
+62
arch/x86/include/asm/realmode.h
··· 1 + #ifndef _ARCH_X86_REALMODE_H 2 + #define _ARCH_X86_REALMODE_H 3 + 4 + #include <linux/types.h> 5 + #include <asm/io.h> 6 + 7 + /* This must match data at realmode.S */ 8 + struct real_mode_header { 9 + u32 text_start; 10 + u32 ro_end; 11 + /* SMP trampoline */ 12 + u32 trampoline_start; 13 + u32 trampoline_status; 14 + u32 trampoline_header; 15 + #ifdef CONFIG_X86_64 16 + u32 trampoline_pgd; 17 + #endif 18 + /* ACPI S3 wakeup */ 19 + #ifdef CONFIG_ACPI_SLEEP 20 + u32 wakeup_start; 21 + u32 wakeup_header; 22 + #endif 23 + /* APM/BIOS reboot */ 24 + #ifdef CONFIG_X86_32 25 + u32 machine_real_restart_asm; 26 + #endif 27 + }; 28 + 29 + /* This must match data at trampoline_32/64.S */ 30 + struct trampoline_header { 31 + #ifdef CONFIG_X86_32 32 + u32 start; 33 + u16 gdt_pad; 34 + u16 gdt_limit; 35 + u32 gdt_base; 36 + #else 37 + u64 start; 38 + u64 efer; 39 + u32 cr4; 40 + #endif 41 + }; 42 + 43 + extern struct real_mode_header *real_mode_header; 44 + extern unsigned char real_mode_blob_end[]; 45 + 46 + extern unsigned long init_rsp; 47 + extern unsigned long initial_code; 48 + extern unsigned long initial_gs; 49 + 50 + extern unsigned char real_mode_blob[]; 51 + extern unsigned char real_mode_relocs[]; 52 + 53 + #ifdef CONFIG_X86_32 54 + extern unsigned char startup_32_smp[]; 55 + extern unsigned char boot_gdt[]; 56 + #else 57 + extern unsigned char secondary_startup_64[]; 58 + #endif 59 + 60 + extern void __init setup_real_mode(void); 61 + 62 + #endif /* _ARCH_X86_REALMODE_H */
-39
arch/x86/include/asm/trampoline.h
··· 1 - #ifndef _ASM_X86_TRAMPOLINE_H 2 - #define _ASM_X86_TRAMPOLINE_H 3 - 4 - #ifndef __ASSEMBLY__ 5 - 6 - #include <linux/types.h> 7 - #include <asm/io.h> 8 - 9 - /* 10 - * Trampoline 80x86 program as an array. These are in the init rodata 11 - * segment, but that's okay, because we only care about the relative 12 - * addresses of the symbols. 13 - */ 14 - extern const unsigned char x86_trampoline_start []; 15 - extern const unsigned char x86_trampoline_end []; 16 - extern unsigned char *x86_trampoline_base; 17 - 18 - extern unsigned long init_rsp; 19 - extern unsigned long initial_code; 20 - extern unsigned long initial_gs; 21 - 22 - extern void __init setup_trampolines(void); 23 - 24 - extern const unsigned char trampoline_data[]; 25 - extern const unsigned char trampoline_status[]; 26 - 27 - #define TRAMPOLINE_SYM(x) \ 28 - ((void *)(x86_trampoline_base + \ 29 - ((const unsigned char *)(x) - x86_trampoline_start))) 30 - 31 - /* Address of the SMP trampoline */ 32 - static inline unsigned long trampoline_address(void) 33 - { 34 - return virt_to_phys(TRAMPOLINE_SYM(trampoline_data)); 35 - } 36 - 37 - #endif /* __ASSEMBLY__ */ 38 - 39 - #endif /* _ASM_X86_TRAMPOLINE_H */
-2
arch/x86/kernel/Makefile
··· 35 35 obj-y += pci-iommu_table.o 36 36 obj-y += resource.o 37 37 38 - obj-y += trampoline.o trampoline_$(BITS).o 39 38 obj-y += process.o 40 39 obj-y += i387.o xsave.o 41 40 obj-y += ptrace.o ··· 47 48 obj-y += cpu/ 48 49 obj-y += acpi/ 49 50 obj-y += reboot.o 50 - obj-$(CONFIG_X86_32) += reboot_32.o 51 51 obj-$(CONFIG_X86_MSR) += msr.o 52 52 obj-$(CONFIG_X86_CPUID) += cpuid.o 53 53 obj-$(CONFIG_PCI) += early-quirks.o
+1 -8
arch/x86/kernel/acpi/Makefile
··· 1 - subdir- := realmode 2 - 3 1 obj-$(CONFIG_ACPI) += boot.o 4 - obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_rm.o wakeup_$(BITS).o 2 + obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_$(BITS).o 5 3 6 4 ifneq ($(CONFIG_ACPI_PROCESSOR),) 7 5 obj-y += cstate.o 8 6 endif 9 - 10 - $(obj)/wakeup_rm.o: $(obj)/realmode/wakeup.bin 11 - 12 - $(obj)/realmode/wakeup.bin: FORCE 13 - $(Q)$(MAKE) $(build)=$(obj)/realmode 14 7
-3
arch/x86/kernel/acpi/realmode/.gitignore
··· 1 - wakeup.bin 2 - wakeup.elf 3 - wakeup.lds
-59
arch/x86/kernel/acpi/realmode/Makefile
··· 1 - # 2 - # arch/x86/kernel/acpi/realmode/Makefile 3 - # 4 - # This file is subject to the terms and conditions of the GNU General Public 5 - # License. See the file "COPYING" in the main directory of this archive 6 - # for more details. 7 - # 8 - 9 - always := wakeup.bin 10 - targets := wakeup.elf wakeup.lds 11 - 12 - wakeup-y += wakeup.o wakemain.o video-mode.o copy.o bioscall.o regs.o 13 - 14 - # The link order of the video-*.o modules can matter. In particular, 15 - # video-vga.o *must* be listed first, followed by video-vesa.o. 16 - # Hardware-specific drivers should follow in the order they should be 17 - # probed, and video-bios.o should typically be last. 18 - wakeup-y += video-vga.o 19 - wakeup-y += video-vesa.o 20 - wakeup-y += video-bios.o 21 - 22 - targets += $(wakeup-y) 23 - 24 - bootsrc := $(src)/../../../boot 25 - 26 - # --------------------------------------------------------------------------- 27 - 28 - # How to compile the 16-bit code. Note we always compile for -march=i386, 29 - # that way we can complain to the user if the CPU is insufficient. 30 - # Compile with _SETUP since this is similar to the boot-time setup code. 31 - KBUILD_CFLAGS := $(LINUXINCLUDE) -g -Os -D_SETUP -D_WAKEUP -D__KERNEL__ \ 32 - -I$(srctree)/$(bootsrc) \ 33 - $(cflags-y) \ 34 - -Wall -Wstrict-prototypes \ 35 - -march=i386 -mregparm=3 \ 36 - -include $(srctree)/$(bootsrc)/code16gcc.h \ 37 - -fno-strict-aliasing -fomit-frame-pointer \ 38 - $(call cc-option, -ffreestanding) \ 39 - $(call cc-option, -fno-toplevel-reorder,\ 40 - $(call cc-option, -fno-unit-at-a-time)) \ 41 - $(call cc-option, -fno-stack-protector) \ 42 - $(call cc-option, -mpreferred-stack-boundary=2) 43 - KBUILD_CFLAGS += $(call cc-option, -m32) 44 - KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ 45 - GCOV_PROFILE := n 46 - 47 - WAKEUP_OBJS = $(addprefix $(obj)/,$(wakeup-y)) 48 - 49 - LDFLAGS_wakeup.elf := -T 50 - 51 - CPPFLAGS_wakeup.lds += -P -C 52 - 53 - $(obj)/wakeup.elf: $(obj)/wakeup.lds $(WAKEUP_OBJS) FORCE 54 - $(call if_changed,ld) 55 - 56 - OBJCOPYFLAGS_wakeup.bin := -O binary 57 - 58 - $(obj)/wakeup.bin: $(obj)/wakeup.elf FORCE 59 - $(call if_changed,objcopy)
-1
arch/x86/kernel/acpi/realmode/bioscall.S
··· 1 - #include "../../../boot/bioscall.S"
-1
arch/x86/kernel/acpi/realmode/copy.S
··· 1 - #include "../../../boot/copy.S"
-1
arch/x86/kernel/acpi/realmode/regs.c
··· 1 - #include "../../../boot/regs.c"
-1
arch/x86/kernel/acpi/realmode/video-bios.c
··· 1 - #include "../../../boot/video-bios.c"
-1
arch/x86/kernel/acpi/realmode/video-mode.c
··· 1 - #include "../../../boot/video-mode.c"
-1
arch/x86/kernel/acpi/realmode/video-vesa.c
··· 1 - #include "../../../boot/video-vesa.c"
-1
arch/x86/kernel/acpi/realmode/video-vga.c
··· 1 - #include "../../../boot/video-vga.c"
+2 -1
arch/x86/kernel/acpi/realmode/wakemain.c arch/x86/realmode/rm/wakemain.c
··· 65 65 { 66 66 /* Kill machine if structures are wrong */ 67 67 if (wakeup_header.real_magic != 0x12345678) 68 - while (1); 68 + while (1) 69 + ; 69 70 70 71 if (wakeup_header.realmode_flags & 4) 71 72 send_morse("...-");
+69 -62
arch/x86/kernel/acpi/realmode/wakeup.S arch/x86/realmode/rm/wakeup_asm.S
··· 1 1 /* 2 2 * ACPI wakeup real mode startup stub 3 3 */ 4 + #include <linux/linkage.h> 4 5 #include <asm/segment.h> 5 6 #include <asm/msr-index.h> 6 7 #include <asm/page_types.h> 7 8 #include <asm/pgtable_types.h> 8 9 #include <asm/processor-flags.h> 10 + #include "realmode.h" 9 11 #include "wakeup.h" 10 12 11 13 .code16 12 - .section ".jump", "ax" 13 - .globl _start 14 - _start: 15 - cli 16 - jmp wakeup_code 17 14 18 15 /* This should match the structure in wakeup.h */ 19 - .section ".header", "a" 20 - .globl wakeup_header 21 - wakeup_header: 22 - video_mode: .short 0 /* Video mode number */ 23 - pmode_return: .byte 0x66, 0xea /* ljmpl */ 24 - .long 0 /* offset goes here */ 25 - .short __KERNEL_CS 26 - pmode_cr0: .long 0 /* Saved %cr0 */ 27 - pmode_cr3: .long 0 /* Saved %cr3 */ 28 - pmode_cr4: .long 0 /* Saved %cr4 */ 29 - pmode_efer: .quad 0 /* Saved EFER */ 30 - pmode_gdt: .quad 0 31 - pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */ 32 - pmode_behavior: .long 0 /* Wakeup behavior flags */ 33 - realmode_flags: .long 0 34 - real_magic: .long 0 35 - trampoline_segment: .word 0 36 - _pad1: .byte 0 37 - wakeup_jmp: .byte 0xea /* ljmpw */ 38 - wakeup_jmp_off: .word 3f 39 - wakeup_jmp_seg: .word 0 40 - wakeup_gdt: .quad 0, 0, 0 41 - signature: .long WAKEUP_HEADER_SIGNATURE 16 + .section ".data", "aw" 17 + 18 + .balign 16 19 + GLOBAL(wakeup_header) 20 + video_mode: .short 0 /* Video mode number */ 21 + pmode_entry: .long 0 22 + pmode_cs: .short __KERNEL_CS 23 + pmode_cr0: .long 0 /* Saved %cr0 */ 24 + pmode_cr3: .long 0 /* Saved %cr3 */ 25 + pmode_cr4: .long 0 /* Saved %cr4 */ 26 + pmode_efer: .quad 0 /* Saved EFER */ 27 + pmode_gdt: .quad 0 28 + pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */ 29 + pmode_behavior: .long 0 /* Wakeup behavior flags */ 30 + realmode_flags: .long 0 31 + real_magic: .long 0 32 + signature: .long WAKEUP_HEADER_SIGNATURE 33 + END(wakeup_header) 42 34 43 35 .text 44 36 .code16 45 - wakeup_code: 37 + 38 + .balign 16 39 + ENTRY(wakeup_start) 40 + cli 46 41 cld 47 42 43 + LJMPW_RM(3f) 44 + 3: 48 45 /* Apparently some dimwit BIOS programmers don't know how to 49 46 program a PM to RM transition, and we might end up here with 50 47 junk in the data segment descriptor registers. The only way ··· 51 54 movl %cr0, %eax 52 55 orb $X86_CR0_PE, %al 53 56 movl %eax, %cr0 54 - jmp 1f 55 - 1: ljmpw $8, $2f 57 + ljmpw $8, $2f 56 58 2: 57 59 movw %cx, %ds 58 60 movw %cx, %es ··· 61 65 62 66 andb $~X86_CR0_PE, %al 63 67 movl %eax, %cr0 64 - jmp wakeup_jmp 68 + LJMPW_RM(3f) 65 69 3: 66 70 /* Set up segments */ 67 71 movw %cs, %ax 72 + movw %ax, %ss 73 + movl $rm_stack_end, %esp 68 74 movw %ax, %ds 69 75 movw %ax, %es 70 - movw %ax, %ss 71 - lidtl wakeup_idt 76 + movw %ax, %fs 77 + movw %ax, %gs 72 78 73 - movl $wakeup_stack_end, %esp 79 + lidtl wakeup_idt 74 80 75 81 /* Clear the EFLAGS */ 76 82 pushl $0 ··· 85 87 86 88 /* Check we really have everything... */ 87 89 movl end_signature, %eax 88 - cmpl $WAKEUP_END_SIGNATURE, %eax 90 + cmpl $REALMODE_END_SIGNATURE, %eax 89 91 jne bogus_real_magic 90 92 91 93 /* Call the C code */ ··· 126 128 lgdtl pmode_gdt 127 129 128 130 /* This really couldn't... */ 129 - movl pmode_cr0, %eax 130 - movl %eax, %cr0 131 - jmp pmode_return 131 + movl pmode_entry, %eax 132 + movl pmode_cr0, %ecx 133 + movl %ecx, %cr0 134 + ljmpl $__KERNEL_CS, $pa_startup_32 135 + /* -> jmp *%eax in trampoline_32.S */ 132 136 #else 133 - pushw $0 134 - pushw trampoline_segment 135 - pushw $0 136 - lret 137 + jmp trampoline_start 137 138 #endif 138 139 139 140 bogus_real_magic: ··· 140 143 hlt 141 144 jmp 1b 142 145 143 - .data 146 + .section ".rodata","a" 147 + 148 + /* 149 + * Set up the wakeup GDT. We set these up as Big Real Mode, 150 + * that is, with limits set to 4 GB. At least the Lenovo 151 + * Thinkpad X61 is known to need this for the video BIOS 152 + * initialization quirk to work; this is likely to also 153 + * be the case for other laptops or integrated video devices. 154 + */ 155 + 156 + .balign 16 157 + GLOBAL(wakeup_gdt) 158 + .word 3*8-1 /* Self-descriptor */ 159 + .long pa_wakeup_gdt 160 + .word 0 161 + 162 + .word 0xffff /* 16-bit code segment @ real_mode_base */ 163 + .long 0x9b000000 + pa_real_mode_base 164 + .word 0x008f /* big real mode */ 165 + 166 + .word 0xffff /* 16-bit data segment @ real_mode_base */ 167 + .long 0x93000000 + pa_real_mode_base 168 + .word 0x008f /* big real mode */ 169 + END(wakeup_gdt) 170 + 171 + .section ".rodata","a" 144 172 .balign 8 145 173 146 174 /* This is the standard real-mode IDT */ 147 - wakeup_idt: 175 + .balign 16 176 + GLOBAL(wakeup_idt) 148 177 .word 0xffff /* limit */ 149 178 .long 0 /* address */ 150 179 .word 0 151 - 152 - .globl HEAP, heap_end 153 - HEAP: 154 - .long wakeup_heap 155 - heap_end: 156 - .long wakeup_stack 157 - 158 - .bss 159 - wakeup_heap: 160 - .space 2048 161 - wakeup_stack: 162 - .space 2048 163 - wakeup_stack_end: 164 - 165 - .section ".signature","a" 166 - end_signature: 167 - .long WAKEUP_END_SIGNATURE 180 + END(wakeup_idt)
+1 -9
arch/x86/kernel/acpi/realmode/wakeup.h arch/x86/realmode/rm/wakeup.h
··· 12 12 /* This must match data at wakeup.S */ 13 13 struct wakeup_header { 14 14 u16 video_mode; /* Video mode number */ 15 - u16 _jmp1; /* ljmpl opcode, 32-bit only */ 16 15 u32 pmode_entry; /* Protected mode resume point, 32-bit only */ 17 - u16 _jmp2; /* CS value, 32-bit only */ 16 + u16 pmode_cs; 18 17 u32 pmode_cr0; /* Protected mode cr0 */ 19 18 u32 pmode_cr3; /* Protected mode cr3 */ 20 19 u32 pmode_cr4; /* Protected mode cr4 */ ··· 25 26 u32 pmode_behavior; /* Wakeup routine behavior flags */ 26 27 u32 realmode_flags; 27 28 u32 real_magic; 28 - u16 trampoline_segment; /* segment with trampoline code, 64-bit only */ 29 - u8 _pad1; 30 - u8 wakeup_jmp; 31 - u16 wakeup_jmp_off; 32 - u16 wakeup_jmp_seg; 33 - u64 wakeup_gdt[3]; 34 29 u32 signature; /* To check we have correct structure */ 35 30 } __attribute__((__packed__)); 36 31 ··· 33 40 34 41 #define WAKEUP_HEADER_OFFSET 8 35 42 #define WAKEUP_HEADER_SIGNATURE 0x51ee1111 36 - #define WAKEUP_END_SIGNATURE 0x65a22c82 37 43 38 44 /* Wakeup behavior bits */ 39 45 #define WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE 0
-62
arch/x86/kernel/acpi/realmode/wakeup.lds.S
··· 1 - /* 2 - * wakeup.ld 3 - * 4 - * Linker script for the real-mode wakeup code 5 - */ 6 - #undef i386 7 - #include "wakeup.h" 8 - 9 - OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") 10 - OUTPUT_ARCH(i386) 11 - ENTRY(_start) 12 - 13 - SECTIONS 14 - { 15 - . = 0; 16 - .jump : { 17 - *(.jump) 18 - } = 0x90909090 19 - 20 - . = WAKEUP_HEADER_OFFSET; 21 - .header : { 22 - *(.header) 23 - } 24 - 25 - . = ALIGN(16); 26 - .text : { 27 - *(.text*) 28 - } = 0x90909090 29 - 30 - . = ALIGN(16); 31 - .rodata : { 32 - *(.rodata*) 33 - } 34 - 35 - .videocards : { 36 - video_cards = .; 37 - *(.videocards) 38 - video_cards_end = .; 39 - } 40 - 41 - . = ALIGN(16); 42 - .data : { 43 - *(.data*) 44 - } 45 - 46 - . = ALIGN(16); 47 - .bss : { 48 - __bss_start = .; 49 - *(.bss) 50 - __bss_end = .; 51 - } 52 - 53 - .signature : { 54 - *(.signature) 55 - } 56 - 57 - _end = .; 58 - 59 - /DISCARD/ : { 60 - *(.note*) 61 - } 62 - }
+4 -29
arch/x86/kernel/acpi/sleep.c
··· 14 14 #include <asm/desc.h> 15 15 #include <asm/pgtable.h> 16 16 #include <asm/cacheflush.h> 17 + #include <asm/realmode.h> 17 18 18 - #include "realmode/wakeup.h" 19 + #include "../../realmode/rm/wakeup.h" 19 20 #include "sleep.h" 20 21 21 22 unsigned long acpi_realmode_flags; ··· 37 36 */ 38 37 int acpi_suspend_lowlevel(void) 39 38 { 40 - struct wakeup_header *header; 41 - /* address in low memory of the wakeup routine. */ 42 - char *acpi_realmode; 39 + struct wakeup_header *header = 40 + (struct wakeup_header *) __va(real_mode_header->wakeup_header); 43 41 44 - acpi_realmode = TRAMPOLINE_SYM(acpi_wakeup_code); 45 - 46 - header = (struct wakeup_header *)(acpi_realmode + WAKEUP_HEADER_OFFSET); 47 42 if (header->signature != WAKEUP_HEADER_SIGNATURE) { 48 43 printk(KERN_ERR "wakeup header does not match\n"); 49 44 return -EINVAL; 50 45 } 51 46 52 47 header->video_mode = saved_video_mode; 53 - 54 - header->wakeup_jmp_seg = acpi_wakeup_address >> 4; 55 - 56 - /* 57 - * Set up the wakeup GDT. We set these up as Big Real Mode, 58 - * that is, with limits set to 4 GB. At least the Lenovo 59 - * Thinkpad X61 is known to need this for the video BIOS 60 - * initialization quirk to work; this is likely to also 61 - * be the case for other laptops or integrated video devices. 62 - */ 63 - 64 - /* GDT[0]: GDT self-pointer */ 65 - header->wakeup_gdt[0] = 66 - (u64)(sizeof(header->wakeup_gdt) - 1) + 67 - ((u64)__pa(&header->wakeup_gdt) << 16); 68 - /* GDT[1]: big real mode-like code segment */ 69 - header->wakeup_gdt[1] = 70 - GDT_ENTRY(0x809b, acpi_wakeup_address, 0xfffff); 71 - /* GDT[2]: big real mode-like data segment */ 72 - header->wakeup_gdt[2] = 73 - GDT_ENTRY(0x8093, acpi_wakeup_address, 0xfffff); 74 48 75 49 #ifndef CONFIG_64BIT 76 50 store_gdt((struct desc_ptr *)&header->pmode_gdt); ··· 71 95 header->pmode_cr3 = (u32)__pa(&initial_page_table); 72 96 saved_magic = 0x12345678; 73 97 #else /* CONFIG_64BIT */ 74 - header->trampoline_segment = trampoline_address() >> 4; 75 98 #ifdef CONFIG_SMP 76 99 stack_start = (unsigned long)temp_stack + sizeof(temp_stack); 77 100 early_gdt_descr.address =
+1 -1
arch/x86/kernel/acpi/sleep.h
··· 2 2 * Variables and functions used by the code in sleep.c 3 3 */ 4 4 5 - #include <asm/trampoline.h> 6 5 #include <linux/linkage.h> 6 + #include <asm/realmode.h> 7 7 8 8 extern unsigned long saved_video_mode; 9 9 extern long saved_magic;
-12
arch/x86/kernel/acpi/wakeup_rm.S
··· 1 - /* 2 - * Wrapper script for the realmode binary as a transport object 3 - * before copying to low memory. 4 - */ 5 - #include <asm/page_types.h> 6 - 7 - .section ".x86_trampoline","a" 8 - .balign PAGE_SIZE 9 - .globl acpi_wakeup_code 10 - acpi_wakeup_code: 11 - .incbin "arch/x86/kernel/acpi/realmode/wakeup.bin" 12 - .size acpi_wakeup_code, .-acpi_wakeup_code
-1
arch/x86/kernel/head32.c
··· 14 14 #include <asm/sections.h> 15 15 #include <asm/e820.h> 16 16 #include <asm/page.h> 17 - #include <asm/trampoline.h> 18 17 #include <asm/apic.h> 19 18 #include <asm/io_apic.h> 20 19 #include <asm/bios_ebda.h>
-1
arch/x86/kernel/head64.c
··· 24 24 #include <asm/sections.h> 25 25 #include <asm/kdebug.h> 26 26 #include <asm/e820.h> 27 - #include <asm/trampoline.h> 28 27 #include <asm/bios_ebda.h> 29 28 30 29 static void __init zap_identity_mappings(void)
+1 -4
arch/x86/kernel/head_32.S
··· 274 274 * If cpu hotplug is not supported then this code can go in init section 275 275 * which will be freed later 276 276 */ 277 - 278 277 __CPUINIT 279 - 280 - #ifdef CONFIG_SMP 281 278 ENTRY(startup_32_smp) 282 279 cld 283 280 movl $(__BOOT_DS),%eax ··· 285 288 movl pa(stack_start),%ecx 286 289 movl %eax,%ss 287 290 leal -__PAGE_OFFSET(%ecx),%esp 288 - #endif /* CONFIG_SMP */ 291 + 289 292 default_entry: 290 293 291 294 /*
-4
arch/x86/kernel/head_64.S
··· 139 139 /* Fixup phys_base */ 140 140 addq %rbp, phys_base(%rip) 141 141 142 - /* Fixup trampoline */ 143 - addq %rbp, trampoline_level4_pgt + 0(%rip) 144 - addq %rbp, trampoline_level4_pgt + (511*8)(%rip) 145 - 146 142 /* Due to ENTRY(), sometimes the empty space gets filled with 147 143 * zeros. Better take a jmp than relying on empty space being 148 144 * filled with 0x90 (nop)
-1
arch/x86/kernel/mpparse.c
··· 27 27 #include <asm/proto.h> 28 28 #include <asm/bios_ebda.h> 29 29 #include <asm/e820.h> 30 - #include <asm/trampoline.h> 31 30 #include <asm/setup.h> 32 31 #include <asm/smp.h> 33 32
+3 -22
arch/x86/kernel/reboot.c
··· 24 24 #ifdef CONFIG_X86_32 25 25 # include <linux/ctype.h> 26 26 # include <linux/mc146818rtc.h> 27 + # include <asm/realmode.h> 27 28 #else 28 29 # include <asm/x86_init.h> 29 30 #endif ··· 157 156 return 0; 158 157 } 159 158 160 - extern const unsigned char machine_real_restart_asm[]; 161 - extern const u64 machine_real_restart_gdt[3]; 162 - 163 159 void machine_real_restart(unsigned int type) 164 160 { 165 - void *restart_va; 166 - unsigned long restart_pa; 167 - void (*restart_lowmem)(unsigned int); 168 - u64 *lowmem_gdt; 161 + void (*restart_lowmem)(unsigned int) = (void (*)(unsigned int)) 162 + real_mode_header->machine_real_restart_asm; 169 163 170 164 local_irq_disable(); 171 165 ··· 190 194 * REBOOT.COM programs, and the previous reset routine did this 191 195 * too. */ 192 196 *((unsigned short *)0x472) = reboot_mode; 193 - 194 - /* Patch the GDT in the low memory trampoline */ 195 - lowmem_gdt = TRAMPOLINE_SYM(machine_real_restart_gdt); 196 - 197 - restart_va = TRAMPOLINE_SYM(machine_real_restart_asm); 198 - restart_pa = virt_to_phys(restart_va); 199 - restart_lowmem = (void (*)(unsigned int))restart_pa; 200 - 201 - /* GDT[0]: GDT self-pointer */ 202 - lowmem_gdt[0] = 203 - (u64)(sizeof(machine_real_restart_gdt) - 1) + 204 - ((u64)virt_to_phys(lowmem_gdt) << 16); 205 - /* GDT[1]: 64K real mode code segment */ 206 - lowmem_gdt[1] = 207 - GDT_ENTRY(0x009b, restart_pa, 0xffff); 208 197 209 198 /* Jump to the identity-mapped low memory code */ 210 199 restart_lowmem(type);
+43 -46
arch/x86/kernel/reboot_32.S arch/x86/realmode/rm/reboot_32.S
··· 2 2 #include <linux/init.h> 3 3 #include <asm/segment.h> 4 4 #include <asm/page_types.h> 5 + #include "realmode.h" 5 6 6 7 /* 7 8 * The following code and data reboots the machine by switching to real ··· 14 13 * 15 14 * This code is called with the restart type (0 = BIOS, 1 = APM) in %eax. 16 15 */ 17 - .section ".x86_trampoline","a" 18 - .balign 16 16 + .section ".text32", "ax" 19 17 .code32 18 + 19 + .balign 16 20 20 ENTRY(machine_real_restart_asm) 21 - r_base = . 22 - /* Get our own relocated address */ 23 - call 1f 24 - 1: popl %ebx 25 - subl $(1b - r_base), %ebx 26 - 27 - /* Compute the equivalent real-mode segment */ 28 - movl %ebx, %ecx 29 - shrl $4, %ecx 30 - 31 - /* Patch post-real-mode segment jump */ 32 - movw (dispatch_table - r_base)(%ebx,%eax,2),%ax 33 - movw %ax, (101f - r_base)(%ebx) 34 - movw %cx, (102f - r_base)(%ebx) 35 - 36 21 /* Set up the IDT for real mode. */ 37 - lidtl (machine_real_restart_idt - r_base)(%ebx) 22 + lidtl pa_machine_real_restart_idt 38 23 39 24 /* 40 25 * Set up a GDT from which we can load segment descriptors for real 41 26 * mode. The GDT is not used in real mode; it is just needed here to 42 27 * prepare the descriptors. 43 28 */ 44 - lgdtl (machine_real_restart_gdt - r_base)(%ebx) 29 + lgdtl pa_machine_real_restart_gdt 45 30 46 31 /* 47 32 * Load the data segment registers with 16-bit compatible values ··· 38 51 movl %ecx, %fs 39 52 movl %ecx, %gs 40 53 movl %ecx, %ss 41 - ljmpl $8, $1f - r_base 54 + ljmpw $8, $1f 42 55 43 56 /* 44 57 * This is 16-bit protected mode code to disable paging and the cache, ··· 63 76 * 64 77 * Most of this work is probably excessive, but it is what is tested. 65 78 */ 79 + .text 66 80 .code16 81 + 82 + .balign 16 83 + machine_real_restart_asm16: 67 84 1: 68 85 xorl %ecx, %ecx 69 - movl %cr0, %eax 70 - andl $0x00000011, %eax 71 - orl $0x60000000, %eax 72 - movl %eax, %cr0 86 + movl %cr0, %edx 87 + andl $0x00000011, %edx 88 + orl $0x60000000, %edx 89 + movl %edx, %cr0 73 90 movl %ecx, %cr3 74 91 movl %cr0, %edx 75 - andl $0x60000000, %edx /* If no cache bits -> no wbinvd */ 92 + testl $0x60000000, %edx /* If no cache bits -> no wbinvd */ 76 93 jz 2f 77 94 wbinvd 78 95 2: 79 - andb $0x10, %al 80 - movl %eax, %cr0 81 - .byte 0xea /* ljmpw */ 82 - 101: .word 0 /* Offset */ 83 - 102: .word 0 /* Segment */ 84 - 85 - bios: 86 - ljmpw $0xf000, $0xfff0 96 + andb $0x10, %dl 97 + movl %edx, %cr0 98 + LJMPW_RM(3f) 99 + 3: 100 + andw %ax, %ax 101 + jz bios 87 102 88 103 apm: 89 104 movw $0x1000, %ax ··· 95 106 movw $0x0001, %bx 96 107 movw $0x0003, %cx 97 108 int $0x15 109 + /* This should never return... */ 98 110 99 - END(machine_real_restart_asm) 111 + bios: 112 + ljmpw $0xf000, $0xfff0 100 113 101 - .balign 16 102 - /* These must match <asm/reboot.h */ 103 - dispatch_table: 104 - .word bios - r_base 105 - .word apm - r_base 106 - END(dispatch_table) 114 + .section ".rodata", "a" 107 115 108 - .balign 16 109 - machine_real_restart_idt: 116 + .balign 16 117 + GLOBAL(machine_real_restart_idt) 110 118 .word 0xffff /* Length - real mode default value */ 111 119 .long 0 /* Base - real mode default value */ 112 120 END(machine_real_restart_idt) 113 121 114 - .balign 16 115 - ENTRY(machine_real_restart_gdt) 116 - .quad 0 /* Self-pointer, filled in by PM code */ 117 - .quad 0 /* 16-bit code segment, filled in by PM code */ 122 + .balign 16 123 + GLOBAL(machine_real_restart_gdt) 124 + /* Self-pointer */ 125 + .word 0xffff /* Length - real mode default value */ 126 + .long pa_machine_real_restart_gdt 127 + .word 0 128 + 129 + /* 130 + * 16-bit code segment pointing to real_mode_seg 131 + * Selector value 8 132 + */ 133 + .word 0xffff /* Limit */ 134 + .long 0x9b000000 + pa_real_mode_base 135 + .word 0 136 + 118 137 /* 119 138 * 16-bit data segment with the selector value 16 = 0x10 and 120 139 * base value 0x100; since this is consistent with real mode
+4 -2
arch/x86/kernel/setup.c
··· 73 73 74 74 #include <asm/mtrr.h> 75 75 #include <asm/apic.h> 76 - #include <asm/trampoline.h> 76 + #include <asm/realmode.h> 77 77 #include <asm/e820.h> 78 78 #include <asm/mpspec.h> 79 79 #include <asm/setup.h> ··· 909 909 printk(KERN_DEBUG "initial memory mapped: [mem 0x00000000-%#010lx]\n", 910 910 (max_pfn_mapped<<PAGE_SHIFT) - 1); 911 911 912 - setup_trampolines(); 912 + setup_real_mode(); 913 913 914 914 init_gbpages(); 915 915 ··· 968 968 if (boot_cpu_data.cpuid_level >= 0) { 969 969 /* A CPU has %cr4 if and only if it has CPUID */ 970 970 mmu_cr4_features = read_cr4(); 971 + if (trampoline_cr4_features) 972 + *trampoline_cr4_features = mmu_cr4_features; 971 973 } 972 974 973 975 #ifdef CONFIG_X86_32
+10 -8
arch/x86/kernel/smpboot.c
··· 57 57 #include <asm/nmi.h> 58 58 #include <asm/irq.h> 59 59 #include <asm/idle.h> 60 - #include <asm/trampoline.h> 60 + #include <asm/realmode.h> 61 61 #include <asm/cpu.h> 62 62 #include <asm/numa.h> 63 63 #include <asm/pgtable.h> ··· 72 72 73 73 #include <asm/smpboot_hooks.h> 74 74 #include <asm/i8259.h> 75 + 76 + #include <asm/realmode.h> 75 77 76 78 /* State of each CPU */ 77 79 DEFINE_PER_CPU(int, cpu_state) = { 0 }; ··· 662 660 */ 663 661 static int __cpuinit do_boot_cpu(int apicid, int cpu, struct task_struct *idle) 664 662 { 663 + volatile u32 *trampoline_status = 664 + (volatile u32 *) __va(real_mode_header->trampoline_status); 665 + /* start_ip had better be page-aligned! */ 666 + unsigned long start_ip = real_mode_header->trampoline_start; 667 + 665 668 unsigned long boot_error = 0; 666 - unsigned long start_ip; 667 669 int timeout; 668 670 669 671 alternatives_smp_switch(1); ··· 689 683 early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu); 690 684 initial_code = (unsigned long)start_secondary; 691 685 stack_start = idle->thread.sp; 692 - 693 - /* start_ip had better be page-aligned! */ 694 - start_ip = trampoline_address(); 695 686 696 687 /* So we see what's up */ 697 688 announce_cpu(cpu, apicid); ··· 752 749 pr_debug("CPU%d: has booted.\n", cpu); 753 750 } else { 754 751 boot_error = 1; 755 - if (*(volatile u32 *)TRAMPOLINE_SYM(trampoline_status) 756 - == 0xA5A5A5A5) 752 + if (*trampoline_status == 0xA5A5A5A5) 757 753 /* trampoline started but...? */ 758 754 pr_err("CPU%d: Stuck ??\n", cpu); 759 755 else ··· 778 776 } 779 777 780 778 /* mark "stuck" area as not stuck */ 781 - *(volatile u32 *)TRAMPOLINE_SYM(trampoline_status) = 0; 779 + *trampoline_status = 0; 782 780 783 781 if (get_uv_system_type() != UV_NON_UNIQUE_APIC) { 784 782 /*
+4 -3
arch/x86/kernel/tboot.c
··· 32 32 #include <linux/mm.h> 33 33 #include <linux/tboot.h> 34 34 35 - #include <asm/trampoline.h> 35 + #include <asm/realmode.h> 36 36 #include <asm/processor.h> 37 37 #include <asm/bootparam.h> 38 38 #include <asm/pgtable.h> ··· 44 44 #include <asm/e820.h> 45 45 #include <asm/io.h> 46 46 47 - #include "acpi/realmode/wakeup.h" 47 + #include "../realmode/rm/wakeup.h" 48 48 49 49 /* Global pointer to shared data; NULL means no measured launch. */ 50 50 struct tboot *tboot __read_mostly; ··· 201 201 add_mac_region(e820.map[i].addr, e820.map[i].size); 202 202 } 203 203 204 - tboot->acpi_sinfo.kernel_s3_resume_vector = acpi_wakeup_address; 204 + tboot->acpi_sinfo.kernel_s3_resume_vector = 205 + real_mode_header->wakeup_start; 205 206 206 207 return 0; 207 208 }
-42
arch/x86/kernel/trampoline.c
··· 1 - #include <linux/io.h> 2 - #include <linux/memblock.h> 3 - 4 - #include <asm/trampoline.h> 5 - #include <asm/cacheflush.h> 6 - #include <asm/pgtable.h> 7 - 8 - unsigned char *x86_trampoline_base; 9 - 10 - void __init setup_trampolines(void) 11 - { 12 - phys_addr_t mem; 13 - size_t size = PAGE_ALIGN(x86_trampoline_end - x86_trampoline_start); 14 - 15 - /* Has to be in very low memory so we can execute real-mode AP code. */ 16 - mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE); 17 - if (!mem) 18 - panic("Cannot allocate trampoline\n"); 19 - 20 - x86_trampoline_base = __va(mem); 21 - memblock_reserve(mem, size); 22 - 23 - printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n", 24 - x86_trampoline_base, (unsigned long long)mem, size); 25 - 26 - memcpy(x86_trampoline_base, x86_trampoline_start, size); 27 - } 28 - 29 - /* 30 - * setup_trampolines() gets called very early, to guarantee the 31 - * availability of low memory. This is before the proper kernel page 32 - * tables are set up, so we cannot set page permissions in that 33 - * function. Thus, we use an arch_initcall instead. 34 - */ 35 - static int __init configure_trampolines(void) 36 - { 37 - size_t size = PAGE_ALIGN(x86_trampoline_end - x86_trampoline_start); 38 - 39 - set_memory_x((unsigned long)x86_trampoline_base, size >> PAGE_SHIFT); 40 - return 0; 41 - } 42 - arch_initcall(configure_trampolines);
-83
arch/x86/kernel/trampoline_32.S
··· 1 - /* 2 - * 3 - * Trampoline.S Derived from Setup.S by Linus Torvalds 4 - * 5 - * 4 Jan 1997 Michael Chastain: changed to gnu as. 6 - * 7 - * This is only used for booting secondary CPUs in SMP machine 8 - * 9 - * Entry: CS:IP point to the start of our code, we are 10 - * in real mode with no stack, but the rest of the 11 - * trampoline page to make our stack and everything else 12 - * is a mystery. 13 - * 14 - * We jump into arch/x86/kernel/head_32.S. 15 - * 16 - * On entry to trampoline_data, the processor is in real mode 17 - * with 16-bit addressing and 16-bit data. CS has some value 18 - * and IP is zero. Thus, data addresses need to be absolute 19 - * (no relocation) and are taken with regard to r_base. 20 - * 21 - * If you work on this file, check the object module with 22 - * objdump --reloc to make sure there are no relocation 23 - * entries except for: 24 - * 25 - * TYPE VALUE 26 - * R_386_32 startup_32_smp 27 - * R_386_32 boot_gdt 28 - */ 29 - 30 - #include <linux/linkage.h> 31 - #include <linux/init.h> 32 - #include <asm/segment.h> 33 - #include <asm/page_types.h> 34 - 35 - #ifdef CONFIG_SMP 36 - 37 - .section ".x86_trampoline","a" 38 - .balign PAGE_SIZE 39 - .code16 40 - 41 - ENTRY(trampoline_data) 42 - r_base = . 43 - wbinvd # Needed for NUMA-Q should be harmless for others 44 - mov %cs, %ax # Code and data in the same place 45 - mov %ax, %ds 46 - 47 - cli # We should be safe anyway 48 - 49 - movl $0xA5A5A5A5, trampoline_status - r_base 50 - # write marker for master knows we're running 51 - 52 - /* GDT tables in non default location kernel can be beyond 16MB and 53 - * lgdt will not be able to load the address as in real mode default 54 - * operand size is 16bit. Use lgdtl instead to force operand size 55 - * to 32 bit. 56 - */ 57 - 58 - lidtl boot_idt_descr - r_base # load idt with 0, 0 59 - lgdtl boot_gdt_descr - r_base # load gdt with whatever is appropriate 60 - 61 - xor %ax, %ax 62 - inc %ax # protected mode (PE) bit 63 - lmsw %ax # into protected mode 64 - # flush prefetch and jump to startup_32_smp in arch/i386/kernel/head.S 65 - ljmpl $__BOOT_CS, $(startup_32_smp-__PAGE_OFFSET) 66 - 67 - # These need to be in the same 64K segment as the above; 68 - # hence we don't use the boot_gdt_descr defined in head.S 69 - boot_gdt_descr: 70 - .word __BOOT_DS + 7 # gdt limit 71 - .long boot_gdt - __PAGE_OFFSET # gdt base 72 - 73 - boot_idt_descr: 74 - .word 0 # idt limit = 0 75 - .long 0 # idt base = 0L 76 - 77 - ENTRY(trampoline_status) 78 - .long 0 79 - 80 - .globl trampoline_end 81 - trampoline_end: 82 - 83 - #endif /* CONFIG_SMP */
-171
arch/x86/kernel/trampoline_64.S
··· 1 - /* 2 - * 3 - * Trampoline.S Derived from Setup.S by Linus Torvalds 4 - * 5 - * 4 Jan 1997 Michael Chastain: changed to gnu as. 6 - * 15 Sept 2005 Eric Biederman: 64bit PIC support 7 - * 8 - * Entry: CS:IP point to the start of our code, we are 9 - * in real mode with no stack, but the rest of the 10 - * trampoline page to make our stack and everything else 11 - * is a mystery. 12 - * 13 - * On entry to trampoline_data, the processor is in real mode 14 - * with 16-bit addressing and 16-bit data. CS has some value 15 - * and IP is zero. Thus, data addresses need to be absolute 16 - * (no relocation) and are taken with regard to r_base. 17 - * 18 - * With the addition of trampoline_level4_pgt this code can 19 - * now enter a 64bit kernel that lives at arbitrary 64bit 20 - * physical addresses. 21 - * 22 - * If you work on this file, check the object module with objdump 23 - * --full-contents --reloc to make sure there are no relocation 24 - * entries. 25 - */ 26 - 27 - #include <linux/linkage.h> 28 - #include <linux/init.h> 29 - #include <asm/pgtable_types.h> 30 - #include <asm/page_types.h> 31 - #include <asm/msr.h> 32 - #include <asm/segment.h> 33 - #include <asm/processor-flags.h> 34 - 35 - .section ".x86_trampoline","a" 36 - .balign PAGE_SIZE 37 - .code16 38 - 39 - ENTRY(trampoline_data) 40 - r_base = . 41 - cli # We should be safe anyway 42 - wbinvd 43 - mov %cs, %ax # Code and data in the same place 44 - mov %ax, %ds 45 - mov %ax, %es 46 - mov %ax, %ss 47 - 48 - 49 - movl $0xA5A5A5A5, trampoline_status - r_base 50 - # write marker for master knows we're running 51 - 52 - # Setup stack 53 - movw $(trampoline_stack_end - r_base), %sp 54 - 55 - call verify_cpu # Verify the cpu supports long mode 56 - testl %eax, %eax # Check for return code 57 - jnz no_longmode 58 - 59 - mov %cs, %ax 60 - movzx %ax, %esi # Find the 32bit trampoline location 61 - shll $4, %esi 62 - 63 - # Fixup the absolute vectors 64 - leal (startup_32 - r_base)(%esi), %eax 65 - movl %eax, startup_32_vector - r_base 66 - leal (startup_64 - r_base)(%esi), %eax 67 - movl %eax, startup_64_vector - r_base 68 - leal (tgdt - r_base)(%esi), %eax 69 - movl %eax, (tgdt + 2 - r_base) 70 - 71 - /* 72 - * GDT tables in non default location kernel can be beyond 16MB and 73 - * lgdt will not be able to load the address as in real mode default 74 - * operand size is 16bit. Use lgdtl instead to force operand size 75 - * to 32 bit. 76 - */ 77 - 78 - lidtl tidt - r_base # load idt with 0, 0 79 - lgdtl tgdt - r_base # load gdt with whatever is appropriate 80 - 81 - mov $X86_CR0_PE, %ax # protected mode (PE) bit 82 - lmsw %ax # into protected mode 83 - 84 - # flush prefetch and jump to startup_32 85 - ljmpl *(startup_32_vector - r_base) 86 - 87 - .code32 88 - .balign 4 89 - startup_32: 90 - movl $__KERNEL_DS, %eax # Initialize the %ds segment register 91 - movl %eax, %ds 92 - 93 - movl $X86_CR4_PAE, %eax 94 - movl %eax, %cr4 # Enable PAE mode 95 - 96 - # Setup trampoline 4 level pagetables 97 - leal (trampoline_level4_pgt - r_base)(%esi), %eax 98 - movl %eax, %cr3 99 - 100 - movl $MSR_EFER, %ecx 101 - movl $(1 << _EFER_LME), %eax # Enable Long Mode 102 - xorl %edx, %edx 103 - wrmsr 104 - 105 - # Enable paging and in turn activate Long Mode 106 - # Enable protected mode 107 - movl $(X86_CR0_PG | X86_CR0_PE), %eax 108 - movl %eax, %cr0 109 - 110 - /* 111 - * At this point we're in long mode but in 32bit compatibility mode 112 - * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn 113 - * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use 114 - * the new gdt/idt that has __KERNEL_CS with CS.L = 1. 115 - */ 116 - ljmp *(startup_64_vector - r_base)(%esi) 117 - 118 - .code64 119 - .balign 4 120 - startup_64: 121 - # Now jump into the kernel using virtual addresses 122 - movq $secondary_startup_64, %rax 123 - jmp *%rax 124 - 125 - .code16 126 - no_longmode: 127 - hlt 128 - jmp no_longmode 129 - #include "verify_cpu.S" 130 - 131 - .balign 4 132 - # Careful these need to be in the same 64K segment as the above; 133 - tidt: 134 - .word 0 # idt limit = 0 135 - .word 0, 0 # idt base = 0L 136 - 137 - # Duplicate the global descriptor table 138 - # so the kernel can live anywhere 139 - .balign 4 140 - tgdt: 141 - .short tgdt_end - tgdt # gdt limit 142 - .long tgdt - r_base 143 - .short 0 144 - .quad 0x00cf9b000000ffff # __KERNEL32_CS 145 - .quad 0x00af9b000000ffff # __KERNEL_CS 146 - .quad 0x00cf93000000ffff # __KERNEL_DS 147 - tgdt_end: 148 - 149 - .balign 4 150 - startup_32_vector: 151 - .long startup_32 - r_base 152 - .word __KERNEL32_CS, 0 153 - 154 - .balign 4 155 - startup_64_vector: 156 - .long startup_64 - r_base 157 - .word __KERNEL_CS, 0 158 - 159 - .balign 4 160 - ENTRY(trampoline_status) 161 - .long 0 162 - 163 - trampoline_stack: 164 - .org 0x1000 165 - trampoline_stack_end: 166 - ENTRY(trampoline_level4_pgt) 167 - .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE 168 - .fill 510,8,0 169 - .quad level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE 170 - 171 - ENTRY(trampoline_end)
-12
arch/x86/kernel/vmlinux.lds.S
··· 197 197 198 198 INIT_DATA_SECTION(16) 199 199 200 - /* 201 - * Code and data for a variety of lowlevel trampolines, to be 202 - * copied into base memory (< 1 MiB) during initialization. 203 - * Since it is copied early, the main copy can be discarded 204 - * afterwards. 205 - */ 206 - .x86_trampoline : AT(ADDR(.x86_trampoline) - LOAD_OFFSET) { 207 - x86_trampoline_start = .; 208 - *(.x86_trampoline) 209 - x86_trampoline_end = .; 210 - } 211 - 212 200 .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) { 213 201 __x86_cpu_dev_start = .; 214 202 *(.x86_cpu_dev.init)
+18
arch/x86/realmode/Makefile
··· 1 + # 2 + # arch/x86/realmode/Makefile 3 + # 4 + # This file is subject to the terms and conditions of the GNU General Public 5 + # License. See the file "COPYING" in the main directory of this archive 6 + # for more details. 7 + # 8 + # 9 + 10 + subdir- := rm 11 + 12 + obj-y += init.o 13 + obj-y += rmpiggy.o 14 + 15 + $(obj)/rmpiggy.o: $(obj)/rm/realmode.bin 16 + 17 + $(obj)/rm/realmode.bin: FORCE 18 + $(Q)$(MAKE) $(build)=$(obj)/rm $@
+115
arch/x86/realmode/init.c
··· 1 + #include <linux/io.h> 2 + #include <linux/memblock.h> 3 + 4 + #include <asm/cacheflush.h> 5 + #include <asm/pgtable.h> 6 + #include <asm/realmode.h> 7 + 8 + struct real_mode_header *real_mode_header; 9 + u32 *trampoline_cr4_features; 10 + 11 + void __init setup_real_mode(void) 12 + { 13 + phys_addr_t mem; 14 + u16 real_mode_seg; 15 + u32 *rel; 16 + u32 count; 17 + u32 *ptr; 18 + u16 *seg; 19 + int i; 20 + unsigned char *base; 21 + struct trampoline_header *trampoline_header; 22 + size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob); 23 + #ifdef CONFIG_X86_64 24 + u64 *trampoline_pgd; 25 + u64 efer; 26 + #endif 27 + 28 + /* Has to be in very low memory so we can execute real-mode AP code. */ 29 + mem = memblock_find_in_range(0, 1<<20, size, PAGE_SIZE); 30 + if (!mem) 31 + panic("Cannot allocate trampoline\n"); 32 + 33 + base = __va(mem); 34 + memblock_reserve(mem, size); 35 + real_mode_header = (struct real_mode_header *) base; 36 + printk(KERN_DEBUG "Base memory trampoline at [%p] %llx size %zu\n", 37 + base, (unsigned long long)mem, size); 38 + 39 + memcpy(base, real_mode_blob, size); 40 + 41 + real_mode_seg = __pa(base) >> 4; 42 + rel = (u32 *) real_mode_relocs; 43 + 44 + /* 16-bit segment relocations. */ 45 + count = rel[0]; 46 + rel = &rel[1]; 47 + for (i = 0; i < count; i++) { 48 + seg = (u16 *) (base + rel[i]); 49 + *seg = real_mode_seg; 50 + } 51 + 52 + /* 32-bit linear relocations. */ 53 + count = rel[i]; 54 + rel = &rel[i + 1]; 55 + for (i = 0; i < count; i++) { 56 + ptr = (u32 *) (base + rel[i]); 57 + *ptr += __pa(base); 58 + } 59 + 60 + /* Must be perfomed *after* relocation. */ 61 + trampoline_header = (struct trampoline_header *) 62 + __va(real_mode_header->trampoline_header); 63 + 64 + #ifdef CONFIG_X86_32 65 + trampoline_header->start = __pa(startup_32_smp); 66 + trampoline_header->gdt_limit = __BOOT_DS + 7; 67 + trampoline_header->gdt_base = __pa(boot_gdt); 68 + #else 69 + /* 70 + * Some AMD processors will #GP(0) if EFER.LMA is set in WRMSR 71 + * so we need to mask it out. 72 + */ 73 + rdmsrl(MSR_EFER, efer); 74 + trampoline_header->efer = efer & ~EFER_LMA; 75 + 76 + trampoline_header->start = (u64) secondary_startup_64; 77 + trampoline_cr4_features = &trampoline_header->cr4; 78 + *trampoline_cr4_features = read_cr4(); 79 + 80 + trampoline_pgd = (u64 *) __va(real_mode_header->trampoline_pgd); 81 + trampoline_pgd[0] = __pa(level3_ident_pgt) + _KERNPG_TABLE; 82 + trampoline_pgd[511] = __pa(level3_kernel_pgt) + _KERNPG_TABLE; 83 + #endif 84 + } 85 + 86 + /* 87 + * set_real_mode_permissions() gets called very early, to guarantee the 88 + * availability of low memory. This is before the proper kernel page 89 + * tables are set up, so we cannot set page permissions in that 90 + * function. Thus, we use an arch_initcall instead. 91 + */ 92 + static int __init set_real_mode_permissions(void) 93 + { 94 + unsigned char *base = (unsigned char *) real_mode_header; 95 + size_t size = PAGE_ALIGN(real_mode_blob_end - real_mode_blob); 96 + 97 + size_t ro_size = 98 + PAGE_ALIGN(real_mode_header->ro_end) - 99 + __pa(base); 100 + 101 + size_t text_size = 102 + PAGE_ALIGN(real_mode_header->ro_end) - 103 + real_mode_header->text_start; 104 + 105 + unsigned long text_start = 106 + (unsigned long) __va(real_mode_header->text_start); 107 + 108 + set_memory_nx((unsigned long) base, size >> PAGE_SHIFT); 109 + set_memory_ro((unsigned long) base, ro_size >> PAGE_SHIFT); 110 + set_memory_x((unsigned long) text_start, text_size >> PAGE_SHIFT); 111 + 112 + return 0; 113 + } 114 + 115 + arch_initcall(set_real_mode_permissions);
+3
arch/x86/realmode/rm/.gitignore
··· 1 + pasyms.h 2 + realmode.lds 3 + realmode.relocs
+82
arch/x86/realmode/rm/Makefile
··· 1 + # 2 + # arch/x86/realmode/Makefile 3 + # 4 + # This file is subject to the terms and conditions of the GNU General Public 5 + # License. See the file "COPYING" in the main directory of this archive 6 + # for more details. 7 + # 8 + # 9 + 10 + always := realmode.bin realmode.relocs 11 + 12 + wakeup-objs := wakeup_asm.o wakemain.o video-mode.o 13 + wakeup-objs += copy.o bioscall.o regs.o 14 + # The link order of the video-*.o modules can matter. In particular, 15 + # video-vga.o *must* be listed first, followed by video-vesa.o. 16 + # Hardware-specific drivers should follow in the order they should be 17 + # probed, and video-bios.o should typically be last. 18 + wakeup-objs += video-vga.o 19 + wakeup-objs += video-vesa.o 20 + wakeup-objs += video-bios.o 21 + 22 + realmode-y += header.o 23 + realmode-y += trampoline_$(BITS).o 24 + realmode-y += stack.o 25 + realmode-$(CONFIG_X86_32) += reboot_32.o 26 + realmode-$(CONFIG_ACPI_SLEEP) += $(wakeup-objs) 27 + 28 + targets += $(realmode-y) 29 + 30 + REALMODE_OBJS = $(addprefix $(obj)/,$(realmode-y)) 31 + 32 + sed-pasyms := -n -r -e 's/^([0-9a-fA-F]+) [ABCDGRSTVW] (.+)$$/pa_\2 = \2;/p' 33 + 34 + quiet_cmd_pasyms = PASYMS $@ 35 + cmd_pasyms = $(NM) $(filter-out FORCE,$^) | \ 36 + sed $(sed-pasyms) | sort | uniq > $@ 37 + 38 + targets += pasyms.h 39 + $(obj)/pasyms.h: $(REALMODE_OBJS) FORCE 40 + $(call if_changed,pasyms) 41 + 42 + targets += realmode.lds 43 + $(obj)/realmode.lds: $(obj)/pasyms.h 44 + 45 + LDFLAGS_realmode.elf := --emit-relocs -T 46 + CPPFLAGS_realmode.lds += -P -C -I$(obj) 47 + 48 + targets += realmode.elf 49 + $(obj)/realmode.elf: $(obj)/realmode.lds $(REALMODE_OBJS) FORCE 50 + $(call if_changed,ld) 51 + 52 + OBJCOPYFLAGS_realmode.bin := -O binary 53 + 54 + targets += realmode.bin 55 + $(obj)/realmode.bin: $(obj)/realmode.elf $(obj)/realmode.relocs 56 + $(call if_changed,objcopy) 57 + 58 + quiet_cmd_relocs = RELOCS $@ 59 + cmd_relocs = arch/x86/tools/relocs --realmode $< > $@ 60 + 61 + targets += realmode.relocs 62 + $(obj)/realmode.relocs: $(obj)/realmode.elf FORCE 63 + $(call if_changed,relocs) 64 + 65 + # --------------------------------------------------------------------------- 66 + 67 + # How to compile the 16-bit code. Note we always compile for -march=i386, 68 + # that way we can complain to the user if the CPU is insufficient. 69 + KBUILD_CFLAGS := $(LINUXINCLUDE) -m32 -g -Os -D_SETUP -D__KERNEL__ -D_WAKEUP \ 70 + -I$(srctree)/arch/x86/boot \ 71 + -DDISABLE_BRANCH_PROFILING \ 72 + -Wall -Wstrict-prototypes \ 73 + -march=i386 -mregparm=3 \ 74 + -include $(srctree)/$(src)/../../boot/code16gcc.h \ 75 + -fno-strict-aliasing -fomit-frame-pointer \ 76 + $(call cc-option, -ffreestanding) \ 77 + $(call cc-option, -fno-toplevel-reorder,\ 78 + $(call cc-option, -fno-unit-at-a-time)) \ 79 + $(call cc-option, -fno-stack-protector) \ 80 + $(call cc-option, -mpreferred-stack-boundary=2) 81 + KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__ 82 + GCOV_PROFILE := n
+1
arch/x86/realmode/rm/bioscall.S
··· 1 + #include "../../boot/bioscall.S"
+1
arch/x86/realmode/rm/copy.S
··· 1 + #include "../../boot/copy.S"
+41
arch/x86/realmode/rm/header.S
··· 1 + /* 2 + * Real-mode blob header; this should match realmode.h and be 3 + * readonly; for mutable data instead add pointers into the .data 4 + * or .bss sections as appropriate. 5 + */ 6 + 7 + #include <linux/linkage.h> 8 + #include <asm/page_types.h> 9 + 10 + #include "realmode.h" 11 + 12 + .section ".header", "a" 13 + 14 + .balign 16 15 + GLOBAL(real_mode_header) 16 + .long pa_text_start 17 + .long pa_ro_end 18 + /* SMP trampoline */ 19 + .long pa_trampoline_start 20 + .long pa_trampoline_status 21 + .long pa_trampoline_header 22 + #ifdef CONFIG_X86_64 23 + .long pa_trampoline_pgd; 24 + #endif 25 + /* ACPI S3 wakeup */ 26 + #ifdef CONFIG_ACPI_SLEEP 27 + .long pa_wakeup_start 28 + .long pa_wakeup_header 29 + #endif 30 + /* APM/BIOS reboot */ 31 + #ifdef CONFIG_X86_32 32 + .long pa_machine_real_restart_asm 33 + #endif 34 + END(real_mode_header) 35 + 36 + /* End signature, used to verify integrity */ 37 + .section ".signature","a" 38 + .balign 4 39 + GLOBAL(end_signature) 40 + .long REALMODE_END_SIGNATURE 41 + END(end_signature)
+21
arch/x86/realmode/rm/realmode.h
··· 1 + #ifndef ARCH_X86_REALMODE_RM_REALMODE_H 2 + #define ARCH_X86_REALMODE_RM_REALMODE_H 3 + 4 + #ifdef __ASSEMBLY__ 5 + 6 + /* 7 + * 16-bit ljmpw to the real_mode_seg 8 + * 9 + * This must be open-coded since gas will choke on using a 10 + * relocatable symbol for the segment portion. 11 + */ 12 + #define LJMPW_RM(to) .byte 0xea ; .word (to), real_mode_seg 13 + 14 + #endif /* __ASSEMBLY__ */ 15 + 16 + /* 17 + * Signature at the end of the realmode region 18 + */ 19 + #define REALMODE_END_SIGNATURE 0x65a22c82 20 + 21 + #endif /* ARCH_X86_REALMODE_RM_REALMODE_H */
+76
arch/x86/realmode/rm/realmode.lds.S
··· 1 + /* 2 + * realmode.lds.S 3 + * 4 + * Linker script for the real-mode code 5 + */ 6 + 7 + #include <asm/page_types.h> 8 + 9 + #undef i386 10 + 11 + OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") 12 + OUTPUT_ARCH(i386) 13 + 14 + SECTIONS 15 + { 16 + real_mode_seg = 0; 17 + 18 + . = 0; 19 + .header : { 20 + pa_real_mode_base = .; 21 + *(.header) 22 + } 23 + 24 + . = ALIGN(4); 25 + .rodata : { 26 + *(.rodata) 27 + *(.rodata.*) 28 + . = ALIGN(16); 29 + video_cards = .; 30 + *(.videocards) 31 + video_cards_end = .; 32 + } 33 + 34 + . = ALIGN(PAGE_SIZE); 35 + pa_text_start = .; 36 + .text : { 37 + *(.text) 38 + *(.text.*) 39 + } 40 + 41 + .text32 : { 42 + *(.text32) 43 + *(.text32.*) 44 + } 45 + 46 + .text64 : { 47 + *(.text64) 48 + *(.text64.*) 49 + } 50 + pa_ro_end = .; 51 + 52 + . = ALIGN(PAGE_SIZE); 53 + .data : { 54 + *(.data) 55 + *(.data.*) 56 + } 57 + 58 + . = ALIGN(128); 59 + .bss : { 60 + *(.bss*) 61 + } 62 + 63 + /* End signature for integrity checking */ 64 + . = ALIGN(4); 65 + .signature : { 66 + *(.signature) 67 + } 68 + 69 + /DISCARD/ : { 70 + *(.note*) 71 + *(.debug*) 72 + *(.eh_frame*) 73 + } 74 + 75 + #include "pasyms.h" 76 + }
+1
arch/x86/realmode/rm/regs.c
··· 1 + #include "../../boot/regs.c"
+19
arch/x86/realmode/rm/stack.S
··· 1 + /* 2 + * Common heap and stack allocations 3 + */ 4 + 5 + #include <linux/linkage.h> 6 + 7 + .data 8 + GLOBAL(HEAP) 9 + .long rm_heap 10 + GLOBAL(heap_end) 11 + .long rm_stack 12 + 13 + .bss 14 + .balign 16 15 + GLOBAL(rm_heap) 16 + .space 2048 17 + GLOBAL(rm_stack) 18 + .space 2048 19 + GLOBAL(rm_stack_end)
+74
arch/x86/realmode/rm/trampoline_32.S
··· 1 + /* 2 + * 3 + * Trampoline.S Derived from Setup.S by Linus Torvalds 4 + * 5 + * 4 Jan 1997 Michael Chastain: changed to gnu as. 6 + * 7 + * This is only used for booting secondary CPUs in SMP machine 8 + * 9 + * Entry: CS:IP point to the start of our code, we are 10 + * in real mode with no stack, but the rest of the 11 + * trampoline page to make our stack and everything else 12 + * is a mystery. 13 + * 14 + * We jump into arch/x86/kernel/head_32.S. 15 + * 16 + * On entry to trampoline_start, the processor is in real mode 17 + * with 16-bit addressing and 16-bit data. CS has some value 18 + * and IP is zero. Thus, we load CS to the physical segment 19 + * of the real mode code before doing anything further. 20 + */ 21 + 22 + #include <linux/linkage.h> 23 + #include <linux/init.h> 24 + #include <asm/segment.h> 25 + #include <asm/page_types.h> 26 + #include "realmode.h" 27 + 28 + .text 29 + .code16 30 + 31 + .balign PAGE_SIZE 32 + ENTRY(trampoline_start) 33 + wbinvd # Needed for NUMA-Q should be harmless for others 34 + 35 + LJMPW_RM(1f) 36 + 1: 37 + mov %cs, %ax # Code and data in the same place 38 + mov %ax, %ds 39 + 40 + cli # We should be safe anyway 41 + 42 + movl tr_start, %eax # where we need to go 43 + 44 + movl $0xA5A5A5A5, trampoline_status 45 + # write marker for master knows we're running 46 + 47 + /* 48 + * GDT tables in non default location kernel can be beyond 16MB and 49 + * lgdt will not be able to load the address as in real mode default 50 + * operand size is 16bit. Use lgdtl instead to force operand size 51 + * to 32 bit. 52 + */ 53 + lidtl tr_idt # load idt with 0, 0 54 + lgdtl tr_gdt # load gdt with whatever is appropriate 55 + 56 + movw $1, %dx # protected mode (PE) bit 57 + lmsw %dx # into protected mode 58 + 59 + ljmpl $__BOOT_CS, $pa_startup_32 60 + 61 + .section ".text32","ax" 62 + .code32 63 + ENTRY(startup_32) # note: also used from wakeup_asm.S 64 + jmp *%eax 65 + 66 + .bss 67 + .balign 8 68 + GLOBAL(trampoline_header) 69 + tr_start: .space 4 70 + tr_gdt_pad: .space 2 71 + tr_gdt: .space 6 72 + END(trampoline_header) 73 + 74 + #include "trampoline_common.S"
+153
arch/x86/realmode/rm/trampoline_64.S
··· 1 + /* 2 + * 3 + * Trampoline.S Derived from Setup.S by Linus Torvalds 4 + * 5 + * 4 Jan 1997 Michael Chastain: changed to gnu as. 6 + * 15 Sept 2005 Eric Biederman: 64bit PIC support 7 + * 8 + * Entry: CS:IP point to the start of our code, we are 9 + * in real mode with no stack, but the rest of the 10 + * trampoline page to make our stack and everything else 11 + * is a mystery. 12 + * 13 + * On entry to trampoline_start, the processor is in real mode 14 + * with 16-bit addressing and 16-bit data. CS has some value 15 + * and IP is zero. Thus, data addresses need to be absolute 16 + * (no relocation) and are taken with regard to r_base. 17 + * 18 + * With the addition of trampoline_level4_pgt this code can 19 + * now enter a 64bit kernel that lives at arbitrary 64bit 20 + * physical addresses. 21 + * 22 + * If you work on this file, check the object module with objdump 23 + * --full-contents --reloc to make sure there are no relocation 24 + * entries. 25 + */ 26 + 27 + #include <linux/linkage.h> 28 + #include <linux/init.h> 29 + #include <asm/pgtable_types.h> 30 + #include <asm/page_types.h> 31 + #include <asm/msr.h> 32 + #include <asm/segment.h> 33 + #include <asm/processor-flags.h> 34 + #include "realmode.h" 35 + 36 + .text 37 + .code16 38 + 39 + .balign PAGE_SIZE 40 + ENTRY(trampoline_start) 41 + cli # We should be safe anyway 42 + wbinvd 43 + 44 + LJMPW_RM(1f) 45 + 1: 46 + mov %cs, %ax # Code and data in the same place 47 + mov %ax, %ds 48 + mov %ax, %es 49 + mov %ax, %ss 50 + 51 + movl $0xA5A5A5A5, trampoline_status 52 + # write marker for master knows we're running 53 + 54 + # Setup stack 55 + movl $rm_stack_end, %esp 56 + 57 + call verify_cpu # Verify the cpu supports long mode 58 + testl %eax, %eax # Check for return code 59 + jnz no_longmode 60 + 61 + /* 62 + * GDT tables in non default location kernel can be beyond 16MB and 63 + * lgdt will not be able to load the address as in real mode default 64 + * operand size is 16bit. Use lgdtl instead to force operand size 65 + * to 32 bit. 66 + */ 67 + 68 + lidtl tr_idt # load idt with 0, 0 69 + lgdtl tr_gdt # load gdt with whatever is appropriate 70 + 71 + movw $__KERNEL_DS, %dx # Data segment descriptor 72 + 73 + # Enable protected mode 74 + movl $X86_CR0_PE, %eax # protected mode (PE) bit 75 + movl %eax, %cr0 # into protected mode 76 + 77 + # flush prefetch and jump to startup_32 78 + ljmpl $__KERNEL32_CS, $pa_startup_32 79 + 80 + no_longmode: 81 + hlt 82 + jmp no_longmode 83 + #include "../kernel/verify_cpu.S" 84 + 85 + .section ".text32","ax" 86 + .code32 87 + .balign 4 88 + ENTRY(startup_32) 89 + movl %edx, %ss 90 + addl $pa_real_mode_base, %esp 91 + movl %edx, %ds 92 + movl %edx, %es 93 + movl %edx, %fs 94 + movl %edx, %gs 95 + 96 + movl pa_tr_cr4, %eax 97 + movl %eax, %cr4 # Enable PAE mode 98 + 99 + # Setup trampoline 4 level pagetables 100 + movl $pa_trampoline_pgd, %eax 101 + movl %eax, %cr3 102 + 103 + # Set up EFER 104 + movl pa_tr_efer, %eax 105 + movl pa_tr_efer + 4, %edx 106 + movl $MSR_EFER, %ecx 107 + wrmsr 108 + 109 + # Enable paging and in turn activate Long Mode 110 + movl $(X86_CR0_PG | X86_CR0_WP | X86_CR0_PE), %eax 111 + movl %eax, %cr0 112 + 113 + /* 114 + * At this point we're in long mode but in 32bit compatibility mode 115 + * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn 116 + * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use 117 + * the new gdt/idt that has __KERNEL_CS with CS.L = 1. 118 + */ 119 + ljmpl $__KERNEL_CS, $pa_startup_64 120 + 121 + .section ".text64","ax" 122 + .code64 123 + .balign 4 124 + ENTRY(startup_64) 125 + # Now jump into the kernel using virtual addresses 126 + jmpq *tr_start(%rip) 127 + 128 + .section ".rodata","a" 129 + # Duplicate the global descriptor table 130 + # so the kernel can live anywhere 131 + .balign 16 132 + .globl tr_gdt 133 + tr_gdt: 134 + .short tr_gdt_end - tr_gdt - 1 # gdt limit 135 + .long pa_tr_gdt 136 + .short 0 137 + .quad 0x00cf9b000000ffff # __KERNEL32_CS 138 + .quad 0x00af9b000000ffff # __KERNEL_CS 139 + .quad 0x00cf93000000ffff # __KERNEL_DS 140 + tr_gdt_end: 141 + 142 + .bss 143 + .balign PAGE_SIZE 144 + GLOBAL(trampoline_pgd) .space PAGE_SIZE 145 + 146 + .balign 8 147 + GLOBAL(trampoline_header) 148 + tr_start: .space 8 149 + GLOBAL(tr_efer) .space 8 150 + GLOBAL(tr_cr4) .space 4 151 + END(trampoline_header) 152 + 153 + #include "trampoline_common.S"
+7
arch/x86/realmode/rm/trampoline_common.S
··· 1 + .section ".rodata","a" 2 + .balign 16 3 + tr_idt: .fill 1, 6, 0 4 + 5 + .bss 6 + .balign 4 7 + GLOBAL(trampoline_status) .space 4
+1
arch/x86/realmode/rm/video-bios.c
··· 1 + #include "../../boot/video-bios.c"
+1
arch/x86/realmode/rm/video-mode.c
··· 1 + #include "../../boot/video-mode.c"
+1
arch/x86/realmode/rm/video-vesa.c
··· 1 + #include "../../boot/video-vesa.c"
+1
arch/x86/realmode/rm/video-vga.c
··· 1 + #include "../../boot/video-vga.c"
+20
arch/x86/realmode/rmpiggy.S
··· 1 + /* 2 + * Wrapper script for the realmode binary as a transport object 3 + * before copying to low memory. 4 + */ 5 + #include <linux/linkage.h> 6 + #include <asm/page_types.h> 7 + 8 + .section ".init.data","aw" 9 + 10 + .balign PAGE_SIZE 11 + 12 + GLOBAL(real_mode_blob) 13 + .incbin "arch/x86/realmode/rm/realmode.bin" 14 + END(real_mode_blob) 15 + 16 + GLOBAL(real_mode_blob_end); 17 + 18 + GLOBAL(real_mode_relocs) 19 + .incbin "arch/x86/realmode/rm/realmode.relocs" 20 + END(real_mode_relocs)
+7
arch/x86/tools/relocs.c
··· 78 78 79 79 static const char * const sym_regex_realmode[S_NSYMTYPES] = { 80 80 /* 81 + * These symbols are known to be relative, even if the linker marks them 82 + * as absolute (typically defined outside any section in the linker script.) 83 + */ 84 + [S_REL] = 85 + "^pa_", 86 + 87 + /* 81 88 * These are 16-bit segment symbols when compiling 16-bit code. 82 89 */ 83 90 [S_SEG] =
+1
drivers/acpi/bgrt.c
··· 11 11 #include <linux/init.h> 12 12 #include <linux/device.h> 13 13 #include <linux/sysfs.h> 14 + #include <linux/io.h> 14 15 #include <acpi/acpi.h> 15 16 #include <acpi/acpi_bus.h> 16 17
+5 -3
drivers/acpi/sleep.c
··· 25 25 #include <acpi/acpi_bus.h> 26 26 #include <acpi/acpi_drivers.h> 27 27 28 + #include <asm/realmode.h> 29 + 28 30 #include "internal.h" 29 31 #include "sleep.h" 30 32 ··· 93 91 static int acpi_sleep_prepare(u32 acpi_state) 94 92 { 95 93 #ifdef CONFIG_ACPI_SLEEP 94 + unsigned long wakeup_pa = real_mode_header->wakeup_start; 96 95 /* do we have a wakeup address for S2 and S3? */ 97 96 if (acpi_state == ACPI_STATE_S3) { 98 - if (!acpi_wakeup_address) { 97 + if (!wakeup_pa) 99 98 return -EFAULT; 100 - } 101 99 acpi_set_firmware_waking_vector( 102 - (acpi_physical_address)acpi_wakeup_address); 100 + (acpi_physical_address)wakeup_pa); 103 101 104 102 } 105 103 ACPI_FLUSH_CPU_CACHE();
+1
drivers/xen/xen-acpi-processor.c
··· 29 29 #include <acpi/acpi_drivers.h> 30 30 #include <acpi/processor.h> 31 31 32 + #include <xen/xen.h> 32 33 #include <xen/interface/platform.h> 33 34 #include <asm/xen/hypercall.h> 34 35