Magellan Linux

Annotation of /trunk/mkinitrd-magellan/isolinux/isolinux.asm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1133 - (hide annotations) (download)
Thu Aug 19 09:50:43 2010 UTC (13 years, 8 months ago) by niro
File size: 44203 byte(s)
-updated to isolinux-3.86
1 niro 532 ; -*- fundamental -*- (asm-mode sucks)
2     ; ****************************************************************************
3     ;
4     ; isolinux.asm
5     ;
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.
10     ;
11 niro 1133 ; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
12     ; Copyright 2009 Intel Corporation; author: H. Peter Anvin
13 niro 532 ;
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.
19     ;
20     ; ****************************************************************************
21    
22     %define IS_ISOLINUX 1
23 niro 1133 %include "head.inc"
24 niro 532
25     ;
26     ; Some semi-configurable constants... change on your own risk.
27     ;
28     my_id equ isolinux_id
29     FILENAME_MAX_LG2 equ 8 ; log2(Max filename size Including final null)
30     FILENAME_MAX equ (1 << FILENAME_MAX_LG2)
31     NULLFILE equ 0 ; Zero byte == null file name
32     NULLOFFSET equ 0 ; Position in which to look
33     retry_count equ 6 ; How patient are we with the BIOS?
34     %assign HIGHMEM_SLOP 128*1024 ; Avoid this much memory near the top
35     MAX_OPEN_LG2 equ 6 ; log2(Max number of open files)
36     MAX_OPEN equ (1 << MAX_OPEN_LG2)
37     SECTOR_SHIFT equ 11 ; 2048 bytes/sector (El Torito requirement)
38     SECTOR_SIZE equ (1 << SECTOR_SHIFT)
39    
40 niro 1133 ROOT_DIR_WORD equ 0x002F
41 niro 532
42     ;
43     ; The following structure is used for "virtual kernels"; i.e. LILO-style
44     ; option labels. The options we permit here are `kernel' and `append
45     ; Since there is no room in the bottom 64K for all of these, we
46 niro 1133 ; stick them in high memory and copy them down before we need them.
47 niro 532 ;
48     struc vkernel
49     vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!**
50     vk_rname: resb FILENAME_MAX ; Real name
51     vk_appendlen: resw 1
52 niro 1133 vk_type: resb 1 ; Type of file
53 niro 532 alignb 4
54     vk_append: resb max_cmd_len+1 ; Command line
55     alignb 4
56     vk_end: equ $ ; Should be <= vk_size
57     endstruc
58    
59     ;
60     ; File structure. This holds the information for each currently open file.
61     ;
62     struc open_file_t
63     file_sector resd 1 ; Sector pointer (0 = structure free)
64 niro 1133 file_bytesleft resd 1 ; Number of bytes left
65 niro 532 file_left resd 1 ; Number of sectors left
66 niro 1133 resd 1 ; Unused
67 niro 532 endstruc
68    
69     %ifndef DEPEND
70     %if (open_file_t_size & (open_file_t_size-1))
71     %error "open_file_t is not a power of 2"
72     %endif
73     %endif
74    
75     struc dir_t
76     dir_lba resd 1 ; Directory start (LBA)
77     dir_len resd 1 ; Length in bytes
78     dir_clust resd 1 ; Length in clusters
79     endstruc
80    
81     ; ---------------------------------------------------------------------------
82     ; BEGIN CODE
83     ; ---------------------------------------------------------------------------
84    
85     ;
86     ; Memory below this point is reserved for the BIOS and the MBR
87     ;
88     section .earlybss
89     trackbufsize equ 8192
90     trackbuf resb trackbufsize ; Track buffer goes here
91 niro 1133 ; ends at 2800h
92 niro 532
93 niro 1133 ; Some of these are touched before the whole image
94     ; is loaded. DO NOT move this to .uibss.
95     section .bss2
96 niro 532 alignb 4
97     ISOFileName resb 64 ; ISO filename canonicalization buffer
98     ISOFileNameEnd equ $
99 niro 1133 CurrentDir resb dir_t_size ; Current directory
100 niro 532 RootDir resb dir_t_size ; Root directory
101     FirstSecSum resd 1 ; Checksum of bytes 64-2048
102     ImageDwords resd 1 ; isolinux.bin size, dwords
103     InitStack resd 1 ; Initial stack pointer (SS:SP)
104     DiskSys resw 1 ; Last INT 13h call
105     ImageSectors resw 1 ; isolinux.bin size, sectors
106 niro 1133 ; These following two are accessed as a single dword...
107     GetlinsecPtr resw 1 ; The sector-read pointer
108     BIOSName resw 1 ; Display string for BIOS type
109     %define HAVE_BIOSNAME 1
110     BIOSType resw 1
111 niro 532 DiskError resb 1 ; Error code for disk I/O
112 niro 1133 DriveNumber resb 1 ; CD-ROM BIOS drive number
113 niro 532 ISOFlags resb 1 ; Flags for ISO directory search
114     RetryCount resb 1 ; Used for disk access retries
115    
116 niro 1133 alignb 8
117     bsHidden resq 1 ; Used in hybrid mode
118     bsSecPerTrack resw 1 ; Used in hybrid mode
119     bsHeads resw 1 ; Used in hybrid mode
120 niro 532
121 niro 1133
122 niro 532 ;
123     ; El Torito spec packet
124     ;
125    
126     alignb 8
127 niro 1133 _spec_start equ $
128 niro 532 spec_packet: resb 1 ; Size of packet
129     sp_media: resb 1 ; Media type
130     sp_drive: resb 1 ; Drive number
131     sp_controller: resb 1 ; Controller index
132     sp_lba: resd 1 ; LBA for emulated disk image
133     sp_devspec: resw 1 ; IDE/SCSI information
134     sp_buffer: resw 1 ; User-provided buffer
135     sp_loadseg: resw 1 ; Load segment
136     sp_sectors: resw 1 ; Sector count
137 niro 1133 sp_chs: resb 3 ; Simulated CHS geometry
138 niro 532 sp_dummy: resb 1 ; Scratch, safe to overwrite
139    
140     ;
141     ; EBIOS drive parameter packet
142     ;
143     alignb 8
144     drive_params: resw 1 ; Buffer size
145     dp_flags: resw 1 ; Information flags
146     dp_cyl: resd 1 ; Physical cylinders
147     dp_head: resd 1 ; Physical heads
148     dp_sec: resd 1 ; Physical sectors/track
149     dp_totalsec: resd 2 ; Total sectors
150     dp_secsize: resw 1 ; Bytes per sector
151     dp_dpte: resd 1 ; Device Parameter Table
152     dp_dpi_key: resw 1 ; 0BEDDh if rest valid
153     dp_dpi_len: resb 1 ; DPI len
154     resb 1
155     resw 1
156     dp_bus: resb 4 ; Host bus type
157     dp_interface: resb 8 ; Interface type
158     db_i_path: resd 2 ; Interface path
159     db_d_path: resd 2 ; Device path
160     resb 1
161     db_dpi_csum: resb 1 ; Checksum for DPI info
162    
163     ;
164     ; EBIOS disk address packet
165     ;
166     alignb 8
167     dapa: resw 1 ; Packet size
168     .count: resw 1 ; Block count
169     .off: resw 1 ; Offset of buffer
170     .seg: resw 1 ; Segment of buffer
171     .lba: resd 2 ; LBA (LSW, MSW)
172    
173     ;
174     ; Spec packet for disk image emulation
175     ;
176     alignb 8
177     dspec_packet: resb 1 ; Size of packet
178     dsp_media: resb 1 ; Media type
179     dsp_drive: resb 1 ; Drive number
180     dsp_controller: resb 1 ; Controller index
181     dsp_lba: resd 1 ; LBA for emulated disk image
182     dsp_devspec: resw 1 ; IDE/SCSI information
183     dsp_buffer: resw 1 ; User-provided buffer
184     dsp_loadseg: resw 1 ; Load segment
185     dsp_sectors: resw 1 ; Sector count
186     dsp_chs: resb 3 ; Simulated CHS geometry
187     dsp_dummy: resb 1 ; Scratch, safe to overwrite
188    
189     alignb 4
190     _spec_end equ $
191     _spec_len equ _spec_end - _spec_start
192    
193     alignb open_file_t_size
194     Files resb MAX_OPEN*open_file_t_size
195    
196     section .text
197     ;;
198     ;; Primary entry point. Because BIOSes are buggy, we only load the first
199     ;; CD-ROM sector (2K) of the file, so the number one priority is actually
200     ;; loading the rest.
201     ;;
202 niro 1133 StackBuf equ STACK_TOP-44 ; 44 bytes needed for
203     ; the bootsector chainloading
204     ; code!
205     OrigESDI equ StackBuf-4 ; The high dword on the stack
206 niro 532
207     bootsec equ $
208    
209     _start: ; Far jump makes sure we canonicalize the address
210     cli
211     jmp 0:_start1
212     times 8-($-$$) nop ; Pad to file offset 8
213    
214     ; This table hopefully gets filled in by mkisofs using the
215     ; -boot-info-table option. If not, the values in this
216     ; table are default values that we can use to get us what
217     ; we need, at least under a certain set of assumptions.
218     bi_pvd: dd 16 ; LBA of primary volume descriptor
219     bi_file: dd 0 ; LBA of boot file
220     bi_length: dd 0xdeadbeef ; Length of boot file
221     bi_csum: dd 0xdeadbeef ; Checksum of boot file
222     bi_reserved: times 10 dd 0xdeadbeef ; Reserved
223 niro 1133 bi_end:
224 niro 532
225 niro 1133 ; Custom entry point for the hybrid-mode disk.
226     ; The following values will have been pushed onto the
227     ; entry stack:
228     ; - partition offset (qword)
229     ; - ES
230     ; - DI
231     ; - DX (including drive number)
232     ; - CBIOS Heads
233     ; - CBIOS Sectors
234     ; - EBIOS flag
235     ; (top of stack)
236     ;
237     ; If we had an old isohybrid, the partition offset will
238     ; be missing; we can check for that with sp >= 0x7c00.
239     ; Serious hack alert.
240     %ifndef DEBUG_MESSAGES
241     _hybrid_signature:
242     dd 0x7078c0fb ; An arbitrary number...
243    
244     _start_hybrid:
245     pop cx ; EBIOS flag
246     pop word [cs:bsSecPerTrack]
247     pop word [cs:bsHeads]
248     pop dx
249     pop di
250     pop es
251     xor eax,eax
252     xor ebx,ebx
253     cmp sp,7C00h
254     jae .nooffset
255     pop eax
256     pop ebx
257     .nooffset:
258     mov [cs:bsHidden],eax
259     mov [cs:bsHidden+4],ebx
260    
261     mov si,bios_cbios
262     jcxz _start_common
263     mov si,bios_ebios
264     jmp _start_common
265     %endif
266    
267     _start1:
268     mov si,bios_cdrom
269     _start_common:
270     mov [cs:InitStack],sp ; Save initial stack pointer
271 niro 532 mov [cs:InitStack+2],ss
272     xor ax,ax
273     mov ss,ax
274 niro 1133 mov sp,StackBuf ; Set up stack
275     push es ; Save initial ES:DI -> $PnP pointer
276     push di
277 niro 532 mov ds,ax
278     mov es,ax
279     mov fs,ax
280     mov gs,ax
281     sti
282 niro 1133 cld
283 niro 532
284 niro 1133 mov [BIOSType],si
285     mov eax,[si]
286     mov [GetlinsecPtr],eax
287    
288 niro 532 ; Show signs of life
289     mov si,syslinux_banner
290 niro 1133 call writestr_early
291 niro 532 %ifdef DEBUG_MESSAGES
292     mov si,copyright_str
293 niro 1133 %else
294     mov si,[BIOSName]
295 niro 532 %endif
296 niro 1133 call writestr_early
297 niro 532
298     ;
299     ; Before modifying any memory, get the checksum of bytes
300     ; 64-2048
301     ;
302     initial_csum: xor edi,edi
303 niro 1133 mov si,bi_end
304 niro 532 mov cx,(SECTOR_SIZE-64) >> 2
305     .loop: lodsd
306     add edi,eax
307     loop .loop
308     mov [FirstSecSum],edi
309    
310 niro 1133 mov [DriveNumber],dl
311 niro 532 %ifdef DEBUG_MESSAGES
312     mov si,startup_msg
313     call writemsg
314     mov al,dl
315     call writehex2
316     call crlf
317     %endif
318     ;
319     ; Initialize spec packet buffers
320     ;
321     mov di,_spec_start
322     mov cx,_spec_len >> 2
323     xor eax,eax
324     rep stosd
325    
326     ; Initialize length field of the various packets
327     mov byte [spec_packet],13h
328     mov byte [drive_params],30
329     mov byte [dapa],16
330     mov byte [dspec_packet],13h
331    
332     ; Other nonzero fields
333     inc word [dsp_sectors]
334    
335 niro 1133 ; Are we just pretending to be a CD-ROM?
336     cmp word [BIOSType],bios_cdrom
337     jne found_drive ; If so, no spec packet...
338    
339 niro 532 ; Now figure out what we're actually doing
340     ; Note: use passed-in DL value rather than 7Fh because
341     ; at least some BIOSes will get the wrong value otherwise
342     mov ax,4B01h ; Get disk emulation status
343 niro 1133 mov dl,[DriveNumber]
344 niro 532 mov si,spec_packet
345 niro 1133 call int13
346 niro 532 jc award_hack ; changed for BrokenAwardHack
347 niro 1133 mov dl,[DriveNumber]
348 niro 532 cmp [sp_drive],dl ; Should contain the drive number
349     jne spec_query_failed
350    
351     %ifdef DEBUG_MESSAGES
352     mov si,spec_ok_msg
353     call writemsg
354     mov al,byte [sp_drive]
355     call writehex2
356     call crlf
357     %endif
358    
359     found_drive:
360     ; Alright, we have found the drive. Now, try to find the
361     ; boot file itself. If we have a boot info table, life is
362     ; good; if not, we have to make some assumptions, and try
363     ; to figure things out ourselves. In particular, the
364     ; assumptions we have to make are:
365     ; - single session only
366     ; - only one boot entry (no menu or other alternatives)
367    
368     cmp dword [bi_file],0 ; Address of code to load
369     jne found_file ; Boot info table present :)
370    
371     %ifdef DEBUG_MESSAGES
372     mov si,noinfotable_msg
373     call writemsg
374     %endif
375 niro 1133
376     ; No such luck. See if the spec packet contained one.
377 niro 532 mov eax,[sp_lba]
378     and eax,eax
379     jz set_file ; Good enough
380    
381     %ifdef DEBUG_MESSAGES
382     mov si,noinfoinspec_msg
383     call writemsg
384     %endif
385 niro 1133
386 niro 532 ; No such luck. Get the Boot Record Volume, assuming single
387 niro 1133 ; session disk, and that we're the first entry in the chain.
388 niro 532 mov eax,17 ; Assumed address of BRV
389     mov bx,trackbuf
390     call getonesec
391    
392     mov eax,[trackbuf+47h] ; Get boot catalog address
393     mov bx,trackbuf
394     call getonesec ; Get boot catalog
395    
396     mov eax,[trackbuf+28h] ; First boot entry
397     ; And hope and pray this is us...
398    
399 niro 1133 ; Some BIOSes apparently have limitations on the size
400 niro 532 ; that may be loaded (despite the El Torito spec being very
401     ; clear on the fact that it must all be loaded.) Therefore,
402     ; we load it ourselves, and *bleep* the BIOS.
403    
404     set_file:
405     mov [bi_file],eax
406    
407     found_file:
408     ; Set up boot file sizes
409     mov eax,[bi_length]
410 niro 1133 sub eax,SECTOR_SIZE-3 ; ... minus sector loaded
411 niro 532 shr eax,2 ; bytes->dwords
412     mov [ImageDwords],eax ; boot file dwords
413     add eax,(2047 >> 2)
414     shr eax,9 ; dwords->sectors
415     mov [ImageSectors],ax ; boot file sectors
416    
417     mov eax,[bi_file] ; Address of code to load
418     inc eax ; Don't reload bootstrap code
419     %ifdef DEBUG_MESSAGES
420     mov si,offset_msg
421     call writemsg
422     call writehex8
423     call crlf
424     %endif
425    
426     ; Just in case some BIOSes have problems with
427     ; segment wraparound, use the normalized address
428     mov bx,((7C00h+2048) >> 4)
429     mov es,bx
430     xor bx,bx
431     mov bp,[ImageSectors]
432     %ifdef DEBUG_MESSAGES
433     push ax
434     mov si,size_msg
435     call writemsg
436     mov ax,bp
437     call writehex4
438     call crlf
439     pop ax
440     %endif
441     call getlinsec
442    
443     push ds
444     pop es
445    
446     %ifdef DEBUG_MESSAGES
447     mov si,loaded_msg
448     call writemsg
449     %endif
450    
451     ; Verify the checksum on the loaded image.
452     verify_image:
453     mov si,7C00h+2048
454     mov bx,es
455     mov ecx,[ImageDwords]
456     mov edi,[FirstSecSum] ; First sector checksum
457     .loop es lodsd
458     add edi,eax
459     dec ecx
460     jz .done
461     and si,si
462     jnz .loop
463     ; SI wrapped around, advance ES
464     add bx,1000h
465     mov es,bx
466     jmp short .loop
467     .done: mov ax,ds
468     mov es,ax
469     cmp [bi_csum],edi
470     je integrity_ok
471    
472     mov si,checkerr_msg
473     call writemsg
474     jmp kaboom
475    
476     integrity_ok:
477     %ifdef DEBUG_MESSAGES
478     mov si,allread_msg
479     call writemsg
480     %endif
481     jmp all_read ; Jump to main code
482    
483     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
484     ;; Start of BrokenAwardHack --- 10-nov-2002 Knut_Petersen@t-online.de
485     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
486     ;;
487 niro 1133 ;; There is a problem with certain versions of the AWARD BIOS ...
488 niro 532 ;; the boot sector will be loaded and executed correctly, but, because the
489     ;; int 13 vector points to the wrong code in the BIOS, every attempt to
490     ;; load the spec packet will fail. We scan for the equivalent of
491     ;;
492     ;; mov ax,0201h
493     ;; mov bx,7c00h
494     ;; mov cx,0006h
495     ;; mov dx,0180h
496     ;; pushf
497     ;; call <direct far>
498     ;;
499     ;; and use <direct far> as the new vector for int 13. The code above is
500     ;; used to load the boot code into ram, and there should be no reason
501     ;; for anybody to change it now or in the future. There are no opcodes
502     ;; that use encodings relativ to IP, so scanning is easy. If we find the
503     ;; code above in the BIOS code we can be pretty sure to run on a machine
504 niro 1133 ;; with an broken AWARD BIOS ...
505 niro 532 ;;
506     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
507     ;;
508     %ifdef DEBUG_MESSAGES ;;
509     ;;
510     award_notice db "Trying BrokenAwardHack first ...",CR,LF,0 ;;
511     award_not_orig db "BAH: Original Int 13 vector : ",0 ;;
512     award_not_new db "BAH: Int 13 vector changed to : ",0 ;;
513     award_not_succ db "BAH: SUCCESS",CR,LF,0 ;;
514     award_not_fail db "BAH: FAILURE" ;;
515     award_not_crlf db CR,LF,0 ;;
516     ;;
517     %endif ;;
518     ;;
519     award_oldint13 dd 0 ;;
520     award_string db 0b8h,1,2,0bbh,0,7ch,0b9h,6,0,0bah,80h,1,09ch,09ah ;;
521     ;;
522     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
523 niro 1133 award_hack: mov si,spec_err_msg ; Moved to this place from
524     call writemsg ; spec_query_faild
525 niro 532 ;
526     %ifdef DEBUG_MESSAGES ;
527     ;
528     mov si,award_notice ; display our plan
529     call writemsg ;
530     mov si,award_not_orig ; display original int 13
531     call writemsg ; vector
532     %endif ;
533     mov eax,[13h*4] ;
534     mov [award_oldint13],eax ;
535     ;
536     %ifdef DEBUG_MESSAGES ;
537     ;
538     call writehex8 ;
539 niro 1133 mov si,award_not_crlf ;
540     call writestr_early ;
541 niro 532 %endif ;
542     push es ; save ES
543 niro 1133 mov ax,0f000h ; ES = BIOS Seg
544     mov es,ax ;
545     cld ;
546     xor di,di ; start at ES:DI = f000:0
547     award_loop: push di ; save DI
548     mov si,award_string ; scan for award_string
549 niro 532 mov cx,7 ; length of award_string = 7dw
550 niro 1133 repz cmpsw ; compare
551     pop di ; restore DI
552     jcxz award_found ; jmp if found
553     inc di ; not found, inc di
554     jno award_loop ;
555 niro 532 ;
556     award_failed: pop es ; No, not this way :-((
557     award_fail2: ;
558     ;
559     %ifdef DEBUG_MESSAGES ;
560     ;
561     mov si,award_not_fail ; display failure ...
562     call writemsg ;
563     %endif ;
564     mov eax,[award_oldint13] ; restore the original int
565     or eax,eax ; 13 vector if there is one
566     jz spec_query_failed ; and try other workarounds
567     mov [13h*4],eax ;
568     jmp spec_query_failed ;
569     ;
570     award_found: mov eax,[es:di+0eh] ; load possible int 13 addr
571     pop es ; restore ES
572     ;
573     cmp eax,[award_oldint13] ; give up if this is the
574     jz award_failed ; active int 13 vector,
575     mov [13h*4],eax ; otherwise change 0:13h*4
576     ;
577     ;
578     %ifdef DEBUG_MESSAGES ;
579     ;
580 niro 1133 push eax ; display message and
581 niro 532 mov si,award_not_new ; new vector address
582     call writemsg ;
583     pop eax ;
584     call writehex8 ;
585     mov si,award_not_crlf ;
586 niro 1133 call writestr_early ;
587 niro 532 %endif ;
588 niro 1133 mov ax,4B01h ; try to read the spec packet
589     mov dl,[DriveNumber] ; now ... it should not fail
590     mov si,spec_packet ; any longer
591     int 13h ;
592 niro 532 jc award_fail2 ;
593     ;
594     %ifdef DEBUG_MESSAGES ;
595     ;
596     mov si,award_not_succ ; display our SUCCESS
597     call writemsg ;
598     %endif ;
599     jmp found_drive ; and leave error recovery code
600     ;
601     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
602     ;; End of BrokenAwardHack ---- 10-nov-2002 Knut_Petersen@t-online.de
603     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
604    
605    
606     ; INT 13h, AX=4B01h, DL=<passed in value> failed.
607     ; Try to scan the entire 80h-FFh from the end.
608    
609     spec_query_failed:
610    
611     ; some code moved to BrokenAwardHack
612    
613     mov dl,0FFh
614     .test_loop: pusha
615     mov ax,4B01h
616     mov si,spec_packet
617 niro 1133 mov byte [si],13h ; Size of buffer
618     call int13
619 niro 532 popa
620     jc .still_broken
621    
622     mov si,maybe_msg
623     call writemsg
624     mov al,dl
625     call writehex2
626     call crlf
627    
628     cmp byte [sp_drive],dl
629     jne .maybe_broken
630    
631     ; Okay, good enough...
632     mov si,alright_msg
633     call writemsg
634 niro 1133 .found_drive0: mov [DriveNumber],dl
635 niro 532 .found_drive: jmp found_drive
636    
637     ; Award BIOS 4.51 apparently passes garbage in sp_drive,
638     ; but if this was the drive number originally passed in
639     ; DL then consider it "good enough"
640     .maybe_broken:
641 niro 1133 mov al,[DriveNumber]
642     cmp al,dl
643 niro 532 je .found_drive
644    
645 niro 1133 ; Intel Classic R+ computer with Adaptec 1542CP BIOS 1.02
646     ; passes garbage in sp_drive, and the drive number originally
647     ; passed in DL does not have 80h bit set.
648     or al,80h
649     cmp al,dl
650     je .found_drive0
651    
652 niro 532 .still_broken: dec dx
653     cmp dl, 80h
654     jnb .test_loop
655    
656     ; No spec packet anywhere. Some particularly pathetic
657     ; BIOSes apparently don't even implement function
658     ; 4B01h, so we can't query a spec packet no matter
659     ; what. If we got a drive number in DL, then try to
660     ; use it, and if it works, then well...
661 niro 1133 mov dl,[DriveNumber]
662 niro 532 cmp dl,81h ; Should be 81-FF at least
663     jb fatal_error ; If not, it's hopeless
664    
665     ; Write a warning to indicate we're on *very* thin ice now
666     mov si,nospec_msg
667     call writemsg
668     mov al,dl
669     call writehex2
670     call crlf
671     mov si,trysbm_msg
672     call writemsg
673     jmp .found_drive ; Pray that this works...
674    
675     fatal_error:
676     mov si,nothing_msg
677     call writemsg
678    
679     .norge: jmp short .norge
680    
681     ; Information message (DS:SI) output
682     ; Prefix with "isolinux: "
683     ;
684     writemsg: push ax
685     push si
686     mov si,isolinux_str
687 niro 1133 call writestr_early
688 niro 532 pop si
689 niro 1133 call writestr_early
690     pop ax
691 niro 532 ret
692    
693     ;
694     ; Write a character to the screen. There is a more "sophisticated"
695     ; version of this in the subsequent code, so we patch the pointer
696     ; when appropriate.
697     ;
698    
699     writechr:
700     jmp near writechr_simple ; 3-byte jump
701    
702     writechr_simple:
703     pushfd
704     pushad
705     mov ah,0Eh
706     xor bx,bx
707     int 10h
708     popad
709     popfd
710     ret
711    
712     ;
713 niro 1133 ; int13: save all the segment registers and call INT 13h.
714     ; Some CD-ROM BIOSes have been found to corrupt segment registers
715     ; and/or disable interrupts.
716     ;
717     int13:
718     pushf
719     push bp
720     push ds
721     push es
722     push fs
723     push gs
724     int 13h
725     mov bp,sp
726     setc [bp+10] ; Propagate CF to the caller
727     pop gs
728     pop fs
729     pop es
730     pop ds
731     pop bp
732     popf
733     ret
734    
735     ;
736 niro 532 ; Get one sector. Convenience entry point.
737     ;
738     getonesec:
739     mov bp,1
740     ; Fall through to getlinsec
741    
742     ;
743     ; Get linear sectors - EBIOS LBA addressing, 2048-byte sectors.
744     ;
745     ; Input:
746     ; EAX - Linear sector number
747     ; ES:BX - Target buffer
748     ; BP - Sector count
749     ;
750 niro 1133 getlinsec: jmp word [cs:GetlinsecPtr]
751    
752     %ifndef DEBUG_MESSAGES
753    
754     ;
755     ; First, the variants that we use when actually loading off a disk
756     ; (hybrid mode.) These are adapted versions of the equivalent routines
757     ; in ldlinux.asm.
758     ;
759    
760     ;
761     ; getlinsec_ebios:
762     ;
763     ; getlinsec implementation for floppy/HDD EBIOS (EDD)
764     ;
765     getlinsec_ebios:
766     xor edx,edx
767     shld edx,eax,2
768     shl eax,2 ; Convert to HDD sectors
769     add eax,[bsHidden]
770     adc edx,[bsHidden+4]
771     shl bp,2
772    
773     .loop:
774     push bp ; Sectors left
775     .retry2:
776     call maxtrans ; Enforce maximum transfer size
777     movzx edi,bp ; Sectors we are about to read
778     mov cx,retry_count
779     .retry:
780    
781     ; Form DAPA on stack
782     push edx
783     push eax
784     push es
785     push bx
786     push di
787     push word 16
788     mov si,sp
789     pushad
790     mov dl,[DriveNumber]
791     push ds
792     push ss
793     pop ds ; DS <- SS
794     mov ah,42h ; Extended Read
795     call int13
796     pop ds
797     popad
798     lea sp,[si+16] ; Remove DAPA
799     jc .error
800     pop bp
801     add eax,edi ; Advance sector pointer
802     adc edx,0
803     sub bp,di ; Sectors left
804     shl di,9 ; 512-byte sectors
805     add bx,di ; Advance buffer pointer
806     and bp,bp
807     jnz .loop
808    
809     ret
810    
811     .error:
812     ; Some systems seem to get "stuck" in an error state when
813     ; using EBIOS. Doesn't happen when using CBIOS, which is
814     ; good, since some other systems get timeout failures
815     ; waiting for the floppy disk to spin up.
816    
817     pushad ; Try resetting the device
818     xor ax,ax
819     mov dl,[DriveNumber]
820     call int13
821     popad
822     loop .retry ; CX-- and jump if not zero
823    
824     ;shr word [MaxTransfer],1 ; Reduce the transfer size
825     ;jnz .retry2
826    
827     ; Total failure. Try falling back to CBIOS.
828     mov word [GetlinsecPtr], getlinsec_cbios
829     ;mov byte [MaxTransfer],63 ; Max possibe CBIOS transfer
830    
831     pop bp
832     jmp getlinsec_cbios.loop
833    
834     ;
835     ; getlinsec_cbios:
836     ;
837     ; getlinsec implementation for legacy CBIOS
838     ;
839     getlinsec_cbios:
840     xor edx,edx
841     shl eax,2 ; Convert to HDD sectors
842     add eax,[bsHidden]
843     shl bp,2
844    
845     .loop:
846     push edx
847     push eax
848     push bp
849     push bx
850    
851     movzx esi,word [bsSecPerTrack]
852     movzx edi,word [bsHeads]
853     ;
854     ; Dividing by sectors to get (track,sector): we may have
855     ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
856     ;
857     div esi
858     xor cx,cx
859     xchg cx,dx ; CX <- sector index (0-based)
860     ; EDX <- 0
861     ; eax = track #
862     div edi ; Convert track to head/cyl
863    
864     ; We should test this, but it doesn't fit...
865     ; cmp eax,1023
866     ; ja .error
867    
868     ;
869     ; Now we have AX = cyl, DX = head, CX = sector (0-based),
870     ; BP = sectors to transfer, SI = bsSecPerTrack,
871     ; ES:BX = data target
872     ;
873    
874     call maxtrans ; Enforce maximum transfer size
875    
876     ; Must not cross track boundaries, so BP <= SI-CX
877     sub si,cx
878     cmp bp,si
879     jna .bp_ok
880     mov bp,si
881     .bp_ok:
882    
883     shl ah,6 ; Because IBM was STOOPID
884     ; and thought 8 bits were enough
885     ; then thought 10 bits were enough...
886     inc cx ; Sector numbers are 1-based, sigh
887     or cl,ah
888     mov ch,al
889     mov dh,dl
890     mov dl,[DriveNumber]
891     xchg ax,bp ; Sector to transfer count
892     mov ah,02h ; Read sectors
893     mov bp,retry_count
894     .retry:
895     pushad
896     call int13
897     popad
898     jc .error
899     .resume:
900     movzx ecx,al ; ECX <- sectors transferred
901     shl ax,9 ; Convert sectors in AL to bytes in AX
902     pop bx
903     add bx,ax
904     pop bp
905     pop eax
906     pop edx
907     add eax,ecx
908     sub bp,cx
909     jnz .loop
910     ret
911    
912     .error:
913     dec bp
914     jnz .retry
915    
916     xchg ax,bp ; Sectors transferred <- 0
917     shr word [MaxTransfer],1
918     jnz .resume
919     jmp disk_error
920    
921     ;
922     ; Truncate BP to MaxTransfer
923     ;
924     maxtrans:
925     cmp bp,[MaxTransfer]
926     jna .ok
927     mov bp,[MaxTransfer]
928     .ok: ret
929    
930     %endif
931    
932     ;
933     ; This is the variant we use for real CD-ROMs:
934     ; LBA, 2K sectors, some special error handling.
935     ;
936     getlinsec_cdrom:
937 niro 532 mov si,dapa ; Load up the DAPA
938     mov [si+4],bx
939 niro 1133 mov [si+6],es
940 niro 532 mov [si+8],eax
941     .loop:
942     push bp ; Sectors left
943 niro 1133 cmp bp,[MaxTransferCD]
944 niro 532 jbe .bp_ok
945 niro 1133 mov bp,[MaxTransferCD]
946 niro 532 .bp_ok:
947     mov [si+2],bp
948     push si
949 niro 1133 mov dl,[DriveNumber]
950 niro 532 mov ah,42h ; Extended Read
951     call xint13
952     pop si
953     pop bp
954     movzx eax,word [si+2] ; Sectors we read
955     add [si+8],eax ; Advance sector pointer
956     sub bp,ax ; Sectors left
957     shl ax,SECTOR_SHIFT-4 ; 2048-byte sectors -> segment
958     add [si+6],ax ; Advance buffer pointer
959     and bp,bp
960     jnz .loop
961     mov eax,[si+8] ; Next sector
962     ret
963    
964     ; INT 13h with retry
965     xint13: mov byte [RetryCount],retry_count
966     .try: pushad
967 niro 1133 call int13
968 niro 532 jc .error
969     add sp,byte 8*4 ; Clean up stack
970     ret
971     .error:
972     mov [DiskError],ah ; Save error code
973     popad
974     mov [DiskSys],ax ; Save system call number
975     dec byte [RetryCount]
976     jz .real_error
977     push ax
978     mov al,[RetryCount]
979     mov ah,[dapa+2] ; Sector transfer count
980     cmp al,2 ; Only 2 attempts left
981     ja .nodanger
982     mov ah,1 ; Drop transfer size to 1
983     jmp short .setsize
984     .nodanger:
985     cmp al,retry_count-2
986     ja .again ; First time, just try again
987     shr ah,1 ; Otherwise, try to reduce
988     adc ah,0 ; the max transfer size, but not to 0
989     .setsize:
990 niro 1133 mov [MaxTransferCD],ah
991 niro 532 mov [dapa+2],ah
992     .again:
993     pop ax
994     jmp .try
995    
996     .real_error: mov si,diskerr_msg
997     call writemsg
998     mov al,[DiskError]
999     call writehex2
1000     mov si,oncall_str
1001 niro 1133 call writestr_early
1002 niro 532 mov ax,[DiskSys]
1003     call writehex4
1004     mov si,ondrive_str
1005 niro 1133 call writestr_early
1006 niro 532 mov al,dl
1007     call writehex2
1008     call crlf
1009     ; Fall through to kaboom
1010    
1011     ;
1012     ; kaboom: write a message and bail out. Wait for a user keypress,
1013     ; then do a hard reboot.
1014     ;
1015 niro 1133 disk_error:
1016 niro 532 kaboom:
1017 niro 1133 RESET_STACK_AND_SEGS AX
1018 niro 532 mov si,err_bootfailed
1019 niro 1133 call writestr
1020 niro 532 call getchar
1021     cli
1022     mov word [BIOS_magic],0 ; Cold reboot
1023     jmp 0F000h:0FFF0h ; Reset vector address
1024    
1025     ; -----------------------------------------------------------------------------
1026     ; Common modules needed in the first sector
1027     ; -----------------------------------------------------------------------------
1028    
1029     %include "writestr.inc" ; String output
1030 niro 1133 writestr_early equ writestr
1031 niro 532 %include "writehex.inc" ; Hexadecimal output
1032    
1033     ; -----------------------------------------------------------------------------
1034     ; Data that needs to be in the first sector
1035     ; -----------------------------------------------------------------------------
1036    
1037 niro 1133 syslinux_banner db CR, LF, MY_NAME, ' ', VERSION_STR, ' ', DATE_STR, ' ', 0
1038     copyright_str db ' Copyright (C) 1994-'
1039     asciidec YEAR
1040     db ' H. Peter Anvin et al', CR, LF, 0
1041 niro 532 isolinux_str db 'isolinux: ', 0
1042     %ifdef DEBUG_MESSAGES
1043     startup_msg: db 'Starting up, DL = ', 0
1044     spec_ok_msg: db 'Loaded spec packet OK, drive = ', 0
1045 niro 1133 secsize_msg: db 'Sector size ', 0
1046     offset_msg: db 'Main image LBA = ', 0
1047 niro 532 size_msg: db 'Sectors to load = ', 0
1048     loaded_msg: db 'Loaded boot image, verifying...', CR, LF, 0
1049     verify_msg: db 'Image checksum verified.', CR, LF, 0
1050     allread_msg db 'Main image read, jumping to main code...', CR, LF, 0
1051     %endif
1052     noinfotable_msg db 'No boot info table, assuming single session disk...', CR, LF, 0
1053     noinfoinspec_msg db 'Spec packet missing LBA information, trying to wing it...', CR, LF, 0
1054     spec_err_msg: db 'Loading spec packet failed, trying to wing it...', CR, LF, 0
1055     maybe_msg: db 'Found something at drive = ', 0
1056 niro 1133 alright_msg: db 'Looks reasonable, continuing...', CR, LF, 0
1057     nospec_msg db 'Extremely broken BIOS detected, last attempt with drive = ', 0
1058 niro 532 nothing_msg: db 'Failed to locate CD-ROM device; boot failed.', CR, LF
1059     trysbm_msg db 'See http://syslinux.zytor.com/sbm for more information.', CR, LF, 0
1060     diskerr_msg: db 'Disk error ', 0
1061     oncall_str: db ', AX = ',0
1062     ondrive_str: db ', drive ', 0
1063     checkerr_msg: db 'Image checksum error, sorry...', CR, LF, 0
1064    
1065     err_bootfailed db CR, LF, 'Boot failed: press a key to retry...'
1066     bailmsg equ err_bootfailed
1067     crlf_msg db CR, LF
1068     null_msg db 0
1069    
1070 niro 1133 bios_cdrom_str db 'ETCD', 0
1071     %ifndef DEBUG_MESSAGES
1072     bios_cbios_str db 'CHDD', 0
1073     bios_ebios_str db 'EHDD' ,0
1074     %endif
1075 niro 532
1076 niro 1133 alignz 4
1077     bios_cdrom: dw getlinsec_cdrom, bios_cdrom_str
1078     %ifndef DEBUG_MESSAGES
1079     bios_cbios: dw getlinsec_cbios, bios_cbios_str
1080     bios_ebios: dw getlinsec_ebios, bios_ebios_str
1081     %endif
1082    
1083     ; Maximum transfer size
1084     MaxTransfer dw 127 ; Hard disk modes
1085     MaxTransferCD dw 32 ; CD mode
1086    
1087 niro 532 rl_checkpt equ $ ; Must be <= 800h
1088    
1089 niro 1133 ; This pads to the end of sector 0 and errors out on
1090     ; overflow.
1091     times 2048-($-$$) db 0
1092 niro 532
1093     ; ----------------------------------------------------------------------------
1094     ; End of code and data that have to be in the first sector
1095     ; ----------------------------------------------------------------------------
1096    
1097     all_read:
1098 niro 1133
1099     ; Test tracers
1100     TRACER 'T'
1101     TRACER '>'
1102    
1103 niro 532 ;
1104 niro 1133 ; Common initialization code
1105 niro 532 ;
1106 niro 1133 %include "init.inc"
1107     %include "cpuinit.inc"
1108 niro 532
1109     ; Patch the writechr routine to point to the full code
1110     mov word [writechr+1], writechr_full-(writechr+3)
1111    
1112     ; Tell the user we got this far...
1113     %ifndef DEBUG_MESSAGES ; Gets messy with debugging on
1114     mov si,copyright_str
1115 niro 1133 call writestr_early
1116 niro 532 %endif
1117    
1118     ;
1119     ; Now we're all set to start with our *real* business. First load the
1120     ; configuration file (if any) and parse it.
1121     ;
1122     ; In previous versions I avoided using 32-bit registers because of a
1123     ; rumour some BIOSes clobbered the upper half of 32-bit registers at
1124     ; random. I figure, though, that if there are any of those still left
1125     ; they probably won't be trying to install Linux on them...
1126     ;
1127     ; The code is still ripe with 16-bitisms, though. Not worth the hassle
1128     ; to take'm out. In fact, we may want to put them back if we're going
1129     ; to boot ELKS at some point.
1130     ;
1131    
1132     ;
1133     ; Now, we need to sniff out the actual filesystem data structures.
1134     ; mkisofs gave us a pointer to the primary volume descriptor
1135     ; (which will be at 16 only for a single-session disk!); from the PVD
1136     ; we should be able to find the rest of what we need to know.
1137 niro 1133 ;
1138 niro 532 get_fs_structures:
1139     mov eax,[bi_pvd]
1140     mov bx,trackbuf
1141     call getonesec
1142    
1143     mov eax,[trackbuf+156+2]
1144     mov [RootDir+dir_lba],eax
1145 niro 1133 mov [CurrentDir+dir_lba],eax
1146 niro 532 %ifdef DEBUG_MESSAGES
1147     mov si,dbg_rootdir_msg
1148     call writemsg
1149     call writehex8
1150     call crlf
1151     %endif
1152     mov eax,[trackbuf+156+10]
1153 niro 1133 mov [RootDir+dir_len],eax
1154     mov [CurrentDir+dir_len],eax
1155 niro 532 add eax,SECTOR_SIZE-1
1156     shr eax,SECTOR_SHIFT
1157     mov [RootDir+dir_clust],eax
1158 niro 1133 mov [CurrentDir+dir_clust],eax
1159 niro 532
1160     ; Look for an isolinux directory, and if found,
1161     ; make it the current directory instead of the root
1162     ; directory.
1163 niro 1133 ; Also copy the name of the directory to CurrentDirName
1164     mov word [CurrentDirName],ROOT_DIR_WORD ; Write '/',0 to the CurrentDirName
1165 niro 532 mov di,boot_dir ; Search for /boot/isolinux
1166     mov al,02h
1167 niro 1133 push di
1168 niro 532 call searchdir_iso
1169 niro 1133 pop di
1170 niro 532 jnz .found_dir
1171     mov di,isolinux_dir
1172     mov al,02h ; Search for /isolinux
1173 niro 1133 push di
1174 niro 532 call searchdir_iso
1175 niro 1133 pop di
1176 niro 532 jz .no_isolinux_dir
1177     .found_dir:
1178 niro 1133 ; Copy current directory name to CurrentDirName
1179     push si
1180     push di
1181     mov si,di
1182     mov di,CurrentDirName
1183     call strcpy
1184     mov byte [di],0 ;done in case it's not word aligned
1185     dec di
1186     mov byte [di],'/'
1187     pop di
1188     pop si
1189    
1190     mov [CurrentDir+dir_len],eax
1191 niro 532 mov eax,[si+file_left]
1192 niro 1133 mov [CurrentDir+dir_clust],eax
1193 niro 532 xor eax,eax ; Free this file pointer entry
1194     xchg eax,[si+file_sector]
1195 niro 1133 mov [CurrentDir+dir_lba],eax
1196 niro 532 %ifdef DEBUG_MESSAGES
1197     push si
1198     mov si,dbg_isodir_msg
1199     call writemsg
1200     pop si
1201     call writehex8
1202     call crlf
1203     %endif
1204     .no_isolinux_dir:
1205    
1206     ;
1207     ; Locate the configuration file
1208     ;
1209     load_config:
1210     %ifdef DEBUG_MESSAGES
1211     mov si,dbg_config_msg
1212     call writemsg
1213     %endif
1214    
1215 niro 1133 mov si,config_name
1216     mov di,ConfigName
1217     call strcpy
1218    
1219     mov di,ConfigName
1220 niro 532 call open
1221     jz no_config_file ; Not found or empty
1222    
1223     %ifdef DEBUG_MESSAGES
1224     mov si,dbg_configok_msg
1225     call writemsg
1226     %endif
1227    
1228     ;
1229     ; Now we have the config file open. Parse the config file and
1230     ; run the user interface.
1231     ;
1232     %include "ui.inc"
1233    
1234     ;
1235 niro 1133 ; Enable disk emulation. The kind of disk we emulate is dependent on the
1236     ; size of the file: 1200K, 1440K or 2880K floppy, otherwise harddisk.
1237 niro 532 ;
1238     is_disk_image:
1239     TRACER CR
1240     TRACER LF
1241     TRACER 'D'
1242     TRACER ':'
1243    
1244 niro 1133 mov edx,eax ; File size
1245 niro 532 mov di,img_table
1246     mov cx,img_table_count
1247     mov eax,[si+file_sector] ; Starting LBA of file
1248     mov [dsp_lba],eax ; Location of file
1249     mov byte [dsp_drive], 0 ; 00h floppy, 80h hard disk
1250     .search_table:
1251     TRACER 't'
1252     mov eax,[di+4]
1253     cmp edx,[di]
1254     je .type_found
1255     add di,8
1256     loop .search_table
1257    
1258     ; Hard disk image. Need to examine the partition table
1259     ; in order to deduce the C/H/S geometry. Sigh.
1260     .hard_disk_image:
1261     TRACER 'h'
1262     cmp edx,512
1263     jb .bad_image
1264    
1265     mov bx,trackbuf
1266     mov cx,1 ; Load 1 sector
1267     call getfssec
1268 niro 1133
1269 niro 532 cmp word [trackbuf+510],0aa55h ; Boot signature
1270     jne .bad_image ; Image not bootable
1271    
1272     mov cx,4 ; 4 partition entries
1273     mov di,trackbuf+446 ; Start of partition table
1274    
1275     xor ax,ax ; Highest sector(al) head(ah)
1276    
1277     .part_scan:
1278     cmp byte [di+4], 0
1279     jz .part_loop
1280     lea si,[di+1]
1281     call .hs_check
1282     add si,byte 4
1283     call .hs_check
1284     .part_loop:
1285     add di,byte 16
1286     loop .part_scan
1287 niro 1133
1288 niro 532 push eax ; H/S
1289     push edx ; File size
1290     mov bl,ah
1291     xor bh,bh
1292     inc bx ; # of heads in BX
1293     xor ah,ah ; # of sectors in AX
1294     cwde ; EAX[31:16] <- 0
1295     mul bx
1296     shl eax,9 ; Convert to bytes
1297     ; Now eax contains the number of bytes per cylinder
1298     pop ebx ; File size
1299     xor edx,edx
1300     div ebx
1301     and edx,edx
1302     jz .no_remainder
1303     inc eax ; Fractional cylinder...
1304     ; Now (e)ax contains the number of cylinders
1305     .no_remainder: cmp eax,1024
1306     jna .ok_cyl
1307     mov ax,1024 ; Max possible #
1308     .ok_cyl: dec ax ; Convert to max cylinder no
1309     pop ebx ; S(bl) H(bh)
1310     shl ah,6
1311     or bl,ah
1312     xchg ax,bx
1313     shl eax,16
1314     mov ah,bl
1315     mov al,4 ; Hard disk boot
1316     mov byte [dsp_drive], 80h ; Drive 80h = hard disk
1317    
1318     .type_found:
1319     TRACER 'T'
1320     mov bl,[sp_media]
1321     and bl,0F0h ; Copy controller info bits
1322     or al,bl
1323     mov [dsp_media],al ; Emulation type
1324     shr eax,8
1325     mov [dsp_chs],eax ; C/H/S geometry
1326     mov ax,[sp_devspec] ; Copy device spec
1327     mov [dsp_devspec],ax
1328     mov al,[sp_controller] ; Copy controller index
1329     mov [dsp_controller],al
1330    
1331     TRACER 'V'
1332     call vgaclearmode ; Reset video
1333    
1334     mov ax,4C00h ; Enable emulation and boot
1335     mov si,dspec_packet
1336 niro 1133 mov dl,[DriveNumber]
1337 niro 532 lss sp,[InitStack]
1338     TRACER 'X'
1339    
1340 niro 1133 call int13
1341 niro 532
1342     ; If this returns, we have problems
1343     .bad_image:
1344     mov si,err_disk_image
1345 niro 1133 call writestr
1346 niro 532 jmp enter_command
1347    
1348     ;
1349     ; Look for the highest seen H/S geometry
1350     ; We compute cylinders separately
1351     ;
1352     .hs_check:
1353     mov bl,[si] ; Head #
1354     cmp bl,ah
1355     jna .done_track
1356     mov ah,bl ; New highest head #
1357     .done_track: mov bl,[si+1]
1358     and bl,3Fh ; Sector #
1359     cmp bl,al
1360     jna .done_sector
1361     mov al,bl
1362     .done_sector: ret
1363    
1364     ;
1365 niro 1133 ; close_file:
1366     ; Deallocates a file structure (pointer in SI)
1367     ; Assumes CS == DS.
1368 niro 532 ;
1369 niro 1133 close_file:
1370     and si,si
1371     jz .closed
1372     mov dword [si],0 ; First dword == file_left
1373     xor si,si
1374     .closed: ret
1375 niro 532
1376     ;
1377     ; searchdir:
1378     ;
1379     ; Open a file
1380     ;
1381     ; On entry:
1382     ; DS:DI = filename
1383     ; If successful:
1384     ; ZF clear
1385     ; SI = file pointer
1386 niro 1133 ; EAX = file length in bytes
1387 niro 532 ; If unsuccessful
1388     ; ZF set
1389     ;
1390     ; Assumes CS == DS == ES, and trashes BX and CX.
1391     ;
1392     ; searchdir_iso is a special entry point for ISOLINUX only. In addition
1393     ; to the above, searchdir_iso passes a file flag mask in AL. This is useful
1394     ; for searching for directories.
1395     ;
1396     alloc_failure:
1397     xor ax,ax ; ZF <- 1
1398     ret
1399    
1400     searchdir:
1401     xor al,al
1402     searchdir_iso:
1403     mov [ISOFlags],al
1404     TRACER 'S'
1405     call allocate_file ; Temporary file structure for directory
1406     jnz alloc_failure
1407     push es
1408     push ds
1409     pop es ; ES = DS
1410 niro 1133 mov si,CurrentDir
1411 niro 532 cmp byte [di],'/' ; If filename begins with slash
1412     jne .not_rooted
1413     inc di ; Skip leading slash
1414     mov si,RootDir ; Reference root directory instead
1415     .not_rooted:
1416     mov eax,[si+dir_clust]
1417     mov [bx+file_left],eax
1418 niro 1133 shl eax,SECTOR_SHIFT
1419     mov [bx+file_bytesleft],eax
1420 niro 532 mov eax,[si+dir_lba]
1421     mov [bx+file_sector],eax
1422     mov edx,[si+dir_len]
1423    
1424     .look_for_slash:
1425     mov ax,di
1426     .scan:
1427     mov cl,[di]
1428     inc di
1429     and cl,cl
1430     jz .isfile
1431     cmp cl,'/'
1432     jne .scan
1433     mov [di-1],byte 0 ; Terminate at directory name
1434     mov cl,02h ; Search for directory
1435     xchg cl,[ISOFlags]
1436    
1437     push di ; Save these...
1438     push cx
1439    
1440     ; Create recursion stack frame...
1441     push word .resume ; Where to "return" to
1442     push es
1443     .isfile: xchg ax,di
1444    
1445     .getsome:
1446     ; Get a chunk of the directory
1447     ; This relies on the fact that ISOLINUX doesn't change SI
1448     mov si,trackbuf
1449     TRACER 'g'
1450     pushad
1451     xchg bx,si
1452     mov cx,[BufSafe]
1453     call getfssec
1454     popad
1455    
1456     .compare:
1457     movzx eax,byte [si] ; Length of directory entry
1458     cmp al,33
1459     jb .next_sector
1460     TRACER 'c'
1461     mov cl,[si+25]
1462     xor cl,[ISOFlags]
1463     test cl, byte 8Eh ; Unwanted file attributes!
1464     jnz .not_file
1465     pusha
1466     movzx cx,byte [si+32] ; File identifier length
1467     add si,byte 33 ; File identifier offset
1468     TRACER 'i'
1469     call iso_compare_names
1470     popa
1471     je .success
1472     .not_file:
1473     sub edx,eax ; Decrease bytes left
1474     jbe .failure
1475     add si,ax ; Advance pointer
1476    
1477     .check_overrun:
1478     ; Did we finish the buffer?
1479     cmp si,trackbuf+trackbufsize
1480     jb .compare ; No, keep going
1481    
1482     jmp short .getsome ; Get some more directory
1483    
1484     .next_sector:
1485     ; Advance to the beginning of next sector
1486     lea ax,[si+SECTOR_SIZE-1]
1487     and ax,~(SECTOR_SIZE-1)
1488     sub ax,si
1489     jmp short .not_file ; We still need to do length checks
1490    
1491     .failure: xor eax,eax ; ZF = 1
1492     mov [bx+file_sector],eax
1493     pop es
1494     ret
1495    
1496     .success:
1497     mov eax,[si+2] ; Location of extent
1498     mov [bx+file_sector],eax
1499     mov eax,[si+10] ; Data length
1500 niro 1133 mov [bx+file_bytesleft],eax
1501 niro 532 push eax
1502     add eax,SECTOR_SIZE-1
1503     shr eax,SECTOR_SHIFT
1504     mov [bx+file_left],eax
1505     pop eax
1506 niro 1133 jz .failure ; Empty file?
1507     ; ZF = 0
1508 niro 532 mov si,bx
1509     pop es
1510     ret
1511    
1512     .resume: ; We get here if we were only doing part of a lookup
1513     ; This relies on the fact that .success returns bx == si
1514     xchg edx,eax ; Directory length in edx
1515     pop cx ; Old ISOFlags
1516     pop di ; Next filename pointer
1517     mov byte [di-1], '/' ; Restore slash
1518     mov [ISOFlags],cl ; Restore the flags
1519     jz .failure ; Did we fail? If so fail for real!
1520     jmp .look_for_slash ; Otherwise, next level
1521    
1522     ;
1523     ; allocate_file: Allocate a file structure
1524     ;
1525     ; If successful:
1526     ; ZF set
1527     ; BX = file pointer
1528     ; In unsuccessful:
1529     ; ZF clear
1530     ;
1531     allocate_file:
1532     TRACER 'a'
1533     push cx
1534     mov bx,Files
1535     mov cx,MAX_OPEN
1536     .check: cmp dword [bx], byte 0
1537     je .found
1538     add bx,open_file_t_size ; ZF = 0
1539     loop .check
1540     ; ZF = 0 if we fell out of the loop
1541     .found: pop cx
1542     ret
1543    
1544     ;
1545 niro 1133 ; iso_compare_names:
1546 niro 532 ; Compare the names DS:SI and DS:DI and report if they are
1547     ; equal from an ISO 9660 perspective. SI is the name from
1548     ; the filesystem; CX indicates its length, and ';' terminates.
1549     ; DI is expected to end with a null.
1550     ;
1551     ; Note: clobbers AX, CX, SI, DI; assumes DS == ES == base segment
1552     ;
1553    
1554     iso_compare_names:
1555     ; First, terminate and canonicalize input filename
1556     push di
1557     mov di,ISOFileName
1558     .canon_loop: jcxz .canon_end
1559     lodsb
1560     dec cx
1561     cmp al,';'
1562     je .canon_end
1563     and al,al
1564     je .canon_end
1565     stosb
1566     cmp di,ISOFileNameEnd-1 ; Guard against buffer overrun
1567     jb .canon_loop
1568     .canon_end:
1569     cmp di,ISOFileName
1570     jbe .canon_done
1571     cmp byte [di-1],'.' ; Remove terminal dots
1572     jne .canon_done
1573     dec di
1574     jmp short .canon_end
1575     .canon_done:
1576     mov [di],byte 0 ; Null-terminate string
1577     pop di
1578     mov si,ISOFileName
1579     .compare:
1580     lodsb
1581     mov ah,[di]
1582     inc di
1583     and ax,ax
1584     jz .success ; End of string for both
1585     and al,al ; Is either one end of string?
1586     jz .failure ; If so, failure
1587     and ah,ah
1588     jz .failure
1589     or ax,2020h ; Convert to lower case
1590     cmp al,ah
1591     je .compare
1592     .failure: and ax,ax ; ZF = 0 (at least one will be nonzero)
1593     .success: ret
1594    
1595     ;
1596     ; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed
1597     ; to by ES:DI; ends on encountering any whitespace.
1598 niro 1133 ; DI is preserved.
1599 niro 532 ;
1600     ; This verifies that a filename is < FILENAME_MAX characters,
1601     ; doesn't contain whitespace, zero-pads the output buffer,
1602     ; and removes trailing dots and redundant slashes,
1603     ; so "repe cmpsb" can do a compare, and the
1604     ; path-searching routine gets a bit of an easier job.
1605 niro 1133 ;
1606 niro 532 mangle_name:
1607 niro 1133 push di
1608 niro 532 push bx
1609     xor ax,ax
1610     mov cx,FILENAME_MAX-1
1611     mov bx,di
1612    
1613     .mn_loop:
1614     lodsb
1615     cmp al,' ' ; If control or space, end
1616     jna .mn_end
1617     cmp al,ah ; Repeated slash?
1618     je .mn_skip
1619     xor ah,ah
1620     cmp al,'/'
1621     jne .mn_ok
1622     mov ah,al
1623     .mn_ok stosb
1624     .mn_skip: loop .mn_loop
1625     .mn_end:
1626     cmp bx,di ; At the beginning of the buffer?
1627     jbe .mn_zero
1628 niro 1133 cmp byte [es:di-1],'.' ; Terminal dot?
1629 niro 532 je .mn_kill
1630 niro 1133 cmp byte [es:di-1],'/' ; Terminal slash?
1631 niro 532 jne .mn_zero
1632     .mn_kill: dec di ; If so, remove it
1633     inc cx
1634     jmp short .mn_end
1635     .mn_zero:
1636     inc cx ; At least one null byte
1637     xor ax,ax ; Zero-fill name
1638     rep stosb
1639     pop bx
1640 niro 1133 pop di
1641 niro 532 ret ; Done
1642    
1643     ;
1644     ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
1645     ; filename to the conventional representation. This is needed
1646     ; for the BOOT_IMAGE= parameter for the kernel.
1647     ;
1648     ; DS:SI -> input mangled file name
1649     ; ES:DI -> output buffer
1650     ;
1651     ; On return, DI points to the first byte after the output name,
1652     ; which is set to a null byte.
1653     ;
1654     unmangle_name: call strcpy
1655     dec di ; Point to final null byte
1656     ret
1657    
1658     ;
1659     ; getfssec: Get multiple clusters from a file, given the file pointer.
1660     ;
1661     ; On entry:
1662     ; ES:BX -> Buffer
1663     ; SI -> File pointer
1664     ; CX -> Cluster count
1665     ; On exit:
1666     ; SI -> File pointer (or 0 on EOF)
1667     ; CF = 1 -> Hit EOF
1668 niro 1133 ; ECX -> Bytes actually read
1669 niro 532 ;
1670     getfssec:
1671     TRACER 'F'
1672     push ds
1673     push cs
1674     pop ds ; DS <- CS
1675    
1676     movzx ecx,cx
1677     cmp ecx,[si+file_left]
1678     jna .ok_size
1679     mov ecx,[si+file_left]
1680     .ok_size:
1681    
1682 niro 1133 pushad
1683     mov eax,[si+file_sector]
1684 niro 532 mov bp,cx
1685     TRACER 'l'
1686     call getlinsec
1687 niro 1133 popad
1688 niro 532
1689 niro 1133 ; ECX[31:16] == 0 here...
1690 niro 532 add [si+file_sector],ecx
1691     sub [si+file_left],ecx
1692 niro 1133 shl ecx,SECTOR_SHIFT ; Convert to bytes
1693     cmp ecx,[si+file_bytesleft]
1694     jb .not_all
1695     mov ecx,[si+file_bytesleft]
1696     .not_all: sub [si+file_bytesleft],ecx
1697     jnz .ret ; CF = 0 in this case...
1698     push eax
1699     xor eax,eax
1700     mov [si+file_sector],eax ; Unused
1701     mov si,ax
1702     pop eax
1703 niro 532 stc
1704 niro 1133 .ret:
1705 niro 532 pop ds
1706     TRACER 'f'
1707     ret
1708    
1709     ; -----------------------------------------------------------------------------
1710     ; Common modules
1711     ; -----------------------------------------------------------------------------
1712    
1713     %include "getc.inc" ; getc et al
1714     %include "conio.inc" ; Console I/O
1715 niro 1133 %include "configinit.inc" ; Initialize configuration
1716 niro 532 %include "parseconfig.inc" ; High-level config file handling
1717     %include "parsecmd.inc" ; Low-level config file handling
1718     %include "bcopy32.inc" ; 32-bit bcopy
1719     %include "loadhigh.inc" ; Load a file into high memory
1720     %include "font.inc" ; VGA font stuff
1721     %include "graphics.inc" ; VGA graphics
1722     %include "highmem.inc" ; High memory sizing
1723     %include "strcpy.inc" ; strcpy()
1724     %include "rawcon.inc" ; Console I/O w/o using the console functions
1725 niro 1133 %include "idle.inc" ; Idle handling
1726     %include "adv.inc" ; Auxillary Data Vector
1727     %include "localboot.inc" ; Disk-based local boot
1728 niro 532
1729     ; -----------------------------------------------------------------------------
1730     ; Begin data section
1731     ; -----------------------------------------------------------------------------
1732    
1733     section .data
1734    
1735     default_str db 'default', 0
1736     default_len equ ($-default_str)
1737     boot_dir db '/boot' ; /boot/isolinux
1738     isolinux_dir db '/isolinux', 0
1739 niro 1133 config_name db 'isolinux.cfg', 0
1740 niro 532 err_disk_image db 'Cannot load disk image (invalid file)?', CR, LF, 0
1741    
1742     %ifdef DEBUG_MESSAGES
1743     dbg_rootdir_msg db 'Root directory at LBA = ', 0
1744     dbg_isodir_msg db 'isolinux directory at LBA = ', 0
1745     dbg_config_msg db 'About to load config file...', CR, LF, 0
1746     dbg_configok_msg db 'Configuration file opened...', CR, LF, 0
1747     %endif
1748    
1749     ;
1750     ; Config file keyword table
1751     ;
1752     %include "keywords.inc"
1753    
1754     ;
1755     ; Extensions to search for (in *forward* order).
1756     ;
1757 niro 1133 alignz 4
1758 niro 532 exten_table: db '.cbt' ; COMBOOT (specific)
1759     db '.img' ; Disk image
1760     db '.bin' ; CD boot sector
1761     db '.com' ; COMBOOT (same as DOS)
1762     db '.c32' ; COM32
1763     exten_table_end:
1764     dd 0, 0 ; Need 8 null bytes here
1765    
1766     ;
1767     ; Floppy image table
1768     ;
1769 niro 1133 alignz 4
1770 niro 532 img_table_count equ 3
1771     img_table:
1772     dd 1200*1024 ; 1200K floppy
1773     db 1 ; Emulation type
1774     db 80-1 ; Max cylinder
1775     db 15 ; Max sector
1776     db 2-1 ; Max head
1777    
1778     dd 1440*1024 ; 1440K floppy
1779     db 2 ; Emulation type
1780     db 80-1 ; Max cylinder
1781     db 18 ; Max sector
1782     db 2-1 ; Max head
1783    
1784     dd 2880*1024 ; 2880K floppy
1785     db 3 ; Emulation type
1786     db 80-1 ; Max cylinder
1787     db 36 ; Max sector
1788     db 2-1 ; Max head
1789    
1790     ;
1791     ; Misc initialized (data) variables
1792     ;
1793    
1794     ;
1795     ; Variables that are uninitialized in SYSLINUX but initialized here
1796     ;
1797     ; **** ISOLINUX:: We may have to make this flexible, based on what the
1798     ; **** BIOS expects our "sector size" to be.
1799     ;
1800 niro 1133 alignz 4
1801 niro 532 BufSafe dw trackbufsize/SECTOR_SIZE ; Clusters we can load into trackbuf
1802     BufSafeBytes dw trackbufsize ; = how many bytes?
1803     %ifndef DEPEND
1804     %if ( trackbufsize % SECTOR_SIZE ) != 0
1805     %error trackbufsize must be a multiple of SECTOR_SIZE
1806     %endif
1807     %endif