aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/realmode/rm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/realmode/rm')
-rw-r--r--arch/x86/realmode/rm/.gitignore3
-rw-r--r--arch/x86/realmode/rm/Makefile82
-rw-r--r--arch/x86/realmode/rm/bioscall.S1
-rw-r--r--arch/x86/realmode/rm/copy.S1
-rw-r--r--arch/x86/realmode/rm/header.S41
-rw-r--r--arch/x86/realmode/rm/realmode.h21
-rw-r--r--arch/x86/realmode/rm/realmode.lds.S76
-rw-r--r--arch/x86/realmode/rm/reboot_32.S132
-rw-r--r--arch/x86/realmode/rm/regs.c1
-rw-r--r--arch/x86/realmode/rm/stack.S19
-rw-r--r--arch/x86/realmode/rm/trampoline_32.S74
-rw-r--r--arch/x86/realmode/rm/trampoline_64.S153
-rw-r--r--arch/x86/realmode/rm/trampoline_common.S7
-rw-r--r--arch/x86/realmode/rm/video-bios.c1
-rw-r--r--arch/x86/realmode/rm/video-mode.c1
-rw-r--r--arch/x86/realmode/rm/video-vesa.c1
-rw-r--r--arch/x86/realmode/rm/video-vga.c1
-rw-r--r--arch/x86/realmode/rm/wakemain.c82
-rw-r--r--arch/x86/realmode/rm/wakeup.h40
-rw-r--r--arch/x86/realmode/rm/wakeup_asm.S177
20 files changed, 914 insertions, 0 deletions
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 @@
1pasyms.h
2realmode.lds
3realmode.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
10always := realmode.bin realmode.relocs
11
12wakeup-objs := wakeup_asm.o wakemain.o video-mode.o
13wakeup-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.
18wakeup-objs += video-vga.o
19wakeup-objs += video-vesa.o
20wakeup-objs += video-bios.o
21
22realmode-y += header.o
23realmode-y += trampoline_$(BITS).o
24realmode-y += stack.o
25realmode-$(CONFIG_X86_32) += reboot_32.o
26realmode-$(CONFIG_ACPI_SLEEP) += $(wakeup-objs)
27
28targets += $(realmode-y)
29
30REALMODE_OBJS = $(addprefix $(obj)/,$(realmode-y))
31
32sed-pasyms := -n -r -e 's/^([0-9a-fA-F]+) [ABCDGRSTVW] (.+)$$/pa_\2 = \2;/p'
33
34quiet_cmd_pasyms = PASYMS $@
35 cmd_pasyms = $(NM) $(filter-out FORCE,$^) | \
36 sed $(sed-pasyms) | sort | uniq > $@
37
38targets += pasyms.h
39$(obj)/pasyms.h: $(REALMODE_OBJS) FORCE
40 $(call if_changed,pasyms)
41
42targets += realmode.lds
43$(obj)/realmode.lds: $(obj)/pasyms.h
44
45LDFLAGS_realmode.elf := --emit-relocs -T
46CPPFLAGS_realmode.lds += -P -C -I$(obj)
47
48targets += realmode.elf
49$(obj)/realmode.elf: $(obj)/realmode.lds $(REALMODE_OBJS) FORCE
50 $(call if_changed,ld)
51
52OBJCOPYFLAGS_realmode.bin := -O binary
53
54targets += realmode.bin
55$(obj)/realmode.bin: $(obj)/realmode.elf $(obj)/realmode.relocs
56 $(call if_changed,objcopy)
57
58quiet_cmd_relocs = RELOCS $@
59 cmd_relocs = arch/x86/tools/relocs --realmode $< > $@
60
61targets += 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.
69KBUILD_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)
81KBUILD_AFLAGS := $(KBUILD_CFLAGS) -D__ASSEMBLY__
82GCOV_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
15GLOBAL(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
34END(real_mode_header)
35
36 /* End signature, used to verify integrity */
37 .section ".signature","a"
38 .balign 4
39GLOBAL(end_signature)
40 .long REALMODE_END_SIGNATURE
41END(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
11OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
12OUTPUT_ARCH(i386)
13
14SECTIONS
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/realmode/rm/reboot_32.S b/arch/x86/realmode/rm/reboot_32.S
new file mode 100644
index 000000000000..114044876b3d
--- /dev/null
+++ b/arch/x86/realmode/rm/reboot_32.S
@@ -0,0 +1,132 @@
1#include <linux/linkage.h>
2#include <linux/init.h>
3#include <asm/segment.h>
4#include <asm/page_types.h>
5#include "realmode.h"
6
7/*
8 * The following code and data reboots the machine by switching to real
9 * mode and jumping to the BIOS reset entry point, as if the CPU has
10 * really been reset. The previous version asked the keyboard
11 * controller to pulse the CPU reset line, which is more thorough, but
12 * doesn't work with at least one type of 486 motherboard. It is easy
13 * to stop this code working; hence the copious comments.
14 *
15 * This code is called with the restart type (0 = BIOS, 1 = APM) in %eax.
16 */
17 .section ".text32", "ax"
18 .code32
19
20 .balign 16
21ENTRY(machine_real_restart_asm)
22 /* Set up the IDT for real mode. */
23 lidtl pa_machine_real_restart_idt
24
25 /*
26 * Set up a GDT from which we can load segment descriptors for real
27 * mode. The GDT is not used in real mode; it is just needed here to
28 * prepare the descriptors.
29 */
30 lgdtl pa_machine_real_restart_gdt
31
32 /*
33 * Load the data segment registers with 16-bit compatible values
34 */
35 movl $16, %ecx
36 movl %ecx, %ds
37 movl %ecx, %es
38 movl %ecx, %fs
39 movl %ecx, %gs
40 movl %ecx, %ss
41 ljmpw $8, $1f
42
43/*
44 * This is 16-bit protected mode code to disable paging and the cache,
45 * switch to real mode and jump to the BIOS reset code.
46 *
47 * The instruction that switches to real mode by writing to CR0 must be
48 * followed immediately by a far jump instruction, which set CS to a
49 * valid value for real mode, and flushes the prefetch queue to avoid
50 * running instructions that have already been decoded in protected
51 * mode.
52 *
53 * Clears all the flags except ET, especially PG (paging), PE
54 * (protected-mode enable) and TS (task switch for coprocessor state
55 * save). Flushes the TLB after paging has been disabled. Sets CD and
56 * NW, to disable the cache on a 486, and invalidates the cache. This
57 * is more like the state of a 486 after reset. I don't know if
58 * something else should be done for other chips.
59 *
60 * More could be done here to set up the registers as if a CPU reset had
61 * occurred; hopefully real BIOSs don't assume much. This is not the
62 * actual BIOS entry point, anyway (that is at 0xfffffff0).
63 *
64 * Most of this work is probably excessive, but it is what is tested.
65 */
66 .text
67 .code16
68
69 .balign 16
70machine_real_restart_asm16:
711:
72 xorl %ecx, %ecx
73 movl %cr0, %edx
74 andl $0x00000011, %edx
75 orl $0x60000000, %edx
76 movl %edx, %cr0
77 movl %ecx, %cr3
78 movl %cr0, %edx
79 testl $0x60000000, %edx /* If no cache bits -> no wbinvd */
80 jz 2f
81 wbinvd
822:
83 andb $0x10, %dl
84 movl %edx, %cr0
85 LJMPW_RM(3f)
863:
87 andw %ax, %ax
88 jz bios
89
90apm:
91 movw $0x1000, %ax
92 movw %ax, %ss
93 movw $0xf000, %sp
94 movw $0x5307, %ax
95 movw $0x0001, %bx
96 movw $0x0003, %cx
97 int $0x15
98 /* This should never return... */
99
100bios:
101 ljmpw $0xf000, $0xfff0
102
103 .section ".rodata", "a"
104
105 .balign 16
106GLOBAL(machine_real_restart_idt)
107 .word 0xffff /* Length - real mode default value */
108 .long 0 /* Base - real mode default value */
109END(machine_real_restart_idt)
110
111 .balign 16
112GLOBAL(machine_real_restart_gdt)
113 /* Self-pointer */
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
126 /*
127 * 16-bit data segment with the selector value 16 = 0x10 and
128 * base value 0x100; since this is consistent with real mode
129 * semantics we don't have to reload the segments once CR0.PE = 0.
130 */
131 .quad GDT_ENTRY(0x0093, 0x100, 0xffff)
132END(machine_real_restart_gdt)
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
8GLOBAL(HEAP)
9 .long rm_heap
10GLOBAL(heap_end)
11 .long rm_stack
12
13 .bss
14 .balign 16
15GLOBAL(rm_heap)
16 .space 2048
17GLOBAL(rm_stack)
18 .space 2048
19GLOBAL(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
32ENTRY(trampoline_start)
33 wbinvd # Needed for NUMA-Q should be harmless for others
34
35 LJMPW_RM(1f)
361:
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
63ENTRY(startup_32) # note: also used from wakeup_asm.S
64 jmp *%eax
65
66 .bss
67 .balign 8
68GLOBAL(trampoline_header)
69 tr_start: .space 4
70 tr_gdt_pad: .space 2
71 tr_gdt: .space 6
72END(trampoline_header)
73
74#include "trampoline_common.S"
diff --git a/arch/x86/realmode/rm/trampoline_64.S b/arch/x86/realmode/rm/trampoline_64.S
new file mode 100644
index 000000000000..bb360dc39d21
--- /dev/null
+++ b/arch/x86/realmode/rm/trampoline_64.S
@@ -0,0 +1,153 @@
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
40ENTRY(trampoline_start)
41 cli # We should be safe anyway
42 wbinvd
43
44 LJMPW_RM(1f)
451:
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
80no_longmode:
81 hlt
82 jmp no_longmode
83#include "../kernel/verify_cpu.S"
84
85 .section ".text32","ax"
86 .code32
87 .balign 4
88ENTRY(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
124ENTRY(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
133tr_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
140tr_gdt_end:
141
142 .bss
143 .balign PAGE_SIZE
144GLOBAL(trampoline_pgd) .space PAGE_SIZE
145
146 .balign 8
147GLOBAL(trampoline_header)
148 tr_start: .space 8
149 GLOBAL(tr_efer) .space 8
150 GLOBAL(tr_cr4) .space 4
151END(trampoline_header)
152
153#include "trampoline_common.S"
diff --git a/arch/x86/realmode/rm/trampoline_common.S b/arch/x86/realmode/rm/trampoline_common.S
new file mode 100644
index 000000000000..b1ecdb9692ad
--- /dev/null
+++ b/arch/x86/realmode/rm/trampoline_common.S
@@ -0,0 +1,7 @@
1 .section ".rodata","a"
2 .balign 16
3tr_idt: .fill 1, 6, 0
4
5 .bss
6 .balign 4
7GLOBAL(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/realmode/rm/wakemain.c b/arch/x86/realmode/rm/wakemain.c
new file mode 100644
index 000000000000..91405d515ec6
--- /dev/null
+++ b/arch/x86/realmode/rm/wakemain.c
@@ -0,0 +1,82 @@
1#include "wakeup.h"
2#include "boot.h"
3
4static void udelay(int loops)
5{
6 while (loops--)
7 io_delay(); /* Approximately 1 us */
8}
9
10static void beep(unsigned int hz)
11{
12 u8 enable;
13
14 if (!hz) {
15 enable = 0x00; /* Turn off speaker */
16 } else {
17 u16 div = 1193181/hz;
18
19 outb(0xb6, 0x43); /* Ctr 2, squarewave, load, binary */
20 io_delay();
21 outb(div, 0x42); /* LSB of counter */
22 io_delay();
23 outb(div >> 8, 0x42); /* MSB of counter */
24 io_delay();
25
26 enable = 0x03; /* Turn on speaker */
27 }
28 inb(0x61); /* Dummy read of System Control Port B */
29 io_delay();
30 outb(enable, 0x61); /* Enable timer 2 output to speaker */
31 io_delay();
32}
33
34#define DOT_HZ 880
35#define DASH_HZ 587
36#define US_PER_DOT 125000
37
38/* Okay, this is totally silly, but it's kind of fun. */
39static void send_morse(const char *pattern)
40{
41 char s;
42
43 while ((s = *pattern++)) {
44 switch (s) {
45 case '.':
46 beep(DOT_HZ);
47 udelay(US_PER_DOT);
48 beep(0);
49 udelay(US_PER_DOT);
50 break;
51 case '-':
52 beep(DASH_HZ);
53 udelay(US_PER_DOT * 3);
54 beep(0);
55 udelay(US_PER_DOT);
56 break;
57 default: /* Assume it's a space */
58 udelay(US_PER_DOT * 3);
59 break;
60 }
61 }
62}
63
64void main(void)
65{
66 /* Kill machine if structures are wrong */
67 if (wakeup_header.real_magic != 0x12345678)
68 while (1)
69 ;
70
71 if (wakeup_header.realmode_flags & 4)
72 send_morse("...-");
73
74 if (wakeup_header.realmode_flags & 1)
75 asm volatile("lcallw $0xc000,$3");
76
77 if (wakeup_header.realmode_flags & 2) {
78 /* Need to call BIOS */
79 probe_cards(0);
80 set_mode(wakeup_header.video_mode);
81 }
82}
diff --git a/arch/x86/realmode/rm/wakeup.h b/arch/x86/realmode/rm/wakeup.h
new file mode 100644
index 000000000000..9317e0042f24
--- /dev/null
+++ b/arch/x86/realmode/rm/wakeup.h
@@ -0,0 +1,40 @@
1/*
2 * Definitions for the wakeup data structure at the head of the
3 * wakeup code.
4 */
5
6#ifndef ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H
7#define ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H
8
9#ifndef __ASSEMBLY__
10#include <linux/types.h>
11
12/* This must match data at wakeup.S */
13struct wakeup_header {
14 u16 video_mode; /* Video mode number */
15 u32 pmode_entry; /* Protected mode resume point, 32-bit only */
16 u16 pmode_cs;
17 u32 pmode_cr0; /* Protected mode cr0 */
18 u32 pmode_cr3; /* Protected mode cr3 */
19 u32 pmode_cr4; /* Protected mode cr4 */
20 u32 pmode_efer_low; /* Protected mode EFER */
21 u32 pmode_efer_high;
22 u64 pmode_gdt;
23 u32 pmode_misc_en_low; /* Protected mode MISC_ENABLE */
24 u32 pmode_misc_en_high;
25 u32 pmode_behavior; /* Wakeup routine behavior flags */
26 u32 realmode_flags;
27 u32 real_magic;
28 u32 signature; /* To check we have correct structure */
29} __attribute__((__packed__));
30
31extern struct wakeup_header wakeup_header;
32#endif
33
34#define WAKEUP_HEADER_OFFSET 8
35#define WAKEUP_HEADER_SIGNATURE 0x51ee1111
36
37/* Wakeup behavior bits */
38#define WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE 0
39
40#endif /* ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H */
diff --git a/arch/x86/realmode/rm/wakeup_asm.S b/arch/x86/realmode/rm/wakeup_asm.S
new file mode 100644
index 000000000000..8905166b0bbb
--- /dev/null
+++ b/arch/x86/realmode/rm/wakeup_asm.S
@@ -0,0 +1,177 @@
1/*
2 * ACPI wakeup real mode startup stub
3 */
4#include <linux/linkage.h>
5#include <asm/segment.h>
6#include <asm/msr-index.h>
7#include <asm/page_types.h>
8#include <asm/pgtable_types.h>
9#include <asm/processor-flags.h>
10#include "realmode.h"
11#include "wakeup.h"
12
13 .code16
14
15/* This should match the structure in wakeup.h */
16 .section ".data", "aw"
17
18 .balign 16
19GLOBAL(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
33END(wakeup_header)
34
35 .text
36 .code16
37
38 .balign 16
39ENTRY(wakeup_start)
40 cli
41 cld
42
43 LJMPW_RM(3f)
443:
45 /* Apparently some dimwit BIOS programmers don't know how to
46 program a PM to RM transition, and we might end up here with
47 junk in the data segment descriptor registers. The only way
48 to repair that is to go into PM and fix it ourselves... */
49 movw $16, %cx
50 lgdtl %cs:wakeup_gdt
51 movl %cr0, %eax
52 orb $X86_CR0_PE, %al
53 movl %eax, %cr0
54 ljmpw $8, $2f
552:
56 movw %cx, %ds
57 movw %cx, %es
58 movw %cx, %ss
59 movw %cx, %fs
60 movw %cx, %gs
61
62 andb $~X86_CR0_PE, %al
63 movl %eax, %cr0
64 LJMPW_RM(3f)
653:
66 /* Set up segments */
67 movw %cs, %ax
68 movw %ax, %ss
69 movl $rm_stack_end, %esp
70 movw %ax, %ds
71 movw %ax, %es
72 movw %ax, %fs
73 movw %ax, %gs
74
75 lidtl wakeup_idt
76
77 /* Clear the EFLAGS */
78 pushl $0
79 popfl
80
81 /* Check header signature... */
82 movl signature, %eax
83 cmpl $WAKEUP_HEADER_SIGNATURE, %eax
84 jne bogus_real_magic
85
86 /* Check we really have everything... */
87 movl end_signature, %eax
88 cmpl $REALMODE_END_SIGNATURE, %eax
89 jne bogus_real_magic
90
91 /* Call the C code */
92 calll main
93
94 /* Restore MISC_ENABLE before entering protected mode, in case
95 BIOS decided to clear XD_DISABLE during S3. */
96 movl pmode_behavior, %eax
97 btl $WAKEUP_BEHAVIOR_RESTORE_MISC_ENABLE, %eax
98 jnc 1f
99
100 movl pmode_misc_en, %eax
101 movl pmode_misc_en + 4, %edx
102 movl $MSR_IA32_MISC_ENABLE, %ecx
103 wrmsr
1041:
105
106 /* Do any other stuff... */
107
108#ifndef CONFIG_64BIT
109 /* This could also be done in C code... */
110 movl pmode_cr3, %eax
111 movl %eax, %cr3
112
113 movl pmode_cr4, %ecx
114 jecxz 1f
115 movl %ecx, %cr4
1161:
117 movl pmode_efer, %eax
118 movl pmode_efer + 4, %edx
119 movl %eax, %ecx
120 orl %edx, %ecx
121 jz 1f
122 movl $MSR_EFER, %ecx
123 wrmsr
1241:
125
126 lgdtl pmode_gdt
127
128 /* This really couldn't... */
129 movl pmode_entry, %eax
130 movl pmode_cr0, %ecx
131 movl %ecx, %cr0
132 ljmpl $__KERNEL_CS, $pa_startup_32
133 /* -> jmp *%eax in trampoline_32.S */
134#else
135 jmp trampoline_start
136#endif
137
138bogus_real_magic:
1391:
140 hlt
141 jmp 1b
142
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
154GLOBAL(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 */
166END(wakeup_gdt)
167
168 .section ".rodata","a"
169 .balign 8
170
171 /* This is the standard real-mode IDT */
172 .balign 16
173GLOBAL(wakeup_idt)
174 .word 0xffff /* limit */
175 .long 0 /* address */
176 .word 0
177END(wakeup_idt)