| Commit | Line | Data |
|---|---|---|
| 409cbc03 | 1 | /* |
| cacaceec MD |
2 | * Copyright (c) 2003,2004 The DragonFly Project. All rights reserved. |
| 3 | * | |
| 4 | * This code is derived from software contributed to The DragonFly Project | |
| 5 | * by Matthew Dillon <dillon@backplane.com> | |
| 6 | * | |
| 7 | * Redistribution and use in source and binary forms, with or without | |
| 8 | * modification, are permitted provided that the following conditions | |
| 9 | * are met: | |
| 10 | * | |
| 11 | * 1. Redistributions of source code must retain the above copyright | |
| 12 | * notice, this list of conditions and the following disclaimer. | |
| 13 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 14 | * notice, this list of conditions and the following disclaimer in | |
| 15 | * the documentation and/or other materials provided with the | |
| 16 | * distribution. | |
| 17 | * 3. Neither the name of The DragonFly Project nor the names of its | |
| 18 | * contributors may be used to endorse or promote products derived | |
| 19 | * from this software without specific, prior written permission. | |
| 20 | * | |
| 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 24 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 25 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| 26 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| 27 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| 28 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| 29 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
| 30 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
| 31 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 32 | * SUCH DAMAGE. | |
| 33 | * | |
| 409cbc03 MD |
34 | * Copyright (c) 1998 Robert Nordier |
| 35 | * All rights reserved. | |
| 36 | * | |
| 37 | * Redistribution and use in source and binary forms are freely | |
| 38 | * permitted provided that the above copyright notice and this | |
| 39 | * paragraph and the following disclaimer are duplicated in all | |
| 40 | * such forms. | |
| 41 | * | |
| 42 | * This software is provided "AS IS" and without any express or | |
| 43 | * implied warranties, including, without limitation, the implied | |
| 44 | * warranties of merchantability and fitness for a particular | |
| 45 | * purpose. | |
| 46 | * | |
| 47 | * $FreeBSD: src/sys/boot/i386/boot2/boot1.s,v 1.23 2003/08/22 01:59:28 imp Exp $ | |
| 7580e818 | 48 | * $DragonFly: src/sys/boot/pc32/boot2/boot1.S,v 1.10 2008/09/13 11:45:45 corecode Exp $ |
| 409cbc03 | 49 | */ |
| 984263bc | 50 | |
| 409cbc03 | 51 | #include "../bootasm.h" |
| 984263bc | 52 | |
| 5ee58eed MD |
53 | // Partition Constants |
| 54 | .set PRT_OFF,0x1be // Partition offset | |
| 55 | .set PRT_NUM,0x4 // Partitions | |
| 56 | .set PRT_BSD,0xa5 // Partition type | |
| 984263bc | 57 | |
| 5ee58eed MD |
58 | // Flag Bits |
| 59 | .set FL_PACKET,0x80 // Packet mode | |
| 984263bc | 60 | |
| 5ee58eed MD |
61 | // Misc. Constants |
| 62 | .set SIZ_PAG,0x1000 // Page size | |
| 63 | .set SIZ_SEC,0x200 // Sector size | |
| 7580e818 | 64 | #ifndef NSECT |
| 5ee58eed | 65 | .set NSECT,0x10 |
| 7580e818 | 66 | #endif |
| 409cbc03 | 67 | |
| 984263bc MD |
68 | .globl start |
| 69 | .globl xread | |
| 70 | .code16 | |
| 71 | ||
| 5ee58eed | 72 | start: jmp main // Start recognizably |
| 984263bc | 73 | |
| 5ee58eed MD |
74 | // This is the start of a standard BIOS Parameter Block (BPB). Most bootable |
| 75 | // FAT disks have this at the start of their MBR. While normal BIOS's will | |
| 76 | // work fine without this section, IBM's El Torito emulation "fixes" up the | |
| 77 | // BPB by writing into the memory copy of the MBR. Rather than have data | |
| 78 | // written into our xread routine, we'll define a BPB to work around it. | |
| 79 | // The data marked with (T) indicates a field required for a ThinkPad to | |
| 80 | // recognize the disk and (W) indicates fields written from IBM BIOS code. | |
| 81 | // The use of the BPB is based on what OpenBSD and NetBSD implemented in | |
| 82 | // their boot code but the required fields were determined by trial and error. | |
| 83 | // | |
| 84 | // Note: If additional space is needed in boot1, one solution would be to | |
| 85 | // move the "prompt" message data (below) to replace the OEM ID. | |
| 984263bc MD |
86 | |
| 87 | .org 0x03, 0x00 | |
| 5ee58eed | 88 | oemid: .space 0x08, 0x00 // OEM ID |
| 984263bc MD |
89 | |
| 90 | .org 0x0b, 0x00 | |
| 5ee58eed MD |
91 | bpb: .word 512 // sector size (T) |
| 92 | .byte 0 // sectors/clustor | |
| 93 | .word 0 // reserved sectors | |
| 94 | .byte 0 // number of FATs | |
| 95 | .word 0 // root entries | |
| 96 | .word 0 // small sectors | |
| 97 | .byte 0 // media type (W) | |
| 98 | .word 0 // sectors/fat | |
| 99 | .word 18 // sectors per track (T) | |
| 100 | .word 2 // number of heads (T) | |
| 101 | .long 0 // hidden sectors (W) | |
| 102 | .long 0 // large sectors | |
| 984263bc MD |
103 | |
| 104 | .org 0x24, 0x00 | |
| 5ee58eed | 105 | ebpb: .byte 0 // BIOS physical drive number (W) |
| 984263bc MD |
106 | |
| 107 | .org 0x25,0x90 | |
| 5ee58eed MD |
108 | // |
| 109 | // Trampoline used by boot2 to call read to read data from the disk via | |
| 110 | // the BIOS. Call with: | |
| 111 | // | |
| 112 | // %cx:%ax - long - LBA to read in | |
| 113 | // %es:(%bx) - caddr_t - buffer to read data into | |
| 114 | // %dl - byte - drive to read from | |
| 115 | // %dh - byte - num sectors to read | |
| 116 | // | |
| 984263bc | 117 | |
| 5ee58eed MD |
118 | xread: push %ss // Address |
| 119 | pop %ds // data | |
| 120 | // | |
| 121 | // Setup an EDD disk packet and pass it to read | |
| 122 | // | |
| 123 | xread.1: // Starting | |
| 124 | pushl $0x0 // absolute | |
| 125 | push %cx // block | |
| 126 | push %ax // number | |
| 127 | push %es // Address of | |
| 128 | push %bx // transfer buffer | |
| 129 | xor %ax,%ax // Number of | |
| 130 | movb %dh,%al // blocks to | |
| 131 | push %ax // transfer | |
| 132 | push $0x10 // Size of packet | |
| 133 | mov %sp,%bp // Packet pointer | |
| 134 | callw read // Read from disk | |
| 135 | lea 0x10(%bp),%sp // Clear stack | |
| 136 | lret // To far caller | |
| 137 | // | |
| 138 | // Load the rest of boot2 and BTX up, copy the parts to the right locations, | |
| 139 | // and start it all up. | |
| 140 | // | |
| 984263bc | 141 | |
| 5ee58eed MD |
142 | // |
| 143 | // Setup the segment registers to flat addressing (segment 0) and setup the | |
| 144 | // stack to end just below the start of our code. | |
| 145 | // | |
| 146 | main: cld // String ops inc | |
| 147 | xor %cx,%cx // Zero | |
| 148 | mov %cx,%es // Address | |
| 149 | mov %cx,%ds // data | |
| 150 | mov %cx,%ss // Set up | |
| 151 | mov $start,%sp // stack | |
| 152 | // | |
| cacaceec MD |
153 | // Relocate ourself to BOOT1_ORIGIN. Since %cx == 0, the inc %ch sets |
| 154 | // %cx == 0x100 (256 words == 512 bytes). | |
| 5ee58eed MD |
155 | // |
| 156 | mov %sp,%si // Source | |
| cacaceec | 157 | mov $BOOT1_ORIGIN,%di // Destination |
| 5ee58eed MD |
158 | incb %ch // Word count |
| 159 | rep // Copy | |
| 160 | movsw // code | |
| 161 | // | |
| 162 | // If we are on a hard drive, then load the MBR and look for the first | |
| 163 | // FreeBSD slice. We use the fake partition entry below that points to | |
| 164 | // the MBR when we call nread. The first pass looks for the first active | |
| 165 | // FreeBSD slice. The second pass looks for the first non-active FreeBSD | |
| 166 | // slice if the first one fails. | |
| 167 | // | |
| 168 | mov $part4,%si // Partition | |
| 169 | cmpb $0x80,%dl // Hard drive? | |
| 170 | jb main.4 // No | |
| 171 | movb $0x1,%dh // Block count | |
| 172 | callw nread // Read MBR | |
| 173 | mov $0x1,%cx // Two passes | |
| 04144d62 | 174 | main.1: mov $BOOT2_LOAD_BUF+PRT_OFF,%si // Partition table |
| 5ee58eed MD |
175 | movb $0x1,%dh // Partition |
| 176 | main.2: cmpb $PRT_BSD,0x4(%si) // Our partition type? | |
| 177 | jne main.3 // No | |
| 178 | jcxz main.5 // If second pass | |
| 179 | testb $0x80,(%si) // Active? | |
| 180 | jnz main.5 // Yes | |
| 181 | main.3: add $0x10,%si // Next entry | |
| 182 | incb %dh // Partition | |
| 183 | cmpb $0x1+PRT_NUM,%dh // In table? | |
| 184 | jb main.2 // Yes | |
| 185 | dec %cx // Do two | |
| 186 | jcxz main.1 // passes | |
| 187 | // | |
| 188 | // If we get here, we didn't find any FreeBSD slices at all, so print an | |
| 189 | // error message and die. | |
| 190 | // | |
| 191 | mov $msg_part,%si // Message | |
| 192 | jmp error // Error | |
| 193 | // | |
| 194 | // Floppies use partition 0 of drive 0. | |
| 195 | // | |
| 196 | main.4: xor %dx,%dx // Partition:drive | |
| 197 | // | |
| 198 | // Ok, we have a slice and drive in %dx now, so use that to locate and load | |
| 199 | // boot2. %si references the start of the slice we are looking for, so go | |
| 04144d62 MD |
200 | // ahead and load up the first 16 sectors (boot1 + boot2) from that. |
| 201 | // | |
| 202 | // When we read it in, we conveniently use BOOT2_LOAD_BUF (0x8c00) as our | |
| 203 | // transfer buffer. Thus, boot1 ends up at 0x8c00, and boot2 starts at | |
| 204 | // 0x8c00 + 0x200 = 0x8e00. | |
| 205 | // | |
| 2d7f6790 | 206 | // The first part of boot2 is the disklabel, which is 0x200 bytes long. |
| 5ee58eed MD |
207 | // The second part is BTX, which is thus loaded into 0x9000, which is where |
| 208 | // it also runs from. The boot2.bin binary starts right after the end of | |
| 209 | // BTX, so we have to figure out where the start of it is and then move the | |
| 04144d62 MD |
210 | // binary to 0xc000. Normally, BTX clients start at MEM_BTX_USR, or 0xa000, |
| 211 | // but when we use btxld to create boot2, we use an entry point of 0x2000. | |
| 212 | // That entry point is relative to MEM_BTX_USR; thus boot2.bin starts | |
| 213 | // at 0xc000. | |
| 5ee58eed | 214 | // |
| cacaceec MD |
215 | // MEM_BTX_USR_ARG will be overwritten by the disk read and the relocation |
| 216 | // loop, so we must store the argument after completing said loops. | |
| 217 | // | |
| 218 | main.5: pushw %dx // Save args | |
| 5ee58eed | 219 | movb $NSECT,%dh // Sector count |
| 6080181b SS |
220 | #ifdef DISKLABEL64 |
| 221 | // In disklabel64 boot2 starts | |
| 222 | addl $7,0x8(%si) // offset 0x1000. | |
| 223 | #endif | |
| 5ee58eed | 224 | callw nread // Read disk |
| 4e06dda7 MD |
225 | mov $MEM_BTX_ORG,%bx // Base of BTX header |
| 226 | mov 0xa(%bx),%si // Get BTX text length (btx.S) | |
| 227 | add %bx,%si // %si = start of boot2.bin | |
| 228 | // %di = relocation target | |
| 229 | mov $MEM_BTX_USR+BOOT2_VORIGIN,%di | |
| 230 | mov $MEM_BTX_ORG+(NSECT-1)*SIZ_SEC,%cx | |
| 231 | sub %si,%cx // %cx = Size of boot2 client | |
| 232 | rep // Relocate boot2 | |
| 233 | movsb | |
| cacaceec | 234 | popw MEM_BTX_USR_ARG // save (disk,slice) for boot2 |
| 4e06dda7 MD |
235 | |
| 236 | #if 0 | |
| 237 | // XXX DISABLED. This makes incorrect assumptions about | |
| 238 | // where BSS begins, potentially leaving garbage in the BSS | |
| 239 | // space. The BSS zeroing code has been moved to | |
| 240 | // btx/lib/btxcsu.S (BTX client startup code) where we have | |
| 241 | // more definitive knowledge about where BSS resides. | |
| 242 | // | |
| 243 | // %cx now contains 0. Calculate 0x[1]0000 - %di to get a | |
| 244 | // count of assumed BSS bytes from the end of boot2.bin up | |
| 245 | // to 0x10000, then zero it out. | |
| 246 | // | |
| 247 | sub %di,%cx | |
| 248 | xorb %al,%al | |
| 249 | rep | |
| 250 | stosb | |
| 251 | #endif | |
| 5ee58eed | 252 | callw seta20 // Enable A20 |
| cacaceec MD |
253 | |
| 254 | // YYY | |
| 255 | pushw $MEM_BTX_ENTRY // Start BTX | |
| 256 | retw | |
| 5ee58eed MD |
257 | // |
| 258 | // Enable A20 so we can access memory above 1 meg. | |
| 259 | // | |
| 260 | seta20: cli // Disable interrupts | |
| 261 | seta20.1: inb $0x64,%al // Get status | |
| 262 | testb $0x2,%al // Busy? | |
| 263 | jnz seta20.1 // Yes | |
| 264 | movb $0xd1,%al // Command: Write | |
| 265 | outb %al,$0x64 // output port | |
| 266 | seta20.2: inb $0x64,%al // Get status | |
| 267 | testb $0x2,%al // Busy? | |
| 268 | jnz seta20.2 // Yes | |
| 269 | movb $0xdf,%al // Enable | |
| 270 | outb %al,$0x60 // A20 | |
| 271 | sti // Enable interrupts | |
| 272 | retw // To caller | |
| 273 | // | |
| 274 | // Trampoline used to call read from within boot1. | |
| 275 | // | |
| 04144d62 | 276 | nread: mov $BOOT2_LOAD_BUF,%bx // Transfer buffer |
| 5ee58eed MD |
277 | mov 0x8(%si),%ax // Get |
| 278 | mov 0xa(%si),%cx // LBA | |
| 279 | push %cs // Read from | |
| 280 | callw xread.1 // disk | |
| 281 | jnc return // If success, return | |
| 282 | mov $msg_read,%si // Otherwise, set the error | |
| 283 | // message and fall through to | |
| 284 | // the error routine | |
| 285 | // | |
| 286 | // Print out the error message pointed to by %ds:(%si) followed | |
| 287 | // by a prompt, wait for a keypress, and then reboot the machine. | |
| 288 | // | |
| 289 | error: callw putstr // Display message | |
| 290 | mov $prompt,%si // Display | |
| 291 | callw putstr // prompt | |
| 292 | xorb %ah,%ah // BIOS: Get | |
| 293 | int $0x16 // keypress | |
| 294 | movw $0x1234, BDA_BOOT // Do a warm boot | |
| 295 | ljmp $0xffff,$0x0 // reboot the machine | |
| 296 | // | |
| 297 | // Display a null-terminated string using the BIOS output. | |
| 298 | // | |
| 299 | putstr.0: mov $0x7,%bx // Page:attribute | |
| 300 | movb $0xe,%ah // BIOS: Display | |
| 301 | int $0x10 // character | |
| 302 | putstr: lodsb // Get char | |
| 303 | testb %al,%al // End of string? | |
| 304 | jne putstr.0 // No | |
| 984263bc | 305 | |
| 5ee58eed MD |
306 | // |
| 307 | // Overused return code. ereturn is used to return an error from the | |
| 308 | // read function. Since we assume putstr succeeds, we (ab)use the | |
| 309 | // same code when we return from putstr. | |
| 310 | // | |
| 311 | ereturn: movb $0x1,%ah // Invalid | |
| 312 | stc // argument | |
| 313 | return: retw // To caller | |
| 314 | // | |
| 315 | // Reads sectors from the disk. If EDD is enabled, then check if it is | |
| 316 | // installed and use it if it is. If it is not installed or not enabled, then | |
| 317 | // fall back to using CHS. Since we use a LBA, if we are using CHS, we have to | |
| 318 | // fetch the drive parameters from the BIOS and divide it out ourselves. | |
| 319 | // Call with: | |
| 320 | // | |
| 321 | // %dl - byte - drive number | |
| 322 | // stack - 10 bytes - EDD Packet | |
| ed987dc9 MD |
323 | |
| 324 | read: | |
| 325 | /* | |
| 326 | * Try EDD mode first. If not enabled or no BIOS support | |
| 327 | * exists, fall back to CHS mode. | |
| 328 | */ | |
| 329 | testb $FL_PACKET,%cs:BOOT1_ORIGIN+flags-start | |
| 330 | jz read.1 | |
| 331 | ||
| 332 | /* | |
| 333 | * BIOS: check extensions present | |
| 334 | */ | |
| 335 | mov $0x55aa,%bx | |
| 336 | push %dx | |
| 337 | movb $0x41,%ah | |
| 338 | int $0x13 | |
| 339 | pop %dx | |
| 340 | jc read.1 /* BIOS error return */ | |
| 341 | cmp $0xaa55,%bx /* check for proper magic */ | |
| 342 | jne read.1 | |
| 343 | testb $0x1,%cl /* packet interface support? */ | |
| 344 | jz read.1 | |
| 345 | ||
| 346 | /* | |
| 347 | * Issue packet command. | |
| 348 | * BIOS: Extended read command | |
| 349 | */ | |
| 350 | mov %bp,%si | |
| 351 | movb $0x42,%ah | |
| 352 | int $0x13 | |
| 353 | retw | |
| 354 | ||
| 355 | /* | |
| 356 | * Fallback to CHS mode | |
| 357 | */ | |
| 358 | read.1: | |
| 359 | push %dx // Save | |
| 5ee58eed MD |
360 | movb $0x8,%ah // BIOS: Get drive |
| 361 | int $0x13 // parameters | |
| 362 | movb %dh,%ch // Max head number | |
| 363 | pop %dx // Restore | |
| 364 | jc return // If error | |
| 365 | andb $0x3f,%cl // Sectors per track | |
| 366 | jz ereturn // If zero | |
| 367 | cli // Disable interrupts | |
| 368 | mov 0x8(%bp),%eax // Get LBA | |
| 369 | push %dx // Save | |
| 370 | movzbl %cl,%ebx // Divide by | |
| 371 | xor %edx,%edx // sectors | |
| 372 | div %ebx // per track | |
| 373 | movb %ch,%bl // Max head number | |
| 374 | movb %dl,%ch // Sector number | |
| 375 | inc %bx // Divide by | |
| 376 | xorb %dl,%dl // number | |
| 377 | div %ebx // of heads | |
| 378 | movb %dl,%bh // Head number | |
| 379 | pop %dx // Restore | |
| 380 | cmpl $0x3ff,%eax // Cylinder number supportable? | |
| 381 | sti // Enable interrupts | |
| ed987dc9 | 382 | ja ereturn // No, failed |
| 5ee58eed MD |
383 | xchgb %al,%ah // Set up cylinder |
| 384 | rorb $0x2,%al // number | |
| 385 | orb %ch,%al // Merge | |
| 386 | inc %ax // sector | |
| 387 | xchg %ax,%cx // number | |
| 388 | movb %bh,%dh // Head number | |
| 389 | subb %ah,%al // Sectors this track | |
| 390 | mov 0x2(%bp),%ah // Blocks to read | |
| 391 | cmpb %ah,%al // To read | |
| 392 | jb read.2 // this | |
| 393 | #ifdef TRACK_AT_A_TIME | |
| 394 | movb %ah,%al // track | |
| 395 | #else | |
| 396 | movb $1,%al // one sector | |
| 397 | #endif | |
| 398 | read.2: mov $0x5,%di // Try count | |
| 399 | read.3: les 0x4(%bp),%bx // Transfer buffer | |
| 400 | push %ax // Save | |
| 401 | movb $0x2,%ah // BIOS: Read | |
| 402 | int $0x13 // from disk | |
| 403 | pop %bx // Restore | |
| 404 | jnc read.4 // If success | |
| 405 | dec %di // Retry? | |
| 406 | jz read.6 // No | |
| 407 | xorb %ah,%ah // BIOS: Reset | |
| 408 | int $0x13 // disk system | |
| 409 | xchg %bx,%ax // Block count | |
| 410 | jmp read.3 // Continue | |
| 411 | read.4: movzbw %bl,%ax // Sectors read | |
| 412 | add %ax,0x8(%bp) // Adjust | |
| 413 | jnc read.5 // LBA, | |
| 414 | incw 0xa(%bp) // transfer | |
| 415 | read.5: shlb %bl // buffer | |
| 416 | add %bl,0x5(%bp) // pointer, | |
| 417 | sub %al,0x2(%bp) // block count | |
| ed987dc9 | 418 | ja read.1 // If not done |
| 5ee58eed | 419 | read.6: retw // To caller |
| 984263bc | 420 | |
| 5ee58eed | 421 | // Messages |
| 984263bc MD |
422 | |
| 423 | msg_read: .asciz "Read" | |
| 424 | msg_part: .asciz "Boot" | |
| 425 | ||
| 426 | prompt: .asciz " error\r\n" | |
| 427 | ||
| 5ee58eed | 428 | flags: .byte FLAGS // Flags |
| 984263bc MD |
429 | |
| 430 | .org PRT_OFF,0x90 | |
| 431 | ||
| 5ee58eed | 432 | // Partition table |
| 984263bc MD |
433 | |
| 434 | .fill 0x30,0x1,0x0 | |
| 435 | part4: .byte 0x80, 0x00, 0x01, 0x00 | |
| 5ee58eed | 436 | .byte 0xa5, 0xfe, 0xff, 0xff |
| 984263bc | 437 | .byte 0x00, 0x00, 0x00, 0x00 |
| 5ee58eed | 438 | .byte 0x50, 0xc3, 0x00, 0x00 // 50000 sectors long, bleh |
| 984263bc | 439 | |
| 5ee58eed | 440 | .word 0xaa55 // Magic number |