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>
This commit is contained in:
@ -17,6 +17,8 @@
|
|||||||
#ifndef BOOT_BOOT_H
|
#ifndef BOOT_BOOT_H
|
||||||
#define BOOT_BOOT_H
|
#define BOOT_BOOT_H
|
||||||
|
|
||||||
|
#define STACK_SIZE 512 /* Minimum number of bytes for stack */
|
||||||
|
|
||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
@ -198,8 +200,6 @@ static inline int isdigit(int ch)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Heap -- available for dynamic lists. */
|
/* Heap -- available for dynamic lists. */
|
||||||
#define STACK_SIZE 512 /* Minimum number of bytes for stack */
|
|
||||||
|
|
||||||
extern char _end[];
|
extern char _end[];
|
||||||
extern char *HEAP;
|
extern char *HEAP;
|
||||||
extern char *heap_end;
|
extern char *heap_end;
|
||||||
|
@ -173,7 +173,8 @@ ramdisk_size: .long 0 # its size in bytes
|
|||||||
bootsect_kludge:
|
bootsect_kludge:
|
||||||
.long 0 # obsolete
|
.long 0 # obsolete
|
||||||
|
|
||||||
heap_end_ptr: .word _end+1024 # (Header version 0x0201 or later)
|
heap_end_ptr: .word _end+STACK_SIZE-512
|
||||||
|
# (Header version 0x0201 or later)
|
||||||
# space from here (exclusive) down to
|
# space from here (exclusive) down to
|
||||||
# end of setup code can be used by setup
|
# end of setup code can be used by setup
|
||||||
# for local heap purposes.
|
# for local heap purposes.
|
||||||
@ -230,28 +231,53 @@ start_of_setup:
|
|||||||
int $0x13
|
int $0x13
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
# We will have entered with %cs = %ds+0x20, normalize %cs so
|
|
||||||
# it is on par with the other segments.
|
|
||||||
pushw %ds
|
|
||||||
pushw $setup2
|
|
||||||
lretw
|
|
||||||
|
|
||||||
setup2:
|
|
||||||
# Force %es = %ds
|
# Force %es = %ds
|
||||||
movw %ds, %ax
|
movw %ds, %ax
|
||||||
movw %ax, %es
|
movw %ax, %es
|
||||||
cld
|
cld
|
||||||
|
|
||||||
# Stack paranoia: align the stack and make sure it is good
|
# Apparently some ancient versions of LILO invoked the kernel
|
||||||
# for both 16- and 32-bit references. In particular, if we
|
# with %ss != %ds, which happened to work by accident for the
|
||||||
# were meant to have been using the full 16-bit segment, the
|
# old code. If the CAN_USE_HEAP flag is set in loadflags, or
|
||||||
# caller might have set %sp to zero, which breaks %esp-based
|
# %ss != %ds, then adjust the stack pointer.
|
||||||
# references.
|
|
||||||
andw $~3, %sp # dword align (might as well...)
|
# Smallest possible stack we can tolerate
|
||||||
jnz 1f
|
movw $(_end+STACK_SIZE), %cx
|
||||||
movw $0xfffc, %sp # Make sure we're not zero
|
|
||||||
1: movzwl %sp, %esp # Clear upper half of %esp
|
movw heap_end_ptr, %dx
|
||||||
sti
|
addw $512, %dx
|
||||||
|
jnc 1f
|
||||||
|
xorw %dx, %dx # Wraparound - whole segment available
|
||||||
|
1: testb $CAN_USE_HEAP, loadflags
|
||||||
|
jnz 2f
|
||||||
|
|
||||||
|
# No CAN_USE_HEAP
|
||||||
|
movw %ss, %dx
|
||||||
|
cmpw %ax, %dx # %ds == %ss?
|
||||||
|
movw %sp, %dx
|
||||||
|
# If so, assume %sp is reasonably set, otherwise use
|
||||||
|
# the smallest possible stack.
|
||||||
|
jne 4f # -> Smallest possible stack...
|
||||||
|
|
||||||
|
# Make sure the stack is at least minimum size. Take a value
|
||||||
|
# of zero to mean "full segment."
|
||||||
|
2:
|
||||||
|
andw $~3, %dx # dword align (might as well...)
|
||||||
|
jnz 3f
|
||||||
|
movw $0xfffc, %dx # Make sure we're not zero
|
||||||
|
3: cmpw %cx, %dx
|
||||||
|
jnb 5f
|
||||||
|
4: movw %cx, %dx # Minimum value we can possibly use
|
||||||
|
5: movw %ax, %ss
|
||||||
|
movzwl %dx, %esp # Clear upper half of %esp
|
||||||
|
sti # Now we should have a working stack
|
||||||
|
|
||||||
|
# We will have entered with %cs = %ds+0x20, normalize %cs so
|
||||||
|
# it is on par with the other segments.
|
||||||
|
pushw %ds
|
||||||
|
pushw $6f
|
||||||
|
lretw
|
||||||
|
6:
|
||||||
|
|
||||||
# Check signature at end of setup
|
# Check signature at end of setup
|
||||||
cmpl $0x5a5aaa55, setup_sig
|
cmpl $0x5a5aaa55, setup_sig
|
||||||
|
Reference in New Issue
Block a user