#if 0
;  first.S  -  LILO first stage boot loader with LBA32 support */
Copyright 1992-1998 Werner Almesberger.
Copyright 1999-2003 John Coffman.
All rights reserved.

Licensed under the terms contained in the file 'COPYING' in the 
source directory.

#endif
#define LILO_ASM
#include "lilo.h"
get common.s            /* as86 "include" will bypass the CPP */

#define VALIDATE 1              /* adds 13h bytes */
#define SECOND_CHECK 1          /* adds  5h bytes */
#define CYL1023 0               /* subs  8h bytes */

#if VERSION_MINOR>=50
# define DEBUG_NEW
# undef VIDEO_ENABLE
# define VIDEO_ENABLE 3
#endif


!  VIDEO_ENABLE for those systems that disable the video on boot
!       = 0             first stage does not enable video
!       = 1             use get vid mode/set vid mode to enable
!       = 2             use VGA enable call to enable video
!                       (cannot use, as code gets too big)
!       = 3             use direct mode set (mode 3, CGA, EGA, VGA)
!       = 7             use direct mode set (mode 7, MDA)
!
#ifndef VIDEO_ENABLE
# if VALIDATE==0
#  define VIDEO_ENABLE 2
# else
#  define VIDEO_ENABLE 2
# endif
#endif

! do not change the following -- it must correspond to the code in bsect.c
#define RELOCATABLE -1


        .text

        .globl  _main

        .org    0

zero:
_main:  cli                     ! NT 4 blows up if this is missing
        jmp     start

stage:  .byte   STAGE_FIRST
        .org    4
reloc:
#if RELOCATABLE
        .word   theend-zero     ! size of the code & params
#else
        .word   0               ! no size indication
#endif
        .org    6

! Boot device parameters. They are set by the installer.

sig:    .ascii  "LILO"
vers:   .word   VERSION
mapstamp: .long 0               ! map timestamp

length  =  *-sig                ! for the stage 1 vs stage 2 comparison

raid:   .long   0               ! raid sector offset
tstamp: .long   0               ! timestamp
map_serial_no:  .long   0       ! volume S/N containing map file
prompt: .byte   0               ! indicates whether to always enter prompt
                                ! contains many other flags, too

d_dev:  .byte   0x80            ! map file device code
d_flag: .byte   0               ! disk addressing flags
d_addr: .long   0               ! disk addr of second stage index sector


edd_packet      =  0
;;;     .word   16              ! size of packet
;;;     .word   1               ! count of bytes to read

edd_addr        =  4
;;;     .word   map2            ! where to read
;;;     .word   *-*             ! segment where to read

edd_d_addr      =  8
;;;     .long   1               ! low address or CX,DX (geometric)
                                ! start at sector 1 for search in geo mode

;;;     .long   0               ! hi address

#if 0
!  These locations are referenced as EX_OFF 
!                                       (they used to be at CODE_START_1)
ext_si: .word   0               ! external interface
ext_es: .word   0               ! these locations are referenced in second.S
ext_bx: .word   0               ! do not disturb the ordering
ext_dl: .byte   0               ! second.S will check this magic number
ext_dh: .byte   0               ! not referenced, but must align stack
ext_stack:
#endif
        
/***************************************************/
!       The following instruction MUST be
!       first instruction after the CLI/JMP short
!       at the start of the file; otherwise
!       the boot sector relocation fails.
!
start:
        mov     ax,#BOOTSEG     ! use DS,ES,SS = 0x07C0
/***************************************************/

        mov     ss,ax
        mov     sp,#SETUP_STACKSIZE     ! set the stack for First Stage
        sti                     ! now it is safe

        push    dx              ! set ext_dl (and ext_dh, which is not used)
        push    bx              ! WATCH the order of pushes
        push    es              ! set ext_es
        push    si              ! set ext_si

#ifdef DEBUG_NEW
        push    ds
        push    es      ! just not enough space with debug turned on
#endif

#define JRC_DS_EQ_SS

        cld                     ! do not forget to do this !!!
        mov     ds,ax           ! address data area
        xor     bp,bp           ! shorted addressing

#if VIDEO_ENABLE
! a BIOS has been found where the video interrupt (0x10) trashes DX
!   so, we had better be very paranoid about DX
!
# if VIDEO_ENABLE==2
        pusha                   ! protect DX
# endif
# if VIDEO_ENABLE > 2
        mov     ax,#VIDEO_ENABLE        ! set video mode 3 or 7
# elif VIDEO_ENABLE==1
        mov     ah,#15          ! get video mode
        int     0x10
        cbw
# else  /* VIDEO_ENABLE==2 */
        mov     ax,#0x1200      ! enable video (VGA)
        mov     bl,#0x36        ! (probably a nop on EGA or MDA)
# endif
        int     0x10            ! video call
# if VIDEO_ENABLE==2
        popa                    ! restore DX
# endif
#endif

#if (VIDEO_ENABLE&1) == 0
        mov     al,#0x0d        ! gimme a CR ...
        call    display
