]>
Commit | Line | Data |
---|---|---|
57c72a9a A |
1 | ; Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved. |
2 | ; | |
3 | ; @APPLE_LICENSE_HEADER_START@ | |
4 | ; | |
5 | ; Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights | |
6 | ; Reserved. This file contains Original Code and/or Modifications of | |
7 | ; Original Code as defined in and that are subject to the Apple Public | |
8 | ; Source License Version 2.0 (the "License"). You may not use this file | |
9 | ; except in compliance with the License. Please obtain a copy of the | |
10 | ; License at http://www.apple.com/publicsource and read it before using | |
11 | ; this file. | |
12 | ; | |
13 | ; The Original Code and all software distributed under the License are | |
14 | ; distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | ; EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | ; INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | ; FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the | |
18 | ; License for the specific language governing rights and limitations | |
19 | ; under the License. | |
20 | ; | |
21 | ; @APPLE_LICENSE_HEADER_END@ | |
22 | ; | |
23 | ; Boot Loader: boot0 | |
24 | ; | |
25 | ; A small boot sector program written in x86 assembly whose only | |
26 | ; responsibility is to locate the active partition, load the | |
27 | ; partition booter into memory, and jump to the booter's entry point. | |
28 | ; It leaves the boot drive in DL and a pointer to the partition entry in SI. | |
29 | ; | |
30 | ; This boot loader must be placed in the Master Boot Record. | |
31 | ; | |
32 | ; In order to coexist with a fdisk partition table (64 bytes), and | |
33 | ; leave room for a two byte signature (0xAA55) in the end, boot0 is | |
34 | ; restricted to 446 bytes (512 - 64 - 2). If boot0 did not have to | |
35 | ; live in the MBR, then we would have 510 bytes to work with. | |
36 | ; | |
37 | ; boot0 is always loaded by the BIOS or another booter to 0:7C00h. | |
38 | ; | |
39 | ; This code is written for the NASM assembler. | |
40 | ; nasm boot0.s -o boot0 | |
41 | ||
42 | ||
43 | ; | |
44 | ; Set to 1 to enable obscure debug messages. | |
45 | ; | |
46 | DEBUG EQU 0 | |
47 | ||
48 | ; | |
49 | ; Set to 1 to support loading the partition booter (boot1) from a | |
50 | ; logical partition. | |
51 | ; | |
52 | EXT_PART_SUPPORT EQU 1 | |
53 | ||
54 | ; | |
55 | ; Various constants. | |
56 | ; | |
57 | kBoot0Segment EQU 0x0000 | |
58 | kBoot0Stack EQU 0xFFF0 ; boot0 stack pointer | |
59 | kBoot0LoadAddr EQU 0x7C00 ; boot0 load address | |
60 | kBoot0RelocAddr EQU 0xE000 ; boot0 relocated address | |
61 | ||
62 | kMBRBuffer EQU 0x1000 ; MBR buffer address | |
63 | kExtBuffer EQU 0x1200 ; EXT boot block buffer address | |
64 | ||
65 | kPartTableOffset EQU 0x1be | |
66 | kMBRPartTable EQU kMBRBuffer + kPartTableOffset | |
67 | kExtPartTable EQU kExtBuffer + kPartTableOffset | |
68 | ||
69 | kSectorBytes EQU 512 ; sector size in bytes | |
70 | kBootSignature EQU 0xAA55 ; boot sector signature | |
71 | ||
72 | kPartCount EQU 4 ; number of paritions per table | |
73 | kPartTypeBoot EQU 0xab ; boot2 partition type | |
74 | kPartTypeUFS EQU 0xa8 ; UFS partition type | |
75 | kPartTypeHFS EQU 0xaf ; HFS partition type | |
76 | kPartTypeExtDOS EQU 0x05 ; DOS extended partition type | |
77 | kPartTypeExtWin EQU 0x0f ; Windows extended partition type | |
78 | kPartTypeExtLinux EQU 0x85 ; Linux extended partition type | |
79 | ||
80 | kPartActive EQU 0x80 | |
81 | ||
82 | ; | |
83 | ; Format of fdisk partition entry. | |
84 | ; | |
85 | ; The symbol 'part_size' is automatically defined as an `EQU' | |
86 | ; giving the size of the structure. | |
87 | ; | |
88 | struc part | |
89 | .bootid: resb 1 ; bootable or not | |
90 | .head: resb 1 ; starting head, sector, cylinder | |
91 | .sect: resb 1 ; | |
92 | .cyl: resb 1 ; | |
93 | .type: resb 1 ; partition type | |
94 | .endhead resb 1 ; ending head, sector, cylinder | |
95 | .endsect: resb 1 ; | |
96 | .endcyl: resb 1 ; | |
97 | .lba: resd 1 ; starting lba | |
98 | .sectors resd 1 ; size in sectors | |
99 | endstruc | |
100 | ||
101 | ; | |
102 | ; Macros. | |
103 | ; | |
104 | %macro DebugCharMacro 1 | |
105 | mov al, %1 | |
106 | call print_char | |
107 | %endmacro | |
108 | ||
109 | %if DEBUG | |
110 | %define DebugChar(x) DebugCharMacro x | |
111 | %else | |
112 | %define DebugChar(x) | |
113 | %endif | |
114 | ||
115 | ;-------------------------------------------------------------------------- | |
116 | ; Start of text segment. | |
117 | ||
118 | SEGMENT .text | |
119 | ||
120 | ORG 0xE000 ; must match kBoot0RelocAddr | |
121 | ||
122 | ;-------------------------------------------------------------------------- | |
123 | ; Boot code is loaded at 0:7C00h. | |
124 | ; | |
125 | start | |
126 | ; | |
127 | ; Set up the stack to grow down from kBoot0Segment:kBoot0Stack. | |
128 | ; Interrupts should be off while the stack is being manipulated. | |
129 | ; | |
130 | cli ; interrupts off | |
131 | xor ax, ax ; zero ax | |
132 | mov ss, ax ; ss <- 0 | |
133 | mov sp, kBoot0Stack ; sp <- top of stack | |
134 | sti ; reenable interrupts | |
135 | ||
136 | mov es, ax ; es <- 0 | |
137 | mov ds, ax ; ds <- 0 | |
138 | ||
139 | ; | |
140 | ; Relocate boot0 code. | |
141 | ; | |
142 | mov si, kBoot0LoadAddr ; si <- source | |
143 | mov di, kBoot0RelocAddr ; di <- destination | |
144 | ; | |
145 | cld ; auto-increment SI and/or DI registers | |
146 | mov cx, kSectorBytes/2 ; copy 256 words | |
147 | repnz movsw ; repeat string move (word) operation | |
148 | ||
149 | ; Code relocated, jump to start_reloc in relocated location. | |
150 | ; | |
151 | jmp 0:start_reloc | |
152 | ||
153 | ;-------------------------------------------------------------------------- | |
154 | ; Start execution from the relocated location. | |
155 | ; | |
156 | start_reloc: | |
157 | ||
158 | DebugChar('>') | |
159 | ||
160 | .loop: | |
161 | ||
162 | %if DEBUG | |
163 | mov al, dl | |
164 | call print_hex | |
165 | %endif | |
166 | ||
167 | ; | |
168 | ; Clear various flags in memory. | |
169 | ; | |
170 | xor eax, eax | |
171 | mov [ebios_lba], eax ; clear EBIOS LBA offset | |
172 | mov [ebios_present], al ; clear EBIOS support flag | |
173 | ||
174 | ; | |
175 | ; Check if EBIOS is supported for this hard drive. | |
176 | ; | |
177 | mov ah, 0x41 ; Function 0x41 | |
178 | mov bx, 0x55AA ; check signature | |
179 | int 0x13 | |
180 | ||
181 | ; | |
182 | ; If successful, the return values are as follows: | |
183 | ; | |
184 | ; carry = 0 | |
185 | ; ah = major version of EBIOS extensions (0x21 = version 1.1) | |
186 | ; al = altered | |
187 | ; bx = 0xAA55 | |
188 | ; cx = support bits. bit 0 must be set for function 0x42. | |
189 | ; | |
190 | jc .ebios_check_done | |
191 | cmp bx, 0xAA55 ; check BX = 0xAA55 | |
192 | jnz .ebios_check_done | |
193 | test cl, 0x01 ; check enhanced drive read support | |
194 | setnz [ebios_present] ; EBIOS supported, set flag | |
195 | DebugChar('E') ; EBIOS supported | |
196 | .ebios_check_done: | |
197 | ||
198 | ; | |
199 | ; Since this code may not always reside in the MBR, always start by | |
200 | ; loading the MBR to kMBRBuffer. | |
201 | ; | |
202 | mov al, 1 ; load one sector | |
203 | xor bx, bx | |
204 | mov es, bx ; MBR load segment = 0 | |
205 | mov bx, kMBRBuffer ; MBR load address | |
206 | mov si, bx ; pointer to fake partition entry | |
207 | mov WORD [si], 0x0000 ; CHS DX: head = 0 | |
208 | mov WORD [si + 2], 0x0001 ; CHS CX: cylinder = 0, sector = 1 | |
209 | mov DWORD [si + part.lba], 0x00000000 ; LBA sector 0 | |
210 | ||
211 | call load | |
212 | jc .next_drive ; MBR load error | |
213 | ||
214 | ; | |
215 | ; Look for the booter partition in the MBR partition table, | |
216 | ; which is at offset kMBRPartTable. | |
217 | ; | |
218 | mov di, kMBRPartTable ; pointer to partition table | |
219 | mov ah, 0 ; initial nesting level is 0 | |
220 | call find_boot ; will not return on success | |
221 | ||
222 | .next_drive: | |
223 | inc dl ; next drive number | |
224 | test dl, 0x4 ; went through all 4 drives? | |
225 | jz .loop ; not yet, loop again | |
226 | ||
227 | mov si, boot_error_str | |
228 | call print_string | |
229 | ||
230 | hang: | |
231 | jmp SHORT hang | |
232 | ||
233 | ;-------------------------------------------------------------------------- | |
234 | ; Find the active (boot) partition and load the booter from the partition. | |
235 | ; | |
236 | ; Arguments: | |
237 | ; AH = recursion nesting level | |
238 | ; DL = drive number (0x80 + unit number) | |
239 | ; DI = pointer to fdisk partition table. | |
240 | ; | |
241 | ; Clobber list: | |
242 | ; AX, BX, EBP | |
243 | ; | |
244 | find_boot: | |
245 | push cx ; preserve CX and SI | |
246 | push si | |
247 | ||
248 | ; | |
249 | ; Check for boot block signature 0xAA55 following the 4 partition | |
250 | ; entries. | |
251 | ; | |
252 | cmp WORD [di + part_size * kPartCount], kBootSignature | |
253 | jne NEAR .exit ; boot signature not found | |
254 | ||
255 | mov si, di ; make SI a pointer to partition table | |
256 | mov cx, kPartCount ; number of partition entries per table | |
257 | ||
258 | .loop: | |
259 | ; | |
260 | ; First scan through the partition table looking for the active | |
261 | ; partition. Postpone walking the extended partition chain for | |
262 | ; the second pass. Do not merge the two without changing the | |
263 | ; buffering scheme used to store extended partition tables. | |
264 | ; | |
265 | %if DEBUG | |
266 | mov al, ah ; indent based on nesting level | |
267 | call print_spaces | |
268 | mov al, [si + part.type] ; print partition type | |
269 | call print_hex | |
270 | %endif | |
271 | ||
272 | cmp BYTE [si + part.type], kPartTypeBoot | |
273 | je .found | |
274 | cmp BYTE [si + part.type], kPartTypeUFS | |
275 | je .found | |
276 | cmp BYTE [si + part.type], kPartTypeHFS | |
277 | je .found | |
278 | ||
279 | jmp .continue | |
280 | ||
281 | .found | |
282 | DebugChar('*') | |
283 | ||
284 | ; | |
285 | ; Found boot partition, read boot sector to memory. | |
286 | ; | |
287 | mov al, 1 | |
288 | mov bx, kBoot0Segment | |
289 | mov es, bx | |
290 | mov bx, kBoot0LoadAddr | |
291 | call load | |
292 | jc .continue ; load error, keep looking? | |
293 | ||
294 | ; | |
295 | ; Check signature | |
296 | ; | |
297 | cmp WORD [bx + 510], kBootSignature | |
298 | jne NEAR .exit ; boot signature not found | |
299 | ||
300 | DebugChar('&') | |
301 | ||
302 | ; | |
303 | ; Fix up absolute block location in partition record. | |
304 | ; | |
305 | mov eax, [si + part.lba] | |
306 | add eax, [ebios_lba] | |
307 | mov [si + part.lba], eax | |
308 | ||
309 | DebugChar('%') | |
310 | ||
311 | ; | |
312 | ; Jump to partition booter. The drive number is already in register DL. | |
313 | ; SI is pointing to the modified partition entry. | |
314 | ; | |
315 | jmp kBoot0Segment:kBoot0LoadAddr | |
316 | ||
317 | .continue: | |
318 | add si, part_size ; advance SI to next partition entry | |
319 | loop .loop ; loop through all partition entries | |
320 | ||
321 | %if EXT_PART_SUPPORT | |
322 | ; | |
323 | ; No primary (or logical) boot partition found in the current | |
324 | ; partition table. Restart and look for extended partitions. | |
325 | ; | |
326 | mov si, di ; make SI a pointer to partition table | |
327 | mov cx, kPartCount ; number of partition entries per table | |
328 | ||
329 | .ext_loop: | |
330 | ||
331 | mov al, [si + part.type] ; AL <- partition type | |
332 | ||
333 | cmp al, kPartTypeExtDOS ; Extended DOS | |
334 | je .ext_load | |
335 | ||
336 | cmp al, kPartTypeExtWin ; Extended Windows(95) | |
337 | je .ext_load | |
338 | ||
339 | cmp al, kPartTypeExtLinux ; Extended Linux | |
340 | je .ext_load | |
341 | ||
342 | .ext_continue: | |
343 | ; | |
344 | ; Advance si to the next partition entry in the extended | |
345 | ; partition table. | |
346 | ; | |
347 | add si, part_size ; advance SI to next partition entry | |
348 | loop .ext_loop ; loop through all partition entries | |
349 | jmp .exit ; boot partition not found | |
350 | ||
351 | .ext_load: | |
352 | ; | |
353 | ; Setup the arguments for the load function call to bring the | |
354 | ; extended partition table into memory. | |
355 | ; Remember that SI points to the extended partition entry. | |
356 | ; | |
357 | mov al, 1 ; read 1 sector | |
358 | xor bx, bx | |
359 | mov es, bx ; es = 0 | |
360 | mov bx, kExtBuffer ; load extended boot sector | |
361 | call load | |
362 | jc .ext_continue ; load error | |
363 | ||
364 | ; | |
365 | ; The LBA address of all extended partitions is relative based | |
366 | ; on the LBA address of the extended partition in the MBR, or | |
367 | ; the extended partition at the head of the chain. Thus it is | |
368 | ; necessary to save the LBA address of the first extended partition. | |
369 | ; | |
370 | or ah, ah | |
371 | jnz .ext_find_boot | |
372 | mov ebp, [si + part.lba] | |
373 | mov [ebios_lba], ebp | |
374 | ||
375 | .ext_find_boot: | |
376 | ; | |
377 | ; Call find_boot recursively to scan through the extended partition | |
378 | ; table. Load DI with a pointer to the extended table in memory. | |
379 | ; | |
380 | inc ah ; increment recursion level | |
381 | mov di, kExtPartTable ; partition table pointer | |
382 | call find_boot ; recursion... | |
383 | ;dec ah | |
384 | ||
385 | ; | |
386 | ; Since there is an "unwritten" rule that limits each partition table | |
387 | ; to have 0 or 1 extended partitions, there is no point in looking for | |
388 | ; any additional extended partition entries at this point. There is no | |
389 | ; boot partition linked beyond the extended partition that was loaded | |
390 | ; above. | |
391 | ; | |
392 | ||
393 | %endif ; EXT_PART_SUPPORT | |
394 | ||
395 | .exit: | |
396 | ; | |
397 | ; Boot partition not found. Giving up. | |
398 | ; | |
399 | DebugChar('X') | |
400 | pop si | |
401 | pop cx | |
402 | ret | |
403 | ||
404 | ;-------------------------------------------------------------------------- | |
405 | ; load - Load one or more sectors from a partition. | |
406 | ; | |
407 | ; Arguments: | |
408 | ; AL = number of 512-byte sectors to read. | |
409 | ; ES:BX = pointer to where the sectors should be stored. | |
410 | ; DL = drive number (0x80 + unit number) | |
411 | ; SI = pointer to the partition entry. | |
412 | ; | |
413 | ; Returns: | |
414 | ; CF = 0 success | |
415 | ; 1 error | |
416 | ; | |
417 | load: | |
418 | push cx | |
419 | test BYTE [ebios_present], 1 | |
420 | jz .chs | |
421 | ||
422 | .ebios: | |
423 | mov cx, 5 ; load retry count | |
424 | .ebios_loop: | |
425 | call read_lba ; use INT13/F42 | |
426 | jnc .exit | |
427 | loop .ebios_loop | |
428 | .chs: | |
429 | mov cx, 5 ; load retry count | |
430 | .chs_loop: | |
431 | call read_chs ; use INT13/F2 | |
432 | jnc .exit | |
433 | loop .chs_loop | |
434 | ||
435 | .exit | |
436 | DebugChar('R') | |
437 | pop cx | |
438 | ret | |
439 | ||
440 | ;-------------------------------------------------------------------------- | |
441 | ; read_chs - Read sectors from a partition using CHS addressing. | |
442 | ; | |
443 | ; Arguments: | |
444 | ; AL = number of 512-byte sectors to read. | |
445 | ; ES:BX = pointer to where the sectors should be stored. | |
446 | ; DL = drive number (0x80 + unit number) | |
447 | ; SI = pointer to the partition entry. | |
448 | ; | |
449 | ; Returns: | |
450 | ; CF = 0 success | |
451 | ; 1 error | |
452 | ; | |
453 | read_chs: | |
454 | pusha ; save all registers | |
455 | ||
456 | ; | |
457 | ; Read the CHS start values from the partition entry. | |
458 | ; | |
459 | mov dh, [ si + part.head ] ; drive head | |
460 | mov cx, [ si + part.sect ] ; drive sector + cylinder | |
461 | ||
462 | ; | |
463 | ; INT13 Func 2 - Read Disk Sectors | |
464 | ; | |
465 | ; Arguments: | |
466 | ; AH = 2 | |
467 | ; AL = number of sectors to read | |
468 | ; CH = lowest 8 bits of the 10-bit cylinder number | |
469 | ; CL = bits 6 & 7: cylinder number bits 8 and 9 | |
470 | ; bits 0 - 5: starting sector number (1-63) | |
471 | ; DH = starting head number (0 to 255) | |
472 | ; DL = drive number (80h + drive unit) | |
473 | ; es:bx = pointer where to place sectors read from disk | |
474 | ; | |
475 | ; Returns: | |
476 | ; AH = return status (sucess is 0) | |
477 | ; AL = burst error length if ah=0x11 (ECC corrected) | |
478 | ; carry = 0 success | |
479 | ; 1 error | |
480 | ; | |
481 | mov ah, 0x02 ; Func 2 | |
482 | int 0x13 ; INT 13 | |
483 | jnc .exit | |
484 | ||
485 | DebugChar('r') ; indicate INT13/F2 error | |
486 | ||
487 | ; | |
488 | ; Issue a disk reset on error. | |
489 | ; Should this be changed to Func 0xD to skip the diskette controller | |
490 | ; reset? | |
491 | ; | |
492 | xor ax, ax ; Func 0 | |
493 | int 0x13 ; INT 13 | |
494 | stc ; set carry to indicate error | |
495 | ||
496 | .exit: | |
497 | popa | |
498 | ret | |
499 | ||
500 | ;-------------------------------------------------------------------------- | |
501 | ; read_lba - Read sectors from a partition using LBA addressing. | |
502 | ; | |
503 | ; Arguments: | |
504 | ; AL = number of 512-byte sectors to read (valid from 1-127). | |
505 | ; ES:BX = pointer to where the sectors should be stored. | |
506 | ; DL = drive number (0x80 + unit number) | |
507 | ; SI = pointer to the partition entry. | |
508 | ; | |
509 | ; Returns: | |
510 | ; CF = 0 success | |
511 | ; 1 error | |
512 | ; | |
513 | read_lba: | |
514 | pusha ; save all registers | |
515 | mov bp, sp ; save current SP | |
516 | ||
517 | ; | |
518 | ; Create the Disk Address Packet structure for the | |
519 | ; INT13/F42 (Extended Read Sectors) on the stack. | |
520 | ; | |
521 | ||
522 | ; push DWORD 0 ; offset 12, upper 32-bit LBA | |
523 | push ds ; For sake of saving memory, | |
524 | push ds ; push DS register, which is 0. | |
525 | ||
526 | mov ecx, [ebios_lba] ; offset 8, lower 32-bit LBA | |
527 | add ecx, [si + part.lba] | |
528 | push ecx | |
529 | ||
530 | push es ; offset 6, memory segment | |
531 | ||
532 | push bx ; offset 4, memory offset | |
533 | ||
534 | xor ah, ah ; offset 3, must be 0 | |
535 | push ax ; offset 2, number of sectors | |
536 | ||
537 | push WORD 16 ; offset 0-1, packet size | |
538 | ||
539 | ; | |
540 | ; INT13 Func 42 - Extended Read Sectors | |
541 | ; | |
542 | ; Arguments: | |
543 | ; AH = 0x42 | |
544 | ; DL = drive number (80h + drive unit) | |
545 | ; DS:SI = pointer to Disk Address Packet | |
546 | ; | |
547 | ; Returns: | |
548 | ; AH = return status (sucess is 0) | |
549 | ; carry = 0 success | |
550 | ; 1 error | |
551 | ; | |
552 | ; Packet offset 2 indicates the number of sectors read | |
553 | ; successfully. | |
554 | ; | |
555 | mov si, sp | |
556 | mov ah, 0x42 | |
557 | int 0x13 | |
558 | ||
559 | jnc .exit | |
560 | ||
561 | DebugChar('R') ; indicate INT13/F42 error | |
562 | ||
563 | ; | |
564 | ; Issue a disk reset on error. | |
565 | ; Should this be changed to Func 0xD to skip the diskette controller | |
566 | ; reset? | |
567 | ; | |
568 | xor ax, ax ; Func 0 | |
569 | int 0x13 ; INT 13 | |
570 | stc ; set carry to indicate error | |
571 | ||
572 | .exit: | |
573 | mov sp, bp ; restore SP | |
574 | popa | |
575 | ret | |
576 | ||
577 | ;-------------------------------------------------------------------------- | |
578 | ; Write a string to the console. | |
579 | ; | |
580 | ; Arguments: | |
581 | ; DS:SI pointer to a NULL terminated string. | |
582 | ; | |
583 | ; Clobber list: | |
584 | ; AX, BX, SI | |
585 | ; | |
586 | print_string | |
587 | mov bx, 1 ; BH=0, BL=1 (blue) | |
588 | cld ; increment SI after each lodsb call | |
589 | .loop | |
590 | lodsb ; load a byte from DS:SI into AL | |
591 | cmp al, 0 ; Is it a NULL? | |
592 | je .exit ; yes, all done | |
593 | mov ah, 0xE ; INT10 Func 0xE | |
594 | int 0x10 ; display byte in tty mode | |
595 | jmp short .loop | |
596 | .exit | |
597 | ret | |
598 | ||
599 | ||
600 | %if DEBUG | |
601 | ||
602 | ;-------------------------------------------------------------------------- | |
603 | ; Write a ASCII character to the console. | |
604 | ; | |
605 | ; Arguments: | |
606 | ; AL = ASCII character. | |
607 | ; | |
608 | print_char | |
609 | pusha | |
610 | mov bx, 1 ; BH=0, BL=1 (blue) | |
611 | mov ah, 0x0e ; bios INT 10, Function 0xE | |
612 | int 0x10 ; display byte in tty mode | |
613 | popa | |
614 | ret | |
615 | ||
616 | %if DEBUG | |
617 | ;-------------------------------------------------------------------------- | |
618 | ; Write a variable number of spaces to the console. | |
619 | ; | |
620 | ; Arguments: | |
621 | ; AL = number to spaces. | |
622 | ; | |
623 | print_spaces: | |
624 | pusha | |
625 | xor cx, cx | |
626 | mov cl, al ; use CX as the loop counter | |
627 | mov al, ' ' ; character to print | |
628 | .loop: | |
629 | jcxz .exit | |
630 | call print_char | |
631 | loop .loop | |
632 | .exit: | |
633 | popa | |
634 | ret | |
635 | %endif | |
636 | ||
637 | ;-------------------------------------------------------------------------- | |
638 | ; Write the byte value to the console in hex. | |
639 | ; | |
640 | ; Arguments: | |
641 | ; AL = Value to be displayed in hex. | |
642 | ; | |
643 | print_hex: | |
644 | push ax | |
645 | ror al, 4 | |
646 | call print_nibble ; display upper nibble | |
647 | pop ax | |
648 | call print_nibble ; display lower nibble | |
649 | ||
650 | mov al, 10 ; carriage return | |
651 | call print_char | |
652 | mov al, 13 | |
653 | call print_char | |
654 | ret | |
655 | ||
656 | print_nibble: | |
657 | and al, 0x0f | |
658 | add al, '0' | |
659 | cmp al, '9' | |
660 | jna .print_ascii | |
661 | add al, 'A' - '9' - 1 | |
662 | .print_ascii: | |
663 | call print_char | |
664 | ret | |
665 | ||
666 | getc: | |
667 | pusha | |
668 | mov ah, 0 | |
669 | int 0x16 | |
670 | popa | |
671 | ret | |
672 | ||
673 | %endif ; DEBUG | |
674 | ||
675 | ;-------------------------------------------------------------------------- | |
676 | ; NULL terminated strings. | |
677 | ; | |
678 | boot_error_str db 10, 13, 'Chain booting error', 0 | |
679 | ||
680 | ;-------------------------------------------------------------------------- | |
681 | ; Pad the rest of the 512 byte sized booter with zeroes. The last | |
682 | ; two bytes is the mandatory boot sector signature. | |
683 | ; | |
684 | ; If the booter code becomes too large, then nasm will complain | |
685 | ; that the 'times' argument is negative. | |
686 | ||
687 | ; | |
688 | ; In memory variables. | |
689 | ; | |
690 | ebios_lba dd 0 ; starting LBA of the intial extended partition. | |
691 | ebios_present db 0 ; 1 if EBIOS is supported, 0 otherwise. | |
692 | ||
693 | pad_boot | |
694 | times 446-($-$$) db 0 | |
695 | ||
696 | pad_table_and_sig | |
697 | times 510-($-$$) db 0 | |
698 | dw kBootSignature | |
699 | ||
700 | END |