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