; the suspect call for trashing DX on one BIOS:
        mov     al,#0x0a        ! ... an LF ...
        call    display
#endif

#if defined(DEBUG_NEW)
        mov     ah,dl
        call    bout            ! code in AH
#endif
        mov     al,#0x4c        ! ... an 'L' ...
        call    display

        pusha                   ! preserve all the registers for restart

lagain:
        push    ds
        pop     es              ! use buffer at end of boot sector

        cmp     dl,#EX_DL_MAG   ! possible boot command line (chain.S)
        jne     boot_in_dl
        mov     dl,dh           ! code passed in DH instead
boot_in_dl:

        mov     bx,#map2        ! buffer for volume search
        mov     dh,[d_dev](bp)  ! map device to DH

#if VALIDATE
        mov     ax,dx           ! copy device code to AL
        and     ah,#0x80        ! AH = 00 or 80
        xor     al,ah           ! hi-bits must be the same
        js      use_installed
        cmp     al,#MAX_BIOS_DEVICES    ! limit the device code
        jae     use_installed   ! jump if DL is not valid

! map is on boot device for RAID1, and if so marked; viz.,

        test    byte ptr [prompt](bp),#FLAG_MAP_ON_BOOT
        jnz     use_boot        ! as passed in from BIOS or MBR loader
#endif

use_installed:
        mov     dl,dh           ! device code to DL
        mov     edi,[map_serial_no](bp) ! to search for
        or      edi,edi
        jz      done_search

        push    dx              ! save flags

        mov     ah,#8           ! get number of hard disks
        mov     dl,#0x80
        int     0x13
        jc      error
#if 0
        movzx   cx,dl           ! extend to word in CX
#else
        xchg    ax,dx           ! AL = device count
        cbw                     ! AX = device count
        xchg    ax,cx           ! CX = device count
#endif
        mov     dx,#0x80-1      ! device 80, flags=0
vagain:
        inc     dx
        xor     eax,eax
        inc     ax
        call    disk_read       ! read 
;;;     jc      error

        cmp     edi,[PART_TABLE_OFFSET-6](bx)
        je      vol_found
        loop    vagain

        pop     dx              ! restore specified BIOS code
                                ! AX and DX are identical at this point

vol_found:
                ! uses value in DX, stack may have extra value

done_search:    
use_boot:
        push    bx              ! save map2 for later

        mov     dh,[d_flag](bp) ! get device flags to DH
        mov     si,#d_addr
        call    pread           ! increments BX

        mov     ah,#0x99        ! possible error code
        cmp     dword (bx-4),#EX_MAG_HL ! "LILO"
        jne     error

        pop     si              ! point at #map2

        push    #SETUP_STACKSIZE/16 + BOOTSEG + SECTOR_SIZE/16*2
        pop     es
        xor     bx,bx

sload:
        call    pread           ! read using map at DS:SI
        jnz     sload           ! into memory at ES:BX (auto increment)

! Verify second stage loader signature
        
        mov     si,#sig         ! pointer to signature area
        mov     di,si
        mov     cx,#length      ! number of bytes to compare
        repe
          cmpsb                 ! check Signature 1 & 2
        jne     no2nd_err       ! check Signature 2

#if SECOND_CHECK
/* it would be nice to re-incorporate this check */
        mov     al,#STAGE_SECOND
        scasb
        jne     no2nd_err
#endif

! Start the second stage loader     DS=location of Params

        push    es              ! segment of second stage
        push    bp              ! BP==0

        mov     al,#0x49        ! display an 'I'
        call    display

        retf                    ! Jump to ES:BP

! error exits below

no2nd_err:
        mov     ah,#0x9A

! no return from error
error:

#ifndef LCF_NO1STDIAG
        mov     al,#32          ! display a space
        call    display

        call    bout
#endif
        dec     byte [zero](bp)         !  CLI == 0xFA == 250
        jz      zzz
#ifndef DEBUG_NEW
        mov     sp,#SETUP_STACKSIZE-4*2-8*2     ! set the stack for First Stage
#else
        mov     sp,#SETUP_STACKSIZE-4*2-2*2-8*2 ! set the stack for First Stage
#endif
        popa                            ! restore registers for restart
        pusha
        jmp     near lagain             ! redo from start

zzz:
#ifndef DEBUG_NEW
        hlt
#endif
        jmp     zzz             ! spin; wait for Ctrl-Alt-Del

! Pointer Read -- read using pointer in DS:SI

pread:
        lodsd                   ! get address
        or      eax,eax
        jz      done
        add     eax,[raid](bp)  ! reloc is 0 on non-raid
        call    disk_read       
;;;     jc      error           ! error, complain
        add     bh,#SECTOR_SIZE/256     ! next sector
done:
        ret

! packet read routine

disk_read:
#ifndef JRC_DS_EQ_SS
        push    ds
#endif
        pusha

#ifndef JRC_DS_EQ_SS
        push    ss
        pop     ds
