644 lines
17 KiB
C
644 lines
17 KiB
C
/* ----------------------------------------------------------------------- *
|
|
*
|
|
* Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
|
|
* Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
|
|
* Copyright 2010 Shao Miller
|
|
* Copyright 2010-2012 Michal Soltys
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, Inc., 53 Temple Place Ste 330,
|
|
* Boston MA 02111-1307, USA; either version 2 of the License, or
|
|
* (at your option) any later version; incorporated herein by reference.
|
|
*
|
|
* ----------------------------------------------------------------------- */
|
|
|
|
/*
|
|
* Please see doc/chain.txt for the detailed documentation.
|
|
*/
|
|
|
|
#include <com32.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <console.h>
|
|
#include <consoles.h>
|
|
#include <minmax.h>
|
|
#include <stdbool.h>
|
|
#include <dprintf.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <syslinux/loadfile.h>
|
|
#include <syslinux/bootrm.h>
|
|
#include <syslinux/config.h>
|
|
#include <syslinux/disk.h>
|
|
#include <syslinux/video.h>
|
|
#include "chain.h"
|
|
#include "utility.h"
|
|
#include "options.h"
|
|
#include "partiter.h"
|
|
#include "mangle.h"
|
|
|
|
static int fixed_cnt = 128; /* see comments in main() */
|
|
|
|
static int overlap(const struct data_area *a, const struct data_area *b)
|
|
{
|
|
return
|
|
a->base + a->size > b->base &&
|
|
b->base + b->size > a->base;
|
|
}
|
|
|
|
static int is_phys(uint8_t sdifs)
|
|
{
|
|
return
|
|
sdifs == SYSLINUX_FS_SYSLINUX ||
|
|
sdifs == SYSLINUX_FS_EXTLINUX ||
|
|
sdifs == SYSLINUX_FS_ISOLINUX;
|
|
}
|
|
|
|
/*
|
|
* Search for a specific drive, based on the MBR signature.
|
|
* Return drive and iterator at 0th position.
|
|
*/
|
|
static int find_by_sig(uint32_t mbr_sig,
|
|
struct part_iter **_boot_part)
|
|
{
|
|
struct part_iter *iter = NULL;
|
|
struct disk_info diskinfo;
|
|
int drive;
|
|
|
|
for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) {
|
|
if (disk_get_params(drive, &diskinfo))
|
|
continue; /* Drive doesn't exist */
|
|
if (!(iter = pi_begin(&diskinfo, opt.piflags)))
|
|
continue;
|
|
/* Check for a matching MBR disk */
|
|
if (iter->type == typedos && iter->dos.disk_sig == mbr_sig)
|
|
goto ok;
|
|
pi_del(&iter);
|
|
}
|
|
drive = -1;
|
|
ok:
|
|
*_boot_part = iter;
|
|
return drive;
|
|
}
|
|
|
|
/*
|
|
* Search for a specific drive/partition, based on the GPT GUID.
|
|
* Return drive and iterator at proper position.
|
|
*/
|
|
static int find_by_guid(const struct guid *gpt_guid,
|
|
struct part_iter **_boot_part)
|
|
{
|
|
struct part_iter *iter = NULL;
|
|
struct disk_info diskinfo;
|
|
int drive;
|
|
|
|
for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) {
|
|
if (disk_get_params(drive, &diskinfo))
|
|
continue; /* Drive doesn't exist */
|
|
if (!(iter = pi_begin(&diskinfo, opt.piflags)))
|
|
continue;
|
|
/* Check for a matching GPT disk/partition guid */
|
|
if (iter->type == typegpt)
|
|
do {
|
|
if (!memcmp(&iter->gpt.part_guid, gpt_guid, sizeof *gpt_guid))
|
|
goto ok;
|
|
} while (!pi_next(iter));
|
|
pi_del(&iter);
|
|
}
|
|
drive = -1;
|
|
ok:
|
|
*_boot_part = iter;
|
|
return drive;
|
|
}
|
|
|
|
/*
|
|
* Search for a specific drive/partition, based on the GPT label.
|
|
* Return drive and iterator at proper position.
|
|
*/
|
|
static int find_by_label(const char *label, struct part_iter **_boot_part)
|
|
{
|
|
struct part_iter *iter = NULL;
|
|
struct disk_info diskinfo;
|
|
int drive;
|
|
|
|
for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) {
|
|
if (disk_get_params(drive, &diskinfo))
|
|
continue; /* Drive doesn't exist */
|
|
if (!(iter = pi_begin(&diskinfo, opt.piflags)))
|
|
continue;
|
|
/* Check for a matching GPT partition label */
|
|
if (iter->type == typegpt)
|
|
while (!pi_next(iter)) {
|
|
if (!strcmp(label, iter->gpt.part_label))
|
|
goto ok;
|
|
}
|
|
pi_del(&iter);
|
|
}
|
|
drive = -1;
|
|
ok:
|
|
*_boot_part = iter;
|
|
return drive;
|
|
}
|
|
|
|
static void do_boot(struct data_area *data, int ndata)
|
|
{
|
|
struct syslinux_memmap *mmap;
|
|
struct syslinux_movelist *mlist = NULL;
|
|
addr_t endimage;
|
|
uint8_t driveno = opt.regs.edx.b[0];
|
|
uint8_t swapdrive = driveno & 0x80;
|
|
int i;
|
|
|
|
mmap = syslinux_memory_map();
|
|
|
|
if (!mmap) {
|
|
error("Cannot read system memory map.");
|
|
return;
|
|
}
|
|
|
|
endimage = 0;
|
|
for (i = 0; i < ndata; i++) {
|
|
if (data[i].base + data[i].size > endimage)
|
|
endimage = data[i].base + data[i].size;
|
|
}
|
|
if (endimage > dosmax)
|
|
goto too_big;
|
|
|
|
for (i = 0; i < ndata; i++) {
|
|
if (syslinux_add_movelist(&mlist, data[i].base,
|
|
(addr_t) data[i].data, data[i].size))
|
|
goto enomem;
|
|
}
|
|
|
|
if (opt.swap && driveno != swapdrive) {
|
|
static const uint8_t swapstub_master[] = {
|
|
/* The actual swap code */
|
|
0x53, /* 00: push bx */
|
|
0x0f, 0xb6, 0xda, /* 01: movzx bx,dl */
|
|
0x2e, 0x8a, 0x57, 0x60, /* 04: mov dl,[cs:bx+0x60] */
|
|
0x5b, /* 08: pop bx */
|
|
0xea, 0, 0, 0, 0, /* 09: jmp far 0:0 */
|
|
0x90, 0x90, /* 0E: nop; nop */
|
|
/* Code to install this in the right location */
|
|
/* Entry with DS = CS; ES = SI = 0; CX = 256 */
|
|
0x26, 0x66, 0x8b, 0x7c, 0x4c, /* 10: mov edi,[es:si+4*0x13] */
|
|
0x66, 0x89, 0x3e, 0x0a, 0x00, /* 15: mov [0x0A],edi */
|
|
0x26, 0x8b, 0x3e, 0x13, 0x04, /* 1A: mov di,[es:0x413] */
|
|
0x4f, /* 1F: dec di */
|
|
0x26, 0x89, 0x3e, 0x13, 0x04, /* 20: mov [es:0x413],di */
|
|
0x66, 0xc1, 0xe7, 0x16, /* 25: shl edi,16+6 */
|
|
0x26, 0x66, 0x89, 0x7c, 0x4c, /* 29: mov [es:si+4*0x13],edi */
|
|
0x66, 0xc1, 0xef, 0x10, /* 2E: shr edi,16 */
|
|
0x8e, 0xc7, /* 32: mov es,di */
|
|
0x31, 0xff, /* 34: xor di,di */
|
|
0xf3, 0x66, 0xa5, /* 36: rep movsd */
|
|
0xbe, 0, 0, /* 39: mov si,0 */
|
|
0xbf, 0, 0, /* 3C: mov di,0 */
|
|
0x8e, 0xde, /* 3F: mov ds,si */
|
|
0x8e, 0xc7, /* 41: mov es,di */
|
|
0x66, 0xb9, 0, 0, 0, 0, /* 43: mov ecx,0 */
|
|
0x66, 0xbe, 0, 0, 0, 0, /* 49: mov esi,0 */
|
|
0x66, 0xbf, 0, 0, 0, 0, /* 4F: mov edi,0 */
|
|
0xea, 0, 0, 0, 0, /* 55: jmp 0:0 */
|
|
/* pad out to segment boundary */
|
|
0x90, 0x90, /* 5A: ... */
|
|
0x90, 0x90, 0x90, 0x90, /* 5C: ... */
|
|
};
|
|
static uint8_t swapstub[1024];
|
|
uint8_t *p;
|
|
|
|
/* Note: we can't rely on either INT 13h nor the dosmax
|
|
vector to be correct at this stage, so we have to use an
|
|
installer stub to put things in the right place.
|
|
Round the installer location to a 1K boundary so the only
|
|
possible overlap is the identity mapping. */
|
|
endimage = (endimage + 1023u) & ~1023u;
|
|
|
|
/* Create swap stub */
|
|
memcpy(swapstub, swapstub_master, sizeof swapstub_master);
|
|
*(uint16_t *) & swapstub[0x3a] = opt.regs.ds;
|
|
*(uint16_t *) & swapstub[0x3d] = opt.regs.es;
|
|
*(uint32_t *) & swapstub[0x45] = opt.regs.ecx.l;
|
|
*(uint32_t *) & swapstub[0x4b] = opt.regs.esi.l;
|
|
*(uint32_t *) & swapstub[0x51] = opt.regs.edi.l;
|
|
*(uint16_t *) & swapstub[0x56] = opt.regs.ip;
|
|
*(uint16_t *) & swapstub[0x58] = opt.regs.cs;
|
|
p = &swapstub[sizeof swapstub_master];
|
|
|
|
/* 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;
|
|
|
|
/* Adjust registers */
|
|
opt.regs.ds = opt.regs.cs = endimage >> 4;
|
|
opt.regs.esi.l = opt.regs.es = 0;
|
|
opt.regs.ecx.l = sizeof swapstub >> 2;
|
|
opt.regs.ip = 0x10; /* Installer offset */
|
|
opt.regs.ebx.b[0] = opt.regs.edx.b[0] = swapdrive;
|
|
|
|
if (syslinux_add_movelist(&mlist, endimage, (addr_t) swapstub,
|
|
sizeof swapstub))
|
|
goto enomem;
|
|
|
|
endimage += sizeof swapstub;
|
|
}
|
|
|
|
/* Tell the shuffler not to muck with this area... */
|
|
syslinux_add_memmap(&mmap, endimage, 0xa0000 - endimage, SMT_RESERVED);
|
|
|
|
/* Force text mode */
|
|
syslinux_force_text_mode();
|
|
|
|
puts("Booting...");
|
|
syslinux_shuffle_boot_rm(mlist, mmap, opt.keeppxe, &opt.regs);
|
|
error("Chainboot failed !");
|
|
return;
|
|
|
|
too_big:
|
|
error("Loader file too large.");
|
|
return;
|
|
|
|
enomem:
|
|
error("Out of memory.");
|
|
return;
|
|
}
|
|
|
|
int find_dp(struct part_iter **_iter)
|
|
{
|
|
struct part_iter *iter = NULL;
|
|
struct disk_info diskinfo;
|
|
struct guid gpt_guid;
|
|
uint64_t fs_lba;
|
|
int drive, hd, partition;
|
|
const union syslinux_derivative_info *sdi;
|
|
|
|
sdi = syslinux_derivative_info();
|
|
|
|
if (!strncmp(opt.drivename, "mbr", 3)) {
|
|
if (find_by_sig(strtoul(opt.drivename + 4, NULL, 0), &iter) < 0) {
|
|
error("Unable to find requested MBR signature.");
|
|
goto bail;
|
|
}
|
|
} else if (!strncmp(opt.drivename, "guid", 4)) {
|
|
if (str_to_guid(opt.drivename + 5, &gpt_guid))
|
|
goto bail;
|
|
if (find_by_guid(&gpt_guid, &iter) < 0) {
|
|
error("Unable to find requested GPT disk or partition by guid.");
|
|
goto bail;
|
|
}
|
|
} else if (!strncmp(opt.drivename, "label", 5)) {
|
|
if (!opt.drivename[6]) {
|
|
error("No label specified.");
|
|
goto bail;
|
|
}
|
|
if (find_by_label(opt.drivename + 6, &iter) < 0) {
|
|
error("Unable to find requested GPT partition by label.");
|
|
goto bail;
|
|
}
|
|
} else if ((opt.drivename[0] == 'h' || opt.drivename[0] == 'f') &&
|
|
opt.drivename[1] == 'd') {
|
|
hd = opt.drivename[0] == 'h' ? 0x80 : 0;
|
|
opt.drivename += 2;
|
|
drive = hd | strtol(opt.drivename, NULL, 0);
|
|
|
|
if (disk_get_params(drive, &diskinfo))
|
|
goto bail;
|
|
/* this will start iteration over FDD, possibly raw */
|
|
if (!(iter = pi_begin(&diskinfo, opt.piflags)))
|
|
goto bail;
|
|
|
|
} else if (!strcmp(opt.drivename, "boot") || !strcmp(opt.drivename, "fs")) {
|
|
if (!is_phys(sdi->c.filesystem)) {
|
|
error("When syslinux is not booted from physical disk (or its emulation),\n"
|
|
"'boot' and 'fs' are meaningless.");
|
|
goto bail;
|
|
}
|
|
/* offsets match, but in case it changes in the future */
|
|
if (sdi->c.filesystem == SYSLINUX_FS_ISOLINUX) {
|
|
drive = sdi->iso.drive_number;
|
|
fs_lba = *sdi->iso.partoffset;
|
|
} else {
|
|
drive = sdi->disk.drive_number;
|
|
fs_lba = *sdi->disk.partoffset;
|
|
}
|
|
if (disk_get_params(drive, &diskinfo))
|
|
goto bail;
|
|
/* this will start iteration over disk emulation, possibly raw */
|
|
if (!(iter = pi_begin(&diskinfo, opt.piflags)))
|
|
goto bail;
|
|
|
|
/* 'fs' => we should lookup the syslinux partition number and use it */
|
|
if (!strcmp(opt.drivename, "fs")) {
|
|
do {
|
|
if (iter->abs_lba == fs_lba)
|
|
break;
|
|
} while (!pi_next(iter));
|
|
/* broken part structure or other problems */
|
|
if (iter->status) {
|
|
error("Unable to find partition with syslinux (fs).");
|
|
goto bail;
|
|
}
|
|
}
|
|
} else {
|
|
error("Unparsable drive specification.");
|
|
goto bail;
|
|
}
|
|
/* main options done - only thing left is explicit partition specification,
|
|
* if we're still at the disk stage with the iterator AND user supplied
|
|
* partition number (including disk pseudo-partition).
|
|
*/
|
|
if (!iter->index && opt.partition) {
|
|
partition = strtol(opt.partition, NULL, 0);
|
|
/* search for matching part#, including disk */
|
|
do {
|
|
if (iter->index == partition)
|
|
break;
|
|
} while (!pi_next(iter));
|
|
if (iter->status) {
|
|
error("Unable to find requested disk / partition combination.");
|
|
goto bail;
|
|
}
|
|
}
|
|
|
|
if (!(iter->di.disk & 0x80) && iter->index) {
|
|
warn("Partitions on floppy devices may not work.");
|
|
}
|
|
|
|
*_iter = iter;
|
|
|
|
return 0;
|
|
|
|
bail:
|
|
pi_del(&iter);
|
|
return -1;
|
|
}
|
|
|
|
static int setup_handover(const struct part_iter *iter,
|
|
struct data_area *data)
|
|
{
|
|
struct disk_dos_part_entry *ha;
|
|
uint32_t synth_size = sizeof *ha;
|
|
|
|
/*
|
|
* we have to cover both non-iterated but otherwise properly detected
|
|
* gpt/dos schemes as well as raw disks; checking index for 0 covers both
|
|
*/
|
|
if (iter->index == 0) {
|
|
uint32_t len;
|
|
/* RAW handover protocol */
|
|
ha = malloc(synth_size);
|
|
if (!ha) {
|
|
critm();
|
|
goto bail;
|
|
}
|
|
len = ~0u;
|
|
if (iter->length < len)
|
|
len = iter->length;
|
|
lba2chs(&ha->start, &iter->di, 0, L2C_CADD);
|
|
lba2chs(&ha->end, &iter->di, len - 1, L2C_CADD);
|
|
ha->active_flag = 0x80;
|
|
ha->ostype = 0xDA; /* "Non-FS Data", anything is good here though ... */
|
|
ha->start_lba = 0;
|
|
ha->length = len;
|
|
} else if (iter->type == typegpt) {
|
|
uint32_t *plen;
|
|
/* GPT handover protocol */
|
|
synth_size += sizeof *plen + iter->gpt.pe_size;
|
|
ha = malloc(synth_size);
|
|
if (!ha) {
|
|
critm();
|
|
goto bail;
|
|
}
|
|
lba2chs(&ha->start, &iter->di, iter->abs_lba, L2C_CADD);
|
|
lba2chs(&ha->end, &iter->di, iter->abs_lba + iter->length - 1, L2C_CADD);
|
|
ha->active_flag = 0x80;
|
|
ha->ostype = 0xED;
|
|
/* All bits set by default */
|
|
ha->start_lba = ~0u;
|
|
ha->length = ~0u;
|
|
/* If these fit the precision, pass them on */
|
|
if (iter->abs_lba < ha->start_lba)
|
|
ha->start_lba = iter->abs_lba;
|
|
if (iter->length < ha->length)
|
|
ha->length = iter->length;
|
|
/* Next comes the GPT partition record length */
|
|
plen = (uint32_t *)(ha + 1);
|
|
plen[0] = iter->gpt.pe_size;
|
|
/* Next comes the GPT partition record copy */
|
|
memcpy(plen + 1, iter->record, plen[0]);
|
|
#ifdef DEBUG
|
|
dprintf("GPT handover:\n");
|
|
disk_dos_part_dump(ha);
|
|
disk_gpt_part_dump((struct disk_gpt_part_entry *)(plen + 1));
|
|
#endif
|
|
/* the only possible case left is dos scheme */
|
|
} else if (iter->type == typedos) {
|
|
/* MBR handover protocol */
|
|
ha = malloc(synth_size);
|
|
if (!ha) {
|
|
critm();
|
|
goto bail;
|
|
}
|
|
memcpy(ha, iter->record, synth_size);
|
|
/* make sure these match bios imaginations and are ebr agnostic */
|
|
lba2chs(&ha->start, &iter->di, iter->abs_lba, L2C_CADD);
|
|
lba2chs(&ha->end, &iter->di, iter->abs_lba + iter->length - 1, L2C_CADD);
|
|
ha->start_lba = iter->abs_lba;
|
|
ha->length = iter->length;
|
|
|
|
#ifdef DEBUG
|
|
dprintf("MBR handover:\n");
|
|
disk_dos_part_dump(ha);
|
|
#endif
|
|
} else {
|
|
/* shouldn't ever happen */
|
|
goto bail;
|
|
}
|
|
|
|
data->base = 0x7be;
|
|
data->size = synth_size;
|
|
data->data = (void *)ha;
|
|
|
|
return 0;
|
|
bail:
|
|
return -1;
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
struct part_iter *iter = NULL;
|
|
void *sbck = NULL;
|
|
struct data_area fdat, hdat, sdat, data[3];
|
|
int ndata = 0;
|
|
|
|
console_ansi_raw();
|
|
|
|
memset(&fdat, 0, sizeof fdat);
|
|
memset(&hdat, 0, sizeof hdat);
|
|
memset(&sdat, 0, sizeof sdat);
|
|
|
|
opt_set_defs();
|
|
if (opt_parse_args(argc, argv))
|
|
goto bail;
|
|
|
|
#if 0
|
|
/* Get max fixed disk number */
|
|
fixed_cnt = *(uint8_t *)(0x475);
|
|
|
|
/*
|
|
* hmm, looks like we can't do that -
|
|
* some bioses/vms just set it to 1
|
|
* and go on living happily
|
|
* any better options than hardcoded 0x80 - 0xFF ?
|
|
*/
|
|
#endif
|
|
|
|
/* Get disk/part iterator matching user supplied options */
|
|
if (find_dp(&iter))
|
|
goto bail;
|
|
|
|
/* Perform initial partition entry mangling */
|
|
if (manglepe_fixchs(iter))
|
|
goto bail;
|
|
if (manglepe_hide(iter))
|
|
goto bail;
|
|
|
|
/* Load the boot file */
|
|
if (opt.file) {
|
|
fdat.base = (opt.fseg << 4) + opt.foff;
|
|
|
|
if (loadfile(opt.file, &fdat.data, &fdat.size)) {
|
|
error("Couldn't read the boot file.");
|
|
goto bail;
|
|
}
|
|
if (fdat.base + fdat.size > dosmax) {
|
|
error("The boot file is too big to load at this address.");
|
|
goto bail;
|
|
}
|
|
}
|
|
|
|
/* Load the sector */
|
|
if (opt.sect) {
|
|
sdat.base = (opt.sseg << 4) + opt.soff;
|
|
sdat.size = iter->di.bps;
|
|
|
|
if (sdat.base + sdat.size > dosmax) {
|
|
error("The sector cannot be loaded at such high address.");
|
|
goto bail;
|
|
}
|
|
if (!(sdat.data = disk_read_sectors(&iter->di, iter->abs_lba, 1))) {
|
|
error("Couldn't read the sector.");
|
|
goto bail;
|
|
}
|
|
if (opt.save) {
|
|
if (!(sbck = malloc(sdat.size))) {
|
|
critm();
|
|
goto bail;
|
|
}
|
|
memcpy(sbck, sdat.data, sdat.size);
|
|
}
|
|
if (opt.file && opt.maps && overlap(&fdat, &sdat)) {
|
|
warn("The sector won't be mmapped, as it would conflict with the boot file.");
|
|
opt.maps = false;
|
|
}
|
|
}
|
|
|
|
/* Prep the handover */
|
|
if (opt.hand) {
|
|
if (setup_handover(iter, &hdat))
|
|
goto bail;
|
|
/* Verify possible conflicts */
|
|
if ( ( opt.file && overlap(&fdat, &hdat)) ||
|
|
( opt.maps && overlap(&sdat, &hdat)) ) {
|
|
warn("Handover area won't be prepared,\n"
|
|
"as it would conflict with the boot file and/or the sector.");
|
|
opt.hand = false;
|
|
}
|
|
}
|
|
|
|
/* Adjust registers */
|
|
|
|
mangler_init(iter);
|
|
mangler_handover(iter, &hdat);
|
|
mangler_grldr(iter);
|
|
|
|
/* Patching functions */
|
|
|
|
if (manglef_isolinux(&fdat))
|
|
goto bail;
|
|
|
|
if (manglef_grub(iter, &fdat))
|
|
goto bail;
|
|
#if 0
|
|
if (manglef_drmk(&fdat))
|
|
goto bail;
|
|
#endif
|
|
if (manglef_bpb(iter, &fdat))
|
|
goto bail;
|
|
|
|
if (mangles_bpb(iter, &sdat))
|
|
goto bail;
|
|
|
|
if (mangles_save(iter, &sdat, sbck))
|
|
goto bail;
|
|
|
|
if (manglesf_bss(&sdat, &fdat))
|
|
goto bail;
|
|
|
|
/* This *must* be after BPB saving or copying */
|
|
if (mangles_cmldr(&sdat))
|
|
goto bail;
|
|
|
|
/*
|
|
* Prepare boot-time mmap data. We should to it here, as manglers could
|
|
* potentially alter some of the data.
|
|
*/
|
|
|
|
if (opt.file)
|
|
memcpy(data + ndata++, &fdat, sizeof fdat);
|
|
if (opt.maps)
|
|
memcpy(data + ndata++, &sdat, sizeof sdat);
|
|
if (opt.hand)
|
|
memcpy(data + ndata++, &hdat, sizeof hdat);
|
|
|
|
#ifdef DEBUG
|
|
dprintf("iter->di dsk, bps: %X, %u\niter->di lbacnt, C*H*S: %"PRIu64", %u\n"
|
|
"iter->di C, H, S: %u, %u, %u\n",
|
|
iter->di.disk, iter->di.bps,
|
|
iter->di.lbacnt, iter->di.cyl * iter->di.head * iter->di.spt,
|
|
iter->di.cyl, iter->di.head, iter->di.spt);
|
|
dprintf("iter idx: %d\n", iter->index);
|
|
dprintf("iter lba: %"PRIu64"\n", iter->abs_lba);
|
|
if (opt.hand)
|
|
dprintf("hand lba: %u\n",
|
|
((struct disk_dos_part_entry *)hdat.data)->start_lba);
|
|
#endif
|
|
|
|
if (opt.warn) {
|
|
puts("Press any key to continue booting...");
|
|
wait_key();
|
|
}
|
|
|
|
if (ndata && !opt.brkchain) /* boot only if we actually chainload */
|
|
do_boot(data, ndata);
|
|
else
|
|
puts("Service-only run completed, exiting.");
|
|
bail:
|
|
pi_del(&iter);
|
|
/* Free allocated areas */
|
|
free(fdat.data);
|
|
free(sdat.data);
|
|
free(hdat.data);
|
|
free(sbck);
|
|
return 255;
|
|
}
|
|
|
|
/* vim: set ts=8 sts=4 sw=4 noet: */
|