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