Adding upstream version 4.00~pre54+dfsg.
[syslinux-debian/hramrach.git] / core / isolinux.asm
blob8060767987da5d51f6ece787ab881cf4017dae77
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
56 ; File structure. This holds the information for each currently open file.
58 struc open_file_t
59 file_sector resd 1 ; Sector pointer (0 = structure free)
60 file_bytesleft resd 1 ; Number of bytes left
61 file_left resd 1 ; Number of sectors left
62 resd 1 ; Unused
63 endstruc
65 %ifndef DEPEND
66 %if (open_file_t_size & (open_file_t_size-1))
67 %error "open_file_t is not a power of 2"
68 %endif
69 %endif
71 ; ---------------------------------------------------------------------------
72 ; BEGIN CODE
73 ; ---------------------------------------------------------------------------
76 ; Memory below this point is reserved for the BIOS and the MBR
78 section .earlybss
79 global trackbuf
80 trackbufsize equ 8192
81 trackbuf resb trackbufsize ; Track buffer goes here
82 ; ends at 2800h
84 ; Some of these are touched before the whole image
85 ; is loaded. DO NOT move this to .bss16/.uibss.
86 section .earlybss
87 alignb 4
88 FirstSecSum resd 1 ; Checksum of bytes 64-2048
89 ImageDwords resd 1 ; isolinux.bin size, dwords
90 InitStack resd 1 ; Initial stack pointer (SS:SP)
91 DiskSys resw 1 ; Last INT 13h call
92 ImageSectors resw 1 ; isolinux.bin size, sectors
93 ; These following two are accessed as a single dword...
94 GetlinsecPtr resw 1 ; The sector-read pointer
95 BIOSName resw 1 ; Display string for BIOS type
96 %define HAVE_BIOSNAME 1
97 BIOSType resw 1
98 DiskError resb 1 ; Error code for disk I/O
99 DriveNumber resb 1 ; CD-ROM BIOS drive number
100 ISOFlags resb 1 ; Flags for ISO directory search
101 RetryCount resb 1 ; Used for disk access retries
103 alignb 8
104 bsHidden resq 1 ; Used in hybrid mode
105 bsSecPerTrack resw 1 ; Used in hybrid mode
106 bsHeads resw 1 ; Used in hybrid mode
110 ; El Torito spec packet
113 alignb 8
114 _spec_start equ $
115 spec_packet: resb 1 ; Size of packet
116 sp_media: resb 1 ; Media type
117 sp_drive: resb 1 ; Drive number
118 sp_controller: resb 1 ; Controller index
119 sp_lba: resd 1 ; LBA for emulated disk image
120 sp_devspec: resw 1 ; IDE/SCSI information
121 sp_buffer: resw 1 ; User-provided buffer
122 sp_loadseg: resw 1 ; Load segment
123 sp_sectors: resw 1 ; Sector count
124 sp_chs: resb 3 ; Simulated CHS geometry
125 sp_dummy: resb 1 ; Scratch, safe to overwrite
128 ; EBIOS drive parameter packet
130 alignb 8
131 drive_params: resw 1 ; Buffer size
132 dp_flags: resw 1 ; Information flags
133 dp_cyl: resd 1 ; Physical cylinders
134 dp_head: resd 1 ; Physical heads
135 dp_sec: resd 1 ; Physical sectors/track
136 dp_totalsec: resd 2 ; Total sectors
137 dp_secsize: resw 1 ; Bytes per sector
138 dp_dpte: resd 1 ; Device Parameter Table
139 dp_dpi_key: resw 1 ; 0BEDDh if rest valid
140 dp_dpi_len: resb 1 ; DPI len
141 resb 1
142 resw 1
143 dp_bus: resb 4 ; Host bus type
144 dp_interface: resb 8 ; Interface type
145 db_i_path: resd 2 ; Interface path
146 db_d_path: resd 2 ; Device path
147 resb 1
148 db_dpi_csum: resb 1 ; Checksum for DPI info
151 ; EBIOS disk address packet
153 alignb 8
154 dapa: resw 1 ; Packet size
155 .count: resw 1 ; Block count
156 .off: resw 1 ; Offset of buffer
157 .seg: resw 1 ; Segment of buffer
158 .lba: resd 2 ; LBA (LSW, MSW)
161 ; Spec packet for disk image emulation
163 alignb 8
164 dspec_packet: resb 1 ; Size of packet
165 dsp_media: resb 1 ; Media type
166 dsp_drive: resb 1 ; Drive number
167 dsp_controller: resb 1 ; Controller index
168 dsp_lba: resd 1 ; LBA for emulated disk image
169 dsp_devspec: resw 1 ; IDE/SCSI information
170 dsp_buffer: resw 1 ; User-provided buffer
171 dsp_loadseg: resw 1 ; Load segment
172 dsp_sectors: resw 1 ; Sector count
173 dsp_chs: resb 3 ; Simulated CHS geometry
174 dsp_dummy: resb 1 ; Scratch, safe to overwrite
176 alignb 4
177 _spec_end equ $
178 _spec_len equ _spec_end - _spec_start
180 section .init
182 ;; Primary entry point. Because BIOSes are buggy, we only load the first
183 ;; CD-ROM sector (2K) of the file, so the number one priority is actually
184 ;; loading the rest.
186 StackBuf equ STACK_TOP-44 ; 44 bytes needed for
187 ; the bootsector chainloading
188 ; code!
189 OrigESDI equ StackBuf-4 ; The high dword on the stack
190 StackHome equ OrigESDI
192 bootsec equ $
194 _start: ; Far jump makes sure we canonicalize the address
196 jmp 0:_start1
197 times 8-($-$$) nop ; Pad to file offset 8
199 ; This table hopefully gets filled in by mkisofs using the
200 ; -boot-info-table option. If not, the values in this
201 ; table are default values that we can use to get us what
202 ; we need, at least under a certain set of assumptions.
203 global iso_boot_info
204 iso_boot_info:
205 bi_pvd: dd 16 ; LBA of primary volume descriptor
206 bi_file: dd 0 ; LBA of boot file
207 bi_length: dd 0xdeadbeef ; Length of boot file
208 bi_csum: dd 0xdeadbeef ; Checksum of boot file
209 bi_reserved: times 10 dd 0xdeadbeef ; Reserved
210 bi_end:
212 ; Custom entry point for the hybrid-mode disk.
213 ; The following values will have been pushed onto the
214 ; entry stack:
215 ; - partition offset (qword)
216 ; - ES
217 ; - DI
218 ; - DX (including drive number)
219 ; - CBIOS Heads
220 ; - CBIOS Sectors
221 ; - EBIOS flag
222 ; (top of stack)
224 ; If we had an old isohybrid, the partition offset will
225 ; be missing; we can check for that with sp >= 0x7c00.
226 ; Serious hack alert.
227 %ifndef DEBUG_MESSAGES
228 _hybrid_signature:
229 dd 0x7078c0fb ; An arbitrary number...
231 _start_hybrid:
232 pop cx ; EBIOS flag
233 pop word [cs:bsSecPerTrack]
234 pop word [cs:bsHeads]
235 pop dx
236 pop di
237 pop es
238 xor eax,eax
239 xor ebx,ebx
240 cmp sp,7C00h
241 jae .nooffset
242 pop eax
243 pop ebx
244 .nooffset:
245 mov [cs:bsHidden],eax
246 mov [cs:bsHidden+4],ebx
248 mov si,bios_cbios
249 jcxz _start_common
250 mov si,bios_ebios
251 jmp _start_common
252 %endif
254 _start1:
255 mov si,bios_cdrom
256 _start_common:
257 mov [cs:InitStack],sp ; Save initial stack pointer
258 mov [cs:InitStack+2],ss
259 xor ax,ax
260 mov ss,ax
261 mov sp,StackBuf ; Set up stack
262 push es ; Save initial ES:DI -> $PnP pointer
263 push di
264 mov ds,ax
265 mov es,ax
266 mov fs,ax
267 mov gs,ax
271 mov [BIOSType],si
272 mov eax,[si]
273 mov [GetlinsecPtr],eax
275 ; Show signs of life
276 mov si,syslinux_banner
277 call writestr_early
278 %ifdef DEBUG_MESSAGES
279 mov si,copyright_str
280 %else
281 mov si,[BIOSName]
282 %endif
283 call writestr_early
286 ; Before modifying any memory, get the checksum of bytes
287 ; 64-2048
289 initial_csum: xor edi,edi
290 mov si,bi_end
291 mov cx,(SECTOR_SIZE-64) >> 2
292 .loop: lodsd
293 add edi,eax
294 loop .loop
295 mov [FirstSecSum],edi
297 mov [DriveNumber],dl
298 %ifdef DEBUG_MESSAGES
299 mov si,startup_msg
300 call writemsg
301 mov al,dl
302 call writehex2
303 call crlf
304 %endif
306 ; Initialize spec packet buffers
308 mov di,_spec_start
309 mov cx,_spec_len >> 2
310 xor eax,eax
311 rep stosd
313 ; Initialize length field of the various packets
314 mov byte [spec_packet],13h
315 mov byte [drive_params],30
316 mov byte [dapa],16
317 mov byte [dspec_packet],13h
319 ; Other nonzero fields
320 inc word [dsp_sectors]
322 ; Are we just pretending to be a CD-ROM?
323 cmp word [BIOSType],bios_cdrom
324 jne found_drive ; If so, no spec packet...
326 ; Now figure out what we're actually doing
327 ; Note: use passed-in DL value rather than 7Fh because
328 ; at least some BIOSes will get the wrong value otherwise
329 mov ax,4B01h ; Get disk emulation status
330 mov dl,[DriveNumber]
331 mov si,spec_packet
332 call int13
333 jc award_hack ; changed for BrokenAwardHack
334 mov dl,[DriveNumber]
335 cmp [sp_drive],dl ; Should contain the drive number
336 jne spec_query_failed
338 %ifdef DEBUG_MESSAGES
339 mov si,spec_ok_msg
340 call writemsg
341 mov al,byte [sp_drive]
342 call writehex2
343 call crlf
344 %endif
346 found_drive:
347 ; Alright, we have found the drive. Now, try to find the
348 ; boot file itself. If we have a boot info table, life is
349 ; good; if not, we have to make some assumptions, and try
350 ; to figure things out ourselves. In particular, the
351 ; assumptions we have to make are:
352 ; - single session only
353 ; - only one boot entry (no menu or other alternatives)
355 cmp dword [bi_file],0 ; Address of code to load
356 jne found_file ; Boot info table present :)
358 %ifdef DEBUG_MESSAGES
359 mov si,noinfotable_msg
360 call writemsg
361 %endif
363 ; No such luck. See if the spec packet contained one.
364 mov eax,[sp_lba]
365 and eax,eax
366 jz set_file ; Good enough
368 %ifdef DEBUG_MESSAGES
369 mov si,noinfoinspec_msg
370 call writemsg
371 %endif
373 ; No such luck. Get the Boot Record Volume, assuming single
374 ; session disk, and that we're the first entry in the chain.
375 mov eax,17 ; Assumed address of BRV
376 mov bx,trackbuf
377 call getonesec
379 mov eax,[trackbuf+47h] ; Get boot catalog address
380 mov bx,trackbuf
381 call getonesec ; Get boot catalog
383 mov eax,[trackbuf+28h] ; First boot entry
384 ; And hope and pray this is us...
386 ; Some BIOSes apparently have limitations on the size
387 ; that may be loaded (despite the El Torito spec being very
388 ; clear on the fact that it must all be loaded.) Therefore,
389 ; we load it ourselves, and *bleep* the BIOS.
391 set_file:
392 mov [bi_file],eax
394 found_file:
395 ; Set up boot file sizes
396 mov eax,[bi_length]
397 sub eax,SECTOR_SIZE-3 ; ... minus sector loaded
398 shr eax,2 ; bytes->dwords
399 mov [ImageDwords],eax ; boot file dwords
400 add eax,((SECTOR_SIZE-1) >> 2)
401 shr eax,SECTOR_SHIFT-2 ; dwords->sectors
402 mov [ImageSectors],ax ; boot file sectors
404 mov eax,[bi_file] ; Address of code to load
405 inc eax ; Don't reload bootstrap code
406 %ifdef DEBUG_MESSAGES
407 mov si,offset_msg
408 call writemsg
409 call writehex8
410 call crlf
411 %endif
413 ; Load the rest of the file. However, just in case there
414 ; are still BIOSes with 64K wraparound problems, we have to
415 ; take some extra precautions. Since the normal load
416 ; address (TEXT_START) is *not* 2K-sector-aligned, we round
417 ; the target address upward to a sector boundary,
418 ; and then move the entire thing down as a unit.
419 MaxLMA equ 384*1024 ; Reasonable limit (384K)
421 mov bx,((TEXT_START+2*SECTOR_SIZE-1) & ~(SECTOR_SIZE-1)) >> 4
422 mov bp,[ImageSectors]
423 push bx ; Load segment address
425 .more:
426 push bx ; Segment address
427 push bp ; Sector count
428 mov es,bx
429 mov cx,0xfff
430 and bx,cx
431 inc cx
432 sub cx,bx
433 shr cx,SECTOR_SHIFT - 4
434 jnz .notaligned
435 mov cx,0x10000 >> SECTOR_SHIFT ; Full 64K segment possible
436 .notaligned:
437 cmp bp,cx
438 jbe .ok
439 mov bp,cx
440 .ok:
441 xor bx,bx
442 push bp
443 call getlinsec
444 pop cx
445 mov dx,cx
446 pop bp
447 pop bx
449 shl cx,SECTOR_SHIFT - 4
450 add bx,cx
451 sub bp,dx
452 jnz .more
454 ; Move the image into place, and also verify the
455 ; checksum
456 pop ax ; Load segment address
457 mov bx,(TEXT_START + SECTOR_SIZE) >> 4
458 mov ecx,[ImageDwords]
459 mov edi,[FirstSecSum] ; First sector checksum
460 xor si,si
462 move_verify_image:
463 .setseg:
464 mov ds,ax
465 mov es,bx
466 .loop:
467 mov edx,[si]
468 add edi,edx
469 dec ecx
470 mov [es:si],edx
471 jz .done
472 add si,4
473 jnz .loop
474 add ax,1000h
475 add bx,1000h
476 jmp .setseg
477 .done:
478 mov ax,cs
479 mov ds,ax
480 mov es,ax
482 ; Verify the checksum on the loaded image.
483 cmp [bi_csum],edi
484 je integrity_ok
486 mov si,checkerr_msg
487 call writemsg
488 jmp kaboom
490 integrity_ok:
491 %ifdef DEBUG_MESSAGES
492 mov si,allread_msg
493 call writemsg
494 %endif
495 jmp all_read ; Jump to main code
497 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
498 ;; Start of BrokenAwardHack --- 10-nov-2002 Knut_Petersen@t-online.de
499 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
501 ;; There is a problem with certain versions of the AWARD BIOS ...
502 ;; the boot sector will be loaded and executed correctly, but, because the
503 ;; int 13 vector points to the wrong code in the BIOS, every attempt to
504 ;; load the spec packet will fail. We scan for the equivalent of
506 ;; mov ax,0201h
507 ;; mov bx,7c00h
508 ;; mov cx,0006h
509 ;; mov dx,0180h
510 ;; pushf
511 ;; call <direct far>
513 ;; and use <direct far> as the new vector for int 13. The code above is
514 ;; used to load the boot code into ram, and there should be no reason
515 ;; for anybody to change it now or in the future. There are no opcodes
516 ;; that use encodings relativ to IP, so scanning is easy. If we find the
517 ;; code above in the BIOS code we can be pretty sure to run on a machine
518 ;; with an broken AWARD BIOS ...
520 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
522 %ifdef DEBUG_MESSAGES ;;
524 award_notice db "Trying BrokenAwardHack first ...",CR,LF,0 ;;
525 award_not_orig db "BAH: Original Int 13 vector : ",0 ;;
526 award_not_new db "BAH: Int 13 vector changed to : ",0 ;;
527 award_not_succ db "BAH: SUCCESS",CR,LF,0 ;;
528 award_not_fail db "BAH: FAILURE" ;;
529 award_not_crlf db CR,LF,0 ;;
531 %endif ;;
533 award_oldint13 dd 0 ;;
534 award_string db 0b8h,1,2,0bbh,0,7ch,0b9h,6,0,0bah,80h,1,09ch,09ah ;;
536 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
537 award_hack: mov si,spec_err_msg ; Moved to this place from
538 call writemsg ; spec_query_faild
540 %ifdef DEBUG_MESSAGES ;
542 mov si,award_notice ; display our plan
543 call writemsg ;
544 mov si,award_not_orig ; display original int 13
545 call writemsg ; vector
546 %endif ;
547 mov eax,[13h*4] ;
548 mov [award_oldint13],eax ;
550 %ifdef DEBUG_MESSAGES ;
552 call writehex8 ;
553 mov si,award_not_crlf ;
554 call writestr_early ;
555 %endif ;
556 push es ; save ES
557 mov ax,0f000h ; ES = BIOS Seg
558 mov es,ax ;
559 cld ;
560 xor di,di ; start at ES:DI = f000:0
561 award_loop: push di ; save DI
562 mov si,award_string ; scan for award_string
563 mov cx,7 ; length of award_string = 7dw
564 repz cmpsw ; compare
565 pop di ; restore DI
566 jcxz award_found ; jmp if found
567 inc di ; not found, inc di
568 jno award_loop ;
570 award_failed: pop es ; No, not this way :-((
571 award_fail2: ;
573 %ifdef DEBUG_MESSAGES ;
575 mov si,award_not_fail ; display failure ...
576 call writemsg ;
577 %endif ;
578 mov eax,[award_oldint13] ; restore the original int
579 or eax,eax ; 13 vector if there is one
580 jz spec_query_failed ; and try other workarounds
581 mov [13h*4],eax ;
582 jmp spec_query_failed ;
584 award_found: mov eax,[es:di+0eh] ; load possible int 13 addr
585 pop es ; restore ES
587 cmp eax,[award_oldint13] ; give up if this is the
588 jz award_failed ; active int 13 vector,
589 mov [13h*4],eax ; otherwise change 0:13h*4
592 %ifdef DEBUG_MESSAGES ;
594 push eax ; display message and
595 mov si,award_not_new ; new vector address
596 call writemsg ;
597 pop eax ;
598 call writehex8 ;
599 mov si,award_not_crlf ;
600 call writestr_early ;
601 %endif ;
602 mov ax,4B01h ; try to read the spec packet
603 mov dl,[DriveNumber] ; now ... it should not fail
604 mov si,spec_packet ; any longer
605 int 13h ;
606 jc award_fail2 ;
608 %ifdef DEBUG_MESSAGES ;
610 mov si,award_not_succ ; display our SUCCESS
611 call writemsg ;
612 %endif ;
613 jmp found_drive ; and leave error recovery code
615 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
616 ;; End of BrokenAwardHack ---- 10-nov-2002 Knut_Petersen@t-online.de
617 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
620 ; INT 13h, AX=4B01h, DL=<passed in value> failed.
621 ; Try to scan the entire 80h-FFh from the end.
623 spec_query_failed:
625 ; some code moved to BrokenAwardHack
627 mov dl,0FFh
628 .test_loop: pusha
629 mov ax,4B01h
630 mov si,spec_packet
631 mov byte [si],13h ; Size of buffer
632 call int13
633 popa
634 jc .still_broken
636 mov si,maybe_msg
637 call writemsg
638 mov al,dl
639 call writehex2
640 call crlf
642 cmp byte [sp_drive],dl
643 jne .maybe_broken
645 ; Okay, good enough...
646 mov si,alright_msg
647 call writemsg
648 .found_drive0: mov [DriveNumber],dl
649 .found_drive: jmp found_drive
651 ; Award BIOS 4.51 apparently passes garbage in sp_drive,
652 ; but if this was the drive number originally passed in
653 ; DL then consider it "good enough"
654 .maybe_broken:
655 mov al,[DriveNumber]
656 cmp al,dl
657 je .found_drive
659 ; Intel Classic R+ computer with Adaptec 1542CP BIOS 1.02
660 ; passes garbage in sp_drive, and the drive number originally
661 ; passed in DL does not have 80h bit set.
662 or al,80h
663 cmp al,dl
664 je .found_drive0
666 .still_broken: dec dx
667 cmp dl, 80h
668 jnb .test_loop
670 ; No spec packet anywhere. Some particularly pathetic
671 ; BIOSes apparently don't even implement function
672 ; 4B01h, so we can't query a spec packet no matter
673 ; what. If we got a drive number in DL, then try to
674 ; use it, and if it works, then well...
675 mov dl,[DriveNumber]
676 cmp dl,81h ; Should be 81-FF at least
677 jb fatal_error ; If not, it's hopeless
679 ; Write a warning to indicate we're on *very* thin ice now
680 mov si,nospec_msg
681 call writemsg
682 mov al,dl
683 call writehex2
684 call crlf
685 mov si,trysbm_msg
686 call writemsg
687 jmp .found_drive ; Pray that this works...
689 fatal_error:
690 mov si,nothing_msg
691 call writemsg
693 .norge: jmp short .norge
695 ; Information message (DS:SI) output
696 ; Prefix with "isolinux: "
698 writemsg: push ax
699 push si
700 mov si,isolinux_str
701 call writestr_early
702 pop si
703 call writestr_early
704 pop ax
708 ; Write a character to the screen. There is a more "sophisticated"
709 ; version of this in the subsequent code, so we patch the pointer
710 ; when appropriate.
713 writechr:
714 .simple:
715 pushfd
716 pushad
717 mov ah,0Eh
718 xor bx,bx
719 int 10h
720 popad
721 popfd
725 ; int13: save all the segment registers and call INT 13h.
726 ; Some CD-ROM BIOSes have been found to corrupt segment registers
727 ; and/or disable interrupts.
729 int13:
730 pushf
731 push bp
732 push ds
733 push es
734 push fs
735 push gs
736 int 13h
737 mov bp,sp
738 setc [bp+10] ; Propagate CF to the caller
739 pop gs
740 pop fs
741 pop es
742 pop ds
743 pop bp
744 popf
748 ; Get one sector. Convenience entry point.
750 getonesec:
751 mov bp,1
752 ; Fall through to getlinsec
755 ; Get linear sectors - EBIOS LBA addressing, 2048-byte sectors.
757 ; Input:
758 ; EAX - Linear sector number
759 ; ES:BX - Target buffer
760 ; BP - Sector count
762 global getlinsec
763 getlinsec: jmp word [cs:GetlinsecPtr]
765 %ifndef DEBUG_MESSAGES
768 ; First, the variants that we use when actually loading off a disk
769 ; (hybrid mode.) These are adapted versions of the equivalent routines
770 ; in ldlinux.asm.
774 ; getlinsec_ebios:
776 ; getlinsec implementation for floppy/HDD EBIOS (EDD)
778 getlinsec_ebios:
779 xor edx,edx
780 shld edx,eax,2
781 shl eax,2 ; Convert to HDD sectors
782 add eax,[bsHidden]
783 adc edx,[bsHidden+4]
784 shl bp,2
786 .loop:
787 push bp ; Sectors left
788 .retry2:
789 call maxtrans ; Enforce maximum transfer size
790 movzx edi,bp ; Sectors we are about to read
791 mov cx,retry_count
792 .retry:
794 ; Form DAPA on stack
795 push edx
796 push eax
797 push es
798 push bx
799 push di
800 push word 16
801 mov si,sp
802 pushad
803 mov dl,[DriveNumber]
804 push ds
805 push ss
806 pop ds ; DS <- SS
807 mov ah,42h ; Extended Read
808 call int13
809 pop ds
810 popad
811 lea sp,[si+16] ; Remove DAPA
812 jc .error
813 pop bp
814 add eax,edi ; Advance sector pointer
815 adc edx,0
816 sub bp,di ; Sectors left
817 shl di,9 ; 512-byte sectors
818 add bx,di ; Advance buffer pointer
819 and bp,bp
820 jnz .loop
824 .error:
825 ; Some systems seem to get "stuck" in an error state when
826 ; using EBIOS. Doesn't happen when using CBIOS, which is
827 ; good, since some other systems get timeout failures
828 ; waiting for the floppy disk to spin up.
830 pushad ; Try resetting the device
831 xor ax,ax
832 mov dl,[DriveNumber]
833 call int13
834 popad
835 loop .retry ; CX-- and jump if not zero
837 ;shr word [MaxTransfer],1 ; Reduce the transfer size
838 ;jnz .retry2
840 ; Total failure. Try falling back to CBIOS.
841 mov word [GetlinsecPtr], getlinsec_cbios
842 ;mov byte [MaxTransfer],63 ; Max possibe CBIOS transfer
844 pop bp
845 jmp getlinsec_cbios.loop
848 ; getlinsec_cbios:
850 ; getlinsec implementation for legacy CBIOS
852 getlinsec_cbios:
853 xor edx,edx
854 shl eax,2 ; Convert to HDD sectors
855 add eax,[bsHidden]
856 shl bp,2
858 .loop:
859 push edx
860 push eax
861 push bp
862 push bx
864 movzx esi,word [bsSecPerTrack]
865 movzx edi,word [bsHeads]
867 ; Dividing by sectors to get (track,sector): we may have
868 ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
870 div esi
871 xor cx,cx
872 xchg cx,dx ; CX <- sector index (0-based)
873 ; EDX <- 0
874 ; eax = track #
875 div edi ; Convert track to head/cyl
877 ; We should test this, but it doesn't fit...
878 ; cmp eax,1023
879 ; ja .error
882 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
883 ; BP = sectors to transfer, SI = bsSecPerTrack,
884 ; ES:BX = data target
887 call maxtrans ; Enforce maximum transfer size
889 ; Must not cross track boundaries, so BP <= SI-CX
890 sub si,cx
891 cmp bp,si
892 jna .bp_ok
893 mov bp,si
894 .bp_ok:
896 shl ah,6 ; Because IBM was STOOPID
897 ; and thought 8 bits were enough
898 ; then thought 10 bits were enough...
899 inc cx ; Sector numbers are 1-based, sigh
900 or cl,ah
901 mov ch,al
902 mov dh,dl
903 mov dl,[DriveNumber]
904 xchg ax,bp ; Sector to transfer count
905 mov ah,02h ; Read sectors
906 mov bp,retry_count
907 .retry:
908 pushad
909 call int13
910 popad
911 jc .error
912 .resume:
913 movzx ecx,al ; ECX <- sectors transferred
914 shl ax,9 ; Convert sectors in AL to bytes in AX
915 pop bx
916 add bx,ax
917 pop bp
918 pop eax
919 pop edx
920 add eax,ecx
921 sub bp,cx
922 jnz .loop
925 .error:
926 dec bp
927 jnz .retry
929 xchg ax,bp ; Sectors transferred <- 0
930 shr word [MaxTransfer],1
931 jnz .resume
932 jmp disk_error
935 ; Truncate BP to MaxTransfer
937 maxtrans:
938 cmp bp,[MaxTransfer]
939 jna .ok
940 mov bp,[MaxTransfer]
941 .ok: ret
943 %endif
946 ; This is the variant we use for real CD-ROMs:
947 ; LBA, 2K sectors, some special error handling.
949 getlinsec_cdrom:
950 mov si,dapa ; Load up the DAPA
951 mov [si+4],bx
952 mov [si+6],es
953 mov [si+8],eax
954 .loop:
955 push bp ; Sectors left
956 cmp bp,[MaxTransferCD]
957 jbe .bp_ok
958 mov bp,[MaxTransferCD]
959 .bp_ok:
960 mov [si+2],bp
961 push si
962 mov dl,[DriveNumber]
963 mov ah,42h ; Extended Read
964 call xint13
965 pop si
966 pop bp
967 movzx eax,word [si+2] ; Sectors we read
968 add [si+8],eax ; Advance sector pointer
969 sub bp,ax ; Sectors left
970 shl ax,SECTOR_SHIFT-4 ; 2048-byte sectors -> segment
971 add [si+6],ax ; Advance buffer pointer
972 and bp,bp
973 jnz .loop
974 mov eax,[si+8] ; Next sector
977 ; INT 13h with retry
978 xint13: mov byte [RetryCount],retry_count
979 .try: pushad
980 call int13
981 jc .error
982 add sp,byte 8*4 ; Clean up stack
984 .error:
985 mov [DiskError],ah ; Save error code
986 popad
987 mov [DiskSys],ax ; Save system call number
988 dec byte [RetryCount]
989 jz .real_error
990 push ax
991 mov al,[RetryCount]
992 mov ah,[dapa+2] ; Sector transfer count
993 cmp al,2 ; Only 2 attempts left
994 ja .nodanger
995 mov ah,1 ; Drop transfer size to 1
996 jmp short .setsize
997 .nodanger:
998 cmp al,retry_count-2
999 ja .again ; First time, just try again
1000 shr ah,1 ; Otherwise, try to reduce
1001 adc ah,0 ; the max transfer size, but not to 0
1002 .setsize:
1003 mov [MaxTransferCD],ah
1004 mov [dapa+2],ah
1005 .again:
1006 pop ax
1007 jmp .try
1009 .real_error: mov si,diskerr_msg
1010 call writemsg
1011 mov al,[DiskError]
1012 call writehex2
1013 mov si,oncall_str
1014 call writestr_early
1015 mov ax,[DiskSys]
1016 call writehex4
1017 mov si,ondrive_str
1018 call writestr_early
1019 mov al,dl
1020 call writehex2
1021 call crlf
1022 ; Fall through to kaboom
1025 ; kaboom: write a message and bail out. Wait for a user keypress,
1026 ; then do a hard reboot.
1028 global kaboom
1029 disk_error:
1030 kaboom:
1031 RESET_STACK_AND_SEGS AX
1032 mov si,err_bootfailed
1033 call writestr
1034 call getchar
1036 mov word [BIOS_magic],0 ; Cold reboot
1037 jmp 0F000h:0FFF0h ; Reset vector address
1039 ; -----------------------------------------------------------------------------
1040 ; Common modules needed in the first sector
1041 ; -----------------------------------------------------------------------------
1043 %include "writestr.inc" ; String output
1044 writestr_early equ writestr
1045 %include "writehex.inc" ; Hexadecimal output
1047 ; -----------------------------------------------------------------------------
1048 ; Data that needs to be in the first sector
1049 ; -----------------------------------------------------------------------------
1051 syslinux_banner db CR, LF, MY_NAME, ' ', VERSION_STR, ' ', DATE_STR, ' ', 0
1052 copyright_str db ' Copyright (C) 1994-'
1053 asciidec YEAR
1054 db ' H. Peter Anvin et al', CR, LF, 0
1055 isolinux_str db 'isolinux: ', 0
1056 %ifdef DEBUG_MESSAGES
1057 startup_msg: db 'Starting up, DL = ', 0
1058 spec_ok_msg: db 'Loaded spec packet OK, drive = ', 0
1059 secsize_msg: db 'Sector size ', 0
1060 offset_msg: db 'Main image LBA = ', 0
1061 verify_msg: db 'Image checksum verified.', CR, LF, 0
1062 allread_msg db 'Main image read, jumping to main code...', CR, LF, 0
1063 %endif
1064 noinfotable_msg db 'No boot info table, assuming single session disk...', CR, LF, 0
1065 noinfoinspec_msg db 'Spec packet missing LBA information, trying to wing it...', CR, LF, 0
1066 spec_err_msg: db 'Loading spec packet failed, trying to wing it...', CR, LF, 0
1067 maybe_msg: db 'Found something at drive = ', 0
1068 alright_msg: db 'Looks reasonable, continuing...', CR, LF, 0
1069 nospec_msg db 'Extremely broken BIOS detected, last attempt with drive = ', 0
1070 nothing_msg: db 'Failed to locate CD-ROM device; boot failed.', CR, LF
1071 trysbm_msg db 'See http://syslinux.zytor.com/sbm for more information.', CR, LF, 0
1072 diskerr_msg: db 'Disk error ', 0
1073 oncall_str: db ', AX = ',0
1074 ondrive_str: db ', drive ', 0
1075 checkerr_msg: db 'Image checksum error, sorry...', CR, LF, 0
1077 err_bootfailed db CR, LF, 'Boot failed: press a key to retry...'
1078 bailmsg equ err_bootfailed
1079 crlf_msg db CR, LF
1080 null_msg db 0
1082 bios_cdrom_str db 'ETCD', 0
1083 %ifndef DEBUG_MESSAGES
1084 bios_cbios_str db 'CHDD', 0
1085 bios_ebios_str db 'EHDD' ,0
1086 %endif
1088 alignz 4
1089 bios_cdrom: dw getlinsec_cdrom, bios_cdrom_str
1090 %ifndef DEBUG_MESSAGES
1091 bios_cbios: dw getlinsec_cbios, bios_cbios_str
1092 bios_ebios: dw getlinsec_ebios, bios_ebios_str
1093 %endif
1095 ; Maximum transfer size
1096 MaxTransfer dw 127 ; Hard disk modes
1097 MaxTransferCD dw 32 ; CD mode
1099 rl_checkpt equ $ ; Must be <= 800h
1101 ; This pads to the end of sector 0 and errors out on
1102 ; overflow.
1103 times 2048-($-$$) db 0
1105 ; ----------------------------------------------------------------------------
1106 ; End of code and data that have to be in the first sector
1107 ; ----------------------------------------------------------------------------
1109 section .text16
1111 all_read:
1113 ; Test tracers
1114 TRACER 'T'
1115 TRACER '>'
1118 ; Common initialization code
1120 %include "init.inc"
1122 ; Patch the writechr routine to point to the full code
1123 mov di,writechr
1124 mov al,0e9h
1125 stosb
1126 mov ax,writechr_full-2
1127 sub ax,di
1128 stosw
1130 ; Tell the user we got this far...
1131 %ifndef DEBUG_MESSAGES ; Gets messy with debugging on
1132 mov si,copyright_str
1133 call writestr_early
1134 %endif
1137 ; Now we're all set to start with our *real* business. First load the
1138 ; configuration file (if any) and parse it.
1140 ; In previous versions I avoided using 32-bit registers because of a
1141 ; rumour some BIOSes clobbered the upper half of 32-bit registers at
1142 ; random. I figure, though, that if there are any of those still left
1143 ; they probably won't be trying to install Linux on them...
1145 ; The code is still ripe with 16-bitisms, though. Not worth the hassle
1146 ; to take'm out. In fact, we may want to put them back if we're going
1147 ; to boot ELKS at some point.
1151 ; Now, we need to sniff out the actual filesystem data structures.
1152 ; mkisofs gave us a pointer to the primary volume descriptor
1153 ; (which will be at 16 only for a single-session disk!); from the PVD
1154 ; we should be able to find the rest of what we need to know.
1156 init_fs:
1157 pushad
1158 mov eax,ROOT_FS_OPS
1159 mov dl,[DriveNumber]
1160 cmp word [BIOSType],bios_cdrom
1161 sete dh ; 1 for cdrom, 0 for hybrid mode
1162 jne .hybrid
1163 movzx ebp,word [MaxTransferCD]
1164 jmp .common
1165 .hybrid:
1166 movzx ebp,word [MaxTransfer]
1167 .common:
1168 mov ecx,[bsHidden]
1169 mov ebx,[bsHidden+4]
1170 mov si,[bsHeads]
1171 mov di,[bsSecPerTrack]
1172 pm_call fs_init
1173 popad
1175 section .rodata
1176 alignz 4
1177 ROOT_FS_OPS:
1178 extern iso_fs_ops
1179 dd iso_fs_ops
1180 dd 0
1182 section .text16
1185 ; Locate the configuration file
1187 pm_call load_config
1190 ; Now we have the config file open. Parse the config file and
1191 ; run the user interface.
1193 %include "ui.inc"
1196 ; Enable disk emulation. The kind of disk we emulate is dependent on the
1197 ; size of the file: 1200K, 1440K or 2880K floppy, otherwise harddisk.
1199 is_disk_image:
1200 TRACER CR
1201 TRACER LF
1202 TRACER 'D'
1203 TRACER ':'
1205 mov edx,eax ; File size
1206 mov di,img_table
1207 mov cx,img_table_count
1208 mov eax,[si+file_sector] ; Starting LBA of file
1209 mov [dsp_lba],eax ; Location of file
1210 mov byte [dsp_drive], 0 ; 00h floppy, 80h hard disk
1211 .search_table:
1212 TRACER 't'
1213 mov eax,[di+4]
1214 cmp edx,[di]
1215 je .type_found
1216 add di,8
1217 loop .search_table
1219 ; Hard disk image. Need to examine the partition table
1220 ; in order to deduce the C/H/S geometry. Sigh.
1221 .hard_disk_image:
1222 TRACER 'h'
1223 cmp edx,512
1224 jb .bad_image
1226 mov bx,trackbuf
1227 mov cx,1 ; Load 1 sector
1228 pm_call getfssec
1230 cmp word [trackbuf+510],0aa55h ; Boot signature
1231 jne .bad_image ; Image not bootable
1233 mov cx,4 ; 4 partition entries
1234 mov di,trackbuf+446 ; Start of partition table
1236 xor ax,ax ; Highest sector(al) head(ah)
1238 .part_scan:
1239 cmp byte [di+4], 0
1240 jz .part_loop
1241 lea si,[di+1]
1242 call .hs_check
1243 add si,byte 4
1244 call .hs_check
1245 .part_loop:
1246 add di,byte 16
1247 loop .part_scan
1249 push eax ; H/S
1250 push edx ; File size
1251 mov bl,ah
1252 xor bh,bh
1253 inc bx ; # of heads in BX
1254 xor ah,ah ; # of sectors in AX
1255 cwde ; EAX[31:16] <- 0
1256 mul bx
1257 shl eax,9 ; Convert to bytes
1258 ; Now eax contains the number of bytes per cylinder
1259 pop ebx ; File size
1260 xor edx,edx
1261 div ebx
1262 and edx,edx
1263 jz .no_remainder
1264 inc eax ; Fractional cylinder...
1265 ; Now (e)ax contains the number of cylinders
1266 .no_remainder: cmp eax,1024
1267 jna .ok_cyl
1268 mov ax,1024 ; Max possible #
1269 .ok_cyl: dec ax ; Convert to max cylinder no
1270 pop ebx ; S(bl) H(bh)
1271 shl ah,6
1272 or bl,ah
1273 xchg ax,bx
1274 shl eax,16
1275 mov ah,bl
1276 mov al,4 ; Hard disk boot
1277 mov byte [dsp_drive], 80h ; Drive 80h = hard disk
1279 .type_found:
1280 TRACER 'T'
1281 mov bl,[sp_media]
1282 and bl,0F0h ; Copy controller info bits
1283 or al,bl
1284 mov [dsp_media],al ; Emulation type
1285 shr eax,8
1286 mov [dsp_chs],eax ; C/H/S geometry
1287 mov ax,[sp_devspec] ; Copy device spec
1288 mov [dsp_devspec],ax
1289 mov al,[sp_controller] ; Copy controller index
1290 mov [dsp_controller],al
1292 TRACER 'V'
1293 call vgaclearmode ; Reset video
1295 mov ax,4C00h ; Enable emulation and boot
1296 mov si,dspec_packet
1297 mov dl,[DriveNumber]
1298 lss sp,[InitStack]
1299 TRACER 'X'
1301 call int13
1303 ; If this returns, we have problems
1304 .bad_image:
1305 mov si,err_disk_image
1306 call writestr
1307 jmp enter_command
1310 ; Look for the highest seen H/S geometry
1311 ; We compute cylinders separately
1313 .hs_check:
1314 mov bl,[si] ; Head #
1315 cmp bl,ah
1316 jna .done_track
1317 mov ah,bl ; New highest head #
1318 .done_track: mov bl,[si+1]
1319 and bl,3Fh ; Sector #
1320 cmp bl,al
1321 jna .done_sector
1322 mov al,bl
1323 .done_sector: ret
1327 ; -----------------------------------------------------------------------------
1328 ; Common modules
1329 ; -----------------------------------------------------------------------------
1331 %include "common.inc" ; Universal modules
1332 %include "rawcon.inc" ; Console I/O w/o using the console functions
1333 %include "localboot.inc" ; Disk-based local boot
1335 ; -----------------------------------------------------------------------------
1336 ; Begin data section
1337 ; -----------------------------------------------------------------------------
1339 section .data16
1340 err_disk_image db 'Cannot load disk image (invalid file)?', CR, LF, 0
1343 ; Config file keyword table
1345 %include "keywords.inc"
1348 ; Extensions to search for (in *forward* order).
1350 alignz 4
1351 exten_table: db '.cbt' ; COMBOOT (specific)
1352 db '.img' ; Disk image
1353 db '.bin' ; CD boot sector
1354 db '.com' ; COMBOOT (same as DOS)
1355 db '.c32' ; COM32
1356 exten_table_end:
1357 dd 0, 0 ; Need 8 null bytes here
1360 ; Floppy image table
1362 alignz 4
1363 img_table_count equ 3
1364 img_table:
1365 dd 1200*1024 ; 1200K floppy
1366 db 1 ; Emulation type
1367 db 80-1 ; Max cylinder
1368 db 15 ; Max sector
1369 db 2-1 ; Max head
1371 dd 1440*1024 ; 1440K floppy
1372 db 2 ; Emulation type
1373 db 80-1 ; Max cylinder
1374 db 18 ; Max sector
1375 db 2-1 ; Max head
1377 dd 2880*1024 ; 2880K floppy
1378 db 3 ; Emulation type
1379 db 80-1 ; Max cylinder
1380 db 36 ; Max sector
1381 db 2-1 ; Max head