]> git.saurik.com Git - apple/boot.git/blame - i386/boot1/boot1.s
boot-132.tar.gz
[apple/boot.git] / i386 / boot1 / boot1.s
CommitLineData
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;
f083c6c3 23; Partition Boot Loader: boot1h
14c7c974 24;
f083c6c3
A
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.
14c7c974 29;
f083c6c3 30; This version requires a BIOS with EBIOS (LBA) support.
14c7c974
A
31;
32; This code is written for the NASM assembler.
33; nasm boot0.s -o boot0
34
75b89a82 35
f083c6c3
A
36;
37; Set to 1 to enable obscure debug messages.
38;
39DEBUG EQU 0
14c7c974 40
f083c6c3
A
41;
42; Various constants.
43;
44kBoot0Segment EQU 0x0000
45kBoot0Stack EQU 0xFFF0 ; boot0 stack pointer
46kBoot0LoadAddr EQU 0x7C00 ; boot0 load address
47kBoot0RelocAddr EQU 0xE000 ; boot0 relocated address
14c7c974 48
f083c6c3
A
49kMBRBuffer EQU 0x1000 ; MBR buffer address
50kExtBuffer EQU 0x1200 ; EXT boot block buffer address
14c7c974 51
f083c6c3
A
52kPartTableOffset EQU 0x1be
53kMBRPartTable EQU kMBRBuffer + kPartTableOffset
54kExtPartTable EQU kExtBuffer + kPartTableOffset
14c7c974 55
57c72a9a 56kBoot2Sectors EQU 126 ; sectors to load for boot2
f083c6c3
A
57kBoot2Address EQU 0x0000 ; boot2 load address
58kBoot2Segment EQU 0x2000 ; boot2 load segment
75b89a82 59
f083c6c3
A
60kSectorBytes EQU 512 ; sector size in bytes
61kBootSignature EQU 0xAA55 ; boot sector signature
14c7c974 62
f083c6c3
A
63kPartCount EQU 4 ; number of paritions per table
64kPartTypeBoot EQU 0xab ; boot2 partition type
65kPartTypeHFS EQU 0xaf
66kPartTypeExtDOS EQU 0x05 ; DOS extended partition type
67kPartTypeExtWin EQU 0x0f ; Windows extended partition type
68kPartTypeExtLinux EQU 0x85 ; Linux extended partition type
69
70kPartActive EQU 0x80
14c7c974 71
f083c6c3
A
72;;
73;; HFS constants
74;;
75kHFSSig EQU 0x4442 ; HFS volume signature
76kAlBlStOffset EQU 0x1c
77kEmbedStartOffset EQU 0x7e
78kAlBlkSizOffset EQU 0x14
14c7c974 79
f083c6c3
A
80;;
81;; HFS+ constants
82;;
83kHFSPlusSig EQU 0x2B48 ; HFS+ volume signature
57c72a9a 84kHFSXSig EQU 0x5848 ; HFSX volume signature
f083c6c3
A
85kBlockSizeOffset EQU 0x28
86kExtentOffset EQU 0x1c0
87
88kHFSBuffer EQU 0x1400 ; HFS volume header address
14c7c974 89
f083c6c3
A
90kHFSSigAddr EQU kHFSBuffer
91kHFSAlBlSt EQU kHFSBuffer + kAlBlStOffset
92kHFSEmbedStart EQU kHFSBuffer + kEmbedStartOffset
93kHFSAlBlkSiz EQU kHFSBuffer + kAlBlkSizOffset
14c7c974 94
f083c6c3
A
95kHFSPlusSigAddr EQU kHFSBuffer
96kHFSPlusBlockSize EQU kHFSBuffer + kBlockSizeOffset
97kHFSPlusExtent EQU kHFSBuffer + kExtentOffset
14c7c974 98
14c7c974 99
f083c6c3 100kDriveNumber EQU 0x80
14c7c974 101
14c7c974 102;
f083c6c3 103; Format of fdisk partition entry.
14c7c974 104;
f083c6c3
A
105; The symbol 'part_size' is automatically defined as an `EQU'
106; giving the size of the structure.
14c7c974 107;
f083c6c3
A
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
14c7c974 120
f083c6c3
A
121;
122; Macros.
123;
124%macro DebugCharMacro 1
125 mov al, %1
126 call print_char
127 call getc
128%endmacro
14c7c974 129
57c72a9a
A
130%macro PrintString 1
131 mov si, %1
132 call print_string
133%endmacro
134
f083c6c3
A
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.
14c7c974 144
f083c6c3 145 SEGMENT .text
14c7c974 146
57c72a9a 147 ORG 0x7C00 ; must match kBoot0RelocAddr
14c7c974 148
f083c6c3
A
149;--------------------------------------------------------------------------
150; Boot code is loaded at 0:7C00h.
151;
152start
14c7c974 153 ;
f083c6c3
A
154 ; Set up the stack to grow down from kBoot0Segment:kBoot0Stack.
155 ; Interrupts should be off while the stack is being manipulated.
14c7c974 156 ;
f083c6c3
A
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
14c7c974 162
f083c6c3
A
163 mov es, ax ; es <- 0
164 mov ds, ax ; ds <- 0
14c7c974 165
f083c6c3 166 DebugChar('H')
75b89a82 167
f083c6c3
A
168%if DEBUG
169 mov eax, [si + part.lba]
170 call print_hex
171%endif
14c7c974 172
14c7c974 173 ;
f083c6c3 174 ; Clear various flags in memory.
14c7c974 175 ;
f083c6c3
A
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
f083c6c3
A
181
182 jmp find_startup
183
184.part_err:
57c72a9a 185 PrintString(part_error_str)
f083c6c3
A
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;;;
198find_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
14c7c974 206 call load
f083c6c3
A
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
57c72a9a
A
249 je .hfs_plus2
250 cmp ax, kHFSXSig
f083c6c3
A
251 jne startup_err
252
253;;; Now the HFS+ volume header is in our buffer.
254
57c72a9a 255.hfs_plus2
f083c6c3
A
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
f083c6c3
A
269 add ecx, eax
270
271 DebugChar('!')
272
273 mov al, kBoot2Sectors
274 mov bx, kBoot2Segment
75b89a82 275 mov es, bx
f083c6c3
A
276 mov bx, kBoot2Address + kSectorBytes
277 call load
278 jc startup_err
14c7c974 279
f083c6c3
A
280 DebugChar('Y')
281 ;
282 ; Jump to boot2. The drive number is already in register DL.
283 ;
284 jmp kBoot2Segment:kBoot2Address + kSectorBytes
285
286startup_err:
75b89a82 287
57c72a9a 288 PrintString(boot2_error_str)
f083c6c3
A
289 DebugChar('X')
290
291hang:
292 hlt
293 jmp SHORT hang
14c7c974 294
14c7c974
A
295
296;--------------------------------------------------------------------------
f083c6c3 297; read_lba - Read sectors from a partition using LBA addressing.
14c7c974
A
298;
299; Arguments:
f083c6c3
A
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.
14c7c974
A
305;
306; Returns:
307; CF = 0 success
f083c6c3 308; 1 error
14c7c974 309;
f083c6c3
A
310read_lba:
311load:
312 pushad ; save all registers
313 mov bp, sp ; save current SP
314
57c72a9a 315 ;
f083c6c3
A
316 ; Create the Disk Address Packet structure for the
317 ; INT13/F42 (Extended Read Sectors) on the stack.
318 ;
14c7c974 319
f083c6c3
A
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.
14c7c974 323
f083c6c3
A
324 add ecx, [ebios_lba] ; offset 8, lower 32-bit LBA
325 add ecx, [si + part.lba]
14c7c974 326
f083c6c3 327 push ecx
14c7c974 328
f083c6c3 329 push es ; offset 6, memory segment
14c7c974 330
f083c6c3 331 push bx ; offset 4, memory offset
14c7c974 332
f083c6c3
A
333 xor ah, ah ; offset 3, must be 0
334 push ax ; offset 2, number of sectors
14c7c974 335
f083c6c3
A
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
14c7c974 347
57c72a9a 348 ;
f083c6c3 349 ; INT13 Func 42 - Extended Read Sectors
57c72a9a 350 ;
f083c6c3
A
351 ; Arguments:
352 ; AH = 0x42
353 ; DL = drive number (80h + drive unit)
354 ; DS:SI = pointer to Disk Address Packet
57c72a9a 355 ;
f083c6c3
A
356 ; Returns:
357 ; AH = return status (sucess is 0)
358 ; carry = 0 success
359 ; 1 error
57c72a9a 360 ;
f083c6c3
A
361 ; Packet offset 2 indicates the number of sectors read
362 ; successfully.
14c7c974 363 ;
57c72a9a 364 ; mov dl, kDriveNumber
f083c6c3
A
365 mov si, sp
366 mov ah, 0x42
367 int 0x13
14c7c974 368
f083c6c3 369 jnc .exit
14c7c974 370
f083c6c3
A
371%if DEBUG
372 call print_hex
373%endif
374 DebugChar('R') ; indicate INT13/F42 error
14c7c974 375
14c7c974 376 ;
f083c6c3
A
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
14c7c974 384
f083c6c3
A
385.exit:
386 mov sp, bp ; restore SP
387 popad
14c7c974
A
388 ret
389
f083c6c3 390;-------------------------------------------------------------------------
14c7c974
A
391; Write a string to the console.
392;
393; Arguments:
f083c6c3 394; DS:SI pointer to a NULL terminated string.
14c7c974 395;
f083c6c3
A
396; Clobber list:
397; AX, BX, SI
14c7c974 398;
f083c6c3
A
399print_string
400 mov bx, 1 ; BH=0, BL=1 (blue)
14c7c974 401 cld ; increment SI after each lodsb call
f083c6c3
A
402.loop
403 lodsb ; load a byte from DS:SI into AL
14c7c974 404 cmp al, 0 ; Is it a NULL?
f083c6c3
A
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
14c7c974 410 ret
f083c6c3
A
411
412%if DEBUG
14c7c974
A
413
414;--------------------------------------------------------------------------
415; Write a ASCII character to the console.
416;
417; Arguments:
f083c6c3
A
418; AL = ASCII character.
419;
420print_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
14c7c974
A
426 ret
427
14c7c974
A
428;--------------------------------------------------------------------------
429; Write a variable number of spaces to the console.
430;
431; Arguments:
f083c6c3 432; AL = number to spaces.
14c7c974 433;
f083c6c3
A
434print_spaces:
435 pushad
14c7c974 436 xor cx, cx
f083c6c3 437 mov cl, al ; use CX as the loop counter
14c7c974 438 mov al, ' ' ; character to print
f083c6c3
A
439.loop:
440 jcxz .exit
441 call print_char
442 loop .loop
443.exit:
444 popad
14c7c974
A
445 ret
446
447;--------------------------------------------------------------------------
f083c6c3 448; Write the byte value to the console in hex.
14c7c974
A
449;
450; Arguments:
f083c6c3 451; AL = Value to be displayed in hex.
14c7c974 452;
f083c6c3
A
453print_hex:
454 pushad
455 mov cx, WORD 4
456 bswap eax
457.loop
14c7c974
A
458 push ax
459 ror al, 4
f083c6c3 460 call print_nibble ; display upper nibble
14c7c974 461 pop ax
f083c6c3
A
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
14c7c974
A
471 ret
472
f083c6c3 473print_nibble:
14c7c974
A
474 and al, 0x0f
475 add al, '0'
476 cmp al, '9'
f083c6c3 477 jna .print_ascii
14c7c974 478 add al, 'A' - '9' - 1
f083c6c3
A
479.print_ascii:
480 call print_char
14c7c974
A
481 ret
482
f083c6c3
A
483getc:
484 mov ah, 0
485 int 0x16
486 ret
14c7c974 487
f083c6c3 488%endif ; DEBUG
14c7c974
A
489
490;--------------------------------------------------------------------------
491; NULL terminated strings.
492;
f083c6c3 493; boot_error_str db 10, 13, 'Error', 0
57c72a9a
A
494part_error_str db 10, 13, 'HFS+ partition error', 0
495boot2_error_str db 10, 13, 'Error loading booter', 0
14c7c974
A
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
14c7c974
A
504pad_table_and_sig
505 times 510-($-$$) db 0
f083c6c3 506 dw kBootSignature
14c7c974 507
57c72a9a
A
508
509 ABSOLUTE 0xE400
510
511;
512; Variable storage area
513;
514ebios_lba resd 1
515
14c7c974 516 END
57c72a9a 517