Merging upstream version 5.01+dfsg.
[syslinux-debian/hramrach.git] / core / isolinux.asm
blobb292d8f9f96058ef62f44edffc189b9ba15cd45f
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 global BIOSName
72 alignb 4
73 FirstSecSum resd 1 ; Checksum of bytes 64-2048
74 ImageDwords resd 1 ; isolinux.bin size, dwords
75 InitStack resd 1 ; Initial stack pointer (SS:SP)
76 DiskSys resw 1 ; Last INT 13h call
77 ImageSectors resw 1 ; isolinux.bin size, sectors
78 ; These following two are accessed as a single dword...
79 GetlinsecPtr resw 1 ; The sector-read pointer
80 BIOSName resw 1 ; Display string for BIOS type
81 %define HAVE_BIOSNAME 1
82 BIOSType resw 1
83 DiskError resb 1 ; Error code for disk I/O
84 DriveNumber resb 1 ; CD-ROM BIOS drive number
85 ISOFlags resb 1 ; Flags for ISO directory search
86 RetryCount resb 1 ; Used for disk access retries
88 alignb 8
89 Hidden resq 1 ; Used in hybrid mode
90 bsSecPerTrack resw 1 ; Used in hybrid mode
91 bsHeads resw 1 ; Used in hybrid mode
95 ; El Torito spec packet
98 alignb 8
99 _spec_start equ $
100 spec_packet: resb 1 ; Size of packet
101 sp_media: resb 1 ; Media type
102 sp_drive: resb 1 ; Drive number
103 sp_controller: resb 1 ; Controller index
104 sp_lba: resd 1 ; LBA for emulated disk image
105 sp_devspec: resw 1 ; IDE/SCSI information
106 sp_buffer: resw 1 ; User-provided buffer
107 sp_loadseg: resw 1 ; Load segment
108 sp_sectors: resw 1 ; Sector count
109 sp_chs: resb 3 ; Simulated CHS geometry
110 sp_dummy: resb 1 ; Scratch, safe to overwrite
113 ; EBIOS drive parameter packet
115 alignb 8
116 drive_params: resw 1 ; Buffer size
117 dp_flags: resw 1 ; Information flags
118 dp_cyl: resd 1 ; Physical cylinders
119 dp_head: resd 1 ; Physical heads
120 dp_sec: resd 1 ; Physical sectors/track
121 dp_totalsec: resd 2 ; Total sectors
122 dp_secsize: resw 1 ; Bytes per sector
123 dp_dpte: resd 1 ; Device Parameter Table
124 dp_dpi_key: resw 1 ; 0BEDDh if rest valid
125 dp_dpi_len: resb 1 ; DPI len
126 resb 1
127 resw 1
128 dp_bus: resb 4 ; Host bus type
129 dp_interface: resb 8 ; Interface type
130 db_i_path: resd 2 ; Interface path
131 db_d_path: resd 2 ; Device path
132 resb 1
133 db_dpi_csum: resb 1 ; Checksum for DPI info
136 ; EBIOS disk address packet
138 alignb 8
139 dapa: resw 1 ; Packet size
140 .count: resw 1 ; Block count
141 .off: resw 1 ; Offset of buffer
142 .seg: resw 1 ; Segment of buffer
143 .lba: resd 2 ; LBA (LSW, MSW)
146 ; Spec packet for disk image emulation
148 alignb 8
149 dspec_packet: resb 1 ; Size of packet
150 dsp_media: resb 1 ; Media type
151 dsp_drive: resb 1 ; Drive number
152 dsp_controller: resb 1 ; Controller index
153 dsp_lba: resd 1 ; LBA for emulated disk image
154 dsp_devspec: resw 1 ; IDE/SCSI information
155 dsp_buffer: resw 1 ; User-provided buffer
156 dsp_loadseg: resw 1 ; Load segment
157 dsp_sectors: resw 1 ; Sector count
158 dsp_chs: resb 3 ; Simulated CHS geometry
159 dsp_dummy: resb 1 ; Scratch, safe to overwrite
161 alignb 4
162 _spec_end equ $
163 _spec_len equ _spec_end - _spec_start
165 section .init
167 ;; Primary entry point. Because BIOSes are buggy, we only load the first
168 ;; CD-ROM sector (2K) of the file, so the number one priority is actually
169 ;; loading the rest.
171 global StackBuf
172 StackBuf equ STACK_TOP-44 ; 44 bytes needed for
173 ; the bootsector chainloading
174 ; code!
175 OrigESDI equ StackBuf-4 ; The high dword on the stack
176 StackHome equ OrigESDI
178 bootsec equ $
180 _start: ; Far jump makes sure we canonicalize the address
182 jmp 0:_start1
183 times 8-($-$$) nop ; Pad to file offset 8
185 ; This table hopefully gets filled in by mkisofs using the
186 ; -boot-info-table option. If not, the values in this
187 ; table are default values that we can use to get us what
188 ; we need, at least under a certain set of assumptions.
189 global iso_boot_info
190 iso_boot_info:
191 bi_pvd: dd 16 ; LBA of primary volume descriptor
192 bi_file: dd 0 ; LBA of boot file
193 bi_length: dd 0xdeadbeef ; Length of boot file
194 bi_csum: dd 0xdeadbeef ; Checksum of boot file
195 bi_reserved: times 10 dd 0xdeadbeef ; Reserved
196 bi_end:
198 ; Custom entry point for the hybrid-mode disk.
199 ; The following values will have been pushed onto the
200 ; entry stack:
201 ; - partition offset (qword)
202 ; - ES
203 ; - DI
204 ; - DX (including drive number)
205 ; - CBIOS Heads
206 ; - CBIOS Sectors
207 ; - EBIOS flag
208 ; (top of stack)
210 ; If we had an old isohybrid, the partition offset will
211 ; be missing; we can check for that with sp >= 0x7c00.
212 ; Serious hack alert.
213 %ifndef DEBUG_MESSAGES
214 _hybrid_signature:
215 dd 0x7078c0fb ; An arbitrary number...
217 _start_hybrid:
218 pop cx ; EBIOS flag
219 pop word [cs:bsSecPerTrack]
220 pop word [cs:bsHeads]
221 pop dx
222 pop di
223 pop es
224 xor eax,eax
225 xor ebx,ebx
226 cmp sp,7C00h
227 jae .nooffset
228 pop eax
229 pop ebx
230 .nooffset:
231 mov si,bios_cbios
232 jcxz _start_common
233 mov si,bios_ebios
234 jmp _start_common
235 %endif
237 _start1:
238 mov si,bios_cdrom
239 xor eax,eax
240 xor ebx,ebx
241 _start_common:
242 mov [cs:InitStack],sp ; Save initial stack pointer
243 mov [cs:InitStack+2],ss
244 xor cx,cx
245 mov ss,cx
246 mov sp,StackBuf ; Set up stack
247 push es ; Save initial ES:DI -> $PnP pointer
248 push di
249 mov ds,cx
250 mov es,cx
251 mov fs,cx
252 mov gs,cx
256 mov [Hidden],eax
257 mov [Hidden+4],ebx
259 mov [BIOSType],si
260 mov eax,[si]
261 mov [GetlinsecPtr],eax
263 ; Show signs of life
264 mov si,syslinux_banner
265 call writestr_early
266 %ifdef DEBUG_MESSAGES
267 mov si,copyright_str
268 %else
269 mov si,[BIOSName]
270 %endif
271 call writestr_early
274 ; Before modifying any memory, get the checksum of bytes
275 ; 64-2048
277 initial_csum: xor edi,edi
278 mov si,bi_end
279 mov cx,(SECTOR_SIZE-64) >> 2
280 .loop: lodsd
281 add edi,eax
282 loop .loop
283 mov [FirstSecSum],edi
285 mov [DriveNumber],dl
286 %ifdef DEBUG_MESSAGES
287 mov si,startup_msg
288 call writemsg
289 mov al,dl
290 call writehex2
291 call crlf_early
292 %endif
294 ; Initialize spec packet buffers
296 mov di,_spec_start
297 mov cx,_spec_len >> 2
298 xor eax,eax
299 rep stosd
301 ; Initialize length field of the various packets
302 mov byte [spec_packet],13h
303 mov byte [drive_params],30
304 mov byte [dapa],16
305 mov byte [dspec_packet],13h
307 ; Other nonzero fields
308 inc word [dsp_sectors]
310 ; Are we just pretending to be a CD-ROM?
311 cmp word [BIOSType],bios_cdrom
312 jne found_drive ; If so, no spec packet...
314 ; Now figure out what we're actually doing
315 ; Note: use passed-in DL value rather than 7Fh because
316 ; at least some BIOSes will get the wrong value otherwise
317 mov ax,4B01h ; Get disk emulation status
318 mov dl,[DriveNumber]
319 mov si,spec_packet
320 call int13
321 jc award_hack ; changed for BrokenAwardHack
322 mov dl,[DriveNumber]
323 cmp [sp_drive],dl ; Should contain the drive number
324 jne spec_query_failed
326 %ifdef DEBUG_MESSAGES
327 mov si,spec_ok_msg
328 call writemsg
329 mov al,byte [sp_drive]
330 call writehex2
331 call crlf_early
332 %endif
334 found_drive:
335 ; Alright, we have found the drive. Now, try to find the
336 ; boot file itself. If we have a boot info table, life is
337 ; good; if not, we have to make some assumptions, and try
338 ; to figure things out ourselves. In particular, the
339 ; assumptions we have to make are:
340 ; - single session only
341 ; - only one boot entry (no menu or other alternatives)
343 cmp dword [bi_file],0 ; Address of code to load
344 jne found_file ; Boot info table present :)
346 %ifdef DEBUG_MESSAGES
347 mov si,noinfotable_msg
348 call writemsg
349 %endif
351 ; No such luck. See if the spec packet contained one.
352 mov eax,[sp_lba]
353 and eax,eax
354 jz set_file ; Good enough
356 %ifdef DEBUG_MESSAGES
357 mov si,noinfoinspec_msg
358 call writemsg
359 %endif
361 ; No such luck. Get the Boot Record Volume, assuming single
362 ; session disk, and that we're the first entry in the chain.
363 mov eax,17 ; Assumed address of BRV
364 mov bx,trackbuf
365 call getonesec
367 mov eax,[trackbuf+47h] ; Get boot catalog address
368 mov bx,trackbuf
369 call getonesec ; Get boot catalog
371 mov eax,[trackbuf+28h] ; First boot entry
372 ; And hope and pray this is us...
374 ; Some BIOSes apparently have limitations on the size
375 ; that may be loaded (despite the El Torito spec being very
376 ; clear on the fact that it must all be loaded.) Therefore,
377 ; we load it ourselves, and *bleep* the BIOS.
379 set_file:
380 mov [bi_file],eax
382 found_file:
383 ; Set up boot file sizes
384 mov eax,[bi_length]
385 sub eax,SECTOR_SIZE-3 ; ... minus sector loaded
386 shr eax,2 ; bytes->dwords
387 mov [ImageDwords],eax ; boot file dwords
388 add eax,((SECTOR_SIZE-1) >> 2)
389 shr eax,SECTOR_SHIFT-2 ; dwords->sectors
390 mov [ImageSectors],ax ; boot file sectors
392 mov eax,[bi_file] ; Address of code to load
393 inc eax ; Don't reload bootstrap code
394 %ifdef DEBUG_MESSAGES
395 mov si,offset_msg
396 call writemsg
397 call writehex8
398 call crlf_early
399 %endif
401 ; Load the rest of the file. However, just in case there
402 ; are still BIOSes with 64K wraparound problems, we have to
403 ; take some extra precautions. Since the normal load
404 ; address (TEXT_START) is *not* 2K-sector-aligned, we round
405 ; the target address upward to a sector boundary,
406 ; and then move the entire thing down as a unit.
407 MaxLMA equ 384*1024 ; Reasonable limit (384K)
409 mov bx,((TEXT_START+2*SECTOR_SIZE-1) & ~(SECTOR_SIZE-1)) >> 4
410 mov bp,[ImageSectors]
411 push bx ; Load segment address
413 .more:
414 push bx ; Segment address
415 push bp ; Sector count
416 mov es,bx
417 mov cx,0xfff
418 and bx,cx
419 inc cx
420 sub cx,bx
421 shr cx,SECTOR_SHIFT - 4
422 jnz .notaligned
423 mov cx,0x10000 >> SECTOR_SHIFT ; Full 64K segment possible
424 .notaligned:
425 cmp bp,cx
426 jbe .ok
427 mov bp,cx
428 .ok:
429 xor bx,bx
430 push bp
431 push eax
432 call getlinsec
433 pop eax
434 pop cx
435 mov dx,cx
436 pop bp
437 pop bx
439 shl cx,SECTOR_SHIFT - 4
440 add bx,cx
441 add eax,edx
442 sub bp,dx
443 jnz .more
445 ; Move the image into place, and also verify the
446 ; checksum
447 pop ax ; Load segment address
448 mov bx,(TEXT_START + SECTOR_SIZE) >> 4
449 mov ecx,[ImageDwords]
450 mov edi,[FirstSecSum] ; First sector checksum
451 xor si,si
453 move_verify_image:
454 .setseg:
455 mov ds,ax
456 mov es,bx
457 .loop:
458 mov edx,[si]
459 add edi,edx
460 dec ecx
461 mov [es:si],edx
462 jz .done
463 add si,4
464 jnz .loop
465 add ax,1000h
466 add bx,1000h
467 jmp .setseg
468 .done:
469 mov ax,cs
470 mov ds,ax
471 mov es,ax
473 ; Verify the checksum on the loaded image.
474 cmp [bi_csum],edi
475 je integrity_ok
477 mov si,checkerr_msg
478 call writemsg
479 jmp kaboom
481 integrity_ok:
482 %ifdef DEBUG_MESSAGES
483 mov si,allread_msg
484 call writemsg
485 %endif
486 jmp all_read ; Jump to main code
488 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
489 ;; Start of BrokenAwardHack --- 10-nov-2002 Knut_Petersen@t-online.de
490 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
492 ;; There is a problem with certain versions of the AWARD BIOS ...
493 ;; the boot sector will be loaded and executed correctly, but, because the
494 ;; int 13 vector points to the wrong code in the BIOS, every attempt to
495 ;; load the spec packet will fail. We scan for the equivalent of
497 ;; mov ax,0201h
498 ;; mov bx,7c00h
499 ;; mov cx,0006h
500 ;; mov dx,0180h
501 ;; pushf
502 ;; call <direct far>
504 ;; and use <direct far> as the new vector for int 13. The code above is
505 ;; used to load the boot code into ram, and there should be no reason
506 ;; for anybody to change it now or in the future. There are no opcodes
507 ;; that use encodings relativ to IP, so scanning is easy. If we find the
508 ;; code above in the BIOS code we can be pretty sure to run on a machine
509 ;; with an broken AWARD BIOS ...
511 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
513 %ifdef DEBUG_MESSAGES ;;
515 award_notice db "Trying BrokenAwardHack first ...",CR,LF,0 ;;
516 award_not_orig db "BAH: Original Int 13 vector : ",0 ;;
517 award_not_new db "BAH: Int 13 vector changed to : ",0 ;;
518 award_not_succ db "BAH: SUCCESS",CR,LF,0 ;;
519 award_not_fail db "BAH: FAILURE" ;;
520 award_not_crlf db CR,LF,0 ;;
522 %endif ;;
524 award_oldint13 dd 0 ;;
525 award_string db 0b8h,1,2,0bbh,0,7ch,0b9h,6,0,0bah,80h,1,09ch,09ah ;;
527 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
528 award_hack: mov si,spec_err_msg ; Moved to this place from
529 call writemsg ; spec_query_failed
531 %ifdef DEBUG_MESSAGES ;
533 mov si,award_notice ; display our plan
534 call writemsg ;
535 mov si,award_not_orig ; display original int 13
536 call writemsg ; vector
537 %endif ;
538 mov eax,[13h*4] ;
539 mov [award_oldint13],eax ;
541 %ifdef DEBUG_MESSAGES ;
543 call writehex8 ;
544 mov si,award_not_crlf ;
545 call writestr_early ;
546 %endif ;
547 push es ; save ES
548 mov ax,0f000h ; ES = BIOS Seg
549 mov es,ax ;
550 cld ;
551 xor di,di ; start at ES:DI = f000:0
552 award_loop: push di ; save DI
553 mov si,award_string ; scan for award_string
554 mov cx,7 ; length of award_string = 7dw
555 repz cmpsw ; compare
556 pop di ; restore DI
557 jcxz award_found ; jmp if found
558 inc di ; not found, inc di
559 jno award_loop ;
561 award_failed: pop es ; No, not this way :-((
562 award_fail2: ;
564 %ifdef DEBUG_MESSAGES ;
566 mov si,award_not_fail ; display failure ...
567 call writemsg ;
568 %endif ;
569 mov eax,[award_oldint13] ; restore the original int
570 or eax,eax ; 13 vector if there is one
571 jz spec_query_failed ; and try other workarounds
572 mov [13h*4],eax ;
573 jmp spec_query_failed ;
575 award_found: mov eax,[es:di+0eh] ; load possible int 13 addr
576 pop es ; restore ES
578 cmp eax,[award_oldint13] ; give up if this is the
579 jz award_failed ; active int 13 vector,
580 mov [13h*4],eax ; otherwise change 0:13h*4
583 %ifdef DEBUG_MESSAGES ;
585 push eax ; display message and
586 mov si,award_not_new ; new vector address
587 call writemsg ;
588 pop eax ;
589 call writehex8 ;
590 mov si,award_not_crlf ;
591 call writestr_early ;
592 %endif ;
593 mov ax,4B01h ; try to read the spec packet
594 mov dl,[DriveNumber] ; now ... it should not fail
595 mov si,spec_packet ; any longer
596 int 13h ;
597 jc award_fail2 ;
599 %ifdef DEBUG_MESSAGES ;
601 mov si,award_not_succ ; display our SUCCESS
602 call writemsg ;
603 %endif ;
604 jmp found_drive ; and leave error recovery code
606 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
607 ;; End of BrokenAwardHack ---- 10-nov-2002 Knut_Petersen@t-online.de
608 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
611 ; INT 13h, AX=4B01h, DL=<passed in value> failed.
612 ; Try to scan the entire 80h-FFh from the end.
614 spec_query_failed:
616 ; some code moved to BrokenAwardHack
618 mov dl,0FFh
619 .test_loop: pusha
620 mov ax,4B01h
621 mov si,spec_packet
622 mov byte [si],13h ; Size of buffer
623 call int13
624 popa
625 jc .still_broken
627 mov si,maybe_msg
628 call writemsg
629 mov al,dl
630 call writehex2
631 call crlf_early
633 cmp byte [sp_drive],dl
634 jne .maybe_broken
636 ; Okay, good enough...
637 mov si,alright_msg
638 call writemsg
639 .found_drive0: mov [DriveNumber],dl
640 .found_drive: jmp found_drive
642 ; Award BIOS 4.51 apparently passes garbage in sp_drive,
643 ; but if this was the drive number originally passed in
644 ; DL then consider it "good enough"
645 .maybe_broken:
646 mov al,[DriveNumber]
647 cmp al,dl
648 je .found_drive
650 ; Intel Classic R+ computer with Adaptec 1542CP BIOS 1.02
651 ; passes garbage in sp_drive, and the drive number originally
652 ; passed in DL does not have 80h bit set.
653 or al,80h
654 cmp al,dl
655 je .found_drive0
657 .still_broken: dec dx
658 cmp dl, 80h
659 jnb .test_loop
661 ; No spec packet anywhere. Some particularly pathetic
662 ; BIOSes apparently don't even implement function
663 ; 4B01h, so we can't query a spec packet no matter
664 ; what. If we got a drive number in DL, then try to
665 ; use it, and if it works, then well...
666 mov dl,[DriveNumber]
667 cmp dl,81h ; Should be 81-FF at least
668 jb fatal_error ; If not, it's hopeless
670 ; Write a warning to indicate we're on *very* thin ice now
671 mov si,nospec_msg
672 call writemsg
673 mov al,dl
674 call writehex2
675 call crlf_early
676 mov si,trysbm_msg
677 call writemsg
678 jmp .found_drive ; Pray that this works...
680 fatal_error:
681 mov si,nothing_msg
682 call writemsg
684 .norge: jmp short .norge
686 ; Information message (DS:SI) output
687 ; Prefix with "isolinux: "
689 writemsg: push ax
690 push si
691 mov si,isolinux_str
692 call writestr_early
693 pop si
694 call writestr_early
695 pop ax
698 writestr_early:
699 pushfd
700 pushad
701 .top: lodsb
702 and al,al
703 jz .end
704 call writechr
705 jmp short .top
706 .end: popad
707 popfd
710 crlf_early: push ax
711 mov al,CR
712 call writechr
713 mov al,LF
714 call writechr
715 pop ax
719 ; Write a character to the screen. There is a more "sophisticated"
720 ; version of this in the subsequent code, so we patch the pointer
721 ; when appropriate.
724 writechr:
725 .simple:
726 pushfd
727 pushad
728 mov ah,0Eh
729 xor bx,bx
730 int 10h
731 popad
732 popfd
736 ; int13: save all the segment registers and call INT 13h.
737 ; Some CD-ROM BIOSes have been found to corrupt segment registers
738 ; and/or disable interrupts.
740 int13:
741 pushf
742 push bp
743 push ds
744 push es
745 push fs
746 push gs
747 int 13h
748 mov bp,sp
749 setc [bp+10] ; Propagate CF to the caller
750 pop gs
751 pop fs
752 pop es
753 pop ds
754 pop bp
755 popf
759 ; Get one sector. Convenience entry point.
761 getonesec:
762 mov bp,1
763 ; Fall through to getlinsec
766 ; Get linear sectors - EBIOS LBA addressing, 2048-byte sectors.
768 ; Input:
769 ; EAX - Linear sector number
770 ; ES:BX - Target buffer
771 ; BP - Sector count
773 global getlinsec
774 getlinsec: jmp word [cs:GetlinsecPtr]
776 %ifndef DEBUG_MESSAGES
779 ; First, the variants that we use when actually loading off a disk
780 ; (hybrid mode.) These are adapted versions of the equivalent routines
781 ; in ldlinux.asm.
785 ; getlinsec_ebios:
787 ; getlinsec implementation for floppy/HDD EBIOS (EDD)
789 getlinsec_ebios:
790 xor edx,edx
791 shld edx,eax,2
792 shl eax,2 ; Convert to HDD sectors
793 add eax,[Hidden]
794 adc edx,[Hidden+4]
795 shl bp,2
797 .loop:
798 push bp ; Sectors left
799 .retry2:
800 call maxtrans ; Enforce maximum transfer size
801 movzx edi,bp ; Sectors we are about to read
802 mov cx,retry_count
803 .retry:
805 ; Form DAPA on stack
806 push edx
807 push eax
808 push es
809 push bx
810 push di
811 push word 16
812 mov si,sp
813 pushad
814 mov dl,[DriveNumber]
815 push ds
816 push ss
817 pop ds ; DS <- SS
818 mov ah,42h ; Extended Read
819 call int13
820 pop ds
821 popad
822 lea sp,[si+16] ; Remove DAPA
823 jc .error
824 pop bp
825 add eax,edi ; Advance sector pointer
826 adc edx,0
827 sub bp,di ; Sectors left
828 shl di,9 ; 512-byte sectors
829 add bx,di ; Advance buffer pointer
830 and bp,bp
831 jnz .loop
835 .error:
836 ; Some systems seem to get "stuck" in an error state when
837 ; using EBIOS. Doesn't happen when using CBIOS, which is
838 ; good, since some other systems get timeout failures
839 ; waiting for the floppy disk to spin up.
841 pushad ; Try resetting the device
842 xor ax,ax
843 mov dl,[DriveNumber]
844 call int13
845 popad
846 loop .retry ; CX-- and jump if not zero
848 ;shr word [MaxTransfer],1 ; Reduce the transfer size
849 ;jnz .retry2
851 ; Total failure. Try falling back to CBIOS.
852 mov word [GetlinsecPtr], getlinsec_cbios
853 ;mov byte [MaxTransfer],63 ; Max possibe CBIOS transfer
855 pop bp
856 jmp getlinsec_cbios.loop
859 ; getlinsec_cbios:
861 ; getlinsec implementation for legacy CBIOS
863 getlinsec_cbios:
864 xor edx,edx
865 shl eax,2 ; Convert to HDD sectors
866 add eax,[Hidden]
867 shl bp,2
869 .loop:
870 push edx
871 push eax
872 push bp
873 push bx
875 movzx esi,word [bsSecPerTrack]
876 movzx edi,word [bsHeads]
878 ; Dividing by sectors to get (track,sector): we may have
879 ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
881 div esi
882 xor cx,cx
883 xchg cx,dx ; CX <- sector index (0-based)
884 ; EDX <- 0
885 ; eax = track #
886 div edi ; Convert track to head/cyl
888 ; We should test this, but it doesn't fit...
889 ; cmp eax,1023
890 ; ja .error
893 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
894 ; BP = sectors to transfer, SI = bsSecPerTrack,
895 ; ES:BX = data target
898 call maxtrans ; Enforce maximum transfer size
900 ; Must not cross track boundaries, so BP <= SI-CX
901 sub si,cx
902 cmp bp,si
903 jna .bp_ok
904 mov bp,si
905 .bp_ok:
907 shl ah,6 ; Because IBM was STOOPID
908 ; and thought 8 bits were enough
909 ; then thought 10 bits were enough...
910 inc cx ; Sector numbers are 1-based, sigh
911 or cl,ah
912 mov ch,al
913 mov dh,dl
914 mov dl,[DriveNumber]
915 xchg ax,bp ; Sector to transfer count
916 mov ah,02h ; Read sectors
917 mov bp,retry_count
918 .retry:
919 pushad
920 call int13
921 popad
922 jc .error
923 .resume:
924 movzx ecx,al ; ECX <- sectors transferred
925 shl ax,9 ; Convert sectors in AL to bytes in AX
926 pop bx
927 add bx,ax
928 pop bp
929 pop eax
930 pop edx
931 add eax,ecx
932 sub bp,cx
933 jnz .loop
936 .error:
937 dec bp
938 jnz .retry
940 xchg ax,bp ; Sectors transferred <- 0
941 shr word [MaxTransfer],1
942 jnz .resume
943 jmp disk_error
946 ; Truncate BP to MaxTransfer
948 maxtrans:
949 cmp bp,[MaxTransfer]
950 jna .ok
951 mov bp,[MaxTransfer]
952 .ok: ret
954 %endif
957 ; This is the variant we use for real CD-ROMs:
958 ; LBA, 2K sectors, some special error handling.
960 getlinsec_cdrom:
961 mov si,dapa ; Load up the DAPA
962 mov [si+4],bx
963 mov [si+6],es
964 mov [si+8],eax
965 .loop:
966 push bp ; Sectors left
967 cmp bp,[MaxTransferCD]
968 jbe .bp_ok
969 mov bp,[MaxTransferCD]
970 .bp_ok:
971 mov [si+2],bp
972 push si
973 mov dl,[DriveNumber]
974 mov ah,42h ; Extended Read
975 call xint13
976 pop si
977 pop bp
978 movzx eax,word [si+2] ; Sectors we read
979 add [si+8],eax ; Advance sector pointer
980 sub bp,ax ; Sectors left
981 shl ax,SECTOR_SHIFT-4 ; 2048-byte sectors -> segment
982 add [si+6],ax ; Advance buffer pointer
983 and bp,bp
984 jnz .loop
985 mov eax,[si+8] ; Next sector
988 ; INT 13h with retry
989 xint13: mov byte [RetryCount],retry_count
990 .try: pushad
991 call int13
992 jc .error
993 add sp,byte 8*4 ; Clean up stack
995 .error:
996 mov [DiskError],ah ; Save error code
997 popad
998 mov [DiskSys],ax ; Save system call number
999 dec byte [RetryCount]
1000 jz .real_error
1001 push ax
1002 mov al,[RetryCount]
1003 mov ah,[dapa+2] ; Sector transfer count
1004 cmp al,2 ; Only 2 attempts left
1005 ja .nodanger
1006 mov ah,1 ; Drop transfer size to 1
1007 jmp short .setsize
1008 .nodanger:
1009 cmp al,retry_count-2
1010 ja .again ; First time, just try again
1011 shr ah,1 ; Otherwise, try to reduce
1012 adc ah,0 ; the max transfer size, but not to 0
1013 .setsize:
1014 mov [MaxTransferCD],ah
1015 mov [dapa+2],ah
1016 .again:
1017 pop ax
1018 jmp .try
1020 .real_error: mov si,diskerr_msg
1021 call writemsg
1022 mov al,[DiskError]
1023 call writehex2
1024 mov si,oncall_str
1025 call writestr_early
1026 mov ax,[DiskSys]
1027 call writehex4
1028 mov si,ondrive_str
1029 call writestr_early
1030 mov al,dl
1031 call writehex2
1032 call crlf_early
1033 ; Fall through to kaboom
1036 ; kaboom: write a message and bail out. Wait for a user keypress,
1037 ; then do a hard reboot.
1039 global kaboom
1040 disk_error:
1041 kaboom:
1042 RESET_STACK_AND_SEGS AX
1043 mov si,bailmsg
1044 pm_call pm_writestr
1045 pm_call pm_getchar
1047 mov word [BIOS_magic],0 ; Cold reboot
1048 jmp 0F000h:0FFF0h ; Reset vector address
1050 ; -----------------------------------------------------------------------------
1051 ; Common modules needed in the first sector
1052 ; -----------------------------------------------------------------------------
1054 %include "writehex.inc" ; Hexadecimal output
1056 ; -----------------------------------------------------------------------------
1057 ; Data that needs to be in the first sector
1058 ; -----------------------------------------------------------------------------
1060 global syslinux_banner, copyright_str
1061 syslinux_banner db CR, LF, MY_NAME, ' ', VERSION_STR, ' ', DATE_STR, ' ', 0
1062 copyright_str db ' Copyright (C) 1994-'
1063 asciidec YEAR
1064 db ' H. Peter Anvin et al', CR, LF, 0
1065 isolinux_str db 'isolinux: ', 0
1066 %ifdef DEBUG_MESSAGES
1067 startup_msg: db 'Starting up, DL = ', 0
1068 spec_ok_msg: db 'Loaded spec packet OK, drive = ', 0
1069 secsize_msg: db 'Sector size ', 0
1070 offset_msg: db 'Main image LBA = ', 0
1071 verify_msg: db 'Image checksum verified.', CR, LF, 0
1072 allread_msg db 'Main image read, jumping to main code...', CR, LF, 0
1073 %endif
1074 noinfotable_msg db 'No boot info table, assuming single session disk...', CR, LF, 0
1075 noinfoinspec_msg db 'Spec packet missing LBA information, trying to wing it...', CR, LF, 0
1076 spec_err_msg: db 'Loading spec packet failed, trying to wing it...', CR, LF, 0
1077 maybe_msg: db 'Found something at drive = ', 0
1078 alright_msg: db 'Looks reasonable, continuing...', CR, LF, 0
1079 nospec_msg db 'Extremely broken BIOS detected, last attempt with drive = ', 0
1080 nothing_msg: db 'Failed to locate CD-ROM device; boot failed.', CR, LF
1081 trysbm_msg db 'See http://syslinux.zytor.com/sbm for more information.', CR, LF, 0
1082 diskerr_msg: db 'Disk error ', 0
1083 oncall_str: db ', AX = ',0
1084 ondrive_str: db ', drive ', 0
1085 checkerr_msg: db 'Image checksum error, sorry...', CR, LF, 0
1087 err_bootfailed db CR, LF, 'Boot failed: press a key to retry...'
1088 bailmsg equ err_bootfailed
1089 crlf_msg db CR, LF
1090 null_msg db 0
1092 bios_cdrom_str db 'ETCD', 0
1093 %ifndef DEBUG_MESSAGES
1094 bios_cbios_str db 'CHDD', 0
1095 bios_ebios_str db 'EHDD' ,0
1096 %endif
1098 alignz 4
1099 bios_cdrom: dw getlinsec_cdrom, bios_cdrom_str
1100 %ifndef DEBUG_MESSAGES
1101 bios_cbios: dw getlinsec_cbios, bios_cbios_str
1102 bios_ebios: dw getlinsec_ebios, bios_ebios_str
1103 %endif
1105 ; Maximum transfer size
1106 MaxTransfer dw 127 ; Hard disk modes
1107 MaxTransferCD dw 32 ; CD mode
1109 rl_checkpt equ $ ; Must be <= 800h
1111 ; This pads to the end of sector 0 and errors out on
1112 ; overflow.
1113 times 2048-($-$$) db 0
1115 ; ----------------------------------------------------------------------------
1116 ; End of code and data that have to be in the first sector
1117 ; ----------------------------------------------------------------------------
1119 section .text16
1121 all_read:
1123 ; Test tracers
1124 TRACER 'T'
1125 TRACER '>'
1128 ; Common initialization code
1130 %include "init.inc"
1132 ; Tell the user we got this far...
1133 %ifndef DEBUG_MESSAGES ; Gets messy with debugging on
1134 mov si,copyright_str
1135 pm_call pm_writestr
1136 %endif
1139 ; Now we're all set to start with our *real* business. First load the
1140 ; configuration file (if any) and parse it.
1142 ; In previous versions I avoided using 32-bit registers because of a
1143 ; rumour some BIOSes clobbered the upper half of 32-bit registers at
1144 ; random. I figure, though, that if there are any of those still left
1145 ; they probably won't be trying to install Linux on them...
1147 ; The code is still ripe with 16-bitisms, though. Not worth the hassle
1148 ; to take'm out. In fact, we may want to put them back if we're going
1149 ; to boot ELKS at some point.
1153 ; Now, we need to sniff out the actual filesystem data structures.
1154 ; mkisofs gave us a pointer to the primary volume descriptor
1155 ; (which will be at 16 only for a single-session disk!); from the PVD
1156 ; we should be able to find the rest of what we need to know.
1158 init_fs:
1159 pushad
1160 mov eax,ROOT_FS_OPS
1161 mov dl,[DriveNumber]
1162 cmp word [BIOSType],bios_cdrom
1163 sete dh ; 1 for cdrom, 0 for hybrid mode
1164 jne .hybrid
1165 movzx ebp,word [MaxTransferCD]
1166 jmp .common
1167 .hybrid:
1168 movzx ebp,word [MaxTransfer]
1169 .common:
1170 mov ecx,[Hidden]
1171 mov ebx,[Hidden+4]
1172 mov si,[bsHeads]
1173 mov di,[bsSecPerTrack]
1174 pm_call fs_init
1175 pm_call load_env32
1176 enter_command:
1177 auto_boot:
1178 jmp kaboom ; load_env32() should never return. If
1179 ; it does, then kaboom!
1180 popad
1182 section .rodata
1183 alignz 4
1184 ROOT_FS_OPS:
1185 extern iso_fs_ops
1186 dd iso_fs_ops
1187 dd 0
1189 section .text16
1191 %ifdef DEBUG_TRACERS
1193 ; debug hack to print a character with minimal code impact
1195 debug_tracer: pushad
1196 pushfd
1197 mov bp,sp
1198 mov bx,[bp+9*4] ; Get return address
1199 mov al,[cs:bx] ; Get data byte
1200 inc word [bp+9*4] ; Return to after data byte
1201 call writechr
1202 popfd
1203 popad
1205 %endif ; DEBUG_TRACERS
1207 section .bss16
1208 alignb 4
1209 ThisKbdTo resd 1 ; Temporary holder for KbdTimeout
1210 ThisTotalTo resd 1 ; Temporary holder for TotalTimeout
1211 KernelExtPtr resw 1 ; During search, final null pointer
1212 FuncFlag resb 1 ; Escape sequences received from keyboard
1213 KernelType resb 1 ; Kernel type, from vkernel, if known
1214 global KernelName
1215 KernelName resb FILENAME_MAX ; Mangled name for kernel
1216 section .data16
1217 global IPAppends, numIPAppends
1218 %if IS_PXELINUX
1219 extern IPOption
1220 alignz 2
1221 IPAppends dw IPOption
1222 numIPAppends equ ($-IPAppends)/2
1223 %else
1224 IPAppends equ 0
1225 numIPAppends equ 0
1226 %endif
1228 section .text16
1230 ; COMBOOT-loading code
1232 %include "comboot.inc"
1233 %include "com32.inc"
1236 ; Boot sector loading code
1240 ; Abort loading code
1244 ; Hardware cleanup common code
1247 %include "localboot.inc"
1249 ; -----------------------------------------------------------------------------
1250 ; Common modules
1251 ; -----------------------------------------------------------------------------
1253 %include "common.inc" ; Universal modules
1255 ; -----------------------------------------------------------------------------
1256 ; Begin data section
1257 ; -----------------------------------------------------------------------------
1259 section .data16
1260 err_disk_image db 'Cannot load disk image (invalid file)?', CR, LF, 0