summaryrefslogtreecommitdiff
path: root/com32
diff options
context:
space:
mode:
Diffstat (limited to 'com32')
-rw-r--r--com32/Makefile4
-rw-r--r--com32/chain/Makefile11
-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.c136
-rw-r--r--com32/chain/utility.h79
-rw-r--r--com32/cmenu/Makefile27
-rw-r--r--com32/cmenu/adv_menu.tpl2
-rw-r--r--com32/cmenu/complex.c2
-rw-r--r--com32/cmenu/display.c2
-rw-r--r--com32/cmenu/libmenu/cmenu.h (renamed from com32/cmenu/libmenu/menu.h)0
-rw-r--r--com32/cmenu/libmenu/help.h2
-rw-r--r--com32/cmenu/libmenu/menu.c2
-rw-r--r--com32/cmenu/libmenu/syslnx.c77
-rw-r--r--com32/cmenu/simple.c2
-rw-r--r--com32/elflink/Makefile36
-rw-r--r--com32/elflink/ldlinux/Makefile50
-rw-r--r--com32/elflink/ldlinux/adv.c (renamed from com32/lib/syslinux/adv.c)12
-rw-r--r--com32/elflink/ldlinux/advwrite.c (renamed from com32/lib/syslinux/advwrite.c)2
-rw-r--r--com32/elflink/ldlinux/chainboot.c156
-rw-r--r--com32/elflink/ldlinux/cli.c486
-rw-r--r--com32/elflink/ldlinux/colors.c184
-rw-r--r--com32/elflink/ldlinux/config.h52
-rw-r--r--com32/elflink/ldlinux/execute.c174
-rw-r--r--com32/elflink/ldlinux/get_key.c (renamed from com32/libutil/get_key.c)76
-rw-r--r--com32/elflink/ldlinux/getadv.c (renamed from com32/lib/syslinux/getadv.c)2
-rw-r--r--com32/elflink/ldlinux/kernel.c131
-rw-r--r--com32/elflink/ldlinux/ldlinux.c349
-rw-r--r--com32/elflink/ldlinux/loadhigh.c112
-rw-r--r--com32/elflink/ldlinux/msg.c228
-rw-r--r--com32/elflink/ldlinux/readconfig.c1572
-rw-r--r--com32/elflink/ldlinux/refstr.c106
-rw-r--r--com32/elflink/ldlinux/setadv.c (renamed from com32/lib/syslinux/setadv.c)2
-rw-r--r--com32/elflink/test_com32.c208
-rw-r--r--com32/gfxboot/Makefile4
-rw-r--r--com32/gfxboot/gfxboot.c2
-rw-r--r--com32/gpllib/Makefile14
-rw-r--r--com32/gpllib/disk/geom.c11
-rw-r--r--com32/gpllib/disk/read.c25
-rw-r--r--com32/gpllib/disk/write.c26
-rw-r--r--com32/gpllib/memory.c15
-rw-r--r--com32/hdt/Makefile5
-rw-r--r--com32/hdt/hdt-cli.c2
-rw-r--r--com32/hdt/hdt-common.c20
-rw-r--r--com32/hdt/hdt-common.h3
-rw-r--r--com32/hdt/hdt.c2
-rw-r--r--com32/include/byteswap.h50
-rw-r--r--com32/include/cli.h20
-rw-r--r--com32/include/com32.h14
-rw-r--r--com32/include/dprintf.h17
-rw-r--r--com32/include/errno.h21
-rw-r--r--com32/include/fcntl.h1
-rw-r--r--com32/include/hw/vga.h104
-rw-r--r--com32/include/klibc/compiler.h15
-rw-r--r--com32/include/linux/list.h464
-rw-r--r--com32/include/menu.h (renamed from com32/menu/menu.h)10
-rw-r--r--com32/include/netinet/in.h50
-rw-r--r--com32/include/refstr.h (renamed from com32/menu/refstr.h)0
-rw-r--r--com32/include/sort.h18
-rw-r--r--com32/include/stddef.h8
-rw-r--r--com32/include/stdio.h28
-rw-r--r--com32/include/sys/cpu.h31
-rw-r--r--com32/include/sys/elfcommon.h231
-rw-r--r--com32/include/sys/exec.h79
-rw-r--r--com32/include/sys/module.h374
-rw-r--r--com32/include/sys/times.h8
-rw-r--r--com32/include/syslinux/boot.h13
-rw-r--r--com32/include/syslinux/config.h13
-rw-r--r--com32/include/syslinux/debug.h15
-rw-r--r--com32/include/syslinux/disk.h7
-rw-r--r--com32/include/syslinux/features.h50
-rw-r--r--com32/include/syslinux/pmapi.h5
-rw-r--r--com32/include/syslinux/pxe_api.h26
-rw-r--r--com32/include/syslinux/sysappend.h (renamed from com32/lib/syslinux/features.c)46
-rw-r--r--com32/lib/Makefile291
-rw-r--r--com32/lib/asprintf.c5
-rw-r--r--com32/lib/bufprintf.c8
-rw-r--r--com32/lib/chdir.c15
-rw-r--r--com32/lib/dprintf.c10
-rw-r--r--com32/lib/elf32.ld171
-rw-r--r--com32/lib/errno.c7
-rw-r--r--com32/lib/exit.c24
-rw-r--r--com32/lib/free.c113
-rw-r--r--com32/lib/getcwd.c3
-rw-r--r--com32/lib/init.h15
-rw-r--r--com32/lib/libpng/libpng.txt2959
-rw-r--r--com32/lib/lmalloc.c13
-rw-r--r--com32/lib/makeerrlist.pl98
-rw-r--r--com32/lib/malloc.c156
-rw-r--r--com32/lib/onexit.c3
-rw-r--r--com32/lib/realloc.c98
-rw-r--r--com32/lib/strerror.c28
-rw-r--r--com32/lib/sys/ansicon_write.c4
-rw-r--r--com32/lib/sys/exit.S41
-rw-r--r--com32/lib/sys/file.h3
-rw-r--r--com32/lib/sys/fileclose.c3
-rw-r--r--com32/lib/sys/fileread.c5
-rw-r--r--com32/lib/sys/gpxe.c19
-rw-r--r--com32/lib/sys/module/common.c599
-rw-r--r--com32/lib/sys/module/common.h73
-rw-r--r--com32/lib/sys/module/elf_module.c631
-rw-r--r--com32/lib/sys/module/elfutils.c89
-rw-r--r--com32/lib/sys/module/elfutils.h64
-rw-r--r--com32/lib/sys/module/exec.c234
-rw-r--r--com32/lib/sys/open.c6
-rw-r--r--com32/lib/sys/rawcon_read.c26
-rw-r--r--com32/lib/sys/rawcon_write.c8
-rw-r--r--com32/lib/sys/readdir.c30
-rw-r--r--com32/lib/sys/screensize.c2
-rw-r--r--com32/lib/sys/serial_write.c8
-rw-r--r--com32/lib/sys/stdcon_write.c15
-rw-r--r--com32/lib/sys/times.c42
-rw-r--r--com32/lib/sys/vesa/background.c1
-rw-r--r--com32/lib/sys/xserial_write.c8
-rw-r--r--com32/lib/syslinux/cleanup.c12
-rw-r--r--com32/lib/syslinux/config.c41
-rw-r--r--com32/lib/syslinux/debug.c95
-rw-r--r--com32/lib/syslinux/disk.c204
-rw-r--r--com32/lib/syslinux/idle.c5
-rw-r--r--com32/lib/syslinux/initramfs_file.c15
-rw-r--r--com32/lib/syslinux/ipappend.c23
-rw-r--r--com32/lib/syslinux/keyboard.c14
-rw-r--r--com32/lib/syslinux/load_linux.c147
-rw-r--r--com32/lib/syslinux/localboot.c10
-rw-r--r--com32/lib/syslinux/pxe_dns.c14
-rw-r--r--com32/lib/syslinux/pxe_get_cached.c11
-rw-r--r--com32/lib/syslinux/pxe_get_nic.c12
-rw-r--r--com32/lib/syslinux/run_command.c9
-rw-r--r--com32/lib/syslinux/run_default.c10
-rw-r--r--com32/lib/syslinux/runimage.c37
-rw-r--r--com32/lib/syslinux/serial.c21
-rw-r--r--com32/lib/syslinux/shuffle.c13
-rw-r--r--com32/lib/syslinux/version.c21
-rw-r--r--com32/lib/syslinux/video/fontquery.c16
-rw-r--r--com32/lib/syslinux/video/forcetext.c42
-rw-r--r--com32/lib/syslinux/video/reportmode.c11
-rw-r--r--com32/lib/vdprintf.c13
-rw-r--r--com32/lib/zalloc.c17
-rw-r--r--com32/libupload/upload_tftp.c18
-rw-r--r--com32/libutil/Makefile17
-rw-r--r--com32/libutil/ansiraw.c19
-rw-r--r--com32/libutil/include/getkey.h3
-rw-r--r--com32/libutil/quicksort.c59
-rw-r--r--com32/lua/etc/luavs.bat56
-rw-r--r--com32/lua/src/Makefile13
-rw-r--r--com32/lua/src/vesa.c31
-rw-r--r--com32/mboot/Makefile2
-rw-r--r--com32/mboot/initvesa.c43
-rw-r--r--com32/mboot/mem.c35
-rw-r--r--com32/menu/Makefile4
-rw-r--r--com32/menu/execute.c69
-rw-r--r--com32/menu/menumain.c12
-rw-r--r--com32/menu/readconfig.c43
-rw-r--r--com32/modules/Makefile16
-rw-r--r--com32/modules/cat.c2
-rw-r--r--com32/modules/cmd.c2
-rw-r--r--com32/modules/config.c2
-rw-r--r--com32/modules/cptime.c284
-rw-r--r--com32/modules/cpuid.c2
-rw-r--r--com32/modules/cpuidtest.c1
-rw-r--r--com32/modules/debug.c54
-rw-r--r--com32/modules/dir.c175
-rw-r--r--com32/modules/disk.c2
-rw-r--r--com32/modules/dmitest.c1
-rw-r--r--com32/modules/elf.c2
-rw-r--r--com32/modules/ethersel.c1
-rw-r--r--com32/modules/gpxecmd.c18
-rw-r--r--com32/modules/hexdump.c245
-rw-r--r--com32/modules/host.c44
-rw-r--r--com32/modules/ifplop.c2
-rw-r--r--com32/modules/kbdmap.c2
-rw-r--r--com32/modules/linux.c202
-rw-r--r--com32/modules/ls.c2
-rw-r--r--com32/modules/meminfo.c20
-rw-r--r--com32/modules/pcitest.c2
-rw-r--r--com32/modules/pmload.c2
-rw-r--r--com32/modules/poweroff.c88
-rw-r--r--com32/modules/prdhcp.c4
-rw-r--r--com32/modules/pwd.c1
-rw-r--r--com32/modules/pxechn.c24
-rw-r--r--com32/modules/sanboot.c18
-rw-r--r--com32/modules/sdi.c2
-rw-r--r--com32/modules/vesainfo.c46
-rw-r--r--com32/modules/vpdtest.c1
-rw-r--r--com32/modules/whichsys.c2
-rw-r--r--com32/rosh/Makefile2
-rw-r--r--com32/samples/Makefile4
-rw-r--r--com32/samples/hello.c37
-rw-r--r--com32/samples/resolv.c17
-rw-r--r--com32/sysdump/Makefile4
-rw-r--r--com32/sysdump/README2
-rw-r--r--com32/sysdump/main.c1
199 files changed, 13505 insertions, 2592 deletions
diff --git a/com32/Makefile b/com32/Makefile
index b59fd3f9..c4699cfd 100644
--- a/com32/Makefile
+++ b/com32/Makefile
@@ -1,5 +1,5 @@
-SUBDIRS = libupload tools lib gpllib libutil modules mboot menu samples rosh cmenu \
- hdt gfxboot sysdump lua/src chain
+SUBDIRS = libupload tools lib elflink/ldlinux gpllib libutil modules mboot \
+ menu samples elflink rosh cmenu hdt gfxboot sysdump lua/src chain
all tidy dist clean spotless install:
set -e; for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done
diff --git a/com32/chain/Makefile b/com32/chain/Makefile
index 9d398a85..c7587eae 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
@@ -14,13 +16,14 @@
topdir = ../..
MAKEDIR = $(topdir)/mk
-include $(MAKEDIR)/com32.mk
+include $(MAKEDIR)/elf.mk
OBJS = chain.o partiter.o utility.o options.o mangle.o
+CFLAGS += -fno-strict-aliasing
all: chain.c32
-chain.elf: $(OBJS) $(LIBS) $(C_LIBS)
+chain.elf: $(OBJS) $(C_LIBS)
$(LD) $(LDFLAGS) -o $@ $^
%.o: %.c
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 fb59551b..b17997f7 100644
--- a/com32/chain/utility.c
+++ b/com32/chain/utility.c
@@ -1,10 +1,43 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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>
#include <unistd.h>
#include <string.h>
+#include <fs.h>
#include <syslinux/disk.h>
+#include <syslinux/pmapi.h>
#include "utility.h"
static const char *bpbtypes[] = {
@@ -16,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;
@@ -46,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;
@@ -59,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) {
@@ -80,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;
}
@@ -93,54 +140,43 @@ void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, uint32_t m
uint32_t get_file_lba(const char *filename)
{
- com32sys_t inregs;
- uint32_t lba;
+ struct com32_filedata fd;
+ uint32_t lba = 0;
+ int size = 65536;
+ char *buf;
- /* Start with clean registers */
- memset(&inregs, 0, sizeof(com32sys_t));
+ buf = lmalloc(size);
+ if (!buf)
+ return 0;
/* Put the filename in the bounce buffer */
- strlcpy(__com32.cs_bounce, filename, __com32.cs_bounce_size);
-
- /* Call comapi_open() which returns a structure pointer in SI
- * to a structure whose first member happens to be the LBA.
- */
- inregs.eax.w[0] = 0x0006;
- inregs.esi.w[0] = OFFS(__com32.cs_bounce);
- inregs.es = SEG(__com32.cs_bounce);
- __com32.cs_intcall(0x22, &inregs, &inregs);
+ strlcpy(buf, filename, size);
- if ((inregs.eflags.l & EFLAGS_CF) || inregs.esi.w[0] == 0) {
- return 0; /* Filename not found */
+ if (open_file(buf, O_RDONLY, &fd) <= 0) {
+ goto fail; /* Filename not found */
}
/* Since the first member is the LBA, we simply cast */
- lba = *((uint32_t *) MK_PTR(inregs.ds, inregs.esi.w[0]));
-
- /* Clean the registers for the next call */
- memset(&inregs, 0, sizeof(com32sys_t));
-
- /* Put the filename in the bounce buffer */
- strlcpy(__com32.cs_bounce, filename, __com32.cs_bounce_size);
+ lba = *((uint32_t *) MK_PTR(0, fd.handle));
/* Call comapi_close() to free the structure */
- inregs.eax.w[0] = 0x0008;
- inregs.esi.w[0] = OFFS(__com32.cs_bounce);
- inregs.es = SEG(__com32.cs_bounce);
- __com32.cs_intcall(0x22, &inregs, &inregs);
+ close_file(fd.handle);
+fail:
+ lfree(buf);
return lba;
}
/* 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;
}
@@ -152,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/cmenu/Makefile b/com32/cmenu/Makefile
index 446bbcdd..d51b2e84 100644
--- a/com32/cmenu/Makefile
+++ b/com32/cmenu/Makefile
@@ -17,41 +17,42 @@
NOGPL := 1
-# This must be defined before com32.mk is included
-LIBS = libmenu/libmenu.a
+LIBS = libmenu/libmenu.c32 \
+ $(com32)/libutil/libutil.c32 \
+ $(com32)/lib/libcom32.c32
topdir = ../..
MAKEDIR = $(topdir)/mk
-include $(MAKEDIR)/com32.mk
+include $(MAKEDIR)/elf.mk
CFLAGS += -I./libmenu
LIBMENU = libmenu/syslnx.o libmenu/com32io.o libmenu/tui.o \
- libmenu/menu.o libmenu/passwords.o libmenu/des.o libmenu/help.o
+ libmenu/menu.o libmenu/passwords.o libmenu/des.o libmenu/help.o \
+ $(com32)/libutil/libutil.c32 $(com32)/lib/libcom32.c32
CMENUS = $(patsubst %.c,%.c32,$(wildcard *.c))
IMENUS = $(patsubst %.menu,%.c32,$(wildcard *.menu))
-MENUS = $(CMENUS) $(IMENUS)
+MENUS = $(LIBS) $(CMENUS) $(IMENUS)
.SUFFIXES: .S .c .o .elf .c32 .menu
.PRECIOUS: %.c
%.c: %.menu adv_menu.tpl
- python menugen.py --input=$< --output=$@ --template=adv_menu.tpl
+ $(PYTHON) menugen.py --input=$< --output=$@ --template=adv_menu.tpl
-all: menus
+all: menus
-libmenu/libmenu.a: $(LIBMENU)
- -rm -f $@
- $(AR) cq $@ $^
- $(RANLIB) $@
+libmenu/libmenu.elf: $(LIBMENU)
+ $(LD) -shared $(LDFLAGS) -soname $(patsubst %.elf,%.c32,$(@F)) \
+ -o $@ $^
tidy dist:
- rm -f *.o *.lo *.a *.lst *.elf .*.d */.*.d
+ rm -f *.o *.lo *.lst *.elf */*.o */*.elf .*.d */.*.d
libclean:
- rm -f libmenu/*.o libmenu/*.a
+ rm -f libmenu/*.c32
clean: tidy menuclean libclean
rm -f *.lss *.c32 *.com
diff --git a/com32/cmenu/adv_menu.tpl b/com32/cmenu/adv_menu.tpl
index e60383f8..89317095 100644
--- a/com32/cmenu/adv_menu.tpl
+++ b/com32/cmenu/adv_menu.tpl
@@ -34,7 +34,7 @@ modify this template to suit your needs
#define NULL ((void *) 0)
#endif
-#include "menu.h"
+#include "cmenu.h"
#include "help.h"
#include "passwords.h"
#include "com32io.h"
diff --git a/com32/cmenu/complex.c b/com32/cmenu/complex.c
index b80005d1..d6658fb3 100644
--- a/com32/cmenu/complex.c
+++ b/com32/cmenu/complex.c
@@ -14,7 +14,7 @@
#define NULL ((void *) 0)
#endif
-#include "menu.h"
+#include "cmenu.h"
#include "com32io.h"
#include "help.h"
#include "passwords.h"
diff --git a/com32/cmenu/display.c b/com32/cmenu/display.c
index 3acdf6aa..59612f9f 100644
--- a/com32/cmenu/display.c
+++ b/com32/cmenu/display.c
@@ -16,7 +16,7 @@
#include "help.h"
#include "com32io.h"
-#include "menu.h"
+#include "cmenu.h"
#include "tui.h"
#include <stdlib.h>
#include <com32.h>
diff --git a/com32/cmenu/libmenu/menu.h b/com32/cmenu/libmenu/cmenu.h
index 141d2ef0..141d2ef0 100644
--- a/com32/cmenu/libmenu/menu.h
+++ b/com32/cmenu/libmenu/cmenu.h
diff --git a/com32/cmenu/libmenu/help.h b/com32/cmenu/libmenu/help.h
index de01b46e..383cc3c5 100644
--- a/com32/cmenu/libmenu/help.h
+++ b/com32/cmenu/libmenu/help.h
@@ -13,7 +13,7 @@
#ifndef __HELP_H_
#define __HELP_H_
-#include "menu.h"
+#include "cmenu.h"
#include "com32io.h"
#include "tui.h"
#include <string.h>
diff --git a/com32/cmenu/libmenu/menu.c b/com32/cmenu/libmenu/menu.c
index 19a7e598..9b1e7ad0 100644
--- a/com32/cmenu/libmenu/menu.c
+++ b/com32/cmenu/libmenu/menu.c
@@ -10,7 +10,7 @@
*
* ----------------------------------------------------------------------- */
-#include "menu.h"
+#include "cmenu.h"
#include "com32io.h"
#include <stdlib.h>
#include <console.h>
diff --git a/com32/cmenu/libmenu/syslnx.c b/com32/cmenu/libmenu/syslnx.c
index 53e2401b..5060c5db 100644
--- a/com32/cmenu/libmenu/syslnx.c
+++ b/com32/cmenu/libmenu/syslnx.c
@@ -12,84 +12,53 @@
#include <string.h>
#include <com32.h>
+#include <core.h>
+#include <graphics.h>
#include "syslnx.h"
+#include <syslinux/config.h>
com32sys_t inreg, outreg; // Global registers for this module
-char issyslinux(void)
-{
- REG_EAX(inreg) = 0x00003000;
- REG_EBX(inreg) = REG_ECX(inreg) = REG_EDX(inreg) = 0xFFFFFFFF;
- __intcall(0x21, &inreg, &outreg);
- return (REG_EAX(outreg) == 0x59530000) &&
- (REG_EBX(outreg) == 0x4c530000) &&
- (REG_ECX(outreg) == 0x4e490000) && (REG_EDX(outreg) == 0x58550000);
-}
-
void runsyslinuxcmd(const char *cmd)
{
- strcpy(__com32.cs_bounce, cmd);
- REG_AX(inreg) = 0x0003; // Run command
- REG_BX(inreg) = OFFS(__com32.cs_bounce);
- REG_ES(inreg) = SEG(__com32.cs_bounce);
- __intcall(0x22, &inreg, &outreg);
+ char *bounce;
+
+ bounce = lmalloc(strlen(cmd) + 1);
+ if (!bounce)
+ return;
+
+ strcpy(bounce, cmd);
+ load_kernel(bounce);
}
void gototxtmode(void)
{
- REG_AX(inreg) = 0x0005;
- __intcall(0x22, &inreg, &outreg);
+ syslinux_force_text_mode();
}
void syslinux_idle(void)
{
- REG_AX(inreg) = 0x0013;
- __intcall(0x22, &inreg, &outreg);
+ __idle();
}
unsigned int getversion(char *deriv, unsigned int *numfun)
{
- REG_AX(inreg) = 0x0001;
- __intcall(0x22, &inreg, &outreg);
if (deriv)
- *deriv = REG_DL(outreg);
+ *deriv = __syslinux_version.filesystem;
if (numfun)
- *numfun = REG_AX(outreg);
- return REG_CX(outreg);
+ *numfun = __syslinux_version.max_api;
+ return __syslinux_version.version;
}
-void runsyslinuximage(const char *cmd, long ipappend)
+char issyslinux(void)
{
- unsigned int numfun = 0;
- char *ptr, *cmdline;
+ return !!getversion(NULL, NULL);
+}
+void runsyslinuximage(const char *cmd, long ipappend)
+{
(void)ipappend; // XXX: Unused?!
- getversion(NULL, &numfun);
- // Function 16h not supported Fall back to runcommand
- if (numfun < 0x16)
- runsyslinuxcmd(cmd);
- // Try the Run Kernel Image function
- // Split command line into
- strcpy(__com32.cs_bounce, cmd);
- ptr = __com32.cs_bounce;
- // serach for first space or end of string
- while ((*ptr) && (*ptr != ' '))
- ptr++;
- if (!*ptr)
- cmdline = ptr; // no command line
- else {
- *ptr++ = '\0'; // terminate kernal name
- cmdline = ptr + 1;
- while (*cmdline != ' ')
- cmdline++; // find first non-space
- }
- // Now call the interrupt
- REG_BX(inreg) = OFFS(cmdline);
- REG_ES(inreg) = SEG(cmdline);
- REG_SI(inreg) = OFFS(__com32.cs_bounce);
- REG_DS(inreg) = SEG(__com32.cs_bounce);
- REG_EDX(inreg) = 0;
-
- __intcall(0x22, &inreg, &outreg); // If successful does not return
+ getversion(NULL, NULL);
+ runsyslinuxcmd(cmd);
}
diff --git a/com32/cmenu/simple.c b/com32/cmenu/simple.c
index 4f602a9a..ba9669fc 100644
--- a/com32/cmenu/simple.c
+++ b/com32/cmenu/simple.c
@@ -14,7 +14,7 @@
#define NULL ((void *) 0)
#endif
-#include "menu.h"
+#include "cmenu.h"
#include "com32io.h"
#include <string.h>
diff --git a/com32/elflink/Makefile b/com32/elflink/Makefile
new file mode 100644
index 00000000..fce1be8c
--- /dev/null
+++ b/com32/elflink/Makefile
@@ -0,0 +1,36 @@
+## -----------------------------------------------------------------------
+##
+## Copyright 2001-2008 H. Peter Anvin - 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., 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.
+##
+## -----------------------------------------------------------------------
+
+MODULES =
+TESTFILES =
+
+all: $(MODULES) $(TESTFILES)
+
+test_memalign.elf : test_memalign.o $(LIBS) $(C_LIBS)
+ $(LD) $(LDFLAGS) -o $@ $^
+
+test_com32.elf: CFLAGS += -DELF_DEBUG
+test_com32.elf: test_com32.o ../lib/libcom32min.a $(LIBGCC)
+ $(LD) -n $(LDFLAGS) -o $@ test_com32.o $(LIBGCC) --whole-archive ../lib/libcom32min.a -Map test_com32.map
+
+tidy dist:
+ rm -f *.o *.lo *.a *.lst *.elf .*.d *.map
+
+clean: tidy
+ rm -f *.lss *.c32 *.lnx *.com
+
+spotless: clean
+ rm -f *~ \#*
+
+install:
+
+-include .*.d
diff --git a/com32/elflink/ldlinux/Makefile b/com32/elflink/ldlinux/Makefile
new file mode 100644
index 00000000..556f93a5
--- /dev/null
+++ b/com32/elflink/ldlinux/Makefile
@@ -0,0 +1,50 @@
+## -----------------------------------------------------------------------
+##
+## Copyright 2011-2013 Intel Corporation - 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., 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.
+##
+## -----------------------------------------------------------------------
+
+topdir = ../../..
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/elf.mk
+
+CFLAGS += -I$(topdir)/core/elflink -I$(topdir)/core/include -I$(topdir)/com32/lib -fvisibility=hidden
+LIBS = --whole-archive $(com32)/lib/libcom32min.a
+
+BTARGET = ldlinux.c32
+
+all: $(BTARGET) ldlinux_lnx.a
+
+ldlinux.elf : ldlinux.o cli.o readconfig.o refstr.o colors.o getadv.o \
+ adv.o execute.o chainboot.o kernel.o get_key.o \
+ advwrite.o setadv.o loadhigh.o msg.o
+ $(LD) $(LDFLAGS) -soname $(patsubst %.elf,%.c32,$(@F)) -o $@ $^ $(LIBS)
+
+LNXCFLAGS += -D__export='__attribute__((visibility("default")))'
+LNXLIBOBJS = get_key.lo
+ldlinux_lnx.a: $(LNXLIBOBJS)
+ rm -f $@
+ $(AR) cq $@ $(LNXLIBOBJS)
+ $(RANLIB) $@
+
+tidy dist:
+ rm -f *.o *.lo *.a *.lst .*.d
+
+clean: tidy
+ rm -f *.lss *.lnx *.com
+
+spotless: clean
+ rm -f *~ \#* $(BTARGET)
+
+install: all
+ mkdir -m 755 -p $(INSTALLROOT)$(AUXDIR)
+ install -m 644 $(BTARGET) $(INSTALLROOT)$(AUXDIR)
+
+
+-include .*.d
diff --git a/com32/lib/syslinux/adv.c b/com32/elflink/ldlinux/adv.c
index be38e89d..4c3ad508 100644
--- a/com32/lib/syslinux/adv.c
+++ b/com32/elflink/ldlinux/adv.c
@@ -33,15 +33,21 @@
#include <syslinux/adv.h>
#include <klibc/compiler.h>
+#include <inttypes.h>
#include <com32.h>
-void *__syslinux_adv_ptr;
-size_t __syslinux_adv_size;
+__export void *__syslinux_adv_ptr;
+__export size_t __syslinux_adv_size;
-void __constructor __syslinux_get_adv(void)
+extern void adv_init(void);
+void __constructor __syslinux_init(void)
{
static com32sys_t reg;
+ /* Initialize the ADV structure */
+ reg.eax.w[0] = 0x0025;
+ __intcall(0x22, &reg, NULL);
+
reg.eax.w[0] = 0x001c;
__intcall(0x22, &reg, &reg);
__syslinux_adv_ptr = MK_PTR(reg.es, reg.ebx.w[0]);
diff --git a/com32/lib/syslinux/advwrite.c b/com32/elflink/ldlinux/advwrite.c
index 4152eea5..35829c1c 100644
--- a/com32/lib/syslinux/advwrite.c
+++ b/com32/elflink/ldlinux/advwrite.c
@@ -35,7 +35,7 @@
#include <klibc/compiler.h>
#include <com32.h>
-int syslinux_adv_write(void)
+__export int syslinux_adv_write(void)
{
static com32sys_t reg;
diff --git a/com32/elflink/ldlinux/chainboot.c b/com32/elflink/ldlinux/chainboot.c
new file mode 100644
index 00000000..27d4618c
--- /dev/null
+++ b/com32/elflink/ldlinux/chainboot.c
@@ -0,0 +1,156 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2012 Intel Corporation, author: H. Peter Anvin
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * chainbooting - replace the current bootloader completely. This
+ * is BIOS-specific.
+ */
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <dprintf.h>
+
+#include <com32.h>
+#include <sys/exec.h>
+#include <sys/io.h>
+#include "core.h"
+#include "menu.h"
+#include "fs.h"
+#include "config.h"
+#include "localboot.h"
+#include "bios.h"
+
+#include <syslinux/boot.h>
+#include <syslinux/bootrm.h>
+#include <syslinux/movebits.h>
+#include <syslinux/config.h>
+
+void chainboot_file(const char *file, uint32_t type)
+{
+ uint8_t keeppxe = 0;
+ const union syslinux_derivative_info *sdi;
+ struct syslinux_rm_regs regs;
+ struct syslinux_movelist *fraglist = NULL;
+ struct syslinux_memmap *mmap = NULL;
+ struct com32_filedata fd;
+ com32sys_t reg;
+ char *stack;
+ void *buf;
+ int rv, max, size;
+
+ max = 0xA0000; /* Maximum load */
+ buf = malloc(max);
+ if (!buf)
+ goto bail;
+
+ rv = open_file(file, O_RDONLY, &fd);
+ if (rv == -1)
+ goto bail;
+
+ reg.eax.l = max;
+ reg.ebx.l = 0;
+ reg.edx.w[0] = 0;
+ reg.edi.l = (uint32_t)buf;
+ reg.ebp.l = -1; /* XXX: limit? */
+ reg.esi.w[0] = rv;
+
+ pm_load_high(&reg);
+
+ size = reg.edi.l - (unsigned long)buf;
+ if (size > 0xA0000 - 0x7C00) {
+ printf("Too large for a boostrap (need LINUX instead of KERNEL?)\n");
+ goto bail;
+ }
+
+ mmap = syslinux_memory_map();
+ if (!mmap)
+ goto bail;
+
+ sdi = syslinux_derivative_info();
+
+ memset(&regs, 0, sizeof(regs));
+ regs.ip = 0x7c00;
+
+ if (sdi->c.filesystem == SYSLINUX_FS_SYSLINUX ||
+ sdi->c.filesystem == SYSLINUX_FS_EXTLINUX) {
+ if (syslinux_add_movelist(&fraglist, 0x800 - 18,
+ (addr_t)sdi->r.esbx, 16))
+ goto bail;
+
+ /* DS:SI points to partition info */
+ regs.esi.l = 0x800 - 18;
+ }
+
+ /*
+ * For a BSS boot sector we have to transfer the
+ * superblock.
+ */
+ if (sdi->c.filesystem == SYSLINUX_FS_SYSLINUX &&
+ type == IMAGE_TYPE_BSS && this_fs->fs_ops->copy_super(buf))
+ goto bail;
+
+ if (sdi->c.filesystem == SYSLINUX_FS_PXELINUX) {
+ keeppxe = 0x03; /* Chainloading + keep PXE */
+ stack = (char *)sdi->r.fssi;
+
+ /*
+ * Set up the registers with their initial values
+ */
+
+ regs.eax.l = *(uint32_t *)&stack[36];
+ regs.ecx.l = *(uint32_t *)&stack[32];
+ regs.edx.l = *(uint32_t *)&stack[28];
+ regs.ebx.l = *(uint32_t *)&stack[24];
+ regs.esp.l = sdi->rr.r.esi.w[0] + 44;
+ regs.ebp.l = *(uint32_t *)&stack[16];
+ regs.esi.l = *(uint32_t *)&stack[12];
+ regs.edi.l = *(uint32_t *)&stack[8];
+ regs.es = *(uint16_t *)&stack[4];
+ regs.ss = sdi->rr.r.fs;
+ regs.ds = *(uint16_t *)&stack[6];
+ regs.fs = *(uint16_t *)&stack[2];
+ regs.gs = *(uint16_t *)&stack[0];
+ } else {
+ const uint16_t *esdi = (const uint16_t *)sdi->disk.esdi_ptr;
+
+ regs.esp.l = (uint16_t)(unsigned long)StackBuf + 44;
+
+ /*
+ * DON'T DO THIS FOR PXELINUX...
+ * For PXE, ES:BX -> PXENV+, and this would
+ * corrupt that use.
+ *
+ * Restore ES:DI -> $PnP (if we were ourselves
+ * called that way...)
+ */
+ regs.edi.w[0] = esdi[0]; /* New DI */
+ regs.es = esdi[2]; /* New ES */
+
+ regs.edx.l = sdi->rr.r.edx.b[0]; /* Drive number -> DL */
+ }
+
+ if (syslinux_add_movelist(&fraglist, 0x7c00, (addr_t)buf, size))
+ goto bail;
+
+ syslinux_shuffle_boot_rm(fraglist, mmap, keeppxe, &regs);
+
+bail:
+ if (fraglist)
+ syslinux_free_movelist(fraglist);
+ if (mmap)
+ syslinux_free_memmap(mmap);
+ if (buf)
+ free(buf);
+ return;
+}
diff --git a/com32/elflink/ldlinux/cli.c b/com32/elflink/ldlinux/cli.c
new file mode 100644
index 00000000..6ff30c64
--- /dev/null
+++ b/com32/elflink/ldlinux/cli.c
@@ -0,0 +1,486 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <console.h>
+#include <com32.h>
+#include <syslinux/adv.h>
+#include <syslinux/config.h>
+#include <setjmp.h>
+#include <netinet/in.h>
+#include <limits.h>
+#include <minmax.h>
+#include <linux/list.h>
+#include <sys/exec.h>
+#include <sys/module.h>
+#include <dprintf.h>
+#include <core.h>
+
+#include "getkey.h"
+#include "menu.h"
+#include "cli.h"
+#include "config.h"
+
+static struct list_head cli_history_head;
+
+void clear_screen(void)
+{
+ //dprintf("enter");
+ fputs("\033e\033%@\033)0\033(B\1#0\033[?25l\033[2J", stdout);
+}
+
+static int mygetkey_timeout(clock_t *kbd_to, clock_t *tto)
+{
+ clock_t t0, t1;
+ int key;
+
+ t0 = times(NULL);
+ key = get_key(stdin, *kbd_to ? *kbd_to : *tto);
+
+ /* kbdtimeout only applies to the first character */
+ if (*kbd_to)
+ *kbd_to = 0;
+
+ t1 = times(NULL) - t0;
+ if (*tto) {
+ /* Timed out. */
+ if (*tto <= (long long)t1)
+ key = KEY_NONE;
+ else {
+ /* Did it wrap? */
+ if (*tto > totaltimeout)
+ key = KEY_NONE;
+
+ *tto -= t1;
+ }
+ }
+
+ return key;
+}
+
+static const char * cmd_reverse_search(int *cursor, clock_t *kbd_to,
+ clock_t *tto)
+{
+ int key;
+ int i = 0;
+ char buf[MAX_CMDLINE_LEN];
+ const char *p = NULL;
+ struct cli_command *last_found;
+ struct cli_command *last_good = NULL;
+
+ last_found = list_entry(cli_history_head.next, typeof(*last_found), list);
+
+ memset(buf, 0, MAX_CMDLINE_LEN);
+
+ printf("\033[1G\033[1;36m(reverse-i-search)`': \033[0m");
+ while (1) {
+ key = mygetkey_timeout(kbd_to, tto);
+
+ if (key == KEY_CTRL('C')) {
+ return NULL;
+ } else if (key == KEY_CTRL('R')) {
+ if (i == 0)
+ continue; /* User typed nothing yet */
+ /* User typed 'CTRL-R' again, so try the next */
+ last_found = list_entry(last_found->list.next, typeof(*last_found), list);
+ } else if (key >= ' ' && key <= 'z') {
+ buf[i++] = key;
+ } else {
+ /* Treat other input chars as terminal */
+ break;
+ }
+
+ while (last_found) {
+ p = strstr(last_found->command, buf);
+ if (p)
+ break;
+
+ if (list_is_last(&last_found->list, &cli_history_head))
+ break;
+
+ last_found = list_entry(last_found->list.next, typeof(*last_found), list);
+ }
+
+ if (!p && !last_good) {
+ return NULL;
+ } else if (!p) {
+ continue;
+ } else {
+ last_good = last_found;
+ *cursor = p - last_good->command;
+ }
+
+ printf("\033[?7l\033[?25l");
+ /* Didn't handle the line wrap case here */
+ printf("\033[1G\033[1;36m(reverse-i-search)\033[0m`%s': %s",
+ buf, last_good->command ? : "");
+ printf("\033[K\r");
+ }
+
+ return last_good ? last_good->command : NULL;
+}
+
+
+
+const char *edit_cmdline(const char *input, int top /*, int width */ ,
+ int (*pDraw_Menu) (int, int, int),
+ void (*show_fkey) (int), bool *timedout)
+{
+ char cmdline[MAX_CMDLINE_LEN] = { };
+ int key, len, prev_len, cursor;
+ int redraw = 0;
+ int x, y;
+ bool done = false;
+ const char *ret;
+ int width = 0;
+ struct cli_command *comm_counter = NULL;
+ clock_t kbd_to = kbdtimeout;
+ clock_t tto = totaltimeout;
+
+ if (!width) {
+ int height;
+ if (getscreensize(1, &height, &width))
+ width = 80;
+ }
+
+ len = cursor = 0;
+ prev_len = 0;
+ x = y = 0;
+
+ /*
+ * Before we start messing with the x,y coordinates print 'input'
+ * so that it follows whatever text has been written to the screen
+ * previously.
+ */
+ printf("%s ", input);
+
+ while (!done) {
+ if (redraw > 1) {
+ /* Clear and redraw whole screen */
+ /* Enable ASCII on G0 and DEC VT on G1; do it in this order
+ to avoid confusing the Linux console */
+ clear_screen();
+ if (pDraw_Menu)
+ (*pDraw_Menu) (-1, top, 1);
+ prev_len = 0;
+ printf("\033[2J\033[H");
+ // printf("\033[0m\033[2J\033[H");
+ }
+
+ if (redraw > 0) {
+ int dy, at;
+
+ prev_len = max(len, prev_len);
+
+ /* Redraw the command line */
+ printf("\033[?25l");
+ printf("\033[1G%s ", input);
+
+ x = strlen(input);
+ y = 0;
+ at = 0;
+ while (at < prev_len) {
+ putchar(at >= len ? ' ' : cmdline[at]);
+ at++;
+ x++;
+ if (x >= width) {
+ printf("\r\n");
+ x = 0;
+ y++;
+ }
+ }
+ printf("\033[K\r");
+
+ dy = y - (cursor + strlen(input) + 1) / width;
+ x = (cursor + strlen(input) + 1) % width;
+
+ if (dy) {
+ printf("\033[%dA", dy);
+ y -= dy;
+ }
+ if (x)
+ printf("\033[%dC", x);
+ printf("\033[?25h");
+ prev_len = len;
+ redraw = 0;
+ }
+
+ key = mygetkey_timeout(&kbd_to, &tto);
+
+ switch (key) {
+ case KEY_NONE:
+ /* We timed out. */
+ *timedout = true;
+ return NULL;
+
+ case KEY_CTRL('L'):
+ redraw = 2;
+ break;
+
+ case KEY_ENTER:
+ case KEY_CTRL('J'):
+ ret = cmdline;
+ done = true;
+ break;
+
+ case KEY_BACKSPACE:
+ case KEY_DEL:
+ if (cursor) {
+ memmove(cmdline + cursor - 1, cmdline + cursor,
+ len - cursor + 1);
+ len--;
+ cursor--;
+ redraw = 1;
+ }
+ break;
+
+ case KEY_CTRL('D'):
+ case KEY_DELETE:
+ if (cursor < len) {
+ memmove(cmdline + cursor, cmdline + cursor + 1, len - cursor);
+ len--;
+ redraw = 1;
+ }
+ break;
+
+ case KEY_CTRL('U'):
+ if (len) {
+ len = cursor = 0;
+ cmdline[len] = '\0';
+ redraw = 1;
+ }
+ break;
+
+ case KEY_CTRL('W'):
+ if (cursor) {
+ int prevcursor = cursor;
+
+ while (cursor && my_isspace(cmdline[cursor - 1]))
+ cursor--;
+
+ while (cursor && !my_isspace(cmdline[cursor - 1]))
+ cursor--;
+
+#if 0
+ memmove(cmdline + cursor, cmdline + prevcursor,
+ len - prevcursor + 1);
+#else
+ {
+ int i;
+ char *q = cmdline + cursor;
+ char *p = cmdline + prevcursor;
+ for (i = 0; i < len - prevcursor + 1; i++)
+ *q++ = *p++;
+ }
+#endif
+ len -= (prevcursor - cursor);
+ redraw = 1;
+ }
+ break;
+
+ case KEY_LEFT:
+ case KEY_CTRL('B'):
+ if (cursor) {
+ cursor--;
+ redraw = 1;
+ }
+ break;
+
+ case KEY_RIGHT:
+ case KEY_CTRL('F'):
+ if (cursor < len) {
+ putchar(cmdline[cursor]);
+ cursor++;
+ x++;
+ if (x >= width) {
+ printf("\r\n");
+ y++;
+ x = 0;
+ }
+ }
+ break;
+
+ case KEY_CTRL('K'):
+ if (cursor < len) {
+ cmdline[len = cursor] = '\0';
+ redraw = 1;
+ }
+ break;
+
+ case KEY_HOME:
+ case KEY_CTRL('A'):
+ if (cursor) {
+ cursor = 0;
+ redraw = 1;
+ }
+ break;
+
+ case KEY_END:
+ case KEY_CTRL('E'):
+ if (cursor != len) {
+ cursor = len;
+ redraw = 1;
+ }
+ break;
+
+ case KEY_F1:
+ case KEY_F2:
+ case KEY_F3:
+ case KEY_F4:
+ case KEY_F5:
+ case KEY_F6:
+ case KEY_F7:
+ case KEY_F8:
+ case KEY_F9:
+ case KEY_F10:
+ case KEY_F11:
+ case KEY_F12:
+ if (show_fkey != NULL) {
+ (*show_fkey) (key);
+ redraw = 1;
+ }
+ break;
+ case KEY_CTRL('P'):
+ case KEY_UP:
+ {
+ if (!list_empty(&cli_history_head)) {
+ struct list_head *next;
+
+ if (!comm_counter)
+ next = cli_history_head.next;
+ else
+ next = comm_counter->list.next;
+
+ comm_counter =
+ list_entry(next, typeof(*comm_counter), list);
+
+ if (&comm_counter->list != &cli_history_head)
+ strcpy(cmdline, comm_counter->command);
+
+ cursor = len = strlen(cmdline);
+ redraw = 1;
+ }
+ }
+ break;
+ case KEY_CTRL('N'):
+ case KEY_DOWN:
+ {
+ if (!list_empty(&cli_history_head)) {
+ struct list_head *prev;
+
+ if (!comm_counter)
+ prev = cli_history_head.prev;
+ else
+ prev = comm_counter->list.prev;
+
+ comm_counter =
+ list_entry(prev, typeof(*comm_counter), list);
+
+ if (&comm_counter->list != &cli_history_head)
+ strcpy(cmdline, comm_counter->command);
+
+ cursor = len = strlen(cmdline);
+ redraw = 1;
+ }
+ }
+ break;
+ case KEY_CTRL('R'):
+ {
+ /*
+ * Handle this case in another function, since it's
+ * a kind of special.
+ */
+ const char *p = cmd_reverse_search(&cursor, &kbd_to, &tto);
+ if (p) {
+ strcpy(cmdline, p);
+ len = strlen(cmdline);
+ } else {
+ cmdline[0] = '\0';
+ cursor = len = 0;
+ }
+ redraw = 1;
+ }
+ break;
+ case KEY_TAB:
+ {
+ const char *p;
+ size_t len;
+
+ /* Label completion enabled? */
+ if (nocomplete)
+ break;
+
+ p = cmdline;
+ len = 0;
+ while(*p && !my_isspace(*p)) {
+ p++;
+ len++;
+ }
+
+ print_labels(cmdline, len);
+ redraw = 1;
+ break;
+ }
+ case KEY_CTRL('V'):
+ if (BIOSName)
+ printf("%s%s%s", syslinux_banner,
+ (char *)MK_PTR(0, BIOSName), copyright_str);
+ else
+ printf("%s%s", syslinux_banner, copyright_str);
+
+ redraw = 1;
+ break;
+
+ default:
+ if (key >= ' ' && key <= 0xFF && len < MAX_CMDLINE_LEN - 1) {
+ if (cursor == len) {
+ cmdline[len++] = key;
+ cmdline[len] = '\0';
+ putchar(key);
+ cursor++;
+ x++;
+ if (x >= width) {
+ printf("\r\n\033[K");
+ y++;
+ x = 0;
+ }
+ prev_len++;
+ } else {
+ if (cursor > len)
+ return NULL;
+
+ memmove(cmdline + cursor + 1, cmdline + cursor,
+ len - cursor + 1);
+ cmdline[cursor++] = key;
+ len++;
+ redraw = 1;
+ }
+ }
+ break;
+ }
+ }
+
+ printf("\033[?7h");
+
+ /* Add the command to the history if its length is larger than 0 */
+ len = strlen(ret);
+ if (len > 0) {
+ comm_counter = malloc(sizeof(struct cli_command));
+ comm_counter->command = malloc(sizeof(char) * (len + 1));
+ strcpy(comm_counter->command, ret);
+ list_add(&(comm_counter->list), &cli_history_head);
+ }
+
+ return len ? ret : NULL;
+}
+
+static int __constructor cli_init(void)
+{
+ INIT_LIST_HEAD(&cli_history_head);
+
+ return 0;
+}
+
+static void __destructor cli_exit(void)
+{
+ /* Nothing to do */
+}
diff --git a/com32/elflink/ldlinux/colors.c b/com32/elflink/ldlinux/colors.c
new file mode 100644
index 00000000..68732bdb
--- /dev/null
+++ b/com32/elflink/ldlinux/colors.c
@@ -0,0 +1,184 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004-2008 H. Peter Anvin - 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <colortbl.h>
+#include "menu.h"
+
+/*
+ * The color/attribute indexes (\1#X, \2#XX, \3#XXX) are as follows
+ *
+ * 00 - screen Rest of the screen
+ * 01 - border Border area
+ * 02 - title Title bar
+ * 03 - unsel Unselected menu item
+ * 04 - hotkey Unselected hotkey
+ * 05 - sel Selection bar
+ * 06 - hotsel Selected hotkey
+ * 07 - scrollbar Scroll bar
+ * 08 - tabmsg Press [Tab] message
+ * 09 - cmdmark Command line marker
+ * 10 - cmdline Command line
+ * 11 - pwdborder Password box border
+ * 12 - pwdheader Password box header
+ * 13 - pwdentry Password box contents
+ * 14 - timeout_msg Timeout message
+ * 15 - timeout Timeout counter
+ * 16 - help Current entry help text
+ * 17 - disabled Disabled menu item
+ */
+
+static const struct color_table default_colors[] = {
+ {"screen", "37;40", 0x80ffffff, 0x00000000, SHADOW_NORMAL},
+ {"border", "30;44", 0x40000000, 0x00000000, SHADOW_NORMAL},
+ {"title", "1;36;44", 0xc00090f0, 0x00000000, SHADOW_NORMAL},
+ {"unsel", "37;44", 0x90ffffff, 0x00000000, SHADOW_NORMAL},
+ {"hotkey", "1;37;44", 0xffffffff, 0x00000000, SHADOW_NORMAL},
+ {"sel", "7;37;40", 0xe0000000, 0x20ff8000, SHADOW_ALL},
+ {"hotsel", "1;7;37;40", 0xe0400000, 0x20ff8000, SHADOW_ALL},
+ {"scrollbar", "30;44", 0x40000000, 0x00000000, SHADOW_NORMAL},
+ {"tabmsg", "31;40", 0x90ffff00, 0x00000000, SHADOW_NORMAL},
+ {"cmdmark", "1;36;40", 0xc000ffff, 0x00000000, SHADOW_NORMAL},
+ {"cmdline", "37;40", 0xc0ffffff, 0x00000000, SHADOW_NORMAL},
+ {"pwdborder", "30;47", 0x80ffffff, 0x20ffffff, SHADOW_NORMAL},
+ {"pwdheader", "31;47", 0x80ff8080, 0x20ffffff, SHADOW_NORMAL},
+ {"pwdentry", "30;47", 0x80ffffff, 0x20ffffff, SHADOW_NORMAL},
+ {"timeout_msg", "37;40", 0x80ffffff, 0x00000000, SHADOW_NORMAL},
+ {"timeout", "1;37;40", 0xc0ffffff, 0x00000000, SHADOW_NORMAL},
+ {"help", "37;40", 0xc0ffffff, 0x00000000, SHADOW_NORMAL},
+ {"disabled", "1;30;44", 0x60cccccc, 0x00000000, SHADOW_NORMAL},
+};
+
+#define NCOLORS (sizeof default_colors/sizeof default_colors[0])
+const int message_base_color = NCOLORS;
+const int menu_color_table_size = NCOLORS + 256;
+
+/* Algorithmically generate the msgXX colors */
+void set_msg_colors_global(struct color_table *tbl,
+ unsigned int fg, unsigned int bg,
+ enum color_table_shadow shadow)
+{
+ struct color_table *cp = tbl + message_base_color;
+ unsigned int i;
+ unsigned int fga, bga;
+ unsigned int fgh, bgh;
+ unsigned int fg_idx, bg_idx;
+ unsigned int fg_rgb, bg_rgb;
+
+ static const unsigned int pc2rgb[8] =
+ { 0x000000, 0x0000ff, 0x00ff00, 0x00ffff, 0xff0000, 0xff00ff, 0xffff00,
+ 0xffffff
+ };
+
+ /* Converting PC RGBI to sensible RGBA values is an "interesting"
+ proposition. This algorithm may need plenty of tweaking. */
+
+ fga = fg & 0xff000000;
+ fgh = ((fg >> 1) & 0xff000000) | 0x80000000;
+
+ bga = bg & 0xff000000;
+ bgh = ((bg >> 1) & 0xff000000) | 0x80000000;
+
+ for (i = 0; i < 256; i++) {
+ fg_idx = i & 15;
+ bg_idx = i >> 4;
+
+ fg_rgb = pc2rgb[fg_idx & 7] & fg;
+ bg_rgb = pc2rgb[bg_idx & 7] & bg;
+
+ if (fg_idx & 8) {
+ /* High intensity foreground */
+ fg_rgb |= fgh;
+ } else {
+ fg_rgb |= fga;
+ }
+
+ if (bg_idx == 0) {
+ /* Default black background, assume transparent */
+ bg_rgb = 0;
+ } else if (bg_idx & 8) {
+ bg_rgb |= bgh;
+ } else {
+ bg_rgb |= bga;
+ }
+
+ cp->argb_fg = fg_rgb;
+ cp->argb_bg = bg_rgb;
+ cp->shadow = shadow;
+ cp++;
+ }
+}
+
+struct color_table *default_color_table(void)
+{
+ unsigned int i;
+ const struct color_table *dp;
+ struct color_table *cp;
+ struct color_table *color_table;
+ static const int pc2ansi[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
+ static char msg_names[6 * 256];
+ char *mp;
+
+ color_table = calloc(NCOLORS + 256, sizeof(struct color_table));
+
+ dp = default_colors;
+ cp = color_table;
+
+ for (i = 0; i < NCOLORS; i++) {
+ *cp = *dp;
+ cp->ansi = refstrdup(dp->ansi);
+ cp++;
+ dp++;
+ }
+
+ mp = msg_names;
+ for (i = 0; i < 256; i++) {
+ cp->name = mp;
+ mp += sprintf(mp, "msg%02x", i) + 1;
+
+ rsprintf(&cp->ansi, "%s3%d;4%d", (i & 8) ? "1;" : "",
+ pc2ansi[i & 7], pc2ansi[(i >> 4) & 7]);
+ cp++;
+ }
+
+ /*** XXX: This needs to move to run_menu() ***/
+ console_color_table = color_table;
+ console_color_table_size = NCOLORS + 256;
+
+ set_msg_colors_global(color_table, MSG_COLORS_DEF_FG,
+ MSG_COLORS_DEF_BG, MSG_COLORS_DEF_SHADOW);
+
+ return color_table;
+}
+
+struct color_table *copy_color_table(const struct color_table *master)
+{
+ const struct color_table *dp;
+ struct color_table *color_table, *cp;
+ unsigned int i;
+
+ color_table = calloc(NCOLORS + 256, sizeof(struct color_table));
+
+ dp = master;
+ cp = color_table;
+
+ for (i = 0; i < NCOLORS + 256; i++) {
+ *cp = *dp;
+ cp->ansi = refstr_get(dp->ansi);
+ cp++;
+ dp++;
+ }
+
+ return color_table;
+}
diff --git a/com32/elflink/ldlinux/config.h b/com32/elflink/ldlinux/config.h
new file mode 100644
index 00000000..242b7dc5
--- /dev/null
+++ b/com32/elflink/ldlinux/config.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2011 Intel Corporation - 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.
+ *
+ */
+
+#ifndef __CONFIG_H__
+#define __CONFIG_H__
+
+/*
+ * These values correspond to the "default" and "ui" commands
+ * respectively. "ui" takes precendence over "default".
+ */
+#define LEVEL_DEFAULT 1
+#define LEVEL_UI 2
+
+extern short uappendlen; //bytes in append= command
+extern short ontimeoutlen; //bytes in ontimeout command
+extern short onerrorlen; //bytes in onerror command
+extern short forceprompt; //force prompt
+extern short noescape; //no escape
+extern short nocomplete; //no label completion on TAB key
+extern short allowimplicit; //allow implicit kernels
+extern short allowoptions; //user-specified options allowed
+extern short includelevel; //nesting level
+extern short defaultlevel; //the current level of default
+extern short vkernel; //have we seen any "label" statements?
+extern short displaycon; //conio.inc
+extern short nohalt; //idle.inc
+
+extern const char *default_cmd; //"default" command line
+extern const char *onerror; //"onerror" command line
+extern const char *ontimeout; //"ontimeout" command line
+
+extern void cat_help_file(int key);
+extern struct menu_entry *find_label(const char *str);
+extern void print_labels(const char *prefix, size_t len);
+
+extern int new_linux_kernel(char *okernel, char *ocmdline);
+
+extern void pm_load_high(com32sys_t *regs);
+
+extern void ldlinux_enter_command(void);
+extern void ldlinux_console_init(void);
+extern const char *apply_extension(const char *kernel, const char *ext);
+
+#endif /* __CONFIG_H__ */
diff --git a/com32/elflink/ldlinux/execute.c b/com32/elflink/ldlinux/execute.c
new file mode 100644
index 00000000..bf0bd8ce
--- /dev/null
+++ b/com32/elflink/ldlinux/execute.c
@@ -0,0 +1,174 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004-2008 H. Peter Anvin - 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <dprintf.h>
+
+#include <com32.h>
+#include <sys/exec.h>
+#include <sys/io.h>
+#include <sys/module.h>
+#include "core.h"
+#include "menu.h"
+#include "fs.h"
+#include "config.h"
+#include "localboot.h"
+#include "bios.h"
+
+#include <syslinux/bootrm.h>
+#include <syslinux/movebits.h>
+#include <syslinux/config.h>
+#include <syslinux/boot.h>
+
+const struct image_types image_boot_types[] = {
+ { "localboot", IMAGE_TYPE_LOCALBOOT },
+ { "kernel", IMAGE_TYPE_KERNEL },
+ { "linux", IMAGE_TYPE_LINUX },
+ { "boot", IMAGE_TYPE_BOOT },
+ { "bss", IMAGE_TYPE_BSS },
+ { "pxe", IMAGE_TYPE_PXE },
+ { "fdimage", IMAGE_TYPE_FDIMAGE },
+ { "com32", IMAGE_TYPE_COM32 },
+ { "config", IMAGE_TYPE_CONFIG },
+ { NULL, 0 },
+};
+
+extern int create_args_and_load(char *);
+
+__export void execute(const char *cmdline, uint32_t type, bool sysappend)
+{
+ const char *kernel, *args;
+ const char *p;
+ com32sys_t ireg;
+ char *q, ch;
+
+ memset(&ireg, 0, sizeof ireg);
+
+ 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);
+ return;
+ }
+
+ kernel = q;
+ p = cmdline;
+ while (*p && !my_isspace(*p))
+ *q++ = *p++;
+ *q++ = '\0';
+
+ args = q;
+ while (*p && my_isspace(*p))
+ 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);
+
+ if (kernel[0] == '.') {
+ /* It might be a type specifier */
+ const struct image_types *t;
+ for (t = image_boot_types; t->name; t++) {
+ if (!strcmp(kernel + 1, t->name)) {
+ /*
+ * Strip the type specifier, apply the
+ * 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, sysappend);
+ return;
+ }
+ }
+ }
+
+ if (type == IMAGE_TYPE_COM32) {
+ /*
+ * We may be called with the console in an unknown
+ * state, so initialise it.
+ */
+ ldlinux_console_init();
+
+ /* new entry for elf format c32 */
+ if (create_args_and_load((char *)cmdline))
+ printf("Failed to load COM32 file %s\n", kernel);
+
+ /*
+ * The old COM32 module code would run the module then
+ * drop the user back at the command prompt,
+ * irrespective of how the COM32 module was loaded,
+ * e.g. from vesamenu.c32.
+ */
+ unload_modules_since("ldlinux.c32");
+
+ /* Restore the console */
+ ldlinux_console_init();
+
+ ldlinux_enter_command();
+ } else if (type == IMAGE_TYPE_CONFIG) {
+ char *argv[] = { "ldlinux.c32", NULL, NULL };
+ char *config;
+ int rv;
+
+ /* kernel contains the config file name */
+ 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);
+
+ 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));
+ } else if (type == IMAGE_TYPE_PXE || type == IMAGE_TYPE_BSS ||
+ type == IMAGE_TYPE_BOOT) {
+ chainboot_file(kernel, 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 *)args);
+ }
+
+out:
+ free((void *)kernel);
+
+ /* If this returns, something went bad; return to menu */
+}
diff --git a/com32/libutil/get_key.c b/com32/elflink/ldlinux/get_key.c
index f277b43b..cece0f81 100644
--- a/com32/libutil/get_key.c
+++ b/com32/elflink/ldlinux/get_key.c
@@ -41,6 +41,7 @@
#include <sys/times.h>
#include <getkey.h>
#include <libutil.h>
+#include <sys/file.h>
struct keycode {
int code;
@@ -48,7 +49,6 @@ struct keycode {
const unsigned char *seq;
};
-#define MAXLEN 8
#define CODE(x,y) { x, (sizeof y)-1, (const unsigned char *)(y) }
static const struct keycode keycodes[] = {
@@ -118,14 +118,62 @@ static const struct keycode keycodes[] = {
#define KEY_TIMEOUT ((CLK_TCK+9)/10)
-int get_key(FILE * f, clock_t timeout)
+/*
+ * Attempt to decode the key sequence in 'buffer'.
+ *
+ * On success (the data in 'buffer' matches a key code) put the
+ * corresponding key code in 'code' and return 0. Return 1 if 'buffer'
+ * partially matches a key code, i.e. we need more data before we can
+ * make an unambiguous match. Return -1 if the buffer does not contain
+ * a key code.
+ */
+int get_key_decode(char *buffer, int nc, int *code)
{
- unsigned char buffer[MAXLEN];
- int nc, i, rv;
const struct keycode *kc;
+ int i, rv;
+
+ rv = -1;
+ for (i = 0, kc = keycodes; i < NCODES; i++, kc++) {
+ if (nc == kc->seqlen && !memcmp(buffer, kc->seq, nc)) {
+ *code = kc->code;
+ rv = 0;
+ break;
+ } else if (nc < kc->seqlen && !memcmp(buffer, kc->seq, nc)) {
+ rv = 1;
+ break;
+ }
+ }
+
+ return rv;
+}
+
+#ifdef __COM32__
+extern ssize_t __rawcon_read(struct file_info *fp, void *buf, size_t count);
+
+int raw_read(int fd, void *buf, size_t count)
+{
+ (void)fd;
+
+ /*
+ * Instead of using the read(2) stdlib function use
+ * __rawcon_read() directly since we want a single key and
+ * don't want any processing/batching of the user input to
+ * occur - we want the raw data.
+ */
+ return __rawcon_read(NULL, buf, count);
+}
+#else
+extern int raw_read(int fd, void *buf, size_t count);
+#endif
+
+__export int get_key(FILE * f, clock_t timeout)
+{
+ char buffer[KEY_MAXLEN];
+ int nc, rv;
int another;
- unsigned char ch;
+ char ch;
clock_t start;
+ int code;
/* We typically start in the middle of a clock tick */
if (timeout)
@@ -134,12 +182,12 @@ int get_key(FILE * f, clock_t timeout)
nc = 0;
start = times(NULL);
do {
- rv = read(fileno(f), &ch, 1);
+ rv = raw_read(fileno(f), &ch, 1);
if (rv == 0 || (rv == -1 && errno == EAGAIN)) {
clock_t lateness = times(NULL) - start;
if (nc && lateness > 1 + KEY_TIMEOUT) {
if (nc == 1)
- return buffer[0]; /* timeout in sequence */
+ return (unsigned char)buffer[0]; /* timeout */
else if (timeout && lateness > timeout)
return KEY_NONE;
} else if (!nc && timeout && lateness > timeout)
@@ -156,17 +204,15 @@ int get_key(FILE * f, clock_t timeout)
buffer[nc++] = ch;
another = 0;
- for (i = 0, kc = keycodes; i < NCODES; i++, kc++) {
- if (nc == kc->seqlen && !memcmp(buffer, kc->seq, nc))
- return kc->code;
- else if (nc < kc->seqlen && !memcmp(buffer, kc->seq, nc)) {
+ rv = get_key_decode(buffer, nc, &code);
+ if (!rv)
+ return code;
+ else if (rv == 1)
another = 1;
- break;
- }
- }
+
} while (another);
/* We got an unrecognized sequence; return the first character */
/* We really should remember this and return subsequent characters later */
- return buffer[0];
+ return (unsigned char)buffer[0];
}
diff --git a/com32/lib/syslinux/getadv.c b/com32/elflink/ldlinux/getadv.c
index 5578313e..1c27f1b8 100644
--- a/com32/lib/syslinux/getadv.c
+++ b/com32/elflink/ldlinux/getadv.c
@@ -36,7 +36,7 @@
#include <klibc/compiler.h>
#include <inttypes.h>
-const void *syslinux_getadv(int tag, size_t * size)
+__export const void *syslinux_getadv(int tag, size_t * size)
{
const uint8_t *p;
size_t left;
diff --git a/com32/elflink/ldlinux/kernel.c b/com32/elflink/ldlinux/kernel.c
new file mode 100644
index 00000000..f3ba37fa
--- /dev/null
+++ b/com32/elflink/ldlinux/kernel.c
@@ -0,0 +1,131 @@
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <console.h>
+#include <dprintf.h>
+#include <syslinux/loadfile.h>
+#include <syslinux/linux.h>
+#include <syslinux/pxe.h>
+#include "core.h"
+
+const char *globaldefault = NULL;
+const char *append = NULL;
+
+/* Will be called from readconfig.c */
+int new_linux_kernel(char *okernel, char *ocmdline)
+{
+ const char *kernel_name = NULL, *args = NULL;
+ struct initramfs *initramfs = NULL;
+ char *temp;
+ void *kernel_data;
+ size_t kernel_len, cmdline_len;
+ bool opt_quiet = false;
+ char *initrd_name, *cmdline;
+
+ dprintf("okernel = %s, ocmdline = %s", okernel, ocmdline);
+
+ if (okernel)
+ kernel_name = okernel;
+ else if (globaldefault)
+ kernel_name = globaldefault;
+
+ if (ocmdline)
+ args = ocmdline;
+ else if (append)
+ args = append;
+
+ 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) {
+ printf("Failed to alloc memory for cmdline\n");
+ return 1;
+ }
+
+ sprintf(cmdline, "BOOT_IMAGE=%s %s", kernel_name, args);
+
+ /* "keeppxe" handling */
+#if IS_PXELINUX
+ extern char KeepPXE;
+
+ if (strstr(cmdline, "keeppxe"))
+ KeepPXE |= 1;
+#endif
+
+ if (strstr(cmdline, "quiet"))
+ opt_quiet = true;
+
+ if (!opt_quiet)
+ printf("Loading %s... ", kernel_name);
+
+ if (loadfile(kernel_name, &kernel_data, &kernel_len)) {
+ if (opt_quiet)
+ printf("Loading %s ", kernel_name);
+ printf("failed: ");
+ goto bail;
+ }
+
+ if (!opt_quiet)
+ printf("ok\n");
+
+ /* Find and load initramfs */
+ temp = strstr(cmdline, "initrd=");
+ if (temp) {
+ /* Initialize the initramfs chain */
+ initramfs = initramfs_init();
+ if (!initramfs)
+ goto bail;
+
+ temp += 6; /* strlen("initrd") */
+ do {
+ size_t n = 0;
+ char *p;
+
+ temp++; /* Skip = or , */
+
+ p = temp;
+ while (*p != ' ' && *p != ',' && *p) {
+ p++;
+ n++;
+ }
+
+ initrd_name = malloc(n + 1);
+ if (!initrd_name) {
+ printf("Failed to allocate space for initrd\n");
+ goto bail;
+ }
+
+ snprintf(initrd_name, n + 1, "%s", temp);
+ temp += n;
+
+ if (!opt_quiet)
+ printf("Loading %s...", initrd_name);
+
+ if (initramfs_load_archive(initramfs, initrd_name)) {
+ if (opt_quiet)
+ printf("Loading %s ", initrd_name);
+ free(initrd_name);
+ printf("failed: ");
+ goto bail;
+ }
+
+ free(initrd_name);
+
+ if (!opt_quiet)
+ printf("ok\n");
+ } while (*temp == ',');
+ }
+
+ /* This should not return... */
+ syslinux_boot_linux(kernel_data, kernel_len, initramfs, NULL, cmdline);
+ printf("Booting kernel failed: ");
+
+bail:
+ free(cmdline);
+ printf("%s\n", strerror(errno));
+ return 1;
+}
diff --git a/com32/elflink/ldlinux/ldlinux.c b/com32/elflink/ldlinux/ldlinux.c
new file mode 100644
index 00000000..76d117c7
--- /dev/null
+++ b/com32/elflink/ldlinux/ldlinux.c
@@ -0,0 +1,349 @@
+#include <linux/list.h>
+#include <sys/times.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <string.h>
+#include <core.h>
+#include <fs.h>
+#include "cli.h"
+#include "console.h"
+#include "com32.h"
+#include "menu.h"
+#include "config.h"
+#include "syslinux/adv.h"
+#include "syslinux/boot.h"
+#include "syslinux/config.h"
+
+#include <sys/module.h>
+
+struct file_ext {
+ const char *name;
+ enum kernel_type type;
+};
+
+static const struct file_ext file_extensions[] = {
+ { ".c32", IMAGE_TYPE_COM32 },
+ { ".img", IMAGE_TYPE_FDIMAGE },
+ { ".bss", IMAGE_TYPE_BSS },
+ { ".bin", IMAGE_TYPE_BOOT },
+ { ".bs", IMAGE_TYPE_BOOT },
+ { ".0", IMAGE_TYPE_PXE },
+ { NULL, 0 },
+};
+
+/*
+ * Return a pointer to one byte after the last character of the
+ * command.
+ */
+static inline const char *find_command(const char *str)
+{
+ const char *p;
+
+ p = str;
+ while (*p && !my_isspace(*p))
+ p++;
+ return p;
+}
+
+__export uint32_t parse_image_type(const char *kernel)
+{
+ const struct file_ext *ext;
+ const char *p;
+ int len;
+
+ /* Find the end of the command */
+ p = find_command(kernel);
+ len = p - kernel;
+
+ for (ext = file_extensions; ext->name; ext++) {
+ int elen = strlen(ext->name);
+
+ if (!strncmp(kernel + len - elen, ext->name, elen))
+ return ext->type;
+ }
+
+ /* use IMAGE_TYPE_KERNEL as default */
+ return IMAGE_TYPE_KERNEL;
+}
+
+/*
+ * Returns the kernel name with file extension if one wasn't present.
+ */
+static const char *get_extension(const char *kernel)
+{
+ const struct file_ext *ext;
+ const char *p;
+ int len;
+
+ /* Find the end of the command */
+ p = find_command(kernel);
+ len = p - kernel;
+
+ for (ext = file_extensions; ext->name; ext++) {
+ char *str;
+ int elen = strlen(ext->name);
+ FILE *f;
+
+ str = malloc(len + elen + 1);
+
+ strncpy(str, kernel, len);
+ strncpy(str + len, ext->name, elen);
+ str[len + elen] = '\0';
+ f = findpath(str);
+ free(str);
+
+ if (f) {
+ fclose(f);
+ return ext->name;
+ }
+ }
+
+ return NULL;
+}
+
+const char *apply_extension(const char *kernel, const char *ext)
+{
+ const char *p;
+ char *k;
+ int len = strlen(kernel);
+ int elen = strlen(ext);
+
+ k = malloc(len + elen + 1);
+ if (!k)
+ return NULL;
+
+ p = find_command(kernel);
+
+ len = p - kernel;
+
+ /* Copy just the kernel name */
+ memcpy(k, kernel, len);
+
+ /* Append the extension */
+ if (strncmp(p - elen, ext, elen)) {
+ memcpy(k + len, ext, elen);
+ len += elen;
+ }
+
+ /* Copy the rest of the command line */
+ strcpy(k + len, p);
+
+ k[len + strlen(p)] = '\0';
+
+ return k;
+}
+
+/*
+ * Attempt to load a kernel after deciding what type of image it is.
+ *
+ * We only return from this function if something went wrong loading
+ * the the kernel. If we return the caller should call enter_cmdline()
+ * so that the user can help us out.
+ */
+__export void load_kernel(const char *command_line)
+{
+ struct menu_entry *me;
+ const char *cmdline;
+ const char *kernel;
+ uint32_t type;
+
+ kernel = strdup(command_line);
+ if (!kernel)
+ goto bad_kernel;
+
+ /* Virtual kernel? */
+ me = find_label(kernel);
+ if (me) {
+ const char *args;
+ char *cmd;
+ size_t len = strlen(me->cmdline) + 1;
+
+ /* 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;
+ }
+
+ if (!allowimplicit)
+ goto bad_implicit;
+
+ /* Insert a null character to ignore any user-specified options */
+ if (!allowoptions) {
+ char *p = (char *)find_command(kernel);
+ *p = '\0';
+ }
+
+ type = parse_image_type(kernel);
+ if (type == IMAGE_TYPE_KERNEL) {
+ const char *ext;
+
+ /*
+ * Automatically lookup the extension if one wasn't
+ * supplied by the user.
+ */
+ ext = get_extension(kernel);
+ if (ext) {
+ const char *k;
+
+ k = apply_extension(kernel, ext);
+ if (!k)
+ goto bad_kernel;
+
+ free((void *)kernel);
+ kernel = k;
+
+ type = parse_image_type(kernel);
+ }
+ }
+
+ execute(kernel, type, true);
+ free((void *)kernel);
+
+bad_implicit:
+bad_kernel:
+ /*
+ * If we fail to boot the kernel execute the "onerror" command
+ * line.
+ */
+ if (onerrorlen) {
+ me = find_label(onerror);
+ if (me)
+ rsprintf(&cmdline, "%s %s", me->cmdline, default_cmd);
+ else
+ rsprintf(&cmdline, "%s %s", onerror, default_cmd);
+
+ type = parse_image_type(cmdline);
+ execute(cmdline, type, true);
+ }
+}
+
+/*
+ * If this function returns you must call ldinux_enter_command() to
+ * preserve the 4.0x behaviour.
+ */
+void ldlinux_auto_boot(void)
+{
+ if (!defaultlevel) {
+ if (strlen(ConfigName))
+ printf("No DEFAULT or UI configuration directive found!\n");
+ if (noescape)
+ kaboom();
+ } else
+ load_kernel(default_cmd);
+}
+
+static void enter_cmdline(void)
+{
+ const char *cmdline;
+
+ /* Enter endless command line prompt, should support "exit" */
+ while (1) {
+ bool to = false;
+
+ if (noescape) {
+ ldlinux_auto_boot();
+ continue;
+ }
+
+ cmdline = edit_cmdline("boot:", 1, NULL, cat_help_file, &to);
+ printf("\n");
+
+ /* return if user only press enter or we timed out */
+ if (!cmdline || cmdline[0] == '\0') {
+ if (to && ontimeoutlen)
+ load_kernel(ontimeout);
+ else
+ ldlinux_auto_boot();
+ } else
+ load_kernel(cmdline);
+ }
+}
+
+void ldlinux_enter_command(void)
+{
+ enter_cmdline();
+}
+
+/*
+ * Undo the work we did in openconsole().
+ */
+static void __destructor close_console(void)
+{
+ int i;
+
+ for (i = 0; i <= 2; i++)
+ close(i);
+}
+
+void ldlinux_console_init(void)
+{
+ openconsole(&dev_stdcon_r, &dev_ansiserial_w);
+}
+
+__export int main(int argc __unused, char **argv)
+{
+ const void *adv;
+ const char *cmdline;
+ size_t count = 0;
+
+ ldlinux_console_init();
+
+ parse_configs(&argv[1]);
+
+ __syslinux_set_serial_console_info();
+
+ adv = syslinux_getadv(ADV_BOOTONCE, &count);
+ if (adv && count) {
+ /*
+ * We apparently have a boot-once set; clear it and
+ * then execute the boot-once.
+ */
+ char *src, *dst;
+ size_t i;
+
+ src = (char *)adv;
+ cmdline = dst = malloc(count + 1);
+ if (!dst) {
+ printf("Failed to allocate memory for ADV\n");
+ ldlinux_enter_command();
+ }
+
+ for (i = 0; i < count; i++)
+ *dst++ = *src++;
+ *dst = '\0'; /* Null-terminate */
+
+ /* Clear the boot-once data from the ADV */
+ if (!syslinux_setadv(ADV_BOOTONCE, 0, NULL))
+ syslinux_adv_write();
+
+ load_kernel(cmdline); /* Shouldn't return */
+ ldlinux_enter_command();
+ }
+
+ /* TODO: Check KbdFlags? */
+ if (!forceprompt)
+ ldlinux_auto_boot();
+
+ if (defaultlevel > 1)
+ ldlinux_auto_boot();
+
+ ldlinux_enter_command();
+ return 0;
+}
diff --git a/com32/elflink/ldlinux/loadhigh.c b/com32/elflink/ldlinux/loadhigh.c
new file mode 100644
index 00000000..0f2f8428
--- /dev/null
+++ b/com32/elflink/ldlinux/loadhigh.c
@@ -0,0 +1,112 @@
+/*
+ * -----------------------------------------------------------------------
+ *
+ * Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * loadhigh.c
+ *
+ * An alternate interface to getfssec.
+ *
+ * Inputs: SI = file handle/cluster pointer
+ * EDI = target address in high memory
+ * EAX = maximum number of bytes to load
+ * DX = zero-padding mask (e.g. 0003h for pad to dword)
+ * BX = 16-bit subroutine to call at the top of each loop
+ * (to print status and check for abort)
+ * EBP = maximum load address
+ *
+ * Outputs: SI = file handle/cluster pointer
+ * EBX = first untouched address (not including padding)
+ * EDI = first untouched address (including padding)
+ * CF = reached EOF
+ * OF = ran out of high memory
+ */
+
+#include <com32.h>
+#include <minmax.h>
+#include "core.h"
+#include "fs.h"
+
+#define MAX_CHUNK (1UL << 20) /* 1 MB */
+
+void pm_load_high(com32sys_t *regs)
+{
+ struct fs_info *fs;
+ uint32_t bytes;
+ uint32_t zero_mask;
+ bool have_more;
+ uint32_t bytes_read;
+ char *buf, *limit;
+ struct file *file;
+ uint32_t sector_mask;
+ size_t pad;
+ uint32_t retflags = 0;
+
+ bytes = regs->eax.l;
+ zero_mask = regs->edx.w[0];
+ buf = (char *)regs->edi.l;
+ limit = (char *)(regs->ebp.l & ~zero_mask);
+ file = handle_to_file(regs->esi.w[0]);
+ fs = file->fs;
+
+ sector_mask = SECTOR_SIZE(fs) - 1;
+
+ while (bytes) {
+ uint32_t sectors;
+ uint32_t chunk;
+
+ if (buf + SECTOR_SIZE(fs) > limit) {
+ /* Can't fit even one more sector in... */
+ retflags = EFLAGS_OF;
+ break;
+ }
+
+ chunk = bytes;
+
+ if (regs->ebx.w[0]) {
+ call16((void (*)(void))(size_t)regs->ebx.w[0], &zero_regs, NULL);
+ chunk = min(chunk, MAX_CHUNK);
+ }
+
+ if (chunk > (((char *)limit - buf) & ~sector_mask))
+ chunk = ((char *)limit - buf) & ~sector_mask;
+
+ sectors = (chunk + sector_mask) >> SECTOR_SHIFT(fs);
+ bytes_read = fs->fs_ops->getfssec(file, buf, sectors, &have_more);
+
+ if (bytes_read > chunk)
+ bytes_read = chunk;
+
+ buf += bytes_read;
+ bytes -= bytes_read;
+
+ if (!have_more) {
+ /*
+ * If we reach EOF, the filesystem driver will have already closed
+ * the underlying file... this really should be cleaner.
+ */
+ _close_file(file);
+ regs->esi.w[0] = 0;
+ retflags = EFLAGS_CF;
+ break;
+ }
+ }
+
+ pad = (size_t)buf & zero_mask;
+ if (pad)
+ memset(buf, 0, pad);
+
+ regs->ebx.l = (size_t)buf;
+ regs->edi.l = (size_t)buf + pad;
+ set_flags(regs, retflags);
+}
diff --git a/com32/elflink/ldlinux/msg.c b/com32/elflink/ldlinux/msg.c
new file mode 100644
index 00000000..9ded33ef
--- /dev/null
+++ b/com32/elflink/ldlinux/msg.c
@@ -0,0 +1,228 @@
+#include <com32.h>
+#include <stdio.h>
+#include <bios.h>
+#include <graphics.h>
+
+static uint8_t TextAttribute; /* Text attribute for message file */
+extern uint8_t DisplayMask; /* Display modes mask */
+
+/* Routine to interpret next print char */
+static void (*NextCharJump)(uint8_t);
+
+void msg_initvars(void);
+static void msg_setfg(uint8_t data);
+static void msg_putchar(uint8_t ch);
+
+/*
+ *
+ * get_msg_file: Load a text file and write its contents to the screen,
+ * interpreting color codes.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+int get_msg_file(char *filename)
+{
+ FILE *f;
+ char ch;
+
+ f = fopen(filename, "r");
+ if (!f)
+ return -1;
+
+ TextAttribute = 0x7; /* Default grey on white */
+ DisplayMask = 0x7; /* Display text in all modes */
+ msg_initvars();
+
+ /*
+ * Read the text file a byte at a time and interpret that
+ * byte.
+ */
+ while ((ch = getc(f)) != EOF) {
+ /* DOS EOF? */
+ if (ch == 0x1A)
+ break;
+
+ NextCharJump(ch); /* Do what shall be done */
+ }
+
+ DisplayMask = 0x07;
+
+ fclose(f);
+ return 0;
+}
+
+static inline int display_mask_vga(void)
+{
+ uint8_t mask = UsingVGA & 0x1;
+ return (DisplayMask & ++mask);
+}
+
+static void msg_setbg(uint8_t data)
+{
+ if (unhexchar(&data) == 0) {
+ data <<= 4;
+ if (display_mask_vga())
+ TextAttribute = data;
+
+ NextCharJump = msg_setfg;
+ } else {
+ TextAttribute = 0x7; /* Default attribute */
+ NextCharJump = msg_putchar;
+ }
+}
+
+static void msg_setfg(uint8_t data)
+{
+ if (unhexchar(&data) == 0) {
+ if (display_mask_vga()) {
+ /* setbg set foreground to 0 */
+ TextAttribute |= data;
+ }
+ } else
+ TextAttribute = 0x7; /* Default attribute */
+
+ NextCharJump = msg_putchar;
+}
+
+static inline void msg_ctrl_o(void)
+{
+ NextCharJump = msg_setbg;
+}
+
+/* Convert ANSI colors to PC display attributes */
+static int convert_to_pcdisplay[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
+
+static void set_fgbg(void)
+{
+ uint8_t bg, fg;
+
+ fg = convert_to_pcdisplay[(TextAttribute & 0x7)];
+ bg = convert_to_pcdisplay[((TextAttribute >> 4) & 0x7)];
+
+ printf("\033[");
+ if (TextAttribute & 0x8)
+ printf("1;"); /* Foreground bright */
+
+ printf("3%dm\033[", fg);
+
+ if (TextAttribute & 0x80)
+ printf("5;"); /* Foreground blink */
+
+ printf("4%dm", bg);
+}
+
+static void msg_formfeed(void)
+{
+ set_fgbg();
+ printf("\033[2J\033[H\033[0m");
+}
+
+static void msg_novga(void)
+{
+ syslinux_force_text_mode();
+ msg_initvars();
+}
+
+static void msg_viewimage(void)
+{
+ FILE *f;
+
+ *VGAFilePtr = '\0'; /* Zero-terminate filename */
+
+ mangle_name(VGAFileMBuf, VGAFileBuf);
+ f = fopen(VGAFileMBuf, "r");
+ if (!f) {
+ /* Not there */
+ NextCharJump = msg_putchar;
+ return;
+ }
+
+ vgadisplayfile(f);
+ fclose(f);
+ msg_initvars();
+}
+
+/*
+ * Getting VGA filename
+ */
+static void msg_filename(uint8_t data)
+{
+ /* <LF> = end of filename */
+ if (data == 0x0A) {
+ msg_viewimage();
+ return;
+ }
+
+ /* Ignore space/control char */
+ if (data > ' ') {
+ if ((char *)VGAFilePtr < (VGAFileBuf + sizeof(VGAFileBuf)))
+ *VGAFilePtr++ = data;
+ }
+}
+
+static void msg_vga(void)
+{
+ NextCharJump = msg_filename;
+ VGAFilePtr = (uint16_t *)VGAFileBuf;
+}
+
+static void msg_normal(uint8_t data)
+{
+ /* 0x1 = text mode, 0x2 = graphics mode */
+ if (!display_mask_vga() || !(DisplayCon & 0x01)) {
+ /* Write to serial port */
+ if (DisplayMask & 0x4)
+ write_serial(data);
+
+ return; /* Not screen */
+ }
+
+ set_fgbg();
+ printf("%c\033[0m", data);
+}
+
+static void msg_modectl(uint8_t data)
+{
+ data &= 0x07;
+ DisplayMask = data;
+ NextCharJump = msg_putchar;
+}
+
+static void msg_putchar(uint8_t ch)
+{
+ /* 10h to 17h are mode controls */
+ if (ch >= 0x10 && ch < 0x18) {
+ msg_modectl(ch);
+ return;
+ }
+
+ switch (ch) {
+ case 0x0F: /* ^O = color code follows */
+ msg_ctrl_o();
+ break;
+ case 0x0D: /* Ignore <CR> */
+ break;
+ case 0x0C: /* <FF> = clear screen */
+ msg_formfeed();
+ break;
+ case 0x19: /* <EM> = return to text mode */
+ msg_novga();
+ break;
+ case 0x18: /* <CAN> = VGA filename follows */
+ msg_vga();
+ break;
+ default:
+ msg_normal(ch);
+ break;
+ }
+}
+
+/*
+ * Subroutine to initialize variables, also needed after loading
+ * graphics file.
+ */
+void msg_initvars(void)
+{
+ /* Initialize state machine */
+ NextCharJump = msg_putchar;
+}
diff --git a/com32/elflink/ldlinux/readconfig.c b/com32/elflink/ldlinux/readconfig.c
new file mode 100644
index 00000000..22efbe43
--- /dev/null
+++ b/com32/elflink/ldlinux/readconfig.c
@@ -0,0 +1,1572 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2013 Intel Corporation; author: H. Peter Anvin
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <sys/io.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <minmax.h>
+#include <alloca.h>
+#include <inttypes.h>
+#include <colortbl.h>
+#include <com32.h>
+#include <syslinux/adv.h>
+#include <syslinux/config.h>
+#include <dprintf.h>
+#include <ctype.h>
+#include <bios.h>
+#include <core.h>
+#include <fs.h>
+#include <syslinux/pxe_api.h>
+
+#include "menu.h"
+#include "config.h"
+#include "getkey.h"
+#include "core.h"
+#include "fs.h"
+
+const struct menu_parameter mparm[NPARAMS] = {
+ [P_WIDTH] = {"width", 0},
+ [P_MARGIN] = {"margin", 10},
+ [P_PASSWD_MARGIN] = {"passwordmargin", 3},
+ [P_MENU_ROWS] = {"rows", 12},
+ [P_TABMSG_ROW] = {"tabmsgrow", 18},
+ [P_CMDLINE_ROW] = {"cmdlinerow", 18},
+ [P_END_ROW] = {"endrow", -1},
+ [P_PASSWD_ROW] = {"passwordrow", 11},
+ [P_TIMEOUT_ROW] = {"timeoutrow", 20},
+ [P_HELPMSG_ROW] = {"helpmsgrow", 22},
+ [P_HELPMSGEND_ROW] = {"helpmsgendrow", -1},
+ [P_HSHIFT] = {"hshift", 0},
+ [P_VSHIFT] = {"vshift", 0},
+ [P_HIDDEN_ROW] = {"hiddenrow", -2},
+};
+
+/* Must match enum kernel_type */
+static const char *const kernel_types[] = {
+ "none",
+ "localboot",
+ "kernel",
+ "linux",
+ "boot",
+ "bss",
+ "pxe",
+ "fdimage",
+ "comboot",
+ "com32",
+ "config",
+ NULL
+};
+
+short uappendlen = 0; //bytes in append= command
+short ontimeoutlen = 0; //bytes in ontimeout command
+short onerrorlen = 0; //bytes in onerror command
+short forceprompt = 0; //force prompt
+short noescape = 0; //no escape
+short nocomplete = 0; //no label completion on TAB key
+short allowimplicit = 1; //allow implicit kernels
+short allowoptions = 1; //user-specified options allowed
+short includelevel = 1; //nesting level
+short defaultlevel = 0; //the current level of default
+short vkernel = 0; //have we seen any "label" statements?
+extern short NoHalt; //idle.c
+
+const char *onerror = NULL; //"onerror" command line
+const char *ontimeout = NULL; //"ontimeout" command line
+
+__export const char *default_cmd = NULL; //"default" command line
+
+/* Empty refstring */
+const char *empty_string;
+
+/* Root menu, starting menu, hidden menu, and list of all menus */
+struct menu *root_menu, *start_menu, *hide_menu, *menu_list, *default_menu;
+
+/* These are global parameters regardless of which menu we're displaying */
+int shiftkey = 0; /* Only display menu if shift key pressed */
+int hiddenmenu = 0;
+long long totaltimeout = 0;
+unsigned int kbdtimeout = 0;
+
+/* Keep track of global default */
+static int has_ui = 0; /* DEFAULT only counts if UI is found */
+extern const char *globaldefault;
+static bool menusave = false; /* True if there is any "menu save" */
+
+/* Linked list of all entires, hidden or not; used by unlabel() */
+static struct menu_entry *all_entries;
+static struct menu_entry **all_entries_end = &all_entries;
+
+static const struct messages messages[MSG_COUNT] = {
+ [MSG_AUTOBOOT] = {"autoboot", "Automatic boot in # second{,s}..."},
+ [MSG_TAB] = {"tabmsg", "Press [Tab] to edit options"},
+ [MSG_NOTAB] = {"notabmsg", ""},
+ [MSG_PASSPROMPT] = {"passprompt", "Password required"},
+};
+
+#define astrdup(x) ({ char *__x = (x); \
+ size_t __n = strlen(__x) + 1; \
+ char *__p = alloca(__n); \
+ if ( __p ) memcpy(__p, __x, __n); \
+ __p; })
+
+/*
+ * Search the list of all menus for a specific label
+ */
+static struct menu *find_menu(const char *label)
+{
+ struct menu *m;
+
+ for (m = menu_list; m; m = m->next) {
+ if (!strcmp(label, m->label))
+ return m;
+ }
+
+ return NULL;
+}
+
+#define MAX_LINE 4096
+
+/* Strip ^ from a string, returning a new reference to the same refstring
+ if none present */
+static const char *strip_caret(const char *str)
+{
+ const char *p, *r;
+ char *q;
+ int carets = 0;
+
+ p = str;
+ for (;;) {
+ p = strchr(p, '^');
+ if (!p)
+ break;
+ carets++;
+ p++;
+ }
+
+ if (!carets)
+ return refstr_get(str);
+
+ r = q = refstr_alloc(strlen(str) - carets);
+ for (p = str; *p; p++)
+ if (*p != '^')
+ *q++ = *p;
+
+ *q = '\0'; /* refstr_alloc() already did this... */
+
+ return r;
+}
+
+/* Check to see if we are at a certain keyword (case insensitive) */
+/* Returns a pointer to the first character past the keyword */
+static char *looking_at(char *line, const char *kwd)
+{
+ char *p = line;
+ const char *q = kwd;
+
+ while (*p && *q && ((*p ^ *q) & ~0x20) == 0) {
+ p++;
+ q++;
+ }
+
+ if (*q)
+ return NULL; /* Didn't see the keyword */
+
+ return my_isspace(*p) ? p : NULL; /* Must be EOL or whitespace */
+}
+
+static struct menu *new_menu(struct menu *parent,
+ struct menu_entry *parent_entry, const char *label)
+{
+ struct menu *m = calloc(1, sizeof(struct menu));
+ int i;
+
+ //dprintf("enter: menu_label = %s", label);
+
+ m->label = label;
+ m->title = refstr_get(empty_string);
+
+ if (parent) {
+ /* Submenu */
+ m->parent = parent;
+ m->parent_entry = parent_entry;
+ parent_entry->action = MA_SUBMENU;
+ parent_entry->submenu = m;
+
+ for (i = 0; i < MSG_COUNT; i++)
+ m->messages[i] = refstr_get(parent->messages[i]);
+
+ memcpy(m->mparm, parent->mparm, sizeof m->mparm);
+
+ m->allowedit = parent->allowedit;
+ m->timeout = parent->timeout;
+ m->save = parent->save;
+
+ m->ontimeout = refstr_get(parent->ontimeout);
+ m->onerror = refstr_get(parent->onerror);
+ m->menu_master_passwd = refstr_get(parent->menu_master_passwd);
+ m->menu_background = refstr_get(parent->menu_background);
+
+ m->color_table = copy_color_table(parent->color_table);
+
+ for (i = 0; i < 12; i++) {
+ m->fkeyhelp[i].textname = refstr_get(parent->fkeyhelp[i].textname);
+ m->fkeyhelp[i].background =
+ refstr_get(parent->fkeyhelp[i].background);
+ }
+ } else {
+ /* Root menu */
+ for (i = 0; i < MSG_COUNT; i++)
+ m->messages[i] = refstrdup(messages[i].defmsg);
+ for (i = 0; i < NPARAMS; i++)
+ m->mparm[i] = mparm[i].value;
+
+ m->allowedit = true; /* Allow edits of the command line */
+ m->color_table = default_color_table();
+ }
+
+ m->next = menu_list;
+ menu_list = m;
+
+ return m;
+}
+
+struct labeldata {
+ const char *label;
+ const char *kernel;
+ enum kernel_type type;
+ const char *append;
+ const char *initrd;
+ const char *menulabel;
+ const char *passwd;
+ char *helptext;
+ unsigned int ipappend;
+ unsigned int menuhide;
+ unsigned int menudefault;
+ unsigned int menuseparator;
+ unsigned int menudisabled;
+ unsigned int menuindent;
+ enum menu_action action;
+ int save;
+ struct menu *submenu;
+};
+
+/* Menu currently being parsed */
+static struct menu *current_menu;
+
+static void clear_label_data(struct labeldata *ld)
+{
+ refstr_put(ld->label);
+ refstr_put(ld->kernel);
+ refstr_put(ld->append);
+ refstr_put(ld->initrd);
+ refstr_put(ld->menulabel);
+ refstr_put(ld->passwd);
+
+ memset(ld, 0, sizeof *ld);
+}
+
+static struct menu_entry *new_entry(struct menu *m)
+{
+ struct menu_entry *me;
+
+ //dprintf("enter, call from menu %s", m->label);
+
+ if (m->nentries >= m->nentries_space) {
+ if (!m->nentries_space)
+ m->nentries_space = 1;
+ else
+ m->nentries_space <<= 1;
+
+ m->menu_entries = realloc(m->menu_entries, m->nentries_space *
+ sizeof(struct menu_entry *));
+ }
+
+ me = calloc(1, sizeof(struct menu_entry));
+ me->menu = m;
+ me->entry = m->nentries;
+ m->menu_entries[m->nentries++] = me;
+ *all_entries_end = me;
+ all_entries_end = &me->next;
+
+ return me;
+}
+
+static void consider_for_hotkey(struct menu *m, struct menu_entry *me)
+{
+ const char *p = strchr(me->displayname, '^');
+
+ if (me->action != MA_DISABLED) {
+ if (p && p[1]) {
+ unsigned char hotkey = p[1] & ~0x20;
+ if (!m->menu_hotkeys[hotkey]) {
+ me->hotkey = hotkey;
+ m->menu_hotkeys[hotkey] = 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;
+ struct menu_entry *me;
+ const struct syslinux_ipappend_strings *ipappend;
+
+ if (!ld->label)
+ return; /* Nothing defined */
+
+ /* Hidden entries are recorded on a special "hidden menu" */
+ if (ld->menuhide)
+ m = hide_menu;
+
+ char ipoptions[4096], *ipp;
+ const char *a;
+ char *s;
+
+ me = new_entry(m);
+
+ me->displayname = ld->menulabel
+ ? refstr_get(ld->menulabel) : refstr_get(ld->label);
+ me->label = refstr_get(ld->label);
+ me->passwd = refstr_get(ld->passwd);
+ me->helptext = ld->helptext;
+ me->hotkey = 0;
+ me->action = ld->action ? ld->action : MA_CMD;
+ me->save = ld->save ? (ld->save > 0) : m->save;
+
+ if (ld->menuindent) {
+ const char *dn;
+
+ rsprintf(&dn, "%*s%s", ld->menuindent, "", me->displayname);
+ refstr_put(me->displayname);
+ me->displayname = dn;
+ }
+
+ if (ld->menuseparator) {
+ refstr_put(me->displayname);
+ me->displayname = refstr_get(empty_string);
+ }
+
+ if (ld->menuseparator || ld->menudisabled) {
+ me->action = MA_DISABLED;
+ refstr_put(me->label);
+ me->label = NULL;
+ refstr_put(me->passwd);
+ me->passwd = NULL;
+ }
+
+ if (ld->menulabel)
+ consider_for_hotkey(m, me);
+
+ switch (me->action) {
+ case MA_CMD:
+ ipp = ipoptions;
+ *ipp = '\0';
+
+ if (ld->initrd)
+ ipp += sprintf(ipp, " initrd=%s", ld->initrd);
+
+ 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++ = ' ';
+ ipp = copy_sysappend_string(ipp, ipappend->ptr[i]);
+ }
+ }
+ }
+
+ a = ld->append;
+ if (!a)
+ a = append;
+ if (!a || (a[0] == '-' && !a[1]))
+ a = "";
+ s = a[0] ? " " : "";
+
+ if (ld->type == KT_KERNEL)
+ rsprintf(&me->cmdline, "%s%s%s%s", ld->kernel, s, a, ipoptions);
+ else
+ rsprintf(&me->cmdline, ".%s %s%s%s%s",
+ kernel_types[ld->type], ld->kernel, s, a, ipoptions);
+ dprintf("type = %s, cmd = %s", kernel_types[ld->type], me->cmdline);
+ break;
+
+ case MA_GOTO_UNRES:
+ case MA_EXIT_UNRES:
+ me->cmdline = refstr_get(ld->kernel);
+ break;
+
+ case MA_GOTO:
+ case MA_EXIT:
+ me->submenu = ld->submenu;
+ break;
+
+ default:
+ break;
+ }
+
+ if (ld->menudefault && me->action == MA_CMD)
+ m->defentry = m->nentries - 1;
+
+ clear_label_data(ld);
+}
+
+static struct menu *begin_submenu(const char *tag)
+{
+ struct menu_entry *me;
+
+ if (!tag[0])
+ tag = NULL;
+
+ me = new_entry(current_menu);
+ me->displayname = refstrdup(tag);
+ return new_menu(current_menu, me, refstr_get(me->displayname));
+}
+
+static struct menu *end_submenu(void)
+{
+ return current_menu->parent ? current_menu->parent : current_menu;
+}
+
+void print_labels(const char *prefix, size_t len)
+{
+ struct menu_entry *me;
+
+ printf("\n");
+ for (me = all_entries; me; me = me->next ) {
+ if (!me->label)
+ continue;
+
+ if (!strncmp(prefix, me->label, len))
+ printf(" %s", me->label);
+ }
+ printf("\n");
+}
+
+struct menu_entry *find_label(const char *str)
+{
+ const char *p;
+ struct menu_entry *me;
+ int pos;
+
+ p = str;
+ while (*p && !my_isspace(*p))
+ p++;
+
+ /* p now points to the first byte beyond the kernel name */
+ pos = p - str;
+
+ for (me = all_entries; me; me = me->next) {
+ if (!strncmp(str, me->label, pos) && !me->label[pos])
+ return me;
+ }
+
+ return NULL;
+}
+
+static const char *unlabel(const char *str)
+{
+ /* Convert a CLI-style command line to an executable command line */
+ const char *p;
+ const char *q;
+ struct menu_entry *me;
+ int pos;
+
+ p = str;
+ while (*p && !my_isspace(*p))
+ p++;
+
+ /* p now points to the first byte beyond the kernel name */
+ pos = p - str;
+
+ for (me = all_entries; me; me = me->next) {
+ if (!strncmp(str, me->label, pos) && !me->label[pos]) {
+ /* Found matching label */
+ rsprintf(&q, "%s%s", me->cmdline, p);
+ refstr_put(str);
+ return q;
+ }
+ }
+
+ return str;
+}
+
+static const char *__refdup_word(char *p, char **ref)
+{
+ char *sp = p;
+ char *ep = sp;
+
+ while (*ep && !my_isspace(*ep))
+ ep++;
+
+ if (ref)
+ *ref = ep;
+ return refstrndup(sp, ep - sp);
+}
+
+static const char *refdup_word(char **p)
+{
+ return __refdup_word(*p, p);
+}
+
+int my_isxdigit(char c)
+{
+ unsigned int uc = c;
+
+ return (uc - '0') < 10 || ((uc | 0x20) - 'a') < 6;
+}
+
+unsigned int hexval(char c)
+{
+ unsigned char uc = c | 0x20;
+ unsigned int v;
+
+ v = uc - '0';
+ if (v < 10)
+ return v;
+
+ return uc - 'a' + 10;
+}
+
+unsigned int hexval2(const char *p)
+{
+ return (hexval(p[0]) << 4) + hexval(p[1]);
+}
+
+uint32_t parse_argb(char **p)
+{
+ char *sp = *p;
+ char *ep;
+ uint32_t argb;
+ size_t len, dl;
+
+ if (*sp == '#')
+ sp++;
+
+ ep = sp;
+
+ while (my_isxdigit(*ep))
+ ep++;
+
+ *p = ep;
+ len = ep - sp;
+
+ switch (len) {
+ case 3: /* #rgb */
+ argb =
+ 0xff000000 +
+ (hexval(sp[0]) * 0x11 << 16) +
+ (hexval(sp[1]) * 0x11 << 8) + (hexval(sp[2]) * 0x11);
+ break;
+ case 4: /* #argb */
+ argb =
+ (hexval(sp[0]) * 0x11 << 24) +
+ (hexval(sp[1]) * 0x11 << 16) +
+ (hexval(sp[2]) * 0x11 << 8) + (hexval(sp[3]) * 0x11);
+ break;
+ case 6: /* #rrggbb */
+ case 9: /* #rrrgggbbb */
+ case 12: /* #rrrrggggbbbb */
+ dl = len / 3;
+ argb =
+ 0xff000000 +
+ (hexval2(sp + 0) << 16) +
+ (hexval2(sp + dl) << 8) + hexval2(sp + dl * 2);
+ break;
+ case 8: /* #aarrggbb */
+ /* #aaarrrgggbbb is indistinguishable from #rrrrggggbbbb,
+ assume the latter is a more common format */
+ case 16: /* #aaaarrrrggggbbbb */
+ dl = len / 4;
+ argb =
+ (hexval2(sp + 0) << 24) +
+ (hexval2(sp + dl) << 16) +
+ (hexval2(sp + dl * 2) << 8) + hexval2(sp + dl * 3);
+ break;
+ default:
+ argb = 0xffff0000; /* Bright red (error indication) */
+ break;
+ }
+
+ return argb;
+}
+
+/*
+ * Parser state. This is global so that including multiple
+ * files work as expected, which is that everything works the
+ * same way as if the files had been concatenated together.
+ */
+//static const char *append = NULL;
+extern const char *append;
+extern uint16_t PXERetry;
+static struct labeldata ld;
+
+static int parse_main_config(const char *filename);
+
+static char *is_kernel_type(char *cmdstr, enum kernel_type *type)
+{
+ const char *const *p;
+ char *q;
+ enum kernel_type t = KT_NONE;
+
+ for (p = kernel_types; *p; p++, t++) {
+ if ((q = looking_at(cmdstr, *p))) {
+ *type = t;
+ return q;
+ }
+ }
+
+ return NULL;
+}
+
+static char *is_message_name(char *cmdstr, enum message_number *msgnr)
+{
+ char *q;
+ enum message_number i;
+
+ for (i = 0; i < MSG_COUNT; i++) {
+ if ((q = looking_at(cmdstr, messages[i].name))) {
+ *msgnr = i;
+ return q;
+ }
+ }
+
+ return NULL;
+}
+
+extern void get_msg_file(char *);
+
+void cat_help_file(int key)
+{
+ struct menu *cm = current_menu;
+ int fkey;
+
+ switch (key) {
+ case KEY_F1:
+ fkey = 0;
+ break;
+ case KEY_F2:
+ fkey = 1;
+ break;
+ case KEY_F3:
+ fkey = 2;
+ break;
+ case KEY_F4:
+ fkey = 3;
+ break;
+ case KEY_F5:
+ fkey = 4;
+ break;
+ case KEY_F6:
+ fkey = 5;
+ break;
+ case KEY_F7:
+ fkey = 6;
+ break;
+ case KEY_F8:
+ fkey = 7;
+ break;
+ case KEY_F9:
+ fkey = 8;
+ break;
+ case KEY_F10:
+ fkey = 9;
+ break;
+ case KEY_F11:
+ fkey = 10;
+ break;
+ case KEY_F12:
+ fkey = 11;
+ break;
+ default:
+ fkey = -1;
+ break;
+ }
+
+ if (fkey == -1)
+ return;
+
+ if (cm->fkeyhelp[fkey].textname) {
+ printf("\n");
+ get_msg_file((char *)cm->fkeyhelp[fkey].textname);
+ }
+}
+
+static char *is_fkey(char *cmdstr, int *fkeyno)
+{
+ char *q;
+ int no;
+
+ if ((cmdstr[0] | 0x20) != 'f')
+ return NULL;
+
+ no = strtoul(cmdstr + 1, &q, 10);
+ if (!my_isspace(*q))
+ return NULL;
+
+ if (no < 0 || no > 12)
+ return NULL;
+
+ *fkeyno = (no == 0) ? 10 : no - 1;
+ return q;
+}
+
+extern uint8_t FlowIgnore;
+extern uint8_t FlowInput;
+extern uint8_t FlowOutput;
+extern uint16_t SerialPort;
+extern uint16_t BaudDivisor;
+static uint8_t SerialNotice = 1;
+
+#define DEFAULT_BAUD 9600
+#define BAUD_DIVISOR 115200
+
+extern void sirq_cleanup_nowipe(void);
+extern void sirq_install(void);
+extern void write_serial_str(char *);
+
+extern void loadfont(char *);
+extern void loadkeys(char *);
+
+extern char syslinux_banner[];
+extern char copyright_str[];
+
+/*
+ * PATH-based lookup
+ *
+ * Each entry in the PATH directive is separated by a colon, e.g.
+ *
+ * PATH /bar:/bin/foo:/baz/bar/bin
+ */
+static int parse_path(char *p)
+{
+ struct path_entry *entry;
+ const char *str;
+
+ while (*p) {
+ char *c = p;
+
+ /* Find the next directory */
+ while (*c && *c != ':')
+ c++;
+
+ str = refstrndup(p, c - p);
+ if (!str)
+ goto bail;
+
+ entry = path_add(str);
+ refstr_put(str);
+
+ if (!entry)
+ goto bail;
+
+ if (!*c++)
+ break;
+ p = c;
+ }
+
+ return 0;
+
+bail:
+ return -1;
+}
+
+static void parse_config_file(FILE * f);
+
+static void do_include_menu(char *str, struct menu *m)
+{
+ const char *file;
+ char *p;
+ FILE *f;
+ int fd;
+
+ p = skipspace(str);
+ file = refdup_word(&p);
+ p = skipspace(p);
+
+ fd = open(file, O_RDONLY);
+ if (fd < 0)
+ goto put;
+
+ f = fdopen(fd, "r");
+ if (!f)
+ goto bail;
+
+ if (*p) {
+ record(m, &ld, append);
+ m = current_menu = begin_submenu(p);
+ }
+
+ parse_config_file(f);
+
+ if (*p) {
+ record(m, &ld, append);
+ m = current_menu = end_submenu();
+ }
+
+bail:
+ close(fd);
+put:
+ refstr_put(file);
+
+}
+
+static void do_include(char *str)
+{
+ const char *file;
+ char *p;
+ FILE *f;
+ int fd;
+
+ p = skipspace(str);
+ file = refdup_word(&p);
+
+ fd = open(file, O_RDONLY);
+ if (fd < 0)
+ goto put;
+
+ f = fdopen(fd, "r");
+ if (f)
+ parse_config_file(f);
+
+bail:
+ close(fd);
+put:
+ refstr_put(file);
+}
+
+static void parse_config_file(FILE * f)
+{
+ char line[MAX_LINE], *p, *ep, ch;
+ enum kernel_type type;
+ enum message_number msgnr;
+ int fkeyno;
+ struct menu *m = current_menu;
+
+ while (fgets(line, sizeof line, f)) {
+ p = strchr(line, '\r');
+ if (p)
+ *p = '\0';
+ p = strchr(line, '\n');
+ if (p)
+ *p = '\0';
+
+ p = skipspace(line);
+
+ if (looking_at(p, "menu")) {
+
+ p = skipspace(p + 4);
+
+ if (looking_at(p, "label")) {
+ if (ld.label) {
+ refstr_put(ld.menulabel);
+ ld.menulabel = refstrdup(skipspace(p + 5));
+ } else if (m->parent_entry) {
+ refstr_put(m->parent_entry->displayname);
+ m->parent_entry->displayname = refstrdup(skipspace(p + 5));
+ consider_for_hotkey(m->parent, m->parent_entry);
+ if (!m->title[0]) {
+ /* MENU LABEL -> MENU TITLE on submenu */
+ refstr_put(m->title);
+ m->title = strip_caret(m->parent_entry->displayname);
+ }
+ }
+ } else if (looking_at(p, "title")) {
+ refstr_put(m->title);
+ m->title = refstrdup(skipspace(p + 5));
+ if (m->parent_entry) {
+ /* MENU TITLE -> MENU LABEL on submenu */
+ if (m->parent_entry->displayname == m->label) {
+ refstr_put(m->parent_entry->displayname);
+ m->parent_entry->displayname = refstr_get(m->title);
+ }
+ }
+ } else if (looking_at(p, "default")) {
+ if (ld.label) {
+ ld.menudefault = 1;
+ } else if (m->parent_entry) {
+ m->parent->defentry = m->parent_entry->entry;
+ }
+ } else if (looking_at(p, "hide")) {
+ ld.menuhide = 1;
+ } else if (looking_at(p, "passwd")) {
+ if (ld.label) {
+ refstr_put(ld.passwd);
+ ld.passwd = refstrdup(skipspace(p + 6));
+ } else if (m->parent_entry) {
+ refstr_put(m->parent_entry->passwd);
+ m->parent_entry->passwd = refstrdup(skipspace(p + 6));
+ }
+ } else if (looking_at(p, "shiftkey")) {
+ shiftkey = 1;
+ } else if (looking_at(p, "save")) {
+ menusave = true;
+ if (ld.label)
+ ld.save = 1;
+ else
+ m->save = true;
+ } else if (looking_at(p, "nosave")) {
+ if (ld.label)
+ ld.save = -1;
+ else
+ m->save = false;
+ } else if (looking_at(p, "onerror")) {
+ refstr_put(m->onerror);
+ m->onerror = refstrdup(skipspace(p + 7));
+ onerrorlen = strlen(m->onerror);
+ refstr_put(onerror);
+ onerror = refstrdup(m->onerror);
+ } else if (looking_at(p, "master")) {
+ p = skipspace(p + 6);
+ if (looking_at(p, "passwd")) {
+ refstr_put(m->menu_master_passwd);
+ m->menu_master_passwd = refstrdup(skipspace(p + 6));
+ }
+ } else if ((ep = looking_at(p, "include"))) {
+ do_include_menu(ep, m);
+ } else if ((ep = looking_at(p, "background"))) {
+ p = skipspace(ep);
+ refstr_put(m->menu_background);
+ m->menu_background = refdup_word(&p);
+ } else if ((ep = looking_at(p, "hidden"))) {
+ hiddenmenu = 1;
+ } else if ((ep = is_message_name(p, &msgnr))) {
+ refstr_put(m->messages[msgnr]);
+ m->messages[msgnr] = refstrdup(skipspace(ep));
+ } else if ((ep = looking_at(p, "color")) ||
+ (ep = looking_at(p, "colour"))) {
+ int i;
+ struct color_table *cptr;
+ p = skipspace(ep);
+ cptr = m->color_table;
+ for (i = 0; i < menu_color_table_size; i++) {
+ if ((ep = looking_at(p, cptr->name))) {
+ p = skipspace(ep);
+ if (*p) {
+ if (looking_at(p, "*")) {
+ p++;
+ } else {
+ refstr_put(cptr->ansi);
+ cptr->ansi = refdup_word(&p);
+ }
+
+ p = skipspace(p);
+ if (*p) {
+ if (looking_at(p, "*"))
+ p++;
+ else
+ cptr->argb_fg = parse_argb(&p);
+
+ p = skipspace(p);
+ if (*p) {
+ if (looking_at(p, "*"))
+ p++;
+ else
+ cptr->argb_bg = parse_argb(&p);
+
+ /* Parse a shadow mode */
+ p = skipspace(p);
+ ch = *p | 0x20;
+ if (ch == 'n') /* none */
+ cptr->shadow = SHADOW_NONE;
+ else if (ch == 's') /* std, standard */
+ cptr->shadow = SHADOW_NORMAL;
+ else if (ch == 'a') /* all */
+ cptr->shadow = SHADOW_ALL;
+ else if (ch == 'r') /* rev, reverse */
+ cptr->shadow = SHADOW_REVERSE;
+ }
+ }
+ }
+ break;
+ }
+ cptr++;
+ }
+ } else if ((ep = looking_at(p, "msgcolor")) ||
+ (ep = looking_at(p, "msgcolour"))) {
+ unsigned int fg_mask = MSG_COLORS_DEF_FG;
+ unsigned int bg_mask = MSG_COLORS_DEF_BG;
+ enum color_table_shadow shadow = MSG_COLORS_DEF_SHADOW;
+
+ p = skipspace(ep);
+ if (*p) {
+ if (!looking_at(p, "*"))
+ fg_mask = parse_argb(&p);
+
+ p = skipspace(p);
+ if (*p) {
+ if (!looking_at(p, "*"))
+ bg_mask = parse_argb(&p);
+
+ p = skipspace(p);
+ switch (*p | 0x20) {
+ case 'n':
+ shadow = SHADOW_NONE;
+ break;
+ case 's':
+ shadow = SHADOW_NORMAL;
+ break;
+ case 'a':
+ shadow = SHADOW_ALL;
+ break;
+ case 'r':
+ shadow = SHADOW_REVERSE;
+ break;
+ default:
+ /* go with default */
+ break;
+ }
+ }
+ }
+ set_msg_colors_global(m->color_table, fg_mask, bg_mask, shadow);
+ } else if (looking_at(p, "separator")) {
+ record(m, &ld, append);
+ ld.label = refstr_get(empty_string);
+ ld.menuseparator = 1;
+ record(m, &ld, append);
+ } else if (looking_at(p, "disable") || looking_at(p, "disabled")) {
+ ld.menudisabled = 1;
+ } else if (looking_at(p, "indent")) {
+ ld.menuindent = atoi(skipspace(p + 6));
+ } else if (looking_at(p, "begin")) {
+ record(m, &ld, append);
+ m = current_menu = begin_submenu(skipspace(p + 5));
+ } else if (looking_at(p, "end")) {
+ record(m, &ld, append);
+ m = current_menu = end_submenu();
+ } else if (looking_at(p, "quit")) {
+ if (ld.label)
+ ld.action = MA_QUIT;
+ } else if (looking_at(p, "goto")) {
+ if (ld.label) {
+ ld.action = MA_GOTO_UNRES;
+ refstr_put(ld.kernel);
+ ld.kernel = refstrdup(skipspace(p + 4));
+ }
+ } else if (looking_at(p, "exit")) {
+ p = skipspace(p + 4);
+ if (ld.label && m->parent) {
+ if (*p) {
+ /* This is really just a goto, except for the marker */
+ ld.action = MA_EXIT_UNRES;
+ refstr_put(ld.kernel);
+ ld.kernel = refstrdup(p);
+ } else {
+ ld.action = MA_EXIT;
+ ld.submenu = m->parent;
+ }
+ }
+ } else if (looking_at(p, "start")) {
+ start_menu = m;
+ } else {
+ /* Unknown, check for layout parameters */
+ enum parameter_number mp;
+ for (mp = 0; mp < NPARAMS; mp++) {
+ if ((ep = looking_at(p, mparm[mp].name))) {
+ m->mparm[mp] = atoi(skipspace(ep));
+ break;
+ }
+ }
+ }
+ }
+ /* feng: menu handling end */
+ else if (looking_at(p, "text")) {
+
+ /* loop till we fined the "endtext" */
+ enum text_cmd {
+ TEXT_UNKNOWN,
+ TEXT_HELP
+ } cmd = TEXT_UNKNOWN;
+ int len = ld.helptext ? strlen(ld.helptext) : 0;
+ int xlen;
+
+ p = skipspace(p + 4);
+
+ if (looking_at(p, "help"))
+ cmd = TEXT_HELP;
+
+ while (fgets(line, sizeof line, f)) {
+ p = skipspace(line);
+ if (looking_at(p, "endtext"))
+ break;
+
+ xlen = strlen(line);
+
+ switch (cmd) {
+ case TEXT_UNKNOWN:
+ break;
+ case TEXT_HELP:
+ ld.helptext = realloc(ld.helptext, len + xlen + 1);
+ memcpy(ld.helptext + len, line, xlen + 1);
+ len += xlen;
+ break;
+ }
+ }
+ } else if ((ep = is_fkey(p, &fkeyno))) {
+ p = skipspace(ep);
+ if (m->fkeyhelp[fkeyno].textname) {
+ refstr_put(m->fkeyhelp[fkeyno].textname);
+ m->fkeyhelp[fkeyno].textname = NULL;
+ }
+ if (m->fkeyhelp[fkeyno].background) {
+ refstr_put(m->fkeyhelp[fkeyno].background);
+ m->fkeyhelp[fkeyno].background = NULL;
+ }
+
+ refstr_put(m->fkeyhelp[fkeyno].textname);
+ m->fkeyhelp[fkeyno].textname = refdup_word(&p);
+ if (*p) {
+ p = skipspace(p);
+ m->fkeyhelp[fkeyno].background = refdup_word(&p);
+ }
+ } else if ((ep = looking_at(p, "include"))) {
+ do_include(ep);
+ } else if (looking_at(p, "append")) {
+ const char *a = refstrdup(skipspace(p + 6));
+ if (ld.label) {
+ refstr_put(ld.append);
+ ld.append = a;
+ } else {
+ refstr_put(append);
+ append = a;
+ }
+ //dprintf("we got a append: %s", a);
+ } else if (looking_at(p, "initrd")) {
+ const char *a = refstrdup(skipspace(p + 6));
+ if (ld.label) {
+ refstr_put(ld.initrd);
+ ld.initrd = a;
+ } else {
+ /* Ignore */
+ }
+ } else if (looking_at(p, "label")) {
+ p = skipspace(p + 5);
+ /* when first time see "label", it will not really record anything */
+ record(m, &ld, append);
+ ld.label = __refdup_word(p, NULL);
+ ld.kernel = __refdup_word(p, NULL);
+ /* feng: this is the default type for all */
+ ld.type = KT_KERNEL;
+ ld.passwd = NULL;
+ ld.append = NULL;
+ ld.initrd = NULL;
+ ld.menulabel = NULL;
+ ld.helptext = NULL;
+ ld.ipappend = SysAppends;
+ ld.menudefault = ld.menuhide = ld.menuseparator =
+ ld.menudisabled = ld.menuindent = 0;
+ } else if ((ep = is_kernel_type(p, &type))) {
+ if (ld.label) {
+ refstr_put(ld.kernel);
+ ld.kernel = refstrdup(skipspace(ep));
+ ld.type = type;
+ //dprintf("got a kernel: %s, type = %d", ld.kernel, ld.type);
+ }
+ } else if (looking_at(p, "timeout")) {
+ kbdtimeout = (atoi(skipspace(p + 7)) * CLK_TCK + 9) / 10;
+ } else if (looking_at(p, "totaltimeout")) {
+ totaltimeout = (atoll(skipspace(p + 13)) * CLK_TCK + 9) / 10;
+ } else if (looking_at(p, "ontimeout")) {
+ ontimeout = refstrdup(skipspace(p + 9));
+ ontimeoutlen = strlen(ontimeout);
+ } else if (looking_at(p, "allowoptions")) {
+ allowoptions = !!atoi(skipspace(p + 12));
+ } else if ((ep = looking_at(p, "ipappend")) ||
+ (ep = looking_at(p, "sysappend"))) {
+ uint32_t s = strtoul(skipspace(ep), NULL, 0);
+ if (ld.label)
+ ld.ipappend = s;
+ else
+ SysAppends = s;
+ } else if (looking_at(p, "default")) {
+ /* default could be a kernel image or another label */
+ refstr_put(globaldefault);
+ globaldefault = refstrdup(skipspace(p + 7));
+
+ /*
+ * On the chance that "default" is actually a kernel image
+ * and not a label, store a copy of it, but only if we
+ * haven't seen a "ui" command. "ui" commands take
+ * precendence over "default" commands.
+ */
+ if (defaultlevel < LEVEL_UI) {
+ defaultlevel = LEVEL_DEFAULT;
+ refstr_put(default_cmd);
+ default_cmd = refstrdup(globaldefault);
+ }
+ } else if (looking_at(p, "ui")) {
+ has_ui = 1;
+ defaultlevel = LEVEL_UI;
+ refstr_put(default_cmd);
+ default_cmd = refstrdup(skipspace(p + 2));
+ }
+
+ /*
+ * subset 1: pc_opencmd
+ * display/font/kbdmap are rather similar, open a file then do sth
+ */
+ else if (looking_at(p, "display")) {
+ const char *filename;
+ char *dst = KernelName;
+ size_t len = FILENAME_MAX - 1;
+
+ filename = refstrdup(skipspace(p + 7));
+
+ while (len-- && not_whitespace(*filename))
+ *dst++ = *filename++;
+ *dst = '\0';
+
+ get_msg_file(KernelName);
+ refstr_put(filename);
+ } else if (looking_at(p, "font")) {
+ const char *filename;
+ char *dst = KernelName;
+ size_t len = FILENAME_MAX - 1;
+
+ filename = refstrdup(skipspace(p + 4));
+
+ while (len-- && not_whitespace(*filename))
+ *dst++ = *filename++;
+ *dst = '\0';
+
+ loadfont(KernelName);
+ refstr_put(filename);
+ } else if (looking_at(p, "kbdmap")) {
+ const char *filename;
+
+ filename = refstrdup(skipspace(p + 6));
+ loadkeys(filename);
+ refstr_put(filename);
+ }
+ /*
+ * subset 2: pc_setint16
+ * set a global flag
+ */
+ else if (looking_at(p, "implicit")) {
+ allowimplicit = atoi(skipspace(p + 8));
+ } else if (looking_at(p, "prompt")) {
+ forceprompt = atoi(skipspace(p + 6));
+ } else if (looking_at(p, "console")) {
+ DisplayCon = atoi(skipspace(p + 7));
+ } else if (looking_at(p, "allowoptions")) {
+ allowoptions = atoi(skipspace(p + 12));
+ } else if (looking_at(p, "noescape")) {
+ noescape = atoi(skipspace(p + 8));
+ } else if (looking_at(p, "nocomplete")) {
+ nocomplete = atoi(skipspace(p + 10));
+ } else if (looking_at(p, "nohalt")) {
+ NoHalt = atoi(skipspace(p + 8));
+ } else if (looking_at(p, "onerror")) {
+ refstr_put(m->onerror);
+ m->onerror = refstrdup(skipspace(p + 7));
+ onerrorlen = strlen(m->onerror);
+ refstr_put(onerror);
+ onerror = refstrdup(m->onerror);
+ }
+
+ else if (looking_at(p, "pxeretry"))
+ PXERetry = atoi(skipspace(p + 8));
+
+ /* serial setting, bps, flow control */
+ else if (looking_at(p, "serial")) {
+ uint16_t port, flow;
+ uint32_t baud;
+
+ p = skipspace(p + 6);
+ port = atoi(p);
+
+ while (isalnum(*p))
+ p++;
+ p = skipspace(p);
+
+ /* Default to no flow control */
+ FlowOutput = 0;
+ FlowInput = 0;
+
+ baud = DEFAULT_BAUD;
+ if (isalnum(*p)) {
+ uint8_t ignore;
+
+ /* setup baud */
+ baud = atoi(p);
+ while (isalnum(*p))
+ p++;
+ p = skipspace(p);
+
+ ignore = 0;
+ flow = 0;
+ if (isalnum(*p)) {
+ /* flow control */
+ flow = atoi(p);
+ ignore = ((flow & 0x0F00) >> 4);
+ }
+
+ FlowIgnore = ignore;
+ flow = ((flow & 0xff) << 8) | (flow & 0xff);
+ flow &= 0xF00B;
+ FlowOutput = (flow & 0xff);
+ FlowInput = ((flow & 0xff00) >> 8);
+ }
+
+ /*
+ * Parse baud
+ */
+ if (baud < 75) {
+ /* < 75 baud == bogus */
+ SerialPort = 0;
+ continue;
+ }
+
+ baud = BAUD_DIVISOR / baud;
+ baud &= 0xffff;
+ BaudDivisor = baud;
+
+ port = get_serial_port(port);
+ SerialPort = port;
+
+ /*
+ * Begin code to actually set up the serial port
+ */
+ sirq_cleanup_nowipe();
+
+ outb(0x83, port + 3); /* Enable DLAB */
+ io_delay();
+
+ outb((baud & 0xff), port); /* write divisor to LS */
+ io_delay();
+
+ outb(((baud & 0xff00) >> 8), port + 1); /* write to MS */
+ io_delay();
+
+ outb(0x03, port + 3); /* Disable DLAB */
+ io_delay();
+
+ /*
+ * Read back LCR (detect missing hw). If nothing here
+ * we'll read 00 or FF.
+ */
+ if (inb(port + 3) != 0x03) {
+ /* Assume serial port busted */
+ SerialPort = 0;
+ continue;
+ }
+
+ outb(0x01, port + 2); /* Enable FIFOs if present */
+ io_delay();
+
+ /* Disable FIFO if unusable */
+ if (inb(port + 2) < 0x0C0) {
+ outb(0, port + 2);
+ io_delay();
+ }
+
+ /* Assert bits in MCR */
+ outb(FlowOutput, port + 4);
+ io_delay();
+
+ /* Enable interrupts if requested */
+ if (FlowOutput & 0x8)
+ sirq_install();
+
+ /* Show some life */
+ if (SerialNotice != 0) {
+ SerialNotice = 0;
+
+ write_serial_str(syslinux_banner);
+ write_serial_str(copyright_str);
+ }
+
+ } else if (looking_at(p, "say")) {
+ printf("%s\n", p+4);
+ } else if (looking_at(p, "path")) {
+ if (parse_path(skipspace(p + 4)))
+ printf("Failed to parse 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();
+ }
+ }
+ }
+}
+
+static int parse_main_config(const char *filename)
+{
+ const char *mode = "r";
+ FILE *f;
+ int fd;
+
+ if (!filename)
+ fd = open_config();
+ else
+ fd = open(filename, O_RDONLY);
+
+ if (fd < 0)
+ return fd;
+
+ if (config_cwd[0]) {
+ if (chdir(config_cwd) < 0)
+ printf("Failed to chdir to %s\n", config_cwd);
+ config_cwd[0] = '\0';
+ }
+
+ 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;
+}
+
+static void resolve_gotos(void)
+{
+ struct menu_entry *me;
+ struct menu *m;
+
+ for (me = all_entries; me; me = me->next) {
+ if (me->action == MA_GOTO_UNRES || me->action == MA_EXIT_UNRES) {
+ m = find_menu(me->cmdline);
+ refstr_put(me->cmdline);
+ me->cmdline = NULL;
+ if (m) {
+ me->submenu = m;
+ me->action--; /* Drop the _UNRES */
+ } else {
+ me->action = MA_DISABLED;
+ }
+ }
+ }
+}
+
+void parse_configs(char **argv)
+{
+ const char *filename;
+ struct menu *m;
+ struct menu_entry *me;
+ dprintf("enter");
+
+ empty_string = refstrdup("");
+
+ /* feng: reset current menu_list and entry list */
+ menu_list = NULL;
+ all_entries = NULL;
+
+ /* Initialize defaults for the root and hidden menus */
+ hide_menu = new_menu(NULL, NULL, refstrdup(".hidden"));
+ root_menu = new_menu(NULL, NULL, refstrdup(".top"));
+ start_menu = root_menu;
+
+ /* Other initialization */
+ memset(&ld, 0, sizeof(struct labeldata));
+
+ /* Actually process the files */
+ current_menu = root_menu;
+
+ if (!argv || !*argv) {
+ if (parse_main_config(NULL) < 0) {
+ printf("WARNING: No configuration file found\n");
+ return;
+ }
+ } else {
+ while ((filename = *argv++)) {
+ dprintf("Parsing config: %s", filename);
+ parse_main_config(filename);
+ }
+ }
+
+ /* On final EOF process the last label statement */
+ record(current_menu, &ld, append);
+
+ /* Common postprocessing */
+ resolve_gotos();
+
+ /* Handle global default */
+ //if (has_ui && globaldefault) {
+ if (globaldefault) {
+ dprintf("gloabldefault = %s", globaldefault);
+ me = find_label(globaldefault);
+ if (me && me->menu != hide_menu) {
+ me->menu->defentry = me->entry;
+ start_menu = me->menu;
+ default_menu = me->menu;
+ }
+ }
+
+ /* If "menu save" is active, let the ADV override the global default */
+ if (menusave) {
+ size_t len;
+ const char *lbl = syslinux_getadv(ADV_MENUSAVE, &len);
+ char *lstr;
+ if (lbl && len) {
+ lstr = refstr_alloc(len);
+ memcpy(lstr, lbl, len); /* refstr_alloc() adds the final null */
+ me = find_label(lstr);
+ if (me && me->menu != hide_menu) {
+ me->menu->defentry = me->entry;
+ start_menu = me->menu;
+ }
+ refstr_put(lstr);
+ }
+ }
+
+ /* Final per-menu initialization, with all labels known */
+ for (m = menu_list; m; m = m->next) {
+ m->curentry = m->defentry; /* All menus start at their defaults */
+
+ if (m->ontimeout)
+ m->ontimeout = unlabel(m->ontimeout);
+ if (m->onerror)
+ m->onerror = unlabel(m->onerror);
+ }
+}
diff --git a/com32/elflink/ldlinux/refstr.c b/com32/elflink/ldlinux/refstr.c
new file mode 100644
index 00000000..f9d98e11
--- /dev/null
+++ b/com32/elflink/ldlinux/refstr.c
@@ -0,0 +1,106 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2008 H. Peter Anvin - 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * refstr.c
+ *
+ * Simple reference-counted strings
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/module.h>
+#include "refstr.h"
+
+/* Allocate space for a refstring of len bytes, plus final null */
+/* The final null is inserted in the string; the rest is uninitialized. */
+char *refstr_alloc(size_t len)
+{
+ char *r = malloc(sizeof(unsigned int) + len + 1);
+ if (!r)
+ return NULL;
+ *(unsigned int *)r = 1;
+ r += sizeof(unsigned int);
+ r[len] = '\0';
+ return r;
+}
+
+const char *refstrndup(const char *str, size_t len)
+{
+ char *r;
+
+ if (!str)
+ return NULL;
+
+ len = strnlen(str, len);
+ r = refstr_alloc(len);
+ if (r)
+ memcpy(r, str, len);
+ return r;
+}
+
+const char *refstrdup(const char *str)
+{
+ char *r;
+ size_t len;
+
+ if (!str)
+ return NULL;
+
+ len = strlen(str);
+ r = refstr_alloc(len);
+ if (r)
+ memcpy(r, str, len);
+ return r;
+}
+
+int vrsprintf(const char **bufp, const char *fmt, va_list ap)
+{
+ va_list ap1;
+ int len;
+ char *p;
+
+ va_copy(ap1, ap);
+ len = vsnprintf(NULL, 0, fmt, ap1);
+ va_end(ap1);
+
+ *bufp = p = refstr_alloc(len);
+ if (!p)
+ return -1;
+
+ return vsnprintf(p, len + 1, fmt, ap);
+}
+
+int rsprintf(const char **bufp, const char *fmt, ...)
+{
+ int rv;
+ va_list ap;
+
+ va_start(ap, fmt);
+ rv = vrsprintf(bufp, fmt, ap);
+ va_end(ap);
+
+ return rv;
+}
+
+void refstr_put(const char *r)
+{
+ unsigned int *ref;
+
+ if (r) {
+ ref = (unsigned int *)r - 1;
+
+ if (!--*ref)
+ free(ref);
+ }
+}
diff --git a/com32/lib/syslinux/setadv.c b/com32/elflink/ldlinux/setadv.c
index 40f00a4e..2e386213 100644
--- a/com32/lib/syslinux/setadv.c
+++ b/com32/elflink/ldlinux/setadv.c
@@ -45,7 +45,7 @@
#include <errno.h>
#include <alloca.h>
-int syslinux_setadv(int tag, size_t size, const void *data)
+__export int syslinux_setadv(int tag, size_t size, const void *data)
{
uint8_t *p, *advtmp;
size_t rleft, left;
diff --git a/com32/elflink/test_com32.c b/com32/elflink/test_com32.c
new file mode 100644
index 00000000..19089dbd
--- /dev/null
+++ b/com32/elflink/test_com32.c
@@ -0,0 +1,208 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <console.h>
+#include <string.h>
+
+#include <sys/module.h>
+#include <sys/exec.h>
+
+#define INFO_PRINT(fmt, args...) printf("[COM32] " fmt, ##args)
+
+#define MAX_COMMAND_SIZE 80 // Maximum size of the cmd line
+#define COMMAND_DELIM " \t\n" // Whitespace delimiters
+#define MAX_COMMAND_ARGS (MAX_COMMAND_SIZE/2) // Maximum argument count for
+ // program execution
+
+/**
+ * print_help - Display usage instructions on the screen.
+ */
+static void print_help(void)
+{
+ printf("List of available commands:\n");
+ printf("exit - exits the program\n");
+ printf("help - shows this message\n");
+ printf("load <library>... - loads the libraries into the environment\n");
+ printf("spawn <executable> <args> - launches an executable module\n");
+ printf
+ ("unload <library>... - unloads the libraries from the environment\n");
+ printf("list - prints the currently loaded modules\n");
+}
+
+/**
+ * print_prompt - Display the command prompt.
+ */
+static void print_prompt(void)
+{
+ printf("\nelflink> ");
+}
+
+/**
+ * read_command - Read a new command from the standard input.
+ * @cmd: the buffer to store the command
+ * @size: the maximum size of the string that can be stored in the buffer
+ *
+ * If the command is larger than the specified size, it is truncated.
+ */
+static void read_command(char *cmd, int size)
+{
+ char *nl = NULL;
+ fgets(cmd, size, stdin);
+
+ // Strip the newline
+ nl = strchr(cmd, '\n');
+
+ if (nl != NULL)
+ *nl = '\0';
+}
+
+/**
+ * process_spawn - Handles the execution of a 'spawn' command.
+ *
+ * The command line is in the internal buffer of strtok.
+ */
+static void process_spawn(void)
+{
+ // Compose the command line
+ char **cmd_line = malloc((MAX_COMMAND_ARGS + 1) * sizeof(char *));
+ int argc = 0, result;
+ char *crt_arg;
+
+ do {
+ crt_arg = strtok(NULL, COMMAND_DELIM);
+ if (crt_arg != NULL && strlen(crt_arg) > 0) {
+ cmd_line[argc] = crt_arg;
+ argc++;
+ } else {
+ break;
+ }
+ } while (argc < MAX_COMMAND_ARGS);
+
+ cmd_line[argc] = NULL;
+
+ if (cmd_line[0] == NULL) {
+ printf("You must specify an executable module.\n");
+ } else {
+ result = spawnv(cmd_line[0], cmd_line);
+
+ printf("Spawn returned %d\n", result);
+ }
+
+ free(cmd_line);
+}
+
+/**
+ * process_library - Handles the execution of the 'load' and 'unload' commands.
+ * @load: contains 1 if the libraries are to be loaded, 0 for unloading.
+ *
+ * The command line is in the internal buffer of strtok.
+ */
+static void process_library(int load)
+{
+ char *crt_lib;
+ int result;
+
+ while ((crt_lib = strtok(NULL, COMMAND_DELIM)) != NULL) {
+ if (strlen(crt_lib) > 0) {
+ if (load)
+ result = load_library(crt_lib);
+ else
+ result = unload_library(crt_lib);
+
+ if (result == 0) {
+ printf("Library '%s' %sloaded successfully.\n", crt_lib,
+ load ? "" : "un");
+ } else {
+ printf("Could not %sload library '%s': error %d\n",
+ load ? "" : "un", crt_lib, result);
+ }
+ }
+ }
+}
+
+/**
+ * process_list - Handles the execution of the 'list' command.
+ *
+ */
+static void process_list(void)
+{
+ struct elf_module *module;
+ struct module_dep *crt_dep;
+
+ for_each_module(module) {
+ printf("%s (%dK, %s, %s) : ", module->name, module->module_size >> 10,
+ module->shallow ? "shallow" : "regular",
+ module->main_func == NULL ? "library" : "program");
+
+ list_for_each_entry(crt_dep, &module->required, list) {
+ printf("%s ", crt_dep->module->name);
+ }
+
+ printf("\n");
+ }
+}
+
+/**
+ * process_command - Recognizes the requested command and executes it.
+ * @cmd: the command to be executed.
+ *
+ * Returns 1 if the command was 'exit', 0 otherwise.
+ */
+static int process_command(char *cmd)
+{
+ char *cmd_name;
+
+ cmd_name = strtok(cmd, COMMAND_DELIM);
+
+ if (strcmp(cmd_name, "exit") == 0) {
+ printf("Goodbye!\n");
+ return 1;
+ } else if (strcmp(cmd_name, "help") == 0) {
+ print_help();
+ } else if (strcmp(cmd_name, "load") == 0) {
+ process_library(1);
+ } else if (strcmp(cmd_name, "spawn") == 0) {
+ process_spawn();
+ } else if (strcmp(cmd_name, "unload") == 0) {
+ process_library(0);
+ } else if (strcmp(cmd_name, "list") == 0) {
+ process_list();
+ } else {
+ printf("Unknown command. Type 'help' for a list of valid commands.\n");
+ }
+
+ return 0;
+}
+
+/**
+ * The entry point of 'test_com32' COM module.
+ */
+int main(int argc, char **argv)
+{
+ int done = 0;
+ int res;
+ char command[MAX_COMMAND_SIZE] = { 0 };
+
+ // Open a standard r/w console
+ openconsole(&dev_stdcon_r, &dev_stdcon_w);
+
+ res = exec_init();
+ if (res != 0) {
+ printf("Failed to initialize the execution environment.\n");
+ return res;
+ } else {
+ printf("Execution environment initialized successfully.\n");
+ }
+
+ printf("\nFor a list of available commands, type 'help'.\n");
+
+ do {
+ print_prompt();
+ read_command(command, MAX_COMMAND_SIZE);
+ done = process_command(command);
+
+ } while (!done);
+
+ exec_term();
+
+ return 0;
+}
diff --git a/com32/gfxboot/Makefile b/com32/gfxboot/Makefile
index 183115f4..bd0bab11 100644
--- a/com32/gfxboot/Makefile
+++ b/com32/gfxboot/Makefile
@@ -13,7 +13,7 @@
topdir = ../..
MAKEDIR = $(topdir)/mk
-include $(MAKEDIR)/com32.mk
+include $(MAKEDIR)/elf.mk
MODULES = gfxboot.c32
@@ -31,7 +31,7 @@ realmode_callback.o: realmode_callback.asm
$*.tmp $@
tidy dist:
- rm -f *.o *.lo *.a *.lst *.elf .*.d *.tmp
+ rm -f *.o *.lo *.a *.lst .*.d *.tmp
clean: tidy
rm -f *.lnx
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/gpllib/Makefile b/com32/gpllib/Makefile
index 4b7b8468..3ccc0dc6 100644
--- a/com32/gpllib/Makefile
+++ b/com32/gpllib/Makefile
@@ -19,26 +19,24 @@ AUXDIR = $(DATADIR)/syslinux
INCDIR = /usr/include
COM32DIR = $(AUXDIR)/com32
-all: libcom32gpl.a
+all: libgpl.c32
-libcom32gpl.a : $(LIBOBJS)
- rm -f $@
- $(AR) cq $@ $^
- $(RANLIB) $@
+libgpl.elf : $(LIBOBJS)
+ $(LD) -shared $(LDFLAGS) -soname $(patsubst %.elf,%.c32,$(@F)) -o $@ $^
tidy dist clean:
- find . \( -name \*.o -o -name \*.a -o -name .\*.d -o -name \*.tmp \) -print0 | \
+ find . \( -name \*.o -o -name .\*.d -o -name \*.tmp \) -print0 | \
xargs -0r rm -f
spotless: clean
- rm -f *.a
+ rm -f *.c32
rm -f *~ \#* */*~ */\#*
# Mixing in the GPL include files is suboptimal, but I'm not sure
# there is a better way to do it.
install: all
mkdir -m 755 -p $(INSTALLROOT)$(COM32DIR)
- install -m 644 libcom32gpl.a $(INSTALLROOT)$(COM32DIR)
+ install -m 644 libgpl.c32 $(INSTALLROOT)$(COM32DIR)
mkdir -p $(INSTALLROOT)$(COM32DIR)/include/
cp -r ../gplinclude $(INSTALLROOT)$(COM32DIR)/include/
diff --git a/com32/gpllib/disk/geom.c b/com32/gpllib/disk/geom.c
index 9e673ed4..e1095200 100644
--- a/com32/gpllib/disk/geom.c
+++ b/com32/gpllib/disk/geom.c
@@ -120,7 +120,7 @@ static int detect_extensions(struct driveinfo *drive_info)
static int get_drive_parameters_with_extensions(struct driveinfo *drive_info)
{
com32sys_t inreg, outreg;
- struct edd_device_parameters *dp = __com32.cs_bounce;
+ struct edd_device_parameters *dp;
memset(&inreg, 0, sizeof inreg);
@@ -134,6 +134,10 @@ static int get_drive_parameters_with_extensions(struct driveinfo *drive_info)
* If the buffer length is less than 26 on entry an error shall be
* returned.
*/
+ dp = lmalloc(sizeof *dp);
+ if (!dp)
+ return -1;
+
dp->len = sizeof(struct edd_device_parameters);
inreg.esi.w[0] = OFFS(dp);
@@ -144,10 +148,13 @@ static int get_drive_parameters_with_extensions(struct driveinfo *drive_info)
__intcall(0x13, &inreg, &outreg);
/* CF set on error */
- if (outreg.eflags.l & EFLAGS_CF)
+ if (outreg.eflags.l & EFLAGS_CF) {
+ lfree(dp);
return outreg.eax.b[1];
+ }
memcpy(&drive_info->edd_params, dp, sizeof drive_info->edd_params);
+ lfree(dp);
return 0;
}
diff --git a/com32/gpllib/disk/read.c b/com32/gpllib/disk/read.c
index 7a6cc430..541957f9 100644
--- a/com32/gpllib/disk/read.c
+++ b/com32/gpllib/disk/read.c
@@ -76,13 +76,22 @@ int read_sectors(struct driveinfo *drive_info, void *data,
const unsigned int lba, const int sectors)
{
com32sys_t inreg, outreg;
- struct ebios_dapa *dapa = __com32.cs_bounce;
- void *buf = (char *)__com32.cs_bounce + sectors * SECTOR;
+ struct ebios_dapa *dapa;
+ void *buf;
char *bufp = data;
+ int rv = -1;
if (get_drive_parameters(drive_info) == -1)
return -1;
+ buf = lmalloc(sectors * SECTOR);
+ if (!buf)
+ return -1;
+
+ dapa = lmalloc(sizeof(*dapa));
+ if (!dapa)
+ goto fail;
+
memset(&inreg, 0, sizeof inreg);
if (drive_info->ebios) {
@@ -102,7 +111,7 @@ int read_sectors(struct driveinfo *drive_info, void *data,
if (!drive_info->cbios) { // XXX errno
/* We failed to get the geometry */
if (lba)
- return -1; /* Can only read MBR */
+ goto fail; /* Can only read MBR */
s = 1;
h = 0;
@@ -112,7 +121,7 @@ int read_sectors(struct driveinfo *drive_info, void *data,
// XXX errno
if (s > 63 || h > 256 || c > 1023)
- return -1;
+ goto fail;
inreg.eax.w[0] = 0x0201; /* Read one sector */
inreg.ecx.b[1] = c & 0xff;
@@ -126,10 +135,14 @@ int read_sectors(struct driveinfo *drive_info, void *data,
/* Perform the read */
if (int13_retry(&inreg, &outreg)) {
errno_disk = outreg.eax.b[1];
- return -1; /* Give up */
+ goto fail; /* Give up */
}
memcpy(bufp, buf, sectors * SECTOR);
+ rv = sectors;
- return sectors;
+fail:
+ lfree(dapa);
+ lfree(buf);
+ return rv;
}
diff --git a/com32/gpllib/disk/write.c b/com32/gpllib/disk/write.c
index 89e530d9..d183adef 100644
--- a/com32/gpllib/disk/write.c
+++ b/com32/gpllib/disk/write.c
@@ -36,8 +36,17 @@ int write_sectors(const struct driveinfo *drive_info, const unsigned int lba,
const void *data, const int size)
{
com32sys_t inreg, outreg;
- struct ebios_dapa *dapa = __com32.cs_bounce;
- void *buf = (char *)__com32.cs_bounce + size;
+ struct ebios_dapa *dapa;
+ void *buf;
+ int rv = -1;
+
+ buf = lmalloc(size);
+ if (!buf)
+ return -1;
+
+ dapa = lmalloc(sizeof(*dapa));
+ if (!dapa)
+ goto out;
memcpy(buf, data, size);
memset(&inreg, 0, sizeof inreg);
@@ -59,7 +68,7 @@ int write_sectors(const struct driveinfo *drive_info, const unsigned int lba,
if (!drive_info->cbios) { // XXX errno
/* We failed to get the geometry */
if (lba)
- return -1; /* Can only write MBR */
+ goto out; /* Can only write MBR */
s = 1;
h = 0;
@@ -69,7 +78,7 @@ int write_sectors(const struct driveinfo *drive_info, const unsigned int lba,
// XXX errno
if (s > 63 || h > 256 || c > 1023)
- return -1;
+ goto out;
inreg.eax.w[0] = 0x0301; /* Write one sector */
inreg.ecx.b[1] = c & 0xff;
@@ -82,10 +91,13 @@ int write_sectors(const struct driveinfo *drive_info, const unsigned int lba,
/* Perform the write */
if (int13_retry(&inreg, &outreg)) {
- errno_disk = outreg.eax.b[1];
- return -1; /* Give up */
+ errno_disk = outreg.eax.b[1]; /* Give up */
} else
- return size;
+ rv = size;
+out:
+ lfree(dapa);
+ lfree(buf);
+ return rv;
}
/**
diff --git a/com32/gpllib/memory.c b/com32/gpllib/memory.c
index 28a95ff4..06c746da 100644
--- a/com32/gpllib/memory.c
+++ b/com32/gpllib/memory.c
@@ -87,15 +87,20 @@ void detect_memory_e820(struct e820entry *desc, int size_map, int *size_found)
{
int count = 0;
static struct e820_ext_entry buf; /* static so it is zeroed */
+ void *bounce;
com32sys_t ireg, oreg;
memset(&ireg, 0, sizeof ireg);
+ bounce = lmalloc(sizeof buf);
+ if (!bounce)
+ goto out;
+
ireg.eax.w[0] = 0xe820;
ireg.edx.l = SMAP;
ireg.ecx.l = sizeof(struct e820_ext_entry);
- ireg.edi.w[0] = OFFS(__com32.cs_bounce);
- ireg.es = SEG(__com32.cs_bounce);
+ ireg.edi.w[0] = OFFS(bounce);
+ ireg.es = SEG(bounce);
/*
* Set this here so that if the BIOS doesn't change this field
@@ -105,7 +110,7 @@ void detect_memory_e820(struct e820entry *desc, int size_map, int *size_found)
buf.ext_flags = 1;
do {
- memcpy(__com32.cs_bounce, &buf, sizeof buf);
+ memcpy(bounce, &buf, sizeof buf);
/* Important: %edx and %esi are clobbered by some BIOSes,
so they must be either used for the error output
@@ -126,7 +131,7 @@ void detect_memory_e820(struct e820entry *desc, int size_map, int *size_found)
if (oreg.eflags.l & EFLAGS_CF || oreg.ecx.l < 20)
break;
- memcpy(&buf, __com32.cs_bounce, sizeof buf);
+ memcpy(&buf, bounce, sizeof buf);
/*
* ACPI 3.0 added the extended flags support. If bit 0
@@ -143,6 +148,8 @@ void detect_memory_e820(struct e820entry *desc, int size_map, int *size_found)
ireg.ebx.l = oreg.ebx.l;
} while (ireg.ebx.l && count < size_map);
+out:
+ lfree(bounce);
*size_found = count;
}
diff --git a/com32/hdt/Makefile b/com32/hdt/Makefile
index add640a7..42f5c0d1 100644
--- a/com32/hdt/Makefile
+++ b/com32/hdt/Makefile
@@ -17,9 +17,10 @@
topdir = ../..
MAKEDIR = $(topdir)/mk
-include $(MAKEDIR)/com32.mk
+include $(MAKEDIR)/elf.mk
-LIBS = ../cmenu/libmenu/libmenu.a ../libupload/libcom32upload.a
+LIBS = ../libupload/libcom32upload.a
+C_LIBS += $(com32)/cmenu/libmenu/libmenu.c32
CFLAGS += -I$(com32)/cmenu/libmenu -I$(com32)
MODULES = hdt.c32
diff --git a/com32/hdt/hdt-cli.c b/com32/hdt/hdt-cli.c
index 7542da83..216b6bde 100644
--- a/com32/hdt/hdt-cli.c
+++ b/com32/hdt/hdt-cli.c
@@ -649,7 +649,7 @@ static void exec_command(char *line, struct s_hardware *hardware)
if ((current_module->nomodule == true) && ( module != NULL)) {
dprintf("CLI_DEBUG exec: Reworking arguments with argc=%d\n",argc);
char **new_argv=NULL;
- new_argv=malloc((argc + 2)*sizeof(char));
+ new_argv=malloc((argc + 2)*sizeof(char *));
for (int argc_iter=0; argc_iter<argc; argc_iter++) {
dprintf("CLI_DEBUG exec rework : copy %d to %d (%s)\n",argc_iter,argc_iter+1,argv[argc_iter]);
new_argv[argc_iter+1] = malloc(strlen(argv[argc_iter]));
diff --git a/com32/hdt/hdt-common.c b/com32/hdt/hdt-common.c
index dcad28cd..289d74e3 100644
--- a/com32/hdt/hdt-common.c
+++ b/com32/hdt/hdt-common.c
@@ -317,6 +317,7 @@ int detect_vesa(struct s_hardware *hardware)
struct vesa_mode_info *mi;
uint16_t mode, *mode_ptr;
char *oem_ptr;
+ int rv = -1;
if (hardware->vesa_detection == true)
return -1;
@@ -324,9 +325,13 @@ int detect_vesa(struct s_hardware *hardware)
hardware->vesa_detection = true;
hardware->is_vesa_valid = false;
- /* Allocate space in the bounce buffer for these structures */
- gi = &((struct vesa_info *)__com32.cs_bounce)->gi;
- mi = &((struct vesa_info *)__com32.cs_bounce)->mi;
+ gi = lmalloc(sizeof(*gi));
+ if (!gi)
+ return -1;
+
+ mi = lmalloc(sizeof(*mi));
+ if (!mi)
+ goto out;
gi->signature = VBE2_MAGIC; /* Get VBE2 extended data */
rm.eax.w[0] = 0x4F00; /* Get SVGA general information */
@@ -335,7 +340,7 @@ int detect_vesa(struct s_hardware *hardware)
__intcall(0x10, &rm, &rm);
if (rm.eax.w[0] != 0x004F) {
- return -1;
+ goto out;
};
mode_ptr = GET_PTR(gi->video_mode_ptr);
@@ -374,7 +379,12 @@ int detect_vesa(struct s_hardware *hardware)
hardware->vesa.vmi_count++;
}
hardware->is_vesa_valid = true;
- return 0;
+
+ rv = 0;
+out:
+ lfree(mi);
+ lfree(gi);
+ return rv;
}
/* Try to detect disks from port 0x80 to 0xff */
diff --git a/com32/hdt/hdt-common.h b/com32/hdt/hdt-common.h
index c2299b48..53aa43e7 100644
--- a/com32/hdt/hdt-common.h
+++ b/com32/hdt/hdt-common.h
@@ -54,9 +54,6 @@
#include <acpi/acpi.h>
#include <libupload/upload_backend.h>
-/* Declare a variable or data structure as unused. */
-#define __unused __attribute__ (( unused ))
-
/* This two values are used for switching for the menu to the CLI mode */
#define HDT_SWITCH_TO_CLI "hdt_switch_to_cli"
#define HDT_DUMP "hdt_dump"
diff --git a/com32/hdt/hdt.c b/com32/hdt/hdt.c
index 653995d0..67b3ab0c 100644
--- a/com32/hdt/hdt.c
+++ b/com32/hdt/hdt.c
@@ -48,7 +48,7 @@ int max_console_lines = MAX_CLI_LINES;
int main(const int argc, const char *argv[])
{
char version_string[256];
- struct s_hardware hardware;
+ static struct s_hardware hardware;
snprintf(version_string, sizeof version_string, "%s %s (%s)",
PRODUCT_NAME, VERSION, CODENAME);
diff --git a/com32/include/byteswap.h b/com32/include/byteswap.h
new file mode 100644
index 00000000..11870e97
--- /dev/null
+++ b/com32/include/byteswap.h
@@ -0,0 +1,50 @@
+#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)
+{
+ asm("xchgb %h0,%b0 ; roll $16,%0 ; xchgb %h0,%b0"
+ : "+q" (v));
+ 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/cli.h b/com32/include/cli.h
new file mode 100644
index 00000000..eee4576f
--- /dev/null
+++ b/com32/include/cli.h
@@ -0,0 +1,20 @@
+#ifndef CLI_H
+#define CLI_H
+
+#define MAX_CMD_HISTORY 64
+#define COMMAND_DELIM " \t\n" // Whitespace delimiters
+#define MAX_COMMAND_ARGS 40
+
+struct cli_command {
+ struct list_head list;
+ char *command;
+};
+
+extern void clear_screen(void);
+extern int mygetkey(clock_t timeout);
+extern const char *edit_cmdline(const char *input, int top /*, int width */ ,
+ int (*pDraw_Menu) (int, int, int),
+ void (*show_fkey) (int), bool *);
+
+extern struct menu *root_menu, *start_menu, *hide_menu, *menu_list, *default_menu;
+#endif
diff --git a/com32/include/com32.h b/com32/include/com32.h
index 6b142082..795b9fba 100644
--- a/com32/include/com32.h
+++ b/com32/include/com32.h
@@ -135,10 +135,22 @@ char *lstrdup(const char *);
* specific segment. OFFS_VALID() will return whether or not the
* pointer is actually reachable from the target segment.
*/
+#if defined(DEBUG) && (defined(__COM32__) || defined(__SYSLINUX_CORE__))
+__noreturn __bad_SEG(const volatile void *);
+
static inline uint16_t SEG(const volatile void *__p)
{
+ if (__unlikely((uintptr_t)__p > 0xfffff))
+ __bad_SEG(__p);
+
return (uint16_t) (((uintptr_t) __p) >> 4);
}
+#else
+static inline uint16_t SEG(const volatile void *__p)
+{
+ return (uint16_t) (((uintptr_t) __p) >> 4);
+}
+#endif
static inline uint16_t OFFS(const volatile void *__p)
{
@@ -194,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/dprintf.h b/com32/include/dprintf.h
index b8a3b84c..1b539698 100644
--- a/com32/include/dprintf.h
+++ b/com32/include/dprintf.h
@@ -5,6 +5,12 @@
#ifndef _DPRINTF_H
#define _DPRINTF_H
+#include <syslinux/debug.h>
+
+#if !defined(DEBUG_PORT) && !defined(DEBUG_STDIO)
+# undef DEBUG
+#endif
+
#ifdef DEBUG
# include <stdio.h>
@@ -12,15 +18,22 @@
# ifdef DEBUG_STDIO
# define dprintf printf
# define vdprintf vprintf
+# define ddprintf dprintf
# else
void dprintf(const char *, ...);
void vdprintf(const char *, va_list);
+# define ddprintf(...) { printf(__VA_ARGS__); dprintf(__VA_ARGS__); }
# endif
#else
-# define dprintf(fmt, ...) ((void)(0))
-# define vdprintf(fmt, ap) ((void)(0))
+#define dprintf(...) \
+ if (syslinux_debug_enabled) \
+ printf(__VA_ARGS__)
+#define vdprintf(fmt, ap) \
+ if (syslinux_debug_enabled) \
+ vprintf(fmt, ap)
+#define ddprintf printf
#endif /* DEBUG */
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/hw/vga.h b/com32/include/hw/vga.h
new file mode 100644
index 00000000..0ebd2e25
--- /dev/null
+++ b/com32/include/hw/vga.h
@@ -0,0 +1,104 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2012 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef _HW_VGA_H
+#define _HW_VGA_H 1
+
+#include <sys/io.h>
+
+/* These are relative to the CRTC base address */
+#define VGA_CRTC_ADDR 0x4
+#define VGA_CRTC_DATA 0x5
+#define VGA_CRTC_IX_HORIZ_TOTAL 0x00
+#define VGA_CRTC_IX_END_HORIZ_DISPLAY 0x01
+#define VGA_CRTC_IX_START_HORIZ_BLANK 0x02
+#define VGA_CRTC_IX_END_HORIZ_BLANK 0x03
+#define VGA_CRTC_IX_START_HORIZ_RETR 0x04
+#define VGA_CRTC_IX_END_HORIZ_RETR 0x05
+#define VGA_CRTC_IX_VERT_TOTAL 0x06
+#define VGA_CRTC_IX_OVERFLOW 0x07
+#define VGA_CRTC_IX_PRESET_ROW_SCAN 0x08
+#define VGA_CRTC_IX_MAX_SCAN_LINE 0x09
+#define VGA_CRTC_IX_CURSOR_START 0x0a
+#define VGA_CRTC_IX_CURSOR_END 0x0b
+#define VGA_CRTC_IX_START_ADDR_HIGH 0x0c
+#define VGA_CRTC_IX_START_ADDR_LOW 0x0d
+#define VGA_CRTC_IX_CURSOR_POS_HIGH 0x0e
+#define VGA_CRTC_IX_CURSOR_POS_LOW 0x0f
+#define VGA_CRTC_IX_START_VERT_RETR 0x10
+#define VGA_CRTC_IX_END_VERT_RETR 0x11
+#define VGA_CRTC_IX_END_VERT_DISPLAY 0x12
+#define VGA_CRTC_IX_OFFSET 0x13
+#define VGA_CRTC_IX_UNDERLINE 0x14
+#define VGA_CRTC_IX_START_VERT_BLANK 0x15
+#define VGA_CRTC_IX_END_VERT_BLANK 0x16
+#define VGA_CRTC_IX_MODE_CONTROL 0x17
+#define VGA_CRTC_IX_LINE_COMPARE 0x18
+#define VGA_CRTC_INPUT_STATUS_1 0xa
+#define VGA_CRTC_FEATURE_CONTROL_WRITE 0xa
+
+#define VGA_ATTR_ADDR_DATA 0x3c0
+#define VGA_ATTR_DATA_READ 0x3c1
+/* 0x00-0x0f are 16->64 palette registers */
+#define VGA_ATTR_IX_MODE_CONTROL 0x10
+#define VGA_ATTR_IX_OVERSCAN 0x11
+#define VGA_ATTR_IX_COLOR_PLANE_ENABLE 0x12
+#define VGA_ATTR_IX_HORIZ_PIXEL_PAN 0x13
+#define VGA_ADDR_IX_COLOR_SELECT 0x14
+#define VGA_INPUT_STATUS_0 0x3c2
+#define VGA_MISC_OUTPUT_WRITE 0x3c2
+#define VGA_SEQ_ADDR 0x3c4
+#define VGA_SEQ_DATA 0x3c5
+#define VGA_SEQ_IX_RESET 0
+#define VGA_SEQ_IX_CLOCKMODE 1
+#define VGA_SEQ_IX_MAP_MASK 2
+#define VGA_SEQ_IX_CHAR_MAP 3
+#define VGA_SEQ_IX_SEQ_MEM_MODE 4
+#define VGA_DAC_STATE 0x3c7
+#define VGA_DAC_ADDR_READ_MODE 0x3c7
+#define VGA_DAC_ADDR_WRITE_MODE 0x3c8
+#define VGA_DAC_DATA 0x3c9
+#define VGA_FEATURE_CONTROL_READ 0x3ca
+#define VGA_MISC_OUTPUT_READ 0x3cc
+#define VGA_GC_ADDR 0x3ce
+#define VGA_GC_DATA 0x3cf
+#define VGA_GC_IX_SET_RESET 0
+#define VGA_GC_IX_ENABLE_SET_RESET 1
+#define VGA_GC_IX_COLOR_COMPARE 2
+#define VGA_GC_IX_DATA_ROTATE 3
+#define VGA_GC_IX_READ_MAP_SELECT 4
+#define VGA_GC_IX_GRAPHICS_MODE 5
+#define VGA_GC_IX_MISC_GRAPHICS 6
+#define VGA_GC_IX_COLOR_DONT_CARE 7
+#define VGA_GC_IX_BIT_MASK 8
+
+static inline uint16_t vga_crtc_base(void)
+{
+ return 0x3b0 + ((inb(VGA_MISC_OUTPUT_READ) & 1) << 5);
+}
+
+#endif /* _HW_VGA_H */
diff --git a/com32/include/klibc/compiler.h b/com32/include/klibc/compiler.h
index 5ac21185..e8548b59 100644
--- a/com32/include/klibc/compiler.h
+++ b/com32/include/klibc/compiler.h
@@ -108,6 +108,16 @@
# define __unusedfunc
#endif
+/* Declare a variable or data structure as unused. */
+#ifdef __GNUC__
+# define __unused __attribute__((unused))
+#else
+# define __unused
+#endif
+
+/* Used symbol */
+#define __used __attribute__((used))
+
/* Constructors and destructors */
#define __constructor __attribute__((constructor))
#define __destructor __attribute__((destructor))
@@ -126,4 +136,9 @@
#define __common __attribute__((common))
#define __nocommon __attribute__((nocommon))
+/* Weak symbols */
+#define __weak __attribute__((weak))
+
+#define __export __attribute__((visibility("default")))
+
#endif
diff --git a/com32/include/linux/list.h b/com32/include/linux/list.h
new file mode 100644
index 00000000..157ded10
--- /dev/null
+++ b/com32/include/linux/list.h
@@ -0,0 +1,464 @@
+// This list structure implementation is adapted from the list implementation
+// on the Linux kernel.
+
+// Original source:
+// http://git.kernel.org/?p=linux/kernel/git/stable/linux-2.6.25.y.git;a=blob_plain;f=include/linux/list.h;hb=HEAD
+
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+#include <stdlib.h>
+#include <stddef.h>
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+ list->next = list;
+ list->prev = list;
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty() on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = NULL;
+ entry->prev = NULL;
+}
+
+/**
+ * list_replace - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ *
+ * If @old was empty, it will be overwritten.
+ */
+static inline void list_replace(struct list_head *old,
+ struct list_head *new)
+{
+ new->next = old->next;
+ new->next->prev = new;
+ new->prev = old->prev;
+ new->prev->next = new;
+}
+
+static inline void list_replace_init(struct list_head *old,
+ struct list_head *new)
+{
+ list_replace(old, new);
+ INIT_LIST_HEAD(old);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+ struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add_tail(list, head);
+}
+
+/**
+ * list_is_last - tests whether @list is the last entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_last(const struct list_head *list,
+ const struct list_head *head)
+{
+ return list->next == head;
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+ return head->next == head;
+}
+
+/**
+ * list_empty_careful - tests whether a list is empty and not being modified
+ * @head: the list to test
+ *
+ * Description:
+ * tests whether a list is empty _and_ checks that no other CPU might be
+ * in the process of modifying either member (next or prev)
+ *
+ * NOTE: using list_empty_careful() without synchronization
+ * can only be safe if the only activity that can happen
+ * to the list entry is list_del_init(). Eg. it cannot be used
+ * if another CPU could re-list_add() it.
+ */
+static inline int list_empty_careful(const struct list_head *head)
+{
+ struct list_head *next = head->next;
+ return (next == head) && (next == head->prev);
+}
+
+static inline void __list_splice(struct list_head *list,
+ struct list_head *head)
+{
+ struct list_head *first = list->next;
+ struct list_head *last = list->prev;
+ struct list_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list)) {
+ __list_splice(list, head);
+ INIT_LIST_HEAD(list);
+ }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * list_first_entry - get the first element from a list
+ * @ptr: the list head to take the element from.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Note, that list is expected to be not empty.
+ */
+#define list_first_entry(ptr, type, member) \
+ list_entry((ptr)->next, type, member)
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); \
+ pos = pos->next)
+
+/**
+ * __list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @head: the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev - iterate over a list backwards
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @head: the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+ for (pos = (head)->prev; pos != (head); \
+ pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/**
+ * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop cursor.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_prev_safe(pos, n, head) \
+ for (pos = (head)->prev, n = pos->prev; \
+ pos != (head); \
+ pos = n, n = pos->prev)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+* @pos: the type * to use as a loop cursor.
+* @n: another type * to use as temporary storage
+* @head: the head for your list.
+* @member: the name of the list_struct within the struct.
+*/
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
+ * @pos: the type * to use as a start point
+ * @head: the head of the list
+ * @member: the name of the list_struct within the struct.
+ *
+ * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
+ */
+#define list_prepare_entry(pos, head, member) \
+ ((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue - continue iteration over list of given type
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Continue to iterate over list of given type, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue(pos, head, member) \
+ for (pos = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue_reverse - iterate backwards from the given point
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Start to iterate over list of given type backwards, continuing after
+ * the current position.
+ */
+#define list_for_each_entry_continue_reverse(pos, head, member) \
+ for (pos = list_entry(pos->member.prev, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_from - iterate over list of given type from the current point
+ * @pos: the type * to use as a loop cursor.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing from current position.
+ */
+#define list_for_each_entry_from(pos, head, member) \
+ for (; &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_continue
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type, continuing after current point,
+ * safe against removal of list entry.
+ */
+#define list_for_each_entry_safe_continue(pos, n, head, member) \
+ for (pos = list_entry(pos->member.next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_from
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate over list of given type from current point, safe against
+ * removal of list entry.
+ */
+#define list_for_each_entry_safe_from(pos, n, head, member) \
+ for (n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_entry_safe_reverse
+ * @pos: the type * to use as a loop cursor.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * Iterate backwards over list of given type, safe against removal
+ * of list entry.
+ */
+#define list_for_each_entry_safe_reverse(pos, n, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member), \
+ n = list_entry(pos->member.prev, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.prev, typeof(*n), member))
+
+
+#endif
diff --git a/com32/menu/menu.h b/com32/include/menu.h
index 1db4d7c9..bc0182f7 100644
--- a/com32/menu/menu.h
+++ b/com32/include/menu.h
@@ -87,13 +87,10 @@ enum kernel_type {
KT_BSS, /* Boot sector with patch */
KT_PXE, /* PXE NBP */
KT_FDIMAGE, /* Floppy disk image */
- KT_COMBOOT, /* COMBOOT image */
KT_COM32, /* COM32 image */
KT_CONFIG, /* Configuration file */
};
-extern const char *const kernel_types[];
-
/* Configurable integer parameters */
enum parameter_number {
P_WIDTH,
@@ -187,6 +184,7 @@ extern int shiftkey;
extern int hiddenmenu;
extern int clearmenu;
extern long long totaltimeout;
+extern clock_t kbdtimeout;
extern const char *hide_key[KEY_MAX];
void parse_configs(char **argv);
@@ -227,10 +225,10 @@ extern const int message_base_color;
extern const char *current_background;
void set_background(const char *new_background);
-/* execute.c */
-void execute(const char *cmdline, enum kernel_type type);
-
/* drain.c */
void drain_keyboard(void);
+/* chainboot.c */
+void chainboot_file(const char *file, enum kernel_type type);
+
#endif /* MENU_H */
diff --git a/com32/include/netinet/in.h b/com32/include/netinet/in.h
index d2af351f..b24f8046 100644
--- a/com32/include/netinet/in.h
+++ b/com32/include/netinet/in.h
@@ -3,49 +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)
-{
- asm("xchgb %h0,%b0 ; roll $16,%0 ; xchgb %h0,%b0"
- : "+q" (v));
- 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/menu/refstr.h b/com32/include/refstr.h
index 7001d407..7001d407 100644
--- a/com32/menu/refstr.h
+++ b/com32/include/refstr.h
diff --git a/com32/include/sort.h b/com32/include/sort.h
new file mode 100644
index 00000000..0b495482
--- /dev/null
+++ b/com32/include/sort.h
@@ -0,0 +1,18 @@
+/*
+ * sort.h - Quick sort module API definitions
+ *
+ * Created on: Aug 11, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+#ifndef SORT_H_
+#define SORT_H_
+
+/**
+ * quick_sort - In place sort of an array of numbers.
+ * @nums: Pointer to the array
+ * @count: The number count in the array
+ */
+extern void quick_sort(int *nums, int count);
+
+#endif /* SORT_H_ */
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/stdio.h b/com32/include/stdio.h
index f37bdd9e..813a0edc 100644
--- a/com32/include/stdio.h
+++ b/com32/include/stdio.h
@@ -100,6 +100,11 @@ __extern int vsnprintf(char *, size_t n, const char *, va_list);
__extern int asprintf(char **, const char *, ...);
__extern int vasprintf(char **, const char *, va_list);
+#define mp(f, x...) \
+ printf("[%s()]: " f "\n", __func__,##x)
+#define mpi() mp("enter")
+#define mpo() mp("exit")
+
/* No buffering, so no flushing needed */
static __inline__ int fflush(FILE * __f)
{
@@ -114,4 +119,27 @@ __extern void perror(const char *);
__extern int rename(const char *, const char *);
+/*
+ * unhexchar: Convert a hexadecimal digit to the equivalent number
+ *
+ * Returns 0 if 'data' was converted succesfully, -1 otherwise.
+ */
+static inline int unhexchar(unsigned char *data)
+{
+ unsigned char num = *data;
+
+ if (num >= '0' && num <= '9') {
+ *data = num - '0';
+ return 0;
+ } else {
+ num |= 0x20; /* upper case -> lower case */
+ if (num >= 'a' && num <= 'f') {
+ *data = num - 'a' + 10;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
#endif /* _STDIO_H */
diff --git a/com32/include/sys/cpu.h b/com32/include/sys/cpu.h
index 53a6250e..807e13c4 100644
--- a/com32/include/sys/cpu.h
+++ b/com32/include/sys/cpu.h
@@ -121,22 +121,45 @@ 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");
}
+typedef unsigned long irq_state_t;
+
+static inline irq_state_t irq_state(void)
+{
+ irq_state_t __st;
+
+ asm volatile("pushfl ; popl %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("pushl %0 ; popfl" : : "rm" (__st) : "memory");
+}
+
+
#endif
diff --git a/com32/include/sys/elfcommon.h b/com32/include/sys/elfcommon.h
index 2489e3c0..8d6ddb05 100644
--- a/com32/include/sys/elfcommon.h
+++ b/com32/include/sys/elfcommon.h
@@ -59,32 +59,108 @@
#define EM_S390_OLD 0xA390 /* Obsolete interrim value for S/390 */
/* Dynamic type values */
-#define DT_NULL 0
-#define DT_NEEDED 1
-#define DT_PLTRELSZ 2
-#define DT_PLTGOT 3
-#define DT_HASH 4
-#define DT_STRTAB 5
-#define DT_SYMTAB 6
-#define DT_RELA 7
-#define DT_RELASZ 8
-#define DT_RELAENT 9
-#define DT_STRSZ 10
-#define DT_SYMENT 11
-#define DT_INIT 12
-#define DT_FINI 13
-#define DT_SONAME 14
-#define DT_RPATH 15
-#define DT_SYMBOLIC 16
-#define DT_REL 17
-#define DT_RELSZ 18
-#define DT_RELENT 19
-#define DT_PLTREL 20
-#define DT_DEBUG 21
-#define DT_TEXTREL 22
-#define DT_JMPREL 23
-#define DT_LOPROC 0x70000000
-#define DT_HIPROC 0x7fffffff
+#define DT_NULL 0 /* Marks end of dynamic section */
+#define DT_NEEDED 1 /* Name of needed library */
+#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */
+#define DT_PLTGOT 3 /* Processor defined value */
+#define DT_HASH 4 /* Address of symbol hash table */
+#define DT_STRTAB 5 /* Address of string table */
+#define DT_SYMTAB 6 /* Address of symbol table */
+#define DT_RELA 7 /* Address of Rela relocs */
+#define DT_RELASZ 8 /* Total size of Rela relocs */
+#define DT_RELAENT 9 /* Size of one Rela reloc */
+#define DT_STRSZ 10 /* Size of string table */
+#define DT_SYMENT 11 /* Size of one symbol table entry */
+#define DT_INIT 12 /* Address of init function */
+#define DT_FINI 13 /* Address of termination function */
+#define DT_SONAME 14 /* Name of shared object */
+#define DT_RPATH 15 /* Library search path (deprecated) */
+#define DT_SYMBOLIC 16 /* Start symbol search here */
+#define DT_REL 17 /* Address of Rel relocs */
+#define DT_RELSZ 18 /* Total size of Rel relocs */
+#define DT_RELENT 19 /* Size of one Rel reloc */
+#define DT_PLTREL 20 /* Type of reloc in PLT */
+#define DT_DEBUG 21 /* For debugging; unspecified */
+#define DT_TEXTREL 22 /* Reloc might modify .text */
+#define DT_JMPREL 23 /* Address of PLT relocs */
+#define DT_BIND_NOW 24 /* Process relocations of object */
+#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */
+#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */
+#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */
+#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */
+#define DT_RUNPATH 29 /* Library search path */
+#define DT_FLAGS 30 /* Flags for the object being loaded */
+#define DT_ENCODING 32 /* Start of encoded range */
+#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/
+#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */
+#define DT_NUM 34 /* Number used */
+#define DT_LOOS 0x6000000d /* Start of OS-specific */
+#define DT_HIOS 0x6ffff000 /* End of OS-specific */
+#define DT_LOPROC 0x70000000 /* Start of processor-specific */
+#define DT_HIPROC 0x7fffffff /* End of processor-specific */
+
+#define DT_VALRNGLO 0x6ffffd00
+#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */
+#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */
+#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */
+#define DT_CHECKSUM 0x6ffffdf8
+#define DT_PLTPADSZ 0x6ffffdf9
+#define DT_MOVEENT 0x6ffffdfa
+#define DT_MOVESZ 0x6ffffdfb
+#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */
+#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting
+ the following DT_* entry. */
+#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */
+#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */
+#define DT_VALRNGHI 0x6ffffdff
+#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */
+#define DT_VALNUM 12
+
+/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
+ Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
+
+ If any adjustment is made to the ELF object after it has been
+ built these entries will need to be adjusted. */
+#define DT_ADDRRNGLO 0x6ffffe00
+#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */
+#define DT_TLSDESC_PLT 0x6ffffef6
+#define DT_TLSDESC_GOT 0x6ffffef7
+#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */
+#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */
+#define DT_CONFIG 0x6ffffefa /* Configuration information. */
+#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */
+#define DT_AUDIT 0x6ffffefc /* Object auditing. */
+#define DT_PLTPAD 0x6ffffefd /* PLT padding. */
+#define DT_MOVETAB 0x6ffffefe /* Move table. */
+#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */
+#define DT_ADDRRNGHI 0x6ffffeff
+#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */
+#define DT_ADDRNUM 11
+
+/* The versioning entry types. The next are defined as part of the
+ GNU extension. */
+#define DT_VERSYM 0x6ffffff0
+
+#define DT_RELACOUNT 0x6ffffff9
+#define DT_RELCOUNT 0x6ffffffa
+
+/* These were chosen by Sun. */
+#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */
+#define DT_VERDEF 0x6ffffffc /* Address of version definition
+ table */
+#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */
+#define DT_VERNEED 0x6ffffffe /* Address of table with needed
+ versions */
+#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */
+#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */
+#define DT_VERSIONTAGNUM 16
+
+/* Sun added these machine-independent extensions in the "processor-specific"
+ range. Be compatible. */
+#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */
+#define DT_FILTER 0x7fffffff /* Shared object to get values from */
+#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1)
+#define DT_EXTRANUM 3
/* Auxilliary table entries */
#define AT_NULL 0 /* end of vector */
@@ -147,6 +223,52 @@
#define SHN_COMMON 0xfff2
#define SHN_HIRESERVE 0xffff
+/* Symbol table definitions */
+
+/* How to extract and insert information held in the st_info field. */
+
+#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4)
+#define ELF32_ST_TYPE(val) ((val) & 0xf)
+#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
+
+/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */
+#define ELF64_ST_BIND(val) ELF32_ST_BIND (val)
+#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val)
+#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type))
+
+/* Legal values for ST_BIND subfield of st_info (symbol binding). */
+
+#define STB_LOCAL 0 /* Local symbol */
+#define STB_GLOBAL 1 /* Global symbol */
+#define STB_WEAK 2 /* Weak symbol */
+#define STB_NUM 3 /* Number of defined types. */
+#define STB_LOOS 10 /* Start of OS-specific */
+#define STB_HIOS 12 /* End of OS-specific */
+#define STB_LOPROC 13 /* Start of processor-specific */
+#define STB_HIPROC 15 /* End of processor-specific */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type). */
+
+#define STT_NOTYPE 0 /* Symbol type is unspecified */
+#define STT_OBJECT 1 /* Symbol is a data object */
+#define STT_FUNC 2 /* Symbol is a code object */
+#define STT_SECTION 3 /* Symbol associated with a section */
+#define STT_FILE 4 /* Symbol's name is file name */
+#define STT_COMMON 5 /* Symbol is a common data object */
+#define STT_TLS 6 /* Symbol is thread-local data object*/
+#define STT_NUM 7 /* Number of defined types. */
+#define STT_LOOS 10 /* Start of OS-specific */
+#define STT_HIOS 12 /* End of OS-specific */
+#define STT_LOPROC 13 /* Start of processor-specific */
+#define STT_HIPROC 15 /* End of processor-specific */
+
+
+/* Symbol table indices are found in the hash buckets and chain table
+ of a symbol hash table section. This special index value indicates
+ the end of a chain, meaning no further symbols are found in that bucket. */
+
+#define STN_UNDEF 0 /* End of a chain. */
+
/* Lenght of magic at the start of a file */
#define EI_NIDENT 16
@@ -184,4 +306,59 @@
#define ELFOSABI_NONE 0
#define ELFOSABI_LINUX 3
-#endif /* _SYS_ELFCOMMON_H */
+/* Intel 80386 specific definitions. */
+
+/* i386 relocs. */
+
+#define R_386_NONE 0 /* No reloc */
+#define R_386_32 1 /* Direct 32 bit */
+#define R_386_PC32 2 /* PC relative 32 bit */
+#define R_386_GOT32 3 /* 32 bit GOT entry */
+#define R_386_PLT32 4 /* 32 bit PLT address */
+#define R_386_COPY 5 /* Copy symbol at runtime */
+#define R_386_GLOB_DAT 6 /* Create GOT entry */
+#define R_386_JMP_SLOT 7 /* Create PLT entry */
+#define R_386_RELATIVE 8 /* Adjust by program base */
+#define R_386_GOTOFF 9 /* 32 bit offset to GOT */
+#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */
+#define R_386_32PLT 11
+#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */
+#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS
+ block offset */
+#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block
+ offset */
+#define R_386_TLS_LE 17 /* Offset relative to static TLS
+ block */
+#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of
+ general dynamic thread local data */
+#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of
+ local dynamic thread local data
+ in LE code */
+#define R_386_16 20
+#define R_386_PC16 21
+#define R_386_8 22
+#define R_386_PC8 23
+#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic
+ thread local data */
+#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */
+#define R_386_TLS_GD_CALL 26 /* Relocation for call to
+ __tls_get_addr() */
+#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */
+#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic
+ thread local data in LE code */
+#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */
+#define R_386_TLS_LDM_CALL 30 /* Relocation for call to
+ __tls_get_addr() in LDM code */
+#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */
+#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */
+#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS
+ block offset */
+#define R_386_TLS_LE_32 34 /* Negated offset relative to static
+ TLS block */
+#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */
+#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */
+#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */
+/* Keep this the last entry. */
+#define R_386_NUM 38
+
+#endif /* _SYS_ELFCOMMON_H */
diff --git a/com32/include/sys/exec.h b/com32/include/sys/exec.h
new file mode 100644
index 00000000..f4559d15
--- /dev/null
+++ b/com32/include/sys/exec.h
@@ -0,0 +1,79 @@
+/*
+ * exec.h
+ *
+ * Created on: Aug 14, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+#ifndef EXEC_H_
+#define EXEC_H_
+
+#include <sys/module.h>
+#include <stdlib.h>
+
+/**
+ * EXEC_ROOT_NAME - The name of the ELF module associated with the COM32 module.
+ *
+ * This is a shallow ELF module, that contains only the symbol table for
+ * the code and data sections of the loaded COM32 root module.
+ */
+#define EXEC_ROOT_NAME "_root_.c32"
+
+/**
+ * spawn_load - Load a library module or executes an executable one
+ * @name the name of the library/executable to use, including the extension
+ * (e.g. 'sort.c32')
+ * @argc: the number of string arguments in @argv
+ * @argv: a NULL-terminated vector of string arguments, starting with
+ * the program name.
+ *
+ * This procedure in essence loads takes the name of a module and checks to see what
+ * kind of module it is ( executable or library ), after which is performs the
+ * appropriate action, either spawning or simply loading the module into memory.
+ */
+extern int spawn_load(const char *name, int argc, char **argv);
+
+/**
+ * spawnv - Executes a program in the current environment.
+ * @name: the name of the program to spawn, including the extension
+ * (e.g. 'hello.c32')
+ * @argv: a NULL-terminated vector of string arguments, starting with
+ * the program name.
+ *
+ * A program is an ELF module that contains a main routine. A program is
+ * loaded into memory, executed, then unloaded, thus remaining in memory only
+ * while the main() function is executing. A program also defines a
+ * memory allocation context, and a simple garbage collection mechanism
+ * it thus provided. This is done by internally associating with the program
+ * module each pointer returned by malloc(). After the program finishes
+ * its execution, all the unallocated memory pertaining to the program
+ * is automatically cleaned up.
+ *
+ * Note that this association takes place both for the allocations happening
+ * directly in the program, or indirectly through a library function. Libraries
+ * do not create allocation contexts, thus each allocation they made belong
+ * to the innermost calling program.
+ */
+extern int spawnv(const char *name, const char **argv);
+
+/**
+ * spawnl - Executes a program in the current environment.
+ * @name: the name of the program to spawn, including the extension
+ * (e.g. 'hello.c32')
+ * @arg: the first argument (argv[0]) to be passed to the main function
+ * of the program
+ * @...: optional subsequent arguments that are passed o the main function
+ * of the program
+ *
+ * This is another version of the spawn routine. Please see 'spawnv' for
+ * a full presentation.
+ */
+extern int spawnl(const char *name, const char *arg, ...);
+
+/**
+ * exec_term - Releases the resources of the execution environment.
+ */
+extern void exec_term(void);
+
+
+#endif /* EXEC_H_ */
diff --git a/com32/include/sys/module.h b/com32/include/sys/module.h
new file mode 100644
index 00000000..8d144203
--- /dev/null
+++ b/com32/include/sys/module.h
@@ -0,0 +1,374 @@
+/**
+ * syslinux/module.h
+ *
+ * Dynamic ELF modules definitions and services.
+ */
+
+
+#ifndef MODULE_H_
+#define MODULE_H_
+
+#include <stdio.h>
+#include <elf.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <stdbool.h>
+#include <linux/list.h>
+
+/*
+ * The maximum length of the module file name (including path), stored
+ * in the struct module descriptor.
+ */
+#define MODULE_NAME_SIZE 256
+
+/*
+ * Some common information about what kind of modules we're dealing with
+ */
+#define EXEC_MODULE 0
+#define LIB_MODULE 1
+
+#define MAX_NR_DEPS 64
+
+/*
+ * Initialization and finalization function signatures
+ */
+
+/**
+ * module_main_t - pointer to an entry routine
+ *
+ * The entry routine is present only in executable modules, and represents
+ * the entry point for the program.
+ */
+typedef int (*module_main_t)(int, char**);
+
+/**
+ * module_ctor_t - pointer to a constructor or destructor routine
+ *
+ * A module may have multiple routines that need to be executed before
+ * or after the main routine. These are the constructors and
+ * destructors, respectively.
+ */
+typedef void (*module_ctor_t) (void);
+
+/**
+ * struct elf_module - structure encapsulating a module loaded in memory.
+ *
+ * Each SYSLINUX ELF module must have an associated struct elf_module descriptor
+ * that keeps track of memory allocations, symbol information, and various other
+ * resources needed by the module itself or by other modules that depend on it.
+ *
+ * There are two types of modules:
+ * - regular modules, which are actual memory images of a loaded & linked shared
+ * object (ELF file). Memory is reserved for the struct elf_module structure itself
+ * and for the object loadable sections read from the file.
+ * - shallow modules, which are not associated with an ELF shared object, but contain
+ * metainformation about a memory region already present and containing the
+ * actual code and data. One particular usage of shallow modules is to access
+ * symbol information from the root COM32 module loaded by the SYSLINUX core.
+ * As their name suggests, memory is reserved only for the elf_module structure
+ * itself and optionally for a usually small memory region containing metainformation
+ * (symbol information).
+ *
+ * Module descriptors are related to each other through dependency information. A module
+ * can depend on symbols from other modules, and in turn it can provide symbols used
+ * by other dependant modules. This relationship can be described as a directed
+ * acyclic graph (DAG). The graph is stored using double linked lists of
+ * predecessors and successors. There is also a global linked list containing all
+ * the modules currently loaded.
+ */
+struct atexit;
+struct elf_module {
+ char name[MODULE_NAME_SIZE]; // The module name
+
+ bool shallow; // Whether the module contains any code
+
+ struct list_head required; // Head of the required modules list
+ struct list_head dependants; // Head of module dependants list
+ struct list_head list; // The list entry in the module list
+
+ module_ctor_t *ctors; // module constructors
+ module_ctor_t *dtors; // module destructors
+ module_main_t main_func; // The main function (for executable modules)
+
+ void *module_addr; // The module location in the memory
+ Elf32_Addr base_addr; // The base address of the module
+ Elf32_Word module_size; // The module size in memory
+
+ Elf32_Word *hash_table; // The symbol hash table
+ Elf32_Word *ghash_table; // The GNU style hash table
+ char *str_table; // The string table
+ void *sym_table; // The symbol table
+ void *got; // The Global Offset Table
+ Elf32_Dyn *dyn_table; // Dynamic loading information table
+
+ Elf32_Word strtable_size; // The size of the string table
+ Elf32_Word syment_size; // The size of a symbol entry
+ Elf32_Word symtable_size; // The size of the symbol table
+
+
+ union {
+ // Transient - Data available while the module is loading
+ struct {
+ FILE *_file; // The file object of the open file
+ Elf32_Off _cr_offset; // The current offset in the open file
+ } l;
+
+ // Process execution data
+ struct {
+ jmp_buf process_exit; // Exit state
+ struct atexit *atexit_list; // atexit() chain
+ } x;
+ } u;
+
+ // ELF DT_NEEDED entries for this module
+ int nr_needed;
+ Elf32_Word needed[MAX_NR_DEPS];
+};
+
+/**
+ * struct module_dep - structure encapsulating a module dependency need
+ *
+ * This structure represents an item in a double linked list of predecessors or
+ * successors. The item contents is a pointer to the corresponding module descriptor.
+ */
+struct module_dep {
+ struct list_head list; // The list entry in the dependency list
+
+ struct elf_module *module; // The target module descriptor
+};
+
+
+/**
+ * Unload all modules that have been loaded since @name.
+ *
+ * Returns the struct elf_module * for @name or %NULL if no modules
+ * have been loaded since @name.
+ */
+extern struct elf_module *unload_modules_since(const char *name);
+
+extern FILE *findpath(char *name);
+
+
+#ifdef DYNAMIC_MODULE
+
+/*
+ * This portion is included by dynamic (ELF) module source files.
+ */
+
+#define MODULE_INIT(fn) static module_init_t __module_init \
+ __used __attribute__((section(".ctors_modinit"))) = fn
+
+#define MODULE_EXIT(fn) static module_exit_t __module_exit \
+ __used __attribute__((section(".dtors_modexit"))) = fn
+
+#else
+
+/*
+ * This portion is included by the core COM32 module.
+ */
+
+/*
+ * Accepted values for various ELF header parameters found in an ELF dynamic
+ * object.
+ */
+#define MODULE_ELF_CLASS ELFCLASS32 // 32-bit modules
+#define MODULE_ELF_CLASS_SIZE 32 // Size of a word value
+#define MODULE_ELF_DATA ELFDATA2LSB // Word endianess
+#define MODULE_ELF_VERSION EV_CURRENT // Object version
+#define MODULE_ELF_TYPE ET_DYN // Executable type (shared object - .so)
+#define MODULE_ELF_MACHINE EM_386 // Target architecture
+
+/**
+ * Names of symbols with special meaning (treated as special cases at linking)
+ */
+#define MODULE_ELF_INIT_PTR "__module_init_ptr" // Initialization pointer symbol name
+#define MODULE_ELF_EXIT_PTR "__module_exit_ptr" // Finalization pointer symbol name
+#define MODULE_ELF_MAIN_PTR "__module_main_ptr" // Entry pointer symbol name
+
+/**
+ * modules_head - A global linked list containing all the loaded modules.
+ */
+extern struct list_head modules_head;
+
+
+/**
+ * for_each_module - iterator loop through the list of loaded modules.
+ */
+#define for_each_module(m) list_for_each_entry(m, &modules_head, list)
+
+/**
+ * for_each_module - iterator loop through the list of loaded modules safe against removal.
+ */
+#define for_each_module_safe(m, n) \
+ list_for_each_entry_safe(m, n, &modules_head, list)
+
+/**
+ * module_current - return the module at the head of the module list.
+ */
+static inline struct elf_module *module_current(void)
+{
+ struct elf_module *head;
+
+ head = list_entry((&modules_head)->next, typeof(*head), list);
+ return head;
+}
+
+/**
+ * modules_init - initialize the module subsystem.
+ *
+ * This function must be called before any module operation is to be performed.
+ */
+extern int modules_init(void);
+
+
+/**
+ * modules_term - releases all resources pertaining to the module subsystem.
+ *
+ * This function should be called after all module operations.
+ */
+extern void modules_term(void);
+
+
+/**
+ * module_alloc - reserves space for a new module descriptor.
+ * @name: the file name of the module to be loaded.
+ *
+ * The function simply allocates a new module descriptor and initializes its fields
+ * in order to be used by subsequent loading operations.
+ */
+extern struct elf_module *module_alloc(const char *name);
+
+
+/**
+ * module_load - loads a regular ELF module into memory.
+ * @module: the module descriptor returned by module_alloc.
+ *
+ * The function reads the module file, checks whether the file has a
+ * valid structure, then loads into memory the code and the data and performs
+ * any symbol relocations. A module dependency is created automatically when the
+ * relocated symbol is defined in a different module.
+ *
+ * The function returns 0 if the operation is completed successfully, and
+ * a non-zero value if an error occurs. Possible errors include invalid module
+ * structure, missing symbol definitions (unsatisfied dependencies) and memory
+ * allocation issues.
+ */
+extern int module_load(struct elf_module *module);
+
+
+/**
+ * module_unload - unloads the module from the system.
+ * @module: the module descriptor structure.
+ *
+ * The function checks to see whether the module can be safely
+ * removed, then it executes any destructors and releases all the
+ * associated memory. This function can be applied both for standard
+ * modules and for shallow modules.
+ *
+ * A module can be safely removed from the system when no other modules reference
+ * symbols from it.
+ */
+extern int module_unload(struct elf_module *module);
+
+/**
+ * _module_unload - unloads the module without running destructors
+ *
+ * This function is the same as module_unload(), except that the
+ * module's destructors are not executed.
+ */
+extern int _module_unload(struct elf_module *module);
+
+/**
+ * module_unload - unloads the module from the system.
+ * @module: the module descriptor structure.
+ *
+ * This function returns the type of module we're dealing with
+ * either a library module ( LIB_MODULE ), executable module ( EXEC_MODULE ),
+ * or an error ( UNKNOWN_MODULE ). The way it checks teh type is by checking to see
+ * if the module has its main_func set ( in which case it's an executable ). In case
+ * it doesn't it then checks to see if init_func is set ( in which case it's a
+ * library module. If this isn't the case either we don't know what it is so bail out
+ */
+extern int get_module_type(struct elf_module *module);
+
+/**
+ * module_unloadable - checks whether the given module can be unloaded.
+ * @module: the module descriptor structure
+ *
+ * A module can be unloaded from the system when no other modules depend on it,
+ * that is, no symbols are referenced from it.
+ */
+extern int module_unloadable(struct elf_module *module);
+
+/**
+ * module_find - searches for a module by its name.
+ * @name: the name of the module, as it was specified in module_alloc.
+ *
+ * The function returns a pointer to the module descriptor, if found, or
+ * NULL otherwise.
+ */
+extern struct elf_module *module_find(const char *name);
+
+/**
+ * module_find_symbol - searches for a symbol definition in a given module.
+ * @name: the name of the symbol to be found.
+ * @module: the module descriptor structure.
+ *
+ * The function searches the module symbol table for a symbol matching exactly
+ * the name provided. The operation uses the following search algorithms, in this
+ * order:
+ * - If a GNU hash table is present in the module, it is used to find the symbol.
+ * - If the symbol cannot be found with the first method (either the hash table
+ * is not present or the symbol is not found) and if a regular (SysV) hash table
+ * is present, a search is performed on the SysV hash table. If the symbol is not
+ * found, NULL is returned.
+ * - If the second method cannot be applied, a linear search is performed by
+ * inspecting every symbol in the symbol table.
+ *
+ * If the symbol is found, a pointer to its descriptor structure is returned, and
+ * NULL otherwise.
+ */
+extern Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module);
+
+/**
+ * global_find_symbol - searches for a symbol definition in the entire module namespace.
+ * @name: the name of the symbol to be found.
+ * @module: an optional (may be NULL) pointer to a module descriptor variable that
+ * will hold the module where the symbol was found.
+ *
+ * The function search for the given symbol name in all the modules currently
+ * loaded in the system, in the reverse module loading order. That is, the most
+ * recently loaded module is searched first, followed by the previous one, until
+ * the first loaded module is reached.
+ *
+ * If no module contains the symbol, NULL is returned, otherwise the return value is
+ * a pointer to the symbol descriptor structure. If the module parameter is not NULL,
+ * it is filled with the address of the module descriptor where the symbol is defined.
+ */
+extern Elf32_Sym *global_find_symbol(const char *name, struct elf_module **module);
+
+/**
+ * module_get_absolute - converts an memory address relative to a module base address
+ * to its absolute value in RAM.
+ * @addr: the relative address to convert.
+ * @module: the module whose base address is used for the conversion.
+ *
+ * The function returns a pointer to the absolute memory address.
+ */
+static inline void *module_get_absolute(Elf32_Addr addr, struct elf_module *module) {
+ return (void*)(module->base_addr + addr);
+}
+
+/**
+ * syslinux_current - get the current module process
+ */
+extern struct elf_module *__syslinux_current;
+static inline const struct elf_module *syslinux_current(void)
+{
+ return __syslinux_current;
+}
+
+
+#endif // DYNAMIC_MODULE
+
+#endif // MODULE_H_
diff --git a/com32/include/sys/times.h b/com32/include/sys/times.h
index 90470063..5eda2954 100644
--- a/com32/include/sys/times.h
+++ b/com32/include/sys/times.h
@@ -16,6 +16,12 @@ struct tms {
typedef uint32_t clock_t;
-clock_t times(struct tms *);
+extern volatile uint32_t __ms_timer;
+
+static inline clock_t times(struct tms *buf)
+{
+ (void)buf;
+ return __ms_timer;
+}
#endif /* _SYS_TIMES_H */
diff --git a/com32/include/syslinux/boot.h b/com32/include/syslinux/boot.h
index 21bea01a..74a311df 100644
--- a/com32/include/syslinux/boot.h
+++ b/com32/include/syslinux/boot.h
@@ -40,7 +40,7 @@
int syslinux_run_command(const char *);
__noreturn syslinux_run_default(void);
-void syslinux_local_boot(uint16_t flags);
+void syslinux_local_boot(int16_t flags);
void syslinux_final_cleanup(uint16_t flags);
@@ -48,15 +48,24 @@ void syslinux_chain_bootstrap(uint16_t flags, const void *bootstrap,
uint32_t bootstrap_len, uint32_t edx,
uint32_t esi, uint16_t ds);
+struct image_types {
+ const char *name;
+ uint32_t type;
+};
+
+extern const struct image_types image_boot_types[];
+
#define IMAGE_TYPE_KERNEL 0
#define IMAGE_TYPE_LINUX 1
#define IMAGE_TYPE_BOOT 2
#define IMAGE_TYPE_BSS 3
#define IMAGE_TYPE_PXE 4
#define IMAGE_TYPE_FDIMAGE 5
-#define IMAGE_TYPE_COMBOOT 6
#define IMAGE_TYPE_COM32 7
#define IMAGE_TYPE_CONFIG 8
+#define IMAGE_TYPE_LOCALBOOT 9
+
+uint32_t parse_image_type(const char *cmdline);
void syslinux_run_kernel_image(const char *filename, const char *cmdline,
uint32_t ipappend_flags, uint32_t type);
diff --git a/com32/include/syslinux/config.h b/com32/include/syslinux/config.h
index 79a4750e..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,
@@ -156,6 +156,8 @@ struct syslinux_serial_console_info {
uint16_t flowctl;
};
+extern void __syslinux_set_serial_console_info(void);
+
extern __nocommon struct syslinux_serial_console_info
__syslinux_serial_console_info;
static inline const struct syslinux_serial_console_info
@@ -164,10 +166,10 @@ static inline const struct syslinux_serial_console_info
return &__syslinux_serial_console_info;
}
-extern __nocommon const char *__syslinux_config_file;
+extern char ConfigName[];
static inline const char *syslinux_config_file(void)
{
- return __syslinux_config_file;
+ return ConfigName;
}
struct syslinux_ipappend_strings {
@@ -181,4 +183,9 @@ static inline const struct syslinux_ipappend_strings
return &__syslinux_ipappend_strings;
}
+static inline enum syslinux_filesystem syslinux_filesystem(void)
+{
+ return syslinux_derivative_info()->c.filesystem;
+}
+
#endif /* _SYSLINUX_CONFIG_H */
diff --git a/com32/include/syslinux/debug.h b/com32/include/syslinux/debug.h
new file mode 100644
index 00000000..aee6fdbb
--- /dev/null
+++ b/com32/include/syslinux/debug.h
@@ -0,0 +1,15 @@
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include <stdbool.h>
+
+#ifdef DYNAMIC_DEBUG
+#define syslinux_debug_enabled __syslinux_debug_enabled(__func__)
+extern bool __syslinux_debug_enabled(const char *func);
+#else
+#define syslinux_debug_enabled (0)
+#endif /* DYNAMIC_DEBUG */
+
+extern int syslinux_debug(const char *str, bool enable);
+
+#endif /* DEBUG_H */
diff --git a/com32/include/syslinux/disk.h b/com32/include/syslinux/disk.h
index f96ca686..b8361fe4 100644
--- a/com32/include/syslinux/disk.h
+++ b/com32/include/syslinux/disk.h
@@ -41,6 +41,13 @@
#define SECTOR 512u /* bytes/sector */
+enum disk_op_codes {
+ EBIOS_READ_CODE = 0x42, /* Extended read */
+ EBIOS_WRITE_CODE = 0x43, /* Extended write */
+ CHS_READ_CODE = 0x02,
+ CHS_WRITE_CODE = 0x03,
+};
+
struct disk_info {
int disk;
int ebios; /* EBIOS supported on this disk */
diff --git a/com32/include/syslinux/features.h b/com32/include/syslinux/features.h
deleted file mode 100644
index 4bebda49..00000000
--- a/com32/include/syslinux/features.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* ----------------------------------------------------------------------- *
- *
- * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
- *
- * 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 _SYSLINUX_FEATURES_H
-#define _SYSLINUX_FEATURES_H
-
-#define SYSLINUX_FEATURE_LOCAL_BOOT (0*8+0)
-#define SYSLINUX_FEATURE_NOOP_IDLE (0*8+1)
-
-extern struct __syslinux_feature_flags {
- unsigned int len;
- const unsigned char *ptr;
-} __syslinux_feature_flags;
-
-static inline int syslinux_has_feature(unsigned int __flag)
-{
- unsigned int __byte = __flag >> 3;
- unsigned int __bit = __flag & 7;
-
- if (__byte <= __syslinux_feature_flags.len)
- return (__syslinux_feature_flags.ptr[__byte] >> __bit) & 1;
- else
- return 0;
-}
-
-#endif /* _SYSLINUX_FEATURE_H */
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 27166b0b..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
@@ -568,4 +585,11 @@ typedef struct s_PXENV_UNLOAD_STACK {
#define PXENV_STATUS_LOADER_UNDI_START 0xca
#define PXENV_STATUS_LOADER_BC_START 0xcb
+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/lib/syslinux/features.c b/com32/include/syslinux/sysappend.h
index c88aef30..f243eabc 100644
--- a/com32/lib/syslinux/features.c
+++ b/com32/include/syslinux/sysappend.h
@@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- *
*
- * Copyright 2007-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
@@ -26,26 +26,34 @@
* ----------------------------------------------------------------------- */
/*
- * syslinux/features.c
+ * syslinux/sysappend.h
*
- * SYSLINUX feature flag query
+ * List of the Syslinux sysappend strings
*/
-#include <klibc/compiler.h>
-#include <syslinux/features.h>
-#include <string.h>
-#include <com32.h>
+#ifndef _SYSLINUX_SYSAPPEND_H
+#define _SYSLINUX_SYSAPPEND_H
-struct __syslinux_feature_flags __syslinux_feature_flags;
+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 */
+};
-void __constructor __syslinux_detect_features(void)
-{
- static com32sys_t reg;
-
- memset(&reg, 0, sizeof reg);
- reg.eax.w[0] = 0x0015;
- __intcall(0x22, &reg, &reg);
-
- __syslinux_feature_flags.len = reg.ecx.w[0];
- __syslinux_feature_flags.ptr = MK_PTR(reg.es, reg.ebx.w[0]);
-}
+#endif
diff --git a/com32/lib/Makefile b/com32/lib/Makefile
index 5ab1fac4..d1b6bf7f 100644
--- a/com32/lib/Makefile
+++ b/com32/lib/Makefile
@@ -8,149 +8,203 @@ topdir = ../../
MAKEDIR = $(topdir)/mk
include $(MAKEDIR)/lib.mk
-LIBOBJS = \
- abort.o atexit.o atoi.o atol.o atoll.o calloc.o creat.o \
- ctypes.o errno.o fgetc.o fgets.o fopen.o fprintf.o fputc.o \
- fclose.o putchar.o setjmp.o \
- fputs.o fread2.o fread.o free.o fwrite2.o fwrite.o \
- getopt.o getopt_long.o \
- lrand48.o malloc.o stack.o memccpy.o memchr.o memcmp.o \
- memcpy.o mempcpy.o memmem.o memmove.o memset.o memswap.o \
- exit.o onexit.o \
- perror.o printf.o puts.o qsort.o realloc.o seed48.o snprintf.o \
- sprintf.o srand48.o sscanf.o stack.o strcasecmp.o strcat.o \
- strchr.o strcmp.o strcpy.o strdup.o strlen.o \
- strerror.o strnlen.o \
- strncasecmp.o strncat.o strncmp.o strncpy.o strndup.o \
- stpcpy.o stpncpy.o \
- strntoimax.o strntoumax.o strrchr.o strsep.o strspn.o strstr.o \
- strtoimax.o strtok.o strtol.o strtoll.o strtoul.o strtoull.o \
- strtoumax.o vfprintf.o vprintf.o vsnprintf.o vsprintf.o \
- asprintf.o vasprintf.o strlcpy.o strlcat.o \
- vsscanf.o zalloc.o \
- skipspace.o \
- chrreplace.o \
- bufprintf.o \
- inet.o dhcppack.o dhcpunpack.o \
- strreplace.o \
- \
- lmalloc.o lstrdup.o \
- \
- dprintf.o vdprintf.o \
- \
- suffix_number.o \
+## OPTIONAL OBJECTS, AVAILABLE AS DYNAMIC LINKED MODULES
+# PNG library object files
+LIBPNG_OBJS = \
+ libpng/png.o libpng/pngset.o libpng/pngget.o libpng/pngrutil.o \
+ libpng/pngtrans.o libpng/pngwutil.o libpng/pngread.o \
+ libpng/pngrio.o libpng/pngwio.o libpng/pngwrite.o \
+ libpng/pngrtran.o libpng/pngwtran.o libpng/pngmem.o \
+ libpng/pngerror.o libpng/pngpread.o
+
+# ZIP library object files
+LIBZLIB_OBJS = \
+ zlib/adler32.o zlib/compress.o zlib/crc32.o \
+ zlib/uncompr.o zlib/deflate.o zlib/trees.o zlib/zutil.o \
+ zlib/inflate.o zlib/infback.o zlib/inftrees.o zlib/inffast.o \
+ sys/zfile.o sys/zfopen.o
+
+# JPG library object files
+LIBJPG_OBJS = \
+ jpeg/tinyjpeg.o jpeg/jidctflt.o jpeg/decode1.o jpeg/decode3.o \
+ jpeg/rgb24.o jpeg/bgr24.o jpeg/yuv420p.o jpeg/grey.o \
+ jpeg/rgba32.o jpeg/bgra32.o
+
+LIBVESA_OBJS = \
+ sys/vesacon_write.o sys/vesaserial_write.o \
+ sys/vesa/initvesa.o sys/vesa/drawtxt.o sys/vesa/background.o \
+ sys/vesa/alphatbl.o sys/vesa/screencpy.o sys/vesa/fmtpixel.o \
+ sys/vesa/i915resolution.o
+
+LIBMISC_OBJS = \
+ sys/libansi.o sys/gpxe.o
+
+LIBPCI_OBJS = \
+ pci/cfgtype.o pci/scan.o pci/bios.o \
+ pci/readb.o pci/readw.o pci/readl.o \
+ pci/writeb.o pci/writew.o pci/writel.o
+
+LIBSYSLINUX_OBJS = \
+ syslinux/reboot.o syslinux/keyboard.o \
+ syslinux/version.o \
+ syslinux/pxe_get_cached.o syslinux/pxe_get_nic.o \
+ syslinux/pxe_dns.o \
+ syslinux/video/fontquery.o syslinux/video/reportmode.o
+
+LIBLOAD_OBJS = \
+ syslinux/addlist.o syslinux/freelist.o syslinux/memmap.o \
+ syslinux/movebits.o syslinux/shuffle.o syslinux/shuffle_pm.o \
+ syslinux/shuffle_rm.o syslinux/zonelist.o \
+ syslinux/dump_mmap.o syslinux/dump_movelist.o \
\
- sys/readdir.o getcwd.o chdir.o fdopendir.o \
+ syslinux/run_default.o syslinux/run_command.o \
+ syslinux/cleanup.o syslinux/localboot.o syslinux/runimage.o \
\
- libgcc/__ashldi3.o libgcc/__udivdi3.o \
- libgcc/__negdi2.o libgcc/__ashrdi3.o libgcc/__lshrdi3.o \
- libgcc/__muldi3.o libgcc/__udivmoddi4.o libgcc/__umoddi3.o \
- libgcc/__divdi3.o libgcc/__moddi3.o \
+ syslinux/loadfile.o syslinux/floadfile.o syslinux/zloadfile.o \
\
+ syslinux/load_linux.o syslinux/initramfs.o \
+ syslinux/initramfs_file.o syslinux/initramfs_loadfile.o \
+ syslinux/initramfs_archive.o
+
+DYNENTRY_OBJS = \
+ atexit.o onexit.o abort.o
+
+## CORE OBJECTS, INCLUDED IN THE ROOT COM32 MODULE
+LIBENTRY_OBJS = \
sys/intcall.o sys/farcall.o sys/cfarcall.o sys/zeroregs.o \
- sys/entry.o sys/exit.o sys/argv.o sys/times.o sys/sleep.o \
+ sys/argv.o sys/sleep.o \
sys/fileinfo.o sys/opendev.o sys/read.o sys/write.o sys/ftell.o \
sys/close.o sys/open.o sys/fileread.o sys/fileclose.o \
- sys/openmem.o \
+ sys/openmem.o \
sys/isatty.o sys/fstat.o \
\
- sys/zfile.o sys/zfopen.o \
+ dprintf.o vdprintf.o \
+ \
+ syslinux/idle.o \
+ \
+ exit.o
+
+LIBMODULE_OBJS = \
+ sys/module/common.o sys/module/elf_module.o \
+ sys/module/elfutils.o \
+ sys/module/exec.o
+
+LIBGCC_OBJS = \
+ libgcc/__ashldi3.o libgcc/__udivdi3.o \
+ libgcc/__negdi2.o libgcc/__ashrdi3.o libgcc/__lshrdi3.o \
+ libgcc/__muldi3.o libgcc/__udivmoddi4.o libgcc/__umoddi3.o \
+ libgcc/__divdi3.o libgcc/__moddi3.o
+
+LIBCONSOLE_OBJS = \
\
sys/openconsole.o sys/line_input.o \
sys/colortable.o sys/screensize.o \
\
- sys/stdcon_read.o sys/stdcon_write.o sys/rawcon_read.o \
- sys/rawcon_write.o sys/err_read.o sys/err_write.o \
- sys/null_read.o sys/null_write.o sys/serial_write.o \
+ sys/stdcon_read.o sys/rawcon_read.o \
+ sys/rawcon_write.o \
+ sys/null_write.o sys/serial_write.o \
\
sys/xserial_write.o \
\
sys/ansi.o \
\
- sys/libansi.o \
- \
- sys/gpxe.o \
+ sys/ansicon_write.o sys/ansiserial_write.o \
\
- sys/ansicon_write.o sys/ansiserial_write.o \
- \
- sys/vesacon_write.o sys/vesaserial_write.o \
- sys/vesa/initvesa.o sys/vesa/drawtxt.o sys/vesa/background.o \
- sys/vesa/alphatbl.o sys/vesa/screencpy.o sys/vesa/fmtpixel.o \
- sys/vesa/i915resolution.o \
- \
- pci/cfgtype.o pci/scan.o pci/bios.o \
- pci/readb.o pci/readw.o pci/readl.o \
- pci/writeb.o pci/writew.o pci/writel.o \
- \
- zlib/adler32.o zlib/compress.o zlib/crc32.o \
- zlib/uncompr.o zlib/deflate.o zlib/trees.o zlib/zutil.o \
- zlib/inflate.o zlib/infback.o zlib/inftrees.o zlib/inffast.o \
- \
- libpng/png.o libpng/pngset.o libpng/pngget.o libpng/pngrutil.o \
- libpng/pngtrans.o libpng/pngwutil.o libpng/pngread.o \
- libpng/pngrio.o libpng/pngwio.o libpng/pngwrite.o \
- libpng/pngrtran.o libpng/pngwtran.o libpng/pngmem.o \
- libpng/pngerror.o libpng/pngpread.o \
- \
- jpeg/tinyjpeg.o jpeg/jidctflt.o jpeg/decode1.o jpeg/decode3.o \
- jpeg/grey.o jpeg/yuv420p.o \
- jpeg/rgb24.o jpeg/bgr24.o \
- jpeg/rgba32.o jpeg/bgra32.o \
- \
- sys/x86_init_fpu.o math/pow.o math/strtod.o \
- \
- syslinux/idle.o syslinux/reboot.o \
- syslinux/features.o syslinux/config.o syslinux/serial.o \
- syslinux/ipappend.o syslinux/dsinfo.o syslinux/version.o \
- syslinux/keyboard.o \
+ syslinux/serial.o
+
+LIBOTHER_OBJS = \
+ atoi.o atol.o atoll.o calloc.o creat.o \
+ fgets.o fprintf.o fputc.o \
+ putchar.o \
+ getopt.o getopt_long.o \
+ lrand48.o stack.o memccpy.o memchr.o \
+ mempcpy.o memmem.o memmove.o memswap.o \
+ perror.o qsort.o seed48.o \
+ srand48.o sscanf.o strcasecmp.o \
+ strerror.o errlist.o \
+ strnlen.o \
+ strncat.o strndup.o \
+ stpncpy.o \
+ strntoimax.o strsep.o strspn.o strstr.o \
+ strtoimax.o strtok.o strtol.o strtoll.o strtoull.o \
+ strtoumax.o vprintf.o vsprintf.o \
+ asprintf.o vasprintf.o \
+ vsscanf.o \
+ skipspace.o \
+ chrreplace.o \
+ bufprintf.o \
+ inet.o dhcppack.o dhcpunpack.o \
+ strreplace.o \
+ lstrdup.o \
\
- syslinux/memscan.o \
+ suffix_number.o \
\
- syslinux/addlist.o syslinux/freelist.o syslinux/memmap.o \
- syslinux/movebits.o syslinux/shuffle.o syslinux/shuffle_pm.o \
- syslinux/shuffle_rm.o syslinux/zonelist.o \
- syslinux/dump_mmap.o syslinux/dump_movelist.o \
+ getcwd.o fdopendir.o \
\
- syslinux/run_default.o syslinux/run_command.o \
- syslinux/cleanup.o syslinux/localboot.o syslinux/runimage.o \
+ sys/line_input.o \
+ sys/colortable.o sys/screensize.o \
\
- syslinux/loadfile.o syslinux/floadfile.o syslinux/zloadfile.o \
+ sys/stdcon_read.o sys/stdcon_write.o sys/rawcon_read.o \
+ sys/rawcon_write.o \
+ sys/null_read.o sys/null_write.o sys/serial_write.o \
\
- syslinux/load_linux.o syslinux/initramfs.o \
- syslinux/initramfs_file.o syslinux/initramfs_loadfile.o \
- syslinux/initramfs_archive.o \
+ sys/xserial_write.o \
\
- syslinux/pxe_get_cached.o syslinux/pxe_get_nic.o \
- syslinux/pxe_dns.o \
+ sys/ansi.o \
\
- syslinux/adv.o syslinux/advwrite.o syslinux/getadv.o \
- syslinux/setadv.o \
+ sys/ansicon_write.o sys/ansiserial_write.o \
\
- syslinux/video/fontquery.o syslinux/video/forcetext.o \
- syslinux/video/reportmode.o \
+ pci/cfgtype.o pci/scan.o pci/bios.o \
+ pci/readb.o pci/readw.o pci/readl.o \
+ pci/writeb.o pci/writew.o pci/writel.o \
\
+ sys/x86_init_fpu.o math/pow.o math/strtod.o \
syslinux/disk.o \
\
syslinux/setup_data.o
-# These are the objects which are also imported into the core
-LIBCOREOBJS = \
- memcpy.o mempcpy.o memset.o memcmp.o memmove.o \
- strlen.o stpcpy.o strcpy.o strcmp.o strlcpy.o strlcat.o \
- strchr.o strncmp.o strncpy.o \
- \
- snprintf.o sprintf.o vsnprintf.o \
- \
- dprintf.o vdprintf.o \
- \
- zalloc.o strdup.o \
- \
- sys/intcall.o sys/farcall.o sys/cfarcall.o sys/zeroregs.o \
- \
+CORELIBOBJS = \
+ memcpy.o memset.o memcmp.o printf.o strncmp.o vfprintf.o \
+ strlen.o vsnprintf.o snprintf.o stpcpy.o strcmp.o strdup.o \
+ strcpy.o strncpy.o setjmp.o fopen.o fread.o fread2.o puts.o \
+ sprintf.o strlcat.o strchr.o strlcpy.o strncasecmp.o ctypes.o \
+ fputs.o fwrite2.o fwrite.o fgetc.o fclose.o lmalloc.o strtoul.o \
+ sys/err_read.o sys/err_write.o sys/null_read.o strntoumax.o \
+ sys/stdcon_write.o \
+ syslinux/memscan.o strrchr.o strcat.o \
libgcc/__ashldi3.o libgcc/__udivdi3.o \
libgcc/__negdi2.o libgcc/__ashrdi3.o libgcc/__lshrdi3.o \
libgcc/__muldi3.o libgcc/__udivmoddi4.o libgcc/__umoddi3.o \
- libgcc/__divdi3.o libgcc/__moddi3.o
+ libgcc/__divdi3.o libgcc/__moddi3.o \
+ syslinux/debug.o \
+ $(LIBENTRY_OBJS) \
+ $(LIBMODULE_OBJS)
+
+MINLIBOBJS = \
+ syslinux/ipappend.o \
+ syslinux/dsinfo.o \
+ $(LIBOTHER_OBJS) \
+ $(LIBGCC_OBJS) \
+ $(LIBCONSOLE_OBJS) \
+ $(LIBLOAD_OBJS) \
+ $(LIBZLIB_OBJS)
+# $(LIBVESA_OBJS)
+
+
+DYNLIBOBJS = \
+ $(LIBZLIB_OBJS) \
+ $(LIBPNG_OBJS) \
+ $(LIBJPG_OBJS) \
+ $(LIBPCI_OBJS) \
+ $(LIBVESA_OBJS) \
+ $(LIBSYSLINUX_OBJS) \
+ $(LIBLOAD_OBJS) \
+ $(LIBMISC_OBJS) \
+ $(DYNENTRY_OBJS)
+
+
+LIBOBJS = \
+ $(DYNLIBOBJS)
BINDIR = /usr/bin
LIBDIR = /usr/lib
@@ -159,33 +213,40 @@ AUXDIR = $(DATADIR)/syslinux
INCDIR = /usr/include
COM32DIR = $(AUXDIR)/com32
-all: libcom32.a libcomcore.a
+all: libcom32.c32 libcom32min.a libcom32core.a
-libcom32.a : $(LIBOBJS)
+libcom32.elf : $(LIBOBJS)
+ rm -f $@
+ $(LD) -shared $(LDFLAGS) -soname $(patsubst %.elf,%.c32,$(@F)) -o $@ $^
+
+libcom32min.a : $(MINLIBOBJS)
rm -f $@
$(AR) cq $@ $^
$(RANLIB) $@
-libcomcore.a : $(LIBCOREOBJS)
+libcom32core.a : $(CORELIBOBJS)
rm -f $@
$(AR) cq $@ $^
$(RANLIB) $@
tidy dist clean:
- rm -f sys/vesa/alphatbl.c
+ rm -f sys/vesa/alphatbl.c errlist.c
find . \( -name \*.o -o -name \*.a -o -name .\*.d -o -name \*.tmp \) -print0 | \
xargs -0r rm -f
spotless: clean
- rm -f *.a
+ rm -f *.a *.c32
rm -f *~ \#* */*~ */\#*
install: all
mkdir -m 755 -p $(INSTALLROOT)$(COM32DIR)
- install -m 644 libcom32.a com32.ld $(INSTALLROOT)$(COM32DIR)
+ install -m 644 com32.ld $(INSTALLROOT)$(COM32DIR)
-rm -rf $(INSTALLROOT)$(COM32DIR)/include
cp -r ../include $(INSTALLROOT)$(COM32DIR)
+errlist.c: makeerrlist.pl ../include/errno.h
+ $(PERL) $< $(CFLAGS) -errlist > $@ || rm -f $@
+
# These files are performance critical, and doesn't compile well with -Os
sys/vesa/drawtxt.o: sys/vesa/drawtxt.c
$(CC) $(MAKEDEPS) $(CFLAGS) -O3 -c -o $@ $<
diff --git a/com32/lib/asprintf.c b/com32/lib/asprintf.c
index ef5b4b2f..eab20118 100644
--- a/com32/lib/asprintf.c
+++ b/com32/lib/asprintf.c
@@ -21,9 +21,10 @@ int asprintf(char **bufp, const char *format, ...)
*bufp = p = malloc(bytes);
if (!p)
- return -1;
+ rv = -1;
+ else
+ rv = vsnprintf(p, bytes, format, ap);
- rv = vsnprintf(p, bytes, format, ap);
va_end(ap);
return rv;
diff --git a/com32/lib/bufprintf.c b/com32/lib/bufprintf.c
index 939bcec3..d2812311 100644
--- a/com32/lib/bufprintf.c
+++ b/com32/lib/bufprintf.c
@@ -17,8 +17,10 @@ int vbufprintf(struct print_buf *buf, const char *format, va_list ap)
char *newbuf;
newbuf = realloc(buf->buf, newsize);
- if (!newbuf)
- return -1;
+ if (!newbuf) {
+ rv = -1;
+ goto bail;
+ }
buf->buf = newbuf;
buf->size = newsize;
@@ -26,6 +28,8 @@ int vbufprintf(struct print_buf *buf, const char *format, va_list ap)
rv = vsnprintf(buf->buf + buf->len, buf->size - buf->len, format, ap2);
buf->len += rv;
+bail:
+ va_end(ap2);
return rv;
}
diff --git a/com32/lib/chdir.c b/com32/lib/chdir.c
deleted file mode 100644
index 00670e35..00000000
--- a/com32/lib/chdir.c
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * chdir.c
- */
-
-#include <dirent.h>
-#include <stdio.h>
-#include <errno.h>
-
-#include <com32.h>
-#include <syslinux/pmapi.h>
-
-int chdir(const char *path)
-{
- return __com32.cs_pm->chdir(path);
-}
diff --git a/com32/lib/dprintf.c b/com32/lib/dprintf.c
index aad11746..dea77b39 100644
--- a/com32/lib/dprintf.c
+++ b/com32/lib/dprintf.c
@@ -5,11 +5,10 @@
#include <stdio.h>
#include <stdarg.h>
-#undef DEBUG
-#define DEBUG 1
-#include <dprintf.h>
+#ifdef DEBUG_PORT
+
+void vdprintf(const char *, va_list);
-#ifndef dprintf
void dprintf(const char *format, ...)
{
va_list ap;
@@ -18,4 +17,5 @@ void dprintf(const char *format, ...)
vdprintf(format, ap);
va_end(ap);
}
-#endif
+
+#endif /* DEBUG_PORT */
diff --git a/com32/lib/elf32.ld b/com32/lib/elf32.ld
new file mode 100644
index 00000000..16d10a38
--- /dev/null
+++ b/com32/lib/elf32.ld
@@ -0,0 +1,171 @@
+/*
+ * Linker script for ELF dynamic loaded modules.
+ */
+
+/* Script for --shared -z combreloc: shared library, combine & sort relocs */
+OUTPUT_FORMAT("elf32-i386", "elf32-i386",
+ "elf32-i386")
+OUTPUT_ARCH(i386)
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = 0 + SIZEOF_HEADERS;
+ .note.gnu.build-id : { *(.note.gnu.build-id) }
+ .hash : { *(.hash) }
+ .gnu.hash : { *(.gnu.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+ .rel.dyn :
+ {
+ *(.rel.init)
+ *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
+ *(.rel.fini)
+ *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
+ *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*)
+ *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
+ *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
+ *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
+ *(.rel.ctors)
+ *(.rel.dtors)
+ *(.rel.got)
+ *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
+ }
+ .rela.dyn :
+ {
+ *(.rela.init)
+ *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+ *(.rela.fini)
+ *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+ *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+ *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+ *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+ *(.rela.ctors)
+ *(.rela.dtors)
+ *(.rela.got)
+ *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+ }
+ .rel.plt : { *(.rel.plt) }
+ .rela.plt : { *(.rela.plt) }
+ .init :
+ {
+ KEEP (*(.init))
+ } =0x90909090
+ .plt : { *(.plt) }
+ .text :
+ {
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ KEEP (*(.text.*personality*))
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ } =0x90909090
+ .fini :
+ {
+ KEEP (*(.fini))
+ } =0x90909090
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+ .rodata1 : { *(.rodata1) }
+ . = ALIGN(4);
+ .preinit_array :
+ {
+ KEEP (*(.preinit_array))
+ }
+ .ctors :
+ {
+ __ctors_start = .;
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ KEEP (*(.ctors_modinit))
+ KEEP (*(.ctors_modmain))
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __ctors_end = .;
+ }
+
+ .dtors :
+ {
+ __dtors_start = .;
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ KEEP (*(.dtors_modexit))
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __dtors_end = .;
+ }
+
+ .jcr : { KEEP (*(.jcr)) }
+ .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
+ .dynamic : { *(.dynamic) }
+ .got : { *(.got) }
+ /*. = DATA_SEGMENT_RELRO_END (12, .); -> This gives a "invalid assignment to location counter" error */
+ .got.plt : { *(.got.plt) }
+ .data :
+ {
+ *(.data .data.* .gnu.linkonce.d.*)
+ KEEP (*(.gnu.linkonce.d.*personality*))
+ SORT(CONSTRUCTORS)
+ }
+ .data1 : { *(.data1) }
+ PROVIDE (edata = .);
+ PROVIDE (_edata = .);
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ /* Align here to ensure that the .bss section occupies space up to
+ _end. Align after .bss to ensure correct alignment even if the
+ .bss section disappears because there are no input sections.
+ FIXME: Why do we need it? When there is no .bss section, we don't
+ pad the .data section. */
+ . = ALIGN(. != 0 ? 32 / 8 : 1);
+ }
+ . = ALIGN(32 / 8);
+ . = ALIGN(32 / 8);
+ PROVIDE (_end = .);
+ PROVIDE (end = .);
+ /*. = DATA_SEGMENT_END (.); -> This gives a "invalid assignment to location counter" error */
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ /* DWARF 3 */
+ .debug_pubtypes 0 : { *(.debug_pubtypes) }
+ .debug_ranges 0 : { *(.debug_ranges) }
+ .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
+ /DISCARD/ : { *(.eh_frame) }
+}
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/exit.c b/com32/lib/exit.c
index ccd6f1ee..ebec0a1a 100644
--- a/com32/lib/exit.c
+++ b/com32/lib/exit.c
@@ -31,11 +31,29 @@
* The regular exit
*/
+#include <sys/module.h>
#include <stdlib.h>
-
-extern __noreturn(*__exit_handler) (int);
+#include <unistd.h>
+#include "atexit.h"
__noreturn exit(int rv)
{
- __exit_handler(rv);
+ struct atexit *ap;
+
+ for (ap = __syslinux_current->u.x.atexit_list; ap; ap = ap->next) {
+ ap->fctn(rv, ap->arg); /* This assumes extra args are harmless */
+ }
+
+ _exit(rv);
+}
+
+__noreturn _Exit(int rv)
+{
+ _exit(rv);
}
+
+__noreturn _exit(int rv)
+{
+ longjmp(__syslinux_current->u.x.process_exit, (uint8_t)rv+1);
+}
+
diff --git a/com32/lib/free.c b/com32/lib/free.c
deleted file mode 100644
index be23865a..00000000
--- a/com32/lib/free.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * free.c
- *
- * Very simple linked-list based malloc()/free().
- */
-
-#include <stdlib.h>
-#include "malloc.h"
-
-static struct free_arena_header *__free_block(struct free_arena_header *ah)
-{
- struct free_arena_header *pah, *nah;
-
- pah = ah->a.prev;
- nah = ah->a.next;
- if (pah->a.type == ARENA_TYPE_FREE &&
- (char *)pah + pah->a.size == (char *)ah) {
- /* Coalesce into the previous block */
- pah->a.size += ah->a.size;
- pah->a.next = nah;
- nah->a.prev = pah;
-
-#ifdef DEBUG_MALLOC
- ah->a.type = ARENA_TYPE_DEAD;
-#endif
-
- ah = pah;
- pah = ah->a.prev;
- } else {
- /* Need to add this block to the free chain */
- ah->a.type = ARENA_TYPE_FREE;
-
- ah->next_free = __malloc_head.next_free;
- ah->prev_free = &__malloc_head;
- __malloc_head.next_free = ah;
- ah->next_free->prev_free = ah;
- }
-
- /* In either of the previous cases, we might be able to merge
- with the subsequent block... */
- if (nah->a.type == ARENA_TYPE_FREE &&
- (char *)ah + ah->a.size == (char *)nah) {
- ah->a.size += nah->a.size;
-
- /* Remove the old block from the chains */
- nah->next_free->prev_free = nah->prev_free;
- nah->prev_free->next_free = nah->next_free;
- ah->a.next = nah->a.next;
- nah->a.next->a.prev = ah;
-
-#ifdef DEBUG_MALLOC
- nah->a.type = ARENA_TYPE_DEAD;
-#endif
- }
-
- /* Return the block that contains the called block */
- return ah;
-}
-
-/*
- * This is used to insert a block which is not previously on the
- * free list. Only the a.size field of the arena header is assumed
- * to be valid.
- */
-void __inject_free_block(struct free_arena_header *ah)
-{
- struct free_arena_header *nah;
- size_t a_end = (size_t) ah + ah->a.size;
- size_t n_end;
-
- for (nah = __malloc_head.a.next; nah->a.type != ARENA_TYPE_HEAD;
- nah = nah->a.next) {
- n_end = (size_t) nah + nah->a.size;
-
- /* Is nah entirely beyond this block? */
- if ((size_t) nah >= a_end)
- break;
-
- /* Is this block entirely beyond nah? */
- if ((size_t) ah >= n_end)
- continue;
-
- /* Otherwise we have some sort of overlap - reject this block */
- return;
- }
-
- /* Now, nah should point to the successor block */
- ah->a.next = nah;
- ah->a.prev = nah->a.prev;
- nah->a.prev = ah;
- ah->a.prev->a.next = ah;
-
- __free_block(ah);
-}
-
-void free(void *ptr)
-{
- struct free_arena_header *ah;
-
- if (!ptr)
- return;
-
- ah = (struct free_arena_header *)
- ((struct arena_header *)ptr - 1);
-
-#ifdef DEBUG_MALLOC
- assert(ah->a.type == ARENA_TYPE_USED);
-#endif
-
- __free_block(ah);
-
- /* Here we could insert code to return memory to the system. */
-}
diff --git a/com32/lib/getcwd.c b/com32/lib/getcwd.c
index 5ce62ec0..d5fa9d7d 100644
--- a/com32/lib/getcwd.c
+++ b/com32/lib/getcwd.c
@@ -4,8 +4,9 @@
#include <com32.h>
#include <syslinux/pmapi.h>
+#include <fs.h>
char *getcwd(char *buf, size_t size)
{
- return __com32.cs_pm->getcwd(buf, size);
+ return core_getcwd(buf, size);
}
diff --git a/com32/lib/init.h b/com32/lib/init.h
deleted file mode 100644
index 2d983427..00000000
--- a/com32/lib/init.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * init.h
- *
- * Magic to set up initializers
- */
-
-#ifndef _INIT_H
-#define _INIT_H 1
-
-#include <inttypes.h>
-
-#define COM32_INIT(x) static const void * const __COM32_INIT \
- __attribute__((section(".init_array"),unused)) = (const void * const)&x
-
-#endif /* _INIT_H */
diff --git a/com32/lib/libpng/libpng.txt b/com32/lib/libpng/libpng.txt
new file mode 100644
index 00000000..9360f33b
--- /dev/null
+++ b/com32/lib/libpng/libpng.txt
@@ -0,0 +1,2959 @@
+libpng.txt - A description on how to use and modify libpng
+
+ libpng version 1.2.8 - December 3, 2004
+ Updated and distributed by Glenn Randers-Pehrson
+ <glennrp at users.sourceforge.net>
+ Copyright (c) 1998-2004 Glenn Randers-Pehrson
+ For conditions of distribution and use, see copyright
+ notice in png.h.
+
+ based on:
+
+ libpng 1.0 beta 6 version 0.96 May 28, 1997
+ Updated and distributed by Andreas Dilger
+ Copyright (c) 1996, 1997 Andreas Dilger
+
+ libpng 1.0 beta 2 - version 0.88 January 26, 1996
+ For conditions of distribution and use, see copyright
+ notice in png.h. Copyright (c) 1995, 1996 Guy Eric
+ Schalnat, Group 42, Inc.
+
+ Updated/rewritten per request in the libpng FAQ
+ Copyright (c) 1995, 1996 Frank J. T. Wojcik
+ December 18, 1995 & January 20, 1996
+
+I. Introduction
+
+This file describes how to use and modify the PNG reference library
+(known as libpng) for your own use. There are five sections to this
+file: introduction, structures, reading, writing, and modification and
+configuration notes for various special platforms. In addition to this
+file, example.c is a good starting point for using the library, as
+it is heavily commented and should include everything most people
+will need. We assume that libpng is already installed; see the
+INSTALL file for instructions on how to install libpng.
+
+Libpng was written as a companion to the PNG specification, as a way
+of reducing the amount of time and effort it takes to support the PNG
+file format in application programs.
+
+The PNG specification (second edition), November 2003, is available as
+a W3C Recommendation and as an ISO Standard (ISO/IEC 15948:2003 (E)) at
+<http://www.w3.org/TR/2003/REC-PNG-20031110/
+The W3C and ISO documents have identical technical content.
+
+The PNG-1.2 specification is available at
+<http://www.libpng.org/pub/png/documents/>
+
+The PNG-1.0 specification is available
+as RFC 2083 <http://www.libpng.org/pub/png/documents/> and as a
+W3C Recommendation <http://www.w3.org/TR/REC.png.html>. Some
+additional chunks are described in the special-purpose public chunks
+documents at <http://www.libpng.org/pub/png/documents/>.
+
+Other information
+about PNG, and the latest version of libpng, can be found at the PNG home
+page, <http://www.libpng.org/pub/png/>.
+
+Most users will not have to modify the library significantly; advanced
+users may want to modify it more. All attempts were made to make it as
+complete as possible, while keeping the code easy to understand.
+Currently, this library only supports C. Support for other languages
+is being considered.
+
+Libpng has been designed to handle multiple sessions at one time,
+to be easily modifiable, to be portable to the vast majority of
+machines (ANSI, K&R, 16-, 32-, and 64-bit) available, and to be easy
+to use. The ultimate goal of libpng is to promote the acceptance of
+the PNG file format in whatever way possible. While there is still
+work to be done (see the TODO file), libpng should cover the
+majority of the needs of its users.
+
+Libpng uses zlib for its compression and decompression of PNG files.
+Further information about zlib, and the latest version of zlib, can
+be found at the zlib home page, <http://www.info-zip.org/pub/infozip/zlib/>.
+The zlib compression utility is a general purpose utility that is
+useful for more than PNG files, and can be used without libpng.
+See the documentation delivered with zlib for more details.
+You can usually find the source files for the zlib utility wherever you
+find the libpng source files.
+
+Libpng is thread safe, provided the threads are using different
+instances of the structures. Each thread should have its own
+png_struct and png_info instances, and thus its own image.
+Libpng does not protect itself against two threads using the
+same instance of a structure. Note: thread safety may be defeated
+by use of some of the MMX assembler code in pnggccrd.c, which is only
+compiled when the user defines PNG_THREAD_UNSAFE_OK.
+
+II. Structures
+
+There are two main structures that are important to libpng, png_struct
+and png_info. The first, png_struct, is an internal structure that
+will not, for the most part, be used by a user except as the first
+variable passed to every libpng function call.
+
+The png_info structure is designed to provide information about the
+PNG file. At one time, the fields of png_info were intended to be
+directly accessible to the user. However, this tended to cause problems
+with applications using dynamically loaded libraries, and as a result
+a set of interface functions for png_info (the png_get_*() and png_set_*()
+functions) was developed. The fields of png_info are still available for
+older applications, but it is suggested that applications use the new
+interfaces if at all possible.
+
+Applications that do make direct access to the members of png_struct (except
+for png_ptr->jmpbuf) must be recompiled whenever the library is updated,
+and applications that make direct access to the members of png_info must
+be recompiled if they were compiled or loaded with libpng version 1.0.6,
+in which the members were in a different order. In version 1.0.7, the
+members of the png_info structure reverted to the old order, as they were
+in versions 0.97c through 1.0.5. Starting with version 2.0.0, both
+structures are going to be hidden, and the contents of the structures will
+only be accessible through the png_get/png_set functions.
+
+The png.h header file is an invaluable reference for programming with libpng.
+And while I'm on the topic, make sure you include the libpng header file:
+
+#include <png.h>
+
+III. Reading
+
+We'll now walk you through the possible functions to call when reading
+in a PNG file sequentially, briefly explaining the syntax and purpose
+of each one. See example.c and png.h for more detail. While
+progressive reading is covered in the next section, you will still
+need some of the functions discussed in this section to read a PNG
+file.
+
+Setup
+
+You will want to do the I/O initialization(*) before you get into libpng,
+so if it doesn't work, you don't have much to undo. Of course, you
+will also want to insure that you are, in fact, dealing with a PNG
+file. Libpng provides a simple check to see if a file is a PNG file.
+To use it, pass in the first 1 to 8 bytes of the file to the function
+png_sig_cmp(), and it will return 0 if the bytes match the corresponding
+bytes of the PNG signature, or nonzero otherwise. Of course, the more bytes
+you pass in, the greater the accuracy of the prediction.
+
+If you are intending to keep the file pointer open for use in libpng,
+you must ensure you don't read more than 8 bytes from the beginning
+of the file, and you also have to make a call to png_set_sig_bytes_read()
+with the number of bytes you read from the beginning. Libpng will
+then only check the bytes (if any) that your program didn't read.
+
+(*): If you are not using the standard I/O functions, you will need
+to replace them with custom functions. See the discussion under
+Customizing libpng.
+
+
+ FILE *fp = fopen(file_name, "rb");
+ if (!fp)
+ {
+ return (ERROR);
+ }
+ fread(header, 1, number, fp);
+ is_png = !png_sig_cmp(header, 0, number);
+ if (!is_png)
+ {
+ return (NOT_PNG);
+ }
+
+
+Next, png_struct and png_info need to be allocated and initialized. In
+order to ensure that the size of these structures is correct even with a
+dynamically linked libpng, there are functions to initialize and
+allocate the structures. We also pass the library version, optional
+pointers to error handling functions, and a pointer to a data struct for
+use by the error functions, if necessary (the pointer and functions can
+be NULL if the default error handlers are to be used). See the section
+on Changes to Libpng below regarding the old initialization functions.
+The structure allocation functions quietly return NULL if they fail to
+create the structure, so your application should check for that.
+
+ png_structp png_ptr = png_create_read_struct
+ (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+ user_error_fn, user_warning_fn);
+ if (!png_ptr)
+ return (ERROR);
+
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_read_struct(&png_ptr,
+ (png_infopp)NULL, (png_infopp)NULL);
+ return (ERROR);
+ }
+
+ png_infop end_info = png_create_info_struct(png_ptr);
+ if (!end_info)
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr,
+ (png_infopp)NULL);
+ return (ERROR);
+ }
+
+If you want to use your own memory allocation routines,
+define PNG_USER_MEM_SUPPORTED and use
+png_create_read_struct_2() instead of png_create_read_struct():
+
+ png_structp png_ptr = png_create_read_struct_2
+ (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+ user_error_fn, user_warning_fn, (png_voidp)
+ user_mem_ptr, user_malloc_fn, user_free_fn);
+
+The error handling routines passed to png_create_read_struct()
+and the memory alloc/free routines passed to png_create_struct_2()
+are only necessary if you are not using the libpng supplied error
+handling and memory alloc/free functions.
+
+When libpng encounters an error, it expects to longjmp back
+to your routine. Therefore, you will need to call setjmp and pass
+your png_jmpbuf(png_ptr). If you read the file from different
+routines, you will need to update the jmpbuf field every time you enter
+a new routine that will call a png_*() function.
+
+See your documentation of setjmp/longjmp for your compiler for more
+information on setjmp/longjmp. See the discussion on libpng error
+handling in the Customizing Libpng section below for more information
+on the libpng error handling. If an error occurs, and libpng longjmp's
+back to your setjmp, you will want to call png_destroy_read_struct() to
+free any memory.
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr,
+ &end_info);
+ fclose(fp);
+ return (ERROR);
+ }
+
+If you would rather avoid the complexity of setjmp/longjmp issues,
+you can compile libpng with PNG_SETJMP_NOT_SUPPORTED, in which case
+errors will result in a call to PNG_ABORT() which defaults to abort().
+
+Now you need to set up the input code. The default for libpng is to
+use the C function fread(). If you use this, you will need to pass a
+valid FILE * in the function png_init_io(). Be sure that the file is
+opened in binary mode. If you wish to handle reading data in another
+way, you need not call the png_init_io() function, but you must then
+implement the libpng I/O methods discussed in the Customizing Libpng
+section below.
+
+ png_init_io(png_ptr, fp);
+
+If you had previously opened the file and read any of the signature from
+the beginning in order to see if this was a PNG file, you need to let
+libpng know that there are some bytes missing from the start of the file.
+
+ png_set_sig_bytes(png_ptr, number);
+
+Setting up callback code
+
+You can set up a callback function to handle any unknown chunks in the
+input stream. You must supply the function
+
+ read_chunk_callback(png_ptr ptr,
+ png_unknown_chunkp chunk);
+ {
+ /* The unknown chunk structure contains your
+ chunk data: */
+ png_byte name[5];
+ png_byte *data;
+ png_size_t size;
+ /* Note that libpng has already taken care of
+ the CRC handling */
+
+ /* put your code here. Return one of the
+ following: */
+
+ return (-n); /* chunk had an error */
+ return (0); /* did not recognize */
+ return (n); /* success */
+ }
+
+(You can give your function another name that you like instead of
+"read_chunk_callback")
+
+To inform libpng about your function, use
+
+ png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr,
+ read_chunk_callback);
+
+This names not only the callback function, but also a user pointer that
+you can retrieve with
+
+ png_get_user_chunk_ptr(png_ptr);
+
+At this point, you can set up a callback function that will be
+called after each row has been read, which you can use to control
+a progress meter or the like. It's demonstrated in pngtest.c.
+You must supply a function
+
+ void read_row_callback(png_ptr ptr, png_uint_32 row,
+ int pass);
+ {
+ /* put your code here */
+ }
+
+(You can give it another name that you like instead of "read_row_callback")
+
+To inform libpng about your function, use
+
+ png_set_read_status_fn(png_ptr, read_row_callback);
+
+Width and height limits
+
+The PNG specification allows the width and height of an image to be as
+large as 2^31-1 (0x7fffffff), or about 2.147 billion rows and columns.
+Since very few applications really need to process such large images,
+we have imposed an arbitrary 1-million limit on rows and columns.
+Larger images will be rejected immediately with a png_error() call. If
+you wish to override this limit, you can use
+
+ png_set_user_limits(png_ptr, width_max, height_max);
+
+to set your own limits, or use width_max = height_max = 0x7fffffffL
+to allow all valid dimensions (libpng may reject some very large images
+anyway because of potential buffer overflow conditions).
+
+You should put this statement after you create the PNG structure and
+before calling png_read_info(), png_read_png(), or png_process_data().
+If you need to retrieve the limits that are being applied, use
+
+ width_max = png_get_user_width_max(png_ptr);
+ height_max = png_get_user_height_max(png_ptr);
+
+Unknown-chunk handling
+
+Now you get to set the way the library processes unknown chunks in the
+input PNG stream. Both known and unknown chunks will be read. Normal
+behavior is that known chunks will be parsed into information in
+various info_ptr members; unknown chunks will be discarded. To change
+this, you can call:
+
+ png_set_keep_unknown_chunks(png_ptr, keep,
+ chunk_list, num_chunks);
+ keep - 0: do not handle as unknown
+ 1: do not keep
+ 2: keep only if safe-to-copy
+ 3: keep even if unsafe-to-copy
+ You can use these definitions:
+ PNG_HANDLE_CHUNK_AS_DEFAULT 0
+ PNG_HANDLE_CHUNK_NEVER 1
+ PNG_HANDLE_CHUNK_IF_SAFE 2
+ PNG_HANDLE_CHUNK_ALWAYS 3
+ chunk_list - list of chunks affected (a byte string,
+ five bytes per chunk, NULL or '\0' if
+ num_chunks is 0)
+ num_chunks - number of chunks affected; if 0, all
+ unknown chunks are affected. If nonzero,
+ only the chunks in the list are affected
+
+Unknown chunks declared in this way will be saved as raw data onto a
+list of png_unknown_chunk structures. If a chunk that is normally
+known to libpng is named in the list, it will be handled as unknown,
+according to the "keep" directive. If a chunk is named in successive
+instances of png_set_keep_unknown_chunks(), the final instance will
+take precedence. The IHDR and IEND chunks should not be named in
+chunk_list; if they are, libpng will process them normally anyway.
+
+The high-level read interface
+
+At this point there are two ways to proceed; through the high-level
+read interface, or through a sequence of low-level read operations.
+You can use the high-level interface if (a) you are willing to read
+the entire image into memory, and (b) the input transformations
+you want to do are limited to the following set:
+
+ PNG_TRANSFORM_IDENTITY No transformation
+ PNG_TRANSFORM_STRIP_16 Strip 16-bit samples to
+ 8 bits
+ PNG_TRANSFORM_STRIP_ALPHA Discard the alpha channel
+ PNG_TRANSFORM_PACKING Expand 1, 2 and 4-bit
+ samples to bytes
+ PNG_TRANSFORM_PACKSWAP Change order of packed
+ pixels to LSB first
+ PNG_TRANSFORM_EXPAND Perform set_expand()
+ PNG_TRANSFORM_INVERT_MONO Invert monochrome images
+ PNG_TRANSFORM_SHIFT Normalize pixels to the
+ sBIT depth
+ PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA
+ to BGRA
+ PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA
+ to AG
+ PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity
+ to transparency
+ PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples
+
+(This excludes setting a background color, doing gamma transformation,
+dithering, and setting filler.) If this is the case, simply do this:
+
+ png_read_png(png_ptr, info_ptr, png_transforms, NULL)
+
+where png_transforms is an integer containing the logical OR of
+some set of transformation flags. This call is equivalent to png_read_info(),
+followed the set of transformations indicated by the transform mask,
+then png_read_image(), and finally png_read_end().
+
+(The final parameter of this call is not yet used. Someday it might point
+to transformation parameters required by some future input transform.)
+
+You must use png_transforms and not call any png_set_transform() functions
+when you use png_read_png().
+
+After you have called png_read_png(), you can retrieve the image data
+with
+
+ row_pointers = png_get_rows(png_ptr, info_ptr);
+
+where row_pointers is an array of pointers to the pixel data for each row:
+
+ png_bytep row_pointers[height];
+
+If you know your image size and pixel size ahead of time, you can allocate
+row_pointers prior to calling png_read_png() with
+
+ if (height > PNG_UINT_32_MAX/png_sizeof(png_byte))
+ png_error (png_ptr,
+ "Image is too tall to process in memory");
+ if (width > PNG_UINT_32_MAX/pixel_size)
+ png_error (png_ptr,
+ "Image is too wide to process in memory");
+ row_pointers = png_malloc(png_ptr,
+ height*png_sizeof(png_bytep));
+ for (int i=0; i<height, i++)
+ row_pointers[i]=png_malloc(png_ptr,
+ width*pixel_size);
+ png_set_rows(png_ptr, info_ptr, &row_pointers);
+
+Alternatively you could allocate your image in one big block and define
+row_pointers[i] to point into the proper places in your block.
+
+If you use png_set_rows(), the application is responsible for freeing
+row_pointers (and row_pointers[i], if they were separately allocated).
+
+If you don't allocate row_pointers ahead of time, png_read_png() will
+do it, and it'll be free'ed when you call png_destroy_*().
+
+The low-level read interface
+
+If you are going the low-level route, you are now ready to read all
+the file information up to the actual image data. You do this with a
+call to png_read_info().
+
+ png_read_info(png_ptr, info_ptr);
+
+This will process all chunks up to but not including the image data.
+
+Querying the info structure
+
+Functions are used to get the information from the info_ptr once it
+has been read. Note that these fields may not be completely filled
+in until png_read_end() has read the chunk data following the image.
+
+ png_get_IHDR(png_ptr, info_ptr, &width, &height,
+ &bit_depth, &color_type, &interlace_type,
+ &compression_type, &filter_method);
+
+ width - holds the width of the image
+ in pixels (up to 2^31).
+ height - holds the height of the image
+ in pixels (up to 2^31).
+ bit_depth - holds the bit depth of one of the
+ image channels. (valid values are
+ 1, 2, 4, 8, 16 and depend also on
+ the color_type. See also
+ significant bits (sBIT) below).
+ color_type - describes which color/alpha channels
+ are present.
+ PNG_COLOR_TYPE_GRAY
+ (bit depths 1, 2, 4, 8, 16)
+ PNG_COLOR_TYPE_GRAY_ALPHA
+ (bit depths 8, 16)
+ PNG_COLOR_TYPE_PALETTE
+ (bit depths 1, 2, 4, 8)
+ PNG_COLOR_TYPE_RGB
+ (bit_depths 8, 16)
+ PNG_COLOR_TYPE_RGB_ALPHA
+ (bit_depths 8, 16)
+
+ PNG_COLOR_MASK_PALETTE
+ PNG_COLOR_MASK_COLOR
+ PNG_COLOR_MASK_ALPHA
+
+ filter_method - (must be PNG_FILTER_TYPE_BASE
+ for PNG 1.0, and can also be
+ PNG_INTRAPIXEL_DIFFERENCING if
+ the PNG datastream is embedded in
+ a MNG-1.0 datastream)
+ compression_type - (must be PNG_COMPRESSION_TYPE_BASE
+ for PNG 1.0)
+ interlace_type - (PNG_INTERLACE_NONE or
+ PNG_INTERLACE_ADAM7)
+ Any or all of interlace_type, compression_type, of
+ filter_method can be NULL if you are
+ not interested in their values.
+
+ channels = png_get_channels(png_ptr, info_ptr);
+ channels - number of channels of info for the
+ color type (valid values are 1 (GRAY,
+ PALETTE), 2 (GRAY_ALPHA), 3 (RGB),
+ 4 (RGB_ALPHA or RGB + filler byte))
+ rowbytes = png_get_rowbytes(png_ptr, info_ptr);
+ rowbytes - number of bytes needed to hold a row
+
+ signature = png_get_signature(png_ptr, info_ptr);
+ signature - holds the signature read from the
+ file (if any). The data is kept in
+ the same offset it would be if the
+ whole signature were read (i.e. if an
+ application had already read in 4
+ bytes of signature before starting
+ libpng, the remaining 4 bytes would
+ be in signature[4] through signature[7]
+ (see png_set_sig_bytes())).
+
+
+ width = png_get_image_width(png_ptr,
+ info_ptr);
+ height = png_get_image_height(png_ptr,
+ info_ptr);
+ bit_depth = png_get_bit_depth(png_ptr,
+ info_ptr);
+ color_type = png_get_color_type(png_ptr,
+ info_ptr);
+ filter_method = png_get_filter_type(png_ptr,
+ info_ptr);
+ compression_type = png_get_compression_type(png_ptr,
+ info_ptr);
+ interlace_type = png_get_interlace_type(png_ptr,
+ info_ptr);
+
+
+These are also important, but their validity depends on whether the chunk
+has been read. The png_get_valid(png_ptr, info_ptr, PNG_INFO_<chunk>) and
+png_get_<chunk>(png_ptr, info_ptr, ...) functions return non-zero if the
+data has been read, or zero if it is missing. The parameters to the
+png_get_<chunk> are set directly if they are simple data types, or a pointer
+into the info_ptr is returned for any complex types.
+
+ png_get_PLTE(png_ptr, info_ptr, &palette,
+ &num_palette);
+ palette - the palette for the file
+ (array of png_color)
+ num_palette - number of entries in the palette
+
+ png_get_gAMA(png_ptr, info_ptr, &gamma);
+ gamma - the gamma the file is written
+ at (PNG_INFO_gAMA)
+
+ png_get_sRGB(png_ptr, info_ptr, &srgb_intent);
+ srgb_intent - the rendering intent (PNG_INFO_sRGB)
+ The presence of the sRGB chunk
+ means that the pixel data is in the
+ sRGB color space. This chunk also
+ implies specific values of gAMA and
+ cHRM.
+
+ png_get_iCCP(png_ptr, info_ptr, &name,
+ &compression_type, &profile, &proflen);
+ name - The profile name.
+ compression - The compression type; always
+ PNG_COMPRESSION_TYPE_BASE for PNG 1.0.
+ You may give NULL to this argument to
+ ignore it.
+ profile - International Color Consortium color
+ profile data. May contain NULs.
+ proflen - length of profile data in bytes.
+
+ png_get_sBIT(png_ptr, info_ptr, &sig_bit);
+ sig_bit - the number of significant bits for
+ (PNG_INFO_sBIT) each of the gray,
+ red, green, and blue channels,
+ whichever are appropriate for the
+ given color type (png_color_16)
+
+ png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans,
+ &trans_values);
+ trans - array of transparent entries for
+ palette (PNG_INFO_tRNS)
+ trans_values - graylevel or color sample values of
+ the single transparent color for
+ non-paletted images (PNG_INFO_tRNS)
+ num_trans - number of transparent entries
+ (PNG_INFO_tRNS)
+
+ png_get_hIST(png_ptr, info_ptr, &hist);
+ (PNG_INFO_hIST)
+ hist - histogram of palette (array of
+ png_uint_16)
+
+ png_get_tIME(png_ptr, info_ptr, &mod_time);
+ mod_time - time image was last modified
+ (PNG_VALID_tIME)
+
+ png_get_bKGD(png_ptr, info_ptr, &background);
+ background - background color (PNG_VALID_bKGD)
+ valid 16-bit red, green and blue
+ values, regardless of color_type
+
+ num_comments = png_get_text(png_ptr, info_ptr,
+ &text_ptr, &num_text);
+ num_comments - number of comments
+ text_ptr - array of png_text holding image
+ comments
+ text_ptr[i].compression - type of compression used
+ on "text" PNG_TEXT_COMPRESSION_NONE
+ PNG_TEXT_COMPRESSION_zTXt
+ PNG_ITXT_COMPRESSION_NONE
+ PNG_ITXT_COMPRESSION_zTXt
+ text_ptr[i].key - keyword for comment. Must contain
+ 1-79 characters.
+ text_ptr[i].text - text comments for current
+ keyword. Can be empty.
+ text_ptr[i].text_length - length of text string,
+ after decompression, 0 for iTXt
+ text_ptr[i].itxt_length - length of itxt string,
+ after decompression, 0 for tEXt/zTXt
+ text_ptr[i].lang - language of comment (empty
+ string for unknown).
+ text_ptr[i].lang_key - keyword in UTF-8
+ (empty string for unknown).
+ num_text - number of comments (same as
+ num_comments; you can put NULL here
+ to avoid the duplication)
+ Note while png_set_text() will accept text, language,
+ and translated keywords that can be NULL pointers, the
+ structure returned by png_get_text will always contain
+ regular zero-terminated C strings. They might be
+ empty strings but they will never be NULL pointers.
+
+ num_spalettes = png_get_sPLT(png_ptr, info_ptr,
+ &palette_ptr);
+ palette_ptr - array of palette structures holding
+ contents of one or more sPLT chunks
+ read.
+ num_spalettes - number of sPLT chunks read.
+
+ png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y,
+ &unit_type);
+ offset_x - positive offset from the left edge
+ of the screen
+ offset_y - positive offset from the top edge
+ of the screen
+ unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER
+
+ png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y,
+ &unit_type);
+ res_x - pixels/unit physical resolution in
+ x direction
+ res_y - pixels/unit physical resolution in
+ x direction
+ unit_type - PNG_RESOLUTION_UNKNOWN,
+ PNG_RESOLUTION_METER
+
+ png_get_sCAL(png_ptr, info_ptr, &unit, &width,
+ &height)
+ unit - physical scale units (an integer)
+ width - width of a pixel in physical scale units
+ height - height of a pixel in physical scale units
+ (width and height are doubles)
+
+ png_get_sCAL_s(png_ptr, info_ptr, &unit, &width,
+ &height)
+ unit - physical scale units (an integer)
+ width - width of a pixel in physical scale units
+ height - height of a pixel in physical scale units
+ (width and height are strings like "2.54")
+
+ num_unknown_chunks = png_get_unknown_chunks(png_ptr,
+ info_ptr, &unknowns)
+ unknowns - array of png_unknown_chunk
+ structures holding unknown chunks
+ unknowns[i].name - name of unknown chunk
+ unknowns[i].data - data of unknown chunk
+ unknowns[i].size - size of unknown chunk's data
+ unknowns[i].location - position of chunk in file
+
+ The value of "i" corresponds to the order in which the
+ chunks were read from the PNG file or inserted with the
+ png_set_unknown_chunks() function.
+
+The data from the pHYs chunk can be retrieved in several convenient
+forms:
+
+ res_x = png_get_x_pixels_per_meter(png_ptr,
+ info_ptr)
+ res_y = png_get_y_pixels_per_meter(png_ptr,
+ info_ptr)
+ res_x_and_y = png_get_pixels_per_meter(png_ptr,
+ info_ptr)
+ res_x = png_get_x_pixels_per_inch(png_ptr,
+ info_ptr)
+ res_y = png_get_y_pixels_per_inch(png_ptr,
+ info_ptr)
+ res_x_and_y = png_get_pixels_per_inch(png_ptr,
+ info_ptr)
+ aspect_ratio = png_get_pixel_aspect_ratio(png_ptr,
+ info_ptr)
+
+ (Each of these returns 0 [signifying "unknown"] if
+ the data is not present or if res_x is 0;
+ res_x_and_y is 0 if res_x != res_y)
+
+The data from the oFFs chunk can be retrieved in several convenient
+forms:
+
+ x_offset = png_get_x_offset_microns(png_ptr, info_ptr);
+ y_offset = png_get_y_offset_microns(png_ptr, info_ptr);
+ x_offset = png_get_x_offset_inches(png_ptr, info_ptr);
+ y_offset = png_get_y_offset_inches(png_ptr, info_ptr);
+
+ (Each of these returns 0 [signifying "unknown" if both
+ x and y are 0] if the data is not present or if the
+ chunk is present but the unit is the pixel)
+
+For more information, see the png_info definition in png.h and the
+PNG specification for chunk contents. Be careful with trusting
+rowbytes, as some of the transformations could increase the space
+needed to hold a row (expand, filler, gray_to_rgb, etc.).
+See png_read_update_info(), below.
+
+A quick word about text_ptr and num_text. PNG stores comments in
+keyword/text pairs, one pair per chunk, with no limit on the number
+of text chunks, and a 2^31 byte limit on their size. While there are
+suggested keywords, there is no requirement to restrict the use to these
+strings. It is strongly suggested that keywords and text be sensible
+to humans (that's the point), so don't use abbreviations. Non-printing
+symbols are not allowed. See the PNG specification for more details.
+There is also no requirement to have text after the keyword.
+
+Keywords should be limited to 79 Latin-1 characters without leading or
+trailing spaces, but non-consecutive spaces are allowed within the
+keyword. It is possible to have the same keyword any number of times.
+The text_ptr is an array of png_text structures, each holding a
+pointer to a language string, a pointer to a keyword and a pointer to
+a text string. The text string, language code, and translated
+keyword may be empty or NULL pointers. The keyword/text
+pairs are put into the array in the order that they are received.
+However, some or all of the text chunks may be after the image, so, to
+make sure you have read all the text chunks, don't mess with these
+until after you read the stuff after the image. This will be
+mentioned again below in the discussion that goes with png_read_end().
+
+Input transformations
+
+After you've read the header information, you can set up the library
+to handle any special transformations of the image data. The various
+ways to transform the data will be described in the order that they
+should occur. This is important, as some of these change the color
+type and/or bit depth of the data, and some others only work on
+certain color types and bit depths. Even though each transformation
+checks to see if it has data that it can do something with, you should
+make sure to only enable a transformation if it will be valid for the
+data. For example, don't swap red and blue on grayscale data.
+
+The colors used for the background and transparency values should be
+supplied in the same format/depth as the current image data. They
+are stored in the same format/depth as the image data in a bKGD or tRNS
+chunk, so this is what libpng expects for this data. The colors are
+transformed to keep in sync with the image data when an application
+calls the png_read_update_info() routine (see below).
+
+Data will be decoded into the supplied row buffers packed into bytes
+unless the library has been told to transform it into another format.
+For example, 4 bit/pixel paletted or grayscale data will be returned
+2 pixels/byte with the leftmost pixel in the high-order bits of the
+byte, unless png_set_packing() is called. 8-bit RGB data will be stored
+in RGB RGB RGB format unless png_set_filler() or png_set_add_alpha()
+is called to insert filler bytes, either before or after each RGB triplet.
+16-bit RGB data will be returned RRGGBB RRGGBB, with the most significant
+byte of the color value first, unless png_set_strip_16() is called to
+transform it to regular RGB RGB triplets, or png_set_filler() or
+png_set_add alpha() is called to insert filler bytes, either before or
+after each RRGGBB triplet. Similarly, 8-bit or 16-bit grayscale data can
+be modified with
+png_set_filler(), png_set_add_alpha(), or png_set_strip_16().
+
+The following code transforms grayscale images of less than 8 to 8 bits,
+changes paletted images to RGB, and adds a full alpha channel if there is
+transparency information in a tRNS chunk. This is most useful on
+grayscale images with bit depths of 2 or 4 or if there is a multiple-image
+viewing application that wishes to treat all images in the same way.
+
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ png_set_palette_to_rgb(png_ptr);
+
+ if (color_type == PNG_COLOR_TYPE_GRAY &&
+ bit_depth < 8) png_set_gray_1_2_4_to_8(png_ptr);
+
+ if (png_get_valid(png_ptr, info_ptr,
+ PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr);
+
+These three functions are actually aliases for png_set_expand(), added
+in libpng version 1.0.4, with the function names expanded to improve code
+readability. In some future version they may actually do different
+things.
+
+PNG can have files with 16 bits per channel. If you only can handle
+8 bits per channel, this will strip the pixels down to 8 bit.
+
+ if (bit_depth == 16)
+ png_set_strip_16(png_ptr);
+
+If, for some reason, you don't need the alpha channel on an image,
+and you want to remove it rather than combining it with the background
+(but the image author certainly had in mind that you *would* combine
+it with the background, so that's what you should probably do):
+
+ if (color_type & PNG_COLOR_MASK_ALPHA)
+ png_set_strip_alpha(png_ptr);
+
+In PNG files, the alpha channel in an image
+is the level of opacity. If you need the alpha channel in an image to
+be the level of transparency instead of opacity, you can invert the
+alpha channel (or the tRNS chunk data) after it's read, so that 0 is
+fully opaque and 255 (in 8-bit or paletted images) or 65535 (in 16-bit
+images) is fully transparent, with
+
+ png_set_invert_alpha(png_ptr);
+
+PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as
+they can, resulting in, for example, 8 pixels per byte for 1 bit
+files. This code expands to 1 pixel per byte without changing the
+values of the pixels:
+
+ if (bit_depth < 8)
+ png_set_packing(png_ptr);
+
+PNG files have possible bit depths of 1, 2, 4, 8, and 16. All pixels
+stored in a PNG image have been "scaled" or "shifted" up to the next
+higher possible bit depth (e.g. from 5 bits/sample in the range [0,31] to
+8 bits/sample in the range [0, 255]). However, it is also possible to
+convert the PNG pixel data back to the original bit depth of the image.
+This call reduces the pixels back down to the original bit depth:
+
+ png_color_8p sig_bit;
+
+ if (png_get_sBIT(png_ptr, info_ptr, &sig_bit))
+ png_set_shift(png_ptr, sig_bit);
+
+PNG files store 3-color pixels in red, green, blue order. This code
+changes the storage of the pixels to blue, green, red:
+
+ if (color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ png_set_bgr(png_ptr);
+
+PNG files store RGB pixels packed into 3 or 6 bytes. This code expands them
+into 4 or 8 bytes for windowing systems that need them in this format:
+
+ if (color_type == PNG_COLOR_TYPE_RGB)
+ png_set_filler(png_ptr, filler, PNG_FILLER_BEFORE);
+
+where "filler" is the 8 or 16-bit number to fill with, and the location is
+either PNG_FILLER_BEFORE or PNG_FILLER_AFTER, depending upon whether
+you want the filler before the RGB or after. This transformation
+does not affect images that already have full alpha channels. To add an
+opaque alpha channel, use filler=0xff or 0xffff and PNG_FILLER_AFTER which
+will generate RGBA pixels.
+
+Note that png_set_filler() does not change the color type. If you want
+to do that, you can add a true alpha channel with
+
+ if (color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_GRAY)
+ png_set_add_alpha(png_ptr, filler, PNG_FILLER_AFTER);
+
+where "filler" contains the alpha value to assign to each pixel.
+This function was added in libpng-1.2.7.
+
+If you are reading an image with an alpha channel, and you need the
+data as ARGB instead of the normal PNG format RGBA:
+
+ if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ png_set_swap_alpha(png_ptr);
+
+For some uses, you may want a grayscale image to be represented as
+RGB. This code will do that conversion:
+
+ if (color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_gray_to_rgb(png_ptr);
+
+Conversely, you can convert an RGB or RGBA image to grayscale or grayscale
+with alpha.
+
+ if (color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ png_set_rgb_to_gray_fixed(png_ptr, error_action,
+ int red_weight, int green_weight);
+
+ error_action = 1: silently do the conversion
+ error_action = 2: issue a warning if the original
+ image has any pixel where
+ red != green or red != blue
+ error_action = 3: issue an error and abort the
+ conversion if the original
+ image has any pixel where
+ red != green or red != blue
+
+ red_weight: weight of red component times 100000
+ green_weight: weight of green component times 100000
+ If either weight is negative, default
+ weights (21268, 71514) are used.
+
+If you have set error_action = 1 or 2, you can
+later check whether the image really was gray, after processing
+the image rows, with the png_get_rgb_to_gray_status(png_ptr) function.
+It will return a png_byte that is zero if the image was gray or
+1 if there were any non-gray pixels. bKGD and sBIT data
+will be silently converted to grayscale, using the green channel
+data, regardless of the error_action setting.
+
+With red_weight+green_weight<=100000,
+the normalized graylevel is computed:
+
+ int rw = red_weight * 65536;
+ int gw = green_weight * 65536;
+ int bw = 65536 - (rw + gw);
+ gray = (rw*red + gw*green + bw*blue)/65536;
+
+The default values approximate those recommended in the Charles
+Poynton's Color FAQ, <http://www.inforamp.net/~poynton/>
+Copyright (c) 1998-01-04 Charles Poynton <poynton at inforamp.net>
+
+ Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
+
+Libpng approximates this with
+
+ Y = 0.21268 * R + 0.7151 * G + 0.07217 * B
+
+which can be expressed with integers as
+
+ Y = (6969 * R + 23434 * G + 2365 * B)/32768
+
+The calculation is done in a linear colorspace, if the image gamma
+is known.
+
+If you have a grayscale and you are using png_set_expand_depth(),
+png_set_expand(), or png_set_gray_to_rgb to change to truecolor or to
+a higher bit-depth, you must either supply the background color as a gray
+value at the original file bit-depth (need_expand = 1) or else supply the
+background color as an RGB triplet at the final, expanded bit depth
+(need_expand = 0). Similarly, if you are reading a paletted image, you
+must either supply the background color as a palette index (need_expand = 1)
+or as an RGB triplet that may or may not be in the palette (need_expand = 0).
+
+ png_color_16 my_background;
+ png_color_16p image_background;
+
+ if (png_get_bKGD(png_ptr, info_ptr, &image_background))
+ png_set_background(png_ptr, image_background,
+ PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
+ else
+ png_set_background(png_ptr, &my_background,
+ PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
+
+The png_set_background() function tells libpng to composite images
+with alpha or simple transparency against the supplied background
+color. If the PNG file contains a bKGD chunk (PNG_INFO_bKGD valid),
+you may use this color, or supply another color more suitable for
+the current display (e.g., the background color from a web page). You
+need to tell libpng whether the color is in the gamma space of the
+display (PNG_BACKGROUND_GAMMA_SCREEN for colors you supply), the file
+(PNG_BACKGROUND_GAMMA_FILE for colors from the bKGD chunk), or one
+that is neither of these gammas (PNG_BACKGROUND_GAMMA_UNIQUE - I don't
+know why anyone would use this, but it's here).
+
+To properly display PNG images on any kind of system, the application needs
+to know what the display gamma is. Ideally, the user will know this, and
+the application will allow them to set it. One method of allowing the user
+to set the display gamma separately for each system is to check for a
+SCREEN_GAMMA or DISPLAY_GAMMA environment variable, which will hopefully be
+correctly set.
+
+Note that display_gamma is the overall gamma correction required to produce
+pleasing results, which depends on the lighting conditions in the surrounding
+environment. In a dim or brightly lit room, no compensation other than
+the physical gamma exponent of the monitor is needed, while in a dark room
+a slightly smaller exponent is better.
+
+ double gamma, screen_gamma;
+
+ if (/* We have a user-defined screen
+ gamma value */)
+ {
+ screen_gamma = user_defined_screen_gamma;
+ }
+ /* One way that applications can share the same
+ screen gamma value */
+ else if ((gamma_str = getenv("SCREEN_GAMMA"))
+ != NULL)
+ {
+ screen_gamma = (double)atof(gamma_str);
+ }
+ /* If we don't have another value */
+ else
+ {
+ screen_gamma = 2.2; /* A good guess for a
+ PC monitor in a bright office or a dim room */
+ screen_gamma = 2.0; /* A good guess for a
+ PC monitor in a dark room */
+ screen_gamma = 1.7 or 1.0; /* A good
+ guess for Mac systems */
+ }
+
+The png_set_gamma() function handles gamma transformations of the data.
+Pass both the file gamma and the current screen_gamma. If the file does
+not have a gamma value, you can pass one anyway if you have an idea what
+it is (usually 0.45455 is a good guess for GIF images on PCs). Note
+that file gammas are inverted from screen gammas. See the discussions
+on gamma in the PNG specification for an excellent description of what
+gamma is, and why all applications should support it. It is strongly
+recommended that PNG viewers support gamma correction.
+
+ if (png_get_gAMA(png_ptr, info_ptr, &gamma))
+ png_set_gamma(png_ptr, screen_gamma, gamma);
+ else
+ png_set_gamma(png_ptr, screen_gamma, 0.45455);
+
+If you need to reduce an RGB file to a paletted file, or if a paletted
+file has more entries then will fit on your screen, png_set_dither()
+will do that. Note that this is a simple match dither that merely
+finds the closest color available. This should work fairly well with
+optimized palettes, and fairly badly with linear color cubes. If you
+pass a palette that is larger then maximum_colors, the file will
+reduce the number of colors in the palette so it will fit into
+maximum_colors. If there is a histogram, it will use it to make
+more intelligent choices when reducing the palette. If there is no
+histogram, it may not do as good a job.
+
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ if (png_get_valid(png_ptr, info_ptr,
+ PNG_INFO_PLTE))
+ {
+ png_uint_16p histogram = NULL;
+
+ png_get_hIST(png_ptr, info_ptr,
+ &histogram);
+ png_set_dither(png_ptr, palette, num_palette,
+ max_screen_colors, histogram, 1);
+ }
+ else
+ {
+ png_color std_color_cube[MAX_SCREEN_COLORS] =
+ { ... colors ... };
+
+ png_set_dither(png_ptr, std_color_cube,
+ MAX_SCREEN_COLORS, MAX_SCREEN_COLORS,
+ NULL,0);
+ }
+ }
+
+PNG files describe monochrome as black being zero and white being one.
+The following code will reverse this (make black be one and white be
+zero):
+
+ if (bit_depth == 1 && color_type == PNG_COLOR_TYPE_GRAY)
+ png_set_invert_mono(png_ptr);
+
+This function can also be used to invert grayscale and gray-alpha images:
+
+ if (color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ png_set_invert_mono(png_ptr);
+
+PNG files store 16 bit pixels in network byte order (big-endian,
+ie. most significant bits first). This code changes the storage to the
+other way (little-endian, i.e. least significant bits first, the
+way PCs store them):
+
+ if (bit_depth == 16)
+ png_set_swap(png_ptr);
+
+If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you
+need to change the order the pixels are packed into bytes, you can use:
+
+ if (bit_depth < 8)
+ png_set_packswap(png_ptr);
+
+Finally, you can write your own transformation function if none of
+the existing ones meets your needs. This is done by setting a callback
+with
+
+ png_set_read_user_transform_fn(png_ptr,
+ read_transform_fn);
+
+You must supply the function
+
+ void read_transform_fn(png_ptr ptr, row_info_ptr
+ row_info, png_bytep data)
+
+See pngtest.c for a working example. Your function will be called
+after all of the other transformations have been processed.
+
+You can also set up a pointer to a user structure for use by your
+callback function, and you can inform libpng that your transform
+function will change the number of channels or bit depth with the
+function
+
+ png_set_user_transform_info(png_ptr, user_ptr,
+ user_depth, user_channels);
+
+The user's application, not libpng, is responsible for allocating and
+freeing any memory required for the user structure.
+
+You can retrieve the pointer via the function
+png_get_user_transform_ptr(). For example:
+
+ voidp read_user_transform_ptr =
+ png_get_user_transform_ptr(png_ptr);
+
+The last thing to handle is interlacing; this is covered in detail below,
+but you must call the function here if you want libpng to handle expansion
+of the interlaced image.
+
+ number_of_passes = png_set_interlace_handling(png_ptr);
+
+After setting the transformations, libpng can update your png_info
+structure to reflect any transformations you've requested with this
+call. This is most useful to update the info structure's rowbytes
+field so you can use it to allocate your image memory. This function
+will also update your palette with the correct screen_gamma and
+background if these have been given with the calls above.
+
+ png_read_update_info(png_ptr, info_ptr);
+
+After you call png_read_update_info(), you can allocate any
+memory you need to hold the image. The row data is simply
+raw byte data for all forms of images. As the actual allocation
+varies among applications, no example will be given. If you
+are allocating one large chunk, you will need to build an
+array of pointers to each row, as it will be needed for some
+of the functions below.
+
+Reading image data
+
+After you've allocated memory, you can read the image data.
+The simplest way to do this is in one function call. If you are
+allocating enough memory to hold the whole image, you can just
+call png_read_image() and libpng will read in all the image data
+and put it in the memory area supplied. You will need to pass in
+an array of pointers to each row.
+
+This function automatically handles interlacing, so you don't need
+to call png_set_interlace_handling() or call this function multiple
+times, or any of that other stuff necessary with png_read_rows().
+
+ png_read_image(png_ptr, row_pointers);
+
+where row_pointers is:
+
+ png_bytep row_pointers[height];
+
+You can point to void or char or whatever you use for pixels.
+
+If you don't want to read in the whole image at once, you can
+use png_read_rows() instead. If there is no interlacing (check
+interlace_type == PNG_INTERLACE_NONE), this is simple:
+
+ png_read_rows(png_ptr, row_pointers, NULL,
+ number_of_rows);
+
+where row_pointers is the same as in the png_read_image() call.
+
+If you are doing this just one row at a time, you can do this with
+a single row_pointer instead of an array of row_pointers:
+
+ png_bytep row_pointer = row;
+ png_read_row(png_ptr, row_pointer, NULL);
+
+If the file is interlaced (interlace_type != 0 in the IHDR chunk), things
+get somewhat harder. The only current (PNG Specification version 1.2)
+interlacing type for PNG is (interlace_type == PNG_INTERLACE_ADAM7)
+is a somewhat complicated 2D interlace scheme, known as Adam7, that
+breaks down an image into seven smaller images of varying size, based
+on an 8x8 grid.
+
+libpng can fill out those images or it can give them to you "as is".
+If you want them filled out, there are two ways to do that. The one
+mentioned in the PNG specification is to expand each pixel to cover
+those pixels that have not been read yet (the "rectangle" method).
+This results in a blocky image for the first pass, which gradually
+smooths out as more pixels are read. The other method is the "sparkle"
+method, where pixels are drawn only in their final locations, with the
+rest of the image remaining whatever colors they were initialized to
+before the start of the read. The first method usually looks better,
+but tends to be slower, as there are more pixels to put in the rows.
+
+If you don't want libpng to handle the interlacing details, just call
+png_read_rows() seven times to read in all seven images. Each of the
+images is a valid image by itself, or they can all be combined on an
+8x8 grid to form a single image (although if you intend to combine them
+you would be far better off using the libpng interlace handling).
+
+The first pass will return an image 1/8 as wide as the entire image
+(every 8th column starting in column 0) and 1/8 as high as the original
+(every 8th row starting in row 0), the second will be 1/8 as wide
+(starting in column 4) and 1/8 as high (also starting in row 0). The
+third pass will be 1/4 as wide (every 4th pixel starting in column 0) and
+1/8 as high (every 8th row starting in row 4), and the fourth pass will
+be 1/4 as wide and 1/4 as high (every 4th column starting in column 2,
+and every 4th row starting in row 0). The fifth pass will return an
+image 1/2 as wide, and 1/4 as high (starting at column 0 and row 2),
+while the sixth pass will be 1/2 as wide and 1/2 as high as the original
+(starting in column 1 and row 0). The seventh and final pass will be as
+wide as the original, and 1/2 as high, containing all of the odd
+numbered scanlines. Phew!
+
+If you want libpng to expand the images, call this before calling
+png_start_read_image() or png_read_update_info():
+
+ if (interlace_type == PNG_INTERLACE_ADAM7)
+ number_of_passes
+ = png_set_interlace_handling(png_ptr);
+
+This will return the number of passes needed. Currently, this
+is seven, but may change if another interlace type is added.
+This function can be called even if the file is not interlaced,
+where it will return one pass.
+
+If you are not going to display the image after each pass, but are
+going to wait until the entire image is read in, use the sparkle
+effect. This effect is faster and the end result of either method
+is exactly the same. If you are planning on displaying the image
+after each pass, the "rectangle" effect is generally considered the
+better looking one.
+
+If you only want the "sparkle" effect, just call png_read_rows() as
+normal, with the third parameter NULL. Make sure you make pass over
+the image number_of_passes times, and you don't change the data in the
+rows between calls. You can change the locations of the data, just
+not the data. Each pass only writes the pixels appropriate for that
+pass, and assumes the data from previous passes is still valid.
+
+ png_read_rows(png_ptr, row_pointers, NULL,
+ number_of_rows);
+
+If you only want the first effect (the rectangles), do the same as
+before except pass the row buffer in the third parameter, and leave
+the second parameter NULL.
+
+ png_read_rows(png_ptr, NULL, row_pointers,
+ number_of_rows);
+
+Finishing a sequential read
+
+After you are finished reading the image through either the high- or
+low-level interfaces, you can finish reading the file. If you are
+interested in comments or time, which may be stored either before or
+after the image data, you should pass the separate png_info struct if
+you want to keep the comments from before and after the image
+separate. If you are not interested, you can pass NULL.
+
+ png_read_end(png_ptr, end_info);
+
+When you are done, you can free all memory allocated by libpng like this:
+
+ png_destroy_read_struct(&png_ptr, &info_ptr,
+ &end_info);
+
+It is also possible to individually free the info_ptr members that
+point to libpng-allocated storage with the following function:
+
+ png_free_data(png_ptr, info_ptr, mask, seq)
+ mask - identifies data to be freed, a mask
+ containing the logical OR of one or
+ more of
+ PNG_FREE_PLTE, PNG_FREE_TRNS,
+ PNG_FREE_HIST, PNG_FREE_ICCP,
+ PNG_FREE_PCAL, PNG_FREE_ROWS,
+ PNG_FREE_SCAL, PNG_FREE_SPLT,
+ PNG_FREE_TEXT, PNG_FREE_UNKN,
+ or simply PNG_FREE_ALL
+ seq - sequence number of item to be freed
+ (-1 for all items)
+
+This function may be safely called when the relevant storage has
+already been freed, or has not yet been allocated, or was allocated
+by the user and not by libpng, and will in those
+cases do nothing. The "seq" parameter is ignored if only one item
+of the selected data type, such as PLTE, is allowed. If "seq" is not
+-1, and multiple items are allowed for the data type identified in
+the mask, such as text or sPLT, only the n'th item in the structure
+is freed, where n is "seq".
+
+The default behavior is only to free data that was allocated internally
+by libpng. This can be changed, so that libpng will not free the data,
+or so that it will free data that was allocated by the user with png_malloc()
+or png_zalloc() and passed in via a png_set_*() function, with
+
+ png_data_freer(png_ptr, info_ptr, freer, mask)
+ mask - which data elements are affected
+ same choices as in png_free_data()
+ freer - one of
+ PNG_DESTROY_WILL_FREE_DATA
+ PNG_SET_WILL_FREE_DATA
+ PNG_USER_WILL_FREE_DATA
+
+This function only affects data that has already been allocated.
+You can call this function after reading the PNG data but before calling
+any png_set_*() functions, to control whether the user or the png_set_*()
+function is responsible for freeing any existing data that might be present,
+and again after the png_set_*() functions to control whether the user
+or png_destroy_*() is supposed to free the data. When the user assumes
+responsibility for libpng-allocated data, the application must use
+png_free() to free it, and when the user transfers responsibility to libpng
+for data that the user has allocated, the user must have used png_malloc()
+or png_zalloc() to allocate it.
+
+If you allocated your row_pointers in a single block, as suggested above in
+the description of the high level read interface, you must not transfer
+responsibility for freeing it to the png_set_rows or png_read_destroy function,
+because they would also try to free the individual row_pointers[i].
+
+If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword
+separately, do not transfer responsibility for freeing text_ptr to libpng,
+because when libpng fills a png_text structure it combines these members with
+the key member, and png_free_data() will free only text_ptr.key. Similarly,
+if you transfer responsibility for free'ing text_ptr from libpng to your
+application, your application must not separately free those members.
+
+The png_free_data() function will turn off the "valid" flag for anything
+it frees. If you need to turn the flag off for a chunk that was freed by your
+application instead of by libpng, you can use
+
+ png_set_invalid(png_ptr, info_ptr, mask);
+ mask - identifies the chunks to be made invalid,
+ containing the logical OR of one or
+ more of
+ PNG_INFO_gAMA, PNG_INFO_sBIT,
+ PNG_INFO_cHRM, PNG_INFO_PLTE,
+ PNG_INFO_tRNS, PNG_INFO_bKGD,
+ PNG_INFO_hIST, PNG_INFO_pHYs,
+ PNG_INFO_oFFs, PNG_INFO_tIME,
+ PNG_INFO_pCAL, PNG_INFO_sRGB,
+ PNG_INFO_iCCP, PNG_INFO_sPLT,
+ PNG_INFO_sCAL, PNG_INFO_IDAT
+
+For a more compact example of reading a PNG image, see the file example.c.
+
+Reading PNG files progressively
+
+The progressive reader is slightly different then the non-progressive
+reader. Instead of calling png_read_info(), png_read_rows(), and
+png_read_end(), you make one call to png_process_data(), which calls
+callbacks when it has the info, a row, or the end of the image. You
+set up these callbacks with png_set_progressive_read_fn(). You don't
+have to worry about the input/output functions of libpng, as you are
+giving the library the data directly in png_process_data(). I will
+assume that you have read the section on reading PNG files above,
+so I will only highlight the differences (although I will show
+all of the code).
+
+png_structp png_ptr;
+png_infop info_ptr;
+
+ /* An example code fragment of how you would
+ initialize the progressive reader in your
+ application. */
+ int
+ initialize_png_reader()
+ {
+ png_ptr = png_create_read_struct
+ (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+ user_error_fn, user_warning_fn);
+ if (!png_ptr)
+ return (ERROR);
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_read_struct(&png_ptr, (png_infopp)NULL,
+ (png_infopp)NULL);
+ return (ERROR);
+ }
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr,
+ (png_infopp)NULL);
+ return (ERROR);
+ }
+
+ /* This one's new. You can provide functions
+ to be called when the header info is valid,
+ when each row is completed, and when the image
+ is finished. If you aren't using all functions,
+ you can specify NULL parameters. Even when all
+ three functions are NULL, you need to call
+ png_set_progressive_read_fn(). You can use
+ any struct as the user_ptr (cast to a void pointer
+ for the function call), and retrieve the pointer
+ from inside the callbacks using the function
+
+ png_get_progressive_ptr(png_ptr);
+
+ which will return a void pointer, which you have
+ to cast appropriately.
+ */
+ png_set_progressive_read_fn(png_ptr, (void *)user_ptr,
+ info_callback, row_callback, end_callback);
+
+ return 0;
+ }
+
+ /* A code fragment that you call as you receive blocks
+ of data */
+ int
+ process_data(png_bytep buffer, png_uint_32 length)
+ {
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ png_destroy_read_struct(&png_ptr, &info_ptr,
+ (png_infopp)NULL);
+ return (ERROR);
+ }
+
+ /* This one's new also. Simply give it a chunk
+ of data from the file stream (in order, of
+ course). On machines with segmented memory
+ models machines, don't give it any more than
+ 64K. The library seems to run fine with sizes
+ of 4K. Although you can give it much less if
+ necessary (I assume you can give it chunks of
+ 1 byte, I haven't tried less then 256 bytes
+ yet). When this function returns, you may
+ want to display any rows that were generated
+ in the row callback if you don't already do
+ so there.
+ */
+ png_process_data(png_ptr, info_ptr, buffer, length);
+ return 0;
+ }
+
+ /* This function is called (as set by
+ png_set_progressive_read_fn() above) when enough data
+ has been supplied so all of the header has been
+ read.
+ */
+ void
+ info_callback(png_structp png_ptr, png_infop info)
+ {
+ /* Do any setup here, including setting any of
+ the transformations mentioned in the Reading
+ PNG files section. For now, you _must_ call
+ either png_start_read_image() or
+ png_read_update_info() after all the
+ transformations are set (even if you don't set
+ any). You may start getting rows before
+ png_process_data() returns, so this is your
+ last chance to prepare for that.
+ */
+ }
+
+ /* This function is called when each row of image
+ data is complete */
+ void
+ row_callback(png_structp png_ptr, png_bytep new_row,
+ png_uint_32 row_num, int pass)
+ {
+ /* If the image is interlaced, and you turned
+ on the interlace handler, this function will
+ be called for every row in every pass. Some
+ of these rows will not be changed from the
+ previous pass. When the row is not changed,
+ the new_row variable will be NULL. The rows
+ and passes are called in order, so you don't
+ really need the row_num and pass, but I'm
+ supplying them because it may make your life
+ easier.
+
+ For the non-NULL rows of interlaced images,
+ you must call png_progressive_combine_row()
+ passing in the row and the old row. You can
+ call this function for NULL rows (it will just
+ return) and for non-interlaced images (it just
+ does the memcpy for you) if it will make the
+ code easier. Thus, you can just do this for
+ all cases:
+ */
+
+ png_progressive_combine_row(png_ptr, old_row,
+ new_row);
+
+ /* where old_row is what was displayed for
+ previously for the row. Note that the first
+ pass (pass == 0, really) will completely cover
+ the old row, so the rows do not have to be
+ initialized. After the first pass (and only
+ for interlaced images), you will have to pass
+ the current row, and the function will combine
+ the old row and the new row.
+ */
+ }
+
+ void
+ end_callback(png_structp png_ptr, png_infop info)
+ {
+ /* This function is called after the whole image
+ has been read, including any chunks after the
+ image (up to and including the IEND). You
+ will usually have the same info chunk as you
+ had in the header, although some data may have
+ been added to the comments and time fields.
+
+ Most people won't do much here, perhaps setting
+ a flag that marks the image as finished.
+ */
+ }
+
+
+
+IV. Writing
+
+Much of this is very similar to reading. However, everything of
+importance is repeated here, so you won't have to constantly look
+back up in the reading section to understand writing.
+
+Setup
+
+You will want to do the I/O initialization before you get into libpng,
+so if it doesn't work, you don't have anything to undo. If you are not
+using the standard I/O functions, you will need to replace them with
+custom writing functions. See the discussion under Customizing libpng.
+
+ FILE *fp = fopen(file_name, "wb");
+ if (!fp)
+ {
+ return (ERROR);
+ }
+
+Next, png_struct and png_info need to be allocated and initialized.
+As these can be both relatively large, you may not want to store these
+on the stack, unless you have stack space to spare. Of course, you
+will want to check if they return NULL. If you are also reading,
+you won't want to name your read structure and your write structure
+both "png_ptr"; you can call them anything you like, such as
+"read_ptr" and "write_ptr". Look at pngtest.c, for example.
+
+ png_structp png_ptr = png_create_write_struct
+ (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+ user_error_fn, user_warning_fn);
+ if (!png_ptr)
+ return (ERROR);
+
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ png_destroy_write_struct(&png_ptr,
+ (png_infopp)NULL);
+ return (ERROR);
+ }
+
+If you want to use your own memory allocation routines,
+define PNG_USER_MEM_SUPPORTED and use
+png_create_write_struct_2() instead of png_create_write_struct():
+
+ png_structp png_ptr = png_create_write_struct_2
+ (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
+ user_error_fn, user_warning_fn, (png_voidp)
+ user_mem_ptr, user_malloc_fn, user_free_fn);
+
+After you have these structures, you will need to set up the
+error handling. When libpng encounters an error, it expects to
+longjmp() back to your routine. Therefore, you will need to call
+setjmp() and pass the png_jmpbuf(png_ptr). If you
+write the file from different routines, you will need to update
+the png_jmpbuf(png_ptr) every time you enter a new routine that will
+call a png_*() function. See your documentation of setjmp/longjmp
+for your compiler for more information on setjmp/longjmp. See
+the discussion on libpng error handling in the Customizing Libpng
+section below for more information on the libpng error handling.
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ {
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+ fclose(fp);
+ return (ERROR);
+ }
+ ...
+ return;
+
+If you would rather avoid the complexity of setjmp/longjmp issues,
+you can compile libpng with PNG_SETJMP_NOT_SUPPORTED, in which case
+errors will result in a call to PNG_ABORT() which defaults to abort().
+
+Now you need to set up the output code. The default for libpng is to
+use the C function fwrite(). If you use this, you will need to pass a
+valid FILE * in the function png_init_io(). Be sure that the file is
+opened in binary mode. Again, if you wish to handle writing data in
+another way, see the discussion on libpng I/O handling in the Customizing
+Libpng section below.
+
+ png_init_io(png_ptr, fp);
+
+Write callbacks
+
+At this point, you can set up a callback function that will be
+called after each row has been written, which you can use to control
+a progress meter or the like. It's demonstrated in pngtest.c.
+You must supply a function
+
+ void write_row_callback(png_ptr, png_uint_32 row,
+ int pass);
+ {
+ /* put your code here */
+ }
+
+(You can give it another name that you like instead of "write_row_callback")
+
+To inform libpng about your function, use
+
+ png_set_write_status_fn(png_ptr, write_row_callback);
+
+You now have the option of modifying how the compression library will
+run. The following functions are mainly for testing, but may be useful
+in some cases, like if you need to write PNG files extremely fast and
+are willing to give up some compression, or if you want to get the
+maximum possible compression at the expense of slower writing. If you
+have no special needs in this area, let the library do what it wants by
+not calling this function at all, as it has been tuned to deliver a good
+speed/compression ratio. The second parameter to png_set_filter() is
+the filter method, for which the only valid values are 0 (as of the
+July 1999 PNG specification, version 1.2) or 64 (if you are writing
+a PNG datastream that is to be embedded in a MNG datastream). The third
+parameter is a flag that indicates which filter type(s) are to be tested
+for each scanline. See the PNG specification for details on the specific filter
+types.
+
+
+ /* turn on or off filtering, and/or choose
+ specific filters. You can use either a single
+ PNG_FILTER_VALUE_NAME or the logical OR of one
+ or more PNG_FILTER_NAME masks. */
+ png_set_filter(png_ptr, 0,
+ PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE |
+ PNG_FILTER_SUB | PNG_FILTER_VALUE_SUB |
+ PNG_FILTER_UP | PNG_FILTER_VALUE_UP |
+ PNG_FILTER_AVE | PNG_FILTER_VALUE_AVE |
+ PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH|
+ PNG_ALL_FILTERS);
+
+If an application
+wants to start and stop using particular filters during compression,
+it should start out with all of the filters (to ensure that the previous
+row of pixels will be stored in case it's needed later), and then add
+and remove them after the start of compression.
+
+If you are writing a PNG datastream that is to be embedded in a MNG
+datastream, the second parameter can be either 0 or 64.
+
+The png_set_compression_*() functions interface to the zlib compression
+library, and should mostly be ignored unless you really know what you are
+doing. The only generally useful call is png_set_compression_level()
+which changes how much time zlib spends on trying to compress the image
+data. See the Compression Library (zlib.h and algorithm.txt, distributed
+with zlib) for details on the compression levels.
+
+ /* set the zlib compression level */
+ png_set_compression_level(png_ptr,
+ Z_BEST_COMPRESSION);
+
+ /* set other zlib parameters */
+ png_set_compression_mem_level(png_ptr, 8);
+ png_set_compression_strategy(png_ptr,
+ Z_DEFAULT_STRATEGY);
+ png_set_compression_window_bits(png_ptr, 15);
+ png_set_compression_method(png_ptr, 8);
+ png_set_compression_buffer_size(png_ptr, 8192)
+
+extern PNG_EXPORT(void,png_set_zbuf_size)
+
+Setting the contents of info for output
+
+You now need to fill in the png_info structure with all the data you
+wish to write before the actual image. Note that the only thing you
+are allowed to write after the image is the text chunks and the time
+chunk (as of PNG Specification 1.2, anyway). See png_write_end() and
+the latest PNG specification for more information on that. If you
+wish to write them before the image, fill them in now, and flag that
+data as being valid. If you want to wait until after the data, don't
+fill them until png_write_end(). For all the fields in png_info and
+their data types, see png.h. For explanations of what the fields
+contain, see the PNG specification.
+
+Some of the more important parts of the png_info are:
+
+ png_set_IHDR(png_ptr, info_ptr, width, height,
+ bit_depth, color_type, interlace_type,
+ compression_type, filter_method)
+ width - holds the width of the image
+ in pixels (up to 2^31).
+ height - holds the height of the image
+ in pixels (up to 2^31).
+ bit_depth - holds the bit depth of one of the
+ image channels.
+ (valid values are 1, 2, 4, 8, 16
+ and depend also on the
+ color_type. See also significant
+ bits (sBIT) below).
+ color_type - describes which color/alpha
+ channels are present.
+ PNG_COLOR_TYPE_GRAY
+ (bit depths 1, 2, 4, 8, 16)
+ PNG_COLOR_TYPE_GRAY_ALPHA
+ (bit depths 8, 16)
+ PNG_COLOR_TYPE_PALETTE
+ (bit depths 1, 2, 4, 8)
+ PNG_COLOR_TYPE_RGB
+ (bit_depths 8, 16)
+ PNG_COLOR_TYPE_RGB_ALPHA
+ (bit_depths 8, 16)
+
+ PNG_COLOR_MASK_PALETTE
+ PNG_COLOR_MASK_COLOR
+ PNG_COLOR_MASK_ALPHA
+
+ interlace_type - PNG_INTERLACE_NONE or
+ PNG_INTERLACE_ADAM7
+ compression_type - (must be
+ PNG_COMPRESSION_TYPE_DEFAULT)
+ filter_method - (must be PNG_FILTER_TYPE_DEFAULT
+ or, if you are writing a PNG to
+ be embedded in a MNG datastream,
+ can also be
+ PNG_INTRAPIXEL_DIFFERENCING)
+
+ png_set_PLTE(png_ptr, info_ptr, palette,
+ num_palette);
+ palette - the palette for the file
+ (array of png_color)
+ num_palette - number of entries in the palette
+
+ png_set_gAMA(png_ptr, info_ptr, gamma);
+ gamma - the gamma the image was created
+ at (PNG_INFO_gAMA)
+
+ png_set_sRGB(png_ptr, info_ptr, srgb_intent);
+ srgb_intent - the rendering intent
+ (PNG_INFO_sRGB) The presence of
+ the sRGB chunk means that the pixel
+ data is in the sRGB color space.
+ This chunk also implies specific
+ values of gAMA and cHRM. Rendering
+ intent is the CSS-1 property that
+ has been defined by the International
+ Color Consortium
+ (http://www.color.org).
+ It can be one of
+ PNG_sRGB_INTENT_SATURATION,
+ PNG_sRGB_INTENT_PERCEPTUAL,
+ PNG_sRGB_INTENT_ABSOLUTE, or
+ PNG_sRGB_INTENT_RELATIVE.
+
+
+ png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr,
+ srgb_intent);
+ srgb_intent - the rendering intent
+ (PNG_INFO_sRGB) The presence of the
+ sRGB chunk means that the pixel
+ data is in the sRGB color space.
+ This function also causes gAMA and
+ cHRM chunks with the specific values
+ that are consistent with sRGB to be
+ written.
+
+ png_set_iCCP(png_ptr, info_ptr, name, compression_type,
+ profile, proflen);
+ name - The profile name.
+ compression - The compression type; always
+ PNG_COMPRESSION_TYPE_BASE for PNG 1.0.
+ You may give NULL to this argument to
+ ignore it.
+ profile - International Color Consortium color
+ profile data. May contain NULs.
+ proflen - length of profile data in bytes.
+
+ png_set_sBIT(png_ptr, info_ptr, sig_bit);
+ sig_bit - the number of significant bits for
+ (PNG_INFO_sBIT) each of the gray, red,
+ green, and blue channels, whichever are
+ appropriate for the given color type
+ (png_color_16)
+
+ png_set_tRNS(png_ptr, info_ptr, trans, num_trans,
+ trans_values);
+ trans - array of transparent entries for
+ palette (PNG_INFO_tRNS)
+ trans_values - graylevel or color sample values of
+ the single transparent color for
+ non-paletted images (PNG_INFO_tRNS)
+ num_trans - number of transparent entries
+ (PNG_INFO_tRNS)
+
+ png_set_hIST(png_ptr, info_ptr, hist);
+ (PNG_INFO_hIST)
+ hist - histogram of palette (array of
+ png_uint_16)
+
+ png_set_tIME(png_ptr, info_ptr, mod_time);
+ mod_time - time image was last modified
+ (PNG_VALID_tIME)
+
+ png_set_bKGD(png_ptr, info_ptr, background);
+ background - background color (PNG_VALID_bKGD)
+
+ png_set_text(png_ptr, info_ptr, text_ptr, num_text);
+ text_ptr - array of png_text holding image
+ comments
+ text_ptr[i].compression - type of compression used
+ on "text" PNG_TEXT_COMPRESSION_NONE
+ PNG_TEXT_COMPRESSION_zTXt
+ PNG_ITXT_COMPRESSION_NONE
+ PNG_ITXT_COMPRESSION_zTXt
+ text_ptr[i].key - keyword for comment. Must contain
+ 1-79 characters.
+ text_ptr[i].text - text comments for current
+ keyword. Can be NULL or empty.
+ text_ptr[i].text_length - length of text string,
+ after decompression, 0 for iTXt
+ text_ptr[i].itxt_length - length of itxt string,
+ after decompression, 0 for tEXt/zTXt
+ text_ptr[i].lang - language of comment (NULL or
+ empty for unknown).
+ text_ptr[i].translated_keyword - keyword in UTF-8 (NULL
+ or empty for unknown).
+ num_text - number of comments
+
+ png_set_sPLT(png_ptr, info_ptr, &palette_ptr,
+ num_spalettes);
+ palette_ptr - array of png_sPLT_struct structures
+ to be added to the list of palettes
+ in the info structure.
+ num_spalettes - number of palette structures to be
+ added.
+
+ png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y,
+ unit_type);
+ offset_x - positive offset from the left
+ edge of the screen
+ offset_y - positive offset from the top
+ edge of the screen
+ unit_type - PNG_OFFSET_PIXEL, PNG_OFFSET_MICROMETER
+
+ png_set_pHYs(png_ptr, info_ptr, res_x, res_y,
+ unit_type);
+ res_x - pixels/unit physical resolution
+ in x direction
+ res_y - pixels/unit physical resolution
+ in y direction
+ unit_type - PNG_RESOLUTION_UNKNOWN,
+ PNG_RESOLUTION_METER
+
+ png_set_sCAL(png_ptr, info_ptr, unit, width, height)
+ unit - physical scale units (an integer)
+ width - width of a pixel in physical scale units
+ height - height of a pixel in physical scale units
+ (width and height are doubles)
+
+ png_set_sCAL_s(png_ptr, info_ptr, unit, width, height)
+ unit - physical scale units (an integer)
+ width - width of a pixel in physical scale units
+ height - height of a pixel in physical scale units
+ (width and height are strings like "2.54")
+
+ png_set_unknown_chunks(png_ptr, info_ptr, &unknowns,
+ num_unknowns)
+ unknowns - array of png_unknown_chunk
+ structures holding unknown chunks
+ unknowns[i].name - name of unknown chunk
+ unknowns[i].data - data of unknown chunk
+ unknowns[i].size - size of unknown chunk's data
+ unknowns[i].location - position to write chunk in file
+ 0: do not write chunk
+ PNG_HAVE_IHDR: before PLTE
+ PNG_HAVE_PLTE: before IDAT
+ PNG_AFTER_IDAT: after IDAT
+
+The "location" member is set automatically according to
+what part of the output file has already been written.
+You can change its value after calling png_set_unknown_chunks()
+as demonstrated in pngtest.c. Within each of the "locations",
+the chunks are sequenced according to their position in the
+structure (that is, the value of "i", which is the order in which
+the chunk was either read from the input file or defined with
+png_set_unknown_chunks).
+
+A quick word about text and num_text. text is an array of png_text
+structures. num_text is the number of valid structures in the array.
+Each png_text structure holds a language code, a keyword, a text value,
+and a compression type.
+
+The compression types have the same valid numbers as the compression
+types of the image data. Currently, the only valid number is zero.
+However, you can store text either compressed or uncompressed, unlike
+images, which always have to be compressed. So if you don't want the
+text compressed, set the compression type to PNG_TEXT_COMPRESSION_NONE.
+Because tEXt and zTXt chunks don't have a language field, if you
+specify PNG_TEXT_COMPRESSION_NONE or PNG_TEXT_COMPRESSION_zTXt
+any language code or translated keyword will not be written out.
+
+Until text gets around 1000 bytes, it is not worth compressing it.
+After the text has been written out to the file, the compression type
+is set to PNG_TEXT_COMPRESSION_NONE_WR or PNG_TEXT_COMPRESSION_zTXt_WR,
+so that it isn't written out again at the end (in case you are calling
+png_write_end() with the same struct.
+
+The keywords that are given in the PNG Specification are:
+
+ Title Short (one line) title or
+ caption for image
+ Author Name of image's creator
+ Description Description of image (possibly long)
+ Copyright Copyright notice
+ Creation Time Time of original image creation
+ (usually RFC 1123 format, see below)
+ Software Software used to create the image
+ Disclaimer Legal disclaimer
+ Warning Warning of nature of content
+ Source Device used to create the image
+ Comment Miscellaneous comment; conversion
+ from other image format
+
+The keyword-text pairs work like this. Keywords should be short
+simple descriptions of what the comment is about. Some typical
+keywords are found in the PNG specification, as is some recommendations
+on keywords. You can repeat keywords in a file. You can even write
+some text before the image and some after. For example, you may want
+to put a description of the image before the image, but leave the
+disclaimer until after, so viewers working over modem connections
+don't have to wait for the disclaimer to go over the modem before
+they start seeing the image. Finally, keywords should be full
+words, not abbreviations. Keywords and text are in the ISO 8859-1
+(Latin-1) character set (a superset of regular ASCII) and can not
+contain NUL characters, and should not contain control or other
+unprintable characters. To make the comments widely readable, stick
+with basic ASCII, and avoid machine specific character set extensions
+like the IBM-PC character set. The keyword must be present, but
+you can leave off the text string on non-compressed pairs.
+Compressed pairs must have a text string, as only the text string
+is compressed anyway, so the compression would be meaningless.
+
+PNG supports modification time via the png_time structure. Two
+conversion routines are provided, png_convert_from_time_t() for
+time_t and png_convert_from_struct_tm() for struct tm. The
+time_t routine uses gmtime(). You don't have to use either of
+these, but if you wish to fill in the png_time structure directly,
+you should provide the time in universal time (GMT) if possible
+instead of your local time. Note that the year number is the full
+year (e.g. 1998, rather than 98 - PNG is year 2000 compliant!), and
+that months start with 1.
+
+If you want to store the time of the original image creation, you should
+use a plain tEXt chunk with the "Creation Time" keyword. This is
+necessary because the "creation time" of a PNG image is somewhat vague,
+depending on whether you mean the PNG file, the time the image was
+created in a non-PNG format, a still photo from which the image was
+scanned, or possibly the subject matter itself. In order to facilitate
+machine-readable dates, it is recommended that the "Creation Time"
+tEXt chunk use RFC 1123 format dates (e.g. "22 May 1997 18:07:10 GMT"),
+although this isn't a requirement. Unlike the tIME chunk, the
+"Creation Time" tEXt chunk is not expected to be automatically changed
+by the software. To facilitate the use of RFC 1123 dates, a function
+png_convert_to_rfc1123(png_timep) is provided to convert from PNG
+time to an RFC 1123 format string.
+
+Writing unknown chunks
+
+You can use the png_set_unknown_chunks function to queue up chunks
+for writing. You give it a chunk name, raw data, and a size; that's
+all there is to it. The chunks will be written by the next following
+png_write_info_before_PLTE, png_write_info, or png_write_end function.
+Any chunks previously read into the info structure's unknown-chunk
+list will also be written out in a sequence that satisfies the PNG
+specification's ordering rules.
+
+The high-level write interface
+
+At this point there are two ways to proceed; through the high-level
+write interface, or through a sequence of low-level write operations.
+You can use the high-level interface if your image data is present
+in the info structure. All defined output
+transformations are permitted, enabled by the following masks.
+
+ PNG_TRANSFORM_IDENTITY No transformation
+ PNG_TRANSFORM_PACKING Pack 1, 2 and 4-bit samples
+ PNG_TRANSFORM_PACKSWAP Change order of packed
+ pixels to LSB first
+ PNG_TRANSFORM_INVERT_MONO Invert monochrome images
+ PNG_TRANSFORM_SHIFT Normalize pixels to the
+ sBIT depth
+ PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA
+ to BGRA
+ PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA
+ to AG
+ PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity
+ to transparency
+ PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples
+ PNG_TRANSFORM_STRIP_FILLER Strip out filler bytes.
+
+If you have valid image data in the info structure (you can use
+png_set_rows() to put image data in the info structure), simply do this:
+
+ png_write_png(png_ptr, info_ptr, png_transforms, NULL)
+
+where png_transforms is an integer containing the logical OR of some set of
+transformation flags. This call is equivalent to png_write_info(),
+followed the set of transformations indicated by the transform mask,
+then png_write_image(), and finally png_write_end().
+
+(The final parameter of this call is not yet used. Someday it might point
+to transformation parameters required by some future output transform.)
+
+You must use png_transforms and not call any png_set_transform() functions
+when you use png_write_png().
+
+The low-level write interface
+
+If you are going the low-level route instead, you are now ready to
+write all the file information up to the actual image data. You do
+this with a call to png_write_info().
+
+ png_write_info(png_ptr, info_ptr);
+
+Note that there is one transformation you may need to do before
+png_write_info(). In PNG files, the alpha channel in an image is the
+level of opacity. If your data is supplied as a level of
+transparency, you can invert the alpha channel before you write it, so
+that 0 is fully transparent and 255 (in 8-bit or paletted images) or
+65535 (in 16-bit images) is fully opaque, with
+
+ png_set_invert_alpha(png_ptr);
+
+This must appear before png_write_info() instead of later with the
+other transformations because in the case of paletted images the tRNS
+chunk data has to be inverted before the tRNS chunk is written. If
+your image is not a paletted image, the tRNS data (which in such cases
+represents a single color to be rendered as transparent) won't need to
+be changed, and you can safely do this transformation after your
+png_write_info() call.
+
+If you need to write a private chunk that you want to appear before
+the PLTE chunk when PLTE is present, you can write the PNG info in
+two steps, and insert code to write your own chunk between them:
+
+ png_write_info_before_PLTE(png_ptr, info_ptr);
+ png_set_unknown_chunks(png_ptr, info_ptr, ...);
+ png_write_info(png_ptr, info_ptr);
+
+After you've written the file information, you can set up the library
+to handle any special transformations of the image data. The various
+ways to transform the data will be described in the order that they
+should occur. This is important, as some of these change the color
+type and/or bit depth of the data, and some others only work on
+certain color types and bit depths. Even though each transformation
+checks to see if it has data that it can do something with, you should
+make sure to only enable a transformation if it will be valid for the
+data. For example, don't swap red and blue on grayscale data.
+
+PNG files store RGB pixels packed into 3 or 6 bytes. This code tells
+the library to strip input data that has 4 or 8 bytes per pixel down
+to 3 or 6 bytes (or strip 2 or 4-byte grayscale+filler data to 1 or 2
+bytes per pixel).
+
+ png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
+
+where the 0 is unused, and the location is either PNG_FILLER_BEFORE or
+PNG_FILLER_AFTER, depending upon whether the filler byte in the pixel
+is stored XRGB or RGBX.
+
+PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as
+they can, resulting in, for example, 8 pixels per byte for 1 bit files.
+If the data is supplied at 1 pixel per byte, use this code, which will
+correctly pack the pixels into a single byte:
+
+ png_set_packing(png_ptr);
+
+PNG files reduce possible bit depths to 1, 2, 4, 8, and 16. If your
+data is of another bit depth, you can write an sBIT chunk into the
+file so that decoders can recover the original data if desired.
+
+ /* Set the true bit depth of the image data */
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ sig_bit.red = true_bit_depth;
+ sig_bit.green = true_bit_depth;
+ sig_bit.blue = true_bit_depth;
+ }
+ else
+ {
+ sig_bit.gray = true_bit_depth;
+ }
+ if (color_type & PNG_COLOR_MASK_ALPHA)
+ {
+ sig_bit.alpha = true_bit_depth;
+ }
+
+ png_set_sBIT(png_ptr, info_ptr, &sig_bit);
+
+If the data is stored in the row buffer in a bit depth other than
+one supported by PNG (e.g. 3 bit data in the range 0-7 for a 4-bit PNG),
+this will scale the values to appear to be the correct bit depth as
+is required by PNG.
+
+ png_set_shift(png_ptr, &sig_bit);
+
+PNG files store 16 bit pixels in network byte order (big-endian,
+ie. most significant bits first). This code would be used if they are
+supplied the other way (little-endian, i.e. least significant bits
+first, the way PCs store them):
+
+ if (bit_depth > 8)
+ png_set_swap(png_ptr);
+
+If you are using packed-pixel images (1, 2, or 4 bits/pixel), and you
+need to change the order the pixels are packed into bytes, you can use:
+
+ if (bit_depth < 8)
+ png_set_packswap(png_ptr);
+
+PNG files store 3 color pixels in red, green, blue order. This code
+would be used if they are supplied as blue, green, red:
+
+ png_set_bgr(png_ptr);
+
+PNG files describe monochrome as black being zero and white being
+one. This code would be used if the pixels are supplied with this reversed
+(black being one and white being zero):
+
+ png_set_invert_mono(png_ptr);
+
+Finally, you can write your own transformation function if none of
+the existing ones meets your needs. This is done by setting a callback
+with
+
+ png_set_write_user_transform_fn(png_ptr,
+ write_transform_fn);
+
+You must supply the function
+
+ void write_transform_fn(png_ptr ptr, row_info_ptr
+ row_info, png_bytep data)
+
+See pngtest.c for a working example. Your function will be called
+before any of the other transformations are processed.
+
+You can also set up a pointer to a user structure for use by your
+callback function.
+
+ png_set_user_transform_info(png_ptr, user_ptr, 0, 0);
+
+The user_channels and user_depth parameters of this function are ignored
+when writing; you can set them to zero as shown.
+
+You can retrieve the pointer via the function png_get_user_transform_ptr().
+For example:
+
+ voidp write_user_transform_ptr =
+ png_get_user_transform_ptr(png_ptr);
+
+It is possible to have libpng flush any pending output, either manually,
+or automatically after a certain number of lines have been written. To
+flush the output stream a single time call:
+
+ png_write_flush(png_ptr);
+
+and to have libpng flush the output stream periodically after a certain
+number of scanlines have been written, call:
+
+ png_set_flush(png_ptr, nrows);
+
+Note that the distance between rows is from the last time png_write_flush()
+was called, or the first row of the image if it has never been called.
+So if you write 50 lines, and then png_set_flush 25, it will flush the
+output on the next scanline, and every 25 lines thereafter, unless
+png_write_flush() is called before 25 more lines have been written.
+If nrows is too small (less than about 10 lines for a 640 pixel wide
+RGB image) the image compression may decrease noticeably (although this
+may be acceptable for real-time applications). Infrequent flushing will
+only degrade the compression performance by a few percent over images
+that do not use flushing.
+
+Writing the image data
+
+That's it for the transformations. Now you can write the image data.
+The simplest way to do this is in one function call. If you have the
+whole image in memory, you can just call png_write_image() and libpng
+will write the image. You will need to pass in an array of pointers to
+each row. This function automatically handles interlacing, so you don't
+need to call png_set_interlace_handling() or call this function multiple
+times, or any of that other stuff necessary with png_write_rows().
+
+ png_write_image(png_ptr, row_pointers);
+
+where row_pointers is:
+
+ png_byte *row_pointers[height];
+
+You can point to void or char or whatever you use for pixels.
+
+If you don't want to write the whole image at once, you can
+use png_write_rows() instead. If the file is not interlaced,
+this is simple:
+
+ png_write_rows(png_ptr, row_pointers,
+ number_of_rows);
+
+row_pointers is the same as in the png_write_image() call.
+
+If you are just writing one row at a time, you can do this with
+a single row_pointer instead of an array of row_pointers:
+
+ png_bytep row_pointer = row;
+
+ png_write_row(png_ptr, row_pointer);
+
+When the file is interlaced, things can get a good deal more
+complicated. The only currently (as of the PNG Specification
+version 1.2, dated July 1999) defined interlacing scheme for PNG files
+is the "Adam7" interlace scheme, that breaks down an
+image into seven smaller images of varying size. libpng will build
+these images for you, or you can do them yourself. If you want to
+build them yourself, see the PNG specification for details of which
+pixels to write when.
+
+If you don't want libpng to handle the interlacing details, just
+use png_set_interlace_handling() and call png_write_rows() the
+correct number of times to write all seven sub-images.
+
+If you want libpng to build the sub-images, call this before you start
+writing any rows:
+
+ number_of_passes =
+ png_set_interlace_handling(png_ptr);
+
+This will return the number of passes needed. Currently, this
+is seven, but may change if another interlace type is added.
+
+Then write the complete image number_of_passes times.
+
+ png_write_rows(png_ptr, row_pointers,
+ number_of_rows);
+
+As some of these rows are not used, and thus return immediately,
+you may want to read about interlacing in the PNG specification,
+and only update the rows that are actually used.
+
+Finishing a sequential write
+
+After you are finished writing the image, you should finish writing
+the file. If you are interested in writing comments or time, you should
+pass an appropriately filled png_info pointer. If you are not interested,
+you can pass NULL.
+
+ png_write_end(png_ptr, info_ptr);
+
+When you are done, you can free all memory used by libpng like this:
+
+ png_destroy_write_struct(&png_ptr, &info_ptr);
+
+It is also possible to individually free the info_ptr members that
+point to libpng-allocated storage with the following function:
+
+ png_free_data(png_ptr, info_ptr, mask, seq)
+ mask - identifies data to be freed, a mask
+ containing the logical OR of one or
+ more of
+ PNG_FREE_PLTE, PNG_FREE_TRNS,
+ PNG_FREE_HIST, PNG_FREE_ICCP,
+ PNG_FREE_PCAL, PNG_FREE_ROWS,
+ PNG_FREE_SCAL, PNG_FREE_SPLT,
+ PNG_FREE_TEXT, PNG_FREE_UNKN,
+ or simply PNG_FREE_ALL
+ seq - sequence number of item to be freed
+ (-1 for all items)
+
+This function may be safely called when the relevant storage has
+already been freed, or has not yet been allocated, or was allocated
+by the user and not by libpng, and will in those
+cases do nothing. The "seq" parameter is ignored if only one item
+of the selected data type, such as PLTE, is allowed. If "seq" is not
+-1, and multiple items are allowed for the data type identified in
+the mask, such as text or sPLT, only the n'th item in the structure
+is freed, where n is "seq".
+
+If you allocated data such as a palette that you passed
+in to libpng with png_set_*, you must not free it until just before the call to
+png_destroy_write_struct().
+
+The default behavior is only to free data that was allocated internally
+by libpng. This can be changed, so that libpng will not free the data,
+or so that it will free data that was allocated by the user with png_malloc()
+or png_zalloc() and passed in via a png_set_*() function, with
+
+ png_data_freer(png_ptr, info_ptr, freer, mask)
+ mask - which data elements are affected
+ same choices as in png_free_data()
+ freer - one of
+ PNG_DESTROY_WILL_FREE_DATA
+ PNG_SET_WILL_FREE_DATA
+ PNG_USER_WILL_FREE_DATA
+
+For example, to transfer responsibility for some data from a read structure
+to a write structure, you could use
+
+ png_data_freer(read_ptr, read_info_ptr,
+ PNG_USER_WILL_FREE_DATA,
+ PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST)
+ png_data_freer(write_ptr, write_info_ptr,
+ PNG_DESTROY_WILL_FREE_DATA,
+ PNG_FREE_PLTE|PNG_FREE_tRNS|PNG_FREE_hIST)
+
+thereby briefly reassigning responsibility for freeing to the user but
+immediately afterwards reassigning it once more to the write_destroy
+function. Having done this, it would then be safe to destroy the read
+structure and continue to use the PLTE, tRNS, and hIST data in the write
+structure.
+
+This function only affects data that has already been allocated.
+You can call this function before calling after the png_set_*() functions
+to control whether the user or png_destroy_*() is supposed to free the data.
+When the user assumes responsibility for libpng-allocated data, the
+application must use
+png_free() to free it, and when the user transfers responsibility to libpng
+for data that the user has allocated, the user must have used png_malloc()
+or png_zalloc() to allocate it.
+
+If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword
+separately, do not transfer responsibility for freeing text_ptr to libpng,
+because when libpng fills a png_text structure it combines these members with
+the key member, and png_free_data() will free only text_ptr.key. Similarly,
+if you transfer responsibility for free'ing text_ptr from libpng to your
+application, your application must not separately free those members.
+For a more compact example of writing a PNG image, see the file example.c.
+
+V. Modifying/Customizing libpng:
+
+There are three issues here. The first is changing how libpng does
+standard things like memory allocation, input/output, and error handling.
+The second deals with more complicated things like adding new chunks,
+adding new transformations, and generally changing how libpng works.
+Both of those are compile-time issues; that is, they are generally
+determined at the time the code is written, and there is rarely a need
+to provide the user with a means of changing them. The third is a
+run-time issue: choosing between and/or tuning one or more alternate
+versions of computationally intensive routines; specifically, optimized
+assembly-language (and therefore compiler- and platform-dependent)
+versions.
+
+Memory allocation, input/output, and error handling
+
+All of the memory allocation, input/output, and error handling in libpng
+goes through callbacks that are user-settable. The default routines are
+in pngmem.c, pngrio.c, pngwio.c, and pngerror.c, respectively. To change
+these functions, call the appropriate png_set_*_fn() function.
+
+Memory allocation is done through the functions png_malloc()
+and png_free(). These currently just call the standard C functions. If
+your pointers can't access more then 64K at a time, you will want to set
+MAXSEG_64K in zlib.h. Since it is unlikely that the method of handling
+memory allocation on a platform will change between applications, these
+functions must be modified in the library at compile time. If you prefer
+to use a different method of allocating and freeing data, you can use
+png_create_read_struct_2() or png_create_write_struct_2() to register
+your own functions as described above.
+These functions also provide a void pointer that can be retrieved via
+
+ mem_ptr=png_get_mem_ptr(png_ptr);
+
+Your replacement memory functions must have prototypes as follows:
+
+ png_voidp malloc_fn(png_structp png_ptr,
+ png_size_t size);
+ void free_fn(png_structp png_ptr, png_voidp ptr);
+
+Your malloc_fn() must return NULL in case of failure. The png_malloc()
+function will normally call png_error() if it receives a NULL from the
+system memory allocator or from your replacement malloc_fn().
+
+Input/Output in libpng is done through png_read() and png_write(),
+which currently just call fread() and fwrite(). The FILE * is stored in
+png_struct and is initialized via png_init_io(). If you wish to change
+the method of I/O, the library supplies callbacks that you can set
+through the function png_set_read_fn() and png_set_write_fn() at run
+time, instead of calling the png_init_io() function. These functions
+also provide a void pointer that can be retrieved via the function
+png_get_io_ptr(). For example:
+
+ png_set_read_fn(png_structp read_ptr,
+ voidp read_io_ptr, png_rw_ptr read_data_fn)
+
+ png_set_write_fn(png_structp write_ptr,
+ voidp write_io_ptr, png_rw_ptr write_data_fn,
+ png_flush_ptr output_flush_fn);
+
+ voidp read_io_ptr = png_get_io_ptr(read_ptr);
+ voidp write_io_ptr = png_get_io_ptr(write_ptr);
+
+The replacement I/O functions must have prototypes as follows:
+
+ void user_read_data(png_structp png_ptr,
+ png_bytep data, png_size_t length);
+ void user_write_data(png_structp png_ptr,
+ png_bytep data, png_size_t length);
+ void user_flush_data(png_structp png_ptr);
+
+Supplying NULL for the read, write, or flush functions sets them back
+to using the default C stream functions. It is an error to read from
+a write stream, and vice versa.
+
+Error handling in libpng is done through png_error() and png_warning().
+Errors handled through png_error() are fatal, meaning that png_error()
+should never return to its caller. Currently, this is handled via
+setjmp() and longjmp() (unless you have compiled libpng with
+PNG_SETJMP_NOT_SUPPORTED, in which case it is handled via PNG_ABORT()),
+but you could change this to do things like exit() if you should wish.
+
+On non-fatal errors, png_warning() is called
+to print a warning message, and then control returns to the calling code.
+By default png_error() and png_warning() print a message on stderr via
+fprintf() unless the library is compiled with PNG_NO_CONSOLE_IO defined
+(because you don't want the messages) or PNG_NO_STDIO defined (because
+fprintf() isn't available). If you wish to change the behavior of the error
+functions, you will need to set up your own message callbacks. These
+functions are normally supplied at the time that the png_struct is created.
+It is also possible to redirect errors and warnings to your own replacement
+functions after png_create_*_struct() has been called by calling:
+
+ png_set_error_fn(png_structp png_ptr,
+ png_voidp error_ptr, png_error_ptr error_fn,
+ png_error_ptr warning_fn);
+
+ png_voidp error_ptr = png_get_error_ptr(png_ptr);
+
+If NULL is supplied for either error_fn or warning_fn, then the libpng
+default function will be used, calling fprintf() and/or longjmp() if a
+problem is encountered. The replacement error functions should have
+parameters as follows:
+
+ void user_error_fn(png_structp png_ptr,
+ png_const_charp error_msg);
+ void user_warning_fn(png_structp png_ptr,
+ png_const_charp warning_msg);
+
+The motivation behind using setjmp() and longjmp() is the C++ throw and
+catch exception handling methods. This makes the code much easier to write,
+as there is no need to check every return code of every function call.
+However, there are some uncertainties about the status of local variables
+after a longjmp, so the user may want to be careful about doing anything after
+setjmp returns non-zero besides returning itself. Consult your compiler
+documentation for more details. For an alternative approach, you may wish
+to use the "cexcept" facility (see http://cexcept.sourceforge.net).
+
+Custom chunks
+
+If you need to read or write custom chunks, you may need to get deeper
+into the libpng code. The library now has mechanisms for storing
+and writing chunks of unknown type; you can even declare callbacks
+for custom chunks. Hoewver, this may not be good enough if the
+library code itself needs to know about interactions between your
+chunk and existing `intrinsic' chunks.
+
+If you need to write a new intrinsic chunk, first read the PNG
+specification. Acquire a first level of
+understanding of how it works. Pay particular attention to the
+sections that describe chunk names, and look at how other chunks were
+designed, so you can do things similarly. Second, check out the
+sections of libpng that read and write chunks. Try to find a chunk
+that is similar to yours and use it as a template. More details can
+be found in the comments inside the code. It is best to handle unknown
+chunks in a generic method, via callback functions, instead of by
+modifying libpng functions.
+
+If you wish to write your own transformation for the data, look through
+the part of the code that does the transformations, and check out some of
+the simpler ones to get an idea of how they work. Try to find a similar
+transformation to the one you want to add and copy off of it. More details
+can be found in the comments inside the code itself.
+
+Configuring for 16 bit platforms
+
+You will want to look into zconf.h to tell zlib (and thus libpng) that
+it cannot allocate more then 64K at a time. Even if you can, the memory
+won't be accessible. So limit zlib and libpng to 64K by defining MAXSEG_64K.
+
+Configuring for DOS
+
+For DOS users who only have access to the lower 640K, you will
+have to limit zlib's memory usage via a png_set_compression_mem_level()
+call. See zlib.h or zconf.h in the zlib library for more information.
+
+Configuring for Medium Model
+
+Libpng's support for medium model has been tested on most of the popular
+compilers. Make sure MAXSEG_64K gets defined, USE_FAR_KEYWORD gets
+defined, and FAR gets defined to far in pngconf.h, and you should be
+all set. Everything in the library (except for zlib's structure) is
+expecting far data. You must use the typedefs with the p or pp on
+the end for pointers (or at least look at them and be careful). Make
+note that the rows of data are defined as png_bytepp, which is an
+unsigned char far * far *.
+
+Configuring for gui/windowing platforms:
+
+You will need to write new error and warning functions that use the GUI
+interface, as described previously, and set them to be the error and
+warning functions at the time that png_create_*_struct() is called,
+in order to have them available during the structure initialization.
+They can be changed later via png_set_error_fn(). On some compilers,
+you may also have to change the memory allocators (png_malloc, etc.).
+
+Configuring for compiler xxx:
+
+All includes for libpng are in pngconf.h. If you need to add/change/delete
+an include, this is the place to do it. The includes that are not
+needed outside libpng are protected by the PNG_INTERNAL definition,
+which is only defined for those routines inside libpng itself. The
+files in libpng proper only include png.h, which includes pngconf.h.
+
+Configuring zlib:
+
+There are special functions to configure the compression. Perhaps the
+most useful one changes the compression level, which currently uses
+input compression values in the range 0 - 9. The library normally
+uses the default compression level (Z_DEFAULT_COMPRESSION = 6). Tests
+have shown that for a large majority of images, compression values in
+the range 3-6 compress nearly as well as higher levels, and do so much
+faster. For online applications it may be desirable to have maximum speed
+(Z_BEST_SPEED = 1). With versions of zlib after v0.99, you can also
+specify no compression (Z_NO_COMPRESSION = 0), but this would create
+files larger than just storing the raw bitmap. You can specify the
+compression level by calling:
+
+ png_set_compression_level(png_ptr, level);
+
+Another useful one is to reduce the memory level used by the library.
+The memory level defaults to 8, but it can be lowered if you are
+short on memory (running DOS, for example, where you only have 640K).
+Note that the memory level does have an effect on compression; among
+other things, lower levels will result in sections of incompressible
+data being emitted in smaller stored blocks, with a correspondingly
+larger relative overhead of up to 15% in the worst case.
+
+ png_set_compression_mem_level(png_ptr, level);
+
+The other functions are for configuring zlib. They are not recommended
+for normal use and may result in writing an invalid PNG file. See
+zlib.h for more information on what these mean.
+
+ png_set_compression_strategy(png_ptr,
+ strategy);
+ png_set_compression_window_bits(png_ptr,
+ window_bits);
+ png_set_compression_method(png_ptr, method);
+ png_set_compression_buffer_size(png_ptr, size);
+
+Controlling row filtering
+
+If you want to control whether libpng uses filtering or not, which
+filters are used, and how it goes about picking row filters, you
+can call one of these functions. The selection and configuration
+of row filters can have a significant impact on the size and
+encoding speed and a somewhat lesser impact on the decoding speed
+of an image. Filtering is enabled by default for RGB and grayscale
+images (with and without alpha), but not for paletted images nor
+for any images with bit depths less than 8 bits/pixel.
+
+The 'method' parameter sets the main filtering method, which is
+currently only '0' in the PNG 1.2 specification. The 'filters'
+parameter sets which filter(s), if any, should be used for each
+scanline. Possible values are PNG_ALL_FILTERS and PNG_NO_FILTERS
+to turn filtering on and off, respectively.
+
+Individual filter types are PNG_FILTER_NONE, PNG_FILTER_SUB,
+PNG_FILTER_UP, PNG_FILTER_AVG, PNG_FILTER_PAETH, which can be bitwise
+ORed together with '|' to specify one or more filters to use.
+These filters are described in more detail in the PNG specification.
+If you intend to change the filter type during the course of writing
+the image, you should start with flags set for all of the filters
+you intend to use so that libpng can initialize its internal
+structures appropriately for all of the filter types. (Note that this
+means the first row must always be adaptively filtered, because libpng
+currently does not allocate the filter buffers until png_write_row()
+is called for the first time.)
+
+ filters = PNG_FILTER_NONE | PNG_FILTER_SUB
+ PNG_FILTER_UP | PNG_FILTER_AVE |
+ PNG_FILTER_PAETH | PNG_ALL_FILTERS;
+
+ png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE,
+ filters);
+ The second parameter can also be
+ PNG_INTRAPIXEL_DIFFERENCING if you are
+ writing a PNG to be embedded in a MNG
+ datastream. This parameter must be the
+ same as the value of filter_method used
+ in png_set_IHDR().
+
+It is also possible to influence how libpng chooses from among the
+available filters. This is done in one or both of two ways - by
+telling it how important it is to keep the same filter for successive
+rows, and by telling it the relative computational costs of the filters.
+
+ double weights[3] = {1.5, 1.3, 1.1},
+ costs[PNG_FILTER_VALUE_LAST] =
+ {1.0, 1.3, 1.3, 1.5, 1.7};
+
+ png_set_filter_heuristics(png_ptr,
+ PNG_FILTER_HEURISTIC_WEIGHTED, 3,
+ weights, costs);
+
+The weights are multiplying factors that indicate to libpng that the
+row filter should be the same for successive rows unless another row filter
+is that many times better than the previous filter. In the above example,
+if the previous 3 filters were SUB, SUB, NONE, the SUB filter could have a
+"sum of absolute differences" 1.5 x 1.3 times higher than other filters
+and still be chosen, while the NONE filter could have a sum 1.1 times
+higher than other filters and still be chosen. Unspecified weights are
+taken to be 1.0, and the specified weights should probably be declining
+like those above in order to emphasize recent filters over older filters.
+
+The filter costs specify for each filter type a relative decoding cost
+to be considered when selecting row filters. This means that filters
+with higher costs are less likely to be chosen over filters with lower
+costs, unless their "sum of absolute differences" is that much smaller.
+The costs do not necessarily reflect the exact computational speeds of
+the various filters, since this would unduly influence the final image
+size.
+
+Note that the numbers above were invented purely for this example and
+are given only to help explain the function usage. Little testing has
+been done to find optimum values for either the costs or the weights.
+
+Removing unwanted object code
+
+There are a bunch of #define's in pngconf.h that control what parts of
+libpng are compiled. All the defines end in _SUPPORTED. If you are
+never going to use a capability, you can change the #define to #undef
+before recompiling libpng and save yourself code and data space, or
+you can turn off individual capabilities with defines that begin with
+PNG_NO_.
+
+You can also turn all of the transforms and ancillary chunk capabilities
+off en masse with compiler directives that define
+PNG_NO_READ[or WRITE]_TRANSFORMS, or PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS,
+or all four,
+along with directives to turn on any of the capabilities that you do
+want. The PNG_NO_READ[or WRITE]_TRANSFORMS directives disable
+the extra transformations but still leave the library fully capable of reading
+and writing PNG files with all known public chunks
+Use of the PNG_NO_READ[or WRITE]_ANCILLARY_CHUNKS directive
+produces a library that is incapable of reading or writing ancillary chunks.
+If you are not using the progressive reading capability, you can
+turn that off with PNG_NO_PROGRESSIVE_READ (don't confuse
+this with the INTERLACING capability, which you'll still have).
+
+All the reading and writing specific code are in separate files, so the
+linker should only grab the files it needs. However, if you want to
+make sure, or if you are building a stand alone library, all the
+reading files start with pngr and all the writing files start with
+pngw. The files that don't match either (like png.c, pngtrans.c, etc.)
+are used for both reading and writing, and always need to be included.
+The progressive reader is in pngpread.c
+
+If you are creating or distributing a dynamically linked library (a .so
+or DLL file), you should not remove or disable any parts of the library,
+as this will cause applications linked with different versions of the
+library to fail if they call functions not available in your library.
+The size of the library itself should not be an issue, because only
+those sections that are actually used will be loaded into memory.
+
+Requesting debug printout
+
+The macro definition PNG_DEBUG can be used to request debugging
+printout. Set it to an integer value in the range 0 to 3. Higher
+numbers result in increasing amounts of debugging information. The
+information is printed to the "stderr" file, unless another file
+name is specified in the PNG_DEBUG_FILE macro definition.
+
+When PNG_DEBUG > 0, the following functions (macros) become available:
+
+ png_debug(level, message)
+ png_debug1(level, message, p1)
+ png_debug2(level, message, p1, p2)
+
+in which "level" is compared to PNG_DEBUG to decide whether to print
+the message, "message" is the formatted string to be printed,
+and p1 and p2 are parameters that are to be embedded in the string
+according to printf-style formatting directives. For example,
+
+ png_debug1(2, "foo=%d\n", foo);
+
+is expanded to
+
+ if(PNG_DEBUG > 2)
+ fprintf(PNG_DEBUG_FILE, "foo=%d\n", foo);
+
+When PNG_DEBUG is defined but is zero, the macros aren't defined, but you
+can still use PNG_DEBUG to control your own debugging:
+
+ #ifdef PNG_DEBUG
+ fprintf(stderr, ...
+ #endif
+
+When PNG_DEBUG = 1, the macros are defined, but only png_debug statements
+having level = 0 will be printed. There aren't any such statements in
+this version of libpng, but if you insert some they will be printed.
+
+VI. Runtime optimization
+
+A new feature in libpng 1.2.0 is the ability to dynamically switch between
+standard and optimized versions of some routines. Currently these are
+limited to three computationally intensive tasks when reading PNG files:
+decoding row filters, expanding interlacing, and combining interlaced or
+transparent row data with previous row data. Currently the optimized
+versions are available only for x86 (Intel, AMD, etc.) platforms with
+MMX support, though this may change in future versions. (For example,
+the non-MMX assembler optimizations for zlib might become similarly
+runtime-selectable in future releases, in which case libpng could be
+extended to support them. Alternatively, the compile-time choice of
+floating-point versus integer routines for gamma correction might become
+runtime-selectable.)
+
+Because such optimizations tend to be very platform- and compiler-dependent,
+both in how they are written and in how they perform, the new runtime code
+in libpng has been written to allow programs to query, enable, and disable
+either specific optimizations or all such optimizations. For example, to
+enable all possible optimizations (bearing in mind that some "optimizations"
+may actually run more slowly in rare cases):
+
+ #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
+ png_uint_32 mask, flags;
+
+ flags = png_get_asm_flags(png_ptr);
+ mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE);
+ png_set_asm_flags(png_ptr, flags | mask);
+ #endif
+
+To enable only optimizations relevant to reading PNGs, use PNG_SELECT_READ
+by itself when calling png_get_asm_flagmask(); similarly for optimizing
+only writing. To disable all optimizations:
+
+ #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
+ flags = png_get_asm_flags(png_ptr);
+ mask = png_get_asm_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE);
+ png_set_asm_flags(png_ptr, flags & ~mask);
+ #endif
+
+To enable or disable only MMX-related features, use png_get_mmx_flagmask()
+in place of png_get_asm_flagmask(). The mmx version takes one additional
+parameter:
+
+ #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
+ int selection = PNG_SELECT_READ | PNG_SELECT_WRITE;
+ int compilerID;
+
+ mask = png_get_mmx_flagmask(selection, &compilerID);
+ #endif
+
+On return, compilerID will indicate which version of the MMX assembler
+optimizations was compiled. Currently two flavors exist: Microsoft
+Visual C++ (compilerID == 1) and GNU C (a.k.a. gcc/gas, compilerID == 2).
+On non-x86 platforms or on systems compiled without MMX optimizations, a
+value of -1 is used.
+
+Note that both png_get_asm_flagmask() and png_get_mmx_flagmask() return
+all valid, settable optimization bits for the version of the library that's
+currently in use. In the case of shared (dynamically linked) libraries,
+this may include optimizations that did not exist at the time the code was
+written and compiled. It is also possible, of course, to enable only known,
+specific optimizations; for example:
+
+ #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
+ flags = PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
+ | PNG_ASM_FLAG_MMX_READ_INTERLACE \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_UP \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ;
+ png_set_asm_flags(png_ptr, flags);
+ #endif
+
+This method would enable only the MMX read-optimizations available at the
+time of libpng 1.2.0's release, regardless of whether a later version of
+the DLL were actually being used. (Also note that these functions did not
+exist in versions older than 1.2.0, so any attempt to run a dynamically
+linked app on such an older version would fail.)
+
+To determine whether the processor supports MMX instructions at all, use
+the png_mmx_support() function:
+
+ #if defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200)
+ mmxsupport = png_mmx_support();
+ #endif
+
+It returns -1 if MMX support is not compiled into libpng, 0 if MMX code
+is compiled but MMX is not supported by the processor, or 1 if MMX support
+is fully available. Note that png_mmx_support(), png_get_mmx_flagmask(),
+and png_get_asm_flagmask() all may be called without allocating and ini-
+tializing any PNG structures (for example, as part of a usage screen or
+"about" box).
+
+The following code can be used to prevent an application from using the
+thread_unsafe features, even if libpng was built with PNG_THREAD_UNSAFE_OK
+defined:
+
+#if defined(PNG_USE_PNGGCCRD) && defined(PNG_ASSEMBLER_CODE_SUPPORTED) \
+ && defined(PNG_THREAD_UNSAFE_OK)
+ /* Disable thread-unsafe features of pnggccrd */
+ if (png_access_version() >= 10200)
+ {
+ png_uint_32 mmx_disable_mask = 0;
+ png_uint_32 asm_flags;
+
+ mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH );
+ asm_flags = png_get_asm_flags(png_ptr);
+ png_set_asm_flags(png_ptr, asm_flags & ~mmx_disable_mask);
+ }
+#endif
+
+For more extensive examples of runtime querying, enabling and disabling
+of optimized features, see contrib/gregbook/readpng2.c in the libpng
+source-code distribution.
+
+VII. MNG support
+
+The MNG specification (available at http://www.libpng.org/pub/mng) allows
+certain extensions to PNG for PNG images that are embedded in MNG datastreams.
+Libpng can support some of these extensions. To enable them, use the
+png_permit_mng_features() function:
+
+ feature_set = png_permit_mng_features(png_ptr, mask)
+ mask is a png_uint_32 containing the logical OR of the
+ features you want to enable. These include
+ PNG_FLAG_MNG_EMPTY_PLTE
+ PNG_FLAG_MNG_FILTER_64
+ PNG_ALL_MNG_FEATURES
+ feature_set is a png_uint_32 that is the logical AND of
+ your mask with the set of MNG features that is
+ supported by the version of libpng that you are using.
+
+It is an error to use this function when reading or writing a standalone
+PNG file with the PNG 8-byte signature. The PNG datastream must be wrapped
+in a MNG datastream. As a minimum, it must have the MNG 8-byte signature
+and the MHDR and MEND chunks. Libpng does not provide support for these
+or any other MNG chunks; your application must provide its own support for
+them. You may wish to consider using libmng (available at
+http://www.libmng.com) instead.
+
+VIII. Changes to Libpng from version 0.88
+
+It should be noted that versions of libpng later than 0.96 are not
+distributed by the original libpng author, Guy Schalnat, nor by
+Andreas Dilger, who had taken over from Guy during 1996 and 1997, and
+distributed versions 0.89 through 0.96, but rather by another member
+of the original PNG Group, Glenn Randers-Pehrson. Guy and Andreas are
+still alive and well, but they have moved on to other things.
+
+The old libpng functions png_read_init(), png_write_init(),
+png_info_init(), png_read_destroy(), and png_write_destroy() have been
+moved to PNG_INTERNAL in version 0.95 to discourage their use. These
+functions will be removed from libpng version 2.0.0.
+
+The preferred method of creating and initializing the libpng structures is
+via the png_create_read_struct(), png_create_write_struct(), and
+png_create_info_struct() because they isolate the size of the structures
+from the application, allow version error checking, and also allow the
+use of custom error handling routines during the initialization, which
+the old functions do not. The functions png_read_destroy() and
+png_write_destroy() do not actually free the memory that libpng
+allocated for these structs, but just reset the data structures, so they
+can be used instead of png_destroy_read_struct() and
+png_destroy_write_struct() if you feel there is too much system overhead
+allocating and freeing the png_struct for each image read.
+
+Setting the error callbacks via png_set_message_fn() before
+png_read_init() as was suggested in libpng-0.88 is no longer supported
+because this caused applications that do not use custom error functions
+to fail if the png_ptr was not initialized to zero. It is still possible
+to set the error callbacks AFTER png_read_init(), or to change them with
+png_set_error_fn(), which is essentially the same function, but with a new
+name to force compilation errors with applications that try to use the old
+method.
+
+Starting with version 1.0.7, you can find out which version of the library
+you are using at run-time:
+
+ png_uint_32 libpng_vn = png_access_version_number();
+
+The number libpng_vn is constructed from the major version, minor
+version with leading zero, and release number with leading zero,
+(e.g., libpng_vn for version 1.0.7 is 10007).
+
+You can also check which version of png.h you used when compiling your
+application:
+
+ png_uint_32 application_vn = PNG_LIBPNG_VER;
+
+IX. Y2K Compliance in libpng
+
+December 3, 2004
+
+Since the PNG Development group is an ad-hoc body, we can't make
+an official declaration.
+
+This is your unofficial assurance that libpng from version 0.71 and
+upward through 1.2.8 are Y2K compliant. It is my belief that earlier
+versions were also Y2K compliant.
+
+Libpng only has three year fields. One is a 2-byte unsigned integer that
+will hold years up to 65535. The other two hold the date in text
+format, and will hold years up to 9999.
+
+The integer is
+ "png_uint_16 year" in png_time_struct.
+
+The strings are
+ "png_charp time_buffer" in png_struct and
+ "near_time_buffer", which is a local character string in png.c.
+
+There are seven time-related functions:
+
+ png_convert_to_rfc_1123() in png.c
+ (formerly png_convert_to_rfc_1152() in error)
+ png_convert_from_struct_tm() in pngwrite.c, called
+ in pngwrite.c
+ png_convert_from_time_t() in pngwrite.c
+ png_get_tIME() in pngget.c
+ png_handle_tIME() in pngrutil.c, called in pngread.c
+ png_set_tIME() in pngset.c
+ png_write_tIME() in pngwutil.c, called in pngwrite.c
+
+All appear to handle dates properly in a Y2K environment. The
+png_convert_from_time_t() function calls gmtime() to convert from system
+clock time, which returns (year - 1900), which we properly convert to
+the full 4-digit year. There is a possibility that applications using
+libpng are not passing 4-digit years into the png_convert_to_rfc_1123()
+function, or that they are incorrectly passing only a 2-digit year
+instead of "year - 1900" into the png_convert_from_struct_tm() function,
+but this is not under our control. The libpng documentation has always
+stated that it works with 4-digit years, and the APIs have been
+documented as such.
+
+The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned
+integer to hold the year, and can hold years as large as 65535.
+
+zlib, upon which libpng depends, is also Y2K compliant. It contains
+no date-related code.
+
+
+ Glenn Randers-Pehrson
+ libpng maintainer
+ PNG Development Group
diff --git a/com32/lib/lmalloc.c b/com32/lib/lmalloc.c
index a646556c..3e69ac1d 100644
--- a/com32/lib/lmalloc.c
+++ b/com32/lib/lmalloc.c
@@ -31,19 +31,10 @@
#include <string.h>
#include <syslinux/pmapi.h>
-void *lmalloc(size_t size)
-{
- void *p;
- p = __com32.cs_pm->lmalloc(size);
- if (!p)
- errno = ENOMEM;
- return p;
-}
-
void *lzalloc(size_t size)
{
void *p;
- p = __com32.cs_pm->lmalloc(size);
+ p = lmalloc(size);
if (!p)
errno = ENOMEM;
else
@@ -53,5 +44,5 @@ void *lzalloc(size_t size)
void lfree(void *ptr)
{
- __com32.cs_pm->lfree(ptr);
+ free(ptr);
}
diff --git a/com32/lib/makeerrlist.pl b/com32/lib/makeerrlist.pl
new file mode 100644
index 00000000..9243b9dd
--- /dev/null
+++ b/com32/lib/makeerrlist.pl
@@ -0,0 +1,98 @@
+#!/usr/bin/perl
+#
+# This creates sys_errlist from <asm/errno.h> through somewhat
+# heuristic matching. It presumes the relevant entries are of the form
+# #define Exxxx <integer> /* comment */
+#
+
+use FileHandle;
+
+%errors = ();
+%errmsg = ();
+$maxerr = -1;
+@includelist = (); # Include directories
+
+sub parse_file($) {
+ my($file) = @_;
+ my($fh) = new FileHandle;
+ my($line, $error, $msg);
+ my($kernelonly) = 0;
+ my($root);
+
+ print STDERR "opening $file\n" unless ( $quiet );
+
+ $ok = 0;
+ foreach $root ( @includelist ) {
+ if ( $fh->open($root.'//'.$file, '<') ) {
+ $ok = 1;
+ last;
+ }
+ }
+
+ if ( ! $ok ) {
+ die "$0: Cannot find file $file\n";
+ }
+
+ while ( defined($line = <$fh>) ) {
+ if ( $kernelonly ) {
+ if ( $line =~ /^\#\s*endif/ ) {
+ $kernelonly--;
+ } elsif ( $line =~ /^\#\sif/ ) {
+ $kernelonly++;
+ }
+ } else {
+ if ( $line =~ /^\#\s*define\s+([A-Z0-9_]+)\s+([0-9]+)\s*\/\*\s*(.*\S)\s*\*\// ) {
+ $error = $1;
+ $errno = $2+0;
+ $msg = $3;
+ print STDERR "$error ($errno) => \"$msg\"\n" unless ( $quiet );
+ $errors{$errno} = $error;
+ $errmsg{$errno} = $msg;
+ $maxerr = $errno if ( $errno > $maxerr );
+ } elsif ( $line =~ /^\#\s*include\s+[\<\"](.*)[\>\"]/ ) {
+ parse_file($1);
+ } elsif ( $line =~ /^\#\s*ifdef\s+__KERNEL__/ ) {
+ $kernelonly++;
+ }
+ }
+ }
+ close($fh);
+ print STDERR "closing $file\n" unless ( $quiet );
+}
+
+$v = $ENV{'KBUILD_VERBOSE'};
+$quiet = defined($v) ? !$v : 0;
+
+foreach $arg ( @ARGV ) {
+ if ( $arg eq '-q' ) {
+ $quiet = 1;
+ } elsif ( $arg =~ /^-(errlist|errnos|maxerr)$/ ) {
+ $type = $arg;
+ } elsif ( $arg =~ '^\-I' ) {
+ push(@includelist, "$'");
+ } else {
+ # Ignore
+ }
+}
+
+parse_file('errno.h');
+
+if ( $type eq '-errlist' ) {
+ print "#include <errno.h>\n";
+ printf "const int sys_nerr = %d;\n", $maxerr+1;
+ printf "const char * const sys_errlist[%d] = {\n", $maxerr+1;
+ foreach $e ( sort(keys(%errors)) ) {
+ printf " [%s] = \"%s\",\n", $errors{$e}, $errmsg{$e};
+ }
+ print "};\n";
+} elsif ( $type eq '-errnos' ) {
+ print "#include <errno.h>\n";
+ printf "const int sys_nerr = %d;\n", $maxerr+1;
+ printf "const char * const sys_errlist[%d] = {\n", $maxerr+1;
+ foreach $e ( sort(keys(%errors)) ) {
+ printf " [%s] = \"%s\",\n", $errors{$e}, $errors{$e};
+ }
+ print "};\n";
+} elsif ( $type eq '-maxerr' ) {
+ print $maxerr, "\n";
+}
diff --git a/com32/lib/malloc.c b/com32/lib/malloc.c
deleted file mode 100644
index ec103ab3..00000000
--- a/com32/lib/malloc.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * malloc.c
- *
- * Very simple linked-list based malloc()/free().
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <com32.h>
-#include <syslinux/memscan.h>
-#include "init.h"
-#include "malloc.h"
-
-struct free_arena_header __malloc_head = {
- {
- ARENA_TYPE_HEAD,
- 0,
- &__malloc_head,
- &__malloc_head,
- },
- &__malloc_head,
- &__malloc_head
-};
-
-/* This is extern so it can be overridden by the user application */
-extern size_t __stack_size;
-extern void *__mem_end; /* Produced after argv parsing */
-
-static inline size_t sp(void)
-{
- size_t sp;
- asm volatile ("movl %%esp,%0":"=rm" (sp));
- return sp;
-}
-
-#define E820_MEM_MAX 0xfff00000 /* 4 GB - 1 MB */
-
-static int consider_memory_area(void *dummy, addr_t start,
- addr_t len, bool valid)
-{
- struct free_arena_header *fp;
- addr_t end;
-
- (void)dummy;
-
- if (valid && start < E820_MEM_MAX) {
- if (len > E820_MEM_MAX - start)
- len = E820_MEM_MAX - start;
-
- end = start + len;
-
- if (end > __com32.cs_memsize) {
- if (start <= __com32.cs_memsize) {
- start = __com32.cs_memsize;
- len = end - start;
- }
-
- if (len >= 2 * sizeof(struct arena_header)) {
- fp = (struct free_arena_header *)start;
- fp->a.size = len;
- __inject_free_block(fp);
- }
- }
- }
-
- return 0;
-}
-
-static void __constructor init_memory_arena(void)
-{
- struct free_arena_header *fp;
- size_t start, total_space;
-
- start = (size_t) ARENA_ALIGN_UP(__mem_end);
- total_space = sp() - start;
-
- if (__stack_size == 0 || __stack_size > total_space >> 1)
- __stack_size = total_space >> 1; /* Half for the stack, half for the heap... */
-
- if (total_space < __stack_size + 4 * sizeof(struct arena_header))
- __stack_size = total_space - 4 * sizeof(struct arena_header);
-
- fp = (struct free_arena_header *)start;
- fp->a.size = total_space - __stack_size;
-
- __inject_free_block(fp);
-
- /* Scan the memory map to look for other suitable regions */
- if (!__com32.cs_memsize)
- return; /* Old Syslinux core, can't do this... */
-
- syslinux_scan_memory(consider_memory_area, NULL);
-}
-
-static void *__malloc_from_block(struct free_arena_header *fp, size_t size)
-{
- size_t fsize;
- struct free_arena_header *nfp, *na;
-
- fsize = fp->a.size;
-
- /* We need the 2* to account for the larger requirements of a free block */
- if (fsize >= size + 2 * sizeof(struct arena_header)) {
- /* Bigger block than required -- split block */
- nfp = (struct free_arena_header *)((char *)fp + size);
- na = fp->a.next;
-
- nfp->a.type = ARENA_TYPE_FREE;
- nfp->a.size = fsize - size;
- fp->a.type = ARENA_TYPE_USED;
- fp->a.size = size;
-
- /* Insert into all-block chain */
- nfp->a.prev = fp;
- nfp->a.next = na;
- na->a.prev = nfp;
- fp->a.next = nfp;
-
- /* Replace current block on free chain */
- nfp->next_free = fp->next_free;
- nfp->prev_free = fp->prev_free;
- fp->next_free->prev_free = nfp;
- fp->prev_free->next_free = nfp;
- } else {
- /* Allocate the whole block */
- fp->a.type = ARENA_TYPE_USED;
-
- /* Remove from free chain */
- fp->next_free->prev_free = fp->prev_free;
- fp->prev_free->next_free = fp->next_free;
- }
-
- return (void *)(&fp->a + 1);
-}
-
-void *malloc(size_t size)
-{
- struct free_arena_header *fp;
-
- if (size == 0)
- return NULL;
-
- /* Add the obligatory arena header, and round up */
- size = (size + 2 * sizeof(struct arena_header) - 1) & ARENA_SIZE_MASK;
-
- for (fp = __malloc_head.next_free; fp->a.type != ARENA_TYPE_HEAD;
- fp = fp->next_free) {
- if (fp->a.size >= size) {
- /* Found fit -- allocate out of this block */
- return __malloc_from_block(fp, size);
- }
- }
-
- /* Nothing found... need to request a block from the kernel */
- return NULL; /* No kernel to get stuff from */
-}
diff --git a/com32/lib/onexit.c b/com32/lib/onexit.c
index d409e82e..272f8f1c 100644
--- a/com32/lib/onexit.c
+++ b/com32/lib/onexit.c
@@ -6,7 +6,6 @@
#include <unistd.h>
#include "atexit.h"
-extern __noreturn(*__exit_handler) (int);
static struct atexit *__atexit_list;
static __noreturn on_exit_exit(int rv)
@@ -33,7 +32,5 @@ int on_exit(void (*fctn) (int, void *), void *arg)
as->next = __atexit_list;
__atexit_list = as;
- __exit_handler = on_exit_exit;
-
return 0;
}
diff --git a/com32/lib/realloc.c b/com32/lib/realloc.c
deleted file mode 100644
index 2969e313..00000000
--- a/com32/lib/realloc.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * realloc.c
- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <minmax.h>
-
-#include "malloc.h"
-
-void *realloc(void *ptr, size_t size)
-{
- struct free_arena_header *ah, *nah;
- void *newptr;
- size_t newsize, oldsize, xsize;
-
- if (!ptr)
- return malloc(size);
-
- if (size == 0) {
- free(ptr);
- return NULL;
- }
-
- ah = (struct free_arena_header *)
- ((struct arena_header *)ptr - 1);
-
- /* Actual size of the old block */
- oldsize = ah->a.size;
-
- /* Add the obligatory arena header, and round up */
- newsize = (size + 2 * sizeof(struct arena_header) - 1) & ARENA_SIZE_MASK;
-
- if (oldsize >= newsize && newsize >= (oldsize >> 2) &&
- oldsize - newsize < 4096) {
- /* This allocation is close enough already. */
- return ptr;
- } else {
- xsize = oldsize;
-
- nah = ah->a.next;
- if ((char *)nah == (char *)ah + ah->a.size &&
- nah->a.type == ARENA_TYPE_FREE &&
- oldsize + nah->a.size >= newsize) {
- /* Merge in subsequent free block */
- ah->a.next = nah->a.next;
- ah->a.next->a.prev = ah;
- nah->next_free->prev_free = nah->prev_free;
- nah->prev_free->next_free = nah->next_free;
- xsize = (ah->a.size += nah->a.size);
- }
-
- if (xsize >= newsize) {
- /* We can reallocate in place */
- if (xsize >= newsize + 2 * sizeof(struct arena_header)) {
- /* Residual free block at end */
- nah = (struct free_arena_header *)((char *)ah + newsize);
- nah->a.type = ARENA_TYPE_FREE;
- nah->a.size = xsize - newsize;
- ah->a.size = newsize;
-
- /* Insert into block list */
- nah->a.next = ah->a.next;
- ah->a.next = nah;
- nah->a.next->a.prev = nah;
- nah->a.prev = ah;
-
- /* Insert into free list */
- if (newsize > oldsize) {
- /* Hack: this free block is in the path of a memory object
- which has already been grown at least once. As such, put
- it at the *end* of the freelist instead of the beginning;
- trying to save it for future realloc()s of the same block. */
- nah->prev_free = __malloc_head.prev_free;
- nah->next_free = &__malloc_head;
- __malloc_head.prev_free = nah;
- nah->prev_free->next_free = nah;
- } else {
- nah->next_free = __malloc_head.next_free;
- nah->prev_free = &__malloc_head;
- __malloc_head.next_free = nah;
- nah->next_free->prev_free = nah;
- }
- }
- /* otherwise, use up the whole block */
- return ptr;
- } else {
- /* Last resort: need to allocate a new block and copy */
- oldsize -= sizeof(struct arena_header);
- newptr = malloc(size);
- if (newptr) {
- memcpy(newptr, ptr, min(size, oldsize));
- free(ptr);
- }
- return newptr;
- }
- }
-}
diff --git a/com32/lib/strerror.c b/com32/lib/strerror.c
index 8dbe74ad..1b3d4452 100644
--- a/com32/lib/strerror.c
+++ b/com32/lib/strerror.c
@@ -6,18 +6,26 @@
char *strerror(int errnum)
{
- static char message[32] = "error "; /* enough for error 2^63-1 */
+ static char message[32] = "error "; /* enough for error 2^63-1 */
+ char numbuf[32];
+ char *p;
+ unsigned int e = (unsigned int)errnum;
- char numbuf[32];
- char *p;
+ extern const int sys_nerr;
+ extern const char *const sys_errlist[];
- p = numbuf + sizeof numbuf;
- *--p = '\0';
+ if (e < (unsigned int)sys_nerr && sys_errlist[e])
+ return (char *)sys_errlist[e];
- do {
- *--p = (errnum % 10) + '0';
- errnum /= 10;
- } while (errnum);
+ p = numbuf + sizeof numbuf;
+ *--p = '\0';
- return (char *)memcpy(message + 6, p, (numbuf + sizeof numbuf) - p);
+ do {
+ *--p = (e % 10) + '0';
+ e /= 10;
+ } while (e);
+
+ memcpy(message + 6, p, (numbuf + sizeof numbuf) - p);
+
+ return message;
}
diff --git a/com32/lib/sys/ansicon_write.c b/com32/lib/sys/ansicon_write.c
index b25f2d2e..e5483fbc 100644
--- a/com32/lib/sys/ansicon_write.c
+++ b/com32/lib/sys/ansicon_write.c
@@ -42,6 +42,7 @@
#include <syslinux/config.h>
#include "file.h"
#include "ansi.h"
+#include "graphics.h"
static void ansicon_erase(const struct term_state *, int, int, int, int);
static void ansicon_write_char(int, int, uint8_t, const struct term_state *);
@@ -90,8 +91,7 @@ int __ansicon_open(struct file_info *fp)
ti.cols = 80;
} else {
/* Force text mode */
- ireg.eax.w[0] = 0x0005;
- __intcall(0x22, &ireg, NULL);
+ syslinux_force_text_mode();
/* Initial state */
ti.rows = BIOS_ROWS ? BIOS_ROWS + 1 : 25;
diff --git a/com32/lib/sys/exit.S b/com32/lib/sys/exit.S
deleted file mode 100644
index 2ab80122..00000000
--- a/com32/lib/sys/exit.S
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Implementation of _exit() for com32 based on c32entry.S
- */
- .text
-
- .globl _Exit
- .type _Exit, @function
-_Exit:
- /* Just fall through to _exit */
- .size _Exit, .-_Exit
-
- .globl _exit
- .type _exit, @function
-_exit:
-#ifdef REGPARM
- pushl %eax
-#endif
-
- /* Run any destructors */
- movl $__dtors_start, %esi
-2:
- cmpl $__dtors_end, %esi
- jae 1f
- call *(%esi)
- addl $4,%esi
- jmp 2b
-
-1:
-#ifdef REGPARM
- popl %eax
-#else
- movl 4(%esp),%eax # Exit code in %eax = return value
-#endif
- movl (__entry_esp),%esp # Return stack pointer to entry value
- ret # Return to termination address
- .size _exit, .-_exit
-
- .data
-__exit_handler:
- .globl __exit_handler
- .long _exit
diff --git a/com32/lib/sys/file.h b/com32/lib/sys/file.h
index e984f160..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 {
@@ -98,6 +98,7 @@ struct file_info {
};
extern struct file_info __file_info[NFILES];
+extern const struct input_dev __file_dev;
/* Line input discipline */
ssize_t __line_input(struct file_info *fp, char *buf, size_t bufsize,
diff --git a/com32/lib/sys/fileclose.c b/com32/lib/sys/fileclose.c
index e2c929f2..699dbe32 100644
--- a/com32/lib/sys/fileclose.c
+++ b/com32/lib/sys/fileclose.c
@@ -34,12 +34,13 @@
#include <errno.h>
#include <com32.h>
#include <string.h>
+#include <fs.h>
#include "file.h"
int __file_close(struct file_info *fp)
{
if (fp->i.fd.handle)
- __com32.cs_pm->close_file(fp->i.fd.handle);
+ close_file(fp->i.fd.handle);
return 0;
}
diff --git a/com32/lib/sys/fileread.c b/com32/lib/sys/fileread.c
index aab99c80..26b0ceb6 100644
--- a/com32/lib/sys/fileread.c
+++ b/com32/lib/sys/fileread.c
@@ -34,6 +34,7 @@
#include <errno.h>
#include <string.h>
#include <com32.h>
+#include <pmapi.h>
#include <syslinux/pmapi.h>
#include <minmax.h>
#include "file.h"
@@ -42,7 +43,7 @@ int __file_get_block(struct file_info *fp)
{
ssize_t bytes_read;
- bytes_read = __com32.cs_pm->read_file(&fp->i.fd.handle, fp->i.buf,
+ bytes_read = pmapi_read_file(&fp->i.fd.handle, fp->i.buf,
MAXBLOCK >> fp->i.fd.blocklg2);
if (!bytes_read) {
errno = EIO;
@@ -67,7 +68,7 @@ ssize_t __file_read(struct file_info * fp, void *buf, size_t count)
if (count > MAXBLOCK) {
/* Large transfer: copy directly, without buffering */
- ncopy = __com32.cs_pm->read_file(&fp->i.fd.handle, bufp,
+ ncopy = pmapi_read_file(&fp->i.fd.handle, bufp,
count >> fp->i.fd.blocklg2);
if (!ncopy) {
errno = EIO;
diff --git a/com32/lib/sys/gpxe.c b/com32/lib/sys/gpxe.c
index d86da42a..3cc2b845 100644
--- a/com32/lib/sys/gpxe.c
+++ b/com32/lib/sys/gpxe.c
@@ -1,13 +1,15 @@
+#include <string.h>
+
#include <sys/gpxe.h>
#include <syslinux/config.h>
-#include <string.h>
+#include <syslinux/pxe_api.h>
bool is_gpxe(void)
{
const struct syslinux_version *sv;
- com32sys_t reg;
struct s_PXENV_FILE_CHECK_API *fca;
bool gpxe;
+ int err;
sv = syslinux_version();
if (sv->filesystem != SYSLINUX_FS_PXELINUX)
@@ -16,23 +18,18 @@ bool is_gpxe(void)
fca = lzalloc(sizeof *fca);
if (!fca)
return false;
+
fca->Size = sizeof *fca;
fca->Magic = 0x91d447b2;
- memset(&reg, 0, sizeof reg);
- reg.eax.w[0] = 0x0009;
- reg.ebx.w[0] = 0x00e6; /* PXENV_FILE_API_CHECK */
- /* reg.edi.w[0] = OFFS(fca); */
- reg.es = SEG(fca);
-
- __intcall(0x22, &reg, &reg);
+ err = pxe_call(PXENV_FILE_API_CHECK, fca);
gpxe = true;
- if (reg.eflags.l & EFLAGS_CF)
+ if (err)
gpxe = false; /* Cannot invoke PXE stack */
- if (reg.eax.w[0] || fca->Status)
+ if (fca->Status)
gpxe = false; /* PXE failure */
if (fca->Magic != 0xe9c17b20)
diff --git a/com32/lib/sys/module/common.c b/com32/lib/sys/module/common.c
new file mode 100644
index 00000000..b763704e
--- /dev/null
+++ b/com32/lib/sys/module/common.c
@@ -0,0 +1,599 @@
+/*
+ * common.c
+ *
+ * Created on: Aug 11, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+#include <stdio.h>
+#include <elf.h>
+#include <string.h>
+#include <fs.h>
+
+#include <linux/list.h>
+#include <sys/module.h>
+
+#include "elfutils.h"
+#include "common.h"
+
+/**
+ * The one and only list of loaded modules
+ */
+LIST_HEAD(modules_head);
+
+// User-space debugging routines
+#ifdef ELF_DEBUG
+void print_elf_ehdr(Elf32_Ehdr *ehdr) {
+ int i;
+
+ fprintf(stderr, "Identification:\t");
+ for (i=0; i < EI_NIDENT; i++) {
+ printf("%d ", ehdr->e_ident[i]);
+ }
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Type:\t\t%u\n", ehdr->e_type);
+ fprintf(stderr, "Machine:\t%u\n", ehdr->e_machine);
+ fprintf(stderr, "Version:\t%u\n", ehdr->e_version);
+ fprintf(stderr, "Entry:\t\t0x%08x\n", ehdr->e_entry);
+ fprintf(stderr, "PHT Offset:\t0x%08x\n", ehdr->e_phoff);
+ fprintf(stderr, "SHT Offset:\t0x%08x\n", ehdr->e_shoff);
+ //fprintf(stderr, "Flags:\t\t%u\n", ehdr->e_flags);
+ //fprintf(stderr, "Header size:\t%u (Structure size: %u)\n", ehdr->e_ehsize,sizeof(Elf32_Ehdr));
+ fprintf(stderr, "phnum: %d shnum: %d\n", ehdr->e_phnum,
+ ehdr->e_shnum);
+}
+
+void print_elf_symbols(struct elf_module *module) {
+ unsigned int i;
+ Elf32_Sym *crt_sym;
+
+ for (i = 1; i < module->symtable_size/module->syment_size; i++)
+ {
+ crt_sym = (Elf32_Sym*)(module->sym_table + i*module->syment_size);
+
+ fprintf(stderr,"%s %d\n", module->str_table + crt_sym->st_name, crt_sym->st_value);
+
+ }
+}
+#endif //ELF_DEBUG
+
+FILE *findpath(char *name)
+{
+ struct path_entry *entry;
+ char path[FILENAME_MAX];
+ FILE *f;
+
+ f = fopen(name, "rb"); /* for full path */
+ if (f)
+ return f;
+
+ list_for_each_entry(entry, &PATH, list) {
+ bool slash = false;
+
+ /* Ensure we have a '/' separator */
+ if (entry->str[strlen(entry->str) - 1] != '/')
+ slash = true;
+
+ snprintf(path, sizeof(path), "%s%s%s",
+ entry->str, slash ? "/" : "", name);
+
+ f = fopen(path, "rb");
+ if (f)
+ return f;
+ }
+
+ return NULL;
+}
+
+/*
+ * Image files manipulation routines
+ */
+
+int image_load(struct elf_module *module)
+{
+ module->u.l._file = findpath(module->name);
+
+ if (module->u.l._file == NULL) {
+ DBG_PRINT("Could not open object file '%s'\n", module->name);
+ goto error;
+ }
+
+ module->u.l._cr_offset = 0;
+
+ return 0;
+
+error:
+ if (module->u.l._file != NULL) {
+ fclose(module->u.l._file);
+ module->u.l._file = NULL;
+ }
+
+ return -1;
+}
+
+
+int image_unload(struct elf_module *module) {
+ if (module->u.l._file != NULL) {
+ fclose(module->u.l._file);
+ module->u.l._file = NULL;
+
+ }
+ module->u.l._cr_offset = 0;
+
+ return 0;
+}
+
+int image_read(void *buff, size_t size, struct elf_module *module) {
+ size_t result = fread(buff, size, 1, module->u.l._file);
+
+ if (result < 1)
+ return -1;
+
+ module->u.l._cr_offset += size;
+ return 0;
+}
+
+int image_skip(size_t size, struct elf_module *module) {
+ void *skip_buff = NULL;
+ size_t result;
+
+ if (size == 0)
+ return 0;
+
+ skip_buff = malloc(size);
+ result = fread(skip_buff, size, 1, module->u.l._file);
+ free(skip_buff);
+
+ if (result < 1)
+ return -1;
+
+ module->u.l._cr_offset += size;
+ return 0;
+}
+
+int image_seek(Elf32_Off offset, struct elf_module *module) {
+ if (offset < module->u.l._cr_offset) // Cannot seek backwards
+ return -1;
+
+ return image_skip(offset - module->u.l._cr_offset, module);
+}
+
+
+// Initialization of the module subsystem
+int modules_init(void) {
+ return 0;
+}
+
+// Termination of the module subsystem
+void modules_term(void) {
+
+}
+
+// Allocates the structure for a new module
+struct elf_module *module_alloc(const char *name) {
+ struct elf_module *result = malloc(sizeof(struct elf_module));
+
+ if (!result) {
+ dprintf("module: Failed to alloc elf_module\n");
+ return NULL;
+ }
+
+ memset(result, 0, sizeof(struct elf_module));
+
+ INIT_LIST_HEAD(&result->list);
+ INIT_LIST_HEAD(&result->required);
+ INIT_LIST_HEAD(&result->dependants);
+
+ strncpy(result->name, name, MODULE_NAME_SIZE);
+
+ return result;
+}
+
+struct module_dep *module_dep_alloc(struct elf_module *module) {
+ struct module_dep *result = malloc(sizeof(struct module_dep));
+
+ INIT_LIST_HEAD (&result->list);
+
+ result->module = module;
+
+ return result;
+}
+
+struct elf_module *module_find(const char *name) {
+ struct elf_module *cr_module;
+
+ for_each_module(cr_module) {
+ if (strcmp(cr_module->name, name) == 0)
+ return cr_module;
+ }
+
+ return NULL;
+}
+
+
+// Performs verifications on ELF header to assure that the open file is a
+// valid SYSLINUX ELF module.
+int check_header_common(Elf32_Ehdr *elf_hdr) {
+ // Check the header magic
+ if (elf_hdr->e_ident[EI_MAG0] != ELFMAG0 ||
+ elf_hdr->e_ident[EI_MAG1] != ELFMAG1 ||
+ elf_hdr->e_ident[EI_MAG2] != ELFMAG2 ||
+ elf_hdr->e_ident[EI_MAG3] != ELFMAG3) {
+
+ DBG_PRINT("The file is not an ELF object\n");
+ return -1;
+ }
+
+ if (elf_hdr->e_ident[EI_CLASS] != MODULE_ELF_CLASS) {
+ DBG_PRINT("Invalid ELF class code\n");
+ return -1;
+ }
+
+ if (elf_hdr->e_ident[EI_DATA] != MODULE_ELF_DATA) {
+ DBG_PRINT("Invalid ELF data encoding\n");
+ return -1;
+ }
+
+ if (elf_hdr->e_ident[EI_VERSION] != MODULE_ELF_VERSION ||
+ elf_hdr->e_version != MODULE_ELF_VERSION) {
+ DBG_PRINT("Invalid ELF file version\n");
+ return -1;
+ }
+
+ if (elf_hdr->e_machine != MODULE_ELF_MACHINE) {
+ DBG_PRINT("Invalid ELF architecture\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int enforce_dependency(struct elf_module *req, struct elf_module *dep) {
+ struct module_dep *crt_dep;
+ struct module_dep *new_dep;
+
+ list_for_each_entry(crt_dep, &req->dependants, list) {
+ if (crt_dep->module == dep) {
+ // The dependency is already enforced
+ return 0;
+ }
+ }
+
+ new_dep = module_dep_alloc(req);
+ list_add(&new_dep->list, &dep->required);
+
+ new_dep = module_dep_alloc(dep);
+ list_add(&new_dep->list, &req->dependants);
+
+ return 0;
+}
+
+int clear_dependency(struct elf_module *req, struct elf_module *dep) {
+ struct module_dep *crt_dep = NULL;
+ int found = 0;
+
+ list_for_each_entry(crt_dep, &req->dependants, list) {
+ if (crt_dep->module == dep) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (found) {
+ list_del(&crt_dep->list);
+ free(crt_dep);
+ }
+
+ found = 0;
+
+ list_for_each_entry(crt_dep, &dep->required, list) {
+ if (crt_dep->module == req) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (found) {
+ list_del(&crt_dep->list);
+ free(crt_dep);
+ }
+
+ return 0;
+}
+
+int check_symbols(struct elf_module *module)
+{
+ unsigned int i;
+ Elf32_Sym *crt_sym = NULL, *ref_sym = NULL;
+ char *crt_name;
+ struct elf_module *crt_module;
+
+ int strong_count;
+ int weak_count;
+
+ for (i = 1; i < module->symtable_size/module->syment_size; i++)
+ {
+ crt_sym = symbol_get_entry(module, i);
+ crt_name = module->str_table + crt_sym->st_name;
+
+ strong_count = 0;
+ weak_count = (ELF32_ST_BIND(crt_sym->st_info) == STB_WEAK);
+
+ for_each_module(crt_module)
+ {
+ ref_sym = module_find_symbol(crt_name, crt_module);
+
+ // If we found a definition for our symbol...
+ if (ref_sym != NULL && ref_sym->st_shndx != SHN_UNDEF)
+ {
+ switch (ELF32_ST_BIND(ref_sym->st_info))
+ {
+ case STB_GLOBAL:
+ strong_count++;
+ break;
+ case STB_WEAK:
+ weak_count++;
+ break;
+ }
+ }
+ }
+
+ if (crt_sym->st_shndx == SHN_UNDEF)
+ {
+ // We have an undefined symbol
+ //
+ // We use the weak_count to differentiate
+ // between Syslinux-derivative-specific
+ // functions. For example, unload_pxe() is
+ // only provided by PXELINUX, so we mark it as
+ // __weak and replace it with a reference to
+ // undefined_symbol() on SYSLINUX, EXTLINUX,
+ // and ISOLINUX. See perform_relocations().
+ if (strong_count == 0 && weak_count == 0)
+ {
+ DBG_PRINT("Symbol %s is undefined\n", crt_name);
+ printf("Undef symbol FAIL: %s\n",crt_name);
+ return -1;
+ }
+ }
+ else
+ {
+ if (strong_count > 0 && ELF32_ST_BIND(ref_sym->st_info) == STB_GLOBAL)
+ {
+ // It's not an error - at relocation, the most recent symbol
+ // will be considered
+ DBG_PRINT("Info: Symbol %s is defined more than once\n", crt_name);
+ }
+ }
+ //printf("symbol %s laoded from %d\n",crt_name,crt_sym->st_value);
+ }
+
+ return 0;
+}
+
+int module_unloadable(struct elf_module *module) {
+ if (!list_empty(&module->dependants))
+ return 0;
+
+ return 1;
+}
+
+
+// Unloads the module from the system and releases all the associated memory
+int _module_unload(struct elf_module *module) {
+ struct module_dep *crt_dep, *tmp;
+ // Make sure nobody needs us
+ if (!module_unloadable(module)) {
+ DBG_PRINT("Module is required by other modules.\n");
+ return -1;
+ }
+
+ // Remove any dependency information
+ list_for_each_entry_safe(crt_dep, tmp, &module->required, list) {
+ clear_dependency(crt_dep->module, module);
+ }
+
+ // Remove the module from the module list
+ list_del_init(&module->list);
+
+ // Release the loaded segments or sections
+ if (module->module_addr != NULL) {
+ elf_free(module->module_addr);
+
+ DBG_PRINT("%s MODULE %s UNLOADED\n", module->shallow ? "SHALLOW" : "",
+ module->name);
+ }
+ // Release the module structure
+ free(module);
+
+ return 0;
+}
+
+int module_unload(struct elf_module *module) {
+ module_ctor_t *dtor;
+
+ for (dtor = module->dtors; dtor && *dtor; dtor++)
+ (*dtor) ();
+
+ return _module_unload(module);
+}
+
+struct elf_module *unload_modules_since(const char *name) {
+ struct elf_module *m, *mod, *begin = NULL;
+
+ for_each_module(mod) {
+ if (!strcmp(mod->name, name)) {
+ begin = mod;
+ break;
+ }
+ }
+
+ if (!begin)
+ return begin;
+
+ for_each_module_safe(mod, m) {
+ if (mod == begin)
+ break;
+
+ if (mod != begin)
+ module_unload(mod);
+ }
+
+ return begin;
+}
+
+static Elf32_Sym *module_find_symbol_sysv(const char *name, struct elf_module *module) {
+ unsigned long h = elf_hash((const unsigned char*)name);
+ Elf32_Word *cr_word = module->hash_table;
+
+ Elf32_Word nbucket = *cr_word++;
+ cr_word++; // Skip nchain
+
+ Elf32_Word *bkt = cr_word;
+ Elf32_Word *chn = cr_word + nbucket;
+
+ Elf32_Word crt_index = bkt[h % module->hash_table[0]];
+ Elf32_Sym *crt_sym;
+
+
+ while (crt_index != STN_UNDEF) {
+ crt_sym = symbol_get_entry(module, crt_index);
+
+ if (strcmp(name, module->str_table + crt_sym->st_name) == 0)
+ return crt_sym;
+
+ crt_index = chn[crt_index];
+ }
+
+ return NULL;
+}
+
+static Elf32_Sym *module_find_symbol_gnu(const char *name, struct elf_module *module) {
+ unsigned long h = elf_gnu_hash((const unsigned char*)name);
+
+ // Setup code (TODO: Optimize this by computing only once)
+ Elf32_Word *cr_word = module->ghash_table;
+ Elf32_Word nbucket = *cr_word++;
+ Elf32_Word symbias = *cr_word++;
+ Elf32_Word bitmask_nwords = *cr_word++;
+
+ if ((bitmask_nwords & (bitmask_nwords - 1)) != 0) {
+ DBG_PRINT("Invalid GNU Hash structure\n");
+ return NULL;
+ }
+
+ Elf32_Word gnu_shift = *cr_word++;
+
+ Elf32_Addr *gnu_bitmask = (Elf32_Addr*)cr_word;
+ cr_word += MODULE_ELF_CLASS_SIZE / 32 * bitmask_nwords;
+
+ Elf32_Word *gnu_buckets = cr_word;
+ cr_word += nbucket;
+
+ Elf32_Word *gnu_chain_zero = cr_word - symbias;
+
+ // Computations
+ Elf32_Word bitmask_word = gnu_bitmask[(h / MODULE_ELF_CLASS_SIZE) &
+ (bitmask_nwords - 1)];
+
+ unsigned int hashbit1 = h & (MODULE_ELF_CLASS_SIZE - 1);
+ unsigned int hashbit2 = (h >> gnu_shift) & (MODULE_ELF_CLASS_SIZE - 1);
+
+ if ((bitmask_word >> hashbit1) & (bitmask_word >> hashbit2) & 1) {
+ unsigned long rem;
+ Elf32_Word bucket;
+
+ rem = h % nbucket;
+
+ bucket = gnu_buckets[rem];
+
+ if (bucket != 0) {
+ const Elf32_Word* hasharr = &gnu_chain_zero[bucket];
+
+ do {
+ if (((*hasharr ^ h ) >> 1) == 0) {
+ Elf32_Sym *crt_sym = symbol_get_entry(module, (hasharr - gnu_chain_zero));
+
+ if (strcmp(name, module->str_table + crt_sym->st_name) == 0) {
+ return crt_sym;
+ }
+ }
+ } while ((*hasharr++ & 1u) == 0);
+ }
+ }
+
+ return NULL;
+}
+
+static Elf32_Sym *module_find_symbol_iterate(const char *name,struct elf_module *module)
+{
+
+ unsigned int i;
+ Elf32_Sym *crt_sym;
+
+ for (i = 1; i < module->symtable_size/module->syment_size; i++)
+ {
+ crt_sym = symbol_get_entry(module, i);
+ if (strcmp(name, module->str_table + crt_sym->st_name) == 0)
+ {
+ return crt_sym;
+ }
+ }
+
+ return NULL;
+}
+
+Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module) {
+ Elf32_Sym *result = NULL;
+
+ if (module->ghash_table != NULL)
+ result = module_find_symbol_gnu(name, module);
+
+ if (result == NULL)
+ {
+ if (module->hash_table != NULL)
+ {
+ //printf("Attempting SYSV Symbol search\n");
+ result = module_find_symbol_sysv(name, module);
+ }
+ else
+ {
+ //printf("Attempting Iterative Symbol search\n");
+ result = module_find_symbol_iterate(name, module);
+ }
+ }
+
+ return result;
+}
+
+Elf32_Sym *global_find_symbol(const char *name, struct elf_module **module) {
+ struct elf_module *crt_module;
+ Elf32_Sym *crt_sym = NULL;
+ Elf32_Sym *result = NULL;
+
+ for_each_module(crt_module) {
+ crt_sym = module_find_symbol(name, crt_module);
+
+ if (crt_sym != NULL && crt_sym->st_shndx != SHN_UNDEF) {
+ switch (ELF32_ST_BIND(crt_sym->st_info)) {
+ case STB_GLOBAL:
+ if (module != NULL) {
+ *module = crt_module;
+ }
+ return crt_sym;
+ case STB_WEAK:
+ // Consider only the first weak symbol
+ if (result == NULL) {
+ if (module != NULL) {
+ *module = crt_module;
+ }
+ result = crt_sym;
+ }
+ break;
+ }
+ }
+ }
+
+ return result;
+}
diff --git a/com32/lib/sys/module/common.h b/com32/lib/sys/module/common.h
new file mode 100644
index 00000000..54f0ec4b
--- /dev/null
+++ b/com32/lib/sys/module/common.h
@@ -0,0 +1,73 @@
+/*
+ * common.h - Common internal operations performed by the module subsystem
+ *
+ * Created on: Aug 11, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+#ifndef COMMON_H_
+#define COMMON_H_
+
+#include <stdio.h>
+
+#include <sys/module.h>
+#include <linux/list.h>
+
+#include "elfutils.h"
+
+
+// Performs an operation and jumps to a given label if an error occurs
+#define CHECKED(res, expr, error) \
+ do { \
+ (res) = (expr); \
+ if ((res) < 0) \
+ goto error; \
+ } while (0)
+
+#define MIN(x,y) (((x) < (y)) ? (x) : (y))
+#define MAX(x,y) (((x) > (y)) ? (x) : (y))
+
+static inline Elf32_Sym *symbol_get_entry(struct elf_module *module, int entry)
+{
+ char *sym_table = (char *)module->sym_table;
+ int index = entry * module->syment_size;
+
+ return (Elf32_Sym *)(sym_table + index);
+}
+
+//#define ELF_DEBUG
+
+#ifdef ELF_DEBUG
+#define DBG_PRINT(fmt, args...) fprintf(stderr, "[ELF] " fmt, ##args)
+#else
+#define DBG_PRINT(fmt, args...) // Expand to nothing
+#endif
+
+// User-space debugging routines
+#ifdef ELF_DEBUG
+extern void print_elf_ehdr(Elf32_Ehdr *ehdr);
+extern void print_elf_symbols(struct elf_module *module);
+#endif //ELF_DEBUG
+
+
+/*
+ * Image files manipulation routines
+ */
+
+extern int image_load(struct elf_module *module);
+extern int image_unload(struct elf_module *module);
+extern int image_read(void *buff, size_t size, struct elf_module *module);
+extern int image_skip(size_t size, struct elf_module *module);
+extern int image_seek(Elf32_Off offset, struct elf_module *module);
+
+extern struct module_dep *module_dep_alloc(struct elf_module *module);
+
+extern int check_header_common(Elf32_Ehdr *elf_hdr);
+
+extern int enforce_dependency(struct elf_module *req, struct elf_module *dep);
+extern int clear_dependency(struct elf_module *req, struct elf_module *dep);
+
+extern int check_symbols(struct elf_module *module);
+
+
+#endif /* COMMON_H_ */
diff --git a/com32/lib/sys/module/elf_module.c b/com32/lib/sys/module/elf_module.c
new file mode 100644
index 00000000..6a540273
--- /dev/null
+++ b/com32/lib/sys/module/elf_module.c
@@ -0,0 +1,631 @@
+/*
+ * elf_module.c
+ *
+ * Created on: Aug 11, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <elf.h>
+#include <dprintf.h>
+#include <core.h>
+
+#include <linux/list.h>
+#include <sys/module.h>
+#include <sys/exec.h>
+
+#include "elfutils.h"
+#include "common.h"
+
+static int check_header(Elf32_Ehdr *elf_hdr) {
+ int res;
+
+ res = check_header_common(elf_hdr);
+
+ if (res != 0)
+ return res;
+
+ if (elf_hdr->e_type != MODULE_ELF_TYPE) {
+ DBG_PRINT("The ELF file must be a shared object\n");
+ return -1;
+ }
+
+ if (elf_hdr->e_phoff == 0x00000000) {
+ DBG_PRINT("PHT missing\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ *
+ * The implementation assumes that the loadable segments are present
+ * in the PHT sorted by their offsets, so that only forward seeks would
+ * be necessary.
+ */
+static int load_segments(struct elf_module *module, Elf32_Ehdr *elf_hdr) {
+ int i;
+ int res = 0;
+ char *pht = NULL;
+ char *sht = NULL;
+ Elf32_Phdr *cr_pht;
+ Elf32_Shdr *cr_sht;
+
+ Elf32_Addr min_addr = 0x00000000; // Min. ELF vaddr
+ Elf32_Addr max_addr = 0x00000000; // Max. ELF vaddr
+ Elf32_Word max_align = sizeof(void*); // Min. align of posix_memalign()
+ Elf32_Addr min_alloc, max_alloc; // Min. and max. aligned allocables
+
+ Elf32_Addr dyn_addr = 0x00000000;
+
+ // Get to the PHT
+ image_seek(elf_hdr->e_phoff, module);
+
+ // Load the PHT
+ pht = malloc(elf_hdr->e_phnum * elf_hdr->e_phentsize);
+ if (!pht)
+ return -1;
+
+ image_read(pht, elf_hdr->e_phnum * elf_hdr->e_phentsize, module);
+
+ // Compute the memory needings of the module
+ for (i=0; i < elf_hdr->e_phnum; i++) {
+ cr_pht = (Elf32_Phdr*)(pht + i * elf_hdr->e_phentsize);
+
+ switch (cr_pht->p_type) {
+ case PT_LOAD:
+ if (i == 0) {
+ min_addr = cr_pht->p_vaddr;
+ } else {
+ min_addr = MIN(min_addr, cr_pht->p_vaddr);
+ }
+
+ max_addr = MAX(max_addr, cr_pht->p_vaddr + cr_pht->p_memsz);
+ max_align = MAX(max_align, cr_pht->p_align);
+ break;
+ case PT_DYNAMIC:
+ dyn_addr = cr_pht->p_vaddr;
+ break;
+ default:
+ // Unsupported - ignore
+ break;
+ }
+ }
+
+ if (max_addr - min_addr == 0) {
+ // No loadable segments
+ DBG_PRINT("No loadable segments found\n");
+ goto out;
+ }
+
+ if (dyn_addr == 0) {
+ DBG_PRINT("No dynamic information segment found\n");
+ goto out;
+ }
+
+ // The minimum address that should be allocated
+ min_alloc = min_addr - (min_addr % max_align);
+
+ // The maximum address that should be allocated
+ max_alloc = max_addr - (max_addr % max_align);
+ if (max_addr % max_align > 0)
+ max_alloc += max_align;
+
+
+ if (elf_malloc(&module->module_addr,
+ max_align,
+ max_alloc-min_alloc) != 0) {
+
+ DBG_PRINT("Could not allocate segments\n");
+ goto out;
+ }
+
+ module->base_addr = (Elf32_Addr)(module->module_addr) - min_alloc;
+ module->module_size = max_alloc - min_alloc;
+
+ // Zero-initialize the memory
+ memset(module->module_addr, 0, module->module_size);
+
+ for (i = 0; i < elf_hdr->e_phnum; i++) {
+ cr_pht = (Elf32_Phdr*)(pht + i * elf_hdr->e_phentsize);
+
+ if (cr_pht->p_type == PT_LOAD) {
+ // Copy the segment at its destination
+ if (cr_pht->p_offset < module->u.l._cr_offset) {
+ // The segment contains data before the current offset
+ // It can be discarded without worry - it would contain only
+ // headers
+ Elf32_Off aux_off = module->u.l._cr_offset - cr_pht->p_offset;
+
+ if (image_read((char *)module_get_absolute(cr_pht->p_vaddr, module) + aux_off,
+ cr_pht->p_filesz - aux_off, module) < 0) {
+ res = -1;
+ goto out;
+ }
+ } else {
+ if (image_seek(cr_pht->p_offset, module) < 0) {
+ res = -1;
+ goto out;
+ }
+
+ if (image_read(module_get_absolute(cr_pht->p_vaddr, module),
+ cr_pht->p_filesz, module) < 0) {
+ res = -1;
+ goto out;
+ }
+ }
+
+ /*
+ DBG_PRINT("Loadable segment of size 0x%08x copied from vaddr 0x%08x at 0x%08x\n",
+ cr_pht->p_filesz,
+ cr_pht->p_vaddr,
+ (Elf32_Addr)module_get_absolute(cr_pht->p_vaddr, module));
+ */
+ }
+ }
+
+ // Get to the SHT
+ image_seek(elf_hdr->e_shoff, module);
+
+ // Load the SHT
+ sht = malloc(elf_hdr->e_shnum * elf_hdr->e_shentsize);
+ if (!sht) {
+ res = -1;
+ goto out;
+ }
+
+ image_read(sht, elf_hdr->e_shnum * elf_hdr->e_shentsize, module);
+
+ // Setup the symtable size
+ for (i = 0; i < elf_hdr->e_shnum; i++) {
+ cr_sht = (Elf32_Shdr*)(sht + i * elf_hdr->e_shentsize);
+
+ if (cr_sht->sh_type == SHT_DYNSYM) {
+ module->symtable_size = cr_sht->sh_size;
+ break;
+ }
+ }
+
+ free(sht);
+
+ // Setup dynamic segment location
+ module->dyn_table = module_get_absolute(dyn_addr, module);
+
+ /*
+ DBG_PRINT("Base address: 0x%08x, aligned at 0x%08x\n", module->base_addr,
+ max_align);
+ DBG_PRINT("Module size: 0x%08x\n", module->module_size);
+ */
+
+out:
+ // Free up allocated memory
+ if (pht != NULL)
+ free(pht);
+
+ return res;
+}
+
+static int prepare_dynlinking(struct elf_module *module) {
+ Elf32_Dyn *dyn_entry = module->dyn_table;
+
+ while (dyn_entry->d_tag != DT_NULL) {
+ switch (dyn_entry->d_tag) {
+ case DT_NEEDED:
+ /*
+ * It's unlikely there'll be more than
+ * MAX_NR_DEPS DT_NEEDED entries but if there
+ * are then inform the user that we ran out of
+ * space.
+ */
+ if (module->nr_needed < MAX_NR_DEPS)
+ module->needed[module->nr_needed++] = dyn_entry->d_un.d_ptr;
+ else {
+ printf("Too many dependencies!\n");
+ return -1;
+ }
+ break;
+ case DT_HASH:
+ module->hash_table =
+ (Elf32_Word*)module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_GNU_HASH:
+ module->ghash_table =
+ (Elf32_Word*)module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_STRTAB:
+ module->str_table =
+ (char*)module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_SYMTAB:
+ module->sym_table =
+ module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_STRSZ:
+ module->strtable_size = dyn_entry->d_un.d_val;
+ break;
+ case DT_SYMENT:
+ module->syment_size = dyn_entry->d_un.d_val;
+ break;
+ case DT_PLTGOT: // The first entry in the GOT
+ module->got = module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ }
+
+ dyn_entry++;
+ }
+
+ return 0;
+}
+
+void undefined_symbol(void)
+{
+ printf("Error: An undefined symbol was referenced\n");
+ kaboom();
+}
+
+static int perform_relocation(struct elf_module *module, Elf32_Rel *rel) {
+ Elf32_Word *dest = module_get_absolute(rel->r_offset, module);
+
+ // The symbol reference index
+ Elf32_Word sym = ELF32_R_SYM(rel->r_info);
+ unsigned char type = ELF32_R_TYPE(rel->r_info);
+
+ // The symbol definition (if applicable)
+ Elf32_Sym *sym_def = NULL;
+ struct elf_module *sym_module = NULL;
+ Elf32_Addr sym_addr = 0x0;
+
+ if (sym > 0) {
+ // Find out details about the symbol
+
+ // The symbol reference
+ Elf32_Sym *sym_ref = symbol_get_entry(module, sym);
+
+ // The symbol definition
+ sym_def =
+ global_find_symbol(module->str_table + sym_ref->st_name,
+ &sym_module);
+
+ if (sym_def == NULL) {
+ DBG_PRINT("Cannot perform relocation for symbol %s\n",
+ module->str_table + sym_ref->st_name);
+
+ if (ELF32_ST_BIND(sym_ref->st_info) != STB_WEAK)
+ return -1;
+
+ // This must be a derivative-specific
+ // function. We're OK as long as we never
+ // execute the function.
+ sym_def = global_find_symbol("undefined_symbol", &sym_module);
+ }
+
+ // Compute the absolute symbol virtual address
+ sym_addr = (Elf32_Addr)module_get_absolute(sym_def->st_value, sym_module);
+
+ if (sym_module != module) {
+ // Create a dependency
+ enforce_dependency(sym_module, module);
+ }
+ }
+
+ switch (type) {
+ case R_386_NONE:
+ // Do nothing
+ break;
+ case R_386_32:
+ *dest += sym_addr;
+ break;
+ case R_386_PC32:
+ *dest += sym_addr - (Elf32_Addr)dest;
+ break;
+ case R_386_COPY:
+ if (sym_addr > 0) {
+ memcpy((void*)dest, (void*)sym_addr, sym_def->st_size);
+ }
+ break;
+ case R_386_GLOB_DAT:
+ case R_386_JMP_SLOT:
+ // Maybe TODO: Keep track of the GOT entries allocations
+ *dest = sym_addr;
+ break;
+ case R_386_RELATIVE:
+ *dest += module->base_addr;
+ break;
+ default:
+ DBG_PRINT("Relocation type %d not supported\n", type);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int resolve_symbols(struct elf_module *module) {
+ Elf32_Dyn *dyn_entry = module->dyn_table;
+ unsigned int i;
+ int res;
+
+ Elf32_Word plt_rel_size = 0;
+ char *plt_rel = NULL;
+
+ char *rel = NULL;
+ Elf32_Word rel_size = 0;
+ Elf32_Word rel_entry = 0;
+
+ // The current relocation
+ Elf32_Rel *crt_rel;
+
+ while (dyn_entry->d_tag != DT_NULL) {
+ switch(dyn_entry->d_tag) {
+
+ // PLT relocation information
+ case DT_PLTRELSZ:
+ plt_rel_size = dyn_entry->d_un.d_val;
+ break;
+ case DT_PLTREL:
+ if (dyn_entry->d_un.d_val != DT_REL) {
+ DBG_PRINT("Unsupported PLT relocation\n");
+ return -1;
+ }
+ case DT_JMPREL:
+ plt_rel = module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+
+ // Standard relocation information
+ case DT_REL:
+ rel = module_get_absolute(dyn_entry->d_un.d_ptr, module);
+ break;
+ case DT_RELSZ:
+ rel_size = dyn_entry->d_un.d_val;
+ break;
+ case DT_RELENT:
+ rel_entry = dyn_entry->d_un.d_val;
+ break;
+
+ // Module initialization and termination
+ case DT_INIT:
+ // TODO Implement initialization functions
+ break;
+ case DT_FINI:
+ // TODO Implement finalization functions
+ break;
+ }
+
+ dyn_entry++;
+ }
+
+ if (rel_size > 0) {
+ // Process standard relocations
+ for (i = 0; i < rel_size/rel_entry; i++) {
+ crt_rel = (Elf32_Rel*)(rel + i*rel_entry);
+
+ res = perform_relocation(module, crt_rel);
+
+ if (res < 0)
+ return res;
+ }
+
+ }
+
+ if (plt_rel_size > 0) {
+ // TODO: Permit this lazily
+ // Process PLT relocations
+ for (i = 0; i < plt_rel_size/sizeof(Elf32_Rel); i++) {
+ crt_rel = (Elf32_Rel*)(plt_rel + i*sizeof(Elf32_Rel));
+
+ res = perform_relocation(module, crt_rel);
+
+ if (res < 0)
+ return res;
+ }
+ }
+
+ return 0;
+}
+
+static int extract_operations(struct elf_module *module) {
+ Elf32_Sym *ctors_start, *ctors_end;
+ Elf32_Sym *dtors_start, *dtors_end;
+ module_ctor_t *ctors = NULL;
+ module_ctor_t *dtors = NULL;
+
+ ctors_start = module_find_symbol("__ctors_start", module);
+ ctors_end = module_find_symbol("__ctors_end", module);
+
+ if (ctors_start && ctors_end) {
+ module_ctor_t *start, *end;
+ int nr_ctors = 0;
+ int i, size;
+
+ start = module_get_absolute(ctors_start->st_value, module);
+ end = module_get_absolute(ctors_end->st_value, module);
+
+ nr_ctors = end - start;
+
+ size = nr_ctors * sizeof(module_ctor_t);
+ size += sizeof(module_ctor_t); /* NULL entry */
+
+ ctors = malloc(size);
+ if (!ctors) {
+ printf("Unable to alloc memory for ctors\n");
+ return -1;
+ }
+
+ memset(ctors, 0, size);
+ for (i = 0; i < nr_ctors; i++)
+ ctors[i] = start[i];
+
+ module->ctors = ctors;
+ }
+
+ dtors_start = module_find_symbol("__dtors_start", module);
+ dtors_end = module_find_symbol("__dtors_end", module);
+
+ if (dtors_start && dtors_end) {
+ module_ctor_t *start, *end;
+ int nr_dtors = 0;
+ int i, size;
+
+ start = module_get_absolute(dtors_start->st_value, module);
+ end = module_get_absolute(dtors_end->st_value, module);
+
+ nr_dtors = end - start;
+
+ size = nr_dtors * sizeof(module_ctor_t);
+ size += sizeof(module_ctor_t); /* NULL entry */
+
+ dtors = malloc(size);
+ if (!dtors) {
+ printf("Unable to alloc memory for dtors\n");
+ free(ctors);
+ return -1;
+ }
+
+ memset(dtors, 0, size);
+ for (i = 0; i < nr_dtors; i++)
+ dtors[i] = start[i];
+
+ module->dtors = dtors;
+ }
+
+ return 0;
+}
+
+// Loads the module into the system
+int module_load(struct elf_module *module) {
+ int res;
+ Elf32_Sym *main_sym;
+ Elf32_Ehdr elf_hdr;
+ module_ctor_t *ctor;
+ struct elf_module *head = NULL;
+
+ // Do not allow duplicate modules
+ if (module_find(module->name) != NULL) {
+ DBG_PRINT("Module %s is already loaded.\n", module->name);
+ return EEXIST;
+ }
+
+ // Get a mapping/copy of the ELF file in memory
+ res = image_load(module);
+
+ if (res < 0) {
+ return res;
+ }
+
+ // The module is a fully featured dynamic library
+ module->shallow = 0;
+
+ CHECKED(res, image_read(&elf_hdr, sizeof(Elf32_Ehdr), module), error);
+ //printf("check... 1\n");
+
+ //print_elf_ehdr(&elf_hdr);
+
+ // Checking the header signature and members
+ CHECKED(res, check_header(&elf_hdr), error);
+ //printf("check... 2\n");
+
+ // Load the segments in the memory
+ CHECKED(res, load_segments(module, &elf_hdr), error);
+ //printf("bleah... 3\n");
+ // Obtain dynamic linking information
+ CHECKED(res, prepare_dynlinking(module), error);
+ //printf("check... 4\n");
+
+ head = module_current();
+
+ /* Find modules we need to load as dependencies */
+ if (module->str_table) {
+ int i;
+
+ /*
+ * Note that we have to load the dependencies in
+ * reverse order.
+ */
+ for (i = module->nr_needed - 1; i >= 0; i--) {
+ char *dep, *p;
+ char *argv[2] = { NULL, NULL };
+
+ dep = module->str_table + module->needed[i];
+
+ /* strip everything but the last component */
+ if (!strlen(dep))
+ continue;
+
+ if (strchr(dep, '/')) {
+ p = strrchr(dep, '/');
+ p++;
+ } else
+ p = dep;
+
+ argv[0] = p;
+ res = spawn_load(p, 1, argv);
+ if (res < 0) {
+ printf("Failed to load %s\n", p);
+ goto error;
+ }
+ }
+ }
+
+ // Check the symbols for duplicates / missing definitions
+ CHECKED(res, check_symbols(module), error);
+ //printf("check... 5\n");
+
+ main_sym = module_find_symbol("main", module);
+ if (main_sym)
+ module->main_func =
+ module_get_absolute(main_sym->st_value, module);
+
+ //printf("check... 6\n");
+
+ // Add the module at the beginning of the module list
+ list_add(&module->list, &modules_head);
+
+ // Perform the relocations
+ resolve_symbols(module);
+
+ // Obtain constructors and destructors
+ CHECKED(res, extract_operations(module), error);
+
+ //dprintf("module->symtable_size = %d\n", module->symtable_size);
+
+ //print_elf_symbols(module);
+
+ // The file image is no longer needed
+ image_unload(module);
+
+ /*
+ DBG_PRINT("MODULE %s LOADED SUCCESSFULLY (main@%p, init@%p, exit@%p)\n",
+ module->name,
+ (module->main_func == NULL) ? NULL : *(module->main_func),
+ (module->init_func == NULL) ? NULL : *(module->init_func),
+ (module->exit_func == NULL) ? NULL : *(module->exit_func));
+ */
+
+ for (ctor = module->ctors; ctor && *ctor; ctor++)
+ (*ctor) ();
+
+ return 0;
+
+error:
+ if (head)
+ unload_modules_since(head->name);
+
+ // Remove the module from the module list (if applicable)
+ list_del_init(&module->list);
+
+ if (module->module_addr != NULL) {
+ elf_free(module->module_addr);
+ module->module_addr = NULL;
+ }
+
+ image_unload(module);
+
+ // Clear the execution part of the module buffer
+ memset(&module->u, 0, sizeof module->u);
+
+ return res;
+}
+
diff --git a/com32/lib/sys/module/elfutils.c b/com32/lib/sys/module/elfutils.c
new file mode 100644
index 00000000..b7d760b4
--- /dev/null
+++ b/com32/lib/sys/module/elfutils.c
@@ -0,0 +1,89 @@
+#include <stdlib.h>
+#include <errno.h>
+
+#include "elfutils.h"
+
+unsigned long elf_hash(const unsigned char *name) {
+ unsigned long h = 0;
+ unsigned long g;
+
+ while (*name) {
+ h = (h << 4) + *name++;
+ if ((g = h & 0xF0000000))
+ h ^= g >> 24;
+
+ h &= ~g;
+ }
+
+ return h;
+}
+
+unsigned long elf_gnu_hash(const unsigned char *name) {
+ unsigned long h = 5381;
+ unsigned char c;
+
+ for (c = *name; c != '\0'; c = *++name) {
+ h = h * 33 + c;
+ }
+
+ return h & 0xFFFFFFFF;
+}
+
+#ifndef HAVE_ELF_POSIX_MEMALIGN
+
+struct memalign_info {
+ void *start_addr;
+ char data[0];
+};
+
+int elf_malloc(void **memptr, size_t alignment, size_t size) {
+ char *start_addr = NULL;
+ struct memalign_info *info;
+
+ if ((alignment & (alignment - 1)) != 0)
+ return EINVAL;
+ if (alignment % sizeof(void*) != 0)
+ alignment = sizeof(void*);
+
+ start_addr = malloc(size + (alignment > sizeof(struct memalign_info) ?
+ alignment : sizeof(struct memalign_info)));
+
+ if (start_addr == NULL)
+ return ENOMEM;
+
+
+ info = (struct memalign_info*)(start_addr -
+ ((unsigned long)start_addr % alignment) +
+ alignment - sizeof(struct memalign_info));
+
+ info->start_addr = start_addr;
+
+ *memptr = info->data;
+
+ return 0;
+}
+
+void elf_free(char *memptr) {
+ struct memalign_info *info = (struct memalign_info*)(memptr -
+ sizeof(struct memalign_info));
+
+ free(info->start_addr);
+}
+
+#else
+
+int elf_malloc(void **memptr, size_t alignment, size_t size) {
+ if ((alignment & (alignment - 1)) != 0)
+ return EINVAL;
+
+ if (alignment % sizeof(void*) != 0)
+ alignment = sizeof(void*);
+
+ return posix_memalign(memptr, alignment, size);
+}
+
+void elf_free(void *memptr) {
+ free(memptr);
+}
+
+#endif //HAVE_ELF_POSIX_MEMALIGN
diff --git a/com32/lib/sys/module/elfutils.h b/com32/lib/sys/module/elfutils.h
new file mode 100644
index 00000000..a901ff48
--- /dev/null
+++ b/com32/lib/sys/module/elfutils.h
@@ -0,0 +1,64 @@
+#ifndef ELF_UTILS_H_
+#define ELF_UTILS_H_
+
+#include <elf.h>
+#include <stdlib.h>
+
+/**
+ * elf_get_header - Returns a pointer to the ELF header structure.
+ * @elf_image: pointer to the ELF file image in memory
+ */
+static inline Elf32_Ehdr *elf_get_header(void *elf_image) {
+ return (Elf32_Ehdr*)elf_image;
+}
+
+/**
+ * elf_get_pht - Returns a pointer to the first entry in the PHT.
+ * @elf_image: pointer to the ELF file image in memory
+ */
+static inline Elf32_Phdr *elf_get_pht(void *elf_image) {
+ Elf32_Ehdr *elf_hdr = elf_get_header(elf_image);
+
+ return (Elf32_Phdr*)((Elf32_Off)elf_hdr + elf_hdr->e_phoff);
+}
+
+//
+/**
+ * elf_get_ph - Returns the element with the given index in the PTH
+ * @elf_image: pointer to the ELF file image in memory
+ * @index: the index of the PHT entry to look for
+ */
+static inline Elf32_Phdr *elf_get_ph(void *elf_image, int index) {
+ Elf32_Phdr *elf_pht = elf_get_pht(elf_image);
+ Elf32_Ehdr *elf_hdr = elf_get_header(elf_image);
+
+ return (Elf32_Phdr*)((Elf32_Off)elf_pht + index * elf_hdr->e_phentsize);
+}
+
+/**
+ * elf_hash - Returns the index in a SysV hash table for the symbol name.
+ * @name: the name of the symbol to look for
+ */
+extern unsigned long elf_hash(const unsigned char *name);
+
+/**
+ * elf_gnu_hash - Returns the index in a GNU hash table for the symbol name.
+ * @name: the name of the symbol to look for
+ */
+extern unsigned long elf_gnu_hash(const unsigned char *name);
+
+/**
+ * elf_malloc - Allocates memory to be used by ELF module contents.
+ * @memptr: pointer to a variable to hold the address of the allocated block.
+ * @alignment: alignment constraints of the block
+ * @size: the required size of the block
+ */
+extern int elf_malloc(void **memptr, size_t alignment, size_t size);
+
+/**
+ * elf_free - Releases memory previously allocated by elf_malloc.
+ * @memptr: the address of the allocated block
+ */
+extern void elf_free(char *memptr);
+
+#endif /*ELF_UTILS_H_*/
diff --git a/com32/lib/sys/module/exec.c b/com32/lib/sys/module/exec.c
new file mode 100644
index 00000000..18c8306d
--- /dev/null
+++ b/com32/lib/sys/module/exec.c
@@ -0,0 +1,234 @@
+/*
+ * exec.c
+ *
+ * Created on: Aug 14, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+#include <sys/module.h>
+#include <sys/exec.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <setjmp.h>
+#include <setjmp.h>
+#include <alloca.h>
+#include <dprintf.h>
+
+#define DBG_PRINT(fmt, args...) dprintf("[EXEC] " fmt, ##args)
+
+struct elf_module *__syslinux_current = NULL;
+
+int get_module_type(struct elf_module *module)
+{
+ if(module->main_func) return EXEC_MODULE;
+ return LIB_MODULE;
+}
+
+jmp_buf __process_exit_jmp;
+
+#if 0
+int spawnv(const char *name, const char **argv)
+{
+ int res, ret_val = 0;
+ const char **arg;
+ int argc;
+ char **argp, **args;
+ struct elf_module *previous;
+ malloc_tag_t prev_mem_tag;
+
+ struct elf_module *module = module_alloc(name);
+
+ if (module == NULL)
+ return -1;
+
+ res = module_load(module);
+ if (res != 0) {
+ module_unload(module);
+ return res;
+ }
+
+ if (module->main_func == NULL) {
+ // We can't execute without a main function
+ module_unload(module);
+ return -1;
+ }
+ /*if (module->main_func != NULL) {
+ const char **last_arg = argv;
+ void *old_tag;
+ while (*last_arg != NULL)
+ last_arg++;
+
+ // Setup the memory allocation context
+ old_tag = __mem_get_tag_global();
+ __mem_set_tag_global(module);
+
+ // Execute the program
+ ret_val = (*(module->main_func))(last_arg - argv, argv);
+
+ // Clean up the allocation context
+ __free_tagged(module);
+ // Restore the allocation context
+ __mem_set_tag_global(old_tag);
+ } else {
+ // We can't execute without a main function
+ module_unload(module);
+ return -1;
+ }*/
+ // Set up the process context
+ previous = __syslinux_current;
+ prev_mem_tag = __mem_get_tag_global();
+
+ // Setup the new process context
+ __syslinux_current = module;
+ __mem_set_tag_global((malloc_tag_t)module);
+
+ // Generate a new process copy of argv (on the stack)
+ argc = 0;
+ for (arg = argv; *arg; arg++)
+ argc++;
+
+ args = alloca((argc+1) * sizeof(char *));
+
+ for (arg = argv, argp = args; *arg; arg++, argp++) {
+ size_t l = strlen(*arg)+1;
+ *argp = alloca(l);
+ memcpy(*argp, *arg, l);
+ }
+
+ *args = NULL;
+
+ // Execute the program
+ ret_val = setjmp(module->u.x.process_exit);
+
+ if (ret_val)
+ ret_val--; /* Valid range is 0-255 */
+ else if (!module->main_func)
+ ret_val = -1;
+ else
+ exit((module->main_func)(argc, args)); /* Actually run! */
+
+ // Clean up the allocation context
+ __free_tagged(module);
+ // Restore the allocation context
+ __mem_set_tag_global(prev_mem_tag);
+ // Restore the process context
+ __syslinux_current = previous;
+
+ res = module_unload(module);
+
+ if (res != 0) {
+ return res;
+ }
+
+ return ((unsigned int)ret_val & 0xFF);
+}
+
+int spawnl(const char *name, const char *arg, ...)
+{
+ /*
+ * NOTE: We assume the standard ABI specification for the i386
+ * architecture. This code may not work if used in other
+ * circumstances, including non-variadic functions, different
+ * architectures and calling conventions.
+ */
+ return spawnv(name, &arg);
+}
+#endif
+
+/*
+ * Load a module and runs its start function.
+ *
+ * For library modules the start function is module->init_func and for
+ * executable modules its module->main_func.
+ *
+ * "name" is the name of the module to load.
+ *
+ * "argv" and "argc" are only passed to module->main_func, for library
+ * modules these arguments can be NULL and 0, respectively.
+ *
+ * "argv" is an array of arguments to pass to module->main_func.
+ * argv[0] must be a pointer to "name" and argv[argc] must be NULL.
+ *
+ * "argc" is the number of arguments in "argv".
+ */
+int spawn_load(const char *name, int argc, char **argv)
+{
+ int res, ret_val = 0;
+ struct elf_module *previous;
+ //malloc_tag_t prev_mem_tag;
+ struct elf_module *module = module_alloc(name);
+ struct elf_module *cur_module;
+ int type;
+
+ dprintf("enter: name = %s", name);
+
+ if (module == NULL)
+ return -1;
+
+ if (get_module_type(module) == EXEC_MODULE) {
+ if (!argc || !argv || strcmp(argv[0], name)) {
+ res = -1;
+ goto out;
+ }
+ }
+
+ cur_module = module_current();
+ if (!strcmp(cur_module->name, module->name)) {
+ dprintf("We is running this module %s already!", module->name);
+
+ module_unload(cur_module);
+ }
+
+ res = module_load(module);
+ if (res != 0)
+ goto out;
+
+ type = get_module_type(module);
+
+ dprintf("type = %d, prev = %s, cur = %s",
+ type, cur_module->name, module->name);
+
+ if(type==EXEC_MODULE)
+ {
+ previous = __syslinux_current;
+ //prev_mem_tag = __mem_get_tag_global();
+
+ // Setup the new process context
+ __syslinux_current = module;
+ //__mem_set_tag_global((malloc_tag_t)module);
+
+ // Execute the program
+ ret_val = setjmp(module->u.x.process_exit);
+
+ if (ret_val)
+ ret_val--; /* Valid range is 0-255 */
+ else if (!module->main_func)
+ ret_val = -1;
+ else
+ exit((module->main_func)(argc, argv)); /* Actually run! */
+
+ // Clean up the allocation context
+ //__free_tagged(module);
+ // Restore the allocation context
+ //__mem_set_tag_global(prev_mem_tag);
+ // Restore the process context
+ __syslinux_current = previous;
+
+ res = module_unload(module);
+
+ if (res != 0)
+ goto out;
+ }
+
+out:
+ if (res)
+ _module_unload(module);
+ return res;
+}
+
+void exec_term(void)
+{
+ modules_term();
+}
diff --git a/com32/lib/sys/open.c b/com32/lib/sys/open.c
index 3e7bb6cf..1ed5bb4c 100644
--- a/com32/lib/sys/open.c
+++ b/com32/lib/sys/open.c
@@ -30,6 +30,7 @@
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
+#include <fs.h>
#include "file.h"
/*
@@ -56,12 +57,15 @@ int open(const char *pathname, int flags, ...)
struct file_info *fp;
fd = opendev(&__file_dev, NULL, flags);
+
+ //printf("enter, file = %s, fd = %d\n", pathname, fd);
+
if (fd < 0)
return -1;
fp = &__file_info[fd];
- handle = __com32.cs_pm->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/sys/rawcon_read.c b/com32/lib/sys/rawcon_read.c
index f7e89c7a..51bb9536 100644
--- a/com32/lib/sys/rawcon_read.c
+++ b/com32/lib/sys/rawcon_read.c
@@ -35,32 +35,38 @@
#include <errno.h>
#include <string.h>
#include <com32.h>
+#include <core.h>
#include <minmax.h>
-#include <sys/times.h>
#include "file.h"
/* Global, since it's used by stdcon_read */
ssize_t __rawcon_read(struct file_info *fp, void *buf, size_t count)
{
- com32sys_t ireg, oreg;
char *bufp = buf;
size_t n = 0;
+ static char hi = 0;
+ static bool hi_key = false;
(void)fp;
- memset(&ireg, 0, sizeof ireg);
-
while (n < count) {
+ if (hi_key) {
+ *bufp++ = hi;
+ n++;
+ hi_key = false;
+ continue;
+ }
+
/* Poll */
- ireg.eax.b[1] = 0x0B;
- __intcall(0x21, &ireg, &oreg);
- if (!oreg.eax.b[0])
+ if (!pollchar())
break;
/* We have data, go get it */
- ireg.eax.b[1] = 0x08;
- __intcall(0x21, &ireg, &oreg);
- *bufp++ = oreg.eax.b[0];
+ *bufp = getchar(&hi);
+ if (!*bufp)
+ hi_key = true;
+
+ bufp++;
n++;
}
diff --git a/com32/lib/sys/rawcon_write.c b/com32/lib/sys/rawcon_write.c
index 2d45a7b2..1f7920b2 100644
--- a/com32/lib/sys/rawcon_write.c
+++ b/com32/lib/sys/rawcon_write.c
@@ -34,24 +34,20 @@
#include <errno.h>
#include <string.h>
#include <com32.h>
+#include <core.h>
#include <minmax.h>
#include "file.h"
static ssize_t __rawcon_write(struct file_info *fp, const void *buf,
size_t count)
{
- com32sys_t ireg;
const char *bufp = buf;
size_t n = 0;
(void)fp;
- memset(&ireg, 0, sizeof ireg);
- ireg.eax.b[1] = 0x02;
-
while (count--) {
- ireg.edx.b[0] = *bufp++;
- __intcall(0x21, &ireg, NULL);
+ writechr(*bufp++);
n++;
}
diff --git a/com32/lib/sys/readdir.c b/com32/lib/sys/readdir.c
deleted file mode 100644
index d2a8c039..00000000
--- a/com32/lib/sys/readdir.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * readdir.c
- */
-
-#include <dirent.h>
-#include <stdio.h>
-#include <errno.h>
-
-#include <com32.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdlib.h>
-
-#include <syslinux/pmapi.h>
-
-DIR *opendir(const char *pathname)
-{
- return __com32.cs_pm->opendir(pathname);
-}
-
-struct dirent *readdir(DIR *dir)
-{
- return __com32.cs_pm->readdir(dir);
-}
-
-int closedir(DIR *dir)
-{
- return __com32.cs_pm->closedir(dir);
-}
diff --git a/com32/lib/sys/screensize.c b/com32/lib/sys/screensize.c
index 340227cd..bcd4496c 100644
--- a/com32/lib/sys/screensize.c
+++ b/com32/lib/sys/screensize.c
@@ -14,7 +14,7 @@ int getscreensize(int fd, int *rows, int *cols)
*rows = fp->o.rows;
*cols = fp->o.cols;
- if (!rows || !cols) {
+ if (!*rows || !*cols) {
errno = ENOTTY;
return -1;
}
diff --git a/com32/lib/sys/serial_write.c b/com32/lib/sys/serial_write.c
index fa0f4f4d..3f949fb7 100644
--- a/com32/lib/sys/serial_write.c
+++ b/com32/lib/sys/serial_write.c
@@ -34,13 +34,13 @@
#include <errno.h>
#include <string.h>
#include <com32.h>
+#include <core.h>
#include <minmax.h>
#include <syslinux/config.h>
#include "file.h"
ssize_t __serial_write(struct file_info *fp, const void *buf, size_t count)
{
- com32sys_t ireg;
const char *bufp = buf;
size_t n = 0;
@@ -49,12 +49,8 @@ ssize_t __serial_write(struct file_info *fp, const void *buf, size_t count)
if (!syslinux_serial_console_info()->iobase)
return count; /* Nothing to do */
- memset(&ireg, 0, sizeof ireg);
- ireg.eax.b[1] = 0x04;
-
while (count--) {
- ireg.edx.b[0] = *bufp++;
- __intcall(0x21, &ireg, NULL);
+ write_serial(*bufp++);
n++;
}
diff --git a/com32/lib/sys/stdcon_write.c b/com32/lib/sys/stdcon_write.c
index 9cb2f7db..9bd225f9 100644
--- a/com32/lib/sys/stdcon_write.c
+++ b/com32/lib/sys/stdcon_write.c
@@ -34,6 +34,7 @@
#include <errno.h>
#include <string.h>
#include <com32.h>
+#include <core.h>
#include <minmax.h>
#include "file.h"
@@ -57,22 +58,16 @@ static int __stdcon_open(struct file_info *fp)
static ssize_t __stdcon_write(struct file_info *fp, const void *buf,
size_t count)
{
- com32sys_t ireg;
const char *bufp = buf;
size_t n = 0;
(void)fp;
- memset(&ireg, 0, sizeof ireg);
- ireg.eax.b[1] = 0x02;
-
while (count--) {
- if (*bufp == '\n') {
- ireg.edx.b[0] = '\r';
- __intcall(0x21, &ireg, NULL);
- }
- ireg.edx.b[0] = *bufp++;
- __intcall(0x21, &ireg, NULL);
+ if (*bufp == '\n')
+ writechr('\r');
+
+ writechr(*bufp++);
n++;
}
diff --git a/com32/lib/sys/times.c b/com32/lib/sys/times.c
deleted file mode 100644
index dd063f37..00000000
--- a/com32/lib/sys/times.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/* ----------------------------------------------------------------------- *
- *
- * Copyright 2004-2008 H. Peter Anvin - All Rights Reserved
- *
- * 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.
- *
- * ----------------------------------------------------------------------- */
-
-/*
- * sys/times.c
- *
- * Returns something like a clock.
- */
-
-#include <sys/times.h>
-#include <syslinux/pmapi.h>
-#include <com32.h>
-
-clock_t times(struct tms * buf)
-{
- (void)buf;
- return *__com32.cs_pm->ms_timer;
-}
diff --git a/com32/lib/sys/vesa/background.c b/com32/lib/sys/vesa/background.c
index 93577461..15e90895 100644
--- a/com32/lib/sys/vesa/background.c
+++ b/com32/lib/sys/vesa/background.c
@@ -205,7 +205,6 @@ static int read_jpeg_file(FILE * fp, uint8_t * header, int len)
unsigned int bytes_per_row[1];
rv = floadfile(fp, &jpeg_file, &length_of_file, header, len);
- fclose(fp);
if (rv)
goto err;
diff --git a/com32/lib/sys/xserial_write.c b/com32/lib/sys/xserial_write.c
index e399f5fc..8a4fb9e0 100644
--- a/com32/lib/sys/xserial_write.c
+++ b/com32/lib/sys/xserial_write.c
@@ -35,6 +35,7 @@
#include <errno.h>
#include <string.h>
#include <com32.h>
+#include <core.h>
#include <minmax.h>
#include <colortbl.h>
#include <syslinux/config.h>
@@ -42,12 +43,7 @@
static void emit(char ch)
{
- static com32sys_t ireg; /* Zeroed with the BSS */
-
- ireg.eax.b[1] = 0x04;
- ireg.edx.b[0] = ch;
-
- __intcall(0x21, &ireg, NULL);
+ write_serial(ch);
}
ssize_t __xserial_write(struct file_info *fp, const void *buf, size_t count)
diff --git a/com32/lib/syslinux/cleanup.c b/com32/lib/syslinux/cleanup.c
index 12140e55..066f174f 100644
--- a/com32/lib/syslinux/cleanup.c
+++ b/com32/lib/syslinux/cleanup.c
@@ -26,15 +26,17 @@
* ----------------------------------------------------------------------- */
#include <syslinux/boot.h>
+#include <syslinux/config.h>
+#include <syslinux/pxe_api.h>
#include <stddef.h>
+#include <bios.h>
#include <com32.h>
+#include <core.h>
void syslinux_final_cleanup(uint16_t flags)
{
- static com32sys_t ireg;
+ if (syslinux_filesystem() == SYSLINUX_FS_PXELINUX)
+ unload_pxe(flags);
- ireg.eax.w[0] = 0x000c;
- ireg.edx.w[0] = flags;
-
- __intcall(0x22, &ireg, NULL);
+ cleanup_hardware();
}
diff --git a/com32/lib/syslinux/config.c b/com32/lib/syslinux/config.c
deleted file mode 100644
index b27aa827..00000000
--- a/com32/lib/syslinux/config.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/* ----------------------------------------------------------------------- *
- *
- * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
- *
- * 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/config.h>
-#include <klibc/compiler.h>
-#include <com32.h>
-
-const char *__syslinux_config_file;
-
-void __constructor __syslinux_get_config_file_name(void)
-{
- static com32sys_t reg;
-
- reg.eax.w[0] = 0x000e;
- __intcall(0x22, &reg, &reg);
- __syslinux_config_file = MK_PTR(reg.es, reg.ebx.w[0]);
-}
diff --git a/com32/lib/syslinux/debug.c b/com32/lib/syslinux/debug.c
new file mode 100644
index 00000000..d9ab863f
--- /dev/null
+++ b/com32/lib/syslinux/debug.c
@@ -0,0 +1,95 @@
+#include <linux/list.h>
+#include <string.h>
+#include <stdbool.h>
+
+#ifdef DYNAMIC_DEBUG
+
+static LIST_HEAD(debug_funcs);
+
+struct debug_func_entry {
+ const char *name;
+ struct list_head list;
+};
+
+static struct debug_func_entry *lookup_entry(const char *func)
+{
+ struct debug_func_entry *e, *entry = NULL;
+
+ list_for_each_entry(e, &debug_funcs, list) {
+ if (!strcmp(e->name, func)) {
+ entry = e;
+ break;
+ }
+ }
+
+ return entry;
+}
+
+bool __syslinux_debug_enabled(const char *func)
+{
+ struct debug_func_entry *entry;
+
+ entry = lookup_entry(func);
+ if (entry)
+ return true;
+
+ return false;
+}
+
+static int __enable(const char *func)
+{
+ struct debug_func_entry *entry;
+
+ entry = lookup_entry(func);
+ if (entry)
+ return 0; /* already enabled */
+
+ entry = malloc(sizeof(*entry));
+ if (!entry)
+ return -1;
+
+ entry->name = func;
+ list_add(&entry->list, &debug_funcs);
+ return 0;
+}
+
+static int __disable(const char *func)
+{
+ struct debug_func_entry *entry;
+
+ entry = lookup_entry(func);
+ if (!entry)
+ return 0; /* already disabled */
+
+ list_del(&entry->list);
+ free(entry);
+ return 0;
+}
+
+/*
+ * Enable or disable debug code for function 'func'.
+ */
+int syslinux_debug(const char *func, bool enable)
+{
+ int rv;
+
+ if (enable)
+ rv = __enable(func);
+ else
+ rv = __disable(func);
+
+ return rv;
+}
+
+#else
+
+int syslinux_debug(const char *func, bool enable)
+{
+ (void)func;
+ (void)enable;
+
+ printf("Dynamic debug unavailable\n");
+ return -1;
+}
+
+#endif /* DYNAMIC_DEBUG */
diff --git a/com32/lib/syslinux/disk.c b/com32/lib/syslinux/disk.c
index d6409af6..0b0c737e 100644
--- a/com32/lib/syslinux/disk.c
+++ b/com32/lib/syslinux/disk.c
@@ -33,6 +33,7 @@
* Deal with disks and partitions
*/
+#include <core.h>
#include <dprintf.h>
#include <stdio.h>
#include <stdlib.h>
@@ -73,7 +74,8 @@ int disk_int13_retry(const com32sys_t * inreg, com32sys_t * outreg)
int disk_get_params(int disk, struct disk_info *const diskinfo)
{
static com32sys_t inreg, outreg;
- struct disk_ebios_eparam *eparam = __com32.cs_bounce;
+ struct disk_ebios_eparam *eparam;
+ int rv = 0;
memset(diskinfo, 0, sizeof *diskinfo);
diskinfo->disk = disk;
@@ -93,6 +95,10 @@ int disk_get_params(int disk, struct disk_info *const diskinfo)
diskinfo->ebios = 1;
}
+ eparam = lmalloc(sizeof *eparam);
+ if (!eparam)
+ return -1;
+
/* Get extended disk parameters if ebios == 1 */
if (diskinfo->ebios) {
memset(&inreg, 0, sizeof inreg);
@@ -127,8 +133,10 @@ int disk_get_params(int disk, struct disk_info *const diskinfo)
__intcall(0x13, &inreg, &outreg);
- if (outreg.eflags.l & EFLAGS_CF)
- return diskinfo->ebios ? 0 : -1;
+ if (outreg.eflags.l & EFLAGS_CF) {
+ rv = diskinfo->ebios ? 0 : -1;
+ goto out;
+ }
diskinfo->spt = 0x3f & outreg.ecx.b[0];
diskinfo->head = 1 + outreg.edx.b[1];
@@ -145,7 +153,86 @@ int disk_get_params(int disk, struct disk_info *const diskinfo)
if (!diskinfo->lbacnt)
diskinfo->lbacnt = diskinfo->cyl * diskinfo->head * diskinfo->spt;
- return 0;
+out:
+ lfree(eparam);
+ return rv;
+}
+
+/**
+ * Fill inreg based on EBIOS addressing properties.
+ *
+ * @v diskinfo The disk drive to read from
+ * @v inreg Register data structure to be filled.
+ * @v lba The logical block address to begin reading at
+ * @v count The number of sectors to read
+ * @v op_code Code to write/read operation
+ * @ret lmalloc'd buf upon success, NULL upon failure
+ */
+static void *ebios_setup(const struct disk_info *const diskinfo, com32sys_t *inreg,
+ uint64_t lba, uint8_t count, uint8_t op_code)
+{
+ static __lowmem struct disk_ebios_dapa dapa;
+ void *buf;
+
+ buf = lmalloc(count * diskinfo->bps);
+ if (!buf)
+ return NULL;
+
+ dapa.len = sizeof(dapa);
+ dapa.count = count;
+ dapa.off = OFFS(buf);
+ dapa.seg = SEG(buf);
+ dapa.lba = lba;
+
+ inreg->eax.b[1] = op_code;
+ inreg->esi.w[0] = OFFS(&dapa);
+ inreg->ds = SEG(&dapa);
+ inreg->edx.b[0] = diskinfo->disk;
+
+ return buf;
+}
+
+/**
+ * Fill inreg based on CHS addressing properties.
+ *
+ * @v diskinfo The disk drive to read from
+ * @v inreg Register data structure to be filled.
+ * @v lba The logical block address to begin reading at
+ * @v count The number of sectors to read
+ * @v op_code Code to write/read operation
+ * @ret lmalloc'd buf upon success, NULL upon failure
+ */
+static void *chs_setup(const struct disk_info *const diskinfo, com32sys_t *inreg,
+ uint64_t lba, uint8_t count, uint8_t op_code)
+{
+ unsigned int c, h, s, t;
+ void *buf;
+
+ buf = lmalloc(count * diskinfo->bps);
+ if (!buf)
+ return NULL;
+
+ /*
+ * if we passed lba + count check and we get here, that means that
+ * lbacnt was calculated from chs geometry (or faked from 1/1/1), thus
+ * 32bits are perfectly enough and lbacnt corresponds to cylinder
+ * boundary
+ */
+ s = lba % diskinfo->spt;
+ t = lba / diskinfo->spt;
+ h = t % diskinfo->head;
+ c = t / diskinfo->head;
+
+ inreg->eax.b[0] = count;
+ inreg->eax.b[1] = op_code;
+ inreg->ecx.b[1] = c;
+ inreg->ecx.b[0] = ((c & 0x300) >> 2) | (s+1);
+ inreg->edx.b[1] = h;
+ inreg->edx.b[0] = diskinfo->disk;
+ inreg->ebx.w[0] = OFFS(buf);
+ inreg->es = SEG(buf);
+
+ return buf;
}
/**
@@ -163,57 +250,33 @@ void *disk_read_sectors(const struct disk_info *const diskinfo, uint64_t lba,
uint8_t count)
{
com32sys_t inreg;
- struct disk_ebios_dapa *dapa = __com32.cs_bounce;
- void *buf = (char *)__com32.cs_bounce + diskinfo->bps;
- void *data;
+ void *buf;
+ void *data = NULL;
uint32_t maxcnt;
+ uint32_t size = 65536;
- maxcnt = (__com32.cs_bounce_size - diskinfo->bps) / diskinfo->bps;
+ maxcnt = (size - diskinfo->bps) / diskinfo->bps;
if (!count || count > maxcnt || lba + count > diskinfo->lbacnt)
return NULL;
memset(&inreg, 0, sizeof inreg);
- if (diskinfo->ebios) {
- dapa->len = sizeof(*dapa);
- dapa->count = count;
- dapa->off = OFFS(buf);
- dapa->seg = SEG(buf);
- dapa->lba = lba;
-
- inreg.esi.w[0] = OFFS(dapa);
- inreg.ds = SEG(dapa);
- inreg.edx.b[0] = diskinfo->disk;
- inreg.eax.b[1] = 0x42; /* Extended read */
- } else {
- unsigned int c, h, s, t;
- /*
- * if we passed lba + count check and we get here, that means that
- * lbacnt was calculated from chs geometry (or faked from 1/1/1), thus
- * 32bits are perfectly enough and lbacnt corresponds to cylinder
- * boundary
- */
- s = lba % diskinfo->spt;
- t = lba / diskinfo->spt;
- h = t % diskinfo->head;
- c = t / diskinfo->head;
-
- inreg.eax.b[0] = count;
- inreg.eax.b[1] = 0x02; /* Read */
- inreg.ecx.b[1] = c;
- inreg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1);
- inreg.edx.b[1] = h;
- inreg.edx.b[0] = diskinfo->disk;
- inreg.ebx.w[0] = OFFS(buf);
- inreg.es = SEG(buf);
- }
+ if (diskinfo->ebios)
+ buf = ebios_setup(diskinfo, &inreg, lba, count, EBIOS_READ_CODE);
+ else
+ buf = chs_setup(diskinfo, &inreg, lba, count, CHS_READ_CODE);
- if (disk_int13_retry(&inreg, NULL))
+ if (!buf)
return NULL;
+ if (disk_int13_retry(&inreg, NULL))
+ goto out;
+
data = malloc(count * diskinfo->bps);
if (data)
memcpy(data, buf, count * diskinfo->bps);
+out:
+ lfree(buf);
return data;
}
@@ -233,55 +296,34 @@ int disk_write_sectors(const struct disk_info *const diskinfo, uint64_t lba,
const void *data, uint8_t count)
{
com32sys_t inreg;
- struct disk_ebios_dapa *dapa = __com32.cs_bounce;
- void *buf = (char *)__com32.cs_bounce + diskinfo->bps;
+ void *buf;
uint32_t maxcnt;
+ uint32_t size = 65536;
+ int rv = -1;
- maxcnt = (__com32.cs_bounce_size - diskinfo->bps) / diskinfo->bps;
+ maxcnt = (size - diskinfo->bps) / diskinfo->bps;
if (!count || count > maxcnt || lba + count > diskinfo->lbacnt)
return -1;
- memcpy(buf, data, count * diskinfo->bps);
memset(&inreg, 0, sizeof inreg);
- if (diskinfo->ebios) {
- dapa->len = sizeof(*dapa);
- dapa->count = count;
- dapa->off = OFFS(buf);
- dapa->seg = SEG(buf);
- dapa->lba = lba;
-
- inreg.esi.w[0] = OFFS(dapa);
- inreg.ds = SEG(dapa);
- inreg.edx.b[0] = diskinfo->disk;
- inreg.eax.b[1] = 0x43; /* Extended write */
- } else {
- unsigned int c, h, s, t;
- /*
- * if we passed lba + count check and we get here, that means that
- * lbacnt was calculated from chs geometry (or faked from 1/1/1), thus
- * 32bits are perfectly enough and lbacnt corresponds to cylinder
- * boundary
- */
- s = lba % diskinfo->spt;
- t = lba / diskinfo->spt;
- h = t % diskinfo->head;
- c = t / diskinfo->head;
-
- inreg.eax.b[0] = count;
- inreg.eax.b[1] = 0x03; /* Write */
- inreg.ecx.b[1] = c;
- inreg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1);
- inreg.edx.b[1] = h;
- inreg.edx.b[0] = diskinfo->disk;
- inreg.ebx.w[0] = OFFS(buf);
- inreg.es = SEG(buf);
- }
+ if (diskinfo->ebios)
+ buf = ebios_setup(diskinfo, &inreg, lba, count, EBIOS_WRITE_CODE);
+ else
+ buf = chs_setup(diskinfo, &inreg, lba, count, CHS_WRITE_CODE);
- if (disk_int13_retry(&inreg, NULL))
+ if (!buf)
return -1;
- return 0; /* ok */
+ memcpy(buf, data, count * diskinfo->bps);
+
+ if (disk_int13_retry(&inreg, NULL))
+ goto out;
+
+ rv = 0; /* ok */
+out:
+ lfree(buf);
+ return rv;
}
/**
diff --git a/com32/lib/syslinux/idle.c b/com32/lib/syslinux/idle.c
index ddaa7fcd..33e8035c 100644
--- a/com32/lib/syslinux/idle.c
+++ b/com32/lib/syslinux/idle.c
@@ -33,15 +33,16 @@
#include <stddef.h>
#include <com32.h>
+#include <core.h>
#include <syslinux/pmapi.h>
#include <syslinux/idle.h>
void syslinux_reset_idle(void)
{
- __com32.cs_pm->reset_idle();
+ reset_idle();
}
void syslinux_idle(void)
{
- __com32.cs_pm->idle();
+ __idle();
}
diff --git a/com32/lib/syslinux/initramfs_file.c b/com32/lib/syslinux/initramfs_file.c
index 763eff28..7eb55b5e 100644
--- a/com32/lib/syslinux/initramfs_file.c
+++ b/com32/lib/syslinux/initramfs_file.c
@@ -65,7 +65,7 @@ static size_t initramfs_mkdirs(const char *filename, void *buffer,
const char *p = filename;
char *bp = buffer;
int len;
- size_t bytes = 0;
+ size_t bytes = 0, hdr_sz;
int pad;
while ((p = strchr(p, '/'))) {
@@ -81,15 +81,17 @@ static size_t initramfs_mkdirs(const char *filename, void *buffer,
while ((p = strchr(p, '/'))) {
if (p != filename && p[-1] != '/') {
len = p - filename;
+ hdr_sz = ((sizeof(struct cpio_header) + len + 1) + 3) & ~3;
bp += sprintf(bp, "070701%08x%08x%08x%08x%08x%08x%08x%08x%08x"
"%08x%08x%08x%08x", next_ino++, S_IFDIR | 0755,
0, 0, 1, 0, 0, 0, 1, 0, 1, len + 1, 0);
memcpy(bp, filename, len);
bp += len;
- pad = (-(sizeof(struct cpio_header) + len) & 3) + 1;
+ pad = hdr_sz - (sizeof(struct cpio_header) + len);
memset(bp, 0, pad);
bp += pad;
}
+ p++;
}
}
@@ -104,7 +106,7 @@ int initramfs_mknod(struct initramfs *ihead, const char *filename,
int do_mkdir,
uint16_t mode, size_t len, uint32_t major, uint32_t minor)
{
- size_t bytes;
+ size_t bytes, hdr_sz;
int namelen = strlen(filename);
int pad;
char *buffer, *bp;
@@ -114,7 +116,8 @@ int initramfs_mknod(struct initramfs *ihead, const char *filename,
else
bytes = 0;
- bytes += ((sizeof(struct cpio_header) + namelen + 1) + 3) & ~3;
+ hdr_sz = ((sizeof(struct cpio_header) + namelen + 1) + 3) & ~3;
+ bytes += hdr_sz;
bp = buffer = malloc(bytes);
if (!buffer)
@@ -127,8 +130,8 @@ int initramfs_mknod(struct initramfs *ihead, const char *filename,
"%08x%08x%08x%08x", next_ino++, mode,
0, 0, 1, 0, len, 0, 1, major, minor, namelen + 1, 0);
memcpy(bp, filename, namelen);
- bp += len;
- pad = (-(sizeof(struct cpio_header) + namelen) & 3) + 1;
+ bp += namelen;
+ pad = hdr_sz - (sizeof(struct cpio_header) + namelen);
memset(bp, 0, pad);
if (initramfs_add_data(ihead, buffer, bytes, bytes, 4)) {
diff --git a/com32/lib/syslinux/ipappend.c b/com32/lib/syslinux/ipappend.c
index bd000920..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,28 +32,16 @@
* Get ipappend strings
*/
+#include <syslinux/sysappend.h>
#include <syslinux/config.h>
+#include <syslinux/pmapi.h>
#include <klibc/compiler.h>
-#include <com32.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)
{
- static com32sys_t reg;
- int i;
-
- reg.eax.w[0] = 0x000f;
- __intcall(0x22, &reg, &reg);
-
- if (!(reg.eflags.l & EFLAGS_CF)) {
- __syslinux_ipappend_strings.count = reg.ecx.w[0];
- __syslinux_ipappend_strings.ptr = syslinux_ipappend_string_list;
- for (i = 0; i < reg.ecx.w[0]; i++) {
- syslinux_ipappend_string_list[i] =
- MK_PTR(reg.es,
- *(uint16_t *) MK_PTR(reg.es, reg.ebx.w[0] + i * 2));
- }
- }
+ __syslinux_ipappend_strings.count = SYSAPPEND_MAX,
+ __syslinux_ipappend_strings.ptr = sysappend_strings;
}
diff --git a/com32/lib/syslinux/keyboard.c b/com32/lib/syslinux/keyboard.c
index feafde0d..03bd216a 100644
--- a/com32/lib/syslinux/keyboard.c
+++ b/com32/lib/syslinux/keyboard.c
@@ -26,19 +26,13 @@
* ----------------------------------------------------------------------- */
#include <syslinux/keyboard.h>
-#include <com32.h>
+#include <core.h>
struct syslinux_keyboard_map __syslinux_keyboard_map;
void __constructor __syslinux_get_keyboard_map(void)
{
- static com32sys_t reg;
-
- reg.eax.w[0] = 0x001e;
- __intcall(0x22, &reg, &reg);
- if (!(reg.eflags.l & EFLAGS_CF)) {
- __syslinux_keyboard_map.version = reg.eax.w[0];
- __syslinux_keyboard_map.length = reg.ecx.w[0];
- __syslinux_keyboard_map.map = MK_PTR(reg.es, reg.ebx.w[0]);
- }
+ __syslinux_keyboard_map.version = 1;
+ __syslinux_keyboard_map.length = sizeof(KbdMap);
+ __syslinux_keyboard_map.map = (void *)KbdMap;
}
diff --git a/com32/lib/syslinux/load_linux.c b/com32/lib/syslinux/load_linux.c
index 856141f8..7638e6f6 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
@@ -40,11 +40,13 @@
#include <minmax.h>
#include <errno.h>
#include <suffix_number.h>
+#include <graphics.h>
+#include <dprintf.h>
+
#include <syslinux/align.h>
#include <syslinux/linux.h>
#include <syslinux/bootrm.h>
#include <syslinux/movebits.h>
-#include <dprintf.h>
struct linux_header {
uint8_t boot_sector_1[0x0020];
@@ -202,8 +204,11 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
cmdline_size = strlen(cmdline) + 1;
- if (kernel_size < 2 * 512)
+ errno = EINVAL;
+ if (kernel_size < 2 * 512) {
+ dprintf("Kernel size too small\n");
goto bail;
+ }
/* Look for specific command-line arguments we care about */
if ((arg = find_argument(cmdline, "mem=")))
@@ -234,8 +239,10 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
memcpy(&hdr, kernel_buf, sizeof hdr);
whdr = (struct linux_header *)kernel_buf;
- if (hdr.boot_flag != BOOT_MAGIC)
+ if (hdr.boot_flag != BOOT_MAGIC) {
+ dprintf("Invalid boot magic\n");
goto bail;
+ }
if (hdr.header != LINUX_MAGIC) {
hdr.version = 0x0100; /* Very old kernel */
@@ -247,7 +254,7 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
if (!hdr.setup_sects)
hdr.setup_sects = 4;
- if (hdr.version < 0x0203)
+ if (hdr.version < 0x0203 || !hdr.initrd_addr_max)
hdr.initrd_addr_max = 0x37ffffff;
if (!memlimit && memlimit - 1 > hdr.initrd_addr_max)
@@ -285,11 +292,18 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
hdr.init_size = 3 * prot_mode_size;
}
- if (!(hdr.loadflags & LOAD_HIGH) && prot_mode_size > 512 * 1024)
- goto bail; /* Kernel cannot be loaded low */
+ if (!(hdr.loadflags & LOAD_HIGH) && prot_mode_size > 512 * 1024) {
+ dprintf("Kernel cannot be loaded low\n");
+ goto bail;
+ }
+
+ /* Get the size of the initramfs, if there is one */
+ irf_size = initramfs_size(initramfs);
- if (initramfs && hdr.version < 0x0200)
- goto bail; /* initrd/initramfs not supported */
+ if (irf_size && hdr.version < 0x0200) {
+ dprintf("Initrd specified but not supported by kernel\n");
+ goto bail;
+ }
if (hdr.version >= 0x0200) {
whdr->type_of_loader = 0x30; /* SYSLINUX unknown module */
@@ -297,21 +311,15 @@ int syslinux_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 */
mmap = syslinux_memory_map(); /* Memory map for shuffle_boot */
amap = syslinux_dup_memmap(mmap); /* Keep track of available memory */
- if (!mmap || !amap)
+ if (!mmap || !amap) {
+ errno = ENOMEM;
goto bail;
+ }
dprintf("Initial memory map:\n");
syslinux_dump_memmap(mmap);
@@ -321,17 +329,22 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
it's unavailable to the boot loader, which probably has already touched
some of it), or just in the amap? */
if (memlimit)
- if (syslinux_add_memmap(&amap, memlimit, -memlimit, SMT_RESERVED))
+ if (syslinux_add_memmap(&amap, memlimit, -memlimit, SMT_RESERVED)) {
+ errno = ENOMEM;
goto bail;
+ }
/* Place the kernel in memory */
/* First, find a suitable place for the protected-mode code */
- if (syslinux_memmap_type(amap, prot_mode_base, prot_mode_size)
+ if (prot_mode_size &&
+ syslinux_memmap_type(amap, prot_mode_base, prot_mode_size)
!= SMT_FREE) {
const struct syslinux_memmap *mp;
- if (!hdr.relocatable_kernel)
- goto bail; /* Can't relocate - no hope */
+ if (!hdr.relocatable_kernel) {
+ dprintf("Cannot relocate kernel\n");
+ goto bail;
+ }
ok = false;
for (mp = amap; mp; mp = mp->next) {
@@ -360,8 +373,10 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
}
}
- if (!ok)
+ if (!ok) {
+ dprintf("Could not find location for protected-mode code\n");
goto bail;
+ }
}
/* Real mode code */
@@ -393,39 +408,65 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
break;
}
}
+
+ if (!ok) {
+ dprintf("Could not find location for real-mode code\n");
+ goto bail;
+ }
}
if (syslinux_add_movelist(&fraglist, real_mode_base, (addr_t) kernel_buf,
real_mode_size))
goto bail;
if (syslinux_add_memmap
- (&amap, real_mode_base, cmdline_offset + cmdline_size, SMT_ALLOC))
+ (&amap, real_mode_base, cmdline_offset + cmdline_size, SMT_ALLOC)) {
+ errno = ENOMEM;
goto bail;
+ }
/* Zero region between real mode code and cmdline */
if (syslinux_add_memmap(&mmap, real_mode_base + real_mode_size,
- cmdline_offset - real_mode_size, SMT_ZERO))
+ cmdline_offset - real_mode_size, SMT_ZERO)) {
+ errno = ENOMEM;
goto bail;
+ }
/* Command line */
if (syslinux_add_movelist(&fraglist, real_mode_base + cmdline_offset,
- (addr_t) cmdline, cmdline_size))
+ (addr_t) cmdline, cmdline_size)) {
+ errno = ENOMEM;
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,
- (addr_t) kernel_buf + real_mode_size,
- prot_mode_size))
- goto bail;
- if (syslinux_add_memmap(&amap, prot_mode_base, prot_mode_size, SMT_ALLOC))
- goto bail;
+ if (prot_mode_size) {
+ if (syslinux_add_movelist(&fraglist, prot_mode_base,
+ (addr_t) kernel_buf + real_mode_size,
+ prot_mode_size)) {
+ errno = ENOMEM;
+ goto bail;
+ }
+ if (syslinux_add_memmap(&amap, prot_mode_base, prot_mode_size,
+ SMT_ALLOC)) {
+ errno = ENOMEM;
+ goto bail;
+ }
+ }
/* Figure out the size of the initramfs, and where to put it.
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;
@@ -439,17 +480,23 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
best_addr = (adj_end - irf_size) & ~align_mask;
}
- if (!best_addr)
- goto bail; /* Insufficient memory for initramfs */
+ if (!best_addr) {
+ dprintf("Insufficient memory for initramfs\n");
+ goto bail;
+ }
whdr->ramdisk_image = best_addr;
whdr->ramdisk_size = irf_size;
- if (syslinux_add_memmap(&amap, best_addr, irf_size, SMT_ALLOC))
+ if (syslinux_add_memmap(&amap, best_addr, irf_size, SMT_ALLOC)) {
+ errno = ENOMEM;
goto bail;
+ }
- if (map_initramfs(&fraglist, &mmap, initramfs, best_addr))
+ if (map_initramfs(&fraglist, &mmap, initramfs, best_addr)) {
+ errno = ENOMEM;
goto bail;
+ }
}
}
@@ -485,14 +532,20 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
*prev_ptr = best_addr;
prev_ptr = &sdp->hdr.next;
- if (syslinux_add_memmap(&amap, best_addr, size, SMT_ALLOC))
+ if (syslinux_add_memmap(&amap, best_addr, size, SMT_ALLOC)) {
+ errno = ENOMEM;
goto bail;
+ }
if (syslinux_add_movelist(&fraglist, best_addr,
- (addr_t)&sdp->hdr, sizeof sdp->hdr))
+ (addr_t)&sdp->hdr, sizeof sdp->hdr)) {
+ errno = ENOMEM;
goto bail;
+ }
if (syslinux_add_movelist(&fraglist, best_addr + sizeof sdp->hdr,
- (addr_t)sdp->data, sdp->hdr.len))
+ (addr_t)sdp->data, sdp->hdr.len)) {
+ errno = ENOMEM;
goto bail;
+ }
}
}
@@ -513,7 +566,19 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
dprintf("Initial movelist:\n");
syslinux_dump_movelist(fraglist);
+ if (video_mode != 0x0f04) {
+ /*
+ * video_mode is not "current", so if we are in graphics mode we
+ * need to revert to text mode...
+ */
+ dprintf("*** Calling syslinux_force_text_mode()...\n");
+ syslinux_force_text_mode();
+ } else {
+ dprintf("*** vga=current, not calling syslinux_force_text_mode()...\n");
+ }
+
syslinux_shuffle_boot_rm(fraglist, mmap, 0, &regs);
+ dprintf("shuffle_boot_rm failed\n");
bail:
syslinux_free_movelist(fraglist);
diff --git a/com32/lib/syslinux/localboot.c b/com32/lib/syslinux/localboot.c
index 3b480c71..16016a9d 100644
--- a/com32/lib/syslinux/localboot.c
+++ b/com32/lib/syslinux/localboot.c
@@ -28,15 +28,11 @@
#include <syslinux/boot.h>
#include <stddef.h>
#include <com32.h>
+#include <localboot.h>
/* This returns only on failure */
-void syslinux_local_boot(uint16_t flags)
+void syslinux_local_boot(int16_t flags)
{
- static com32sys_t ireg;
-
- ireg.eax.w[0] = 0x0014;
- ireg.edx.w[0] = flags;
-
- __intcall(0x22, &ireg, NULL);
+ local_boot(flags);
}
diff --git a/com32/lib/syslinux/pxe_dns.c b/com32/lib/syslinux/pxe_dns.c
index 6620396f..b813b543 100644
--- a/com32/lib/syslinux/pxe_dns.c
+++ b/com32/lib/syslinux/pxe_dns.c
@@ -43,12 +43,12 @@
or -1 on invocation failure */
uint32_t pxe_dns(const char *hostname)
{
- com32sys_t regs;
union {
unsigned char b[4];
uint32_t ip;
} q;
char *lm_hostname;
+ uint32_t status;
/* Is this a dot-quad? */
if (sscanf(hostname, "%hhu.%hhu.%hhu.%hhu",
@@ -59,17 +59,9 @@ uint32_t pxe_dns(const char *hostname)
if (!lm_hostname)
return 0;
- memset(&regs, 0, sizeof regs);
- regs.eax.w[0] = 0x0010;
- regs.es = SEG(lm_hostname);
- /* regs.ebx.w[0] = OFFS(lm_hostname); */
-
- __intcall(0x22, &regs, &regs);
+ status = dns_resolv(lm_hostname);
lfree(lm_hostname);
- if (regs.eflags.l & EFLAGS_CF)
- return 0;
-
- return regs.eax.l;
+ return status;
}
diff --git a/com32/lib/syslinux/pxe_get_cached.c b/com32/lib/syslinux/pxe_get_cached.c
index 47040378..a090a4c9 100644
--- a/com32/lib/syslinux/pxe_get_cached.c
+++ b/com32/lib/syslinux/pxe_get_cached.c
@@ -43,7 +43,6 @@
int pxe_get_cached_info(int level, void **buf, size_t * len)
{
const int max_dhcp_packet = 2048;
- com32sys_t regs;
t_PXENV_GET_CACHED_INFO *gci;
void *bbuf, *nbuf;
int err;
@@ -52,12 +51,6 @@ int pxe_get_cached_info(int level, void **buf, size_t * len)
if (!gci)
return -1;
- memset(&regs, 0, sizeof regs);
- regs.eax.w[0] = 0x0009;
- regs.ebx.w[0] = PXENV_GET_CACHED_INFO;
- regs.es = SEG(gci);
- /* regs.edi.w[0] = OFFS(gci); */
-
bbuf = &gci[1];
gci->Status = PXENV_STATUS_FAILURE;
@@ -66,9 +59,9 @@ int pxe_get_cached_info(int level, void **buf, size_t * len)
gci->Buffer.seg = SEG(bbuf);
gci->Buffer.offs = OFFS(bbuf);
- __intcall(0x22, &regs, &regs);
+ err = pxe_call(PXENV_GET_CACHED_INFO, gci);
- if (regs.eflags.l & EFLAGS_CF) {
+ if (err) {
err = -1;
goto exit;
}
diff --git a/com32/lib/syslinux/pxe_get_nic.c b/com32/lib/syslinux/pxe_get_nic.c
index b301a75a..6e256f92 100644
--- a/com32/lib/syslinux/pxe_get_nic.c
+++ b/com32/lib/syslinux/pxe_get_nic.c
@@ -42,25 +42,19 @@
or -1 on invocation failure */
int pxe_get_nic_type(t_PXENV_UNDI_GET_NIC_TYPE *gnt)
{
- com32sys_t regs;
t_PXENV_UNDI_GET_NIC_TYPE *lgnt;
+ int err;
lgnt = lzalloc(sizeof *lgnt);
if (!lgnt)
return -1;
- memset(&regs, 0, sizeof regs);
- regs.eax.w[0] = 0x0009;
- regs.ebx.w[0] = PXENV_UNDI_GET_NIC_TYPE;
- regs.es = SEG(lgnt);
- /* regs.edi.w[0] = OFFS(lgnt); */
-
- __intcall(0x22, &regs, &regs);
+ err = pxe_call(PXENV_UNDI_GET_NIC_TYPE, lgnt);
memcpy(gnt, lgnt, sizeof(t_PXENV_UNDI_GET_NIC_TYPE));
lfree(lgnt);
- if (regs.eflags.l & EFLAGS_CF)
+ if (err)
return -1;
return gnt->Status;
diff --git a/com32/lib/syslinux/run_command.c b/com32/lib/syslinux/run_command.c
index a0ac9a0d..7e4dc41b 100644
--- a/com32/lib/syslinux/run_command.c
+++ b/com32/lib/syslinux/run_command.c
@@ -28,21 +28,16 @@
#include <syslinux/boot.h>
#include <stddef.h>
#include <string.h>
-#include <com32.h>
+#include <core.h>
int syslinux_run_command(const char *command)
{
- static com32sys_t ireg;
char *lm_command = lstrdup(command);
if (!lm_command)
return -1;
- ireg.eax.w[0] = 0x0003;
- ireg.es = SEG(lm_command);
- /* ireg.ebx.w[0] = OFFS(lm_command); */
-
- __intcall(0x22, &ireg, NULL);
+ load_kernel(lm_command);
/* Should not return even on failure, but in case... */
lfree(lm_command);
diff --git a/com32/lib/syslinux/run_default.c b/com32/lib/syslinux/run_default.c
index 8dc9fbe4..0cfa5470 100644
--- a/com32/lib/syslinux/run_default.c
+++ b/com32/lib/syslinux/run_default.c
@@ -26,16 +26,14 @@
* ----------------------------------------------------------------------- */
#include <syslinux/boot.h>
+#include <core.h>
#include <stddef.h>
-#include <com32.h>
+
+extern const char *default_cmd;
__noreturn syslinux_run_default(void)
{
- static com32sys_t ireg;
-
- ireg.eax.w[0] = 0x0004;
- __intcall(0x22, &ireg, NULL);
-
+ load_kernel(default_cmd);
/* Should not return even on failure */
for (;;) ;
}
diff --git a/com32/lib/syslinux/runimage.c b/com32/lib/syslinux/runimage.c
index d5cdbc62..4dcd029d 100644
--- a/com32/lib/syslinux/runimage.c
+++ b/com32/lib/syslinux/runimage.c
@@ -34,37 +34,26 @@
#include <stdlib.h>
#include <string.h>
#include <syslinux/boot.h>
-#include <com32.h>
+#include <syslinux/config.h>
+#include <core.h>
void syslinux_run_kernel_image(const char *filename, const char *cmdline,
uint32_t ipappend_flags, uint32_t type)
{
- static com32sys_t ireg;
- char *bbfilename = NULL;
char *bbcmdline = NULL;
+ size_t len;
+ int rv;
- bbfilename = lstrdup(filename);
- if (!bbfilename)
- goto fail;
-
- bbcmdline = lstrdup(cmdline);
+ /* +2 for NULL and space */
+ len = strlen(filename) + strlen(cmdline) + 2;
+ bbcmdline = malloc(len);
if (!bbcmdline)
- goto fail;
-
-
- ireg.eax.w[0] = 0x0016;
- ireg.ds = SEG(bbfilename);
- /* ireg.esi.w[0] = OFFS(bbfilename); */
- ireg.es = SEG(bbcmdline);
- /* ireg.ebx.w[0] = OFFS(bbcmdline); */
- ireg.ecx.l = ipappend_flags;
- ireg.edx.l = type;
+ return;
- __intcall(0x22, &ireg, 0);
+ rv = snprintf(bbcmdline, len, "%s %s", filename, cmdline);
+ if (rv == -1 || (size_t)rv >= len)
+ return;
-fail:
- if (bbcmdline)
- lfree(bbcmdline);
- if (bbfilename)
- lfree(bbfilename);
+ SysAppends = ipappend_flags;
+ execute(bbcmdline, type, true);
}
diff --git a/com32/lib/syslinux/serial.c b/com32/lib/syslinux/serial.c
index f06e8c8e..aa5690fa 100644
--- a/com32/lib/syslinux/serial.c
+++ b/com32/lib/syslinux/serial.c
@@ -34,19 +34,22 @@
#include <klibc/compiler.h>
#include <syslinux/config.h>
#include <string.h>
-#include <com32.h>
+#include <bios.h>
+#include <core.h>
struct syslinux_serial_console_info __syslinux_serial_console_info;
-void __constructor __syslinux_get_serial_console_info(void)
+void __syslinux_set_serial_console_info(void)
{
- static com32sys_t reg;
+ uint16_t flowctl;
- memset(&reg, 0, sizeof reg);
- reg.eax.w[0] = 0x000b;
- __intcall(0x22, &reg, &reg);
+ __syslinux_serial_console_info.iobase = SerialPort;
+ __syslinux_serial_console_info.divisor = BaudDivisor;
- __syslinux_serial_console_info.iobase = reg.edx.w[0];
- __syslinux_serial_console_info.divisor = reg.ecx.w[0];
- __syslinux_serial_console_info.flowctl = reg.ebx.w[0];
+ flowctl = FlowOutput | FlowInput | (FlowIgnore << 4);
+
+ if (!DisplayCon)
+ flowctl |= (0x80 << 8);
+
+ __syslinux_serial_console_info.flowctl = flowctl;
}
diff --git a/com32/lib/syslinux/shuffle.c b/com32/lib/syslinux/shuffle.c
index e9ee6aad..1dcdb9d0 100644
--- a/com32/lib/syslinux/shuffle.c
+++ b/com32/lib/syslinux/shuffle.c
@@ -38,6 +38,7 @@
#include <string.h>
#include <inttypes.h>
#include <com32.h>
+#include <core.h>
#include <minmax.h>
#include <dprintf.h>
#include <syslinux/movebits.h>
@@ -51,12 +52,8 @@ static int shuffler_size;
static void __constructor __syslinux_get_shuffer_size(void)
{
- static com32sys_t reg;
-
- reg.eax.w[0] = 0x0023;
- __intcall(0x22, &reg, &reg);
-
- shuffler_size = (reg.eflags.l & EFLAGS_CF) ? 2048 : reg.ecx.w[0];
+ /* +15 padding is to guarantee alignment */
+ shuffler_size = __bcopyxx_len + 15;
}
/*
@@ -135,7 +132,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 +152,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/lib/syslinux/version.c b/com32/lib/syslinux/version.c
index 15b617b0..1cd2efd3 100644
--- a/com32/lib/syslinux/version.c
+++ b/com32/lib/syslinux/version.c
@@ -27,20 +27,23 @@
#include <syslinux/config.h>
#include <klibc/compiler.h>
-#include <com32.h>
+#include <core.h>
+#include <../../../version.h>
struct syslinux_version __syslinux_version;
void __constructor __syslinux_get_version(void)
{
- static com32sys_t reg;
+ __syslinux_version.version = (VERSION_MAJOR << 8) + VERSION_MINOR;
- reg.eax.w[0] = 0x0001;
- __intcall(0x22, &reg, &reg);
+ /* We no longer support the COMBOOT API */
+ __syslinux_version.max_api = 0xffff;
- __syslinux_version.version = reg.ecx.w[0];
- __syslinux_version.max_api = reg.eax.w[0];
- __syslinux_version.filesystem = reg.edx.b[0];
- __syslinux_version.version_string = MK_PTR(reg.es, reg.esi.w[0]);
- __syslinux_version.copyright_string = MK_PTR(reg.es, reg.edi.w[0]);
+ __syslinux_version.filesystem = syslinux_filesystem();
+
+ /* Skip leading CR LF */
+ __syslinux_version.version_string = &syslinux_banner[2];
+
+ /* Skip leading space */
+ __syslinux_version.copyright_string = &copyright_str[1];
}
diff --git a/com32/lib/syslinux/video/fontquery.c b/com32/lib/syslinux/video/fontquery.c
index dd5d86e3..ac1fab3f 100644
--- a/com32/lib/syslinux/video/fontquery.c
+++ b/com32/lib/syslinux/video/fontquery.c
@@ -31,24 +31,18 @@
*/
#include <syslinux/video.h>
-#include <com32.h>
+#include <graphics.h>
/*
* Returns height of font or zero if no custom font loaded
*/
int syslinux_font_query(uint8_t **font)
{
- static com32sys_t ireg;
- com32sys_t oreg;
- int height;
+ if (!UserFont)
+ return 0;
- ireg.eax.w[0] = 0x0018;
- __intcall(0x22, &ireg, &oreg);
+ *font = (uint8_t *)fontbuf;
- height = !(oreg.eflags.l & EFLAGS_CF) ? oreg.eax.b[0] : 0;
- if (height)
- *font = MK_PTR(oreg.es, oreg.ebx.w[0]);
-
- return height;
+ return VGAFontSize;
}
diff --git a/com32/lib/syslinux/video/forcetext.c b/com32/lib/syslinux/video/forcetext.c
deleted file mode 100644
index 136cb279..00000000
--- a/com32/lib/syslinux/video/forcetext.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/* ----------------------------------------------------------------------- *
- *
- * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
- * Copyright 2009 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/video/forcetext.c
- */
-
-#include <syslinux/video.h>
-#include <com32.h>
-
-void syslinux_force_text_mode(void)
-{
- static com32sys_t ireg;
-
- ireg.eax.w[0] = 0x0005;
- __intcall(0x22, &ireg, NULL);
-}
diff --git a/com32/lib/syslinux/video/reportmode.c b/com32/lib/syslinux/video/reportmode.c
index 57fd6fdc..2a2c5770 100644
--- a/com32/lib/syslinux/video/reportmode.c
+++ b/com32/lib/syslinux/video/reportmode.c
@@ -31,15 +31,12 @@
*/
#include <syslinux/video.h>
-#include <com32.h>
+#include <graphics.h>
void syslinux_report_video_mode(uint16_t flags, uint16_t xsize, uint16_t ysize)
{
- static com32sys_t ireg;
+ if (flags > 0x0f)
+ return;
- ireg.eax.w[0] = 0x0017;
- ireg.ebx.w[0] = flags;
- ireg.ecx.w[0] = xsize;
- ireg.edx.w[0] = ysize;
- __intcall(0x22, &ireg, NULL);
+ using_vga(flags, xsize, ysize);
}
diff --git a/com32/lib/vdprintf.c b/com32/lib/vdprintf.c
index c1f90a63..bcf55bb7 100644
--- a/com32/lib/vdprintf.c
+++ b/com32/lib/vdprintf.c
@@ -10,11 +10,7 @@
#include <sys/io.h>
#include <sys/cpu.h>
-#undef DEBUG
-#define DEBUG 1
-#include <dprintf.h>
-
-#ifndef vdprintf
+#ifdef DEBUG_PORT
#define BUFFER_SIZE 4096
@@ -33,10 +29,6 @@ enum serial_port_regs {
SCR = 7,
};
-#ifndef DEBUG_PORT
-# define DEBUG_PORT 0x03f8 /* I/O base address */
-#endif
-
static const uint16_t debug_base = DEBUG_PORT;
static void debug_putc(char c)
@@ -58,7 +50,6 @@ void vdprintf(const char *format, va_list ap)
static bool debug_ok = false;
rv = vsnprintf(buffer, BUFFER_SIZE, format, ap);
-
if (rv < 0)
return;
@@ -117,4 +108,4 @@ void vdprintf(const char *format, va_list ap)
debug_putc(*p++);
}
-#endif /* vdprintf */
+#endif /* DEBUG_PORT */
diff --git a/com32/lib/zalloc.c b/com32/lib/zalloc.c
deleted file mode 100644
index 0e6ed28d..00000000
--- a/com32/lib/zalloc.c
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * zalloc.c
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-void *zalloc(size_t size)
-{
- void *ptr;
-
- ptr = malloc(size);
- if (ptr)
- memset(ptr, 0, size);
-
- return ptr;
-}
diff --git a/com32/libupload/upload_tftp.c b/com32/libupload/upload_tftp.c
index 5e73c1c5..6a0dacb7 100644
--- a/com32/libupload/upload_tftp.c
+++ b/com32/libupload/upload_tftp.c
@@ -53,7 +53,6 @@ const char *tftp_string_error_message[]={
static int send_ack_packet(struct tftp_state *tftp,
const void *pkt, size_t len)
{
- com32sys_t ireg, oreg;
t_PXENV_UDP_WRITE *uw;
t_PXENV_UDP_READ *ur;
clock_t start;
@@ -67,9 +66,6 @@ static int send_ack_packet(struct tftp_state *tftp,
uw = lmalloc(sizeof *uw + len);
ur = lmalloc(sizeof *ur + RCV_BUF);
- memset(&ireg, 0, sizeof ireg);
- ireg.eax.w[0] = 0x0009;
-
for (timeout = timeouts ; *timeout ; timeout++) {
memset(uw, 0, sizeof *uw);
memcpy(uw+1, pkt, len);
@@ -80,11 +76,7 @@ static int send_ack_packet(struct tftp_state *tftp,
uw->buffer_size = len;
uw->buffer = FAR_PTR(uw+1);
- ireg.ebx.w[0] = PXENV_UDP_WRITE;
- ireg.es = SEG(uw);
- ireg.edi.w[0] = OFFS(uw);
-
- __intcall(0x22, &ireg, &oreg);
+ pxe_call(PXENV_UDP_WRITE, uw);
start = times(NULL);
@@ -97,13 +89,9 @@ static int send_ack_packet(struct tftp_state *tftp,
ur->buffer_size = RCV_BUF;
ur->buffer = FAR_PTR(ur+1);
- ireg.ebx.w[0] = PXENV_UDP_READ;
- ireg.es = SEG(ur);
- ireg.edi.w[0] = OFFS(ur);
- __intcall(0x22, &ireg, &oreg);
+ err = pxe_call(PXENV_UDP_READ, ur);
- if (!(oreg.eflags.l & EFLAGS_CF) &&
- ur->status == PXENV_STATUS_SUCCESS &&
+ if (!err && ur->status == PXENV_STATUS_SUCCESS &&
tftp->srv_ip == ur->src_ip &&
(tftp->srv_port == 0 ||
tftp->srv_port == ur->s_port)) {
diff --git a/com32/libutil/Makefile b/com32/libutil/Makefile
index 83e23a0a..5aa7ceb8 100644
--- a/com32/libutil/Makefile
+++ b/com32/libutil/Makefile
@@ -31,19 +31,18 @@
topdir = ../..
MAKEDIR = $(topdir)/mk
-include $(MAKEDIR)/com32.mk
+include $(MAKEDIR)/elf.mk
-LIBOBJS = ansiline.o ansiraw.o get_key.o keyname.o \
+LIBOBJS = ansiline.o ansiraw.o keyname.o \
sha1hash.o unbase64.o \
- md5.o crypt-md5.o sha256crypt.o sha512crypt.o base64.o
+ md5.o crypt-md5.o sha256crypt.o sha512crypt.o base64.o \
+ quicksort.o
LNXLIBOBJS = $(patsubst %.o,%.lo,$(LIBOBJS))
-all: libutil_com.a libutil_lnx.a
+all: libutil.c32 libutil_lnx.a
-libutil_com.a: $(LIBOBJS)
- rm -f $@
- $(AR) cq $@ $(LIBOBJS)
- $(RANLIB) $@
+libutil.elf: $(LIBOBJS)
+ $(LD) $(LDFLAGS) -soname $(patsubst %.elf,%.c32,$(@F)) -o $@ $^
libutil_lnx.a: $(LNXLIBOBJS)
rm -f $@
@@ -62,6 +61,6 @@ spotless: clean
install: all
mkdir -m 755 -p $(INSTALLROOT)$(COM32DIR)
- install -m 644 libutil_com.a libutil_lnx.a $(INSTALLROOT)$(COM32DIR)
+ install -m 644 libutil_lnx.a $(INSTALLROOT)$(COM32DIR)
-include .*.d
diff --git a/com32/libutil/ansiraw.c b/com32/libutil/ansiraw.c
index 2afd48a7..b67768c5 100644
--- a/com32/libutil/ansiraw.c
+++ b/com32/libutil/ansiraw.c
@@ -47,6 +47,7 @@ void console_ansi_raw(void)
#include <stdio.h>
#include <termios.h>
+#include <unistd.h>
static struct termios original_termios_settings;
@@ -82,4 +83,22 @@ void console_ansi_raw(void)
tcsetattr(0, TCSAFLUSH, &tio);
}
+int raw_read(int fd, void *buf, size_t count)
+{
+ struct termios tio, rtio;
+ int rv;
+
+ tcgetattr(fd, &tio);
+
+ cfmakeraw(&rtio);
+ tcsetattr(fd, 0, &rtio);
+
+ rv = read(fd, buf, count);
+
+ /* Restore settings */
+ tcsetattr(fd, 0, &tio);
+
+ return rv;
+}
+
#endif
diff --git a/com32/libutil/include/getkey.h b/com32/libutil/include/getkey.h
index a46de812..0733723b 100644
--- a/com32/libutil/include/getkey.h
+++ b/com32/libutil/include/getkey.h
@@ -77,8 +77,11 @@
#define KEY_MAX 0x012a
+#define KEY_MAXLEN 8
+
int get_key(FILE *, clock_t);
int key_name_to_code(const char *);
const char *key_code_to_name(int);
+int get_key_decode(char *, int, int *);
#endif /* LIBUTIL_GETKEY_H */
diff --git a/com32/libutil/quicksort.c b/com32/libutil/quicksort.c
new file mode 100644
index 00000000..32ac0f01
--- /dev/null
+++ b/com32/libutil/quicksort.c
@@ -0,0 +1,59 @@
+/*
+ * sort.c - Sample ELF module providing a quick sort function
+ *
+ * Created on: Aug 11, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+#include <stdlib.h>
+
+static inline void swap(int *x, int *y)
+{
+ int tmp;
+ tmp = *x;
+ *x = *y;
+ *y = tmp;
+}
+
+static inline int randint(int l, int u)
+{
+ return l + (rand() % (u - l + 1));
+}
+
+/**
+ * quick_sort_range - A small and efficient version of quicksort.
+ * @nums: The numbers to sort
+ * @l: The lower index in the vector (inclusive)
+ * @u: The upper index in the vector (inclusive)
+ *
+ * The implementation is taken from "Beautiful Code", by O'Reilly, the
+ * book students received from Google as a gift for their acceptance
+ * in the GSoC 2008 program. The code belongs to Jon Bentley, who
+ * wrote the third chapter of the book. Since ELF modules were written
+ * as part of this program, the author of the module considered
+ * the book had to be put to some use. :)
+ */
+static void quick_sort_range(int *nums, int l, int u)
+{
+ int i, m;
+ if (l >= u)
+ return;
+
+ swap(&nums[l], &nums[randint(l, u)]);
+
+ m = l;
+ for (i = l + 1; i <= u; i++) {
+ if (nums[i] < nums[l])
+ swap(&nums[++m], &nums[i]);
+ }
+
+ swap(&nums[l], &nums[m]);
+
+ quick_sort_range(nums, l, m - 1);
+ quick_sort_range(nums, m + 1, u);
+}
+
+void quick_sort(int *nums, int count)
+{
+ quick_sort_range(nums, 0, count - 1);
+}
diff --git a/com32/lua/etc/luavs.bat b/com32/lua/etc/luavs.bat
index 08c2bedd..054b4625 100644
--- a/com32/lua/etc/luavs.bat
+++ b/com32/lua/etc/luavs.bat
@@ -1,28 +1,28 @@
-@rem Script to build Lua under "Visual Studio .NET Command Prompt".
-@rem Do not run from this directory; run it from the toplevel: etc\luavs.bat .
-@rem It creates lua51.dll, lua51.lib, lua.exe, and luac.exe in src.
-@rem (contributed by David Manura and Mike Pall)
-
-@setlocal
-@set MYCOMPILE=cl /nologo /MD /O2 /W3 /c /D_CRT_SECURE_NO_DEPRECATE
-@set MYLINK=link /nologo
-@set MYMT=mt /nologo
-
-cd src
-%MYCOMPILE% /DLUA_BUILD_AS_DLL l*.c
-del lua.obj luac.obj
-%MYLINK% /DLL /out:lua51.dll l*.obj
-if exist lua51.dll.manifest^
- %MYMT% -manifest lua51.dll.manifest -outputresource:lua51.dll;2
-%MYCOMPILE% /DLUA_BUILD_AS_DLL lua.c
-%MYLINK% /out:lua.exe lua.obj lua51.lib
-if exist lua.exe.manifest^
- %MYMT% -manifest lua.exe.manifest -outputresource:lua.exe
-%MYCOMPILE% l*.c print.c
-del lua.obj linit.obj lbaselib.obj ldblib.obj liolib.obj lmathlib.obj^
- loslib.obj ltablib.obj lstrlib.obj loadlib.obj
-%MYLINK% /out:luac.exe *.obj
-if exist luac.exe.manifest^
- %MYMT% -manifest luac.exe.manifest -outputresource:luac.exe
-del *.obj *.manifest
-cd ..
+@rem Script to build Lua under "Visual Studio .NET Command Prompt".
+@rem Do not run from this directory; run it from the toplevel: etc\luavs.bat .
+@rem It creates lua51.dll, lua51.lib, lua.exe, and luac.exe in src.
+@rem (contributed by David Manura and Mike Pall)
+
+@setlocal
+@set MYCOMPILE=cl /nologo /MD /O2 /W3 /c /D_CRT_SECURE_NO_DEPRECATE
+@set MYLINK=link /nologo
+@set MYMT=mt /nologo
+
+cd src
+%MYCOMPILE% /DLUA_BUILD_AS_DLL l*.c
+del lua.obj luac.obj
+%MYLINK% /DLL /out:lua51.dll l*.obj
+if exist lua51.dll.manifest^
+ %MYMT% -manifest lua51.dll.manifest -outputresource:lua51.dll;2
+%MYCOMPILE% /DLUA_BUILD_AS_DLL lua.c
+%MYLINK% /out:lua.exe lua.obj lua51.lib
+if exist lua.exe.manifest^
+ %MYMT% -manifest lua.exe.manifest -outputresource:lua.exe
+%MYCOMPILE% l*.c print.c
+del lua.obj linit.obj lbaselib.obj ldblib.obj liolib.obj lmathlib.obj^
+ loslib.obj ltablib.obj lstrlib.obj loadlib.obj
+%MYLINK% /out:luac.exe *.obj
+if exist luac.exe.manifest^
+ %MYMT% -manifest luac.exe.manifest -outputresource:luac.exe
+del *.obj *.manifest
+cd ..
diff --git a/com32/lua/src/Makefile b/com32/lua/src/Makefile
index f03f7a7f..d70d23ea 100644
--- a/com32/lua/src/Makefile
+++ b/com32/lua/src/Makefile
@@ -17,7 +17,7 @@
topdir = ../../..
MAKEDIR = $(topdir)/mk
-include $(MAKEDIR)/com32.mk
+include $(MAKEDIR)/elf.mk
LNXLIBS =
@@ -30,7 +30,7 @@ TESTFILES =
OBJS = lua.o
-LIBLUA = liblua.a
+LIBLUA = liblua.c32
LIBLUA_OBJS := lapi.o lcode.o ldebug.o ldo.o ldump.o lfunc.o
LIBLUA_OBJS += lgc.o llex.o lmem.o lobject.o lopcodes.o lparser.o
@@ -50,16 +50,15 @@ CFLAGS += -DLUA_ANSI
all: $(MODULES) $(TESTFILES)
-$(LIBLUA) : $(LIBLUA_OBJS)
- rm -f $@
- $(AR) cq $@ $^
- $(RANLIB) $@
+liblua.elf : $(LIBLUA_OBJS)
+ $(LD) $(LDFLAGS) -shared -soname $(patsubst %.elf,%.c32,$(@F)) \
+ -o $@ $^
lua.elf : $(OBJS) $(LIBLUA) $(C_LIBS)
$(LD) $(LDFLAGS) -o $@ $^
tidy dist:
- rm -f *.o *.lo *.a *.lst *.elf .*.d *.tmp
+ rm -f *.o *.lo *.lst *.elf .*.d *.tmp
clean: tidy
rm -f *.lnx
diff --git a/com32/lua/src/vesa.c b/com32/lua/src/vesa.c
index 9f281348..06649e11 100644
--- a/com32/lua/src/vesa.c
+++ b/com32/lua/src/vesa.c
@@ -17,10 +17,15 @@ static int vesa_getmodes(lua_State *L)
struct vesa_general_info *gi;
struct vesa_mode_info *mi;
int nmode = 1;
+ int rv = -1;
- /* Allocate space in the bounce buffer for these structures */
- gi = &((struct vesa_info *)__com32.cs_bounce)->gi;
- mi = &((struct vesa_info *)__com32.cs_bounce)->mi;
+ gi = lmalloc(sizeof *gi);
+ if (!gi)
+ return -1;
+
+ mi = lmalloc(sizeof *mi);
+ if (!mi)
+ goto out;
memset(&rm, 0, sizeof rm);
memset(gi, 0, sizeof *gi);
@@ -32,11 +37,15 @@ static int vesa_getmodes(lua_State *L)
__intcall(0x10, &rm, &rm);
if ( rm.eax.w[0] != 0x004F )
- return -1; /* Function call failed */
- if ( gi->signature != VESA_MAGIC )
- return -2; /* No magic */
- if ( gi->version < 0x0102 )
- return -3; /* VESA 1.2+ required */
+ goto out; /* Function call failed */
+ if ( gi->signature != VESA_MAGIC ) {
+ rv = -2; /* No magic */
+ goto out;
+ }
+ if ( gi->version < 0x0102 ) {
+ rv = -3; /* VESA 1.2+ required */
+ goto out;
+ }
lua_newtable(L); /* list of modes */
@@ -86,7 +95,11 @@ static int vesa_getmodes(lua_State *L)
}
- return 1;
+ rv = 1;
+out:
+ lfree(mi);
+ lfree(gi);
+ return rv;
}
diff --git a/com32/mboot/Makefile b/com32/mboot/Makefile
index b7ee1154..6e010b1c 100644
--- a/com32/mboot/Makefile
+++ b/com32/mboot/Makefile
@@ -17,7 +17,7 @@
topdir = ../..
MAKEDIR = $(topdir)/mk
-include $(MAKEDIR)/com32.mk
+include $(MAKEDIR)/elf.mk
LNXLIBS = ../libutil/libutil_lnx.a
diff --git a/com32/mboot/initvesa.c b/com32/mboot/initvesa.c
index cf2707df..bd869e3d 100644
--- a/com32/mboot/initvesa.c
+++ b/com32/mboot/initvesa.c
@@ -38,6 +38,7 @@
#include <stdlib.h>
#include <string.h>
#include <limits.h>
+#include <graphics.h>
#include "vesa.h"
#include "mboot.h"
@@ -61,9 +62,13 @@ void set_graphics_mode(const struct multiboot_header *mbh,
if (!(mbh->flags & MULTIBOOT_VIDEO_MODE) || mbh->mode_type != 0)
return;
- /* Allocate space in the bounce buffer for these structures */
- gi = &((struct vesa_info *)__com32.cs_bounce)->gi;
- mi = &((struct vesa_info *)__com32.cs_bounce)->mi;
+ gi = lmalloc(sizeof *gi);
+ if (!gi)
+ return;
+
+ mi = lmalloc(sizeof *mi);
+ if (!mi)
+ goto out;
memset(&rm, 0, sizeof rm);
memset(gi, 0, sizeof *gi);
@@ -75,11 +80,11 @@ void set_graphics_mode(const struct multiboot_header *mbh,
__intcall(0x10, &rm, &rm);
if (rm.eax.w[0] != 0x004F)
- return; /* Function call failed */
+ goto out; /* Function call failed */
if (gi->signature != VESA_MAGIC)
- return; /* No magic */
+ goto out; /* No magic */
if (gi->version < 0x0102)
- return; /* VESA 1.2+ required */
+ goto out; /* VESA 1.2+ required */
memcpy(&vesa_info.gi, gi, sizeof *gi);
@@ -182,7 +187,7 @@ void set_graphics_mode(const struct multiboot_header *mbh,
}
if (!bestpxf)
- return; /* No mode found */
+ goto out; /* No mode found */
mi = &vesa_info.mi;
mode = bestmode;
@@ -193,7 +198,7 @@ void set_graphics_mode(const struct multiboot_header *mbh,
rm.ebx.w[0] = mode;
__intcall(0x10, &rm, &rm);
if (rm.eax.w[0] != 0x004F)
- return; /* Failed to set mode */
+ goto out; /* Failed to set mode */
mbi->flags |= MB_INFO_VIDEO_INFO;
mbi->vbe_mode = mode;
@@ -211,16 +216,16 @@ void set_graphics_mode(const struct multiboot_header *mbh,
mbi->vbe_interface_len = rm.ecx.w[0];
}
- /* Tell syslinux we changed video mode */
- rm.eax.w[0] = 0x0017; /* Report video mode change */
/* In theory this should be:
-
- rm.ebx.w[0] = (mi->mode_attr & 4) ? 0x0007 : 0x000f;
-
- However, that would assume all systems that claim to handle text
- output in VESA modes actually do that... */
- rm.ebx.w[0] = 0x000f;
- rm.ecx.w[0] = vesa_info.mi.h_res;
- rm.edx.w[0] = vesa_info.mi.v_res;
- __intcall(0x22, &rm, NULL);
+ *
+ * UsingVga = (mi->mode_attr & 4) ? 0x0007 : 0x000f;
+ *
+ * However, that would assume all systems that claim to handle text
+ * output in VESA modes actually do that...
+ */
+ graphics_using_vga(0x0F, vesa_info.mi.h_res, vesa_info.mi.v_res);
+
+out:
+ lfree(mi);
+ lfree(gi);
}
diff --git a/com32/mboot/mem.c b/com32/mboot/mem.c
index 6a31fac0..6e3995bf 100644
--- a/com32/mboot/mem.c
+++ b/com32/mboot/mem.c
@@ -49,9 +49,10 @@ struct e820_entry {
static int mboot_scan_memory(struct AddrRangeDesc **ardp, uint32_t * dosmem)
{
com32sys_t ireg, oreg;
- struct e820_entry *e820buf = __com32.cs_bounce;
+ struct e820_entry *e820buf;
struct AddrRangeDesc *ard;
size_t ard_count, ard_space;
+ int rv = 0;
/* Use INT 12h to get DOS memory */
__intcall(0x12, &__com32_zero_regs, &oreg);
@@ -65,10 +66,14 @@ static int mboot_scan_memory(struct AddrRangeDesc **ardp, uint32_t * dosmem)
*dosmem = 640 * 1024; /* Hope for the best... */
}
+ e820buf = lmalloc(sizeof(*e820buf));
+ if (!e820buf)
+ return 0;
+
/* Allocate initial space */
*ardp = ard = malloc(RANGE_ALLOC_BLOCK * sizeof *ard);
if (!ard)
- return 0;
+ goto out;
ard_count = 0;
ard_space = RANGE_ALLOC_BLOCK;
@@ -93,8 +98,10 @@ static int mboot_scan_memory(struct AddrRangeDesc **ardp, uint32_t * dosmem)
if (ard_count >= ard_space) {
ard_space += RANGE_ALLOC_BLOCK;
*ardp = ard = realloc(ard, ard_space * sizeof *ard);
- if (!ard)
- return ard_count;
+ if (!ard) {
+ rv = ard_count;
+ goto out;
+ }
}
ard[ard_count].size = 20;
@@ -106,8 +113,10 @@ static int mboot_scan_memory(struct AddrRangeDesc **ardp, uint32_t * dosmem)
ireg.ebx.l = oreg.ebx.l;
} while (oreg.ebx.l);
- if (ard_count)
- return ard_count;
+ if (ard_count) {
+ rv = ard_count;
+ goto out;
+ };
ard[0].size = 20;
ard[0].BaseAddr = 0;
@@ -129,10 +138,12 @@ static int mboot_scan_memory(struct AddrRangeDesc **ardp, uint32_t * dosmem)
ard[2].BaseAddr = 16 << 20;
ard[2].Length = oreg.edx.w[0] << 16;
ard[2].Type = 1;
- return 3;
+ rv = 3;
} else {
- return 2;
+ rv = 2;
}
+
+ goto out;
}
/* Finally try INT 15h AH=88h */
@@ -142,10 +153,14 @@ static int mboot_scan_memory(struct AddrRangeDesc **ardp, uint32_t * dosmem)
ard[1].BaseAddr = 1 << 20;
ard[1].Length = oreg.ecx.w[0] << 10;
ard[1].Type = 1;
- return 2;
+ rv = 2;
+ goto out;
}
- return 1; /* ... problematic ... */
+ rv = 1; /* ... problematic ... */
+out:
+ lfree(e820buf);
+ return rv;
}
void mboot_make_memmap(void)
diff --git a/com32/menu/Makefile b/com32/menu/Makefile
index b67b997d..e62c6b87 100644
--- a/com32/menu/Makefile
+++ b/com32/menu/Makefile
@@ -16,7 +16,7 @@
topdir = ../..
MAKEDIR = $(topdir)/mk
-include $(MAKEDIR)/com32.mk
+include $(MAKEDIR)/elf.mk
LNXLIBS = ../libutil/libutil_lnx.a
@@ -24,7 +24,7 @@ MODULES = menu.c32 vesamenu.c32
TESTFILES =
COMMONOBJS = menumain.o readconfig.o passwd.o drain.o printmsg.o colors.o \
- background.o refstr.o execute.o
+ background.o refstr.o
all: $(MODULES) $(TESTFILES)
diff --git a/com32/menu/execute.c b/com32/menu/execute.c
deleted file mode 100644
index c2de7353..00000000
--- a/com32/menu/execute.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/* ----------------------------------------------------------------------- *
- *
- * Copyright 2004-2008 H. Peter Anvin - 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.
- *
- * ----------------------------------------------------------------------- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <com32.h>
-#include "menu.h"
-
-void execute(const char *cmdline, enum kernel_type type)
-{
- com32sys_t ireg;
- const char *p, *const *pp;
- char *q = __com32.cs_bounce;
- const char *kernel, *args;
-
- memset(&ireg, 0, sizeof ireg);
-
- kernel = q;
- p = cmdline;
- while (*p && !my_isspace(*p)) {
- *q++ = *p++;
- }
- *q++ = '\0';
-
- args = q;
- while (*p && my_isspace(*p))
- p++;
-
- strcpy(q, p);
-
- if (kernel[0] == '.' && type == KT_NONE) {
- /* It might be a type specifier */
- enum kernel_type type = KT_NONE;
- for (pp = kernel_types; *pp; pp++, type++) {
- if (!strcmp(kernel + 1, *pp)) {
- execute(p, type); /* Strip the type specifier and retry */
- }
- }
- }
-
- if (type == KT_LOCALBOOT) {
- ireg.eax.w[0] = 0x0014; /* Local boot */
- ireg.edx.w[0] = strtoul(kernel, NULL, 0);
- } else {
- if (type < KT_KERNEL)
- type = KT_KERNEL;
-
- ireg.eax.w[0] = 0x0016; /* Run kernel image */
- ireg.esi.w[0] = OFFS(kernel);
- ireg.ds = SEG(kernel);
- ireg.ebx.w[0] = OFFS(args);
- ireg.es = SEG(args);
- ireg.edx.l = type - KT_KERNEL;
- /* ireg.ecx.l = 0; *//* We do ipappend "manually" */
- }
-
- __intcall(0x22, &ireg, NULL);
-
- /* If this returns, something went bad; return to menu */
-}
diff --git a/com32/menu/menumain.c b/com32/menu/menumain.c
index 8573901c..a3061ede 100644
--- a/com32/menu/menumain.c
+++ b/com32/menu/menumain.c
@@ -28,7 +28,9 @@
#include <setjmp.h>
#include <limits.h>
#include <com32.h>
+#include <core.h>
#include <syslinux/adv.h>
+#include <syslinux/boot.h>
#include "menu.h"
@@ -1157,9 +1159,13 @@ int main(int argc, char *argv[])
printf("\033[?25h\033[%d;1H\033[0m", END_ROW);
if (cmdline) {
- execute(cmdline, KT_NONE);
- if (cm->onerror)
- execute(cm->onerror, KT_NONE);
+ uint32_t type = parse_image_type(cmdline);
+
+ execute(cmdline, type, false);
+ if (cm->onerror) {
+ type = parse_image_type(cm->onerror);
+ execute(cm->onerror, type, true);
+ }
} else {
return 0; /* Exit */
}
diff --git a/com32/menu/readconfig.c b/com32/menu/readconfig.c
index 431017f6..b7814be2 100644
--- a/com32/menu/readconfig.c
+++ b/com32/menu/readconfig.c
@@ -62,7 +62,7 @@ static const struct messages messages[MSG_COUNT] = {
__p; })
/* Must match enum kernel_type */
-const char *const kernel_types[] = {
+static const char *const kernel_types[] = {
"none",
"localboot",
"kernel",
@@ -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,11 +1044,13 @@ 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 ((ep = looking_at(p, "ipappend")) ||
+ (ep = looking_at(p, "sysappend"))) {
+ uint32_t s = strtoul(skipspace(ep), NULL, 0);
if (ld.label)
- ld.ipappend = atoi(skipspace(p + 8));
+ ld.ipappend = s;
else
- ipappend = atoi(skipspace(p + 8));
+ ipappend = s;
} else if (looking_at(p, "default")) {
refstr_put(globaldefault);
globaldefault = refstrdup(skipspace(p + 7));
diff --git a/com32/modules/Makefile b/com32/modules/Makefile
index f110e584..d801a260 100644
--- a/com32/modules/Makefile
+++ b/com32/modules/Makefile
@@ -17,33 +17,25 @@
topdir = ../..
MAKEDIR = $(topdir)/mk
-include $(MAKEDIR)/com32.mk
+include $(MAKEDIR)/elf.mk
MODULES = config.c32 ethersel.c32 dmitest.c32 cpuidtest.c32 \
disk.c32 pcitest.c32 elf.c32 linux.c32 reboot.c32 pmload.c32 \
meminfo.c32 sdi.c32 sanboot.c32 ifcpu64.c32 vesainfo.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
+ whichsys.c32 prdhcp.c32 pxechn.c32 kontron_wdt.c32 ifmemdsk.c32 \
+ hexdump.c32 poweroff.c32 cptime.c32 debug.c32
TESTFILES =
all: $(MODULES) $(TESTFILES)
-pcitest.elf : pcitest.o $(LIBS) $(C_LIBS)
- $(LD) $(LDFLAGS) -o $@ $^
-
-cpuidtest.elf : cpuidtest.o $(GPLLIB) $(LIBS) $(C_LIBS)
- $(LD) $(LDFLAGS) -o $@ $^
-
.PRECIOUS: %.o
dmitest.o: dmitest.c
$(CC) $(CFLAGS) $(GPLINCLUDE) -c -o $@ $<
-dmitest.elf : dmi_utils.o dmitest.o $(GPLLIB) $(LIBS) $(C_LIBS)
- $(LD) $(LDFLAGS) -o $@ $^
-
-ethersel.elf : ethersel.o $(LIBS) $(C_LIBS)
+dmitest.elf : dmi_utils.o dmitest.o $(C_LIBS)
$(LD) $(LDFLAGS) -o $@ $^
tidy dist:
diff --git a/com32/modules/cat.c b/com32/modules/cat.c
index 0a9514c4..2a7683f2 100644
--- a/com32/modules/cat.c
+++ b/com32/modules/cat.c
@@ -9,8 +9,6 @@ int main(int argc, char *argv[])
int len;
char buf[4096];
- openconsole(&dev_stdcon_r, &dev_stdcon_w);
-
if (argc < 2) {
fprintf(stderr, "Usage: %s filename...\n", argv[0]);
return 1;
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/config.c b/com32/modules/config.c
index 334a635c..04cb0ab2 100644
--- a/com32/modules/config.c
+++ b/com32/modules/config.c
@@ -24,8 +24,6 @@
int main(int argc, char *argv[])
{
- openconsole(&dev_null_r, &dev_stdcon_w);
-
if (argc < 2 || argc > 3) {
fprintf(stderr, "Usage: config <filename> [<directory>]\n");
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/cpuid.c b/com32/modules/cpuid.c
index 78cb3f58..a2438960 100644
--- a/com32/modules/cpuid.c
+++ b/com32/modules/cpuid.c
@@ -34,8 +34,6 @@ int main(int argc, char *argv[])
uint32_t leaf, counter;
uint32_t eax, ebx, ecx, edx;
- openconsole(&dev_null_r, &dev_stdcon_w);
-
if (argc < 2 || argc > 4) {
printf("Usage: %s leaf [counter]\n", argv[0]);
exit(1);
diff --git a/com32/modules/cpuidtest.c b/com32/modules/cpuidtest.c
index b7688852..d00256fa 100644
--- a/com32/modules/cpuidtest.c
+++ b/com32/modules/cpuidtest.c
@@ -42,7 +42,6 @@ char display_line;
int main(void)
{
s_cpu cpu;
- openconsole(&dev_stdcon_r, &dev_stdcon_w);
for (;;) {
detect_cpu(&cpu);
diff --git a/com32/modules/debug.c b/com32/modules/debug.c
new file mode 100644
index 00000000..1026ebf3
--- /dev/null
+++ b/com32/modules/debug.c
@@ -0,0 +1,54 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2013 Intel Corporation; author: Matt Fleming
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <syslinux/debug.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static char *progname;
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: %s [-e|-d] <func1> [<func2>, ...]\n", progname);
+}
+
+int main(int argc, char *argv[])
+{
+ bool enable;
+ int i;
+
+ progname = argv[0];
+
+ if (argc < 3) {
+ usage();
+ return -1;
+ }
+
+ if (!strncmp(argv[1], "-e", 2))
+ enable = true;
+ else if (!strncmp(argv[1], "-d", 2))
+ enable = false;
+ else {
+ usage();
+ return -1;
+ }
+
+ for (i = 2; i < argc; i++) {
+ char *str = argv[i];
+
+ if (syslinux_debug(str, enable) < 0)
+ fprintf(stderr, "Failed to debug symbol \"%s\"\n", str);
+ }
+
+ return 0;
+}
diff --git a/com32/modules/dir.c b/com32/modules/dir.c
new file mode 100644
index 00000000..01a99ed5
--- /dev/null
+++ b/com32/modules/dir.c
@@ -0,0 +1,175 @@
+/*
+ * Display directory contents
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <console.h>
+#include <string.h>
+#include <com32.h>
+#include <dirent.h>
+#include <minmax.h>
+#include <unistd.h>
+#include <getkey.h>
+
+static int rows, cols; /* Screen parameters */
+
+#define DIR_CHUNK 1024
+
+static const char *type_str(int type)
+{
+ switch (type) {
+ case DT_FIFO:
+ return "[fif]";
+ case DT_CHR:
+ return "[chr]";
+ case DT_DIR:
+ return "[dir]";
+ case DT_BLK:
+ return "[blk]";
+ case DT_UNKNOWN:
+ case DT_REG:
+ return "";
+ case DT_LNK:
+ return "[lnk]";
+ case DT_SOCK:
+ return "[sck]";
+ case DT_WHT:
+ return "[wht]";
+ default:
+ return "[???]";
+ }
+}
+
+static void free_dirents(struct dirent **dex, size_t n_de)
+{
+ size_t i;
+
+ for (i = 0; i < n_de; i++)
+ free(dex[i]);
+
+ free(dex);
+}
+
+static int compare_dirent(const void *p_de1, const void *p_de2)
+{
+ const struct dirent *de1 = *(const struct dirent **)p_de1;
+ const struct dirent *de2 = *(const struct dirent **)p_de2;
+ int ndir1, ndir2;
+
+ ndir1 = de1->d_type != DT_DIR;
+ ndir2 = de2->d_type != DT_DIR;
+
+ if (ndir1 != ndir2)
+ return ndir1 - ndir2;
+
+ return strcmp(de1->d_name, de2->d_name);
+}
+
+static int display_directory(const char *dirname)
+{
+ DIR *dir;
+ struct dirent *de;
+ struct dirent **dex = NULL;
+ size_t n_dex = 0, n_de = 0;
+ size_t i, j, k;
+ size_t nrows, ncols, perpage;
+ size_t endpage;
+ int maxlen = 0;
+ int pos, tpos, colwidth;
+
+ dir = opendir(dirname);
+ if (!dir) {
+ printf("Unable to read directory: %s\n", dirname);
+ return -1;
+ }
+
+ while ((de = readdir(dir)) != NULL) {
+ struct dirent *nde;
+
+ if (n_de >= n_dex) {
+ struct dirent **ndex;
+
+ ndex = realloc(dex, (n_dex + DIR_CHUNK) * sizeof *dex);
+ if (!ndex)
+ goto nomem;
+
+ dex = ndex;
+ n_dex += DIR_CHUNK;
+ }
+
+ nde = malloc(de->d_reclen);
+ if (!nde)
+ goto nomem;
+
+ memcpy(nde, de, de->d_reclen);
+ dex[n_de++] = nde;
+
+ maxlen = max(maxlen, de->d_reclen);
+ }
+
+ closedir(dir);
+
+ qsort(dex, n_de, sizeof *dex, compare_dirent);
+
+ maxlen -= offsetof(struct dirent, d_name) + 1;
+ ncols = (cols + 2)/(maxlen + 8);
+ ncols = min(ncols, n_de);
+ ncols = max(ncols, 1U);
+ colwidth = (cols + 2)/ncols;
+ perpage = ncols * (rows - 1);
+
+ for (i = 0; i < n_de; i += perpage) {
+ /* Rows on this page */
+ endpage = min(i+perpage, n_de);
+ nrows = ((endpage-i) + ncols - 1)/ncols;
+
+ for (j = 0; j < nrows; j++) {
+ pos = tpos = 0;
+ for (k = i+j; k < endpage; k += nrows) {
+ pos += printf("%*s%-5s %s",
+ (tpos - pos), "",
+ type_str(dex[k]->d_type),
+ dex[k]->d_name);
+ tpos += colwidth;
+ }
+ printf("\n");
+ }
+
+ if (endpage >= n_de)
+ break;
+
+ get_key(stdin, 0);
+ }
+
+ free_dirents(dex, n_de);
+ return 0;
+
+nomem:
+ closedir(dir);
+ printf("Out of memory error!\n");
+ free_dirents(dex, n_de);
+ return -1;
+}
+
+int main(int argc, char *argv[])
+{
+ int rv;
+
+ if (getscreensize(1, &rows, &cols)) {
+ /* Unknown screen size? */
+ rows = 24;
+ cols = 80;
+ }
+
+ if (argc < 2)
+ rv = display_directory(".");
+ else if (argc == 2)
+ rv = display_directory(argv[1]);
+ else {
+ printf("Usage: dir directory\n");
+ rv = 1;
+ }
+
+ return rv ? 1 : 0;
+}
+
diff --git a/com32/modules/disk.c b/com32/modules/disk.c
index ca4b5988..5d68381e 100644
--- a/com32/modules/disk.c
+++ b/com32/modules/disk.c
@@ -27,8 +27,6 @@ int main(int argc, char *argv[])
(void)argc;
(void)argv;
- openconsole(&dev_null_r, &dev_stdcon_w);
-
for (int disk = 0x80; disk < 0xff; disk++) {
memset(d, 0, sizeof(struct driveinfo));
d->disk = disk;
diff --git a/com32/modules/dmitest.c b/com32/modules/dmitest.c
index 294585bb..4ce2eaad 100644
--- a/com32/modules/dmitest.c
+++ b/com32/modules/dmitest.c
@@ -179,7 +179,6 @@ int main(void)
{
char buffer[1024];
s_dmi dmi;
- openconsole(&dev_stdcon_r, &dev_stdcon_w);
if (dmi_iterate(&dmi) == -ENODMITABLE) {
printf("No DMI Structure found\n");
diff --git a/com32/modules/elf.c b/com32/modules/elf.c
index 0ac45174..a946af1f 100644
--- a/com32/modules/elf.c
+++ b/com32/modules/elf.c
@@ -263,8 +263,6 @@ int main(int argc, char *argv[])
void *data;
size_t data_len;
- openconsole(&dev_null_r, &dev_stdcon_w);
-
if (argc < 2) {
error("Usage: elf.c32 elf_file arguments...\n");
return 1;
diff --git a/com32/modules/ethersel.c b/com32/modules/ethersel.c
index 28dc62ca..039de276 100644
--- a/com32/modules/ethersel.c
+++ b/com32/modules/ethersel.c
@@ -180,7 +180,6 @@ int main(int argc, char *argv[])
struct match *list, *match;
struct pci_domain *pci_domain;
- openconsole(&dev_null_r, &dev_stdcon_w);
pci_domain = pci_scan();
if (pci_domain) {
diff --git a/com32/modules/gpxecmd.c b/com32/modules/gpxecmd.c
index 057659bd..d2d90a2f 100644
--- a/com32/modules/gpxecmd.c
+++ b/com32/modules/gpxecmd.c
@@ -22,7 +22,9 @@
#include <console.h>
#include <com32.h>
#include <string.h>
+
#include <sys/gpxe.h>
+#include <syslinux/pxe_api.h>
struct segoff16 {
uint16_t offs, seg;
@@ -37,11 +39,11 @@ static void gpxecmd(const char **args)
{
char *q;
struct s_PXENV_FILE_EXEC *fx;
- com32sys_t reg;
- memset(&reg, 0, sizeof reg);
+ fx = lmalloc(sizeof *fx);
+ if (!fx)
+ return;
- fx = __com32.cs_bounce;
q = (char *)(fx + 1);
fx->Status = 1;
@@ -55,21 +57,13 @@ static void gpxecmd(const char **args)
}
*--q = '\0';
- memset(&reg, 0, sizeof reg);
- reg.eax.w[0] = 0x0009;
- reg.ebx.w[0] = 0x00e5; /* PXENV_FILE_EXEC */
- reg.edi.w[0] = OFFS(fx);
- reg.es = SEG(fx);
-
- __intcall(0x22, &reg, &reg);
+ pxe_call(PXENV_FILE_EXEC, fx);
/* This should not return... */
}
int main(int argc, const char *argv[])
{
- openconsole(&dev_null_r, &dev_stdcon_w);
-
if (argc < 2) {
printf("Usage: gpxecmd command...\n");
return 1;
diff --git a/com32/modules/hexdump.c b/com32/modules/hexdump.c
new file mode 100644
index 00000000..bc2c70dd
--- /dev/null
+++ b/com32/modules/hexdump.c
@@ -0,0 +1,245 @@
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <console.h>
+#include <errno.h>
+#include <syslinux/loadfile.h>
+
+/* Macros */
+#define ROWS_PER_PAGE 24
+#define COLS_PER_ROW 16
+#define BYTES_PER_PAGE (ROWS_PER_PAGE * COLS_PER_ROW)
+
+/* Functions declarations */
+static int usage(void);
+static void eat_stdin(void);
+static int do_page(void);
+static void hexdump(const void *memory, size_t bytes);
+
+/* Objects */
+static const char *prog_name;
+static int opt_page;
+static int opt_no_buffer;
+static int opt_extended_ascii;
+
+int main(int argc, char **argv)
+{
+ int rc;
+ const char *filename;
+ int i;
+ void *file_data;
+ size_t file_sz;
+ FILE *f;
+ size_t len;
+ const char *cur_pos;
+
+ /* Assume failure */
+ rc = EXIT_FAILURE;
+
+ /* Determine the program name, as invoked */
+ if (argc < 1 || !argv || !argv[0]) {
+ fprintf(stderr, "argc or argv failure!\n");
+ goto err_prog_name;
+ }
+ prog_name = argv[0];
+
+ /* Process arguments */
+ filename = NULL;
+ for (i = 1; i < argc; ++i) {
+ if (!argv[i]) {
+ fprintf(stderr, "argc and argv mismatch!\n");
+ goto err_argv;
+ }
+
+ if (!strncmp(argv[i], "--page", sizeof "--page") ||
+ !strncmp(argv[i], "-p", sizeof "-p")) {
+ opt_page = 1;
+ continue;
+ }
+
+ if (!strncmp(argv[i], "--no-buffer", sizeof "--no-buffer")) {
+ opt_no_buffer = 1;
+ continue;
+ }
+
+ if (!strncmp(argv[i], "--extended-ascii", sizeof "--extended-ascii")) {
+ opt_extended_ascii = 1;
+ continue;
+ }
+
+ if (!strncmp(argv[i], "--help", sizeof "--help") ||
+ !strncmp(argv[i], "-h", sizeof "-h") ||
+ !strncmp(argv[i], "-?", sizeof "-?"))
+ return usage();
+
+ /* Otherwise, interpret as a filename, but only accept one */
+ if (filename)
+ return usage();
+ filename = argv[i];
+ }
+ if (!filename)
+ return usage();
+ fprintf(stdout, "Dumping file: %s\n", filename);
+
+ /* Either fetch the whole file, or just allocate a buffer */
+ f = NULL;
+ if (opt_no_buffer) {
+ errno = 0;
+ if (loadfile(filename, &file_data, &file_sz)) {
+ fprintf(stderr, "Couldn't load file. Error: %d\n", errno);
+ goto err_file_data;
+ }
+ } else {
+ file_sz = BYTES_PER_PAGE;
+ file_data = malloc(file_sz);
+ if (!file_data) {
+ fprintf(stderr, "Couldn't allocate file data buffer\n");
+ goto err_file_data;
+ }
+ errno = 0;
+ f = fopen(filename, "r");
+ if (!f) {
+ fprintf(stderr, "Couldn't open file. Error: %d\n", errno);
+ goto err_f;
+ }
+ }
+
+ /* Dump the data */
+ len = BYTES_PER_PAGE;
+ cur_pos = file_data;
+ do {
+ if (f) {
+ /* Buffered */
+ len = fread(file_data, 1, file_sz, f);
+ cur_pos = file_data;
+ } else {
+ /* Non-buffered */
+ if (file_sz < len)
+ len = file_sz;
+ }
+ if (!len)
+ break;
+
+ hexdump(cur_pos, len);
+
+ /* Pause, if requested */
+ if (opt_page) {
+ /* The user might choose to quit */
+ if (do_page())
+ break;
+ }
+
+ /* Reduce file_sz for non-buffered mode */
+ if (!f)
+ file_sz -= len;
+ } while (cur_pos += len);
+
+ rc = EXIT_SUCCESS;
+
+ if (f)
+ fclose(f);
+ err_f:
+
+ free(file_data);
+ err_file_data:
+
+ err_argv:
+
+ err_prog_name:
+
+ return rc;
+}
+
+static int usage(void)
+{
+ static const char usage[] =
+ "Usage: %s [<option> [...]] <filename> [<option> [...]]\n"
+ "\n"
+ "Options: -p\n"
+ " --page . . . . . . . Pause output every 24 lines\n"
+ " --no-buffer . . . . Load the entire file before dumping\n"
+ " --extended-ascii . . Use extended ASCII chars in dump\n"
+ " -?\n"
+ " -h\n"
+ " --help . . . . . . Display this help\n";
+
+ fprintf(stderr, usage, prog_name);
+ return EXIT_FAILURE;
+}
+
+static void eat_stdin(void)
+{
+ int i;
+
+ while (1) {
+ i = fgetc(stdin);
+ if (i == EOF || i == '\n')
+ return;
+ }
+}
+static int do_page(void)
+{
+ int i;
+
+ while (1) {
+ fprintf(stdout, "Continue? [Y|n]: ");
+ i = fgetc(stdin);
+ switch (i) {
+ case 'n':
+ case 'N':
+ eat_stdin();
+ return 1;
+
+ case EOF:
+ fprintf(stderr, "No response. Continuing...\n");
+ /* Fall through to "yes" */
+
+ case 'y':
+ case 'Y':
+ eat_stdin();
+ case '\n':
+ return 0;
+
+ default:
+ fprintf(stderr, "Invalid choice\n");
+ eat_stdin();
+ }
+ }
+}
+
+static void hexdump(const void *memory, size_t bytes)
+{
+ const unsigned char *p, *q;
+ int i;
+
+ p = memory;
+ while (bytes) {
+ q = p;
+ printf("%p: ", (void *) p);
+ for (i = 0; i < 16 && bytes; ++i) {
+ printf("%02X ", *p);
+ ++p;
+ --bytes;
+ }
+ bytes += i;
+ while (i < 16) {
+ printf("XX ");
+ ++i;
+ }
+ printf("| ");
+ p = q;
+ for (i = 0; i < 16 && bytes; ++i) {
+ printf("%c", isprint(*p) && !isspace(*p) ? *p : ' ');
+ ++p;
+ --bytes;
+ }
+ while (i < 16) {
+ printf(" ");
+ ++i;
+ }
+ printf("\n");
+ }
+ return;
+}
diff --git a/com32/modules/host.c b/com32/modules/host.c
index 94ca876d..d70efffd 100644
--- a/com32/modules/host.c
+++ b/com32/modules/host.c
@@ -1,41 +1,41 @@
#include <stdio.h>
-#include <console.h>
+#include <stdlib.h>
#include <string.h>
+#include <console.h>
#include <netinet/in.h>
#include <com32.h>
+#include <syslinux/pxe.h>
-static struct in_addr dnsresolve(const char *hostname)
+static inline uint32_t dns_resolve(const char *hostname)
{
- com32sys_t regs;
- struct in_addr addr;
-
- strcpy(__com32.cs_bounce, hostname);
-
- regs.eax.w[0] = 0x0010;
- regs.es = SEG(__com32.cs_bounce);
- regs.ebx.w[0] = OFFS(__com32.cs_bounce);
- __intcall(0x22, &regs, &regs);
+ return pxe_dns(hostname);
+}
- addr.s_addr = regs.eax.l;
- return addr;
+static inline void usage(const char *s)
+{
+ fprintf(stderr, "Usage: %s hostname [, hostname_1, hostname_2, ...]\n", s);
}
int main(int argc, char *argv[])
{
int i;
- struct in_addr addr;
+ uint32_t ip;
openconsole(&dev_null_r, &dev_stdcon_w);
- for (i = 1; i < argc; i++) {
- addr = dnsresolve(argv[i]);
+ if (argc < 2) {
+ usage(argv[0]);
+ return 1;
+ }
- printf("%-39s %08X %d.%d.%d.%d\n",
- argv[i], ntohl(addr.s_addr),
- ((uint8_t *)&addr.s_addr)[0],
- ((uint8_t *)&addr.s_addr)[1],
- ((uint8_t *)&addr.s_addr)[2],
- ((uint8_t *)&addr.s_addr)[3]);
+ for (i = 1; i < argc; i++) {
+ ip = dns_resolve(argv[i]);
+ if (!ip) {
+ printf("%s not found.\n", argv[i]);
+ } else {
+ printf("%-39s %08X %u.%u.%u.%u\n", argv[i], ntohl(ip), ip & 0xFF,
+ (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, (ip >> 24) & 0xFF);
+ }
}
return 0;
diff --git a/com32/modules/ifplop.c b/com32/modules/ifplop.c
index a846df8d..f502e2b3 100644
--- a/com32/modules/ifplop.c
+++ b/com32/modules/ifplop.c
@@ -144,8 +144,6 @@ int main(int argc, char *argv[])
char **args[2];
int arg = 0;
- openconsole(&dev_null_r, &dev_stdcon_w);
-
if (argc)
arg++;
args[0] = &argv[arg];
diff --git a/com32/modules/kbdmap.c b/com32/modules/kbdmap.c
index f1c736d5..7ec40018 100644
--- a/com32/modules/kbdmap.c
+++ b/com32/modules/kbdmap.c
@@ -27,8 +27,6 @@ int main(int argc, char *argv[])
size_t map_size;
void *kbdmap;
- openconsole(&dev_null_r, &dev_stdcon_w);
-
if (argc != 2) {
error("Usage: kbdmap mapfile\n");
return 1;
diff --git a/com32/modules/linux.c b/com32/modules/linux.c
index 76443f91..f657eab4 100644
--- a/com32/modules/linux.c
+++ b/com32/modules/linux.c
@@ -48,6 +48,14 @@
#include <syslinux/linux.h>
#include <syslinux/pxe.h>
+enum ldmode {
+ ldmode_raw,
+ ldmode_cpio,
+ ldmodes
+};
+
+typedef int f_ldinitramfs(struct initramfs *, char *);
+
const char *progname = "linux.c32";
/* Find the last instance of a particular command line argument
@@ -59,13 +67,34 @@ static char *find_argument(char **argv, const char *argument)
char *ptr = NULL;
for (arg = argv; *arg; arg++) {
- if (!memcmp(*arg, argument, la))
+ if (!strncmp(*arg, argument, la))
ptr = *arg + la;
}
return ptr;
}
+/* Find the next instance of a particular command line argument */
+static char **find_arguments(char **argv, char **ptr,
+ const char *argument)
+{
+ int la = strlen(argument);
+ char **arg;
+
+ for (arg = argv; *arg; arg++) {
+ if (!strncmp(*arg, argument, la)) {
+ *ptr = *arg + la;
+ break;
+ }
+ }
+
+ /* Exhausted all arguments */
+ if (!*arg)
+ return NULL;
+
+ return arg;
+}
+
/* Search for a boolean argument; return its position, or 0 if not present */
static int find_boolean(char **argv, const char *argument)
{
@@ -109,6 +138,99 @@ static char *make_cmdline(char **argv)
return cmdline;
}
+static f_ldinitramfs ldinitramfs_raw;
+static int ldinitramfs_raw(struct initramfs *initramfs, char *fname)
+{
+ return initramfs_load_archive(initramfs, fname);
+}
+
+static f_ldinitramfs ldinitramfs_cpio;
+static int ldinitramfs_cpio(struct initramfs *initramfs, char *fname)
+{
+ char *target_fname, *p;
+ int do_mkdir, unmangle, rc;
+
+ /* Choose target_fname based on presence of "@" syntax */
+ target_fname = strchr(fname, '@');
+ if (target_fname) {
+ /* Temporarily mangle */
+ unmangle = 1;
+ *target_fname++ = '\0';
+
+ /* Make parent directories? */
+ do_mkdir = !!strchr(target_fname, '/');
+ } else {
+ unmangle = 0;
+
+ /* Forget the source path */
+ target_fname = fname;
+ while ((p = strchr(target_fname, '/')))
+ target_fname = p + 1;
+
+ /* The user didn't specify a desired path */
+ do_mkdir = 0;
+ }
+
+ /*
+ * Load the file, encapsulate it with the desired path, make the
+ * parent directories if the desired path contains them, add to initramfs
+ */
+ rc = initramfs_load_file(initramfs, fname, target_fname, do_mkdir, 0755);
+
+ /* Unmangle, if needed*/
+ if (unmangle)
+ *--target_fname = '@';
+
+ return rc;
+}
+
+/* It only makes sense to call this function from main */
+static int process_initramfs_args(char *arg, struct initramfs *initramfs,
+ const char *kernel_name, enum ldmode mode,
+ bool opt_quiet)
+{
+ const char *mode_msg;
+ f_ldinitramfs *ldinitramfs;
+ char *p;
+
+ switch (mode) {
+ case ldmode_raw:
+ mode_msg = "Loading";
+ ldinitramfs = ldinitramfs_raw;
+ break;
+ case ldmode_cpio:
+ mode_msg = "Encapsulating";
+ ldinitramfs = ldinitramfs_cpio;
+ break;
+ case ldmodes:
+ default:
+ return 1;
+ }
+
+ do {
+ p = strchr(arg, ',');
+ if (p)
+ *p = '\0';
+
+ if (!opt_quiet)
+ printf("%s %s... ", mode_msg, arg);
+ errno = 0;
+ if (ldinitramfs(initramfs, arg)) {
+ if (opt_quiet)
+ printf("Loading %s ", kernel_name);
+ printf("failed: ");
+ return 1;
+ }
+ if (!opt_quiet)
+ printf("ok\n");
+
+ if (p)
+ *p++ = ',';
+ } while ((arg = p));
+
+ return 0;
+}
+
static int setup_data_file(struct setup_data *setup_data,
uint32_t type, const char *filename,
bool opt_quiet)
@@ -142,9 +264,7 @@ int main(int argc, char *argv[])
bool opt_quiet = false;
void *dhcpdata;
size_t dhcplen;
- char **argp, **argl, *arg, *p;
-
- openconsole(&dev_null_r, &dev_stdcon_w);
+ char **argp, **argl, *arg;
(void)argc;
argp = argv + 1;
@@ -209,27 +329,27 @@ int main(int argc, char *argv[])
goto bail;
}
+ /* Process initramfs arguments */
if ((arg = find_argument(argp, "initrd="))) {
- do {
- p = strchr(arg, ',');
- if (p)
- *p = '\0';
-
- if (!opt_quiet)
- printf("Loading %s... ", arg);
- errno = 0;
- if (initramfs_load_archive(initramfs, arg)) {
- if (opt_quiet)
- printf("Loading %s ", kernel_name);
- printf("failed: ");
- goto bail;
- }
- if (!opt_quiet)
- printf("ok\n");
-
- if (p)
- *p++ = ',';
- } while ((arg = p));
+ if (process_initramfs_args(arg, initramfs, kernel_name, ldmode_raw,
+ opt_quiet))
+ goto bail;
+ }
+
+ argl = argv;
+ while ((argl = find_arguments(argl, &arg, "initrd+="))) {
+ argl++;
+ if (process_initramfs_args(arg, initramfs, kernel_name, ldmode_raw,
+ opt_quiet))
+ goto bail;
+ }
+
+ argl = argv;
+ while ((argl = find_arguments(argl, &arg, "initrdfile="))) {
+ argl++;
+ if (process_initramfs_args(arg, initramfs, kernel_name, ldmode_cpio,
+ opt_quiet))
+ goto bail;
}
/* Append the DHCP info */
@@ -248,24 +368,28 @@ int main(int argc, char *argv[])
if (!setup_data)
goto bail;
- for (argl = argv; (arg = *argl); argl++) {
- if (!memcmp(arg, "dtb=", 4)) {
- if (setup_data_file(setup_data, SETUP_DTB, arg+4, opt_quiet))
- goto bail;
- } else if (!memcmp(arg, "blob.", 5)) {
- uint32_t type;
- char *ep;
+ argl = argv;
+ while ((argl = find_arguments(argl, &arg, "dtb="))) {
+ argl++;
+ if (setup_data_file(setup_data, SETUP_DTB, arg, opt_quiet))
+ goto bail;
+ }
+
+ argl = argv;
+ while ((argl = find_arguments(argl, &arg, "blob."))) {
+ uint32_t type;
+ char *ep;
- type = strtoul(arg + 5, &ep, 10);
- if (ep[0] != '=' || !ep[1])
- continue;
+ argl++;
+ type = strtoul(arg, &ep, 10);
+ if (ep[0] != '=' || !ep[1])
+ continue;
- if (!type)
- continue;
+ if (!type)
+ continue;
- if (setup_data_file(setup_data, type, ep+1, opt_quiet))
- goto bail;
- }
+ if (setup_data_file(setup_data, type, ep+1, opt_quiet))
+ goto bail;
}
/* This should not return... */
diff --git a/com32/modules/ls.c b/com32/modules/ls.c
index c311621e..11c18ae0 100644
--- a/com32/modules/ls.c
+++ b/com32/modules/ls.c
@@ -155,8 +155,6 @@ int main(int argc, char *argv[])
{
int rv;
- openconsole(&dev_rawcon_r, &dev_stdcon_w);
-
if (getscreensize(1, &rows, &cols)) {
/* Unknown screen size? */
rows = 24;
diff --git a/com32/modules/meminfo.c b/com32/modules/meminfo.c
index 6e24f355..34b3e91d 100644
--- a/com32/modules/meminfo.c
+++ b/com32/modules/meminfo.c
@@ -42,27 +42,32 @@ static void dump_e820(void)
com32sys_t ireg, oreg;
struct e820_data ed;
uint32_t type;
+ void *low_ed;
+
+ low_ed = lmalloc(sizeof ed);
+ if (!low_ed)
+ return;
memset(&ireg, 0, sizeof ireg);
ireg.eax.w[0] = 0xe820;
ireg.edx.l = 0x534d4150;
ireg.ecx.l = sizeof(struct e820_data);
- ireg.edi.w[0] = OFFS(__com32.cs_bounce);
- ireg.es = SEG(__com32.cs_bounce);
+ ireg.edi.w[0] = OFFS(low_ed);
+ ireg.es = SEG(low_ed);
memset(&ed, 0, sizeof ed);
ed.extattr = 1;
do {
- memcpy(__com32.cs_bounce, &ed, sizeof ed);
+ memcpy(low_ed, &ed, sizeof ed);
__intcall(0x15, &ireg, &oreg);
if (oreg.eflags.l & EFLAGS_CF ||
oreg.eax.l != 0x534d4150 || oreg.ecx.l < 20)
break;
- memcpy(&ed, __com32.cs_bounce, sizeof ed);
+ memcpy(&ed, low_ed, sizeof ed);
if (oreg.ecx.l >= 24) {
/* ebx base length end type */
@@ -84,6 +89,8 @@ static void dump_e820(void)
ireg.ebx.l = oreg.ebx.l;
} while (ireg.ebx.l);
+
+ lfree(low_ed);
}
static void dump_legacy(void)
@@ -115,12 +122,9 @@ static void dump_legacy(void)
oreg.ecx.w[0], oreg.ecx.w[0], oreg.edx.w[0], oreg.edx.w[0] << 6);
}
-int main(void)
+int main(int argc __unused, char **argv __unused)
{
- openconsole(&dev_null_r, &dev_stdcon_w);
-
dump_legacy();
dump_e820();
-
return 0;
}
diff --git a/com32/modules/pcitest.c b/com32/modules/pcitest.c
index 9921ee6d..fb6bbbf1 100644
--- a/com32/modules/pcitest.c
+++ b/com32/modules/pcitest.c
@@ -103,8 +103,6 @@ int main(int argc, char *argv[])
(void)argc;
(void)argv;
- openconsole(&dev_stdcon_r, &dev_stdcon_w);
-
/* Scanning to detect pci buses and devices */
printf("PCI: Scanning PCI BUS\n");
pci_domain = pci_scan();
diff --git a/com32/modules/pmload.c b/com32/modules/pmload.c
index 4c01db08..6808d38a 100644
--- a/com32/modules/pmload.c
+++ b/com32/modules/pmload.c
@@ -198,8 +198,6 @@ int main(int argc, char *argv[])
size_t data_len;
addr_t where;
- openconsole(&dev_null_r, &dev_stdcon_w);
-
if (argc < 3) {
error("Usage: pmload.c32 bin_file address arguments...\n");
return 1;
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;
+}
diff --git a/com32/modules/prdhcp.c b/com32/modules/prdhcp.c
index e1785a03..4ae295e8 100644
--- a/com32/modules/prdhcp.c
+++ b/com32/modules/prdhcp.c
@@ -39,11 +39,11 @@
#include <unistd.h>
#include <getkey.h>
-#define DEBUG 0
+#define PRDHCP_DEBUG 0
#define dprintf0(f, ...) ((void)0)
-#ifdef DEBUG
+#ifdef PRDHCP_DEBUG
# define dpressanykey pressanykey
# define dprintf printf
# define dprint_pxe_bootp_t print_pxe_bootp_t
diff --git a/com32/modules/pwd.c b/com32/modules/pwd.c
index 880327d6..2794e3dd 100644
--- a/com32/modules/pwd.c
+++ b/com32/modules/pwd.c
@@ -36,7 +36,6 @@ int main(void)
int rv = 0;
char pwd[PATH_MAX], *pwdptr;
- openconsole(&dev_rawcon_r, &dev_stdcon_w);
pwdptr = getcwd(pwd, PATH_MAX);
if (pwdptr) {
if (pwd[0] != 0)
diff --git a/com32/modules/pxechn.c b/com32/modules/pxechn.c
index 26376900..7f2002db 100644
--- a/com32/modules/pxechn.c
+++ b/com32/modules/pxechn.c
@@ -884,7 +884,6 @@ int pxechn_args(int argc, char *argv[], struct pxelinux_opt *pxe)
*/
int dhcp_pkt2pxe(pxe_bootp_t *p, size_t len, int ptype)
{
- com32sys_t reg;
t_PXENV_GET_CACHED_INFO *ci;
void *cp;
int rv = -1;
@@ -896,12 +895,7 @@ int dhcp_pkt2pxe(pxe_bootp_t *p, size_t len, int ptype)
}
ci->Status = PXENV_STATUS_FAILURE;
ci->PacketType = ptype;
- memset(&reg, 0, sizeof(reg));
- reg.eax.w[0] = 0x0009;
- reg.ebx.w[0] = PXENV_GET_CACHED_INFO;
- reg.edi.w[0] = OFFS(ci);
- reg.es = SEG(ci);
- __intcall(0x22, &reg, &reg);
+ pxe_call(PXENV_GET_CACHED_INFO, ci);
if (ci->Status != PXENV_STATUS_SUCCESS) {
dprintf("PXE Get Cached Info failed: %d\n", ci->Status);
@@ -1054,7 +1048,6 @@ int pxe_restart(char *ifn)
{
int rv = 0;
struct pxelinux_opt pxe;
- com32sys_t reg;
t_PXENV_RESTART_TFTP *pxep; /* PXENV callback Parameter */
pxe.fn = ifn;
@@ -1069,11 +1062,7 @@ int pxe_restart(char *ifn)
goto ret;
}
printf(" Attempting to boot '%s'...\n\n", pxe.fn);
- memset(&reg, 0, sizeof reg);
- if (sizeof(t_PXENV_TFTP_READ_FILE) <= __com32.cs_bounce_size) {
- pxep = __com32.cs_bounce;
- memset(pxep, 0, sizeof(t_PXENV_RESTART_TFTP));
- } else if (!(pxep = lzalloc(sizeof(t_PXENV_RESTART_TFTP)))){
+ if (!(pxep = lzalloc(sizeof(t_PXENV_RESTART_TFTP)))){
dprintf("Unable to lzalloc() for PXE call structure\n");
goto ret;
}
@@ -1086,16 +1075,11 @@ int pxe_restart(char *ifn)
pxep->ServerIPAddress, (unsigned int)pxep,
pxep->BufferSize, (unsigned int)pxep->Buffer);
dprintf("PXENV_RESTART_TFTP status %d\n", pxep->Status);
- reg.eax.w[0] = 0x0009;
- reg.ebx.w[0] = PXENV_RESTART_TFTP;
- reg.edi.w[0] = OFFS(pxep);
- reg.es = SEG(pxep);
- __intcall(0x22, &reg, &reg);
+ pxe_call(PXENV_RESTART_TFTP, pxep);
printf("PXENV_RESTART_TFTP returned %d\n", pxep->Status);
- if (pxep != __com32.cs_bounce)
- lfree(pxep);
+ lfree(pxep);
ret:
return rv;
diff --git a/com32/modules/sanboot.c b/com32/modules/sanboot.c
index 46df6bc3..ff55f68e 100644
--- a/com32/modules/sanboot.c
+++ b/com32/modules/sanboot.c
@@ -22,7 +22,9 @@
#include <console.h>
#include <com32.h>
#include <string.h>
+
#include <sys/gpxe.h>
+#include <syslinux/pxe_api.h>
struct segoff16 {
uint16_t offs, seg;
@@ -37,11 +39,11 @@ static void sanboot(const char **args)
{
char *q;
struct s_PXENV_FILE_EXEC *fx;
- com32sys_t reg;
- memset(&reg, 0, sizeof reg);
+ fx = lmalloc(sizeof *fx);
+ if (!fx)
+ return;
- fx = __com32.cs_bounce;
q = (char *)(fx + 1);
fx->Status = 1;
@@ -56,21 +58,13 @@ static void sanboot(const char **args)
args++;
}
- memset(&reg, 0, sizeof reg);
- reg.eax.w[0] = 0x0009;
- reg.ebx.w[0] = 0x00e5; /* PXENV_FILE_EXEC */
- reg.edi.w[0] = OFFS(fx);
- reg.es = SEG(fx);
-
- __intcall(0x22, &reg, &reg);
+ pxe_call(PXENV_FILE_EXEC, fx);
/* This should not return... */
}
int main(int argc, const char *argv[])
{
- openconsole(&dev_null_r, &dev_stdcon_w);
-
if (argc < 2) {
printf("Usage: sanboot rootpath\n");
return 1;
diff --git a/com32/modules/sdi.c b/com32/modules/sdi.c
index 69841d20..e57ad4a3 100644
--- a/com32/modules/sdi.c
+++ b/com32/modules/sdi.c
@@ -160,8 +160,6 @@ int main(int argc, char *argv[])
void *data;
size_t data_len;
- openconsole(&dev_null_r, &dev_stdcon_w);
-
if (argc != 2) {
error("Usage: sdi.c32 sdi_file\n");
return 1;
diff --git a/com32/modules/vesainfo.c b/com32/modules/vesainfo.c
index 00181e47..66b121d7 100644
--- a/com32/modules/vesainfo.c
+++ b/com32/modules/vesainfo.c
@@ -20,25 +20,31 @@ static void wait_key(void)
static void print_modes(void)
{
- static com32sys_t rm;
- struct vesa_general_info *gi;
- struct vesa_mode_info *mi;
- uint16_t mode, *mode_ptr;
- int lines;
-
- /* Allocate space in the bounce buffer for these structures */
- gi = &((struct vesa_info *)__com32.cs_bounce)->gi;
- mi = &((struct vesa_info *)__com32.cs_bounce)->mi;
-
- gi->signature = VBE2_MAGIC; /* Get VBE2 extended data */
- rm.eax.w[0] = 0x4F00; /* Get SVGA general information */
- rm.edi.w[0] = OFFS(gi);
- rm.es = SEG(gi);
- __intcall(0x10, &rm, &rm);
+ static com32sys_t rm;
+ struct vesa_general_info *gi;
+ struct vesa_mode_info *mi;
+ uint16_t mode, *mode_ptr;
+ int lines;
+
+ struct vesa_info *vesa;
+
+ vesa = lmalloc(sizeof(*vesa));
+ if (!vesa) {
+ printf("vesainfo.c32: fail in lmalloc\n");
+ return;
+ }
+ gi = &vesa->gi;
+ mi = &vesa->mi;
+
+ gi->signature = VBE2_MAGIC; /* Get VBE2 extended data */
+ rm.eax.w[0] = 0x4F00; /* Get SVGA general information */
+ rm.edi.w[0] = OFFS(gi);
+ rm.es = SEG(gi);
+ __intcall(0x10, &rm, &rm);
if (rm.eax.w[0] != 0x004F) {
printf("No VESA BIOS detected\n");
- return;
+ goto exit;
} else if (gi->signature != VESA_MAGIC) {
printf("VESA information structure has bad magic, trying anyway...\n");
}
@@ -71,12 +77,14 @@ static void print_modes(void)
mode, mi->mode_attr, mi->h_res, mi->v_res, mi->bpp,
mi->memory_layout, mi->rpos, mi->gpos, mi->bpos);
}
+
+exit:
+ lfree(vesa);
+ return;
}
-int main(void)
+int main(int argc __unused, char **argv __unused)
{
- openconsole(&dev_rawcon_r, &dev_stdcon_w);
-
print_modes();
return 0;
}
diff --git a/com32/modules/vpdtest.c b/com32/modules/vpdtest.c
index 1d50c680..c0f32ba6 100644
--- a/com32/modules/vpdtest.c
+++ b/com32/modules/vpdtest.c
@@ -40,7 +40,6 @@
int main(void)
{
s_vpd vpd;
- openconsole(&dev_stdcon_r, &dev_stdcon_w);
if (vpd_decode(&vpd) == -ENOVPDTABLE) {
printf("No VPD Structure found\n");
diff --git a/com32/modules/whichsys.c b/com32/modules/whichsys.c
index af133f2c..777cb9e8 100644
--- a/com32/modules/whichsys.c
+++ b/com32/modules/whichsys.c
@@ -78,8 +78,6 @@ int main(int argc, char *argv[])
int arg = 0;
- openconsole(&dev_null_r, &dev_stdcon_w);
-
/* If no argument got passed, let's show the usage */
if (argc == 1) {
usage();
diff --git a/com32/rosh/Makefile b/com32/rosh/Makefile
index 766f68d5..5b54225b 100644
--- a/com32/rosh/Makefile
+++ b/com32/rosh/Makefile
@@ -16,6 +16,8 @@
## ROSH Read Only Shell
##
+LIBS = $(com32)/libutil/libutil.c32 $(com32)/lib/libcom32.c32
+
topdir = ../..
MAKEDIR = $(topdir)/mk
include $(MAKEDIR)/rosh.mk
diff --git a/com32/samples/Makefile b/com32/samples/Makefile
index 76986d59..f6ae00ab 100644
--- a/com32/samples/Makefile
+++ b/com32/samples/Makefile
@@ -14,9 +14,11 @@
## samples for syslinux users
##
+LIBS = $(com32)/libutil/libutil.c32
+
topdir = ../..
MAKEDIR = $(topdir)/mk
-include $(MAKEDIR)/com32.mk
+include $(MAKEDIR)/elf.mk
all: hello.c32 resolv.c32 serialinfo.c32 \
localboot.c32 \
diff --git a/com32/samples/hello.c b/com32/samples/hello.c
index 77e93ac7..d3d4d299 100644
--- a/com32/samples/hello.c
+++ b/com32/samples/hello.c
@@ -1,35 +1,26 @@
-/* ----------------------------------------------------------------------- *
- *
- * Copyright 2004-2008 H. Peter Anvin - 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., 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.
- *
- * ----------------------------------------------------------------------- */
-
/*
- * hello.c
+ * hello.c - A simple ELF module that sorts a couple of numbers
*
- * Hello, World! using libcom32
+ * Created on: Aug 11, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
*/
-#include <string.h>
#include <stdio.h>
-#include <console.h>
+#include <stdlib.h>
-int main(int argc, char *argv[])
-{
- int i;
+#include "sort.h"
+
+#define NUM_COUNT 10
+#define MAX_NUM 100
- openconsole(&dev_stdcon_r, &dev_stdcon_w);
+int main(int argc __unused, char **argv __unused)
+{
+ int *nums = NULL;
- printf("Hello, World!\n");
+ nums = malloc(NUM_COUNT * sizeof(int));
+ printf("Hello, world, from 0x%08X! malloc return %p\n", (unsigned int)&main, nums);
- for (i = 1; i < argc; i++)
- printf("%s%c", argv[i], (i == argc - 1) ? '\n' : ' ');
+ free(nums);
return 0;
}
diff --git a/com32/samples/resolv.c b/com32/samples/resolv.c
index bd49d9f9..f4a0e52a 100644
--- a/com32/samples/resolv.c
+++ b/com32/samples/resolv.c
@@ -16,6 +16,7 @@
* Resolve an IP address
*/
+#include <syslinux/pxe_api.h>
#include <string.h>
#include <stdio.h>
#include <console.h>
@@ -24,21 +25,7 @@
uint32_t resolv(const char *name)
{
- com32sys_t reg;
-
- strcpy((char *)__com32.cs_bounce, name);
-
- memset(&reg, 0, sizeof reg);
- reg.eax.w[0] = 0x0010;
- reg.ebx.w[0] = OFFS(__com32.cs_bounce);
- reg.es = SEG(__com32.cs_bounce);
-
- __intcall(0x22, &reg, &reg);
-
- if (reg.eflags.l & EFLAGS_CF)
- return 0;
- else
- return reg.eax.l;
+ return dns_resolv(name);
}
int main(int argc, char *argv[])
diff --git a/com32/sysdump/Makefile b/com32/sysdump/Makefile
index 98e7f15a..7d42ae0c 100644
--- a/com32/sysdump/Makefile
+++ b/com32/sysdump/Makefile
@@ -17,7 +17,7 @@
topdir = ../..
MAKEDIR = $(topdir)/mk
-include $(MAKEDIR)/com32.mk
+include $(MAKEDIR)/elf.mk
-include $(topdir)/version.mk
LIBS = ../libupload/libcom32upload.a
@@ -49,7 +49,7 @@ sysdump.elf : $(OBJS) $(LIBS) $(C_LIBS)
$(LD) $(LDFLAGS) -o $@ $^
tidy dist:
- rm -f *.o *.lo *.a *.lst *.elf .*.d *.tmp
+ rm -f *.o *.lo *.a *.lst .*.d *.tmp
clean: tidy
rm -f *.lnx
diff --git a/com32/sysdump/README b/com32/sysdump/README
index 2b825775..7d10e32b 100644
--- a/com32/sysdump/README
+++ b/com32/sysdump/README
@@ -1,4 +1,4 @@
-This is a very simple COMBOOT program which can be used to dump memory
+This is a very simple COM32 program which can be used to dump memory
regions over a serial port. To use it, type on the SYSLINUX command
line:
diff --git a/com32/sysdump/main.c b/com32/sysdump/main.c
index f672585d..eac931e5 100644
--- a/com32/sysdump/main.c
+++ b/com32/sysdump/main.c
@@ -72,7 +72,6 @@ int main(int argc, char *argv[])
{
struct upload_backend **bep, *be;
- openconsole(&dev_null_r, &dev_stdcon_w);
fputs(version, stdout);
if (argc < 2)