1 ; Copyright (c) 1999-2002 Apple Computer, Inc. All rights reserved.
3 ; @APPLE_LICENSE_HEADER_START@
5 ; Portions Copyright (c) 1999-2002 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 1.2 (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.
42 ; Set to 1 to support loading the booter (boot2) from a
45 EXT_PART_SUPPORT EQU 0
50 kBoot0Segment EQU 0x0000
51 kBoot0Stack EQU 0xFFF0 ; boot0 stack pointer
52 kBoot0LoadAddr EQU 0x7C00 ; boot0 load address
53 kBoot0RelocAddr EQU 0xE000 ; boot0 relocated address
55 ebios_lba EQU 0xEF00 ; storage for variables
57 kMBRBuffer EQU 0x1000 ; MBR buffer address
58 kExtBuffer EQU 0x1200 ; EXT boot block buffer address
60 kPartTableOffset EQU 0x1be
61 kMBRPartTable EQU kMBRBuffer + kPartTableOffset
62 kExtPartTable EQU kExtBuffer + kPartTableOffset
64 kBoot2Sectors EQU 112 ; sectors to load for boot2
65 kBoot2Address EQU 0x0000 ; boot2 load address
66 kBoot2Segment EQU 0x2000 ; boot2 load segment
68 kSectorBytes EQU 512 ; sector size in bytes
69 kBootSignature EQU 0xAA55 ; boot sector signature
71 kPartCount EQU 4 ; number of paritions per table
72 kPartTypeBoot EQU 0xab ; boot2 partition type
74 kPartTypeExtDOS EQU 0x05 ; DOS extended partition type
75 kPartTypeExtWin EQU 0x0f ; Windows extended partition type
76 kPartTypeExtLinux EQU 0x85 ; Linux extended partition type
83 kHFSSig EQU 0x4442 ; HFS volume signature
84 kAlBlStOffset EQU 0x1c
85 kEmbedStartOffset EQU 0x7e
86 kAlBlkSizOffset EQU 0x14
91 kHFSPlusSig EQU 0x2B48 ; HFS+ volume signature
92 kBlockSizeOffset EQU 0x28
93 kExtentOffset EQU 0x1c0
95 kHFSBuffer EQU 0x1400 ; HFS volume header address
97 kHFSSigAddr EQU kHFSBuffer
98 kHFSAlBlSt EQU kHFSBuffer + kAlBlStOffset
99 kHFSEmbedStart EQU kHFSBuffer + kEmbedStartOffset
100 kHFSAlBlkSiz EQU kHFSBuffer + kAlBlkSizOffset
102 kHFSPlusSigAddr EQU kHFSBuffer
103 kHFSPlusBlockSize EQU kHFSBuffer + kBlockSizeOffset
104 kHFSPlusExtent EQU kHFSBuffer + kExtentOffset
108 kDriveNumber EQU 0x00
110 kDriveNumber EQU 0x80
114 ; Format of fdisk partition entry.
116 ; The symbol 'part_size' is automatically defined as an `EQU'
117 ; giving the size of the structure.
120 .bootid: resb 1 ; bootable or not
121 .head: resb 1 ; starting head, sector, cylinder
124 .type: resb 1 ; partition type
125 .endhead resb 1 ; ending head, sector, cylinder
128 .lba: resd 1 ; starting lba
129 .sectors resd 1 ; size in sectors
135 %macro DebugCharMacro 1
142 %define DebugChar(x) DebugCharMacro x
148 ;--------------------------------------------------------------------------
149 ; Start of text segment.
153 ORG 0xE000 ; must match kBoot0RelocAddr
155 ;--------------------------------------------------------------------------
156 ; Boot code is loaded at 0:7C00h.
160 ; Set up the stack to grow down from kBoot0Segment:kBoot0Stack.
161 ; Interrupts should be off while the stack is being manipulated.
166 mov sp, kBoot0Stack ; sp <- top of stack
167 sti ; reenable interrupts
175 mov eax, [si + part.lba]
180 ; Clear various flags in memory.
183 mov [ebios_lba], eax ; clear EBIOS LBA offset
185 cmp BYTE [si + part.type], kPartTypeHFS
187 cmp BYTE [si + part.bootid], kPartActive
196 ;;; ---------------------------------------
198 ;;; find_startup - Find HFS+ startup file in a partition.
201 ;;; DL = drive number (0x80 + unit number)
202 ;;; SI = pointer to the partition entry.
204 ;;; On success, loads booter and jumps to it.
209 mov al, 1 ; read 1 sector
212 mov bx, kHFSBuffer ; load volume header
220 mov ax, [kHFSSigAddr]
225 mov ebx, [kHFSAlBlkSiz]
230 mov ax, [kHFSEmbedStart]
231 xchg al, ah ; byte-swap
233 mul ebx ; result in eax
238 xchg bl, bh ; byte-swap
241 ;; now eax has sector of HFS+ partition
246 mov al, 1 ; read 1 sector
249 mov bx, kHFSBuffer ; load volume header
251 jc startup_err ; load error
255 mov ax, [kHFSPlusSigAddr]
259 ;;; Now the HFS+ volume header is in our buffer.
262 mov eax, [kHFSPlusBlockSize]
266 mov ebx, [kHFSPlusExtent]
269 mul ebx ; result in eax
274 ; add [ebios_lba], eax ; offset to startup file
275 ; mov ecx, [ebios_lba]
280 mov al, kBoot2Sectors
281 mov bx, kBoot2Segment
283 mov bx, kBoot2Address + kSectorBytes
289 ; Jump to boot2. The drive number is already in register DL.
291 jmp kBoot2Segment:kBoot2Address + kSectorBytes
301 ;--------------------------------------------------------------------------
302 ; load - Load one or more sectors from a partition.
305 ; AL = number of 512-byte sectors to read.
306 ; ES:BX = pointer to where the sectors should be stored.
307 ; ECX = sector offset in partition
308 ; DL = drive number (0x80 + unit number)
309 ; SI = pointer to the partition entry.
319 ; ; mov cx, 5 ; load retry count
321 ; call read_lba ; use INT13/F42
330 ;--------------------------------------------------------------------------
331 ; read_lba - Read sectors from a partition using LBA addressing.
334 ; AL = number of 512-byte sectors to read (valid from 1-127).
335 ; ES:BX = pointer to where the sectors should be stored.
336 ; ECX = sector offset in partition
337 ; DL = drive number (0x80 + unit number)
338 ; SI = pointer to the partition entry.
346 pushad ; save all registers
347 mov bp, sp ; save current SP
350 ; Create the Disk Address Packet structure for the
351 ; INT13/F42 (Extended Read Sectors) on the stack.
354 ; push DWORD 0 ; offset 12, upper 32-bit LBA
355 push ds ; For sake of saving memory,
356 push ds ; push DS register, which is 0.
358 add ecx, [ebios_lba] ; offset 8, lower 32-bit LBA
359 add ecx, [si + part.lba]
363 push es ; offset 6, memory segment
365 push bx ; offset 4, memory offset
367 xor ah, ah ; offset 3, must be 0
368 push ax ; offset 2, number of sectors
372 DebugChar('-') ; absolute sector offset
375 DebugChar('=') ; count
380 push WORD 16 ; offset 0-1, packet size
383 ; INT13 Func 42 - Extended Read Sectors
387 ; DL = drive number (80h + drive unit)
388 ; DS:SI = pointer to Disk Address Packet
391 ; AH = return status (sucess is 0)
395 ; Packet offset 2 indicates the number of sectors read
398 ; mov dl, kDriveNumber
408 DebugChar('R') ; indicate INT13/F42 error
411 ; Issue a disk reset on error.
412 ; Should this be changed to Func 0xD to skip the diskette controller
417 stc ; set carry to indicate error
420 mov sp, bp ; restore SP
425 ;-------------------------------------------------------------------------
426 ; Write a string to the console.
429 ; DS:SI pointer to a NULL terminated string.
435 mov bx, 1 ; BH=0, BL=1 (blue)
436 cld ; increment SI after each lodsb call
438 lodsb ; load a byte from DS:SI into AL
439 cmp al, 0 ; Is it a NULL?
440 je .exit ; yes, all done
441 mov ah, 0xE ; INT10 Func 0xE
442 int 0x10 ; display byte in tty mode
450 ;--------------------------------------------------------------------------
451 ; Write a ASCII character to the console.
454 ; AL = ASCII character.
458 mov bx, 1 ; BH=0, BL=1 (blue)
459 mov ah, 0x0e ; bios INT 10, Function 0xE
460 int 0x10 ; display byte in tty mode
464 ;--------------------------------------------------------------------------
465 ; Write a variable number of spaces to the console.
468 ; AL = number to spaces.
473 mov cl, al ; use CX as the loop counter
474 mov al, ' ' ; character to print
483 ;--------------------------------------------------------------------------
484 ; Write the byte value to the console in hex.
487 ; AL = Value to be displayed in hex.
496 call print_nibble ; display upper nibble
498 call print_nibble ; display lower nibble
502 mov al, 10 ; carriage return
514 add al, 'A' - '9' - 1
526 ;--------------------------------------------------------------------------
527 ; NULL terminated strings.
529 ; boot_error_str db 10, 13, 'Error', 0
531 ;--------------------------------------------------------------------------
532 ; Pad the rest of the 512 byte sized booter with zeroes. The last
533 ; two bytes is the mandatory boot sector signature.
535 ; If the booter code becomes too large, then nasm will complain
536 ; that the 'times' argument is negative.
539 times 510-($-$$) db 0
542 ;--------------------------------------------------------------------------
543 ; Put fake partition entries for the bootable floppy image
545 part1bootid db 0x80 ; first partition active
546 part1head db 0x00 ; head #
547 part1sect db 0x02 ; sector # (low 6 bits)
548 part1cyl db 0x00 ; cylinder # (+ high 2 bits of above)
549 part1systid db 0xab ; Apple boot partition
550 times 3 db 0x00 ; ignore head/cyl/sect #'s
551 part1relsect dd 0x00000001 ; start at sector 1
552 part1numsect dd 0x00000080 ; 64K for booter
553 part2bootid db 0x00 ; not active
554 times 3 db 0x00 ; ignore head/cyl/sect #'s
555 part2systid db 0xa8 ; Apple UFS partition
556 times 3 db 0x00 ; ignore head/cyl/sect #'s
557 part2relsect dd 0x00000082 ; start after booter
558 ; part2numsect dd 0x00000abe ; 1.44MB - 65K
559 part2numsect dd 0x000015fe ; 2.88MB - 65K
563 times 510-($-$$) db 0