aboutsummaryrefslogtreecommitdiffstats
path: root/com32
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2013-03-20 17:14:21 +0000
committerMatt Fleming <matt.fleming@intel.com>2013-03-22 13:57:44 +0000
commit37d43cf9dd5dd2d2cef1e86aa651097473fd0b48 (patch)
tree07a7df546f178c4e1576f4cbcc0bb4db3a8e18b4 /com32
parentbf20364b582c383b4927f898de213b1cc0981a80 (diff)
parenta107cb3b6fa219cf5f65bef366c9b00b108e9a3a (diff)
downloadsyslinux-37d43cf9dd5dd2d2cef1e86aa651097473fd0b48.tar.gz
syslinux-37d43cf9dd5dd2d2cef1e86aa651097473fd0b48.tar.xz
syslinux-37d43cf9dd5dd2d2cef1e86aa651097473fd0b48.zip
Merge tag 'syslinux-5.10-pre2' into for-hpa/elflink/firmware
syslinux-5.10-pre2 Conflicts: NEWS com32/include/netinet/in.h com32/include/sys/cpu.h com32/lib/Makefile core/Makefile core/fs/diskio.c core/fs/pxe/pxe.h core/init.c core/mem/free.c core/mem/malloc.c mk/devel.mk version
Diffstat (limited to 'com32')
-rw-r--r--com32/chain/Makefile7
-rw-r--r--com32/chain/chain.c171
-rw-r--r--com32/chain/chain.h19
-rw-r--r--com32/chain/common.h9
-rw-r--r--com32/chain/mangle.c244
-rw-r--r--com32/chain/mangle.h34
-rw-r--r--com32/chain/options.c230
-rw-r--r--com32/chain/options.h54
-rw-r--r--com32/chain/partiter.c619
-rw-r--r--com32/chain/partiter.h85
-rw-r--r--com32/chain/utility.c96
-rw-r--r--com32/chain/utility.h79
-rw-r--r--com32/elflink/ldlinux/chainboot.c3
-rw-r--r--com32/elflink/ldlinux/execute.c41
-rw-r--r--com32/elflink/ldlinux/kernel.c17
-rw-r--r--com32/elflink/ldlinux/ldlinux.c36
-rw-r--r--com32/elflink/ldlinux/readconfig.c67
-rw-r--r--com32/gfxboot/gfxboot.c2
-rw-r--r--com32/include/byteswap.h58
-rw-r--r--com32/include/com32.h2
-rw-r--r--com32/include/errno.h21
-rw-r--r--com32/include/fcntl.h1
-rw-r--r--com32/include/linux/list.h12
-rw-r--r--com32/include/netinet/in.h58
-rw-r--r--com32/include/stddef.h8
-rw-r--r--com32/include/sys/cpu.h41
-rw-r--r--com32/include/sys/i386/cpu.h29
-rw-r--r--com32/include/sys/x86_64/cpu.h28
-rw-r--r--com32/include/syslinux/config.h2
-rw-r--r--com32/include/syslinux/pmapi.h5
-rw-r--r--com32/include/syslinux/pxe_api.h22
-rw-r--r--com32/include/syslinux/sysappend.h59
-rw-r--r--com32/lib/errno.c7
-rw-r--r--com32/lib/sys/file.h2
-rw-r--r--com32/lib/sys/open.c2
-rw-r--r--com32/lib/syslinux/ipappend.c13
-rw-r--r--com32/lib/syslinux/load_linux.c30
-rw-r--r--com32/lib/syslinux/run_command.c2
-rw-r--r--com32/lib/syslinux/runimage.c8
-rw-r--r--com32/lib/syslinux/shuffle.c4
-rw-r--r--com32/menu/menumain.c4
-rw-r--r--com32/menu/readconfig.c35
-rw-r--r--com32/modules/Makefile2
-rw-r--r--com32/modules/cmd.c2
-rw-r--r--com32/modules/cptime.c284
-rw-r--r--com32/modules/poweroff.c88
46 files changed, 1687 insertions, 955 deletions
diff --git a/com32/chain/Makefile b/com32/chain/Makefile
index 1a7ac9e6..4a5af919 100644
--- a/com32/chain/Makefile
+++ b/com32/chain/Makefile
@@ -1,7 +1,9 @@
## -----------------------------------------------------------------------
##
-## Copyright 2001-2010 H. Peter Anvin - All Rights Reserved
-## Copyright 2010 Michal Soltys
+## Copyright 2001-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
@@ -15,6 +17,7 @@ VPATH = $(SRC)
include $(MAKEDIR)/elf.mk
OBJS = chain.o partiter.o utility.o options.o mangle.o
+CFLAGS += -fno-strict-aliasing
all: chain.c32
diff --git a/com32/chain/chain.c b/com32/chain/chain.c
index 30153c4d..ae95d45c 100644
--- a/com32/chain/chain.c
+++ b/com32/chain/chain.c
@@ -3,7 +3,7 @@
* Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
* Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
* Copyright 2010 Shao Miller
- * Copyright 2010 Michal Soltys
+ * 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
@@ -34,7 +34,6 @@
#include <syslinux/config.h>
#include <syslinux/disk.h>
#include <syslinux/video.h>
-#include "common.h"
#include "chain.h"
#include "utility.h"
#include "options.h"
@@ -72,14 +71,14 @@ static int find_by_sig(uint32_t mbr_sig,
for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) {
if (disk_get_params(drive, &diskinfo))
continue; /* Drive doesn't exist */
- if (!(boot_part = pi_begin(&diskinfo, 0)))
+ if (!(boot_part = pi_begin(&diskinfo, opt.piflags)))
continue;
/* Check for a MBR disk */
if (boot_part->type != typedos) {
pi_del(&boot_part);
continue;
}
- if (boot_part->sub.dos.disk_sig == mbr_sig) {
+ if (boot_part->dos.disk_sig == mbr_sig) {
goto ok;
}
}
@@ -103,22 +102,18 @@ static int find_by_guid(const struct guid *gpt_guid,
for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) {
if (disk_get_params(drive, &diskinfo))
continue; /* Drive doesn't exist */
- if (!(boot_part = pi_begin(&diskinfo, 0)))
+ if (!(boot_part = pi_begin(&diskinfo, opt.piflags)))
continue;
/* Check for a GPT disk */
if (boot_part->type != typegpt) {
pi_del(&boot_part);
continue;
}
- /* Check for a matching GPT disk guid */
- if (!memcmp(&boot_part->sub.gpt.disk_guid, gpt_guid, sizeof(*gpt_guid))) {
- goto ok;
- }
- /* disk guid doesn't match, maybe partition guid will */
- while (!pi_next(&boot_part)) {
- if (!memcmp(&boot_part->sub.gpt.part_guid, gpt_guid, sizeof(*gpt_guid)))
+ /* Check for a matching GPT disk/partition guid */
+ do {
+ if (!memcmp(&boot_part->gpt.part_guid, gpt_guid, sizeof *gpt_guid))
goto ok;
- }
+ } while (!pi_next(boot_part));
}
drive = -1;
ok:
@@ -139,7 +134,7 @@ static int find_by_label(const char *label, struct part_iter **_boot_part)
for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) {
if (disk_get_params(drive, &diskinfo))
continue; /* Drive doesn't exist */
- if (!(boot_part = pi_begin(&diskinfo, 0)))
+ if (!(boot_part = pi_begin(&diskinfo, opt.piflags)))
continue;
/* Check for a GPT disk */
if (!(boot_part->type == typegpt)) {
@@ -147,8 +142,8 @@ static int find_by_label(const char *label, struct part_iter **_boot_part)
continue;
}
/* Check for a matching partition */
- while (!pi_next(&boot_part)) {
- if (!strcmp(label, boot_part->sub.gpt.part_label))
+ while (!pi_next(boot_part)) {
+ if (!strcmp(label, boot_part->gpt.part_label))
goto ok;
}
}
@@ -160,8 +155,6 @@ ok:
static void do_boot(struct data_area *data, int ndata)
{
- uint16_t *const bios_fbm = (uint16_t *) 0x413;
- addr_t dosmem = (addr_t)(*bios_fbm << 10); /* Technically a low bound */
struct syslinux_memmap *mmap;
struct syslinux_movelist *mlist = NULL;
addr_t endimage;
@@ -172,7 +165,7 @@ static void do_boot(struct data_area *data, int ndata)
mmap = syslinux_memory_map();
if (!mmap) {
- error("Cannot read system memory map\n");
+ error("Cannot read system memory map.");
return;
}
@@ -181,7 +174,7 @@ static void do_boot(struct data_area *data, int ndata)
if (data[i].base + data[i].size > endimage)
endimage = data[i].base + data[i].size;
}
- if (endimage > dosmem)
+ if (endimage > dosmax)
goto too_big;
for (i = 0; i < ndata; i++) {
@@ -227,7 +220,7 @@ static void do_boot(struct data_area *data, int ndata)
static uint8_t swapstub[1024];
uint8_t *p;
- /* Note: we can't rely on either INT 13h nor the dosmem
+ /* 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
@@ -247,14 +240,14 @@ static void do_boot(struct data_area *data, int ndata)
/* Mapping table; start out with identity mapping everything */
for (i = 0; i < 256; i++)
- p[i] = (uint8_t)i;
+ p[i] = i;
/* And the actual swap */
p[driveno] = swapdrive;
p[swapdrive] = driveno;
/* Adjust registers */
- opt.regs.ds = opt.regs.cs = (uint16_t)(endimage >> 4);
+ 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 */
@@ -273,17 +266,17 @@ static void do_boot(struct data_area *data, int ndata)
/* Force text mode */
syslinux_force_text_mode();
- fputs("Booting...\n", stdout);
+ puts("Booting...");
syslinux_shuffle_boot_rm(mlist, mmap, opt.keeppxe, &opt.regs);
- error("Chainboot failed!\n");
+ error("Chainboot failed !");
return;
too_big:
- error("Loader file too large\n");
+ error("Loader file too large.");
return;
enomem:
- error("Out of memory\n");
+ error("Out of memory.");
return;
}
@@ -300,23 +293,23 @@ int find_dp(struct part_iter **_iter)
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.\n");
+ 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.\n");
+ 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.\n");
+ error("No label specified.");
goto bail;
}
if (find_by_label(opt.drivename + 6, &iter) < 0) {
- error("Unable to find requested GPT partition by label.\n");
+ error("Unable to find requested GPT partition by label.");
goto bail;
}
} else if ((opt.drivename[0] == 'h' || opt.drivename[0] == 'f') &&
@@ -328,13 +321,13 @@ int find_dp(struct part_iter **_iter)
if (disk_get_params(drive, &diskinfo))
goto bail;
/* this will start iteration over FDD, possibly raw */
- if (!(iter = pi_begin(&diskinfo, 0)))
+ 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.\n");
+ "'boot' and 'fs' are meaningless.");
goto bail;
}
/* offsets match, but in case it changes in the future */
@@ -348,23 +341,23 @@ int find_dp(struct part_iter **_iter)
if (disk_get_params(drive, &diskinfo))
goto bail;
/* this will start iteration over disk emulation, possibly raw */
- if (!(iter = pi_begin(&diskinfo, 0)))
+ 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")) {
- while (!pi_next(&iter)) {
- if (iter->start_lba == fs_lba)
+ do {
+ if (iter->abs_lba == fs_lba)
break;
- }
+ } while (!pi_next(iter));
/* broken part structure or other problems */
if (iter->status) {
- error("Can't find myself on the drive I booted from.\n");
+ error("Can't find myself on the drive I booted from.");
goto bail;
}
}
} else {
- error("Unparsable drive specification.\n");
+ error("Unparsable drive specification.");
goto bail;
}
/* main options done - only thing left is explicit partition specification,
@@ -377,15 +370,15 @@ int find_dp(struct part_iter **_iter)
do {
if (iter->index == partition)
break;
- } while (!pi_next(&iter));
+ } while (!pi_next(iter));
if (iter->status) {
- error("Requested disk / partition combination not found.\n");
+ error("Requested disk / partition combination not found.");
goto bail;
}
}
if (!(iter->di.disk & 0x80) && iter->index) {
- error("WARNING: Partitions on floppy devices may not work.\n");
+ warn("Partitions on floppy devices may not work.");
}
*_iter = iter;
@@ -401,51 +394,53 @@ static int setup_handover(const struct part_iter *iter,
struct data_area *data)
{
struct disk_dos_part_entry *ha;
- uint32_t synth_size;
- uint32_t *plen;
+ uint32_t synth_size = sizeof *ha;
- if (!iter->index) { /* implies typeraw or non-iterated */
+ /*
+ * 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 */
- synth_size = sizeof(struct disk_dos_part_entry);
ha = malloc(synth_size);
if (!ha) {
- error("Could not build RAW hand-over record!\n");
+ critm();
goto bail;
}
len = ~0u;
if (iter->length < len)
- len = (uint32_t)iter->length;
- lba2chs(&ha->start, &iter->di, 0, l2c_cadd);
- lba2chs(&ha->end, &iter->di, len - 1, l2c_cadd);
+ 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(struct disk_dos_part_entry) +
- sizeof(uint32_t) + (uint32_t)iter->sub.gpt.pe_size;
+ synth_size += sizeof *plen + iter->gpt.pe_size;
ha = malloc(synth_size);
if (!ha) {
- error("Could not build GPT hand-over record!\n");
+ critm();
goto bail;
}
- lba2chs(&ha->start, &iter->di, iter->start_lba, l2c_cadd);
- lba2chs(&ha->end, &iter->di, iter->start_lba + iter->length - 1, l2c_cadd);
+ 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->start_lba < ha->start_lba)
- ha->start_lba = (uint32_t)iter->start_lba;
+ if (iter->abs_lba < ha->start_lba)
+ ha->start_lba = iter->abs_lba;
if (iter->length < ha->length)
- ha->length = (uint32_t)iter->length;
+ ha->length = iter->length;
/* Next comes the GPT partition record length */
- plen = (uint32_t *) (ha + 1);
- plen[0] = (uint32_t)iter->sub.gpt.pe_size;
+ 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
@@ -453,20 +448,20 @@ static int setup_handover(const struct part_iter *iter,
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 */
- synth_size = sizeof(struct disk_dos_part_entry);
ha = malloc(synth_size);
if (!ha) {
- error("Could not build MBR hand-over record!\n");
+ 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->start_lba, l2c_cadd);
- lba2chs(&ha->end, &iter->di, iter->start_lba + iter->length - 1, l2c_cadd);
- ha->start_lba = (uint32_t)iter->start_lba;
- ha->length = (uint32_t)iter->length;
+ 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");
@@ -495,9 +490,9 @@ int main(int argc, char *argv[])
console_ansi_raw();
- memset(&fdat, 0, sizeof(fdat));
- memset(&hdat, 0, sizeof(hdat));
- memset(&sdat, 0, sizeof(sdat));
+ memset(&fdat, 0, sizeof fdat);
+ memset(&hdat, 0, sizeof hdat);
+ memset(&sdat, 0, sizeof sdat);
opt_set_defs();
if (opt_parse_args(argc, argv))
@@ -530,11 +525,11 @@ int main(int argc, char *argv[])
fdat.base = (opt.fseg << 4) + opt.foff;
if (loadfile(opt.file, &fdat.data, &fdat.size)) {
- error("Couldn't read the boot file.\n");
+ error("Couldn't read the boot file.");
goto bail;
}
- if (fdat.base + fdat.size - 1 > ADDRMAX) {
- error("The boot file is too big to load at this address.\n");
+ if (fdat.base + fdat.size > dosmax) {
+ error("The boot file is too big to load at this address.");
goto bail;
}
}
@@ -544,23 +539,23 @@ int main(int argc, char *argv[])
sdat.base = (opt.sseg << 4) + opt.soff;
sdat.size = iter->di.bps;
- if (sdat.base + sdat.size - 1 > ADDRMAX) {
- error("The sector cannot be loaded at such high address.\n");
+ 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->start_lba, 1))) {
- error("Couldn't read the sector.\n");
+ 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))) {
- error("Couldn't allocate cmp-buf for option 'save'.\n");
+ critm();
goto bail;
}
memcpy(sbck, sdat.data, sdat.size);
}
if (opt.file && opt.maps && overlap(&fdat, &sdat)) {
- error("WARNING: The sector won't be mmapped, as it would conflict with the boot file.\n");
+ warn("The sector won't be mmapped, as it would conflict with the boot file.");
opt.maps = false;
}
}
@@ -572,8 +567,8 @@ int main(int argc, char *argv[])
/* Verify possible conflicts */
if ( ( opt.file && overlap(&fdat, &hdat)) ||
( opt.maps && overlap(&sdat, &hdat)) ) {
- error("WARNING: Handover area won't be prepared,\n"
- "as it would conflict with the boot file and/or the sector.\n");
+ warn("Handover area won't be prepared,\n"
+ "as it would conflict with the boot file and/or the sector.");
opt.hand = false;
}
}
@@ -617,22 +612,22 @@ int main(int argc, char *argv[])
*/
if (opt.file)
- memcpy(data + ndata++, &fdat, sizeof(fdat));
+ memcpy(data + ndata++, &fdat, sizeof fdat);
if (opt.maps)
- memcpy(data + ndata++, &sdat, sizeof(sdat));
+ memcpy(data + ndata++, &sdat, sizeof sdat);
if (opt.hand)
- memcpy(data + ndata++, &hdat, sizeof(hdat));
+ memcpy(data + ndata++, &hdat, sizeof hdat);
#ifdef DEBUG
- printf("iter->di dsk, bps: %X, %u\niter->di lbacnt, C*H*S: %"PRIu64", %u\n"
+ 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);
- printf("iter idx: %d\n", iter->index);
- printf("iter lba: %"PRIu64"\n", iter->start_lba);
+ dprintf("iter idx: %d\n", iter->index);
+ dprintf("iter lba: %"PRIu64"\n", iter->abs_lba);
if (opt.hand)
- printf("hand lba: %u\n",
+ dprintf("hand lba: %u\n",
((struct disk_dos_part_entry *)hdat.data)->start_lba);
#endif
@@ -644,7 +639,7 @@ int main(int argc, char *argv[])
if (ndata && !opt.brkchain) /* boot only if we actually chainload */
do_boot(data, ndata);
else
- error("Service-only run completed, exiting.\n");
+ puts("Service-only run completed, exiting.");
bail:
pi_del(&iter);
/* Free allocated areas */
diff --git a/com32/chain/chain.h b/com32/chain/chain.h
index fc481bc6..fb5914b1 100644
--- a/com32/chain/chain.h
+++ b/com32/chain/chain.h
@@ -1,5 +1,20 @@
-#ifndef _COM32_CHAIN_CHAIN_H
-#define _COM32_CHAIN_CHAIN_H
+/* ----------------------------------------------------------------------- *
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef COM32_CHAIN_CHAIN_H
+#define COM32_CHAIN_CHAIN_H
#include <syslinux/movebits.h>
diff --git a/com32/chain/common.h b/com32/chain/common.h
deleted file mode 100644
index b170a732..00000000
--- a/com32/chain/common.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef _COM32_CHAIN_COMMON_H
-#define _COM32_CHAIN_COMMON_H
-
-#define ADDRMAX 0x9EFFFu
-#define ADDRMIN 0x500u
-
-#endif
-
-/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/mangle.c b/com32/chain/mangle.c
index 8358106e..ffdaab8d 100644
--- a/com32/chain/mangle.c
+++ b/com32/chain/mangle.c
@@ -1,3 +1,33 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
#include <com32.h>
#include <stdlib.h>
#include <stdio.h>
@@ -5,7 +35,6 @@
#include <stdint.h>
#include <dprintf.h>
#include <syslinux/config.h>
-#include "common.h"
#include "chain.h"
#include "options.h"
#include "utility.h"
@@ -32,7 +61,7 @@ int manglef_isolinux(struct data_area *data)
sdi = syslinux_derivative_info();
if (sdi->c.filesystem != SYSLINUX_FS_ISOLINUX) {
- error ("The isolinux= option is only valid when run from ISOLINUX.\n");
+ error("The isolinux= option is only valid when run from ISOLINUX.");
goto bail;
}
@@ -58,7 +87,7 @@ int manglef_isolinux(struct data_area *data)
file_lba = get_file_lba(opt.file);
if (file_lba == 0) {
- error("Failed to find LBA offset of the boot file\n");
+ error("Failed to find LBA offset of the boot file.");
goto bail;
}
/* Set it */
@@ -132,8 +161,8 @@ int manglef_grub(const struct part_iter *iter, struct data_area *data)
if (!(opt.file && opt.grub))
return 0;
- if (data->size < sizeof(struct grub_stage2_patch_area)) {
- error("The file specified by grub=<loader> is too small to be stage2 of GRUB Legacy.\n");
+ if (data->size < sizeof *stage2) {
+ error("The file specified by grub=<loader> is too small to be stage2 of GRUB Legacy.");
goto bail;
}
stage2 = data->data;
@@ -144,7 +173,7 @@ int manglef_grub(const struct part_iter *iter, struct data_area *data)
*/
if (stage2->compat_version_major != 3
|| stage2->compat_version_minor != 2) {
- error("The file specified by grub=<loader> is not a supported stage2 GRUB Legacy binary.\n");
+ error("The file specified by grub=<loader> is not a supported stage2 GRUB Legacy binary.");
goto bail;
}
@@ -174,7 +203,7 @@ int manglef_grub(const struct part_iter *iter, struct data_area *data)
* 0-3: primary partitions
* 4-*: logical partitions
*/
- stage2->install_partition.part1 = (uint8_t)(iter->index - 1);
+ stage2->install_partition.part1 = iter->index - 1;
/*
* Grub Legacy reserves 89 bytes (from 0x8217 to 0x826f) for the
@@ -182,8 +211,8 @@ int manglef_grub(const struct part_iter *iter, struct data_area *data)
* the default config filename "/boot/grub/menu.lst".
*/
if (opt.grubcfg) {
- if (strlen(opt.grubcfg) > sizeof(stage2->config_file) - 1) {
- error ("The config filename length can't exceed 88 characters.\n");
+ if (strlen(opt.grubcfg) >= sizeof stage2->config_file) {
+ error("The config filename length can't exceed 88 characters.");
goto bail;
}
@@ -224,19 +253,19 @@ int manglef_drmk(struct data_area *data)
dprintf(" fs_lba offset is %d\n", fs_lba);
/* DRMK only uses a DWORD */
if (fs_lba > 0xffffffff) {
- error("LBA very large; Only using lower 32 bits; DRMK will probably fail\n");
+ error("LBA very large; Only using lower 32 bits; DRMK will probably fail.");
}
opt.regs.ss = opt.regs.fs = opt.regs.gs = 0; /* Used before initialized */
if (!realloc(data->data, tsize)) {
- error("Failed to realloc for DRMK.\n");
+ error("Failed to realloc for DRMK.");
goto bail;
}
data->size = tsize;
/* ds:bp is assumed by DRMK to be the boot sector */
/* offset 28 is the FAT HiddenSectors value */
- opt.regs.ds = (uint16_t)((tsize >> 4) + (opt.fseg - 2));
+ opt.regs.ds = (tsize >> 4) + (opt.fseg - 2);
/* "Patch" into tail of the new space */
- *(uint32_t *)((char*)data->data + tsize - 4) = (uint32_t)fs_lba;
+ *(uint32_t *)((char*)data->data + tsize - 4) = fs_lba;
return 0;
bail:
@@ -246,29 +275,32 @@ bail:
/* Adjust BPB common function */
static int mangle_bpb(const struct part_iter *iter, struct data_area *data, const char *tag)
{
- unsigned int off;
int type = bpb_detect(data->data, tag);
+ int off = drvoff_detect(type);
+ /* BPB: hidden sectors 64bit - exFAT only for now */
+ if (type == bpbEXF)
+ *(uint64_t *) ((char *)data->data + 0x40) = iter->abs_lba;
/* BPB: hidden sectors 32bit*/
- if (type >= bpbV34) {
- if (iter->start_lba < ~0u)
- *(uint32_t *) ((char *)data->data + 0x1c) = (uint32_t)iter->start_lba;
+ else if (bpbV34 <= type && type <= bpbV70) {
+ if (iter->abs_lba < ~0u)
+ *(uint32_t *) ((char *)data->data + 0x1c) = iter->abs_lba;
else
/* won't really help much, but ... */
*(uint32_t *) ((char *)data->data + 0x1c) = ~0u;
- }
/* BPB: hidden sectors 16bit*/
- if (bpbV30 <= type && type <= bpbV32) {
- if (iter->start_lba < 0xFFFF)
- *(uint16_t *) ((char *)data->data + 0x1c) = (uint16_t)iter->start_lba;
+ } else if (bpbV30 <= type && type <= bpbV32) {
+ if (iter->abs_lba < 0xFFFF)
+ *(uint16_t *) ((char *)data->data + 0x1c) = iter->abs_lba;
else
/* won't really help much, but ... */
*(uint16_t *) ((char *)data->data + 0x1c) = (uint16_t)~0u;
}
+
/* BPB: legacy geometry */
- if (type >= bpbV30) {
+ if (bpbV30 <= type && type <= bpbV70) {
if (iter->di.cbios)
- *(uint32_t *)((char *)data->data + 0x18) = (uint32_t)((iter->di.head << 16) | iter->di.spt);
+ *(uint32_t *)((char *)data->data + 0x18) = (iter->di.head << 16) | iter->di.spt;
else {
if (iter->di.disk & 0x80)
*(uint32_t *)((char *)data->data + 0x18) = 0x00FF003F;
@@ -277,9 +309,8 @@ static int mangle_bpb(const struct part_iter *iter, struct data_area *data, cons
}
}
/* BPB: drive */
- if (drvoff_detect(type, &off)) {
- *(uint8_t *)((char *)data->data + off) = (uint8_t)
- (opt.swap ? iter->di.disk & 0x80 : iter->di.disk);
+ if (off >= 0) {
+ *(uint8_t *)((char *)data->data + off) = (opt.swap ? iter->di.disk & 0x80 : iter->di.disk);
}
return 0;
@@ -314,7 +345,7 @@ int mangles_bpb(const struct part_iter *iter, struct data_area *data)
int manglesf_bss(struct data_area *sec, struct data_area *fil)
{
int type1, type2;
- unsigned int cnt = 0;
+ size_t cnt = 0;
if (!(opt.sect && opt.file && opt.bss))
return 0;
@@ -323,12 +354,12 @@ int manglesf_bss(struct data_area *sec, struct data_area *fil)
type2 = bpb_detect(sec->data, "bss/sect");
if (!type1 || !type2) {
- error("Couldn't determine the BPB type for option 'bss'.\n");
+ error("Couldn't determine the BPB type for option 'bss'.");
goto bail;
}
if (type1 != type2) {
error("Option 'bss' can't be used,\n"
- "when a sector and a file have incompatible BPBs.\n");
+ "when a sector and a file have incompatible BPBs.");
goto bail;
}
@@ -348,6 +379,8 @@ int manglesf_bss(struct data_area *sec, struct data_area *fil)
cnt = 0x3C;
} else if (type1 <= bpbV70) {
cnt = 0x42;
+ } else if (type1 <= bpbEXF) {
+ cnt = 0x60;
}
memcpy((char *)fil->data + 0x18, (char *)sec->data + 0x18, cnt);
@@ -365,8 +398,8 @@ int mangles_save(const struct part_iter *iter, const struct data_area *data, voi
return 0;
if (memcmp(org, data->data, data->size)) {
- if (disk_write_sectors(&iter->di, iter->start_lba, data->data, 1)) {
- error("Cannot write the updated sector.\n");
+ if (disk_write_sectors(&iter->di, iter->abs_lba, data->data, 1)) {
+ error("Cannot write the updated sector.");
goto bail;
}
/* function can be called again */
@@ -388,7 +421,7 @@ int mangles_cmldr(struct data_area *data)
if (!(opt.sect && opt.cmldr))
return 0;
- memcpy((char *)data->data + 3, cmldr_signature, sizeof(cmldr_signature));
+ memcpy((char *)data->data + 3, cmldr_signature, sizeof cmldr_signature);
return 0;
}
@@ -397,18 +430,18 @@ int mangler_init(const struct part_iter *iter)
{
/* Set initial registry values */
if (opt.file) {
- opt.regs.cs = opt.regs.ds = opt.regs.ss = (uint16_t)opt.fseg;
- opt.regs.ip = (uint16_t)opt.fip;
+ opt.regs.cs = opt.regs.ds = opt.regs.ss = opt.fseg;
+ opt.regs.ip = opt.fip;
} else {
- opt.regs.cs = opt.regs.ds = opt.regs.ss = (uint16_t)opt.sseg;
- opt.regs.ip = (uint16_t)opt.sip;
+ opt.regs.cs = opt.regs.ds = opt.regs.ss = opt.sseg;
+ opt.regs.ip = opt.sip;
}
if (opt.regs.ip == 0x7C00 && !opt.regs.cs)
opt.regs.esp.l = 0x7C00;
/* DOS kernels want the drive number in BL instead of DL. Indulge them. */
- opt.regs.ebx.b[0] = opt.regs.edx.b[0] = (uint8_t)iter->di.disk;
+ opt.regs.ebx.b[0] = opt.regs.edx.b[0] = iter->di.disk;
return 0;
}
@@ -418,7 +451,7 @@ int mangler_handover(const struct part_iter *iter, const struct data_area *data)
{
if (opt.file && opt.maps && !opt.hptr) {
opt.regs.esi.l = opt.regs.ebp.l = opt.soff;
- opt.regs.ds = (uint16_t)opt.sseg;
+ opt.regs.ds = opt.sseg;
opt.regs.eax.l = 0;
} else if (opt.hand) {
/* base is really 0x7be */
@@ -442,7 +475,7 @@ int mangler_handover(const struct part_iter *iter, const struct data_area *data)
int mangler_grldr(const struct part_iter *iter)
{
if (opt.grldr)
- opt.regs.edx.b[1] = (uint8_t)(iter->index - 1);
+ opt.regs.edx.b[1] = iter->index - 1;
return 0;
}
@@ -450,15 +483,15 @@ int mangler_grldr(const struct part_iter *iter)
/*
* try to copy values from temporary iterator, if positions match
*/
-static void push_embr(struct part_iter *diter, struct part_iter *siter)
+static void mbrcpy(struct part_iter *diter, struct part_iter *siter)
{
- if (diter->sub.dos.cebr_lba == siter->sub.dos.cebr_lba &&
+ if (diter->dos.cebr_lba == siter->dos.cebr_lba &&
diter->di.disk == siter->di.disk) {
memcpy(diter->data, siter->data, sizeof(struct disk_dos_mbr));
}
}
-static int mpe_sethide(struct part_iter *iter, struct part_iter *miter)
+static int fliphide(struct part_iter *iter, struct part_iter *miter)
{
struct disk_dos_part_entry *dp;
static const uint16_t mask =
@@ -471,8 +504,8 @@ static int mpe_sethide(struct part_iter *iter, struct part_iter *miter)
if ((t <= 0x1f) && ((mask >> (t & ~0x10u)) & 1)) {
/* It's a hideable partition type */
- if (miter->index == iter->index || opt.hide & 4)
- t &= (uint8_t)(~0x10u); /* unhide */
+ if (miter->index == iter->index || opt.hide & HIDE_REV)
+ t &= ~0x10u; /* unhide */
else
t |= 0x10u; /* hide */
}
@@ -494,69 +527,98 @@ int manglepe_hide(struct part_iter *miter)
{
int wb = 0, werr = 0;
struct part_iter *iter = NULL;
- struct disk_dos_part_entry *dp;
int ridx;
- if (!opt.hide)
+ if (!(opt.hide & HIDE_ON))
return 0;
if (miter->type != typedos) {
- error("Options '*hide*' is meaningful only for legacy partition scheme.\n");
+ error("Option '[un]hide[all]' works only for legacy (DOS) partition scheme.");
return -1;
}
- if (miter->index < 1)
- error("WARNING: It's impossible to unhide a disk.\n");
-
- if (miter->index > 4 && !(opt.hide & 2))
- error("WARNING: your partition is beyond mbr, so it can't be unhidden without '*hideall'.\n");
+ if (miter->index > 4 && !(opt.hide & HIDE_EXT))
+ warn("Specified partition is logical, so it can't be unhidden without 'unhideall'.");
- if (!(iter = pi_begin(&miter->di, 1))) /* turn stepall on */
+ if (!(iter = pi_begin(&miter->di, PIF_STEPALL | opt.piflags)))
return -1;
- while (!pi_next(&iter) && !werr) {
- ridx = iter->rawindex;
- if (!(opt.hide & 2) && ridx > 4)
+ while (!pi_next(iter) && !werr) {
+ ridx = iter->index0;
+ if (!(opt.hide & HIDE_EXT) && ridx > 3)
break; /* skip when we're constrained to pri only */
- dp = (struct disk_dos_part_entry *)iter->record;
- if (dp->ostype)
- wb |= mpe_sethide(iter, miter);
+ if (iter->index != -1)
+ wb |= fliphide(iter, miter);
- if (ridx >= 4 && wb && !werr) {
- push_embr(miter, iter);
- werr |= disk_write_sectors(&iter->di, iter->sub.dos.cebr_lba, iter->data, 1);
+ /*
+ * we have to update mbr and each extended partition, but only if
+ * changes (wb) were detected and there was no prior write error (werr)
+ */
+ if (ridx >= 3 && wb && !werr) {
+ mbrcpy(miter, iter);
+ werr |= disk_write_sectors(&iter->di, iter->dos.cebr_lba, iter->data, 1);
wb = 0;
}
}
- if (iter->status > PI_DONE)
+ if (pi_errored(iter))
goto bail;
- /* last write */
+ /* last update */
if (wb && !werr) {
- push_embr(miter, iter);
- werr |= disk_write_sectors(&iter->di, iter->sub.dos.cebr_lba, iter->data, 1);
+ mbrcpy(miter, iter);
+ werr |= disk_write_sectors(&iter->di, iter->dos.cebr_lba, iter->data, 1);
}
if (werr)
- error("WARNING: failed to write E/MBR during '*hide*'\n");
+ warn("Failed to write E/MBR during '[un]hide[all]'.");
bail:
pi_del(&iter);
return 0;
}
-static int mpe_setchs(const struct disk_info *di,
- struct disk_dos_part_entry *dp,
- uint32_t lba1)
+static int updchs(struct part_iter *iter, int ext)
{
- uint32_t ochs1, ochs2;
+ struct disk_dos_part_entry *dp;
+ uint32_t ochs1, ochs2, lba;
+ dp = (struct disk_dos_part_entry *)iter->record;
+ if (!ext) {
+ /* primary or logical */
+ lba = (uint32_t)iter->abs_lba;
+ } else {
+ /* extended */
+ dp += 1;
+ lba = iter->dos.nebr_lba;
+ }
ochs1 = *(uint32_t *)dp->start;
ochs2 = *(uint32_t *)dp->end;
- lba2chs(&dp->start, di, lba1, l2c_cadd);
- lba2chs(&dp->end, di, lba1 + dp->length - 1, l2c_cadd);
+ /*
+ * We have to be a bit more careful here in case of 0 start and/or length;
+ * start = 0 would be converted to the beginning of the disk (C/H/S =
+ * 0/0/1) or the [B]EBR, length = 0 would actually set the end CHS to be
+ * lower than the start CHS.
+ *
+ * Both are harmless in case of a hole (and in non-hole case will make
+ * partiter complain about corrupt layout unless PIF_RELAX is set), but it
+ * makes everything look silly and not really correct.
+ *
+ * Thus the approach as seen below.
+ */
+
+ if (dp->start_lba || iter->index != -1) {
+ lba2chs(&dp->start, &iter->di, lba, L2C_CADD);
+ } else {
+ memset(&dp->start, 0, sizeof dp->start);
+ }
+
+ if ((dp->start_lba || iter->index != -1) && dp->length) {
+ lba2chs(&dp->end, &iter->di, lba + dp->length - 1, L2C_CADD);
+ } else {
+ memset(&dp->end, 0, sizeof dp->end);
+ }
return
*(uint32_t *)dp->start != ochs1 ||
@@ -570,45 +632,47 @@ int manglepe_fixchs(struct part_iter *miter)
{
int wb = 0, werr = 0;
struct part_iter *iter = NULL;
- struct disk_dos_part_entry *dp;
int ridx;
if (!opt.fixchs)
return 0;
if (miter->type != typedos) {
- error("Options 'fixchs' is meaningful only for legacy partition scheme.\n");
+ error("Option 'fixchs' works only for legacy (DOS) partition scheme.");
return -1;
}
- if (!(iter = pi_begin(&miter->di, 1))) /* turn stepall on */
+ if (!(iter = pi_begin(&miter->di, PIF_STEPALL | opt.piflags)))
return -1;
- while (!pi_next(&iter) && !werr) {
- ridx = iter->rawindex;
- dp = (struct disk_dos_part_entry *)iter->record;
+ while (!pi_next(iter) && !werr) {
+ ridx = iter->index0;
- wb |= mpe_setchs(&iter->di, dp, (uint32_t)iter->start_lba);
- if (ridx > 4)
- wb |= mpe_setchs(&iter->di, dp + 1, iter->sub.dos.nebr_lba);
+ wb |= updchs(iter, 0);
+ if (ridx > 3)
+ wb |= updchs(iter, 1);
- if (ridx >= 4 && wb && !werr) {
- push_embr(miter, iter);
- werr |= disk_write_sectors(&iter->di, iter->sub.dos.cebr_lba, iter->data, 1);
+ /*
+ * we have to update mbr and each extended partition, but only if
+ * changes (wb) were detected and there was no prior write error (werr)
+ */
+ if (ridx >= 3 && wb && !werr) {
+ mbrcpy(miter, iter);
+ werr |= disk_write_sectors(&iter->di, iter->dos.cebr_lba, iter->data, 1);
wb = 0;
}
}
- if (iter->status > PI_DONE)
+ if (pi_errored(iter))
goto bail;
- /* last write */
+ /* last update */
if (wb && !werr) {
- push_embr(miter, iter);
- werr |= disk_write_sectors(&iter->di, iter->sub.dos.cebr_lba, iter->data, 1);
+ mbrcpy(miter, iter);
+ werr |= disk_write_sectors(&iter->di, iter->dos.cebr_lba, iter->data, 1);
}
if (werr)
- error("WARNING: failed to write E/MBR during 'fixchs'\n");
+ warn("Failed to write E/MBR during 'fixchs'.");
bail:
pi_del(&iter);
diff --git a/com32/chain/mangle.h b/com32/chain/mangle.h
index bcefea3b..d4a5b759 100644
--- a/com32/chain/mangle.h
+++ b/com32/chain/mangle.h
@@ -1,5 +1,35 @@
-#ifndef _COM32_CHAIN_MANGLE_H
-#define _COM32_CHAIN_MANGLE_H
+/* ----------------------------------------------------------------------- *
+ *
+ * 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
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef COM32_CHAIN_MANGLE_H
+#define COM32_CHAIN_MANGLE_H
#include "chain.h"
#include "partiter.h"
diff --git a/com32/chain/options.c b/com32/chain/options.c
index 658a45ca..4e722a01 100644
--- a/com32/chain/options.c
+++ b/com32/chain/options.c
@@ -1,21 +1,55 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <syslinux/movebits.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
-#include "common.h"
#include "chain.h"
+#include "partiter.h"
#include "utility.h"
#include "options.h"
struct options opt;
-static int soi_s2n(char *ptr, unsigned int *seg,
- unsigned int *off,
- unsigned int *ip,
- unsigned int def)
+static int soi_s2n(char *ptr,
+ addr_t *seg,
+ addr_t *off,
+ addr_t *ip,
+ addr_t def)
{
- unsigned int segval = 0, offval, ipval, val;
+ addr_t segval, offval, ipval, val;
char *p;
+ /* defaults */
+ segval = 0;
offval = def;
ipval = def;
@@ -25,17 +59,22 @@ static int soi_s2n(char *ptr, unsigned int *seg,
if (p[0] == ':' && p[1] && p[1] != ':')
ipval = strtoul(p+1, NULL, 0);
+ /* verify if load address is within [dosmin, dosmax) */
val = (segval << 4) + offval;
- if (val < ADDRMIN || val > ADDRMAX) {
- error("Invalid seg:off:* address specified..\n");
+ if (val < dosmin || val >= dosmax) {
+ error("Invalid seg:off:* address specified.");
goto bail;
}
+ /*
+ * verify if jump address is within [dosmin, dosmax) and offset is 16bit
+ * sane
+ */
val = (segval << 4) + ipval;
- if (ipval > 0xFFFE || val < ADDRMIN || val > ADDRMAX) {
- error("Invalid seg:*:ip address specified.\n");
+ if (ipval > 0xFFFE || val < dosmin || val >= dosmax) {
+ error("Invalid seg:*:ip address specified.");
goto bail;
}
@@ -53,75 +92,82 @@ bail:
static void usage(void)
{
- unsigned int i;
- static const char key[] = "Press any key...\n";
+ size_t i;
static const char *const usage[] = {
-"\
-Usage:\n\
- chain.c32 [options]\n\
- chain.c32 {fd|hd}<disk#>{,| }[<part#>] [options]\n\
- chain.c32 mbr{:|=}<id>{,| }[<part#>] [options]\n\
- chain.c32 guid{:|=}<guid>{,| }[<part#>] [options]\n\
- chain.c32 label{:|=}<label> [<part#>] [options]\n\
- chain.c32 boot{,| }[<part#>] [options]\n\
- chain.c32 fs [options]\n\
-", "\
-\nOptions ('no' prefix specifies default value):\n\
- sect[=<s[:o[:i]]>] Load sector at <s:o>, jump to <s:i>\n\
- - defaults to 0:0x7C00:0x7C00\n\
- - ommited o/i values default to 0\n\
- maps Map loaded sector into real memory\n\
- nosetbpb Fix BPB fields in loaded sector\n\
- nofilebpb Apply 'setbpb' to loaded file\n\
- nosave Write adjusted sector back to disk\n\
- hand Prepare handover area\n\
- nohptr Force ds:si and ds:bp to point to handover area\n\
- noswap Swap drive numbers, if bootdisk is not fd0/hd0\n\
- nohide Disable all hide variations (also the default)\n\
- hide Hide primary partitions, unhide selected partition\n\
- hideall Hide *all* partitions, unhide selected partition\n\
- unhide Unhide primary partitions\n\
- unhideall Unhide *all* partitions\n\
- nofixchs Walk *all* partitions and fix E/MBRs' chs values\n\
- nokeeppxe Keep the PXE and UNDI stacks in memory (PXELINUX)\n\
- nowarn Wait for a keypress to continue chainloading\n\
- - useful to see emited warnings\n\
- nobreak Actually perform the chainloading\n\
-", "\
-\nOptions continued ...\n\
- file=<file> Load and execute <file>\n\
- seg=<s[:o[:i]]> Load file at <s:o>, jump to <s:i>\n\
- - defaults to 0:0x7C00:0x7C00\n\
- - ommited o/i values default to 0\n\
- isolinux=<loader> Load another version of ISOLINUX\n\
- ntldr=<loader> Load Windows NTLDR, SETUPLDR.BIN or BOOTMGR\n\
- reactos=<loader> Load ReactOS's loader\n\
- cmldr=<loader> Load Recovery Console of Windows NT/2K/XP/2003\n\
- freedos=<loader> Load FreeDOS KERNEL.SYS\n\
- msdos=<loader> Load MS-DOS 2.xx - 6.xx IO.SYS\n\
- msdos7=<loader> Load MS-DOS 7+ IO.SYS\n\
- pcdos=<loader> Load PC-DOS IBMBIO.COM\n\
- drmk=<loader> Load DRMK DELLBIO.BIN\n\
- grub=<loader> Load GRUB Legacy stage2\n\
- grubcfg=<filename> Set alternative config filename for GRUB Legacy\n\
- grldr=<loader> Load GRUB4DOS grldr\n\
- bss=<filename> Emulate syslinux's BSS\n\
- bs=<filename> Emulate syslinux's BS\n\
-\nPlease see doc/chain.txt for the detailed documentation.\n\
-"
- };
+"Usage:",
+"",
+" disk + partition selection:",
+" chain.c32 [options]",
+" chain.c32 hd#[,#] [options]",
+" chain.c32 fd#[,#] [options]",
+" chain.c32 mbr=<id>[,#] [options]",
+" chain.c32 guid=<guid>[,#] [options]",
+" chain.c32 boot[,#] [options]",
+"",
+" direct partition selection:",
+" chain.c32 guid=<guid> [options]",
+" chain.c32 label=<label> [options]",
+" chain.c32 fs [options]",
+"",
+"You can use ':' instead of '=' and ' ' instead of ','.",
+"The default is 'boot,0'.",
+"",
+"Options:",
+" sect[=<s[:o[:i]]>] Load sector at <s:o>, jump to <s:i>",
+" - defaults to 0:0x7C00:0x7C00",
+" - omitted o/i values default to 0",
+" maps Map loaded sector into real memory",
+" setbpb Fix BPB fields in loaded sector",
+" filebpb Apply 'setbpb' to loaded file",
+" save Write adjusted sector back to disk",
+" hand Prepare handover area",
+" hptr Force ds:si and ds:bp to point to handover area",
+" swap Swap drive numbers, if bootdisk is not fd0/hd0",
+" nohide Disable all hide variations (default)",
+" hide Hide primary partitions, unhide selected partition",
+" hideall Hide *all* partitions, unhide selected partition",
+" unhide Unhide primary partitions",
+" unhideall Unhide *all* partitions",
+" fixchs Walk *all* partitions and fix E/MBRs' CHS values",
+" keeppxe Keep the PXE and UNDI stacks in memory (PXELINUX)",
+" warn Wait for a keypress to continue chainloading",
+" break Don't chainload",
+" relax Relax sanity checks",
+" prefmbr On hybrid MBR/GPT disks, prefer legacy layout",
+"",
+" file=<file> Load and execute <file>",
+" seg=<s[:o[:i]]> Load file at <s:o>, jump to <s:i>",
+" - defaults to 0:0x7C00:0x7C00",
+" - omitted o/i values default to 0",
+" isolinux=<loader> Load another version of ISOLINUX",
+" ntldr=<loader> Load Windows NTLDR, SETUPLDR.BIN or BOOTMGR",
+" reactos=<loader> Load ReactOS's loader",
+" cmldr=<loader> Load Recovery Console of Windows NT/2K/XP/2003",
+" freedos=<loader> Load FreeDOS KERNEL.SYS",
+" msdos=<loader> Load MS-DOS 2.xx - 6.xx IO.SYS",
+" msdos7=<loader> Load MS-DOS 7+ IO.SYS",
+" pcdos=<loader> Load PC-DOS IBMBIO.COM",
+" drmk=<loader> Load DRMK DELLBIO.BIN",
+" grub=<loader> Load GRUB Legacy stage2",
+" grubcfg=<config> Set alternative config filename for GRUB Legacy",
+" grldr=<loader> Load GRUB4DOS grldr",
+" bss=<sectimage> Emulate syslinux's BSS",
+" bs=<sectimage> Emulate syslinux's BS",
+"",
+"Please see doc/chain.txt for the detailed documentation."
+};
for (i = 0; i < sizeof(usage)/sizeof(usage[0]); i++) {
- if (i) {
- error(key);
+ if (i % 20 == 19) {
+ puts("Press any key...");
wait_key();
}
- error(usage[i]);
+ puts(usage[i]);
}
}
void opt_set_defs(void)
{
- memset(&opt, 0, sizeof(opt));
+ memset(&opt, 0, sizeof opt);
opt.sect = true; /* by def. load sector */
opt.maps = true; /* by def. map sector */
opt.hand = true; /* by def. prepare handover */
@@ -136,7 +182,7 @@ void opt_set_defs(void)
int opt_parse_args(int argc, char *argv[])
{
int i;
- unsigned int v;
+ size_t v;
char *p;
for (i = 1; i < argc; i++) {
@@ -152,7 +198,6 @@ int opt_parse_args(int argc, char *argv[])
opt.bss = true;
opt.maps = false;
opt.setbpb = true;
- /* opt.save = true; */
} else if (!strncmp(argv[i], "bs=", 3)) {
opt.file = argv[i] + 3;
opt.sect = false;
@@ -168,7 +213,6 @@ int opt_parse_args(int argc, char *argv[])
opt.fip = 0;
opt.file = argv[i] + 6;
opt.setbpb = true;
- /* opt.save = true; */
opt.hand = false;
} else if (!strncmp(argv[i], "reactos=", 8)) {
/*
@@ -182,7 +226,6 @@ int opt_parse_args(int argc, char *argv[])
opt.fip = 0x8100;
opt.file = argv[i] + 8;
opt.setbpb = true;
- /* opt.save = true; */
opt.hand = false;
} else if (!strncmp(argv[i], "cmldr=", 6)) {
opt.fseg = 0x2000; /* CMLDR wants this address */
@@ -191,7 +234,6 @@ int opt_parse_args(int argc, char *argv[])
opt.file = argv[i] + 6;
opt.cmldr = true;
opt.setbpb = true;
- /* opt.save = true; */
opt.hand = false;
} else if (!strncmp(argv[i], "freedos=", 8)) {
opt.fseg = 0x60; /* FREEDOS wants this address */
@@ -200,7 +242,6 @@ int opt_parse_args(int argc, char *argv[])
opt.sseg = 0x1FE0;
opt.file = argv[i] + 8;
opt.setbpb = true;
- /* opt.save = true; */
opt.hand = false;
} else if ( (v = 6, !strncmp(argv[i], "msdos=", v) ||
!strncmp(argv[i], "pcdos=", v)) ||
@@ -211,7 +252,6 @@ int opt_parse_args(int argc, char *argv[])
opt.sseg = 0x8000;
opt.file = argv[i] + v;
opt.setbpb = true;
- /* opt.save = true; */
opt.hand = false;
} else if (!strncmp(argv[i], "drmk=", 5)) {
opt.fseg = 0x70; /* DRMK wants this address */
@@ -223,7 +263,6 @@ int opt_parse_args(int argc, char *argv[])
opt.file = argv[i] + 5;
/* opt.drmk = true; */
opt.setbpb = true;
- /* opt.save = true; */
opt.hand = false;
} else if (!strncmp(argv[i], "grub=", 5)) {
opt.fseg = 0x800; /* stage2 wants this address */
@@ -261,15 +300,15 @@ int opt_parse_args(int argc, char *argv[])
} else if (!strcmp(argv[i], "noswap")) {
opt.swap = false;
} else if (!strcmp(argv[i], "nohide")) {
- opt.hide = 0;
+ opt.hide = HIDE_OFF;
} else if (!strcmp(argv[i], "hide")) {
- opt.hide = 1; /* 001b */
+ opt.hide = HIDE_ON;
} else if (!strcmp(argv[i], "hideall")) {
- opt.hide = 2; /* 010b */
+ opt.hide = HIDE_ON | HIDE_EXT;
} else if (!strcmp(argv[i], "unhide")) {
- opt.hide = 5; /* 101b */
+ opt.hide = HIDE_ON | HIDE_REV;
} else if (!strcmp(argv[i], "unhideall")) {
- opt.hide = 6; /* 110b */
+ opt.hide = HIDE_ON | HIDE_EXT | HIDE_REV;
} else if (!strcmp(argv[i], "setbpb")) {
opt.setbpb = true;
} else if (!strcmp(argv[i], "nosetbpb")) {
@@ -296,10 +335,18 @@ int opt_parse_args(int argc, char *argv[])
opt.fixchs = true;
} else if (!strcmp(argv[i], "nofixchs")) {
opt.fixchs = false;
+ } else if (!strcmp(argv[i], "relax")) {
+ opt.piflags |= PIF_RELAX;
+ } else if (!strcmp(argv[i], "norelax")) {
+ opt.piflags &= ~PIF_RELAX;
} else if (!strcmp(argv[i], "warn")) {
opt.warn = true;
} else if (!strcmp(argv[i], "nowarn")) {
opt.warn = false;
+ } else if (!strcmp(argv[i], "prefmbr")) {
+ opt.piflags |= PIF_PREFMBR;
+ } else if (!strcmp(argv[i], "noprefmbr")) {
+ opt.piflags &= ~PIF_PREFMBR;
} else if (!strcmp(argv[i], "nobreak")) {
opt.brkchain = false;
} else if (!strcmp(argv[i], "break")) {
@@ -337,34 +384,27 @@ int opt_parse_args(int argc, char *argv[])
}
if (opt.grubcfg && !opt.grub) {
- error("grubcfg=<filename> must be used together with grub=<loader>.\n");
+ error("grubcfg=<filename> must be used together with grub=<loader>.");
goto bail;
}
-#if 0
- if ((!opt.maps || !opt.sect) && !opt.file) {
- error("You have to load something.\n");
- goto bail;
- }
-#endif
-
if (opt.filebpb && !opt.file) {
- error("Option 'filebpb' requires a file.\n");
+ error("Option 'filebpb' requires a file.");
goto bail;
}
if (opt.save && !opt.sect) {
- error("Option 'save' requires a sector.\n");
+ error("Option 'save' requires a sector.");
goto bail;
}
if (opt.setbpb && !opt.sect) {
- error("Option 'setbpb' requires a sector.\n");
+ error("Option 'setbpb' requires a sector.");
goto bail;
}
if (opt.maps && !opt.sect) {
- error("Option 'maps' requires a sector.\n");
+ error("Option 'maps' requires a sector.");
goto bail;
}
diff --git a/com32/chain/options.h b/com32/chain/options.h
index 4493ef1f..df96e2d3 100644
--- a/com32/chain/options.h
+++ b/com32/chain/options.h
@@ -1,20 +1,56 @@
-#ifndef _COM32_CHAIN_OPTIONS_H
-#define _COM32_CHAIN_OPTIONS_H
+/* ----------------------------------------------------------------------- *
+ *
+ * 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
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef COM32_CHAIN_OPTIONS_H
+#define COM32_CHAIN_OPTIONS_H
#include <stdint.h>
#include <syslinux/bootrm.h>
+#include <syslinux/movebits.h>
+
+enum {HIDE_OFF = 0, HIDE_ON = 1, HIDE_EXT = 2, HIDE_REV = 4};
struct options {
- unsigned int fseg;
- unsigned int foff;
- unsigned int fip;
- unsigned int sseg;
- unsigned int soff;
- unsigned int sip;
const char *drivename;
const char *partition;
const char *file;
const char *grubcfg;
+ addr_t fseg;
+ addr_t foff;
+ addr_t fip;
+ addr_t sseg;
+ addr_t soff;
+ addr_t sip;
+ int hide;
+ int piflags;
+ uint16_t keeppxe;
bool isolinux;
bool cmldr;
bool drmk;
@@ -24,7 +60,6 @@ struct options {
bool hand;
bool hptr;
bool swap;
- int hide;
bool sect;
bool save;
bool bss;
@@ -33,7 +68,6 @@ struct options {
bool fixchs;
bool warn;
bool brkchain;
- uint16_t keeppxe;
struct syslinux_rm_regs regs;
};
diff --git a/com32/chain/partiter.c b/com32/chain/partiter.c
index 1acd1958..1eb5350d 100644
--- a/com32/chain/partiter.c
+++ b/com32/chain/partiter.c
@@ -1,8 +1,9 @@
/* ----------------------------------------------------------------------- *
*
- * Copyright 2003-2010 H. Peter Anvin - All Rights Reserved
+ * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
* Copyright 2010 Shao Miller
- * Copyright 2010 Michal Soltys
+ * Copyright 2010-2012 Michal Soltys
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -39,7 +40,6 @@
#include <stdarg.h>
#include <zlib.h>
#include <syslinux/disk.h>
-#include "common.h"
#include "partiter.h"
#include "utility.h"
@@ -47,175 +47,110 @@
#define ost_is_nondata(type) (ost_is_ext(type) || (type) == 0x00)
#define sane(s,l) ((s)+(l) > (s))
-/* forwards */
+/* virtual forwards */
-static int iter_ctor(struct part_iter *, va_list *);
-static int iter_dos_ctor(struct part_iter *, va_list *);
-static int iter_gpt_ctor(struct part_iter *, va_list *);
-static void iter_dtor(struct part_iter *);
-static struct part_iter *pi_dos_next(struct part_iter *);
-static struct part_iter *pi_gpt_next(struct part_iter *);
-static struct part_iter *pi_raw_next(struct part_iter *);
+static void pi_dtor_(struct part_iter *);
+static int pi_next_(struct part_iter *);
+static int pi_dos_next(struct part_iter *);
+static int pi_gpt_next(struct part_iter *);
+
+/* vtab and types */
static struct itertype types[] = {
[0] = {
- .ctor = &iter_dos_ctor,
- .dtor = &iter_dtor,
+ .dtor = &pi_dtor_,
.next = &pi_dos_next,
}, [1] = {
- .ctor = &iter_gpt_ctor,
- .dtor = &iter_dtor,
+ .dtor = &pi_dtor_,
.next = &pi_gpt_next,
}, [2] = {
- .ctor = &iter_ctor,
- .dtor = &iter_dtor,
- .next = &pi_raw_next,
+ .dtor = &pi_dtor_,
+ .next = &pi_next_,
}};
const struct itertype * const typedos = types;
const struct itertype * const typegpt = types+1;
const struct itertype * const typeraw = types+2;
-#ifdef DEBUG
-static int inv_type(const void *type)
+/* pi_dtor_() - common/raw iterator cleanup */
+static void pi_dtor_(struct part_iter *iter)
{
- int i, cnt = sizeof(types)/sizeof(types[0]);
- for (i = 0; i < cnt; i++) {
- if (type == types + i)
- return 0;
- }
- return -1;
+ /* syslinux's free is null resilient */
+ free(iter->data);
}
-#endif
-/**
- * iter_ctor() - common iterator initialization
- * @iter: iterator pointer
- * @args(0): disk_info structure used for disk functions
- * @args(1): stepall modifier
- *
- * Second and further arguments are passed as a pointer to va_list
- **/
-static int iter_ctor(struct part_iter *iter, va_list *args)
+/* pi_ctor() - common/raw iterator initialization */
+static int pi_ctor(struct part_iter *iter,
+ const struct disk_info *di, int flags
+)
{
- const struct disk_info *di = va_arg(*args, const struct disk_info *);
- int stepall = va_arg(*args, int);
-
-#ifdef DEBUG
- if (!di)
- return -1;
-#endif
-
- memcpy(&iter->di, di, sizeof(struct disk_info));
- iter->stepall = stepall;
+ memcpy(&iter->di, di, sizeof *di);
+ iter->flags = flags;
iter->index0 = -1;
iter->length = di->lbacnt;
+ iter->type = typeraw;
return 0;
}
-/**
- * iter_dtor() - common iterator cleanup
- * @iter: iterator pointer
- *
- **/
-static void iter_dtor(struct part_iter *iter)
+/* pi_dos_ctor() - MBR/EBR iterator specific initialization */
+static int pi_dos_ctor(struct part_iter *iter,
+ const struct disk_info *di, int flags,
+ const struct disk_dos_mbr *mbr
+)
{
- free(iter->data);
-}
-
-/**
- * iter_dos_ctor() - MBR/EBR iterator specific initialization
- * @iter: iterator pointer
- * @args(0): disk_info structure used for disk functions
- * @args(1): pointer to buffer with loaded valid MBR
- *
- * Second and further arguments are passed as a pointer to va_list.
- * This function only makes rudimentary checks. If user uses
- * pi_new(), he/she is responsible for doing proper sanity checks.
- **/
-static int iter_dos_ctor(struct part_iter *iter, va_list *args)
-{
- const struct disk_dos_mbr *mbr;
-
- /* uses args(0) */
- if (iter_ctor(iter, args))
+ if (pi_ctor(iter, di, flags))
return -1;
- mbr = va_arg(*args, const struct disk_dos_mbr *);
-
-#ifdef DEBUG
- if (!mbr)
- goto bail;
-#endif
-
- if (!(iter->data = malloc(sizeof(struct disk_dos_mbr))))
+ if (!(iter->data = malloc(sizeof *mbr))) {
+ critm();
goto bail;
+ }
- memcpy(iter->data, mbr, sizeof(struct disk_dos_mbr));
+ memcpy(iter->data, mbr, sizeof *mbr);
- iter->sub.dos.bebr_index0 = -1;
- iter->sub.dos.disk_sig = mbr->disk_sig;
+ iter->dos.bebr_index0 = -1;
+ iter->dos.disk_sig = mbr->disk_sig;
+ iter->type = typedos;
return 0;
bail:
- iter->type->dtor(iter);
+ pi_dtor_(iter);
return -1;
}
-/**
- * iter_gpt_ctor() - GPT iterator specific initialization
- * @iter: iterator pointer
- * @args(0): ptr to disk_info structure
- * @args(1): ptr to buffer with GPT header
- * @args(2): ptr to buffer with GPT partition list
- *
- * Second and further arguments are passed as a pointer to va_list.
- * This function only makes rudimentary checks. If user uses
- * pi_new(), he/she is responsible for doing proper sanity checks.
- **/
-static int iter_gpt_ctor(struct part_iter *iter, va_list *args)
+/* pi_gpt_ctor() - GPT iterator specific initialization */
+static int pi_gpt_ctor(struct part_iter *iter,
+ const struct disk_info *di, int flags,
+ const struct disk_gpt_header *gpth, const struct disk_gpt_part_entry *gptl
+)
{
uint64_t siz;
- const struct disk_gpt_header *gpth;
- const struct disk_gpt_part_entry *gptl;
- /* uses args(0) */
- if (iter_ctor(iter, args))
+ if (pi_ctor(iter, di, flags))
return -1;
- gpth = va_arg(*args, const struct disk_gpt_header *);
- gptl = va_arg(*args, const struct disk_gpt_part_entry *);
-
-#ifdef DEBUG
- if (!gpth || !gptl)
- goto bail;
-#endif
-
siz = (uint64_t)gpth->part_count * gpth->part_size;
-#ifdef DEBUG
- if (!siz || (siz + iter->di.bps - 1) / iter->di.bps > 255u ||
- gpth->part_size < sizeof(struct disk_gpt_part_entry)) {
+ if (!(iter->data = malloc((size_t)siz))) {
+ critm();
goto bail;
}
-#endif
-
- if (!(iter->data = malloc((size_t)siz)))
- goto bail;
memcpy(iter->data, gptl, (size_t)siz);
- iter->sub.gpt.pe_count = (int)gpth->part_count;
- iter->sub.gpt.pe_size = (int)gpth->part_size;
- iter->sub.gpt.ufirst = gpth->lba_first_usable;
- iter->sub.gpt.ulast = gpth->lba_last_usable;
+ iter->gpt.pe_count = (int)gpth->part_count;
+ iter->gpt.pe_size = (int)gpth->part_size;
+ iter->gpt.ufirst = gpth->lba_first_usable;
+ iter->gpt.ulast = gpth->lba_last_usable;
- memcpy(&iter->sub.gpt.disk_guid, &gpth->disk_guid, sizeof(struct guid));
+ memcpy(&iter->gpt.disk_guid, &gpth->disk_guid, sizeof gpth->disk_guid);
+ memcpy(&iter->gpt.part_guid, &gpth->disk_guid, sizeof gpth->disk_guid);
+ iter->type = typegpt;
return 0;
bail:
- iter->type->dtor(iter);
+ pi_dtor_(iter);
return -1;
}
@@ -237,18 +172,21 @@ static int notsane_logical(const struct part_iter *iter)
return 0;
if (ost_is_ext(dp[0].ostype)) {
- error("1st EBR entry must be data or empty.\n");
+ error("The 1st EBR entry must be data or empty.");
return -1;
}
+ if (iter->flags & PIF_RELAX)
+ return 0;
+
end_log = dp[0].start_lba + dp[0].length;
if (!dp[0].start_lba ||
!dp[0].length ||
!sane(dp[0].start_lba, dp[0].length) ||
- end_log > iter->sub.dos.ebr_size) {
+ end_log > iter->dos.nebr_siz) {
- error("Insane logical partition.\n");
+ error("Logical partition (in EBR) with invalid offset and/or length.");
return -1;
}
@@ -273,18 +211,21 @@ static int notsane_extended(const struct part_iter *iter)
return 0;
if (!ost_is_nondata(dp[1].ostype)) {
- error("2nd EBR entry must be extended or empty.\n");
+ error("The 2nd EBR entry must be extended or empty.");
return -1;
}
+ if (iter->flags & PIF_RELAX)
+ return 0;
+
end_ebr = dp[1].start_lba + dp[1].length;
if (!dp[1].start_lba ||
!dp[1].length ||
!sane(dp[1].start_lba, dp[1].length) ||
- end_ebr > iter->sub.dos.bebr_size) {
+ end_ebr > iter->dos.bebr_siz) {
- error("Insane extended partition.\n");
+ error("Extended partition (EBR) with invalid offset and/or length.");
return -1;
}
@@ -304,11 +245,14 @@ static int notsane_primary(const struct part_iter *iter)
if (!dp->ostype)
return 0;
+ if (iter->flags & PIF_RELAX)
+ return 0;
+
if (!dp->start_lba ||
!dp->length ||
!sane(dp->start_lba, dp->length) ||
dp->start_lba + dp->length > iter->di.lbacnt) {
- error("Insane primary (MBR) partition.\n");
+ error("Primary partition (in MBR) with invalid offset and/or length.");
return -1;
}
@@ -319,21 +263,24 @@ static int notsane_gpt(const struct part_iter *iter)
{
const struct disk_gpt_part_entry *gp;
gp = (const struct disk_gpt_part_entry *)
- (iter->data + iter->index0 * iter->sub.gpt.pe_size);
+ (iter->data + iter->index0 * iter->gpt.pe_size);
if (guid_is0(&gp->type))
return 0;
- if (gp->lba_first < iter->sub.gpt.ufirst ||
- gp->lba_last > iter->sub.gpt.ulast) {
- error("Insane GPT partition.\n");
+ if (iter->flags & PIF_RELAX)
+ return 0;
+
+ if (gp->lba_first < iter->gpt.ufirst ||
+ gp->lba_last > iter->gpt.ulast) {
+ error("LBA sectors of GPT partition are beyond the range allowed in GPT header.");
return -1;
}
return 0;
}
-static int pi_dos_next_mbr(struct part_iter *iter, uint32_t *lba,
+static int dos_next_mbr(struct part_iter *iter, uint32_t *lba,
struct disk_dos_part_entry **_dp)
{
struct disk_dos_part_entry *dp;
@@ -343,19 +290,19 @@ static int pi_dos_next_mbr(struct part_iter *iter, uint32_t *lba,
if (notsane_primary(iter)) {
iter->status = PI_INSANE;
- goto bail;
+ return -1;
}
if (ost_is_ext(dp->ostype)) {
- if (iter->sub.dos.bebr_index0 >= 0) {
- error("You have more than 1 extended partition.\n");
+ if (iter->dos.bebr_index0 >= 0) {
+ error("More than 1 extended partition.");
iter->status = PI_INSANE;
- goto bail;
+ return -1;
}
/* record base EBR index */
- iter->sub.dos.bebr_index0 = iter->index0;
+ iter->dos.bebr_index0 = iter->index0;
}
- if (!ost_is_nondata(dp->ostype) || iter->stepall) {
+ if (!ost_is_nondata(dp->ostype) || (iter->flags & PIF_STEPALL)) {
*lba = dp->start_lba;
*_dp = dp;
break;
@@ -363,52 +310,48 @@ static int pi_dos_next_mbr(struct part_iter *iter, uint32_t *lba,
}
return 0;
-bail:
- return -1;
}
static int prep_base_ebr(struct part_iter *iter)
{
struct disk_dos_part_entry *dp;
- if (iter->sub.dos.bebr_index0 < 0) /* if we don't have base extended partition at all */
+ if (iter->dos.bebr_index0 < 0) /* if we don't have base extended partition at all */
return -1;
- else if (!iter->sub.dos.bebr_start) { /* if not initialized yet */
- dp = ((struct disk_dos_mbr *)iter->data)->table + iter->sub.dos.bebr_index0;
-
- iter->sub.dos.bebr_start = dp->start_lba;
- iter->sub.dos.bebr_size = dp->length;
+ else if (!iter->dos.bebr_lba) { /* if not initialized yet */
+ dp = ((struct disk_dos_mbr *)iter->data)->table + iter->dos.bebr_index0;
- iter->sub.dos.ebr_start = 0;
- iter->sub.dos.ebr_size = iter->sub.dos.bebr_size;
+ iter->dos.bebr_lba = dp->start_lba;
+ iter->dos.bebr_siz = dp->length;
- iter->sub.dos.cebr_lba = 0;
- iter->sub.dos.nebr_lba = iter->sub.dos.bebr_start;
+ iter->dos.nebr_lba = dp->start_lba;
+ iter->dos.nebr_siz = dp->length;
iter->index0--;
}
return 0;
}
-static int pi_dos_next_ebr(struct part_iter *iter, uint32_t *lba,
+static int dos_next_ebr(struct part_iter *iter, uint32_t *lba,
struct disk_dos_part_entry **_dp)
{
struct disk_dos_part_entry *dp;
- if (prep_base_ebr(iter)) {
+ if (prep_base_ebr(iter) < 0) {
iter->status = PI_DONE;
return -1;
}
- while (++iter->index0 < 1024 && iter->sub.dos.nebr_lba) {
+ while (++iter->index0 < 1024 && iter->dos.nebr_lba) {
free(iter->data);
if (!(iter->data =
- disk_read_sectors(&iter->di, iter->sub.dos.nebr_lba, 1))) {
- error("Couldn't load EBR.\n");
+ disk_read_sectors(&iter->di, iter->dos.nebr_lba, 1))) {
+ error("Couldn't load EBR.");
iter->status = PI_ERRLOAD;
return -1;
}
+ /* check sanity of loaded data */
if (notsane_logical(iter) || notsane_extended(iter)) {
iter->status = PI_INSANE;
return -1;
@@ -416,24 +359,23 @@ static int pi_dos_next_ebr(struct part_iter *iter, uint32_t *lba,
dp = ((struct disk_dos_mbr *)iter->data)->table;
- iter->sub.dos.cebr_lba = iter->sub.dos.nebr_lba;
+ iter->dos.cebr_lba = iter->dos.nebr_lba;
+ iter->dos.cebr_siz = iter->dos.nebr_siz;
/* setup next frame values */
if (dp[1].ostype) {
- iter->sub.dos.ebr_start = dp[1].start_lba;
- iter->sub.dos.ebr_size = dp[1].length;
- iter->sub.dos.nebr_lba = iter->sub.dos.bebr_start + dp[1].start_lba;
+ iter->dos.nebr_lba = iter->dos.bebr_lba + dp[1].start_lba;
+ iter->dos.nebr_siz = dp[1].length;
} else {
- iter->sub.dos.ebr_start = 0;
- iter->sub.dos.ebr_size = 0;
- iter->sub.dos.nebr_lba = 0;
+ iter->dos.nebr_lba = 0;
+ iter->dos.nebr_siz = 0;
}
if (!dp[0].ostype)
- iter->sub.dos.skipcnt++;
+ iter->dos.logskipcnt++;
- if (dp[0].ostype || iter->stepall) {
- *lba = iter->sub.dos.cebr_lba + dp[0].start_lba;
+ if (dp[0].ostype || (iter->flags & PIF_STEPALL)) {
+ *lba = dp[0].start_lba ? iter->dos.cebr_lba + dp[0].start_lba : 0;
*_dp = dp;
return 0;
}
@@ -441,128 +383,33 @@ static int pi_dos_next_ebr(struct part_iter *iter, uint32_t *lba,
* This way it's possible to continue, if some crazy soft left a "hole"
* - EBR with a valid extended partition without a logical one. In
* such case, linux will not reserve a number for such hole - so we
- * don't increase index0. If stepall flag is set, we will never reach
- * this place.
+ * don't increase index0. If PIF_STEPALL flag is set, we will never
+ * reach this place.
*/
}
iter->status = PI_DONE;
return -1;
}
-static struct part_iter *pi_dos_next(struct part_iter *iter)
-{
- uint32_t start_lba = 0;
- struct disk_dos_part_entry *dos_part = NULL;
-
- if (iter->status)
- goto bail;
-
- /* look for primary partitions */
- if (iter->index0 < 4 &&
- pi_dos_next_mbr(iter, &start_lba, &dos_part))
- goto bail;
-
- /* look for logical partitions */
- if (iter->index0 >= 4 &&
- pi_dos_next_ebr(iter, &start_lba, &dos_part))
- goto bail;
-
- /*
- * note special index handling, if we have stepall set -
- * this is made to keep index consistent with non-stepall
- * iterators
- */
-
- if (iter->index0 >= 4 && !dos_part->ostype)
- iter->index = -1;
- else
- iter->index = iter->index0 - iter->sub.dos.skipcnt + 1;
- iter->rawindex = iter->index0 + 1;
- iter->start_lba = start_lba;
- iter->length = dos_part->length;
- iter->record = (char *)dos_part;
-
-#ifdef DEBUG
- disk_dos_part_dump(dos_part);
-#endif
-
- return iter;
-bail:
- return NULL;
-}
-
static void gpt_conv_label(struct part_iter *iter)
{
const struct disk_gpt_part_entry *gp;
const int16_t *orig_lab;
gp = (const struct disk_gpt_part_entry *)
- (iter->data + iter->index0 * iter->sub.gpt.pe_size);
+ (iter->data + iter->index0 * iter->gpt.pe_size);
orig_lab = (const int16_t *)gp->name;
/* caveat: this is very crude conversion */
for (int i = 0; i < PI_GPTLABSIZE/2; i++) {
- iter->sub.gpt.part_label[i] = (char)orig_lab[i];
- }
- iter->sub.gpt.part_label[PI_GPTLABSIZE/2] = 0;
-}
-
-static struct part_iter *pi_gpt_next(struct part_iter *iter)
-{
- const struct disk_gpt_part_entry *gpt_part = NULL;
-
- if (iter->status)
- goto bail;
-
- while (++iter->index0 < iter->sub.gpt.pe_count) {
- gpt_part = (const struct disk_gpt_part_entry *)
- (iter->data + iter->index0 * iter->sub.gpt.pe_size);
-
- if (notsane_gpt(iter)) {
- iter->status = PI_INSANE;
- goto bail;
- }
-
- if (!guid_is0(&gpt_part->type) || iter->stepall)
- break;
- }
- /* no more partitions ? */
- if (iter->index0 == iter->sub.gpt.pe_count) {
- iter->status = PI_DONE;
- goto bail;
+ iter->gpt.part_label[i] = (char)orig_lab[i];
}
- /* gpt_part is guaranteed to be valid here */
- iter->index = iter->index0 + 1;
- iter->rawindex = iter->index0 + 1;
- iter->start_lba = gpt_part->lba_first;
- iter->length = gpt_part->lba_last - gpt_part->lba_first + 1;
- iter->record = (char *)gpt_part;
- memcpy(&iter->sub.gpt.part_guid, &gpt_part->uid, sizeof(struct guid));
- gpt_conv_label(iter);
-
-#ifdef DEBUG
- disk_gpt_part_dump(gpt_part);
-#endif
-
- return iter;
-bail:
- return NULL;
-}
-
-static struct part_iter *pi_raw_next(struct part_iter *iter)
-{
- iter->status = PI_DONE;
- return NULL;
+ iter->gpt.part_label[PI_GPTLABSIZE/2] = 0;
}
-static int check_crc(uint32_t crc_match, const uint8_t *buf, unsigned int siz)
+static inline int valid_crc(uint32_t crc, const uint8_t *buf, unsigned int siz)
{
- uint32_t crc;
-
- crc = crc32(0, NULL, 0);
- crc = crc32(crc, buf, siz);
-
- return crc_match != crc;
+ return crc == crc32(crc32(0, NULL, 0), buf, siz);
}
static int gpt_check_hdr_crc(const struct disk_info * const diskinfo, struct disk_gpt_header **_gh)
@@ -573,19 +420,19 @@ static int gpt_check_hdr_crc(const struct disk_info * const diskinfo, struct dis
hold_crc32 = gh->chksum;
gh->chksum = 0;
- if (check_crc(hold_crc32, (const uint8_t *)gh, gh->hdr_size)) {
- error("WARNING: Primary GPT header checksum invalid.\n");
+ if (!valid_crc(hold_crc32, (const uint8_t *)gh, gh->hdr_size)) {
+ warn("Primary GPT header checksum invalid.");
/* retry with backup */
lba_alt = gh->lba_alt;
free(gh);
if (!(gh = *_gh = disk_read_sectors(diskinfo, lba_alt, 1))) {
- error("Couldn't read backup GPT header.\n");
+ error("Couldn't read backup GPT header.");
return -1;
}
hold_crc32 = gh->chksum;
gh->chksum = 0;
- if (check_crc(hold_crc32, (const uint8_t *)gh, gh->hdr_size)) {
- error("Secondary GPT header checksum invalid.\n");
+ if (!valid_crc(hold_crc32, (const uint8_t *)gh, gh->hdr_size)) {
+ error("Secondary GPT header checksum invalid.");
return -1;
}
}
@@ -595,149 +442,156 @@ static int gpt_check_hdr_crc(const struct disk_info * const diskinfo, struct dis
return 0;
}
-/*
- * ----------------------------------------------------------------------------
- * Following functions are for users to call.
- * ----------------------------------------------------------------------------
- */
-
+static int pi_next_(struct part_iter *iter)
+{
+ iter->status = PI_DONE;
+ return iter->status;
+}
-int pi_next(struct part_iter **_iter)
+static int pi_dos_next(struct part_iter *iter)
{
- struct part_iter *iter;
+ uint32_t abs_lba = 0;
+ struct disk_dos_part_entry *dos_part = NULL;
+
+ if (iter->status)
+ return iter->status;
+
+ /* look for primary partitions */
+ if (iter->index0 < 4 &&
+ dos_next_mbr(iter, &abs_lba, &dos_part) < 0)
+ return iter->status;
+
+ /* look for logical partitions */
+ if (iter->index0 >= 4 &&
+ dos_next_ebr(iter, &abs_lba, &dos_part) < 0)
+ return iter->status;
+
+ /*
+ * note special index handling:
+ * in case PIF_STEPALL is set - this makes the index consistent with
+ * non-PIF_STEPALL iterators
+ */
+
+ if (!dos_part->ostype)
+ iter->index = -1;
+ else
+ iter->index = iter->index0 + 1 - iter->dos.logskipcnt;
+ iter->abs_lba = abs_lba;
+ iter->length = dos_part->length;
+ iter->record = (char *)dos_part;
- if(!_iter || !*_iter)
- return 0;
- iter = *_iter;
#ifdef DEBUG
- if (inv_type(iter->type)) {
- error("This is not a valid iterator.\n");
- return 0;
- }
+ disk_dos_part_dump(dos_part);
#endif
- if ((iter = iter->type->next(iter))) {
- *_iter = iter;
- }
- return (*_iter)->status;
+
+ return iter->status;
}
-/**
- * pi_new() - get new iterator
- * @itertype: iterator type
- * @...: variable arguments passed to ctors
- *
- * Variable arguments depend on the type. Please see functions:
- * iter_gpt_ctor() and iter_dos_ctor() for details.
- **/
-struct part_iter *pi_new(const struct itertype *type, ...)
+static int pi_gpt_next(struct part_iter *iter)
{
- int badctor = 0;
- struct part_iter *iter = NULL;
- va_list ap;
+ const struct disk_gpt_part_entry *gpt_part = NULL;
- va_start(ap, type);
+ if (iter->status)
+ return iter->status;
-#ifdef DEBUG
- if (inv_type(type)) {
- error("Unknown iterator requested.\n");
- goto bail;
- }
-#endif
+ while (++iter->index0 < iter->gpt.pe_count) {
+ gpt_part = (const struct disk_gpt_part_entry *)
+ (iter->data + iter->index0 * iter->gpt.pe_size);
- if (!(iter = malloc(sizeof(struct part_iter)))) {
- error("Couldn't allocate memory for the iterator.\n");
- goto bail;
+ if (notsane_gpt(iter)) {
+ iter->status = PI_INSANE;
+ return iter->status;
+ }
+
+ if (!guid_is0(&gpt_part->type) || (iter->flags & PIF_STEPALL))
+ break;
}
+ /* no more partitions ? */
+ if (iter->index0 == iter->gpt.pe_count) {
+ iter->status = PI_DONE;
+ return iter->status;
+ }
+ /* gpt_part is guaranteed to be valid here */
+ iter->index = iter->index0 + 1;
+ iter->abs_lba = gpt_part->lba_first;
+ iter->length = gpt_part->lba_last - gpt_part->lba_first + 1;
+ iter->record = (char *)gpt_part;
+ memcpy(&iter->gpt.part_guid, &gpt_part->uid, sizeof(struct guid));
+ gpt_conv_label(iter);
- memset(iter, 0, sizeof(struct part_iter));
- iter->type = type;
+#ifdef DEBUG
+ disk_gpt_part_dump(gpt_part);
+#endif
- if (type->ctor(iter, &ap)) {
- badctor = -1;
- error("Cannot initialize the iterator.\n");
- goto bail;
- }
+ return iter->status;
+}
-bail:
- va_end(ap);
- if (badctor) {
- free(iter);
- iter = NULL;
- }
+static struct part_iter *pi_alloc(void)
+{
+ struct part_iter *iter;
+ if (!(iter = malloc(sizeof *iter)))
+ critm();
+ else
+ memset(iter, 0, sizeof *iter);
return iter;
}
-/**
- * pi_del() - delete iterator
- * @iter: iterator double pointer
- *
- **/
-
+/* pi_del() - delete iterator */
void pi_del(struct part_iter **_iter)
{
- struct part_iter *iter;
-
if(!_iter || !*_iter)
return;
- iter = *_iter;
-
-#ifdef DEBUG
- if (inv_type(iter->type)) {
- error("This is not a valid iterator.\n");
- return;
- }
-#endif
-
- iter->type->dtor(iter);
- free(iter);
+ pi_dtor(*_iter);
+ free(*_iter);
*_iter = NULL;
}
-/**
- * pi_begin() - check disk, validate, and get proper iterator
- * @di: diskinfo struct pointer
- *
- * This function checks the disk for GPT or legacy partition table and allocates
- * an appropriate iterator.
- **/
-struct part_iter *pi_begin(const struct disk_info *di, int stepall)
+/* pi_begin() - validate and and get proper iterator for a disk described by di */
+struct part_iter *pi_begin(const struct disk_info *di, int flags)
{
- int setraw = 0;
- struct part_iter *iter = NULL;
+ int gptprot, ret = -1;
+ struct part_iter *iter;
struct disk_dos_mbr *mbr = NULL;
struct disk_gpt_header *gpth = NULL;
struct disk_gpt_part_entry *gptl = NULL;
+ /* Preallocate iterator */
+ if (!(iter = pi_alloc()))
+ goto bail;
+
/* Read MBR */
if (!(mbr = disk_read_sectors(di, 0, 1))) {
- error("Couldn't read first disk sector.\n");
+ error("Couldn't read the first disk sector.");
goto bail;
}
- setraw = -1;
-
- /* Check for MBR magic*/
+ /* Check for MBR magic */
if (mbr->sig != disk_mbr_sig_magic) {
- error("No MBR magic.\n");
+ warn("No MBR magic, treating disk as raw.");
+ /* looks like RAW */
+ ret = pi_ctor(iter, di, flags);
goto bail;
}
/* Check for GPT protective MBR */
- if (mbr->table[0].ostype == 0xEE) {
+ gptprot = 0;
+ for (size_t i = 0; i < 4; i++)
+ gptprot |= (mbr->table[i].ostype == 0xEE);
+ if (gptprot && !(flags & PIF_PREFMBR)) {
if (!(gpth = disk_read_sectors(di, 1, 1))) {
- error("Couldn't read potential GPT header.\n");
+ error("Couldn't read potential GPT header.");
goto bail;
}
}
if (gpth && gpth->rev.uint32 == 0x00010000 &&
- !memcmp(gpth->sig, disk_gpt_sig_magic, sizeof(disk_gpt_sig_magic))) {
+ !memcmp(gpth->sig, disk_gpt_sig_magic, sizeof gpth->sig)) {
/* looks like GPT v1.0 */
uint64_t gpt_loff; /* offset to GPT partition list in sectors */
uint64_t gpt_lsiz; /* size of GPT partition list in bytes */
uint64_t gpt_lcnt; /* size of GPT partition in sectors */
#ifdef DEBUG
- puts("Looks like a GPT v1.0 disk.");
+ dprintf("Looks like a GPT v1.0 disk.\n");
disk_gpt_header_dump(gpth);
#endif
/* Verify checksum, fallback to backup, then bail if invalid */
@@ -753,48 +607,45 @@ struct part_iter *pi_begin(const struct disk_info *di, int stepall)
* it as a sanity check base. EFI doesn't specify max (AFAIK).
* Apart from that, some extensive sanity checks.
*/
- if (!gpt_loff || !gpt_lsiz || gpt_lcnt > 255u ||
+ if (!(flags & PIF_RELAX) && (
+ !gpt_loff || !gpt_lsiz || gpt_lcnt > 255u ||
gpth->lba_first_usable > gpth->lba_last_usable ||
!sane(gpt_loff, gpt_lcnt) ||
gpt_loff + gpt_lcnt > gpth->lba_first_usable ||
!sane(gpth->lba_last_usable, gpt_lcnt) ||
gpth->lba_last_usable + gpt_lcnt >= gpth->lba_alt ||
gpth->lba_alt >= di->lbacnt ||
- gpth->part_size < sizeof(struct disk_gpt_part_entry)) {
- error("Invalid GPT header's values.\n");
+ gpth->part_size < sizeof *gptl)) {
+ error("Invalid GPT header's values.");
goto bail;
}
- if (!(gptl = disk_read_sectors(di, gpt_loff, (uint8_t)gpt_lcnt))) {
- error("Couldn't read GPT partition list.\n");
+ if (!(gptl = disk_read_sectors(di, gpt_loff, gpt_lcnt))) {
+ error("Couldn't read GPT partition list.");
goto bail;
}
/* Check array checksum(s). */
- if (check_crc(gpth->table_chksum, (const uint8_t *)gptl, (unsigned int)gpt_lsiz)) {
- error("WARNING: GPT partition list checksum invalid, trying backup.\n");
+ if (!valid_crc(gpth->table_chksum, (const uint8_t *)gptl, (unsigned int)gpt_lsiz)) {
+ warn("Checksum of the main GPT partition list is invalid, trying backup.");
free(gptl);
/* secondary array directly precedes secondary header */
- if (!(gptl = disk_read_sectors(di, gpth->lba_alt - gpt_lcnt, (uint8_t)gpt_lcnt))) {
- error("Couldn't read backup GPT partition list.\n");
+ if (!(gptl = disk_read_sectors(di, gpth->lba_alt - gpt_lcnt, gpt_lcnt))) {
+ error("Couldn't read backup GPT partition list.");
goto bail;
}
- if (check_crc(gpth->table_chksum, (const uint8_t *)gptl, (unsigned int)gpt_lsiz)) {
- error("Backup GPT partition list checksum invalid.\n");
+ if (!valid_crc(gpth->table_chksum, (const uint8_t *)gptl, gpt_lsiz)) {
+ error("Checksum of the backup GPT partition list is invalid, giving up.");
goto bail;
}
}
- /* allocate iterator and exit */
- iter = pi_new(typegpt, di, stepall, gpth, gptl);
+ /* looks like GPT */
+ ret = pi_gpt_ctor(iter, di, flags, gpth, gptl);
} else {
/* looks like MBR */
- iter = pi_new(typedos, di, stepall, mbr);
+ ret = pi_dos_ctor(iter, di, flags, mbr);
}
-
- setraw = 0;
bail:
- if (setraw) {
- error("WARNING: treating disk as raw.\n");
- iter = pi_new(typeraw, di, stepall);
- }
+ if (ret < 0)
+ free(iter);
free(mbr);
free(gpth);
free(gptl);
diff --git a/com32/chain/partiter.h b/com32/chain/partiter.h
index 7deeb534..13dec848 100644
--- a/com32/chain/partiter.h
+++ b/com32/chain/partiter.h
@@ -1,8 +1,9 @@
/* ----------------------------------------------------------------------- *
*
- * Copyright 2003-2010 H. Peter Anvin - All Rights Reserved
- * Copyright 2010 Michal Soltys
+ * 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
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -33,24 +34,26 @@
* Provides disk / partition iteration.
*/
-#ifndef _COM32_CHAIN_PARTITER_H
-#define _COM32_CHAIN_PARTITER_H
+#ifndef COM32_CHAIN_PARTITER_H
+#define COM32_CHAIN_PARTITER_H
#include <stdint.h>
#include <syslinux/disk.h>
-#define PI_ERRLOAD 3
-#define PI_INSANE 2
-#define PI_DONE 1
-#define PI_OK 0
+/* status */
+
+enum {PI_OK, PI_DONE, PI_INSANE, PI_ERRLOAD};
+
+/* flags */
+
+enum {PIF_STEPALL = 1, PIF_RELAX = 2, PIF_PREFMBR = 4};
struct itertype;
struct part_iter;
struct itertype {
- int (*ctor)(struct part_iter *, va_list *);
void (*dtor)(struct part_iter *);
- struct part_iter *(*next) (struct part_iter *);
+ int (*next)(struct part_iter *);
};
#define PI_GPTLABSIZE ((int)sizeof(((struct disk_gpt_part_entry *)0)->name))
@@ -59,29 +62,29 @@ struct part_iter {
const struct itertype *type;
char *data;
char *record;
- uint64_t start_lba;
+ uint64_t abs_lba;
uint64_t length;
- int index;
- int rawindex;
+ int index0; /* including holes, from -1 (disk, then parts from 0) */
+ int index; /* excluding holes, from 0 (disk, then parts from 1), -1 means hole, if PIF_STEPALL is set */
+ int flags; /* flags, see #defines above */
+ int status; /* current status, see enums above */
struct disk_info di;
- int stepall;
- int status;
- /* internal */
- int index0;
- union _sub {
- struct _dos {
- uint32_t disk_sig;
- uint32_t nebr_lba;
- uint32_t cebr_lba;
- /* internal */
- uint32_t ebr_start;
- uint32_t ebr_size;
- uint32_t bebr_start;
- uint32_t bebr_size;
- int bebr_index0;
- int skipcnt;
+ union {
+ struct {
+ uint32_t disk_sig; /* 32bit disk signature as stored in MBR */
+
+ uint32_t bebr_lba; /* absolute lba of base extended partition */
+ uint32_t bebr_siz; /* size of base extended partition */
+
+ uint32_t cebr_lba; /* absolute lba of curr ext. partition */
+ uint32_t cebr_siz; /* size of curr ext. partition */
+ uint32_t nebr_lba; /* absolute lba of next ext. partition */
+ uint32_t nebr_siz; /* size of next ext. partition */
+
+ int bebr_index0; /* index of (0-3) of base ext. part., -1 if not present in MBR */
+ int logskipcnt; /* how many logical holes were skipped */
} dos;
- struct _gpt {
+ struct {
struct guid disk_guid;
struct guid part_guid;
char part_label[PI_GPTLABSIZE/2+1];
@@ -90,17 +93,31 @@ struct part_iter {
uint64_t ufirst;
uint64_t ulast;
} gpt;
- } sub;
+ };
};
extern const struct itertype * const typedos;
extern const struct itertype * const typegpt;
extern const struct itertype * const typeraw;
-struct part_iter *pi_begin(const struct disk_info *, int stepall);
-struct part_iter *pi_new(const struct itertype *, ...);
+struct part_iter *pi_begin(const struct disk_info *, int flags);
void pi_del(struct part_iter **);
-int pi_next(struct part_iter **);
+
+static inline int pi_errored(struct part_iter *iter)
+{
+ return iter->status > PI_DONE;
+}
+
+/* inline virtuals */
+static inline int pi_next(struct part_iter *iter)
+{
+ return iter->type->next(iter);
+}
+
+static inline void pi_dtor(struct part_iter *iter)
+{
+ iter->type->dtor(iter);
+}
#endif
diff --git a/com32/chain/utility.c b/com32/chain/utility.c
index cb882722..b17997f7 100644
--- a/com32/chain/utility.c
+++ b/com32/chain/utility.c
@@ -1,4 +1,35 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
#include <com32.h>
+#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <errno.h>
@@ -18,18 +49,9 @@ static const char *bpbtypes[] = {
[5] = "4.0",
[6] = "8.0 (NT+)",
[7] = "7.0",
+ [8] = "exFAT",
};
-void error(const char *msg)
-{
- fputs(msg, stderr);
-}
-
-int guid_is0(const struct guid *guid)
-{
- return !*(const uint64_t *)guid && !*((const uint64_t *)guid + 1);
-}
-
void wait_key(void)
{
int cnt;
@@ -48,7 +70,29 @@ void wait_key(void)
} while (!cnt || (cnt < 0 && errno == EAGAIN));
}
-void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, uint32_t mode)
+int guid_is0(const struct guid *guid)
+{
+ return
+ !(guid->data1 ||
+ guid->data2 ||
+ guid->data3 ||
+ guid->data4);
+}
+
+/*
+ * mode explanation:
+ *
+ * cnul - "strict" mode, never returning higher value than obtained from cbios
+ * cadd - if the disk is larger than reported geometry /and/ if the geometry has
+ * less cylinders than 1024 - it means that the total size is somewhere
+ * between cs and cs+1; in this particular case, we bump the cs to be able
+ * to return matching chs triplet
+ * cmax - assume we can use any cylinder value
+ *
+ * by default cadd seems most reasonable, giving consistent results with e.g.
+ * sfdisk's behavior
+ */
+void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, int mode)
{
uint32_t c, h, s, t;
uint32_t cs, hs, ss;
@@ -61,9 +105,10 @@ void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, uint32_t m
cs = di->cyl;
hs = di->head;
ss = di->spt;
- if (mode == l2c_cadd && cs < 1024 && di->lbacnt > cs*hs*ss)
- cs++;
- else if (mode == l2c_cmax)
+ if (mode == L2C_CADD) {
+ if (cs < 1024 && di->lbacnt > cs*hs*ss)
+ cs++;
+ } else if (mode == L2C_CMAX)
cs = 1024;
} else {
if (di->disk & 0x80) {
@@ -82,8 +127,8 @@ void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, uint32_t m
h = hs - 1;
c = cs - 1;
} else {
- s = ((uint32_t)lba % ss) + 1;
- t = (uint32_t)lba / ss;
+ s = (lba % ss) + 1;
+ t = lba / ss;
h = t % hs;
c = t / hs;
}
@@ -107,7 +152,7 @@ uint32_t get_file_lba(const char *filename)
/* Put the filename in the bounce buffer */
strlcpy(buf, filename, size);
- if (open_file(buf, &fd) <= 0) {
+ if (open_file(buf, O_RDONLY, &fd) <= 0) {
goto fail; /* Filename not found */
}
@@ -123,14 +168,15 @@ fail:
}
/* drive offset detection */
-int drvoff_detect(int type, unsigned int *off)
+int drvoff_detect(int type)
{
if (bpbV40 <= type && type <= bpbVNT) {
- *off = 0x24;
+ return 0x24;
} else if (type == bpbV70) {
- *off = 0x40;
- } else
- return 0;
+ return 0x40;
+ } else if (type == bpbEXF) {
+ return 0x6F;
+ }
return -1;
}
@@ -142,6 +188,12 @@ int bpb_detect(const uint8_t *sec, const char *tag)
{
int a, b, c, jmp = -1, rev = 0;
+ /* exFAT mess first (media descriptor is 0 here) */
+ if (!memcmp(sec + 0x03, "EXFAT ", 8)) {
+ rev = bpbEXF;
+ goto out;
+ }
+
/* media descriptor check */
if ((sec[0x15] & 0xF0) != 0xF0)
goto out;
diff --git a/com32/chain/utility.h b/com32/chain/utility.h
index 8a08be71..596017bb 100644
--- a/com32/chain/utility.h
+++ b/com32/chain/utility.h
@@ -1,29 +1,74 @@
-#ifndef _COM32_CHAIN_UTILITY_H
-#define _COM32_CHAIN_UTILITY_H
+/* ----------------------------------------------------------------------- *
+ *
+ * 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
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef COM32_CHAIN_UTILITY_H
+#define COM32_CHAIN_UTILITY_H
#include <stdint.h>
+#include <stdio.h>
#include <syslinux/disk.h>
+#include <syslinux/movebits.h>
-#define bpbUNK 0
-#define bpbV20 1
-#define bpbV30 2
-#define bpbV32 3
-#define bpbV34 4
-#define bpbV40 5
-#define bpbVNT 6
-#define bpbV70 7
+/* most (all ?) bpb "types" known to humankind as of 2012 */
+enum {bpbUNK, bpbV20, bpbV30, bpbV32, bpbV34, bpbV40, bpbVNT, bpbV70, bpbEXF};
-#define l2c_cnul 0
-#define l2c_cadd 1
-#define l2c_cmax 2
+/* see utility.c for details */
+enum {L2C_CNUL, L2C_CADD, L2C_CMAX};
+
+/* first usable and first unusable offsets */
+#define dosmin ((addr_t)0x500u)
+#define dosmax ((addr_t)(*(uint16_t *) 0x413 << 10))
-void error(const char *msg);
-int guid_is0(const struct guid *guid);
void wait_key(void);
-void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, uint32_t mode);
+void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, int mode);
uint32_t get_file_lba(const char *filename);
-int drvoff_detect(int type, unsigned int *off);
+int drvoff_detect(int type);
int bpb_detect(const uint8_t *bpb, const char *tag);
+int guid_is0(const struct guid *guid);
+
+static inline int warn(const char *x)
+{
+ return fprintf(stderr, "WARN: %s\n", x);
+}
+
+static inline int error(const char *x)
+{
+ return fprintf(stderr, "ERR: %s\n", x);
+}
+
+static inline int crit(const char *x)
+{
+ return fprintf(stderr, "CRIT: %s @%s:%d\n", x, __FILE__, __LINE__);
+}
+
+#define critm() crit("Malloc failure.")
#endif
diff --git a/com32/elflink/ldlinux/chainboot.c b/com32/elflink/ldlinux/chainboot.c
index ff19c530..27d4618c 100644
--- a/com32/elflink/ldlinux/chainboot.c
+++ b/com32/elflink/ldlinux/chainboot.c
@@ -15,6 +15,7 @@
* is BIOS-specific.
*/
+#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
@@ -53,7 +54,7 @@ void chainboot_file(const char *file, uint32_t type)
if (!buf)
goto bail;
- rv = open_file(file, &fd);
+ rv = open_file(file, O_RDONLY, &fd);
if (rv == -1)
goto bail;
diff --git a/com32/elflink/ldlinux/execute.c b/com32/elflink/ldlinux/execute.c
index 5c53b995..bf0bd8ce 100644
--- a/com32/elflink/ldlinux/execute.c
+++ b/com32/elflink/ldlinux/execute.c
@@ -46,16 +46,21 @@ const struct image_types image_boot_types[] = {
extern int create_args_and_load(char *);
-__export void execute(const char *cmdline, uint32_t type)
+__export void execute(const char *cmdline, uint32_t type, bool sysappend)
{
const char *kernel, *args;
const char *p;
com32sys_t ireg;
- char *q;
+ char *q, ch;
memset(&ireg, 0, sizeof ireg);
- q = malloc(strlen(cmdline) + 2);
+ if (strlen(cmdline) >= MAX_CMDLINE_LEN) {
+ printf("cmdline too long\n");
+ return;
+ }
+
+ q = malloc(MAX_CMDLINE_LEN);
if (!q) {
printf("%s(): Fail to malloc a buffer to exec %s\n",
__func__, cmdline);
@@ -72,7 +77,17 @@ __export void execute(const char *cmdline, uint32_t type)
while (*p && my_isspace(*p))
p++;
- strcpy(q, p);
+ do {
+ *q++ = ch = *p++;
+ } while (ch);
+
+ if (sysappend) {
+ /* If we've seen some args, insert a space */
+ if (--q != args)
+ *q++ = ' ';
+
+ do_sysappend(q);
+ }
dprintf("kernel is %s, args = %s type = %d \n", kernel, args, type);
@@ -86,13 +101,14 @@ __export void execute(const char *cmdline, uint32_t type)
* filename extension if COM32 and
* retry.
*/
+ p = args;
if (t->type == IMAGE_TYPE_COM32) {
p = apply_extension(p, ".c32");
if (!p)
return;
}
- execute(p, t->type);
+ execute(p, t->type, sysappend);
return;
}
}
@@ -122,17 +138,23 @@ __export void execute(const char *cmdline, uint32_t type)
ldlinux_enter_command();
} else if (type == IMAGE_TYPE_CONFIG) {
- char *argv[] = { "ldlinux.c32", NULL };
+ char *argv[] = { "ldlinux.c32", NULL, NULL };
+ char *config;
int rv;
/* kernel contains the config file name */
- realpath(ConfigName, kernel, FILENAME_MAX);
+ config = malloc(FILENAME_MAX);
+ if (!config)
+ goto out;
+
+ realpath(config, kernel, FILENAME_MAX);
/* If we got anything on the command line, do a chdir */
if (*args)
mangle_name(config_cwd, args);
- rv = start_ldlinux(argv);
+ argv[1] = config;
+ rv = start_ldlinux(2, argv);
printf("Failed to exec ldlinux.c32: %s\n", strerror(rv));
} else if (type == IMAGE_TYPE_LOCALBOOT) {
local_boot(strtoul(kernel, NULL, 0));
@@ -142,9 +164,10 @@ __export void execute(const char *cmdline, uint32_t type)
} else {
/* Need add one item for kernel load, as we don't use
* the assembly runkernel.inc any more */
- new_linux_kernel((char *)kernel, (char *)cmdline);
+ new_linux_kernel((char *)kernel, (char *)args);
}
+out:
free((void *)kernel);
/* If this returns, something went bad; return to menu */
diff --git a/com32/elflink/ldlinux/kernel.c b/com32/elflink/ldlinux/kernel.c
index 920246fc..f3ba37fa 100644
--- a/com32/elflink/ldlinux/kernel.c
+++ b/com32/elflink/ldlinux/kernel.c
@@ -35,14 +35,10 @@ int new_linux_kernel(char *okernel, char *ocmdline)
else if (append)
args = append;
- cmdline_len = strlen(kernel_name);
- if (args) {
- /* +1 for the space (' ') between kernel and args */
- cmdline_len += strlen(args) + 1;
- }
-
- /* +1 for NUL termination */
- cmdline_len++;
+ cmdline_len = strlen("BOOT_IMAGE=") + strlen(kernel_name);
+ cmdline_len += 1; /* space between BOOT_IMAGE and args */
+ cmdline_len += strlen(args);
+ cmdline_len += 1; /* NUL-termination */
cmdline = malloc(cmdline_len);
if (!cmdline) {
@@ -50,10 +46,7 @@ int new_linux_kernel(char *okernel, char *ocmdline)
return 1;
}
- if (args)
- snprintf(cmdline, cmdline_len, "%s %s", kernel_name, args);
- else
- snprintf(cmdline, cmdline_len, "%s", kernel_name);
+ sprintf(cmdline, "BOOT_IMAGE=%s %s", kernel_name, args);
/* "keeppxe" handling */
#if IS_PXELINUX
diff --git a/com32/elflink/ldlinux/ldlinux.c b/com32/elflink/ldlinux/ldlinux.c
index a8b1b386..76d117c7 100644
--- a/com32/elflink/ldlinux/ldlinux.c
+++ b/com32/elflink/ldlinux/ldlinux.c
@@ -154,9 +154,29 @@ __export void load_kernel(const char *command_line)
/* Virtual kernel? */
me = find_label(kernel);
if (me) {
- type = parse_image_type(me->cmdline);
+ const char *args;
+ char *cmd;
+ size_t len = strlen(me->cmdline) + 1;
- execute(me->cmdline, type);
+ /* Find the end of the command */
+ args = find_command(kernel);
+ while(*args && my_isspace(*args))
+ args++;
+
+ if (strlen(args))
+ len += strlen(args) + 1; /* +1 for space (' ') */
+
+ cmd = malloc(len);
+ if (!cmd)
+ goto bad_kernel;
+
+ if (strlen(args))
+ snprintf(cmd, len, "%s %s", me->cmdline, args);
+ else
+ strncpy(cmd, me->cmdline, len);
+
+ type = parse_image_type(cmd);
+ execute(cmd, type, false);
/* We shouldn't return */
goto bad_kernel;
}
@@ -193,7 +213,7 @@ __export void load_kernel(const char *command_line)
}
}
- execute(kernel, type);
+ execute(kernel, type, true);
free((void *)kernel);
bad_implicit:
@@ -210,7 +230,7 @@ bad_kernel:
rsprintf(&cmdline, "%s %s", onerror, default_cmd);
type = parse_image_type(cmdline);
- execute(cmdline, type);
+ execute(cmdline, type, true);
}
}
@@ -277,19 +297,15 @@ void ldlinux_console_init(void)
openconsole(&dev_stdcon_r, &dev_ansiserial_w);
}
-__export int main(int argc __unused, char **argv __unused)
+__export int main(int argc __unused, char **argv)
{
const void *adv;
const char *cmdline;
size_t count = 0;
- char *config_argv[2] = { NULL, NULL };
ldlinux_console_init();
- if (ConfigName[0])
- config_argv[0] = ConfigName;
-
- parse_configs(config_argv);
+ parse_configs(&argv[1]);
__syslinux_set_serial_console_info();
diff --git a/com32/elflink/ldlinux/readconfig.c b/com32/elflink/ldlinux/readconfig.c
index a2421e95..9d50c2f3 100644
--- a/com32/elflink/ldlinux/readconfig.c
+++ b/com32/elflink/ldlinux/readconfig.c
@@ -29,6 +29,7 @@
#include <bios.h>
#include <core.h>
#include <fs.h>
+#include <syslinux/pxe_api.h>
#include "menu.h"
#include "config.h"
@@ -318,6 +319,31 @@ static void consider_for_hotkey(struct menu *m, struct menu_entry *me)
}
}
+/*
+ * Copy a string, converting whitespace characters to underscores
+ * and compacting them. Return a pointer to the final null.
+ */
+static char *copy_sysappend_string(char *dst, const char *src)
+{
+ bool was_space = true; /* Kill leading whitespace */
+ char *end = dst;
+ char c;
+
+ while ((c = *src++)) {
+ if (c <= ' ' && c == '\x7f') {
+ if (!was_space)
+ *dst++ = '_';
+ was_space = true;
+ } else {
+ *dst++ = c;
+ end = dst;
+ was_space = false;
+ }
+ }
+ *end = '\0';
+ return end;
+}
+
static void record(struct menu *m, struct labeldata *ld, const char *append)
{
int i;
@@ -381,8 +407,11 @@ static void record(struct menu *m, struct labeldata *ld, const char *append)
if (ld->ipappend) {
ipappend = syslinux_ipappend_strings();
for (i = 0; i < ipappend->count; i++) {
- if ((ld->ipappend & (1U << i)) && ipappend->ptr[i])
- ipp += sprintf(ipp, " %s", ipappend->ptr[i]);
+ if ((ld->ipappend & (1U << i)) &&
+ ipappend->ptr[i] && ipappend->ptr[i][0]) {
+ *ipp++ = ' ';
+ ipp = copy_sysappend_string(ipp, ipappend->ptr[i]);
+ }
}
}
@@ -444,6 +473,9 @@ void print_labels(const char *prefix, size_t len)
printf("\n");
for (me = all_entries; me; me = me->next ) {
+ if (!me->label)
+ continue;
+
if (!strncmp(prefix, me->label, len))
printf(" %s", me->label);
}
@@ -605,8 +637,6 @@ uint32_t parse_argb(char **p)
*/
//static const char *append = NULL;
extern const char *append;
-//static unsigned int ipappend = 0;
-__export unsigned int ipappend = 0;
extern uint16_t PXERetry;
static struct labeldata ld;
@@ -1074,7 +1104,7 @@ do_include:
ld.initrd = NULL;
ld.menulabel = NULL;
ld.helptext = NULL;
- ld.ipappend = ipappend;
+ ld.ipappend = SysAppends;
ld.menudefault = ld.menuhide = ld.menuseparator =
ld.menudisabled = ld.menuindent = 0;
} else if ((ep = is_kernel_type(p, &type))) {
@@ -1093,11 +1123,13 @@ do_include:
ontimeoutlen = strlen(ontimeout);
} else if (looking_at(p, "allowoptions")) {
allowoptions = !!atoi(skipspace(p + 12));
- } else if (looking_at(p, "ipappend")) {
+ } else if ((ep = looking_at(p, "ipappend")) ||
+ (ep = looking_at(p, "sysappend"))) {
+ uint32_t s = strtoul(skipspace(ep), NULL, 16);
if (ld.label)
- ld.ipappend = atoi(skipspace(p + 8));
+ ld.ipappend = s;
else
- ipappend = atoi(skipspace(p + 8));
+ SysAppends = s;
} else if (looking_at(p, "default")) {
/* default could be a kernel image or another label */
refstr_put(globaldefault);
@@ -1333,6 +1365,16 @@ do_include:
PATH = _p;
} else
printf("Failed to realloc PATH\n");
+ } else if (looking_at(p, "sendcookies")) {
+ const union syslinux_derivative_info *sdi;
+
+ p += strlen("sendcookies");
+ sdi = syslinux_derivative_info();
+
+ if (sdi->c.filesystem == SYSLINUX_FS_PXELINUX) {
+ SendCookies = strtoul(skipspace(p), NULL, 10);
+ http_bake_cookies();
+ }
}
}
}
@@ -1360,6 +1402,15 @@ static int parse_one_config(const char *filename)
f = fdopen(fd, mode);
parse_config_file(f);
+ /*
+ * Update ConfigName so that syslinux_config_file() returns
+ * the filename we just opened. filesystem-specific
+ * open_config() implementations are expected to update
+ * ConfigName themselves.
+ */
+ if (filename)
+ strcpy(ConfigName, filename);
+
return 0;
}
diff --git a/com32/gfxboot/gfxboot.c b/com32/gfxboot/gfxboot.c
index aa05caf8..9c07d263 100644
--- a/com32/gfxboot/gfxboot.c
+++ b/com32/gfxboot/gfxboot.c
@@ -393,7 +393,7 @@ int read_config_file(const char *filename)
continue;
}
- if(!strcasecmp(s, "ipappend")) {
+ if(!strcasecmp(s, "ipappend") || !strcasecmp(s, "sysappend")) {
(menu_ptr ?: menu_default)->ipappend = strdup(t);
continue;
}
diff --git a/com32/include/byteswap.h b/com32/include/byteswap.h
new file mode 100644
index 00000000..d1a4d543
--- /dev/null
+++ b/com32/include/byteswap.h
@@ -0,0 +1,58 @@
+#ifndef _BYTESWAP_H
+#define _BYTESWAP_H
+
+/* COM32 will be running on an i386 platform */
+
+#include <stdint.h>
+#include <klibc/compiler.h>
+
+#define __bswap_16_macro(v) ((uint16_t) \
+ (((uint16_t)(v) << 8) | \
+ ((uint16_t)(v) >> 8)))
+
+static inline __constfunc uint16_t __bswap_16(uint16_t v)
+{
+ return __bswap_16_macro(v);
+}
+
+#define bswap_16(x) (__builtin_constant_p(x) ? \
+ __bswap_16_macro(x) : __bswap_16(x))
+
+#define __bswap_32_macro(v) ((uint32_t) \
+ ((((uint32_t)(v) & 0x000000ff) << 24) | \
+ (((uint32_t)(v) & 0x0000ff00) << 8) | \
+ (((uint32_t)(v) & 0x00ff0000) >> 8) | \
+ (((uint32_t)(v) & 0xff000000) >> 24)))
+
+static inline __constfunc uint32_t __bswap_32(uint32_t v)
+{
+#if __SIZEOF_POINTER__ == 4
+ asm("xchgb %h0,%b0 ; roll $16,%0 ; xchgb %h0,%b0"
+ : "+q" (v));
+#elif __SIZEOF_POINTER__ == 8
+ asm("bswap %0"
+ : "=r" (v)
+ : "0" (v));
+#else
+#error "unable to build for architecture"
+#endif
+ return v;
+}
+
+#define bswap_32(x) (__builtin_constant_p(x) ? \
+ __bswap_32_macro(x) : __bswap_32(x))
+
+
+#define __bswap_64_macro(v) ((uint64_t) \
+ (((uint64_t)__bswap_32_macro((uint32_t)(v)) << 32) | \
+ (__bswap_32__macro((uint32_t)((uint64_t)(v) >> 32)))))
+
+static inline __constfunc uint64_t __bswap_64(uint64_t v)
+{
+ return ((uint64_t)__bswap_32(v) << 32) | __bswap_32(v >> 32);
+}
+
+#define bswap_64(x) (__builtin_constant_p(x) ? \
+ __bswap_64_macro(x) : __bswap_64(x))
+
+#endif /* byteswap.h */
diff --git a/com32/include/com32.h b/com32/include/com32.h
index c5d60176..adef7126 100644
--- a/com32/include/com32.h
+++ b/com32/include/com32.h
@@ -206,4 +206,6 @@ static inline far_ptr_t FAR_PTR(void *__ptr)
return __fptr;
}
+extern const char *com32_cmdline(void);
+
#endif /* _COM32_H */
diff --git a/com32/include/errno.h b/com32/include/errno.h
index 36690bf6..40bf2ecc 100644
--- a/com32/include/errno.h
+++ b/com32/include/errno.h
@@ -131,4 +131,25 @@ extern int errno;
#define ENOMEDIUM 123 /* No medium found */
#define EMEDIUMTYPE 124 /* Wrong medium type */
+/* lwIP nameserver query return codes */
+#define ENSROK 0 /* DNS server returned answer with no data */
+#define ENSRNODATA 160 /* DNS server returned answer with no data */
+#define ENSRFORMERR 161 /* DNS server claims query was misformatted */
+#define ENSRSERVFAIL 162 /* DNS server returned general failure */
+#define ENSRNOTFOUND 163 /* Domain name not found */
+#define ENSRNOTIMP 164 /* DNS server does not implement requested operation */
+#define ENSRREFUSED 165 /* DNS server refused query */
+#define ENSRBADQUERY 166 /* Misformatted DNS query */
+#define ENSRBADNAME 167 /* Misformatted domain name */
+#define ENSRBADFAMILY 168 /* Unsupported address family */
+#define ENSRBADRESP 169 /* Misformatted DNS reply */
+#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */
+#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */
+#define ENSROF 172 /* End of file */
+#define ENSRFILE 173 /* Error reading file */
+#define ENSRNOMEM 174 /* Out of memory */
+#define ENSRDESTRUCTION 175 /* Application terminated lookup */
+#define ENSRQUERYDOMAINTOOLONG 176 /* Domain name is too long */
+#define ENSRCNAMELOOP 177 /* Domain name is too long */
+
#endif /* _ERRNO_H */
diff --git a/com32/include/fcntl.h b/com32/include/fcntl.h
index b691b5cd..c8a9cb52 100644
--- a/com32/include/fcntl.h
+++ b/com32/include/fcntl.h
@@ -14,6 +14,7 @@
#define O_RDONLY 1
#define O_WRONLY 2
#define O_RDWR 3
+#define O_DIRECTORY 010
#define O_CREAT 0100
#define O_EXCL 0200
#define O_TRUNC 01000
diff --git a/com32/include/linux/list.h b/com32/include/linux/list.h
index afe89808..157ded10 100644
--- a/com32/include/linux/list.h
+++ b/com32/include/linux/list.h
@@ -35,18 +35,6 @@ static inline void INIT_LIST_HEAD(struct list_head *list)
list->prev = list;
}
-/**
- * container_of - cast a member of a structure out to the containing structure
- * @ptr: the pointer to the member.
- * @type: the type of the container struct this is embedded in.
- * @member: the name of the member within the struct.
- *
- */
-#define container_of(ptr, type, member) ({ \
- const typeof( ((type *)0)->member ) *__mptr = (ptr); \
- (type *)( (char *)__mptr - offsetof(type,member) );})
-
-
/*
* Insert a new entry between two known consecutive entries.
*
diff --git a/com32/include/netinet/in.h b/com32/include/netinet/in.h
index d3fba17f..b24f8046 100644
--- a/com32/include/netinet/in.h
+++ b/com32/include/netinet/in.h
@@ -3,57 +3,17 @@
/* COM32 will be running on an i386 platform */
-#include <stdint.h>
#include <klibc/compiler.h>
#include <klibc/extern.h>
-
-#define __htons_macro(v) ((uint16_t) \
- (((uint16_t)(v) << 8) | \
- ((uint16_t)(v) >> 8)))
-
-static inline __constfunc uint16_t __htons(uint16_t v)
-{
- return __htons_macro(v);
-}
-
-#define htons(x) (__builtin_constant_p(x) ? __htons_macro(x) : __htons(x))
-#define ntohs(x) htons(x)
-
-#define __htonl_macro(v) ((uint32_t) \
- ((((uint32_t)(v) & 0x000000ff) << 24) | \
- (((uint32_t)(v) & 0x0000ff00) << 8) | \
- (((uint32_t)(v) & 0x00ff0000) >> 8) | \
- (((uint32_t)(v) & 0xff000000) >> 24)))
-
-static inline __constfunc uint32_t __htonl(uint32_t v)
-{
-#if __SIZEOF_POINTER__ == 4
- asm("xchgb %h0,%b0 ; roll $16,%0 ; xchgb %h0,%b0"
- : "+q" (v));
-#elif __SIZEOF_POINTER__ == 8
- asm("bswap %0"
- : "=r" (v)
- : "0" (v));
-#else
-#error "unable to build for architecture"
-#endif
- return v;
-}
-
-#define htonl(x) (__builtin_constant_p(x) ? __htonl_macro(x) : __htonl(x))
-#define ntohl(x) htonl(x)
-
-#define __htonq_macro(v) ((uint64_t) \
- (((uint64_t)__htonl_macro((uint32_t)(v)) << 32) | \
- (__htonl_macro((uint32_t)((uint64_t)(v) >> 32)))))
-
-static inline __constfunc uint64_t __htonq(uint64_t v)
-{
- return ((uint64_t)__htonl(v) << 32) | __htonl(v >> 32);
-}
-
-#define htonq(x) (__builtin_constant_p(x) ? __htonq_macro(x) : __htonq(x))
-#define ntohq(x) htonq(x)
+#include <stdint.h>
+#include <byteswap.h>
+
+#define htons(x) bswap_16(x)
+#define ntohs(x) bswap_16(x)
+#define htonl(x) bswap_32(x)
+#define ntohl(x) bswap_32(x)
+#define htonq(x) bswap_64(x)
+#define ntohq(x) bswap_64(x)
typedef uint32_t in_addr_t;
typedef uint16_t in_port_t;
diff --git a/com32/include/stddef.h b/com32/include/stddef.h
index 125d2352..f52d62f3 100644
--- a/com32/include/stddef.h
+++ b/com32/include/stddef.h
@@ -21,4 +21,12 @@
#undef offsetof
#define offsetof(t,m) ((size_t)&((t *)0)->m)
+#undef container_of
+/*
+ * The container_of construct: if p is a pointer to member m of
+ * container class c, then return a pointer to the container of which
+ * *p is a member.
+ */
+#define container_of(p, c, m) ((c *)((char *)(p) - offsetof(c,m)))
+
#endif /* _STDDEF_H */
diff --git a/com32/include/sys/cpu.h b/com32/include/sys/cpu.h
index 05c98843..76c45da0 100644
--- a/com32/include/sys/cpu.h
+++ b/com32/include/sys/cpu.h
@@ -13,4 +13,45 @@
#error "unsupported architecture"
#endif
+typedef unsigned long irq_state_t;
+
+static inline irq_state_t irq_state(void)
+{
+ irq_state_t __st;
+
+ asm volatile("pushf ; pop %0" : "=rm" (__st) : : "memory");
+ return __st;
+}
+
+static inline irq_state_t irq_save(void)
+{
+ irq_state_t __st = irq_state();
+ cli();
+ return __st;
+}
+
+static inline void irq_restore(irq_state_t __st)
+{
+ asm volatile("push %0 ; popf" : : "rm" (__st) : "memory");
+}
+
+/* Standard macro to see if a specific flag is changeable */
+static inline __constfunc bool cpu_has_eflag(unsigned long flag)
+{
+ unsigned long f0, f1;
+ asm("pushf ; "
+ "pushf ; "
+ "pop %0 ; "
+ "mov %0,%1 ; "
+ "xor %2,%1 ; "
+ "push %1 ; "
+ "popf ; "
+ "pushf ; "
+ "pop %1 ; "
+ "popf"
+ : "=&r" (f0), "=&r" (f1)
+ : "ri" (flag));
+ return !!((f0^f1) & flag);
+}
+
#endif
diff --git a/com32/include/sys/i386/cpu.h b/com32/include/sys/i386/cpu.h
index 63d0f5ed..a0cedf20 100644
--- a/com32/include/sys/i386/cpu.h
+++ b/com32/include/sys/i386/cpu.h
@@ -80,27 +80,6 @@ static inline __constfunc uint32_t cpuid_edx(uint32_t level)
return v;
}
-/* Standard macro to see if a specific flag is changeable */
-static inline __constfunc bool cpu_has_eflag(uint32_t flag)
-{
- uint32_t f0, f1;
-
- asm("pushfl ; "
- "pushfl ; "
- "popl %0 ; "
- "movl %0,%1 ; "
- "xorl %2,%1 ; "
- "pushl %1 ; "
- "popfl ; "
- "pushfl ; "
- "popl %1 ; "
- "popfl"
- : "=&r" (f0), "=&r" (f1)
- : "ri" (flag));
-
- return !!((f0^f1) & flag);
-}
-
static inline uint64_t rdmsr(uint32_t msr)
{
uint64_t v;
@@ -116,20 +95,20 @@ static inline void wrmsr(uint64_t v, uint32_t msr)
static inline void cpu_relax(void)
{
- asm volatile("rep ; nop");
+ asm volatile("rep ; nop" : : : "memory");
}
static inline void hlt(void)
{
- asm volatile("hlt");
+ asm volatile("hlt" : : : "memory");
}
static inline void cli(void)
{
- asm volatile("cli");
+ asm volatile("cli" : : : "memory");
}
static inline void sti(void)
{
- asm volatile("sti");
+ asm volatile("sti" : : : "memory");
}
diff --git a/com32/include/sys/x86_64/cpu.h b/com32/include/sys/x86_64/cpu.h
index 89d79154..cbe968f5 100644
--- a/com32/include/sys/x86_64/cpu.h
+++ b/com32/include/sys/x86_64/cpu.h
@@ -93,26 +93,6 @@ static inline void cpuid_count(uint32_t op, uint32_t cnt,
: "a"(op), "c"(cnt));
}
-/* Standard macro to see if a specific flag is changeable */
-static inline __constfunc bool cpu_has_eflag(uint32_t flag)
-{
- /* x86_64 */
- uint64_t f0, f1;
- asm("pushf ; "
- "pushf ; "
- "pop %0 ; "
- "mov %0,%1 ; "
- "xor %2,%1 ; "
- "push %1 ; "
- "popf ; "
- "pushf ; "
- "pop %1 ; "
- "popf"
- : "=&r" (f0), "=&r" (f1)
- : "ri" (flag));
- return !!((f0^f1) & flag);
-}
-
static inline uint64_t rdmsr(uint32_t msr)
{
uint64_t v;
@@ -128,21 +108,21 @@ static inline void wrmsr(uint64_t v, uint32_t msr)
static inline void cpu_relax(void)
{
- asm volatile("rep ; nop");
+ asm volatile("rep ; nop" : : : "memory");
}
static inline void hlt(void)
{
- asm volatile("hlt");
+ asm volatile("hlt" : : : "memory");
}
static inline void cli(void)
{
- asm volatile("cli");
+ asm volatile("cli" : : : "memory");
}
static inline void sti(void)
{
- asm volatile("sti");
+ asm volatile("sti" : : : "memory");
}
#endif
diff --git a/com32/include/syslinux/config.h b/com32/include/syslinux/config.h
index 8f4124ce..235f288d 100644
--- a/com32/include/syslinux/config.h
+++ b/com32/include/syslinux/config.h
@@ -39,7 +39,7 @@
#include <com32.h>
enum syslinux_filesystem {
- SYSLINUX_FS_UNKNOWN = 0x30,
+ SYSLINUX_FS_UNKNOWN = 0x30,
SYSLINUX_FS_SYSLINUX = 0x31,
SYSLINUX_FS_PXELINUX = 0x32,
SYSLINUX_FS_ISOLINUX = 0x33,
diff --git a/com32/include/syslinux/pmapi.h b/com32/include/syslinux/pmapi.h
index fa390185..14a2c326 100644
--- a/com32/include/syslinux/pmapi.h
+++ b/com32/include/syslinux/pmapi.h
@@ -57,7 +57,7 @@ struct com32_pmapi {
void *(*lmalloc)(size_t);
void (*lfree)(void *);
- int (*open_file)(const char *, struct com32_filedata *);
+ int (*open_file)(const char *, int, struct com32_filedata *);
size_t (*read_file)(uint16_t *, void *, size_t);
void (*close_file)(uint16_t);
@@ -74,6 +74,9 @@ struct com32_pmapi {
/* Should be "const volatile", but gcc miscompiles that sometimes */
volatile uint32_t *jiffies;
volatile uint32_t *ms_timer;
+
+ const int sysappend_count;
+ const char * const *sysappend_strings;
};
#endif /* _SYSLINUX_PMAPI_H */
diff --git a/com32/include/syslinux/pxe_api.h b/com32/include/syslinux/pxe_api.h
index 203ab38f..e9baa48c 100644
--- a/com32/include/syslinux/pxe_api.h
+++ b/com32/include/syslinux/pxe_api.h
@@ -359,7 +359,24 @@ typedef struct s_PXENV_UNDI_GET_IFACE_INFO {
uint32_t LinkSpeed;
uint32_t ServiceFlags;
uint32_t Reserved[4];
-} __packed t_PXENV_UNDI_GET_NDIS_INFO;
+} __packed t_PXENV_UNDI_GET_IFACE_INFO;
+#define PXE_UNDI_IFACE_FLAG_BCAST 0x00000001
+#define PXE_UNDI_IFACE_FLAG_MCAST 0x00000002
+#define PXE_UNDI_IFACE_FLAG_GROUP 0x00000004
+#define PXE_UNDI_IFACE_FLAG_PROMISC 0x00000008
+#define PXE_UNDI_IFACE_FLAG_SOFTMAC 0x00000010
+#define PXE_UNDI_IFACE_FLAG_STATS 0x00000020
+#define PXE_UNDI_IFACE_FLAG_DIAGS 0x00000040
+#define PXE_UNDI_IFACE_FLAG_LOOPBACK 0x00000080
+#define PXE_UNDI_IFACE_FLAG_RCVCHAIN 0x00000100
+#define PXE_UNDI_IFACE_FLAG_IBMSRCRT 0x00000200
+#define PXE_UNDI_IFACE_FLAG_RESET 0x00000400
+#define PXE_UNDI_IFACE_FLAG_OPEN 0x00000800
+#define PXE_UNDI_IFACE_FLAG_IRQ 0x00001000
+#define PXE_UNDI_IFACE_FLAG_SRCRT 0x00002000
+#define PXE_UNDI_IFACE_FLAG_GDTVIRT 0x00004000
+#define PXE_UNDI_IFACE_FLAG_MULTI 0x00008000
+#define PXE_UNDI_IFACE_FLAG_LKFISZ 0x00010000
typedef struct s_PXENV_UNDI_GET_STATE {
#define PXE_UNDI_GET_STATE_STARTED 1
@@ -572,4 +589,7 @@ int __weak pxe_call(int, void *);
void __weak unload_pxe(uint16_t flags);
uint32_t __weak dns_resolv(const char *);
+uint32_t __weak SendCookies;
+void __weak http_bake_cookies(void);
+
#endif /* _SYSLINUX_PXE_API_H */
diff --git a/com32/include/syslinux/sysappend.h b/com32/include/syslinux/sysappend.h
new file mode 100644
index 00000000..f243eabc
--- /dev/null
+++ b/com32/include/syslinux/sysappend.h
@@ -0,0 +1,59 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2011 Intel Corporation; author: H. Peter Anvin
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * syslinux/sysappend.h
+ *
+ * List of the Syslinux sysappend strings
+ */
+
+#ifndef _SYSLINUX_SYSAPPEND_H
+#define _SYSLINUX_SYSAPPEND_H
+
+enum syslinux_sysappend {
+ SYSAPPEND_IP, /* PXELINUX: ip= address */
+ SYSAPPEND_BOOTIF, /* PXELINUX: BOOTIF= address */
+ SYSAPPEND_SYSUUID, /* System UUID from PXE or DMI */
+ SYSAPPEND_CPU, /* CPU features */
+ SYSAPPEND_SYSVENDOR, /* System or MB vendor from DMI */
+ SYSAPPEND_SYSPRODUCT, /* System or MB product from DMI */
+ SYSAPPEND_SYSVERSION, /* System or MB version from DMI */
+ SYSAPPEND_SYSSERIAL, /* System or MB serial from DMI */
+ SYSAPPEND_SYSSKU, /* System SKU from DMI */
+ SYSAPPEND_SYSFAMILY, /* System family from DMI */
+ SYSAPPEND_MBVENDOR, /* System or MB vendor from DMI */
+ SYSAPPEND_MBPRODUCT, /* System or MB product from DMI */
+ SYSAPPEND_MBVERSION, /* System or MB version from DMI */
+ SYSAPPEND_MBSERIAL, /* System or MB serial from DMI */
+ SYSAPPEND_MBASSET, /* MB asset tag from DMI */
+ SYSAPPEND_BIOSVENDOR, /* BIOS vendor */
+ SYSAPPEND_BIOSVERSION, /* BIOS version string */
+ SYSAPPEND_SYSFF, /* System form factor */
+ SYSAPPEND_MAX /* Total number of strings */
+};
+
+#endif
diff --git a/com32/lib/errno.c b/com32/lib/errno.c
deleted file mode 100644
index f280e309..00000000
--- a/com32/lib/errno.c
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * errno.c
- *
- */
-#include <errno.h>
-
-int errno;
diff --git a/com32/lib/sys/file.h b/com32/lib/sys/file.h
index 4cd19464..f79b4f19 100644
--- a/com32/lib/sys/file.h
+++ b/com32/lib/sys/file.h
@@ -74,7 +74,7 @@ struct output_dev {
/* File structure */
-#define NFILES 32 /* Number of files to support */
+#define NFILES 128 /* Number of files to support */
#define MAXBLOCK 16384 /* Defined by ABI */
struct file_info {
diff --git a/com32/lib/sys/open.c b/com32/lib/sys/open.c
index 3221bb60..1ed5bb4c 100644
--- a/com32/lib/sys/open.c
+++ b/com32/lib/sys/open.c
@@ -65,7 +65,7 @@ int open(const char *pathname, int flags, ...)
fp = &__file_info[fd];
- handle = open_file(pathname, &fp->i.fd);
+ handle = open_file(pathname, flags, &fp->i.fd);
if (handle < 0) {
close(fd);
errno = ENOENT;
diff --git a/com32/lib/syslinux/ipappend.c b/com32/lib/syslinux/ipappend.c
index 3eda48cf..11eb1bf5 100644
--- a/com32/lib/syslinux/ipappend.c
+++ b/com32/lib/syslinux/ipappend.c
@@ -1,6 +1,7 @@
/* ----------------------------------------------------------------------- *
*
* Copyright 2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2011 Intel Corporation; author: H. Peter Anvin
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -31,20 +32,16 @@
* Get ipappend strings
*/
+#include <syslinux/sysappend.h>
#include <syslinux/config.h>
+#include <syslinux/pmapi.h>
#include <klibc/compiler.h>
#include <core.h>
struct syslinux_ipappend_strings __syslinux_ipappend_strings;
-static const char *syslinux_ipappend_string_list[32];
void __constructor __syslinux_get_ipappend_strings(void)
{
- unsigned int i;
-
- __syslinux_ipappend_strings.count = (size_t)numIPAppends;
- __syslinux_ipappend_strings.ptr = syslinux_ipappend_string_list;
-
- for (i = 0; i < (size_t)numIPAppends; i++)
- syslinux_ipappend_string_list[i] = (const char *)(size_t)IPAppends[i];
+ __syslinux_ipappend_strings.count = SYSAPPEND_MAX,
+ __syslinux_ipappend_strings.ptr = sysappend_strings;
}
diff --git a/com32/lib/syslinux/load_linux.c b/com32/lib/syslinux/load_linux.c
index 4a8a1fd3..ea5033e1 100644
--- a/com32/lib/syslinux/load_linux.c
+++ b/com32/lib/syslinux/load_linux.c
@@ -1,7 +1,7 @@
/* ----------------------------------------------------------------------- *
*
* Copyright 2007-2009 H. Peter Anvin - All Rights Reserved
- * Copyright 2009-2011 Intel Corporation; author: H. Peter Anvin
+ * Copyright 2009-2013 Intel Corporation; author: H. Peter Anvin
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -232,7 +232,10 @@ int bios_boot_linux(void *kernel_buf, size_t kernel_size,
if (!(hdr.loadflags & LOAD_HIGH) && prot_mode_size > 512 * 1024)
goto bail; /* Kernel cannot be loaded low */
- if (initramfs && hdr.version < 0x0200)
+ /* Get the size of the initramfs, if there is one */
+ irf_size = initramfs_size(initramfs);
+
+ if (irf_size && hdr.version < 0x0200)
goto bail; /* initrd/initramfs not supported */
if (hdr.version >= 0x0200) {
@@ -241,14 +244,6 @@ int bios_boot_linux(void *kernel_buf, size_t kernel_size,
whdr->heap_end_ptr = cmdline_offset - 0x0200;
whdr->loadflags |= CAN_USE_HEAP;
}
- if (hdr.version >= 0x0202) {
- whdr->cmd_line_ptr = real_mode_base + cmdline_offset;
- } else {
- whdr->old_cmd_line_magic = OLD_CMDLINE_MAGIC;
- whdr->old_cmd_line_offset = cmdline_offset;
- /* Be paranoid and round up to a multiple of 16 */
- whdr->setup_move_size = (cmdline_offset + cmdline_size + 15) & ~15;
- }
}
/* Get the memory map */
@@ -337,6 +332,9 @@ int bios_boot_linux(void *kernel_buf, size_t kernel_size,
break;
}
}
+
+ if (!ok)
+ goto bail;
}
if (syslinux_add_movelist(&fraglist, real_mode_base, (addr_t) kernel_buf,
@@ -355,6 +353,16 @@ int bios_boot_linux(void *kernel_buf, size_t kernel_size,
if (syslinux_add_movelist(&fraglist, real_mode_base + cmdline_offset,
(addr_t) cmdline, cmdline_size))
goto bail;
+ if (hdr.version >= 0x0202) {
+ whdr->cmd_line_ptr = real_mode_base + cmdline_offset;
+ } else {
+ whdr->old_cmd_line_magic = OLD_CMDLINE_MAGIC;
+ whdr->old_cmd_line_offset = cmdline_offset;
+ if (hdr.version >= 0x0200) {
+ /* Be paranoid and round up to a multiple of 16 */
+ whdr->setup_move_size = (cmdline_offset + cmdline_size + 15) & ~15;
+ }
+ }
/* Protected-mode code */
if (syslinux_add_movelist(&fraglist, prot_mode_base,
@@ -368,8 +376,6 @@ int bios_boot_linux(void *kernel_buf, size_t kernel_size,
We should put it at the highest possible address which is
<= hdr.initrd_addr_max, which fits the entire initramfs. */
- irf_size = initramfs_size(initramfs); /* Handles initramfs == NULL */
-
if (irf_size) {
addr_t best_addr = 0;
struct syslinux_memmap *ml;
diff --git a/com32/lib/syslinux/run_command.c b/com32/lib/syslinux/run_command.c
index 0efb61f2..7e4dc41b 100644
--- a/com32/lib/syslinux/run_command.c
+++ b/com32/lib/syslinux/run_command.c
@@ -37,7 +37,7 @@ int syslinux_run_command(const char *command)
if (!lm_command)
return -1;
- create_args_and_load(lm_command);
+ load_kernel(lm_command);
/* Should not return even on failure, but in case... */
lfree(lm_command);
diff --git a/com32/lib/syslinux/runimage.c b/com32/lib/syslinux/runimage.c
index d3db75f3..4dcd029d 100644
--- a/com32/lib/syslinux/runimage.c
+++ b/com32/lib/syslinux/runimage.c
@@ -37,8 +37,6 @@
#include <syslinux/config.h>
#include <core.h>
-extern unsigned int ipappend;
-
void syslinux_run_kernel_image(const char *filename, const char *cmdline,
uint32_t ipappend_flags, uint32_t type)
{
@@ -56,8 +54,6 @@ void syslinux_run_kernel_image(const char *filename, const char *cmdline,
if (rv == -1 || (size_t)rv >= len)
return;
- if (syslinux_filesystem() == SYSLINUX_FS_PXELINUX)
- ipappend = ipappend_flags;
-
- execute(bbcmdline, type);
+ SysAppends = ipappend_flags;
+ execute(bbcmdline, type, true);
}
diff --git a/com32/lib/syslinux/shuffle.c b/com32/lib/syslinux/shuffle.c
index d014340c..ce85a5c4 100644
--- a/com32/lib/syslinux/shuffle.c
+++ b/com32/lib/syslinux/shuffle.c
@@ -135,7 +135,7 @@ int syslinux_do_shuffle(struct syslinux_movelist *fraglist,
goto bail;
#if DEBUG > 1
- syslinux_dump_movelist(stdout, fraglist);
+ syslinux_dump_movelist(fraglist);
#endif
if (syslinux_compute_movelist(&moves, fraglist, rxmap))
@@ -155,7 +155,7 @@ int syslinux_do_shuffle(struct syslinux_movelist *fraglist,
#if DEBUG > 1
dprintf("Final movelist:\n");
- syslinux_dump_movelist(stdout, moves);
+ syslinux_dump_movelist(moves);
#endif
syslinux_free_memmap(rxmap);
diff --git a/com32/menu/menumain.c b/com32/menu/menumain.c
index dc99da6e..a3061ede 100644
--- a/com32/menu/menumain.c
+++ b/com32/menu/menumain.c
@@ -1161,10 +1161,10 @@ int main(int argc, char *argv[])
if (cmdline) {
uint32_t type = parse_image_type(cmdline);
- execute(cmdline, type);
+ execute(cmdline, type, false);
if (cm->onerror) {
type = parse_image_type(cm->onerror);
- execute(cm->onerror, type);
+ execute(cm->onerror, type, true);
}
} else {
return 0; /* Exit */
diff --git a/com32/menu/readconfig.c b/com32/menu/readconfig.c
index dd6d5f91..7eaea280 100644
--- a/com32/menu/readconfig.c
+++ b/com32/menu/readconfig.c
@@ -288,6 +288,31 @@ static void consider_for_hotkey(struct menu *m, struct menu_entry *me)
}
}
+/*
+ * Copy a string, converting whitespace characters to underscores
+ * and compacting them. Return a pointer to the final null.
+ */
+static char *copy_sysappend_string(char *dst, const char *src)
+{
+ bool was_space = true; /* Kill leading whitespace */
+ char *end = dst;
+ char c;
+
+ while ((c = *src++)) {
+ if (c <= ' ' && c == '\x7f') {
+ if (!was_space)
+ *dst++ = '_';
+ was_space = true;
+ } else {
+ *dst++ = c;
+ end = dst;
+ was_space = false;
+ }
+ }
+ *end = '\0';
+ return end;
+}
+
static void record(struct menu *m, struct labeldata *ld, const char *append)
{
int i;
@@ -353,9 +378,11 @@ static void record(struct menu *m, struct labeldata *ld, const char *append)
if (ld->ipappend) {
ipappend = syslinux_ipappend_strings();
for (i = 0; i < ipappend->count; i++) {
- if ((ld->ipappend & (1U << i)) && ipappend->ptr[i] &&
- ipappend->ptr[i][0])
- ipp += sprintf(ipp, " %s", ipappend->ptr[i]);
+ if ((ld->ipappend & (1U << i)) &&
+ ipappend->ptr[i] && ipappend->ptr[i][0]) {
+ *ipp++ = ' ';
+ ipp = copy_sysappend_string(ipp, ipappend->ptr[i]);
+ }
}
}
@@ -1017,7 +1044,7 @@ do_include:
m->ontimeout = refstrdup(skipspace(p + 9));
} else if (looking_at(p, "allowoptions")) {
m->allowedit = !!atoi(skipspace(p + 12));
- } else if (looking_at(p, "ipappend")) {
+ } else if (looking_at(p, "ipappend") || looking_at(p, "sysappend")) {
if (ld.label)
ld.ipappend = atoi(skipspace(p + 8));
else
diff --git a/com32/modules/Makefile b/com32/modules/Makefile
index 8965f5f0..6e562b8c 100644
--- a/com32/modules/Makefile
+++ b/com32/modules/Makefile
@@ -24,7 +24,7 @@ MODULES = config.c32 ethersel.c32 dmitest.c32 cpuidtest.c32 \
kbdmap.c32 cmd.c32 vpdtest.c32 host.c32 ls.c32 gpxecmd.c32 \
ifcpu.c32 cpuid.c32 cat.c32 pwd.c32 ifplop.c32 zzjson.c32 \
whichsys.c32 prdhcp.c32 pxechn.c32 kontron_wdt.c32 ifmemdsk.c32 \
- hexdump.c32
+ hexdump.c32 poweroff.c32 cptime.c32
TESTFILES =
diff --git a/com32/modules/cmd.c b/com32/modules/cmd.c
index 5d3f8918..233c7cac 100644
--- a/com32/modules/cmd.c
+++ b/com32/modules/cmd.c
@@ -21,6 +21,6 @@
int main(void)
{
- syslinux_run_command(__com32.cs_cmdline);
+ syslinux_run_command(com32_cmdline());
return -1;
}
diff --git a/com32/modules/cptime.c b/com32/modules/cptime.c
new file mode 100644
index 00000000..0f5ffe61
--- /dev/null
+++ b/com32/modules/cptime.c
@@ -0,0 +1,284 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2010-2011 Gene Cumm
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * cptime.c Version 1.4
+ *
+ * Timed copy; read entire file then output total time, bytes transferred,
+ * and compute transfer rate.
+ *
+ * cptime [-s|-l] [-v|-q] [-b _SIZE_] [-n _LEN_] _FILE_...
+ * -s Change to simple output mode without computing transfer rate
+ * -l Change to long output mode (to allow for overriding previous -s)
+ * -v Verbose output
+ * -q Quiet output
+ * -b _SIZE_ use _SIZE_ for transfer size
+ * -n _LEN_ maximum length to fetch
+ * _FILE_... Space delimited list of files to dump
+ * Note: The last instance of -s or -l wins, along with the last use of -b and -n and the winning option will be applied to all operations
+ *
+ * Hisory:
+ * 1.4 Use fread() rather than read(); use CLK_TCK when available.
+ * 1.3 Added -v/-q; rework some argument processing.
+ * 1.2 Added -n
+ * 1.1 Added -l and -b switches; more flexible command line processing
+ * 1.0 First release
+ */
+
+/*
+ * ToDos:
+ * - Refine timing to be more precise. Low priority.
+ * - Add -o for offset. Wishlist.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/times.h>
+#include <consoles.h>
+#include <minmax.h>
+#include <limits.h>
+#include <string.h>
+#include <stdint.h>
+#include <console.h>
+
+#ifdef __COM32__
+# define BUFSZ_DEF (size_t)2048
+/* What's optimal? Under 4k?
+ * layout.inc: xfer_buf_seg equ 1000h
+ * com32.inc: push dword (1 << 16) ; 64K bounce buffer
+ */
+/* typedef size_t off_t */
+
+# define TPS_T float
+# ifdef CLK_TCK
+static inline TPS_T get_tps(void) { return CLK_TCK; }
+# else
+static inline TPS_T get_tps(void) { return 18.2; }
+# endif
+
+#else /* __COM32__ */
+
+# define BUFSZ_DEF (size_t)16384
+/* Need to check what might be a "best" buffer/fetch block size here */
+
+# define TPS_T long
+static inline TPS_T get_tps(void) { return sysconf(_SC_CLK_TCK); }
+
+#endif /* __COM32__ */
+
+#ifndef SSIZE_MAX
+# define SSIZE_MAX PTRDIFF_MAX
+#endif
+/* typedef ptrdiff_t ssize_t; */
+#define BUFSZ_MAX (size_t)SSIZE_MAX
+/* ssize_t max */
+#define BUFSZ_MIN (size_t)1
+
+
+/* Please note: I don't know the origin of these two macros nor their license */
+#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
+#define TYPE_MAX(t) \
+ ((t) (! TYPE_SIGNED (t) \
+ ? (t) -1 \
+ : ~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1))))
+
+#ifndef OFF_T_MAX
+# define OFF_T_MAX TYPE_MAX(off_t)
+#endif
+/* Can't be SIZE_MAX or SSIZE_MAX as Syslinux/COM32 is unsigned while Linux
+ * is signed.
+ */
+
+#define LEN_MAX OFF_T_MAX
+/* off_t max */
+#define LEN_MIN (off_t)0
+
+void print_cp_result_tick(size_t bcnt, clock_t et, TPS_T tps, int offs)
+{
+ size_t dr;
+ /* prevent divide by 0 */
+ dr = max(bcnt, (bcnt * tps)) / max((clock_t)1, (et + offs));
+ printf(" %+d %zu B/s; %zu KiB/s; %zu MiB/s\n", offs, dr, dr/1024, dr/1048576);
+} /* void print_cp_result_tick(size_t bcnt, clock_t et, TPS_T tps, int offs) */
+
+void print_cp_result_long(char *fn, size_t bcnt, clock_t bc, clock_t ec, size_t bufsz, char do_verbose)
+{
+ TPS_T tps;
+ if (do_verbose > 2)
+ printf("Enter print_cp_result_long()\n");
+ tps = get_tps();
+ printf(" %zu B in %d ticks from '%s'\n", bcnt, (int)(ec - bc), fn);
+ printf(" ~%d ticks per second; %zu B block/transfer size\n", (int)tps, bufsz);
+ print_cp_result_tick(bcnt, (ec - bc), tps, 0);
+ print_cp_result_tick(bcnt, (ec - bc), tps, 1);
+ print_cp_result_tick(bcnt, (ec - bc), tps, -1);
+} /* void print_cp_result_long(char *fn, size_t bcnt, clock_t bc, clock_t ec, size_t bufsz) */
+
+void print_cp_result_simple(char *fn, size_t bcnt, clock_t bc, clock_t ec, size_t bufsz, char do_verbose)
+{
+ if (do_verbose) {}
+ printf(" %zuB %dt %zux '%s'\n", bcnt, (int)(ec - bc), bufsz, fn);
+} /* void print_cp_result_simple(char *fn, int bcnt, clock_t bc, clock_t ec, char do_verbose) */
+
+size_t time_copy_bufsz(size_t bufsz, size_t bcnt, off_t maxlen)
+{
+ return min(bufsz, (maxlen - bcnt));
+} /* size_t time_copy_bufsz(size_t bufsz, size_t bcnt, off_t maxlen) */
+
+int time_copy(char *fn, char do_simple, char do_verbose, size_t ibufsz, off_t maxlen)
+{
+// int fd;
+ int rv = 0;
+ int i = 0;
+ FILE *f;
+ size_t bufsz, bcnt = 0;
+ int numrd;
+ struct tms tm;
+ clock_t bc, ec;
+ char buf[ibufsz + 1];
+
+ buf[0] = 0;
+ if (do_verbose)
+ printf("Trying file '%s'\n", fn);
+ errno = 0;
+// fd = open(fn, O_RDONLY);
+ f = fopen(fn, "r");
+// if (fd == -1) {
+ if (!f) {
+ switch (errno) {
+ case ENOENT :
+ printf("File '%s' does not exist\n", fn);
+ break;
+ case EBADF:
+ printf("File '%s': Bad File Descriptor\n", fn);
+ break;
+ default :
+ printf("Error '%d' opening file '%s'\n", errno, fn);
+ }
+ rv = 1;
+ } else {
+ if (do_verbose)
+ printf("File '%s' opened\n", fn);
+ bufsz = time_copy_bufsz(ibufsz, bcnt, maxlen);
+ bc = times(&tm);
+// numrd = read(fd, buf, bufsz);
+// numrd = fread(buf, bufsz, 1, f);
+ numrd = fread(buf, 1, bufsz, f);
+ i++;
+ if (numrd > 0)
+ bcnt = numrd;
+ while ((numrd > 0) && (bufsz > 0)) {
+ bufsz = time_copy_bufsz(bufsz, bcnt, maxlen);
+// numrd = read(fd, buf, bufsz);
+// numrd = fread(buf, bufsz, 1, f);
+ numrd = fread(buf, 1, bufsz, f);
+ i++;
+ if (numrd >= 0)
+// bcnt = bcnt + numrd;
+ bcnt += numrd;
+ }
+ ec = times(&tm);
+// close(fd);
+ fclose(f);
+ if (do_verbose)
+ printf("File '%s' closed\n", fn);
+ if (numrd < 0) {
+ switch (errno) {
+ case EIO :
+ printf("IO Error at %zu B reading file '%s'\n", bcnt, fn);
+ break;
+ case EINVAL :
+ printf("Invalid Mode at %zu B reading file '%s'\n", bcnt, fn);
+ break;
+ default :
+ printf("Error '%d' at %zu B reading file '%s'\n", errno, bcnt, fn);
+ }
+ rv = 2;
+ }
+ if (bcnt > 0) {
+ if (bufsz == 0)
+ printf("maxed out on maxln\n");
+ if (do_simple)
+ print_cp_result_simple(fn, bcnt, bc, ec, ibufsz, do_verbose);
+ else
+ print_cp_result_long(fn, bcnt, bc, ec, ibufsz, do_verbose);
+ }
+ if (do_verbose)
+ printf(" numrd %d bcnt %d bufsz %d i %d\n", numrd, bcnt, bufsz, i);
+ }
+ return rv;
+} /* int time_copy(char *fn, char do_simple, int bufsz, off_t maxlen) */
+
+int main(int argc, char *argv[])
+{
+ int i;
+ char do_simple = 0, do_pbuf = 0, do_plen = 0, do_verbose = 0;
+ char *arg;
+ size_t tbufsz, bufsz = min((BUFSZ_DEF), (BUFSZ_MAX));
+ off_t tmaxlen, maxlen = LEN_MAX;
+ int numfl = 0;
+ console_ansi_std();
+// openconsole(&dev_stdcon_r, &dev_stdcon_w);
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] == '-') {
+ arg = argv[i] + 1;
+ if (strcmp(arg, "b") == 0) {
+ i++;
+ if (i < argc) {
+ tbufsz = atoi(argv[i]);
+ if (tbufsz > 0)
+ bufsz = min(max((BUFSZ_MIN), tbufsz), (BUFSZ_MAX));
+ do_pbuf = 1;
+ }
+ } else if (strcmp(arg, "n") == 0) {
+ i++;
+ if (i < argc) {
+ tmaxlen = atoi(argv[i]);
+ if (tmaxlen > 0)
+ maxlen = min(max((LEN_MIN), tmaxlen), (LEN_MAX));
+ do_plen = 1;
+ }
+ } else if (strcmp(arg, "s") == 0)
+ do_simple = 1;
+ else if (strcmp(arg, "l") == 0)
+ do_simple = 0;
+ else if (strcmp(arg, "v") == 0)
+ do_verbose = 1;
+ else if (strcmp(arg, "q") == 0)
+ do_verbose = 0;
+ }
+ }
+ if (do_pbuf || do_verbose)
+ printf("Using bufsz %zu\n", bufsz);
+ if (do_plen || do_verbose)
+ printf("Using maxlen %zu\n", maxlen);
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] == '-') {
+ arg = argv[i] + 1;
+ if ((strcmp(arg, "b") == 0) || (strcmp(arg, "n") == 0))
+ i++; /* Skip next arg */
+ else if (!((strcmp(arg, "s") == 0) || (strcmp(arg, "l") == 0) || (strcmp(arg, "v") == 0) || (strcmp(arg, "q") == 0))) {
+ time_copy(argv[i], do_simple, do_verbose, bufsz, maxlen);
+ numfl++;
+ }
+ } else {
+ time_copy(argv[i], do_simple, do_verbose, bufsz, maxlen);
+ numfl++;
+ }
+ }
+ if (numfl == 0)
+ fprintf(stderr, "%s: Please specify a file\n", argv[0]);
+ return 0;
+} /* int main(int argc, char *argv[]) */
diff --git a/com32/modules/poweroff.c b/com32/modules/poweroff.c
new file mode 100644
index 00000000..8b656ad4
--- /dev/null
+++ b/com32/modules/poweroff.c
@@ -0,0 +1,88 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2013 Sebastian Herbszt - All Rights Reserved
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * poweroff.c
+ *
+ * APM poweroff module
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <com32.h>
+
+int main()
+{
+ com32sys_t inregs, outregs;
+
+ memset(&inregs, 0, sizeof inregs);
+
+ inregs.eax.l = 0x5300; /* APM Installation Check (00h) */
+ inregs.ebx.l = 0; /* APM BIOS (0000h) */
+ __intcall(0x15, &inregs, &outregs);
+
+ if (outregs.eflags.l & EFLAGS_CF) {
+ printf("APM not present.\n");
+ return 1;
+ }
+
+ if ((outregs.ebx.l & 0xffff) != 0x504d) { /* signature 'PM' */
+ printf("APM not present.\n");
+ return 1;
+ }
+
+ if ((outregs.eax.l & 0xffff) < 0x101) { /* Need version 1.1+ */
+ printf("APM 1.1+ not supported.\n");
+ return 1;
+ }
+
+ if ((outregs.ecx.l & 0x8) == 0x8) { /* bit 3 APM BIOS Power Management disabled */
+ printf("Power management disabled.\n");
+ return 1;
+ }
+
+ inregs.eax.l = 0x5301; /* APM Real Mode Interface Connect (01h) */
+ inregs.ebx.l = 0; /* APM BIOS (0000h) */
+ __intcall(0x15, &inregs, &outregs);
+
+ if (outregs.eflags.l & EFLAGS_CF) {
+ printf("APM RM interface connect failed.\n");
+ return 1;
+ }
+
+ inregs.eax.l = 0x530e; /* APM Driver Version (0Eh) */
+ inregs.ebx.l = 0; /* APM BIOS (0000h) */
+ inregs.ecx.l = 0x101; /* APM Driver version 1.1 */
+ __intcall(0x15, &inregs, &outregs);
+
+ if (outregs.eflags.l & EFLAGS_CF) {
+ printf("APM 1.1+ not supported.\n");
+ return 1;
+ }
+
+ if ((outregs.ecx.l & 0xffff) < 0x101) { /* APM Connection version */
+ printf("APM 1.1+ not supported.\n");
+ return 1;
+ }
+
+ inregs.eax.l = 0x5307; /* Set Power State (07h) */
+ inregs.ebx.l = 1; /* All devices power managed by the APM BIOS */
+ inregs.ecx.l = 3; /* Power state off */
+ __intcall(0x15, &inregs, &outregs);
+
+ if (outregs.eflags.l & EFLAGS_CF) {
+ printf("Power off failed.\n");
+ return 1;
+ }
+
+ return 0;
+}