1 ; Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
3 ; @APPLE_LICENSE_HEADER_START@
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
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
21 ; @APPLE_LICENSE_HEADER_END@
23 ; Partition Boot Loader: boot1h
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.
30 ; This version requires a BIOS with EBIOS (LBA) support.
32 ; This code is written for the NASM assembler.
33 ; nasm boot0.s -o boot0
37 ; Set to 1 to enable obscure debug messages.
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
49 kMBRBuffer EQU 0x1000 ; MBR buffer address
50 kExtBuffer EQU 0x1200 ; EXT boot block buffer address
52 kPartTableOffset EQU 0x1be
53 kMBRPartTable EQU kMBRBuffer + kPartTableOffset
54 kExtPartTable EQU kExtBuffer + kPartTableOffset
56 kBoot2Sectors EQU 126 ; sectors to load for boot2
57 kBoot2Address EQU 0x0000 ; boot2 load address
58 kBoot2Segment EQU 0x2000 ; boot2 load segment
60 kSectorBytes EQU 512 ; sector size in bytes
61 kBootSignature EQU 0xAA55 ; boot sector signature
63 kPartCount EQU 4 ; number of paritions per table
64 kPartTypeBoot EQU 0xab ; boot2 partition type
66 kPartTypeExtDOS EQU 0x05 ; DOS extended partition type
67 kPartTypeExtWin EQU 0x0f ; Windows extended partition type
68 kPartTypeExtLinux EQU 0x85 ; Linux extended partition type
75 kHFSSig EQU 0x4442 ; HFS volume signature
76 kAlBlStOffset EQU 0x1c
77 kEmbedStartOffset EQU 0x7e
78 kAlBlkSizOffset EQU 0x14
83 kHFSPlusSig EQU 0x2B48 ; HFS+ volume signature
84 kHFSXSig EQU 0x5848 ; HFSX volume signature
85 kBlockSizeOffset EQU 0x28
86 kExtentOffset EQU 0x1c0
88 kHFSBuffer EQU 0x1400 ; HFS volume header address
90 kHFSSigAddr EQU kHFSBuffer
91 kHFSAlBlSt EQU kHFSBuffer + kAlBlStOffset
92 kHFSEmbedStart EQU kHFSBuffer + kEmbedStartOffset
93 kHFSAlBlkSiz EQU kHFSBuffer + kAlBlkSizOffset
95 kHFSPlusSigAddr EQU kHFSBuffer
96 kHFSPlusBlockSize EQU kHFSBuffer + kBlockSizeOffset
97 kHFSPlusExtent EQU kHFSBuffer + kExtentOffset
100 kDriveNumber EQU 0x80
103 ; Format of fdisk partition entry.
105 ; The symbol 'part_size' is automatically defined as an `EQU'
106 ; giving the size of the structure.
109 .bootid: resb 1 ; bootable or not
110 .head: resb 1 ; starting head, sector, cylinder
113 .type: resb 1 ; partition type
114 .endhead resb 1 ; ending head, sector, cylinder
117 .lba: resd 1 ; starting lba
118 .sectors resd 1 ; size in sectors
124 %macro DebugCharMacro 1
136 %define DebugChar(x) DebugCharMacro x
142 ;--------------------------------------------------------------------------
143 ; Start of text segment.
147 ORG 0x7C00 ; must match kBoot0RelocAddr
149 ;--------------------------------------------------------------------------
150 ; Boot code is loaded at 0:7C00h.
154 ; Set up the stack to grow down from kBoot0Segment:kBoot0Stack.
155 ; Interrupts should be off while the stack is being manipulated.
160 mov sp, kBoot0Stack ; sp <- top of stack
161 sti ; reenable interrupts
169 mov eax, [si + part.lba]
174 ; Clear various flags in memory.
177 mov [ebios_lba], eax ; clear EBIOS LBA offset
179 cmp BYTE [si + part.type], kPartTypeHFS
185 PrintString(part_error_str)
188 ;;; ---------------------------------------
190 ;;; find_startup - Find HFS+ startup file in a partition.
193 ;;; DL = drive number (0x80 + unit number)
194 ;;; SI = pointer to the partition entry.
196 ;;; On success, loads booter and jumps to it.
201 mov al, 1 ; read 1 sector
204 mov bx, kHFSBuffer ; load volume header
212 mov ax, [kHFSSigAddr]
217 mov ebx, [kHFSAlBlkSiz]
222 mov ax, [kHFSEmbedStart]
223 xchg al, ah ; byte-swap
225 mul ebx ; result in eax
230 xchg bl, bh ; byte-swap
233 ;; now eax has sector of HFS+ partition
238 mov al, 1 ; read 1 sector
241 mov bx, kHFSBuffer ; load volume header
243 jc startup_err ; load error
247 mov ax, [kHFSPlusSigAddr]
253 ;;; Now the HFS+ volume header is in our buffer.
257 mov eax, [kHFSPlusBlockSize]
261 mov ebx, [kHFSPlusExtent]
264 mul ebx ; result in eax
273 mov al, kBoot2Sectors
274 mov bx, kBoot2Segment
276 mov bx, kBoot2Address + kSectorBytes
282 ; Jump to boot2. The drive number is already in register DL.
284 jmp kBoot2Segment:kBoot2Address + kSectorBytes
288 PrintString(boot2_error_str)
296 ;--------------------------------------------------------------------------
297 ; read_lba - Read sectors from a partition using LBA addressing.
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.
312 pushad ; save all registers
313 mov bp, sp ; save current SP
316 ; Create the Disk Address Packet structure for the
317 ; INT13/F42 (Extended Read Sectors) on the stack.
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.
324 add ecx, [ebios_lba] ; offset 8, lower 32-bit LBA
325 add ecx, [si + part.lba]
329 push es ; offset 6, memory segment
331 push bx ; offset 4, memory offset
333 xor ah, ah ; offset 3, must be 0
334 push ax ; offset 2, number of sectors
338 DebugChar('-') ; absolute sector offset
341 DebugChar('=') ; count
346 push WORD 16 ; offset 0-1, packet size
349 ; INT13 Func 42 - Extended Read Sectors
353 ; DL = drive number (80h + drive unit)
354 ; DS:SI = pointer to Disk Address Packet
357 ; AH = return status (sucess is 0)
361 ; Packet offset 2 indicates the number of sectors read
364 ; mov dl, kDriveNumber
374 DebugChar('R') ; indicate INT13/F42 error
377 ; Issue a disk reset on error.
378 ; Should this be changed to Func 0xD to skip the diskette controller
383 stc ; set carry to indicate error
386 mov sp, bp ; restore SP
390 ;-------------------------------------------------------------------------
391 ; Write a string to the console.
394 ; DS:SI pointer to a NULL terminated string.
400 mov bx, 1 ; BH=0, BL=1 (blue)
401 cld ; increment SI after each lodsb call
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
414 ;--------------------------------------------------------------------------
415 ; Write a ASCII character to the console.
418 ; AL = ASCII character.
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
428 ;--------------------------------------------------------------------------
429 ; Write a variable number of spaces to the console.
432 ; AL = number to spaces.
437 mov cl, al ; use CX as the loop counter
438 mov al, ' ' ; character to print
447 ;--------------------------------------------------------------------------
448 ; Write the byte value to the console in hex.
451 ; AL = Value to be displayed in hex.
460 call print_nibble ; display upper nibble
462 call print_nibble ; display lower nibble
466 mov al, 10 ; carriage return
478 add al, 'A' - '9' - 1
490 ;--------------------------------------------------------------------------
491 ; NULL terminated strings.
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
497 ;--------------------------------------------------------------------------
498 ; Pad the rest of the 512 byte sized booter with zeroes. The last
499 ; two bytes is the mandatory boot sector signature.
501 ; If the booter code becomes too large, then nasm will complain
502 ; that the 'times' argument is negative.
505 times 510-($-$$) db 0
512 ; Variable storage area