source: bootcd/isolinux/syslinux-6.03/core/isolinux.asm

Last change on this file was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

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