chain module: setbpb changes, bss & bs options, bugfixes
[profile/ivi/syslinux.git] / com32 / chain / chain.c
1 /* ----------------------------------------------------------------------- *
2  *
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"]
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 /*
17  * Please see doc/chain.txt for the detailed documentation.
18  */
19
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"
43
44 struct options opt;
45
46 static int fixed_cnt;
47
48 static int overlap(const struct data_area *a, const struct data_area *b)
49 {
50     return
51         a->base + a->size > b->base &&
52         b->base + b->size > a->base;
53 }
54
55 static int is_phys(uint8_t sdifs)
56 {
57     return
58         sdifs == SYSLINUX_FS_SYSLINUX ||
59         sdifs == SYSLINUX_FS_EXTLINUX ||
60         sdifs == SYSLINUX_FS_ISOLINUX;
61 }
62
63 /*
64  * Search for a specific drive, based on the MBR signature.
65  * Return drive and iterator at 0th position.
66  */
67 static int find_by_sig(uint32_t mbr_sig,
68                         struct part_iter **_boot_part)
69 {
70     struct part_iter *boot_part = NULL;
71     struct disk_info diskinfo;
72     int drive;
73
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;
83         }
84         if (boot_part->sub.dos.disk_sig == mbr_sig) {
85             goto ok;
86         }
87     }
88     drive = -1;
89 ok:
90     *_boot_part = boot_part;
91     return drive;
92 }
93
94 /*
95  * Search for a specific drive/partition, based on the GPT GUID.
96  * Return drive and iterator at proper position.
97  */
98 static int find_by_guid(const struct guid *gpt_guid,
99                         struct part_iter **_boot_part)
100 {
101     struct part_iter *boot_part = NULL;
102     struct disk_info diskinfo;
103     int drive;
104
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;
114         }
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;
118         }
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;
123         }
124     }
125     drive = -1;
126 ok:
127     *_boot_part = boot_part;
128     return drive;
129 }
130
131 /*
132  * Search for a specific drive/partition, based on the GPT label.
133  * Return drive and iterator at proper position.
134  */
135 static int find_by_label(const char *label, struct part_iter **_boot_part)
136 {
137     struct part_iter *boot_part = NULL;
138     struct disk_info diskinfo;
139     int drive;
140
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;
150         }
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;
155         }
156     }
157     drive = -1;
158 ok:
159     *_boot_part = boot_part;
160     return drive;
161 }
162
163 static void do_boot(struct data_area *data, int ndata)
164 {
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;
173
174     mmap = syslinux_memory_map();
175
176     if (!mmap) {
177         error("Cannot read system memory map\n");
178         return;
179     }
180
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;
185     }
186     if (endimage > dosmem)
187         goto too_big;
188
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;
193     }
194
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: ... */
228         };
229         static uint8_t swapstub[1024];
230         uint8_t *p;
231
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;
238
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];
249
250         /* Mapping table; start out with identity mapping everything */
251         for (i = 0; i < 256; i++)
252             p[i] = (uint8_t)i;
253
254         /* And the actual swap */
255         p[driveno] = swapdrive;
256         p[swapdrive] = driveno;
257
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;
264
265         if (syslinux_add_movelist(&mlist, endimage, (addr_t) swapstub,
266                                   sizeof swapstub))
267             goto enomem;
268
269         endimage += sizeof swapstub;
270     }
271
272     /* Tell the shuffler not to muck with this area... */
273     syslinux_add_memmap(&mmap, endimage, 0xa0000 - endimage, SMT_RESERVED);
274
275     /* Force text mode */
276     syslinux_force_text_mode();
277
278     fputs("Booting...\n", stdout);
279     syslinux_shuffle_boot_rm(mlist, mmap, opt.keeppxe, &opt.regs);
280     error("Chainboot failed!\n");
281     return;
282
283 too_big:
284     error("Loader file too large\n");
285     return;
286
287 enomem:
288     error("Out of memory\n");
289     return;
290 }
291 #if 0
292 static void hide_unhide(const struct part_iter *_iter)
293 {
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;
302
303     if (_iter->type != typedos) {
304         error("Option 'hide' is only meaningful for legacy partition scheme.");
305         goto bail;
306     }
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;
310     }
311
312     if (_iter->index < 1 || _iter->index > 4)
313         error("WARNING: option 'hide' specified with a non-primary partition.\n");
314
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 */
324         }
325         if (t != pt->ostype) {
326             write_back = true;
327             pt->ostype = t;
328         }
329     }
330     if (write_back && disk_write_verify_sector(&_iter->di, 0, mbr))
331         error("WARNING: failed to write MBR for option 'hide'\n");
332
333 bail:
334     free(mbr);
335 }
336 #endif
337 static int pem_sethide(struct disk_dos_part_entry *dp, int midx, int idx)
338 {
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;
343
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 */
351     }
352     if (t != dp->ostype) {
353         dp->ostype = t;
354         return -1;
355     }
356     return 0;
357 }
358
359 static int pem_setchs(const struct disk_info *di,
360                      struct disk_dos_part_entry *dp,
361                      uint32_t lba1)
362 {
363     uint32_t ochs1, ochs2;
364
365     ochs1 = *(uint32_t *)dp->start;
366     ochs2 = *(uint32_t *)dp->end;
367
368     *(uint32_t *)dp->start =
369         lba2chs(di, lba1) |
370         (*(uint32_t *)dp->start & 0xFF000000);
371
372     *(uint32_t *)dp->end =
373         lba2chs(di, lba1 + dp->length - 1) |
374         (*(uint32_t *)dp->end & 0xFF000000);
375
376     return
377         *(uint32_t *)dp->start != ochs1 ||
378         *(uint32_t *)dp->end != ochs2;
379 }
380
381 static int pentry_mangle(struct part_iter *_iter)
382 {
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;
389
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;
394     }
395     if ((_iter->index < 1 || _iter->index > 4) && opt.hide == 1)
396         error("WARNING: option 'hide' specified with a non-primary partition.\n");
397
398     if (!(iter = pi_begin(&_iter->di, 1)))  /* turn on stepall */
399         goto bail;
400
401     memcpy(&mbr, iter->data, sizeof(struct disk_dos_mbr));
402
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;
411             }
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;
423             }
424         }
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);
429         }
430     }
431     /* last write */
432     if (wb && !werr)
433         werr |= disk_write_sector(&_iter->di, cebr_lba, &mbr);
434
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;
441 }
442
443 int find_dp(struct part_iter **_iter)
444 {
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;
451
452     sdi = syslinux_derivative_info();
453
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;
458         }
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;
465         }
466     } else if (!strncmp(opt.drivename, "label", 5)) {
467         if (!opt.drivename[6]) {
468             error("No label specified.\n");
469             goto bail;
470         }
471         if (find_by_label(opt.drivename + 6, &iter)) {
472             error("Unable to find requested GPT partition by label.\n");
473             goto bail;
474         }
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);
480
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;
486
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;
492         }
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;
500         }
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;
506
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;
512             }
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;
517             }
518         }
519     } else {
520         error("Unparsable drive specification.\n");
521         goto bail;
522     }
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).
526      */
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;
537         }
538     }
539
540     if (!(iter->di.disk & 0x80) && iter->index) {
541         error("WARNING: Partitions on floppy devices may not work.\n");
542     }
543
544     *_iter = iter;
545
546     return 0;
547
548 bail:
549     return -1;
550 }
551
552 static int setup_handover(const struct part_iter *iter,
553                    struct data_area *data)
554 {
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;
561
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;
568
569         ha = malloc(synth_size);
570         if (!ha) {
571             error("Could not build GPT hand-over record!\n");
572             goto bail;
573         }
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;
605         }
606
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;
613
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;
621     }
622
623     data->base = 0x7be;
624     data->size = synth_size;
625     data->data = (void *)ha;
626
627     return 0;
628 bail:
629     return -1;
630 }
631
632 int main(int argc, char *argv[])
633 {
634     struct part_iter *iter = NULL;
635
636     void *sbck = NULL;
637     struct data_area fdat, hdat, sdat, data[3];
638     int ndata = 0;
639
640     console_ansi_raw();
641 /*    openconsole(&dev_null_r, &dev_stdcon_w);*/
642
643     /* Prepare and set defaults */
644     memset(&fdat, 0, sizeof(fdat));
645     memset(&hdat, 0, sizeof(hdat));
646     memset(&sdat, 0, sizeof(sdat));
647     memset(&opt, 0, sizeof(opt));
648     opt.sect = true;    /* by def load sector */
649     opt.maps = true;    /* by def map sector */
650     opt.hand = true;    /* by def prepare handover */
651     opt.foff = opt.soff = opt.fip = opt.sip = 0x7C00;
652     opt.drivename = "boot";
653 #ifdef DEBUG
654     opt.warn = true;
655 #endif
656
657     /* Parse arguments */
658     if (parse_args(argc, argv))
659         goto bail;
660
661     /* Get max fixed disk number */
662     fixed_cnt = *(uint8_t *)(0x475);
663
664     /* Get disk/part iterator matching user supplied options */
665     if (find_dp(&iter))
666         goto bail;
667
668     /* Perform initial partition entry mangling */
669     if (opt.hide || opt.mbrchs)
670         pentry_mangle(iter);
671 /*      hide_unhide(iter);*/
672
673     /* Load the boot file */
674     if (opt.file) {
675         fdat.base = (opt.fseg << 4) + opt.foff;
676
677         if (loadfile(opt.file, &fdat.data, &fdat.size)) {
678             error("Couldn't read the boot file.\n");
679             goto bail;
680         }
681         if (fdat.base + fdat.size - 1 > ADDRMAX) {
682             error("The boot file is too big to load at this address.\n");
683             goto bail;
684         }
685     }
686
687     /* Load the sector */
688     if (opt.sect) {
689         sdat.size = SECTOR;
690         sdat.base = (opt.sseg << 4) + opt.soff;
691
692         if (opt.file && opt.maps && overlap(&fdat, &sdat)) {
693             error("WARNING: The sector won't be loaded, as it would conflict with the boot file.\n");
694             opt.sect = false;
695         } else {
696             if (!(sdat.data = disk_read_sectors(&iter->di, iter->start_lba, 1))) {
697                 error("Couldn't read the sector.\n");
698                 goto bail;
699             }
700             if (opt.save) {
701                 if (!(sbck = malloc(SECTOR))) {
702                     error("Couldn't allocate cmp-buf for option 'save'.\n");
703                     goto bail;
704                 }
705                 memcpy(sbck, sdat.data, sdat.size);
706             }
707         }
708     }
709
710     /* Prep the handover */
711     if (!iter->index) {
712         opt.hand = false;
713     } else if (opt.hand) {
714         if (setup_handover(iter, &hdat))
715             goto bail;
716         /* Verify possible conflicts */
717         if ( ( opt.file && overlap(&fdat, &hdat)) ||
718              ( opt.sect && overlap(&sdat, &hdat) && opt.maps) ) {
719             error("WARNING: Handover area won't be prepared,\n"
720                   "as it would conflict with the boot file and/or the sector.\n");
721             opt.hand = false;
722         }
723     }
724
725     /* Adjust registers */
726     mangler_common(iter);
727     mangler_handover(iter, &hdat);
728     mangler_grldr(iter);
729
730     /*
731      * Patching functions
732      * opt.* are tested inside
733      */
734
735     if (manglef_isolinux(&fdat))
736         goto bail;
737
738     if (manglef_grub(iter, &fdat))
739         goto bail;
740 #if 0
741     if (manglef_drmk(&fdat))
742         goto bail;
743 #endif
744     if (manglef_bpb(iter, &fdat))
745         goto bail;
746
747     if (mangles_bpb(iter, &sdat))
748         goto bail;
749
750     if (mangles_save(iter, &sdat, sbck))
751         goto bail;
752
753     if (manglesf_bss(&sdat, &fdat))
754         goto bail;
755
756     /* This *must* be after BPB saving or copying */
757     if (mangles_cmldr(&sdat))
758         goto bail;
759
760     /* Prepare boot-time mmap data */
761
762     if (opt.file)
763         memcpy(data + ndata++, &fdat, sizeof(fdat));
764     if (opt.sect && opt.maps)
765         memcpy(data + ndata++, &sdat, sizeof(sdat));
766     if (opt.hand)
767         memcpy(data + ndata++, &hdat, sizeof(hdat));
768
769 #ifdef DEBUG
770     printf("iter dsk: %d\n", iter->di.disk);
771     printf("iter idx: %d\n", iter->index);
772     printf("iter lba: %llu\n", iter->start_lba);
773     if (opt.hand)
774         printf("hand lba: %u\n", ((disk_dos_part_entry *)hdat.data)->start_lba);
775 #endif
776
777     if (opt.warn) {
778         puts("Press any key to continue booting...");
779         wait_key();
780     }
781
782     do_boot(data, ndata);
783 bail:
784     pi_del(&iter);
785     /* Free allocated areas */
786     free(fdat.data);
787     free(sdat.data);
788     free(hdat.data);
789     free(sbck);
790     return 255;
791 }
792
793 /* vim: set ts=8 sts=4 sw=4 noet: */