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