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