1. 程式人生 > >From real mode to protected mode

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          /*

 update the correct start address of system */

! 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