#endif

;;;;    push    dword #0        ! high order disk address
        push    bp
        push    bp

        push    eax             ! low order disk address
        push    es              ! memory segment ES
        push    bx              ! memory offset BX
        push    #1              ! sector count
        push    #16             ! size of packet = 16 bytes
        mov     si,sp           ! address of packet  DS:SI

        push    bx

        test    dh,#LINEAR_FLAG|LBA32_FLAG
        jz      disk_geometric
        
        test    dh,#LBA32_FLAG
        jz      disk_convert    ; it must be LINEAR

        mov     bx,#0x55AA      ;magic number
        mov     ah,#0x41
        int     0x13
        jc      disk_convert
        cmp     bx,#0xAA55      ;changed?
        jne     disk_convert
        test    cl,#EDD_PACKET  ;EDD packet calls supported
        jnz     disk_edd

disk_convert:
        push    dx
        push    es              ! protect on floppies
        mov     ah,#8           ! get geometry
        int     0x13
        pop     es
        jc      disk_error12

#if !CYL1023
        push    cx
        shr     cl,#6           ;;;;
        xchg    cl,ch      ;CX is max cylinder number
        mov     di,cx      ;DI saves it
        pop     cx
#endif
        shr     dx,#8
        xchg    ax,dx           ;AX <- DX
        inc     ax              ;AX is number of heads (256 allowed)

        and     cx,#0x003f      ;CX is number of sectors
        mul     cx              ; kills DX also
        xchg    ax,bx           ;save in BX

        mov     ax,[edd_d_addr](si)     ;low part of address
        mov     dx,[edd_d_addr+2](si)   ;hi part of address

        cmp     dx,bx
        jae     disk_error2     ;prevent division error
        div     bx              ;AX is cyl, DX is head/sect
#if CYL1023
        cmp     ax,#1023
#else
        cmp     ax,di
#endif
        ja      disk_error2     ;cyl is too big

        shl     ah,#6           ; save hi 2 bits
        xchg    al,ah
        xchg    ax,dx
        div     cl              ;AH = sec-1, AL = head
        or      dl,ah      ;form Cyl/Sec
        mov     cx,dx
        inc     cx              ; sector is 1 based

        pop     dx              ! restore device code
        mov     dh,al           ! set head#
        jmp     disk_read2

disk_geometric:
        push    eax
        pop     cx
        pop     ax
        mov     dh,ah

disk_read2:
        mov     ax,#0x201       ;read, count of 1
        jmp     disk_int13

disk_edd:
        mov     ah,#0x42

disk_int13:

        pop     bx

        mov     bp,#5
disk_retry:
        pusha
        int     0x13
        jnc     disk_okay

        dec     bp
        jz      disk_err

        xor     ax,ax           ! reset the disk controller
        int     0x13
        popa                    ! reset AX,BX,CX,DX,SI
        jmp     disk_retry

disk_error2:
        mov     ah,#0x40        ; signal seek error
disk_error12:

disk_err:
        jmp     near error

disk_okay:
; the pusha block is implicitly removed below
disk_ret:
        mov     (si+2*16-1),ah  ! set error code
        lea     sp,(si+16)      ! do not touch carry; 
        popa
#ifndef JRC_DS_EQ_SS
        pop     ds
#endif
        ret






#ifndef LCF_NO1STDIAG
bout:   rol     ax,#4           ! bring hi-nibble to position
        call    nout
        rol     ax,#4           ! bring lo-nibble to position
nout:   and     al,#0x0F        ! display one nibble
        daa                     ! shorter conversion routine
        add     al,#0xF0
        adc     al,#0x40        ! is now a hex char 0..9A..F
#endif
; display - write byte in AL to console
;       preserves all register contents
; 
display: pusha          ! make sure no register is changed
        mov     bx,#7           !  BH=0, BL=07
;;;     xor     bh,bh           ! BH=0, page to write to
        mov     ah,#14
        int     0x10
        popa            ! restore all the registers
        ret


theend:

!
!   If 'first' loads as the MBR, then there must be space for the partition
!   table.  If 'first' loads as the boot record of some partition, then
!   the space reserved below is not used.  But we must reserve the area
!   as a hedge against the first case.
!
!
        .org    MAX_BOOT_SIZE   !
        .word   0,0,0,0         ! space for NT, DRDOS, and LILO volume S/N

!       .org    0x1be           ! spot for the partition table
p_table:
        .blkb   16
        .blkb   16
        .blkb   16
        .blkb   16
#ifdef FIRST
        .org    *-2
        .long   FIRST           ! boot block check
#else
        .word   0xAA55          ! boot block signature
#endif

! Better be exactly 0x200

map2    equ     *               ! addressed as ES:[map2]
-- 
Some people claim that the UNIX learning curve is steep, but at least you
only have to climb it once.

Andres Roldan <[EMAIL PROTECTED]>
http://people.fluidsignal.com/~aroldan

Reply via email to