From: H. Peter Anvin Date: Mon, 16 Jun 2008 00:05:37 +0000 (-0700) Subject: chain.c32: finalize the NTLDR interface X-Git-Tag: syslinux-3.70-pre18^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=aa7cc7229e6e715e81abb47994163af6479595ae;p=platform%2Fupstream%2Fsyslinux.git chain.c32: finalize the NTLDR interface Settle on a final implementation of the NTLDR support. --- diff --git a/NEWS b/NEWS index e48e6c7..a70bdaa 100644 --- a/NEWS +++ b/NEWS @@ -36,6 +36,13 @@ Changes in 3.70: * chain.c32: option -file to support loading a boot file from the SYSLINUX filesystem instead of loading the boot sector from the drive. + * chain.c32: option -seg to control the load location. + * chain.c32: option -ntldr as a shorthand for "-seg 0x2000 + -file"; use this to load one of WinNT's loaders: + + chain.c32 hd0 1 -ntldr /MiniNT/setupldr.bin + + Note that the file needs to be in the SYSLINUX filesystem. Changes in 3.64: * SYSLINUX/EXTLINUX: support "localboot" with the same feature diff --git a/com32/modules/chain.c b/com32/modules/chain.c index a9ebf76..10cfb03 100644 --- a/com32/modules/chain.c +++ b/com32/modules/chain.c @@ -34,9 +34,11 @@ * loads the file **from the SYSLINUX filesystem** * instead of loading the boot sector. * - * -ntldr: - * jumps to 07C0:0000 instead of 0000:7C00, not sure if this is - * really necessary. + * -seg : + * loads at and jumps to :0000 instead of 0000:7C00. + * + * -ntldr : + * equivalent to -seg 0x2000 -file , used with WinNT's loaders * * -swap: * if the disk is not fd0/hd0, install a BIOS stub which swaps @@ -58,7 +60,7 @@ static struct options { const char *loadfile; uint16_t keeppxe; - bool ntldr; + uint16_t seg; bool swap; } opt; @@ -141,7 +143,8 @@ static int get_disk_params(int disk) } /* - * Get a disk block; buf is REQUIRED TO BE IN LOW MEMORY. + * Get a disk block and return a malloc'd buffer. + * Uses the disk number and information from disk_info. */ struct ebios_dapa { uint16_t len; @@ -151,9 +154,11 @@ struct ebios_dapa { uint64_t lba; } *dapa; -static int read_sector(void *buf, unsigned int lba) +static void *read_sector(unsigned int lba) { com32sys_t inreg; + void *buf = __com32.cs_bounce; + void *data; memset(&inreg, 0, sizeof inreg); @@ -175,7 +180,7 @@ static int read_sector(void *buf, unsigned int lba) /* We failed to get the geometry */ if ( lba ) - return -1; /* Can only read MBR */ + return NULL; /* Can only read MBR */ s = 1; h = 0; c = 0; } else { @@ -186,7 +191,7 @@ static int read_sector(void *buf, unsigned int lba) } if ( s > 63 || h > 256 || c > 1023 ) - return -1; + return NULL; inreg.eax.w[0] = 0x0201; /* Read one sector */ inreg.ecx.b[1] = c & 0xff; @@ -197,7 +202,13 @@ static int read_sector(void *buf, unsigned int lba) inreg.es = SEG(buf); } - return int13_retry(&inreg, NULL); + if (int13_retry(&inreg, NULL)) + return NULL; + + data = malloc(SECTOR); + if (data) + memcpy(data, buf, SECTOR); + return data; } /* Search for a specific drive, based on the MBR signature; bytes @@ -205,17 +216,18 @@ static int read_sector(void *buf, unsigned int lba) static int find_disk(uint32_t mbr_sig, void *buf) { int drive; + bool is_me; for (drive = 0x80; drive <= 0xff; drive++) { if (get_disk_params(drive)) continue; /* Drive doesn't exist */ - if (read_sector(buf, 0)) + if (!(buf = read_sector(0))) continue; /* Cannot read sector */ - - if (*(uint32_t *)((char *)buf + 440) == mbr_sig) + is_me = (*(uint32_t *)((char *)buf + 440) == mbr_sig); + free(buf); + if (is_me) return drive; } - return -1; } @@ -249,8 +261,11 @@ static struct part_entry * find_logical_partition(int whichpart, char *table, struct part_entry *self, struct part_entry *root) { + static struct part_entry ltab_entry; struct part_entry *ptab = (struct part_entry *)(table + 0x1be); struct part_entry *found; + char *sector; + int i; if ( *(uint16_t *)(table + 0x1fe) != 0xaa55 ) @@ -280,8 +295,10 @@ find_logical_partition(int whichpart, char *table, struct part_entry *self, continue; /* OK, it's a data partition. Is it the one we're looking for? */ - if ( nextpart++ == whichpart ) - return &ptab[i]; + if ( nextpart++ == whichpart ) { + memcpy(<ab_entry, &ptab[i], sizeof ltab_entry); + return <ab_entry; + } } } @@ -306,11 +323,13 @@ find_logical_partition(int whichpart, char *table, struct part_entry *self, continue; /* Process this partition */ - if ( read_sector(table+SECTOR, ptab[i].start_lba) ) + if ( !(sector = read_sector(ptab[i].start_lba)) ) continue; /* Read error, must be invalid */ - if ( (found = find_logical_partition(whichpart, table+SECTOR, &ptab[i], - root ? root : &ptab[i])) ) + found = find_logical_partition(whichpart, sector, &ptab[i], + root ? root : &ptab[i]); + free(sector); + if (found) return found; } @@ -321,6 +340,14 @@ find_logical_partition(int whichpart, char *table, struct part_entry *self, static void do_boot(void *boot_sector, size_t boot_size, struct syslinux_rm_regs *regs) { + static const uint8_t swapstub[] = { + 0x53, /* 00: push bx */ + 0x0f,0xb6,0xda, /* 01: movzx bx,dl */ + 0x2e,0x8a,0x57,0x10, /* 04: mov dl,[cs:bx+16] */ + 0x5b, /* 08: pop bx */ + 0xea,0,0,0,0, /* 09: jmp far 0:0 */ + 0x90,0x90, /* 0E: nop; nop */ + }; uint16_t * const bios_fbm = (uint16_t *)0x413; uint32_t * const int13_vec = (uint32_t *)(0x13*4); uint16_t old_bios_fbm = *bios_fbm; @@ -330,6 +357,8 @@ static void do_boot(void *boot_sector, size_t boot_size, addr_t dosmem = old_bios_fbm << 10; uint8_t driveno = regs->edx.b[0]; uint8_t swapdrive = driveno & 0x80; + int i; + addr_t loadbase = opt.seg ? (opt.seg << 4) : 0x7c00; mmap = syslinux_memory_map(); @@ -347,34 +376,29 @@ static void do_boot(void *boot_sector, size_t boot_size, p = (uint8_t *)dosmem; /* Install swapper stub */ - *p++ = 0x80; /* cmp dl,swapdrive */ - *p++ = 0xfa; - *p++ = swapdrive; - *p++ = 0x74; /* je swap1 */ - *p++ = 0x09; - *p++ = 0x80; /* cmp dl,driveno */ - *p++ = 0xfa; - *p++ = driveno; - *p++ = 0x75; /* je noswap */ - *p++ = 0x06; - *p++ = 0xb2; /* mov dl,swapdrive */ - *p++ = swapdrive; - *p++ = 0xeb; /* jmp noswap */ - *p++ = 0x02; - *p++ = 0xb2; /* swap1: mov dl,driveno */ - *p++ = driveno; - *p++ = 0xea; /* noswap: jmp far */ - *(uint32_t *)p = old_int13_vec; + memset(p, 0, 1024); /* For debugging... */ + memcpy(p, swapstub, sizeof swapstub); + *(uint32_t *)&p[0x0a] = old_int13_vec; + p += sizeof swapstub; + + /* Mapping table; start out with identity mapping everything */ + for (i = 0; i < 256; i++) + p[i] = i; + + /* And the actual swap */ + p[driveno] = swapdrive; + p[swapdrive] = driveno; } syslinux_add_memmap(&mmap, dosmem, 0xa0000-dosmem, SMT_RESERVED); - if (syslinux_memmap_type(mmap, 0x7c00, boot_size) != SMT_FREE) { + if (syslinux_memmap_type(mmap, loadbase, boot_size) != SMT_FREE) { error("Loader file too large"); return; } - if (syslinux_add_movelist(&mlist, 0x7c00, (addr_t)boot_sector, boot_size)) { + if (syslinux_add_movelist(&mlist, loadbase, (addr_t)boot_sector, + boot_size)) { error("Out of memory"); return; } @@ -419,8 +443,16 @@ int main(int argc, char *argv[]) for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-file") && argv[i+1]) { opt.loadfile = argv[++i]; - } else if (!strcmp(argv[i], "-ntldr")) { - opt.ntldr = true; + } else if (!strcmp(argv[i], "-seg") && argv[i+1]) { + uint32_t segval = strtoul(argv[++i], NULL, 0); + if (segval < 0x7c0 || segval > 0x9f000) { + error("Invalid segment"); + goto bail; + } + opt.seg = segval; + } else if (!strcmp(argv[i], "-ntldr") && argv[i+1]) { + opt.seg = 0x2000; /* NTLDR wants this address */ + opt.loadfile = argv[++i]; } else if (!strcmp(argv[i], "-swap")) { opt.swap = true; } else if (!strcmp(argv[i], "keeppxe")) { @@ -434,13 +466,12 @@ int main(int argc, char *argv[]) } if ( !drivename ) { - error("Usage: chain.c32 (hd#|fd#|mbr:#) [partition] [-swap][-ntldr] " - "[-file loader]\n"); + error("Usage: chain.c32 (hd#|fd#|mbr:#) [partition] [options]\n"); goto bail; } - if (opt.ntldr) { - regs.es = regs.cs = regs.ss = regs.ds = regs.fs = regs.gs = 0x07c0; + if (opt.seg) { + regs.es = regs.cs = regs.ss = regs.ds = regs.fs = regs.gs = opt.seg; } else { regs.ip = regs.esp.l = 0x7c00; } @@ -489,7 +520,7 @@ int main(int argc, char *argv[]) } /* Get MBR */ - if ( read_sector(mbr, 0) ) { + if ( !(mbr = read_sector(0)) ) { error("Cannot read Master Boot Record\n"); goto bail; } @@ -519,6 +550,7 @@ int main(int argc, char *argv[]) /* Do the actual chainloading */ if (opt.loadfile) { + fputs("Loading the boot file...\n", stdout); if ( loadfile(opt.loadfile, &boot_sector, &boot_size) ) { error("Failed to load the boot file\n"); goto bail; @@ -526,8 +558,7 @@ int main(int argc, char *argv[]) } else if (partinfo) { /* Actually read the boot sector */ /* Pick the first buffer that isn't already in use */ - boot_sector = (void *)(((uintptr_t)partinfo + 511) & ~511); - if ( read_sector(boot_sector, partinfo->start_lba) ) { + if ( !(boot_sector = read_sector(partinfo->start_lba)) ) { error("Cannot read boot sector\n"); goto bail; }