- Update to r53061
[reactos.git] / boot / freeldr / bootsect / isoboot.S
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Bootsector for ISO file system
4 * FILE:
5 * PURPOSE:
6 * PROGRAMMERS: ?
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <asm.inc>
12 #include "../freeldr/include/arch/pc/x86common.h"
13
14 .code16
15
16 // ****************************************************************************
17 //
18 // isolinux.asm
19 //
20 // A program to boot Linux kernels off a CD-ROM using the El Torito
21 // boot standard in "no emulation" mode, making the entire filesystem
22 // available. It is based on the SYSLINUX boot loader for MS-DOS
23 // floppies.
24 //
25 // Copyright (C) 1994-2001 H. Peter Anvin
26 //
27 // This program is free software; you can redistribute it and/or modify
28 // it under the terms of the GNU General Public License as published by
29 // the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
30 // USA; either version 2 of the License, or (at your option) any later
31 // version; incorporated herein by reference.
32 //
33 // ****************************************************************************
34 //
35 // THIS FILE IS A MODIFIED VERSION OF ISOLINUX.ASM
36 // MODIFICATION DONE BY MICHAEL K TER LOUW
37 // LAST UPDATED 3-9-2002
38 // SEE "COPYING" FOR INFORMATION ABOUT THE LICENSE THAT APPLIES TO THIS RELEASE
39 //
40 // ****************************************************************************
41 //
42 // This file is a modified version of ISOLINUX.ASM.
43 // Modification done by Eric Kohl
44 // Last update 04-25-2002
45 //
46 // ****************************************************************************
47
48 //#define DEBUG_MESSAGES /* Uncomment to get debugging messages */
49 #ifndef ROS_REGTEST
50 #define WAIT_FOR_KEY
51 #endif
52
53 // ****************************************************************************
54 // BEGIN THE BIOS/CODE/DATA SEGMENT
55 // ****************************************************************************
56 serial_base = HEX(0400) // Base addresses for 4 serial ports (4 words)
57 BIOS_fbm = HEX(0413) // Free Base Memory (kilobytes) (1 word)
58 BIOS_timer = HEX(046C) // Timer ticks (1 word)
59 BIOS_magic = HEX(0472) // BIOS reset magic (1 word)
60 BIOS_vidrows = HEX(0484) // Number of screen rows (1 byte)
61
62 // Memory below this point is reserved for the BIOS and the MBR
63 trackbuf = HEX(1000) // Track buffer goes here (8192 bytes)
64 trackbufsize = 8192 // trackbuf ends at 3000h
65
66 // struct open_file_t
67 file_sector = 0 // Sector pointer (0 = structure free)
68 file_left = 4 // Number of sectors left
69
70 //struct dir_t
71 dir_lba = 0 // Directory start (LBA)
72 dir_len = 4 // Length in bytes
73 dir_clust = 8 // Length in clusters
74
75 #define dir_t_size 12
76 #define open_file_t_size 8
77
78 MAX_OPEN_LG2 = 2 // log2(Max number of open files)
79 MAX_OPEN = 4
80 SECTORSIZE_LG2 = 11 // 2048 bytes/sector (El Torito requirement)
81 SECTORSIZE = 2048
82 retry_count = 6 // How patient are we with the BIOS?
83
84 /******************************************************************************/
85 absolute HEX(5000) // Here we keep our BSS stuff
86
87 resb DriveNo, 1 // CD-ROM BIOS drive number (BYTE)
88 resb DiskError, 1 // Error code for disk I/O (BYTE)
89 resb RetryCount, 1 // Used for disk access retries (BYTE)
90 resb TimeoutCount, 1 // Timeout counter (BYTE)
91 resb ISOFlags, 1 // Flags for ISO directory search (BYTE)
92 resb RootDir, dir_t_size // Root directory (dir_t_size BYTES)
93 resb CurDir, dir_t_size // Current directory (dir_t_size BYTES)
94 resb ISOFileName, 64 // ISO filename canonicalization buffer
95 resb ISOFileNameEnd, 1
96
97 //align open_file_t_size
98 absolute HEX(5060)
99 resb Files, (MAX_OPEN * open_file_t_size)
100
101
102 /******************************************************************************/
103
104
105 start:
106 cli // Disable interrupts
107 xor ax, ax // ax = segment zero
108 mov ss, ax // Initialize stack segment
109 mov sp, offset start // Set up stack
110 mov ds, ax // Initialize other segment registers
111 mov es, ax
112 mov fs, ax
113 mov gs, ax
114 sti // Enable interrupts
115 cld // Increment pointers
116
117 mov cx, 2048 / 4 // Copy the bootsector
118 mov si, HEX(7C00) // from 0000:7C00
119 mov di, HEX(7000) // to 0000:7000
120 rep movsd // copy the program
121
122 ljmp16 0, relocate // jump into relocated code
123
124 relocate:
125 #ifdef DEBUG_MESSAGES
126 // Display the banner and copyright
127 mov si, offset isolinux_banner // si points to hello message
128 call writestr // display the message
129 mov si, offset copyright_str
130 call writestr
131 #endif
132
133 // Make sure the keyboard buffer is empty
134 call pollchar_and_empty
135
136 // Check for MBR on harddisk
137 pusha
138 mov ax, HEX(0201)
139 mov dx, HEX(0080)
140 mov cx, HEX(0001)
141 mov bx, trackbuf
142 int HEX(13)
143 popa
144 jc .boot_cdrom // could not read hdd
145
146 push ax
147 mov ax, word ptr ds:[trackbuf]
148 cmp ax, 0
149 je .boot_cdrom // no boot sector found (hopefully there are no weird bootsectors which begin with 0)
150 pop ax
151
152 #ifdef WAIT_FOR_KEY
153 // Display the 'Press key' message and wait for a maximum of 5 seconds
154 call crlf
155 mov si, offset presskey_msg // si points to 'Press key' message
156 call writestr // display the message
157
158 mov byte ptr ds:[TimeoutCount], 5
159 .next_second:
160 mov eax, ds:[BIOS_timer] // load current tick counter
161 add eax, 19
162
163 .poll_again:
164 call pollchar_and_empty
165 jnz .boot_cdrom
166
167 mov ebx, ds:[BIOS_timer]
168 cmp eax, ebx
169 jnz .poll_again
170
171 mov si, offset dot_msg // print '.'
172 call writestr
173 dec byte ptr ds:[TimeoutCount] // decrement timeout counter
174 jz .boot_harddisk
175 jmp .next_second
176 #endif
177
178 .boot_harddisk:
179 call crlf
180
181 // Boot first harddisk (drive 0x80)
182 mov ax, HEX(0201)
183 mov dx, HEX(0080)
184 mov cx, HEX(0001)
185 mov bx, HEX(7C00)
186 int HEX(13)
187 jnc .go_hd
188 jmp kaboom
189 .go_hd:
190 mov ax, cs
191 mov ds, ax
192 mov es, ax
193 mov fs, ax
194 mov gs, ax
195 mov dx, HEX(0080)
196
197 ljmp16 0, HEX(7C00)
198
199 .boot_cdrom:
200 #ifdef WAIT_FOR_KEY
201 call crlf
202 call crlf
203 #endif
204
205 // Save and display the boot drive number
206 mov byte ptr ds:[DriveNo], dl
207 #ifdef DEBUG_MESSAGES
208 mov si, offset startup_msg
209 call writemsg
210 mov al, dl
211 call writehex2
212 call crlf
213 #endif
214
215 // Now figure out what we're actually doing
216 // Note: use passed-in DL value rather than 7Fh because
217 // at least some BIOSes will get the wrong value otherwise
218 mov ax, HEX(4B01) // Get disk emulation status
219 mov dl, byte ptr ds:[DriveNo]
220 mov si, offset spec_packet
221 int HEX(13)
222 jc spec_query_failed // Shouldn't happen (BIOS bug)
223 mov dl, byte ptr ds:[DriveNo]
224 cmp byte ptr ds:[sp_drive], dl // Should contain the drive number
225 jne spec_query_failed
226
227 #ifdef DEBUG_MESSAGES
228 mov si, offset spec_ok_msg
229 call writemsg
230 mov al, byte ptr ds:[sp_drive]
231 call writehex2
232 call crlf
233 #endif
234
235 found_drive:
236 // Get drive information
237 mov ah, HEX(48)
238 mov dl, byte ptr ds:[DriveNo]
239 mov si, offset drive_params
240 int HEX(13)
241 jnc params_ok
242
243 // mov si, nosecsize_msg No use in reporting this
244 // call writemsg
245
246 params_ok:
247 // Check for the sector size (should be 2048, but
248 // some BIOSes apparently think we're 512-byte media)
249 //
250 // FIX: We need to check what the proper behaviour
251 // is for getlinsec when the BIOS thinks the sector
252 // size is 512!!! For that, we need such a BIOS, though...
253 #ifdef DEBUG_MESSAGES
254 mov si, offset secsize_msg
255 call writemsg
256 mov ax, word ptr ds:[dp_secsize]
257 call writehex4
258 call crlf
259 #endif
260
261
262 //
263 // Clear Files structures
264 //
265 mov di, Files
266 mov cx, (MAX_OPEN*open_file_t_size)/4
267 xor eax, eax
268 rep stosd
269
270 //
271 // Now, we need to sniff out the actual filesystem data structures.
272 // mkisofs gave us a pointer to the primary volume descriptor
273 // (which will be at 16 only for a single-session disk!); from the PVD
274 // we should be able to find the rest of what we need to know.
275 //
276 get_fs_structures:
277 mov eax, 16 // Primary Volume Descriptor (sector 16)
278 mov bx, trackbuf
279 call getonesec
280
281 mov eax, dword ptr ds:[trackbuf+156+2]
282 mov dword ptr ds:[RootDir+dir_lba],eax
283 mov dword ptr ds:[CurDir+dir_lba],eax
284 #ifdef DEBUG_MESSAGES
285 mov si, offset rootloc_msg
286 call writemsg
287 call writehex8
288 call crlf
289 #endif
290
291 mov eax, dword ptr ds:[trackbuf+156+10]
292 mov dword ptr ds:[RootDir+dir_len],eax
293 mov dword ptr ds:[CurDir+dir_len],eax
294 #ifdef DEBUG_MESSAGES
295 mov si, offset rootlen_msg
296 call writemsg
297 call writehex8
298 call crlf
299 #endif
300 add eax,SECTORSIZE-1
301 shr eax,SECTORSIZE_LG2
302 mov dword ptr ds:[RootDir+dir_clust],eax
303 mov dword ptr ds:[CurDir+dir_clust],eax
304 #ifdef DEBUG_MESSAGES
305 mov si, offset rootsect_msg
306 call writemsg
307 call writehex8
308 call crlf
309 #endif
310
311 // Look for the "REACTOS" directory, and if found,
312 // make it the current directory instead of the root
313 // directory.
314 mov di, offset isolinux_dir
315 mov al, 2 // Search for a directory
316 call searchdir_iso
317 jnz .dir_found
318 mov si, offset no_dir_msg
319 call writemsg
320 jmp kaboom
321
322 .dir_found:
323 mov dword ptr ds:[CurDir+dir_len],eax
324 mov eax, dword ptr ds:[si+file_left]
325 mov dword ptr ds:[CurDir+dir_clust],eax
326 xor eax,eax // Free this file pointer entry
327 xchg eax,dword ptr ds:[si+file_sector]
328 mov dword ptr ds:[CurDir+dir_lba],eax
329
330
331 mov di, offset isolinux_bin // di points to Isolinux filename
332 call searchdir // look for the file
333 jnz .isolinux_opened // got the file
334 mov si, offset no_isolinux_msg // si points to error message
335 call writemsg // display the message
336 jmp kaboom // fail boot
337
338 .isolinux_opened:
339 mov di, si // save file pointer
340
341 #ifdef DEBUG_MESSAGES
342 mov si, offset filelen_msg
343 call writemsg
344 call writehex8
345 call crlf
346 #endif
347
348 mov ecx, eax // calculate sector count
349 shr ecx, 11
350 test eax, HEX(7FF)
351 jz .full_sector
352 inc ecx
353 .full_sector:
354
355 #ifdef DEBUG_MESSAGES
356 mov eax, ecx
357 mov si, offset filesect_msg
358 call writemsg
359 call writehex8
360 call crlf
361 #endif
362
363 // use high segment, as some bios can fail, when offset is too big
364 mov bx, FREELDR_BASE / 16 // es = load segment
365 mov es, bx
366 xor ebx, ebx // bx = load offset
367 mov si, di // restore file pointer
368 mov cx, HEX(0FFFF) // load the whole file
369 call getfssec // get the whole file
370
371 #ifdef DEBUG_MESSAGES
372 mov si, offset startldr_msg
373 call writemsg
374 call crlf
375 #endif
376
377 mov dl, byte ptr ds:[DriveNo] // dl = boot drive
378 mov dh, 0 // dh = boot partition
379
380 /* Transfer execution to the bootloader */
381 ljmp16 0, FREELDR_BASE
382
383 //
384 // searchdir:
385 //
386 // Open a file
387 //
388 // On entry:
389 // DS:DI = filename
390 // If successful:
391 // ZF clear
392 // SI = file pointer
393 // DX:AX or EAX = file length in bytes
394 // If unsuccessful
395 // ZF set
396 //
397
398 //
399 // searchdir_iso is a special entry point for ISOLINUX only. In addition
400 // to the above, searchdir_iso passes a file flag mask in AL. This is useful
401 // for searching for directories.
402 //
403 alloc_failure:
404 xor ax,ax // ZF <- 1
405 ret
406
407 searchdir:
408 xor al, al
409 searchdir_iso:
410 mov byte ptr ds:[ISOFlags],al
411 call allocate_file // Temporary file structure for directory
412 jnz alloc_failure
413 push es
414 push ds
415 pop es // ES = DS
416 mov si, offset CurDir
417 cmp byte ptr ds:[di], 92 //'\' // If filename begins with slash
418 jne .not_rooted
419 inc di // Skip leading slash
420 mov si, offset RootDir // Reference root directory instead
421 .not_rooted:
422 mov eax, dword ptr ds:[si+dir_clust]
423 mov dword ptr ds:[bx+file_left],eax
424 mov eax,dword ptr ds:[si+dir_lba]
425 mov dword ptr ds:[bx+file_sector],eax
426 mov edx,dword ptr ds:[si+dir_len]
427
428 .look_for_slash:
429 mov ax,di
430 .scan:
431 mov cl, byte ptr ds:[di]
432 inc di
433 and cl,cl
434 jz .isfile
435 cmp cl, 92 // '\'
436 jne .scan
437 mov byte ptr ds:[di-1], 0 // Terminate at directory name
438 mov cl,2 // Search for directory
439 xchg cl, byte ptr ds:[ISOFlags]
440 push di
441 push cx
442 push offset .resume // Where to "return" to
443 push es
444 .isfile:
445 xchg ax,di
446
447 .getsome:
448 // Get a chunk of the directory
449 mov si,trackbuf
450 pushad
451 xchg bx,si
452 mov cx,1 // load one sector
453 call getfssec
454 popad
455
456 .compare:
457 movzx eax, byte ptr ds:[si] // Length of directory entry
458 cmp al, 33
459 jb .next_sector
460 mov cl, byte ptr ds:[si+25]
461 xor cl, byte ptr ds:[ISOFlags]
462 test cl, HEX(8E) // Unwanted file attributes!
463 jnz .not_file
464 pusha
465 movzx cx, byte ptr ds:[si+32] // File identifier length
466 add si, 33 // File identifier offset
467 call iso_compare_names
468 popa
469 je .success
470 .not_file:
471 sub edx, eax // Decrease bytes left
472 jbe .failure
473 add si, ax // Advance pointer
474
475 .check_overrun:
476 // Did we finish the buffer?
477 cmp si, trackbuf+trackbufsize
478 jb .compare // No, keep going
479
480 jmp .getsome // Get some more directory
481
482 .next_sector:
483 // Advance to the beginning of next sector
484 lea ax, [si+SECTORSIZE-1]
485 and ax, not (SECTORSIZE-1)
486 sub ax, si
487 jmp .not_file // We still need to do length checks
488
489 .failure:
490 #ifdef DEBUG_MESSAGES
491 mov si, offset findfail_msg
492 call writemsg
493 call crlf
494 #endif
495 xor eax, eax // ZF = 1
496 mov dword ptr ds:[bx+file_sector], eax
497 pop es
498 ret
499
500 .success:
501 mov eax, dword ptr ds:[si+2] // Location of extent
502 mov dword ptr ds:[bx+file_sector], eax
503 mov eax, dword ptr ds:[si+10] // Data length
504 push eax
505 add eax, SECTORSIZE-1
506 shr eax, SECTORSIZE_LG2
507 mov dword ptr ds:[bx+file_left], eax
508 pop eax
509 mov edx, eax
510 shr edx, 16
511 and bx, bx // ZF = 0
512 mov si, bx
513 pop es
514 ret
515
516 .resume:
517 // We get here if we were only doing part of a lookup
518 // This relies on the fact that .success returns bx == si
519 xchg edx, eax // Directory length in edx
520 pop cx // Old ISOFlags
521 pop di // Next filename pointer
522
523 // restore the backslash in the filename
524 mov byte ptr ds:[di-1], 92 // '\'
525
526 mov byte ptr ds:[ISOFlags], cl // Restore the flags
527 jz .failure // Did we fail? If so fail for real!
528 jmp .look_for_slash // Otherwise, next level
529
530 //
531 // allocate_file: Allocate a file structure
532 //
533 // If successful:
534 // ZF set
535 // BX = file pointer
536 // In unsuccessful:
537 // ZF clear
538 //
539 allocate_file:
540 push cx
541 mov bx, Files
542 mov cx, MAX_OPEN
543 .check:
544 cmp dword ptr ds:[bx], 0
545 je .found
546 add bx, open_file_t_size // ZF = 0
547 loop .check
548 // ZF = 0 if we fell out of the loop
549 .found:
550 pop cx
551 ret
552
553 //
554 // iso_compare_names:
555 // Compare the names DS:SI and DS:DI and report if they are
556 // equal from an ISO 9660 perspective. SI is the name from
557 // the filesystem; CX indicates its length, and ';' terminates.
558 // DI is expected to end with a null.
559 //
560 // Note: clobbers AX, CX, SI, DI; assumes DS == ES == base segment
561 //
562 iso_compare_names:
563 // First, terminate and canonicalize input filename
564 push di
565 mov di, offset ISOFileName
566 .canon_loop:
567 jcxz .canon_end
568 lodsb
569 dec cx
570 cmp al, ';'
571 je .canon_end
572 and al, al
573 je .canon_end
574 stosb
575 cmp di, offset ISOFileNameEnd-1 // Guard against buffer overrun
576 jb .canon_loop
577 .canon_end:
578 cmp di, ISOFileName
579 jbe .canon_done
580 cmp byte ptr ds:[di-1], '.' // Remove terminal dots
581 jne .canon_done
582 dec di
583 jmp short .canon_end
584 .canon_done:
585 mov byte ptr ds:[di], 0 // Null-terminate string
586 pop di
587 mov si, ISOFileName
588 .compare2:
589 lodsb
590 mov ah, byte ptr ds:[di]
591 inc di
592 and ax, ax
593 jz .success2 // End of string for both
594 and al, al // Is either one end of string?
595 jz .failure2 // If so, failure
596 and ah, ah
597 jz .failure2
598 or ax, HEX(2020) // Convert to lower case
599 cmp al, ah
600 je .compare2
601 .failure2:
602 and ax, ax // ZF = 0 (at least one will be nonzero)
603 .success2:
604 ret
605
606
607
608
609
610
611
612 //
613 // getfssec: Get multiple clusters from a file, given the file pointer.
614 //
615 // On entry:
616 // ES:BX -> Buffer
617 // SI -> File pointer
618 // CX -> Cluster count; 0FFFFh = until end of file
619 // On exit:
620 // SI -> File pointer (or 0 on EOF)
621 // CF = 1 -> Hit EOF
622 //
623 getfssec:
624 cmp cx, word ptr ds:[si+file_left]
625 jna .ok_size
626 mov cx, word ptr ds:[si+file_left]
627
628 .ok_size:
629 mov bp, cx
630 push cx
631 push si
632 mov eax, dword ptr ds:[si+file_sector]
633 call getlinsec
634 xor ecx, ecx
635 pop si
636 pop cx
637
638 add dword ptr ds:[si+file_sector], ecx
639 sub dword ptr ds:[si+file_left], ecx
640 ja .not_eof // CF = 0
641
642 xor ecx, ecx
643 mov dword ptr ds:[si+file_sector], ecx // Mark as unused
644 xor si,si
645 stc
646
647 .not_eof:
648 ret
649
650
651 // INT 13h, AX=4B01h, DL=<passed in value> failed.
652 // Try to scan the entire 80h-FFh from the end.
653 spec_query_failed:
654 mov si, offset spec_err_msg
655 call writemsg
656
657 mov dl, HEX(0FF)
658 .test_loop:
659 pusha
660 mov ax, HEX(4B01)
661 mov si, offset spec_packet
662 mov byte ptr ds:[si], 13 // Size of buffer
663 int HEX(13)
664 popa
665 jc .still_broken
666
667 mov si, offset maybe_msg
668 call writemsg
669 mov al, dl
670 call writehex2
671 call crlf
672
673 cmp byte ptr ds:[sp_drive], dl
674 jne .maybe_broken
675
676 // Okay, good enough...
677 mov si, offset alright_msg
678 call writemsg
679 mov byte ptr ds:[DriveNo], dl
680 .found_drive:
681 jmp found_drive
682
683 // Award BIOS 4.51 apparently passes garbage in sp_drive,
684 // but if this was the drive number originally passed in
685 // DL then consider it "good enough"
686 .maybe_broken:
687 cmp byte ptr ds:[DriveNo], dl
688 je .found_drive
689
690 .still_broken:
691 dec dx
692 cmp dl, HEX(80)
693 jnb .test_loop
694
695 fatal_error:
696 mov si, offset nothing_msg
697 call writemsg
698
699 .norge:
700 jmp .norge
701
702
703
704 // Information message (DS:SI) output
705 // Prefix with "isolinux: "
706 writemsg:
707 push ax
708 push si
709 mov si, offset isolinux_str
710 call writestr
711 pop si
712 call writestr
713 pop ax
714 ret
715
716 //
717 // crlf: Print a newline
718 crlf:
719 mov si, offset crlf_msg
720 // Fall through
721
722 //
723 // writestr: write a null-terminated string to the console, saving
724 // registers on entry.
725 //
726 writestr:
727 pushfd
728 pushad
729 writestr_top:
730 lodsb
731 and al, al
732 jz writestr_end
733 call writechr
734 jmp short writestr_top
735 writestr_end:
736 popad
737 popfd
738 ret
739
740 //
741 // writehex[248]: Write a hex number in (AL, AX, EAX) to the console
742 //
743 writehex2:
744 pushfd
745 pushad
746 shl eax, 24
747 mov cx, 2
748 jmp short writehex_common
749 writehex4:
750 pushfd
751 pushad
752 shl eax, 16
753 mov cx, 4
754 jmp short writehex_common
755 writehex8:
756 pushfd
757 pushad
758 mov cx, 8
759 writehex_common:
760 .loop:
761 rol eax, 4
762 push eax
763 and al, HEX(0F)
764 cmp al, 10
765 jae .high
766 .low:
767 add al, '0'
768 jmp short .ischar
769 .high:
770 add al, 'A'-10
771 .ischar:
772 call writechr
773 pop eax
774 loop .loop
775 popad
776 popfd
777 ret
778
779 //
780 // writechr: Write a character to the screen. There is a more "sophisticated"
781 // version of this in the subsequent code, so we patch the pointer
782 // when appropriate.
783 writechr:
784 pushfd
785 pushad
786 mov ah, HEX(0E)
787 xor bx, bx
788 int HEX(10)
789 popad
790 popfd
791 ret
792
793 //
794 // Get one sector. Convenience entry point.
795 //
796 getonesec:
797 mov bp, 1
798 // Fall through to getlinsec
799
800 //
801 // Get linear sectors - EBIOS LBA addressing, 2048-byte sectors.
802 //
803 // Note that we can't always do this as a single request, because at least
804 // Phoenix BIOSes has a 127-sector limit. To be on the safe side, stick
805 // to 32 sectors (64K) per request.
806 //
807 // Input:
808 // EAX - Linear sector number
809 // ES:BX - Target buffer
810 // BP - Sector count
811 //
812 getlinsec:
813 mov si, offset dapa // Load up the DAPA
814 mov word ptr ds:[si+4], bx
815 mov bx, es
816 mov word ptr ds:[si+6], bx
817 mov dword ptr ds:[si+8], eax
818 .loop2:
819 push bp // Sectors left
820 cmp bp, word ptr ds:[MaxTransfer]
821 jbe .bp_ok
822 mov bp, word ptr ds:[MaxTransfer]
823 .bp_ok:
824 mov word ptr ds:[si+2], bp
825 push si
826 mov dl, byte ptr ds:[DriveNo]
827 mov ah, HEX(42) // Extended Read
828 call xint13
829 pop si
830 pop bp
831 movzx eax,word ptr ds:[si+2] // Sectors we read
832 add dword ptr ds:[si+8], eax // Advance sector pointer
833 sub bp, ax // Sectors left
834 shl ax, SECTORSIZE_LG2-4 // 2048-byte sectors -> segment
835 add word ptr ds:[si+6], ax // Advance buffer pointer
836 and bp, bp
837 jnz .loop2
838 mov eax, dword ptr ds:[si+8] // Next sector
839 ret
840
841 // INT 13h with retry
842 xint13:
843 mov byte ptr ds:[RetryCount], retry_count
844 .try:
845 pushad
846 int HEX(13)
847 jc .error
848 add sp, 8*4 // Clean up stack
849 ret
850 .error:
851 mov byte ptr ds:[DiskError], ah // Save error code
852 popad
853 dec byte ptr ds:[RetryCount]
854 jz .real_error
855 push ax
856 mov al, byte ptr ds:[RetryCount]
857 mov ah, byte ptr ds:[dapa+2] // Sector transfer count
858 cmp al,2 // Only 2 attempts left
859 ja .nodanger
860 mov ah,1 // Drop transfer size to 1
861 jmp short .setsize
862 .nodanger:
863 cmp al, retry_count-2
864 ja .again // First time, just try again
865 shr ah,1 // Otherwise, try to reduce
866 adc ah,0 // the max transfer size, but not to 0
867 .setsize:
868 mov byte ptr ds:[MaxTransfer],ah
869 mov byte ptr ds:[dapa+2],ah
870 .again:
871 pop ax
872 jmp .try
873
874 .real_error:
875 mov si, offset diskerr_msg
876 call writemsg
877 mov al, byte ptr ds:[DiskError]
878 call writehex2
879 mov si, offset ondrive_str
880 call writestr
881 mov al, dl
882 call writehex2
883 call crlf
884 // Fall through to kaboom
885
886 //
887 // kaboom: write a message and bail out. Wait for a user keypress,
888 // then do a hard reboot.
889 //
890 kaboom:
891 mov ax, cs
892 mov ds, ax
893 mov es, ax
894 mov fs, ax
895 mov gs, ax
896 sti
897 mov si, offset err_bootfailed
898 call writestr
899 xor ax, ax // Wait for keypress
900 int HEX(16)
901 cli
902 mov word ptr ds:[BIOS_magic], 0 // Cold reboot
903 ljmp16 HEX(0F000), HEX(0FFF0) // Reset vector address
904
905
906 //
907 // pollchar_and_empty: check if we have an input character pending (ZF = 0) and empty the input buffer afterwards
908 //
909 pollchar_and_empty:
910 pushad
911 mov ah, 1 // Did the user press a key?
912 int HEX(16)
913 jz .end // No, then we're done
914 mov ah, 0 // Otherwise empty the buffer by reading it
915 int HEX(16)
916 .end:
917 popad
918 ret
919
920
921 isolinux_banner:
922 .ascii CR, LF, "Loading IsoBoot...", CR, LF, NUL
923 copyright_str:
924 .ascii " (C) 1994-2002 H. Peter Anvin", CR, LF, NUL
925 presskey_msg:
926 .ascii "Press any key to boot from CD", NUL
927 dot_msg:
928 .ascii ".", NUL
929
930 #ifdef DEBUG_MESSAGES
931 startup_msg:
932 .ascii "Startup, DL = '", NUL
933 spec_ok_msg:
934 .ascii "packet OK, drive = ", NUL
935 secsize_msg:
936 .ascii "size appears to be ", NUL
937 rootloc_msg:
938 .ascii "Root dir loc: ", NUL
939 rootlen_msg:
940 .ascii "Root dir len: ", NUL
941 rootsect_msg:
942 .ascii "Root dir len(sect): ", NUL
943 fileloc_msg:
944 .ascii "SETUPLDR loc: ", NUL
945 filelen_msg:
946 .ascii "SETUPLDR len: ", NUL
947 filesect_msg:
948 .ascii "SETUPLDR len(sect): ", NUL
949 findfail_msg:
950 .ascii "Failed to find file!", NUL
951 startldr_msg:
952 .ascii "Starting SETUPLDR.SYS", NUL
953 #endif
954
955 spec_err_msg:
956 .ascii "Load spec failed, trying wing ...", CR, LF, NUL
957 maybe_msg:
958 .ascii "Found smth at drive = ", NUL
959 alright_msg:
960 .ascii "might be ok, continuing...", CR, LF, NUL
961 nothing_msg:
962 .ascii "Failed locate CD-ROM; boot failed.", CR, LF, NUL
963
964 isolinux_str:
965 .ascii "IsoBoot: ", NUL
966 crlf_msg:
967 .ascii CR, LF, NUL
968 diskerr_msg:
969 .ascii "Disk error ", NUL
970 ondrive_str:
971 .ascii ", drive ", NUL
972
973 err_bootfailed:
974 .ascii CR, LF, "failed..", NUL
975 isolinux_dir:
976 .ascii "\\LOADER", NUL
977 no_dir_msg:
978 .ascii "LOADER dir not found.", CR, LF, NUL
979 isolinux_bin:
980 .ascii "SETUPLDR.SYS", NUL
981 no_isolinux_msg:
982 .ascii "SETUPLDR not found.", CR, LF, NUL
983
984
985 //
986 // El Torito spec packet
987 //
988 .align 8
989 spec_packet:
990 .byte HEX(13) // Size of packet
991 sp_media:
992 .byte 0 // Media type
993 sp_drive:
994 .byte 0 // Drive number
995 sp_controller:
996 .byte 0 // Controller index
997 sp_lba:
998 .long 0 // LBA for emulated disk image
999 sp_devspec:
1000 .word 0 // IDE/SCSI information
1001 sp_buffer:
1002 .word 0 // User-provided buffer
1003 sp_loadseg:
1004 .word 0 // Load segment
1005 sp_sectors:
1006 .word 0 // Sector count
1007 sp_chs:
1008 .byte 0,0,0 // Simulated CHS geometry
1009 sp_dummy:
1010 .byte 0 // Scratch, safe to overwrite
1011
1012 //
1013 // EBIOS drive parameter packet
1014 //
1015 .align 8
1016 drive_params:
1017 .word 30 // Buffer size
1018 dp_flags:
1019 .word 0 // Information flags
1020 dp_cyl:
1021 .long 0 // Physical cylinders
1022 dp_head:
1023 .long 0 // Physical heads
1024 dp_sec:
1025 .long 0 // Physical sectors/track
1026 dp_totalsec:
1027 .long 0,0 // Total sectors
1028 dp_secsize:
1029 .word 0 // Bytes per sector
1030 dp_dpte:
1031 .long 0 // Device Parameter Table
1032 dp_dpi_key:
1033 .word 0 // 0BEDDh if rest valid
1034 dp_dpi_len:
1035 .byte 0 // DPI len
1036 .byte 0
1037 .word 0
1038 dp_bus:
1039 .byte 0,0,0,0 // Host bus type
1040 dp_interface:
1041 .byte 0,0,0,0,0,0,0,0 // Interface type
1042 db_i_path:
1043 .long 0,0 // Interface path
1044 db_d_path:
1045 .long 0,0 // Device path
1046 .byte 0
1047 db_dpi_csum:
1048 .byte 0 // Checksum for DPI info
1049
1050 //
1051 // EBIOS disk address packet
1052 //
1053 .align 8
1054 dapa:
1055 .word 16 // Packet size
1056 .count:
1057 .word 0 // Block count
1058 .off:
1059 .word 0 // Offset of buffer
1060 .seg:
1061 .word 0 // Segment of buffer
1062 .lba:
1063 .long 0 // LBA (LSW)
1064 .long 0 // LBA (MSW)
1065
1066 .align 4
1067 MaxTransfer:
1068 .word 2 //32 // Max sectors per transfer
1069
1070 .org 2046 // Pad to file offset 2046
1071 .word HEX(0aa55) // BootSector signature
1072
1073 .endcode16
1074
1075 END