]> git.saurik.com Git - apple/boot.git/blob - i386/boot1/boot1.s
boot-132.tar.gz
[apple/boot.git] / i386 / boot1 / boot1.s
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 ; Partition Boot Loader: boot1h
24 ;
25 ; This program is designed to reside in sector 0 of an HFS+ partition.
26 ; The HFS+ partition can be a primary or a logical partition.
27 ; It expects that the MBR has left the drive number in DL
28 ; and a pointer to the partition entry in SI.
29 ;
30 ; This version requires a BIOS with EBIOS (LBA) support.
31 ;
32 ; This code is written for the NASM assembler.
33 ; nasm boot0.s -o boot0
34
35
36 ;
37 ; Set to 1 to enable obscure debug messages.
38 ;
39 DEBUG EQU 0
40
41 ;
42 ; Various constants.
43 ;
44 kBoot0Segment EQU 0x0000
45 kBoot0Stack EQU 0xFFF0 ; boot0 stack pointer
46 kBoot0LoadAddr EQU 0x7C00 ; boot0 load address
47 kBoot0RelocAddr EQU 0xE000 ; boot0 relocated address
48
49 kMBRBuffer EQU 0x1000 ; MBR buffer address
50 kExtBuffer EQU 0x1200 ; EXT boot block buffer address
51
52 kPartTableOffset EQU 0x1be
53 kMBRPartTable EQU kMBRBuffer + kPartTableOffset
54 kExtPartTable EQU kExtBuffer + kPartTableOffset
55
56 kBoot2Sectors EQU 126 ; sectors to load for boot2
57 kBoot2Address EQU 0x0000 ; boot2 load address
58 kBoot2Segment EQU 0x2000 ; boot2 load segment
59
60 kSectorBytes EQU 512 ; sector size in bytes
61 kBootSignature EQU 0xAA55 ; boot sector signature
62
63 kPartCount EQU 4 ; number of paritions per table
64 kPartTypeBoot EQU 0xab ; boot2 partition type
65 kPartTypeHFS EQU 0xaf
66 kPartTypeExtDOS EQU 0x05 ; DOS extended partition type
67 kPartTypeExtWin EQU 0x0f ; Windows extended partition type
68 kPartTypeExtLinux EQU 0x85 ; Linux extended partition type
69
70 kPartActive EQU 0x80
71
72 ;;
73 ;; HFS constants
74 ;;
75 kHFSSig EQU 0x4442 ; HFS volume signature
76 kAlBlStOffset EQU 0x1c
77 kEmbedStartOffset EQU 0x7e
78 kAlBlkSizOffset EQU 0x14
79
80 ;;
81 ;; HFS+ constants
82 ;;
83 kHFSPlusSig EQU 0x2B48 ; HFS+ volume signature
84 kHFSXSig EQU 0x5848 ; HFSX volume signature
85 kBlockSizeOffset EQU 0x28
86 kExtentOffset EQU 0x1c0
87
88 kHFSBuffer EQU 0x1400 ; HFS volume header address
89
90 kHFSSigAddr EQU kHFSBuffer
91 kHFSAlBlSt EQU kHFSBuffer + kAlBlStOffset
92 kHFSEmbedStart EQU kHFSBuffer + kEmbedStartOffset
93 kHFSAlBlkSiz EQU kHFSBuffer + kAlBlkSizOffset
94
95 kHFSPlusSigAddr EQU kHFSBuffer
96 kHFSPlusBlockSize EQU kHFSBuffer + kBlockSizeOffset
97 kHFSPlusExtent EQU kHFSBuffer + kExtentOffset
98
99
100 kDriveNumber EQU 0x80
101
102 ;
103 ; Format of fdisk partition entry.
104 ;
105 ; The symbol 'part_size' is automatically defined as an `EQU'
106 ; giving the size of the structure.
107 ;
108 struc part
109 .bootid: resb 1 ; bootable or not
110 .head: resb 1 ; starting head, sector, cylinder
111 .sect: resb 1 ;
112 .cyl: resb 1 ;
113 .type: resb 1 ; partition type
114 .endhead resb 1 ; ending head, sector, cylinder
115 .endsect: resb 1 ;
116 .endcyl: resb 1 ;
117 .lba: resd 1 ; starting lba
118 .sectors resd 1 ; size in sectors
119 endstruc
120
121 ;
122 ; Macros.
123 ;
124 %macro DebugCharMacro 1
125 mov al, %1
126 call print_char
127 call getc
128 %endmacro
129
130 %macro PrintString 1
131 mov si, %1
132 call print_string
133 %endmacro
134
135 %if DEBUG
136 %define DebugChar(x) DebugCharMacro x
137 %else
138 %define DebugChar(x)
139 %endif
140
141
142 ;--------------------------------------------------------------------------
143 ; Start of text segment.
144
145 SEGMENT .text
146
147 ORG 0x7C00 ; must match kBoot0RelocAddr
148
149 ;--------------------------------------------------------------------------
150 ; Boot code is loaded at 0:7C00h.
151 ;
152 start
153 ;
154 ; Set up the stack to grow down from kBoot0Segment:kBoot0Stack.
155 ; Interrupts should be off while the stack is being manipulated.
156 ;
157 cli ; interrupts off
158 xor ax, ax ; zero ax
159 mov ss, ax ; ss <- 0
160 mov sp, kBoot0Stack ; sp <- top of stack
161 sti ; reenable interrupts
162
163 mov es, ax ; es <- 0
164 mov ds, ax ; ds <- 0
165
166 DebugChar('H')
167
168 %if DEBUG
169 mov eax, [si + part.lba]
170 call print_hex
171 %endif
172
173 ;
174 ; Clear various flags in memory.
175 ;
176 xor eax, eax
177 mov [ebios_lba], eax ; clear EBIOS LBA offset
178
179 cmp BYTE [si + part.type], kPartTypeHFS
180 jne .part_err
181
182 jmp find_startup
183
184 .part_err:
185 PrintString(part_error_str)
186 jmp hang
187
188 ;;; ---------------------------------------
189 ;;;
190 ;;; find_startup - Find HFS+ startup file in a partition.
191 ;;;
192 ;;; Arguments:
193 ;;; DL = drive number (0x80 + unit number)
194 ;;; SI = pointer to the partition entry.
195 ;;;
196 ;;; On success, loads booter and jumps to it.
197 ;;;
198 find_startup:
199 DebugChar(']')
200
201 mov al, 1 ; read 1 sector
202 xor bx, bx
203 mov es, bx ; es = 0
204 mov bx, kHFSBuffer ; load volume header
205 mov ecx, DWORD 2
206 call load
207 jnc .ok ; load error
208
209 jmp startup_err
210
211 .ok
212 mov ax, [kHFSSigAddr]
213 cmp ax, kHFSSig
214 jne .hfs_plus
215
216 DebugChar('|')
217 mov ebx, [kHFSAlBlkSiz]
218 bswap ebx
219 sar ebx, 9
220
221 xor eax, eax
222 mov ax, [kHFSEmbedStart]
223 xchg al, ah ; byte-swap
224 push dx
225 mul ebx ; result in eax
226 pop dx
227
228 xor ebx, ebx
229 mov bx, [kHFSAlBlSt]
230 xchg bl, bh ; byte-swap
231 add eax, ebx
232
233 ;; now eax has sector of HFS+ partition
234 inc eax
235 inc eax
236 mov ecx, eax
237
238 mov al, 1 ; read 1 sector
239 xor bx, bx
240 mov es, bx ; es = 0
241 mov bx, kHFSBuffer ; load volume header
242 call load
243 jc startup_err ; load error
244
245 .hfs_plus
246 DebugChar('}')
247 mov ax, [kHFSPlusSigAddr]
248 cmp ax, kHFSPlusSig
249 je .hfs_plus2
250 cmp ax, kHFSXSig
251 jne startup_err
252
253 ;;; Now the HFS+ volume header is in our buffer.
254
255 .hfs_plus2
256 DebugChar('*')
257 mov eax, [kHFSPlusBlockSize]
258 bswap eax
259 sar eax, 9
260
261 mov ebx, [kHFSPlusExtent]
262 bswap ebx
263 push dx
264 mul ebx ; result in eax
265 pop dx
266
267 dec eax
268 dec eax
269 add ecx, eax
270
271 DebugChar('!')
272
273 mov al, kBoot2Sectors
274 mov bx, kBoot2Segment
275 mov es, bx
276 mov bx, kBoot2Address + kSectorBytes
277 call load
278 jc startup_err
279
280 DebugChar('Y')
281 ;
282 ; Jump to boot2. The drive number is already in register DL.
283 ;
284 jmp kBoot2Segment:kBoot2Address + kSectorBytes
285
286 startup_err:
287
288 PrintString(boot2_error_str)
289 DebugChar('X')
290
291 hang:
292 hlt
293 jmp SHORT hang
294
295
296 ;--------------------------------------------------------------------------
297 ; read_lba - Read sectors from a partition using LBA addressing.
298 ;
299 ; Arguments:
300 ; AL = number of 512-byte sectors to read (valid from 1-127).
301 ; ES:BX = pointer to where the sectors should be stored.
302 ; ECX = sector offset in partition
303 ; DL = drive number (0x80 + unit number)
304 ; SI = pointer to the partition entry.
305 ;
306 ; Returns:
307 ; CF = 0 success
308 ; 1 error
309 ;
310 read_lba:
311 load:
312 pushad ; save all registers
313 mov bp, sp ; save current SP
314
315 ;
316 ; Create the Disk Address Packet structure for the
317 ; INT13/F42 (Extended Read Sectors) on the stack.
318 ;
319
320 ; push DWORD 0 ; offset 12, upper 32-bit LBA
321 push ds ; For sake of saving memory,
322 push ds ; push DS register, which is 0.
323
324 add ecx, [ebios_lba] ; offset 8, lower 32-bit LBA
325 add ecx, [si + part.lba]
326
327 push ecx
328
329 push es ; offset 6, memory segment
330
331 push bx ; offset 4, memory offset
332
333 xor ah, ah ; offset 3, must be 0
334 push ax ; offset 2, number of sectors
335
336 %if DEBUG
337 push ax
338 DebugChar('-') ; absolute sector offset
339 mov eax, ecx
340 call print_hex
341 DebugChar('=') ; count
342 pop ax
343 call print_hex
344 %endif
345
346 push WORD 16 ; offset 0-1, packet size
347
348 ;
349 ; INT13 Func 42 - Extended Read Sectors
350 ;
351 ; Arguments:
352 ; AH = 0x42
353 ; DL = drive number (80h + drive unit)
354 ; DS:SI = pointer to Disk Address Packet
355 ;
356 ; Returns:
357 ; AH = return status (sucess is 0)
358 ; carry = 0 success
359 ; 1 error
360 ;
361 ; Packet offset 2 indicates the number of sectors read
362 ; successfully.
363 ;
364 ; mov dl, kDriveNumber
365 mov si, sp
366 mov ah, 0x42
367 int 0x13
368
369 jnc .exit
370
371 %if DEBUG
372 call print_hex
373 %endif
374 DebugChar('R') ; indicate INT13/F42 error
375
376 ;
377 ; Issue a disk reset on error.
378 ; Should this be changed to Func 0xD to skip the diskette controller
379 ; reset?
380 ;
381 xor ax, ax ; Func 0
382 int 0x13 ; INT 13
383 stc ; set carry to indicate error
384
385 .exit:
386 mov sp, bp ; restore SP
387 popad
388 ret
389
390 ;-------------------------------------------------------------------------
391 ; Write a string to the console.
392 ;
393 ; Arguments:
394 ; DS:SI pointer to a NULL terminated string.
395 ;
396 ; Clobber list:
397 ; AX, BX, SI
398 ;
399 print_string
400 mov bx, 1 ; BH=0, BL=1 (blue)
401 cld ; increment SI after each lodsb call
402 .loop
403 lodsb ; load a byte from DS:SI into AL
404 cmp al, 0 ; Is it a NULL?
405 je .exit ; yes, all done
406 mov ah, 0xE ; INT10 Func 0xE
407 int 0x10 ; display byte in tty mode
408 jmp short .loop
409 .exit
410 ret
411
412 %if DEBUG
413
414 ;--------------------------------------------------------------------------
415 ; Write a ASCII character to the console.
416 ;
417 ; Arguments:
418 ; AL = ASCII character.
419 ;
420 print_char
421 pushad
422 mov bx, 1 ; BH=0, BL=1 (blue)
423 mov ah, 0x0e ; bios INT 10, Function 0xE
424 int 0x10 ; display byte in tty mode
425 popad
426 ret
427
428 ;--------------------------------------------------------------------------
429 ; Write a variable number of spaces to the console.
430 ;
431 ; Arguments:
432 ; AL = number to spaces.
433 ;
434 print_spaces:
435 pushad
436 xor cx, cx
437 mov cl, al ; use CX as the loop counter
438 mov al, ' ' ; character to print
439 .loop:
440 jcxz .exit
441 call print_char
442 loop .loop
443 .exit:
444 popad
445 ret
446
447 ;--------------------------------------------------------------------------
448 ; Write the byte value to the console in hex.
449 ;
450 ; Arguments:
451 ; AL = Value to be displayed in hex.
452 ;
453 print_hex:
454 pushad
455 mov cx, WORD 4
456 bswap eax
457 .loop
458 push ax
459 ror al, 4
460 call print_nibble ; display upper nibble
461 pop ax
462 call print_nibble ; display lower nibble
463 ror eax, 8
464 loop .loop
465
466 mov al, 10 ; carriage return
467 call print_char
468 mov al, 13
469 call print_char
470 popad
471 ret
472
473 print_nibble:
474 and al, 0x0f
475 add al, '0'
476 cmp al, '9'
477 jna .print_ascii
478 add al, 'A' - '9' - 1
479 .print_ascii:
480 call print_char
481 ret
482
483 getc:
484 mov ah, 0
485 int 0x16
486 ret
487
488 %endif ; DEBUG
489
490 ;--------------------------------------------------------------------------
491 ; NULL terminated strings.
492 ;
493 ; boot_error_str db 10, 13, 'Error', 0
494 part_error_str db 10, 13, 'HFS+ partition error', 0
495 boot2_error_str db 10, 13, 'Error loading booter', 0
496
497 ;--------------------------------------------------------------------------
498 ; Pad the rest of the 512 byte sized booter with zeroes. The last
499 ; two bytes is the mandatory boot sector signature.
500 ;
501 ; If the booter code becomes too large, then nasm will complain
502 ; that the 'times' argument is negative.
503
504 pad_table_and_sig
505 times 510-($-$$) db 0
506 dw kBootSignature
507
508
509 ABSOLUTE 0xE400
510
511 ;
512 ; Variable storage area
513 ;
514 ebios_lba resd 1
515
516 END
517