1 ; Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
3 ; @APPLE_LICENSE_HEADER_START@
5 ; Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
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
14 ; The Original Code and all software distributed under the License are
15 ; distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 ; EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 ; INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
22 ; @APPLE_LICENSE_HEADER_END@
24 ; Partition Boot Loader: boot1h
26 ; This program is designed to reside in sector 0 of an HFS+ partition.
27 ; The HFS+ partition can be a primary or a logical partition.
28 ; It expects that the MBR has left the drive number in DL
29 ; and a pointer to the partition entry in SI.
31 ; This version requires a BIOS with EBIOS (LBA) support.
33 ; This code is written for the NASM assembler.
34 ; nasm boot0.s -o boot0
38 ; Set to 1 to enable obscure debug messages.
43 ; Set to 1 to support loading the booter (boot2) from a
46 EXT_PART_SUPPORT EQU 0
51 kBoot0Segment EQU 0x0000
52 kBoot0Stack EQU 0xFFF0 ; boot0 stack pointer
53 kBoot0LoadAddr EQU 0x7C00 ; boot0 load address
54 kBoot0RelocAddr EQU 0xE000 ; boot0 relocated address
56 ebios_lba EQU 0xEF00 ; storage for variables
58 kMBRBuffer EQU 0x1000 ; MBR buffer address
59 kExtBuffer EQU 0x1200 ; EXT boot block buffer address
61 kPartTableOffset EQU 0x1be
62 kMBRPartTable EQU kMBRBuffer + kPartTableOffset
63 kExtPartTable EQU kExtBuffer + kPartTableOffset
65 kBoot2Sectors EQU 112 ; sectors to load for boot2
66 kBoot2Address EQU 0x0000 ; boot2 load address
67 kBoot2Segment EQU 0x2000 ; boot2 load segment
69 kSectorBytes EQU 512 ; sector size in bytes
70 kBootSignature EQU 0xAA55 ; boot sector signature
72 kPartCount EQU 4 ; number of paritions per table
73 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
84 kHFSSig EQU 0x4442 ; HFS volume signature
85 kAlBlStOffset EQU 0x1c
86 kEmbedStartOffset EQU 0x7e
87 kAlBlkSizOffset EQU 0x14
92 kHFSPlusSig EQU 0x2B48 ; HFS+ volume signature
93 kBlockSizeOffset EQU 0x28
94 kExtentOffset EQU 0x1c0
96 kHFSBuffer EQU 0x1400 ; HFS volume header address
98 kHFSSigAddr EQU kHFSBuffer
99 kHFSAlBlSt EQU kHFSBuffer + kAlBlStOffset
100 kHFSEmbedStart EQU kHFSBuffer + kEmbedStartOffset
101 kHFSAlBlkSiz EQU kHFSBuffer + kAlBlkSizOffset
103 kHFSPlusSigAddr EQU kHFSBuffer
104 kHFSPlusBlockSize EQU kHFSBuffer + kBlockSizeOffset
105 kHFSPlusExtent EQU kHFSBuffer + kExtentOffset
109 kDriveNumber EQU 0x00
111 kDriveNumber EQU 0x80
115 ; Format of fdisk partition entry.
117 ; The symbol 'part_size' is automatically defined as an `EQU'
118 ; giving the size of the structure.
121 .bootid: resb 1 ; bootable or not
122 .head: resb 1 ; starting head, sector, cylinder
125 .type: resb 1 ; partition type
126 .endhead resb 1 ; ending head, sector, cylinder
129 .lba: resd 1 ; starting lba
130 .sectors resd 1 ; size in sectors
136 %macro DebugCharMacro 1
143 %define DebugChar(x) DebugCharMacro x
149 ;--------------------------------------------------------------------------
150 ; Start of text segment.
154 ORG 0xE000 ; must match kBoot0RelocAddr
156 ;--------------------------------------------------------------------------
157 ; Boot code is loaded at 0:7C00h.
161 ; Set up the stack to grow down from kBoot0Segment:kBoot0Stack.
162 ; Interrupts should be off while the stack is being manipulated.
167 mov sp, kBoot0Stack ; sp <- top of stack
168 sti ; reenable interrupts
176 mov eax, [si + part.lba]
181 ; Clear various flags in memory.
184 mov [ebios_lba], eax ; clear EBIOS LBA offset
186 cmp BYTE [si + part.type], kPartTypeHFS
188 cmp BYTE [si + part.bootid], kPartActive
197 ;;; ---------------------------------------
199 ;;; find_startup - Find HFS+ startup file in a partition.
202 ;;; DL = drive number (0x80 + unit number)
203 ;;; SI = pointer to the partition entry.
205 ;;; On success, loads booter and jumps to it.
210 mov al, 1 ; read 1 sector
213 mov bx, kHFSBuffer ; load volume header
221 mov ax, [kHFSSigAddr]
226 mov ebx, [kHFSAlBlkSiz]
231 mov ax, [kHFSEmbedStart]
232 xchg al, ah ; byte-swap
234 mul ebx ; result in eax
239 xchg bl, bh ; byte-swap
242 ;; now eax has sector of HFS+ partition
247 mov al, 1 ; read 1 sector
250 mov bx, kHFSBuffer ; load volume header
252 jc startup_err ; load error
256 mov ax, [kHFSPlusSigAddr]
260 ;;; Now the HFS+ volume header is in our buffer.
263 mov eax, [kHFSPlusBlockSize]
267 mov ebx, [kHFSPlusExtent]
270 mul ebx ; result in eax
275 ; add [ebios_lba], eax ; offset to startup file
276 ; mov ecx, [ebios_lba]
281 mov al, kBoot2Sectors
282 mov bx, kBoot2Segment
284 mov bx, kBoot2Address + kSectorBytes
290 ; Jump to boot2. The drive number is already in register DL.
292 jmp kBoot2Segment:kBoot2Address + kSectorBytes
302 ;--------------------------------------------------------------------------
303 ; load - Load one or more sectors from a partition.
306 ; AL = number of 512-byte sectors to read.
307 ; ES:BX = pointer to where the sectors should be stored.
308 ; ECX = sector offset in partition
309 ; DL = drive number (0x80 + unit number)
310 ; SI = pointer to the partition entry.
320 ; ; mov cx, 5 ; load retry count
322 ; call read_lba ; use INT13/F42
331 ;--------------------------------------------------------------------------
332 ; read_lba - Read sectors from a partition using LBA addressing.
335 ; AL = number of 512-byte sectors to read (valid from 1-127).
336 ; ES:BX = pointer to where the sectors should be stored.
337 ; ECX = sector offset in partition
338 ; DL = drive number (0x80 + unit number)
339 ; SI = pointer to the partition entry.
347 pushad ; save all registers
348 mov bp, sp ; save current SP
351 ; Create the Disk Address Packet structure for the
352 ; INT13/F42 (Extended Read Sectors) on the stack.
355 ; push DWORD 0 ; offset 12, upper 32-bit LBA
356 push ds ; For sake of saving memory,
357 push ds ; push DS register, which is 0.
359 add ecx, [ebios_lba] ; offset 8, lower 32-bit LBA
360 add ecx, [si + part.lba]
364 push es ; offset 6, memory segment
366 push bx ; offset 4, memory offset
368 xor ah, ah ; offset 3, must be 0
369 push ax ; offset 2, number of sectors
373 DebugChar('-') ; absolute sector offset
376 DebugChar('=') ; count
381 push WORD 16 ; offset 0-1, packet size
384 ; INT13 Func 42 - Extended Read Sectors
388 ; DL = drive number (80h + drive unit)
389 ; DS:SI = pointer to Disk Address Packet
392 ; AH = return status (sucess is 0)
396 ; Packet offset 2 indicates the number of sectors read
399 ; mov dl, kDriveNumber
409 DebugChar('R') ; indicate INT13/F42 error
412 ; Issue a disk reset on error.
413 ; Should this be changed to Func 0xD to skip the diskette controller
418 stc ; set carry to indicate error
421 mov sp, bp ; restore SP
426 ;-------------------------------------------------------------------------
427 ; Write a string to the console.
430 ; DS:SI pointer to a NULL terminated string.
436 mov bx, 1 ; BH=0, BL=1 (blue)
437 cld ; increment SI after each lodsb call
439 lodsb ; load a byte from DS:SI into AL
440 cmp al, 0 ; Is it a NULL?
441 je .exit ; yes, all done
442 mov ah, 0xE ; INT10 Func 0xE
443 int 0x10 ; display byte in tty mode
451 ;--------------------------------------------------------------------------
452 ; Write a ASCII character to the console.
455 ; AL = ASCII character.
459 mov bx, 1 ; BH=0, BL=1 (blue)
460 mov ah, 0x0e ; bios INT 10, Function 0xE
461 int 0x10 ; display byte in tty mode
465 ;--------------------------------------------------------------------------
466 ; Write a variable number of spaces to the console.
469 ; AL = number to spaces.
474 mov cl, al ; use CX as the loop counter
475 mov al, ' ' ; character to print
484 ;--------------------------------------------------------------------------
485 ; Write the byte value to the console in hex.
488 ; AL = Value to be displayed in hex.
497 call print_nibble ; display upper nibble
499 call print_nibble ; display lower nibble
503 mov al, 10 ; carriage return
515 add al, 'A' - '9' - 1
527 ;--------------------------------------------------------------------------
528 ; NULL terminated strings.
530 ; boot_error_str db 10, 13, 'Error', 0
532 ;--------------------------------------------------------------------------
533 ; Pad the rest of the 512 byte sized booter with zeroes. The last
534 ; two bytes is the mandatory boot sector signature.
536 ; If the booter code becomes too large, then nasm will complain
537 ; that the 'times' argument is negative.
540 times 510-($-$$) db 0
543 ;--------------------------------------------------------------------------
544 ; Put fake partition entries for the bootable floppy image
546 part1bootid db 0x80 ; first partition active
547 part1head db 0x00 ; head #
548 part1sect db 0x02 ; sector # (low 6 bits)
549 part1cyl db 0x00 ; cylinder # (+ high 2 bits of above)
550 part1systid db 0xab ; Apple boot partition
551 times 3 db 0x00 ; ignore head/cyl/sect #'s
552 part1relsect dd 0x00000001 ; start at sector 1
553 part1numsect dd 0x00000080 ; 64K for booter
554 part2bootid db 0x00 ; not active
555 times 3 db 0x00 ; ignore head/cyl/sect #'s
556 part2systid db 0xa8 ; Apple UFS partition
557 times 3 db 0x00 ; ignore head/cyl/sect #'s
558 part2relsect dd 0x00000082 ; start after booter
559 ; part2numsect dd 0x00000abe ; 1.44MB - 65K
560 part2numsect dd 0x000015fe ; 2.88MB - 65K
564 times 510-($-$$) db 0