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