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