1/* ----------------------------------------------------------------------- * 2 * 3 * Copyright 2001-2009 H. Peter Anvin - All Rights Reserved 4 * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin 5 * Portions copyright 2009-2010 Shao Miller 6 * [El Torito code, mBFT, "safe hook"] 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation, Inc., 53 Temple Place Ste 330, 11 * Boston MA 02111-1307, USA; either version 2 of the License, or 12 * (at your option) any later version; incorporated herein by reference. 13 * 14 * ----------------------------------------------------------------------- */ 15 16#include <stdint.h> 17#include <minmax.h> 18#include <suffix_number.h> 19#include "bda.h" 20#include "dskprobe.h" 21#include "e820.h" 22#include "conio.h" 23#include "version.h" 24#include "memdisk.h" 25#include <version.h> 26 27const char memdisk_version[] = "MEMDISK " VERSION_STR " " DATE; 28const char copyright[] = 29 "Copyright " FIRSTYEAR "-" YEAR_STR " H. Peter Anvin et al"; 30 31extern const char _binary_memdisk_chs_512_bin_start[]; 32extern const char _binary_memdisk_chs_512_bin_end[]; 33extern const char _binary_memdisk_chs_512_bin_size[]; 34extern const char _binary_memdisk_edd_512_bin_start[]; 35extern const char _binary_memdisk_edd_512_bin_end[]; 36extern const char _binary_memdisk_edd_512_bin_size[]; 37extern const char _binary_memdisk_iso_512_bin_start[]; 38extern const char _binary_memdisk_iso_512_bin_end[]; 39extern const char _binary_memdisk_iso_512_bin_size[]; 40extern const char _binary_memdisk_iso_2048_bin_start[]; 41extern const char _binary_memdisk_iso_2048_bin_end[]; 42extern const char _binary_memdisk_iso_2048_bin_size[]; 43 44/* Pull in structures common to MEMDISK and MDISKCHK.COM */ 45#include "mstructs.h" 46 47/* An EDD disk packet */ 48struct edd_dsk_pkt { 49 uint8_t size; /* Packet size */ 50 uint8_t res1; /* Reserved */ 51 uint16_t count; /* Count to transfer */ 52 uint32_t buf; /* Buffer pointer */ 53 uint64_t start; /* LBA to start from */ 54 uint64_t buf64; /* 64-bit buf pointer */ 55} __attribute__ ((packed)); 56 57/* Change to 1 for El Torito debugging */ 58#define DBG_ELTORITO 0 59 60#if DBG_ELTORITO 61extern void eltorito_dump(uint32_t); 62#endif 63 64/* 65 * Routine to seek for a command-line item and return a pointer 66 * to the data portion, if present 67 */ 68 69/* Magic return values */ 70#define CMD_NOTFOUND ((char *)-1) /* Not found */ 71#define CMD_BOOL ((char *)-2) /* Found boolean option */ 72#define CMD_HASDATA(X) ((int)(X) >= 0) 73 74static const char *getcmditem(const char *what) 75{ 76 const char *p; 77 const char *wp = what; 78 int match = 0; 79 80 for (p = shdr->cmdline; *p; p++) { 81 switch (match) { 82 case 0: /* Ground state */ 83 if (*p == ' ') 84 break; 85 86 wp = what; 87 match = 1; 88 /* Fall through */ 89 90 case 1: /* Matching */ 91 if (*wp == '\0') { 92 if (*p == '=') 93 return p + 1; 94 else if (*p == ' ') 95 return CMD_BOOL; 96 else { 97 match = 2; 98 break; 99 } 100 } 101 if (*p != *wp++) 102 match = 2; 103 break; 104 105 case 2: /* Mismatch, skip rest of option */ 106 if (*p == ' ') 107 match = 0; /* Next option */ 108 break; 109 } 110 } 111 112 /* Check for matching string at end of line */ 113 if (match == 1 && *wp == '\0') 114 return CMD_BOOL; 115 116 return CMD_NOTFOUND; 117} 118 119/* 120 * Check to see if this is a gzip image 121 */ 122#define UNZIP_ALIGN 512 123 124extern const char _end[]; /* Symbol signalling end of data */ 125 126void unzip_if_needed(uint32_t * where_p, uint32_t * size_p) 127{ 128 uint32_t where = *where_p; 129 uint32_t size = *size_p; 130 uint32_t zbytes; 131 uint32_t startrange, endrange; 132 uint32_t gzdatasize, gzwhere; 133 uint32_t orig_crc, offset; 134 uint32_t target = 0; 135 int i, okmem; 136 137 /* Is it a gzip image? */ 138 if (check_zip((void *)where, size, &zbytes, &gzdatasize, 139 &orig_crc, &offset) == 0) { 140 141 if (offset + zbytes > size) { 142 /* 143 * Assertion failure; check_zip is supposed to guarantee this 144 * never happens. 145 */ 146 die("internal error: check_zip returned nonsense\n"); 147 } 148 149 /* 150 * Find a good place to put it: search memory ranges in descending 151 * order until we find one that is legal and fits 152 */ 153 okmem = 0; 154 for (i = nranges - 1; i >= 0; i--) { 155 /* 156 * We can't use > 4G memory (32 bits only.) Truncate to 2^32-1 157 * so we don't have to deal with funny wraparound issues. 158 */ 159 160 /* Must be memory */ 161 if (ranges[i].type != 1) 162 continue; 163 164 /* Range start */ 165 if (ranges[i].start >= 0xFFFFFFFF) 166 continue; 167 168 startrange = (uint32_t) ranges[i].start; 169 170 /* Range end (0 for end means 2^64) */ 171 endrange = ((ranges[i + 1].start >= 0xFFFFFFFF || 172 ranges[i + 1].start == 0) 173 ? 0xFFFFFFFF : (uint32_t) ranges[i + 1].start); 174 175 /* Make sure we don't overwrite ourselves */ 176 if (startrange < (uint32_t) _end) 177 startrange = (uint32_t) _end; 178 179 /* Allow for alignment */ 180 startrange = 181 (ranges[i].start + (UNZIP_ALIGN - 1)) & ~(UNZIP_ALIGN - 1); 182 183 /* In case we just killed the whole range... */ 184 if (startrange >= endrange) 185 continue; 186 187 /* 188 * Must be large enough... don't rely on gzwhere for this 189 * (wraparound) 190 */ 191 if (endrange - startrange < gzdatasize) 192 continue; 193 194 /* 195 * This is where the gz image would be put if we put it in this 196 * range... 197 */ 198 gzwhere = (endrange - gzdatasize) & ~(UNZIP_ALIGN - 1); 199 200 /* Cast to uint64_t just in case we're flush with the top byte */ 201 if ((uint64_t) where + size >= gzwhere && where < endrange) { 202 /* 203 * Need to move source data to avoid compressed/uncompressed 204 * overlap 205 */ 206 uint32_t newwhere; 207 208 if (gzwhere - startrange < size) 209 continue; /* Can't fit both old and new */ 210 211 newwhere = (gzwhere - size) & ~(UNZIP_ALIGN - 1); 212 printf("Moving compressed data from 0x%08x to 0x%08x\n", 213 where, newwhere); 214 215 memmove((void *)newwhere, (void *)where, size); 216 where = newwhere; 217 } 218 219 target = gzwhere; 220 okmem = 1; 221 break; 222 } 223 224 if (!okmem) 225 die("Not enough memory to decompress image (need 0x%08x bytes)\n", 226 gzdatasize); 227 228 printf("gzip image: decompressed addr 0x%08x, len 0x%08x: ", 229 target, gzdatasize); 230 231 *size_p = gzdatasize; 232 *where_p = (uint32_t) unzip((void *)(where + offset), zbytes, 233 gzdatasize, orig_crc, (void *)target); 234 } 235} 236 237/* 238 * Figure out the "geometry" of the disk in question 239 */ 240struct geometry { 241 uint32_t sectors; /* Sector count */ 242 uint32_t c, h, s; /* C/H/S geometry */ 243 uint32_t offset; /* Byte offset for disk */ 244 uint32_t boot_lba; /* LBA of bootstrap code */ 245 uint8_t type; /* Type byte for INT 13h AH=08h */ 246 uint8_t driveno; /* Drive no */ 247 uint8_t sector_shift; /* Sector size as a power of 2 */ 248 const char *hsrc, *ssrc; /* Origins of H and S geometries */ 249}; 250 251/* Format of a DOS partition table entry */ 252struct ptab_entry { 253 uint8_t active; 254 uint8_t start_h, start_s, start_c; 255 uint8_t type; 256 uint8_t end_h, end_s, end_c; 257 uint32_t start; 258 uint32_t size; 259} __attribute__ ((packed)); 260 261/* Format of a FAT filesystem superblock */ 262struct fat_extra { 263 uint8_t bs_drvnum; 264 uint8_t bs_resv1; 265 uint8_t bs_bootsig; 266 uint32_t bs_volid; 267 char bs_vollab[11]; 268 char bs_filsystype[8]; 269} __attribute__ ((packed)); 270struct fat_super { 271 uint8_t bs_jmpboot[3]; 272 char bs_oemname[8]; 273 uint16_t bpb_bytspersec; 274 uint8_t bpb_secperclus; 275 uint16_t bpb_rsvdseccnt; 276 uint8_t bpb_numfats; 277 uint16_t bpb_rootentcnt; 278 uint16_t bpb_totsec16; 279 uint8_t bpb_media; 280 uint16_t bpb_fatsz16; 281 uint16_t bpb_secpertrk; 282 uint16_t bpb_numheads; 283 uint32_t bpb_hiddsec; 284 uint32_t bpb_totsec32; 285 union { 286 struct { 287 struct fat_extra extra; 288 } fat16; 289 struct { 290 uint32_t bpb_fatsz32; 291 uint16_t bpb_extflags; 292 uint16_t bpb_fsver; 293 uint32_t bpb_rootclus; 294 uint16_t bpb_fsinfo; 295 uint16_t bpb_bkbootsec; 296 char bpb_reserved[12]; 297 /* Clever, eh? Same fields, different offset... */ 298 struct fat_extra extra; 299 } fat32 __attribute__ ((packed)); 300 } x; 301} __attribute__ ((packed)); 302 303/* Format of a DOSEMU header */ 304struct dosemu_header { 305 uint8_t magic[7]; /* DOSEMU\0 */ 306 uint32_t h; 307 uint32_t s; 308 uint32_t c; 309 uint32_t offset; 310 uint8_t pad[105]; 311} __attribute__ ((packed)); 312 313#define FOUR(a,b,c,d) (((a) << 24)|((b) << 16)|((c) << 8)|(d)) 314 315static const struct geometry *get_disk_image_geometry(uint32_t where, 316 uint32_t size) 317{ 318 static struct geometry hd_geometry; 319 struct dosemu_header dosemu; 320 unsigned int sectors, xsectors, v; 321 unsigned int offset; 322 int i; 323 const char *p; 324 325 printf("command line: %s\n", shdr->cmdline); 326 327 hd_geometry.sector_shift = 9; /* Assume floppy/HDD at first */ 328 329 offset = 0; 330 if (CMD_HASDATA(p = getcmditem("offset")) && (v = atou(p))) 331 offset = v; 332 333 sectors = xsectors = (size - offset) >> hd_geometry.sector_shift; 334 335 hd_geometry.hsrc = "guess"; 336 hd_geometry.ssrc = "guess"; 337 hd_geometry.sectors = sectors; 338 hd_geometry.offset = offset; 339 340 if ((p = getcmditem("iso")) != CMD_NOTFOUND) { 341#if DBG_ELTORITO 342 eltorito_dump(where); 343#endif 344 struct edd4_bvd *bvd = (struct edd4_bvd *)(where + 17 * 2048); 345 /* Tiny sanity check */ 346 if ((bvd->boot_rec_ind != 0) || (bvd->ver != 1)) 347 printf("El Torito BVD sanity check failed.\n"); 348 struct edd4_bootcat *boot_cat = 349 (struct edd4_bootcat *)(where + bvd->boot_cat * 2048); 350 /* Another tiny sanity check */ 351 if ((boot_cat->validation_entry.platform_id != 0) || 352 (boot_cat->validation_entry.key55 != 0x55) || 353 (boot_cat->validation_entry.keyAA != 0xAA)) 354 printf("El Torito boot catalog sanity check failed.\n"); 355 /* If we have an emulation mode, set the offset to the image */ 356 if (boot_cat->initial_entry.media_type) 357 hd_geometry.offset += boot_cat->initial_entry.load_block * 2048; 358 else 359 /* We're a no-emulation mode, so we will boot to an offset */ 360 hd_geometry.boot_lba = boot_cat->initial_entry.load_block * 4; 361 if (boot_cat->initial_entry.media_type < 4) { 362 /* We're a floppy emulation mode or our params will be 363 * overwritten by the no emulation mode case 364 */ 365 hd_geometry.driveno = 0x00; 366 hd_geometry.c = 80; 367 hd_geometry.h = 2; 368 } 369 switch (boot_cat->initial_entry.media_type) { 370 case 0: /* No emulation */ 371 hd_geometry.driveno = 0xE0; 372 hd_geometry.type = 10; /* ATAPI removable media device */ 373 hd_geometry.c = 65535; 374 hd_geometry.h = 255; 375 hd_geometry.s = 15; 376 /* 2048-byte sectors, so adjust the size and count */ 377 hd_geometry.sector_shift = 11; 378 break; 379 case 1: /* 1.2 MB floppy */ 380 hd_geometry.s = 15; 381 hd_geometry.type = 2; 382 sectors = 2400; 383 break; 384 case 2: /* 1.44 MB floppy */ 385 hd_geometry.s = 18; 386 hd_geometry.type = 4; 387 sectors = 2880; 388 break; 389 case 3: /* 2.88 MB floppy */ 390 hd_geometry.s = 36; 391 hd_geometry.type = 6; 392 sectors = 5760; 393 break; 394 case 4: 395 hd_geometry.driveno = 0x80; 396 hd_geometry.type = 0; 397 break; 398 } 399 sectors = (size - hd_geometry.offset) >> hd_geometry.sector_shift; 400 401 /* For HDD emulation, we figure out the geometry later. Otherwise: */ 402 if (hd_geometry.s) { 403 hd_geometry.hsrc = hd_geometry.ssrc = "El Torito"; 404 } 405 hd_geometry.sectors = sectors; 406 } 407 408 /* Do we have a DOSEMU header? */ 409 memcpy(&dosemu, (char *)where + hd_geometry.offset, sizeof dosemu); 410 if (!memcmp("DOSEMU", dosemu.magic, 7)) { 411 /* Always a hard disk unless overruled by command-line options */ 412 hd_geometry.driveno = 0x80; 413 hd_geometry.type = 0; 414 hd_geometry.c = dosemu.c; 415 hd_geometry.h = dosemu.h; 416 hd_geometry.s = dosemu.s; 417 hd_geometry.offset += dosemu.offset; 418 sectors = (size - hd_geometry.offset) >> hd_geometry.sector_shift; 419 420 hd_geometry.hsrc = hd_geometry.ssrc = "DOSEMU"; 421 } 422 423 if (CMD_HASDATA(p = getcmditem("c")) && (v = atou(p))) 424 hd_geometry.c = v; 425 if (CMD_HASDATA(p = getcmditem("h")) && (v = atou(p))) { 426 hd_geometry.h = v; 427 hd_geometry.hsrc = "cmd"; 428 } 429 if (CMD_HASDATA(p = getcmditem("s")) && (v = atou(p))) { 430 hd_geometry.s = v; 431 hd_geometry.ssrc = "cmd"; 432 } 433 434 if (!hd_geometry.h || !hd_geometry.s) { 435 int h, s, max_h, max_s; 436 437 max_h = hd_geometry.h; 438 max_s = hd_geometry.s; 439 440 if (!(max_h | max_s)) { 441 /* Look for a FAT superblock and if we find something that looks 442 enough like one, use geometry from that. This takes care of 443 megafloppy images and unpartitioned hard disks. */ 444 const struct fat_extra *extra = NULL; 445 const struct fat_super *fs = (const struct fat_super *) 446 ((char *)where + hd_geometry.offset); 447 448 if ((fs->bpb_media == 0xf0 || fs->bpb_media >= 0xf8) && 449 (fs->bs_jmpboot[0] == 0xe9 || fs->bs_jmpboot[0] == 0xeb) && 450 fs->bpb_bytspersec == 512 && 451 fs->bpb_numheads >= 1 && fs->bpb_numheads <= 256 && 452 fs->bpb_secpertrk >= 1 && fs->bpb_secpertrk <= 63) { 453 extra = 454 fs->bpb_fatsz16 ? &fs->x.fat16.extra : &fs->x.fat32.extra; 455 if (! 456 (extra->bs_bootsig == 0x29 && extra->bs_filsystype[0] == 'F' 457 && extra->bs_filsystype[1] == 'A' 458 && extra->bs_filsystype[2] == 'T')) 459 extra = NULL; 460 } 461 if (extra) { 462 hd_geometry.driveno = extra->bs_drvnum & 0x80; 463 max_h = fs->bpb_numheads; 464 max_s = fs->bpb_secpertrk; 465 hd_geometry.hsrc = hd_geometry.ssrc = "FAT"; 466 } 467 } 468 469 if (!(max_h | max_s)) { 470 /* No FAT filesystem found to steal geometry from... */ 471 if ((sectors < 4096 * 2) && (hd_geometry.sector_shift == 9)) { 472 int ok = 0; 473 unsigned int xsectors = sectors; 474 475 hd_geometry.driveno = 0; /* Assume floppy */ 476 477 while (!ok) { 478 /* Assume it's a floppy drive, guess a geometry */ 479 unsigned int type, track; 480 int c, h, s = 0; 481 482 if (xsectors < 320 * 2) { 483 c = 40; 484 h = 1; 485 type = 1; 486 } else if (xsectors < 640 * 2) { 487 c = 40; 488 h = 2; 489 type = 1; 490 } else if (xsectors < 1200 * 2) { 491 c = 80; 492 h = 2; 493 type = 3; 494 } else if (xsectors < 1440 * 2) { 495 c = 80; 496 h = 2; 497 type = 2; 498 } else if (xsectors < 2880 * 2) { 499 c = 80; 500 h = 2; 501 type = 4; 502 } else { 503 c = 80; 504 h = 2; 505 type = 6; 506 } 507 track = c * h; 508 while (c < 256) { 509 s = xsectors / track; 510 if (s < 63 && (xsectors % track) == 0) { 511 ok = 1; 512 break; 513 } 514 c++; 515 track += h; 516 } 517 if (ok) { 518 max_h = h; 519 max_s = s; 520 hd_geometry.hsrc = hd_geometry.ssrc = "fd"; 521 } else { 522 /* No valid floppy geometry, fake it by simulating broken 523 sectors at the end of the image... */ 524 xsectors++; 525 } 526 527 hd_geometry.type = type; 528 } 529 } else { 530 /* Assume it is a hard disk image and scan for a partition table */ 531 const struct ptab_entry *ptab = (const struct ptab_entry *) 532 ((char *)where + hd_geometry.offset + (512 - 2 - 4 * 16)); 533 534 /* Assume hard disk */ 535 if (!hd_geometry.driveno) 536 hd_geometry.driveno = 0x80; 537 538 if (*(uint16_t *) ((char *)where + hd_geometry.offset + 512 - 2) == 0xaa55) { 539 for (i = 0; i < 4; i++) { 540 if (ptab[i].type && !(ptab[i].active & 0x7f)) { 541 s = (ptab[i].start_s & 0x3f); 542 h = ptab[i].start_h + 1; 543 544 if (max_h < h) 545 max_h = h; 546 if (max_s < s) 547 max_s = s; 548 549 s = (ptab[i].end_s & 0x3f); 550 h = ptab[i].end_h + 1; 551 552 if (max_h < h) { 553 max_h = h; 554 hd_geometry.hsrc = "MBR"; 555 } 556 if (max_s < s) { 557 max_s = s; 558 hd_geometry.ssrc = "MBR"; 559 } 560 } 561 } 562 } 563 564 hd_geometry.type = 0; 565 } 566 } 567 568 if (!max_h) 569 max_h = xsectors > 2097152 ? 255 : 64; 570 if (!max_s) 571 max_s = xsectors > 2097152 ? 63 : 32; 572 573 hd_geometry.h = max_h; 574 hd_geometry.s = max_s; 575 } 576 577 if (!hd_geometry.c) 578 hd_geometry.c = xsectors / (hd_geometry.h * hd_geometry.s); 579 580 if ((p = getcmditem("floppy")) != CMD_NOTFOUND) { 581 hd_geometry.driveno = CMD_HASDATA(p) ? atou(p) & 0x7f : 0; 582 } else if ((p = getcmditem("harddisk")) != CMD_NOTFOUND) { 583 hd_geometry.driveno = CMD_HASDATA(p) ? atou(p) | 0x80 : 0x80; 584 } 585 586 if (hd_geometry.driveno & 0x80) { 587 hd_geometry.type = 0; /* Type = hard disk */ 588 } else { 589 if (hd_geometry.type == 0) 590 hd_geometry.type = 0x10; /* ATAPI floppy, e.g. LS-120 */ 591 } 592 593 if ((size - hd_geometry.offset) & 0x1ff) { 594 puts("MEMDISK: Image has fractional end sector\n"); 595 } 596 if (sectors % (hd_geometry.h * hd_geometry.s)) { 597 puts("MEMDISK: Image seems to have fractional end cylinder\n"); 598 } 599 if ((hd_geometry.c * hd_geometry.h * hd_geometry.s) > sectors) { 600 puts("MEMDISK: Image appears to be truncated\n"); 601 } 602 603 return &hd_geometry; 604} 605 606/* 607 * Find a $PnP installation check structure; return (ES << 16) + DI value 608 */ 609static uint32_t pnp_install_check(void) 610{ 611 uint32_t *seg; 612 unsigned char *p, csum; 613 int i, len; 614 615 for (seg = (uint32_t *) 0xf0000; seg < (uint32_t *) 0x100000; seg += 4) { 616 if (*seg == ('$' + ('P' << 8) + ('n' << 16) + ('P' << 24))) { 617 p = (unsigned char *)seg; 618 len = p[5]; 619 if (len < 0x21) 620 continue; 621 csum = 0; 622 for (i = len; i; i--) 623 csum += *p++; 624 if (csum != 0) 625 continue; 626 627 return (0xf000 << 16) + (uint16_t) (unsigned long)seg; 628 } 629 } 630 631 return 0; 632} 633 634/* 635 * Relocate the real-mode code to a new segment 636 */ 637struct gdt_ptr { 638 uint16_t limit; 639 uint32_t base; 640} __attribute__ ((packed)); 641 642static void set_seg_base(uint32_t gdt_base, int seg, uint32_t v) 643{ 644 *(uint16_t *) (gdt_base + seg + 2) = v; 645 *(uint8_t *) (gdt_base + seg + 4) = v >> 16; 646 *(uint8_t *) (gdt_base + seg + 7) = v >> 24; 647} 648 649static void relocate_rm_code(uint32_t newbase) 650{ 651 uint32_t gdt_base; 652 uint32_t oldbase = rm_args.rm_base; 653 uint32_t delta = newbase - oldbase; 654 655 cli(); 656 memmove((void *)newbase, (void *)oldbase, rm_args.rm_size); 657 658 rm_args.rm_return += delta; 659 rm_args.rm_intcall += delta; 660 rm_args.rm_bounce += delta; 661 rm_args.rm_base += delta; 662 rm_args.rm_gdt += delta; 663 rm_args.rm_pmjmp += delta; 664 rm_args.rm_rmjmp += delta; 665 666 gdt_base = rm_args.rm_gdt; 667 668 *(uint32_t *) (gdt_base + 2) = gdt_base; /* GDT self-pointer */ 669 670 /* Segments 0x10 and 0x18 are real-mode-based */ 671 set_seg_base(gdt_base, 0x10, rm_args.rm_base); 672 set_seg_base(gdt_base, 0x18, rm_args.rm_base); 673 674#if __SIZEOF_POINTER__ == 4 675 asm volatile ("lgdtl %0"::"m" (*(char *)gdt_base)); 676#elif __SIZEOF_POINTER__ == 8 677 asm volatile ("lgdt %0"::"m" (*(char *)gdt_base)); 678#else 679#error "unsupported architecture" 680#endif 681 682 *(uint32_t *) rm_args.rm_pmjmp += delta; 683 *(uint16_t *) rm_args.rm_rmjmp += delta >> 4; 684 685 rm_args.rm_handle_interrupt += delta; 686 687 sti(); 688} 689 690static uint8_t checksum_buf(const void *buf, int count) 691{ 692 const uint8_t *p = buf; 693 uint8_t c = 0; 694 695 while (count--) 696 c += *p++; 697 698 return c; 699} 700 701static int stack_needed(void) 702{ 703 const unsigned int min_stack = 128; /* Minimum stack size */ 704 const unsigned int def_stack = 512; /* Default stack size */ 705 unsigned int v = 0; 706 const char *p; 707 708 if (CMD_HASDATA(p = getcmditem("stack"))) 709 v = atou(p); 710 711 if (!v) 712 v = def_stack; 713 714 if (v < min_stack) 715 v = min_stack; 716 717 return v; 718} 719 720/* 721 * Set max memory by reservation 722 * Adds reservations to data in INT15h to prevent access to the top of RAM 723 * if there's any above the point specified. 724 */ 725void setmaxmem(unsigned long long restop_ull) 726{ 727 uint32_t restop; 728 struct e820range *ep; 729 const int int15restype = 2; 730 731 /* insertrange() works on uint32_t */ 732 restop = min(restop_ull, UINT32_MAX); 733 /* printf(" setmaxmem '%08x%08x' => %08x\n", 734 (unsigned int)(restop_ull>>32), (unsigned int)restop_ull, restop); */ 735 736 for (ep = ranges; ep->type != -1U; ep++) { 737 if (ep->type == 1) { /* Only if available */ 738 if (ep->start >= restop) { 739 /* printf(" %08x -> 2\n", ep->start); */ 740 ep->type = int15restype; 741 } else if (ep[1].start > restop) { 742 /* printf(" +%08x =2; cut %08x\n", restop, ep->start); */ 743 insertrange(restop, (ep[1].start - restop), int15restype); 744 } 745 } 746 } 747 parse_mem(); 748} 749 750struct real_mode_args rm_args; 751 752/* 753 * Actual setup routine 754 * Returns the drive number (which is then passed in %dl to the 755 * called routine.) 756 */ 757void setup(const struct real_mode_args *rm_args_ptr) 758{ 759 unsigned int bin_size; 760 char *memdisk_hook; 761 struct memdisk_header *hptr; 762 struct patch_area *pptr; 763 struct mBFT *mbft; 764 uint16_t driverseg; 765 uint32_t driverptr, driveraddr; 766 uint16_t dosmem_k; 767 uint32_t stddosmem; 768 const struct geometry *geometry; 769 unsigned int total_size; 770 unsigned int cmdline_len, stack_len, e820_len; 771 const struct edd4_bvd *bvd; 772 const struct edd4_bootcat *boot_cat = 0; 773 com32sys_t regs; 774 uint32_t ramdisk_image, ramdisk_size; 775 uint32_t boot_base, rm_base; 776 int bios_drives; 777 int do_edd = 1; /* 0 = no, 1 = yes, default is yes */ 778 int do_eltorito = 0; /* default is no */ 779 int no_bpt; /* No valid BPT presented */ 780 uint32_t boot_seg = 0; /* Meaning 0000:7C00 */ 781 uint32_t boot_len = 512; /* One sector */ 782 const char *p; 783 784 /* We need to copy the rm_args into their proper place */ 785 memcpy(&rm_args, rm_args_ptr, sizeof rm_args); 786 sti(); /* ... then interrupts are safe */ 787 788 /* Show signs of life */ 789 printf("%s %s\n", memdisk_version, copyright); 790 791 if (!shdr->ramdisk_image || !shdr->ramdisk_size) 792 die("MEMDISK: No ramdisk image specified!\n"); 793 794 ramdisk_image = shdr->ramdisk_image; 795 ramdisk_size = shdr->ramdisk_size; 796 797 e820map_init(); /* Initialize memory data structure */ 798 get_mem(); /* Query BIOS for memory map */ 799 parse_mem(); /* Parse memory map */ 800 801 printf("Ramdisk at 0x%08x, length 0x%08x\n", ramdisk_image, ramdisk_size); 802 803 unzip_if_needed(&ramdisk_image, &ramdisk_size); 804 805 geometry = get_disk_image_geometry(ramdisk_image, ramdisk_size); 806 807 if (getcmditem("edd") != CMD_NOTFOUND || 808 getcmditem("ebios") != CMD_NOTFOUND) 809 do_edd = 1; 810 else if (getcmditem("noedd") != CMD_NOTFOUND || 811 getcmditem("noebios") != CMD_NOTFOUND || 812 getcmditem("cbios") != CMD_NOTFOUND) 813 do_edd = 0; 814 else 815 do_edd = (geometry->driveno & 0x80) ? 1 : 0; 816 817 if (getcmditem("iso") != CMD_NOTFOUND) { 818 do_eltorito = 1; 819 do_edd = 1; /* Mandatory */ 820 } 821 822 /* Choose the appropriate installable memdisk hook */ 823 if (do_eltorito) { 824 if (geometry->sector_shift == 11) { 825 bin_size = (int)&_binary_memdisk_iso_2048_bin_size; 826 memdisk_hook = (char *)&_binary_memdisk_iso_2048_bin_start; 827 } else { 828 bin_size = (int)&_binary_memdisk_iso_512_bin_size; 829 memdisk_hook = (char *)&_binary_memdisk_iso_512_bin_start; 830 } 831 } else { 832 if (do_edd) { 833 bin_size = (int)&_binary_memdisk_edd_512_bin_size; 834 memdisk_hook = (char *)&_binary_memdisk_edd_512_bin_start; 835 } else { 836 bin_size = (int)&_binary_memdisk_chs_512_bin_size; 837 memdisk_hook = (char *)&_binary_memdisk_chs_512_bin_start; 838 } 839 } 840 841 /* Reserve the ramdisk memory */ 842 insertrange(ramdisk_image, ramdisk_size, 2); 843 parse_mem(); /* Recompute variables */ 844 845 /* Figure out where it needs to go */ 846 hptr = (struct memdisk_header *)memdisk_hook; 847 pptr = (struct patch_area *)(memdisk_hook + hptr->patch_offs); 848 849 dosmem_k = rdz_16(BIOS_BASEMEM); 850 pptr->mdi.olddosmem = dosmem_k; 851 stddosmem = dosmem_k << 10; 852 /* If INT 15 E820 and INT 12 disagree, go with the most conservative */ 853 if (stddosmem > dos_mem) 854 stddosmem = dos_mem; 855 856 pptr->driveno = geometry->driveno; 857 pptr->drivetype = geometry->type; 858 pptr->cylinders = geometry->c; /* Possible precision loss */ 859 pptr->heads = geometry->h; 860 pptr->sectors = geometry->s; 861 pptr->mdi.disksize = geometry->sectors; 862 pptr->mdi.diskbuf = ramdisk_image + geometry->offset; 863 pptr->mdi.sector_shift = geometry->sector_shift; 864 pptr->statusptr = (geometry->driveno & 0x80) ? 0x474 : 0x441; 865 866 pptr->mdi.bootloaderid = shdr->type_of_loader; 867 868 pptr->configflags = CONFIG_SAFEINT; /* Default */ 869 /* Set config flags */ 870 if (getcmditem("ro") != CMD_NOTFOUND) { 871 pptr->configflags |= CONFIG_READONLY; 872 } 873 if (getcmditem("raw") != CMD_NOTFOUND) { 874 pptr->configflags &= ~CONFIG_MODEMASK; 875 pptr->configflags |= CONFIG_RAW; 876 } 877 if (getcmditem("bigraw") != CMD_NOTFOUND) { 878 pptr->configflags &= ~CONFIG_MODEMASK; 879 pptr->configflags |= CONFIG_BIGRAW | CONFIG_RAW; 880 } 881 if (getcmditem("int") != CMD_NOTFOUND) { 882 pptr->configflags &= ~CONFIG_MODEMASK; 883 /* pptr->configflags |= 0; */ 884 } 885 if (getcmditem("safeint") != CMD_NOTFOUND) { 886 pptr->configflags &= ~CONFIG_MODEMASK; 887 pptr->configflags |= CONFIG_SAFEINT; 888 } 889 890 printf("Disk is %s%d, %u%s K, C/H/S = %u/%u/%u (%s/%s), EDD %s, %s\n", 891 (geometry->driveno & 0x80) ? "hd" : "fd", 892 geometry->driveno & 0x7f, 893 geometry->sectors >> 1, 894 (geometry->sectors & 1) ? ".5" : "", 895 geometry->c, geometry->h, geometry->s, 896 geometry->hsrc, geometry->ssrc, 897 do_edd ? "on" : "off", 898 pptr->configflags & CONFIG_READONLY ? "ro" : "rw"); 899 900 puts("Using "); 901 switch (pptr->configflags & CONFIG_MODEMASK) { 902 case 0: 903 puts("standard INT 15h"); 904 break; 905 case CONFIG_SAFEINT: 906 puts("safe INT 15h"); 907 break; 908 case CONFIG_RAW: 909 puts("raw"); 910 break; 911 case CONFIG_RAW | CONFIG_BIGRAW: 912 puts("big real mode raw"); 913 break; 914 default: 915 printf("unknown %#x", pptr->configflags & CONFIG_MODEMASK); 916 break; 917 } 918 puts(" access to high memory\n"); 919 920 /* Set up a drive parameter table */ 921 if (geometry->driveno & 0x80) { 922 /* Hard disk */ 923 pptr->dpt.hd.max_cyl = geometry->c - 1; 924 pptr->dpt.hd.max_head = geometry->h - 1; 925 pptr->dpt.hd.ctrl = (geometry->h > 8) ? 0x08 : 0; 926 } else { 927 /* Floppy - most of these fields are bogus and mimic 928 a 1.44 MB floppy drive */ 929 pptr->dpt.fd.specify1 = 0xdf; 930 pptr->dpt.fd.specify2 = 0x02; 931 pptr->dpt.fd.delay = 0x25; 932 pptr->dpt.fd.sectors = geometry->s; 933 pptr->dpt.fd.bps = 0x02; 934 pptr->dpt.fd.isgap = 0x12; 935 pptr->dpt.fd.dlen = 0xff; 936 pptr->dpt.fd.fgap = 0x6c; 937 pptr->dpt.fd.ffill = 0xf6; 938 pptr->dpt.fd.settle = 0x0f; 939 pptr->dpt.fd.mstart = 0x05; 940 pptr->dpt.fd.maxtrack = geometry->c - 1; 941 pptr->dpt.fd.cmos = geometry->type > 5 ? 5 : geometry->type; 942 943 pptr->dpt.fd.old_fd_dpt = rdz_32(BIOS_INT1E); 944 } 945 946 /* Set up an EDD drive parameter table */ 947 if (do_edd) { 948 pptr->edd_dpt.sectors = geometry->sectors; 949 /* The EDD spec has this as <= 15482880 sectors (1024x240x63); 950 this seems to make very little sense. Try for something saner. */ 951 if (geometry->c <= 1024 && geometry->h <= 255 && geometry->s <= 63) { 952 pptr->edd_dpt.c = geometry->c; 953 pptr->edd_dpt.h = geometry->h; 954 pptr->edd_dpt.s = geometry->s; 955 /* EDD-4 states that invalid geometry should be returned 956 * for INT 0x13, AH=0x48 "EDD Get Disk Parameters" call on an 957 * El Torito ODD. Check for 2048-byte sector size 958 */ 959 if (geometry->sector_shift != 11) 960 pptr->edd_dpt.flags |= 0x0002; /* Geometry valid */ 961 } 962 if (!(geometry->driveno & 0x80)) { 963 /* Floppy drive. Mark it as a removable device with 964 media change notification; media is present. */ 965 pptr->edd_dpt.flags |= 0x0014; 966 } 967 968 pptr->edd_dpt.devpath[0] = pptr->mdi.diskbuf; 969 pptr->edd_dpt.chksum = -checksum_buf(&pptr->edd_dpt.dpikey, 73 - 30); 970 } 971 972 if (do_eltorito) { 973 bvd = (struct edd4_bvd *)(ramdisk_image + 17 * 2048); 974 boot_cat = 975 (struct edd4_bootcat *)(ramdisk_image + bvd->boot_cat * 2048); 976 pptr->cd_pkt.type = boot_cat->initial_entry.media_type; /* Cheat */ 977 pptr->cd_pkt.driveno = geometry->driveno; 978 pptr->cd_pkt.start = boot_cat->initial_entry.load_block; 979 boot_seg = pptr->cd_pkt.load_seg = boot_cat->initial_entry.load_seg; 980 pptr->cd_pkt.sect_count = boot_cat->initial_entry.sect_count; 981 boot_len = pptr->cd_pkt.sect_count * 512; 982 pptr->cd_pkt.geom1 = (uint8_t)(pptr->cylinders) & 0xFF; 983 pptr->cd_pkt.geom2 = 984 (uint8_t)(pptr->sectors) | (uint8_t)((pptr->cylinders >> 2) & 0xC0); 985 pptr->cd_pkt.geom3 = (uint8_t)(pptr->heads); 986 } 987 988 if ((p = getcmditem("mem")) != CMD_NOTFOUND) { 989 setmaxmem(suffix_number(p)); 990 } 991 992 /* The size is given by hptr->total_size plus the size of the E820 993 map -- 12 bytes per range; we may need as many as 2 additional 994 ranges (each insertrange() can worst-case turn 1 area into 3) 995 plus the terminating range, over what nranges currently show. */ 996 total_size = hptr->total_size; /* Actual memdisk code */ 997 e820_len = (nranges + 3) * sizeof(ranges[0]); 998 total_size += e820_len; /* E820 memory ranges */ 999 cmdline_len = strlen(shdr->cmdline) + 1; 1000 total_size += cmdline_len; /* Command line */ 1001 stack_len = stack_needed(); 1002 total_size += stack_len; /* Stack */ 1003 printf("Code %u, meminfo %u, cmdline %u, stack %u\n", 1004 hptr->total_size, e820_len, cmdline_len, stack_len); 1005 printf("Total size needed = %u bytes, allocating %uK\n", 1006 total_size, (total_size + 0x3ff) >> 10); 1007 1008 if (total_size > dos_mem) 1009 die("MEMDISK: Insufficient low memory\n"); 1010 1011 driveraddr = stddosmem - total_size; 1012 driveraddr &= ~0x3FF; 1013 1014 printf("Old dos memory at 0x%05x (map says 0x%05x), loading at 0x%05x\n", 1015 stddosmem, dos_mem, driveraddr); 1016 1017 /* Reserve this range of memory */ 1018 wrz_16(BIOS_BASEMEM, driveraddr >> 10); 1019 insertrange(driveraddr, dos_mem - driveraddr, 2); 1020 parse_mem(); 1021 1022 pptr->mem1mb = low_mem >> 10; 1023 pptr->mem16mb = high_mem >> 16; 1024 if (low_mem == (15 << 20)) { 1025 /* lowmem maxed out */ 1026 uint32_t int1588mem = (high_mem >> 10) + (low_mem >> 10); 1027 pptr->memint1588 = (int1588mem > 0xffff) ? 0xffff : int1588mem; 1028 } else { 1029 pptr->memint1588 = low_mem >> 10; 1030 } 1031 1032 printf("1588: 0x%04x 15E801: 0x%04x 0x%04x\n", 1033 pptr->memint1588, pptr->mem1mb, pptr->mem16mb); 1034 1035 driverseg = driveraddr >> 4; 1036 driverptr = driverseg << 16; 1037 1038 /* Anything beyond the end is for the stack */ 1039 pptr->mystack = (uint16_t) (stddosmem - driveraddr); 1040 1041 pptr->mdi.oldint13.uint32 = rdz_32(BIOS_INT13); 1042 pptr->mdi.oldint15.uint32 = rdz_32(BIOS_INT15); 1043 1044 /* Adjust the E820 table: if there are null ranges (type 0) 1045 at the end, change them to type end of list (-1). 1046 This is necessary for the driver to be able to report end 1047 of list correctly. */ 1048 while (nranges && ranges[nranges - 1].type == 0) { 1049 ranges[--nranges].type = -1; 1050 } 1051 1052 if (getcmditem("nopassany") != CMD_NOTFOUND) { 1053 printf("nopassany specified - we're the only drive of any kind\n"); 1054 bios_drives = 0; 1055 pptr->drivecnt = 0; 1056 no_bpt = 1; 1057 pptr->mdi.oldint13.uint32 = driverptr + hptr->iret_offs; 1058 wrz_8(BIOS_EQUIP, rdz_8(BIOS_EQUIP) & ~0xc1); 1059 wrz_8(BIOS_HD_COUNT, 0); 1060 } else if (getcmditem("nopass") != CMD_NOTFOUND) { 1061 printf("nopass specified - we're the only drive\n"); 1062 bios_drives = 0; 1063 pptr->drivecnt = 0; 1064 no_bpt = 1; 1065 } else { 1066 /* Query drive parameters of this type */ 1067 memset(®s, 0, sizeof regs); 1068 regs.es = 0; 1069 regs.eax.b[1] = 0x08; 1070 regs.edx.b[0] = geometry->driveno & 0x80; 1071 intcall(0x13, ®s, ®s); 1072 1073 /* Note: per suggestion from the Interrupt List, consider 1074 INT 13 08 to have failed if the sector count in CL is zero. */ 1075 if ((regs.eflags.l & 1) || !(regs.ecx.b[0] & 0x3f)) { 1076 printf("INT 13 08: Failure, assuming this is the only drive\n"); 1077 pptr->drivecnt = 0; 1078 no_bpt = 1; 1079 } else { 1080 printf("INT 13 08: Success, count = %u, BPT = %04x:%04x\n", 1081 regs.edx.b[0], regs.es, regs.edi.w[0]); 1082 pptr->drivecnt = regs.edx.b[0]; 1083 no_bpt = !(regs.es | regs.edi.w[0]); 1084 } 1085 1086 /* Compare what INT 13h returned with the appropriate equipment byte */ 1087 if (geometry->driveno & 0x80) { 1088 bios_drives = rdz_8(BIOS_HD_COUNT); 1089 } else { 1090 uint8_t equip = rdz_8(BIOS_EQUIP); 1091 1092 if (equip & 1) 1093 bios_drives = (equip >> 6) + 1; 1094 else 1095 bios_drives = 0; 1096 } 1097 1098 if (pptr->drivecnt > bios_drives) { 1099 printf("BIOS equipment byte says count = %d, go with that\n", 1100 bios_drives); 1101 pptr->drivecnt = bios_drives; 1102 } 1103 } 1104 1105 /* Add ourselves to the drive count */ 1106 pptr->drivecnt++; 1107 1108 /* Discontiguous drive space. There is no really good solution for this. */ 1109 if (pptr->drivecnt <= (geometry->driveno & 0x7f)) 1110 pptr->drivecnt = (geometry->driveno & 0x7f) + 1; 1111 1112 /* Probe for contiguous range of BIOS drives starting with driveno */ 1113 pptr->driveshiftlimit = probe_drive_range(geometry->driveno) + 1; 1114 if ((pptr->driveshiftlimit & 0x80) != (geometry->driveno & 0x80)) 1115 printf("We lost the last drive in our class of drives.\n"); 1116 printf("Drive probing gives drive shift limit: 0x%02x\n", 1117 pptr->driveshiftlimit); 1118 1119 /* Pointer to the command line */ 1120 pptr->mdi.cmdline.seg_off.offset = bin_size + (nranges + 1) * sizeof(ranges[0]); 1121 pptr->mdi.cmdline.seg_off.segment = driverseg; 1122 1123 /* Copy driver followed by E820 table followed by command line */ 1124 { 1125 unsigned char *dpp = (unsigned char *)(driverseg << 4); 1126 1127 /* Adjust these pointers to point to the installed image */ 1128 /* Careful about the order here... the image isn't copied yet! */ 1129 pptr = (struct patch_area *)(dpp + hptr->patch_offs); 1130 hptr = (struct memdisk_header *)dpp; 1131 1132 /* Actually copy to low memory */ 1133 dpp = mempcpy(dpp, memdisk_hook, bin_size); 1134 dpp = mempcpy(dpp, ranges, (nranges + 1) * sizeof(ranges[0])); 1135 dpp = mempcpy(dpp, shdr->cmdline, cmdline_len); 1136 } 1137 1138 /* Note the previous INT 13h hook in the "safe hook" structure */ 1139 hptr->safe_hook.old_hook.uint32 = pptr->mdi.oldint13.uint32; 1140 1141 /* Re-fill the "safe hook" mBFT field with the physical address */ 1142 mbft = (struct mBFT *)(((const char *)hptr) + hptr->safe_hook.mbft); 1143 hptr->safe_hook.mbft = (size_t)mbft; 1144 1145 /* Update various BIOS magic data areas (gotta love this shit) */ 1146 1147 if (geometry->driveno & 0x80) { 1148 /* Update BIOS hard disk count */ 1149 uint8_t nhd = pptr->drivecnt; 1150 1151 if (nhd > 128) 1152 nhd = 128; 1153 1154 if (!do_eltorito) 1155 wrz_8(BIOS_HD_COUNT, nhd); 1156 } else { 1157 /* Update BIOS floppy disk count */ 1158 uint8_t equip = rdz_8(BIOS_EQUIP); 1159 uint8_t nflop = pptr->drivecnt; 1160 1161 if (nflop > 4) /* Limit of equipment byte */ 1162 nflop = 4; 1163 1164 equip &= 0x3E; 1165 if (nflop) 1166 equip |= ((nflop - 1) << 6) | 0x01; 1167 1168 wrz_8(BIOS_EQUIP, equip); 1169 1170 /* Install DPT pointer if this was the only floppy */ 1171 if (getcmditem("dpt") != CMD_NOTFOUND || 1172 ((nflop == 1 || no_bpt) && getcmditem("nodpt") == CMD_NOTFOUND)) { 1173 /* Do install a replacement DPT into INT 1Eh */ 1174 pptr->mdi.dpt_ptr = 1175 hptr->patch_offs + offsetof(struct patch_area, dpt); 1176 } 1177 } 1178 1179 /* Complete the mBFT */ 1180 mbft->acpi.signature[0] = 'm'; /* "mBFT" */ 1181 mbft->acpi.signature[1] = 'B'; 1182 mbft->acpi.signature[2] = 'F'; 1183 mbft->acpi.signature[3] = 'T'; 1184 mbft->safe_hook = (size_t)&hptr->safe_hook; 1185 mbft->acpi.checksum = -checksum_buf(mbft, mbft->acpi.length); 1186 1187 /* Install the interrupt handlers */ 1188 printf("old: int13 = %08x int15 = %08x int1e = %08x\n", 1189 rdz_32(BIOS_INT13), rdz_32(BIOS_INT15), rdz_32(BIOS_INT1E)); 1190 1191 wrz_32(BIOS_INT13, driverptr + hptr->int13_offs); 1192 wrz_32(BIOS_INT15, driverptr + hptr->int15_offs); 1193 if (pptr->mdi.dpt_ptr) 1194 wrz_32(BIOS_INT1E, driverptr + pptr->mdi.dpt_ptr); 1195 1196 printf("new: int13 = %08x int15 = %08x int1e = %08x\n", 1197 rdz_32(BIOS_INT13), rdz_32(BIOS_INT15), rdz_32(BIOS_INT1E)); 1198 1199 /* Figure out entry point */ 1200 if (!boot_seg) { 1201 boot_base = 0x7c00; 1202 shdr->sssp = 0x7c00; 1203 shdr->csip = 0x7c00; 1204 } else { 1205 boot_base = boot_seg << 4; 1206 shdr->sssp = boot_seg << 16; 1207 shdr->csip = boot_seg << 16; 1208 } 1209 1210 /* Relocate the real-mode code to below the stub */ 1211 rm_base = (driveraddr - rm_args.rm_size) & ~15; 1212 if (rm_base < boot_base + boot_len) 1213 die("MEMDISK: bootstrap too large to load\n"); 1214 1215 relocate_rm_code(rm_base); 1216 1217 /* Reboot into the new "disk" */ 1218 puts("Loading boot sector... "); 1219 1220 memcpy((void *)boot_base, 1221 (char *)pptr->mdi.diskbuf + geometry->boot_lba * 512, 1222 boot_len); 1223 1224 if (getcmditem("pause") != CMD_NOTFOUND) { 1225 puts("press any key to boot... "); 1226 memset(®s, 0, sizeof regs); 1227 regs.eax.w[0] = 0; 1228 intcall(0x16, ®s, NULL); 1229 } 1230 1231 puts("booting...\n"); 1232 1233 /* On return the assembly code will jump to the boot vector */ 1234 shdr->esdi = pnp_install_check(); 1235 shdr->edx = geometry->driveno; 1236} 1237 1238