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

Etherboot: can boot with grub too
author Pascal Bellard <pascal.bellard@slitaz.org>
date Thu Apr 10 21:55:02 2008 +0000 (2008-04-10)
parents
children e0c2f4f235e9
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@538 3 @@ -1,92 +1,361 @@
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@538 88
pascal@538 89 -bootsector:
pascal@538 90 - jmp $BOOTSEG, $go - _prefix /* reload cs:ip to match relocation addr */
pascal@538 91 + .org 0
pascal@538 92 + .arch i386
pascal@538 93 + .text
pascal@538 94 + .section ".prefix", "ax", @progbits
pascal@538 95 + .code16
pascal@538 96 +
pascal@538 97 + jmp $BOOTSEG, $go /* reload cs:ip to match relocation addr */
pascal@538 98 go:
pascal@538 99 - movw $0x2000, %di /* 0x2000 is arbitrary value >= length
pascal@538 100 - of bootsect + room for stack */
pascal@538 101 + movw $0x2000-12, %di /* 0x2000 is arbitrary value >= length */
pascal@538 102 + /* of bootsect + room for stack + 12 for */
pascal@538 103 + /* saved disk parm block */
pascal@538 104
pascal@538 105 movw $BOOTSEG, %ax
pascal@538 106 movw %ax,%ds
pascal@538 107 movw %ax,%es
pascal@538 108 -
pascal@538 109 - cli
pascal@538 110 - movw %ax, %ss /* put stack at BOOTSEG:0x2000. */
pascal@538 111 + movw %ax,%ss /* put stack at initial position */
pascal@538 112 movw %di,%sp
pascal@538 113 - sti
pascal@538 114
pascal@538 115 - movw $why_end-why, %cx
pascal@538 116 - movw $why - _prefix, %si
pascal@538 117 +/* Many BIOS's default disk parameter tables will not recognize multi-sector
pascal@538 118 + * reads beyond the maximum sector number specified in the default diskette
pascal@538 119 + * parameter tables - this may mean 7 sectors in some cases.
pascal@538 120 + *
pascal@538 121 + * Since single sector reads are slow and out of the question, we must take care
pascal@538 122 + * of this by creating new parameter tables (for the first disk) in RAM. We
pascal@538 123 + * will set the maximum sector count to 36 - the most we will encounter on an
pascal@538 124 + * ED 2.88. High doesn't hurt. Low does.
pascal@538 125 + *
pascal@538 126 + * Segments are as follows: ds=es=ss=cs - BOOTSEG
pascal@538 127 + */
pascal@538 128 +
pascal@538 129 + xorw %cx,%cx
pascal@538 130 + movw %cx,%es /* access segment 0 */
pascal@538 131 + movw $0x78, %bx /* 0:bx is parameter table address */
pascal@538 132 + pushw %ds /* save ds */
pascal@538 133 +/* 0:bx is parameter table address */
pascal@538 134 + ldsw %es:(%bx),%si /* loads ds and si */
pascal@538 135 +
pascal@538 136 + movw %ax,%es /* ax is BOOTSECT (loaded above) */
pascal@538 137 + movb $6, %cl /* copy 12 bytes */
pascal@538 138 + cld
pascal@538 139 + pushw %di /* keep a copy for later */
pascal@538 140 + rep
pascal@538 141 + movsw /* ds:si is source, es:di is dest */
pascal@538 142 + popw %di
pascal@538 143 +
pascal@538 144 + movb $36,%es:4(%di)
pascal@538 145 +
pascal@538 146 + movw %cx,%ds /* access segment 0 */
pascal@538 147 + xchgw %di,(%bx)
pascal@538 148 + movw %es,%si
pascal@538 149 + xchgw %si,2(%bx)
pascal@538 150 + popw %ds /* restore ds */
pascal@538 151 + movw %di, dpoff /* save old parameters */
pascal@538 152 + movw %si, dpseg /* to restore just before finishing */
pascal@538 153 + pushw %ds
pascal@538 154 + popw %es /* reload es */
pascal@538 155 +
pascal@538 156 +/* Note that es is already set up. Also cx is 0 from rep movsw above. */
pascal@538 157 +
pascal@538 158 + xorb %ah,%ah /* reset FDC */
pascal@538 159 + xorb %dl,%dl
pascal@538 160 + int $0x13
pascal@538 161 +
pascal@538 162 +/* Get disk drive parameters, specifically number of sectors/track.
pascal@538 163 + *
pascal@538 164 + * It seems that there is no BIOS call to get the number of sectors. Guess
pascal@538 165 + * 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read,
pascal@538 166 + * 15 if sector 15 can be read. Otherwise guess 9.
pascal@538 167 + */
pascal@538 168 +
pascal@538 169 + movw $disksizes, %si /* table of sizes to try */
pascal@538 170 +
pascal@538 171 +probe_loop:
pascal@538 172 + lodsb
pascal@538 173 + cbtw /* extend to word */
pascal@538 174 + movw %ax, sectors
pascal@538 175 + cmpw $disksizes+4, %si
pascal@538 176 + jae got_sectors /* if all else fails, try 9 */
pascal@538 177 + xchgw %cx,%ax /* cx = track and sector */
pascal@538 178 + xorw %dx,%dx /* drive 0, head 0 */
pascal@538 179 + movw $0x0200, %bx /* address after boot sector */
pascal@538 180 + /* (512 bytes from origin, es = cs) */
pascal@538 181 + movw $0x0201, %ax /* service 2, 1 sector */
pascal@538 182 + int $0x13
pascal@538 183 + jc probe_loop /* try next value */
pascal@538 184 +
pascal@538 185 +got_sectors:
pascal@538 186 + movw $msg1end-msg1, %cx
pascal@538 187 + movw $msg1, %si
pascal@538 188 + call print_str
pascal@538 189 +
pascal@538 190 +/* ok, we've written the Loading... message, now we want to load the system */
pascal@538 191 +
pascal@538 192 + pushw %es /* = ds */
pascal@538 193 + movw $SYSSEG, %ax
pascal@538 194 + movw %ax,%es /* segment of SYSSEG<<4 */
pascal@538 195 + pushw %es
pascal@538 196 + call read_it
pascal@538 197 +
pascal@538 198 +/* This turns off the floppy drive motor, so that we enter the kernel in a
pascal@538 199 + * known state, and don't have to worry about it later.
pascal@538 200 + */
pascal@538 201 + movw $0x3f2, %dx
pascal@538 202 + xorb %al,%al
pascal@538 203 + outb %al,%dx
pascal@538 204 +
pascal@538 205 + call print_nl
pascal@538 206 + pop %es /* = SYSSEG */
pascal@538 207 + pop %es /* balance push/pop es */
pascal@538 208 +sigok:
pascal@538 209 +
pascal@538 210 +/* Restore original disk parameters */
pascal@538 211 + movw $0x78, %bx
pascal@538 212 + movw dpoff, %di
pascal@538 213 + movw dpseg, %si
pascal@538 214 + xorw %ax,%ax
pascal@538 215 + movw %ax,%ds
pascal@538 216 + movw %di,(%bx)
pascal@538 217 + movw %si,2(%bx)
pascal@538 218 +
pascal@538 219 +/* after that (everything loaded), we call to the .ROM file loaded. */
pascal@538 220 +
pascal@538 221 + pushl $0 /* No parameters to preserve for exit path */
pascal@538 222 + pushw $0 /* Use prefix exit path mechanism */
pascal@538 223 + ljmp $SYSSEG, $_start
pascal@538 224 +
pascal@538 225 +/* This routine loads the system at address SYSSEG<<4, making sure no 64kB
pascal@538 226 + * boundaries are crossed. We try to load it as fast as possible, loading whole
pascal@538 227 + * tracks whenever we can.
pascal@538 228 + *
pascal@538 229 + * in: es - starting address segment (normally SYSSEG)
pascal@538 230 + */
pascal@538 231 +read_it:
pascal@538 232 + movw $0,sread /* read whole image incl boot sector */
pascal@538 233 + movw %es,%ax
pascal@538 234 + testw $0x0fff, %ax
pascal@538 235 +die: jne die /* es must be at 64kB boundary */
pascal@538 236 + xorw %bx,%bx /* bx is starting address within segment */
pascal@538 237 +rp_read:
pascal@538 238 + movw %es,%ax
pascal@538 239 + movw %bx,%dx
pascal@538 240 + movb $4, %cl
pascal@538 241 + shrw %cl,%dx /* bx is always divisible by 16 */
pascal@538 242 + addw %dx,%ax
pascal@538 243 + cmpw $SYSSEG+SYSSIZE, %ax /* have we loaded all yet? */
pascal@538 244 + jb ok1_read
pascal@538 245 + ret
pascal@538 246 +ok1_read:
pascal@538 247 + movw sectors, %ax
pascal@538 248 + subw sread, %ax
pascal@538 249 + movw %ax,%cx
pascal@538 250 + shlw $9, %cx
pascal@538 251 + addw %bx,%cx
pascal@538 252 + jnc ok2_read
pascal@538 253 + je ok2_read
pascal@538 254 + xorw %ax,%ax
pascal@538 255 + subw %bx,%ax
pascal@538 256 + shrw $9, %ax
pascal@538 257 +ok2_read:
pascal@538 258 + call read_track
pascal@538 259 + movw %ax,%cx
pascal@538 260 + addw sread, %ax
pascal@538 261 + cmpw sectors, %ax
pascal@538 262 + jne ok3_read
pascal@538 263 + movw $1, %ax
pascal@538 264 + subw head, %ax
pascal@538 265 + jne ok4_read
pascal@538 266 + incw track
pascal@538 267 +ok4_read:
pascal@538 268 + movw %ax, head
pascal@538 269 + xorw %ax,%ax
pascal@538 270 +ok3_read:
pascal@538 271 + movw %ax, sread
pascal@538 272 + shlw $9, %cx
pascal@538 273 + addw %cx,%bx
pascal@538 274 + jnc rp_read
pascal@538 275 + movw %es,%ax
pascal@538 276 + addb $0x10, %ah
pascal@538 277 + movw %ax,%es
pascal@538 278 + xorw %bx,%bx
pascal@538 279 + jmp rp_read
pascal@538 280 +
pascal@538 281 +read_track:
pascal@538 282 + pusha
pascal@538 283 + pushw %ax
pascal@538 284 + pushw %bx
pascal@538 285 + pushw %bp /* just in case the BIOS is buggy */
pascal@538 286 + movw $0x0e2e, %ax /* 0x2e = . */
pascal@538 287 + movw $0x0007, %bx
pascal@538 288 + int $0x10
pascal@538 289 + popw %bp
pascal@538 290 + popw %bx
pascal@538 291 + popw %ax
pascal@538 292 +
pascal@538 293 + movw track, %dx
pascal@538 294 + movw sread, %cx
pascal@538 295 + incw %cx
pascal@538 296 + movb %dl,%ch
pascal@538 297 + movw head, %dx
pascal@538 298 + movb %dl,%dh
pascal@538 299 + andw $0x0100, %dx
pascal@538 300 + movb $2, %ah
pascal@538 301 +
pascal@538 302 + pushw %dx /* save for error dump */
pascal@538 303 + pushw %cx
pascal@538 304 + pushw %bx
pascal@538 305 + pushw %ax
pascal@538 306 +
pascal@538 307 + int $0x13
pascal@538 308 + jc bad_rt
pascal@538 309 + addw $8, %sp
pascal@538 310 + popa
pascal@538 311 + ret
pascal@538 312 +
pascal@538 313 +bad_rt: pushw %ax /* save error code */
pascal@538 314 + call print_all /* ah = error, al = read */
pascal@538 315 +
pascal@538 316 + xorb %ah,%ah
pascal@538 317 + xorb %dl,%dl
pascal@538 318 + int $0x13
pascal@538 319 +
pascal@538 320 + addw $10, %sp
pascal@538 321 + popa
pascal@538 322 + jmp read_track
pascal@538 323 +
pascal@538 324 +/* print_all is for debugging purposes. It will print out all of the registers.
pascal@538 325 + * The assumption is that this is called from a routine, with a stack frame like
pascal@538 326 + * dx
pascal@538 327 + * cx
pascal@538 328 + * bx
pascal@538 329 + * ax
pascal@538 330 + * error
pascal@538 331 + * ret <- sp
pascal@538 332 + */
pascal@538 333 +
pascal@538 334 +print_all:
pascal@538 335 + call print_nl /* nl for readability */
pascal@538 336 + movw $5, %cx /* error code + 4 registers */
pascal@538 337 + movw %sp,%bp
pascal@538 338 +
pascal@538 339 +print_loop:
pascal@538 340 + pushw %cx /* save count left */
pascal@538 341 +
pascal@538 342 + cmpb $5, %cl
pascal@538 343 + jae no_reg /* see if register name is needed */
pascal@538 344
pascal@538 345 movw $0x0007, %bx /* page 0, attribute 7 (normal) */
pascal@538 346 + movw $0xe05+0x41-1, %ax
pascal@538 347 + subb %cl,%al
pascal@538 348 + int $0x10
pascal@538 349 +
pascal@538 350 + movb $0x58, %al /* 'X' */
pascal@538 351 + int $0x10
pascal@538 352 +
pascal@538 353 + movb $0x3A, %al /* ':' */
pascal@538 354 + int $0x10
pascal@538 355 +
pascal@538 356 +no_reg:
pascal@538 357 + addw $2, %bp /* next register */
pascal@538 358 + call print_hex /* print it */
pascal@538 359 + movb $0x20, %al /* print a space */
pascal@538 360 + int $0x10
pascal@538 361 + popw %cx
pascal@538 362 + loop print_loop
pascal@538 363 + call print_nl /* nl for readability */
pascal@538 364 + ret
pascal@538 365 +
pascal@538 366 +print_str:
pascal@538 367 + movw $0x0007, %bx /* page 0, attribute 7 (normal) */
pascal@538 368 movb $0x0e, %ah /* write char, tty mode */
pascal@538 369 prloop:
pascal@538 370 lodsb
pascal@538 371 int $0x10
pascal@538 372 loop prloop
pascal@538 373 -freeze: jmp freeze
pascal@538 374 + ret
pascal@538 375 +
pascal@538 376 +print_nl:
pascal@538 377 + movw $0x0007, %bx /* page 0, attribute 7 (normal) */
pascal@538 378 + movw $0xe0d, %ax /* CR */
pascal@538 379 + int $0x10
pascal@538 380 + movb $0xa, %al /* LF */
pascal@538 381 + int $0x10
pascal@538 382 + ret
pascal@538 383 +
pascal@538 384 +/* print_hex prints the word pointed to by ss:bp in hexadecimal. */
pascal@538 385 +
pascal@538 386 +print_hex:
pascal@538 387 + movw (%bp),%dx /* load word into dx */
pascal@538 388 + movb $4, %cl
pascal@538 389 + movb $0x0e, %ah /* write char, tty mode */
pascal@538 390 + movw $0x0007, %bx /* page 0, attribute 7 (normal) */
pascal@538 391 + call print_digit
pascal@538 392 + call print_digit
pascal@538 393 + call print_digit
pascal@538 394 +/* fall through */
pascal@538 395 +print_digit:
pascal@538 396 + rol %cl,%dx /* rotate so that lowest 4 bits are used */
pascal@538 397 + movb $0x0f, %al /* mask for nybble */
pascal@538 398 + andb %dl,%al
pascal@538 399 + addb $0x90, %al /* convert al to ascii hex (four instructions) */
pascal@538 400 + daa
pascal@538 401 + adcb $0x40, %al
pascal@538 402 + daa
pascal@538 403 + int $0x10
pascal@538 404 + ret
pascal@538 405 +
pascal@538 406 +sread: .word 0 /* sectors read of current track */
pascal@538 407 +head: .word 0 /* current head */
pascal@538 408 +track: .word 0 /* current track */
pascal@538 409 +
pascal@538 410 +sectors:
pascal@538 411 + .word 0
pascal@538 412 +
pascal@538 413 +dpseg: .word 0
pascal@538 414 +dpoff: .word 0
pascal@538 415
pascal@538 416 -why: .ascii "This image cannot be loaded from a floppy disk.\r\n"
pascal@538 417 -why_end:
pascal@538 418 +disksizes:
pascal@538 419 + .byte 36,18,15,9
pascal@538 420
pascal@538 421 +msg1:
pascal@538 422 + .ascii "Loading ROM image"
pascal@538 423 +msg1end:
pascal@538 424
pascal@538 425 .org 497
pascal@538 426 setup_sects: