Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (hide annotations) (download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 8 months ago) by niro
File size: 41054 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd

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