root/core/isolinux.asm

Revision faf815967c276bab95989d22a62b8378d7ebf6f3, 29.8 KB (checked in by H. Peter Anvin <hpa@…>, 13 months ago)

isolinux: remove broken and obsolete open_file_t

Signed-off-by: H. Peter Anvin <hpa@…>

  • Property mode set to 100644
Line 
1; -*- 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;   Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
12;   Copyright 2009 Intel Corporation; author: 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 "head.inc"
24
25;
26; Some semi-configurable constants... change on your own risk.
27;
28my_id           equ isolinux_id
29NULLFILE        equ 0                   ; Zero byte == null file name
30NULLOFFSET      equ 0                   ; Position in which to look
31retry_count     equ 6                   ; How patient are we with the BIOS?
32%assign HIGHMEM_SLOP 128*1024           ; Avoid this much memory near the top
33SECTOR_SHIFT    equ 11                  ; 2048 bytes/sector (El Torito requirement)
34SECTOR_SIZE     equ (1 << SECTOR_SHIFT)
35
36ROOT_DIR_WORD   equ 0x002F
37
38;
39; The following structure is used for "virtual kernels"; i.e. LILO-style
40; option labels.  The options we permit here are `kernel' and `append
41; Since there is no room in the bottom 64K for all of these, we
42; stick them in high memory and copy them down before we need them.
43;
44                struc vkernel
45vk_vname:       resb FILENAME_MAX       ; Virtual name **MUST BE FIRST!**
46vk_rname:       resb FILENAME_MAX       ; Real name
47vk_appendlen:   resw 1
48vk_type:        resb 1                  ; Type of file
49                alignb 4
50vk_append:      resb max_cmd_len+1      ; Command line
51                alignb 4
52vk_end:         equ $                   ; Should be <= vk_size
53                endstruc
54
55; ---------------------------------------------------------------------------
56;   BEGIN CODE
57; ---------------------------------------------------------------------------
58
59;
60; Memory below this point is reserved for the BIOS and the MBR
61;
62                section .earlybss
63                global trackbuf
64trackbufsize    equ 8192
65trackbuf        resb trackbufsize       ; Track buffer goes here
66;               ends at 2800h
67
68                ; Some of these are touched before the whole image
69                ; is loaded.  DO NOT move this to .bss16/.uibss.
70                section .earlybss
71                alignb 4
72FirstSecSum     resd 1                  ; Checksum of bytes 64-2048
73ImageDwords     resd 1                  ; isolinux.bin size, dwords
74InitStack       resd 1                  ; Initial stack pointer (SS:SP)
75DiskSys         resw 1                  ; Last INT 13h call
76ImageSectors    resw 1                  ; isolinux.bin size, sectors
77; These following two are accessed as a single dword...
78GetlinsecPtr    resw 1                  ; The sector-read pointer
79BIOSName        resw 1                  ; Display string for BIOS type
80%define HAVE_BIOSNAME 1
81BIOSType        resw 1
82DiskError       resb 1                  ; Error code for disk I/O
83DriveNumber     resb 1                  ; CD-ROM BIOS drive number
84ISOFlags        resb 1                  ; Flags for ISO directory search
85RetryCount      resb 1                  ; Used for disk access retries
86
87                alignb 8
88Hidden          resq 1                  ; Used in hybrid mode
89bsSecPerTrack   resw 1                  ; Used in hybrid mode
90bsHeads         resw 1                  ; Used in hybrid mode
91
92
93;
94; El Torito spec packet
95;
96
97                alignb 8
98_spec_start     equ $
99spec_packet:    resb 1                          ; Size of packet
100sp_media:       resb 1                          ; Media type
101sp_drive:       resb 1                          ; Drive number
102sp_controller:  resb 1                          ; Controller index
103sp_lba:         resd 1                          ; LBA for emulated disk image
104sp_devspec:     resw 1                          ; IDE/SCSI information
105sp_buffer:      resw 1                          ; User-provided buffer
106sp_loadseg:     resw 1                          ; Load segment
107sp_sectors:     resw 1                          ; Sector count
108sp_chs:         resb 3                          ; Simulated CHS geometry
109sp_dummy:       resb 1                          ; Scratch, safe to overwrite
110
111;
112; EBIOS drive parameter packet
113;
114                alignb 8
115drive_params:   resw 1                          ; Buffer size
116dp_flags:       resw 1                          ; Information flags
117dp_cyl:         resd 1                          ; Physical cylinders
118dp_head:        resd 1                          ; Physical heads
119dp_sec:         resd 1                          ; Physical sectors/track
120dp_totalsec:    resd 2                          ; Total sectors
121dp_secsize:     resw 1                          ; Bytes per sector
122dp_dpte:        resd 1                          ; Device Parameter Table
123dp_dpi_key:     resw 1                          ; 0BEDDh if rest valid
124dp_dpi_len:     resb 1                          ; DPI len
125                resb 1
126                resw 1
127dp_bus:         resb 4                          ; Host bus type
128dp_interface:   resb 8                          ; Interface type
129db_i_path:      resd 2                          ; Interface path
130db_d_path:      resd 2                          ; Device path
131                resb 1
132db_dpi_csum:    resb 1                          ; Checksum for DPI info
133
134;
135; EBIOS disk address packet
136;
137                alignb 8
138dapa:           resw 1                          ; Packet size
139.count:         resw 1                          ; Block count
140.off:           resw 1                          ; Offset of buffer
141.seg:           resw 1                          ; Segment of buffer
142.lba:           resd 2                          ; LBA (LSW, MSW)
143
144;
145; Spec packet for disk image emulation
146;
147                alignb 8
148dspec_packet:   resb 1                          ; Size of packet
149dsp_media:      resb 1                          ; Media type
150dsp_drive:      resb 1                          ; Drive number
151dsp_controller: resb 1                          ; Controller index
152dsp_lba:        resd 1                          ; LBA for emulated disk image
153dsp_devspec:    resw 1                          ; IDE/SCSI information
154dsp_buffer:     resw 1                          ; User-provided buffer
155dsp_loadseg:    resw 1                          ; Load segment
156dsp_sectors:    resw 1                          ; Sector count
157dsp_chs:        resb 3                          ; Simulated CHS geometry
158dsp_dummy:      resb 1                          ; Scratch, safe to overwrite
159
160                alignb 4
161_spec_end       equ $
162_spec_len       equ _spec_end - _spec_start
163
164                section .init
165;;
166;; Primary entry point.  Because BIOSes are buggy, we only load the first
167;; CD-ROM sector (2K) of the file, so the number one priority is actually
168;; loading the rest.
169;;
170StackBuf        equ STACK_TOP-44        ; 44 bytes needed for
171                                        ; the bootsector chainloading
172                                        ; code!
173OrigESDI        equ StackBuf-4          ; The high dword on the stack
174StackHome       equ OrigESDI
175
176bootsec         equ $
177
178_start:         ; Far jump makes sure we canonicalize the address
179                cli
180                jmp 0:_start1
181                times 8-($-$$) nop              ; Pad to file offset 8
182
183                ; This table hopefully gets filled in by mkisofs using the
184                ; -boot-info-table option.  If not, the values in this
185                ; table are default values that we can use to get us what
186                ; we need, at least under a certain set of assumptions.
187                global iso_boot_info
188iso_boot_info:
189bi_pvd:         dd 16                           ; LBA of primary volume descriptor
190bi_file:        dd 0                            ; LBA of boot file
191bi_length:      dd 0xdeadbeef                   ; Length of boot file
192bi_csum:        dd 0xdeadbeef                   ; Checksum of boot file
193bi_reserved:    times 10 dd 0xdeadbeef          ; Reserved
194bi_end:
195
196                ; Custom entry point for the hybrid-mode disk.
197                ; The following values will have been pushed onto the
198                ; entry stack:
199                ;       - partition offset (qword)
200                ;       - ES
201                ;       - DI
202                ;       - DX (including drive number)
203                ;       - CBIOS Heads
204                ;       - CBIOS Sectors
205                ;       - EBIOS flag
206                ;       (top of stack)
207                ;
208                ; If we had an old isohybrid, the partition offset will
209                ; be missing; we can check for that with sp >= 0x7c00.
210                ; Serious hack alert.
211%ifndef DEBUG_MESSAGES
212_hybrid_signature:
213               dd 0x7078c0fb                    ; An arbitrary number...
214
215_start_hybrid:
216                pop cx                          ; EBIOS flag
217                pop word [cs:bsSecPerTrack]
218                pop word [cs:bsHeads]
219                pop dx
220                pop di
221                pop es
222                xor eax,eax
223                xor ebx,ebx
224                cmp sp,7C00h
225                jae .nooffset
226                pop eax
227                pop ebx
228.nooffset:
229                mov si,bios_cbios
230                jcxz _start_common
231                mov si,bios_ebios
232                jmp _start_common
233%endif
234
235_start1:
236                mov si,bios_cdrom
237                xor eax,eax
238                xor ebx,ebx
239_start_common:
240                mov [cs:InitStack],sp   ; Save initial stack pointer
241                mov [cs:InitStack+2],ss
242                xor cx,cx
243                mov ss,cx
244                mov sp,StackBuf         ; Set up stack
245                push es                 ; Save initial ES:DI -> $PnP pointer
246                push di
247                mov ds,cx
248                mov es,cx
249                mov fs,cx
250                mov gs,cx
251                sti
252                cld
253
254                mov [Hidden],eax
255                mov [Hidden+4],ebx
256
257                mov [BIOSType],si
258                mov eax,[si]
259                mov [GetlinsecPtr],eax
260
261                ; Show signs of life
262                mov si,syslinux_banner
263                call writestr_early
264%ifdef DEBUG_MESSAGES
265                mov si,copyright_str
266%else
267                mov si,[BIOSName]
268%endif
269                call writestr_early
270
271                ;
272                ; Before modifying any memory, get the checksum of bytes
273                ; 64-2048
274                ;
275initial_csum:   xor edi,edi
276                mov si,bi_end
277                mov cx,(SECTOR_SIZE-64) >> 2
278.loop:          lodsd
279                add edi,eax
280                loop .loop
281                mov [FirstSecSum],edi
282
283                mov [DriveNumber],dl
284%ifdef DEBUG_MESSAGES
285                mov si,startup_msg
286                call writemsg
287                mov al,dl
288                call writehex2
289                call crlf
290%endif
291                ;
292                ; Initialize spec packet buffers
293                ;
294                mov di,_spec_start
295                mov cx,_spec_len >> 2
296                xor eax,eax
297                rep stosd
298
299                ; Initialize length field of the various packets
300                mov byte [spec_packet],13h
301                mov byte [drive_params],30
302                mov byte [dapa],16
303                mov byte [dspec_packet],13h
304
305                ; Other nonzero fields
306                inc word [dsp_sectors]
307
308                ; Are we just pretending to be a CD-ROM?
309                cmp word [BIOSType],bios_cdrom
310                jne found_drive                 ; If so, no spec packet...
311
312                ; Now figure out what we're actually doing
313                ; Note: use passed-in DL value rather than 7Fh because
314                ; at least some BIOSes will get the wrong value otherwise
315                mov ax,4B01h                    ; Get disk emulation status
316                mov dl,[DriveNumber]
317                mov si,spec_packet
318                call int13
319                jc award_hack                   ; changed for BrokenAwardHack
320                mov dl,[DriveNumber]
321                cmp [sp_drive],dl               ; Should contain the drive number
322                jne spec_query_failed
323
324%ifdef DEBUG_MESSAGES
325                mov si,spec_ok_msg
326                call writemsg
327                mov al,byte [sp_drive]
328                call writehex2
329                call crlf
330%endif
331
332found_drive:
333                ; Alright, we have found the drive.  Now, try to find the
334                ; boot file itself.  If we have a boot info table, life is
335                ; good; if not, we have to make some assumptions, and try
336                ; to figure things out ourselves.  In particular, the
337                ; assumptions we have to make are:
338                ; - single session only
339                ; - only one boot entry (no menu or other alternatives)
340
341                cmp dword [bi_file],0           ; Address of code to load
342                jne found_file                  ; Boot info table present :)
343
344%ifdef DEBUG_MESSAGES
345                mov si,noinfotable_msg
346                call writemsg
347%endif
348
349                ; No such luck.  See if the spec packet contained one.
350                mov eax,[sp_lba]
351                and eax,eax
352                jz set_file                     ; Good enough
353
354%ifdef DEBUG_MESSAGES
355                mov si,noinfoinspec_msg
356                call writemsg
357%endif
358
359                ; No such luck.  Get the Boot Record Volume, assuming single
360                ; session disk, and that we're the first entry in the chain.
361                mov eax,17                      ; Assumed address of BRV
362                mov bx,trackbuf
363                call getonesec
364
365                mov eax,[trackbuf+47h]          ; Get boot catalog address
366                mov bx,trackbuf
367                call getonesec                  ; Get boot catalog
368
369                mov eax,[trackbuf+28h]          ; First boot entry
370                ; And hope and pray this is us...
371
372                ; Some BIOSes apparently have limitations on the size
373                ; that may be loaded (despite the El Torito spec being very
374                ; clear on the fact that it must all be loaded.)  Therefore,
375                ; we load it ourselves, and *bleep* the BIOS.
376
377set_file:
378                mov [bi_file],eax
379
380found_file:
381                ; Set up boot file sizes
382                mov eax,[bi_length]
383                sub eax,SECTOR_SIZE-3           ; ... minus sector loaded
384                shr eax,2                       ; bytes->dwords
385                mov [ImageDwords],eax           ; boot file dwords
386                add eax,((SECTOR_SIZE-1) >> 2)
387                shr eax,SECTOR_SHIFT-2          ; dwords->sectors
388                mov [ImageSectors],ax           ; boot file sectors
389
390                mov eax,[bi_file]               ; Address of code to load
391                inc eax                         ; Don't reload bootstrap code
392%ifdef DEBUG_MESSAGES
393                mov si,offset_msg
394                call writemsg
395                call writehex8
396                call crlf
397%endif
398
399                ; Load the rest of the file.  However, just in case there
400                ; are still BIOSes with 64K wraparound problems, we have to
401                ; take some extra precautions.  Since the normal load
402                ; address (TEXT_START) is *not* 2K-sector-aligned, we round
403                ; the target address upward to a sector boundary,
404                ; and then move the entire thing down as a unit.
405MaxLMA          equ 384*1024            ; Reasonable limit (384K)
406
407                mov bx,((TEXT_START+2*SECTOR_SIZE-1) & ~(SECTOR_SIZE-1)) >> 4
408                mov bp,[ImageSectors]
409                push bx                 ; Load segment address
410
411.more:
412                push bx                 ; Segment address
413                push bp                 ; Sector count
414                mov es,bx
415                mov cx,0xfff
416                and bx,cx
417                inc cx
418                sub cx,bx
419                shr cx,SECTOR_SHIFT - 4
420                jnz .notaligned
421                mov cx,0x10000 >> SECTOR_SHIFT  ; Full 64K segment possible
422.notaligned:
423                cmp bp,cx
424                jbe .ok
425                mov bp,cx
426.ok:
427                xor bx,bx
428                push bp
429                call getlinsec
430                pop cx
431                mov dx,cx
432                pop bp
433                pop bx
434
435                shl cx,SECTOR_SHIFT - 4
436                add bx,cx
437                sub bp,dx
438                jnz .more
439
440                ; Move the image into place, and also verify the
441                ; checksum
442                pop ax                          ; Load segment address
443                mov bx,(TEXT_START + SECTOR_SIZE) >> 4
444                mov ecx,[ImageDwords]
445                mov edi,[FirstSecSum]           ; First sector checksum
446                xor si,si
447
448move_verify_image:
449.setseg:
450                mov ds,ax
451                mov es,bx
452.loop:
453                mov edx,[si]
454                add edi,edx
455                dec ecx
456                mov [es:si],edx
457                jz .done
458                add si,4
459                jnz .loop
460                add ax,1000h
461                add bx,1000h
462                jmp .setseg
463.done:
464                mov ax,cs
465                mov ds,ax
466                mov es,ax
467
468                ; Verify the checksum on the loaded image.
469                cmp [bi_csum],edi
470                je integrity_ok
471
472                mov si,checkerr_msg
473                call writemsg
474                jmp kaboom
475
476integrity_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;; There is a problem with certain versions of the AWARD BIOS ...
488;; 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;; with an broken AWARD BIOS ...
505;;
506;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
507                                                                             ;;
508%ifdef DEBUG_MESSAGES                                                        ;;
509                                                                             ;;
510award_notice    db      "Trying BrokenAwardHack first ...",CR,LF,0           ;;
511award_not_orig  db      "BAH: Original Int 13 vector   : ",0                 ;;
512award_not_new   db      "BAH: Int 13 vector changed to : ",0                 ;;
513award_not_succ  db      "BAH: SUCCESS",CR,LF,0                               ;;
514award_not_fail  db      "BAH: FAILURE"                                       ;;
515award_not_crlf  db      CR,LF,0                                              ;;
516                                                                             ;;
517%endif                                                                       ;;
518                                                                             ;;
519award_oldint13  dd      0                                                    ;;
520award_string    db      0b8h,1,2,0bbh,0,7ch,0b9h,6,0,0bah,80h,1,09ch,09ah    ;;
521                                                                             ;;
522                                                ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
523award_hack:     mov     si,spec_err_msg         ; Moved to this place from
524                call    writemsg                ; spec_query_faild
525                                                ;
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                mov     si,award_not_crlf       ;
540                call    writestr_early          ;
541%endif                                          ;
542                push    es                      ; save ES
543                mov     ax,0f000h               ; ES = BIOS Seg
544                mov     es,ax                   ;
545                cld                             ;
546                xor     di,di                   ; start at ES:DI = f000:0
547award_loop:     push    di                      ; save DI
548                mov     si,award_string         ; scan for award_string
549                mov     cx,7                    ; length of award_string = 7dw
550                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                                                ;
556award_failed:   pop     es                      ; No, not this way :-((
557award_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                                                ;
570award_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                push    eax                     ; display message and
581                mov     si,award_not_new        ; new vector address
582                call    writemsg                ;
583                pop     eax                     ;
584                call    writehex8               ;
585                mov     si,award_not_crlf       ;
586                call    writestr_early          ;
587%endif                                          ;
588                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                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
609spec_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                mov byte [si],13h               ; Size of buffer
618                call int13
619                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.found_drive0:  mov [DriveNumber],dl
635.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                mov al,[DriveNumber]
642                cmp al,dl
643                je .found_drive
644
645                ; 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.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                mov dl,[DriveNumber]
662                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
675fatal_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                ;
684writemsg:       push ax
685                push si
686                mov si,isolinux_str
687                call writestr_early
688                pop si
689                call writestr_early
690                pop ax
691                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
699writechr:
700.simple:
701                pushfd
702                pushad
703                mov ah,0Eh
704                xor bx,bx
705                int 10h
706                popad
707                popfd
708                ret
709
710;
711; int13: save all the segment registers and call INT 13h.
712;        Some CD-ROM BIOSes have been found to corrupt segment registers
713;        and/or disable interrupts.
714;
715int13:
716                pushf
717                push bp
718                push ds
719                push es
720                push fs
721                push gs
722                int 13h
723                mov bp,sp
724                setc [bp+10]            ; Propagate CF to the caller
725                pop gs
726                pop fs
727                pop es
728                pop ds
729                pop bp
730                popf
731                ret
732
733;
734; Get one sector.  Convenience entry point.
735;
736getonesec:
737                mov bp,1
738                ; Fall through to getlinsec
739
740;
741; Get linear sectors - EBIOS LBA addressing, 2048-byte sectors.
742;
743; Input:
744;       EAX     - Linear sector number
745;       ES:BX   - Target buffer
746;       BP      - Sector count
747;
748                global getlinsec
749getlinsec:      jmp word [cs:GetlinsecPtr]
750
751%ifndef DEBUG_MESSAGES
752
753;
754; First, the variants that we use when actually loading off a disk
755; (hybrid mode.)  These are adapted versions of the equivalent routines
756; in ldlinux.asm.
757;
758
759;
760; getlinsec_ebios:
761;
762; getlinsec implementation for floppy/HDD EBIOS (EDD)
763;
764getlinsec_ebios:
765                xor edx,edx
766                shld edx,eax,2
767                shl eax,2                       ; Convert to HDD sectors
768                add eax,[Hidden]
769                adc edx,[Hidden+4]
770                shl bp,2
771
772.loop:
773                push bp                         ; Sectors left
774.retry2:
775                call maxtrans                   ; Enforce maximum transfer size
776                movzx edi,bp                    ; Sectors we are about to read
777                mov cx,retry_count
778.retry:
779
780                ; Form DAPA on stack
781                push edx
782                push eax
783                push es
784                push bx
785                push di
786                push word 16
787                mov si,sp
788                pushad
789                mov dl,[DriveNumber]
790                push ds
791                push ss
792                pop ds                          ; DS <- SS
793                mov ah,42h                      ; Extended Read
794                call int13
795                pop ds
796                popad
797                lea sp,[si+16]                  ; Remove DAPA
798                jc .error
799                pop bp
800                add eax,edi                     ; Advance sector pointer
801                adc edx,0
802                sub bp,di                       ; Sectors left
803                shl di,9                        ; 512-byte sectors
804                add bx,di                       ; Advance buffer pointer
805                and bp,bp
806                jnz .loop
807
808                ret
809
810.error:
811                ; Some systems seem to get "stuck" in an error state when
812                ; using EBIOS.  Doesn't happen when using CBIOS, which is
813                ; good, since some other systems get timeout failures
814                ; waiting for the floppy disk to spin up.
815
816                pushad                          ; Try resetting the device
817                xor ax,ax
818                mov dl,[DriveNumber]
819                call int13
820                popad
821                loop .retry                     ; CX-- and jump if not zero
822
823                ;shr word [MaxTransfer],1       ; Reduce the transfer size
824                ;jnz .retry2
825
826                ; Total failure.  Try falling back to CBIOS.
827                mov word [GetlinsecPtr], getlinsec_cbios
828                ;mov byte [MaxTransfer],63      ; Max possibe CBIOS transfer
829
830                pop bp
831                jmp getlinsec_cbios.loop
832
833;
834; getlinsec_cbios:
835;
836; getlinsec implementation for legacy CBIOS
837;
838getlinsec_cbios:
839                xor edx,edx
840                shl eax,2                       ; Convert to HDD sectors
841                add eax,[Hidden]
842                shl bp,2
843
844.loop:
845                push edx
846                push eax
847                push bp
848                push bx
849
850                movzx esi,word [bsSecPerTrack]
851                movzx edi,word [bsHeads]
852                ;
853                ; Dividing by sectors to get (track,sector): we may have
854                ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
855                ;
856                div esi
857                xor cx,cx
858                xchg cx,dx              ; CX <- sector index (0-based)
859                                        ; EDX <- 0
860                ; eax = track #
861                div edi                 ; Convert track to head/cyl
862
863                ; We should test this, but it doesn't fit...
864                ; cmp eax,1023
865                ; ja .error
866
867                ;
868                ; Now we have AX = cyl, DX = head, CX = sector (0-based),
869                ; BP = sectors to transfer, SI = bsSecPerTrack,
870                ; ES:BX = data target
871                ;
872
873                call maxtrans                   ; Enforce maximum transfer size
874
875                ; Must not cross track boundaries, so BP <= SI-CX
876                sub si,cx
877                cmp bp,si
878                jna .bp_ok
879                mov bp,si
880.bp_ok:
881
882                shl ah,6                ; Because IBM was STOOPID
883                                        ; and thought 8 bits were enough
884                                        ; then thought 10 bits were enough...
885                inc cx                  ; Sector numbers are 1-based, sigh
886                or cl,ah
887                mov ch,al
888                mov dh,dl
889                mov dl,[DriveNumber]
890                xchg ax,bp              ; Sector to transfer count
891                mov ah,02h              ; Read sectors
892                mov bp,retry_count
893.retry:
894                pushad
895                call int13
896                popad
897                jc .error
898.resume:
899                movzx ecx,al            ; ECX <- sectors transferred
900                shl ax,9                ; Convert sectors in AL to bytes in AX
901                pop bx
902                add bx,ax
903                pop bp
904                pop eax
905                pop edx
906                add eax,ecx
907                sub bp,cx
908                jnz .loop
909                ret
910
911.error:
912                dec bp
913                jnz .retry
914
915                xchg ax,bp              ; Sectors transferred <- 0
916                shr word [MaxTransfer],1
917                jnz .resume
918                jmp disk_error
919
920;
921; Truncate BP to MaxTransfer
922;
923maxtrans:
924                cmp bp,[MaxTransfer]
925                jna .ok
926                mov bp,[MaxTransfer]
927.ok:            ret
928
929%endif
930
931;
932; This is the variant we use for real CD-ROMs:
933; LBA, 2K sectors, some special error handling.
934;
935getlinsec_cdrom:
936                mov si,dapa                     ; Load up the DAPA
937                mov [si+4],bx
938                mov [si+6],es
939                mov [si+8],eax
940.loop:
941                push bp                         ; Sectors left
942                cmp bp,[MaxTransferCD]
943                jbe .bp_ok
944                mov bp,[MaxTransferCD]
945.bp_ok:
946                mov [si+2],bp
947                push si
948                mov dl,[DriveNumber]
949                mov ah,42h                      ; Extended Read
950                call xint13
951                pop si
952                pop bp
953                movzx eax,word [si+2]           ; Sectors we read
954                add [si+8],eax                  ; Advance sector pointer
955                sub bp,ax                       ; Sectors left
956                shl ax,SECTOR_SHIFT-4           ; 2048-byte sectors -> segment
957                add [si+6],ax                   ; Advance buffer pointer
958                and bp,bp
959                jnz .loop
960                mov eax,[si+8]                  ; Next sector
961                ret
962
963                ; INT 13h with retry
964xint13:         mov byte [RetryCount],retry_count
965.try:           pushad
966                call int13
967                jc .error
968                add sp,byte 8*4                 ; Clean up stack
969                ret
970.error:
971                mov [DiskError],ah              ; Save error code
972                popad
973                mov [DiskSys],ax                ; Save system call number
974                dec byte [RetryCount]
975                jz .real_error
976                push ax
977                mov al,[RetryCount]
978                mov ah,[dapa+2]                 ; Sector transfer count
979                cmp al,2                        ; Only 2 attempts left
980                ja .nodanger
981                mov ah,1                        ; Drop transfer size to 1
982                jmp short .setsize
983.nodanger:
984                cmp al,retry_count-2
985                ja .again                       ; First time, just try again
986                shr ah,1                        ; Otherwise, try to reduce
987                adc ah,0                        ; the max transfer size, but not to 0
988.setsize:
989                mov [MaxTransferCD],ah
990                mov [dapa+2],ah
991.again:
992                pop ax
993                jmp .try
994
995.real_error:    mov si,diskerr_msg
996                call writemsg
997                mov al,[DiskError]
998                call writehex2
999                mov si,oncall_str
1000                call writestr_early
1001                mov ax,[DiskSys]
1002                call writehex4
1003                mov si,ondrive_str
1004                call writestr_early
1005                mov al,dl
1006                call writehex2
1007                call crlf
1008                ; Fall through to kaboom
1009
1010;
1011; kaboom: write a message and bail out.  Wait for a user keypress,
1012;         then do a hard reboot.
1013;
1014                global kaboom
1015disk_error:
1016kaboom:
1017                RESET_STACK_AND_SEGS AX
1018                mov si,err_bootfailed
1019                call writestr
1020                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
1030writestr_early  equ writestr
1031%include "writehex.inc"         ; Hexadecimal output
1032
1033; -----------------------------------------------------------------------------
1034; Data that needs to be in the first sector
1035; -----------------------------------------------------------------------------
1036
1037syslinux_banner db CR, LF, MY_NAME, ' ', VERSION_STR, ' ', DATE_STR, ' ', 0
1038copyright_str   db ' Copyright (C) 1994-'
1039                asciidec YEAR
1040                db ' H. Peter Anvin et al', CR, LF, 0
1041isolinux_str    db 'isolinux: ', 0
1042%ifdef DEBUG_MESSAGES
1043startup_msg:    db 'Starting up, DL = ', 0
1044spec_ok_msg:    db 'Loaded spec packet OK, drive = ', 0
1045secsize_msg:    db 'Sector size ', 0
1046offset_msg:     db 'Main image LBA = ', 0
1047verify_msg:     db 'Image checksum verified.', CR, LF, 0
1048allread_msg     db 'Main image read, jumping to main code...', CR, LF, 0
1049%endif
1050noinfotable_msg db 'No boot info table, assuming single session disk...', CR, LF, 0
1051noinfoinspec_msg db 'Spec packet missing LBA information, trying to wing it...', CR, LF, 0
1052spec_err_msg:   db 'Loading spec packet failed, trying to wing it...', CR, LF, 0
1053maybe_msg:      db 'Found something at drive = ', 0
1054alright_msg:    db 'Looks reasonable, continuing...', CR, LF, 0
1055nospec_msg      db 'Extremely broken BIOS detected, last attempt with drive = ', 0
1056nothing_msg:    db 'Failed to locate CD-ROM device; boot failed.', CR, LF
1057trysbm_msg      db 'See http://syslinux.zytor.com/sbm for more information.', CR, LF, 0
1058diskerr_msg:    db 'Disk error ', 0
1059oncall_str:     db ', AX = ',0
1060ondrive_str:    db ', drive ', 0
1061checkerr_msg:   db 'Image checksum error, sorry...', CR, LF, 0
1062
1063err_bootfailed  db CR, LF, 'Boot failed: press a key to retry...'
1064bailmsg         equ err_bootfailed
1065crlf_msg        db CR, LF
1066null_msg        db 0
1067
1068bios_cdrom_str  db 'ETCD', 0
1069%ifndef DEBUG_MESSAGES
1070bios_cbios_str  db 'CHDD', 0
1071bios_ebios_str  db 'EHDD' ,0
1072%endif
1073
1074                alignz 4
1075bios_cdrom:     dw getlinsec_cdrom, bios_cdrom_str
1076%ifndef DEBUG_MESSAGES
1077bios_cbios:     dw getlinsec_cbios, bios_cbios_str
1078bios_ebios:     dw getlinsec_ebios, bios_ebios_str
1079%endif
1080
1081; Maximum transfer size
1082MaxTransfer     dw 127                          ; Hard disk modes
1083MaxTransferCD   dw 32                           ; CD mode
1084
1085rl_checkpt      equ $                           ; Must be <= 800h
1086
1087                ; This pads to the end of sector 0 and errors out on
1088                ; overflow.
1089                times 2048-($-$$) db 0
1090
1091; ----------------------------------------------------------------------------
1092;  End of code and data that have to be in the first sector
1093; ----------------------------------------------------------------------------
1094
1095                section .text16
1096
1097all_read:
1098
1099; Test tracers
1100                TRACER 'T'
1101                TRACER '>'
1102
1103;
1104; Common initialization code
1105;
1106%include "init.inc"
1107
1108                ; Patch the writechr routine to point to the full code
1109                mov di,writechr
1110                mov al,0e9h
1111                stosb
1112                mov ax,writechr_full-2
1113                sub ax,di
1114                stosw
1115
1116; Tell the user we got this far...
1117%ifndef DEBUG_MESSAGES                  ; Gets messy with debugging on
1118                mov si,copyright_str
1119                call writestr_early
1120%endif
1121
1122;
1123; Now we're all set to start with our *real* business.  First load the
1124; configuration file (if any) and parse it.
1125;
1126; In previous versions I avoided using 32-bit registers because of a
1127; rumour some BIOSes clobbered the upper half of 32-bit registers at
1128; random.  I figure, though, that if there are any of those still left
1129; they probably won't be trying to install Linux on them...
1130;
1131; The code is still ripe with 16-bitisms, though.  Not worth the hassle
1132; to take'm out.  In fact, we may want to put them back if we're going
1133; to boot ELKS at some point.
1134;
1135
1136;
1137; Now, we need to sniff out the actual filesystem data structures.
1138; mkisofs gave us a pointer to the primary volume descriptor
1139; (which will be at 16 only for a single-session disk!); from the PVD
1140; we should be able to find the rest of what we need to know.
1141;
1142init_fs:
1143                pushad
1144                mov eax,ROOT_FS_OPS
1145                mov dl,[DriveNumber]
1146                cmp word [BIOSType],bios_cdrom
1147                sete dh                        ; 1 for cdrom, 0 for hybrid mode
1148                jne .hybrid
1149                movzx ebp,word [MaxTransferCD]
1150                jmp .common
1151.hybrid:
1152                movzx ebp,word [MaxTransfer]
1153.common:
1154                mov ecx,[Hidden]
1155                mov ebx,[Hidden+4]
1156                mov si,[bsHeads]
1157                mov di,[bsSecPerTrack]
1158                pm_call fs_init
1159                popad
1160
1161                section .rodata
1162                alignz 4
1163ROOT_FS_OPS:
1164                extern iso_fs_ops
1165                dd iso_fs_ops
1166                dd 0
1167
1168                section .text16
1169
1170;
1171; Locate the configuration file
1172;
1173                pm_call pm_load_config
1174                jz no_config_file
1175
1176;
1177; Now we have the config file open.  Parse the config file and
1178; run the user interface.
1179;
1180%include "ui.inc"
1181
1182; -----------------------------------------------------------------------------
1183;  Common modules
1184; -----------------------------------------------------------------------------
1185
1186%include "common.inc"           ; Universal modules
1187%include "rawcon.inc"           ; Console I/O w/o using the console functions
1188%include "localboot.inc"        ; Disk-based local boot
1189
1190; -----------------------------------------------------------------------------
1191;  Begin data section
1192; -----------------------------------------------------------------------------
1193
1194                section .data16
1195err_disk_image  db 'Cannot load disk image (invalid file)?', CR, LF, 0
1196
1197;
1198; Config file keyword table
1199;
1200%include "keywords.inc"
1201
1202;
1203; Extensions to search for (in *forward* order).
1204;
1205                alignz 4
1206exten_table:    db '.cbt'               ; COMBOOT (specific)
1207                db '.bin'               ; CD boot sector
1208                db '.com'               ; COMBOOT (same as DOS)
1209                db '.c32'               ; COM32
1210exten_table_end:
1211                dd 0, 0                 ; Need 8 null bytes here
Note: See TracBrowser for help on using the browser.