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