aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/realmode/rm
diff options
context:
space:
mode:
authorJarkko Sakkinen <jarkko.sakkinen@intel.com>2012-05-08 14:22:27 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2012-05-08 14:41:50 -0400
commit5a8c9aebe04a78b069828d364798d5f24c5a42bd (patch)
tree0c56b496e810fea8b97c31c9a72f49855983234e /arch/x86/realmode/rm
parent084ee1c641a068bfd1194d545f7dc9ab2043eb35 (diff)
x86, realmode: Move reboot_32.S to unified realmode code
Migrated reboot_32.S from x86_trampoline to the real-mode blob. Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@intel.com> Link: http://lkml.kernel.org/r/1336501366-28617-5-git-send-email-jarkko.sakkinen@intel.com Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'arch/x86/realmode/rm')
-rw-r--r--arch/x86/realmode/rm/Makefile1
-rw-r--r--arch/x86/realmode/rm/header.S3
-rw-r--r--arch/x86/realmode/rm/reboot_32.S134
3 files changed, 138 insertions, 0 deletions
diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
index 7c3f202cbccf..3f851c488593 100644
--- a/arch/x86/realmode/rm/Makefile
+++ b/arch/x86/realmode/rm/Makefile
@@ -12,6 +12,7 @@ subdir- := wakeup
12always := realmode.bin 12always := realmode.bin
13 13
14realmode-y += header.o 14realmode-y += header.o
15realmode-$(CONFIG_X86_32) += reboot_32.o
15 16
16targets += $(realmode-y) 17targets += $(realmode-y)
17 18
diff --git a/arch/x86/realmode/rm/header.S b/arch/x86/realmode/rm/header.S
index 7be17f2c65a3..db21401c0c57 100644
--- a/arch/x86/realmode/rm/header.S
+++ b/arch/x86/realmode/rm/header.S
@@ -13,4 +13,7 @@ ENTRY(real_mode_header)
13 .long pa_text_start 13 .long pa_text_start
14 .long pa_ro_end 14 .long pa_ro_end
15 .long pa_end 15 .long pa_end
16#ifdef CONFIG_X86_32
17 .long pa_machine_real_restart_asm
18#endif
16END(real_mode_header) 19END(real_mode_header)
diff --git a/arch/x86/realmode/rm/reboot_32.S b/arch/x86/realmode/rm/reboot_32.S
new file mode 100644
index 000000000000..83803c222b4a
--- /dev/null
+++ b/arch/x86/realmode/rm/reboot_32.S
@@ -0,0 +1,134 @@
1#include <linux/linkage.h>
2#include <linux/init.h>
3#include <asm/segment.h>
4#include <asm/page_types.h>
5
6/*
7 * The following code and data reboots the machine by switching to real
8 * mode and jumping to the BIOS reset entry point, as if the CPU has
9 * really been reset. The previous version asked the keyboard
10 * controller to pulse the CPU reset line, which is more thorough, but
11 * doesn't work with at least one type of 486 motherboard. It is easy
12 * to stop this code working; hence the copious comments.
13 *
14 * This code is called with the restart type (0 = BIOS, 1 = APM) in %eax.
15 */
16 .section ".text32", "ax"
17 .code32
18 .globl machine_real_restart_asm
19
20 .balign 16
21machine_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 andl $0x60000000, %edx /* If no cache bits -> no wbinvd */
80 jz 2f
81 wbinvd
822:
83 andb $0x10, %dl
84 movl %edx, %cr0
85 .byte 0xea /* ljmpw */
86 .word 3f /* Offset */
87 .word real_mode_seg /* Segment */
88
893:
90 testb $0, %al
91 jz bios
92
93apm:
94 movw $0x1000, %ax
95 movw %ax, %ss
96 movw $0xf000, %sp
97 movw $0x5307, %ax
98 movw $0x0001, %bx
99 movw $0x0003, %cx
100 int $0x15
101 /* This should never return... */
102
103bios:
104 ljmpw $0xf000, $0xfff0
105
106 .section ".rodata", "a"
107 .globl machine_real_restart_idt, machine_real_restart_gdt
108
109 .balign 16
110machine_real_restart_idt:
111 .word 0xffff /* Length - real mode default value */
112 .long 0 /* Base - real mode default value */
113
114 .balign 16
115machine_real_restart_gdt:
116 /* Self-pointer */
117 .word 0xffff /* Length - real mode default value */
118 .long pa_machine_real_restart_gdt
119 .word 0
120
121 /*
122 * 16-bit code segment pointing to real_mode_seg
123 * Selector value 8
124 */
125 .word 0xffff /* Limit */
126 .long 0x9b000000 + pa_real_mode_base
127 .word 0
128
129 /*
130 * 16-bit data segment with the selector value 16 = 0x10 and
131 * base value 0x100; since this is consistent with real mode
132 * semantics we don't have to reload the segments once CR0.PE = 0.
133 */
134 .quad GDT_ENTRY(0x0093, 0x100, 0xffff)