Annotation of /tags/mkinitrd-6_1_10/isolinux/isolinux.asm
Parent Directory | Revision Log
Revision 922 -
(hide annotations)
(download)
Wed Oct 28 09:51:31 2009 UTC (14 years, 11 months ago) by niro
File size: 41054 byte(s)
Wed Oct 28 09:51:31 2009 UTC (14 years, 11 months ago) by niro
File size: 41054 byte(s)
tagged 'mkinitrd-6_1_10'
1 | niro | 532 | ; -*- fundamental -*- (asm-mode sucks) |
2 | ; $Id: isolinux.asm,v 1.1 2007-09-01 22:44:04 niro Exp $ | ||
3 | ; **************************************************************************** | ||
4 | ; | ||
5 | ; isolinux.asm | ||
6 | ; | ||
7 | ; A program to boot Linux kernels off a CD-ROM using the El Torito | ||
8 | ; boot standard in "no emulation" mode, making the entire filesystem | ||
9 | ; available. It is based on the SYSLINUX boot loader for MS-DOS | ||
10 | ; floppies. | ||
11 | ; | ||
12 | ; Copyright (C) 1994-2005 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 "macros.inc" | ||
24 | %include "config.inc" | ||
25 | %include "kernel.inc" | ||
26 | %include "bios.inc" | ||
27 | %include "tracers.inc" | ||
28 | %include "layout.inc" | ||
29 | |||
30 | ; | ||
31 | ; Some semi-configurable constants... change on your own risk. | ||
32 | ; | ||
33 | my_id equ isolinux_id | ||
34 | FILENAME_MAX_LG2 equ 8 ; log2(Max filename size Including final null) | ||
35 | FILENAME_MAX equ (1 << FILENAME_MAX_LG2) | ||
36 | NULLFILE equ 0 ; Zero byte == null file name | ||
37 | NULLOFFSET equ 0 ; Position in which to look | ||
38 | retry_count equ 6 ; How patient are we with the BIOS? | ||
39 | %assign HIGHMEM_SLOP 128*1024 ; Avoid this much memory near the top | ||
40 | MAX_OPEN_LG2 equ 6 ; log2(Max number of open files) | ||
41 | MAX_OPEN equ (1 << MAX_OPEN_LG2) | ||
42 | SECTOR_SHIFT equ 11 ; 2048 bytes/sector (El Torito requirement) | ||
43 | SECTOR_SIZE equ (1 << SECTOR_SHIFT) | ||
44 | |||
45 | ; | ||
46 | ; This is what we need to do when idle | ||
47 | ; | ||
48 | %macro RESET_IDLE 0 | ||
49 | ; Nothing | ||
50 | %endmacro | ||
51 | %macro DO_IDLE 0 | ||
52 | ; Nothing | ||
53 | %endmacro | ||
54 | |||
55 | ; | ||
56 | ; The following structure is used for "virtual kernels"; i.e. LILO-style | ||
57 | ; option labels. The options we permit here are `kernel' and `append | ||
58 | ; Since there is no room in the bottom 64K for all of these, we | ||
59 | ; stick them at vk_seg:0000 and copy them down before we need them. | ||
60 | ; | ||
61 | struc vkernel | ||
62 | vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!** | ||
63 | vk_rname: resb FILENAME_MAX ; Real name | ||
64 | vk_appendlen: resw 1 | ||
65 | alignb 4 | ||
66 | vk_append: resb max_cmd_len+1 ; Command line | ||
67 | alignb 4 | ||
68 | vk_end: equ $ ; Should be <= vk_size | ||
69 | endstruc | ||
70 | |||
71 | ; | ||
72 | ; Segment assignments in the bottom 640K | ||
73 | ; 0000h - main code/data segment (and BIOS segment) | ||
74 | ; | ||
75 | real_mode_seg equ 3000h | ||
76 | vk_seg equ 2000h ; Virtual kernels | ||
77 | xfer_buf_seg equ 1000h ; Bounce buffer for I/O to high mem | ||
78 | comboot_seg equ real_mode_seg ; COMBOOT image loading zone | ||
79 | |||
80 | ; | ||
81 | ; File structure. This holds the information for each currently open file. | ||
82 | ; | ||
83 | struc open_file_t | ||
84 | file_sector resd 1 ; Sector pointer (0 = structure free) | ||
85 | file_left resd 1 ; Number of sectors left | ||
86 | endstruc | ||
87 | |||
88 | %ifndef DEPEND | ||
89 | %if (open_file_t_size & (open_file_t_size-1)) | ||
90 | %error "open_file_t is not a power of 2" | ||
91 | %endif | ||
92 | %endif | ||
93 | |||
94 | struc dir_t | ||
95 | dir_lba resd 1 ; Directory start (LBA) | ||
96 | dir_len resd 1 ; Length in bytes | ||
97 | dir_clust resd 1 ; Length in clusters | ||
98 | endstruc | ||
99 | |||
100 | ; --------------------------------------------------------------------------- | ||
101 | ; BEGIN CODE | ||
102 | ; --------------------------------------------------------------------------- | ||
103 | |||
104 | ; | ||
105 | ; Memory below this point is reserved for the BIOS and the MBR | ||
106 | ; | ||
107 | section .earlybss | ||
108 | trackbufsize equ 8192 | ||
109 | trackbuf resb trackbufsize ; Track buffer goes here | ||
110 | getcbuf resb trackbufsize | ||
111 | ; ends at 4800h | ||
112 | |||
113 | section .bss | ||
114 | alignb 4 | ||
115 | ISOFileName resb 64 ; ISO filename canonicalization buffer | ||
116 | ISOFileNameEnd equ $ | ||
117 | CurDir resb dir_t_size ; Current directory | ||
118 | RootDir resb dir_t_size ; Root directory | ||
119 | FirstSecSum resd 1 ; Checksum of bytes 64-2048 | ||
120 | ImageDwords resd 1 ; isolinux.bin size, dwords | ||
121 | InitStack resd 1 ; Initial stack pointer (SS:SP) | ||
122 | DiskSys resw 1 ; Last INT 13h call | ||
123 | ImageSectors resw 1 ; isolinux.bin size, sectors | ||
124 | DiskError resb 1 ; Error code for disk I/O | ||
125 | DriveNo resb 1 ; CD-ROM BIOS drive number | ||
126 | ISOFlags resb 1 ; Flags for ISO directory search | ||
127 | RetryCount resb 1 ; Used for disk access retries | ||
128 | |||
129 | _spec_start equ $ | ||
130 | |||
131 | ; | ||
132 | ; El Torito spec packet | ||
133 | ; | ||
134 | |||
135 | alignb 8 | ||
136 | spec_packet: resb 1 ; Size of packet | ||
137 | sp_media: resb 1 ; Media type | ||
138 | sp_drive: resb 1 ; Drive number | ||
139 | sp_controller: resb 1 ; Controller index | ||
140 | sp_lba: resd 1 ; LBA for emulated disk image | ||
141 | sp_devspec: resw 1 ; IDE/SCSI information | ||
142 | sp_buffer: resw 1 ; User-provided buffer | ||
143 | sp_loadseg: resw 1 ; Load segment | ||
144 | sp_sectors: resw 1 ; Sector count | ||
145 | sp_chs: resb 3 ; Simulated CHS geometry | ||
146 | sp_dummy: resb 1 ; Scratch, safe to overwrite | ||
147 | |||
148 | ; | ||
149 | ; EBIOS drive parameter packet | ||
150 | ; | ||
151 | alignb 8 | ||
152 | drive_params: resw 1 ; Buffer size | ||
153 | dp_flags: resw 1 ; Information flags | ||
154 | dp_cyl: resd 1 ; Physical cylinders | ||
155 | dp_head: resd 1 ; Physical heads | ||
156 | dp_sec: resd 1 ; Physical sectors/track | ||
157 | dp_totalsec: resd 2 ; Total sectors | ||
158 | dp_secsize: resw 1 ; Bytes per sector | ||
159 | dp_dpte: resd 1 ; Device Parameter Table | ||
160 | dp_dpi_key: resw 1 ; 0BEDDh if rest valid | ||
161 | dp_dpi_len: resb 1 ; DPI len | ||
162 | resb 1 | ||
163 | resw 1 | ||
164 | dp_bus: resb 4 ; Host bus type | ||
165 | dp_interface: resb 8 ; Interface type | ||
166 | db_i_path: resd 2 ; Interface path | ||
167 | db_d_path: resd 2 ; Device path | ||
168 | resb 1 | ||
169 | db_dpi_csum: resb 1 ; Checksum for DPI info | ||
170 | |||
171 | ; | ||
172 | ; EBIOS disk address packet | ||
173 | ; | ||
174 | alignb 8 | ||
175 | dapa: resw 1 ; Packet size | ||
176 | .count: resw 1 ; Block count | ||
177 | .off: resw 1 ; Offset of buffer | ||
178 | .seg: resw 1 ; Segment of buffer | ||
179 | .lba: resd 2 ; LBA (LSW, MSW) | ||
180 | |||
181 | ; | ||
182 | ; Spec packet for disk image emulation | ||
183 | ; | ||
184 | alignb 8 | ||
185 | dspec_packet: resb 1 ; Size of packet | ||
186 | dsp_media: resb 1 ; Media type | ||
187 | dsp_drive: resb 1 ; Drive number | ||
188 | dsp_controller: resb 1 ; Controller index | ||
189 | dsp_lba: resd 1 ; LBA for emulated disk image | ||
190 | dsp_devspec: resw 1 ; IDE/SCSI information | ||
191 | dsp_buffer: resw 1 ; User-provided buffer | ||
192 | dsp_loadseg: resw 1 ; Load segment | ||
193 | dsp_sectors: resw 1 ; Sector count | ||
194 | dsp_chs: resb 3 ; Simulated CHS geometry | ||
195 | dsp_dummy: resb 1 ; Scratch, safe to overwrite | ||
196 | |||
197 | alignb 4 | ||
198 | _spec_end equ $ | ||
199 | _spec_len equ _spec_end - _spec_start | ||
200 | |||
201 | alignb open_file_t_size | ||
202 | Files resb MAX_OPEN*open_file_t_size | ||
203 | |||
204 | ; | ||
205 | ; Constants for the xfer_buf_seg | ||
206 | ; | ||
207 | ; The xfer_buf_seg is also used to store message file buffers. We | ||
208 | ; need two trackbuffers (text and graphics), plus a work buffer | ||
209 | ; for the graphics decompressor. | ||
210 | ; | ||
211 | xbs_textbuf equ 0 ; Also hard-coded, do not change | ||
212 | xbs_vgabuf equ trackbufsize | ||
213 | xbs_vgatmpbuf equ 2*trackbufsize | ||
214 | |||
215 | section .text | ||
216 | ;; | ||
217 | ;; Primary entry point. Because BIOSes are buggy, we only load the first | ||
218 | ;; CD-ROM sector (2K) of the file, so the number one priority is actually | ||
219 | ;; loading the rest. | ||
220 | ;; | ||
221 | StackBuf equ $ | ||
222 | |||
223 | bootsec equ $ | ||
224 | |||
225 | _start: ; Far jump makes sure we canonicalize the address | ||
226 | cli | ||
227 | jmp 0:_start1 | ||
228 | times 8-($-$$) nop ; Pad to file offset 8 | ||
229 | |||
230 | ; This table hopefully gets filled in by mkisofs using the | ||
231 | ; -boot-info-table option. If not, the values in this | ||
232 | ; table are default values that we can use to get us what | ||
233 | ; we need, at least under a certain set of assumptions. | ||
234 | bi_pvd: dd 16 ; LBA of primary volume descriptor | ||
235 | bi_file: dd 0 ; LBA of boot file | ||
236 | bi_length: dd 0xdeadbeef ; Length of boot file | ||
237 | bi_csum: dd 0xdeadbeef ; Checksum of boot file | ||
238 | bi_reserved: times 10 dd 0xdeadbeef ; Reserved | ||
239 | |||
240 | _start1: mov [cs:InitStack],sp ; Save initial stack pointer | ||
241 | mov [cs:InitStack+2],ss | ||
242 | xor ax,ax | ||
243 | mov ss,ax | ||
244 | mov sp,StackBuf ; Set up stack | ||
245 | mov ds,ax | ||
246 | mov es,ax | ||
247 | mov fs,ax | ||
248 | mov gs,ax | ||
249 | sti | ||
250 | |||
251 | cld | ||
252 | ; Show signs of life | ||
253 | mov si,syslinux_banner | ||
254 | call writestr | ||
255 | %ifdef DEBUG_MESSAGES | ||
256 | mov si,copyright_str | ||
257 | call writestr | ||
258 | %endif | ||
259 | |||
260 | ; | ||
261 | ; Before modifying any memory, get the checksum of bytes | ||
262 | ; 64-2048 | ||
263 | ; | ||
264 | initial_csum: xor edi,edi | ||
265 | mov si,_start1 | ||
266 | mov cx,(SECTOR_SIZE-64) >> 2 | ||
267 | .loop: lodsd | ||
268 | add edi,eax | ||
269 | loop .loop | ||
270 | mov [FirstSecSum],edi | ||
271 | |||
272 | mov [DriveNo],dl | ||
273 | %ifdef DEBUG_MESSAGES | ||
274 | mov si,startup_msg | ||
275 | call writemsg | ||
276 | mov al,dl | ||
277 | call writehex2 | ||
278 | call crlf | ||
279 | %endif | ||
280 | ; | ||
281 | ; Initialize spec packet buffers | ||
282 | ; | ||
283 | mov di,_spec_start | ||
284 | mov cx,_spec_len >> 2 | ||
285 | xor eax,eax | ||
286 | rep stosd | ||
287 | |||
288 | ; Initialize length field of the various packets | ||
289 | mov byte [spec_packet],13h | ||
290 | mov byte [drive_params],30 | ||
291 | mov byte [dapa],16 | ||
292 | mov byte [dspec_packet],13h | ||
293 | |||
294 | ; Other nonzero fields | ||
295 | inc word [dsp_sectors] | ||
296 | |||
297 | ; Now figure out what we're actually doing | ||
298 | ; Note: use passed-in DL value rather than 7Fh because | ||
299 | ; at least some BIOSes will get the wrong value otherwise | ||
300 | mov ax,4B01h ; Get disk emulation status | ||
301 | mov dl,[DriveNo] | ||
302 | mov si,spec_packet | ||
303 | int 13h | ||
304 | jc award_hack ; changed for BrokenAwardHack | ||
305 | mov dl,[DriveNo] | ||
306 | cmp [sp_drive],dl ; Should contain the drive number | ||
307 | jne spec_query_failed | ||
308 | |||
309 | %ifdef DEBUG_MESSAGES | ||
310 | mov si,spec_ok_msg | ||
311 | call writemsg | ||
312 | mov al,byte [sp_drive] | ||
313 | call writehex2 | ||
314 | call crlf | ||
315 | %endif | ||
316 | |||
317 | found_drive: | ||
318 | ; Alright, we have found the drive. Now, try to find the | ||
319 | ; boot file itself. If we have a boot info table, life is | ||
320 | ; good; if not, we have to make some assumptions, and try | ||
321 | ; to figure things out ourselves. In particular, the | ||
322 | ; assumptions we have to make are: | ||
323 | ; - single session only | ||
324 | ; - only one boot entry (no menu or other alternatives) | ||
325 | |||
326 | cmp dword [bi_file],0 ; Address of code to load | ||
327 | jne found_file ; Boot info table present :) | ||
328 | |||
329 | %ifdef DEBUG_MESSAGES | ||
330 | mov si,noinfotable_msg | ||
331 | call writemsg | ||
332 | %endif | ||
333 | |||
334 | ; No such luck. See if the the spec packet contained one. | ||
335 | mov eax,[sp_lba] | ||
336 | and eax,eax | ||
337 | jz set_file ; Good enough | ||
338 | |||
339 | %ifdef DEBUG_MESSAGES | ||
340 | mov si,noinfoinspec_msg | ||
341 | call writemsg | ||
342 | %endif | ||
343 | |||
344 | ; No such luck. Get the Boot Record Volume, assuming single | ||
345 | ; session disk, and that we're the first entry in the chain | ||
346 | mov eax,17 ; Assumed address of BRV | ||
347 | mov bx,trackbuf | ||
348 | call getonesec | ||
349 | |||
350 | mov eax,[trackbuf+47h] ; Get boot catalog address | ||
351 | mov bx,trackbuf | ||
352 | call getonesec ; Get boot catalog | ||
353 | |||
354 | mov eax,[trackbuf+28h] ; First boot entry | ||
355 | ; And hope and pray this is us... | ||
356 | |||
357 | ; Some BIOSes apparently have limitations on the size | ||
358 | ; that may be loaded (despite the El Torito spec being very | ||
359 | ; clear on the fact that it must all be loaded.) Therefore, | ||
360 | ; we load it ourselves, and *bleep* the BIOS. | ||
361 | |||
362 | set_file: | ||
363 | mov [bi_file],eax | ||
364 | |||
365 | found_file: | ||
366 | ; Set up boot file sizes | ||
367 | mov eax,[bi_length] | ||
368 | sub eax,SECTOR_SIZE-3 | ||
369 | shr eax,2 ; bytes->dwords | ||
370 | mov [ImageDwords],eax ; boot file dwords | ||
371 | add eax,(2047 >> 2) | ||
372 | shr eax,9 ; dwords->sectors | ||
373 | mov [ImageSectors],ax ; boot file sectors | ||
374 | |||
375 | mov eax,[bi_file] ; Address of code to load | ||
376 | inc eax ; Don't reload bootstrap code | ||
377 | %ifdef DEBUG_MESSAGES | ||
378 | mov si,offset_msg | ||
379 | call writemsg | ||
380 | call writehex8 | ||
381 | call crlf | ||
382 | %endif | ||
383 | |||
384 | ; Just in case some BIOSes have problems with | ||
385 | ; segment wraparound, use the normalized address | ||
386 | mov bx,((7C00h+2048) >> 4) | ||
387 | mov es,bx | ||
388 | xor bx,bx | ||
389 | mov bp,[ImageSectors] | ||
390 | %ifdef DEBUG_MESSAGES | ||
391 | push ax | ||
392 | mov si,size_msg | ||
393 | call writemsg | ||
394 | mov ax,bp | ||
395 | call writehex4 | ||
396 | call crlf | ||
397 | pop ax | ||
398 | %endif | ||
399 | call getlinsec | ||
400 | |||
401 | push ds | ||
402 | pop es | ||
403 | |||
404 | %ifdef DEBUG_MESSAGES | ||
405 | mov si,loaded_msg | ||
406 | call writemsg | ||
407 | %endif | ||
408 | |||
409 | ; Verify the checksum on the loaded image. | ||
410 | verify_image: | ||
411 | mov si,7C00h+2048 | ||
412 | mov bx,es | ||
413 | mov ecx,[ImageDwords] | ||
414 | mov edi,[FirstSecSum] ; First sector checksum | ||
415 | .loop es lodsd | ||
416 | add edi,eax | ||
417 | dec ecx | ||
418 | jz .done | ||
419 | and si,si | ||
420 | jnz .loop | ||
421 | ; SI wrapped around, advance ES | ||
422 | add bx,1000h | ||
423 | mov es,bx | ||
424 | jmp short .loop | ||
425 | .done: mov ax,ds | ||
426 | mov es,ax | ||
427 | cmp [bi_csum],edi | ||
428 | je integrity_ok | ||
429 | |||
430 | mov si,checkerr_msg | ||
431 | call writemsg | ||
432 | jmp kaboom | ||
433 | |||
434 | integrity_ok: | ||
435 | %ifdef DEBUG_MESSAGES | ||
436 | mov si,allread_msg | ||
437 | call writemsg | ||
438 | %endif | ||
439 | jmp all_read ; Jump to main code | ||
440 | |||
441 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
442 | ;; Start of BrokenAwardHack --- 10-nov-2002 Knut_Petersen@t-online.de | ||
443 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
444 | ;; | ||
445 | ;; There is a problem with certain versions of the AWARD BIOS ... | ||
446 | ;; the boot sector will be loaded and executed correctly, but, because the | ||
447 | ;; int 13 vector points to the wrong code in the BIOS, every attempt to | ||
448 | ;; load the spec packet will fail. We scan for the equivalent of | ||
449 | ;; | ||
450 | ;; mov ax,0201h | ||
451 | ;; mov bx,7c00h | ||
452 | ;; mov cx,0006h | ||
453 | ;; mov dx,0180h | ||
454 | ;; pushf | ||
455 | ;; call <direct far> | ||
456 | ;; | ||
457 | ;; and use <direct far> as the new vector for int 13. The code above is | ||
458 | ;; used to load the boot code into ram, and there should be no reason | ||
459 | ;; for anybody to change it now or in the future. There are no opcodes | ||
460 | ;; that use encodings relativ to IP, so scanning is easy. If we find the | ||
461 | ;; code above in the BIOS code we can be pretty sure to run on a machine | ||
462 | ;; with an broken AWARD BIOS ... | ||
463 | ;; | ||
464 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
465 | ;; | ||
466 | %ifdef DEBUG_MESSAGES ;; | ||
467 | ;; | ||
468 | award_notice db "Trying BrokenAwardHack first ...",CR,LF,0 ;; | ||
469 | award_not_orig db "BAH: Original Int 13 vector : ",0 ;; | ||
470 | award_not_new db "BAH: Int 13 vector changed to : ",0 ;; | ||
471 | award_not_succ db "BAH: SUCCESS",CR,LF,0 ;; | ||
472 | award_not_fail db "BAH: FAILURE" ;; | ||
473 | award_not_crlf db CR,LF,0 ;; | ||
474 | ;; | ||
475 | %endif ;; | ||
476 | ;; | ||
477 | award_oldint13 dd 0 ;; | ||
478 | award_string db 0b8h,1,2,0bbh,0,7ch,0b9h,6,0,0bah,80h,1,09ch,09ah ;; | ||
479 | ;; | ||
480 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
481 | award_hack: mov si,spec_err_msg ; Moved to this place from | ||
482 | call writemsg ; spec_query_faild | ||
483 | ; | ||
484 | %ifdef DEBUG_MESSAGES ; | ||
485 | ; | ||
486 | mov si,award_notice ; display our plan | ||
487 | call writemsg ; | ||
488 | mov si,award_not_orig ; display original int 13 | ||
489 | call writemsg ; vector | ||
490 | %endif ; | ||
491 | mov eax,[13h*4] ; | ||
492 | mov [award_oldint13],eax ; | ||
493 | ; | ||
494 | %ifdef DEBUG_MESSAGES ; | ||
495 | ; | ||
496 | call writehex8 ; | ||
497 | mov si,award_not_crlf ; | ||
498 | call writestr ; | ||
499 | %endif ; | ||
500 | push es ; save ES | ||
501 | mov ax,0f000h ; ES = BIOS Seg | ||
502 | mov es,ax ; | ||
503 | cld ; | ||
504 | xor di,di ; start at ES:DI = f000:0 | ||
505 | award_loop: push di ; save DI | ||
506 | mov si,award_string ; scan for award_string | ||
507 | mov cx,7 ; length of award_string = 7dw | ||
508 | repz cmpsw ; compare | ||
509 | pop di ; restore DI | ||
510 | jcxz award_found ; jmp if found | ||
511 | inc di ; not found, inc di | ||
512 | jno award_loop ; | ||
513 | ; | ||
514 | award_failed: pop es ; No, not this way :-(( | ||
515 | award_fail2: ; | ||
516 | ; | ||
517 | %ifdef DEBUG_MESSAGES ; | ||
518 | ; | ||
519 | mov si,award_not_fail ; display failure ... | ||
520 | call writemsg ; | ||
521 | %endif ; | ||
522 | mov eax,[award_oldint13] ; restore the original int | ||
523 | or eax,eax ; 13 vector if there is one | ||
524 | jz spec_query_failed ; and try other workarounds | ||
525 | mov [13h*4],eax ; | ||
526 | jmp spec_query_failed ; | ||
527 | ; | ||
528 | award_found: mov eax,[es:di+0eh] ; load possible int 13 addr | ||
529 | pop es ; restore ES | ||
530 | ; | ||
531 | cmp eax,[award_oldint13] ; give up if this is the | ||
532 | jz award_failed ; active int 13 vector, | ||
533 | mov [13h*4],eax ; otherwise change 0:13h*4 | ||
534 | ; | ||
535 | ; | ||
536 | %ifdef DEBUG_MESSAGES ; | ||
537 | ; | ||
538 | push eax ; display message and | ||
539 | mov si,award_not_new ; new vector address | ||
540 | call writemsg ; | ||
541 | pop eax ; | ||
542 | call writehex8 ; | ||
543 | mov si,award_not_crlf ; | ||
544 | call writestr ; | ||
545 | %endif ; | ||
546 | mov ax,4B01h ; try to read the spec packet | ||
547 | mov dl,[DriveNo] ; now ... it should not fail | ||
548 | mov si,spec_packet ; any longer | ||
549 | int 13h ; | ||
550 | jc award_fail2 ; | ||
551 | ; | ||
552 | %ifdef DEBUG_MESSAGES ; | ||
553 | ; | ||
554 | mov si,award_not_succ ; display our SUCCESS | ||
555 | call writemsg ; | ||
556 | %endif ; | ||
557 | jmp found_drive ; and leave error recovery code | ||
558 | ; | ||
559 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
560 | ;; End of BrokenAwardHack ---- 10-nov-2002 Knut_Petersen@t-online.de | ||
561 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||
562 | |||
563 | |||
564 | ; INT 13h, AX=4B01h, DL=<passed in value> failed. | ||
565 | ; Try to scan the entire 80h-FFh from the end. | ||
566 | |||
567 | spec_query_failed: | ||
568 | |||
569 | ; some code moved to BrokenAwardHack | ||
570 | |||
571 | mov dl,0FFh | ||
572 | .test_loop: pusha | ||
573 | mov ax,4B01h | ||
574 | mov si,spec_packet | ||
575 | mov byte [si],13 ; Size of buffer | ||
576 | int 13h | ||
577 | popa | ||
578 | jc .still_broken | ||
579 | |||
580 | mov si,maybe_msg | ||
581 | call writemsg | ||
582 | mov al,dl | ||
583 | call writehex2 | ||
584 | call crlf | ||
585 | |||
586 | cmp byte [sp_drive],dl | ||
587 | jne .maybe_broken | ||
588 | |||
589 | ; Okay, good enough... | ||
590 | mov si,alright_msg | ||
591 | call writemsg | ||
592 | mov [DriveNo],dl | ||
593 | .found_drive: jmp found_drive | ||
594 | |||
595 | ; Award BIOS 4.51 apparently passes garbage in sp_drive, | ||
596 | ; but if this was the drive number originally passed in | ||
597 | ; DL then consider it "good enough" | ||
598 | .maybe_broken: | ||
599 | cmp byte [DriveNo],dl | ||
600 | je .found_drive | ||
601 | |||
602 | .still_broken: dec dx | ||
603 | cmp dl, 80h | ||
604 | jnb .test_loop | ||
605 | |||
606 | ; No spec packet anywhere. Some particularly pathetic | ||
607 | ; BIOSes apparently don't even implement function | ||
608 | ; 4B01h, so we can't query a spec packet no matter | ||
609 | ; what. If we got a drive number in DL, then try to | ||
610 | ; use it, and if it works, then well... | ||
611 | mov dl,[DriveNo] | ||
612 | cmp dl,81h ; Should be 81-FF at least | ||
613 | jb fatal_error ; If not, it's hopeless | ||
614 | |||
615 | ; Write a warning to indicate we're on *very* thin ice now | ||
616 | mov si,nospec_msg | ||
617 | call writemsg | ||
618 | mov al,dl | ||
619 | call writehex2 | ||
620 | call crlf | ||
621 | mov si,trysbm_msg | ||
622 | call writemsg | ||
623 | jmp .found_drive ; Pray that this works... | ||
624 | |||
625 | fatal_error: | ||
626 | mov si,nothing_msg | ||
627 | call writemsg | ||
628 | |||
629 | .norge: jmp short .norge | ||
630 | |||
631 | ; Information message (DS:SI) output | ||
632 | ; Prefix with "isolinux: " | ||
633 | ; | ||
634 | writemsg: push ax | ||
635 | push si | ||
636 | mov si,isolinux_str | ||
637 | call writestr | ||
638 | pop si | ||
639 | call writestr | ||
640 | pop ax | ||
641 | ret | ||
642 | |||
643 | ; | ||
644 | ; Write a character to the screen. There is a more "sophisticated" | ||
645 | ; version of this in the subsequent code, so we patch the pointer | ||
646 | ; when appropriate. | ||
647 | ; | ||
648 | |||
649 | writechr: | ||
650 | jmp near writechr_simple ; 3-byte jump | ||
651 | |||
652 | writechr_simple: | ||
653 | pushfd | ||
654 | pushad | ||
655 | mov ah,0Eh | ||
656 | xor bx,bx | ||
657 | int 10h | ||
658 | popad | ||
659 | popfd | ||
660 | ret | ||
661 | |||
662 | ; | ||
663 | ; Get one sector. Convenience entry point. | ||
664 | ; | ||
665 | getonesec: | ||
666 | mov bp,1 | ||
667 | ; Fall through to getlinsec | ||
668 | |||
669 | ; | ||
670 | ; Get linear sectors - EBIOS LBA addressing, 2048-byte sectors. | ||
671 | ; | ||
672 | ; Note that we can't always do this as a single request, because at least | ||
673 | ; Phoenix BIOSes has a 127-sector limit. To be on the safe side, stick | ||
674 | ; to 32 sectors (64K) per request. | ||
675 | ; | ||
676 | ; Input: | ||
677 | ; EAX - Linear sector number | ||
678 | ; ES:BX - Target buffer | ||
679 | ; BP - Sector count | ||
680 | ; | ||
681 | getlinsec: | ||
682 | mov si,dapa ; Load up the DAPA | ||
683 | mov [si+4],bx | ||
684 | mov bx,es | ||
685 | mov [si+6],bx | ||
686 | mov [si+8],eax | ||
687 | .loop: | ||
688 | push bp ; Sectors left | ||
689 | cmp bp,[MaxTransfer] | ||
690 | jbe .bp_ok | ||
691 | mov bp,[MaxTransfer] | ||
692 | .bp_ok: | ||
693 | mov [si+2],bp | ||
694 | push si | ||
695 | mov dl,[DriveNo] | ||
696 | mov ah,42h ; Extended Read | ||
697 | call xint13 | ||
698 | pop si | ||
699 | pop bp | ||
700 | movzx eax,word [si+2] ; Sectors we read | ||
701 | add [si+8],eax ; Advance sector pointer | ||
702 | sub bp,ax ; Sectors left | ||
703 | shl ax,SECTOR_SHIFT-4 ; 2048-byte sectors -> segment | ||
704 | add [si+6],ax ; Advance buffer pointer | ||
705 | and bp,bp | ||
706 | jnz .loop | ||
707 | mov eax,[si+8] ; Next sector | ||
708 | ret | ||
709 | |||
710 | ; INT 13h with retry | ||
711 | xint13: mov byte [RetryCount],retry_count | ||
712 | .try: pushad | ||
713 | int 13h | ||
714 | jc .error | ||
715 | add sp,byte 8*4 ; Clean up stack | ||
716 | ret | ||
717 | .error: | ||
718 | mov [DiskError],ah ; Save error code | ||
719 | popad | ||
720 | mov [DiskSys],ax ; Save system call number | ||
721 | dec byte [RetryCount] | ||
722 | jz .real_error | ||
723 | push ax | ||
724 | mov al,[RetryCount] | ||
725 | mov ah,[dapa+2] ; Sector transfer count | ||
726 | cmp al,2 ; Only 2 attempts left | ||
727 | ja .nodanger | ||
728 | mov ah,1 ; Drop transfer size to 1 | ||
729 | jmp short .setsize | ||
730 | .nodanger: | ||
731 | cmp al,retry_count-2 | ||
732 | ja .again ; First time, just try again | ||
733 | shr ah,1 ; Otherwise, try to reduce | ||
734 | adc ah,0 ; the max transfer size, but not to 0 | ||
735 | .setsize: | ||
736 | mov [MaxTransfer],ah | ||
737 | mov [dapa+2],ah | ||
738 | .again: | ||
739 | pop ax | ||
740 | jmp .try | ||
741 | |||
742 | .real_error: mov si,diskerr_msg | ||
743 | call writemsg | ||
744 | mov al,[DiskError] | ||
745 | call writehex2 | ||
746 | mov si,oncall_str | ||
747 | call writestr | ||
748 | mov ax,[DiskSys] | ||
749 | call writehex4 | ||
750 | mov si,ondrive_str | ||
751 | call writestr | ||
752 | mov al,dl | ||
753 | call writehex2 | ||
754 | call crlf | ||
755 | ; Fall through to kaboom | ||
756 | |||
757 | ; | ||
758 | ; kaboom: write a message and bail out. Wait for a user keypress, | ||
759 | ; then do a hard reboot. | ||
760 | ; | ||
761 | kaboom: | ||
762 | lss sp,[cs:StackPtr] | ||
763 | mov ax,cs | ||
764 | mov ds,ax | ||
765 | mov es,ax | ||
766 | mov fs,ax | ||
767 | mov gs,ax | ||
768 | sti | ||
769 | mov si,err_bootfailed | ||
770 | call cwritestr | ||
771 | call getchar | ||
772 | cli | ||
773 | mov word [BIOS_magic],0 ; Cold reboot | ||
774 | jmp 0F000h:0FFF0h ; Reset vector address | ||
775 | |||
776 | ; ----------------------------------------------------------------------------- | ||
777 | ; Common modules needed in the first sector | ||
778 | ; ----------------------------------------------------------------------------- | ||
779 | |||
780 | %include "writestr.inc" ; String output | ||
781 | writestr equ cwritestr | ||
782 | %include "writehex.inc" ; Hexadecimal output | ||
783 | |||
784 | ; ----------------------------------------------------------------------------- | ||
785 | ; Data that needs to be in the first sector | ||
786 | ; ----------------------------------------------------------------------------- | ||
787 | |||
788 | syslinux_banner db CR, LF, 'ISOLINUX ', version_str, ' ', date, ' ', 0 | ||
789 | copyright_str db ' Copyright (C) 1994-', year, ' H. Peter Anvin' | ||
790 | db CR, LF, 0 | ||
791 | isolinux_str db 'isolinux: ', 0 | ||
792 | %ifdef DEBUG_MESSAGES | ||
793 | startup_msg: db 'Starting up, DL = ', 0 | ||
794 | spec_ok_msg: db 'Loaded spec packet OK, drive = ', 0 | ||
795 | secsize_msg: db 'Sector size appears to be ', 0 | ||
796 | offset_msg: db 'Loading main image from LBA = ', 0 | ||
797 | size_msg: db 'Sectors to load = ', 0 | ||
798 | loaded_msg: db 'Loaded boot image, verifying...', CR, LF, 0 | ||
799 | verify_msg: db 'Image checksum verified.', CR, LF, 0 | ||
800 | allread_msg db 'Main image read, jumping to main code...', CR, LF, 0 | ||
801 | %endif | ||
802 | noinfotable_msg db 'No boot info table, assuming single session disk...', CR, LF, 0 | ||
803 | noinfoinspec_msg db 'Spec packet missing LBA information, trying to wing it...', CR, LF, 0 | ||
804 | spec_err_msg: db 'Loading spec packet failed, trying to wing it...', CR, LF, 0 | ||
805 | maybe_msg: db 'Found something at drive = ', 0 | ||
806 | alright_msg: db 'Looks like it might be right, continuing...', CR, LF, 0 | ||
807 | nospec_msg db 'Extremely broken BIOS detected, last ditch attempt with drive = ', 0 | ||
808 | nothing_msg: db 'Failed to locate CD-ROM device; boot failed.', CR, LF | ||
809 | trysbm_msg db 'See http://syslinux.zytor.com/sbm for more information.', CR, LF, 0 | ||
810 | diskerr_msg: db 'Disk error ', 0 | ||
811 | oncall_str: db ', AX = ',0 | ||
812 | ondrive_str: db ', drive ', 0 | ||
813 | checkerr_msg: db 'Image checksum error, sorry...', CR, LF, 0 | ||
814 | |||
815 | err_bootfailed db CR, LF, 'Boot failed: press a key to retry...' | ||
816 | bailmsg equ err_bootfailed | ||
817 | crlf_msg db CR, LF | ||
818 | null_msg db 0 | ||
819 | |||
820 | alignb 4, db 0 | ||
821 | StackPtr dw StackBuf, 0 ; SS:SP for stack reset | ||
822 | MaxTransfer dw 32 ; Max sectors per transfer | ||
823 | |||
824 | rl_checkpt equ $ ; Must be <= 800h | ||
825 | |||
826 | rl_checkpt_off equ ($-$$) | ||
827 | ;%ifndef DEPEND | ||
828 | ;%if rl_checkpt_off > 0x800 | ||
829 | ;%error "Sector 0 overflow" | ||
830 | ;%endif | ||
831 | ;%endif | ||
832 | |||
833 | ; ---------------------------------------------------------------------------- | ||
834 | ; End of code and data that have to be in the first sector | ||
835 | ; ---------------------------------------------------------------------------- | ||
836 | |||
837 | all_read: | ||
838 | ; | ||
839 | ; Initialize screen (if we're using one) | ||
840 | ; | ||
841 | ; Now set up screen parameters | ||
842 | call adjust_screen | ||
843 | |||
844 | ; Wipe the F-key area | ||
845 | mov al,NULLFILE | ||
846 | mov di,FKeyName | ||
847 | mov cx,10*(1 << FILENAME_MAX_LG2) | ||
848 | rep stosb | ||
849 | |||
850 | ; Patch the writechr routine to point to the full code | ||
851 | mov word [writechr+1], writechr_full-(writechr+3) | ||
852 | |||
853 | ; Tell the user we got this far... | ||
854 | %ifndef DEBUG_MESSAGES ; Gets messy with debugging on | ||
855 | mov si,copyright_str | ||
856 | call writestr | ||
857 | %endif | ||
858 | |||
859 | ; Test tracers | ||
860 | TRACER 'T' | ||
861 | TRACER '>' | ||
862 | |||
863 | ; | ||
864 | ; Common initialization code | ||
865 | ; | ||
866 | %include "init.inc" | ||
867 | %include "cpuinit.inc" | ||
868 | |||
869 | ; | ||
870 | ; Now we're all set to start with our *real* business. First load the | ||
871 | ; configuration file (if any) and parse it. | ||
872 | ; | ||
873 | ; In previous versions I avoided using 32-bit registers because of a | ||
874 | ; rumour some BIOSes clobbered the upper half of 32-bit registers at | ||
875 | ; random. I figure, though, that if there are any of those still left | ||
876 | ; they probably won't be trying to install Linux on them... | ||
877 | ; | ||
878 | ; The code is still ripe with 16-bitisms, though. Not worth the hassle | ||
879 | ; to take'm out. In fact, we may want to put them back if we're going | ||
880 | ; to boot ELKS at some point. | ||
881 | ; | ||
882 | |||
883 | ; | ||
884 | ; Now, we need to sniff out the actual filesystem data structures. | ||
885 | ; mkisofs gave us a pointer to the primary volume descriptor | ||
886 | ; (which will be at 16 only for a single-session disk!); from the PVD | ||
887 | ; we should be able to find the rest of what we need to know. | ||
888 | ; | ||
889 | get_fs_structures: | ||
890 | mov eax,[bi_pvd] | ||
891 | mov bx,trackbuf | ||
892 | call getonesec | ||
893 | |||
894 | mov eax,[trackbuf+156+2] | ||
895 | mov [RootDir+dir_lba],eax | ||
896 | mov [CurDir+dir_lba],eax | ||
897 | %ifdef DEBUG_MESSAGES | ||
898 | mov si,dbg_rootdir_msg | ||
899 | call writemsg | ||
900 | call writehex8 | ||
901 | call crlf | ||
902 | %endif | ||
903 | mov eax,[trackbuf+156+10] | ||
904 | mov [RootDir+dir_len],eax | ||
905 | mov [CurDir+dir_len],eax | ||
906 | add eax,SECTOR_SIZE-1 | ||
907 | shr eax,SECTOR_SHIFT | ||
908 | mov [RootDir+dir_clust],eax | ||
909 | mov [CurDir+dir_clust],eax | ||
910 | |||
911 | ; Look for an isolinux directory, and if found, | ||
912 | ; make it the current directory instead of the root | ||
913 | ; directory. | ||
914 | mov di,boot_dir ; Search for /boot/isolinux | ||
915 | mov al,02h | ||
916 | call searchdir_iso | ||
917 | jnz .found_dir | ||
918 | mov di,isolinux_dir | ||
919 | mov al,02h ; Search for /isolinux | ||
920 | call searchdir_iso | ||
921 | jz .no_isolinux_dir | ||
922 | .found_dir: | ||
923 | mov [CurDir+dir_len],eax | ||
924 | mov eax,[si+file_left] | ||
925 | mov [CurDir+dir_clust],eax | ||
926 | xor eax,eax ; Free this file pointer entry | ||
927 | xchg eax,[si+file_sector] | ||
928 | mov [CurDir+dir_lba],eax | ||
929 | %ifdef DEBUG_MESSAGES | ||
930 | push si | ||
931 | mov si,dbg_isodir_msg | ||
932 | call writemsg | ||
933 | pop si | ||
934 | call writehex8 | ||
935 | call crlf | ||
936 | %endif | ||
937 | .no_isolinux_dir: | ||
938 | |||
939 | ; | ||
940 | ; Locate the configuration file | ||
941 | ; | ||
942 | load_config: | ||
943 | %ifdef DEBUG_MESSAGES | ||
944 | mov si,dbg_config_msg | ||
945 | call writemsg | ||
946 | %endif | ||
947 | |||
948 | mov di,isolinux_cfg | ||
949 | call open | ||
950 | jz no_config_file ; Not found or empty | ||
951 | |||
952 | %ifdef DEBUG_MESSAGES | ||
953 | mov si,dbg_configok_msg | ||
954 | call writemsg | ||
955 | %endif | ||
956 | |||
957 | ; | ||
958 | ; Now we have the config file open. Parse the config file and | ||
959 | ; run the user interface. | ||
960 | ; | ||
961 | %include "ui.inc" | ||
962 | |||
963 | ; | ||
964 | ; Linux kernel loading code is common. | ||
965 | ; | ||
966 | %include "runkernel.inc" | ||
967 | |||
968 | ; | ||
969 | ; COMBOOT-loading code | ||
970 | ; | ||
971 | %include "comboot.inc" | ||
972 | %include "com32.inc" | ||
973 | %include "cmdline.inc" | ||
974 | |||
975 | ; | ||
976 | ; Boot sector loading code | ||
977 | ; | ||
978 | %include "bootsect.inc" | ||
979 | |||
980 | ; | ||
981 | ; Enable disk emulation. The kind of disk we emulate is dependent on the size of | ||
982 | ; the file: 1200K, 1440K or 2880K floppy, otherwise harddisk. | ||
983 | ; | ||
984 | is_disk_image: | ||
985 | TRACER CR | ||
986 | TRACER LF | ||
987 | TRACER 'D' | ||
988 | TRACER ':' | ||
989 | |||
990 | shl edx,16 | ||
991 | mov dx,ax ; Set EDX <- file size | ||
992 | mov di,img_table | ||
993 | mov cx,img_table_count | ||
994 | mov eax,[si+file_sector] ; Starting LBA of file | ||
995 | mov [dsp_lba],eax ; Location of file | ||
996 | mov byte [dsp_drive], 0 ; 00h floppy, 80h hard disk | ||
997 | .search_table: | ||
998 | TRACER 't' | ||
999 | mov eax,[di+4] | ||
1000 | cmp edx,[di] | ||
1001 | je .type_found | ||
1002 | add di,8 | ||
1003 | loop .search_table | ||
1004 | |||
1005 | ; Hard disk image. Need to examine the partition table | ||
1006 | ; in order to deduce the C/H/S geometry. Sigh. | ||
1007 | .hard_disk_image: | ||
1008 | TRACER 'h' | ||
1009 | cmp edx,512 | ||
1010 | jb .bad_image | ||
1011 | |||
1012 | mov bx,trackbuf | ||
1013 | mov cx,1 ; Load 1 sector | ||
1014 | call getfssec | ||
1015 | |||
1016 | cmp word [trackbuf+510],0aa55h ; Boot signature | ||
1017 | jne .bad_image ; Image not bootable | ||
1018 | |||
1019 | mov cx,4 ; 4 partition entries | ||
1020 | mov di,trackbuf+446 ; Start of partition table | ||
1021 | |||
1022 | xor ax,ax ; Highest sector(al) head(ah) | ||
1023 | |||
1024 | .part_scan: | ||
1025 | cmp byte [di+4], 0 | ||
1026 | jz .part_loop | ||
1027 | lea si,[di+1] | ||
1028 | call .hs_check | ||
1029 | add si,byte 4 | ||
1030 | call .hs_check | ||
1031 | .part_loop: | ||
1032 | add di,byte 16 | ||
1033 | loop .part_scan | ||
1034 | |||
1035 | push eax ; H/S | ||
1036 | push edx ; File size | ||
1037 | mov bl,ah | ||
1038 | xor bh,bh | ||
1039 | inc bx ; # of heads in BX | ||
1040 | xor ah,ah ; # of sectors in AX | ||
1041 | cwde ; EAX[31:16] <- 0 | ||
1042 | mul bx | ||
1043 | shl eax,9 ; Convert to bytes | ||
1044 | ; Now eax contains the number of bytes per cylinder | ||
1045 | pop ebx ; File size | ||
1046 | xor edx,edx | ||
1047 | div ebx | ||
1048 | and edx,edx | ||
1049 | jz .no_remainder | ||
1050 | inc eax ; Fractional cylinder... | ||
1051 | ; Now (e)ax contains the number of cylinders | ||
1052 | .no_remainder: cmp eax,1024 | ||
1053 | jna .ok_cyl | ||
1054 | mov ax,1024 ; Max possible # | ||
1055 | .ok_cyl: dec ax ; Convert to max cylinder no | ||
1056 | pop ebx ; S(bl) H(bh) | ||
1057 | shl ah,6 | ||
1058 | or bl,ah | ||
1059 | xchg ax,bx | ||
1060 | shl eax,16 | ||
1061 | mov ah,bl | ||
1062 | mov al,4 ; Hard disk boot | ||
1063 | mov byte [dsp_drive], 80h ; Drive 80h = hard disk | ||
1064 | |||
1065 | .type_found: | ||
1066 | TRACER 'T' | ||
1067 | mov bl,[sp_media] | ||
1068 | and bl,0F0h ; Copy controller info bits | ||
1069 | or al,bl | ||
1070 | mov [dsp_media],al ; Emulation type | ||
1071 | shr eax,8 | ||
1072 | mov [dsp_chs],eax ; C/H/S geometry | ||
1073 | mov ax,[sp_devspec] ; Copy device spec | ||
1074 | mov [dsp_devspec],ax | ||
1075 | mov al,[sp_controller] ; Copy controller index | ||
1076 | mov [dsp_controller],al | ||
1077 | |||
1078 | TRACER 'V' | ||
1079 | call vgaclearmode ; Reset video | ||
1080 | |||
1081 | mov ax,4C00h ; Enable emulation and boot | ||
1082 | mov si,dspec_packet | ||
1083 | mov dl,[DriveNo] | ||
1084 | lss sp,[InitStack] | ||
1085 | TRACER 'X' | ||
1086 | |||
1087 | int 13h | ||
1088 | |||
1089 | ; If this returns, we have problems | ||
1090 | .bad_image: | ||
1091 | mov si,err_disk_image | ||
1092 | call cwritestr | ||
1093 | jmp enter_command | ||
1094 | |||
1095 | ; | ||
1096 | ; Look for the highest seen H/S geometry | ||
1097 | ; We compute cylinders separately | ||
1098 | ; | ||
1099 | .hs_check: | ||
1100 | mov bl,[si] ; Head # | ||
1101 | cmp bl,ah | ||
1102 | jna .done_track | ||
1103 | mov ah,bl ; New highest head # | ||
1104 | .done_track: mov bl,[si+1] | ||
1105 | and bl,3Fh ; Sector # | ||
1106 | cmp bl,al | ||
1107 | jna .done_sector | ||
1108 | mov al,bl | ||
1109 | .done_sector: ret | ||
1110 | |||
1111 | ; | ||
1112 | ; Boot a specified local disk. AX specifies the BIOS disk number; or | ||
1113 | ; 0xFFFF in case we should execute INT 18h ("next device.") | ||
1114 | ; | ||
1115 | local_boot: | ||
1116 | call vgaclearmode | ||
1117 | lss sp,[cs:Stack] ; Restore stack pointer | ||
1118 | xor dx,dx | ||
1119 | mov ds,dx | ||
1120 | mov es,dx | ||
1121 | mov fs,dx | ||
1122 | mov gs,dx | ||
1123 | mov si,localboot_msg | ||
1124 | call writestr | ||
1125 | cmp ax,-1 | ||
1126 | je .int18 | ||
1127 | |||
1128 | ; Load boot sector from the specified BIOS device and jump to it. | ||
1129 | mov dl,al | ||
1130 | xor dh,dh | ||
1131 | push dx | ||
1132 | xor ax,ax ; Reset drive | ||
1133 | call xint13 | ||
1134 | mov ax,0201h ; Read one sector | ||
1135 | mov cx,0001h ; C/H/S = 0/0/1 (first sector) | ||
1136 | mov bx,trackbuf | ||
1137 | call xint13 | ||
1138 | pop dx | ||
1139 | cli ; Abandon hope, ye who enter here | ||
1140 | mov si,trackbuf | ||
1141 | mov di,07C00h | ||
1142 | mov cx,512 ; Probably overkill, but should be safe | ||
1143 | rep movsd | ||
1144 | lss sp,[cs:InitStack] | ||
1145 | jmp 0:07C00h ; Jump to new boot sector | ||
1146 | |||
1147 | .int18: | ||
1148 | int 18h ; Hope this does the right thing... | ||
1149 | jmp kaboom ; If we returned, oh boy... | ||
1150 | |||
1151 | ; | ||
1152 | ; Abort loading code | ||
1153 | ; | ||
1154 | %include "abort.inc" | ||
1155 | |||
1156 | ; | ||
1157 | ; searchdir: | ||
1158 | ; | ||
1159 | ; Open a file | ||
1160 | ; | ||
1161 | ; On entry: | ||
1162 | ; DS:DI = filename | ||
1163 | ; If successful: | ||
1164 | ; ZF clear | ||
1165 | ; SI = file pointer | ||
1166 | ; DX:AX or EAX = file length in bytes | ||
1167 | ; If unsuccessful | ||
1168 | ; ZF set | ||
1169 | ; | ||
1170 | ; Assumes CS == DS == ES, and trashes BX and CX. | ||
1171 | ; | ||
1172 | ; searchdir_iso is a special entry point for ISOLINUX only. In addition | ||
1173 | ; to the above, searchdir_iso passes a file flag mask in AL. This is useful | ||
1174 | ; for searching for directories. | ||
1175 | ; | ||
1176 | alloc_failure: | ||
1177 | xor ax,ax ; ZF <- 1 | ||
1178 | ret | ||
1179 | |||
1180 | searchdir: | ||
1181 | xor al,al | ||
1182 | searchdir_iso: | ||
1183 | mov [ISOFlags],al | ||
1184 | TRACER 'S' | ||
1185 | call allocate_file ; Temporary file structure for directory | ||
1186 | jnz alloc_failure | ||
1187 | push es | ||
1188 | push ds | ||
1189 | pop es ; ES = DS | ||
1190 | mov si,CurDir | ||
1191 | cmp byte [di],'/' ; If filename begins with slash | ||
1192 | jne .not_rooted | ||
1193 | inc di ; Skip leading slash | ||
1194 | mov si,RootDir ; Reference root directory instead | ||
1195 | .not_rooted: | ||
1196 | mov eax,[si+dir_clust] | ||
1197 | mov [bx+file_left],eax | ||
1198 | mov eax,[si+dir_lba] | ||
1199 | mov [bx+file_sector],eax | ||
1200 | mov edx,[si+dir_len] | ||
1201 | |||
1202 | .look_for_slash: | ||
1203 | mov ax,di | ||
1204 | .scan: | ||
1205 | mov cl,[di] | ||
1206 | inc di | ||
1207 | and cl,cl | ||
1208 | jz .isfile | ||
1209 | cmp cl,'/' | ||
1210 | jne .scan | ||
1211 | mov [di-1],byte 0 ; Terminate at directory name | ||
1212 | mov cl,02h ; Search for directory | ||
1213 | xchg cl,[ISOFlags] | ||
1214 | |||
1215 | push di ; Save these... | ||
1216 | push cx | ||
1217 | |||
1218 | ; Create recursion stack frame... | ||
1219 | push word .resume ; Where to "return" to | ||
1220 | push es | ||
1221 | .isfile: xchg ax,di | ||
1222 | |||
1223 | .getsome: | ||
1224 | ; Get a chunk of the directory | ||
1225 | ; This relies on the fact that ISOLINUX doesn't change SI | ||
1226 | mov si,trackbuf | ||
1227 | TRACER 'g' | ||
1228 | pushad | ||
1229 | xchg bx,si | ||
1230 | mov cx,[BufSafe] | ||
1231 | call getfssec | ||
1232 | popad | ||
1233 | |||
1234 | .compare: | ||
1235 | movzx eax,byte [si] ; Length of directory entry | ||
1236 | cmp al,33 | ||
1237 | jb .next_sector | ||
1238 | TRACER 'c' | ||
1239 | mov cl,[si+25] | ||
1240 | xor cl,[ISOFlags] | ||
1241 | test cl, byte 8Eh ; Unwanted file attributes! | ||
1242 | jnz .not_file | ||
1243 | pusha | ||
1244 | movzx cx,byte [si+32] ; File identifier length | ||
1245 | add si,byte 33 ; File identifier offset | ||
1246 | TRACER 'i' | ||
1247 | call iso_compare_names | ||
1248 | popa | ||
1249 | je .success | ||
1250 | .not_file: | ||
1251 | sub edx,eax ; Decrease bytes left | ||
1252 | jbe .failure | ||
1253 | add si,ax ; Advance pointer | ||
1254 | |||
1255 | .check_overrun: | ||
1256 | ; Did we finish the buffer? | ||
1257 | cmp si,trackbuf+trackbufsize | ||
1258 | jb .compare ; No, keep going | ||
1259 | |||
1260 | jmp short .getsome ; Get some more directory | ||
1261 | |||
1262 | .next_sector: | ||
1263 | ; Advance to the beginning of next sector | ||
1264 | lea ax,[si+SECTOR_SIZE-1] | ||
1265 | and ax,~(SECTOR_SIZE-1) | ||
1266 | sub ax,si | ||
1267 | jmp short .not_file ; We still need to do length checks | ||
1268 | |||
1269 | .failure: xor eax,eax ; ZF = 1 | ||
1270 | mov [bx+file_sector],eax | ||
1271 | pop es | ||
1272 | ret | ||
1273 | |||
1274 | .success: | ||
1275 | mov eax,[si+2] ; Location of extent | ||
1276 | mov [bx+file_sector],eax | ||
1277 | mov eax,[si+10] ; Data length | ||
1278 | push eax | ||
1279 | add eax,SECTOR_SIZE-1 | ||
1280 | shr eax,SECTOR_SHIFT | ||
1281 | mov [bx+file_left],eax | ||
1282 | pop eax | ||
1283 | mov edx,eax | ||
1284 | shr edx,16 | ||
1285 | and bx,bx ; ZF = 0 | ||
1286 | mov si,bx | ||
1287 | pop es | ||
1288 | ret | ||
1289 | |||
1290 | .resume: ; We get here if we were only doing part of a lookup | ||
1291 | ; This relies on the fact that .success returns bx == si | ||
1292 | xchg edx,eax ; Directory length in edx | ||
1293 | pop cx ; Old ISOFlags | ||
1294 | pop di ; Next filename pointer | ||
1295 | mov byte [di-1], '/' ; Restore slash | ||
1296 | mov [ISOFlags],cl ; Restore the flags | ||
1297 | jz .failure ; Did we fail? If so fail for real! | ||
1298 | jmp .look_for_slash ; Otherwise, next level | ||
1299 | |||
1300 | ; | ||
1301 | ; allocate_file: Allocate a file structure | ||
1302 | ; | ||
1303 | ; If successful: | ||
1304 | ; ZF set | ||
1305 | ; BX = file pointer | ||
1306 | ; In unsuccessful: | ||
1307 | ; ZF clear | ||
1308 | ; | ||
1309 | allocate_file: | ||
1310 | TRACER 'a' | ||
1311 | push cx | ||
1312 | mov bx,Files | ||
1313 | mov cx,MAX_OPEN | ||
1314 | .check: cmp dword [bx], byte 0 | ||
1315 | je .found | ||
1316 | add bx,open_file_t_size ; ZF = 0 | ||
1317 | loop .check | ||
1318 | ; ZF = 0 if we fell out of the loop | ||
1319 | .found: pop cx | ||
1320 | ret | ||
1321 | |||
1322 | ; | ||
1323 | ; iso_compare_names: | ||
1324 | ; Compare the names DS:SI and DS:DI and report if they are | ||
1325 | ; equal from an ISO 9660 perspective. SI is the name from | ||
1326 | ; the filesystem; CX indicates its length, and ';' terminates. | ||
1327 | ; DI is expected to end with a null. | ||
1328 | ; | ||
1329 | ; Note: clobbers AX, CX, SI, DI; assumes DS == ES == base segment | ||
1330 | ; | ||
1331 | |||
1332 | iso_compare_names: | ||
1333 | ; First, terminate and canonicalize input filename | ||
1334 | push di | ||
1335 | mov di,ISOFileName | ||
1336 | .canon_loop: jcxz .canon_end | ||
1337 | lodsb | ||
1338 | dec cx | ||
1339 | cmp al,';' | ||
1340 | je .canon_end | ||
1341 | and al,al | ||
1342 | je .canon_end | ||
1343 | stosb | ||
1344 | cmp di,ISOFileNameEnd-1 ; Guard against buffer overrun | ||
1345 | jb .canon_loop | ||
1346 | .canon_end: | ||
1347 | cmp di,ISOFileName | ||
1348 | jbe .canon_done | ||
1349 | cmp byte [di-1],'.' ; Remove terminal dots | ||
1350 | jne .canon_done | ||
1351 | dec di | ||
1352 | jmp short .canon_end | ||
1353 | .canon_done: | ||
1354 | mov [di],byte 0 ; Null-terminate string | ||
1355 | pop di | ||
1356 | mov si,ISOFileName | ||
1357 | .compare: | ||
1358 | lodsb | ||
1359 | mov ah,[di] | ||
1360 | inc di | ||
1361 | and ax,ax | ||
1362 | jz .success ; End of string for both | ||
1363 | and al,al ; Is either one end of string? | ||
1364 | jz .failure ; If so, failure | ||
1365 | and ah,ah | ||
1366 | jz .failure | ||
1367 | or ax,2020h ; Convert to lower case | ||
1368 | cmp al,ah | ||
1369 | je .compare | ||
1370 | .failure: and ax,ax ; ZF = 0 (at least one will be nonzero) | ||
1371 | .success: ret | ||
1372 | |||
1373 | ; | ||
1374 | ; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed | ||
1375 | ; to by ES:DI; ends on encountering any whitespace. | ||
1376 | ; | ||
1377 | ; This verifies that a filename is < FILENAME_MAX characters, | ||
1378 | ; doesn't contain whitespace, zero-pads the output buffer, | ||
1379 | ; and removes trailing dots and redundant slashes, | ||
1380 | ; so "repe cmpsb" can do a compare, and the | ||
1381 | ; path-searching routine gets a bit of an easier job. | ||
1382 | ; | ||
1383 | mangle_name: | ||
1384 | push bx | ||
1385 | xor ax,ax | ||
1386 | mov cx,FILENAME_MAX-1 | ||
1387 | mov bx,di | ||
1388 | |||
1389 | .mn_loop: | ||
1390 | lodsb | ||
1391 | cmp al,' ' ; If control or space, end | ||
1392 | jna .mn_end | ||
1393 | cmp al,ah ; Repeated slash? | ||
1394 | je .mn_skip | ||
1395 | xor ah,ah | ||
1396 | cmp al,'/' | ||
1397 | jne .mn_ok | ||
1398 | mov ah,al | ||
1399 | .mn_ok stosb | ||
1400 | .mn_skip: loop .mn_loop | ||
1401 | .mn_end: | ||
1402 | cmp bx,di ; At the beginning of the buffer? | ||
1403 | jbe .mn_zero | ||
1404 | cmp byte [di-1],'.' ; Terminal dot? | ||
1405 | je .mn_kill | ||
1406 | cmp byte [di-1],'/' ; Terminal slash? | ||
1407 | jne .mn_zero | ||
1408 | .mn_kill: dec di ; If so, remove it | ||
1409 | inc cx | ||
1410 | jmp short .mn_end | ||
1411 | .mn_zero: | ||
1412 | inc cx ; At least one null byte | ||
1413 | xor ax,ax ; Zero-fill name | ||
1414 | rep stosb | ||
1415 | pop bx | ||
1416 | ret ; Done | ||
1417 | |||
1418 | ; | ||
1419 | ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled | ||
1420 | ; filename to the conventional representation. This is needed | ||
1421 | ; for the BOOT_IMAGE= parameter for the kernel. | ||
1422 | ; NOTE: A 13-byte buffer is mandatory, even if the string is | ||
1423 | ; known to be shorter. | ||
1424 | ; | ||
1425 | ; DS:SI -> input mangled file name | ||
1426 | ; ES:DI -> output buffer | ||
1427 | ; | ||
1428 | ; On return, DI points to the first byte after the output name, | ||
1429 | ; which is set to a null byte. | ||
1430 | ; | ||
1431 | unmangle_name: call strcpy | ||
1432 | dec di ; Point to final null byte | ||
1433 | ret | ||
1434 | |||
1435 | ; | ||
1436 | ; getfssec: Get multiple clusters from a file, given the file pointer. | ||
1437 | ; | ||
1438 | ; On entry: | ||
1439 | ; ES:BX -> Buffer | ||
1440 | ; SI -> File pointer | ||
1441 | ; CX -> Cluster count | ||
1442 | ; On exit: | ||
1443 | ; SI -> File pointer (or 0 on EOF) | ||
1444 | ; CF = 1 -> Hit EOF | ||
1445 | ; | ||
1446 | getfssec: | ||
1447 | TRACER 'F' | ||
1448 | |||
1449 | push ds | ||
1450 | push cs | ||
1451 | pop ds ; DS <- CS | ||
1452 | |||
1453 | movzx ecx,cx | ||
1454 | cmp ecx,[si+file_left] | ||
1455 | jna .ok_size | ||
1456 | mov ecx,[si+file_left] | ||
1457 | .ok_size: | ||
1458 | |||
1459 | mov bp,cx | ||
1460 | push cx | ||
1461 | push si | ||
1462 | mov eax,[si+file_sector] | ||
1463 | TRACER 'l' | ||
1464 | call getlinsec | ||
1465 | xor ecx,ecx | ||
1466 | pop si | ||
1467 | pop cx | ||
1468 | |||
1469 | add [si+file_sector],ecx | ||
1470 | sub [si+file_left],ecx | ||
1471 | ja .not_eof ; CF = 0 | ||
1472 | |||
1473 | xor ecx,ecx | ||
1474 | mov [si+file_sector],ecx ; Mark as unused | ||
1475 | xor si,si | ||
1476 | stc | ||
1477 | |||
1478 | .not_eof: | ||
1479 | pop ds | ||
1480 | TRACER 'f' | ||
1481 | ret | ||
1482 | |||
1483 | ; ----------------------------------------------------------------------------- | ||
1484 | ; Common modules | ||
1485 | ; ----------------------------------------------------------------------------- | ||
1486 | |||
1487 | %include "getc.inc" ; getc et al | ||
1488 | %include "conio.inc" ; Console I/O | ||
1489 | %include "parseconfig.inc" ; High-level config file handling | ||
1490 | %include "parsecmd.inc" ; Low-level config file handling | ||
1491 | %include "bcopy32.inc" ; 32-bit bcopy | ||
1492 | %include "loadhigh.inc" ; Load a file into high memory | ||
1493 | %include "font.inc" ; VGA font stuff | ||
1494 | %include "graphics.inc" ; VGA graphics | ||
1495 | %include "highmem.inc" ; High memory sizing | ||
1496 | %include "strcpy.inc" ; strcpy() | ||
1497 | %include "rawcon.inc" ; Console I/O w/o using the console functions | ||
1498 | |||
1499 | ; ----------------------------------------------------------------------------- | ||
1500 | ; Begin data section | ||
1501 | ; ----------------------------------------------------------------------------- | ||
1502 | |||
1503 | section .data | ||
1504 | |||
1505 | boot_prompt db 'boot: ', 0 | ||
1506 | wipe_char db BS, ' ', BS, 0 | ||
1507 | err_notfound db 'Could not find kernel image: ',0 | ||
1508 | err_notkernel db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0 | ||
1509 | err_noram db 'It appears your computer has less than ' | ||
1510 | asciidec dosram_k | ||
1511 | db 'K of low ("DOS")' | ||
1512 | db CR, LF | ||
1513 | db 'RAM. Linux needs at least this amount to boot. If you get' | ||
1514 | db CR, LF | ||
1515 | db 'this message in error, hold down the Ctrl key while' | ||
1516 | db CR, LF | ||
1517 | db 'booting, and I will take your word for it.', CR, LF, 0 | ||
1518 | err_badcfg db 'Unknown keyword in config file.', CR, LF, 0 | ||
1519 | err_noparm db 'Missing parameter in config file.', CR, LF, 0 | ||
1520 | err_noinitrd db CR, LF, 'Could not find ramdisk image: ', 0 | ||
1521 | err_nohighmem db 'Not enough memory to load specified kernel.', CR, LF, 0 | ||
1522 | err_highload db CR, LF, 'Kernel transfer failure.', CR, LF, 0 | ||
1523 | err_oldkernel db 'Cannot load a ramdisk with an old kernel image.' | ||
1524 | db CR, LF, 0 | ||
1525 | err_notdos db ': attempted DOS system call', CR, LF, 0 | ||
1526 | err_comlarge db 'COMBOOT image too large.', CR, LF, 0 | ||
1527 | err_bssimage db 'BSS images not supported.', CR, LF, 0 | ||
1528 | err_a20 db CR, LF, 'A20 gate not responding!', CR, LF, 0 | ||
1529 | notfound_msg db 'not found', CR, LF, 0 | ||
1530 | localboot_msg db 'Booting from local disk...', CR, LF, 0 | ||
1531 | cmdline_msg db 'Command line: ', CR, LF, 0 | ||
1532 | ready_msg db 'Ready.', CR, LF, 0 | ||
1533 | trying_msg db 'Trying to load: ', 0 | ||
1534 | crlfloading_msg db CR, LF ; Fall through | ||
1535 | loading_msg db 'Loading ', 0 | ||
1536 | dotdot_msg db '.' | ||
1537 | dot_msg db '.', 0 | ||
1538 | fourbs_msg db BS, BS, BS, BS, 0 | ||
1539 | aborted_msg db ' aborted.', CR, LF, 0 | ||
1540 | crff_msg db CR, FF, 0 | ||
1541 | default_str db 'default', 0 | ||
1542 | default_len equ ($-default_str) | ||
1543 | boot_dir db '/boot' ; /boot/isolinux | ||
1544 | isolinux_dir db '/isolinux', 0 | ||
1545 | ConfigName equ $ | ||
1546 | isolinux_cfg db 'isolinux.cfg', 0 | ||
1547 | err_disk_image db 'Cannot load disk image (invalid file)?', CR, LF, 0 | ||
1548 | |||
1549 | %ifdef DEBUG_MESSAGES | ||
1550 | dbg_rootdir_msg db 'Root directory at LBA = ', 0 | ||
1551 | dbg_isodir_msg db 'isolinux directory at LBA = ', 0 | ||
1552 | dbg_config_msg db 'About to load config file...', CR, LF, 0 | ||
1553 | dbg_configok_msg db 'Configuration file opened...', CR, LF, 0 | ||
1554 | %endif | ||
1555 | ; | ||
1556 | ; Command line options we'd like to take a look at | ||
1557 | ; | ||
1558 | ; mem= and vga= are handled as normal 32-bit integer values | ||
1559 | initrd_cmd db 'initrd=' | ||
1560 | initrd_cmd_len equ 7 | ||
1561 | |||
1562 | ; | ||
1563 | ; Config file keyword table | ||
1564 | ; | ||
1565 | %include "keywords.inc" | ||
1566 | |||
1567 | ; | ||
1568 | ; Extensions to search for (in *forward* order). | ||
1569 | ; | ||
1570 | align 4, db 0 | ||
1571 | exten_table: db '.cbt' ; COMBOOT (specific) | ||
1572 | db '.img' ; Disk image | ||
1573 | db '.bin' ; CD boot sector | ||
1574 | db '.com' ; COMBOOT (same as DOS) | ||
1575 | db '.c32' ; COM32 | ||
1576 | exten_table_end: | ||
1577 | dd 0, 0 ; Need 8 null bytes here | ||
1578 | |||
1579 | ; | ||
1580 | ; Floppy image table | ||
1581 | ; | ||
1582 | align 4, db 0 | ||
1583 | img_table_count equ 3 | ||
1584 | img_table: | ||
1585 | dd 1200*1024 ; 1200K floppy | ||
1586 | db 1 ; Emulation type | ||
1587 | db 80-1 ; Max cylinder | ||
1588 | db 15 ; Max sector | ||
1589 | db 2-1 ; Max head | ||
1590 | |||
1591 | dd 1440*1024 ; 1440K floppy | ||
1592 | db 2 ; Emulation type | ||
1593 | db 80-1 ; Max cylinder | ||
1594 | db 18 ; Max sector | ||
1595 | db 2-1 ; Max head | ||
1596 | |||
1597 | dd 2880*1024 ; 2880K floppy | ||
1598 | db 3 ; Emulation type | ||
1599 | db 80-1 ; Max cylinder | ||
1600 | db 36 ; Max sector | ||
1601 | db 2-1 ; Max head | ||
1602 | |||
1603 | ; | ||
1604 | ; Misc initialized (data) variables | ||
1605 | ; | ||
1606 | |||
1607 | ; | ||
1608 | ; Variables that are uninitialized in SYSLINUX but initialized here | ||
1609 | ; | ||
1610 | ; **** ISOLINUX:: We may have to make this flexible, based on what the | ||
1611 | ; **** BIOS expects our "sector size" to be. | ||
1612 | ; | ||
1613 | alignb 4, db 0 | ||
1614 | BufSafe dw trackbufsize/SECTOR_SIZE ; Clusters we can load into trackbuf | ||
1615 | BufSafeSec dw trackbufsize/SECTOR_SIZE ; = how many sectors? | ||
1616 | BufSafeBytes dw trackbufsize ; = how many bytes? | ||
1617 | EndOfGetCBuf dw getcbuf+trackbufsize ; = getcbuf+BufSafeBytes | ||
1618 | %ifndef DEPEND | ||
1619 | %if ( trackbufsize % SECTOR_SIZE ) != 0 | ||
1620 | %error trackbufsize must be a multiple of SECTOR_SIZE | ||
1621 | %endif | ||
1622 | %endif |