7a871f0e82c7ffef1bb0daa8ac7578c84858a2b1
[profile/ivi/syslinux.git] / core / isolinux.asm
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 ;
28 my_id           equ isolinux_id
29 NULLFILE        equ 0                   ; Zero byte == null file name
30 NULLOFFSET      equ 0                   ; Position in which to look
31 retry_count     equ 6                   ; How patient are we with the BIOS?
32 %assign HIGHMEM_SLOP 128*1024           ; Avoid this much memory near the top
33 SECTOR_SHIFT    equ 11                  ; 2048 bytes/sector (El Torito requirement)
34 SECTOR_SIZE     equ (1 << SECTOR_SHIFT)
35
36 ROOT_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
45 vk_vname:       resb FILENAME_MAX       ; Virtual name **MUST BE FIRST!**
46 vk_rname:       resb FILENAME_MAX       ; Real name
47 vk_appendlen:   resw 1
48 vk_type:        resb 1                  ; Type of file
49                 alignb 4
50 vk_append:      resb max_cmd_len+1      ; Command line
51                 alignb 4
52 vk_end:         equ $                   ; Should be <= vk_size
53                 endstruc
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
64 trackbufsize    equ 8192
65 trackbuf        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
72 FirstSecSum     resd 1                  ; Checksum of bytes 64-2048
73 ImageDwords     resd 1                  ; isolinux.bin size, dwords
74 InitStack       resd 1                  ; Initial stack pointer (SS:SP)
75 DiskSys         resw 1                  ; Last INT 13h call
76 ImageSectors    resw 1                  ; isolinux.bin size, sectors
77 ; These following two are accessed as a single dword...
78 GetlinsecPtr    resw 1                  ; The sector-read pointer
79 BIOSName        resw 1                  ; Display string for BIOS type
80 %define HAVE_BIOSNAME 1
81 BIOSType        resw 1
82 DiskError       resb 1                  ; Error code for disk I/O
83 DriveNumber     resb 1                  ; CD-ROM BIOS drive number
84 ISOFlags        resb 1                  ; Flags for ISO directory search
85 RetryCount      resb 1                  ; Used for disk access retries
86
87                 alignb 8
88 Hidden          resq 1                  ; Used in hybrid mode
89 bsSecPerTrack   resw 1                  ; Used in hybrid mode
90 bsHeads         resw 1                  ; Used in hybrid mode
91
92
93 ;
94 ; El Torito spec packet
95 ;
96
97                 alignb 8
98 _spec_start     equ $
99 spec_packet:    resb 1                          ; Size of packet
100 sp_media:       resb 1                          ; Media type
101 sp_drive:       resb 1                          ; Drive number
102 sp_controller:  resb 1                          ; Controller index
103 sp_lba:         resd 1                          ; LBA for emulated disk image
104 sp_devspec:     resw 1                          ; IDE/SCSI information
105 sp_buffer:      resw 1                          ; User-provided buffer
106 sp_loadseg:     resw 1                          ; Load segment
107 sp_sectors:     resw 1                          ; Sector count
108 sp_chs:         resb 3                          ; Simulated CHS geometry
109 sp_dummy:       resb 1                          ; Scratch, safe to overwrite
110
111 ;
112 ; EBIOS drive parameter packet
113 ;
114                 alignb 8
115 drive_params:   resw 1                          ; Buffer size
116 dp_flags:       resw 1                          ; Information flags
117 dp_cyl:         resd 1                          ; Physical cylinders
118 dp_head:        resd 1                          ; Physical heads
119 dp_sec:         resd 1                          ; Physical sectors/track
120 dp_totalsec:    resd 2                          ; Total sectors
121 dp_secsize:     resw 1                          ; Bytes per sector
122 dp_dpte:        resd 1                          ; Device Parameter Table
123 dp_dpi_key:     resw 1                          ; 0BEDDh if rest valid
124 dp_dpi_len:     resb 1                          ; DPI len
125                 resb 1
126                 resw 1
127 dp_bus:         resb 4                          ; Host bus type
128 dp_interface:   resb 8                          ; Interface type
129 db_i_path:      resd 2                          ; Interface path
130 db_d_path:      resd 2                          ; Device path
131                 resb 1
132 db_dpi_csum:    resb 1                          ; Checksum for DPI info
133
134 ;
135 ; EBIOS disk address packet
136 ;
137                 alignb 8
138 dapa:           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
148 dspec_packet:   resb 1                          ; Size of packet
149 dsp_media:      resb 1                          ; Media type
150 dsp_drive:      resb 1                          ; Drive number
151 dsp_controller: resb 1                          ; Controller index
152 dsp_lba:        resd 1                          ; LBA for emulated disk image
153 dsp_devspec:    resw 1                          ; IDE/SCSI information
154 dsp_buffer:     resw 1                          ; User-provided buffer
155 dsp_loadseg:    resw 1                          ; Load segment
156 dsp_sectors:    resw 1                          ; Sector count
157 dsp_chs:        resb 3                          ; Simulated CHS geometry
158 dsp_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 ;;
170 StackBuf        equ STACK_TOP-44        ; 44 bytes needed for
171                                         ; the bootsector chainloading
172                                         ; code!
173 OrigESDI        equ StackBuf-4          ; The high dword on the stack
174 StackHome       equ OrigESDI
175
176 bootsec         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
188 iso_boot_info:
189 bi_pvd:         dd 16                           ; LBA of primary volume descriptor
190 bi_file:        dd 0                            ; LBA of boot file
191 bi_length:      dd 0xdeadbeef                   ; Length of boot file
192 bi_csum:        dd 0xdeadbeef                   ; Checksum of boot file
193 bi_reserved:    times 10 dd 0xdeadbeef          ; Reserved
194 bi_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                 ;
275 initial_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
332 found_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
377 set_file:
378                 mov [bi_file],eax
379
380 found_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.
405 MaxLMA          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
448 move_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
476 integrity_ok:
477 %ifdef DEBUG_MESSAGES
478                 mov si,allread_msg
479                 call writemsg
480 %endif
481                 jmp all_read                    ; Jump to main code
482
483 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
484 ;; Start of BrokenAwardHack --- 10-nov-2002           Knut_Petersen@t-online.de
485 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
486 ;;
487 ;; 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                                                                              ;;
510 award_notice    db      "Trying BrokenAwardHack first ...",CR,LF,0           ;;
511 award_not_orig  db      "BAH: Original Int 13 vector   : ",0                 ;;
512 award_not_new   db      "BAH: Int 13 vector changed to : ",0                 ;;
513 award_not_succ  db      "BAH: SUCCESS",CR,LF,0                               ;;
514 award_not_fail  db      "BAH: FAILURE"                                       ;;
515 award_not_crlf  db      CR,LF,0                                              ;;
516                                                                              ;;
517 %endif                                                                       ;;
518                                                                              ;;
519 award_oldint13  dd      0                                                    ;;
520 award_string    db      0b8h,1,2,0bbh,0,7ch,0b9h,6,0,0bah,80h,1,09ch,09ah    ;;
521                                                                              ;;
522                                                 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
523 award_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
547 award_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                                                 ;
556 award_failed:   pop     es                      ; No, not this way :-((
557 award_fail2:                                    ;
558                                                 ;
559 %ifdef DEBUG_MESSAGES                           ;
560                                                 ;
561                 mov     si,award_not_fail       ; display failure ...
562                 call    writemsg                ;
563 %endif                                          ;
564                 mov     eax,[award_oldint13]    ; restore the original int
565                 or      eax,eax                 ; 13 vector if there is one
566                 jz      spec_query_failed       ; and try other workarounds
567                 mov     [13h*4],eax             ;
568                 jmp     spec_query_failed       ;
569                                                 ;
570 award_found:    mov     eax,[es:di+0eh]         ; load possible int 13 addr
571                 pop     es                      ; restore ES
572                                                 ;
573                 cmp     eax,[award_oldint13]    ; give up if this is the
574                 jz      award_failed            ; active int 13 vector,
575                 mov     [13h*4],eax             ; otherwise change 0:13h*4
576                                                 ;
577                                                 ;
578 %ifdef DEBUG_MESSAGES                           ;
579                                                 ;
580                 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
609 spec_query_failed:
610
611                 ; some code moved to BrokenAwardHack
612
613                 mov dl,0FFh
614 .test_loop:     pusha
615                 mov ax,4B01h
616                 mov si,spec_packet
617                 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
675 fatal_error:
676                 mov si,nothing_msg
677                 call writemsg
678
679 .norge:         jmp short .norge
680
681                 ; Information message (DS:SI) output
682                 ; Prefix with "isolinux: "
683                 ;
684 writemsg:       push ax
685                 push si
686                 mov si,isolinux_str
687                 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
699 writechr:
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 ;
715 int13:
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 ;
736 getonesec:
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
749 getlinsec:      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 ;
764 getlinsec_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 ;
838 getlinsec_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 ;
923 maxtrans:
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 ;
935 getlinsec_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
964 xint13:         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
1015 disk_error:
1016 kaboom:
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
1030 writestr_early  equ writestr
1031 %include "writehex.inc"         ; Hexadecimal output
1032
1033 ; -----------------------------------------------------------------------------
1034 ; Data that needs to be in the first sector
1035 ; -----------------------------------------------------------------------------
1036
1037 syslinux_banner db CR, LF, MY_NAME, ' ', VERSION_STR, ' ', DATE_STR, ' ', 0
1038 copyright_str   db ' Copyright (C) 1994-'
1039                 asciidec YEAR
1040                 db ' H. Peter Anvin et al', CR, LF, 0
1041 isolinux_str    db 'isolinux: ', 0
1042 %ifdef DEBUG_MESSAGES
1043 startup_msg:    db 'Starting up, DL = ', 0
1044 spec_ok_msg:    db 'Loaded spec packet OK, drive = ', 0
1045 secsize_msg:    db 'Sector size ', 0
1046 offset_msg:     db 'Main image LBA = ', 0
1047 verify_msg:     db 'Image checksum verified.', CR, LF, 0
1048 allread_msg     db 'Main image read, jumping to main code...', CR, LF, 0
1049 %endif
1050 noinfotable_msg db 'No boot info table, assuming single session disk...', CR, LF, 0
1051 noinfoinspec_msg db 'Spec packet missing LBA information, trying to wing it...', CR, LF, 0
1052 spec_err_msg:   db 'Loading spec packet failed, trying to wing it...', CR, LF, 0
1053 maybe_msg:      db 'Found something at drive = ', 0
1054 alright_msg:    db 'Looks reasonable, continuing...', CR, LF, 0
1055 nospec_msg      db 'Extremely broken BIOS detected, last attempt with drive = ', 0
1056 nothing_msg:    db 'Failed to locate CD-ROM device; boot failed.', CR, LF
1057 trysbm_msg      db 'See http://syslinux.zytor.com/sbm for more information.', CR, LF, 0
1058 diskerr_msg:    db 'Disk error ', 0
1059 oncall_str:     db ', AX = ',0
1060 ondrive_str:    db ', drive ', 0
1061 checkerr_msg:   db 'Image checksum error, sorry...', CR, LF, 0
1062
1063 err_bootfailed  db CR, LF, 'Boot failed: press a key to retry...'
1064 bailmsg         equ err_bootfailed
1065 crlf_msg        db CR, LF
1066 null_msg        db 0
1067
1068 bios_cdrom_str  db 'ETCD', 0
1069 %ifndef DEBUG_MESSAGES
1070 bios_cbios_str  db 'CHDD', 0
1071 bios_ebios_str  db 'EHDD' ,0
1072 %endif
1073
1074                 alignz 4
1075 bios_cdrom:     dw getlinsec_cdrom, bios_cdrom_str
1076 %ifndef DEBUG_MESSAGES
1077 bios_cbios:     dw getlinsec_cbios, bios_cbios_str
1078 bios_ebios:     dw getlinsec_ebios, bios_ebios_str
1079 %endif
1080
1081 ; Maximum transfer size
1082 MaxTransfer     dw 127                          ; Hard disk modes
1083 MaxTransferCD   dw 32                           ; CD mode
1084
1085 rl_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
1097 all_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 ;
1142 init_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
1163 ROOT_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
1195 err_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
1206 exten_table:    db '.cbt'               ; COMBOOT (specific)
1207                 db '.bin'               ; CD boot sector
1208                 db '.com'               ; COMBOOT (same as DOS)
1209                 db '.c32'               ; COM32
1210 exten_table_end:
1211                 dd 0, 0                 ; Need 8 null bytes here