]> git.saurik.com Git - apple/boot.git/blame - i386/boot1u/boot1u0.s
boot-122.tar.gz
[apple/boot.git] / i386 / boot1u / boot1u0.s
CommitLineData
57c72a9a 1; Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
f083c6c3
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.
f083c6c3
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
f083c6c3
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.
f083c6c3
A
20;
21; @APPLE_LICENSE_HEADER_END@
22;
23; Boot Loader: boot0
24;
25; A small boot sector program written in x86 assembly whose only
57c72a9a
A
26; responsibility is to load the booter into memory
27; and jump to the booter's entry point.
f083c6c3
A
28; The booter partition can be a primary or a logical partition.
29;
30; This boot loader can be placed at any of the following places:
57c72a9a
A
31; 1. Boot sector of an extended partition
32; 2. Boot sector of a primary partition
33; 3. Boot sector of a logical partition
34;
35; It expects that the MBR has left the drive number in DL
36; and a pointer to the partition entry in SI.
f083c6c3
A
37;
38; In order to coexist with a fdisk partition table (64 bytes), and
39; leave room for a two byte signature (0xAA55) in the end, boot0 is
40; restricted to 446 bytes (512 - 64 - 2). If boot0 did not have to
41; live in the MBR, then we would have 510 bytes to work with.
42;
43; boot0 is always loaded by the BIOS or another booter to 0:7C00h.
44;
45; This code is written for the NASM assembler.
46; nasm boot0.s -o boot0
47
48
49;
50; Set to 1 to enable obscure debug messages.
51;
52DEBUG EQU 0
53
54;
55; Set to 1 to support loading the booter (boot2) from a
56; logical partition.
57;
58EXT_PART_SUPPORT EQU 1
59
60;
61; Various constants.
62;
63kBoot0Segment EQU 0x0000
64kBoot0Stack EQU 0xFFF0 ; boot0 stack pointer
65kBoot0LoadAddr EQU 0x7C00 ; boot0 load address
66kBoot0RelocAddr EQU 0xE000 ; boot0 relocated address
67
68kMBRBuffer EQU 0x1000 ; MBR buffer address
69kExtBuffer EQU 0x1200 ; EXT boot block buffer address
70
71kPartTableOffset EQU 0x1be
72kMBRPartTable EQU kMBRBuffer + kPartTableOffset
73kExtPartTable EQU kExtBuffer + kPartTableOffset
74
75kBoot1uSectors EQU 16 ; sectors to load for boot2
76kBoot1uAddress EQU 0x0000 ; boot2 load address
77kBoot1uSegment EQU 0x1000 ; boot2 load segment
78
79kSectorBytes EQU 512 ; sector size in bytes
80kBootSignature EQU 0xAA55 ; boot sector signature
81
82kPartCount EQU 4 ; number of paritions per table
83kPartTypeBoot EQU 0xab ; boot2 partition type
84kPartTypeUFS EQU 0xa8 ;
85kPartTypeExtDOS EQU 0x05 ; DOS extended partition type
86kPartTypeExtWin EQU 0x0f ; Windows extended partition type
87kPartTypeExtLinux EQU 0x85 ; Linux extended partition type
88kPartActive EQU 0x80
89
90%ifdef FLOPPY
91kDriveNumber EQU 0x00
92%else
93kDriveNumber EQU 0x80
94%endif
95
f083c6c3
A
96;
97; Format of fdisk partition entry.
98;
99; The symbol 'part_size' is automatically defined as an `EQU'
100; giving the size of the structure.
101;
102 struc part
103.bootid: resb 1 ; bootable or not
104.head: resb 1 ; starting head, sector, cylinder
105.sect: resb 1 ;
106.cyl: resb 1 ;
107.type: resb 1 ; partition type
108.endhead resb 1 ; ending head, sector, cylinder
109.endsect: resb 1 ;
110.endcyl: resb 1 ;
111.lba: resd 1 ; starting lba
112.sectors resd 1 ; size in sectors
113 endstruc
114
115;
116; Macros.
117;
118%macro DebugCharMacro 1
119 mov al, %1
120 call print_char
121%endmacro
122
123%if DEBUG
124%define DebugChar(x) DebugCharMacro x
125%else
126%define DebugChar(x)
127%endif
128
129;--------------------------------------------------------------------------
130; Start of text segment.
131
132 SEGMENT .text
133
57c72a9a 134 ORG 0x7C00
f083c6c3
A
135
136;--------------------------------------------------------------------------
137; Boot code is loaded at 0:7C00h.
138;
139start
57c72a9a
A
140 DebugChar('!')
141%if DEBUG
142 mov al, dl
143 call print_hex
144%endif
f083c6c3
A
145 ;
146 ; Set up the stack to grow down from kBoot0Segment:kBoot0Stack.
147 ; Interrupts should be off while the stack is being manipulated.
148 ;
149 cli ; interrupts off
150 xor ax, ax ; zero ax
151 mov ss, ax ; ss <- 0
152 mov sp, kBoot0Stack ; sp <- top of stack
153 sti ; reenable interrupts
154
155 mov es, ax ; es <- 0
156 mov ds, ax ; ds <- 0
157
57c72a9a
A
158%if 0
159 ;
160 ; Save SI register.
161 ;
162 mov bx, si
163
f083c6c3 164 ;
57c72a9a 165 ; Relocate ourselves.
f083c6c3
A
166 ;
167 mov si, kBoot0LoadAddr ; si <- source
168 mov di, kBoot0RelocAddr ; di <- destination
169 ;
170 cld ; auto-increment SI and/or DI registers
171 mov cx, kSectorBytes/2 ; copy 256 words
172 repnz movsw ; repeat string move (word) operation
173
174 ; Code relocated, jump to start_reloc in relocated location.
175 ;
176 jmp 0:start_reloc
177
178;--------------------------------------------------------------------------
179; Start execution from the relocated location.
180;
181start_reloc:
57c72a9a
A
182%endif
183
f083c6c3
A
184 DebugChar('*')
185
f083c6c3
A
186.loop:
187
188%if DEBUG
189 mov al, dl
190 call print_hex
191%endif
192
193 ;
194 ; Clear various flags in memory.
195 ;
196 xor eax, eax
197 mov [ebios_lba], eax ; clear EBIOS LBA offset
198 mov [ebios_present], al ; clear EBIOS support flag
199
f083c6c3
A
200 ;
201 ; Check if EBIOS is supported for this hard drive.
202 ;
203 mov ah, 0x41 ; Function 0x41
204 mov bx, 0x55AA ; check signature
205; mov dl, kDriveNumber ; Drive number
206 int 0x13
207
208 ;
209 ; If successful, the return values are as follows:
210 ;
211 ; carry = 0
212 ; ah = major version of EBIOS extensions (0x21 = version 1.1)
213 ; al = altered
214 ; bx = 0xAA55
215 ; cx = support bits. bit 0 must be set for function 0x42.
216 ;
217 jc .ebios_check_done
218 cmp bx, 0xAA55 ; check BX = 0xAA55
219 jnz .ebios_check_done
220 test cl, 0x01 ; check enhanced drive read support
221 setnz [ebios_present] ; EBIOS supported, set flag
222 DebugChar('E') ; EBIOS supported
223.ebios_check_done:
224
57c72a9a 225 DebugChar('L')
f083c6c3 226
57c72a9a
A
227%if DEBUG
228 mov al, BYTE [si + part.type]
229 call print_hex
230%endif
231
232 ; Check to make sure our partition is the correct type.
233 cmp BYTE [si + part.type], kPartTypeUFS
234 je load_boot
f083c6c3 235
57c72a9a
A
236part_error:
237 ; Drat, the partition entry was the wrong type.
238 ; Print an error and hang.
239 mov si, part_error_str
f083c6c3
A
240 call print_string
241
242hang:
243 hlt
244 jmp SHORT hang
245
57c72a9a
A
246 ;--------------------------------------------------------------------------
247 ; Load the booter from the partition.
f083c6c3 248
57c72a9a 249load_boot:
f083c6c3
A
250
251 ;
252 ; Found boot partition, read boot1u image to memory.
253 ;
254 mov al, kBoot1uSectors
255 mov bx, kBoot1uSegment
256 mov es, bx
257 mov bx, kBoot1uAddress
258 call load ;
57c72a9a
A
259 jc part_error ; load error, keep looking?
260
261 DebugChar('^')
f083c6c3 262
f083c6c3
A
263 ;
264 ; Jump to boot1u. The drive number is already in register DL.
265 ;
266 ; The first sector loaded from the disk is reserved for the boot
267 ; block (boot1), adjust the jump location by adding a sector offset.
268 ;
269 jmp kBoot1uSegment:kBoot1uAddress + kSectorBytes
270
f083c6c3
A
271.exit:
272 ;
273 ; Boot partition not found. Giving up.
274 ;
275 pop si
276 pop cx
277 ret
278
279;--------------------------------------------------------------------------
280; load - Load one or more sectors from a partition.
281;
282; Arguments:
283; AL = number of 512-byte sectors to read.
284; ES:BX = pointer to where the sectors should be stored.
285; DL = drive number (0x80 + unit number)
286; SI = pointer to the partition entry.
287;
288; Returns:
289; CF = 0 success
290; 1 error
291;
292load:
293 push cx
294 test BYTE [ebios_present], 1
295 jz .chs
296
297.ebios:
298 mov cx, 5 ; load retry count
299.ebios_loop:
300 call read_lba ; use INT13/F42
301 jnc .exit
302 loop .ebios_loop
303
304.chs:
305 mov cx, 5 ; load retry count
306.chs_loop:
307 call read_chs ; use INT13/F2
308 jnc .exit
309 loop .chs_loop
310
311.exit
312 pop cx
313 ret
314
315;--------------------------------------------------------------------------
316; read_chs - Read sectors from a partition using CHS addressing.
317;
318; Arguments:
319; AL = number of 512-byte sectors to read.
320; ES:BX = pointer to where the sectors should be stored.
321; DL = drive number (0x80 + unit number)
322; SI = pointer to the partition entry.
323;
324; Returns:
325; CF = 0 success
326; 1 error
327;
328read_chs:
329 pusha ; save all registers
330
331 ;
332 ; Read the CHS start values from the partition entry.
333 ;
334 mov dh, [ si + part.head ] ; drive head
335 mov cx, [ si + part.sect ] ; drive sector + cylinder
336
337 ;
338 ; INT13 Func 2 - Read Disk Sectors
339 ;
340 ; Arguments:
341 ; AH = 2
342 ; AL = number of sectors to read
343 ; CH = lowest 8 bits of the 10-bit cylinder number
344 ; CL = bits 6 & 7: cylinder number bits 8 and 9
345 ; bits 0 - 5: starting sector number (1-63)
346 ; DH = starting head number (0 to 255)
347 ; DL = drive number (80h + drive unit)
348 ; es:bx = pointer where to place sectors read from disk
349 ;
350 ; Returns:
351 ; AH = return status (sucess is 0)
352 ; AL = burst error length if ah=0x11 (ECC corrected)
353 ; carry = 0 success
354 ; 1 error
355 ;
356; mov dl, kDriveNumber
357 mov ah, 0x02 ; Func 2
358 int 0x13 ; INT 13
359 jnc .exit
360
361 DebugChar('r') ; indicate INT13/F2 error
362
363 ;
364 ; Issue a disk reset on error.
365 ; Should this be changed to Func 0xD to skip the diskette controller
366 ; reset?
367 ;
368 xor ax, ax ; Func 0
369 int 0x13 ; INT 13
370 stc ; set carry to indicate error
371
372.exit:
373 popa
374 ret
375
376;--------------------------------------------------------------------------
377; read_lba - Read sectors from a partition using LBA addressing.
378;
379; Arguments:
380; AL = number of 512-byte sectors to read (valid from 1-127).
381; ES:BX = pointer to where the sectors should be stored.
382; DL = drive number (0x80 + unit number)
383; SI = pointer to the partition entry.
384;
385; Returns:
386; CF = 0 success
387; 1 error
388;
389read_lba:
390 pusha ; save all registers
391 mov bp, sp ; save current SP
392
393 ;
394 ; Create the Disk Address Packet structure for the
395 ; INT13/F42 (Extended Read Sectors) on the stack.
396 ;
397
398 ; push DWORD 0 ; offset 12, upper 32-bit LBA
399 push ds ; For sake of saving memory,
400 push ds ; push DS register, which is 0.
401
402 mov ecx, [ebios_lba] ; offset 8, lower 32-bit LBA
403 add ecx, [si + part.lba]
404 push ecx
405
406 push es ; offset 6, memory segment
407
408 push bx ; offset 4, memory offset
409
410 xor ah, ah ; offset 3, must be 0
411 push ax ; offset 2, number of sectors
412
413 push WORD 16 ; offset 0-1, packet size
414
415 ;
416 ; INT13 Func 42 - Extended Read Sectors
417 ;
418 ; Arguments:
419 ; AH = 0x42
420 ; DL = drive number (80h + drive unit)
421 ; DS:SI = pointer to Disk Address Packet
422 ;
423 ; Returns:
424 ; AH = return status (sucess is 0)
425 ; carry = 0 success
426 ; 1 error
427 ;
428 ; Packet offset 2 indicates the number of sectors read
429 ; successfully.
430 ;
431; mov dl, kDriveNumber
432 mov si, sp
433 mov ah, 0x42
434 int 0x13
435
436 jnc .exit
437
438 DebugChar('R') ; indicate INT13/F42 error
439
440 ;
441 ; Issue a disk reset on error.
442 ; Should this be changed to Func 0xD to skip the diskette controller
443 ; reset?
444 ;
445 xor ax, ax ; Func 0
446 int 0x13 ; INT 13
447 stc ; set carry to indicate error
448
449.exit:
450 mov sp, bp ; restore SP
451 popa
452 ret
453
454;--------------------------------------------------------------------------
455; Write a string to the console.
456;
457; Arguments:
458; DS:SI pointer to a NULL terminated string.
459;
460; Clobber list:
461; AX, BX, SI
462;
463print_string
464 mov bx, 1 ; BH=0, BL=1 (blue)
465 cld ; increment SI after each lodsb call
466.loop
467 lodsb ; load a byte from DS:SI into AL
468 cmp al, 0 ; Is it a NULL?
469 je .exit ; yes, all done
470 mov ah, 0xE ; INT10 Func 0xE
471 int 0x10 ; display byte in tty mode
472 jmp short .loop
473.exit
474 ret
475
476%if DEBUG
477
478;--------------------------------------------------------------------------
479; Write a ASCII character to the console.
480;
481; Arguments:
482; AL = ASCII character.
483;
484print_char
485 pusha
486 mov bx, 1 ; BH=0, BL=1 (blue)
487 mov ah, 0x0e ; bios INT 10, Function 0xE
488 int 0x10 ; display byte in tty mode
489 popa
490 ret
491
f083c6c3
A
492;--------------------------------------------------------------------------
493; Write the byte value to the console in hex.
494;
495; Arguments:
496; AL = Value to be displayed in hex.
497;
498print_hex:
499 push ax
500 ror al, 4
501 call print_nibble ; display upper nibble
502 pop ax
503 call print_nibble ; display lower nibble
504
505 mov al, 10 ; carriage return
506 call print_char
507 mov al, 13
508 call print_char
509 ret
510
511print_nibble:
512 and al, 0x0f
513 add al, '0'
514 cmp al, '9'
515 jna .print_ascii
516 add al, 'A' - '9' - 1
517.print_ascii:
518 call print_char
519 ret
520
521%endif ; DEBUG
522
523;--------------------------------------------------------------------------
524; NULL terminated strings.
525;
57c72a9a 526part_error_str db 10, 13, 'Error loading UFS partition', 0
f083c6c3
A
527
528;--------------------------------------------------------------------------
529; Pad the rest of the 512 byte sized booter with zeroes. The last
530; two bytes is the mandatory boot sector signature.
531;
532; If the booter code becomes too large, then nasm will complain
533; that the 'times' argument is negative.
534
535;;pad_boot
536 ;; times 446-($-$$) db 0
537
538%ifdef FLOPPY
539;--------------------------------------------------------------------------
540; Put fake partition entries for the bootable floppy image
541;
542part1bootid db 0x80 ; first partition active
543part1head db 0x00 ; head #
544part1sect db 0x02 ; sector # (low 6 bits)
545part1cyl db 0x00 ; cylinder # (+ high 2 bits of above)
546part1systid db 0xab ; Apple boot partition
547times 3 db 0x00 ; ignore head/cyl/sect #'s
548part1relsect dd 0x00000001 ; start at sector 1
549part1numsect dd 0x00000080 ; 64K for booter
550part2bootid db 0x00 ; not active
551times 3 db 0x00 ; ignore head/cyl/sect #'s
552part2systid db 0xa8 ; Apple UFS partition
553times 3 db 0x00 ; ignore head/cyl/sect #'s
554part2relsect dd 0x00000082 ; start after booter
555; part2numsect dd 0x00000abe ; 1.44MB - 65K
556part2numsect dd 0x000015fe ; 2.88MB - 65K
557%endif
558
559pad_table_and_sig
560 times 510-($-$$) db 0
561 dw kBootSignature
562
57c72a9a
A
563 ABSOLUTE 0xE400
564
565;
566; In memory variables.
567;
568ebios_lba resd 1 ; starting LBA of the intial extended partition.
569ebios_present resb 1 ; 1 if EBIOS is supported, 0 otherwise.
570
f083c6c3 571 END