win: Use lower-case private definition of STORAGE_DEVICE_NUMBER
[syslinux/sherbszt.git] / core / isolinux.asm
blob7a871f0e82c7ffef1bb0daa8ac7578c84858a2b1
1 ; -*- fundamental -*- (asm-mode sucks)
2 ; ****************************************************************************
4 ; isolinux.asm
6 ; A program to boot Linux kernels off a CD-ROM using the El Torito
7 ; boot standard in "no emulation" mode, making the entire filesystem
8 ; available. It is based on the SYSLINUX boot loader for MS-DOS
9 ; floppies.
11 ; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
12 ; Copyright 2009 Intel Corporation; author: H. Peter Anvin
14 ; This program is free software; you can redistribute it and/or modify
15 ; it under the terms of the GNU General Public License as published by
16 ; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
17 ; Boston MA 02111-1307, USA; either version 2 of the License, or
18 ; (at your option) any later version; incorporated herein by reference.
20 ; ****************************************************************************
22 %define IS_ISOLINUX 1
23 %include "head.inc"
26 ; Some semi-configurable constants... change on your own risk.
28 my_id equ isolinux_id
29 NULLFILE equ 0 ; Zero byte == null file name
30 NULLOFFSET equ 0 ; Position in which to look
31 retry_count equ 6 ; How patient are we with the BIOS?
32 %assign HIGHMEM_SLOP 128*1024 ; Avoid this much memory near the top
33 SECTOR_SHIFT equ 11 ; 2048 bytes/sector (El Torito requirement)
34 SECTOR_SIZE equ (1 << SECTOR_SHIFT)
36 ROOT_DIR_WORD equ 0x002F
39 ; The following structure is used for "virtual kernels"; i.e. LILO-style
40 ; option labels. The options we permit here are `kernel' and `append
41 ; Since there is no room in the bottom 64K for all of these, we
42 ; stick them in high memory and copy them down before we need them.
44 struc vkernel
45 vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!**
46 vk_rname: resb FILENAME_MAX ; Real name
47 vk_appendlen: resw 1
48 vk_type: resb 1 ; Type of file
49 alignb 4
50 vk_append: resb max_cmd_len+1 ; Command line
51 alignb 4
52 vk_end: equ $ ; Should be <= vk_size
53 endstruc
55 ; ---------------------------------------------------------------------------
56 ; BEGIN CODE
57 ; ---------------------------------------------------------------------------
60 ; Memory below this point is reserved for the BIOS and the MBR
62 section .earlybss
63 global trackbuf
64 trackbufsize equ 8192
65 trackbuf resb trackbufsize ; Track buffer goes here
66 ; ends at 2800h
68 ; Some of these are touched before the whole image
69 ; is loaded. DO NOT move this to .bss16/.uibss.
70 section .earlybss
71 alignb 4
72 FirstSecSum resd 1 ; Checksum of bytes 64-2048
73 ImageDwords resd 1 ; isolinux.bin size, dwords
74 InitStack resd 1 ; Initial stack pointer (SS:SP)
75 DiskSys resw 1 ; Last INT 13h call
76 ImageSectors resw 1 ; isolinux.bin size, sectors
77 ; These following two are accessed as a single dword...
78 GetlinsecPtr resw 1 ; The sector-read pointer
79 BIOSName resw 1 ; Display string for BIOS type
80 %define HAVE_BIOSNAME 1
81 BIOSType resw 1
82 DiskError resb 1 ; Error code for disk I/O
83 DriveNumber resb 1 ; CD-ROM BIOS drive number
84 ISOFlags resb 1 ; Flags for ISO directory search
85 RetryCount resb 1 ; Used for disk access retries
87 alignb 8
88 Hidden resq 1 ; Used in hybrid mode
89 bsSecPerTrack resw 1 ; Used in hybrid mode
90 bsHeads resw 1 ; Used in hybrid mode
94 ; El Torito spec packet
97 alignb 8
98 _spec_start equ $
99 spec_packet: resb 1 ; Size of packet
100 sp_media: resb 1 ; Media type
101 sp_drive: resb 1 ; Drive number
102 sp_controller: resb 1 ; Controller index
103 sp_lba: resd 1 ; LBA for emulated disk image
104 sp_devspec: resw 1 ; IDE/SCSI information
105 sp_buffer: resw 1 ; User-provided buffer
106 sp_loadseg: resw 1 ; Load segment
107 sp_sectors: resw 1 ; Sector count
108 sp_chs: resb 3 ; Simulated CHS geometry
109 sp_dummy: resb 1 ; Scratch, safe to overwrite
112 ; EBIOS drive parameter packet
114 alignb 8
115 drive_params: resw 1 ; Buffer size
116 dp_flags: resw 1 ; Information flags
117 dp_cyl: resd 1 ; Physical cylinders
118 dp_head: resd 1 ; Physical heads
119 dp_sec: resd 1 ; Physical sectors/track
120 dp_totalsec: resd 2 ; Total sectors
121 dp_secsize: resw 1 ; Bytes per sector
122 dp_dpte: resd 1 ; Device Parameter Table
123 dp_dpi_key: resw 1 ; 0BEDDh if rest valid
124 dp_dpi_len: resb 1 ; DPI len
125 resb 1
126 resw 1
127 dp_bus: resb 4 ; Host bus type
128 dp_interface: resb 8 ; Interface type
129 db_i_path: resd 2 ; Interface path
130 db_d_path: resd 2 ; Device path
131 resb 1
132 db_dpi_csum: resb 1 ; Checksum for DPI info
135 ; EBIOS disk address packet
137 alignb 8
138 dapa: resw 1 ; Packet size
139 .count: resw 1 ; Block count
140 .off: resw 1 ; Offset of buffer
141 .seg: resw 1 ; Segment of buffer
142 .lba: resd 2 ; LBA (LSW, MSW)
145 ; Spec packet for disk image emulation
147 alignb 8
148 dspec_packet: resb 1 ; Size of packet
149 dsp_media: resb 1 ; Media type
150 dsp_drive: resb 1 ; Drive number
151 dsp_controller: resb 1 ; Controller index
152 dsp_lba: resd 1 ; LBA for emulated disk image
153 dsp_devspec: resw 1 ; IDE/SCSI information
154 dsp_buffer: resw 1 ; User-provided buffer
155 dsp_loadseg: resw 1 ; Load segment
156 dsp_sectors: resw 1 ; Sector count
157 dsp_chs: resb 3 ; Simulated CHS geometry
158 dsp_dummy: resb 1 ; Scratch, safe to overwrite
160 alignb 4
161 _spec_end equ $
162 _spec_len equ _spec_end - _spec_start
164 section .init
166 ;; Primary entry point. Because BIOSes are buggy, we only load the first
167 ;; CD-ROM sector (2K) of the file, so the number one priority is actually
168 ;; loading the rest.
170 StackBuf equ STACK_TOP-44 ; 44 bytes needed for
171 ; the bootsector chainloading
172 ; code!
173 OrigESDI equ StackBuf-4 ; The high dword on the stack
174 StackHome equ OrigESDI
176 bootsec equ $
178 _start: ; Far jump makes sure we canonicalize the address
180 jmp 0:_start1
181 times 8-($-$$) nop ; Pad to file offset 8
183 ; This table hopefully gets filled in by mkisofs using the
184 ; -boot-info-table option. If not, the values in this
185 ; table are default values that we can use to get us what
186 ; we need, at least under a certain set of assumptions.
187 global iso_boot_info
188 iso_boot_info:
189 bi_pvd: dd 16 ; LBA of primary volume descriptor
190 bi_file: dd 0 ; LBA of boot file
191 bi_length: dd 0xdeadbeef ; Length of boot file
192 bi_csum: dd 0xdeadbeef ; Checksum of boot file
193 bi_reserved: times 10 dd 0xdeadbeef ; Reserved
194 bi_end:
196 ; Custom entry point for the hybrid-mode disk.
197 ; The following values will have been pushed onto the
198 ; entry stack:
199 ; - partition offset (qword)
200 ; - ES
201 ; - DI
202 ; - DX (including drive number)
203 ; - CBIOS Heads
204 ; - CBIOS Sectors
205 ; - EBIOS flag
206 ; (top of stack)
208 ; If we had an old isohybrid, the partition offset will
209 ; be missing; we can check for that with sp >= 0x7c00.
210 ; Serious hack alert.
211 %ifndef DEBUG_MESSAGES
212 _hybrid_signature:
213 dd 0x7078c0fb ; An arbitrary number...
215 _start_hybrid:
216 pop cx ; EBIOS flag
217 pop word [cs:bsSecPerTrack]
218 pop word [cs:bsHeads]
219 pop dx
220 pop di
221 pop es
222 xor eax,eax
223 xor ebx,ebx
224 cmp sp,7C00h
225 jae .nooffset
226 pop eax
227 pop ebx
228 .nooffset:
229 mov si,bios_cbios
230 jcxz _start_common
231 mov si,bios_ebios
232 jmp _start_common
233 %endif
235 _start1:
236 mov si,bios_cdrom
237 xor eax,eax
238 xor ebx,ebx
239 _start_common:
240 mov [cs:InitStack],sp ; Save initial stack pointer
241 mov [cs:InitStack+2],ss
242 xor cx,cx
243 mov ss,cx
244 mov sp,StackBuf ; Set up stack
245 push es ; Save initial ES:DI -> $PnP pointer
246 push di
247 mov ds,cx
248 mov es,cx
249 mov fs,cx
250 mov gs,cx
254 mov [Hidden],eax
255 mov [Hidden+4],ebx
257 mov [BIOSType],si
258 mov eax,[si]
259 mov [GetlinsecPtr],eax
261 ; Show signs of life
262 mov si,syslinux_banner
263 call writestr_early
264 %ifdef DEBUG_MESSAGES
265 mov si,copyright_str
266 %else
267 mov si,[BIOSName]
268 %endif
269 call writestr_early
272 ; Before modifying any memory, get the checksum of bytes
273 ; 64-2048
275 initial_csum: xor edi,edi
276 mov si,bi_end
277 mov cx,(SECTOR_SIZE-64) >> 2
278 .loop: lodsd
279 add edi,eax
280 loop .loop
281 mov [FirstSecSum],edi
283 mov [DriveNumber],dl
284 %ifdef DEBUG_MESSAGES
285 mov si,startup_msg
286 call writemsg
287 mov al,dl
288 call writehex2
289 call crlf
290 %endif
292 ; Initialize spec packet buffers
294 mov di,_spec_start
295 mov cx,_spec_len >> 2
296 xor eax,eax
297 rep stosd
299 ; Initialize length field of the various packets
300 mov byte [spec_packet],13h
301 mov byte [drive_params],30
302 mov byte [dapa],16
303 mov byte [dspec_packet],13h
305 ; Other nonzero fields
306 inc word [dsp_sectors]
308 ; Are we just pretending to be a CD-ROM?
309 cmp word [BIOSType],bios_cdrom
310 jne found_drive ; If so, no spec packet...
312 ; Now figure out what we're actually doing
313 ; Note: use passed-in DL value rather than 7Fh because
314 ; at least some BIOSes will get the wrong value otherwise
315 mov ax,4B01h ; Get disk emulation status
316 mov dl,[DriveNumber]
317 mov si,spec_packet
318 call int13
319 jc award_hack ; changed for BrokenAwardHack
320 mov dl,[DriveNumber]
321 cmp [sp_drive],dl ; Should contain the drive number
322 jne spec_query_failed
324 %ifdef DEBUG_MESSAGES
325 mov si,spec_ok_msg
326 call writemsg
327 mov al,byte [sp_drive]
328 call writehex2
329 call crlf
330 %endif
332 found_drive:
333 ; Alright, we have found the drive. Now, try to find the
334 ; boot file itself. If we have a boot info table, life is
335 ; good; if not, we have to make some assumptions, and try
336 ; to figure things out ourselves. In particular, the
337 ; assumptions we have to make are:
338 ; - single session only
339 ; - only one boot entry (no menu or other alternatives)
341 cmp dword [bi_file],0 ; Address of code to load
342 jne found_file ; Boot info table present :)
344 %ifdef DEBUG_MESSAGES
345 mov si,noinfotable_msg
346 call writemsg
347 %endif
349 ; No such luck. See if the spec packet contained one.
350 mov eax,[sp_lba]
351 and eax,eax
352 jz set_file ; Good enough
354 %ifdef DEBUG_MESSAGES
355 mov si,noinfoinspec_msg
356 call writemsg
357 %endif
359 ; No such luck. Get the Boot Record Volume, assuming single
360 ; session disk, and that we're the first entry in the chain.
361 mov eax,17 ; Assumed address of BRV
362 mov bx,trackbuf
363 call getonesec
365 mov eax,[trackbuf+47h] ; Get boot catalog address
366 mov bx,trackbuf
367 call getonesec ; Get boot catalog
369 mov eax,[trackbuf+28h] ; First boot entry
370 ; And hope and pray this is us...
372 ; Some BIOSes apparently have limitations on the size
373 ; that may be loaded (despite the El Torito spec being very
374 ; clear on the fact that it must all be loaded.) Therefore,
375 ; we load it ourselves, and *bleep* the BIOS.
377 set_file:
378 mov [bi_file],eax
380 found_file:
381 ; Set up boot file sizes
382 mov eax,[bi_length]
383 sub eax,SECTOR_SIZE-3 ; ... minus sector loaded
384 shr eax,2 ; bytes->dwords
385 mov [ImageDwords],eax ; boot file dwords
386 add eax,((SECTOR_SIZE-1) >> 2)
387 shr eax,SECTOR_SHIFT-2 ; dwords->sectors
388 mov [ImageSectors],ax ; boot file sectors
390 mov eax,[bi_file] ; Address of code to load
391 inc eax ; Don't reload bootstrap code
392 %ifdef DEBUG_MESSAGES
393 mov si,offset_msg
394 call writemsg
395 call writehex8
396 call crlf
397 %endif
399 ; Load the rest of the file. However, just in case there
400 ; are still BIOSes with 64K wraparound problems, we have to
401 ; take some extra precautions. Since the normal load
402 ; address (TEXT_START) is *not* 2K-sector-aligned, we round
403 ; the target address upward to a sector boundary,
404 ; and then move the entire thing down as a unit.
405 MaxLMA equ 384*1024 ; Reasonable limit (384K)
407 mov bx,((TEXT_START+2*SECTOR_SIZE-1) & ~(SECTOR_SIZE-1)) >> 4
408 mov bp,[ImageSectors]
409 push bx ; Load segment address
411 .more:
412 push bx ; Segment address
413 push bp ; Sector count
414 mov es,bx
415 mov cx,0xfff
416 and bx,cx
417 inc cx
418 sub cx,bx
419 shr cx,SECTOR_SHIFT - 4
420 jnz .notaligned
421 mov cx,0x10000 >> SECTOR_SHIFT ; Full 64K segment possible
422 .notaligned:
423 cmp bp,cx
424 jbe .ok
425 mov bp,cx
426 .ok:
427 xor bx,bx
428 push bp
429 call getlinsec
430 pop cx
431 mov dx,cx
432 pop bp
433 pop bx
435 shl cx,SECTOR_SHIFT - 4
436 add bx,cx
437 sub bp,dx
438 jnz .more
440 ; Move the image into place, and also verify the
441 ; checksum
442 pop ax ; Load segment address
443 mov bx,(TEXT_START + SECTOR_SIZE) >> 4
444 mov ecx,[ImageDwords]
445 mov edi,[FirstSecSum] ; First sector checksum
446 xor si,si
448 move_verify_image:
449 .setseg:
450 mov ds,ax
451 mov es,bx
452 .loop:
453 mov edx,[si]
454 add edi,edx
455 dec ecx
456 mov [es:si],edx
457 jz .done
458 add si,4
459 jnz .loop
460 add ax,1000h
461 add bx,1000h
462 jmp .setseg
463 .done:
464 mov ax,cs
465 mov ds,ax
466 mov es,ax
468 ; Verify the checksum on the loaded image.
469 cmp [bi_csum],edi
470 je integrity_ok
472 mov si,checkerr_msg
473 call writemsg
474 jmp kaboom
476 integrity_ok:
477 %ifdef DEBUG_MESSAGES
478 mov si,allread_msg
479 call writemsg
480 %endif
481 jmp all_read ; Jump to main code
483 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
484 ;; Start of BrokenAwardHack --- 10-nov-2002 Knut_Petersen@t-online.de
485 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
487 ;; There is a problem with certain versions of the AWARD BIOS ...
488 ;; the boot sector will be loaded and executed correctly, but, because the
489 ;; int 13 vector points to the wrong code in the BIOS, every attempt to
490 ;; load the spec packet will fail. We scan for the equivalent of
492 ;; mov ax,0201h
493 ;; mov bx,7c00h
494 ;; mov cx,0006h
495 ;; mov dx,0180h
496 ;; pushf
497 ;; call <direct far>
499 ;; and use <direct far> as the new vector for int 13. The code above is
500 ;; used to load the boot code into ram, and there should be no reason
501 ;; for anybody to change it now or in the future. There are no opcodes
502 ;; that use encodings relativ to IP, so scanning is easy. If we find the
503 ;; code above in the BIOS code we can be pretty sure to run on a machine
504 ;; with an broken AWARD BIOS ...
506 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
508 %ifdef DEBUG_MESSAGES ;;
510 award_notice db "Trying BrokenAwardHack first ...",CR,LF,0 ;;
511 award_not_orig db "BAH: Original Int 13 vector : ",0 ;;
512 award_not_new db "BAH: Int 13 vector changed to : ",0 ;;
513 award_not_succ db "BAH: SUCCESS",CR,LF,0 ;;
514 award_not_fail db "BAH: FAILURE" ;;
515 award_not_crlf db CR,LF,0 ;;
517 %endif ;;
519 award_oldint13 dd 0 ;;
520 award_string db 0b8h,1,2,0bbh,0,7ch,0b9h,6,0,0bah,80h,1,09ch,09ah ;;
522 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
523 award_hack: mov si,spec_err_msg ; Moved to this place from
524 call writemsg ; spec_query_faild
526 %ifdef DEBUG_MESSAGES ;
528 mov si,award_notice ; display our plan
529 call writemsg ;
530 mov si,award_not_orig ; display original int 13
531 call writemsg ; vector
532 %endif ;
533 mov eax,[13h*4] ;
534 mov [award_oldint13],eax ;
536 %ifdef DEBUG_MESSAGES ;
538 call writehex8 ;
539 mov si,award_not_crlf ;
540 call writestr_early ;
541 %endif ;
542 push es ; save ES
543 mov ax,0f000h ; ES = BIOS Seg
544 mov es,ax ;
545 cld ;
546 xor di,di ; start at ES:DI = f000:0
547 award_loop: push di ; save DI
548 mov si,award_string ; scan for award_string
549 mov cx,7 ; length of award_string = 7dw
550 repz cmpsw ; compare
551 pop di ; restore DI
552 jcxz award_found ; jmp if found
553 inc di ; not found, inc di
554 jno award_loop ;
556 award_failed: pop es ; No, not this way :-((
557 award_fail2: ;
559 %ifdef DEBUG_MESSAGES ;
561 mov si,award_not_fail ; display failure ...
562 call writemsg ;
563 %endif ;
564 mov eax,[award_oldint13] ; restore the original int
565 or eax,eax ; 13 vector if there is one
566 jz spec_query_failed ; and try other workarounds
567 mov [13h*4],eax ;
568 jmp spec_query_failed ;
570 award_found: mov eax,[es:di+0eh] ; load possible int 13 addr
571 pop es ; restore ES
573 cmp eax,[award_oldint13] ; give up if this is the
574 jz award_failed ; active int 13 vector,
575 mov [13h*4],eax ; otherwise change 0:13h*4
578 %ifdef DEBUG_MESSAGES ;
580 push eax ; display message and
581 mov si,award_not_new ; new vector address
582 call writemsg ;
583 pop eax ;
584 call writehex8 ;
585 mov si,award_not_crlf ;
586 call writestr_early ;
587 %endif ;
588 mov ax,4B01h ; try to read the spec packet
589 mov dl,[DriveNumber] ; now ... it should not fail
590 mov si,spec_packet ; any longer
591 int 13h ;
592 jc award_fail2 ;
594 %ifdef DEBUG_MESSAGES ;
596 mov si,award_not_succ ; display our SUCCESS
597 call writemsg ;
598 %endif ;
599 jmp found_drive ; and leave error recovery code
601 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
602 ;; End of BrokenAwardHack ---- 10-nov-2002 Knut_Petersen@t-online.de
603 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
606 ; INT 13h, AX=4B01h, DL=<passed in value> failed.
607 ; Try to scan the entire 80h-FFh from the end.
609 spec_query_failed:
611 ; some code moved to BrokenAwardHack
613 mov dl,0FFh
614 .test_loop: pusha
615 mov ax,4B01h
616 mov si,spec_packet
617 mov byte [si],13h ; Size of buffer
618 call int13
619 popa
620 jc .still_broken
622 mov si,maybe_msg
623 call writemsg
624 mov al,dl
625 call writehex2
626 call crlf
628 cmp byte [sp_drive],dl
629 jne .maybe_broken
631 ; Okay, good enough...
632 mov si,alright_msg
633 call writemsg
634 .found_drive0: mov [DriveNumber],dl
635 .found_drive: jmp found_drive
637 ; Award BIOS 4.51 apparently passes garbage in sp_drive,
638 ; but if this was the drive number originally passed in
639 ; DL then consider it "good enough"
640 .maybe_broken:
641 mov al,[DriveNumber]
642 cmp al,dl
643 je .found_drive
645 ; Intel Classic R+ computer with Adaptec 1542CP BIOS 1.02
646 ; passes garbage in sp_drive, and the drive number originally
647 ; passed in DL does not have 80h bit set.
648 or al,80h
649 cmp al,dl
650 je .found_drive0
652 .still_broken: dec dx
653 cmp dl, 80h
654 jnb .test_loop
656 ; No spec packet anywhere. Some particularly pathetic
657 ; BIOSes apparently don't even implement function
658 ; 4B01h, so we can't query a spec packet no matter
659 ; what. If we got a drive number in DL, then try to
660 ; use it, and if it works, then well...
661 mov dl,[DriveNumber]
662 cmp dl,81h ; Should be 81-FF at least
663 jb fatal_error ; If not, it's hopeless
665 ; Write a warning to indicate we're on *very* thin ice now
666 mov si,nospec_msg
667 call writemsg
668 mov al,dl
669 call writehex2
670 call crlf
671 mov si,trysbm_msg
672 call writemsg
673 jmp .found_drive ; Pray that this works...
675 fatal_error:
676 mov si,nothing_msg
677 call writemsg
679 .norge: jmp short .norge
681 ; Information message (DS:SI) output
682 ; Prefix with "isolinux: "
684 writemsg: push ax
685 push si
686 mov si,isolinux_str
687 call writestr_early
688 pop si
689 call writestr_early
690 pop ax
694 ; Write a character to the screen. There is a more "sophisticated"
695 ; version of this in the subsequent code, so we patch the pointer
696 ; when appropriate.
699 writechr:
700 .simple:
701 pushfd
702 pushad
703 mov ah,0Eh
704 xor bx,bx
705 int 10h
706 popad
707 popfd
711 ; int13: save all the segment registers and call INT 13h.
712 ; Some CD-ROM BIOSes have been found to corrupt segment registers
713 ; and/or disable interrupts.
715 int13:
716 pushf
717 push bp
718 push ds
719 push es
720 push fs
721 push gs
722 int 13h
723 mov bp,sp
724 setc [bp+10] ; Propagate CF to the caller
725 pop gs
726 pop fs
727 pop es
728 pop ds
729 pop bp
730 popf
734 ; Get one sector. Convenience entry point.
736 getonesec:
737 mov bp,1
738 ; Fall through to getlinsec
741 ; Get linear sectors - EBIOS LBA addressing, 2048-byte sectors.
743 ; Input:
744 ; EAX - Linear sector number
745 ; ES:BX - Target buffer
746 ; BP - Sector count
748 global getlinsec
749 getlinsec: jmp word [cs:GetlinsecPtr]
751 %ifndef DEBUG_MESSAGES
754 ; First, the variants that we use when actually loading off a disk
755 ; (hybrid mode.) These are adapted versions of the equivalent routines
756 ; in ldlinux.asm.
760 ; getlinsec_ebios:
762 ; getlinsec implementation for floppy/HDD EBIOS (EDD)
764 getlinsec_ebios:
765 xor edx,edx
766 shld edx,eax,2
767 shl eax,2 ; Convert to HDD sectors
768 add eax,[Hidden]
769 adc edx,[Hidden+4]
770 shl bp,2
772 .loop:
773 push bp ; Sectors left
774 .retry2:
775 call maxtrans ; Enforce maximum transfer size
776 movzx edi,bp ; Sectors we are about to read
777 mov cx,retry_count
778 .retry:
780 ; Form DAPA on stack
781 push edx
782 push eax
783 push es
784 push bx
785 push di
786 push word 16
787 mov si,sp
788 pushad
789 mov dl,[DriveNumber]
790 push ds
791 push ss
792 pop ds ; DS <- SS
793 mov ah,42h ; Extended Read
794 call int13
795 pop ds
796 popad
797 lea sp,[si+16] ; Remove DAPA
798 jc .error
799 pop bp
800 add eax,edi ; Advance sector pointer
801 adc edx,0
802 sub bp,di ; Sectors left
803 shl di,9 ; 512-byte sectors
804 add bx,di ; Advance buffer pointer
805 and bp,bp
806 jnz .loop
810 .error:
811 ; Some systems seem to get "stuck" in an error state when
812 ; using EBIOS. Doesn't happen when using CBIOS, which is
813 ; good, since some other systems get timeout failures
814 ; waiting for the floppy disk to spin up.
816 pushad ; Try resetting the device
817 xor ax,ax
818 mov dl,[DriveNumber]
819 call int13
820 popad
821 loop .retry ; CX-- and jump if not zero
823 ;shr word [MaxTransfer],1 ; Reduce the transfer size
824 ;jnz .retry2
826 ; Total failure. Try falling back to CBIOS.
827 mov word [GetlinsecPtr], getlinsec_cbios
828 ;mov byte [MaxTransfer],63 ; Max possibe CBIOS transfer
830 pop bp
831 jmp getlinsec_cbios.loop
834 ; getlinsec_cbios:
836 ; getlinsec implementation for legacy CBIOS
838 getlinsec_cbios:
839 xor edx,edx
840 shl eax,2 ; Convert to HDD sectors
841 add eax,[Hidden]
842 shl bp,2
844 .loop:
845 push edx
846 push eax
847 push bp
848 push bx
850 movzx esi,word [bsSecPerTrack]
851 movzx edi,word [bsHeads]
853 ; Dividing by sectors to get (track,sector): we may have
854 ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
856 div esi
857 xor cx,cx
858 xchg cx,dx ; CX <- sector index (0-based)
859 ; EDX <- 0
860 ; eax = track #
861 div edi ; Convert track to head/cyl
863 ; We should test this, but it doesn't fit...
864 ; cmp eax,1023
865 ; ja .error
868 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
869 ; BP = sectors to transfer, SI = bsSecPerTrack,
870 ; ES:BX = data target
873 call maxtrans ; Enforce maximum transfer size
875 ; Must not cross track boundaries, so BP <= SI-CX
876 sub si,cx
877 cmp bp,si
878 jna .bp_ok
879 mov bp,si
880 .bp_ok:
882 shl ah,6 ; Because IBM was STOOPID
883 ; and thought 8 bits were enough
884 ; then thought 10 bits were enough...
885 inc cx ; Sector numbers are 1-based, sigh
886 or cl,ah
887 mov ch,al
888 mov dh,dl
889 mov dl,[DriveNumber]
890 xchg ax,bp ; Sector to transfer count
891 mov ah,02h ; Read sectors
892 mov bp,retry_count
893 .retry:
894 pushad
895 call int13
896 popad
897 jc .error
898 .resume:
899 movzx ecx,al ; ECX <- sectors transferred
900 shl ax,9 ; Convert sectors in AL to bytes in AX
901 pop bx
902 add bx,ax
903 pop bp
904 pop eax
905 pop edx
906 add eax,ecx
907 sub bp,cx
908 jnz .loop
911 .error:
912 dec bp
913 jnz .retry
915 xchg ax,bp ; Sectors transferred <- 0
916 shr word [MaxTransfer],1
917 jnz .resume
918 jmp disk_error
921 ; Truncate BP to MaxTransfer
923 maxtrans:
924 cmp bp,[MaxTransfer]
925 jna .ok
926 mov bp,[MaxTransfer]
927 .ok: ret
929 %endif
932 ; This is the variant we use for real CD-ROMs:
933 ; LBA, 2K sectors, some special error handling.
935 getlinsec_cdrom:
936 mov si,dapa ; Load up the DAPA
937 mov [si+4],bx
938 mov [si+6],es
939 mov [si+8],eax
940 .loop:
941 push bp ; Sectors left
942 cmp bp,[MaxTransferCD]
943 jbe .bp_ok
944 mov bp,[MaxTransferCD]
945 .bp_ok:
946 mov [si+2],bp
947 push si
948 mov dl,[DriveNumber]
949 mov ah,42h ; Extended Read
950 call xint13
951 pop si
952 pop bp
953 movzx eax,word [si+2] ; Sectors we read
954 add [si+8],eax ; Advance sector pointer
955 sub bp,ax ; Sectors left
956 shl ax,SECTOR_SHIFT-4 ; 2048-byte sectors -> segment
957 add [si+6],ax ; Advance buffer pointer
958 and bp,bp
959 jnz .loop
960 mov eax,[si+8] ; Next sector
963 ; INT 13h with retry
964 xint13: mov byte [RetryCount],retry_count
965 .try: pushad
966 call int13
967 jc .error
968 add sp,byte 8*4 ; Clean up stack
970 .error:
971 mov [DiskError],ah ; Save error code
972 popad
973 mov [DiskSys],ax ; Save system call number
974 dec byte [RetryCount]
975 jz .real_error
976 push ax
977 mov al,[RetryCount]
978 mov ah,[dapa+2] ; Sector transfer count
979 cmp al,2 ; Only 2 attempts left
980 ja .nodanger
981 mov ah,1 ; Drop transfer size to 1
982 jmp short .setsize
983 .nodanger:
984 cmp al,retry_count-2
985 ja .again ; First time, just try again
986 shr ah,1 ; Otherwise, try to reduce
987 adc ah,0 ; the max transfer size, but not to 0
988 .setsize:
989 mov [MaxTransferCD],ah
990 mov [dapa+2],ah
991 .again:
992 pop ax
993 jmp .try
995 .real_error: mov si,diskerr_msg
996 call writemsg
997 mov al,[DiskError]
998 call writehex2
999 mov si,oncall_str
1000 call writestr_early
1001 mov ax,[DiskSys]
1002 call writehex4
1003 mov si,ondrive_str
1004 call writestr_early
1005 mov al,dl
1006 call writehex2
1007 call crlf
1008 ; Fall through to kaboom
1011 ; kaboom: write a message and bail out. Wait for a user keypress,
1012 ; then do a hard reboot.
1014 global kaboom
1015 disk_error:
1016 kaboom:
1017 RESET_STACK_AND_SEGS AX
1018 mov si,err_bootfailed
1019 call writestr
1020 call getchar
1022 mov word [BIOS_magic],0 ; Cold reboot
1023 jmp 0F000h:0FFF0h ; Reset vector address
1025 ; -----------------------------------------------------------------------------
1026 ; Common modules needed in the first sector
1027 ; -----------------------------------------------------------------------------
1029 %include "writestr.inc" ; String output
1030 writestr_early equ writestr
1031 %include "writehex.inc" ; Hexadecimal output
1033 ; -----------------------------------------------------------------------------
1034 ; Data that needs to be in the first sector
1035 ; -----------------------------------------------------------------------------
1037 syslinux_banner db CR, LF, MY_NAME, ' ', VERSION_STR, ' ', DATE_STR, ' ', 0
1038 copyright_str db ' Copyright (C) 1994-'
1039 asciidec YEAR
1040 db ' H. Peter Anvin et al', CR, LF, 0
1041 isolinux_str db 'isolinux: ', 0
1042 %ifdef DEBUG_MESSAGES
1043 startup_msg: db 'Starting up, DL = ', 0
1044 spec_ok_msg: db 'Loaded spec packet OK, drive = ', 0
1045 secsize_msg: db 'Sector size ', 0
1046 offset_msg: db 'Main image LBA = ', 0
1047 verify_msg: db 'Image checksum verified.', CR, LF, 0
1048 allread_msg db 'Main image read, jumping to main code...', CR, LF, 0
1049 %endif
1050 noinfotable_msg db 'No boot info table, assuming single session disk...', CR, LF, 0
1051 noinfoinspec_msg db 'Spec packet missing LBA information, trying to wing it...', CR, LF, 0
1052 spec_err_msg: db 'Loading spec packet failed, trying to wing it...', CR, LF, 0
1053 maybe_msg: db 'Found something at drive = ', 0
1054 alright_msg: db 'Looks reasonable, continuing...', CR, LF, 0
1055 nospec_msg db 'Extremely broken BIOS detected, last attempt with drive = ', 0
1056 nothing_msg: db 'Failed to locate CD-ROM device; boot failed.', CR, LF
1057 trysbm_msg db 'See http://syslinux.zytor.com/sbm for more information.', CR, LF, 0
1058 diskerr_msg: db 'Disk error ', 0
1059 oncall_str: db ', AX = ',0
1060 ondrive_str: db ', drive ', 0
1061 checkerr_msg: db 'Image checksum error, sorry...', CR, LF, 0
1063 err_bootfailed db CR, LF, 'Boot failed: press a key to retry...'
1064 bailmsg equ err_bootfailed
1065 crlf_msg db CR, LF
1066 null_msg db 0
1068 bios_cdrom_str db 'ETCD', 0
1069 %ifndef DEBUG_MESSAGES
1070 bios_cbios_str db 'CHDD', 0
1071 bios_ebios_str db 'EHDD' ,0
1072 %endif
1074 alignz 4
1075 bios_cdrom: dw getlinsec_cdrom, bios_cdrom_str
1076 %ifndef DEBUG_MESSAGES
1077 bios_cbios: dw getlinsec_cbios, bios_cbios_str
1078 bios_ebios: dw getlinsec_ebios, bios_ebios_str
1079 %endif
1081 ; Maximum transfer size
1082 MaxTransfer dw 127 ; Hard disk modes
1083 MaxTransferCD dw 32 ; CD mode
1085 rl_checkpt equ $ ; Must be <= 800h
1087 ; This pads to the end of sector 0 and errors out on
1088 ; overflow.
1089 times 2048-($-$$) db 0
1091 ; ----------------------------------------------------------------------------
1092 ; End of code and data that have to be in the first sector
1093 ; ----------------------------------------------------------------------------
1095 section .text16
1097 all_read:
1099 ; Test tracers
1100 TRACER 'T'
1101 TRACER '>'
1104 ; Common initialization code
1106 %include "init.inc"
1108 ; Patch the writechr routine to point to the full code
1109 mov di,writechr
1110 mov al,0e9h
1111 stosb
1112 mov ax,writechr_full-2
1113 sub ax,di
1114 stosw
1116 ; Tell the user we got this far...
1117 %ifndef DEBUG_MESSAGES ; Gets messy with debugging on
1118 mov si,copyright_str
1119 call writestr_early
1120 %endif
1123 ; Now we're all set to start with our *real* business. First load the
1124 ; configuration file (if any) and parse it.
1126 ; In previous versions I avoided using 32-bit registers because of a
1127 ; rumour some BIOSes clobbered the upper half of 32-bit registers at
1128 ; random. I figure, though, that if there are any of those still left
1129 ; they probably won't be trying to install Linux on them...
1131 ; The code is still ripe with 16-bitisms, though. Not worth the hassle
1132 ; to take'm out. In fact, we may want to put them back if we're going
1133 ; to boot ELKS at some point.
1137 ; Now, we need to sniff out the actual filesystem data structures.
1138 ; mkisofs gave us a pointer to the primary volume descriptor
1139 ; (which will be at 16 only for a single-session disk!); from the PVD
1140 ; we should be able to find the rest of what we need to know.
1142 init_fs:
1143 pushad
1144 mov eax,ROOT_FS_OPS
1145 mov dl,[DriveNumber]
1146 cmp word [BIOSType],bios_cdrom
1147 sete dh ; 1 for cdrom, 0 for hybrid mode
1148 jne .hybrid
1149 movzx ebp,word [MaxTransferCD]
1150 jmp .common
1151 .hybrid:
1152 movzx ebp,word [MaxTransfer]
1153 .common:
1154 mov ecx,[Hidden]
1155 mov ebx,[Hidden+4]
1156 mov si,[bsHeads]
1157 mov di,[bsSecPerTrack]
1158 pm_call fs_init
1159 popad
1161 section .rodata
1162 alignz 4
1163 ROOT_FS_OPS:
1164 extern iso_fs_ops
1165 dd iso_fs_ops
1166 dd 0
1168 section .text16
1171 ; Locate the configuration file
1173 pm_call pm_load_config
1174 jz no_config_file
1177 ; Now we have the config file open. Parse the config file and
1178 ; run the user interface.
1180 %include "ui.inc"
1182 ; -----------------------------------------------------------------------------
1183 ; Common modules
1184 ; -----------------------------------------------------------------------------
1186 %include "common.inc" ; Universal modules
1187 %include "rawcon.inc" ; Console I/O w/o using the console functions
1188 %include "localboot.inc" ; Disk-based local boot
1190 ; -----------------------------------------------------------------------------
1191 ; Begin data section
1192 ; -----------------------------------------------------------------------------
1194 section .data16
1195 err_disk_image db 'Cannot load disk image (invalid file)?', CR, LF, 0
1198 ; Config file keyword table
1200 %include "keywords.inc"
1203 ; Extensions to search for (in *forward* order).
1205 alignz 4
1206 exten_table: db '.cbt' ; COMBOOT (specific)
1207 db '.bin' ; CD boot sector
1208 db '.com' ; COMBOOT (same as DOS)
1209 db '.c32' ; COM32
1210 exten_table_end:
1211 dd 0, 0 ; Need 8 null bytes here