wok-current annotate etherboot/stuff/etherboot-prefix.u @ rev 11546

Add blogotext form wok-undigest
author Pascal Bellard <pascal.bellard@slitaz.org>
date Sun Dec 25 15:18:50 2011 +0100 (2011-12-25)
parents e0c2f4f235e9
children
rev   line source
pascal@538 1 --- etherboot-5.4.3/src/arch/i386/prefix/liloprefix.S
pascal@538 2 +++ etherboot-5.4.3/src/arch/i386/prefix/liloprefix.S
pascal@541 3 @@ -1,92 +1,377 @@
pascal@538 4 -/*
pascal@538 5 - Copyright (C) 2000, Entity Cyber, Inc.
pascal@538 6 -
pascal@538 7 - Authors: Gary Byers (gb@thinguin.org)
pascal@538 8 - Marty Connor (mdc@thinguin.org)
pascal@538 9 -
pascal@538 10 - This software may be used and distributed according to the terms
pascal@538 11 - of the GNU Public License (GPL), incorporated herein by reference.
pascal@538 12 -
pascal@538 13 - Description:
pascal@538 14 -
pascal@538 15 - This is just a little bit of code and data that can get prepended
pascal@538 16 - to an Etherboot ROM image in order to allow LILO to load the
pascal@538 17 - result as if it were a Linux kernel image.
pascal@538 18 -
pascal@538 19 - A real Linux kernel image consists of a one-sector boot loader
pascal@538 20 - (to load the image from a floppy disk), followed a few sectors
pascal@538 21 - of setup code, followed by the kernel code itself. There's
pascal@538 22 - a table in the first sector (starting at offset 497) that indicates
pascal@538 23 - how many sectors of setup code follow the first sector and which
pascal@538 24 - contains some other parameters that aren't interesting in this
pascal@538 25 - case.
pascal@538 26 -
pascal@538 27 - When LILO loads the sectors that comprise a kernel image, it doesn't
pascal@538 28 - execute the code in the first sector (since that code would try to
pascal@538 29 - load the image from a floppy disk.) The code in the first sector
pascal@538 30 - below doesn't expect to get executed (and prints an error message
pascal@538 31 - if it ever -is- executed.) LILO's only interested in knowing the
pascal@538 32 - number of setup sectors advertised in the table (at offset 497 in
pascal@538 33 - the first sector.)
pascal@538 34 -
pascal@538 35 - Etherboot doesn't require much in the way of setup code.
pascal@538 36 - Historically, the Linux kernel required at least 4 sectors of
pascal@538 37 - setup code. Current versions of LILO look at the byte at
pascal@538 38 - offset 497 in the first sector to indicate how many sectors
pascal@538 39 - of setup code are contained in the image.
pascal@538 40 -
pascal@538 41 -*/
pascal@541 42 +/* SYS_SIZE is the number of clicks (16 bytes) to be loaded. For Etherboot
pascal@538 43 + * purposes, we need to load everything but the boot sector itself, i.e. 32
pascal@538 44 + * clicks less than the size of the entire (verbatim) image. The image size
pascal@538 45 + * is practically limited only by the available base memory size.
pascal@538 46 + */
pascal@538 47 +.globl SYSSIZE
pascal@538 48 +.equ SYSSIZE, _verbatim_size_pgh - 32
pascal@538 49 +
pascal@538 50 +/* floppyload.S Copyright (C) 1991, 1992 Linus Torvalds
pascal@538 51 + * modified by Drew Eckhardt
pascal@538 52 + * modified by Bruce Evans (bde)
pascal@538 53 + *
pascal@538 54 + * floppyprefix.S is loaded at 0x0000:0x7c00 by the bios-startup routines.
pascal@538 55 + *
pascal@538 56 + * It then loads the system at SYSSEG<<4, using BIOS interrupts.
pascal@538 57 + *
pascal@538 58 + * The loader has been made as simple as possible, and continuous read errors
pascal@538 59 + * will result in a unbreakable loop. Reboot by hand. It loads pretty fast by
pascal@538 60 + * getting whole tracks at a time whenever possible.
pascal@538 61 + */
pascal@538 62
pascal@538 63 #define SETUPSECS 4 /* Minimal nr of setup-sectors */
pascal@538 64 #define PREFIXSIZE ((SETUPSECS+1)*512)
pascal@538 65 #define PREFIXPGH (PREFIXSIZE / 16 )
pascal@538 66 -#define BOOTSEG 0x07C0 /* original address of boot-sector */
pascal@538 67 #define INITSEG 0x9000 /* we move boot here - out of the way */
pascal@538 68 #define SETUPSEG 0x9020 /* setup starts here */
pascal@538 69 -#define SYSSEG 0x1000 /* system loaded at 0x10000 (65536). */
pascal@538 70
pascal@538 71 - .text
pascal@538 72 - .code16
pascal@538 73 - .arch i386
pascal@538 74 - .org 0
pascal@538 75 - .section ".prefix", "ax", @progbits
pascal@538 76 .globl _prefix
pascal@538 77 _prefix:
pascal@538 78 +.equ BOOTSEG, 0x07C0 /* original address of boot-sector */
pascal@538 79
pascal@538 80 -/*
pascal@538 81 - This is a minimal boot sector. If anyone tries to execute it (e.g., if
pascal@538 82 - a .lilo file is dd'ed to a floppy), print an error message.
pascal@538 83 -*/
pascal@538 84 +.equ SYSSEG, 0x1000 /* system loaded at SYSSEG<<4 */
pascal@540 85 +
pascal@538 86 + .org 0
pascal@538 87 + .arch i386
pascal@538 88 + .text
pascal@538 89 + .section ".prefix", "ax", @progbits
pascal@538 90 + .code16
pascal@541 91 +
pascal@540 92 + call here
pascal@540 93 +here:
pascal@540 94 + pop %ax
pascal@540 95 + cmpw $0x103, %ax /* COM entry point is cs:0x100 */
pascal@540 96 + jne bootsector
pascal@541 97 +
pascal@540 98 +/* We need a real mode stack that won't be stomped on by Etherboot
pascal@540 99 + which starts at 0x20000. Choose something that's sufficiently high,
pascal@540 100 + but not in DOC territory. Note that we couldn't do this in a real
pascal@540 101 + .com program since stack variables are in the same segment as the
pascal@540 102 + code and data, but this isn't really a .com program, it just looks
pascal@540 103 + like one to make DOS load it into memory. It still has the 64kB
pascal@540 104 + limitation of .com files though. */
pascal@540 105 +#define STACK_SEG 0x7000
pascal@540 106 +#define STACK_SIZE 0x4000
pascal@540 107 + /* Set up temporary stack */
pascal@540 108 + movw $STACK_SEG, %ax
pascal@540 109 + movw %ax, %ss
pascal@540 110 + movw $STACK_SIZE, %sp
pascal@538 111 +
pascal@540 112 + /* Calculate segment address of image start */
pascal@540 113 + pushw %cs
pascal@540 114 + popw %ax
pascal@540 115 + addw $(0x100/16), %ax
pascal@541 116 + jmp go_setup_code
pascal@541 117
pascal@541 118 -bootsector:
pascal@541 119 - jmp $BOOTSEG, $go - _prefix /* reload cs:ip to match relocation addr */
pascal@540 120 +bootsector:
pascal@538 121 + jmp $BOOTSEG, $go /* reload cs:ip to match relocation addr */
pascal@538 122 go:
pascal@538 123 - movw $0x2000, %di /* 0x2000 is arbitrary value >= length
pascal@538 124 - of bootsect + room for stack */
pascal@538 125 + movw $0x2000-12, %di /* 0x2000 is arbitrary value >= length */
pascal@538 126 + /* of bootsect + room for stack + 12 for */
pascal@538 127 + /* saved disk parm block */
pascal@538 128
pascal@538 129 movw $BOOTSEG, %ax
pascal@538 130 movw %ax,%ds
pascal@538 131 movw %ax,%es
pascal@538 132 -
pascal@538 133 - cli
pascal@538 134 - movw %ax, %ss /* put stack at BOOTSEG:0x2000. */
pascal@538 135 + movw %ax,%ss /* put stack at initial position */
pascal@538 136 movw %di,%sp
pascal@538 137 - sti
pascal@538 138
pascal@538 139 - movw $why_end-why, %cx
pascal@538 140 - movw $why - _prefix, %si
pascal@538 141 +/* Many BIOS's default disk parameter tables will not recognize multi-sector
pascal@538 142 + * reads beyond the maximum sector number specified in the default diskette
pascal@538 143 + * parameter tables - this may mean 7 sectors in some cases.
pascal@538 144 + *
pascal@538 145 + * Since single sector reads are slow and out of the question, we must take care
pascal@538 146 + * of this by creating new parameter tables (for the first disk) in RAM. We
pascal@538 147 + * will set the maximum sector count to 36 - the most we will encounter on an
pascal@538 148 + * ED 2.88. High doesn't hurt. Low does.
pascal@538 149 + *
pascal@538 150 + * Segments are as follows: ds=es=ss=cs - BOOTSEG
pascal@538 151 + */
pascal@538 152 +
pascal@538 153 + xorw %cx,%cx
pascal@538 154 + movw %cx,%es /* access segment 0 */
pascal@538 155 + movw $0x78, %bx /* 0:bx is parameter table address */
pascal@538 156 + pushw %ds /* save ds */
pascal@538 157 +/* 0:bx is parameter table address */
pascal@538 158 + ldsw %es:(%bx),%si /* loads ds and si */
pascal@538 159 +
pascal@538 160 + movw %ax,%es /* ax is BOOTSECT (loaded above) */
pascal@538 161 + movb $6, %cl /* copy 12 bytes */
pascal@538 162 + cld
pascal@538 163 + pushw %di /* keep a copy for later */
pascal@538 164 + rep
pascal@538 165 + movsw /* ds:si is source, es:di is dest */
pascal@538 166 + popw %di
pascal@538 167 +
pascal@538 168 + movb $36,%es:4(%di)
pascal@538 169 +
pascal@538 170 + movw %cx,%ds /* access segment 0 */
pascal@538 171 + xchgw %di,(%bx)
pascal@538 172 + movw %es,%si
pascal@538 173 + xchgw %si,2(%bx)
pascal@538 174 + popw %ds /* restore ds */
pascal@538 175 + movw %di, dpoff /* save old parameters */
pascal@538 176 + movw %si, dpseg /* to restore just before finishing */
pascal@538 177 + pushw %ds
pascal@538 178 + popw %es /* reload es */
pascal@538 179 +
pascal@538 180 +/* Note that es is already set up. Also cx is 0 from rep movsw above. */
pascal@538 181 +
pascal@538 182 + xorb %ah,%ah /* reset FDC */
pascal@538 183 + xorb %dl,%dl
pascal@538 184 + int $0x13
pascal@538 185 +
pascal@538 186 +/* Get disk drive parameters, specifically number of sectors/track.
pascal@538 187 + *
pascal@538 188 + * It seems that there is no BIOS call to get the number of sectors. Guess
pascal@538 189 + * 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read,
pascal@538 190 + * 15 if sector 15 can be read. Otherwise guess 9.
pascal@538 191 + */
pascal@541 192
pascal@541 193 - movw $0x0007, %bx /* page 0, attribute 7 (normal) */
pascal@541 194 - movb $0x0e, %ah /* write char, tty mode */
pascal@541 195 -prloop:
pascal@538 196 + movw $disksizes, %si /* table of sizes to try */
pascal@538 197 +
pascal@538 198 +probe_loop:
pascal@541 199 lodsb
pascal@541 200 + orb %al, %al
pascal@541 201 + je got_sectors /* if all else fails, try 9 */
pascal@538 202 + cbtw /* extend to word */
pascal@538 203 + movw %ax, sectors
pascal@538 204 + xchgw %cx,%ax /* cx = track and sector */
pascal@538 205 + xorw %dx,%dx /* drive 0, head 0 */
pascal@538 206 + movw $0x0200, %bx /* address after boot sector */
pascal@538 207 + /* (512 bytes from origin, es = cs) */
pascal@538 208 + movw $0x0201, %ax /* service 2, 1 sector */
pascal@538 209 + int $0x13
pascal@538 210 + jc probe_loop /* try next value */
pascal@538 211 +
pascal@538 212 +got_sectors:
pascal@538 213 + movw $msg1end-msg1, %cx
pascal@538 214 + movw $msg1, %si
pascal@538 215 + call print_str
pascal@538 216 +
pascal@538 217 +/* ok, we've written the Loading... message, now we want to load the system */
pascal@538 218 +
pascal@538 219 + pushw %es /* = ds */
pascal@538 220 + movw $SYSSEG, %ax
pascal@538 221 + movw %ax,%es /* segment of SYSSEG<<4 */
pascal@538 222 + pushw %es
pascal@538 223 + call read_it
pascal@538 224 +
pascal@538 225 +/* This turns off the floppy drive motor, so that we enter the kernel in a
pascal@538 226 + * known state, and don't have to worry about it later.
pascal@538 227 + */
pascal@538 228 + movw $0x3f2, %dx
pascal@538 229 + xorb %al,%al
pascal@538 230 + outb %al,%dx
pascal@538 231 +
pascal@538 232 + call print_nl
pascal@538 233 + pop %es /* = SYSSEG */
pascal@538 234 + pop %es /* balance push/pop es */
pascal@538 235 +sigok:
pascal@538 236 +
pascal@538 237 +/* Restore original disk parameters */
pascal@538 238 + movw $0x78, %bx
pascal@538 239 + movw dpoff, %di
pascal@538 240 + movw dpseg, %si
pascal@538 241 + xorw %ax,%ax
pascal@538 242 + movw %ax,%ds
pascal@538 243 + movw %di,(%bx)
pascal@538 244 + movw %si,2(%bx)
pascal@538 245 +
pascal@538 246 +/* after that (everything loaded), we call to the .ROM file loaded. */
pascal@538 247 +
pascal@541 248 + movw $SYSSEG, %ax
pascal@541 249 + jmp go_setup_code
pascal@538 250 +
pascal@538 251 +/* This routine loads the system at address SYSSEG<<4, making sure no 64kB
pascal@538 252 + * boundaries are crossed. We try to load it as fast as possible, loading whole
pascal@538 253 + * tracks whenever we can.
pascal@538 254 + *
pascal@538 255 + * in: es - starting address segment (normally SYSSEG)
pascal@538 256 + */
pascal@538 257 +read_it:
pascal@538 258 + movw $0,sread /* read whole image incl boot sector */
pascal@538 259 + movw %es,%ax
pascal@538 260 + testw $0x0fff, %ax
pascal@538 261 +die: jne die /* es must be at 64kB boundary */
pascal@538 262 + xorw %bx,%bx /* bx is starting address within segment */
pascal@538 263 +rp_read:
pascal@538 264 + movw %es,%ax
pascal@538 265 + movw %bx,%dx
pascal@538 266 + movb $4, %cl
pascal@538 267 + shrw %cl,%dx /* bx is always divisible by 16 */
pascal@538 268 + addw %dx,%ax
pascal@538 269 + cmpw $SYSSEG+SYSSIZE, %ax /* have we loaded all yet? */
pascal@538 270 + jb ok1_read
pascal@538 271 + ret
pascal@538 272 +ok1_read:
pascal@538 273 + movw sectors, %ax
pascal@538 274 + subw sread, %ax
pascal@538 275 + movw %ax,%cx
pascal@541 276 + shlw $9, %cx /* 80186 opcode */
pascal@538 277 + addw %bx,%cx
pascal@538 278 + jnc ok2_read
pascal@538 279 + je ok2_read
pascal@538 280 + xorw %ax,%ax
pascal@538 281 + subw %bx,%ax
pascal@541 282 + shrw $9, %ax /* 80186 opcode */
pascal@538 283 +ok2_read:
pascal@538 284 + call read_track
pascal@538 285 + movw %ax,%cx
pascal@538 286 + addw sread, %ax
pascal@538 287 + cmpw sectors, %ax
pascal@538 288 + jne ok3_read
pascal@538 289 + movw $1, %ax
pascal@538 290 + subw head, %ax
pascal@538 291 + jne ok4_read
pascal@538 292 + incw track
pascal@538 293 +ok4_read:
pascal@538 294 + movw %ax, head
pascal@538 295 + xorw %ax,%ax
pascal@538 296 +ok3_read:
pascal@538 297 + movw %ax, sread
pascal@541 298 + shlw $9, %cx /* 80186 opcode */
pascal@538 299 + addw %cx,%bx
pascal@538 300 + jnc rp_read
pascal@538 301 + movw %es,%ax
pascal@538 302 + addb $0x10, %ah
pascal@538 303 + movw %ax,%es
pascal@538 304 + xorw %bx,%bx
pascal@538 305 + jmp rp_read
pascal@538 306 +
pascal@538 307 +read_track:
pascal@541 308 + pusha /* 80186 opcode */
pascal@538 309 + pushw %ax
pascal@538 310 + pushw %bx
pascal@538 311 + pushw %bp /* just in case the BIOS is buggy */
pascal@541 312 + movb $0x2e, %al /* 0x2e = . */
pascal@541 313 + call print_char
pascal@538 314 + popw %bp
pascal@538 315 + popw %bx
pascal@538 316 + popw %ax
pascal@538 317 +
pascal@538 318 + movw sread, %cx
pascal@538 319 + incw %cx
pascal@541 320 + movb track, %ch
pascal@541 321 + movw $0x0100, %dx
pascal@541 322 + andb head, %dh
pascal@538 323 + movb $2, %ah
pascal@538 324 +
pascal@538 325 + pushw %dx /* save for error dump */
pascal@538 326 + pushw %cx
pascal@538 327 + pushw %bx
pascal@538 328 + pushw %ax
pascal@538 329 +
pascal@538 330 + int $0x13
pascal@538 331 + jc bad_rt
pascal@538 332 + addw $8, %sp
pascal@541 333 + popa /* 80186 opcode */
pascal@538 334 + ret
pascal@538 335 +
pascal@538 336 +bad_rt: pushw %ax /* save error code */
pascal@538 337 + call print_all /* ah = error, al = read */
pascal@538 338 +
pascal@538 339 + xorb %ah,%ah
pascal@538 340 + xorb %dl,%dl
pascal@538 341 + int $0x13
pascal@538 342 +
pascal@538 343 + addw $10, %sp
pascal@541 344 + popa /* 80186 opcode */
pascal@538 345 + jmp read_track
pascal@538 346 +
pascal@538 347 +/* print_all is for debugging purposes. It will print out all of the registers.
pascal@538 348 + * The assumption is that this is called from a routine, with a stack frame like
pascal@538 349 + * dx
pascal@538 350 + * cx
pascal@538 351 + * bx
pascal@538 352 + * ax
pascal@538 353 + * error
pascal@538 354 + * ret <- sp
pascal@538 355 + */
pascal@538 356 +
pascal@538 357 +print_all:
pascal@538 358 + call print_nl /* nl for readability */
pascal@541 359 + /* print_nl update ah and bx */
pascal@538 360 + movw $5, %cx /* error code + 4 registers */
pascal@538 361 + movw %sp,%bp
pascal@538 362 +
pascal@538 363 +print_loop:
pascal@538 364 + pushw %cx /* save count left */
pascal@538 365 +
pascal@538 366 + cmpb $5, %cl
pascal@538 367 + jae no_reg /* see if register name is needed */
pascal@541 368 +
pascal@541 369 + movb $0x5+0x41-1, %al
pascal@538 370 + subb %cl,%al
pascal@538 371 + int $0x10
pascal@538 372 +
pascal@538 373 + movb $0x58, %al /* 'X' */
pascal@538 374 + int $0x10
pascal@538 375 +
pascal@538 376 + movb $0x3A, %al /* ':' */
pascal@538 377 + int $0x10
pascal@538 378 +
pascal@538 379 +no_reg:
pascal@538 380 + addw $2, %bp /* next register */
pascal@538 381 + call print_hex /* print it */
pascal@538 382 + movb $0x20, %al /* print a space */
pascal@541 383 int $0x10
pascal@538 384 + popw %cx
pascal@538 385 + loop print_loop
pascal@541 386 + /* nl for readability */
pascal@541 387 +print_nl:
pascal@541 388 + movb $0xd, %al /* CR */
pascal@541 389 + call print_char
pascal@541 390 + movb $0xa, %al /* LF */
pascal@541 391 + jmp print_char
pascal@541 392 +
pascal@538 393 +
pascal@538 394 +print_str:
pascal@541 395 +prloop:
pascal@541 396 + lodsb
pascal@541 397 + call print_char
pascal@538 398 loop prloop
pascal@538 399 -freeze: jmp freeze
pascal@538 400 + ret
pascal@538 401 +
pascal@538 402 +/* print_hex prints the word pointed to by ss:bp in hexadecimal. */
pascal@538 403 +
pascal@538 404 +print_hex:
pascal@538 405 + movw (%bp),%dx /* load word into dx */
pascal@538 406 + movb $4, %cl
pascal@541 407 + call print_2digits
pascal@541 408 +print_2digits:
pascal@538 409 + call print_digit
pascal@538 410 +/* fall through */
pascal@538 411 +print_digit:
pascal@541 412 + rol %cl,%dx /* rotate to use lowest 4 bits */
pascal@538 413 + movb $0x0f, %al /* mask for nybble */
pascal@538 414 + andb %dl,%al
pascal@541 415 + addb $0x90, %al /* convert al to ascii hex */
pascal@541 416 + daa /* (four instructions) */
pascal@538 417 + adcb $0x40, %al
pascal@538 418 + daa
pascal@541 419 +print_char:
pascal@541 420 + movb $0x0e, %ah /* write char, tty mode */
pascal@541 421 + movw $0x0007, %bx /* page 0, attribute 7 (normal) */
pascal@538 422 + int $0x10
pascal@538 423 + ret
pascal@538 424 +
pascal@538 425 +sread: .word 0 /* sectors read of current track */
pascal@538 426 +head: .word 0 /* current head */
pascal@538 427 +track: .word 0 /* current track */
pascal@538 428 +
pascal@538 429 +sectors:
pascal@538 430 + .word 0
pascal@538 431 +
pascal@538 432 +dpseg: .word 0
pascal@538 433 +dpoff: .word 0
pascal@538 434
pascal@538 435 -why: .ascii "This image cannot be loaded from a floppy disk.\r\n"
pascal@538 436 -why_end:
pascal@538 437 +disksizes:
pascal@541 438 + .byte 36,18,15,9,0
pascal@538 439
pascal@538 440 +msg1:
pascal@541 441 + .ascii "Loading ROM image"
pascal@538 442 +msg1end:
pascal@538 443
pascal@538 444 .org 497
pascal@538 445 setup_sects:
pascal@541 446 @@ -117,15 +402,22 @@
pascal@541 447 whose entry point is SYSSEG:0.
pascal@541 448 */
pascal@541 449 setup_code:
pascal@541 450 - pushl $0 /* No parameters to preserve for exit path */
pascal@541 451 - pushw $0 /* Use prefix exit path mechanism */
pascal@541 452 + movw $(SYSSEG-(PREFIXSIZE/16)), %ax
pascal@541 453 /* Etherboot expects to be contiguous in memory once loaded.
pascal@541 454 * LILO doesn't do this, but since we don't need any
pascal@541 455 * information that's left in the prefix, it doesn't matter:
pascal@541 456 * we just have to ensure that %cs:0000 is where the start of
pascal@541 457 * the Etherboot image *would* be.
pascal@541 458 */
pascal@541 459 - ljmp $(SYSSEG-(PREFIXSIZE/16)), $_start
pascal@541 460 +go_setup_code:
pascal@541 461 + xorw %cx, %cx
pascal@541 462 + pushw %cx
pascal@541 463 + pushw %cx /* No parameters to preserve for exit path */
pascal@541 464 + pushw %cx /* Use prefix exit path mechanism */
pascal@541 465 + pushw %ax
pascal@541 466 + pushw $_start
pascal@541 467 + /* Calculated lcall to _start with %cs:0000 = image start */
pascal@541 468 + lret
pascal@541 469
pascal@541 470 .section ".text16", "ax", @progbits
pascal@541 471 .globl prefix_exit
pascal@541 472
pascal@541 473 --- etherboot-5.4.3/src/arch/i386/prefix/bImageprefix.S
pascal@541 474 +++ etherboot-5.4.3/src/arch/i386/prefix/bImageprefix.S
pascal@541 475 @@ -82,6 +82,14 @@
pascal@541 476 #define SIG1 0xAA55
pascal@541 477 #define SIG2 0x5A5A
pascal@541 478
pascal@541 479 +/* SYS_SIZE is the number of clicks (16 bytes) to be loaded. For Etherboot
pascal@541 480 + * purposes, we need to load everything but the boot sector itself, i.e. 32
pascal@541 481 + * clicks less than the size of the entire (verbatim) image. The image size
pascal@541 482 + * is practically limited only by the available base memory size.
pascal@541 483 + */
pascal@541 484 +.globl SYSSIZE
pascal@541 485 +.equ SYSSIZE, _verbatim_size_pgh - 32
pascal@541 486 +
pascal@541 487 .text
pascal@541 488 .code16
pascal@541 489 .arch i386
pascal@541 490 @@ -90,40 +98,349 @@
pascal@541 491 .globl _prefix
pascal@541 492 _prefix:
pascal@541 493
pascal@541 494 -/*
pascal@541 495 - This is a minimal boot sector. If anyone tries to execute it (e.g., if
pascal@541 496 - a .lilo file is dd'ed to a floppy), print an error message.
pascal@541 497 -*/
pascal@541 498 + call here
pascal@541 499 +here:
pascal@541 500 + pop %ax
pascal@541 501 + cmpw $0x103, %ax /* COM entry point is cs:0x100 */
pascal@541 502 + jne bootsector
pascal@541 503 +
pascal@541 504 +/* We need a real mode stack that won't be stomped on by Etherboot
pascal@541 505 + which starts at 0x20000. Choose something that's sufficiently high,
pascal@541 506 + but not in DOC territory. Note that we couldn't do this in a real
pascal@541 507 + .com program since stack variables are in the same segment as the
pascal@541 508 + code and data, but this isn't really a .com program, it just looks
pascal@541 509 + like one to make DOS load it into memory. It still has the 64kB
pascal@541 510 + limitation of .com files though. */
pascal@541 511 +#define STACK_SEG 0x7000
pascal@541 512 +#define STACK_SIZE 0x4000
pascal@541 513 + /* Set up temporary stack */
pascal@541 514 + movw $STACK_SEG, %ax
pascal@541 515 + movw %ax, %ss
pascal@541 516 + movw $STACK_SIZE, %sp
pascal@541 517 +
pascal@541 518 + /* Calculate segment address of image start */
pascal@541 519 + pushw %cs
pascal@541 520 + popw %ax
pascal@541 521 + addw $(0x100/16), %ax
pascal@541 522 + jmp go_setup_code
pascal@541 523
pascal@541 524 -bootsector:
pascal@541 525 - jmp $BOOTSEG, $go - _prefix /* reload cs:ip to match relocation addr */
pascal@541 526 +bootsector:
pascal@541 527 + jmp $BOOTSEG, $go /* reload cs:ip to match relocation addr */
pascal@541 528 go:
pascal@541 529 - movw $0x2000, %di /* 0x2000 is arbitrary value >= length
pascal@541 530 - of bootsect + room for stack */
pascal@541 531 + movw $0x2000-12, %di /* 0x2000 is arbitrary value >= length */
pascal@541 532 + /* of bootsect + room for stack + 12 for */
pascal@541 533 + /* saved disk parm block */
pascal@541 534
pascal@541 535 movw $BOOTSEG, %ax
pascal@541 536 movw %ax,%ds
pascal@541 537 movw %ax,%es
pascal@541 538 -
pascal@541 539 - cli
pascal@541 540 - movw %ax, %ss /* put stack at BOOTSEG:0x2000. */
pascal@541 541 + movw %ax,%ss /* put stack at initial position */
pascal@541 542 movw %di,%sp
pascal@541 543 - sti
pascal@541 544
pascal@541 545 - movw $why_end-why, %cx
pascal@541 546 - movw $why - _prefix, %si
pascal@541 547 +/* Many BIOS's default disk parameter tables will not recognize multi-sector
pascal@541 548 + * reads beyond the maximum sector number specified in the default diskette
pascal@541 549 + * parameter tables - this may mean 7 sectors in some cases.
pascal@541 550 + *
pascal@541 551 + * Since single sector reads are slow and out of the question, we must take care
pascal@541 552 + * of this by creating new parameter tables (for the first disk) in RAM. We
pascal@541 553 + * will set the maximum sector count to 36 - the most we will encounter on an
pascal@541 554 + * ED 2.88. High doesn't hurt. Low does.
pascal@541 555 + *
pascal@541 556 + * Segments are as follows: ds=es=ss=cs - BOOTSEG
pascal@541 557 + */
pascal@541 558 +
pascal@541 559 + xorw %cx,%cx
pascal@541 560 + movw %cx,%es /* access segment 0 */
pascal@541 561 + movw $0x78, %bx /* 0:bx is parameter table address */
pascal@541 562 + pushw %ds /* save ds */
pascal@541 563 +/* 0:bx is parameter table address */
pascal@541 564 + ldsw %es:(%bx),%si /* loads ds and si */
pascal@541 565 +
pascal@541 566 + movw %ax,%es /* ax is BOOTSECT (loaded above) */
pascal@541 567 + movb $6, %cl /* copy 12 bytes */
pascal@541 568 + cld
pascal@541 569 + pushw %di /* keep a copy for later */
pascal@541 570 + rep
pascal@541 571 + movsw /* ds:si is source, es:di is dest */
pascal@541 572 + popw %di
pascal@541 573
pascal@541 574 - movw $0x0007, %bx /* page 0, attribute 7 (normal) */
pascal@541 575 - movb $0x0e, %ah /* write char, tty mode */
pascal@541 576 -prloop:
pascal@541 577 + movb $36,%es:4(%di)
pascal@541 578 +
pascal@541 579 + movw %cx,%ds /* access segment 0 */
pascal@541 580 + xchgw %di,(%bx)
pascal@541 581 + movw %es,%si
pascal@541 582 + xchgw %si,2(%bx)
pascal@541 583 + popw %ds /* restore ds */
pascal@541 584 + movw %di, dpoff /* save old parameters */
pascal@541 585 + movw %si, dpseg /* to restore just before finishing */
pascal@541 586 + pushw %ds
pascal@541 587 + popw %es /* reload es */
pascal@541 588 +
pascal@541 589 +/* Note that es is already set up. Also cx is 0 from rep movsw above. */
pascal@541 590 +
pascal@541 591 + xorb %ah,%ah /* reset FDC */
pascal@541 592 + xorb %dl,%dl
pascal@541 593 + int $0x13
pascal@541 594 +
pascal@541 595 +/* Get disk drive parameters, specifically number of sectors/track.
pascal@541 596 + *
pascal@541 597 + * It seems that there is no BIOS call to get the number of sectors. Guess
pascal@541 598 + * 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read,
pascal@541 599 + * 15 if sector 15 can be read. Otherwise guess 9.
pascal@541 600 + */
pascal@541 601 +
pascal@541 602 + movw $disksizes, %si /* table of sizes to try */
pascal@541 603 +
pascal@541 604 +probe_loop:
pascal@541 605 lodsb
pascal@541 606 + orb %al, %al
pascal@541 607 + je got_sectors /* if all else fails, try 9 */
pascal@541 608 + cbtw /* extend to word */
pascal@541 609 + movw %ax, sectors
pascal@541 610 + xchgw %cx,%ax /* cx = track and sector */
pascal@541 611 + xorw %dx,%dx /* drive 0, head 0 */
pascal@541 612 + movw $0x0200, %bx /* address after boot sector */
pascal@541 613 + /* (512 bytes from origin, es = cs) */
pascal@541 614 + movw $0x0201, %ax /* service 2, 1 sector */
pascal@541 615 + int $0x13
pascal@541 616 + jc probe_loop /* try next value */
pascal@541 617 +
pascal@541 618 +got_sectors:
pascal@541 619 + movw $msg1end-msg1, %cx
pascal@541 620 + movw $msg1, %si
pascal@541 621 + call print_str
pascal@541 622 +
pascal@541 623 +/* ok, we've written the Loading... message, now we want to load the system */
pascal@541 624 +
pascal@541 625 + pushw %es /* = ds */
pascal@541 626 + movw $SYSSEG, %ax
pascal@541 627 + movw %ax,%es /* segment of SYSSEG<<4 */
pascal@541 628 + pushw %es
pascal@541 629 + call read_it
pascal@541 630 +
pascal@541 631 +/* This turns off the floppy drive motor, so that we enter the kernel in a
pascal@541 632 + * known state, and don't have to worry about it later.
pascal@541 633 + */
pascal@541 634 + movw $0x3f2, %dx
pascal@541 635 + xorb %al,%al
pascal@541 636 + outb %al,%dx
pascal@541 637 +
pascal@541 638 + call print_nl
pascal@541 639 + pop %es /* = SYSSEG */
pascal@541 640 + pop %es /* balance push/pop es */
pascal@541 641 +sigok:
pascal@541 642 +
pascal@541 643 +/* Restore original disk parameters */
pascal@541 644 + movw $0x78, %bx
pascal@541 645 + movw dpoff, %di
pascal@541 646 + movw dpseg, %si
pascal@541 647 + xorw %ax,%ax
pascal@541 648 + movw %ax,%ds
pascal@541 649 + movw %di,(%bx)
pascal@541 650 + movw %si,2(%bx)
pascal@541 651 +
pascal@541 652 +/* after that (everything loaded), we call to the .ROM file loaded. */
pascal@541 653 +
pascal@541 654 + movw $SYSSEG, %ax
pascal@541 655 +go_setup_code:
pascal@541 656 + xorw %cx, %cx
pascal@541 657 + pushw %cx
pascal@541 658 + pushw %cx /* No parameters to preserve for exit path */
pascal@541 659 + pushw %cx /* Use prefix exit path mechanism */
pascal@541 660 + pushw %ax
pascal@541 661 + pushw $_start
pascal@541 662 + /* Calculated lcall to _start with %cs:0000 = image start */
pascal@541 663 + lret
pascal@541 664 +
pascal@541 665 +/* This routine loads the system at address SYSSEG<<4, making sure no 64kB
pascal@541 666 + * boundaries are crossed. We try to load it as fast as possible, loading whole
pascal@541 667 + * tracks whenever we can.
pascal@541 668 + *
pascal@541 669 + * in: es - starting address segment (normally SYSSEG)
pascal@541 670 + */
pascal@541 671 +read_it:
pascal@541 672 + movw $0,sread /* read whole image incl boot sector */
pascal@541 673 + movw %es,%ax
pascal@541 674 + testw $0x0fff, %ax
pascal@541 675 +die: jne die /* es must be at 64kB boundary */
pascal@541 676 + xorw %bx,%bx /* bx is starting address within segment */
pascal@541 677 +rp_read:
pascal@541 678 + movw %es,%ax
pascal@541 679 + movw %bx,%dx
pascal@541 680 + movb $4, %cl
pascal@541 681 + shrw %cl,%dx /* bx is always divisible by 16 */
pascal@541 682 + addw %dx,%ax
pascal@541 683 + cmpw $SYSSEG+SYSSIZE, %ax /* have we loaded all yet? */
pascal@541 684 + jb ok1_read
pascal@541 685 + ret
pascal@541 686 +ok1_read:
pascal@541 687 + movw sectors, %ax
pascal@541 688 + subw sread, %ax
pascal@541 689 + movw %ax,%cx
pascal@541 690 + shlw $9, %cx /* 80186 opcode */
pascal@541 691 + addw %bx,%cx
pascal@541 692 + jnc ok2_read
pascal@541 693 + je ok2_read
pascal@541 694 + xorw %ax,%ax
pascal@541 695 + subw %bx,%ax
pascal@541 696 + shrw $9, %ax /* 80186 opcode */
pascal@541 697 +ok2_read:
pascal@541 698 + call read_track
pascal@541 699 + movw %ax,%cx
pascal@541 700 + addw sread, %ax
pascal@541 701 + cmpw sectors, %ax
pascal@541 702 + jne ok3_read
pascal@541 703 + movw $1, %ax
pascal@541 704 + subw head, %ax
pascal@541 705 + jne ok4_read
pascal@541 706 + incw track
pascal@541 707 +ok4_read:
pascal@541 708 + movw %ax, head
pascal@541 709 + xorw %ax,%ax
pascal@541 710 +ok3_read:
pascal@541 711 + movw %ax, sread
pascal@541 712 + shlw $9, %cx /* 80186 opcode */
pascal@541 713 + addw %cx,%bx
pascal@541 714 + jnc rp_read
pascal@541 715 + movw %es,%ax
pascal@541 716 + addb $0x10, %ah
pascal@541 717 + movw %ax,%es
pascal@541 718 + xorw %bx,%bx
pascal@541 719 + jmp rp_read
pascal@541 720 +
pascal@541 721 +read_track:
pascal@541 722 + pusha /* 80186 opcode */
pascal@541 723 + pushw %ax
pascal@541 724 + pushw %bx
pascal@541 725 + pushw %bp /* just in case the BIOS is buggy */
pascal@541 726 + movb $0x2e, %al /* 0x2e = . */
pascal@541 727 + call print_char
pascal@541 728 + popw %bp
pascal@541 729 + popw %bx
pascal@541 730 + popw %ax
pascal@541 731 +
pascal@541 732 + movw sread, %cx
pascal@541 733 + incw %cx
pascal@541 734 + movb track, %ch
pascal@541 735 + movw $0x0100, %dx
pascal@541 736 + andb head, %dh
pascal@541 737 + movb $2, %ah
pascal@541 738 +
pascal@541 739 + pushw %dx /* save for error dump */
pascal@541 740 + pushw %cx
pascal@541 741 + pushw %bx
pascal@541 742 + pushw %ax
pascal@541 743 +
pascal@541 744 + int $0x13
pascal@541 745 + jc bad_rt
pascal@541 746 + addw $8, %sp
pascal@541 747 + popa /* 80186 opcode */
pascal@541 748 + ret
pascal@541 749 +
pascal@541 750 +bad_rt: pushw %ax /* save error code */
pascal@541 751 + call print_all /* ah = error, al = read */
pascal@541 752 +
pascal@541 753 + xorb %ah,%ah
pascal@541 754 + xorb %dl,%dl
pascal@541 755 + int $0x13
pascal@541 756 +
pascal@541 757 + addw $10, %sp
pascal@541 758 + popa /* 80186 opcode */
pascal@541 759 + jmp read_track
pascal@541 760 +
pascal@541 761 +/* print_all is for debugging purposes. It will print out all of the registers.
pascal@541 762 + * The assumption is that this is called from a routine, with a stack frame like
pascal@541 763 + * dx
pascal@541 764 + * cx
pascal@541 765 + * bx
pascal@541 766 + * ax
pascal@541 767 + * error
pascal@541 768 + * ret <- sp
pascal@541 769 + */
pascal@541 770 +
pascal@541 771 +print_all:
pascal@541 772 + call print_nl /* nl for readability */
pascal@541 773 + /* print_nl update ah and bx */
pascal@541 774 + movw $5, %cx /* error code + 4 registers */
pascal@541 775 + movw %sp,%bp
pascal@541 776 +
pascal@541 777 +print_loop:
pascal@541 778 + pushw %cx /* save count left */
pascal@541 779 +
pascal@541 780 + cmpb $5, %cl
pascal@541 781 + jae no_reg /* see if register name is needed */
pascal@541 782 +
pascal@541 783 + movb $0x5+0x41-1, %al
pascal@541 784 + subb %cl,%al
pascal@541 785 int $0x10
pascal@541 786 +
pascal@541 787 + movb $0x58, %al /* 'X' */
pascal@541 788 + int $0x10
pascal@541 789 +
pascal@541 790 + movb $0x3A, %al /* ':' */
pascal@541 791 + int $0x10
pascal@541 792 +
pascal@541 793 +no_reg:
pascal@541 794 + addw $2, %bp /* next register */
pascal@541 795 + call print_hex /* print it */
pascal@541 796 + movb $0x20, %al /* print a space */
pascal@541 797 + int $0x10
pascal@541 798 + popw %cx
pascal@541 799 + loop print_loop
pascal@541 800 + /* nl for readability */
pascal@541 801 +print_nl:
pascal@541 802 + movb $0xd, %al /* CR */
pascal@541 803 + call print_char
pascal@541 804 + movb $0xa, %al /* LF */
pascal@541 805 + jmp print_char
pascal@541 806 +
pascal@541 807 +
pascal@541 808 +print_str:
pascal@541 809 +prloop:
pascal@541 810 + lodsb
pascal@541 811 + call print_char
pascal@541 812 loop prloop
pascal@541 813 -freeze: jmp freeze
pascal@541 814 + ret
pascal@541 815
pascal@541 816 -why: .ascii "This image cannot be loaded from a floppy disk.\r\n"
pascal@541 817 -why_end:
pascal@541 818 +/* print_hex prints the word pointed to by ss:bp in hexadecimal. */
pascal@541 819 +
pascal@541 820 +print_hex:
pascal@541 821 + movw (%bp),%dx /* load word into dx */
pascal@541 822 + movb $4, %cl
pascal@541 823 + call print_2digits
pascal@541 824 +print_2digits:
pascal@541 825 + call print_digit
pascal@541 826 +/* fall through */
pascal@541 827 +print_digit:
pascal@541 828 + rol %cl,%dx /* rotate to use lowest 4 bits */
pascal@541 829 + movb $0x0f, %al /* mask for nybble */
pascal@541 830 + andb %dl,%al
pascal@541 831 + addb $0x90, %al /* convert al to ascii hex */
pascal@541 832 + daa /* (four instructions) */
pascal@541 833 + adcb $0x40, %al
pascal@541 834 + daa
pascal@541 835 +print_char:
pascal@541 836 + movb $0x0e, %ah /* write char, tty mode */
pascal@541 837 + movw $0x0007, %bx /* page 0, attribute 7 (normal) */
pascal@541 838 + int $0x10
pascal@541 839 + ret
pascal@541 840
pascal@541 841 +sread: .word 0 /* sectors read of current track */
pascal@541 842 +head: .word 0 /* current head */
pascal@541 843 +track: .word 0 /* current track */
pascal@541 844 +
pascal@541 845 +sectors:
pascal@541 846 + .word 0
pascal@541 847 +
pascal@541 848 +dpseg: .word 0
pascal@541 849 +dpoff: .word 0
pascal@541 850 +
pascal@541 851 +disksizes:
pascal@541 852 + .byte 36,18,15,9,0
pascal@541 853 +
pascal@541 854 +msg1:
pascal@541 855 + .ascii "Loading ROM image"
pascal@541 856 +msg1end:
pascal@541 857
pascal@541 858 .org 497
pascal@541 859 setup_sects: