From real mode to protected mode
bootsect or LILO will jump to this setup function which located at 0x9020:0000.
/* Because LILO only load 4 sectors of setup to 0x90200, so left will be copied to 0x10000 with system if setup has more than 4 sectors. move rest of setup code/data from 0x10000 to 0x90800*/
! We now have to find the rest of the setup code/data
bad_sig:
mov ax,cs ! aka #SETUPSEG
sub ax,#DELTA_INITSEG ! aka #INITSEG
mov ds,ax
xor bh,bh
mov bl,[497] ! get setup sects from boot sector
sub bx,#4 ! LILO loads 4 sectors of setup
shl bx,#8 ! convert to words
mov cx,bx
shr bx,#3 ! convert to segment
add bx,#SYSSEG
seg cs
mov start_sys_seg,bx /*
! Move rest of setup code/data to here
mov di,#2048 ! four sectors loaded by LILO
sub si,si
mov ax,cs ! aka #SETUPSEG
mov es,ax
mov ax,#SYSSEG
mov ds,ax
rep
movsw
mov ax,cs ! aka #SETUPSEG
mov ds,ax
cmp setup_sig1,#SIG1
jne no_sig
cmp setup_sig2,#SIG2
jne no_sig
jmp good_sig /* completed successfully */
/* if a20 is turned off, then only 20bit address pin is available, that it, maximun adress is 0xffff0 + 0xffff = 0x10ffef, and contents of 0x00000 - 0x0ffef is the same with 0x10000 - 0x10ffef. so following check whether contents of 0x0007c is the same with 0x1007c, if not the same, then A20 is turned on */
! wait until a20 really *is* enabled; it can take a fair amount of
! time on certain systems; Toshiba Tecras are known to have this
! problem. The memory location used here is the int 0x1f vector,
! which should be safe to use; any *unused* memory location < 0xfff0
! should work here.
#define TEST_ADDR 0x7c
push ds
xor ax,ax ! segment 0x0000
mov ds,ax
dec ax ! segment 0xffff (HMA)
mov gs,ax
mov bx,[TEST_ADDR] ! we want to restore the value later
a20_wait:
inc ax
mov [TEST_ADDR],ax
seg gs
cmp ax,[TEST_ADDR+0x10] /* 0xffff0 + 0x008c = 0x10007c */
je a20_wait ! loop until no longer aliased
mov [TEST_ADDR],bx ! restore original value
pop ds
/* turn on PE bit, and jump to physical address: 0x100000 (bzImage) or 0x1000 (zImage) */
mov ax,#1 ! protected mode (PE) bit
lmsw ax ! This is it!
jmp flush_instr
flush_instr:
xor bx,bx ! Flag to indicate a boot
! NOTE: For high loaded big kernels we need a
! jmpi 0x100000,__KERNEL_CS
!
! but we yet haven't reloaded the CS register, so the default size
! of the target offset still is 16 bit.
! However, using an operant prefix (0x66), the CPU will properly
! take our 48 bit far pointer. (INTeL 80386 Programmer's Reference
! Manual, Mixing 16-bit and 32-bit code, page 16-6)
db 0x66,0xea ! prefix + jmpi-opcode
code32: dd 0x1000 ! will be set to 0x100000 for big kernels
dw __KERNEL_CS