wok annotate etherboot/stuff/etherboot-prefix.u @ rev 540

Etherboot: by the way, add DOS/COM support
author Pascal Bellard <pascal.bellard@slitaz.org>
date Thu Apr 10 22:34:56 2008 +0000 (2008-04-10)
parents 8d43117e4680
children 4a87a0aa0476
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@540 3 @@ -1,92 +1,393 @@
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@538 42 +/* NOTE: this boot sector contains instructions that need at least an 80186.
pascal@538 43 + * Yes, as86 has a bug somewhere in the valid instruction set checks.
pascal@538 44 + *
pascal@538 45 + * SYS_SIZE is the number of clicks (16 bytes) to be loaded. For Etherboot
pascal@538 46 + * purposes, we need to load everything but the boot sector itself, i.e. 32
pascal@538 47 + * clicks less than the size of the entire (verbatim) image. The image size
pascal@538 48 + * is practically limited only by the available base memory size.
pascal@538 49 + */
pascal@538 50 +.globl SYSSIZE
pascal@538 51 +.equ SYSSIZE, _verbatim_size_pgh - 32
pascal@538 52 +
pascal@538 53 +/* floppyload.S Copyright (C) 1991, 1992 Linus Torvalds
pascal@538 54 + * modified by Drew Eckhardt
pascal@538 55 + * modified by Bruce Evans (bde)
pascal@538 56 + *
pascal@538 57 + * floppyprefix.S is loaded at 0x0000:0x7c00 by the bios-startup routines.
pascal@538 58 + *
pascal@538 59 + * It then loads the system at SYSSEG<<4, using BIOS interrupts.
pascal@538 60 + *
pascal@538 61 + * The loader has been made as simple as possible, and continuous read errors
pascal@538 62 + * will result in a unbreakable loop. Reboot by hand. It loads pretty fast by
pascal@538 63 + * getting whole tracks at a time whenever possible.
pascal@538 64 + */
pascal@538 65
pascal@538 66 #define SETUPSECS 4 /* Minimal nr of setup-sectors */
pascal@538 67 #define PREFIXSIZE ((SETUPSECS+1)*512)
pascal@538 68 #define PREFIXPGH (PREFIXSIZE / 16 )
pascal@538 69 -#define BOOTSEG 0x07C0 /* original address of boot-sector */
pascal@538 70 #define INITSEG 0x9000 /* we move boot here - out of the way */
pascal@538 71 #define SETUPSEG 0x9020 /* setup starts here */
pascal@538 72 -#define SYSSEG 0x1000 /* system loaded at 0x10000 (65536). */
pascal@538 73
pascal@538 74 - .text
pascal@538 75 - .code16
pascal@538 76 - .arch i386
pascal@538 77 - .org 0
pascal@538 78 - .section ".prefix", "ax", @progbits
pascal@538 79 .globl _prefix
pascal@538 80 _prefix:
pascal@538 81 +.equ BOOTSEG, 0x07C0 /* original address of boot-sector */
pascal@538 82
pascal@538 83 -/*
pascal@538 84 - This is a minimal boot sector. If anyone tries to execute it (e.g., if
pascal@538 85 - a .lilo file is dd'ed to a floppy), print an error message.
pascal@538 86 -*/
pascal@538 87 +.equ SYSSEG, 0x1000 /* system loaded at SYSSEG<<4 */
pascal@540 88 +
pascal@538 89 + .org 0
pascal@538 90 + .arch i386
pascal@538 91 + .text
pascal@538 92 + .section ".prefix", "ax", @progbits
pascal@538 93 + .code16
pascal@540 94
pascal@540 95 -bootsector:
pascal@540 96 - jmp $BOOTSEG, $go - _prefix /* reload cs:ip to match relocation addr */
pascal@540 97 + call here
pascal@540 98 +here:
pascal@540 99 + pop %ax
pascal@540 100 + cmpw $0x103, %ax /* COM entry point is cs:0x100 */
pascal@540 101 + jne bootsector
pascal@540 102 +/* We need a real mode stack that won't be stomped on by Etherboot
pascal@540 103 + which starts at 0x20000. Choose something that's sufficiently high,
pascal@540 104 + but not in DOC territory. Note that we couldn't do this in a real
pascal@540 105 + .com program since stack variables are in the same segment as the
pascal@540 106 + code and data, but this isn't really a .com program, it just looks
pascal@540 107 + like one to make DOS load it into memory. It still has the 64kB
pascal@540 108 + limitation of .com files though. */
pascal@540 109 +#define STACK_SEG 0x7000
pascal@540 110 +#define STACK_SIZE 0x4000
pascal@540 111 + /* Set up temporary stack */
pascal@540 112 + movw $STACK_SEG, %ax
pascal@540 113 + movw %ax, %ss
pascal@540 114 + movw $STACK_SIZE, %sp
pascal@538 115 +
pascal@540 116 + pushl $0 /* No parameters to preserve for exit path */
pascal@540 117 + pushw $0 /* Dummy return address - use prefix_exit */
pascal@540 118 +
pascal@540 119 + /* Calculate segment address of image start */
pascal@540 120 + pushw %cs
pascal@540 121 + popw %ax
pascal@540 122 + addw $(0x100/16), %ax
pascal@540 123 + pushw %ax
pascal@540 124 + pushw $_start
pascal@540 125 + /* Calculated lcall to _start with %cs:0000 = image start */
pascal@540 126 + lret
pascal@540 127 +
pascal@540 128 +bootsector:
pascal@538 129 + jmp $BOOTSEG, $go /* reload cs:ip to match relocation addr */
pascal@538 130 go:
pascal@538 131 - movw $0x2000, %di /* 0x2000 is arbitrary value >= length
pascal@538 132 - of bootsect + room for stack */
pascal@538 133 + movw $0x2000-12, %di /* 0x2000 is arbitrary value >= length */
pascal@538 134 + /* of bootsect + room for stack + 12 for */
pascal@538 135 + /* saved disk parm block */
pascal@538 136
pascal@538 137 movw $BOOTSEG, %ax
pascal@538 138 movw %ax,%ds
pascal@538 139 movw %ax,%es
pascal@538 140 -
pascal@538 141 - cli
pascal@538 142 - movw %ax, %ss /* put stack at BOOTSEG:0x2000. */
pascal@538 143 + movw %ax,%ss /* put stack at initial position */
pascal@538 144 movw %di,%sp
pascal@538 145 - sti
pascal@538 146
pascal@538 147 - movw $why_end-why, %cx
pascal@538 148 - movw $why - _prefix, %si
pascal@538 149 +/* Many BIOS's default disk parameter tables will not recognize multi-sector
pascal@538 150 + * reads beyond the maximum sector number specified in the default diskette
pascal@538 151 + * parameter tables - this may mean 7 sectors in some cases.
pascal@538 152 + *
pascal@538 153 + * Since single sector reads are slow and out of the question, we must take care
pascal@538 154 + * of this by creating new parameter tables (for the first disk) in RAM. We
pascal@538 155 + * will set the maximum sector count to 36 - the most we will encounter on an
pascal@538 156 + * ED 2.88. High doesn't hurt. Low does.
pascal@538 157 + *
pascal@538 158 + * Segments are as follows: ds=es=ss=cs - BOOTSEG
pascal@538 159 + */
pascal@538 160 +
pascal@538 161 + xorw %cx,%cx
pascal@538 162 + movw %cx,%es /* access segment 0 */
pascal@538 163 + movw $0x78, %bx /* 0:bx is parameter table address */
pascal@538 164 + pushw %ds /* save ds */
pascal@538 165 +/* 0:bx is parameter table address */
pascal@538 166 + ldsw %es:(%bx),%si /* loads ds and si */
pascal@538 167 +
pascal@538 168 + movw %ax,%es /* ax is BOOTSECT (loaded above) */
pascal@538 169 + movb $6, %cl /* copy 12 bytes */
pascal@538 170 + cld
pascal@538 171 + pushw %di /* keep a copy for later */
pascal@538 172 + rep
pascal@538 173 + movsw /* ds:si is source, es:di is dest */
pascal@538 174 + popw %di
pascal@538 175 +
pascal@538 176 + movb $36,%es:4(%di)
pascal@538 177 +
pascal@538 178 + movw %cx,%ds /* access segment 0 */
pascal@538 179 + xchgw %di,(%bx)
pascal@538 180 + movw %es,%si
pascal@538 181 + xchgw %si,2(%bx)
pascal@538 182 + popw %ds /* restore ds */
pascal@538 183 + movw %di, dpoff /* save old parameters */
pascal@538 184 + movw %si, dpseg /* to restore just before finishing */
pascal@538 185 + pushw %ds
pascal@538 186 + popw %es /* reload es */
pascal@538 187 +
pascal@538 188 +/* Note that es is already set up. Also cx is 0 from rep movsw above. */
pascal@538 189 +
pascal@538 190 + xorb %ah,%ah /* reset FDC */
pascal@538 191 + xorb %dl,%dl
pascal@538 192 + int $0x13
pascal@538 193 +
pascal@538 194 +/* Get disk drive parameters, specifically number of sectors/track.
pascal@538 195 + *
pascal@538 196 + * It seems that there is no BIOS call to get the number of sectors. Guess
pascal@538 197 + * 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read,
pascal@538 198 + * 15 if sector 15 can be read. Otherwise guess 9.
pascal@538 199 + */
pascal@538 200 +
pascal@538 201 + movw $disksizes, %si /* table of sizes to try */
pascal@538 202 +
pascal@538 203 +probe_loop:
pascal@538 204 + lodsb
pascal@538 205 + cbtw /* extend to word */
pascal@538 206 + movw %ax, sectors
pascal@538 207 + cmpw $disksizes+4, %si
pascal@538 208 + jae got_sectors /* if all else fails, try 9 */
pascal@538 209 + xchgw %cx,%ax /* cx = track and sector */
pascal@538 210 + xorw %dx,%dx /* drive 0, head 0 */
pascal@538 211 + movw $0x0200, %bx /* address after boot sector */
pascal@538 212 + /* (512 bytes from origin, es = cs) */
pascal@538 213 + movw $0x0201, %ax /* service 2, 1 sector */
pascal@538 214 + int $0x13
pascal@538 215 + jc probe_loop /* try next value */
pascal@538 216 +
pascal@538 217 +got_sectors:
pascal@538 218 + movw $msg1end-msg1, %cx
pascal@538 219 + movw $msg1, %si
pascal@538 220 + call print_str
pascal@538 221 +
pascal@538 222 +/* ok, we've written the Loading... message, now we want to load the system */
pascal@538 223 +
pascal@538 224 + pushw %es /* = ds */
pascal@538 225 + movw $SYSSEG, %ax
pascal@538 226 + movw %ax,%es /* segment of SYSSEG<<4 */
pascal@538 227 + pushw %es
pascal@538 228 + call read_it
pascal@538 229 +
pascal@538 230 +/* This turns off the floppy drive motor, so that we enter the kernel in a
pascal@538 231 + * known state, and don't have to worry about it later.
pascal@538 232 + */
pascal@538 233 + movw $0x3f2, %dx
pascal@538 234 + xorb %al,%al
pascal@538 235 + outb %al,%dx
pascal@538 236 +
pascal@538 237 + call print_nl
pascal@538 238 + pop %es /* = SYSSEG */
pascal@538 239 + pop %es /* balance push/pop es */
pascal@538 240 +sigok:
pascal@538 241 +
pascal@538 242 +/* Restore original disk parameters */
pascal@538 243 + movw $0x78, %bx
pascal@538 244 + movw dpoff, %di
pascal@538 245 + movw dpseg, %si
pascal@538 246 + xorw %ax,%ax
pascal@538 247 + movw %ax,%ds
pascal@538 248 + movw %di,(%bx)
pascal@538 249 + movw %si,2(%bx)
pascal@538 250 +
pascal@538 251 +/* after that (everything loaded), we call to the .ROM file loaded. */
pascal@538 252 +
pascal@538 253 + pushl $0 /* No parameters to preserve for exit path */
pascal@538 254 + pushw $0 /* Use prefix exit path mechanism */
pascal@538 255 + ljmp $SYSSEG, $_start
pascal@538 256 +
pascal@538 257 +/* This routine loads the system at address SYSSEG<<4, making sure no 64kB
pascal@538 258 + * boundaries are crossed. We try to load it as fast as possible, loading whole
pascal@538 259 + * tracks whenever we can.
pascal@538 260 + *
pascal@538 261 + * in: es - starting address segment (normally SYSSEG)
pascal@538 262 + */
pascal@538 263 +read_it:
pascal@538 264 + movw $0,sread /* read whole image incl boot sector */
pascal@538 265 + movw %es,%ax
pascal@538 266 + testw $0x0fff, %ax
pascal@538 267 +die: jne die /* es must be at 64kB boundary */
pascal@538 268 + xorw %bx,%bx /* bx is starting address within segment */
pascal@538 269 +rp_read:
pascal@538 270 + movw %es,%ax
pascal@538 271 + movw %bx,%dx
pascal@538 272 + movb $4, %cl
pascal@538 273 + shrw %cl,%dx /* bx is always divisible by 16 */
pascal@538 274 + addw %dx,%ax
pascal@538 275 + cmpw $SYSSEG+SYSSIZE, %ax /* have we loaded all yet? */
pascal@538 276 + jb ok1_read
pascal@538 277 + ret
pascal@538 278 +ok1_read:
pascal@538 279 + movw sectors, %ax
pascal@538 280 + subw sread, %ax
pascal@538 281 + movw %ax,%cx
pascal@538 282 + shlw $9, %cx
pascal@538 283 + addw %bx,%cx
pascal@538 284 + jnc ok2_read
pascal@538 285 + je ok2_read
pascal@538 286 + xorw %ax,%ax
pascal@538 287 + subw %bx,%ax
pascal@538 288 + shrw $9, %ax
pascal@538 289 +ok2_read:
pascal@538 290 + call read_track
pascal@538 291 + movw %ax,%cx
pascal@538 292 + addw sread, %ax
pascal@538 293 + cmpw sectors, %ax
pascal@538 294 + jne ok3_read
pascal@538 295 + movw $1, %ax
pascal@538 296 + subw head, %ax
pascal@538 297 + jne ok4_read
pascal@538 298 + incw track
pascal@538 299 +ok4_read:
pascal@538 300 + movw %ax, head
pascal@538 301 + xorw %ax,%ax
pascal@538 302 +ok3_read:
pascal@538 303 + movw %ax, sread
pascal@538 304 + shlw $9, %cx
pascal@538 305 + addw %cx,%bx
pascal@538 306 + jnc rp_read
pascal@538 307 + movw %es,%ax
pascal@538 308 + addb $0x10, %ah
pascal@538 309 + movw %ax,%es
pascal@538 310 + xorw %bx,%bx
pascal@538 311 + jmp rp_read
pascal@538 312 +
pascal@538 313 +read_track:
pascal@538 314 + pusha
pascal@538 315 + pushw %ax
pascal@538 316 + pushw %bx
pascal@538 317 + pushw %bp /* just in case the BIOS is buggy */
pascal@538 318 + movw $0x0e2e, %ax /* 0x2e = . */
pascal@538 319 + movw $0x0007, %bx
pascal@538 320 + int $0x10
pascal@538 321 + popw %bp
pascal@538 322 + popw %bx
pascal@538 323 + popw %ax
pascal@538 324 +
pascal@538 325 + movw track, %dx
pascal@538 326 + movw sread, %cx
pascal@538 327 + incw %cx
pascal@538 328 + movb %dl,%ch
pascal@538 329 + movw head, %dx
pascal@538 330 + movb %dl,%dh
pascal@538 331 + andw $0x0100, %dx
pascal@538 332 + movb $2, %ah
pascal@538 333 +
pascal@538 334 + pushw %dx /* save for error dump */
pascal@538 335 + pushw %cx
pascal@538 336 + pushw %bx
pascal@538 337 + pushw %ax
pascal@538 338 +
pascal@538 339 + int $0x13
pascal@538 340 + jc bad_rt
pascal@538 341 + addw $8, %sp
pascal@538 342 + popa
pascal@538 343 + ret
pascal@538 344 +
pascal@538 345 +bad_rt: pushw %ax /* save error code */
pascal@538 346 + call print_all /* ah = error, al = read */
pascal@538 347 +
pascal@538 348 + xorb %ah,%ah
pascal@538 349 + xorb %dl,%dl
pascal@538 350 + int $0x13
pascal@538 351 +
pascal@538 352 + addw $10, %sp
pascal@538 353 + popa
pascal@538 354 + jmp read_track
pascal@538 355 +
pascal@538 356 +/* print_all is for debugging purposes. It will print out all of the registers.
pascal@538 357 + * The assumption is that this is called from a routine, with a stack frame like
pascal@538 358 + * dx
pascal@538 359 + * cx
pascal@538 360 + * bx
pascal@538 361 + * ax
pascal@538 362 + * error
pascal@538 363 + * ret <- sp
pascal@538 364 + */
pascal@538 365 +
pascal@538 366 +print_all:
pascal@538 367 + call print_nl /* nl for readability */
pascal@538 368 + movw $5, %cx /* error code + 4 registers */
pascal@538 369 + movw %sp,%bp
pascal@538 370 +
pascal@538 371 +print_loop:
pascal@538 372 + pushw %cx /* save count left */
pascal@538 373 +
pascal@538 374 + cmpb $5, %cl
pascal@538 375 + jae no_reg /* see if register name is needed */
pascal@538 376
pascal@538 377 movw $0x0007, %bx /* page 0, attribute 7 (normal) */
pascal@538 378 + movw $0xe05+0x41-1, %ax
pascal@538 379 + subb %cl,%al
pascal@538 380 + int $0x10
pascal@538 381 +
pascal@538 382 + movb $0x58, %al /* 'X' */
pascal@538 383 + int $0x10
pascal@538 384 +
pascal@538 385 + movb $0x3A, %al /* ':' */
pascal@538 386 + int $0x10
pascal@538 387 +
pascal@538 388 +no_reg:
pascal@538 389 + addw $2, %bp /* next register */
pascal@538 390 + call print_hex /* print it */
pascal@538 391 + movb $0x20, %al /* print a space */
pascal@538 392 + int $0x10
pascal@538 393 + popw %cx
pascal@538 394 + loop print_loop
pascal@538 395 + call print_nl /* nl for readability */
pascal@538 396 + ret
pascal@538 397 +
pascal@538 398 +print_str:
pascal@538 399 + movw $0x0007, %bx /* page 0, attribute 7 (normal) */
pascal@538 400 movb $0x0e, %ah /* write char, tty mode */
pascal@538 401 prloop:
pascal@538 402 lodsb
pascal@538 403 int $0x10
pascal@538 404 loop prloop
pascal@538 405 -freeze: jmp freeze
pascal@538 406 + ret
pascal@538 407 +
pascal@538 408 +print_nl:
pascal@538 409 + movw $0x0007, %bx /* page 0, attribute 7 (normal) */
pascal@538 410 + movw $0xe0d, %ax /* CR */
pascal@538 411 + int $0x10
pascal@538 412 + movb $0xa, %al /* LF */
pascal@538 413 + int $0x10
pascal@538 414 + ret
pascal@538 415 +
pascal@538 416 +/* print_hex prints the word pointed to by ss:bp in hexadecimal. */
pascal@538 417 +
pascal@538 418 +print_hex:
pascal@538 419 + movw (%bp),%dx /* load word into dx */
pascal@538 420 + movb $4, %cl
pascal@538 421 + movb $0x0e, %ah /* write char, tty mode */
pascal@538 422 + movw $0x0007, %bx /* page 0, attribute 7 (normal) */
pascal@540 423 + call print_digit2
pascal@540 424 +print_digit2:
pascal@538 425 + call print_digit
pascal@538 426 +/* fall through */
pascal@538 427 +print_digit:
pascal@538 428 + rol %cl,%dx /* rotate so that lowest 4 bits are used */
pascal@538 429 + movb $0x0f, %al /* mask for nybble */
pascal@538 430 + andb %dl,%al
pascal@538 431 + addb $0x90, %al /* convert al to ascii hex (four instructions) */
pascal@538 432 + daa
pascal@538 433 + adcb $0x40, %al
pascal@538 434 + daa
pascal@538 435 + int $0x10
pascal@538 436 + ret
pascal@538 437 +
pascal@538 438 +sread: .word 0 /* sectors read of current track */
pascal@538 439 +head: .word 0 /* current head */
pascal@538 440 +track: .word 0 /* current track */
pascal@538 441 +
pascal@538 442 +sectors:
pascal@538 443 + .word 0
pascal@538 444 +
pascal@538 445 +dpseg: .word 0
pascal@538 446 +dpoff: .word 0
pascal@538 447
pascal@538 448 -why: .ascii "This image cannot be loaded from a floppy disk.\r\n"
pascal@538 449 -why_end:
pascal@538 450 +disksizes:
pascal@538 451 + .byte 36,18,15,9
pascal@538 452
pascal@538 453 +msg1:
pascal@540 454 + .ascii "Loading ROM"
pascal@538 455 +msg1end:
pascal@538 456
pascal@538 457 .org 497
pascal@538 458 setup_sects: