chain module: make option 'save' truly separate
[syslinux.git] / com32 / chain / chain.c
blob3bd2a318fd76c362ed01b199c4fd3e1a415fdd7f
1 /* ----------------------------------------------------------------------- *
3 * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
4 * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
5 * Significant portions copyright (C) 2010 Shao Miller
6 * [partition iteration, GPT, "fs"]
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.
14 * ----------------------------------------------------------------------- */
17 * Please see doc/chain.txt for the detailed documentation.
20 #include <com32.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <ctype.h>
24 #include <string.h>
25 #include <console.h>
26 #include <consoles.h>
27 #include <minmax.h>
28 #include <stdbool.h>
29 #include <dprintf.h>
30 #include <errno.h>
31 #include <unistd.h>
32 #include <syslinux/loadfile.h>
33 #include <syslinux/bootrm.h>
34 #include <syslinux/config.h>
35 #include <syslinux/disk.h>
36 #include <syslinux/video.h>
37 #include "common.h"
38 #include "chain.h"
39 #include "utility.h"
40 #include "options.h"
41 #include "partiter.h"
42 #include "mangle.h"
44 struct options opt;
46 static int fixed_cnt;
48 static int overlap(const struct data_area *a, const struct data_area *b)
50 return
51 a->base + a->size > b->base &&
52 b->base + b->size > a->base;
55 static int is_phys(uint8_t sdifs)
57 return
58 sdifs == SYSLINUX_FS_SYSLINUX ||
59 sdifs == SYSLINUX_FS_EXTLINUX ||
60 sdifs == SYSLINUX_FS_ISOLINUX;
64 * Search for a specific drive, based on the MBR signature.
65 * Return drive and iterator at 0th position.
67 static int find_by_sig(uint32_t mbr_sig,
68 struct part_iter **_boot_part)
70 struct part_iter *boot_part = NULL;
71 struct disk_info diskinfo;
72 int drive;
74 for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) {
75 if (disk_get_params(drive, &diskinfo))
76 continue; /* Drive doesn't exist */
77 if (!(boot_part = pi_begin(&diskinfo, 0)))
78 continue;
79 /* Check for a MBR disk */
80 if (boot_part->type != typedos) {
81 pi_del(&boot_part);
82 continue;
84 if (boot_part->sub.dos.disk_sig == mbr_sig) {
85 goto ok;
88 drive = -1;
89 ok:
90 *_boot_part = boot_part;
91 return drive;
95 * Search for a specific drive/partition, based on the GPT GUID.
96 * Return drive and iterator at proper position.
98 static int find_by_guid(const struct guid *gpt_guid,
99 struct part_iter **_boot_part)
101 struct part_iter *boot_part = NULL;
102 struct disk_info diskinfo;
103 int drive;
105 for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) {
106 if (disk_get_params(drive, &diskinfo))
107 continue; /* Drive doesn't exist */
108 if (!(boot_part = pi_begin(&diskinfo, 0)))
109 continue;
110 /* Check for a GPT disk */
111 if (boot_part->type != typegpt) {
112 pi_del(&boot_part);
113 continue;
115 /* Check for a matching GPT disk guid */
116 if (!memcmp(&boot_part->sub.gpt.disk_guid, gpt_guid, sizeof(*gpt_guid))) {
117 goto ok;
119 /* disk guid doesn't match, maybe partition guid will */
120 while (pi_next(&boot_part)) {
121 if (!memcmp(&boot_part->sub.gpt.part_guid, gpt_guid, sizeof(*gpt_guid)))
122 goto ok;
125 drive = -1;
127 *_boot_part = boot_part;
128 return drive;
132 * Search for a specific drive/partition, based on the GPT label.
133 * Return drive and iterator at proper position.
135 static int find_by_label(const char *label, struct part_iter **_boot_part)
137 struct part_iter *boot_part = NULL;
138 struct disk_info diskinfo;
139 int drive;
141 for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) {
142 if (disk_get_params(drive, &diskinfo))
143 continue; /* Drive doesn't exist */
144 if (!(boot_part = pi_begin(&diskinfo, 0)))
145 continue;
146 /* Check for a GPT disk */
147 if (!(boot_part->type == typegpt)) {
148 pi_del(&boot_part);
149 continue;
151 /* Check for a matching partition */
152 while (pi_next(&boot_part)) {
153 if (!strcmp(label, boot_part->sub.gpt.part_label))
154 goto ok;
157 drive = -1;
159 *_boot_part = boot_part;
160 return drive;
163 static void do_boot(struct data_area *data, int ndata)
165 uint16_t *const bios_fbm = (uint16_t *) 0x413;
166 addr_t dosmem = (addr_t)(*bios_fbm << 10); /* Technically a low bound */
167 struct syslinux_memmap *mmap;
168 struct syslinux_movelist *mlist = NULL;
169 addr_t endimage;
170 uint8_t driveno = opt.regs.edx.b[0];
171 uint8_t swapdrive = driveno & 0x80;
172 int i;
174 mmap = syslinux_memory_map();
176 if (!mmap) {
177 error("Cannot read system memory map\n");
178 return;
181 endimage = 0;
182 for (i = 0; i < ndata; i++) {
183 if (data[i].base + data[i].size > endimage)
184 endimage = data[i].base + data[i].size;
186 if (endimage > dosmem)
187 goto too_big;
189 for (i = 0; i < ndata; i++) {
190 if (syslinux_add_movelist(&mlist, data[i].base,
191 (addr_t) data[i].data, data[i].size))
192 goto enomem;
195 if (opt.swap && driveno != swapdrive) {
196 static const uint8_t swapstub_master[] = {
197 /* The actual swap code */
198 0x53, /* 00: push bx */
199 0x0f, 0xb6, 0xda, /* 01: movzx bx,dl */
200 0x2e, 0x8a, 0x57, 0x60, /* 04: mov dl,[cs:bx+0x60] */
201 0x5b, /* 08: pop bx */
202 0xea, 0, 0, 0, 0, /* 09: jmp far 0:0 */
203 0x90, 0x90, /* 0E: nop; nop */
204 /* Code to install this in the right location */
205 /* Entry with DS = CS; ES = SI = 0; CX = 256 */
206 0x26, 0x66, 0x8b, 0x7c, 0x4c, /* 10: mov edi,[es:si+4*0x13] */
207 0x66, 0x89, 0x3e, 0x0a, 0x00, /* 15: mov [0x0A],edi */
208 0x26, 0x8b, 0x3e, 0x13, 0x04, /* 1A: mov di,[es:0x413] */
209 0x4f, /* 1F: dec di */
210 0x26, 0x89, 0x3e, 0x13, 0x04, /* 20: mov [es:0x413],di */
211 0x66, 0xc1, 0xe7, 0x16, /* 25: shl edi,16+6 */
212 0x26, 0x66, 0x89, 0x7c, 0x4c, /* 29: mov [es:si+4*0x13],edi */
213 0x66, 0xc1, 0xef, 0x10, /* 2E: shr edi,16 */
214 0x8e, 0xc7, /* 32: mov es,di */
215 0x31, 0xff, /* 34: xor di,di */
216 0xf3, 0x66, 0xa5, /* 36: rep movsd */
217 0xbe, 0, 0, /* 39: mov si,0 */
218 0xbf, 0, 0, /* 3C: mov di,0 */
219 0x8e, 0xde, /* 3F: mov ds,si */
220 0x8e, 0xc7, /* 41: mov es,di */
221 0x66, 0xb9, 0, 0, 0, 0, /* 43: mov ecx,0 */
222 0x66, 0xbe, 0, 0, 0, 0, /* 49: mov esi,0 */
223 0x66, 0xbf, 0, 0, 0, 0, /* 4F: mov edi,0 */
224 0xea, 0, 0, 0, 0, /* 55: jmp 0:0 */
225 /* pad out to segment boundary */
226 0x90, 0x90, /* 5A: ... */
227 0x90, 0x90, 0x90, 0x90, /* 5C: ... */
229 static uint8_t swapstub[1024];
230 uint8_t *p;
232 /* Note: we can't rely on either INT 13h nor the dosmem
233 vector to be correct at this stage, so we have to use an
234 installer stub to put things in the right place.
235 Round the installer location to a 1K boundary so the only
236 possible overlap is the identity mapping. */
237 endimage = (endimage + 1023u) & ~1023u;
239 /* Create swap stub */
240 memcpy(swapstub, swapstub_master, sizeof swapstub_master);
241 *(uint16_t *) & swapstub[0x3a] = opt.regs.ds;
242 *(uint16_t *) & swapstub[0x3d] = opt.regs.es;
243 *(uint32_t *) & swapstub[0x45] = opt.regs.ecx.l;
244 *(uint32_t *) & swapstub[0x4b] = opt.regs.esi.l;
245 *(uint32_t *) & swapstub[0x51] = opt.regs.edi.l;
246 *(uint16_t *) & swapstub[0x56] = opt.regs.ip;
247 *(uint16_t *) & swapstub[0x58] = opt.regs.cs;
248 p = &swapstub[sizeof swapstub_master];
250 /* Mapping table; start out with identity mapping everything */
251 for (i = 0; i < 256; i++)
252 p[i] = (uint8_t)i;
254 /* And the actual swap */
255 p[driveno] = swapdrive;
256 p[swapdrive] = driveno;
258 /* Adjust registers */
259 opt.regs.ds = opt.regs.cs = (uint16_t)(endimage >> 4);
260 opt.regs.esi.l = opt.regs.es = 0;
261 opt.regs.ecx.l = sizeof swapstub >> 2;
262 opt.regs.ip = 0x10; /* Installer offset */
263 opt.regs.ebx.b[0] = opt.regs.edx.b[0] = swapdrive;
265 if (syslinux_add_movelist(&mlist, endimage, (addr_t) swapstub,
266 sizeof swapstub))
267 goto enomem;
269 endimage += sizeof swapstub;
272 /* Tell the shuffler not to muck with this area... */
273 syslinux_add_memmap(&mmap, endimage, 0xa0000 - endimage, SMT_RESERVED);
275 /* Force text mode */
276 syslinux_force_text_mode();
278 fputs("Booting...\n", stdout);
279 syslinux_shuffle_boot_rm(mlist, mmap, opt.keeppxe, &opt.regs);
280 error("Chainboot failed!\n");
281 return;
283 too_big:
284 error("Loader file too large\n");
285 return;
287 enomem:
288 error("Out of memory\n");
289 return;
291 #if 0
292 static void hide_unhide(const struct part_iter *_iter)
294 int i;
295 struct disk_dos_mbr *mbr = NULL;
296 struct disk_dos_part_entry *pt;
297 const uint16_t mask =
298 (1 << 0x01) | (1 << 0x04) | (1 << 0x06) |
299 (1 << 0x07) | (1 << 0x0b) | (1 << 0x0c) | (1 << 0x0e);
300 uint8_t t;
301 bool write_back = false;
303 if (_iter->type != typedos) {
304 error("Option 'hide' is only meaningful for legacy partition scheme.");
305 goto bail;
307 if (!(mbr = disk_read_sectors(&_iter->di, 0, 1))) {
308 error("WARNING: Couldn't read MBR to hide/unhide partitions.\n");
309 goto bail;
312 if (_iter->index < 1 || _iter->index > 4)
313 error("WARNING: option 'hide' specified with a non-primary partition.\n");
315 for (i = 1; i <= 4; i++) {
316 pt = mbr->table + i - 1;
317 t = pt->ostype;
318 if ((t <= 0x1f) && ((mask >> (t & ~0x10u)) & 1)) {
319 /* It's a hideable partition type */
320 if (i == _iter->index)
321 t &= (uint8_t)(~0x10u); /* unhide */
322 else
323 t |= 0x10u; /* hide */
325 if (t != pt->ostype) {
326 write_back = true;
327 pt->ostype = t;
330 if (write_back && disk_write_verify_sector(&_iter->di, 0, mbr))
331 error("WARNING: failed to write MBR for option 'hide'\n");
333 bail:
334 free(mbr);
336 #endif
337 static int pem_sethide(struct disk_dos_part_entry *dp, int midx, int idx)
339 static const uint16_t mask =
340 (1 << 0x01) | (1 << 0x04) | (1 << 0x06) |
341 (1 << 0x07) | (1 << 0x0b) | (1 << 0x0c) | (1 << 0x0e);
342 uint8_t t;
344 t = dp->ostype;
345 if ((t <= 0x1f) && ((mask >> (t & ~0x10u)) & 1)) {
346 /* It's a hideable partition type */
347 if (midx == idx)
348 t &= (uint8_t)(~0x10u); /* unhide */
349 else
350 t |= 0x10u; /* hide */
352 if (t != dp->ostype) {
353 dp->ostype = t;
354 return -1;
356 return 0;
359 static int pem_setchs(const struct disk_info *di,
360 struct disk_dos_part_entry *dp,
361 uint32_t lba1)
363 uint32_t ochs1, ochs2;
365 ochs1 = *(uint32_t *)dp->start;
366 ochs2 = *(uint32_t *)dp->end;
368 *(uint32_t *)dp->start =
369 lba2chs(di, lba1) |
370 (*(uint32_t *)dp->start & 0xFF000000);
372 *(uint32_t *)dp->end =
373 lba2chs(di, lba1 + dp->length - 1) |
374 (*(uint32_t *)dp->end & 0xFF000000);
376 return
377 *(uint32_t *)dp->start != ochs1 ||
378 *(uint32_t *)dp->end != ochs2;
381 static int pentry_mangle(struct part_iter *_iter)
383 int wb = 0, werr = 0;
384 uint32_t cebr_lba = 0;
385 struct part_iter *iter = NULL;
386 struct disk_dos_part_entry *dp;
387 struct disk_dos_mbr mbr;
388 int ridx;
390 if (_iter->type != typedos) {
391 error("Partition entry mangling ('hide[all]', 'mbrchs')\n"
392 "is meaningful only for legacy partition scheme.");
393 goto bail;
395 if ((_iter->index < 1 || _iter->index > 4) && opt.hide == 1)
396 error("WARNING: option 'hide' specified with a non-primary partition.\n");
398 if (!(iter = pi_begin(&_iter->di, 1))) /* turn on stepall */
399 goto bail;
401 memcpy(&mbr, iter->data, sizeof(struct disk_dos_mbr));
403 while (pi_next(&iter) && !werr) {
404 ridx = iter->rawindex;
405 if (ridx > 4) {
406 if (opt.hide < 2 && !opt.mbrchs)
407 break; /* don't walk unnecessarily */
408 if (wb && !werr) {
409 werr |= disk_write_sector(&iter->di, cebr_lba, &mbr);
410 wb = false;
412 memcpy(&mbr, iter->data, sizeof(struct disk_dos_mbr));
413 cebr_lba = iter->sub.dos.cebr_lba;
414 dp = mbr.table;
415 } else
416 dp = mbr.table + ridx - 1;
417 if (opt.hide == 2 ||
418 (opt.hide == 1 && ridx <= 4)) {
419 wb |= pem_sethide(dp, _iter->index, iter->index);
420 if (_iter->index == iter->index) {
421 ((struct disk_dos_part_entry *)_iter->record)->ostype =
422 dp->ostype;
425 if (opt.mbrchs) {
426 wb |= pem_setchs(&iter->di, dp, (uint32_t)iter->start_lba);
427 if (ridx > 4)
428 wb |= pem_setchs(&iter->di, mbr.table + 1, iter->sub.dos.ebr_lba);
431 /* last write */
432 if (wb && !werr)
433 werr |= disk_write_sector(&_iter->di, cebr_lba, &mbr);
435 bail:
436 pi_del(&iter);
437 if (werr)
438 error("WARNING: failed to write E/MBR for partition\n"
439 "mangling options ('hide[all]', 'mbrchs').\n");
440 return 0;
443 int find_dp(struct part_iter **_iter)
445 struct part_iter *iter;
446 struct disk_info diskinfo;
447 struct guid gpt_guid;
448 uint64_t fs_lba;
449 int drive, hd, partition;
450 const union syslinux_derivative_info *sdi;
452 sdi = syslinux_derivative_info();
454 if (!strncmp(opt.drivename, "mbr", 3)) {
455 if (find_by_sig(strtoul(opt.drivename + 4, NULL, 0), &iter)) {
456 error("Unable to find requested MBR signature.\n");
457 goto bail;
459 } else if (!strncmp(opt.drivename, "guid", 4)) {
460 if (str_to_guid(opt.drivename + 5, &gpt_guid))
461 goto bail;
462 if (find_by_guid(&gpt_guid, &iter)) {
463 error("Unable to find requested GPT disk or partition by guid.\n");
464 goto bail;
466 } else if (!strncmp(opt.drivename, "label", 5)) {
467 if (!opt.drivename[6]) {
468 error("No label specified.\n");
469 goto bail;
471 if (find_by_label(opt.drivename + 6, &iter)) {
472 error("Unable to find requested GPT partition by label.\n");
473 goto bail;
475 } else if ((opt.drivename[0] == 'h' || opt.drivename[0] == 'f') &&
476 opt.drivename[1] == 'd') {
477 hd = opt.drivename[0] == 'h' ? 0x80 : 0;
478 opt.drivename += 2;
479 drive = hd | strtol(opt.drivename, NULL, 0);
481 if (disk_get_params(drive, &diskinfo))
482 goto bail;
483 /* this will start iteration over FDD, possibly raw */
484 if (!(iter = pi_begin(&diskinfo, 0)))
485 goto bail;
487 } else if (!strcmp(opt.drivename, "boot") || !strcmp(opt.drivename, "fs")) {
488 if (!is_phys(sdi->c.filesystem)) {
489 error("When syslinux is not booted from physical disk (or its emulation),\n"
490 "'boot' and 'fs' are meaningless.\n");
491 goto bail;
493 /* offsets match, but in case it changes in the future */
494 if (sdi->c.filesystem == SYSLINUX_FS_ISOLINUX) {
495 drive = sdi->iso.drive_number;
496 fs_lba = *sdi->iso.partoffset;
497 } else {
498 drive = sdi->disk.drive_number;
499 fs_lba = *sdi->disk.partoffset;
501 if (disk_get_params(drive, &diskinfo))
502 goto bail;
503 /* this will start iteration over disk emulation, possibly raw */
504 if (!(iter = pi_begin(&diskinfo, 0)))
505 goto bail;
507 /* 'fs' => we should lookup the syslinux partition number and use it */
508 if (!strcmp(opt.drivename, "fs")) {
509 while (pi_next(&iter)) {
510 if (iter->start_lba == fs_lba)
511 break;
513 /* broken part structure or other problems */
514 if (!iter) {
515 error("Can't find myself on the drive I booted from.\n");
516 goto bail;
519 } else {
520 error("Unparsable drive specification.\n");
521 goto bail;
523 /* main options done - only thing left is explicit partition specification,
524 * if we're still at the disk stage with the iterator AND user supplied
525 * partition number (including disk pseudo-partition).
527 if (!iter->index && opt.partition) {
528 partition = strtol(opt.partition, NULL, 0);
529 /* search for matching part#, including disk */
530 do {
531 if (iter->index == partition)
532 break;
533 } while (pi_next(&iter));
534 if (!iter) {
535 error("Requested disk / partition combination not found.\n");
536 goto bail;
540 if (!(iter->di.disk & 0x80) && iter->index) {
541 error("WARNING: Partitions on floppy devices may not work.\n");
544 *_iter = iter;
546 return 0;
548 bail:
549 return -1;
552 static int setup_handover(const struct part_iter *iter,
553 struct data_area *data)
555 const struct disk_dos_part_entry *dp;
556 const struct disk_gpt_part_entry *gp;
557 struct disk_dos_part_entry *ha;
558 uint64_t lba_count;
559 uint32_t synth_size;
560 uint32_t *plen;
562 if (iter->type == typegpt) {
563 /* GPT handover protocol */
564 gp = (const struct disk_gpt_part_entry *)iter->record;
565 lba_count = gp->lba_last - gp->lba_first + 1;
566 synth_size = sizeof(struct disk_dos_part_entry) +
567 sizeof(uint32_t) + (uint32_t)iter->sub.gpt.pe_size;
569 ha = malloc(synth_size);
570 if (!ha) {
571 error("Could not build GPT hand-over record!\n");
572 goto bail;
574 memset(ha, 0, synth_size);
575 *(uint32_t *)ha->start = lba2chs(&iter->di, gp->lba_first);
576 *(uint32_t *)ha->end = lba2chs(&iter->di, gp->lba_last);
577 ha->active_flag = 0x80;
578 ha->ostype = 0xED;
579 /* All bits set by default */
580 ha->start_lba = ~0u;
581 ha->length = ~0u;
582 /* If these fit the precision, pass them on */
583 if (iter->start_lba < ha->start_lba)
584 ha->start_lba = (uint32_t)iter->start_lba;
585 if (lba_count < ha->length)
586 ha->length = (uint32_t)lba_count;
587 /* Next comes the GPT partition record length */
588 plen = (uint32_t *) (ha + 1);
589 plen[0] = (uint32_t)iter->sub.gpt.pe_size;
590 /* Next comes the GPT partition record copy */
591 memcpy(plen + 1, gp, plen[0]);
592 #ifdef DEBUG
593 dprintf("GPT handover:\n");
594 disk_dos_part_dump(ha);
595 disk_gpt_part_dump((struct disk_gpt_part_entry *)(plen + 1));
596 #endif
597 } else if (iter->type == typedos) {
598 /* MBR handover protocol */
599 dp = (const struct disk_dos_part_entry *)iter->record;
600 synth_size = sizeof(struct disk_dos_part_entry);
601 ha = malloc(synth_size);
602 if (!ha) {
603 error("Could not build MBR hand-over record!\n");
604 goto bail;
607 *(uint32_t *)ha->start = lba2chs(&iter->di, iter->start_lba);
608 *(uint32_t *)ha->end = lba2chs(&iter->di, iter->start_lba + dp->length - 1);
609 ha->active_flag = dp->active_flag;
610 ha->ostype = dp->ostype;
611 ha->start_lba = (uint32_t)iter->start_lba; /* fine, we iterate over legacy scheme */
612 ha->length = dp->length;
614 #ifdef DEBUG
615 dprintf("MBR handover:\n");
616 disk_dos_part_dump(ha);
617 #endif
618 } else {
619 /* shouldn't ever happen */
620 goto bail;
623 data->base = 0x7be;
624 data->size = synth_size;
625 data->data = (void *)ha;
627 return 0;
628 bail:
629 return -1;
632 int setdrv_auto(const struct part_iter *iter)
634 int a, b;
635 char *buf;
637 if (!(buf = disk_read_sectors(&iter->di, iter->start_lba, 1))) {
638 error("Couldn't read a sector to detect 'setdrv' offset.\n");
639 return -1;
642 a = strncmp(buf + 0x36, "FAT", 3);
643 b = strncmp(buf + 0x52, "FAT", 3);
645 if ((!a && b && (buf[0x26] & 0xFE) == 0x28) || *((uint8_t*)buf + 0x26) == 0x80) {
646 opt.drvoff = 0x24;
647 } else if (a && !b && (buf[0x42] & 0xFE) == 0x28) {
648 opt.drvoff = 0x40;
649 } else {
650 error("WARNING: Couldn't autodetect 'setdrv' offset - turning option off.\n");
651 opt.setdrv = false;
654 free(buf);
655 return 0;
659 int main(int argc, char *argv[])
661 struct part_iter *iter = NULL;
663 void *file_area = NULL;
664 void *sect_area = NULL;
665 void *sbck_area = NULL;
666 struct disk_dos_part_entry *hand_area = NULL;
668 struct data_area data[3], bdata[3];
669 int ndata = 0, fidx = -1, sidx = -1, hidx = -1;
671 console_ansi_raw();
672 /* openconsole(&dev_null_r, &dev_stdcon_w);*/
674 /* Prepare and set defaults */
675 memset(&opt, 0, sizeof(opt));
676 opt.sect = true; /* by def load sector */
677 opt.maps = true; /* by def map sector */
678 opt.hand = true; /* by def prepare handover */
679 opt.foff = opt.soff = opt.fip = opt.sip = 0x7C00;
680 opt.drivename = "boot";
681 #ifdef DEBUG
682 opt.warn = true;
683 #endif
685 /* Parse arguments */
686 if (parse_args(argc, argv))
687 goto bail;
689 /* Set initial registry values */
690 if (opt.file) {
691 opt.regs.cs = opt.regs.ds = opt.regs.ss = (uint16_t)opt.fseg;
692 opt.regs.ip = (uint16_t)opt.fip;
693 } else {
694 opt.regs.cs = opt.regs.ds = opt.regs.ss = (uint16_t)opt.sseg;
695 opt.regs.ip = (uint16_t)opt.sip;
698 if (opt.regs.ip == 0x7C00 && !opt.regs.cs)
699 opt.regs.esp.l = 0x7C00;
701 /* Get max fixed disk number */
702 fixed_cnt = *(uint8_t *)(0x475);
704 /* Get disk/part iterator matching user supplied options */
705 if (find_dp(&iter))
706 goto bail;
708 /* Try to autodetect setdrv offest */
709 if (opt.setdrv && opt.drvoff == ~0u && setdrv_auto(iter))
710 goto bail;
712 /* DOS kernels want the drive number in BL instead of DL. Indulge them. */
713 opt.regs.ebx.b[0] = opt.regs.edx.b[0] = (uint8_t)iter->di.disk;
715 /* Perform initial partition entry mangling */
716 if (opt.hide || opt.mbrchs)
717 pentry_mangle(iter);
718 /* hide_unhide(iter);*/
720 /* Load the boot file */
721 if (opt.file) {
722 data[ndata].base = (opt.fseg << 4) + opt.foff;
724 if (loadfile(opt.file, &data[ndata].data, &data[ndata].size)) {
725 error("Couldn't read the boot file.\n");
726 goto bail;
728 file_area = (void *)data[ndata].data;
730 if (data[ndata].base + data[ndata].size - 1 > ADDRMAX) {
731 error("The boot file is too big to load at this address.\n");
732 goto bail;
735 fidx = ndata;
736 ndata++;
739 /* Load the sector */
740 if (opt.sect) {
741 data[ndata].size = SECTOR;
742 data[ndata].base = (opt.sseg << 4) + opt.soff;
744 if (opt.file && opt.maps && overlap(data + fidx, data + ndata)) {
745 error("WARNING: The sector won't be loaded, as it would conflict with the boot file.\n");
746 } else {
747 if (!(data[ndata].data = disk_read_sectors(&iter->di, iter->start_lba, 1))) {
748 error("Couldn't read the sector.\n");
749 goto bail;
751 sect_area = (void *)data[ndata].data;
753 if (opt.save) {
754 if (!(sbck_area = malloc(SECTOR))) {
755 error("Couldn't allocate cmp-buf for option 'save'.\n");
756 goto bail;
758 memcpy(sbck_area, data->data, data->size);
761 sidx = ndata;
762 ndata++;
766 /* Prep the handover */
767 if (opt.hand && iter->index) {
768 if (setup_handover(iter, data + ndata))
769 goto bail;
770 hand_area = (void *)data[ndata].data;
772 /* Verify possible conflicts */
773 if ( ( fidx >= 0 && overlap(data + fidx, data + ndata)) ||
774 ( sidx >= 0 && opt.maps && overlap(data + sidx, data + ndata)) ) {
775 error("WARNING: Handover area won't be prepared,\n"
776 "as it would conflict with the boot file and/or the sector.\n");
777 } else {
778 hidx = ndata;
779 ndata++;
784 * Adjust registers - ds:si & ds:bp
785 * We do it here, as they might get further
786 * overriden during mangling.
789 if (sidx >= 0 && fidx >= 0 && opt.maps && !opt.hptr) {
790 opt.regs.esi.l = opt.regs.ebp.l = opt.soff;
791 opt.regs.ds = (uint16_t)opt.sseg;
792 opt.regs.eax.l = 0;
793 } else if (hidx >= 0) {
794 opt.regs.esi.l = opt.regs.ebp.l = data[hidx].base;
795 opt.regs.ds = 0;
796 if (iter->type == typegpt)
797 opt.regs.eax.l = 0x54504721; /* '!GPT' */
798 else
799 opt.regs.eax.l = 0;
802 /* Do file related stuff */
804 if (fidx >= 0) {
805 if (manglef_isolinux(data + fidx))
806 goto bail;
808 if (manglef_grldr(iter))
809 goto bail;
811 if (manglef_grub(iter, data + fidx))
812 goto bail;
813 #if 0
814 if (manglef_drmk(data + fidx))
815 goto bail;
816 #endif
817 if (manglef_bpb(iter, data + fidx))
818 goto bail;
821 /* Do sector related stuff */
823 if (sidx >= 0) {
824 if (mangles_bpb(iter, data + sidx))
825 goto bail;
827 if (mangles_save(iter, data + sidx, sbck_area))
828 goto bail;
830 /* This *must* be after last BPB saving */
831 if (mangles_cmldr(data + sidx))
832 goto bail;
835 /* Prepare boot-time mmap data */
837 ndata = 0;
838 if (sidx >= 0)
839 memcpy(bdata + ndata++, data + sidx, sizeof(struct data_area));
840 if (fidx >= 0)
841 memcpy(bdata + ndata++, data + fidx, sizeof(struct data_area));
842 if (hidx >= 0)
843 memcpy(bdata + ndata++, data + hidx, sizeof(struct data_area));
845 #ifdef DEBUG
846 printf("iter dsk: %d\n", iter->di.disk);
847 printf("iter idx: %d\n", iter->index);
848 printf("iter lba: %llu\n", iter->start_lba);
849 if (hidx >= 0)
850 printf("hand lba: %u\n", hand_area->start_lba);
851 #endif
853 if (opt.warn) {
854 puts("Press any key to continue booting...");
855 wait_key();
858 do_boot(bdata, ndata);
859 bail:
860 pi_del(&iter);
861 /* Free allocated areas */
862 free(file_area);
863 free(sect_area);
864 free(sbck_area);
865 free(hand_area);
866 return 255;
869 /* vim: set ts=8 sts=4 sw=4 noet: */