diff options
59 files changed, 774 insertions, 613 deletions
diff --git a/arch/x86/Kbuild b/arch/x86/Kbuild index 0e9dec6cadd1..e5287d8517aa 100644 --- a/arch/x86/Kbuild +++ b/arch/x86/Kbuild | |||
@@ -1,4 +1,3 @@ | |||
1 | |||
2 | obj-$(CONFIG_KVM) += kvm/ | 1 | obj-$(CONFIG_KVM) += kvm/ |
3 | 2 | ||
4 | # Xen paravirtualization support | 3 | # Xen paravirtualization support |
@@ -7,6 +6,7 @@ obj-$(CONFIG_XEN) += xen/ | |||
7 | # lguest paravirtualization support | 6 | # lguest paravirtualization support |
8 | obj-$(CONFIG_LGUEST_GUEST) += lguest/ | 7 | obj-$(CONFIG_LGUEST_GUEST) += lguest/ |
9 | 8 | ||
9 | obj-y += realmode/ | ||
10 | obj-y += kernel/ | 10 | obj-y += kernel/ |
11 | obj-y += mm/ | 11 | obj-y += mm/ |
12 | 12 | ||
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 @@ | |||
29 | #include <asm/processor.h> | 29 | #include <asm/processor.h> |
30 | #include <asm/mmu.h> | 30 | #include <asm/mmu.h> |
31 | #include <asm/mpspec.h> | 31 | #include <asm/mpspec.h> |
32 | #include <asm/trampoline.h> | ||
33 | 32 | ||
34 | #define COMPILER_DEPENDENT_INT64 long long | 33 | #define COMPILER_DEPENDENT_INT64 long long |
35 | #define COMPILER_DEPENDENT_UINT64 unsigned long long | 34 | #define COMPILER_DEPENDENT_UINT64 unsigned long long |
@@ -118,7 +117,6 @@ static inline void acpi_disable_pci(void) | |||
118 | extern int acpi_suspend_lowlevel(void); | 117 | extern int acpi_suspend_lowlevel(void); |
119 | 118 | ||
120 | extern const unsigned char acpi_wakeup_code[]; | 119 | extern const unsigned char acpi_wakeup_code[]; |
121 | #define acpi_wakeup_address (__pa(TRAMPOLINE_SYM(acpi_wakeup_code))) | ||
122 | 120 | ||
123 | /* early initialization routine */ | 121 | /* early initialization routine */ |
124 | extern void acpi_reserve_wakeup_memory(void); | 122 | extern void acpi_reserve_wakeup_memory(void); |
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 7745b257f035..39bc5777211a 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, | |||
544 | * enable), so that any CPU's that boot up | 544 | * enable), so that any CPU's that boot up |
545 | * after us can get the correct flags. | 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 | static inline void set_in_cr4(unsigned long mask) | 550 | static inline void set_in_cr4(unsigned long mask) |
550 | { | 551 | { |
551 | unsigned long cr4; | 552 | unsigned long cr4; |
552 | 553 | ||
553 | mmu_cr4_features |= mask; | 554 | mmu_cr4_features |= mask; |
555 | if (trampoline_cr4_features) | ||
556 | *trampoline_cr4_features = mmu_cr4_features; | ||
554 | cr4 = read_cr4(); | 557 | cr4 = read_cr4(); |
555 | cr4 |= mask; | 558 | cr4 |= mask; |
556 | write_cr4(cr4); | 559 | write_cr4(cr4); |
@@ -561,6 +564,8 @@ static inline void clear_in_cr4(unsigned long mask) | |||
561 | unsigned long cr4; | 564 | unsigned long cr4; |
562 | 565 | ||
563 | mmu_cr4_features &= ~mask; | 566 | mmu_cr4_features &= ~mask; |
567 | if (trampoline_cr4_features) | ||
568 | *trampoline_cr4_features = mmu_cr4_features; | ||
564 | cr4 = read_cr4(); | 569 | cr4 = read_cr4(); |
565 | cr4 &= ~mask; | 570 | cr4 &= ~mask; |
566 | write_cr4(cr4); | 571 | write_cr4(cr4); |
diff --git a/arch/x86/include/asm/realmode.h b/arch/x86/include/asm/realmode.h new file mode 100644 index 000000000000..fce3f4ae5bd6 --- /dev/null +++ b/arch/x86/include/asm/realmode.h | |||
@@ -0,0 +1,62 @@ | |||
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 */ | ||
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 @@ | |||
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 */ | ||
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 9bba5b79902b..8215e5652d97 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile | |||
@@ -35,7 +35,6 @@ obj-y += tsc.o io_delay.o rtc.o | |||
35 | obj-y += pci-iommu_table.o | 35 | obj-y += pci-iommu_table.o |
36 | obj-y += resource.o | 36 | obj-y += resource.o |
37 | 37 | ||
38 | obj-y += trampoline.o trampoline_$(BITS).o | ||
39 | obj-y += process.o | 38 | obj-y += process.o |
40 | obj-y += i387.o xsave.o | 39 | obj-y += i387.o xsave.o |
41 | obj-y += ptrace.o | 40 | obj-y += ptrace.o |
@@ -48,7 +47,6 @@ obj-$(CONFIG_STACKTRACE) += stacktrace.o | |||
48 | obj-y += cpu/ | 47 | obj-y += cpu/ |
49 | obj-y += acpi/ | 48 | obj-y += acpi/ |
50 | obj-y += reboot.o | 49 | obj-y += reboot.o |
51 | obj-$(CONFIG_X86_32) += reboot_32.o | ||
52 | obj-$(CONFIG_X86_MSR) += msr.o | 50 | obj-$(CONFIG_X86_MSR) += msr.o |
53 | obj-$(CONFIG_X86_CPUID) += cpuid.o | 51 | obj-$(CONFIG_X86_CPUID) += cpuid.o |
54 | obj-$(CONFIG_PCI) += early-quirks.o | 52 | obj-$(CONFIG_PCI) += early-quirks.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 @@ | |||
1 | subdir- := realmode | ||
2 | |||
3 | obj-$(CONFIG_ACPI) += boot.o | 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 | ifneq ($(CONFIG_ACPI_PROCESSOR),) | 4 | ifneq ($(CONFIG_ACPI_PROCESSOR),) |
7 | obj-y += cstate.o | 5 | obj-y += cstate.o |
8 | endif | 6 | endif |
9 | 7 | ||
10 | $(obj)/wakeup_rm.o: $(obj)/realmode/wakeup.bin | ||
11 | |||
12 | $(obj)/realmode/wakeup.bin: FORCE | ||
13 | $(Q)$(MAKE) $(build)=$(obj)/realmode | ||
14 | |||
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 @@ | |||
1 | wakeup.bin | ||
2 | wakeup.elf | ||
3 | 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 @@ | |||
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) | ||
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 @@ | |||
1 | #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 @@ | |||
1 | #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 @@ | |||
1 | #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 @@ | |||
1 | #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 @@ | |||
1 | #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 @@ | |||
1 | #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 @@ | |||
1 | #include "../../../boot/video-vga.c" | ||
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 @@ | |||
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 | } | ||
diff --git a/arch/x86/kernel/acpi/sleep.c b/arch/x86/kernel/acpi/sleep.c index 146a49c763a4..95bf99de9058 100644 --- a/arch/x86/kernel/acpi/sleep.c +++ b/arch/x86/kernel/acpi/sleep.c | |||
@@ -14,8 +14,9 @@ | |||
14 | #include <asm/desc.h> | 14 | #include <asm/desc.h> |
15 | #include <asm/pgtable.h> | 15 | #include <asm/pgtable.h> |
16 | #include <asm/cacheflush.h> | 16 | #include <asm/cacheflush.h> |
17 | #include <asm/realmode.h> | ||
17 | 18 | ||
18 | #include "realmode/wakeup.h" | 19 | #include "../../realmode/rm/wakeup.h" |
19 | #include "sleep.h" | 20 | #include "sleep.h" |
20 | 21 | ||
21 | unsigned long acpi_realmode_flags; | 22 | unsigned long acpi_realmode_flags; |
@@ -36,13 +37,9 @@ asmlinkage void acpi_enter_s3(void) | |||
36 | */ | 37 | */ |
37 | int acpi_suspend_lowlevel(void) | 38 | int acpi_suspend_lowlevel(void) |
38 | { | 39 | { |
39 | struct wakeup_header *header; | 40 | struct wakeup_header *header = |
40 | /* address in low memory of the wakeup routine. */ | 41 | (struct wakeup_header *) __va(real_mode_header->wakeup_header); |
41 | char *acpi_realmode; | ||
42 | 42 | ||
43 | acpi_realmode = TRAMPOLINE_SYM(acpi_wakeup_code); | ||
44 | |||
45 | header = (struct wakeup_header *)(acpi_realmode + WAKEUP_HEADER_OFFSET); | ||
46 | if (header->signature != WAKEUP_HEADER_SIGNATURE) { | 43 | if (header->signature != WAKEUP_HEADER_SIGNATURE) { |
47 | printk(KERN_ERR "wakeup header does not match\n"); | 44 | printk(KERN_ERR "wakeup header does not match\n"); |
48 | return -EINVAL; | 45 | return -EINVAL; |
@@ -50,27 +47,6 @@ int acpi_suspend_lowlevel(void) | |||
50 | 47 | ||
51 | header->video_mode = saved_video_mode; | 48 | header->video_mode = saved_video_mode; |
52 | 49 | ||
53 | header->wakeup_jmp_seg = acpi_wakeup_address >> 4; | ||
54 | |||
55 | /* | ||
56 | * Set up the wakeup GDT. We set these up as Big Real Mode, | ||
57 | * that is, with limits set to 4 GB. At least the Lenovo | ||
58 | * Thinkpad X61 is known to need this for the video BIOS | ||
59 | * initialization quirk to work; this is likely to also | ||
60 | * be the case for other laptops or integrated video devices. | ||
61 | */ | ||
62 | |||
63 | /* GDT[0]: GDT self-pointer */ | ||
64 | header->wakeup_gdt[0] = | ||
65 | (u64)(sizeof(header->wakeup_gdt) - 1) + | ||
66 | ((u64)__pa(&header->wakeup_gdt) << 16); | ||
67 | /* GDT[1]: big real mode-like code segment */ | ||
68 | header->wakeup_gdt[1] = | ||
69 | GDT_ENTRY(0x809b, acpi_wakeup_address, 0xfffff); | ||
70 | /* GDT[2]: big real mode-like data segment */ | ||
71 | header->wakeup_gdt[2] = | ||
72 | GDT_ENTRY(0x8093, acpi_wakeup_address, 0xfffff); | ||
73 | |||
74 | #ifndef CONFIG_64BIT | 50 | #ifndef CONFIG_64BIT |
75 | store_gdt((struct desc_ptr *)&header->pmode_gdt); | 51 | store_gdt((struct desc_ptr *)&header->pmode_gdt); |
76 | 52 | ||
@@ -95,7 +71,6 @@ int acpi_suspend_lowlevel(void) | |||
95 | header->pmode_cr3 = (u32)__pa(&initial_page_table); | 71 | header->pmode_cr3 = (u32)__pa(&initial_page_table); |
96 | saved_magic = 0x12345678; | 72 | saved_magic = 0x12345678; |
97 | #else /* CONFIG_64BIT */ | 73 | #else /* CONFIG_64BIT */ |
98 | header->trampoline_segment = trampoline_address() >> 4; | ||
99 | #ifdef CONFIG_SMP | 74 | #ifdef CONFIG_SMP |
100 | stack_start = (unsigned long)temp_stack + sizeof(temp_stack); | 75 | stack_start = (unsigned long)temp_stack + sizeof(temp_stack); |
101 | early_gdt_descr.address = | 76 | 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 @@ | |||
2 | * Variables and functions used by the code in sleep.c | 2 | * Variables and functions used by the code in sleep.c |
3 | */ | 3 | */ |
4 | 4 | ||
5 | #include <asm/trampoline.h> | ||
6 | #include <linux/linkage.h> | 5 | #include <linux/linkage.h> |
6 | #include <asm/realmode.h> | ||
7 | 7 | ||
8 | extern unsigned long saved_video_mode; | 8 | extern unsigned long saved_video_mode; |
9 | extern long saved_magic; | 9 | 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 @@ | |||
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 | ||
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 @@ | |||
14 | #include <asm/sections.h> | 14 | #include <asm/sections.h> |
15 | #include <asm/e820.h> | 15 | #include <asm/e820.h> |
16 | #include <asm/page.h> | 16 | #include <asm/page.h> |
17 | #include <asm/trampoline.h> | ||
18 | #include <asm/apic.h> | 17 | #include <asm/apic.h> |
19 | #include <asm/io_apic.h> | 18 | #include <asm/io_apic.h> |
20 | #include <asm/bios_ebda.h> | 19 | #include <asm/bios_ebda.h> |
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 @@ | |||
24 | #include <asm/sections.h> | 24 | #include <asm/sections.h> |
25 | #include <asm/kdebug.h> | 25 | #include <asm/kdebug.h> |
26 | #include <asm/e820.h> | 26 | #include <asm/e820.h> |
27 | #include <asm/trampoline.h> | ||
28 | #include <asm/bios_ebda.h> | 27 | #include <asm/bios_ebda.h> |
29 | 28 | ||
30 | static void __init zap_identity_mappings(void) | 29 | static void __init zap_identity_mappings(void) |
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S index 463c9797ca6a..d42ab17b7397 100644 --- a/arch/x86/kernel/head_32.S +++ b/arch/x86/kernel/head_32.S | |||
@@ -274,10 +274,7 @@ num_subarch_entries = (. - subarch_entries) / 4 | |||
274 | * If cpu hotplug is not supported then this code can go in init section | 274 | * If cpu hotplug is not supported then this code can go in init section |
275 | * which will be freed later | 275 | * which will be freed later |
276 | */ | 276 | */ |
277 | |||
278 | __CPUINIT | 277 | __CPUINIT |
279 | |||
280 | #ifdef CONFIG_SMP | ||
281 | ENTRY(startup_32_smp) | 278 | ENTRY(startup_32_smp) |
282 | cld | 279 | cld |
283 | movl $(__BOOT_DS),%eax | 280 | movl $(__BOOT_DS),%eax |
@@ -288,7 +285,7 @@ ENTRY(startup_32_smp) | |||
288 | movl pa(stack_start),%ecx | 285 | movl pa(stack_start),%ecx |
289 | movl %eax,%ss | 286 | movl %eax,%ss |
290 | leal -__PAGE_OFFSET(%ecx),%esp | 287 | leal -__PAGE_OFFSET(%ecx),%esp |
291 | #endif /* CONFIG_SMP */ | 288 | |
292 | default_entry: | 289 | default_entry: |
293 | 290 | ||
294 | /* | 291 | /* |
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index 7a40f2447321..94bf9cc2c7ee 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S | |||
@@ -139,10 +139,6 @@ ident_complete: | |||
139 | /* Fixup phys_base */ | 139 | /* Fixup phys_base */ |
140 | addq %rbp, phys_base(%rip) | 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 | /* Due to ENTRY(), sometimes the empty space gets filled with | 142 | /* Due to ENTRY(), sometimes the empty space gets filled with |
147 | * zeros. Better take a jmp than relying on empty space being | 143 | * zeros. Better take a jmp than relying on empty space being |
148 | * filled with 0x90 (nop) | 144 | * filled with 0x90 (nop) |
diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c index fbca2e6223bf..d2b56489d70f 100644 --- a/arch/x86/kernel/mpparse.c +++ b/arch/x86/kernel/mpparse.c | |||
@@ -27,7 +27,6 @@ | |||
27 | #include <asm/proto.h> | 27 | #include <asm/proto.h> |
28 | #include <asm/bios_ebda.h> | 28 | #include <asm/bios_ebda.h> |
29 | #include <asm/e820.h> | 29 | #include <asm/e820.h> |
30 | #include <asm/trampoline.h> | ||
31 | #include <asm/setup.h> | 30 | #include <asm/setup.h> |
32 | #include <asm/smp.h> | 31 | #include <asm/smp.h> |
33 | 32 | ||
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 77215c23fba1..79c45af81604 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #ifdef CONFIG_X86_32 | 24 | #ifdef CONFIG_X86_32 |
25 | # include <linux/ctype.h> | 25 | # include <linux/ctype.h> |
26 | # include <linux/mc146818rtc.h> | 26 | # include <linux/mc146818rtc.h> |
27 | # include <asm/realmode.h> | ||
27 | #else | 28 | #else |
28 | # include <asm/x86_init.h> | 29 | # include <asm/x86_init.h> |
29 | #endif | 30 | #endif |
@@ -156,15 +157,10 @@ static int __init set_bios_reboot(const struct dmi_system_id *d) | |||
156 | return 0; | 157 | return 0; |
157 | } | 158 | } |
158 | 159 | ||
159 | extern const unsigned char machine_real_restart_asm[]; | ||
160 | extern const u64 machine_real_restart_gdt[3]; | ||
161 | |||
162 | void machine_real_restart(unsigned int type) | 160 | void machine_real_restart(unsigned int type) |
163 | { | 161 | { |
164 | void *restart_va; | 162 | void (*restart_lowmem)(unsigned int) = (void (*)(unsigned int)) |
165 | unsigned long restart_pa; | 163 | real_mode_header->machine_real_restart_asm; |
166 | void (*restart_lowmem)(unsigned int); | ||
167 | u64 *lowmem_gdt; | ||
168 | 164 | ||
169 | local_irq_disable(); | 165 | local_irq_disable(); |
170 | 166 | ||
@@ -195,21 +191,6 @@ void machine_real_restart(unsigned int type) | |||
195 | * too. */ | 191 | * too. */ |
196 | *((unsigned short *)0x472) = reboot_mode; | 192 | *((unsigned short *)0x472) = reboot_mode; |
197 | 193 | ||
198 | /* Patch the GDT in the low memory trampoline */ | ||
199 | lowmem_gdt = TRAMPOLINE_SYM(machine_real_restart_gdt); | ||
200 | |||
201 | restart_va = TRAMPOLINE_SYM(machine_real_restart_asm); | ||
202 | restart_pa = virt_to_phys(restart_va); | ||
203 | restart_lowmem = (void (*)(unsigned int))restart_pa; | ||
204 | |||
205 | /* GDT[0]: GDT self-pointer */ | ||
206 | lowmem_gdt[0] = | ||
207 | (u64)(sizeof(machine_real_restart_gdt) - 1) + | ||
208 | ((u64)virt_to_phys(lowmem_gdt) << 16); | ||
209 | /* GDT[1]: 64K real mode code segment */ | ||
210 | lowmem_gdt[1] = | ||
211 | GDT_ENTRY(0x009b, restart_pa, 0xffff); | ||
212 | |||
213 | /* Jump to the identity-mapped low memory code */ | 194 | /* Jump to the identity-mapped low memory code */ |
214 | restart_lowmem(type); | 195 | restart_lowmem(type); |
215 | } | 196 | } |
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 982e44f960db..16be6dc14db1 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c | |||
@@ -73,7 +73,7 @@ | |||
73 | 73 | ||
74 | #include <asm/mtrr.h> | 74 | #include <asm/mtrr.h> |
75 | #include <asm/apic.h> | 75 | #include <asm/apic.h> |
76 | #include <asm/trampoline.h> | 76 | #include <asm/realmode.h> |
77 | #include <asm/e820.h> | 77 | #include <asm/e820.h> |
78 | #include <asm/mpspec.h> | 78 | #include <asm/mpspec.h> |
79 | #include <asm/setup.h> | 79 | #include <asm/setup.h> |
@@ -909,7 +909,7 @@ void __init setup_arch(char **cmdline_p) | |||
909 | printk(KERN_DEBUG "initial memory mapped: [mem 0x00000000-%#010lx]\n", | 909 | printk(KERN_DEBUG "initial memory mapped: [mem 0x00000000-%#010lx]\n", |
910 | (max_pfn_mapped<<PAGE_SHIFT) - 1); | 910 | (max_pfn_mapped<<PAGE_SHIFT) - 1); |
911 | 911 | ||
912 | setup_trampolines(); | 912 | setup_real_mode(); |
913 | 913 | ||
914 | init_gbpages(); | 914 | init_gbpages(); |
915 | 915 | ||
@@ -968,6 +968,8 @@ void __init setup_arch(char **cmdline_p) | |||
968 | if (boot_cpu_data.cpuid_level >= 0) { | 968 | if (boot_cpu_data.cpuid_level >= 0) { |
969 | /* A CPU has %cr4 if and only if it has CPUID */ | 969 | /* A CPU has %cr4 if and only if it has CPUID */ |
970 | mmu_cr4_features = read_cr4(); | 970 | mmu_cr4_features = read_cr4(); |
971 | if (trampoline_cr4_features) | ||
972 | *trampoline_cr4_features = mmu_cr4_features; | ||
971 | } | 973 | } |
972 | 974 | ||
973 | #ifdef CONFIG_X86_32 | 975 | #ifdef CONFIG_X86_32 |
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 433529e29be4..f56f96da77f5 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c | |||
@@ -57,7 +57,7 @@ | |||
57 | #include <asm/nmi.h> | 57 | #include <asm/nmi.h> |
58 | #include <asm/irq.h> | 58 | #include <asm/irq.h> |
59 | #include <asm/idle.h> | 59 | #include <asm/idle.h> |
60 | #include <asm/trampoline.h> | 60 | #include <asm/realmode.h> |
61 | #include <asm/cpu.h> | 61 | #include <asm/cpu.h> |
62 | #include <asm/numa.h> | 62 | #include <asm/numa.h> |
63 | #include <asm/pgtable.h> | 63 | #include <asm/pgtable.h> |
@@ -73,6 +73,8 @@ | |||
73 | #include <asm/smpboot_hooks.h> | 73 | #include <asm/smpboot_hooks.h> |
74 | #include <asm/i8259.h> | 74 | #include <asm/i8259.h> |
75 | 75 | ||
76 | #include <asm/realmode.h> | ||
77 | |||
76 | /* State of each CPU */ | 78 | /* State of each CPU */ |
77 | DEFINE_PER_CPU(int, cpu_state) = { 0 }; | 79 | DEFINE_PER_CPU(int, cpu_state) = { 0 }; |
78 | 80 | ||
@@ -660,8 +662,12 @@ static void __cpuinit announce_cpu(int cpu, int apicid) | |||
660 | */ | 662 | */ |
661 | static int __cpuinit do_boot_cpu(int apicid, int cpu, struct task_struct *idle) | 663 | static int __cpuinit do_boot_cpu(int apicid, int cpu, struct task_struct *idle) |
662 | { | 664 | { |
665 | volatile u32 *trampoline_status = | ||
666 | (volatile u32 *) __va(real_mode_header->trampoline_status); | ||
667 | /* start_ip had better be page-aligned! */ | ||
668 | unsigned long start_ip = real_mode_header->trampoline_start; | ||
669 | |||
663 | unsigned long boot_error = 0; | 670 | unsigned long boot_error = 0; |
664 | unsigned long start_ip; | ||
665 | int timeout; | 671 | int timeout; |
666 | 672 | ||
667 | alternatives_smp_switch(1); | 673 | alternatives_smp_switch(1); |
@@ -684,9 +690,6 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu, struct task_struct *idle) | |||
684 | initial_code = (unsigned long)start_secondary; | 690 | initial_code = (unsigned long)start_secondary; |
685 | stack_start = idle->thread.sp; | 691 | stack_start = idle->thread.sp; |
686 | 692 | ||
687 | /* start_ip had better be page-aligned! */ | ||
688 | start_ip = trampoline_address(); | ||
689 | |||
690 | /* So we see what's up */ | 693 | /* So we see what's up */ |
691 | announce_cpu(cpu, apicid); | 694 | announce_cpu(cpu, apicid); |
692 | 695 | ||
@@ -749,8 +752,7 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu, struct task_struct *idle) | |||
749 | pr_debug("CPU%d: has booted.\n", cpu); | 752 | pr_debug("CPU%d: has booted.\n", cpu); |
750 | } else { | 753 | } else { |
751 | boot_error = 1; | 754 | boot_error = 1; |
752 | if (*(volatile u32 *)TRAMPOLINE_SYM(trampoline_status) | 755 | if (*trampoline_status == 0xA5A5A5A5) |
753 | == 0xA5A5A5A5) | ||
754 | /* trampoline started but...? */ | 756 | /* trampoline started but...? */ |
755 | pr_err("CPU%d: Stuck ??\n", cpu); | 757 | pr_err("CPU%d: Stuck ??\n", cpu); |
756 | else | 758 | else |
@@ -776,7 +778,7 @@ static int __cpuinit do_boot_cpu(int apicid, int cpu, struct task_struct *idle) | |||
776 | } | 778 | } |
777 | 779 | ||
778 | /* mark "stuck" area as not stuck */ | 780 | /* mark "stuck" area as not stuck */ |
779 | *(volatile u32 *)TRAMPOLINE_SYM(trampoline_status) = 0; | 781 | *trampoline_status = 0; |
780 | 782 | ||
781 | if (get_uv_system_type() != UV_NON_UNIQUE_APIC) { | 783 | if (get_uv_system_type() != UV_NON_UNIQUE_APIC) { |
782 | /* | 784 | /* |
diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c index 6410744ac5cb..f84fe00fad48 100644 --- a/arch/x86/kernel/tboot.c +++ b/arch/x86/kernel/tboot.c | |||
@@ -32,7 +32,7 @@ | |||
32 | #include <linux/mm.h> | 32 | #include <linux/mm.h> |
33 | #include <linux/tboot.h> | 33 | #include <linux/tboot.h> |
34 | 34 | ||
35 | #include <asm/trampoline.h> | 35 | #include <asm/realmode.h> |
36 | #include <asm/processor.h> | 36 | #include <asm/processor.h> |
37 | #include <asm/bootparam.h> | 37 | #include <asm/bootparam.h> |
38 | #include <asm/pgtable.h> | 38 | #include <asm/pgtable.h> |
@@ -44,7 +44,7 @@ | |||
44 | #include <asm/e820.h> | 44 | #include <asm/e820.h> |
45 | #include <asm/io.h> | 45 | #include <asm/io.h> |
46 | 46 | ||
47 | #include "acpi/realmode/wakeup.h" | 47 | #include "../realmode/rm/wakeup.h" |
48 | 48 | ||
49 | /* Global pointer to shared data; NULL means no measured launch. */ | 49 | /* Global pointer to shared data; NULL means no measured launch. */ |
50 | struct tboot *tboot __read_mostly; | 50 | struct tboot *tboot __read_mostly; |
@@ -201,7 +201,8 @@ static int tboot_setup_sleep(void) | |||
201 | add_mac_region(e820.map[i].addr, e820.map[i].size); | 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 | return 0; | 207 | return 0; |
207 | } | 208 | } |
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 @@ | |||
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); | ||
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 @@ | |||
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 */ | ||
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 | |||
197 | 197 | ||
198 | INIT_DATA_SECTION(16) | 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 | .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) { | 200 | .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) { |
213 | __x86_cpu_dev_start = .; | 201 | __x86_cpu_dev_start = .; |
214 | *(.x86_cpu_dev.init) | 202 | *(.x86_cpu_dev.init) |
diff --git a/arch/x86/realmode/Makefile b/arch/x86/realmode/Makefile new file mode 100644 index 000000000000..94f7fbe97b08 --- /dev/null +++ b/arch/x86/realmode/Makefile | |||
@@ -0,0 +1,18 @@ | |||
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 $@ | ||
diff --git a/arch/x86/realmode/init.c b/arch/x86/realmode/init.c new file mode 100644 index 000000000000..cbca565af5bd --- /dev/null +++ b/arch/x86/realmode/init.c | |||
@@ -0,0 +1,115 @@ | |||
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); | ||
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 @@ | |||
1 | pasyms.h | ||
2 | realmode.lds | ||
3 | realmode.relocs | ||
diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile new file mode 100644 index 000000000000..5b84a2d30888 --- /dev/null +++ b/arch/x86/realmode/rm/Makefile | |||
@@ -0,0 +1,82 @@ | |||
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 | ||
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/header.S b/arch/x86/realmode/rm/header.S new file mode 100644 index 000000000000..fadf48378ada --- /dev/null +++ b/arch/x86/realmode/rm/header.S | |||
@@ -0,0 +1,41 @@ | |||
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) | ||
diff --git a/arch/x86/realmode/rm/realmode.h b/arch/x86/realmode/rm/realmode.h new file mode 100644 index 000000000000..d74cff6350ed --- /dev/null +++ b/arch/x86/realmode/rm/realmode.h | |||
@@ -0,0 +1,21 @@ | |||
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 */ | ||
diff --git a/arch/x86/realmode/rm/realmode.lds.S b/arch/x86/realmode/rm/realmode.lds.S new file mode 100644 index 000000000000..86b2e8d6b1f1 --- /dev/null +++ b/arch/x86/realmode/rm/realmode.lds.S | |||
@@ -0,0 +1,76 @@ | |||
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 | } | ||
diff --git a/arch/x86/kernel/reboot_32.S b/arch/x86/realmode/rm/reboot_32.S index 1d5c46df0d78..114044876b3d 100644 --- a/arch/x86/kernel/reboot_32.S +++ b/arch/x86/realmode/rm/reboot_32.S | |||
@@ -2,6 +2,7 @@ | |||
2 | #include <linux/init.h> | 2 | #include <linux/init.h> |
3 | #include <asm/segment.h> | 3 | #include <asm/segment.h> |
4 | #include <asm/page_types.h> | 4 | #include <asm/page_types.h> |
5 | #include "realmode.h" | ||
5 | 6 | ||
6 | /* | 7 | /* |
7 | * The following code and data reboots the machine by switching to real | 8 | * The following code and data reboots the machine by switching to real |
@@ -13,34 +14,20 @@ | |||
13 | * | 14 | * |
14 | * This code is called with the restart type (0 = BIOS, 1 = APM) in %eax. | 15 | * This code is called with the restart type (0 = BIOS, 1 = APM) in %eax. |
15 | */ | 16 | */ |
16 | .section ".x86_trampoline","a" | 17 | .section ".text32", "ax" |
17 | .balign 16 | ||
18 | .code32 | 18 | .code32 |
19 | ENTRY(machine_real_restart_asm) | ||
20 | r_base = . | ||
21 | /* Get our own relocated address */ | ||
22 | call 1f | ||
23 | 1: popl %ebx | ||
24 | subl $(1b - r_base), %ebx | ||
25 | |||
26 | /* Compute the equivalent real-mode segment */ | ||
27 | movl %ebx, %ecx | ||
28 | shrl $4, %ecx | ||
29 | |||
30 | /* Patch post-real-mode segment jump */ | ||
31 | movw (dispatch_table - r_base)(%ebx,%eax,2),%ax | ||
32 | movw %ax, (101f - r_base)(%ebx) | ||
33 | movw %cx, (102f - r_base)(%ebx) | ||
34 | 19 | ||
20 | .balign 16 | ||
21 | ENTRY(machine_real_restart_asm) | ||
35 | /* Set up the IDT for real mode. */ | 22 | /* Set up the IDT for real mode. */ |
36 | lidtl (machine_real_restart_idt - r_base)(%ebx) | 23 | lidtl pa_machine_real_restart_idt |
37 | 24 | ||
38 | /* | 25 | /* |
39 | * Set up a GDT from which we can load segment descriptors for real | 26 | * Set up a GDT from which we can load segment descriptors for real |
40 | * mode. The GDT is not used in real mode; it is just needed here to | 27 | * mode. The GDT is not used in real mode; it is just needed here to |
41 | * prepare the descriptors. | 28 | * prepare the descriptors. |
42 | */ | 29 | */ |
43 | lgdtl (machine_real_restart_gdt - r_base)(%ebx) | 30 | lgdtl pa_machine_real_restart_gdt |
44 | 31 | ||
45 | /* | 32 | /* |
46 | * Load the data segment registers with 16-bit compatible values | 33 | * Load the data segment registers with 16-bit compatible values |
@@ -51,7 +38,7 @@ r_base = . | |||
51 | movl %ecx, %fs | 38 | movl %ecx, %fs |
52 | movl %ecx, %gs | 39 | movl %ecx, %gs |
53 | movl %ecx, %ss | 40 | movl %ecx, %ss |
54 | ljmpl $8, $1f - r_base | 41 | ljmpw $8, $1f |
55 | 42 | ||
56 | /* | 43 | /* |
57 | * This is 16-bit protected mode code to disable paging and the cache, | 44 | * This is 16-bit protected mode code to disable paging and the cache, |
@@ -76,27 +63,29 @@ r_base = . | |||
76 | * | 63 | * |
77 | * Most of this work is probably excessive, but it is what is tested. | 64 | * Most of this work is probably excessive, but it is what is tested. |
78 | */ | 65 | */ |
66 | .text | ||
79 | .code16 | 67 | .code16 |
68 | |||
69 | .balign 16 | ||
70 | machine_real_restart_asm16: | ||
80 | 1: | 71 | 1: |
81 | xorl %ecx, %ecx | 72 | xorl %ecx, %ecx |
82 | movl %cr0, %eax | 73 | movl %cr0, %edx |
83 | andl $0x00000011, %eax | 74 | andl $0x00000011, %edx |
84 | orl $0x60000000, %eax | 75 | orl $0x60000000, %edx |
85 | movl %eax, %cr0 | 76 | movl %edx, %cr0 |
86 | movl %ecx, %cr3 | 77 | movl %ecx, %cr3 |
87 | movl %cr0, %edx | 78 | movl %cr0, %edx |
88 | andl $0x60000000, %edx /* If no cache bits -> no wbinvd */ | 79 | testl $0x60000000, %edx /* If no cache bits -> no wbinvd */ |
89 | jz 2f | 80 | jz 2f |
90 | wbinvd | 81 | wbinvd |
91 | 2: | 82 | 2: |
92 | andb $0x10, %al | 83 | andb $0x10, %dl |
93 | movl %eax, %cr0 | 84 | movl %edx, %cr0 |
94 | .byte 0xea /* ljmpw */ | 85 | LJMPW_RM(3f) |
95 | 101: .word 0 /* Offset */ | 86 | 3: |
96 | 102: .word 0 /* Segment */ | 87 | andw %ax, %ax |
97 | 88 | jz bios | |
98 | bios: | ||
99 | ljmpw $0xf000, $0xfff0 | ||
100 | 89 | ||
101 | apm: | 90 | apm: |
102 | movw $0x1000, %ax | 91 | movw $0x1000, %ax |
@@ -106,26 +95,34 @@ apm: | |||
106 | movw $0x0001, %bx | 95 | movw $0x0001, %bx |
107 | movw $0x0003, %cx | 96 | movw $0x0003, %cx |
108 | int $0x15 | 97 | int $0x15 |
98 | /* This should never return... */ | ||
109 | 99 | ||
110 | END(machine_real_restart_asm) | 100 | bios: |
101 | ljmpw $0xf000, $0xfff0 | ||
111 | 102 | ||
112 | .balign 16 | 103 | .section ".rodata", "a" |
113 | /* These must match <asm/reboot.h */ | ||
114 | dispatch_table: | ||
115 | .word bios - r_base | ||
116 | .word apm - r_base | ||
117 | END(dispatch_table) | ||
118 | 104 | ||
119 | .balign 16 | 105 | .balign 16 |
120 | machine_real_restart_idt: | 106 | GLOBAL(machine_real_restart_idt) |
121 | .word 0xffff /* Length - real mode default value */ | 107 | .word 0xffff /* Length - real mode default value */ |
122 | .long 0 /* Base - real mode default value */ | 108 | .long 0 /* Base - real mode default value */ |
123 | END(machine_real_restart_idt) | 109 | END(machine_real_restart_idt) |
124 | 110 | ||
125 | .balign 16 | 111 | .balign 16 |
126 | ENTRY(machine_real_restart_gdt) | 112 | GLOBAL(machine_real_restart_gdt) |
127 | .quad 0 /* Self-pointer, filled in by PM code */ | 113 | /* Self-pointer */ |
128 | .quad 0 /* 16-bit code segment, filled in by PM code */ | 114 | .word 0xffff /* Length - real mode default value */ |
115 | .long pa_machine_real_restart_gdt | ||
116 | .word 0 | ||
117 | |||
118 | /* | ||
119 | * 16-bit code segment pointing to real_mode_seg | ||
120 | * Selector value 8 | ||
121 | */ | ||
122 | .word 0xffff /* Limit */ | ||
123 | .long 0x9b000000 + pa_real_mode_base | ||
124 | .word 0 | ||
125 | |||
129 | /* | 126 | /* |
130 | * 16-bit data segment with the selector value 16 = 0x10 and | 127 | * 16-bit data segment with the selector value 16 = 0x10 and |
131 | * base value 0x100; since this is consistent with real mode | 128 | * base value 0x100; since this is consistent with real mode |
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/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 @@ | |||
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) | ||
diff --git a/arch/x86/realmode/rm/trampoline_32.S b/arch/x86/realmode/rm/trampoline_32.S new file mode 100644 index 000000000000..c1b2791183e7 --- /dev/null +++ b/arch/x86/realmode/rm/trampoline_32.S | |||
@@ -0,0 +1,74 @@ | |||
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" | ||
diff --git a/arch/x86/kernel/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S index 09ff51799e96..bb360dc39d21 100644 --- a/arch/x86/kernel/trampoline_64.S +++ b/arch/x86/realmode/rm/trampoline_64.S | |||
@@ -5,12 +5,12 @@ | |||
5 | * 4 Jan 1997 Michael Chastain: changed to gnu as. | 5 | * 4 Jan 1997 Michael Chastain: changed to gnu as. |
6 | * 15 Sept 2005 Eric Biederman: 64bit PIC support | 6 | * 15 Sept 2005 Eric Biederman: 64bit PIC support |
7 | * | 7 | * |
8 | * Entry: CS:IP point to the start of our code, we are | 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 | 9 | * in real mode with no stack, but the rest of the |
10 | * trampoline page to make our stack and everything else | 10 | * trampoline page to make our stack and everything else |
11 | * is a mystery. | 11 | * is a mystery. |
12 | * | 12 | * |
13 | * On entry to trampoline_data, the processor is in real mode | 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 | 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 | 15 | * and IP is zero. Thus, data addresses need to be absolute |
16 | * (no relocation) and are taken with regard to r_base. | 16 | * (no relocation) and are taken with regard to r_base. |
@@ -31,43 +31,33 @@ | |||
31 | #include <asm/msr.h> | 31 | #include <asm/msr.h> |
32 | #include <asm/segment.h> | 32 | #include <asm/segment.h> |
33 | #include <asm/processor-flags.h> | 33 | #include <asm/processor-flags.h> |
34 | #include "realmode.h" | ||
34 | 35 | ||
35 | .section ".x86_trampoline","a" | 36 | .text |
36 | .balign PAGE_SIZE | ||
37 | .code16 | 37 | .code16 |
38 | 38 | ||
39 | ENTRY(trampoline_data) | 39 | .balign PAGE_SIZE |
40 | r_base = . | 40 | ENTRY(trampoline_start) |
41 | cli # We should be safe anyway | 41 | cli # We should be safe anyway |
42 | wbinvd | 42 | wbinvd |
43 | |||
44 | LJMPW_RM(1f) | ||
45 | 1: | ||
43 | mov %cs, %ax # Code and data in the same place | 46 | mov %cs, %ax # Code and data in the same place |
44 | mov %ax, %ds | 47 | mov %ax, %ds |
45 | mov %ax, %es | 48 | mov %ax, %es |
46 | mov %ax, %ss | 49 | mov %ax, %ss |
47 | 50 | ||
51 | movl $0xA5A5A5A5, trampoline_status | ||
52 | # write marker for master knows we're running | ||
48 | 53 | ||
49 | movl $0xA5A5A5A5, trampoline_status - r_base | 54 | # Setup stack |
50 | # write marker for master knows we're running | 55 | movl $rm_stack_end, %esp |
51 | |||
52 | # Setup stack | ||
53 | movw $(trampoline_stack_end - r_base), %sp | ||
54 | 56 | ||
55 | call verify_cpu # Verify the cpu supports long mode | 57 | call verify_cpu # Verify the cpu supports long mode |
56 | testl %eax, %eax # Check for return code | 58 | testl %eax, %eax # Check for return code |
57 | jnz no_longmode | 59 | jnz no_longmode |
58 | 60 | ||
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 | /* | 61 | /* |
72 | * GDT tables in non default location kernel can be beyond 16MB and | 62 | * 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 | 63 | * lgdt will not be able to load the address as in real mode default |
@@ -75,36 +65,49 @@ r_base = . | |||
75 | * to 32 bit. | 65 | * to 32 bit. |
76 | */ | 66 | */ |
77 | 67 | ||
78 | lidtl tidt - r_base # load idt with 0, 0 | 68 | lidtl tr_idt # load idt with 0, 0 |
79 | lgdtl tgdt - r_base # load gdt with whatever is appropriate | 69 | lgdtl tr_gdt # load gdt with whatever is appropriate |
70 | |||
71 | movw $__KERNEL_DS, %dx # Data segment descriptor | ||
80 | 72 | ||
81 | mov $X86_CR0_PE, %ax # protected mode (PE) bit | 73 | # Enable protected mode |
82 | lmsw %ax # into protected mode | 74 | movl $X86_CR0_PE, %eax # protected mode (PE) bit |
75 | movl %eax, %cr0 # into protected mode | ||
83 | 76 | ||
84 | # flush prefetch and jump to startup_32 | 77 | # flush prefetch and jump to startup_32 |
85 | ljmpl *(startup_32_vector - r_base) | 78 | ljmpl $__KERNEL32_CS, $pa_startup_32 |
86 | 79 | ||
80 | no_longmode: | ||
81 | hlt | ||
82 | jmp no_longmode | ||
83 | #include "../kernel/verify_cpu.S" | ||
84 | |||
85 | .section ".text32","ax" | ||
87 | .code32 | 86 | .code32 |
88 | .balign 4 | 87 | .balign 4 |
89 | startup_32: | 88 | ENTRY(startup_32) |
90 | movl $__KERNEL_DS, %eax # Initialize the %ds segment register | 89 | movl %edx, %ss |
91 | movl %eax, %ds | 90 | addl $pa_real_mode_base, %esp |
92 | 91 | movl %edx, %ds | |
93 | movl $X86_CR4_PAE, %eax | 92 | movl %edx, %es |
93 | movl %edx, %fs | ||
94 | movl %edx, %gs | ||
95 | |||
96 | movl pa_tr_cr4, %eax | ||
94 | movl %eax, %cr4 # Enable PAE mode | 97 | movl %eax, %cr4 # Enable PAE mode |
95 | 98 | ||
96 | # Setup trampoline 4 level pagetables | 99 | # Setup trampoline 4 level pagetables |
97 | leal (trampoline_level4_pgt - r_base)(%esi), %eax | 100 | movl $pa_trampoline_pgd, %eax |
98 | movl %eax, %cr3 | 101 | movl %eax, %cr3 |
99 | 102 | ||
103 | # Set up EFER | ||
104 | movl pa_tr_efer, %eax | ||
105 | movl pa_tr_efer + 4, %edx | ||
100 | movl $MSR_EFER, %ecx | 106 | movl $MSR_EFER, %ecx |
101 | movl $(1 << _EFER_LME), %eax # Enable Long Mode | ||
102 | xorl %edx, %edx | ||
103 | wrmsr | 107 | wrmsr |
104 | 108 | ||
105 | # Enable paging and in turn activate Long Mode | 109 | # Enable paging and in turn activate Long Mode |
106 | # Enable protected mode | 110 | movl $(X86_CR0_PG | X86_CR0_WP | X86_CR0_PE), %eax |
107 | movl $(X86_CR0_PG | X86_CR0_PE), %eax | ||
108 | movl %eax, %cr0 | 111 | movl %eax, %cr0 |
109 | 112 | ||
110 | /* | 113 | /* |
@@ -113,59 +116,38 @@ startup_32: | |||
113 | * EFER.LMA = 1). Now we want to jump in 64bit mode, to do that we use | 116 | * 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. | 117 | * the new gdt/idt that has __KERNEL_CS with CS.L = 1. |
115 | */ | 118 | */ |
116 | ljmp *(startup_64_vector - r_base)(%esi) | 119 | ljmpl $__KERNEL_CS, $pa_startup_64 |
117 | 120 | ||
121 | .section ".text64","ax" | ||
118 | .code64 | 122 | .code64 |
119 | .balign 4 | 123 | .balign 4 |
120 | startup_64: | 124 | ENTRY(startup_64) |
121 | # Now jump into the kernel using virtual addresses | 125 | # Now jump into the kernel using virtual addresses |
122 | movq $secondary_startup_64, %rax | 126 | jmpq *tr_start(%rip) |
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 | 127 | ||
128 | .section ".rodata","a" | ||
137 | # Duplicate the global descriptor table | 129 | # Duplicate the global descriptor table |
138 | # so the kernel can live anywhere | 130 | # so the kernel can live anywhere |
139 | .balign 4 | 131 | .balign 16 |
140 | tgdt: | 132 | .globl tr_gdt |
141 | .short tgdt_end - tgdt # gdt limit | 133 | tr_gdt: |
142 | .long tgdt - r_base | 134 | .short tr_gdt_end - tr_gdt - 1 # gdt limit |
143 | .short 0 | 135 | .long pa_tr_gdt |
136 | .short 0 | ||
144 | .quad 0x00cf9b000000ffff # __KERNEL32_CS | 137 | .quad 0x00cf9b000000ffff # __KERNEL32_CS |
145 | .quad 0x00af9b000000ffff # __KERNEL_CS | 138 | .quad 0x00af9b000000ffff # __KERNEL_CS |
146 | .quad 0x00cf93000000ffff # __KERNEL_DS | 139 | .quad 0x00cf93000000ffff # __KERNEL_DS |
147 | tgdt_end: | 140 | tr_gdt_end: |
148 | 141 | ||
149 | .balign 4 | 142 | .bss |
150 | startup_32_vector: | 143 | .balign PAGE_SIZE |
151 | .long startup_32 - r_base | 144 | GLOBAL(trampoline_pgd) .space PAGE_SIZE |
152 | .word __KERNEL32_CS, 0 | ||
153 | 145 | ||
154 | .balign 4 | 146 | .balign 8 |
155 | startup_64_vector: | 147 | GLOBAL(trampoline_header) |
156 | .long startup_64 - r_base | 148 | tr_start: .space 8 |
157 | .word __KERNEL_CS, 0 | 149 | GLOBAL(tr_efer) .space 8 |
150 | GLOBAL(tr_cr4) .space 4 | ||
151 | END(trampoline_header) | ||
158 | 152 | ||
159 | .balign 4 | 153 | #include "trampoline_common.S" |
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) | ||
diff --git a/arch/x86/realmode/rm/trampoline_common.S b/arch/x86/realmode/rm/trampoline_common.S new file mode 100644 index 000000000000..b1ecdb9692ad --- /dev/null +++ b/arch/x86/realmode/rm/trampoline_common.S | |||
@@ -0,0 +1,7 @@ | |||
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 | ||
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/kernel/acpi/realmode/wakemain.c b/arch/x86/realmode/rm/wakemain.c index 883962d9eef2..91405d515ec6 100644 --- a/arch/x86/kernel/acpi/realmode/wakemain.c +++ b/arch/x86/realmode/rm/wakemain.c | |||
@@ -65,7 +65,8 @@ void main(void) | |||
65 | { | 65 | { |
66 | /* Kill machine if structures are wrong */ | 66 | /* Kill machine if structures are wrong */ |
67 | if (wakeup_header.real_magic != 0x12345678) | 67 | if (wakeup_header.real_magic != 0x12345678) |
68 | while (1); | 68 | while (1) |
69 | ; | ||
69 | 70 | ||
70 | if (wakeup_header.realmode_flags & 4) | 71 | if (wakeup_header.realmode_flags & 4) |
71 | send_morse("...-"); | 72 | send_morse("...-"); |
diff --git a/arch/x86/kernel/acpi/realmode/wakeup.h b/arch/x86/realmode/rm/wakeup.h index 97a29e1430e3..9317e0042f24 100644 --- a/arch/x86/kernel/acpi/realmode/wakeup.h +++ b/arch/x86/realmode/rm/wakeup.h | |||
@@ -12,9 +12,8 @@ | |||
12 | /* This must match data at wakeup.S */ | 12 | /* This must match data at wakeup.S */ |
13 | struct wakeup_header { | 13 | struct wakeup_header { |
14 | u16 video_mode; /* Video mode number */ | 14 | u16 video_mode; /* Video mode number */ |
15 | u16 _jmp1; /* ljmpl opcode, 32-bit only */ | ||
16 | u32 pmode_entry; /* Protected mode resume point, 32-bit only */ | 15 | u32 pmode_entry; /* Protected mode resume point, 32-bit only */ |
17 | u16 _jmp2; /* CS value, 32-bit only */ | 16 | u16 pmode_cs; |
18 | u32 pmode_cr0; /* Protected mode cr0 */ | 17 | u32 pmode_cr0; /* Protected mode cr0 */ |
19 | u32 pmode_cr3; /* Protected mode cr3 */ | 18 | u32 pmode_cr3; /* Protected mode cr3 */ |
20 | u32 pmode_cr4; /* Protected mode cr4 */ | 19 | u32 pmode_cr4; /* Protected mode cr4 */ |
@@ -26,12 +25,6 @@ struct wakeup_header { | |||
26 | u32 pmode_behavior; /* Wakeup routine behavior flags */ | 25 | u32 pmode_behavior; /* Wakeup routine behavior flags */ |
27 | u32 realmode_flags; | 26 | u32 realmode_flags; |
28 | u32 real_magic; | 27 | u32 real_magic; |
29 | u16 trampoline_segment; /* segment with trampoline code, 64-bit only */ | ||
30 | u8 _pad1; | ||
31 | u8 wakeup_jmp; | ||
32 | u16 wakeup_jmp_off; | ||
33 | u16 wakeup_jmp_seg; | ||
34 | u64 wakeup_gdt[3]; | ||
35 | u32 signature; /* To check we have correct structure */ | 28 | u32 signature; /* To check we have correct structure */ |
36 | } __attribute__((__packed__)); | 29 | } __attribute__((__packed__)); |
37 | 30 | ||
@@ -40,7 +33,6 @@ extern struct wakeup_header wakeup_header; | |||
40 | 33 | ||
41 | #define WAKEUP_HEADER_OFFSET 8 | 34 | #define WAKEUP_HEADER_OFFSET 8 |
42 | #define WAKEUP_HEADER_SIGNATURE 0x51ee1111 | 35 | #define WAKEUP_HEADER_SIGNATURE 0x51ee1111 |
43 | #define WAKEUP_END_SIGNATURE 0x65a22c82 | ||
44 | 36 | ||
45 | /* Wakeup behavior bits */ | 37 | /* Wakeup behavior bits */ |
46 | #define WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE 0 | 38 | #define WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE 0 |
diff --git a/arch/x86/kernel/acpi/realmode/wakeup.S b/arch/x86/realmode/rm/wakeup_asm.S index b4fd836e4053..8905166b0bbb 100644 --- a/arch/x86/kernel/acpi/realmode/wakeup.S +++ b/arch/x86/realmode/rm/wakeup_asm.S | |||
@@ -1,50 +1,47 @@ | |||
1 | /* | 1 | /* |
2 | * ACPI wakeup real mode startup stub | 2 | * ACPI wakeup real mode startup stub |
3 | */ | 3 | */ |
4 | #include <linux/linkage.h> | ||
4 | #include <asm/segment.h> | 5 | #include <asm/segment.h> |
5 | #include <asm/msr-index.h> | 6 | #include <asm/msr-index.h> |
6 | #include <asm/page_types.h> | 7 | #include <asm/page_types.h> |
7 | #include <asm/pgtable_types.h> | 8 | #include <asm/pgtable_types.h> |
8 | #include <asm/processor-flags.h> | 9 | #include <asm/processor-flags.h> |
10 | #include "realmode.h" | ||
9 | #include "wakeup.h" | 11 | #include "wakeup.h" |
10 | 12 | ||
11 | .code16 | 13 | .code16 |
12 | .section ".jump", "ax" | ||
13 | .globl _start | ||
14 | _start: | ||
15 | cli | ||
16 | jmp wakeup_code | ||
17 | 14 | ||
18 | /* This should match the structure in wakeup.h */ | 15 | /* This should match the structure in wakeup.h */ |
19 | .section ".header", "a" | 16 | .section ".data", "aw" |
20 | .globl wakeup_header | 17 | |
21 | wakeup_header: | 18 | .balign 16 |
22 | video_mode: .short 0 /* Video mode number */ | 19 | GLOBAL(wakeup_header) |
23 | pmode_return: .byte 0x66, 0xea /* ljmpl */ | 20 | video_mode: .short 0 /* Video mode number */ |
24 | .long 0 /* offset goes here */ | 21 | pmode_entry: .long 0 |
25 | .short __KERNEL_CS | 22 | pmode_cs: .short __KERNEL_CS |
26 | pmode_cr0: .long 0 /* Saved %cr0 */ | 23 | pmode_cr0: .long 0 /* Saved %cr0 */ |
27 | pmode_cr3: .long 0 /* Saved %cr3 */ | 24 | pmode_cr3: .long 0 /* Saved %cr3 */ |
28 | pmode_cr4: .long 0 /* Saved %cr4 */ | 25 | pmode_cr4: .long 0 /* Saved %cr4 */ |
29 | pmode_efer: .quad 0 /* Saved EFER */ | 26 | pmode_efer: .quad 0 /* Saved EFER */ |
30 | pmode_gdt: .quad 0 | 27 | pmode_gdt: .quad 0 |
31 | pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */ | 28 | pmode_misc_en: .quad 0 /* Saved MISC_ENABLE MSR */ |
32 | pmode_behavior: .long 0 /* Wakeup behavior flags */ | 29 | pmode_behavior: .long 0 /* Wakeup behavior flags */ |
33 | realmode_flags: .long 0 | 30 | realmode_flags: .long 0 |
34 | real_magic: .long 0 | 31 | real_magic: .long 0 |
35 | trampoline_segment: .word 0 | 32 | signature: .long WAKEUP_HEADER_SIGNATURE |
36 | _pad1: .byte 0 | 33 | END(wakeup_header) |
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 | ||
42 | 34 | ||
43 | .text | 35 | .text |
44 | .code16 | 36 | .code16 |
45 | wakeup_code: | 37 | |
38 | .balign 16 | ||
39 | ENTRY(wakeup_start) | ||
40 | cli | ||
46 | cld | 41 | cld |
47 | 42 | ||
43 | LJMPW_RM(3f) | ||
44 | 3: | ||
48 | /* Apparently some dimwit BIOS programmers don't know how to | 45 | /* Apparently some dimwit BIOS programmers don't know how to |
49 | program a PM to RM transition, and we might end up here with | 46 | program a PM to RM transition, and we might end up here with |
50 | junk in the data segment descriptor registers. The only way | 47 | junk in the data segment descriptor registers. The only way |
@@ -54,8 +51,7 @@ wakeup_code: | |||
54 | movl %cr0, %eax | 51 | movl %cr0, %eax |
55 | orb $X86_CR0_PE, %al | 52 | orb $X86_CR0_PE, %al |
56 | movl %eax, %cr0 | 53 | movl %eax, %cr0 |
57 | jmp 1f | 54 | ljmpw $8, $2f |
58 | 1: ljmpw $8, $2f | ||
59 | 2: | 55 | 2: |
60 | movw %cx, %ds | 56 | movw %cx, %ds |
61 | movw %cx, %es | 57 | movw %cx, %es |
@@ -65,16 +61,18 @@ wakeup_code: | |||
65 | 61 | ||
66 | andb $~X86_CR0_PE, %al | 62 | andb $~X86_CR0_PE, %al |
67 | movl %eax, %cr0 | 63 | movl %eax, %cr0 |
68 | jmp wakeup_jmp | 64 | LJMPW_RM(3f) |
69 | 3: | 65 | 3: |
70 | /* Set up segments */ | 66 | /* Set up segments */ |
71 | movw %cs, %ax | 67 | movw %cs, %ax |
68 | movw %ax, %ss | ||
69 | movl $rm_stack_end, %esp | ||
72 | movw %ax, %ds | 70 | movw %ax, %ds |
73 | movw %ax, %es | 71 | movw %ax, %es |
74 | movw %ax, %ss | 72 | movw %ax, %fs |
75 | lidtl wakeup_idt | 73 | movw %ax, %gs |
76 | 74 | ||
77 | movl $wakeup_stack_end, %esp | 75 | lidtl wakeup_idt |
78 | 76 | ||
79 | /* Clear the EFLAGS */ | 77 | /* Clear the EFLAGS */ |
80 | pushl $0 | 78 | pushl $0 |
@@ -87,7 +85,7 @@ wakeup_code: | |||
87 | 85 | ||
88 | /* Check we really have everything... */ | 86 | /* Check we really have everything... */ |
89 | movl end_signature, %eax | 87 | movl end_signature, %eax |
90 | cmpl $WAKEUP_END_SIGNATURE, %eax | 88 | cmpl $REALMODE_END_SIGNATURE, %eax |
91 | jne bogus_real_magic | 89 | jne bogus_real_magic |
92 | 90 | ||
93 | /* Call the C code */ | 91 | /* Call the C code */ |
@@ -128,14 +126,13 @@ wakeup_code: | |||
128 | lgdtl pmode_gdt | 126 | lgdtl pmode_gdt |
129 | 127 | ||
130 | /* This really couldn't... */ | 128 | /* This really couldn't... */ |
131 | movl pmode_cr0, %eax | 129 | movl pmode_entry, %eax |
132 | movl %eax, %cr0 | 130 | movl pmode_cr0, %ecx |
133 | jmp pmode_return | 131 | movl %ecx, %cr0 |
132 | ljmpl $__KERNEL_CS, $pa_startup_32 | ||
133 | /* -> jmp *%eax in trampoline_32.S */ | ||
134 | #else | 134 | #else |
135 | pushw $0 | 135 | jmp trampoline_start |
136 | pushw trampoline_segment | ||
137 | pushw $0 | ||
138 | lret | ||
139 | #endif | 136 | #endif |
140 | 137 | ||
141 | bogus_real_magic: | 138 | bogus_real_magic: |
@@ -143,28 +140,38 @@ bogus_real_magic: | |||
143 | hlt | 140 | hlt |
144 | jmp 1b | 141 | jmp 1b |
145 | 142 | ||
146 | .data | 143 | .section ".rodata","a" |
144 | |||
145 | /* | ||
146 | * Set up the wakeup GDT. We set these up as Big Real Mode, | ||
147 | * that is, with limits set to 4 GB. At least the Lenovo | ||
148 | * Thinkpad X61 is known to need this for the video BIOS | ||
149 | * initialization quirk to work; this is likely to also | ||
150 | * be the case for other laptops or integrated video devices. | ||
151 | */ | ||
152 | |||
153 | .balign 16 | ||
154 | GLOBAL(wakeup_gdt) | ||
155 | .word 3*8-1 /* Self-descriptor */ | ||
156 | .long pa_wakeup_gdt | ||
157 | .word 0 | ||
158 | |||
159 | .word 0xffff /* 16-bit code segment @ real_mode_base */ | ||
160 | .long 0x9b000000 + pa_real_mode_base | ||
161 | .word 0x008f /* big real mode */ | ||
162 | |||
163 | .word 0xffff /* 16-bit data segment @ real_mode_base */ | ||
164 | .long 0x93000000 + pa_real_mode_base | ||
165 | .word 0x008f /* big real mode */ | ||
166 | END(wakeup_gdt) | ||
167 | |||
168 | .section ".rodata","a" | ||
147 | .balign 8 | 169 | .balign 8 |
148 | 170 | ||
149 | /* This is the standard real-mode IDT */ | 171 | /* This is the standard real-mode IDT */ |
150 | wakeup_idt: | 172 | .balign 16 |
173 | GLOBAL(wakeup_idt) | ||
151 | .word 0xffff /* limit */ | 174 | .word 0xffff /* limit */ |
152 | .long 0 /* address */ | 175 | .long 0 /* address */ |
153 | .word 0 | 176 | .word 0 |
154 | 177 | END(wakeup_idt) | |
155 | .globl HEAP, heap_end | ||
156 | HEAP: | ||
157 | .long wakeup_heap | ||
158 | heap_end: | ||
159 | .long wakeup_stack | ||
160 | |||
161 | .bss | ||
162 | wakeup_heap: | ||
163 | .space 2048 | ||
164 | wakeup_stack: | ||
165 | .space 2048 | ||
166 | wakeup_stack_end: | ||
167 | |||
168 | .section ".signature","a" | ||
169 | end_signature: | ||
170 | .long WAKEUP_END_SIGNATURE | ||
diff --git a/arch/x86/realmode/rmpiggy.S b/arch/x86/realmode/rmpiggy.S new file mode 100644 index 000000000000..204c6ece0e97 --- /dev/null +++ b/arch/x86/realmode/rmpiggy.S | |||
@@ -0,0 +1,20 @@ | |||
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) | ||
diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c index b685296d4464..5a1847d61930 100644 --- a/arch/x86/tools/relocs.c +++ b/arch/x86/tools/relocs.c | |||
@@ -78,6 +78,13 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = { | |||
78 | 78 | ||
79 | static const char * const sym_regex_realmode[S_NSYMTYPES] = { | 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 | * These are 16-bit segment symbols when compiling 16-bit code. | 88 | * These are 16-bit segment symbols when compiling 16-bit code. |
82 | */ | 89 | */ |
83 | [S_SEG] = | 90 | [S_SEG] = |
diff --git a/drivers/acpi/bgrt.c b/drivers/acpi/bgrt.c index 8cf6c46e99fb..6680df36b963 100644 --- a/drivers/acpi/bgrt.c +++ b/drivers/acpi/bgrt.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <linux/device.h> | 12 | #include <linux/device.h> |
13 | #include <linux/sysfs.h> | 13 | #include <linux/sysfs.h> |
14 | #include <linux/io.h> | ||
14 | #include <acpi/acpi.h> | 15 | #include <acpi/acpi.h> |
15 | #include <acpi/acpi_bus.h> | 16 | #include <acpi/acpi_bus.h> |
16 | 17 | ||
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 06527c526618..ebaa04593236 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c | |||
@@ -25,6 +25,8 @@ | |||
25 | #include <acpi/acpi_bus.h> | 25 | #include <acpi/acpi_bus.h> |
26 | #include <acpi/acpi_drivers.h> | 26 | #include <acpi/acpi_drivers.h> |
27 | 27 | ||
28 | #include <asm/realmode.h> | ||
29 | |||
28 | #include "internal.h" | 30 | #include "internal.h" |
29 | #include "sleep.h" | 31 | #include "sleep.h" |
30 | 32 | ||
@@ -91,13 +93,13 @@ static struct notifier_block tts_notifier = { | |||
91 | static int acpi_sleep_prepare(u32 acpi_state) | 93 | static int acpi_sleep_prepare(u32 acpi_state) |
92 | { | 94 | { |
93 | #ifdef CONFIG_ACPI_SLEEP | 95 | #ifdef CONFIG_ACPI_SLEEP |
96 | unsigned long wakeup_pa = real_mode_header->wakeup_start; | ||
94 | /* do we have a wakeup address for S2 and S3? */ | 97 | /* do we have a wakeup address for S2 and S3? */ |
95 | if (acpi_state == ACPI_STATE_S3) { | 98 | if (acpi_state == ACPI_STATE_S3) { |
96 | if (!acpi_wakeup_address) { | 99 | if (!wakeup_pa) |
97 | return -EFAULT; | 100 | return -EFAULT; |
98 | } | ||
99 | acpi_set_firmware_waking_vector( | 101 | acpi_set_firmware_waking_vector( |
100 | (acpi_physical_address)acpi_wakeup_address); | 102 | (acpi_physical_address)wakeup_pa); |
101 | 103 | ||
102 | } | 104 | } |
103 | ACPI_FLUSH_CPU_CACHE(); | 105 | ACPI_FLUSH_CPU_CACHE(); |
diff --git a/drivers/xen/xen-acpi-processor.c b/drivers/xen/xen-acpi-processor.c index 0b48579a9cd6..7ff2569e17ae 100644 --- a/drivers/xen/xen-acpi-processor.c +++ b/drivers/xen/xen-acpi-processor.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <acpi/acpi_drivers.h> | 29 | #include <acpi/acpi_drivers.h> |
30 | #include <acpi/processor.h> | 30 | #include <acpi/processor.h> |
31 | 31 | ||
32 | #include <xen/xen.h> | ||
32 | #include <xen/interface/platform.h> | 33 | #include <xen/interface/platform.h> |
33 | #include <asm/xen/hypercall.h> | 34 | #include <asm/xen/hypercall.h> |
34 | 35 | ||