com32/chain: make raw handover use total sectors info
[syslinux.git] / core / isolinux.asm
blobca8ee3a317e3a9211cb551e4cccae22029db32f7
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 Hidden 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 si,bios_cbios
246 jcxz _start_common
247 mov si,bios_ebios
248 jmp _start_common
249 %endif
251 _start1:
252 mov si,bios_cdrom
253 xor eax,eax
254 xor ebx,ebx
255 _start_common:
256 mov [cs:InitStack],sp ; Save initial stack pointer
257 mov [cs:InitStack+2],ss
258 xor cx,cx
259 mov ss,cx
260 mov sp,StackBuf ; Set up stack
261 push es ; Save initial ES:DI -> $PnP pointer
262 push di
263 mov ds,cx
264 mov es,cx
265 mov fs,cx
266 mov gs,cx
270 mov [Hidden],eax
271 mov [Hidden+4],ebx
273 mov [BIOSType],si
274 mov eax,[si]
275 mov [GetlinsecPtr],eax
277 ; Show signs of life
278 mov si,syslinux_banner
279 call writestr_early
280 %ifdef DEBUG_MESSAGES
281 mov si,copyright_str
282 %else
283 mov si,[BIOSName]
284 %endif
285 call writestr_early
288 ; Before modifying any memory, get the checksum of bytes
289 ; 64-2048
291 initial_csum: xor edi,edi
292 mov si,bi_end
293 mov cx,(SECTOR_SIZE-64) >> 2
294 .loop: lodsd
295 add edi,eax
296 loop .loop
297 mov [FirstSecSum],edi
299 mov [DriveNumber],dl
300 %ifdef DEBUG_MESSAGES
301 mov si,startup_msg
302 call writemsg
303 mov al,dl
304 call writehex2
305 call crlf
306 %endif
308 ; Initialize spec packet buffers
310 mov di,_spec_start
311 mov cx,_spec_len >> 2
312 xor eax,eax
313 rep stosd
315 ; Initialize length field of the various packets
316 mov byte [spec_packet],13h
317 mov byte [drive_params],30
318 mov byte [dapa],16
319 mov byte [dspec_packet],13h
321 ; Other nonzero fields
322 inc word [dsp_sectors]
324 ; Are we just pretending to be a CD-ROM?
325 cmp word [BIOSType],bios_cdrom
326 jne found_drive ; If so, no spec packet...
328 ; Now figure out what we're actually doing
329 ; Note: use passed-in DL value rather than 7Fh because
330 ; at least some BIOSes will get the wrong value otherwise
331 mov ax,4B01h ; Get disk emulation status
332 mov dl,[DriveNumber]
333 mov si,spec_packet
334 call int13
335 jc award_hack ; changed for BrokenAwardHack
336 mov dl,[DriveNumber]
337 cmp [sp_drive],dl ; Should contain the drive number
338 jne spec_query_failed
340 %ifdef DEBUG_MESSAGES
341 mov si,spec_ok_msg
342 call writemsg
343 mov al,byte [sp_drive]
344 call writehex2
345 call crlf
346 %endif
348 found_drive:
349 ; Alright, we have found the drive. Now, try to find the
350 ; boot file itself. If we have a boot info table, life is
351 ; good; if not, we have to make some assumptions, and try
352 ; to figure things out ourselves. In particular, the
353 ; assumptions we have to make are:
354 ; - single session only
355 ; - only one boot entry (no menu or other alternatives)
357 cmp dword [bi_file],0 ; Address of code to load
358 jne found_file ; Boot info table present :)
360 %ifdef DEBUG_MESSAGES
361 mov si,noinfotable_msg
362 call writemsg
363 %endif
365 ; No such luck. See if the spec packet contained one.
366 mov eax,[sp_lba]
367 and eax,eax
368 jz set_file ; Good enough
370 %ifdef DEBUG_MESSAGES
371 mov si,noinfoinspec_msg
372 call writemsg
373 %endif
375 ; No such luck. Get the Boot Record Volume, assuming single
376 ; session disk, and that we're the first entry in the chain.
377 mov eax,17 ; Assumed address of BRV
378 mov bx,trackbuf
379 call getonesec
381 mov eax,[trackbuf+47h] ; Get boot catalog address
382 mov bx,trackbuf
383 call getonesec ; Get boot catalog
385 mov eax,[trackbuf+28h] ; First boot entry
386 ; And hope and pray this is us...
388 ; Some BIOSes apparently have limitations on the size
389 ; that may be loaded (despite the El Torito spec being very
390 ; clear on the fact that it must all be loaded.) Therefore,
391 ; we load it ourselves, and *bleep* the BIOS.
393 set_file:
394 mov [bi_file],eax
396 found_file:
397 ; Set up boot file sizes
398 mov eax,[bi_length]
399 sub eax,SECTOR_SIZE-3 ; ... minus sector loaded
400 shr eax,2 ; bytes->dwords
401 mov [ImageDwords],eax ; boot file dwords
402 add eax,((SECTOR_SIZE-1) >> 2)
403 shr eax,SECTOR_SHIFT-2 ; dwords->sectors
404 mov [ImageSectors],ax ; boot file sectors
406 mov eax,[bi_file] ; Address of code to load
407 inc eax ; Don't reload bootstrap code
408 %ifdef DEBUG_MESSAGES
409 mov si,offset_msg
410 call writemsg
411 call writehex8
412 call crlf
413 %endif
415 ; Load the rest of the file. However, just in case there
416 ; are still BIOSes with 64K wraparound problems, we have to
417 ; take some extra precautions. Since the normal load
418 ; address (TEXT_START) is *not* 2K-sector-aligned, we round
419 ; the target address upward to a sector boundary,
420 ; and then move the entire thing down as a unit.
421 MaxLMA equ 384*1024 ; Reasonable limit (384K)
423 mov bx,((TEXT_START+2*SECTOR_SIZE-1) & ~(SECTOR_SIZE-1)) >> 4
424 mov bp,[ImageSectors]
425 push bx ; Load segment address
427 .more:
428 push bx ; Segment address
429 push bp ; Sector count
430 mov es,bx
431 mov cx,0xfff
432 and bx,cx
433 inc cx
434 sub cx,bx
435 shr cx,SECTOR_SHIFT - 4
436 jnz .notaligned
437 mov cx,0x10000 >> SECTOR_SHIFT ; Full 64K segment possible
438 .notaligned:
439 cmp bp,cx
440 jbe .ok
441 mov bp,cx
442 .ok:
443 xor bx,bx
444 push bp
445 call getlinsec
446 pop cx
447 mov dx,cx
448 pop bp
449 pop bx
451 shl cx,SECTOR_SHIFT - 4
452 add bx,cx
453 sub bp,dx
454 jnz .more
456 ; Move the image into place, and also verify the
457 ; checksum
458 pop ax ; Load segment address
459 mov bx,(TEXT_START + SECTOR_SIZE) >> 4
460 mov ecx,[ImageDwords]
461 mov edi,[FirstSecSum] ; First sector checksum
462 xor si,si
464 move_verify_image:
465 .setseg:
466 mov ds,ax
467 mov es,bx
468 .loop:
469 mov edx,[si]
470 add edi,edx
471 dec ecx
472 mov [es:si],edx
473 jz .done
474 add si,4
475 jnz .loop
476 add ax,1000h
477 add bx,1000h
478 jmp .setseg
479 .done:
480 mov ax,cs
481 mov ds,ax
482 mov es,ax
484 ; Verify the checksum on the loaded image.
485 cmp [bi_csum],edi
486 je integrity_ok
488 mov si,checkerr_msg
489 call writemsg
490 jmp kaboom
492 integrity_ok:
493 %ifdef DEBUG_MESSAGES
494 mov si,allread_msg
495 call writemsg
496 %endif
497 jmp all_read ; Jump to main code
499 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
500 ;; Start of BrokenAwardHack --- 10-nov-2002 Knut_Petersen@t-online.de
501 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
503 ;; There is a problem with certain versions of the AWARD BIOS ...
504 ;; the boot sector will be loaded and executed correctly, but, because the
505 ;; int 13 vector points to the wrong code in the BIOS, every attempt to
506 ;; load the spec packet will fail. We scan for the equivalent of
508 ;; mov ax,0201h
509 ;; mov bx,7c00h
510 ;; mov cx,0006h
511 ;; mov dx,0180h
512 ;; pushf
513 ;; call <direct far>
515 ;; and use <direct far> as the new vector for int 13. The code above is
516 ;; used to load the boot code into ram, and there should be no reason
517 ;; for anybody to change it now or in the future. There are no opcodes
518 ;; that use encodings relativ to IP, so scanning is easy. If we find the
519 ;; code above in the BIOS code we can be pretty sure to run on a machine
520 ;; with an broken AWARD BIOS ...
522 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
524 %ifdef DEBUG_MESSAGES ;;
526 award_notice db "Trying BrokenAwardHack first ...",CR,LF,0 ;;
527 award_not_orig db "BAH: Original Int 13 vector : ",0 ;;
528 award_not_new db "BAH: Int 13 vector changed to : ",0 ;;
529 award_not_succ db "BAH: SUCCESS",CR,LF,0 ;;
530 award_not_fail db "BAH: FAILURE" ;;
531 award_not_crlf db CR,LF,0 ;;
533 %endif ;;
535 award_oldint13 dd 0 ;;
536 award_string db 0b8h,1,2,0bbh,0,7ch,0b9h,6,0,0bah,80h,1,09ch,09ah ;;
538 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
539 award_hack: mov si,spec_err_msg ; Moved to this place from
540 call writemsg ; spec_query_faild
542 %ifdef DEBUG_MESSAGES ;
544 mov si,award_notice ; display our plan
545 call writemsg ;
546 mov si,award_not_orig ; display original int 13
547 call writemsg ; vector
548 %endif ;
549 mov eax,[13h*4] ;
550 mov [award_oldint13],eax ;
552 %ifdef DEBUG_MESSAGES ;
554 call writehex8 ;
555 mov si,award_not_crlf ;
556 call writestr_early ;
557 %endif ;
558 push es ; save ES
559 mov ax,0f000h ; ES = BIOS Seg
560 mov es,ax ;
561 cld ;
562 xor di,di ; start at ES:DI = f000:0
563 award_loop: push di ; save DI
564 mov si,award_string ; scan for award_string
565 mov cx,7 ; length of award_string = 7dw
566 repz cmpsw ; compare
567 pop di ; restore DI
568 jcxz award_found ; jmp if found
569 inc di ; not found, inc di
570 jno award_loop ;
572 award_failed: pop es ; No, not this way :-((
573 award_fail2: ;
575 %ifdef DEBUG_MESSAGES ;
577 mov si,award_not_fail ; display failure ...
578 call writemsg ;
579 %endif ;
580 mov eax,[award_oldint13] ; restore the original int
581 or eax,eax ; 13 vector if there is one
582 jz spec_query_failed ; and try other workarounds
583 mov [13h*4],eax ;
584 jmp spec_query_failed ;
586 award_found: mov eax,[es:di+0eh] ; load possible int 13 addr
587 pop es ; restore ES
589 cmp eax,[award_oldint13] ; give up if this is the
590 jz award_failed ; active int 13 vector,
591 mov [13h*4],eax ; otherwise change 0:13h*4
594 %ifdef DEBUG_MESSAGES ;
596 push eax ; display message and
597 mov si,award_not_new ; new vector address
598 call writemsg ;
599 pop eax ;
600 call writehex8 ;
601 mov si,award_not_crlf ;
602 call writestr_early ;
603 %endif ;
604 mov ax,4B01h ; try to read the spec packet
605 mov dl,[DriveNumber] ; now ... it should not fail
606 mov si,spec_packet ; any longer
607 int 13h ;
608 jc award_fail2 ;
610 %ifdef DEBUG_MESSAGES ;
612 mov si,award_not_succ ; display our SUCCESS
613 call writemsg ;
614 %endif ;
615 jmp found_drive ; and leave error recovery code
617 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
618 ;; End of BrokenAwardHack ---- 10-nov-2002 Knut_Petersen@t-online.de
619 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
622 ; INT 13h, AX=4B01h, DL=<passed in value> failed.
623 ; Try to scan the entire 80h-FFh from the end.
625 spec_query_failed:
627 ; some code moved to BrokenAwardHack
629 mov dl,0FFh
630 .test_loop: pusha
631 mov ax,4B01h
632 mov si,spec_packet
633 mov byte [si],13h ; Size of buffer
634 call int13
635 popa
636 jc .still_broken
638 mov si,maybe_msg
639 call writemsg
640 mov al,dl
641 call writehex2
642 call crlf
644 cmp byte [sp_drive],dl
645 jne .maybe_broken
647 ; Okay, good enough...
648 mov si,alright_msg
649 call writemsg
650 .found_drive0: mov [DriveNumber],dl
651 .found_drive: jmp found_drive
653 ; Award BIOS 4.51 apparently passes garbage in sp_drive,
654 ; but if this was the drive number originally passed in
655 ; DL then consider it "good enough"
656 .maybe_broken:
657 mov al,[DriveNumber]
658 cmp al,dl
659 je .found_drive
661 ; Intel Classic R+ computer with Adaptec 1542CP BIOS 1.02
662 ; passes garbage in sp_drive, and the drive number originally
663 ; passed in DL does not have 80h bit set.
664 or al,80h
665 cmp al,dl
666 je .found_drive0
668 .still_broken: dec dx
669 cmp dl, 80h
670 jnb .test_loop
672 ; No spec packet anywhere. Some particularly pathetic
673 ; BIOSes apparently don't even implement function
674 ; 4B01h, so we can't query a spec packet no matter
675 ; what. If we got a drive number in DL, then try to
676 ; use it, and if it works, then well...
677 mov dl,[DriveNumber]
678 cmp dl,81h ; Should be 81-FF at least
679 jb fatal_error ; If not, it's hopeless
681 ; Write a warning to indicate we're on *very* thin ice now
682 mov si,nospec_msg
683 call writemsg
684 mov al,dl
685 call writehex2
686 call crlf
687 mov si,trysbm_msg
688 call writemsg
689 jmp .found_drive ; Pray that this works...
691 fatal_error:
692 mov si,nothing_msg
693 call writemsg
695 .norge: jmp short .norge
697 ; Information message (DS:SI) output
698 ; Prefix with "isolinux: "
700 writemsg: push ax
701 push si
702 mov si,isolinux_str
703 call writestr_early
704 pop si
705 call writestr_early
706 pop ax
710 ; Write a character to the screen. There is a more "sophisticated"
711 ; version of this in the subsequent code, so we patch the pointer
712 ; when appropriate.
715 writechr:
716 .simple:
717 pushfd
718 pushad
719 mov ah,0Eh
720 xor bx,bx
721 int 10h
722 popad
723 popfd
727 ; int13: save all the segment registers and call INT 13h.
728 ; Some CD-ROM BIOSes have been found to corrupt segment registers
729 ; and/or disable interrupts.
731 int13:
732 pushf
733 push bp
734 push ds
735 push es
736 push fs
737 push gs
738 int 13h
739 mov bp,sp
740 setc [bp+10] ; Propagate CF to the caller
741 pop gs
742 pop fs
743 pop es
744 pop ds
745 pop bp
746 popf
750 ; Get one sector. Convenience entry point.
752 getonesec:
753 mov bp,1
754 ; Fall through to getlinsec
757 ; Get linear sectors - EBIOS LBA addressing, 2048-byte sectors.
759 ; Input:
760 ; EAX - Linear sector number
761 ; ES:BX - Target buffer
762 ; BP - Sector count
764 global getlinsec
765 getlinsec: jmp word [cs:GetlinsecPtr]
767 %ifndef DEBUG_MESSAGES
770 ; First, the variants that we use when actually loading off a disk
771 ; (hybrid mode.) These are adapted versions of the equivalent routines
772 ; in ldlinux.asm.
776 ; getlinsec_ebios:
778 ; getlinsec implementation for floppy/HDD EBIOS (EDD)
780 getlinsec_ebios:
781 xor edx,edx
782 shld edx,eax,2
783 shl eax,2 ; Convert to HDD sectors
784 add eax,[Hidden]
785 adc edx,[Hidden+4]
786 shl bp,2
788 .loop:
789 push bp ; Sectors left
790 .retry2:
791 call maxtrans ; Enforce maximum transfer size
792 movzx edi,bp ; Sectors we are about to read
793 mov cx,retry_count
794 .retry:
796 ; Form DAPA on stack
797 push edx
798 push eax
799 push es
800 push bx
801 push di
802 push word 16
803 mov si,sp
804 pushad
805 mov dl,[DriveNumber]
806 push ds
807 push ss
808 pop ds ; DS <- SS
809 mov ah,42h ; Extended Read
810 call int13
811 pop ds
812 popad
813 lea sp,[si+16] ; Remove DAPA
814 jc .error
815 pop bp
816 add eax,edi ; Advance sector pointer
817 adc edx,0
818 sub bp,di ; Sectors left
819 shl di,9 ; 512-byte sectors
820 add bx,di ; Advance buffer pointer
821 and bp,bp
822 jnz .loop
826 .error:
827 ; Some systems seem to get "stuck" in an error state when
828 ; using EBIOS. Doesn't happen when using CBIOS, which is
829 ; good, since some other systems get timeout failures
830 ; waiting for the floppy disk to spin up.
832 pushad ; Try resetting the device
833 xor ax,ax
834 mov dl,[DriveNumber]
835 call int13
836 popad
837 loop .retry ; CX-- and jump if not zero
839 ;shr word [MaxTransfer],1 ; Reduce the transfer size
840 ;jnz .retry2
842 ; Total failure. Try falling back to CBIOS.
843 mov word [GetlinsecPtr], getlinsec_cbios
844 ;mov byte [MaxTransfer],63 ; Max possibe CBIOS transfer
846 pop bp
847 jmp getlinsec_cbios.loop
850 ; getlinsec_cbios:
852 ; getlinsec implementation for legacy CBIOS
854 getlinsec_cbios:
855 xor edx,edx
856 shl eax,2 ; Convert to HDD sectors
857 add eax,[Hidden]
858 shl bp,2
860 .loop:
861 push edx
862 push eax
863 push bp
864 push bx
866 movzx esi,word [bsSecPerTrack]
867 movzx edi,word [bsHeads]
869 ; Dividing by sectors to get (track,sector): we may have
870 ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
872 div esi
873 xor cx,cx
874 xchg cx,dx ; CX <- sector index (0-based)
875 ; EDX <- 0
876 ; eax = track #
877 div edi ; Convert track to head/cyl
879 ; We should test this, but it doesn't fit...
880 ; cmp eax,1023
881 ; ja .error
884 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
885 ; BP = sectors to transfer, SI = bsSecPerTrack,
886 ; ES:BX = data target
889 call maxtrans ; Enforce maximum transfer size
891 ; Must not cross track boundaries, so BP <= SI-CX
892 sub si,cx
893 cmp bp,si
894 jna .bp_ok
895 mov bp,si
896 .bp_ok:
898 shl ah,6 ; Because IBM was STOOPID
899 ; and thought 8 bits were enough
900 ; then thought 10 bits were enough...
901 inc cx ; Sector numbers are 1-based, sigh
902 or cl,ah
903 mov ch,al
904 mov dh,dl
905 mov dl,[DriveNumber]
906 xchg ax,bp ; Sector to transfer count
907 mov ah,02h ; Read sectors
908 mov bp,retry_count
909 .retry:
910 pushad
911 call int13
912 popad
913 jc .error
914 .resume:
915 movzx ecx,al ; ECX <- sectors transferred
916 shl ax,9 ; Convert sectors in AL to bytes in AX
917 pop bx
918 add bx,ax
919 pop bp
920 pop eax
921 pop edx
922 add eax,ecx
923 sub bp,cx
924 jnz .loop
927 .error:
928 dec bp
929 jnz .retry
931 xchg ax,bp ; Sectors transferred <- 0
932 shr word [MaxTransfer],1
933 jnz .resume
934 jmp disk_error
937 ; Truncate BP to MaxTransfer
939 maxtrans:
940 cmp bp,[MaxTransfer]
941 jna .ok
942 mov bp,[MaxTransfer]
943 .ok: ret
945 %endif
948 ; This is the variant we use for real CD-ROMs:
949 ; LBA, 2K sectors, some special error handling.
951 getlinsec_cdrom:
952 mov si,dapa ; Load up the DAPA
953 mov [si+4],bx
954 mov [si+6],es
955 mov [si+8],eax
956 .loop:
957 push bp ; Sectors left
958 cmp bp,[MaxTransferCD]
959 jbe .bp_ok
960 mov bp,[MaxTransferCD]
961 .bp_ok:
962 mov [si+2],bp
963 push si
964 mov dl,[DriveNumber]
965 mov ah,42h ; Extended Read
966 call xint13
967 pop si
968 pop bp
969 movzx eax,word [si+2] ; Sectors we read
970 add [si+8],eax ; Advance sector pointer
971 sub bp,ax ; Sectors left
972 shl ax,SECTOR_SHIFT-4 ; 2048-byte sectors -> segment
973 add [si+6],ax ; Advance buffer pointer
974 and bp,bp
975 jnz .loop
976 mov eax,[si+8] ; Next sector
979 ; INT 13h with retry
980 xint13: mov byte [RetryCount],retry_count
981 .try: pushad
982 call int13
983 jc .error
984 add sp,byte 8*4 ; Clean up stack
986 .error:
987 mov [DiskError],ah ; Save error code
988 popad
989 mov [DiskSys],ax ; Save system call number
990 dec byte [RetryCount]
991 jz .real_error
992 push ax
993 mov al,[RetryCount]
994 mov ah,[dapa+2] ; Sector transfer count
995 cmp al,2 ; Only 2 attempts left
996 ja .nodanger
997 mov ah,1 ; Drop transfer size to 1
998 jmp short .setsize
999 .nodanger:
1000 cmp al,retry_count-2
1001 ja .again ; First time, just try again
1002 shr ah,1 ; Otherwise, try to reduce
1003 adc ah,0 ; the max transfer size, but not to 0
1004 .setsize:
1005 mov [MaxTransferCD],ah
1006 mov [dapa+2],ah
1007 .again:
1008 pop ax
1009 jmp .try
1011 .real_error: mov si,diskerr_msg
1012 call writemsg
1013 mov al,[DiskError]
1014 call writehex2
1015 mov si,oncall_str
1016 call writestr_early
1017 mov ax,[DiskSys]
1018 call writehex4
1019 mov si,ondrive_str
1020 call writestr_early
1021 mov al,dl
1022 call writehex2
1023 call crlf
1024 ; Fall through to kaboom
1027 ; kaboom: write a message and bail out. Wait for a user keypress,
1028 ; then do a hard reboot.
1030 global kaboom
1031 disk_error:
1032 kaboom:
1033 RESET_STACK_AND_SEGS AX
1034 mov si,err_bootfailed
1035 call writestr
1036 call getchar
1038 mov word [BIOS_magic],0 ; Cold reboot
1039 jmp 0F000h:0FFF0h ; Reset vector address
1041 ; -----------------------------------------------------------------------------
1042 ; Common modules needed in the first sector
1043 ; -----------------------------------------------------------------------------
1045 %include "writestr.inc" ; String output
1046 writestr_early equ writestr
1047 %include "writehex.inc" ; Hexadecimal output
1049 ; -----------------------------------------------------------------------------
1050 ; Data that needs to be in the first sector
1051 ; -----------------------------------------------------------------------------
1053 syslinux_banner db CR, LF, MY_NAME, ' ', VERSION_STR, ' ', DATE_STR, ' ', 0
1054 copyright_str db ' Copyright (C) 1994-'
1055 asciidec YEAR
1056 db ' H. Peter Anvin et al', CR, LF, 0
1057 isolinux_str db 'isolinux: ', 0
1058 %ifdef DEBUG_MESSAGES
1059 startup_msg: db 'Starting up, DL = ', 0
1060 spec_ok_msg: db 'Loaded spec packet OK, drive = ', 0
1061 secsize_msg: db 'Sector size ', 0
1062 offset_msg: db 'Main image LBA = ', 0
1063 verify_msg: db 'Image checksum verified.', CR, LF, 0
1064 allread_msg db 'Main image read, jumping to main code...', CR, LF, 0
1065 %endif
1066 noinfotable_msg db 'No boot info table, assuming single session disk...', CR, LF, 0
1067 noinfoinspec_msg db 'Spec packet missing LBA information, trying to wing it...', CR, LF, 0
1068 spec_err_msg: db 'Loading spec packet failed, trying to wing it...', CR, LF, 0
1069 maybe_msg: db 'Found something at drive = ', 0
1070 alright_msg: db 'Looks reasonable, continuing...', CR, LF, 0
1071 nospec_msg db 'Extremely broken BIOS detected, last attempt with drive = ', 0
1072 nothing_msg: db 'Failed to locate CD-ROM device; boot failed.', CR, LF
1073 trysbm_msg db 'See http://syslinux.zytor.com/sbm for more information.', CR, LF, 0
1074 diskerr_msg: db 'Disk error ', 0
1075 oncall_str: db ', AX = ',0
1076 ondrive_str: db ', drive ', 0
1077 checkerr_msg: db 'Image checksum error, sorry...', CR, LF, 0
1079 err_bootfailed db CR, LF, 'Boot failed: press a key to retry...'
1080 bailmsg equ err_bootfailed
1081 crlf_msg db CR, LF
1082 null_msg db 0
1084 bios_cdrom_str db 'ETCD', 0
1085 %ifndef DEBUG_MESSAGES
1086 bios_cbios_str db 'CHDD', 0
1087 bios_ebios_str db 'EHDD' ,0
1088 %endif
1090 alignz 4
1091 bios_cdrom: dw getlinsec_cdrom, bios_cdrom_str
1092 %ifndef DEBUG_MESSAGES
1093 bios_cbios: dw getlinsec_cbios, bios_cbios_str
1094 bios_ebios: dw getlinsec_ebios, bios_ebios_str
1095 %endif
1097 ; Maximum transfer size
1098 MaxTransfer dw 127 ; Hard disk modes
1099 MaxTransferCD dw 32 ; CD mode
1101 rl_checkpt equ $ ; Must be <= 800h
1103 ; This pads to the end of sector 0 and errors out on
1104 ; overflow.
1105 times 2048-($-$$) db 0
1107 ; ----------------------------------------------------------------------------
1108 ; End of code and data that have to be in the first sector
1109 ; ----------------------------------------------------------------------------
1111 section .text16
1113 all_read:
1115 ; Test tracers
1116 TRACER 'T'
1117 TRACER '>'
1120 ; Common initialization code
1122 %include "init.inc"
1124 ; Patch the writechr routine to point to the full code
1125 mov di,writechr
1126 mov al,0e9h
1127 stosb
1128 mov ax,writechr_full-2
1129 sub ax,di
1130 stosw
1132 ; Tell the user we got this far...
1133 %ifndef DEBUG_MESSAGES ; Gets messy with debugging on
1134 mov si,copyright_str
1135 call writestr_early
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 popad
1177 section .rodata
1178 alignz 4
1179 ROOT_FS_OPS:
1180 extern iso_fs_ops
1181 dd iso_fs_ops
1182 dd 0
1184 section .text16
1187 ; Locate the configuration file
1189 pm_call pm_load_config
1190 jz no_config_file
1193 ; Now we have the config file open. Parse the config file and
1194 ; run the user interface.
1196 %include "ui.inc"
1199 ; Enable disk emulation. The kind of disk we emulate is dependent on the
1200 ; size of the file: 1200K, 1440K or 2880K floppy, otherwise harddisk.
1202 is_disk_image:
1203 TRACER CR
1204 TRACER LF
1205 TRACER 'D'
1206 TRACER ':'
1208 mov edx,eax ; File size
1209 mov di,img_table
1210 mov cx,img_table_count
1211 mov eax,[si+file_sector] ; Starting LBA of file
1212 mov [dsp_lba],eax ; Location of file
1213 mov byte [dsp_drive], 0 ; 00h floppy, 80h hard disk
1214 .search_table:
1215 TRACER 't'
1216 mov eax,[di+4]
1217 cmp edx,[di]
1218 je .type_found
1219 add di,8
1220 loop .search_table
1222 ; Hard disk image. Need to examine the partition table
1223 ; in order to deduce the C/H/S geometry. Sigh.
1224 .hard_disk_image:
1225 TRACER 'h'
1226 cmp edx,512
1227 jb .bad_image
1229 mov bx,trackbuf
1230 mov cx,1 ; Load 1 sector
1231 pm_call getfssec
1233 cmp word [trackbuf+510],0aa55h ; Boot signature
1234 jne .bad_image ; Image not bootable
1236 mov cx,4 ; 4 partition entries
1237 mov di,trackbuf+446 ; Start of partition table
1239 xor ax,ax ; Highest sector(al) head(ah)
1241 .part_scan:
1242 cmp byte [di+4], 0
1243 jz .part_loop
1244 lea si,[di+1]
1245 call .hs_check
1246 add si,byte 4
1247 call .hs_check
1248 .part_loop:
1249 add di,byte 16
1250 loop .part_scan
1252 push eax ; H/S
1253 push edx ; File size
1254 mov bl,ah
1255 xor bh,bh
1256 inc bx ; # of heads in BX
1257 xor ah,ah ; # of sectors in AX
1258 cwde ; EAX[31:16] <- 0
1259 mul bx
1260 shl eax,9 ; Convert to bytes
1261 ; Now eax contains the number of bytes per cylinder
1262 pop ebx ; File size
1263 xor edx,edx
1264 div ebx
1265 and edx,edx
1266 jz .no_remainder
1267 inc eax ; Fractional cylinder...
1268 ; Now (e)ax contains the number of cylinders
1269 .no_remainder: cmp eax,1024
1270 jna .ok_cyl
1271 mov ax,1024 ; Max possible #
1272 .ok_cyl: dec ax ; Convert to max cylinder no
1273 pop ebx ; S(bl) H(bh)
1274 shl ah,6
1275 or bl,ah
1276 xchg ax,bx
1277 shl eax,16
1278 mov ah,bl
1279 mov al,4 ; Hard disk boot
1280 mov byte [dsp_drive], 80h ; Drive 80h = hard disk
1282 .type_found:
1283 TRACER 'T'
1284 mov bl,[sp_media]
1285 and bl,0F0h ; Copy controller info bits
1286 or al,bl
1287 mov [dsp_media],al ; Emulation type
1288 shr eax,8
1289 mov [dsp_chs],eax ; C/H/S geometry
1290 mov ax,[sp_devspec] ; Copy device spec
1291 mov [dsp_devspec],ax
1292 mov al,[sp_controller] ; Copy controller index
1293 mov [dsp_controller],al
1295 TRACER 'V'
1296 call vgaclearmode ; Reset video
1298 mov ax,4C00h ; Enable emulation and boot
1299 mov si,dspec_packet
1300 mov dl,[DriveNumber]
1301 lss sp,[InitStack]
1302 TRACER 'X'
1304 call int13
1306 ; If this returns, we have problems
1307 .bad_image:
1308 mov si,err_disk_image
1309 call writestr
1310 jmp enter_command
1313 ; Look for the highest seen H/S geometry
1314 ; We compute cylinders separately
1316 .hs_check:
1317 mov bl,[si] ; Head #
1318 cmp bl,ah
1319 jna .done_track
1320 mov ah,bl ; New highest head #
1321 .done_track: mov bl,[si+1]
1322 and bl,3Fh ; Sector #
1323 cmp bl,al
1324 jna .done_sector
1325 mov al,bl
1326 .done_sector: ret
1330 ; -----------------------------------------------------------------------------
1331 ; Common modules
1332 ; -----------------------------------------------------------------------------
1334 %include "common.inc" ; Universal modules
1335 %include "rawcon.inc" ; Console I/O w/o using the console functions
1336 %include "localboot.inc" ; Disk-based local boot
1338 ; -----------------------------------------------------------------------------
1339 ; Begin data section
1340 ; -----------------------------------------------------------------------------
1342 section .data16
1343 err_disk_image db 'Cannot load disk image (invalid file)?', CR, LF, 0
1346 ; Config file keyword table
1348 %include "keywords.inc"
1351 ; Extensions to search for (in *forward* order).
1353 alignz 4
1354 exten_table: db '.cbt' ; COMBOOT (specific)
1355 db '.img' ; Disk image
1356 db '.bin' ; CD boot sector
1357 db '.com' ; COMBOOT (same as DOS)
1358 db '.c32' ; COM32
1359 exten_table_end:
1360 dd 0, 0 ; Need 8 null bytes here
1363 ; Floppy image table
1365 alignz 4
1366 img_table_count equ 3
1367 img_table:
1368 dd 1200*1024 ; 1200K floppy
1369 db 1 ; Emulation type
1370 db 80-1 ; Max cylinder
1371 db 15 ; Max sector
1372 db 2-1 ; Max head
1374 dd 1440*1024 ; 1440K floppy
1375 db 2 ; Emulation type
1376 db 80-1 ; Max cylinder
1377 db 18 ; Max sector
1378 db 2-1 ; Max head
1380 dd 2880*1024 ; 2880K floppy
1381 db 3 ; Emulation type
1382 db 80-1 ; Max cylinder
1383 db 36 ; Max sector
1384 db 2-1 ; Max head