aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2007-10-25 19:11:33 -0400
committerH. Peter Anvin <hpa@zytor.com>2007-10-25 22:55:03 -0400
commit6b6815c6d5d1dc209701d1661a7a0e09a295db2f (patch)
tree9e1c07acbc4926279fcef068efb60141c6eed2af
parentc9927c2bf4f45bb85e8b502ab3fb79ad6483c244 (diff)
x86 setup: handle boot loaders which set up the stack incorrectly
Apparently some specific versions of LILO enter the kernel with a stack pointer that doesn't match the rest of the segments. Make our best attempt at untangling the resulting mess. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--arch/x86/boot/boot.h4
-rw-r--r--arch/x86/boot/header.S62
2 files changed, 46 insertions, 20 deletions
diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h
index 5f9a2e72a731..887874f4b49f 100644
--- a/arch/x86/boot/boot.h
+++ b/arch/x86/boot/boot.h
@@ -17,6 +17,8 @@
17#ifndef BOOT_BOOT_H 17#ifndef BOOT_BOOT_H
18#define BOOT_BOOT_H 18#define BOOT_BOOT_H
19 19
20#define STACK_SIZE 512 /* Minimum number of bytes for stack */
21
20#ifndef __ASSEMBLY__ 22#ifndef __ASSEMBLY__
21 23
22#include <stdarg.h> 24#include <stdarg.h>
@@ -198,8 +200,6 @@ static inline int isdigit(int ch)
198} 200}
199 201
200/* Heap -- available for dynamic lists. */ 202/* Heap -- available for dynamic lists. */
201#define STACK_SIZE 512 /* Minimum number of bytes for stack */
202
203extern char _end[]; 203extern char _end[];
204extern char *HEAP; 204extern char *HEAP;
205extern char *heap_end; 205extern char *heap_end;
diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index 8353c81c41c0..6ef5a060fa11 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -173,7 +173,8 @@ ramdisk_size: .long 0 # its size in bytes
173bootsect_kludge: 173bootsect_kludge:
174 .long 0 # obsolete 174 .long 0 # obsolete
175 175
176heap_end_ptr: .word _end+1024 # (Header version 0x0201 or later) 176heap_end_ptr: .word _end+STACK_SIZE-512
177 # (Header version 0x0201 or later)
177 # space from here (exclusive) down to 178 # space from here (exclusive) down to
178 # end of setup code can be used by setup 179 # end of setup code can be used by setup
179 # for local heap purposes. 180 # for local heap purposes.
@@ -230,28 +231,53 @@ start_of_setup:
230 int $0x13 231 int $0x13
231#endif 232#endif
232 233
233# We will have entered with %cs = %ds+0x20, normalize %cs so
234# it is on par with the other segments.
235 pushw %ds
236 pushw $setup2
237 lretw
238
239setup2:
240# Force %es = %ds 234# Force %es = %ds
241 movw %ds, %ax 235 movw %ds, %ax
242 movw %ax, %es 236 movw %ax, %es
243 cld 237 cld
244 238
245# Stack paranoia: align the stack and make sure it is good 239# Apparently some ancient versions of LILO invoked the kernel
246# for both 16- and 32-bit references. In particular, if we 240# with %ss != %ds, which happened to work by accident for the
247# were meant to have been using the full 16-bit segment, the 241# old code. If the CAN_USE_HEAP flag is set in loadflags, or
248# caller might have set %sp to zero, which breaks %esp-based 242# %ss != %ds, then adjust the stack pointer.
249# references. 243
250 andw $~3, %sp # dword align (might as well...) 244 # Smallest possible stack we can tolerate
251 jnz 1f 245 movw $(_end+STACK_SIZE), %cx
252 movw $0xfffc, %sp # Make sure we're not zero 246
2531: movzwl %sp, %esp # Clear upper half of %esp 247 movw heap_end_ptr, %dx
254 sti 248 addw $512, %dx
249 jnc 1f
250 xorw %dx, %dx # Wraparound - whole segment available
2511: testb $CAN_USE_HEAP, loadflags
252 jnz 2f
253
254 # No CAN_USE_HEAP
255 movw %ss, %dx
256 cmpw %ax, %dx # %ds == %ss?
257 movw %sp, %dx
258 # If so, assume %sp is reasonably set, otherwise use
259 # the smallest possible stack.
260 jne 4f # -> Smallest possible stack...
261
262 # Make sure the stack is at least minimum size. Take a value
263 # of zero to mean "full segment."
2642:
265 andw $~3, %dx # dword align (might as well...)
266 jnz 3f
267 movw $0xfffc, %dx # Make sure we're not zero
2683: cmpw %cx, %dx
269 jnb 5f
2704: movw %cx, %dx # Minimum value we can possibly use
2715: movw %ax, %ss
272 movzwl %dx, %esp # Clear upper half of %esp
273 sti # Now we should have a working stack
274
275# We will have entered with %cs = %ds+0x20, normalize %cs so
276# it is on par with the other segments.
277 pushw %ds
278 pushw $6f
279 lretw
2806:
255 281
256# Check signature at end of setup 282# Check signature at end of setup
257 cmpl $0x5a5aaa55, setup_sig 283 cmpl $0x5a5aaa55, setup_sig