2 ; first.S - LILO first stage boot loader with LBA32 support */
3 Copyright 1992-1998 Werner Almesberger.
4 Copyright 1999-2005 John Coffman.
7 Licensed under the terms contained in the file 'COPYING' in the
13 get common.s /* as86 "include" will bypass the CPP */
21 # define VIDEO_ENABLE 3
23 # define VALIDATE !DEBUG /* adds 0Dh bytes */
24 # define SECOND_CHECK !DEBUG /* adds 5h bytes */
25 # define CYL1023 DEBUG /* subs 8h bytes */
26 # define GEOMETRIC !DEBUG /* adds 1h byte */
33 # define VALIDATE 1 /* adds 0Dh bytes */
34 # define SECOND_CHECK 1 /* adds 5h bytes */
35 # define CYL1023 0 /* subs 8h bytes */
36 # define GEOMETRIC 1 /* adds 1h byte */
40 ! VIDEO_ENABLE for those systems that disable the video on boot
41 ! = 0 first stage does not enable video
42 ! = 1 use get vid mode/set vid mode to enable
43 ! = 2 use VGA enable call to enable video
44 ! (cannot use, as code gets too big)
45 ! = 3 use direct mode set (mode 3, CGA, EGA, VGA)
46 ! = 7 use direct mode set (mode 7, MDA)
50 # define VIDEO_ENABLE 2
52 # define VIDEO_ENABLE 2
56 ! do not change the following -- it must correspond to the code in bsect.c
57 #define RELOCATABLE -1
67 _main: cli ! NT 4 blows up if this is missing
70 stage: .byte STAGE_FIRST
74 .word theend-zero ! size of the code & params
76 .word 0 ! no size indication
80 ! Boot device parameters. They are set by the installer.
84 mapstamp: .long 0 ! map timestamp
86 length = *-sig ! for the stage 1 vs stage 2 comparison
88 raid: .long 0 ! raid sector offset
89 tstamp: .long 0 ! timestamp
90 map_serial_no: .long 0 ! volume S/N containing map file
91 prompt: .word 0 ! indicates whether to always enter prompt
92 ! contains many other flags, too
94 d_dev: .byte 0x80 ! map file device code
95 d_flag: .byte 0 ! disk addressing flags
96 d_addr: .long 0 ! disk addr of second stage index sector
100 ;;; .word 16 ! size of packet
101 ;;; .word 1 ! count of bytes to read
104 ;;; .word map2 ! where to read
105 ;;; .word *-* ! segment where to read
108 ;;; .long 1 ! low address or CX,DX (geometric)
109 ! start at sector 1 for search in geo mode
111 ;;; .long 0 ! hi address
114 ! These locations are referenced as EX_OFF
115 ! (they used to be at CODE_START_1)
116 ext_si: .word 0 ! external interface
117 ext_es: .word 0 ! these locations are referenced in second.S
118 ext_bx: .word 0 ! do not disturb the ordering
119 ext_dl: .byte 0 ! second.S will check this magic number
120 ext_dh: .byte 0 ! not referenced, but must align stack
124 /***************************************************/
125 ! The following instruction MUST be
126 ! first instruction after the CLI/JMP short
127 ! at the start of the file; otherwise
128 ! the boot sector relocation fails.
131 mov ax,#BOOTSEG ! use DS,ES,SS = 0x07C0
132 /***************************************************/
135 mov sp,#SETUP_STACKSIZE ! set the stack for First Stage
138 push dx ! set ext_dl (and ext_dh, which is not used)
139 push bx ! WATCH the order of pushes
145 push es ! just not enough space with debug turned on
150 cld ! do not forget to do this !!!
151 mov ds,ax ! address data area
152 xor bp,bp ! shorted addressing
155 ! a BIOS has been found where the video interrupt (0x10) trashes DX
156 ! so, we had better be very paranoid about DX
161 # if VIDEO_ENABLE > 2
162 mov ax,#VIDEO_ENABLE ! set video mode 3 or 7
163 # elif VIDEO_ENABLE==1
164 mov ah,#15 ! get video mode
167 # else /* VIDEO_ENABLE==2 */
168 mov ax,#0x1200 ! enable video (VGA)
169 mov bl,#0x36 ! (probably a nop on EGA or MDA)
171 int 0x10 ! video call
177 #if (VIDEO_ENABLE&1) == 0
178 mov al,#0x0d ! gimme a CR ...
180 ; the suspect call for trashing DX on one BIOS:
181 mov al,#0x0a ! ... an LF ...
185 #if defined(DEBUG_NEW)
187 call bout ! code in AH
189 mov al,#0x4c ! ... an 'L' ...
193 pusha ! preserve all the registers for restart
196 pop es ! use buffer at end of boot sector
198 cmp dl,#EX_DL_MAG ! possible boot command line (chain.S)
200 mov dl,dh ! code passed in DH instead
203 mov bx,#map2 ! buffer for volume search
204 mov dh,[d_dev](bp) ! map device to DH
207 mov ax,dx ! copy device code to AL
208 and ah,#0x80 ! AH = 00 or 80
209 xor al,ah ! hi-bits must be the same
211 cmp al,#MAX_BIOS_DEVICES ! limit the device code
212 jae use_installed ! jump if DL is not valid
215 ! map is on boot device for RAID1, and if so marked; viz.,
217 test byte ptr [prompt](bp),#FLAG_MAP_ON_BOOT
218 jnz use_boot ! as passed in from BIOS or MBR loader
221 mov dl,dh ! device code to DL
222 mov esi,[map_serial_no](bp) ! to search for
228 mov ah,#8 ! get number of hard disks
235 movzx cx,dl ! extend to word in CX
238 mov dx,#0x80-1 ! device 80, flags=0
240 mov dx,#LBA32_FLAG*256+0x80-1 ! device 80, flags=LBA32
247 inc ax ! geometric addressing
249 call disk_read ! read
251 cmp esi,[PART_TABLE_OFFSET-6](bx)
255 pop dx ! restore specified BIOS code
256 ! AX and DX are identical at this point
259 ! uses value in DX, stack may have extra value
263 push bx ! save map2 for later
265 mov dh,[d_flag](bp) ! get device flags to DH
267 call pread ! increments BX
269 mov ah,#0x99 ! possible error code
270 cmp dword (bx-4),#EX_MAG_HL ! "LILO"
273 pop si ! point at #map2
276 push #SETUP_STACKSIZE/16 + BOOTSEG + SECTOR_SIZE/16*2
279 mov ax,ds ! get segment
280 add ax,#SETUP_STACKSIZE/16 ! + SECTOR_SIZE/16*2
286 call pread ! read using map at DS:SI
287 jnz sload ! into memory at ES:BX (auto increment)
289 ! Verify second stage loader signature
291 mov si,#sig ! pointer to signature area
293 mov cx,#length ! number of bytes to compare
294 mov ah,#0x9A ! possible error code
296 cmpsb ! check Signature 1 & 2
297 jne error ! check Signature 2
300 /* it would be nice to re-incorporate this check */
301 mov al,#STAGE_SECOND ! do not touch AH (error code)
306 ! Start the second stage loader DS=location of Params
308 push es ! segment of second stage
311 mov al,#0x49 ! display an 'I'
320 mov ah,#0x40 ; signal seek error
322 ! no return from error
325 #ifndef LCF_NO1STDIAG
326 mov al,#32 ! display a space
333 dec byte [zero](bp) ! CLI == 0xFA == 250
337 mov sp,#SETUP_STACKSIZE-4*2-8*2 ! set the stack for First Stage
339 mov sp,#SETUP_STACKSIZE-4*2-2*2-8*2 ! set the stack for First Stage
341 popa ! restore registers for restart
342 jmp near lagain ! redo from start
350 jmp zzz ! spin; wait for Ctrl-Alt-Del
355 ! packet read routine
371 push eax ! low order disk address
376 call dout ! print out disk address
378 push es ! memory segment ES
379 push bx ! memory offset BX
380 push #1 ! sector count
381 push #16 ! size of packet = 16 bytes
382 mov si,sp ! address of packet DS:SI
386 test dh,#LINEAR_FLAG|LBA32_FLAG
390 jz disk_convert ; it must be LINEAR
392 mov bx,#0x55AA ;magic number
396 cmp bx,#0xAA55 ;changed?
398 test cl,#EDD_PACKET ;EDD packet calls supported
403 push es ! protect on floppies
404 mov ah,#8 ! get geometry
407 disk_error3: ! transfer through on CF=1
408 jc error ! disk_error12
413 xchg cl,ch ;CX is max cylinder number
414 mov di,cx ;DI saves it
419 inc ax ;AX is number of heads (256 allowed)
421 ; compensate for Davide BIOS bug
422 dec cx ; 1..63 -> 0..62; 0->63
423 and cx,#0x003f ;CX is number of sectors
424 inc cx ; allow Sectors==0 to mean 64
426 mul cx ; kills DX also
427 xchg ax,bx ;save in BX
429 mov ax,[edd_d_addr](si) ;low part of address
430 mov dx,[edd_d_addr+2](si) ;hi part of address
433 jae disk_error2 ;prevent division error
435 div bx ;AX is cyl, DX is head/sect
441 ja disk_error2 ;cyl is too big
443 shl ah,#6 ; save hi 2 bits
446 div cl ;AH = sec-1, AL = head
447 or dl,ah ;form Cyl/Sec
449 inc cx ; sector is 1 based
451 pop dx ! restore device code
452 mov dh,al ! set head#
472 dec bp ! does not alter CF, already 0
473 jz disk_error3 ! go to "jc" with CF=1 & ZF=1
475 xor ax,ax ! reset the disk controller
477 popa ! reset AX,BX,CX,DX,SI
478 dec bp ! fix up BP count
489 mov ax,#0x201 ;read, count of 1
494 ; the pusha block is implicitly removed below
495 ;;; mov (si+2*16-1),ah ! set error code
496 ; the error code is never checked
497 lea sp,(si+16) ! do not touch carry;
506 ! Pointer Read -- read using pointer in DS:SI
512 add eax,[raid](bp) ! reloc is 0 on non-raid
515 add bh,#SECTOR_SIZE/256 ! next sector
522 #if !defined(LCF_NO1STDIAG) || defined(DEBUG_NEW)
523 bout: rol ax,#4 ! bring hi-nibble to position
525 rol ax,#4 ! bring lo-nibble to position
526 nout: and al,#0x0F ! display one nibble
527 daa ! shorter conversion routine
529 adc al,#0x40 ! is now a hex char 0..9A..F
531 ; display - write byte in AL to console
532 ; preserves all register contents
538 pusha ! make sure no register is changed
539 mov bx,#7 ! BH=0, BL=07
542 popa ! restore all the registers
561 call bout ! put out AH
565 call bout ! put out AL (now in AH)
573 ! If 'first' loads as the MBR, then there must be space for the partition
574 ! table. If 'first' loads as the boot record of some partition, then
575 ! the space reserved below is not used. But we must reserve the area
576 ! as a hedge against the first case.
580 .word 0,0,0,0 ! space for NT, DRDOS, and LiLO volume S/N
582 ! .org 0x1be ! spot for the partition table
590 .long FIRST ! boot block check
592 .word 0xAA55 ! boot block signature
595 ! Better be exactly 0x200
597 map2 equ * ! addressed as ES:[map2]