aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFeng Tang <feng.tang@intel.com>2010-07-19 19:30:57 -0700
committerFeng Tang <feng.tang@intel.com>2010-07-19 19:30:57 -0700
commitc871f9662c773690723f3d23ad39fe5983717717 (patch)
tree0d7be0ea9e8ce514b1c7a8c3ba8a9c449cd42d5d
parent0ee50473e37cbc22ef1b2f9897bce48c41be8f5e (diff)
downloadbak.git-elflink-merge-allin1.tar.gz
bak.git-elflink-merge-allin1.tar.xz
bak.git-elflink-merge-allin1.zip
elflink: merge with master branchelflink-merge-allin1
ELF modules basically work This is merged with "master" barnch, with commit it 0ee50473, and subject: NEWS: correct credit for new Lua work. Signed-off-by: H. Peter Anvin <hpa@linux.intel.com Signed-off-by: Feng Tang <feng.tang@intel.com>
-rw-r--r--MCONFIG1
-rw-r--r--MCONFIG.devel2
-rw-r--r--com32/MCONFIG9
-rw-r--r--com32/Makefile3
-rw-r--r--com32/elflink/Makefile41
-rw-r--r--com32/elflink/modules/MCONFIG69
-rw-r--r--com32/elflink/modules/Makefile109
-rw-r--r--com32/elflink/modules/README1
-rw-r--r--com32/elflink/modules/ansiraw.c115
-rw-r--r--com32/elflink/modules/background.c54
-rw-r--r--com32/elflink/modules/base64.h51
-rw-r--r--com32/elflink/modules/cli.h19
-rw-r--r--com32/elflink/modules/cpuid.c61
-rw-r--r--com32/elflink/modules/cpuidtest.c140
-rw-r--r--com32/elflink/modules/crypt-md5.c173
-rw-r--r--com32/elflink/modules/dir.c178
-rw-r--r--com32/elflink/modules/disk.c60
-rw-r--r--com32/elflink/modules/drain.c40
-rw-r--r--com32/elflink/modules/get_key.c187
-rw-r--r--com32/elflink/modules/hello.c30
-rw-r--r--com32/elflink/modules/md5.c288
-rw-r--r--com32/elflink/modules/md5.h46
-rw-r--r--com32/elflink/modules/meminfo.c133
-rw-r--r--com32/elflink/modules/menu.c19
-rw-r--r--com32/elflink/modules/menu.h228
-rw-r--r--com32/elflink/modules/menumain.c975
-rw-r--r--com32/elflink/modules/modules.dep19
-rw-r--r--com32/elflink/modules/mytest.c29
-rw-r--r--com32/elflink/modules/passwd.c111
-rw-r--r--com32/elflink/modules/pcitest.c156
-rw-r--r--com32/elflink/modules/printmsg.c115
-rw-r--r--com32/elflink/modules/refstr.h40
-rw-r--r--com32/elflink/modules/sha1.h18
-rw-r--r--com32/elflink/modules/sha1hash.c347
-rw-r--r--com32/elflink/modules/sha256crypt.c559
-rw-r--r--com32/elflink/modules/sha512crypt.c606
-rw-r--r--com32/elflink/modules/sort.c80
-rw-r--r--com32/elflink/modules/sort.h18
-rw-r--r--com32/elflink/modules/test.c111
-rw-r--r--com32/elflink/modules/unbase64.c91
-rw-r--r--com32/elflink/modules/vesainfo.c93
-rw-r--r--com32/elflink/test_com32.c208
-rw-r--r--com32/include/com32.h2
-rw-r--r--com32/include/klibc/compiler.h6
-rw-r--r--com32/include/linux/list.h463
-rw-r--r--com32/include/stdio.h5
-rw-r--r--com32/include/sys/elfcommon.h231
-rw-r--r--com32/include/sys/exec.h134
-rw-r--r--com32/include/sys/module.h377
-rw-r--r--com32/lib/MCONFIG2
-rw-r--r--com32/lib/Makefile248
-rw-r--r--com32/lib/elf32.ld184
-rw-r--r--com32/lib/exit.c24
-rw-r--r--com32/lib/libpng/libpng.txt2959
-rw-r--r--com32/lib/lmalloc.c2
-rw-r--r--com32/lib/lstrdup.c2
-rw-r--r--com32/lib/sys/module/common.c526
-rw-r--r--com32/lib/sys/module/common.h65
-rw-r--r--com32/lib/sys/module/elf_module.c515
-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.c402
-rw-r--r--com32/lib/sys/module/shallow_module.c161
-rw-r--r--com32/lib/sys/open.c2
-rw-r--r--com32/lib/sys/rawcon_read.c4
-rw-r--r--com32/lua/etc/luavs.bat56
-rw-r--r--com32/modules/Makefile4
-rw-r--r--com32/modules/dir.c177
-rw-r--r--core/Makefile13
-rw-r--r--core/common.inc1
-rw-r--r--core/configinit.inc5
-rw-r--r--core/diskfs.inc6
-rw-r--r--core/diskstart.inc1
-rw-r--r--core/elflink/abort_new.c29
-rw-r--r--core/elflink/adv.c49
-rw-r--r--core/elflink/advwrite.c45
-rw-r--r--core/elflink/cli.c410
-rw-r--r--core/elflink/cli.h23
-rw-r--r--core/elflink/colors.c184
-rw-r--r--core/elflink/common.h62
-rw-r--r--core/elflink/config.c41
-rw-r--r--core/elflink/core-elf.h16
-rw-r--r--core/elflink/elfutils.h67
-rw-r--r--core/elflink/execute.c96
-rw-r--r--core/elflink/get_key.c175
-rw-r--r--core/elflink/getadv.c68
-rw-r--r--core/elflink/getkey.h80
-rw-r--r--core/elflink/ipappend.c58
-rw-r--r--core/elflink/kernel.c124
-rw-r--r--core/elflink/load_env32.c123
-rw-r--r--core/elflink/menu.h229
-rw-r--r--core/elflink/readconfig.c1184
-rw-r--r--core/elflink/refstr.c106
-rw-r--r--core/elflink/refstr.h40
-rw-r--r--core/elflink/setadv.c116
-rw-r--r--core/extern.inc22
-rw-r--r--core/fs/getcwd.c2
-rw-r--r--core/hello.c89
-rw-r--r--core/include/core.h1
-rw-r--r--core/include/fs.h2
-rw-r--r--core/init.inc8
-rw-r--r--core/mem/free.c13
-rw-r--r--core/mem/init.c101
-rw-r--r--core/mem/malloc.c119
-rw-r--r--core/mem/malloc.h42
-rw-r--r--core/pmapi.c2
-rw-r--r--core/printf.c20
-rw-r--r--core/syslinux.ld47
-rw-r--r--core/ui.inc27
-rw-r--r--elf_gen_dep.sh111
-rw-r--r--libinstaller/syslxmod.c2
-rw-r--r--lzo/prepcore.c2
112 files changed, 16033 insertions, 265 deletions
diff --git a/MCONFIG b/MCONFIG
index c76b5917..21777188 100644
--- a/MCONFIG
+++ b/MCONFIG
@@ -49,6 +49,7 @@ gcc_ok = $(shell tmpf=gcc_ok.$$$$.tmp; \
LD = ld
OBJDUMP = objdump
OBJCOPY = objcopy
+STRIP = strip
AR = ar
NM = nm
RANLIB = ranlib
diff --git a/MCONFIG.devel b/MCONFIG.devel
index 104207f5..c05d76e8 100644
--- a/MCONFIG.devel
+++ b/MCONFIG.devel
@@ -1,2 +1,2 @@
# Useful while doing development, but not for production.
-GCCWARN += -Wno-clobbered -Werror
+GCCWARN += -Wno-clobbered
diff --git a/com32/MCONFIG b/com32/MCONFIG
index a74ed326..6216f0d7 100644
--- a/com32/MCONFIG
+++ b/com32/MCONFIG
@@ -54,8 +54,8 @@ SFLAGS = $(GCCOPT) $(GCCWARN) -march=i386 \
-nostdinc -iwithprefix include \
-I$(com32)/libutil/include -I$(com32)/include $(GPLINCLUDE)
-COM32LD = $(com32)/lib/com32.ld
-LDFLAGS = -m elf_i386 --emit-relocs -T $(COM32LD)
+COM32LD = $(com32)/lib/elf32.ld
+LDFLAGS = -m elf_i386 -shared --hash-style=gnu -T $(COM32LD)
LIBGCC := $(shell $(CC) $(GCCOPT) --print-libgcc)
LNXCFLAGS = -I$(com32)/libutil/include $(GCCWARN) -O -g \
@@ -94,5 +94,6 @@ C_LNXLIBS = $(com32)/libutil/libutil_lnx.a
$(CC) $(LNXCFLAGS) -o $@ $^
%.c32: %.elf
- $(OBJCOPY) -O binary $< $@
- $(RELOCS) $< >> $@ || ( rm -f $@ ; false )
+ $(OBJCOPY) --strip-debug --strip-unneeded $< $@
+ ##$(OBJCOPY) -O binary $< $@
+ ##$(RELOCS) $< >> $@ || ( rm -f $@ ; false )
diff --git a/com32/Makefile b/com32/Makefile
index b090c403..de9ad28e 100644
--- a/com32/Makefile
+++ b/com32/Makefile
@@ -1,5 +1,4 @@
-SUBDIRS = tools lib gpllib libutil modules mboot menu samples rosh cmenu \
+SUBDIRS = tools lib gpllib libutil modules mboot menu samples elflink elflink/modules rosh cmenu \
hdt gfxboot sysdump lua/src
-
all tidy dist clean spotless install:
set -e; for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done
diff --git a/com32/elflink/Makefile b/com32/elflink/Makefile
new file mode 100644
index 00000000..39266ded
--- /dev/null
+++ b/com32/elflink/Makefile
@@ -0,0 +1,41 @@
+## -----------------------------------------------------------------------
+##
+## 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.
+##
+## -----------------------------------------------------------------------
+
+topdir = ../..
+include ../MCONFIG
+
+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 ../libutil/libutil_com.a ../lib/libcom32min.a $(LIBGCC)
+ $(LD) -n $(LDFLAGS) -o $@ test_com32.o ../libutil/libutil_com.a $(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: all
+ mkdir -m 755 -p $(INSTALLROOT)$(AUXDIR)
+ install -m 644 $(MODULES) $(INSTALLROOT)$(AUXDIR)
+
+-include .*.d
diff --git a/com32/elflink/modules/MCONFIG b/com32/elflink/modules/MCONFIG
new file mode 100644
index 00000000..0049128e
--- /dev/null
+++ b/com32/elflink/modules/MCONFIG
@@ -0,0 +1,69 @@
+## -*- makefile -*- -------------------------------------------------------
+##
+## 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.
+##
+## -----------------------------------------------------------------------
+
+##
+## COM32 common configurables
+##
+
+include $(topdir)/MCONFIG
+
+GCCOPT := $(call gcc_ok,-std=gnu99,)
+GCCOPT += $(call gcc_ok,-m32,)
+GCCOPT += $(call gcc_ok,-fno-stack-protector,)
+GCCOPT += $(call gcc_ok,-fwrapv,)
+GCCOPT += $(call gcc_ok,-freg-struct-return,)
+GCCOPT += -march=i386 -Os -fomit-frame-pointer -mregparm=3 -DREGPARM=3
+GCCOPT += $(call gcc_ok,-fno-exceptions,)
+GCCOPT += $(call gcc_ok,-fno-asynchronous-unwind-tables,)
+GCCOPT += $(call gcc_ok,-fPIE,-fPIC)
+GCCOPT += $(call gcc_ok,-falign-functions=0,-malign-functions=0)
+GCCOPT += $(call gcc_ok,-falign-jumps=0,-malign-jumps=0)
+GCCOPT += $(call gcc_ok,-falign-labels=0,-malign-labels=0)
+GCCOPT += $(call gcc_ok,-falign-loops=0,-malign-loops=0)
+GCCOPT += $(call gcc_ok,-mpreferred-stack-boundary=2,)
+
+com32 = $(topdir)/com32
+
+CFLAGS = $(GCCOPT) -W -Wall -march=i386 \
+ -fomit-frame-pointer -D__COM32__ -DDYNAMIC_MODULE \
+ -nostdinc -iwithprefix include \
+ -I$(com32)/libutil/include -I$(com32)/include -I$(com32)/gplinclude
+SFLAGS = $(GCCOPT) -D__COM32__ -march=i386
+LDFLAGS = -m elf_i386 -shared --hash-style=gnu -T $(com32)/lib/elf32.ld
+LIBGCC := $(shell $(CC) $(GCCOPT) --print-libgcc)
+
+LNXCFLAGS = -I$(com32)/libutil/include -W -Wall -O -g -D_GNU_SOURCE
+LNXSFLAGS = -g
+LNXLDFLAGS = -g
+
+.SUFFIXES: .lss .c .o
+
+.PRECIOUS: %.o
+%.o: %.S
+ $(CC) $(SFLAGS) -c -o $@ $<
+
+.PRECIOUS: %.o
+%.o: %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+.PRECIOUS: %.lo
+%.lo: %.S
+ $(CC) $(LNXSFLAGS) -c -o $@ $<
+
+.PRECIOUS: %.lo
+%.lo: %.c
+ $(CC) $(LNXCFLAGS) -c -o $@ $<
+
+.PRECIOUS: %.lnx
+%.lnx: %.lo $(LNXLIBS)
+ $(CC) $(LNXLDFLAGS) -o $@ $^
+
diff --git a/com32/elflink/modules/Makefile b/com32/elflink/modules/Makefile
new file mode 100644
index 00000000..9c9cb972
--- /dev/null
+++ b/com32/elflink/modules/Makefile
@@ -0,0 +1,109 @@
+## -----------------------------------------------------------------------
+##
+## 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.
+##
+## -----------------------------------------------------------------------
+
+topdir = ../../..
+include MCONFIG
+
+MODULES = hello.c32 sort.c32 mytest.c32 menumain.c32 printmsg.c32 background.c32 passwd.c32 sha1hash.c32 \
+ unbase64.c32 sha512crypt.c32 md5.c32 crypt-md5.c32 sha256crypt.c32 get_key.c32 ansiraw.c32 test.c32 \
+ meminfo.c32 menu.c32 drain.c32 dir.c32 pcitest.c32 vesainfo.c32 cpuid.c32 cpuidtest.c32
+
+TESTFILES =
+
+all: $(MODULES) $(TESTFILES)
+
+test.c32 : test.o
+ $(LD) $(LDFLAGS) -o $@ $^
+
+menu.c32 : menu.o
+ $(LD) $(LDFLAGS) -o $@ $^
+
+hello.c32 : hello.o
+ $(LD) $(LDFLAGS) -o $@ $^
+
+sort.c32 : sort.o
+ $(LD) $(LDFLAGS) -o $@ $^
+
+mytest.c32 : mytest.o
+ $(LD) $(LDFLAGS) -o $@ $^
+
+menumain.c32 : menumain.o
+ $(LD) $(LDFLAGS) -o $@ $^
+
+printmsg.c32 : printmsg.o
+ $(LD) $(LDFLAGS) -o $@ $^
+
+background.c32 : background.o
+ $(LD) $(LDFLAGS) -o $@ $^
+
+drain.c32 : drain.o
+ $(LD) $(LDFLAGS) -o $@ $^
+
+passwd.c32 : passwd.o
+ $(LD) $(LDFLAGS) -o $@ $^
+
+sha1hash.c32 : sha1hash.o
+ $(LD) $(LDFLAGS) -o $@ $^
+
+unbase64.c32 : unbase64.o
+ $(LD) $(LDFLAGS) -o $@ $^
+
+sha512crypt.c32 : sha512crypt.o
+ $(LD) $(LDFLAGS) -o $@ $^
+
+sha256crypt.c32 : sha256crypt.o
+ $(LD) $(LDFLAGS) -o $@ $^
+
+md5.c32 : md5.o
+ $(LD) $(LDFLAGS) -o $@ $^
+
+crypt-md5.c32 : crypt-md5.o
+ $(LD) $(LDFLAGS) -o $@ $^
+
+get_key.c32 : get_key.o
+ $(LD) $(LDFLAGS) -o $@ $^
+
+ansiraw.c32 : ansiraw.o
+ $(LD) $(LDFLAGS) -o $@ $^
+
+meminfo.c32 : meminfo.o
+ $(LD) $(LDFLAGS) -o $@ $^
+
+pcitest.c32 : pcitest.o
+ $(LD) $(LDFLAGS) -o $@ $^
+
+dir.c32 : dir.o
+ $(LD) $(LDFLAGS) -o $@ $^
+
+vesainfo.c32 : vesainfo.o
+ $(LD) $(LDFLAGS) -o $@ $^
+
+cpuid.c32 : cpuid.o
+ $(LD) $(LDFLAGS) -o $@ $^
+
+cpuidtest.c32 : cpuidtest.o
+ $(LD) $(LDFLAGS) -o $@ $^
+
+tidy dist:
+ rm -f *.o *.lo *.a *.lst .*.d
+
+clean: tidy
+ rm -f *.lss *.lnx *.com
+
+spotless: clean
+ rm -f *~ \#*
+
+install: all
+ mkdir -m 755 -p $(INSTALLROOT)$(AUXDIR)
+ install -m 644 $(MODULES) $(INSTALLROOT)$(AUXDIR)
+
+-include .*.d
diff --git a/com32/elflink/modules/README b/com32/elflink/modules/README
new file mode 100644
index 00000000..090313a7
--- /dev/null
+++ b/com32/elflink/modules/README
@@ -0,0 +1 @@
+This folder contains dynamically loadable ELF modules for SYSLINUX. \ No newline at end of file
diff --git a/com32/elflink/modules/ansiraw.c b/com32/elflink/modules/ansiraw.c
new file mode 100644
index 00000000..aca90ce6
--- /dev/null
+++ b/com32/elflink/modules/ansiraw.c
@@ -0,0 +1,115 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * ansiraw.c
+ *
+ * Configures the console for ANSI output in raw mode; versions
+ * for COM32 and Linux support.
+ */
+
+#ifdef __COM32__
+
+#include <stdio.h>
+#include <unistd.h>
+#include <console.h>
+#include <sys/module.h>
+
+static int ansiraw_init(void)
+{
+ return 0; // Nothing to do; return success
+}
+
+void console_ansi_raw(void)
+{
+ openconsole(&dev_rawcon_r, &dev_ansiserial_w);
+}
+
+static void ansiraw_exit(void)
+{
+ // Nothing to do
+}
+
+// Define entry and exit points.
+MODULE_INIT(ansiraw_init);
+MODULE_EXIT(ansiraw_exit);
+
+#else
+
+#include <stdio.h>
+#include <termios.h>
+#include <sys/module.h>
+
+static int ansiraw_init(void)
+{
+ return 0; // Nothing to do; return success
+}
+
+static struct termios original_termios_settings;
+
+static void __attribute__ ((constructor)) console_init(void)
+{
+ tcgetattr(0, &original_termios_settings);
+}
+
+static void __attribute__ ((destructor)) console_cleanup(void)
+{
+ tcsetattr(0, TCSANOW, &original_termios_settings);
+}
+
+void console_ansi_raw(void)
+{
+ struct termios tio;
+
+ /* Disable stdio buffering */
+ setbuf(stdin, NULL);
+ setbuf(stdout, NULL);
+ setbuf(stderr, NULL);
+
+ /* Set the termios flag so we behave the same as libcom32 */
+ tcgetattr(0, &tio);
+ tio.c_iflag &= ~ICRNL;
+ tio.c_iflag |= IGNCR;
+ tio.c_lflag &= ~(ISIG | ICANON | ECHO);
+ if (!tio.c_oflag & OPOST)
+ tio.c_oflag = 0;
+ tio.c_oflag |= OPOST | ONLCR;
+ tio.c_cc[VMIN] = 0;
+ tio.c_cc[VTIME] = 1; /* Don't 100% busy-wait in Linux */
+ tcsetattr(0, TCSAFLUSH, &tio);
+}
+
+static void ansiraw_exit(void)
+{
+ // Nothing to do
+}
+
+// Define entry and exit points.
+MODULE_INIT(ansiraw_init);
+MODULE_EXIT(ansiraw_exit);
+
+#endif
diff --git a/com32/elflink/modules/background.c b/com32/elflink/modules/background.c
new file mode 100644
index 00000000..61d8c609
--- /dev/null
+++ b/com32/elflink/modules/background.c
@@ -0,0 +1,54 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <consoles.h>
+#include <string.h>
+#include <syslinux/vesacon.h>
+#include <sys/module.h>
+#include "menu.h"
+
+static int background_init(void)
+{
+ return 0; // Nothing to do; return success
+}
+
+const char *current_background = NULL;
+
+int draw_background(const char *what)
+{
+#if 0
+ if (!what)
+ return vesacon_default_background();
+ else if (what[0] == '#')
+ return vesacon_set_background(parse_argb((char **)&what));
+ else
+ return vesacon_load_background(what);
+#endif
+}
+
+void set_background(const char *new_background)
+{
+ if (!current_background || !new_background ||
+ strcmp(current_background, new_background)) {
+ draw_background(new_background);
+ current_background = new_background;
+ }
+}
+
+static void background_exit(void)
+{
+ // Nothing to do
+}
+
+// Define entry and exit points.
+MODULE_INIT(background_init);
+MODULE_EXIT(background_exit);
diff --git a/com32/elflink/modules/base64.h b/com32/elflink/modules/base64.h
new file mode 100644
index 00000000..b71855b8
--- /dev/null
+++ b/com32/elflink/modules/base64.h
@@ -0,0 +1,51 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2005-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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * base64.h
+ *
+ * Simple routines for handing base64 text
+ */
+
+#ifndef LIBUTIL_BASE64_H
+#define LIBUTIL_BASE64_H
+
+#include <stddef.h>
+
+#define BASE64_PAD 0x10000
+
+/* There is plenty of disagreement w.r.t. the last few characters... */
+#define BASE64_MIME ('+' + ('/' << 8))
+#define BASE64_SAFE ('-' + ('_' << 8))
+#define BASE64_CRYPT ('.' + ('/' << 8))
+#define BASE64_URL ('*' + ('-' << 8)) /* Haven't seen myself */
+#define BASE64_REGEX ('|' + ('-' << 8)) /* Ditto... */
+
+size_t genbase64(char *output, const void *digest, size_t size, int flags);
+size_t unbase64(unsigned char *, size_t, const char *);
+
+#endif
diff --git a/com32/elflink/modules/cli.h b/com32/elflink/modules/cli.h
new file mode 100644
index 00000000..c452643d
--- /dev/null
+++ b/com32/elflink/modules/cli.h
@@ -0,0 +1,19 @@
+#ifndef CLI_H
+#define CLI_H
+
+#define MAX_CMD_HISTORY 64
+
+struct cli_command {
+ struct list_head list;
+ char *command;
+};
+
+struct list_head cli_history_head;
+
+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));
+
+#endif
diff --git a/com32/elflink/modules/cpuid.c b/com32/elflink/modules/cpuid.c
new file mode 100644
index 00000000..1b5d1886
--- /dev/null
+++ b/com32/elflink/modules/cpuid.c
@@ -0,0 +1,61 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 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., 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 <stdio.h>
+#include <stdlib.h>
+#include <sys/cpu.h>
+#include <console.h>
+#include <com32.h>
+
+#include <sys/module.h>
+
+static void dump_reg(const char *name, uint32_t val)
+{
+ int i;
+
+ printf("%-3s : %10u 0x%08x ", name, val, val);
+
+ for (i = 3; i >= 0; i--) {
+ uint8_t c = val >> (i*8);
+ putchar((c >= ' ' && c <= '~') ? c : '.');
+ }
+ putchar('\n');
+}
+
+static int cpuid_main(int argc, char *argv[])
+{
+ uint32_t leaf, counter;
+ uint32_t eax, ebx, ecx, edx;
+
+ if (argc < 2 || argc > 4) {
+ printf("Usage: %s leaf [counter]\n", argv[0]);
+ exit(1);
+ }
+
+ leaf = strtoul(argv[1], NULL, 0);
+ counter = (argc > 2) ? strtoul(argv[2], NULL, 0) : 0;
+
+ if (!cpu_has_eflag(EFLAGS_ID)) {
+ printf("The CPUID instruction is not supported\n");
+ exit(1);
+ }
+
+ cpuid_count(leaf, counter, &eax, &ebx, &ecx, &edx);
+
+ dump_reg("eax", eax);
+ dump_reg("ebx", ebx);
+ dump_reg("ecx", ecx);
+ dump_reg("edx", edx);
+
+ return 0;
+}
+MODULE_MAIN(cpuid_main);
diff --git a/com32/elflink/modules/cpuidtest.c b/com32/elflink/modules/cpuidtest.c
new file mode 100644
index 00000000..942955fe
--- /dev/null
+++ b/com32/elflink/modules/cpuidtest.c
@@ -0,0 +1,140 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2006 Erwan Velu - 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.
+ *
+ * -----------------------------------------------------------------------
+*/
+
+/*
+ * cpuidtest.c
+ *
+ * A CPUID demo program using libcom32
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <console.h>
+#include "cpuid.h"
+
+#include <sys/module.h>
+
+char display_line;
+
+static int cpuidtest_main(void)
+{
+ s_cpu cpu;
+
+ for (;;) {
+ detect_cpu(&cpu);
+ printf("Vendor = %s\n", cpu.vendor);
+ printf("Model = %s\n", cpu.model);
+ printf("Vendor ID = %d\n", cpu.vendor_id);
+ printf("Family = %d\n", cpu.family);
+ printf("Model ID = %d\n", cpu.model_id);
+ printf("Stepping = %d\n", cpu.stepping);
+ printf("Flags = ");
+ if (cpu.flags.fpu)
+ printf("fpu ");
+ if (cpu.flags.vme)
+ printf("vme ");
+ if (cpu.flags.de)
+ printf("de ");
+ if (cpu.flags.pse)
+ printf("pse ");
+ if (cpu.flags.tsc)
+ printf("tsc ");
+ if (cpu.flags.msr)
+ printf("msr ");
+ if (cpu.flags.pae)
+ printf("pae ");
+ if (cpu.flags.mce)
+ printf("mce ");
+ if (cpu.flags.cx8)
+ printf("cx8 ");
+ if (cpu.flags.apic)
+ printf("apic ");
+ if (cpu.flags.sep)
+ printf("sep ");
+ if (cpu.flags.mtrr)
+ printf("mtrr ");
+ if (cpu.flags.pge)
+ printf("pge ");
+ if (cpu.flags.mca)
+ printf("mca ");
+ if (cpu.flags.cmov)
+ printf("cmov ");
+ if (cpu.flags.pat)
+ printf("pat ");
+ if (cpu.flags.pse_36)
+ printf("pse_36 ");
+ if (cpu.flags.psn)
+ printf("psn ");
+ if (cpu.flags.clflsh)
+ printf("clflsh ");
+ if (cpu.flags.dts)
+ printf("dts ");
+ if (cpu.flags.acpi)
+ printf("acpi ");
+ if (cpu.flags.mmx)
+ printf("mmx ");
+ if (cpu.flags.sse)
+ printf("sse ");
+ if (cpu.flags.sse2)
+ printf("sse2 ");
+ if (cpu.flags.ss)
+ printf("ss ");
+ if (cpu.flags.htt)
+ printf("ht ");
+ if (cpu.flags.acc)
+ printf("acc ");
+ if (cpu.flags.syscall)
+ printf("syscall ");
+ if (cpu.flags.mp)
+ printf("mp ");
+ if (cpu.flags.nx)
+ printf("nx ");
+ if (cpu.flags.mmxext)
+ printf("mmxext ");
+ if (cpu.flags.lm)
+ printf("lm ");
+ if (cpu.flags.nowext)
+ printf("3dnowext ");
+ if (cpu.flags.now)
+ printf("3dnow! ");
+ if (cpu.flags.vmx)
+ printf("vmx ");
+ if (cpu.flags.svm)
+ printf("svm ");
+ printf("\n");
+ printf("SMP = ");
+ if (cpu.flags.smp)
+ printf("yes\n");
+ else
+ printf("no\n");
+ break;
+ }
+
+ return 0;
+}
+MODULE_MAIN(cpuidtest_main);
diff --git a/com32/elflink/modules/crypt-md5.c b/com32/elflink/modules/crypt-md5.c
new file mode 100644
index 00000000..08e36391
--- /dev/null
+++ b/com32/elflink/modules/crypt-md5.c
@@ -0,0 +1,173 @@
+/*-
+ * Copyright (c) 2003 Poul-Henning Kamp
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <inttypes.h>
+#include <md5.h>
+#include <string.h>
+#include <sys/module.h>
+
+static int crypt_md5_init(void)
+{
+ return 0; // Nothing to do; return success
+}
+
+/*
+ * UNIX password
+ */
+
+static char *_crypt_to64(char *s, uint32_t v, int n)
+{
+ static const char itoa64[64] = "./0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+ while (--n >= 0) {
+ *s++ = itoa64[v & 0x3f];
+ v >>= 6;
+ }
+ return s;
+}
+
+char *crypt_md5(const char *pw, const char *salt)
+{
+ MD5_CTX ctx, ctx1;
+ unsigned long l;
+ int sl, pl;
+ uint32_t i;
+ uint8_t final[MD5_SIZE];
+ const char *sp;
+ static char passwd[120]; /* Output buffer */
+ static const char magic[] = "$1$";
+ char *p;
+ const int magic_len = sizeof magic - 1;
+ int pwlen = strlen(pw);
+
+ /* Refine the Salt first */
+ sp = salt;
+
+ /* If it starts with the magic string, then skip that */
+ if (!strncmp(sp, magic, magic_len))
+ sp += magic_len;
+
+ /* Compute the salt length:
+ it stops at the first '$', max 8 chars */
+ for (sl = 0; sl < 8 && sp[sl] && sp[sl] != '$'; sl++) ;
+
+ MD5Init(&ctx);
+
+ /* The password first, since that is what is most unknown */
+ MD5Update(&ctx, pw, pwlen);
+
+ /* Then our magic string */
+ MD5Update(&ctx, magic, magic_len);
+
+ /* Then the raw salt */
+ MD5Update(&ctx, sp, sl);
+
+ /* Then just as many characters of the MD5(pw,salt,pw) */
+ MD5Init(&ctx1);
+ MD5Update(&ctx1, pw, pwlen);
+ MD5Update(&ctx1, sp, sl);
+ MD5Update(&ctx1, pw, pwlen);
+ MD5Final(final, &ctx1);
+ for (pl = pwlen; pl > 0; pl -= MD5_SIZE)
+ MD5Update(&ctx, final, pl > MD5_SIZE ? MD5_SIZE : pl);
+
+ /* Don't leave anything around in vm they could use. */
+ memset(final, 0, sizeof final);
+
+ /* Then something really weird... */
+ for (i = pwlen; i; i >>= 1)
+ if (i & 1)
+ MD5Update(&ctx, final, 1);
+ else
+ MD5Update(&ctx, pw, 1);
+
+ /* Now make the output string */
+ p = passwd;
+
+ memcpy(p, magic, magic_len);
+ p += magic_len;
+
+ memcpy(p, sp, sl);
+ p += sl;
+
+ *p++ = '$';
+
+ MD5Final(final, &ctx);
+
+ /*
+ * and now, just to make sure things don't run too fast
+ * On a 60 Mhz Pentium this takes 34 msec, so you would
+ * need 30 seconds to build a 1000 entry dictionary...
+ */
+ for (i = 0; i < 1000; i++) {
+ MD5Init(&ctx1);
+ if (i & 1)
+ MD5Update(&ctx1, pw, pwlen);
+ else
+ MD5Update(&ctx1, final, MD5_SIZE);
+
+ if (i % 3)
+ MD5Update(&ctx1, sp, sl);
+
+ if (i % 7)
+ MD5Update(&ctx1, pw, pwlen);
+
+ if (i & 1)
+ MD5Update(&ctx1, final, MD5_SIZE);
+ else
+ MD5Update(&ctx1, pw, pwlen);
+ MD5Final(final, &ctx1);
+ }
+
+ l = (final[0] << 16) | (final[6] << 8) | final[12];
+ p = _crypt_to64(p, l, 4);
+ l = (final[1] << 16) | (final[7] << 8) | final[13];
+ p = _crypt_to64(p, l, 4);
+ l = (final[2] << 16) | (final[8] << 8) | final[14];
+ p = _crypt_to64(p, l, 4);
+ l = (final[3] << 16) | (final[9] << 8) | final[15];
+ p = _crypt_to64(p, l, 4);
+ l = (final[4] << 16) | (final[10] << 8) | final[5];
+ p = _crypt_to64(p, l, 4);
+ l = final[11];
+ p = _crypt_to64(p, l, 2);
+ *p = '\0';
+
+ /* Don't leave anything around in vm they could use. */
+ memset(final, 0, sizeof final);
+
+ return passwd;
+}
+
+static void crypt_md5_exit(void)
+{
+ // Nothing to do
+}
+
+// Define entry and exit points.
+MODULE_INIT(crypt_md5_init);
+MODULE_EXIT(crypt_md5_exit);
diff --git a/com32/elflink/modules/dir.c b/com32/elflink/modules/dir.c
new file mode 100644
index 00000000..17e78801
--- /dev/null
+++ b/com32/elflink/modules/dir.c
@@ -0,0 +1,178 @@
+/*
+ * 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>
+
+#include <sys/module.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;
+}
+
+static int dir_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;
+}
+MODULE_MAIN(dir_main);
+
diff --git a/com32/elflink/modules/disk.c b/com32/elflink/modules/disk.c
new file mode 100644
index 00000000..3c864bd1
--- /dev/null
+++ b/com32/elflink/modules/disk.c
@@ -0,0 +1,60 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2009 Pierre-Alexandre Meyer - 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 <stdio.h>
+#include <console.h>
+#include <stdlib.h>
+#include <string.h>
+#include <disk/geom.h>
+#include <disk/util.h>
+#include <disk/errno_disk.h>
+#include <disk/error.h>
+
+#include <sys/module.h>
+
+int disk_main(int argc, char *argv[])
+{
+ struct driveinfo drive;
+ struct driveinfo *d = &drive;
+
+ for (int disk = 0x80; disk < 0xff; disk++) {
+ memset(d, 0, sizeof(struct driveinfo));
+ d->disk = disk;
+ get_drive_parameters(d);
+
+ /* Do not print output when drive does not exists */
+ if (errno_disk == -1 || !d->cbios)
+ continue;
+
+ if (errno_disk) {
+ printf("reading disk");
+ continue;
+ }
+
+ printf("DISK 0x%X:\n", d->disk);
+ printf(" C/H/S: %d heads, %d cylinders\n",
+ d->legacy_max_head + 1, d->legacy_max_cylinder + 1);
+ printf(" %d sectors/track, %d drives\n",
+ d->legacy_sectors_per_track, d->legacy_max_drive);
+ printf(" EDD: ebios=%d, EDD version: %X\n",
+ d->ebios, d->edd_version);
+ printf(" %d heads, %d cylinders\n",
+ (int) d->edd_params.heads, (int) d->edd_params.cylinders);
+ printf(" %d sectors, %d bytes/sector, %d sectors/track\n",
+ (int) d->edd_params.sectors, (int) d->edd_params.bytes_per_sector,
+ (int) d->edd_params.sectors_per_track);
+ printf(" Host bus: %s, Interface type: %s\n\n",
+ d->edd_params.host_bus_type, d->edd_params.interface_type);
+ }
+ return 0;
+}
+MODULE_MAIN(disk_main);
diff --git a/com32/elflink/modules/drain.c b/com32/elflink/modules/drain.c
new file mode 100644
index 00000000..032003c9
--- /dev/null
+++ b/com32/elflink/modules/drain.c
@@ -0,0 +1,40 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/cpu.h>
+#include <sys/module.h>
+
+static int drain_init(void)
+{
+ return 0; // Nothing to do; return success
+}
+
+void drain_keyboard(void)
+{
+ /* Prevent "ghost typing" and keyboard buffer snooping */
+ volatile char junk;
+ int rv;
+
+ do {
+ rv = read(0, (char *)&junk, 1);
+ } while (rv > 0);
+
+ junk = 0;
+
+ cli();
+ *(volatile uint8_t *)0x419 = 0; /* Alt-XXX keyboard area */
+ *(volatile uint16_t *)0x41a = 0x1e; /* Keyboard buffer empty */
+ *(volatile uint16_t *)0x41c = 0x1e;
+ memset((void *)0x41e, 0, 32); /* Clear the actual keyboard buffer */
+ sti();
+}
+
+static void drain_exit(void)
+{
+ // Nothing to do
+}
+
+// Define entry and exit points.
+MODULE_INIT(drain_init);
+MODULE_EXIT(drain_exit);
diff --git a/com32/elflink/modules/get_key.c b/com32/elflink/modules/get_key.c
new file mode 100644
index 00000000..5749b054
--- /dev/null
+++ b/com32/elflink/modules/get_key.c
@@ -0,0 +1,187 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * get_key.c
+ *
+ * Get a single key, and try to pick apart function key codes.
+ * This doesn't decode anywhere close to all possiblities, but
+ * hopefully is enough to be useful.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/times.h>
+#include <getkey.h>
+#include <libutil.h>
+#include <sys/module.h>
+
+static int getkey_init(void)
+{
+ return 0; // Nothing to do; return success
+}
+
+struct keycode {
+ int code;
+ int seqlen;
+ const unsigned char *seq;
+};
+
+#define MAXLEN 8
+#define CODE(x,y) { x, (sizeof y)-1, y }
+
+static const struct keycode keycodes[] = {
+ /* First, the BIOS combined codes */
+ CODE(KEY_F1, "\0\x3B"),
+ CODE(KEY_F2, "\0\x3C"),
+ CODE(KEY_F3, "\0\x3D"),
+ CODE(KEY_F4, "\0\x3E"),
+ CODE(KEY_F5, "\0\x3F"),
+ CODE(KEY_F6, "\0\x40"),
+ CODE(KEY_F7, "\0\x41"),
+ CODE(KEY_F8, "\0\x42"),
+ CODE(KEY_F9, "\0\x43"),
+ CODE(KEY_F10, "\0\x44"),
+ CODE(KEY_F11, "\0\x85"),
+ CODE(KEY_F12, "\0\x86"),
+
+ CODE(KEY_UP, "\0\x48"),
+ CODE(KEY_DOWN, "\0\x50"),
+ CODE(KEY_LEFT, "\0\x4B"),
+ CODE(KEY_RIGHT, "\0\x4D"),
+ CODE(KEY_PGUP, "\0\x49"),
+ CODE(KEY_PGDN, "\0\x51"),
+ CODE(KEY_HOME, "\0\x47"),
+ CODE(KEY_END, "\0\x4F"),
+ CODE(KEY_INSERT, "\0\x52"),
+ CODE(KEY_DELETE, "\0\x53"),
+
+ /* Now, VT/xterm/Linux codes */
+ CODE(KEY_F1, "\033[[A"),
+ CODE(KEY_F1, "\033OP"),
+ CODE(KEY_F2, "\033[[B"),
+ CODE(KEY_F2, "\033OQ"),
+ CODE(KEY_F3, "\033[[C"),
+ CODE(KEY_F3, "\033OR"),
+ CODE(KEY_F4, "\033[[D"),
+ CODE(KEY_F4, "\033OS"),
+ CODE(KEY_F5, "\033[[E"),
+ CODE(KEY_F5, "\033[15~"),
+ CODE(KEY_F6, "\033[17~"),
+ CODE(KEY_F7, "\033[18~"),
+ CODE(KEY_F8, "\033[19~"),
+ CODE(KEY_F9, "\033[20~"),
+ CODE(KEY_F10, "\033[21~"),
+ CODE(KEY_F11, "\033[23~"),
+ CODE(KEY_F12, "\033[24~"),
+
+ CODE(KEY_UP, "\033[A"),
+ CODE(KEY_DOWN, "\033[B"),
+ CODE(KEY_LEFT, "\033[D"),
+ CODE(KEY_RIGHT, "\033[C"),
+ CODE(KEY_PGUP, "\033[5~"),
+ CODE(KEY_PGUP, "\033[V"),
+ CODE(KEY_PGDN, "\033[6~"),
+ CODE(KEY_PGDN, "\033[U"),
+ CODE(KEY_HOME, "\033[1~"),
+ CODE(KEY_HOME, "\033[H"),
+ CODE(KEY_END, "\033[4~"),
+ CODE(KEY_END, "\033[F"),
+ CODE(KEY_END, "\033OF"),
+ CODE(KEY_INSERT, "\033[2~"),
+ CODE(KEY_INSERT, "\033[@"),
+ CODE(KEY_DELETE, "\033[3~"),
+};
+
+#define NCODES ((int)(sizeof keycodes/sizeof(struct keycode)))
+
+#define KEY_TIMEOUT ((CLK_TCK+9)/10)
+
+int get_key(FILE * f, clock_t timeout)
+{
+ unsigned char buffer[MAXLEN];
+ int nc, i, rv;
+ const struct keycode *kc;
+ int another;
+ unsigned char ch;
+ clock_t start;
+
+ /* We typically start in the middle of a clock tick */
+ if (timeout)
+ timeout++;
+
+ nc = 0;
+ start = times(NULL);
+ do {
+ rv = 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 */
+ else if (timeout && lateness > timeout)
+ return KEY_NONE;
+ } else if (!nc && timeout && lateness > timeout)
+ return KEY_NONE; /* timeout before sequence */
+
+ do_idle();
+
+ another = 1;
+ continue;
+ }
+
+ start = times(NULL);
+
+ 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)) {
+ 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];
+}
+
+static void getkey_exit(void)
+{
+ // Nothing to do
+}
+
+// Define entry and exit points.
+MODULE_INIT(getkey_init);
+MODULE_EXIT(getkey_exit);
diff --git a/com32/elflink/modules/hello.c b/com32/elflink/modules/hello.c
new file mode 100644
index 00000000..cba63e2e
--- /dev/null
+++ b/com32/elflink/modules/hello.c
@@ -0,0 +1,30 @@
+/*
+ * hello.c - A simple ELF module that sorts a couple of numbers
+ *
+ * Created on: Aug 11, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/module.h>
+
+#include "sort.h"
+
+#define NUM_COUNT 10
+#define MAX_NUM 100
+
+static int hello_main(int argc, char **argv)
+{
+ int *nums = NULL;
+ int i;
+
+ nums = malloc(NUM_COUNT * sizeof(int));
+ printf("Hello, world, from 0x%08X! malloc return %p\n", (unsigned int)&hello_main), nums;
+
+ free(nums);
+
+ return 0;
+}
+
+MODULE_MAIN(hello_main);
diff --git a/com32/elflink/modules/md5.c b/com32/elflink/modules/md5.c
new file mode 100644
index 00000000..c39bd9b7
--- /dev/null
+++ b/com32/elflink/modules/md5.c
@@ -0,0 +1,288 @@
+/*
+ * MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ *
+ * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ * rights reserved.
+ *
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ *
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ *
+ * This code is the same as the code published by RSA Inc. It has been
+ * edited for clarity and style only.
+ */
+
+#include <string.h>
+#include <endian.h>
+#include <md5.h>
+#include <sys/module.h>
+
+static int md5_init(void)
+{
+ return 0; // Nothing to do; return success
+}
+
+static void MD5Transform(uint32_t[4], const unsigned char[64]);
+
+#define Encode memcpy
+#define Decode memcpy
+
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions. */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits. */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/*
+ * FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+ * Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (uint32_t)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context. */
+
+void MD5Init(MD5_CTX * context)
+{
+ context->count[0] = context->count[1] = 0;
+
+ /* Load magic initialization constants. */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/*
+ * MD5 block update operation. Continues an MD5 message-digest
+ * operation, processing another message block, and updating the
+ * context.
+ */
+
+void MD5Update(MD5_CTX * context, const void *in, size_t inputLen)
+{
+ unsigned int i, idx, partLen;
+ const unsigned char *input = in;
+
+ /* Compute number of bytes mod 64 */
+ idx = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((uint32_t) inputLen << 3))
+ < ((uint32_t) inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((uint32_t) inputLen >> 29);
+
+ partLen = 64 - idx;
+
+ /* Transform as many times as possible. */
+ if (inputLen >= partLen) {
+ memcpy((void *)&context->buffer[idx], (const void *)input, partLen);
+ MD5Transform(context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform(context->state, &input[i]);
+
+ idx = 0;
+ } else
+ i = 0;
+
+ /* Buffer remaining input */
+ memcpy((void *)&context->buffer[idx], (const void *)&input[i],
+ inputLen - i);
+}
+
+/*
+ * MD5 padding. Adds padding followed by original length.
+ */
+
+static void MD5Pad(MD5_CTX * context)
+{
+ unsigned char bits[8];
+ unsigned int idx, padLen;
+
+ /* Save number of bits */
+ Encode(bits, context->count, 8);
+
+ /* Pad out to 56 mod 64. */
+ idx = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (idx < 56) ? (56 - idx) : (120 - idx);
+ MD5Update(context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD5Update(context, bits, 8);
+}
+
+/*
+ * MD5 finalization. Ends an MD5 message-digest operation, writing the
+ * the message digest and zeroizing the context.
+ */
+
+void MD5Final(unsigned char digest[16], MD5_CTX * context)
+{
+ /* Do padding. */
+ MD5Pad(context);
+
+ /* Store state in digest */
+ Encode(digest, context->state, 16);
+
+ /* Zeroize sensitive information. */
+ memset((void *)context, 0, sizeof(*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block. */
+
+static void MD5Transform(state, block)
+uint32_t state[4];
+const unsigned char block[64];
+{
+ uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode(x, block, 64);
+
+ /* Round 1 */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+ FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
+ FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
+ FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */
+ FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
+ FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
+ FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
+ FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
+ FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
+ FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
+ FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
+ FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+ GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
+ GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
+ GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
+ GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
+ GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
+ GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
+ GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
+ GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
+ GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
+ GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
+ GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+ HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
+ HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
+ HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
+ HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
+ HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
+ HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
+ HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
+ HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
+ HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
+ HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+ II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
+ II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
+ II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
+ II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
+ II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
+ II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
+ II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
+ II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
+ II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
+ II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information. */
+ memset((void *)x, 0, sizeof(x));
+}
+
+static void md5_exit(void)
+{
+ // Nothing to do
+}
+
+// Define entry and exit points.
+MODULE_INIT(md5_init);
+MODULE_EXIT(md5_exit);
diff --git a/com32/elflink/modules/md5.h b/com32/elflink/modules/md5.h
new file mode 100644
index 00000000..db38c66d
--- /dev/null
+++ b/com32/elflink/modules/md5.h
@@ -0,0 +1,46 @@
+/* MD5.H - header file for MD5C.C
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+#ifndef _LIBUTIL_MD5_H
+#define _LIBUTIL_MD5_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#define MD5_SIZE 16 /* 128 bits */
+
+/* MD5 context. */
+typedef struct {
+ uint32_t state[4]; /* state (ABCD) */
+ uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} MD5_CTX;
+
+void MD5Init(MD5_CTX *);
+void MD5Update(MD5_CTX *, const void *, size_t);
+void MD5Final(unsigned char[MD5_SIZE], MD5_CTX *);
+
+char *crypt_md5(const char *, const char *);
+
+#endif
diff --git a/com32/elflink/modules/meminfo.c b/com32/elflink/modules/meminfo.c
new file mode 100644
index 00000000..db9718ae
--- /dev/null
+++ b/com32/elflink/modules/meminfo.c
@@ -0,0 +1,133 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * meminfo.c
+ *
+ * Dump the memory map of the system
+ */
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+#include <console.h>
+#include <com32.h>
+
+#include <sys/module.h>
+
+struct e820_data {
+ uint64_t base;
+ uint64_t len;
+ uint32_t type;
+ uint32_t extattr;
+} __attribute__ ((packed));
+
+static const char *const e820_types[] = {
+ "usable",
+ "reserved",
+ "ACPI reclaim",
+ "ACPI NVS",
+ "unusable",
+};
+
+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(low_ed);
+ ireg.es = SEG(low_ed);
+
+ memset(&ed, 0, sizeof ed);
+ ed.extattr = 1;
+
+ do {
+ 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, low_ed, sizeof ed);
+
+ if (oreg.ecx.l >= 24) {
+ /* ebx base length end type */
+ printf("%8x %016llx %016llx %016llx %d [%x]",
+ ireg.ebx.l, ed.base, ed.len, ed.base + ed.len, ed.type,
+ ed.extattr);
+ } else {
+ /* ebx base length end */
+ printf("%8x %016llx %016llx %016llx %d [-]",
+ ireg.ebx.l, ed.base, ed.len, ed.base + ed.len, ed.type);
+ ed.extattr = 1;
+ }
+
+ type = ed.type - 1;
+ if (type < sizeof(e820_types) / sizeof(e820_types[0]))
+ printf(" %s", e820_types[type]);
+
+ putchar('\n');
+
+ ireg.ebx.l = oreg.ebx.l;
+ } while (ireg.ebx.l);
+
+ free(low_ed);
+}
+
+static void dump_legacy(void)
+{
+ com32sys_t ireg, oreg;
+ uint16_t dosram = *(uint16_t *) 0x413;
+ struct {
+ uint16_t offs, seg;
+ } *const ivt = (void *)0;
+
+ memset(&ireg, 0, sizeof ireg);
+
+ __intcall(0x12, &ireg, &oreg);
+
+ printf
+ ("INT 15h = %04x:%04x DOS RAM: %dK (0x%05x) INT 12h: %dK (0x%05x)\n",
+ ivt[0x15].seg, ivt[0x15].offs, dosram, dosram << 10, oreg.eax.w[0],
+ oreg.eax.w[0] << 10);
+
+ ireg.eax.b[1] = 0x88;
+ __intcall(0x15, &ireg, &oreg);
+
+ printf("INT 15 88: 0x%04x (%uK) ", oreg.eax.w[0], oreg.eax.w[0]);
+
+ ireg.eax.w[0] = 0xe801;
+ __intcall(0x15, &ireg, &oreg);
+
+ printf("INT 15 E801: 0x%04x (%uK) 0x%04x (%uK)\n",
+ oreg.ecx.w[0], oreg.ecx.w[0], oreg.edx.w[0], oreg.edx.w[0] << 6);
+}
+
+static int meminfo_main(void)
+{
+ dump_legacy();
+ dump_e820();
+ return 0;
+}
+MODULE_MAIN(meminfo_main);
diff --git a/com32/elflink/modules/menu.c b/com32/elflink/modules/menu.c
new file mode 100644
index 00000000..a4faf898
--- /dev/null
+++ b/com32/elflink/modules/menu.c
@@ -0,0 +1,19 @@
+/*
+ * menu.c -- simple program to test menu_main()
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/module.h>
+
+#include "menu.h"
+
+/*
+ * useage: menu.c32 [config file]
+ */
+static int menu(int argc, char **argv)
+{
+ menu_main(argc, argv);
+ return 0;
+}
+MODULE_MAIN(menu);
diff --git a/com32/elflink/modules/menu.h b/com32/elflink/modules/menu.h
new file mode 100644
index 00000000..5b05fe81
--- /dev/null
+++ b/com32/elflink/modules/menu.h
@@ -0,0 +1,228 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * menu.h
+ *
+ * Header file for the simple menu system
+ */
+
+#ifndef MENU_H
+#define MENU_H
+
+#include <time.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <colortbl.h>
+#include <stdbool.h>
+#include <setjmp.h>
+#include "refstr.h"
+
+#ifndef CLK_TCK
+# define CLK_TCK sysconf(_SC_CLK_TCK)
+#endif
+
+struct menu;
+
+/* Note: the _UNRES variants must always be immediately after their
+ "normal" versions. */
+enum menu_action {
+ MA_NONE, /* Undefined value */
+ MA_CMD, /* Execute a command */
+ MA_DISABLED, /* Disabled menu entry */
+ MA_SUBMENU, /* This is a submenu entry */
+ MA_GOTO, /* Go to another menu */
+ MA_GOTO_UNRES, /* Unresolved go to */
+ MA_QUIT, /* Quit to CLI */
+ MA_EXIT, /* Exit to higher-level menu */
+ MA_EXIT_UNRES, /* Unresolved exit */
+};
+
+struct menu_entry {
+ struct menu *menu; /* Parent menu */
+ const char *displayname;
+ const char *label;
+ const char *passwd;
+ char *helptext;
+ const char *cmdline;
+ struct menu *submenu;
+ struct menu_entry *next; /* Linked list of all labels across menus */
+ int entry; /* Entry number inside menu */
+ enum menu_action action;
+ unsigned char hotkey;
+ bool save; /* Save this entry if selected */
+};
+
+static inline bool is_disabled(struct menu_entry *me)
+{
+ return me->action == MA_DISABLED;
+}
+
+enum kernel_type {
+ /* Meta-types for internal use */
+ KT_NONE,
+ KT_LOCALBOOT,
+
+ /* The ones we can pass off to SYSLINUX, in order */
+ KT_KERNEL, /* Undefined type */
+ KT_LINUX, /* Linux kernel */
+ KT_BOOT, /* Bootstrap program */
+ 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,
+ P_MARGIN,
+ P_PASSWD_MARGIN,
+ P_MENU_ROWS,
+ P_TABMSG_ROW,
+ P_CMDLINE_ROW,
+ P_END_ROW,
+ P_PASSWD_ROW,
+ P_TIMEOUT_ROW,
+ P_HELPMSG_ROW,
+ P_HELPMSGEND_ROW,
+ P_HSHIFT,
+ P_VSHIFT,
+ P_HIDDEN_ROW,
+
+ NPARAMS
+};
+
+/* Configurable messages */
+enum message_number {
+ MSG_TITLE,
+ MSG_AUTOBOOT,
+ MSG_TAB,
+ MSG_NOTAB,
+ MSG_PASSPROMPT,
+
+ MSG_COUNT
+};
+
+struct messages {
+ const char *name; /* Message configuration name */
+ const char *defmsg; /* Default message text */
+};
+
+struct menu_parameter {
+ const char *name;
+ int value;
+};
+
+extern const struct menu_parameter mparm[NPARAMS];
+
+struct fkey_help {
+ const char *textname;
+ const char *background;
+};
+
+struct menu {
+ struct menu *next; /* Linked list of all menus */
+ const char *label; /* Goto label for this menu */
+ struct menu *parent;
+ struct menu_entry *parent_entry; /* Entry for self in parent */
+
+ struct menu_entry **menu_entries;
+ struct menu_entry *menu_hotkeys[256];
+
+ const char *messages[MSG_COUNT];
+ int mparm[NPARAMS];
+
+ int nentries;
+ int nentries_space;
+ int defentry;
+ int timeout;
+
+ bool allowedit;
+ bool save; /* MENU SAVE default for this menu */
+
+ int curentry;
+ int curtop;
+
+ const char *title;
+ const char *ontimeout;
+ const char *onerror;
+ const char *menu_master_passwd;
+ const char *menu_background;
+
+ struct color_table *color_table;
+
+ struct fkey_help fkeyhelp[12];
+};
+
+extern struct menu *root_menu, *start_menu, *hide_menu, *menu_list;
+
+/* 2048 is the current definition inside syslinux */
+#define MAX_CMDLINE_LEN 2048
+
+/* These are global parameters regardless of which menu we're displaying */
+extern int shiftkey;
+extern int hiddenmenu;
+extern long long totaltimeout;
+
+void parse_configs(char **argv);
+extern int draw_background(const char *filename);
+
+static inline int my_isspace(char c)
+{
+ return (unsigned char)c <= ' ';
+}
+
+int my_isxdigit(char c);
+unsigned int hexval(char c);
+unsigned int hexval2(const char *p);
+uint32_t parse_argb(char **p);
+
+int menu_main(int argc, char *argv[]);
+void console_prepare(void);
+void console_cleanup(void);
+
+extern const int message_base_color, menu_color_table_size;
+int mygetkey(clock_t timeout);
+int show_message_file(const char *filename, const char *background);
+
+/* passwd.c */
+int passwd_compare(const char *passwd, const char *entry);
+
+/* colors.c */
+#define MSG_COLORS_DEF_FG 0x90ffffff
+#define MSG_COLORS_DEF_BG 0x80ffffff
+#define MSG_COLORS_DEF_SHADOW SHADOW_NORMAL
+void set_msg_colors_global(struct color_table *tbl,
+ unsigned int fg, unsigned int bg,
+ enum color_table_shadow shadow);
+struct color_table *default_color_table(void);
+struct color_table *copy_color_table(const struct color_table *master);
+extern const int message_base_color;
+
+/* background.c */
+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);
+
+#endif /* MENU_H */
diff --git a/com32/elflink/modules/menumain.c b/com32/elflink/modules/menumain.c
new file mode 100644
index 00000000..86285857
--- /dev/null
+++ b/com32/elflink/modules/menumain.c
@@ -0,0 +1,975 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * menumain.c
+ *
+ * Simple menu system which displays a list and allows the user to select
+ * a command line and/or edit it.
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <consoles.h>
+#include <getkey.h>
+#include <minmax.h>
+#include <setjmp.h>
+#include <limits.h>
+#include <com32.h>
+#include <syslinux/adv.h>
+#include <sys/module.h>
+
+#include "menu.h"
+#include "cli.h"
+
+static jmp_buf timeout_jump;
+
+static int menumain_init(void)
+{
+ return 0; // Nothing to do; return success
+}
+
+/* The symbol "cm" always refers to the current menu across this file... */
+static struct menu *cm;
+
+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},
+};
+
+/* These macros assume "cm" is a pointer to the current menu */
+#define WIDTH (cm->mparm[P_WIDTH])
+#define MARGIN (cm->mparm[P_MARGIN])
+#define PASSWD_MARGIN (cm->mparm[P_PASSWD_MARGIN])
+#define MENU_ROWS (cm->mparm[P_MENU_ROWS])
+#define TABMSG_ROW (cm->mparm[P_TABMSG_ROW]+VSHIFT)
+#define CMDLINE_ROW (cm->mparm[P_CMDLINE_ROW]+VSHIFT)
+#define END_ROW (cm->mparm[P_END_ROW])
+#define PASSWD_ROW (cm->mparm[P_PASSWD_ROW]+VSHIFT)
+#define TIMEOUT_ROW (cm->mparm[P_TIMEOUT_ROW]+VSHIFT)
+#define HELPMSG_ROW (cm->mparm[P_HELPMSG_ROW]+VSHIFT)
+#define HELPMSGEND_ROW (cm->mparm[P_HELPMSGEND_ROW])
+#define HSHIFT (cm->mparm[P_HSHIFT])
+#define VSHIFT (cm->mparm[P_VSHIFT])
+#define HIDDEN_ROW (cm->mparm[P_HIDDEN_ROW])
+
+static char *pad_line(const char *text, int align, int width)
+{
+ static char buffer[MAX_CMDLINE_LEN];
+ int n, p;
+
+ if (width >= (int)sizeof buffer)
+ return NULL; /* Can't do it */
+
+ n = strlen(text);
+ if (n >= width)
+ n = width;
+
+ memset(buffer, ' ', width);
+ buffer[width] = 0;
+ p = ((width - n) * align) >> 1;
+ memcpy(buffer + p, text, n);
+
+ return buffer;
+}
+
+/* Display an entry, with possible hotkey highlight. Assumes
+ that the current attribute is the non-hotkey one, and will
+ guarantee that as an exit condition as well. */
+static void
+display_entry(const struct menu_entry *entry, const char *attrib,
+ const char *hotattrib, int width)
+{
+ const char *p = entry->displayname;
+ char marker;
+
+ if (!p)
+ p = "";
+
+ switch (entry->action) {
+ case MA_SUBMENU:
+ marker = '>';
+ break;
+ case MA_EXIT:
+ marker = '<';
+ break;
+ default:
+ marker = 0;
+ break;
+ }
+
+ if (marker)
+ width -= 2;
+
+ while (width) {
+ if (*p) {
+ if (*p == '^') {
+ p++;
+ if (*p && ((unsigned char)*p & ~0x20) == entry->hotkey) {
+ fputs(hotattrib, stdout);
+ putchar(*p++);
+ fputs(attrib, stdout);
+ width--;
+ }
+ } else {
+ putchar(*p++);
+ width--;
+ }
+ } else {
+ putchar(' ');
+ width--;
+ }
+ }
+
+ if (marker) {
+ putchar(' ');
+ putchar(marker);
+ }
+}
+
+static void draw_row(int y, int sel, int top, int sbtop, int sbbot)
+{
+ int i = (y - 4 - VSHIFT) + top;
+ int dis = (i < cm->nentries) && is_disabled(cm->menu_entries[i]);
+
+ printf("\033[%d;%dH\1#1\016x\017%s ",
+ y, MARGIN + 1 + HSHIFT,
+ (i == sel) ? "\1#5" : dis ? "\2#17" : "\1#3");
+
+ if (i >= cm->nentries) {
+ fputs(pad_line("", 0, WIDTH - 2 * MARGIN - 4), stdout);
+ } else {
+ display_entry(cm->menu_entries[i],
+ (i == sel) ? "\1#5" : dis ? "\2#17" : "\1#3",
+ (i == sel) ? "\1#6" : dis ? "\2#17" : "\1#4",
+ WIDTH - 2 * MARGIN - 4);
+ }
+
+ if (cm->nentries <= MENU_ROWS) {
+ printf(" \1#1\016x\017");
+ } else if (sbtop > 0) {
+ if (y >= sbtop && y <= sbbot)
+ printf(" \1#7\016a\017");
+ else
+ printf(" \1#1\016x\017");
+ } else {
+ putchar(' '); /* Don't modify the scrollbar */
+ }
+}
+
+int show_message_file(const char *filename, const char *background)
+{
+ int rv = KEY_NONE;
+ const char *old_background = NULL;
+
+ if (background) {
+ old_background = current_background;
+ set_background(background);
+ }
+
+ if (!(rv = draw_message_file(filename)))
+ rv = mygetkey(0); /* Wait for keypress */
+
+ if (old_background)
+ set_background(old_background);
+
+ return rv;
+}
+
+static int ask_passwd(const char *menu_entry)
+{
+ char user_passwd[WIDTH], *p;
+ int done;
+ int key;
+ int x;
+ int rv;
+
+ printf("\033[%d;%dH\2#11\016l", PASSWD_ROW, PASSWD_MARGIN + 1);
+ for (x = 2; x <= WIDTH - 2 * PASSWD_MARGIN - 1; x++)
+ putchar('q');
+
+ printf("k\033[%d;%dHx", PASSWD_ROW + 1, PASSWD_MARGIN + 1);
+ for (x = 2; x <= WIDTH - 2 * PASSWD_MARGIN - 1; x++)
+ putchar(' ');
+
+ printf("x\033[%d;%dHm", PASSWD_ROW + 2, PASSWD_MARGIN + 1);
+ for (x = 2; x <= WIDTH - 2 * PASSWD_MARGIN - 1; x++)
+ putchar('q');
+
+ printf("j\017\033[%d;%dH\2#12 %s \033[%d;%dH\2#13",
+ PASSWD_ROW, (WIDTH - (strlen(cm->messages[MSG_PASSPROMPT]) + 2)) / 2,
+ cm->messages[MSG_PASSPROMPT], PASSWD_ROW + 1, PASSWD_MARGIN + 3);
+
+ drain_keyboard();
+
+ /* Actually allow user to type a password, then compare to the SHA1 */
+ done = 0;
+ p = user_passwd;
+
+ while (!done) {
+ key = mygetkey(0);
+
+ switch (key) {
+ case KEY_ENTER:
+ case KEY_CTRL('J'):
+ done = 1;
+ break;
+
+ case KEY_ESC:
+ case KEY_CTRL('C'):
+ p = user_passwd; /* No password entered */
+ done = 1;
+ break;
+
+ case KEY_BACKSPACE:
+ case KEY_DEL:
+ case KEY_DELETE:
+ if (p > user_passwd) {
+ printf("\b \b");
+ p--;
+ }
+ break;
+
+ case KEY_CTRL('U'):
+ while (p > user_passwd) {
+ printf("\b \b");
+ p--;
+ }
+ break;
+
+ default:
+ if (key >= ' ' && key <= 0xFF &&
+ (p - user_passwd) < WIDTH - 2 * PASSWD_MARGIN - 5) {
+ *p++ = key;
+ putchar('*');
+ }
+ break;
+ }
+ }
+
+ if (p == user_passwd)
+ return 0; /* No password entered */
+
+ *p = '\0';
+
+ rv = (cm->menu_master_passwd &&
+ passwd_compare(cm->menu_master_passwd, user_passwd))
+ || (menu_entry && passwd_compare(menu_entry, user_passwd));
+
+ /* Clean up */
+ memset(user_passwd, 0, WIDTH);
+ drain_keyboard();
+
+ return rv;
+}
+
+static int draw_menu(int sel, int top, int edit_line)
+{
+ int x, y;
+ int sbtop = 0, sbbot = 0;
+ const char *tabmsg;
+ int tabmsg_len;
+
+ if (cm->nentries > MENU_ROWS) {
+ int sblen = max(MENU_ROWS * MENU_ROWS / cm->nentries, 1);
+ sbtop = (MENU_ROWS - sblen + 1) * top / (cm->nentries - MENU_ROWS + 1);
+ sbbot = sbtop + sblen - 1;
+ sbtop += 4;
+ sbbot += 4; /* Starting row of scrollbar */
+ }
+
+ printf("\033[%d;%dH\1#1\016l", VSHIFT + 1, HSHIFT + MARGIN + 1);
+ for (x = 2 + HSHIFT; x <= (WIDTH - 2 * MARGIN - 1) + HSHIFT; x++)
+ putchar('q');
+
+ printf("k\033[%d;%dH\1#1x\017\1#2 %s \1#1\016x",
+ VSHIFT + 2,
+ HSHIFT + MARGIN + 1, pad_line(cm->title, 1, WIDTH - 2 * MARGIN - 4));
+
+ printf("\033[%d;%dH\1#1t", VSHIFT + 3, HSHIFT + MARGIN + 1);
+ for (x = 2 + HSHIFT; x <= (WIDTH - 2 * MARGIN - 1) + HSHIFT; x++)
+ putchar('q');
+ fputs("u\017", stdout);
+
+ for (y = 4 + VSHIFT; y < 4 + VSHIFT + MENU_ROWS; y++)
+ draw_row(y, sel, top, sbtop, sbbot);
+
+ printf("\033[%d;%dH\1#1\016m", y, HSHIFT + MARGIN + 1);
+ for (x = 2 + HSHIFT; x <= (WIDTH - 2 * MARGIN - 1) + HSHIFT; x++)
+ putchar('q');
+ fputs("j\017", stdout);
+
+ if (edit_line && cm->allowedit && !cm->menu_master_passwd)
+ tabmsg = cm->messages[MSG_TAB];
+ else
+ tabmsg = cm->messages[MSG_NOTAB];
+
+ tabmsg_len = strlen(tabmsg);
+
+ printf("\1#8\033[%d;%dH%s",
+ TABMSG_ROW, 1 + HSHIFT + ((WIDTH - tabmsg_len) >> 1), tabmsg);
+ printf("\1#0\033[%d;1H", END_ROW);
+ return 0;
+}
+
+static void display_help(const char *text)
+{
+ int row;
+ const char *p;
+
+ if (!text) {
+ text = "";
+ printf("\1#0\033[%d;1H", HELPMSG_ROW);
+ } else {
+ printf("\2#16\033[%d;1H", HELPMSG_ROW);
+ }
+
+ for (p = text, row = HELPMSG_ROW; *p && row <= HELPMSGEND_ROW; p++) {
+ switch (*p) {
+ case '\r':
+ case '\f':
+ case '\v':
+ case '\033':
+ break;
+ case '\n':
+ printf("\033[K\033[%d;1H", ++row);
+ break;
+ default:
+ putchar(*p);
+ }
+ }
+
+ fputs("\033[K", stdout);
+
+ while (row <= HELPMSGEND_ROW) {
+ printf("\033[K\033[%d;1H", ++row);
+ }
+}
+
+static void show_fkey(int key)
+{
+ int fkey;
+
+ while (1) {
+ 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)
+ break;
+
+ if (cm->fkeyhelp[fkey].textname)
+ key = show_message_file(cm->fkeyhelp[fkey].textname,
+ cm->fkeyhelp[fkey].background);
+ else
+ break;
+ }
+}
+
+static inline int shift_is_held(void)
+{
+ uint8_t shift_bits = *(uint8_t *) 0x417;
+
+ return !!(shift_bits & 0x5d); /* Caps/Scroll/Alt/Shift */
+}
+
+static void print_timeout_message(int tol, int row, const char *msg)
+{
+ char buf[256];
+ int nc = 0, nnc;
+ const char *tp = msg;
+ char tc;
+ char *tq = buf;
+
+ while ((size_t) (tq - buf) < (sizeof buf - 16) && (tc = *tp)) {
+ tp++;
+ if (tc == '#') {
+ nnc = sprintf(tq, "\2#15%d\2#14", tol);
+ tq += nnc;
+ nc += nnc - 8; /* 8 formatting characters */
+ } else if (tc == '{') {
+ /* Deal with {singular[,dual],plural} constructs */
+ struct {
+ const char *s, *e;
+ } tx[3];
+ const char *tpp;
+ int n = 0;
+
+ memset(tx, 0, sizeof tx);
+
+ tx[0].s = tp;
+
+ while (*tp && *tp != '}') {
+ if (*tp == ',' && n < 2) {
+ tx[n].e = tp;
+ n++;
+ tx[n].s = tp + 1;
+ }
+ tp++;
+ }
+ tx[n].e = tp;
+
+ if (*tp)
+ tp++; /* Skip final bracket */
+
+ if (!tx[1].s)
+ tx[1] = tx[0];
+ if (!tx[2].s)
+ tx[2] = tx[1];
+
+ /* Now [0] is singular, [1] is dual, and [2] is plural,
+ even if the user only specified some of them. */
+
+ switch (tol) {
+ case 1:
+ n = 0;
+ break;
+ case 2:
+ n = 1;
+ break;
+ default:
+ n = 2;
+ break;
+ }
+
+ for (tpp = tx[n].s; tpp < tx[n].e; tpp++) {
+ if ((size_t) (tq - buf) < (sizeof buf)) {
+ *tq++ = *tpp;
+ nc++;
+ }
+ }
+ } else {
+ *tq++ = tc;
+ nc++;
+ }
+ }
+ *tq = '\0';
+
+ /* Let's hope 4 spaces on each side is enough... */
+ printf("\033[%d;%dH\2#14 %s ", row,
+ HSHIFT + 1 + ((WIDTH - nc - 8) >> 1), buf);
+}
+
+/* Set the background screen, etc. */
+static void prepare_screen_for_menu(void)
+{
+ console_color_table = cm->color_table;
+ console_color_table_size = menu_color_table_size;
+ set_background(cm->menu_background);
+}
+
+static const char *do_hidden_menu(void)
+{
+ int key;
+ int timeout_left, this_timeout;
+
+ clear_screen();
+
+ if (!setjmp(timeout_jump)) {
+ timeout_left = cm->timeout;
+
+ while (!cm->timeout || timeout_left) {
+ int tol = timeout_left / CLK_TCK;
+
+ print_timeout_message(tol, HIDDEN_ROW, cm->messages[MSG_AUTOBOOT]);
+
+ this_timeout = min(timeout_left, CLK_TCK);
+ key = mygetkey(this_timeout);
+
+ if (key != KEY_NONE)
+ return NULL; /* Key pressed */
+
+ timeout_left -= this_timeout;
+ }
+ }
+
+ if (cm->ontimeout)
+ return cm->ontimeout;
+ else
+ return cm->menu_entries[cm->defentry]->cmdline; /* Default entry */
+}
+
+static const char *run_menu(void)
+{
+ int key;
+ int done = 0;
+ volatile int entry = cm->curentry;
+ int prev_entry = -1;
+ volatile int top = cm->curtop;
+ int prev_top = -1;
+ int clear = 1, to_clear;
+ const char *cmdline = NULL;
+ volatile clock_t key_timeout, timeout_left, this_timeout;
+ const struct menu_entry *me;
+
+ /* Note: for both key_timeout and timeout == 0 means no limit */
+ timeout_left = key_timeout = cm->timeout;
+
+ /* If we're in shiftkey mode, exit immediately unless a shift key
+ is pressed */
+ if (shiftkey && !shift_is_held()) {
+ return cm->menu_entries[cm->defentry]->cmdline;
+ } else {
+ shiftkey = 0;
+ }
+
+ /* Do this before hiddenmenu handling, so we show the background */
+ prepare_screen_for_menu();
+
+ /* Handle hiddenmenu */
+ if (hiddenmenu) {
+ cmdline = do_hidden_menu();
+ if (cmdline)
+ return cmdline;
+
+ /* Otherwise display the menu now; the timeout has already been
+ cancelled, since the user pressed a key. */
+ hiddenmenu = 0;
+ key_timeout = 0;
+ }
+
+ /* Handle both local and global timeout */
+ if (setjmp(timeout_jump)) {
+ entry = cm->defentry;
+
+ if (top < 0 || top < entry - MENU_ROWS + 1)
+ top = max(0, entry - MENU_ROWS + 1);
+ else if (top > entry || top > max(0, cm->nentries - MENU_ROWS))
+ top = min(entry, max(0, cm->nentries - MENU_ROWS));
+
+ draw_menu(cm->ontimeout ? -1 : entry, top, 1);
+ cmdline =
+ cm->ontimeout ? cm->ontimeout : cm->menu_entries[entry]->cmdline;
+ done = 1;
+ }
+
+ while (!done) {
+ if (entry <= 0) {
+ entry = 0;
+ while (entry < cm->nentries && is_disabled(cm->menu_entries[entry]))
+ entry++;
+ }
+ if (entry >= cm->nentries) {
+ entry = cm->nentries - 1;
+ while (entry > 0 && is_disabled(cm->menu_entries[entry]))
+ entry--;
+ }
+
+ me = cm->menu_entries[entry];
+
+ if (top < 0 || top < entry - MENU_ROWS + 1)
+ top = max(0, entry - MENU_ROWS + 1);
+ else if (top > entry || top > max(0, cm->nentries - MENU_ROWS))
+ top = min(entry, max(0, cm->nentries - MENU_ROWS));
+
+ /* Start with a clear screen */
+ if (clear) {
+ /* 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 */
+ if (clear >= 2)
+ prepare_screen_for_menu();
+ clear_screen();
+ clear = 0;
+ prev_entry = prev_top = -1;
+ }
+
+ if (top != prev_top) {
+ draw_menu(entry, top, 1);
+ display_help(me->helptext);
+ } else if (entry != prev_entry) {
+ draw_row(prev_entry - top + 4 + VSHIFT, entry, top, 0, 0);
+ draw_row(entry - top + 4 + VSHIFT, entry, top, 0, 0);
+ display_help(me->helptext);
+ }
+
+ prev_entry = entry;
+ prev_top = top;
+ cm->curentry = entry;
+ cm->curtop = top;
+
+ /* Cursor movement cancels timeout */
+ if (entry != cm->defentry)
+ key_timeout = 0;
+
+ if (key_timeout) {
+ int tol = timeout_left / CLK_TCK;
+ print_timeout_message(tol, TIMEOUT_ROW, cm->messages[MSG_AUTOBOOT]);
+ to_clear = 1;
+ } else {
+ to_clear = 0;
+ }
+
+ this_timeout = min(min(key_timeout, timeout_left), (clock_t) CLK_TCK);
+ key = mygetkey(this_timeout);
+
+ if (key != KEY_NONE) {
+ timeout_left = key_timeout;
+ if (to_clear)
+ printf("\033[%d;1H\1#0\033[K", TIMEOUT_ROW);
+ }
+
+ switch (key) {
+ case KEY_NONE: /* Timeout */
+ /* This is somewhat hacky, but this at least lets the user
+ know what's going on, and still deals with "phantom inputs"
+ e.g. on serial ports.
+
+ Warning: a timeout will boot the default entry without any
+ password! */
+ if (key_timeout) {
+ if (timeout_left <= this_timeout)
+ longjmp(timeout_jump, 1);
+
+ timeout_left -= this_timeout;
+ }
+ break;
+
+ case KEY_CTRL('L'):
+ clear = 1;
+ break;
+
+ case KEY_ENTER:
+ case KEY_CTRL('J'):
+ key_timeout = 0; /* Cancels timeout */
+ if (me->passwd) {
+ clear = 1;
+ done = ask_passwd(me->passwd);
+ } else {
+ done = 1;
+ }
+ cmdline = NULL;
+ if (done) {
+ switch (me->action) {
+ case MA_CMD:
+ cmdline = me->cmdline;
+ break;
+ case MA_SUBMENU:
+ case MA_GOTO:
+ case MA_EXIT:
+ done = 0;
+ clear = 2;
+ cm = me->submenu;
+ entry = cm->curentry;
+ top = cm->curtop;
+ break;
+ case MA_QUIT:
+ /* Quit menu system */
+ done = 1;
+ clear = 1;
+ draw_row(entry - top + 4 + VSHIFT, -1, top, 0, 0);
+ break;
+ default:
+ done = 0;
+ break;
+ }
+ }
+ if (done && !me->passwd) {
+ /* Only save a new default if we don't have a password... */
+ /*
+ if (me->save && me->label) {
+ syslinux_setadv(ADV_MENUSAVE, strlen(me->label), me->label);
+ syslinux_adv_write();
+ }
+ */
+ }
+ break;
+
+ case KEY_UP:
+ case KEY_CTRL('P'):
+ while (entry > 0) {
+ entry--;
+ if (entry < top)
+ top -= MENU_ROWS;
+ if (!is_disabled(cm->menu_entries[entry]))
+ break;
+ }
+ break;
+
+ case KEY_DOWN:
+ case KEY_CTRL('N'):
+ while (entry < cm->nentries - 1) {
+ entry++;
+ if (entry >= top + MENU_ROWS)
+ top += MENU_ROWS;
+ if (!is_disabled(cm->menu_entries[entry]))
+ break;
+ }
+ break;
+
+ case KEY_PGUP:
+ case KEY_LEFT:
+ case KEY_CTRL('B'):
+ case '<':
+ entry -= MENU_ROWS;
+ top -= MENU_ROWS;
+ while (entry > 0 && is_disabled(cm->menu_entries[entry])) {
+ entry--;
+ if (entry < top)
+ top -= MENU_ROWS;
+ }
+ break;
+
+ case KEY_PGDN:
+ case KEY_RIGHT:
+ case KEY_CTRL('F'):
+ case '>':
+ case ' ':
+ entry += MENU_ROWS;
+ top += MENU_ROWS;
+ while (entry < cm->nentries - 1
+ && is_disabled(cm->menu_entries[entry])) {
+ entry++;
+ if (entry >= top + MENU_ROWS)
+ top += MENU_ROWS;
+ }
+ break;
+
+ case '-':
+ while (entry > 0) {
+ entry--;
+ top--;
+ if (!is_disabled(cm->menu_entries[entry]))
+ break;
+ }
+ break;
+
+ case '+':
+ while (entry < cm->nentries - 1) {
+ entry++;
+ top++;
+ if (!is_disabled(cm->menu_entries[entry]))
+ break;
+ }
+ break;
+
+ case KEY_CTRL('A'):
+ case KEY_HOME:
+ top = entry = 0;
+ break;
+
+ case KEY_CTRL('E'):
+ case KEY_END:
+ entry = cm->nentries - 1;
+ top = max(0, cm->nentries - MENU_ROWS);
+ 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:
+ show_fkey(key);
+ clear = 1;
+ break;
+
+ case KEY_TAB:
+ if (cm->allowedit && me->action == MA_CMD) {
+ int ok = 1;
+
+ key_timeout = 0; /* Cancels timeout */
+ draw_row(entry - top + 4 + VSHIFT, -1, top, 0, 0);
+
+ if (cm->menu_master_passwd) {
+ ok = ask_passwd(NULL);
+ clear_screen();
+ draw_menu(-1, top, 0);
+ } else {
+ /* Erase [Tab] message and help text */
+ printf("\033[%d;1H\1#0\033[K", TABMSG_ROW);
+ display_help(NULL);
+ }
+
+ if (ok) {
+ cmdline =
+ edit_cmdline(me->cmdline, top, &draw_menu, &show_fkey);
+ done = !!cmdline;
+ clear = 1; /* In case we hit [Esc] and done is null */
+ } else {
+ draw_row(entry - top + 4 + VSHIFT, entry, top, 0, 0);
+ }
+ }
+ break;
+ case KEY_CTRL('C'): /* Ctrl-C */
+ case KEY_ESC: /* Esc */
+ if (cm->parent) {
+ cm = cm->parent;
+ clear = 2;
+ entry = cm->curentry;
+ top = cm->curtop;
+ } else if (cm->allowedit) {
+ done = 1;
+ clear = 1;
+ key_timeout = 0;
+
+ draw_row(entry - top + 4 + VSHIFT, -1, top, 0, 0);
+
+ if (cm->menu_master_passwd)
+ done = ask_passwd(NULL);
+ }
+ break;
+ default:
+ if (key > 0 && key < 0xFF) {
+ key &= ~0x20; /* Upper case */
+ if (cm->menu_hotkeys[key]) {
+ key_timeout = 0;
+ entry = cm->menu_hotkeys[key]->entry;
+ /* Should we commit at this point? */
+ }
+ }
+ break;
+ }
+ }
+
+ printf("\033[?25h"); /* Show cursor */
+
+ /* Return the label name so localboot and ipappend work */
+ return cmdline;
+}
+
+static void dump_menu(struct menu *menu)
+{
+ mp("will dump menu for %s:", menu->label);
+ printf("entries num: %d\n", menu->nentries);
+ printf("defentry: %d, nam = %s\n",
+ menu->defentry, menu->menu_entries[menu->defentry]->label);
+ //printf("save: %d\n", menu->save);
+ //printf("", menu->);
+ //printf("", menu->);
+ //printf("", menu->);
+}
+
+int menu_main(int argc, char *argv[])
+{
+ const char *cmdline;
+ struct menu *m;
+ int rows, cols;
+ int i;
+
+ (void)argc;
+
+ if (getscreensize(1, &rows, &cols)) {
+ /* Unknown screen size? */
+ rows = 24;
+ cols = 80;
+ }
+
+ /*
+ * If there is a config file given, parse it
+ * otherwise use the config already parsed
+ */
+ if (argc == 2)
+ parse_configs(argv + 1);
+
+ /* Some postprocessing for all menus */
+ for (m = menu_list; m; m = m->next) {
+ if (!m->mparm[P_WIDTH])
+ m->mparm[P_WIDTH] = cols;
+
+ /* If anyone has specified negative parameters, consider them
+ relative to the bottom row of the screen. */
+ for (i = 0; i < NPARAMS; i++)
+ if (m->mparm[i] < 0)
+ m->mparm[i] = max(m->mparm[i] + rows, 0);
+ }
+
+ cm = start_menu;
+ if (!cm->nentries) {
+ fputs("Initial menu has no LABEL entries!\n", stdout);
+ return 1; /* Error! */
+ }
+
+ dump_menu(cm);
+ for (;;) {
+ cmdline = run_menu();
+
+ printf("\033[?25h\033[%d;1H\033[0m", END_ROW);
+
+ if (cmdline) {
+ mp("cmdline = %s", cmdline);
+ execute(cmdline, KT_NONE);
+ if (cm->onerror)
+ execute(cm->onerror, KT_NONE);
+ } else {
+ return 0; /* Exit */
+ }
+ }
+}
+
+static void menumain_exit(void)
+{
+ // Nothing to do
+}
+
+// Define entry and exit points.
+MODULE_INIT(menumain_init);
+MODULE_EXIT(menumain_exit);
diff --git a/com32/elflink/modules/modules.dep b/com32/elflink/modules/modules.dep
new file mode 100644
index 00000000..90feb0b4
--- /dev/null
+++ b/com32/elflink/modules/modules.dep
@@ -0,0 +1,19 @@
+ansiraw:
+background:
+crypt-md5: md5
+drain:
+execute:
+get_key:
+hello:
+md5:
+menu: menumain
+menumain: drain passwd background printmsg execute
+mytest: ansiraw menumain
+passwd: crypt-md5 sha1hash unbase64 sha256crypt sha512crypt
+printmsg:
+sha1hash:
+sha256crypt:
+sha512crypt:
+sort:
+test:
+unbase64:
diff --git a/com32/elflink/modules/mytest.c b/com32/elflink/modules/mytest.c
new file mode 100644
index 00000000..ddc8a0ef
--- /dev/null
+++ b/com32/elflink/modules/mytest.c
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <minmax.h>
+#include <console.h>
+#include <consoles.h>
+#include <alloca.h>
+#include <inttypes.h>
+#include <colortbl.h>
+#include <getkey.h>
+#include <setjmp.h>
+#include <limits.h>
+#include <com32.h>
+#include <syslinux/adv.h>
+#include <syslinux/config.h>
+#include <sys/module.h>
+
+#include "menu.h"
+
+static int mytest_main(int argc, char **argv)
+{
+ console_ansi_raw();
+ //edit_cmdline("",1);
+ menu_main(argc, argv);
+ return 0;
+}
+
+MODULE_MAIN(mytest_main);
diff --git a/com32/elflink/modules/passwd.c b/com32/elflink/modules/passwd.c
new file mode 100644
index 00000000..a467a81d
--- /dev/null
+++ b/com32/elflink/modules/passwd.c
@@ -0,0 +1,111 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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 <string.h>
+#include <xcrypt.h>
+#include <sha1.h>
+#include <base64.h>
+#include <sys/module.h>
+
+#include "menu.h"
+
+static int passwd_init(void)
+{
+ return 0; // Nothing to do; return success
+}
+
+static int passwd_compare_sha1(const char *passwd, const char *entry)
+{
+ struct {
+ SHA1_CTX ctx;
+ unsigned char sha1[20], pwdsha1[20];
+ } d;
+ const char *p;
+ int rv;
+
+ SHA1Init(&d.ctx);
+
+ if ((p = strchr(passwd + 3, '$'))) {
+ SHA1Update(&d.ctx, (void *)passwd + 3, p - (passwd + 3));
+ p++;
+ } else {
+ p = passwd + 3; /* Assume no salt */
+ }
+
+ SHA1Update(&d.ctx, (void *)entry, strlen(entry));
+ SHA1Final(d.sha1, &d.ctx);
+
+ memset(d.pwdsha1, 0, 20);
+ unbase64(d.pwdsha1, 20, p);
+
+ rv = !memcmp(d.sha1, d.pwdsha1, 20);
+
+ memset(&d, 0, sizeof d);
+ return rv;
+}
+
+static int passwd_compare_md5(const char *passwd, const char *entry)
+{
+ const char *crypted = crypt_md5(entry, passwd + 3);
+ int len = strlen(crypted);
+
+ return !strncmp(crypted, passwd, len) &&
+ (passwd[len] == '\0' || passwd[len] == '$');
+}
+
+static int passwd_compare_sha256(const char *passwd, const char *entry)
+{
+ const char *crypted = sha256_crypt(entry, passwd + 3);
+ int len = strlen(crypted);
+
+ return !strncmp(crypted, passwd, len) &&
+ (passwd[len] == '\0' || passwd[len] == '$');
+}
+
+static int passwd_compare_sha512(const char *passwd, const char *entry)
+{
+ const char *crypted = sha512_crypt(entry, passwd + 3);
+ int len = strlen(crypted);
+
+ return !strncmp(crypted, passwd, len) &&
+ (passwd[len] == '\0' || passwd[len] == '$');
+}
+
+int passwd_compare(const char *passwd, const char *entry)
+{
+ if (passwd[0] != '$' || !passwd[1] || passwd[2] != '$') {
+ /* Plaintext passwd, yuck! */
+ return !strcmp(entry, passwd);
+ } else {
+ switch (passwd[1]) {
+ case '1':
+ return passwd_compare_md5(passwd, entry);
+ case '4':
+ return passwd_compare_sha1(passwd, entry);
+ case '5':
+ return passwd_compare_sha256(passwd, entry);
+ case '6':
+ return passwd_compare_sha512(passwd, entry);
+ default:
+ return 0; /* Unknown encryption algorithm -> false */
+ }
+ }
+}
+
+static void passwd_exit(void)
+{
+ // Nothing to do
+}
+
+// Define entry and exit points.
+MODULE_INIT(passwd_init);
+MODULE_EXIT(passwd_exit);
diff --git a/com32/elflink/modules/pcitest.c b/com32/elflink/modules/pcitest.c
new file mode 100644
index 00000000..dcb80983
--- /dev/null
+++ b/com32/elflink/modules/pcitest.c
@@ -0,0 +1,156 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2006 Erwan Velu - 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.
+ *
+ * -----------------------------------------------------------------------
+*/
+
+/*
+ * pcitest.c
+ *
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <console.h>
+#include <com32.h>
+#include <sys/pci.h>
+#include <stdbool.h>
+
+#include <sys/module.h>
+
+#ifdef DEBUG
+# define dprintf printf
+#else
+# define dprintf(...) ((void)0)
+#endif
+
+char display_line = 0;
+#define moreprintf(...) \
+ do { \
+ display_line++; \
+ if (display_line == 24) { \
+ char tempbuf[10]; \
+ display_line=0; \
+ printf("Press Enter to continue\n"); \
+ fgets(tempbuf, sizeof tempbuf, stdin); \
+ } \
+ printf ( __VA_ARGS__); \
+ } while (0);
+
+void display_pci_devices(struct pci_domain *pci_domain)
+{
+ struct pci_device *pci_device;
+ char kernel_modules[LINUX_KERNEL_MODULE_SIZE *
+ MAX_KERNEL_MODULES_PER_PCI_DEVICE];
+
+ for_each_pci_func(pci_device, pci_domain) {
+
+ memset(kernel_modules, 0, sizeof kernel_modules);
+
+/* printf("PCI: found %d kernel modules for %04x:%04x[%04x:%04x]\n",
+ pci_device->dev_info->linux_kernel_module_count,
+ pci_device->vendor, pci_device->product,
+ pci_device->sub_vendor, pci_device->sub_product);
+*/
+ for (int i = 0; i < pci_device->dev_info->linux_kernel_module_count;
+ i++) {
+ if (i > 0) {
+ strncat(kernel_modules, " | ", 3);
+ }
+ strncat(kernel_modules,
+ pci_device->dev_info->linux_kernel_module[i],
+ LINUX_KERNEL_MODULE_SIZE - 1);
+ }
+
+ moreprintf("%04x:%04x[%04x:%04x]: %s\n",
+ pci_device->vendor, pci_device->product,
+ pci_device->sub_vendor, pci_device->sub_product,
+ pci_device->dev_info->class_name);
+
+ moreprintf(" Vendor Name : %s\n",
+ pci_device->dev_info->vendor_name);
+ moreprintf(" Product Name : %s\n",
+ pci_device->dev_info->product_name);
+ moreprintf(" PCI bus position : %02x:%02x.%01x\n", __pci_bus,
+ __pci_slot, __pci_func);
+ moreprintf(" Kernel modules : %s\n\n", kernel_modules);
+ }
+}
+
+static int pcitest_main(int argc, char *argv[])
+{
+ struct pci_domain *pci_domain;
+ int return_code = 0;
+ int nb_pci_devices = 0;
+
+ /* Scanning to detect pci buses and devices */
+ printf("PCI: Scanning PCI BUS\n");
+ pci_domain = pci_scan();
+ if (!pci_domain) {
+ printf("PCI: no devices found!\n");
+ return 1;
+ }
+
+ struct pci_device *pci_device;
+ for_each_pci_func(pci_device, pci_domain) {
+ nb_pci_devices++;
+ }
+
+ printf("PCI: %d PCI devices found\n", nb_pci_devices);
+
+ printf("PCI: Looking for device name\n");
+ /* Assigning product & vendor name for each device */
+ return_code = get_name_from_pci_ids(pci_domain, "pci.ids");
+ if (return_code == -ENOPCIIDS) {
+ printf("PCI: ERROR !\n");
+ printf("PCI: Unable to open pci.ids file in current directory.\n");
+ printf("PCI: PCI Device names can't be computed.\n");
+ }
+
+ printf("PCI: Resolving class names\n");
+ /* Assigning class name for each device */
+ return_code = get_class_name_from_pci_ids(pci_domain, "pci.ids");
+ if (return_code == -ENOPCIIDS) {
+ printf("PCI: ERROR !\n");
+ printf("PCI: Unable to open pci.ids file in current directory.\n");
+ printf("PCI: PCI class names can't be computed.\n");
+ }
+
+ printf("PCI: Looking for Kernel modules\n");
+ /* Detecting which kernel module should match each device */
+ return_code = get_module_name_from_pcimap(pci_domain, "modules.pcimap");
+ if (return_code == -ENOMODULESPCIMAP) {
+ printf("PCI: ERROR !\n");
+ printf("PCI: Unable to open modules.pcimap file in current directory.\n");
+ printf("PCI: Kernel Module names can't be computed.\n");
+ }
+
+ /* display the pci devices we found */
+ display_pci_devices(pci_domain);
+ return 0;
+}
+MODULE_MAIN(pcitest_main);
diff --git a/com32/elflink/modules/printmsg.c b/com32/elflink/modules/printmsg.c
new file mode 100644
index 00000000..da9ec29b
--- /dev/null
+++ b/com32/elflink/modules/printmsg.c
@@ -0,0 +1,115 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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 <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <consoles.h>
+#include <getkey.h>
+#include <minmax.h>
+#include <setjmp.h>
+#include <limits.h>
+#include <sha1.h>
+#include <base64.h>
+#include <colortbl.h>
+#include <sys/module.h>
+#ifdef __COM32__
+#include <com32.h>
+#endif
+
+#include "menu.h"
+
+static int printmsg_init(void)
+{
+ return 0; // Nothing to do; return success
+}
+
+int draw_message_file(const char *filename)
+{
+ FILE *f;
+ int ch;
+ enum msgname_state {
+ st_init, /* Base state */
+ st_si_1, /* <SI> digit 1 */
+ st_si_2, /* <SI> digit 2 */
+ st_skipline, /* Skip until NL */
+ } state = st_init;
+ int eof = 0;
+ int attr = 0;
+
+ f = fopen(filename, "r");
+ if (!f)
+ return -1;
+
+ /* Clear screen, hide cursor, default attribute */
+ printf("\033e\033%%@\033)0\033(B\3#%03d\033[?25l\033[2J\033[H",
+ message_base_color + 0x07);
+
+ while (!eof && (ch = getc(f)) != EOF) {
+ switch (state) {
+ case st_init:
+ switch (ch) {
+ case '\f':
+ fputs("\033[2J\033[H", stdout);
+ break;
+ case 15: /* SI */
+ state = st_si_1;
+ break;
+ case 24:
+ state = st_skipline;
+ break;
+ case 26:
+ eof = 1;
+ break;
+ case '\a':
+ case '\n':
+ case '\r':
+ putchar(ch);
+ break;
+ default:
+ if (ch >= 32)
+ putchar(ch);
+ break;
+ }
+ break;
+
+ case st_si_1:
+ attr = hexval(ch) << 4;
+ state = st_si_2;
+ break;
+
+ case st_si_2:
+ attr |= hexval(ch);
+ printf("\3#%03d", attr + message_base_color);
+ state = st_init;
+ break;
+
+ case st_skipline:
+ if (ch == '\n')
+ state = st_init;
+ break;
+ }
+ }
+
+ fclose(f);
+ return 0;
+}
+
+static void printmsg_exit(void)
+{
+ // Nothing to do
+}
+
+// Define entry and exit points.
+MODULE_INIT(printmsg_init);
+MODULE_EXIT(printmsg_exit);
diff --git a/com32/elflink/modules/refstr.h b/com32/elflink/modules/refstr.h
new file mode 100644
index 00000000..7001d407
--- /dev/null
+++ b/com32/elflink/modules/refstr.h
@@ -0,0 +1,40 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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.h
+ *
+ * Simple reference-counted strings
+ */
+
+#ifndef REFSTR_H
+#define REFSTR_H
+
+#include <stddef.h>
+#include <stdarg.h>
+
+static inline __attribute__ ((always_inline))
+const char *refstr_get(const char *r)
+{
+ if (r)
+ ((unsigned int *)r)[-1]++;
+ return r;
+}
+
+void refstr_put(const char *);
+char *refstr_alloc(size_t);
+const char *refstrdup(const char *);
+const char *refstrndup(const char *, size_t);
+int rsprintf(const char **, const char *, ...);
+int vrsprintf(const char **, const char *, va_list);
+
+#endif
diff --git a/com32/elflink/modules/sha1.h b/com32/elflink/modules/sha1.h
new file mode 100644
index 00000000..3b35e773
--- /dev/null
+++ b/com32/elflink/modules/sha1.h
@@ -0,0 +1,18 @@
+#ifndef LIBUTIL_SHA1_H
+#define LIBUTIL_SHA1_H
+
+#include <stdint.h>
+
+typedef struct {
+ uint32_t state[5];
+ uint32_t count[2];
+ unsigned char buffer[64];
+} SHA1_CTX;
+
+void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]);
+void SHA1Init(SHA1_CTX * context);
+void SHA1Update(SHA1_CTX * context, const unsigned char *data, uint32_t len); /*
+ JHB */
+void SHA1Final(unsigned char digest[20], SHA1_CTX * context);
+
+#endif /* LIBUTIL_SHA1_H */
diff --git a/com32/elflink/modules/sha1hash.c b/com32/elflink/modules/sha1hash.c
new file mode 100644
index 00000000..cafdc46c
--- /dev/null
+++ b/com32/elflink/modules/sha1hash.c
@@ -0,0 +1,347 @@
+/*
+SHA-1 in C
+By Steve Reid <sreid@sea-to-sky.net>
+100% Public Domain
+
+-----------------
+Modified 7/98
+By James H. Brown <jbrown@burgoyne.com>
+Still 100% Public Domain
+
+Corrected a problem which generated improper hash values on 16 bit machines
+Routine SHA1Update changed from
+ void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int
+len)
+to
+ void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned
+long len)
+
+The 'len' parameter was declared an int which works fine on 32 bit machines.
+However, on 16 bit machines an int is too small for the shifts being done
+against
+it. This caused the hash function to generate incorrect values if len was
+greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().
+
+Since the file IO in main() reads 16K at a time, any file 8K or larger would
+be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
+"a"s).
+
+I also changed the declaration of variables i & j in SHA1Update to
+unsigned long from unsigned int for the same reason.
+
+These changes should make no difference to any 32 bit implementations since
+an
+int and a long are the same size in those environments.
+
+--
+I also corrected a few compiler warnings generated by Borland C.
+1. Added #include <process.h> for exit() prototype
+2. Removed unused variable 'j' in SHA1Final
+3. Changed exit(0) to return(0) at end of main.
+
+ALL changes I made can be located by searching for comments containing 'JHB'
+-----------------
+Modified 8/98
+By Steve Reid <sreid@sea-to-sky.net>
+Still 100% public domain
+
+1- Removed #include <process.h> and used return() instead of exit()
+2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall)
+3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net
+
+-----------------
+Modified 4/01
+By Saul Kravitz <Saul.Kravitz@celera.com>
+Still 100% PD
+Modified to run on Compaq Alpha hardware.
+
+-----------------
+Modified 2/03
+By H. Peter Anvin <hpa@zytor.com>
+Still 100% PD
+Modified to run on any hardware with <inttypes.h> and <netinet/in.h>
+Changed the driver program
+
+*/
+
+/*
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+ A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+ 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+/* #define SHA1HANDSOFF */
+
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <netinet/in.h> /* For htonl/ntohl/htons/ntohs */
+#include <sys/module.h>
+
+#include "sha1.h"
+
+static int sha1hash_init(void)
+{
+ return 0; // Nothing to do; return success
+}
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+#define blk0(i) (block->l[i] = ntohl(block->l[i]))
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+ ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+#ifdef VERBOSE /* SAK */
+void SHAPrintContext(SHA1_CTX * context, char *msg)
+{
+ printf("%s (%d,%d) %x %x %x %x %x\n",
+ msg,
+ context->count[0], context->count[1],
+ context->state[0],
+ context->state[1],
+ context->state[2], context->state[3], context->state[4]);
+}
+#endif
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+void SHA1Transform(uint32_t state[5], const unsigned char buffer[64])
+{
+ uint32_t a, b, c, d, e;
+ typedef union {
+ unsigned char c[64];
+ uint32_t l[16];
+ } CHAR64LONG16;
+ CHAR64LONG16 *block;
+#ifdef SHA1HANDSOFF
+ static unsigned char workspace[64];
+ block = (CHAR64LONG16 *) workspace;
+ memcpy(block, buffer, 64);
+#else
+ block = (CHAR64LONG16 *) buffer;
+#endif
+ /* Copy context->state[] to working vars */
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ /* 4 rounds of 20 operations each. Loop unrolled. */
+ R0(a, b, c, d, e, 0);
+ R0(e, a, b, c, d, 1);
+ R0(d, e, a, b, c, 2);
+ R0(c, d, e, a, b, 3);
+ R0(b, c, d, e, a, 4);
+ R0(a, b, c, d, e, 5);
+ R0(e, a, b, c, d, 6);
+ R0(d, e, a, b, c, 7);
+ R0(c, d, e, a, b, 8);
+ R0(b, c, d, e, a, 9);
+ R0(a, b, c, d, e, 10);
+ R0(e, a, b, c, d, 11);
+ R0(d, e, a, b, c, 12);
+ R0(c, d, e, a, b, 13);
+ R0(b, c, d, e, a, 14);
+ R0(a, b, c, d, e, 15);
+ R1(e, a, b, c, d, 16);
+ R1(d, e, a, b, c, 17);
+ R1(c, d, e, a, b, 18);
+ R1(b, c, d, e, a, 19);
+ R2(a, b, c, d, e, 20);
+ R2(e, a, b, c, d, 21);
+ R2(d, e, a, b, c, 22);
+ R2(c, d, e, a, b, 23);
+ R2(b, c, d, e, a, 24);
+ R2(a, b, c, d, e, 25);
+ R2(e, a, b, c, d, 26);
+ R2(d, e, a, b, c, 27);
+ R2(c, d, e, a, b, 28);
+ R2(b, c, d, e, a, 29);
+ R2(a, b, c, d, e, 30);
+ R2(e, a, b, c, d, 31);
+ R2(d, e, a, b, c, 32);
+ R2(c, d, e, a, b, 33);
+ R2(b, c, d, e, a, 34);
+ R2(a, b, c, d, e, 35);
+ R2(e, a, b, c, d, 36);
+ R2(d, e, a, b, c, 37);
+ R2(c, d, e, a, b, 38);
+ R2(b, c, d, e, a, 39);
+ R3(a, b, c, d, e, 40);
+ R3(e, a, b, c, d, 41);
+ R3(d, e, a, b, c, 42);
+ R3(c, d, e, a, b, 43);
+ R3(b, c, d, e, a, 44);
+ R3(a, b, c, d, e, 45);
+ R3(e, a, b, c, d, 46);
+ R3(d, e, a, b, c, 47);
+ R3(c, d, e, a, b, 48);
+ R3(b, c, d, e, a, 49);
+ R3(a, b, c, d, e, 50);
+ R3(e, a, b, c, d, 51);
+ R3(d, e, a, b, c, 52);
+ R3(c, d, e, a, b, 53);
+ R3(b, c, d, e, a, 54);
+ R3(a, b, c, d, e, 55);
+ R3(e, a, b, c, d, 56);
+ R3(d, e, a, b, c, 57);
+ R3(c, d, e, a, b, 58);
+ R3(b, c, d, e, a, 59);
+ R4(a, b, c, d, e, 60);
+ R4(e, a, b, c, d, 61);
+ R4(d, e, a, b, c, 62);
+ R4(c, d, e, a, b, 63);
+ R4(b, c, d, e, a, 64);
+ R4(a, b, c, d, e, 65);
+ R4(e, a, b, c, d, 66);
+ R4(d, e, a, b, c, 67);
+ R4(c, d, e, a, b, 68);
+ R4(b, c, d, e, a, 69);
+ R4(a, b, c, d, e, 70);
+ R4(e, a, b, c, d, 71);
+ R4(d, e, a, b, c, 72);
+ R4(c, d, e, a, b, 73);
+ R4(b, c, d, e, a, 74);
+ R4(a, b, c, d, e, 75);
+ R4(e, a, b, c, d, 76);
+ R4(d, e, a, b, c, 77);
+ R4(c, d, e, a, b, 78);
+ R4(b, c, d, e, a, 79);
+ /* Add the working vars back into context.state[] */
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+ /* Wipe variables */
+ a = b = c = d = e = 0;
+}
+
+/* SHA1Init - Initialize new context */
+
+void SHA1Init(SHA1_CTX * context)
+{
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
+}
+
+/* Run your data through this. */
+
+void SHA1Update(SHA1_CTX * context, const unsigned char *data, uint32_t len)
+{ /*
+ JHB */
+ uint32_t i, j; /* JHB */
+
+#ifdef VERBOSE
+ SHAPrintContext(context, "before");
+#endif
+ j = (context->count[0] >> 3) & 63;
+ if ((context->count[0] += len << 3) < (len << 3))
+ context->count[1]++;
+ context->count[1] += (len >> 29);
+ if ((j + len) > 63) {
+ memcpy(&context->buffer[j], data, (i = 64 - j));
+ SHA1Transform(context->state, context->buffer);
+ for (; i + 63 < len; i += 64) {
+ SHA1Transform(context->state, &data[i]);
+ }
+ j = 0;
+ } else
+ i = 0;
+ memcpy(&context->buffer[j], &data[i], len - i);
+#ifdef VERBOSE
+ SHAPrintContext(context, "after ");
+#endif
+}
+
+/* Add padding and return the message digest. */
+
+void SHA1Final(unsigned char digest[20], SHA1_CTX * context)
+{
+ uint32_t i; /* JHB */
+ unsigned char finalcount[8];
+
+ for (i = 0; i < 8; i++) {
+ finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]
+ >> ((3 - (i & 3)) * 8)) & 255); /* Endian independent */
+ }
+ SHA1Update(context, (unsigned char *)"\200", 1);
+ while ((context->count[0] & 504) != 448) {
+ SHA1Update(context, (unsigned char *)"\0", 1);
+ }
+ SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform()
+ */
+ for (i = 0; i < 20; i++) {
+ digest[i] = (unsigned char)
+ ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
+ }
+ /* Wipe variables */
+ i = 0; /* JHB */
+ memset(context->buffer, 0, 64);
+ memset(context->state, 0, 20);
+ memset(context->count, 0, 8);
+ memset(finalcount, 0, 8); /* SWR */
+#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite it's own static vars */
+ SHA1Transform(context->state, context->buffer);
+#endif
+}
+
+/*************************************************************/
+
+/* This is not quite the MIME base64 algorithm: it uses _ instead of /,
+ and instead of padding the output with = characters we just make the
+ output shorter. */
+char *mybase64(uint8_t digest[20])
+{
+ static const char charz[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_";
+ uint8_t input[21];
+ static char output[28];
+ int i, j;
+ uint8_t *p;
+ char *q;
+ uint32_t bv;
+
+ memcpy(input, digest, 20);
+ input[20] = 0; /* Pad to multiple of 3 bytes */
+
+ p = input;
+ q = output;
+ for (i = 0; i < 7; i++) {
+ bv = (p[0] << 16) | (p[1] << 8) | p[2];
+ p += 3;
+ for (j = 0; j < 4; j++) {
+ *q++ = charz[(bv >> 18) & 0x3f];
+ bv <<= 6;
+ }
+ }
+ *--q = '\0'; /* The last character is not significant */
+ return output;
+}
+
+static void sha1hash_exit(void)
+{
+ // Nothing to do
+}
+
+// Define entry and exit points.
+MODULE_INIT(sha1hash_init);
+MODULE_EXIT(sha1hash_exit);
diff --git a/com32/elflink/modules/sha256crypt.c b/com32/elflink/modules/sha256crypt.c
new file mode 100644
index 00000000..61b23f2a
--- /dev/null
+++ b/com32/elflink/modules/sha256crypt.c
@@ -0,0 +1,559 @@
+/* SHA256-based Unix crypt implementation.
+ Released into the Public Domain by Ulrich Drepper <drepper@redhat.com>. */
+
+#include <alloca.h>
+#include <endian.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <minmax.h>
+#include <sys/types.h>
+#include <sys/module.h>
+
+#include "xcrypt.h"
+
+static int sha256crypt_init(void)
+{
+ return 0; // Nothing to do; return success
+}
+
+#define MIN(x,y) min(x,y)
+#define MAX(x,y) max(x,y)
+
+/* Structure to save state of computation between the single steps. */
+struct sha256_ctx {
+ uint32_t H[8];
+
+ uint32_t total[2];
+ uint32_t buflen;
+ char buffer[128]; /* NB: always correctly aligned for uint32_t. */
+};
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+# define SWAP(n) \
+ (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
+#else
+# define SWAP(n) (n)
+#endif
+
+/* This array contains the bytes used to pad the buffer to the next
+ 64-byte boundary. (FIPS 180-2:5.1.1) */
+static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
+
+/* Constants for SHA256 from FIPS 180-2:4.2.2. */
+static const uint32_t K[64] = {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+ 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+ 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+ 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+ 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+ 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+
+/* Process LEN bytes of BUFFER, accumulating context into CTX.
+ It is assumed that LEN % 64 == 0. */
+static void
+sha256_process_block(const void *buffer, size_t len, struct sha256_ctx *ctx)
+{
+ unsigned int t;
+ const uint32_t *words = buffer;
+ size_t nwords = len / sizeof(uint32_t);
+ uint32_t a = ctx->H[0];
+ uint32_t b = ctx->H[1];
+ uint32_t c = ctx->H[2];
+ uint32_t d = ctx->H[3];
+ uint32_t e = ctx->H[4];
+ uint32_t f = ctx->H[5];
+ uint32_t g = ctx->H[6];
+ uint32_t h = ctx->H[7];
+
+ /* First increment the byte count. FIPS 180-2 specifies the possible
+ length of the file up to 2^64 bits. Here we only compute the
+ number of bytes. Do a double word increment. */
+ ctx->total[0] += len;
+ if (ctx->total[0] < len)
+ ++ctx->total[1];
+
+ /* Process all bytes in the buffer with 64 bytes in each round of
+ the loop. */
+ while (nwords > 0) {
+ uint32_t W[64];
+ uint32_t a_save = a;
+ uint32_t b_save = b;
+ uint32_t c_save = c;
+ uint32_t d_save = d;
+ uint32_t e_save = e;
+ uint32_t f_save = f;
+ uint32_t g_save = g;
+ uint32_t h_save = h;
+
+ /* Operators defined in FIPS 180-2:4.1.2. */
+#define Ch(x, y, z) ((x & y) ^ (~x & z))
+#define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
+#define S0(x) (CYCLIC (x, 2) ^ CYCLIC (x, 13) ^ CYCLIC (x, 22))
+#define S1(x) (CYCLIC (x, 6) ^ CYCLIC (x, 11) ^ CYCLIC (x, 25))
+#define R0(x) (CYCLIC (x, 7) ^ CYCLIC (x, 18) ^ (x >> 3))
+#define R1(x) (CYCLIC (x, 17) ^ CYCLIC (x, 19) ^ (x >> 10))
+
+ /* It is unfortunate that C does not provide an operator for
+ cyclic rotation. Hope the C compiler is smart enough. */
+#define CYCLIC(w, s) ((w >> s) | (w << (32 - s)))
+
+ /* Compute the message schedule according to FIPS 180-2:6.2.2 step 2. */
+ for (t = 0; t < 16; ++t) {
+ W[t] = SWAP(*words);
+ ++words;
+ }
+ for (t = 16; t < 64; ++t)
+ W[t] = R1(W[t - 2]) + W[t - 7] + R0(W[t - 15]) + W[t - 16];
+
+ /* The actual computation according to FIPS 180-2:6.2.2 step 3. */
+ for (t = 0; t < 64; ++t) {
+ uint32_t T1 = h + S1(e) + Ch(e, f, g) + K[t] + W[t];
+ uint32_t T2 = S0(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+ }
+
+ /* Add the starting values of the context according to FIPS 180-2:6.2.2
+ step 4. */
+ a += a_save;
+ b += b_save;
+ c += c_save;
+ d += d_save;
+ e += e_save;
+ f += f_save;
+ g += g_save;
+ h += h_save;
+
+ /* Prepare for the next round. */
+ nwords -= 16;
+ }
+
+ /* Put checksum in context given as argument. */
+ ctx->H[0] = a;
+ ctx->H[1] = b;
+ ctx->H[2] = c;
+ ctx->H[3] = d;
+ ctx->H[4] = e;
+ ctx->H[5] = f;
+ ctx->H[6] = g;
+ ctx->H[7] = h;
+}
+
+/* Initialize structure containing state of computation.
+ (FIPS 180-2:5.3.2) */
+static void sha256_init_ctx(struct sha256_ctx *ctx)
+{
+ ctx->H[0] = 0x6a09e667;
+ ctx->H[1] = 0xbb67ae85;
+ ctx->H[2] = 0x3c6ef372;
+ ctx->H[3] = 0xa54ff53a;
+ ctx->H[4] = 0x510e527f;
+ ctx->H[5] = 0x9b05688c;
+ ctx->H[6] = 0x1f83d9ab;
+ ctx->H[7] = 0x5be0cd19;
+
+ ctx->total[0] = ctx->total[1] = 0;
+ ctx->buflen = 0;
+}
+
+/* Process the remaining bytes in the internal buffer and the usual
+ prolog according to the standard and write the result to RESBUF.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+static void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf)
+{
+ unsigned int i;
+ /* Take yet unprocessed bytes into account. */
+ uint32_t bytes = ctx->buflen;
+ size_t pad;
+
+ /* Now count remaining bytes. */
+ ctx->total[0] += bytes;
+ if (ctx->total[0] < bytes)
+ ++ctx->total[1];
+
+ pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
+ memcpy(&ctx->buffer[bytes], fillbuf, pad);
+
+ /* Put the 64-bit file length in *bits* at the end of the buffer. */
+ *(uint32_t *) & ctx->buffer[bytes + pad + 4] = SWAP(ctx->total[0] << 3);
+ *(uint32_t *) & ctx->buffer[bytes + pad] = SWAP((ctx->total[1] << 3) |
+ (ctx->total[0] >> 29));
+
+ /* Process last bytes. */
+ sha256_process_block(ctx->buffer, bytes + pad + 8, ctx);
+
+ /* Put result from CTX in first 32 bytes following RESBUF. */
+ for (i = 0; i < 8; ++i)
+ ((uint32_t *) resbuf)[i] = SWAP(ctx->H[i]);
+
+ return resbuf;
+}
+
+static void
+sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx)
+{
+ /* When we already have some bits in our internal buffer concatenate
+ both inputs first. */
+ if (ctx->buflen != 0) {
+ size_t left_over = ctx->buflen;
+ size_t add = 128 - left_over > len ? len : 128 - left_over;
+
+ memcpy(&ctx->buffer[left_over], buffer, add);
+ ctx->buflen += add;
+
+ if (ctx->buflen > 64) {
+ sha256_process_block(ctx->buffer, ctx->buflen & ~63, ctx);
+
+ ctx->buflen &= 63;
+ /* The regions in the following copy operation cannot overlap. */
+ memcpy(ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
+ ctx->buflen);
+ }
+
+ buffer = (const char *)buffer + add;
+ len -= add;
+ }
+
+ /* Process available complete blocks. */
+ if (len >= 64) {
+/* To check alignment gcc has an appropriate operator. Other
+ compilers don't. */
+#if __GNUC__ >= 2
+# define UNALIGNED_P(p) (((uintptr_t) p) % __alignof__ (uint32_t) != 0)
+#else
+# define UNALIGNED_P(p) (((uintptr_t) p) % sizeof (uint32_t) != 0)
+#endif
+ if (UNALIGNED_P(buffer))
+ while (len > 64) {
+ sha256_process_block(memcpy(ctx->buffer, buffer, 64), 64, ctx);
+ buffer = (const char *)buffer + 64;
+ len -= 64;
+ } else {
+ sha256_process_block(buffer, len & ~63, ctx);
+ buffer = (const char *)buffer + (len & ~63);
+ len &= 63;
+ }
+ }
+
+ /* Move remaining bytes into internal buffer. */
+ if (len > 0) {
+ size_t left_over = ctx->buflen;
+
+ memcpy(&ctx->buffer[left_over], buffer, len);
+ left_over += len;
+ if (left_over >= 64) {
+ sha256_process_block(ctx->buffer, 64, ctx);
+ left_over -= 64;
+ memcpy(ctx->buffer, &ctx->buffer[64], left_over);
+ }
+ ctx->buflen = left_over;
+ }
+}
+
+/* Define our magic string to mark salt for SHA256 "encryption"
+ replacement. */
+static const char sha256_salt_prefix[] = "$5$";
+
+/* Prefix for optional rounds specification. */
+static const char sha256_rounds_prefix[] = "rounds=";
+
+/* Maximum salt string length. */
+#define SALT_LEN_MAX 16
+/* Default number of rounds if not explicitly specified. */
+#define ROUNDS_DEFAULT 5000
+/* Minimum number of rounds. */
+#define ROUNDS_MIN 1000
+/* Maximum number of rounds. */
+#define ROUNDS_MAX 999999999
+
+/* Table with characters for base64 transformation. */
+static const char b64t[64] =
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+static char *sha256_crypt_r(const char *key, const char *salt, char *buffer,
+ int buflen)
+{
+ unsigned char alt_result[32]
+ __attribute__ ((__aligned__(__alignof__(uint32_t))));
+ unsigned char temp_result[32]
+ __attribute__ ((__aligned__(__alignof__(uint32_t))));
+ struct sha256_ctx ctx;
+ struct sha256_ctx alt_ctx;
+ size_t salt_len;
+ size_t key_len;
+ size_t cnt;
+ char *cp;
+ char *copied_key = NULL;
+ char *copied_salt = NULL;
+ char *p_bytes;
+ char *s_bytes;
+ /* Default number of rounds. */
+ size_t rounds = ROUNDS_DEFAULT;
+ bool rounds_custom = false;
+
+ /* Find beginning of salt string. The prefix should normally always
+ be present. Just in case it is not. */
+ if (strncmp(sha256_salt_prefix, salt, sizeof(sha256_salt_prefix) - 1) == 0)
+ /* Skip salt prefix. */
+ salt += sizeof(sha256_salt_prefix) - 1;
+
+ if (strncmp(salt, sha256_rounds_prefix, sizeof(sha256_rounds_prefix) - 1)
+ == 0) {
+ const char *num = salt + sizeof(sha256_rounds_prefix) - 1;
+ char *endp;
+ unsigned long int srounds = strtoul(num, &endp, 10);
+ if (*endp == '$') {
+ salt = endp + 1;
+ rounds = MAX(ROUNDS_MIN, MIN(srounds, ROUNDS_MAX));
+ rounds_custom = true;
+ }
+ }
+
+ salt_len = MIN(strcspn(salt, "$"), SALT_LEN_MAX);
+ key_len = strlen(key);
+
+ if ((key - (char *)0) % __alignof__(uint32_t) != 0) {
+ char *tmp = (char *)alloca(key_len + __alignof__(uint32_t));
+ key = copied_key = memcpy(tmp + __alignof__(uint32_t)
+ - (tmp - (char *)0) % __alignof__(uint32_t),
+ key, key_len);
+ }
+
+ if ((salt - (char *)0) % __alignof__(uint32_t) != 0) {
+ char *tmp = (char *)alloca(salt_len + __alignof__(uint32_t));
+ salt = copied_salt = memcpy(tmp + __alignof__(uint32_t)
+ - (tmp - (char *)0) % __alignof__(uint32_t),
+ salt, salt_len);
+ }
+
+ /* Prepare for the real work. */
+ sha256_init_ctx(&ctx);
+
+ /* Add the key string. */
+ sha256_process_bytes(key, key_len, &ctx);
+
+ /* The last part is the salt string. This must be at most 8
+ characters and it ends at the first `$' character (for
+ compatibility with existing implementations). */
+ sha256_process_bytes(salt, salt_len, &ctx);
+
+ /* Compute alternate SHA256 sum with input KEY, SALT, and KEY. The
+ final result will be added to the first context. */
+ sha256_init_ctx(&alt_ctx);
+
+ /* Add key. */
+ sha256_process_bytes(key, key_len, &alt_ctx);
+
+ /* Add salt. */
+ sha256_process_bytes(salt, salt_len, &alt_ctx);
+
+ /* Add key again. */
+ sha256_process_bytes(key, key_len, &alt_ctx);
+
+ /* Now get result of this (32 bytes) and add it to the other
+ context. */
+ sha256_finish_ctx(&alt_ctx, alt_result);
+
+ /* Add for any character in the key one byte of the alternate sum. */
+ for (cnt = key_len; cnt > 32; cnt -= 32)
+ sha256_process_bytes(alt_result, 32, &ctx);
+ sha256_process_bytes(alt_result, cnt, &ctx);
+
+ /* Take the binary representation of the length of the key and for every
+ 1 add the alternate sum, for every 0 the key. */
+ for (cnt = key_len; cnt > 0; cnt >>= 1)
+ if ((cnt & 1) != 0)
+ sha256_process_bytes(alt_result, 32, &ctx);
+ else
+ sha256_process_bytes(key, key_len, &ctx);
+
+ /* Create intermediate result. */
+ sha256_finish_ctx(&ctx, alt_result);
+
+ /* Start computation of P byte sequence. */
+ sha256_init_ctx(&alt_ctx);
+
+ /* For every character in the password add the entire password. */
+ for (cnt = 0; cnt < key_len; ++cnt)
+ sha256_process_bytes(key, key_len, &alt_ctx);
+
+ /* Finish the digest. */
+ sha256_finish_ctx(&alt_ctx, temp_result);
+
+ /* Create byte sequence P. */
+ cp = p_bytes = alloca(key_len);
+ for (cnt = key_len; cnt >= 32; cnt -= 32)
+ cp = mempcpy(cp, temp_result, 32);
+ memcpy(cp, temp_result, cnt);
+
+ /* Start computation of S byte sequence. */
+ sha256_init_ctx(&alt_ctx);
+
+ /* For every character in the password add the entire password. */
+ for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt)
+ sha256_process_bytes(salt, salt_len, &alt_ctx);
+
+ /* Finish the digest. */
+ sha256_finish_ctx(&alt_ctx, temp_result);
+
+ /* Create byte sequence S. */
+ cp = s_bytes = alloca(salt_len);
+ for (cnt = salt_len; cnt >= 32; cnt -= 32)
+ cp = mempcpy(cp, temp_result, 32);
+ memcpy(cp, temp_result, cnt);
+
+ /* Repeatedly run the collected hash value through SHA256 to burn
+ CPU cycles. */
+ for (cnt = 0; cnt < rounds; ++cnt) {
+ /* New context. */
+ sha256_init_ctx(&ctx);
+
+ /* Add key or last result. */
+ if ((cnt & 1) != 0)
+ sha256_process_bytes(p_bytes, key_len, &ctx);
+ else
+ sha256_process_bytes(alt_result, 32, &ctx);
+
+ /* Add salt for numbers not divisible by 3. */
+ if (cnt % 3 != 0)
+ sha256_process_bytes(s_bytes, salt_len, &ctx);
+
+ /* Add key for numbers not divisible by 7. */
+ if (cnt % 7 != 0)
+ sha256_process_bytes(p_bytes, key_len, &ctx);
+
+ /* Add key or last result. */
+ if ((cnt & 1) != 0)
+ sha256_process_bytes(alt_result, 32, &ctx);
+ else
+ sha256_process_bytes(p_bytes, key_len, &ctx);
+
+ /* Create intermediate result. */
+ sha256_finish_ctx(&ctx, alt_result);
+ }
+
+ /* Now we can construct the result string. It consists of three
+ parts. */
+ cp = stpncpy(buffer, sha256_salt_prefix, MAX(0, buflen));
+ buflen -= sizeof(sha256_salt_prefix) - 1;
+
+ if (rounds_custom) {
+ int n = snprintf(cp, MAX(0, buflen), "%s%zu$",
+ sha256_rounds_prefix, rounds);
+ cp += n;
+ buflen -= n;
+ }
+
+ cp = stpncpy(cp, salt, MIN((size_t) MAX(0, buflen), salt_len));
+ buflen -= MIN((size_t) MAX(0, buflen), salt_len);
+
+ if (buflen > 0) {
+ *cp++ = '$';
+ --buflen;
+ }
+#define b64_from_24bit(B2, B1, B0, N) \
+ do { \
+ unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0); \
+ int n = (N); \
+ while (n-- > 0 && buflen > 0) \
+ { \
+ *cp++ = b64t[w & 0x3f]; \
+ --buflen; \
+ w >>= 6; \
+ } \
+ } while (0)
+
+ b64_from_24bit(alt_result[0], alt_result[10], alt_result[20], 4);
+ b64_from_24bit(alt_result[21], alt_result[1], alt_result[11], 4);
+ b64_from_24bit(alt_result[12], alt_result[22], alt_result[2], 4);
+ b64_from_24bit(alt_result[3], alt_result[13], alt_result[23], 4);
+ b64_from_24bit(alt_result[24], alt_result[4], alt_result[14], 4);
+ b64_from_24bit(alt_result[15], alt_result[25], alt_result[5], 4);
+ b64_from_24bit(alt_result[6], alt_result[16], alt_result[26], 4);
+ b64_from_24bit(alt_result[27], alt_result[7], alt_result[17], 4);
+ b64_from_24bit(alt_result[18], alt_result[28], alt_result[8], 4);
+ b64_from_24bit(alt_result[9], alt_result[19], alt_result[29], 4);
+ b64_from_24bit(0, alt_result[31], alt_result[30], 3);
+ if (buflen <= 0) {
+ errno = ERANGE;
+ buffer = NULL;
+ } else
+ *cp = '\0'; /* Terminate the string. */
+
+ /* Clear the buffer for the intermediate result so that people
+ attaching to processes or reading core dumps cannot get any
+ information. We do it in this way to clear correct_words[]
+ inside the SHA256 implementation as well. */
+ sha256_init_ctx(&ctx);
+ sha256_finish_ctx(&ctx, alt_result);
+ memset(temp_result, '\0', sizeof(temp_result));
+ memset(p_bytes, '\0', key_len);
+ memset(s_bytes, '\0', salt_len);
+ memset(&ctx, '\0', sizeof(ctx));
+ memset(&alt_ctx, '\0', sizeof(alt_ctx));
+ if (copied_key != NULL)
+ memset(copied_key, '\0', key_len);
+ if (copied_salt != NULL)
+ memset(copied_salt, '\0', salt_len);
+
+ return buffer;
+}
+
+/* This entry point is equivalent to the `crypt' function in Unix
+ libcs. */
+char *sha256_crypt(const char *key, const char *salt)
+{
+ /* We don't want to have an arbitrary limit in the size of the
+ password. We can compute an upper bound for the size of the
+ result in advance and so we can prepare the buffer we pass to
+ `sha256_crypt_r'. */
+ static char *buffer;
+ static int buflen;
+ int needed = (sizeof(sha256_salt_prefix) - 1
+ + sizeof(sha256_rounds_prefix) + 9 + 1
+ + strlen(salt) + 1 + 43 + 1);
+
+ if (buflen < needed) {
+ char *new_buffer = (char *)realloc(buffer, needed);
+ if (new_buffer == NULL)
+ return NULL;
+
+ buffer = new_buffer;
+ buflen = needed;
+ }
+
+ return sha256_crypt_r(key, salt, buffer, buflen);
+}
+
+static void sha256crypt_exit(void)
+{
+ // Nothing to do
+}
+
+// Define entry and exit points.
+MODULE_INIT(sha256crypt_init);
+MODULE_EXIT(sha256crypt_exit);
diff --git a/com32/elflink/modules/sha512crypt.c b/com32/elflink/modules/sha512crypt.c
new file mode 100644
index 00000000..617423c2
--- /dev/null
+++ b/com32/elflink/modules/sha512crypt.c
@@ -0,0 +1,606 @@
+/* SHA512-based Unix crypt implementation.
+ Released into the Public Domain by Ulrich Drepper <drepper@redhat.com>. */
+
+#include <alloca.h>
+#include <endian.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <minmax.h>
+#include <sys/types.h>
+#include <sys/module.h>
+
+#include "xcrypt.h"
+
+static int sha512crypt_init()
+{
+ return 0; // Nothing to do; return success
+}
+
+#define MIN(x,y) min(x,y)
+#define MAX(x,y) max(x,y)
+
+/* Structure to save state of computation between the single steps. */
+struct sha512_ctx {
+ uint64_t H[8];
+
+ uint64_t total[2];
+ uint64_t buflen;
+ char buffer[256]; /* NB: always correctly aligned for uint64_t. */
+};
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+# define SWAP(n) \
+ (((n) << 56) \
+ | (((n) & 0xff00) << 40) \
+ | (((n) & 0xff0000) << 24) \
+ | (((n) & 0xff000000) << 8) \
+ | (((n) >> 8) & 0xff000000) \
+ | (((n) >> 24) & 0xff0000) \
+ | (((n) >> 40) & 0xff00) \
+ | ((n) >> 56))
+#else
+# define SWAP(n) (n)
+#endif
+
+/* This array contains the bytes used to pad the buffer to the next
+ 64-byte boundary. (FIPS 180-2:5.1.2) */
+static const unsigned char fillbuf[128] = { 0x80, 0 /* , 0, 0, ... */ };
+
+/* Constants for SHA512 from FIPS 180-2:4.2.3. */
+static const uint64_t K[80] = {
+ UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd),
+ UINT64_C(0xb5c0fbcfec4d3b2f), UINT64_C(0xe9b5dba58189dbbc),
+ UINT64_C(0x3956c25bf348b538), UINT64_C(0x59f111f1b605d019),
+ UINT64_C(0x923f82a4af194f9b), UINT64_C(0xab1c5ed5da6d8118),
+ UINT64_C(0xd807aa98a3030242), UINT64_C(0x12835b0145706fbe),
+ UINT64_C(0x243185be4ee4b28c), UINT64_C(0x550c7dc3d5ffb4e2),
+ UINT64_C(0x72be5d74f27b896f), UINT64_C(0x80deb1fe3b1696b1),
+ UINT64_C(0x9bdc06a725c71235), UINT64_C(0xc19bf174cf692694),
+ UINT64_C(0xe49b69c19ef14ad2), UINT64_C(0xefbe4786384f25e3),
+ UINT64_C(0x0fc19dc68b8cd5b5), UINT64_C(0x240ca1cc77ac9c65),
+ UINT64_C(0x2de92c6f592b0275), UINT64_C(0x4a7484aa6ea6e483),
+ UINT64_C(0x5cb0a9dcbd41fbd4), UINT64_C(0x76f988da831153b5),
+ UINT64_C(0x983e5152ee66dfab), UINT64_C(0xa831c66d2db43210),
+ UINT64_C(0xb00327c898fb213f), UINT64_C(0xbf597fc7beef0ee4),
+ UINT64_C(0xc6e00bf33da88fc2), UINT64_C(0xd5a79147930aa725),
+ UINT64_C(0x06ca6351e003826f), UINT64_C(0x142929670a0e6e70),
+ UINT64_C(0x27b70a8546d22ffc), UINT64_C(0x2e1b21385c26c926),
+ UINT64_C(0x4d2c6dfc5ac42aed), UINT64_C(0x53380d139d95b3df),
+ UINT64_C(0x650a73548baf63de), UINT64_C(0x766a0abb3c77b2a8),
+ UINT64_C(0x81c2c92e47edaee6), UINT64_C(0x92722c851482353b),
+ UINT64_C(0xa2bfe8a14cf10364), UINT64_C(0xa81a664bbc423001),
+ UINT64_C(0xc24b8b70d0f89791), UINT64_C(0xc76c51a30654be30),
+ UINT64_C(0xd192e819d6ef5218), UINT64_C(0xd69906245565a910),
+ UINT64_C(0xf40e35855771202a), UINT64_C(0x106aa07032bbd1b8),
+ UINT64_C(0x19a4c116b8d2d0c8), UINT64_C(0x1e376c085141ab53),
+ UINT64_C(0x2748774cdf8eeb99), UINT64_C(0x34b0bcb5e19b48a8),
+ UINT64_C(0x391c0cb3c5c95a63), UINT64_C(0x4ed8aa4ae3418acb),
+ UINT64_C(0x5b9cca4f7763e373), UINT64_C(0x682e6ff3d6b2b8a3),
+ UINT64_C(0x748f82ee5defb2fc), UINT64_C(0x78a5636f43172f60),
+ UINT64_C(0x84c87814a1f0ab72), UINT64_C(0x8cc702081a6439ec),
+ UINT64_C(0x90befffa23631e28), UINT64_C(0xa4506cebde82bde9),
+ UINT64_C(0xbef9a3f7b2c67915), UINT64_C(0xc67178f2e372532b),
+ UINT64_C(0xca273eceea26619c), UINT64_C(0xd186b8c721c0c207),
+ UINT64_C(0xeada7dd6cde0eb1e), UINT64_C(0xf57d4f7fee6ed178),
+ UINT64_C(0x06f067aa72176fba), UINT64_C(0x0a637dc5a2c898a6),
+ UINT64_C(0x113f9804bef90dae), UINT64_C(0x1b710b35131c471b),
+ UINT64_C(0x28db77f523047d84), UINT64_C(0x32caab7b40c72493),
+ UINT64_C(0x3c9ebe0a15c9bebc), UINT64_C(0x431d67c49c100d4c),
+ UINT64_C(0x4cc5d4becb3e42b6), UINT64_C(0x597f299cfc657e2a),
+ UINT64_C(0x5fcb6fab3ad6faec), UINT64_C(0x6c44198c4a475817)
+};
+
+/* Process LEN bytes of BUFFER, accumulating context into CTX.
+ It is assumed that LEN % 128 == 0. */
+static void
+sha512_process_block(const void *buffer, size_t len, struct sha512_ctx *ctx)
+{
+ unsigned int t;
+ const uint64_t *words = buffer;
+ size_t nwords = len / sizeof(uint64_t);
+ uint64_t a = ctx->H[0];
+ uint64_t b = ctx->H[1];
+ uint64_t c = ctx->H[2];
+ uint64_t d = ctx->H[3];
+ uint64_t e = ctx->H[4];
+ uint64_t f = ctx->H[5];
+ uint64_t g = ctx->H[6];
+ uint64_t h = ctx->H[7];
+
+ /* First increment the byte count. FIPS 180-2 specifies the possible
+ length of the file up to 2^128 bits. Here we only compute the
+ number of bytes. Do a double word increment. */
+ ctx->total[0] += len;
+ if (ctx->total[0] < len)
+ ++ctx->total[1];
+
+ /* Process all bytes in the buffer with 128 bytes in each round of
+ the loop. */
+ while (nwords > 0) {
+ uint64_t W[80];
+ uint64_t a_save = a;
+ uint64_t b_save = b;
+ uint64_t c_save = c;
+ uint64_t d_save = d;
+ uint64_t e_save = e;
+ uint64_t f_save = f;
+ uint64_t g_save = g;
+ uint64_t h_save = h;
+
+ /* Operators defined in FIPS 180-2:4.1.2. */
+#define Ch(x, y, z) ((x & y) ^ (~x & z))
+#define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
+#define S0(x) (CYCLIC (x, 28) ^ CYCLIC (x, 34) ^ CYCLIC (x, 39))
+#define S1(x) (CYCLIC (x, 14) ^ CYCLIC (x, 18) ^ CYCLIC (x, 41))
+#define R0(x) (CYCLIC (x, 1) ^ CYCLIC (x, 8) ^ (x >> 7))
+#define R1(x) (CYCLIC (x, 19) ^ CYCLIC (x, 61) ^ (x >> 6))
+
+ /* It is unfortunate that C does not provide an operator for
+ cyclic rotation. Hope the C compiler is smart enough. */
+#define CYCLIC(w, s) ((w >> s) | (w << (64 - s)))
+
+ /* Compute the message schedule according to FIPS 180-2:6.3.2 step 2. */
+ for (t = 0; t < 16; ++t) {
+ W[t] = SWAP(*words);
+ ++words;
+ }
+ for (t = 16; t < 80; ++t)
+ W[t] = R1(W[t - 2]) + W[t - 7] + R0(W[t - 15]) + W[t - 16];
+
+ /* The actual computation according to FIPS 180-2:6.3.2 step 3. */
+ for (t = 0; t < 80; ++t) {
+ uint64_t T1 = h + S1(e) + Ch(e, f, g) + K[t] + W[t];
+ uint64_t T2 = S0(a) + Maj(a, b, c);
+ h = g;
+ g = f;
+ f = e;
+ e = d + T1;
+ d = c;
+ c = b;
+ b = a;
+ a = T1 + T2;
+ }
+
+ /* Add the starting values of the context according to FIPS 180-2:6.3.2
+ step 4. */
+ a += a_save;
+ b += b_save;
+ c += c_save;
+ d += d_save;
+ e += e_save;
+ f += f_save;
+ g += g_save;
+ h += h_save;
+
+ /* Prepare for the next round. */
+ nwords -= 16;
+ }
+
+ /* Put checksum in context given as argument. */
+ ctx->H[0] = a;
+ ctx->H[1] = b;
+ ctx->H[2] = c;
+ ctx->H[3] = d;
+ ctx->H[4] = e;
+ ctx->H[5] = f;
+ ctx->H[6] = g;
+ ctx->H[7] = h;
+}
+
+/* Initialize structure containing state of computation.
+ (FIPS 180-2:5.3.3) */
+static void sha512_init_ctx(struct sha512_ctx *ctx)
+{
+ ctx->H[0] = UINT64_C(0x6a09e667f3bcc908);
+ ctx->H[1] = UINT64_C(0xbb67ae8584caa73b);
+ ctx->H[2] = UINT64_C(0x3c6ef372fe94f82b);
+ ctx->H[3] = UINT64_C(0xa54ff53a5f1d36f1);
+ ctx->H[4] = UINT64_C(0x510e527fade682d1);
+ ctx->H[5] = UINT64_C(0x9b05688c2b3e6c1f);
+ ctx->H[6] = UINT64_C(0x1f83d9abfb41bd6b);
+ ctx->H[7] = UINT64_C(0x5be0cd19137e2179);
+
+ ctx->total[0] = ctx->total[1] = 0;
+ ctx->buflen = 0;
+}
+
+/* Process the remaining bytes in the internal buffer and the usual
+ prolog according to the standard and write the result to RESBUF.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+static void *sha512_finish_ctx(struct sha512_ctx *ctx, void *resbuf)
+{
+ unsigned int i;
+ /* Take yet unprocessed bytes into account. */
+ uint64_t bytes = ctx->buflen;
+ size_t pad;
+
+ /* Now count remaining bytes. */
+ ctx->total[0] += bytes;
+ if (ctx->total[0] < bytes)
+ ++ctx->total[1];
+
+ pad = bytes >= 112 ? 128 + 112 - bytes : 112 - bytes;
+ memcpy(&ctx->buffer[bytes], fillbuf, pad);
+
+ /* Put the 128-bit file length in *bits* at the end of the buffer. */
+ *(uint64_t *) & ctx->buffer[bytes + pad + 8] = SWAP(ctx->total[0] << 3);
+ *(uint64_t *) & ctx->buffer[bytes + pad] = SWAP((ctx->total[1] << 3) |
+ (ctx->total[0] >> 61));
+
+ /* Process last bytes. */
+ sha512_process_block(ctx->buffer, bytes + pad + 16, ctx);
+
+ /* Put result from CTX in first 64 bytes following RESBUF. */
+ for (i = 0; i < 8; ++i)
+ ((uint64_t *) resbuf)[i] = SWAP(ctx->H[i]);
+
+ return resbuf;
+}
+
+static void
+sha512_process_bytes(const void *buffer, size_t len, struct sha512_ctx *ctx)
+{
+ /* When we already have some bits in our internal buffer concatenate
+ both inputs first. */
+ if (ctx->buflen != 0) {
+ size_t left_over = ctx->buflen;
+ size_t add = 256 - left_over > len ? len : 256 - left_over;
+
+ memcpy(&ctx->buffer[left_over], buffer, add);
+ ctx->buflen += add;
+
+ if (ctx->buflen > 128) {
+ sha512_process_block(ctx->buffer, ctx->buflen & ~127, ctx);
+
+ ctx->buflen &= 127;
+ /* The regions in the following copy operation cannot overlap. */
+ memcpy(ctx->buffer, &ctx->buffer[(left_over + add) & ~127],
+ ctx->buflen);
+ }
+
+ buffer = (const char *)buffer + add;
+ len -= add;
+ }
+
+ /* Process available complete blocks. */
+ if (len >= 128) {
+#if !_STRING_ARCH_unaligned
+/* To check alignment gcc has an appropriate operator. Other
+ compilers don't. */
+# if __GNUC__ >= 2
+# define UNALIGNED_P(p) (((uintptr_t) p) % __alignof__ (uint64_t) != 0)
+# else
+# define UNALIGNED_P(p) (((uintptr_t) p) % sizeof (uint64_t) != 0)
+# endif
+ if (UNALIGNED_P(buffer))
+ while (len > 128) {
+ sha512_process_block(memcpy(ctx->buffer, buffer, 128), 128,
+ ctx);
+ buffer = (const char *)buffer + 128;
+ len -= 128;
+ } else
+#endif
+ {
+ sha512_process_block(buffer, len & ~127, ctx);
+ buffer = (const char *)buffer + (len & ~127);
+ len &= 127;
+ }
+ }
+
+ /* Move remaining bytes into internal buffer. */
+ if (len > 0) {
+ size_t left_over = ctx->buflen;
+
+ memcpy(&ctx->buffer[left_over], buffer, len);
+ left_over += len;
+ if (left_over >= 128) {
+ sha512_process_block(ctx->buffer, 128, ctx);
+ left_over -= 128;
+ memcpy(ctx->buffer, &ctx->buffer[128], left_over);
+ }
+ ctx->buflen = left_over;
+ }
+}
+
+/* Define our magic string to mark salt for SHA512 "encryption"
+ replacement. */
+static const char sha512_salt_prefix[] = "$6$";
+
+/* Prefix for optional rounds specification. */
+static const char sha512_rounds_prefix[] = "rounds=";
+
+/* Maximum salt string length. */
+#define SALT_LEN_MAX 16
+/* Default number of rounds if not explicitly specified. */
+#define ROUNDS_DEFAULT 5000
+/* Minimum number of rounds. */
+#define ROUNDS_MIN 1000
+/* Maximum number of rounds. */
+#define ROUNDS_MAX 999999999
+
+/* Table with characters for base64 transformation. */
+static const char b64t[64] =
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+static char *sha512_crypt_r(const char *key, const char *salt, char *buffer,
+ int buflen)
+{
+ unsigned char alt_result[64]
+ __attribute__ ((__aligned__(__alignof__(uint64_t))));
+ unsigned char temp_result[64]
+ __attribute__ ((__aligned__(__alignof__(uint64_t))));
+ struct sha512_ctx ctx;
+ struct sha512_ctx alt_ctx;
+ size_t salt_len;
+ size_t key_len;
+ size_t cnt;
+ char *cp;
+ char *copied_key = NULL;
+ char *copied_salt = NULL;
+ char *p_bytes;
+ char *s_bytes;
+ /* Default number of rounds. */
+ size_t rounds = ROUNDS_DEFAULT;
+ bool rounds_custom = false;
+
+ /* Find beginning of salt string. The prefix should normally always
+ be present. Just in case it is not. */
+ if (strncmp(sha512_salt_prefix, salt, sizeof(sha512_salt_prefix) - 1) == 0)
+ /* Skip salt prefix. */
+ salt += sizeof(sha512_salt_prefix) - 1;
+
+ if (strncmp(salt, sha512_rounds_prefix, sizeof(sha512_rounds_prefix) - 1)
+ == 0) {
+ const char *num = salt + sizeof(sha512_rounds_prefix) - 1;
+ char *endp;
+ unsigned long int srounds = strtoul(num, &endp, 10);
+ if (*endp == '$') {
+ salt = endp + 1;
+ rounds = MAX(ROUNDS_MIN, MIN(srounds, ROUNDS_MAX));
+ rounds_custom = true;
+ }
+ }
+
+ salt_len = MIN(strcspn(salt, "$"), SALT_LEN_MAX);
+ key_len = strlen(key);
+
+ if ((key - (char *)0) % __alignof__(uint64_t) != 0) {
+ char *tmp = (char *)alloca(key_len + __alignof__(uint64_t));
+ key = copied_key = memcpy(tmp + __alignof__(uint64_t)
+ - (tmp - (char *)0) % __alignof__(uint64_t),
+ key, key_len);
+ }
+
+ if ((salt - (char *)0) % __alignof__(uint64_t) != 0) {
+ char *tmp = (char *)alloca(salt_len + __alignof__(uint64_t));
+ salt = copied_salt = memcpy(tmp + __alignof__(uint64_t)
+ - (tmp - (char *)0) % __alignof__(uint64_t),
+ salt, salt_len);
+ }
+
+ /* Prepare for the real work. */
+ sha512_init_ctx(&ctx);
+
+ /* Add the key string. */
+ sha512_process_bytes(key, key_len, &ctx);
+
+ /* The last part is the salt string. This must be at most 8
+ characters and it ends at the first `$' character (for
+ compatibility with existing implementations). */
+ sha512_process_bytes(salt, salt_len, &ctx);
+
+ /* Compute alternate SHA512 sum with input KEY, SALT, and KEY. The
+ final result will be added to the first context. */
+ sha512_init_ctx(&alt_ctx);
+
+ /* Add key. */
+ sha512_process_bytes(key, key_len, &alt_ctx);
+
+ /* Add salt. */
+ sha512_process_bytes(salt, salt_len, &alt_ctx);
+
+ /* Add key again. */
+ sha512_process_bytes(key, key_len, &alt_ctx);
+
+ /* Now get result of this (64 bytes) and add it to the other
+ context. */
+ sha512_finish_ctx(&alt_ctx, alt_result);
+
+ /* Add for any character in the key one byte of the alternate sum. */
+ for (cnt = key_len; cnt > 64; cnt -= 64)
+ sha512_process_bytes(alt_result, 64, &ctx);
+ sha512_process_bytes(alt_result, cnt, &ctx);
+
+ /* Take the binary representation of the length of the key and for every
+ 1 add the alternate sum, for every 0 the key. */
+ for (cnt = key_len; cnt > 0; cnt >>= 1)
+ if ((cnt & 1) != 0)
+ sha512_process_bytes(alt_result, 64, &ctx);
+ else
+ sha512_process_bytes(key, key_len, &ctx);
+
+ /* Create intermediate result. */
+ sha512_finish_ctx(&ctx, alt_result);
+
+ /* Start computation of P byte sequence. */
+ sha512_init_ctx(&alt_ctx);
+
+ /* For every character in the password add the entire password. */
+ for (cnt = 0; cnt < key_len; ++cnt)
+ sha512_process_bytes(key, key_len, &alt_ctx);
+
+ /* Finish the digest. */
+ sha512_finish_ctx(&alt_ctx, temp_result);
+
+ /* Create byte sequence P. */
+ cp = p_bytes = alloca(key_len);
+ for (cnt = key_len; cnt >= 64; cnt -= 64)
+ cp = mempcpy(cp, temp_result, 64);
+ memcpy(cp, temp_result, cnt);
+
+ /* Start computation of S byte sequence. */
+ sha512_init_ctx(&alt_ctx);
+
+ /* For every character in the password add the entire password. */
+ for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt)
+ sha512_process_bytes(salt, salt_len, &alt_ctx);
+
+ /* Finish the digest. */
+ sha512_finish_ctx(&alt_ctx, temp_result);
+
+ /* Create byte sequence S. */
+ cp = s_bytes = alloca(salt_len);
+ for (cnt = salt_len; cnt >= 64; cnt -= 64)
+ cp = mempcpy(cp, temp_result, 64);
+ memcpy(cp, temp_result, cnt);
+
+ /* Repeatedly run the collected hash value through SHA512 to burn
+ CPU cycles. */
+ for (cnt = 0; cnt < rounds; ++cnt) {
+ /* New context. */
+ sha512_init_ctx(&ctx);
+
+ /* Add key or last result. */
+ if ((cnt & 1) != 0)
+ sha512_process_bytes(p_bytes, key_len, &ctx);
+ else
+ sha512_process_bytes(alt_result, 64, &ctx);
+
+ /* Add salt for numbers not divisible by 3. */
+ if (cnt % 3 != 0)
+ sha512_process_bytes(s_bytes, salt_len, &ctx);
+
+ /* Add key for numbers not divisible by 7. */
+ if (cnt % 7 != 0)
+ sha512_process_bytes(p_bytes, key_len, &ctx);
+
+ /* Add key or last result. */
+ if ((cnt & 1) != 0)
+ sha512_process_bytes(alt_result, 64, &ctx);
+ else
+ sha512_process_bytes(p_bytes, key_len, &ctx);
+
+ /* Create intermediate result. */
+ sha512_finish_ctx(&ctx, alt_result);
+ }
+
+ /* Now we can construct the result string. It consists of three
+ parts. */
+ cp = stpncpy(buffer, sha512_salt_prefix, MAX(0, buflen));
+ buflen -= sizeof(sha512_salt_prefix) - 1;
+
+ if (rounds_custom) {
+ int n = snprintf(cp, MAX(0, buflen), "%s%zu$",
+ sha512_rounds_prefix, rounds);
+ cp += n;
+ buflen -= n;
+ }
+
+ cp = stpncpy(cp, salt, MIN((size_t) MAX(0, buflen), salt_len));
+ buflen -= MIN((size_t) MAX(0, buflen), salt_len);
+
+ if (buflen > 0) {
+ *cp++ = '$';
+ --buflen;
+ }
+#define b64_from_24bit(B2, B1, B0, N) \
+ do { \
+ unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0); \
+ int n = (N); \
+ while (n-- > 0 && buflen > 0) \
+ { \
+ *cp++ = b64t[w & 0x3f]; \
+ --buflen; \
+ w >>= 6; \
+ } \
+ } while (0)
+
+ b64_from_24bit(alt_result[0], alt_result[21], alt_result[42], 4);
+ b64_from_24bit(alt_result[22], alt_result[43], alt_result[1], 4);
+ b64_from_24bit(alt_result[44], alt_result[2], alt_result[23], 4);
+ b64_from_24bit(alt_result[3], alt_result[24], alt_result[45], 4);
+ b64_from_24bit(alt_result[25], alt_result[46], alt_result[4], 4);
+ b64_from_24bit(alt_result[47], alt_result[5], alt_result[26], 4);
+ b64_from_24bit(alt_result[6], alt_result[27], alt_result[48], 4);
+ b64_from_24bit(alt_result[28], alt_result[49], alt_result[7], 4);
+ b64_from_24bit(alt_result[50], alt_result[8], alt_result[29], 4);
+ b64_from_24bit(alt_result[9], alt_result[30], alt_result[51], 4);
+ b64_from_24bit(alt_result[31], alt_result[52], alt_result[10], 4);
+ b64_from_24bit(alt_result[53], alt_result[11], alt_result[32], 4);
+ b64_from_24bit(alt_result[12], alt_result[33], alt_result[54], 4);
+ b64_from_24bit(alt_result[34], alt_result[55], alt_result[13], 4);
+ b64_from_24bit(alt_result[56], alt_result[14], alt_result[35], 4);
+ b64_from_24bit(alt_result[15], alt_result[36], alt_result[57], 4);
+ b64_from_24bit(alt_result[37], alt_result[58], alt_result[16], 4);
+ b64_from_24bit(alt_result[59], alt_result[17], alt_result[38], 4);
+ b64_from_24bit(alt_result[18], alt_result[39], alt_result[60], 4);
+ b64_from_24bit(alt_result[40], alt_result[61], alt_result[19], 4);
+ b64_from_24bit(alt_result[62], alt_result[20], alt_result[41], 4);
+ b64_from_24bit(0, 0, alt_result[63], 2);
+
+ if (buflen <= 0) {
+ errno = ERANGE;
+ buffer = NULL;
+ } else
+ *cp = '\0'; /* Terminate the string. */
+
+ /* Clear the buffer for the intermediate result so that people
+ attaching to processes or reading core dumps cannot get any
+ information. We do it in this way to clear correct_words[]
+ inside the SHA512 implementation as well. */
+ sha512_init_ctx(&ctx);
+ sha512_finish_ctx(&ctx, alt_result);
+ memset(temp_result, '\0', sizeof(temp_result));
+ memset(p_bytes, '\0', key_len);
+ memset(s_bytes, '\0', salt_len);
+ memset(&ctx, '\0', sizeof(ctx));
+ memset(&alt_ctx, '\0', sizeof(alt_ctx));
+ if (copied_key != NULL)
+ memset(copied_key, '\0', key_len);
+ if (copied_salt != NULL)
+ memset(copied_salt, '\0', salt_len);
+
+ return buffer;
+}
+
+/* This entry point is equivalent to the `crypt' function in Unix
+ libcs. */
+char *sha512_crypt(const char *key, const char *salt)
+{
+ /* We don't want to have an arbitrary limit in the size of the
+ password. We can compute an upper bound for the size of the
+ result in advance and so we can prepare the buffer we pass to
+ `sha512_crypt_r'. */
+ static char *buffer;
+ static int buflen;
+ int needed = (sizeof(sha512_salt_prefix) - 1
+ + sizeof(sha512_rounds_prefix) + 9 + 1
+ + strlen(salt) + 1 + 86 + 1);
+
+ if (buflen < needed) {
+ char *new_buffer = (char *)realloc(buffer, needed);
+ if (new_buffer == NULL)
+ return NULL;
+
+ buffer = new_buffer;
+ buflen = needed;
+ }
+
+ return sha512_crypt_r(key, salt, buffer, buflen);
+}
+
+static void sha512crypt_exit()
+{
+ // Nothing to do
+}
+
+// Define entry and exit points.
+MODULE_INIT(sha512crypt_init);
+MODULE_EXIT(sha512crypt_exit);
diff --git a/com32/elflink/modules/sort.c b/com32/elflink/modules/sort.c
new file mode 100644
index 00000000..f91cb603
--- /dev/null
+++ b/com32/elflink/modules/sort.c
@@ -0,0 +1,80 @@
+/*
+ * sort.c - Sample ELF module providing a quick sort function
+ *
+ * Created on: Aug 11, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+#include <stdlib.h>
+#include <sys/module.h>
+
+/**
+ * sort_init - Module entry point.
+ */
+static int sort_init(void)
+{
+ return 0; // Nothing to do; return success
+}
+
+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);
+}
+
+/**
+ * sort_exit - Module exit point.
+ */
+static void sort_exit(void)
+{
+ // Nothing to do
+}
+
+// Define entry and exit points.
+MODULE_INIT(sort_init);
+MODULE_EXIT(sort_exit);
diff --git a/com32/elflink/modules/sort.h b/com32/elflink/modules/sort.h
new file mode 100644
index 00000000..0b495482
--- /dev/null
+++ b/com32/elflink/modules/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/elflink/modules/test.c b/com32/elflink/modules/test.c
new file mode 100644
index 00000000..82df6425
--- /dev/null
+++ b/com32/elflink/modules/test.c
@@ -0,0 +1,111 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * linux.c
+ *
+ * Sample module to load Linux kernels. This module can also create
+ * a file out of the DHCP return data if running under PXELINUX.
+ *
+ * If -dhcpinfo is specified, the DHCP info is written into the file
+ * /dhcpinfo.dat in the initramfs.
+ *
+ * Usage: linux.c32 [-dhcpinfo] kernel arguments...
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <console.h>
+#include <syslinux/loadfile.h>
+#include <syslinux/linux.h>
+#include <sys/module.h>
+
+//const char *progname = "test.c32";
+
+static int test_main(int argc, char *argv[])
+{
+ const char *kernel_name;
+ struct initramfs *initramfs;
+ char *cmdline;
+ char *boot_image;
+ void *kernel_data;
+ size_t kernel_len;
+ bool opt_quiet = false;
+ char **argp, *arg, *p;
+
+ /*
+ while ((arg = *argp) && arg[0] == '-') {
+ if (!strcmp("-dhcpinfo", arg)) {
+ printf("haha\n");
+ } else {
+ fprintf(stderr, "%s: unknown option: %s\n", progname, arg);
+ return 1;
+ }
+ argp++;
+ }
+
+ if (!arg) {
+ fprintf(stderr, "%s: missing kernel name\n", progname);
+ return 1;
+ }
+ */
+
+ //kernel_name = arg;
+ kernel_name = "vmlinuz";
+
+ printf("Loading %s... ", kernel_name);
+ if (loadfile(kernel_name, &kernel_data, &kernel_len)) {
+ printf("failed!\n");
+ goto bail;
+ }
+ printf("ok\n");
+
+ /* Initialize the initramfs chain */
+ initramfs = initramfs_init();
+ if (!initramfs)
+ goto bail;
+
+
+ if (initramfs_load_archive(initramfs, "initrd.gz"))
+ mp("initrd load failure\n");
+ else
+ mp("initrd load success\n");
+
+ mp("1111");
+
+ /* This should not return... */
+ syslinux_boot_linux(kernel_data, kernel_len, initramfs, cmdline);
+
+bail:
+ fprintf(stderr, "Kernel load failure (insufficient memory?)\n");
+ return 1;
+}
+
+MODULE_MAIN(test_main);
diff --git a/com32/elflink/modules/unbase64.c b/com32/elflink/modules/unbase64.c
new file mode 100644
index 00000000..86ddfc87
--- /dev/null
+++ b/com32/elflink/modules/unbase64.c
@@ -0,0 +1,91 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2005-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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * unbase64.c
+ *
+ * Convert a string in base64 format to a byte array.
+ */
+
+#include <string.h>
+#include <base64.h>
+#include <sys/module.h>
+
+static int unbase64_init(void)
+{
+ return 0; // Nothing to do; return success
+}
+
+static const unsigned char _base64chars[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+size_t unbase64(unsigned char *buffer, size_t bufsiz, const char *txt)
+{
+ unsigned int bits = 0;
+ int nbits = 0;
+ char base64tbl[256];
+ int i;
+ char v;
+ size_t nbytes = 0;
+
+ memset(base64tbl, -1, sizeof base64tbl);
+
+ for (i = 0; _base64chars[i]; i++) {
+ base64tbl[_base64chars[i]] = i;
+ }
+
+ /* Also support filesystem safe alternate base64 encoding */
+ base64tbl['.'] = 62;
+ base64tbl['-'] = 62;
+ base64tbl['_'] = 63;
+
+ while (*txt) {
+ if ((v = base64tbl[(unsigned char)*txt]) >= 0) {
+ bits <<= 6;
+ bits += v;
+ nbits += 6;
+ if (nbits >= 8) {
+ if (nbytes < bufsiz)
+ *buffer++ = (bits >> (nbits - 8));
+ nbytes++;
+ nbits -= 8;
+ }
+ }
+ txt++;
+ }
+
+ return nbytes;
+}
+
+static void unbase64_exit(void)
+{
+ // Nothing to do
+}
+
+// Define entry and exit points.
+MODULE_INIT(unbase64_init);
+MODULE_EXIT(unbase64_exit);
diff --git a/com32/elflink/modules/vesainfo.c b/com32/elflink/modules/vesainfo.c
new file mode 100644
index 00000000..05e4f2c9
--- /dev/null
+++ b/com32/elflink/modules/vesainfo.c
@@ -0,0 +1,93 @@
+/*
+ * vesainfo.c
+ *
+ * Dump information about what VESA graphics modes are supported.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <console.h>
+#include <com32.h>
+#include <inttypes.h>
+#include "../lib/sys/vesa/vesa.h"
+
+#include <sys/module.h>
+
+/* Wait for a keypress */
+static void wait_key(void)
+{
+ char ch;
+ while (fread(&ch, 1, 1, stdin) == 0) ;
+}
+
+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;
+
+ 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");
+ goto exit;
+ } else if (gi->signature != VESA_MAGIC) {
+ printf("VESA information structure has bad magic, trying anyway...\n");
+ }
+
+ printf("VBE version %d.%d\n"
+ "Mode attrib h_res v_res bpp layout rpos gpos bpos\n",
+ (gi->version >> 8) & 0xff, gi->version & 0xff);
+
+ lines = 1;
+
+ mode_ptr = GET_PTR(gi->video_mode_ptr);
+
+ while ((mode = *mode_ptr++) != 0xFFFF) {
+ if (++lines >= 23) {
+ wait_key();
+ lines = 0;
+ }
+
+ rm.eax.w[0] = 0x4F01; /* Get SVGA mode information */
+ rm.ecx.w[0] = mode;
+ rm.edi.w[0] = OFFS(mi);
+ rm.es = SEG(mi);
+ __intcall(0x10, &rm, &rm);
+
+ /* Must be a supported mode */
+ if (rm.eax.w[0] != 0x004f)
+ continue;
+
+ printf("0x%04x 0x%04x %5u %5u %3u %6u %4u %4u %4u\n",
+ mode, mi->mode_attr, mi->h_res, mi->v_res, mi->bpp,
+ mi->memory_layout, mi->rpos, mi->gpos, mi->bpos);
+ }
+
+exit:
+ free(vesa);
+ return;
+}
+
+static int vesainfo_main(void)
+{
+ print_modes();
+ return 0;
+}
+MODULE_MAIN(vesainfo_main);
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/include/com32.h b/com32/include/com32.h
index 6b142082..f49f9eab 100644
--- a/com32/include/com32.h
+++ b/com32/include/com32.h
@@ -120,7 +120,7 @@ extern const com32sys_t __com32_zero_regs;
/*
* Lowmem allocation functions
*/
-void *lmalloc(size_t);
+void *clmalloc(size_t);
void *lzalloc(size_t);
void lfree(void *);
char *lstrdup(const char *);
diff --git a/com32/include/klibc/compiler.h b/com32/include/klibc/compiler.h
index 5ac21185..b5919d67 100644
--- a/com32/include/klibc/compiler.h
+++ b/com32/include/klibc/compiler.h
@@ -108,6 +108,9 @@
# define __unusedfunc
#endif
+/* Used symbol */
+#define __used __attribute__((used))
+
/* Constructors and destructors */
#define __constructor __attribute__((constructor))
#define __destructor __attribute__((destructor))
@@ -126,4 +129,7 @@
#define __common __attribute__((common))
#define __nocommon __attribute__((nocommon))
+/* Weak symbols */
+#define __weak __attribute__((weak))
+
#endif
diff --git a/com32/include/linux/list.h b/com32/include/linux/list.h
new file mode 100644
index 00000000..3b92e254
--- /dev/null
+++ b/com32/include/linux/list.h
@@ -0,0 +1,463 @@
+// 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;
+}
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr: the pointer to the member.
+ * @type: the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * 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_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/include/stdio.h b/com32/include/stdio.h
index f37bdd9e..238c396e 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)
{
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..31b62beb
--- /dev/null
+++ b/com32/include/sys/exec.h
@@ -0,0 +1,134 @@
+/*
+ * 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"
+
+/**
+ * MODULES_DEP - The name of the standard module dependency file
+ *
+ * This is the file which contains information about the module dependency
+ * graph ( what other modules it depends on ). The file format is identical
+ * to the standard linux modules.dep file... for more information check out the
+ * man page ).
+ */
+#define MODULES_DEP "modules.dep"
+
+/**
+ * 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')
+ * @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,const char **argv);
+
+extern int module_load_dependencies(const char*name,const char*dep_file);
+
+/**
+ * exec_init - Initialize the dynamic execution environment.
+ *
+ * Among others, it initializes the module subsystem and loads the root
+ * module into memory. You should note the difference between the module
+ * management API, and the execution API:
+ * - the module system is a static one - it only manages the data structures
+ * and their relationship. It does not describe the way modules are executed,
+ * when and how they are loaded/unloaded, etc. It acts as a service layer for
+ * the execution API.
+ * - the execution environment is the dynamic part of the SYSLINUX dynamic
+ * module API - it implements the behavior of the modules: it
+ * triggers the execution of initialization and termination functions for
+ * libraries, executes the modules marked as executable, handles dynamic
+ * memory cleanup, etc. In other words, at this layer the code and data
+ * loaded by the lower module layer gets to be executed by the CPU,
+ * thus becoming part of the SYSLINUX environment.
+ */
+extern int exec_init(void);
+
+
+/**
+ * load_library - Loads a dynamic library into the environment.
+ * @name: the name of the library to load, including the extension
+ * (e.g. 'sort.c32')
+ *
+ * A dynamic library is an ELF module that may contain initialization and
+ * termination routines, but not a main routine. At the same time, any memory
+ * allocations using malloc() and its derivatives are made on behalf of the
+ * currently executing program or the COM32 root module. If the library
+ * is unloaded, no memory cleanup is performed.
+ */
+extern int load_library(const char *name);
+
+/**
+ * unload_library - unloads a library from the environment.
+ * @name: the name of the library to unload, including the extension
+ * (e.g. 'sort.c32')
+ *
+ * Note that no memory allocated by the library code is cleaned up, as the
+ * allocations belong to the innermost calling program in the call stack.
+ */
+extern int unload_library(const char *name);
+
+/**
+ * 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..0c7c71f4
--- /dev/null
+++ b/com32/include/sys/module.h
@@ -0,0 +1,377 @@
+/**
+ * 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 UNKNOWN_MODULE -1
+#define EXEC_MODULE 0
+#define LIB_MODULE 1
+
+/*
+ * Initialization and finalization function signatures
+ */
+
+
+/**
+ * module_init_t - pointer to a initialization routine
+ *
+ * The initialization routine is called after all module constructors were invoked.
+ * It takes no parameters and returns 0 if the module was initialized successfully,
+ * or a non-zero value if errors have occurred.
+ */
+typedef int (*module_init_t)(void);
+
+/**
+ * module_exit_t - pointer to a finalization routine
+ *
+ * The finalization routine is called before the module destructors are to be invoked.
+ * It simply executes some cleanup code, without error reporting.
+ */
+typedef void (*module_exit_t)(void);
+
+/**
+ * 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**);
+
+
+/**
+ * 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_init_t *init_func; // The initialization entry point
+ module_exit_t *exit_func; // The module finalization code
+ 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;
+
+};
+
+static inline void dump_elf_module(struct elf_module *module)
+{
+ /*
+ mp("module name = %s", module->name);
+ printf("base_addr = 0x%p, module_size = %d\n", module->base_addr, module->module_size);
+ printf("hash tlb = 0x%p, ghash tbl = 0x%p\n", module->hash_table, module->ghash_table);
+ printf("str tbl = 0x%p, size = %d\n", module->str_table, module->strtable_size);
+ printf("sym tbl = 0x%p, entry = %d, size = %d\n", module->sym_table, module->syment_size, module->symtable_size);
+ printf("init: %p", module->init_func);
+ printf("main: %p", module->main_func);
+ printf("exit: %p", module->exit_func);
+ printf("", module->base_addr);
+ printf("", module->base_addr);
+ printf("", module->base_addr);
+ */
+}
+
+/**
+ * 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
+};
+
+
+
+#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
+
+#define MODULE_MAIN(fn) static module_main_t __module_main \
+ __used __attribute__((section(".ctors_modmain"))) = 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)
+
+/**
+ * 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_load_shallow - loads a shallow 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 module metadata. The metadata currently
+ * contains a symbol table that describes code & data allocated by other means.
+ * Its current use is to describe the root COM32 module to the rest of the
+ * module subsystem.
+ */
+extern int module_load_shallow(struct elf_module *module, Elf32_Addr base_addr);
+
+/**
+ * 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 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 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/lib/MCONFIG b/com32/lib/MCONFIG
index 44278bd1..c441c9c1 100644
--- a/com32/lib/MCONFIG
+++ b/com32/lib/MCONFIG
@@ -38,7 +38,7 @@ OPTFLAGS = -Os -march=i386 -falign-functions=0 -falign-jumps=0 \
WARNFLAGS = $(GCCWARN) -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Winline
CFLAGS = $(OPTFLAGS) $(REQFLAGS) $(WARNFLAGS) $(LIBFLAGS)
-LDFLAGS = -m elf32_i386
+LDFLAGS = -m elf32_i386 --hash-style=gnu
.SUFFIXES: .c .o .a .so .lo .i .S .s .ls .ss .lss
diff --git a/com32/lib/Makefile b/com32/lib/Makefile
index 2035df22..c8558c64 100644
--- a/com32/lib/Makefile
+++ b/com32/lib/Makefile
@@ -7,46 +7,89 @@ NOGPL := 1
topdir = ../..
include MCONFIG
-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 \
- \
- lmalloc.o lstrdup.o \
- \
- dprintf.o vdprintf.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
+
+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/features.o syslinux/config.o \
+ syslinux/ipappend.o syslinux/dsinfo.o syslinux/version.o \
+ syslinux/pxe_get_cached.o syslinux/pxe_get_nic.o \
+ syslinux/adv.o syslinux/advwrite.o syslinux/getadv.o \
+ syslinux/setadv.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/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 \
+ syslinux/idle.o \
+ \
+ exit.o
+
+LIBMODULE_OBJS = \
+ sys/module/common.o sys/module/elf_module.o \
+ sys/module/shallow_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 \
@@ -59,86 +102,86 @@ LIBOBJS = \
\
sys/ansi.o \
\
- sys/libansi.o \
- \
- sys/gpxe.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 \
+ sys/ansicon_write.o sys/ansiserial_write.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 \
+ syslinux/serial.o
+
+LIBOTHER_OBJS = \
+ 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 fwrite2.o fwrite.o getopt.o \
+ lrand48.o stack.o memccpy.o memchr.o memcmp.o \
+ memcpy.o mempcpy.o memmem.o memmove.o memset.o memswap.o \
+ perror.o printf.o puts.o qsort.o seed48.o snprintf.o \
+ sprintf.o srand48.o sscanf.o strcasecmp.o strcat.o \
+ strchr.o strcmp.o strcpy.o strdup.o strerror.o strlen.o \
+ strnlen.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 \
\
- 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 \
+ lmalloc.o lstrdup.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 \
+ dprintf.o vdprintf.o \
\
- sys/x86_init_fpu.o math/pow.o math/strtod.o \
+ getcwd.o fdopendir.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 \
+ 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/memscan.o \
+ sys/openconsole.o sys/line_input.o \
+ sys/colortable.o sys/screensize.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 \
+ 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 \
\
- syslinux/run_default.o syslinux/run_command.o \
- syslinux/cleanup.o syslinux/localboot.o syslinux/runimage.o \
+ sys/xserial_write.o \
\
- syslinux/loadfile.o syslinux/floadfile.o syslinux/zloadfile.o \
+ sys/ansi.o \
\
- syslinux/load_linux.o syslinux/initramfs.o \
- syslinux/initramfs_file.o syslinux/initramfs_loadfile.o \
- syslinux/initramfs_archive.o \
+ sys/ansicon_write.o sys/ansiserial_write.o \
\
- syslinux/pxe_get_cached.o syslinux/pxe_get_nic.o \
- syslinux/pxe_dns.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 \
\
- syslinux/adv.o syslinux/advwrite.o syslinux/getadv.o \
- syslinux/setadv.o \
+ sys/x86_init_fpu.o math/pow.o math/strtod.o \
\
- syslinux/video/fontquery.o syslinux/video/forcetext.o \
- syslinux/video/reportmode.o
+ syslinux/memscan.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 \
- \
- 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
+MINLIBOBJS = \
+ $(LIBOTHER_OBJS) \
+ $(LIBENTRY_OBJS) \
+ $(LIBGCC_OBJS) \
+ $(LIBCONSOLE_OBJS) \
+ $(LIBLOAD_OBJS) \
+ $(LIBMODULE_OBJS) \
+ $(LIBZLIB_OBJS)
+# $(LIBVESA_OBJS)
+
+
+DYNLIBOBJS = \
+ $(LIBZLIB_OBJS) \
+ $(LIBPNG_OBJS) \
+ $(LIBJPG_OBJS) \
+ $(LIBPCI_OBJS) \
+ $(LIBVESA_OBJS) \
+ $(LIBSYSLINUX_OBJS) \
+ $(LIBLOAD_OBJS) \
+ $(DYNENTRY_OBJS)
+
+
+LIBOBJS = \
+ $(MINLIBOBJS) \
+ $(DYNLIBOBJS)
BINDIR = /usr/bin
LIBDIR = /usr/lib
@@ -147,18 +190,23 @@ AUXDIR = $(DATADIR)/syslinux
INCDIR = /usr/include
COM32DIR = $(AUXDIR)/com32
-all: libcom32.a libcomcore.a
+all: libcom32.a libcom32min.a klibc.c32
libcom32.a : $(LIBOBJS)
rm -f $@
$(AR) cq $@ $^
$(RANLIB) $@
-libcomcore.a : $(LIBCOREOBJS)
+$(LIBMODULE_OBJS) : CFLAGS += -DELF_DEBUG
+libcom32min.a : $(MINLIBOBJS)
rm -f $@
$(AR) cq $@ $^
$(RANLIB) $@
+klibc.c32 : $(DYNLIBOBJS)
+ rm -f $@
+ $(LD) -shared -T elf32.ld -o $@ $(DYNLIBOBJS)
+
tidy dist clean:
rm -f sys/vesa/alphatbl.c
find . \( -name \*.o -o -name \*.a -o -name .\*.d -o -name \*.tmp \) -print0 | \
diff --git a/com32/lib/elf32.ld b/com32/lib/elf32.ld
new file mode 100644
index 00000000..158badbb
--- /dev/null
+++ b/com32/lib/elf32.ld
@@ -0,0 +1,184 @@
+/*
+ * 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))
+ }
+ .init_array :
+ {
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ }
+ .fini_array :
+ {
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ }
+
+ .ctors :
+ {
+ __ctors_start = .;
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ LONG(0x00000000)
+ __module_init_ptr = .;
+ KEEP (*(.ctors_modinit))
+ LONG(0x00000000)
+ __module_main_ptr = .;
+ KEEP (*(.ctors_modmain))
+ LONG(0x00000000)
+ }
+
+ .dtors :
+ {
+ __dtors_start = .;
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ LONG(0x00000000)
+ __module_exit_ptr = .;
+ KEEP (*(.dtors_modexit))
+ LONG(0x00000000)
+ }
+
+ .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/exit.c b/com32/lib/exit.c
index ccd6f1ee..cba6cee0 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, rv+1);
+}
+
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..69438bdc 100644
--- a/com32/lib/lmalloc.c
+++ b/com32/lib/lmalloc.c
@@ -31,7 +31,7 @@
#include <string.h>
#include <syslinux/pmapi.h>
-void *lmalloc(size_t size)
+void *clmalloc(size_t size)
{
void *p;
p = __com32.cs_pm->lmalloc(size);
diff --git a/com32/lib/lstrdup.c b/com32/lib/lstrdup.c
index d11efe7e..6747ef3a 100644
--- a/com32/lib/lstrdup.c
+++ b/com32/lib/lstrdup.c
@@ -9,7 +9,7 @@
char *lstrdup(const char *s)
{
int l = strlen(s) + 1;
- char *d = lmalloc(l);
+ char *d = clmalloc(l);
if (d)
memcpy(d, s, l);
diff --git a/com32/lib/sys/module/common.c b/com32/lib/sys/module/common.c
new file mode 100644
index 00000000..431f5cd4
--- /dev/null
+++ b/com32/lib/sys/module/common.c
@@ -0,0 +1,526 @@
+/*
+ * common.c
+ *
+ * Created on: Aug 11, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+#include <stdio.h>
+#include <elf.h>
+#include <string.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; 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
+
+/*
+ * Image files manipulation routines
+ */
+
+int image_load(struct elf_module *module)
+{
+ module->u.l._file = fopen(module->name, "rb");
+
+ 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));
+
+ 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; i++)
+ {
+ crt_sym = (Elf32_Sym*)(module->sym_table + i * module->syment_size);
+ crt_name = module->str_table + crt_sym->st_name;
+
+ strong_count = 0;
+ weak_count = 0;
+
+ 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
+ if (strong_count == 0 && weak_count == 0)
+ {
+ DBG_PRINT("Symbol %s is undefined\n", crt_name);
+ printf("Undef symbol FAIL: %s ",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;
+}
+
+
+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 = (Elf32_Sym*)(module->sym_table + crt_index*module->syment_size);
+
+ 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 = (Elf32_Sym*)(module->sym_table +
+ (hasharr - gnu_chain_zero) * module->syment_size);
+
+ 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; i++)
+ {
+ crt_sym = (Elf32_Sym*)(module->sym_table + i*module->syment_size);
+ 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..6259df51
--- /dev/null
+++ b/com32/lib/sys/module/common.h
@@ -0,0 +1,65 @@
+/*
+ * 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))
+
+//#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..d04230ea
--- /dev/null
+++ b/com32/lib/sys/module/elf_module.c
@@ -0,0 +1,515 @@
+/*
+ * elf_module.c
+ *
+ * Created on: Aug 11, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <elf.h>
+
+#include <linux/list.h>
+#include <sys/module.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;
+ void *pht = NULL;
+ Elf32_Phdr *cr_pht;
+
+ 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);
+ 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(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));
+ */
+ }
+ }
+
+ // 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:
+ // TODO: Manage dependencies here
+ 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++;
+ }
+
+ // Now compute the number of symbols in the symbol table
+ if (module->ghash_table != NULL) {
+ module->symtable_size = module->ghash_table[1];
+ } else {
+ module->symtable_size = module->hash_table[1];
+ }
+
+ return 0;
+}
+
+
+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 =
+ (Elf32_Sym*)(module->sym_table + sym * module->syment_size);
+
+ // The symbol definition
+ sym_def =
+ global_find_symbol(module->str_table + sym_ref->st_name,
+ &sym_module);
+
+ if (sym_def == NULL) {
+ // This should never happen
+ DBG_PRINT("Cannot perform relocation for symbol %s\n",
+ module->str_table + sym_ref->st_name);
+
+ return -1;
+ }
+
+ // 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;
+ void *plt_rel = NULL;
+
+ void *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 *init_sym = module_find_symbol(MODULE_ELF_INIT_PTR, module);
+ Elf32_Sym *exit_sym = module_find_symbol(MODULE_ELF_EXIT_PTR, module);
+ Elf32_Sym *main_sym = module_find_symbol(MODULE_ELF_MAIN_PTR, module);
+
+ if (init_sym == NULL) {
+ DBG_PRINT("Cannot find initialization routine pointer.\n");
+ printf("Cannot find initialization routine pointer.\n");
+ return -1;
+ }
+ if (exit_sym == NULL) {
+ DBG_PRINT("Cannot find exit routine pointer.\n");
+ printf("Cannot find exit routine pointer.\n");
+ return -1;
+ }
+ if (main_sym == NULL) {
+ DBG_PRINT("Cannot find main routine pointer.\n");
+ printf("Cannot find main routine pointer.\n");
+ return -1;
+ }
+
+ module->init_func = (module_init_t*)module_get_absolute(
+ init_sym->st_value, module);
+ if (*(module->init_func) == NULL) {
+ module->init_func = NULL;
+ }
+
+ module->exit_func = (module_exit_t*)module_get_absolute(
+ exit_sym->st_value, module);
+ if (*(module->exit_func) == NULL) {
+ module->exit_func = NULL;
+ }
+
+ module->main_func = (module_main_t*)module_get_absolute(
+ main_sym->st_value, module);
+ if (*(module->main_func) == NULL) {
+ module->main_func = NULL;
+ }
+
+
+ return 0;
+}
+
+// Loads the module into the system
+int module_load(struct elf_module *module) {
+ int res;
+ Elf32_Ehdr elf_hdr;
+
+ // Do not allow duplicate modules
+ if (module_find(module->name) != NULL) {
+ DBG_PRINT("Module %s is already loaded.\n", module->name);
+ return -1;
+ }
+
+ // 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");
+ //
+ //dump_elf_module(module);
+
+ // Check the symbols for duplicates / missing definitions
+ CHECKED(res, check_symbols(module), error);
+ //printf("check... 5\n");
+
+ // Obtain constructors and destructors
+ CHECKED(res, extract_operations(module), error);
+ //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);
+
+ //mp("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));
+ */
+ return 0;
+
+error:
+ // 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..64be0770
--- /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) {
+ void *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(void *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..b18968f3
--- /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(void *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..30a61c06
--- /dev/null
+++ b/com32/lib/sys/module/exec.c
@@ -0,0 +1,402 @@
+/*
+ * 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>
+
+#define DBG_PRINT(fmt, args...) fprintf(stderr, "[EXEC] " fmt, ##args)
+
+static struct elf_module *mod_root = NULL;
+struct elf_module *__syslinux_current = NULL;
+
+int exec_init(void)
+{
+ int res;
+
+ res = modules_init();
+ if (res != 0)
+ return res;
+
+ // Load the root module
+ mod_root = module_alloc(EXEC_ROOT_NAME);
+
+ if (mod_root == NULL)
+ return -1;
+
+ res = module_load_shallow(mod_root, 0);
+ if (res != 0) {
+ mod_root = NULL;
+ return res;
+ }
+
+ return 0;
+}
+
+int get_module_type(struct elf_module *module)
+{
+ if(module->main_func) return EXEC_MODULE;
+ else if(module->init_func) return LIB_MODULE;
+ return UNKNOWN_MODULE;
+}
+
+int load_library(const char *name)
+{
+ int res;
+ 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) {
+ DBG_PRINT("Cannot load executable module as library.\n");
+ module_unload(module);
+ return -1;
+ }
+
+ if (module->init_func != NULL) {
+ res = (*(module->init_func))();
+ if (res)
+ DBG_PRINT("Initialization error! function returned: %d\n", res);
+ } else {
+ DBG_PRINT("No initialization function present.\n");
+ }
+
+ if (res != 0) {
+ module_unload(module);
+ return res;
+ }
+
+ return 0;
+}
+
+int unload_library(const char *name)
+{
+ int res;
+ struct elf_module *module = module_find(name);
+
+ if (module == NULL)
+ return -1;
+
+ if (!module_unloadable(module)) {
+ return -1;
+ }
+
+ if (module->exit_func != NULL) {
+ (*(module->exit_func))();
+ }
+
+ res = module_unload(module);
+ return res;
+}
+
+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
+
+struct elf_module *cur_module;
+
+int spawn_load(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);
+ struct elf_module *prev_module;
+
+ int type;
+
+ mp("enter: name = %s", name);
+
+ if (module == NULL)
+ return -1;
+
+ /* ugly hack to reload the same module */
+ if (!strcmp(cur_module->name, module->name)) {
+ mp("We is running this module %s already!", module->name);
+ module_unload(cur_module);
+ cur_module = NULL;
+ }
+
+ res = module_load(module);
+ if (res != 0) {
+ module_unload(module);
+ return res;
+ }
+
+ type = get_module_type(module);
+ prev_module = cur_module;
+ cur_module = module;
+
+ mp("type = %d, prev = %s, cur = %s",
+ type, prev_module->name, cur_module->name);
+
+ if(type==LIB_MODULE)
+ {
+ if (module->init_func != NULL) {
+ res = (*(module->init_func))();
+ DBG_PRINT("Initialization function returned: %d\n", res);
+ } else {
+ DBG_PRINT("No initialization function present.\n");
+ }
+
+ if (res != 0) {
+ cur_module = prev_module;
+ module_unload(module);
+ return res;
+ }
+ return 0;
+ }
+ else 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);
+
+ // 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;
+
+ cur_module = prev_module;
+ res = module_unload(module);
+
+ if (res != 0) {
+ return res;
+ }
+
+ return ((unsigned int)ret_val & 0xFF);
+ }
+ /*
+ module_unload(module);
+ return -1;
+ */
+}
+
+int module_load_dependencies(const char *name,const char *dep_file)
+{
+ FILE *d_file=fopen(dep_file,"r");
+ char line[2048],aux[2048],temp_name[MODULE_NAME_SIZE],slbz[24];
+ int i=0,j=0,res=0;
+
+ if(d_file==NULL)
+ {
+ DBG_PRINT("Could not open object file '%s'\n",dep_file);
+ return -1;
+ }
+
+ /* Note from feng:
+ * new modues.dep has line like this:
+ * a.c32: b.32 c.c32 d.c32
+ * with desktop glibc
+ * sscanf(line,"%[^:]: %[^\n]", temp_name, aux);
+ * works, which doesn't work here
+ */
+ memset(temp_name, 0, sizeof(temp_name));
+ memset(aux, 0, sizeof(aux));
+ while (1) {
+ if(fgets(line,2048,d_file)==NULL)
+ break;
+
+ //sscanf(line,"%s %[^\t\n]s",temp_name,aux);
+ //sscanf(line,"%[^:]: %[^\n]", temp_name, aux);
+ //sscanf(line,"%[^:]: %[^\n]\n", temp_name, aux);
+
+ sscanf(line,"%[^:]:", temp_name);
+ if (!strncmp(name, temp_name, strlen(name))) {
+ /* The next 2 chars should be ':' and ' ' */
+ i = strlen(temp_name);
+ if (line[i] != ':' || line[i+1] != ' ')
+ break;
+
+ i +=2;
+ j = 0;
+ while (line[i] != '\n')
+ aux[j++] = line[i++];
+ aux[j] = '\0';
+ //mp("found dependency: temp_name = %s, aux = %s, name = %s", temp_name, aux, name);
+ break;
+ }
+ }
+ fclose(d_file);
+
+ /* Reuse temp_name for dependent module name buffer */
+ memset(temp_name, 0, sizeof(temp_name));
+ i = 0;
+ while (aux[i]) {
+ sscanf(aux + i, "%s", temp_name);
+ //mp("load module: %s", temp_name);
+ i += strlen(temp_name);
+ i++; /* skip a space */
+
+ if (strlen(temp_name)) {
+ module_load_dependencies(temp_name, MODULES_DEP);
+ if (spawn_load(temp_name, NULL) < 0)
+ continue;
+ }
+ }
+
+ return 0;
+}
+
+void exec_term(void)
+{
+ modules_term();
+}
diff --git a/com32/lib/sys/module/shallow_module.c b/com32/lib/sys/module/shallow_module.c
new file mode 100644
index 00000000..fbcf781b
--- /dev/null
+++ b/com32/lib/sys/module/shallow_module.c
@@ -0,0 +1,161 @@
+/*
+ * shallow_module.c
+ *
+ * Created on: Aug 11, 2008
+ * Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+
+#include <string.h>
+#include <sys/module.h>
+
+#include "common.h"
+#include "elfutils.h"
+
+
+static int check_header_shallow(Elf32_Ehdr *elf_hdr) {
+ int res;
+
+ res = check_header_common(elf_hdr);
+
+ if (res != 0)
+ return res;
+
+ if (elf_hdr->e_shoff == 0x00000000) {
+ DBG_PRINT("SHT missing\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int load_shallow_sections(struct elf_module *module, Elf32_Ehdr *elf_hdr) {
+ int i;
+ int res = 0;
+ void *sht = NULL;
+ void *buffer = NULL;
+ Elf32_Shdr *crt_sht;
+ Elf32_Off buff_offset;
+
+ Elf32_Off min_offset = 0xFFFFFFFF;
+ Elf32_Off max_offset = 0x00000000;
+ Elf32_Word max_align = 0x1;
+
+ Elf32_Off sym_offset = 0xFFFFFFFF;
+ Elf32_Off str_offset = 0xFFFFFFFF;
+
+
+ char *sh_strtable;
+
+ // We buffer the data up to the SHT
+ buff_offset = module->u.l._cr_offset;
+
+ buffer = malloc(elf_hdr->e_shoff - buff_offset);
+ // Get to the SHT
+ image_read(buffer, elf_hdr->e_shoff - buff_offset, module);
+
+ // Load the SHT
+ sht = malloc(elf_hdr->e_shnum * elf_hdr->e_shentsize);
+ image_read(sht, elf_hdr->e_shnum * elf_hdr->e_shentsize, module);
+
+ // Get the string table of the section names
+ crt_sht = (Elf32_Shdr*)(sht + elf_hdr->e_shstrndx * elf_hdr->e_shentsize);
+ sh_strtable = (char*)(buffer + (crt_sht->sh_offset - buff_offset));
+
+ for (i = 0; i < elf_hdr->e_shnum; i++) {
+ crt_sht = (Elf32_Shdr*)(sht + i*elf_hdr->e_shentsize);
+
+ if (strcmp(".symtab", sh_strtable + crt_sht->sh_name) == 0) {
+ // We found the symbol table
+ min_offset = MIN(min_offset, crt_sht->sh_offset);
+ max_offset = MAX(max_offset, crt_sht->sh_offset + crt_sht->sh_size);
+ max_align = MAX(max_align, crt_sht->sh_addralign);
+
+ sym_offset = crt_sht->sh_offset;
+
+ module->syment_size = crt_sht->sh_entsize;
+ module->symtable_size = crt_sht->sh_size / crt_sht->sh_entsize;
+ }
+ if (strcmp(".strtab", sh_strtable + crt_sht->sh_name) == 0) {
+ // We found the string table
+ min_offset = MIN(min_offset, crt_sht->sh_offset);
+ max_offset = MAX(max_offset, crt_sht->sh_offset + crt_sht->sh_size);
+ max_align = MAX(max_align, crt_sht->sh_addralign);
+
+ str_offset = crt_sht->sh_offset;
+
+ module->strtable_size = crt_sht->sh_size;
+ }
+ }
+
+ if (elf_malloc(&module->module_addr, max_align,
+ max_offset - min_offset) != 0) {
+ DBG_PRINT("Could not allocate sections\n");
+ goto out;
+ }
+
+ // Copy the data
+ image_seek(min_offset, module);
+ image_read(module->module_addr, max_offset - min_offset, module);
+
+ // Setup module information
+ module->module_size = max_offset - min_offset;
+ module->str_table = (char*)(module->module_addr + (str_offset - min_offset));
+ module->sym_table = module->module_addr + (sym_offset - min_offset);
+
+out:
+ // Release the SHT
+ if (sht != NULL)
+ free(sht);
+
+ // Release the buffer
+ if (buffer != NULL)
+ free(buffer);
+
+ return res;
+}
+
+
+int module_load_shallow(struct elf_module *module, Elf32_Addr base_addr) {
+ int res;
+ Elf32_Ehdr elf_hdr;
+
+ // Do not allow duplicate modules
+ if (module_find(module->name) != NULL) {
+ DBG_PRINT("Module already loaded.\n");
+ return -1;
+ }
+
+ res = image_load(module);
+
+ if (res < 0)
+ return res;
+
+ module->shallow = 1;
+
+ CHECKED(res, image_read(&elf_hdr, sizeof(Elf32_Ehdr), module), error);
+
+ // Checking the header signature and members
+ CHECKED(res, check_header_shallow(&elf_hdr), error);
+
+ CHECKED(res, load_shallow_sections(module, &elf_hdr), error);
+ module->base_addr = base_addr;
+
+ // Check the symbols for duplicates / missing definitions
+ CHECKED(res, check_symbols(module), error);
+
+ // Add the module at the beginning of the module list
+ list_add(&module->list, &modules_head);
+
+ // The file image is no longer needed
+ image_unload(module);
+
+ DBG_PRINT("SHALLOW MODULE %s LOADED SUCCESSFULLY\n", module->name);
+
+ return 0;
+
+error:
+ image_unload(module);
+
+ return res;
+}
diff --git a/com32/lib/sys/open.c b/com32/lib/sys/open.c
index cb7c1b4d..1d7677bc 100644
--- a/com32/lib/sys/open.c
+++ b/com32/lib/sys/open.c
@@ -57,6 +57,8 @@ int open(const char *pathname, int flags, ...)
fd = opendev(&__file_dev, NULL, flags);
+ //printf("enter, file = %s, fd = %d\n", pathname, fd);
+
if (fd < 0)
return -1;
diff --git a/com32/lib/sys/rawcon_read.c b/com32/lib/sys/rawcon_read.c
index 92c9b294..fbcd9364 100644
--- a/com32/lib/sys/rawcon_read.c
+++ b/com32/lib/sys/rawcon_read.c
@@ -36,7 +36,6 @@
#include <string.h>
#include <com32.h>
#include <minmax.h>
-#include <sys/times.h>
#include "file.h"
/* Global, since it's used by stdcon_read */
@@ -45,14 +44,11 @@ ssize_t __rawcon_read(struct file_info *fp, void *buf, size_t count)
com32sys_t ireg, oreg;
char *bufp = buf;
size_t n = 0;
- clock_t start;
(void)fp;
memset(&ireg, 0, sizeof ireg);
- start = times(NULL);
-
while (n < count) {
/* Poll */
ireg.eax.b[1] = 0x0B;
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/modules/Makefile b/com32/modules/Makefile
index 2d479132..69bd01bd 100644
--- a/com32/modules/Makefile
+++ b/com32/modules/Makefile
@@ -21,8 +21,8 @@ include ../MCONFIG
MODULES = chain.c32 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 whichsys.c32
+ kbdmap.c32 cmd.c32 vpdtest.c32 host.c32 dir.c32 gpxecmd.c32 \
+ ifcpu.c32 cpuid.c32 cat.c32
TESTFILES =
diff --git a/com32/modules/dir.c b/com32/modules/dir.c
new file mode 100644
index 00000000..c9d93708
--- /dev/null
+++ b/com32/modules/dir.c
@@ -0,0 +1,177 @@
+/*
+ * 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;
+
+ openconsole(&dev_rawcon_r, &dev_stdcon_w);
+
+ 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/core/Makefile b/core/Makefile
index 1330fb9e..54848f28 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -41,15 +41,16 @@ NASMSRC := $(wildcard *.asm)
NASMHDR := $(wildcard *.inc)
CSRC := $(wildcard *.c */*.c */*/*.c)
SSRC := $(wildcard *.S */*.S */*/*.S)
-CHDR := $(wildcard *.h)
+CHDR := $(wildcard *.h */*.h */*/*.h)
OTHERSRC := keywords
ALLSRC = $(NASMSRC) $(NASMHDR) $(CSRC) $(SSRC) $(CHDR) $(OTHERSRC)
COBJ := $(patsubst %.c,%.o,$(CSRC))
SOBJ := $(patsubst %.S,%.o,$(SSRC))
-LIB = libcore.a
-LIBS = $(LIB) $(com32)/lib/libcomcore.a $(LIBGCC)
+LIB = libcom32.a
+LIBS = $(LIB) --whole-archive $(com32)/lib/libcom32min.a
+LIBDEP = $(filter-out -% %start%,$(LIBS))
LIBOBJS = $(COBJ) $(SOBJ)
NASMDEBUG = -g -F dwarf
@@ -77,7 +78,7 @@ kwdhash.gen: keywords genhash.pl
.PRECIOUS: %.elf
%.raw: %.elf
- $(OBJCOPY) -O binary $< $(@:.bin=.raw)
+ $(OBJCOPY) -O binary -S $< $(@:.bin=.raw)
%.bin: %.raw $(PREPCORE)
$(PREPCORE) $< $@
@@ -87,8 +88,8 @@ kwdhash.gen: keywords genhash.pl
-DHEXDATE="$(HEXDATE)" \
-l $(@:.o=.lsr) -o $@ -MP -MD .$@.d $<
-%.elf: %.o $(LIBS) syslinux.ld
- $(LD) $(LDFLAGS) -T syslinux.ld -M -o $@ $< \
+%.elf: %.o $(LIBDEP) syslinux.ld
+ $(LD) $(LDFLAGS) -s -Bsymbolic -pie -E --hash-style=gnu -T syslinux.ld -M -o $@ $< \
--start-group $(LIBS) --end-group \
> $(@:.elf=.map)
$(OBJDUMP) -h $@ > $(@:.elf=.sec)
diff --git a/core/common.inc b/core/common.inc
index 7078011e..0b507ce7 100644
--- a/core/common.inc
+++ b/core/common.inc
@@ -14,7 +14,6 @@
%include "loadhigh.inc" ; Load a file into high memory
%include "font.inc" ; VGA font stuff
%include "graphics.inc" ; VGA graphics
-%include "highmem.inc" ; High memory sizing
%include "strcpy.inc" ; strcpy()
%include "idle.inc" ; Idle handling
%include "adv.inc" ; Auxillary Data Vector
diff --git a/core/configinit.inc b/core/configinit.inc
index 915e77f7..7386a8cf 100644
--- a/core/configinit.inc
+++ b/core/configinit.inc
@@ -20,8 +20,6 @@
section .text16
reset_config:
- call highmemsize
-
; Initialize the .config section
xor eax,eax
mov si,__config_lma
@@ -45,7 +43,4 @@ mkkeymap: stosb
inc al
loop mkkeymap
- mov eax,[HighMemSize]
- mov [VKernelEnd],eax
-
ret
diff --git a/core/diskfs.inc b/core/diskfs.inc
index 9f18c765..19a46cc2 100644
--- a/core/diskfs.inc
+++ b/core/diskfs.inc
@@ -97,13 +97,15 @@ trackbuf resb trackbufsize ; Track buffer goes here
;
; Load configuration file
;
- pm_call load_config
- jz no_config_file
+ ;feng
+ ;pm_call load_config
+ ;jz no_config_file
;
; Now we have the config file open. Parse the config file and
; run the user interface.
;
+ pm_call hello
%include "ui.inc"
;
diff --git a/core/diskstart.inc b/core/diskstart.inc
index c0ba52a0..c61a615f 100644
--- a/core/diskstart.inc
+++ b/core/diskstart.inc
@@ -866,6 +866,7 @@ expand_super:
mov di,[bsSecPerTrack]
movzx ebp,word [MaxTransfer]
pm_call fs_init
+ pm_call load_env32
popad
section .bss16
diff --git a/core/elflink/abort_new.c b/core/elflink/abort_new.c
new file mode 100644
index 00000000..39ba2267
--- /dev/null
+++ b/core/elflink/abort_new.c
@@ -0,0 +1,29 @@
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <console.h>
+
+//#include <syslinux/loadfile.h>
+//#include <syslinux/linux.h>
+//#include <syslinux/pxe.h>
+
+#include "core.h"
+#include "core-elf.h"
+#include "menu.h"
+
+void abort_load_new(com32sys_t *reg)
+{
+ char *str;
+
+ str = (void *)reg->esi.l;
+
+ printf("Error!\n");
+ if (str)
+ printf("%s\n", str);
+
+ if (onerrorlen)
+ execute(start_menu->onerror, KT_NONE);
+ enter_cmdline();
+ return;
+}
diff --git a/core/elflink/adv.c b/core/elflink/adv.c
new file mode 100644
index 00000000..be38e89d
--- /dev/null
+++ b/core/elflink/adv.c
@@ -0,0 +1,49 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * syslinux/adv.c
+ *
+ * Access the syslinux auxilliary data vector
+ */
+
+#include <syslinux/adv.h>
+#include <klibc/compiler.h>
+#include <com32.h>
+
+void *__syslinux_adv_ptr;
+size_t __syslinux_adv_size;
+
+void __constructor __syslinux_get_adv(void)
+{
+ static com32sys_t reg;
+
+ reg.eax.w[0] = 0x001c;
+ __intcall(0x22, &reg, &reg);
+ __syslinux_adv_ptr = MK_PTR(reg.es, reg.ebx.w[0]);
+ __syslinux_adv_size = reg.ecx.w[0];
+}
diff --git a/core/elflink/advwrite.c b/core/elflink/advwrite.c
new file mode 100644
index 00000000..4152eea5
--- /dev/null
+++ b/core/elflink/advwrite.c
@@ -0,0 +1,45 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * syslinux/advwrite.c
+ *
+ * Write back the ADV
+ */
+
+#include <syslinux/adv.h>
+#include <klibc/compiler.h>
+#include <com32.h>
+
+int syslinux_adv_write(void)
+{
+ static com32sys_t reg;
+
+ reg.eax.w[0] = 0x001d;
+ __intcall(0x22, &reg, &reg);
+ return (reg.eflags.l & EFLAGS_CF) ? -1 : 0;
+}
diff --git a/core/elflink/cli.c b/core/elflink/cli.c
new file mode 100644
index 00000000..f029ae44
--- /dev/null
+++ b/core/elflink/cli.c
@@ -0,0 +1,410 @@
+#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 <core.h>
+
+#include "getkey.h"
+#include "common.h"
+#include "menu.h"
+#include "cli.h"
+
+void clear_screen(void)
+{
+ mp("enter");
+ fputs("\033e\033%@\033)0\033(B\1#0\033[?25l\033[2J", stdout);
+}
+
+int mygetkey(clock_t timeout)
+{
+ clock_t t0, t;
+ clock_t tto, to;
+ int key;
+
+ //mp("enter");
+ if (!totaltimeout)
+ return get_key(stdin, timeout);
+
+ for (;;) {
+ tto = min(totaltimeout, INT_MAX);
+ to = timeout ? min(tto, timeout) : tto;
+
+ t0 = jiffies();
+ key = get_key(stdin, to);
+ t = jiffies() - t0;
+
+ if (totaltimeout <= t)
+ longjmp(timeout_jump, 1);
+
+ totaltimeout -= t;
+
+ if (key != KEY_NONE) {
+ //mp("get key 0x%x", key);
+ return key;
+ }
+
+ if (timeout) {
+ if (timeout <= t) {
+ //mp("timeout");
+ return KEY_NONE;
+ }
+
+ timeout -= t;
+ }
+ }
+}
+
+const char *edit_cmdline(const char *input, int top /*, int width */ ,
+ int (*pDraw_Menu) (int, int, int),
+ void (*show_fkey) (int))
+{
+ static char cmdline[MAX_CMDLINE_LEN];
+ char temp_cmdline[MAX_CMDLINE_LEN] = { };
+ int key, len, prev_len, cursor;
+ int redraw = 1; /* We enter with the menu already drawn */
+ int x, y;
+ bool done = false;
+ const char *ret;
+ int width = 0;
+ struct cli_command *comm_counter;
+ comm_counter =
+ list_entry(cli_history_head.next->prev, typeof(*comm_counter), list);
+
+ if (!width) {
+ int height;
+ if (getscreensize(1, &height, &width))
+ width = 80;
+ }
+
+ strncpy(cmdline, input, MAX_CMDLINE_LEN);
+ cmdline[MAX_CMDLINE_LEN - 1] = '\0';
+
+ len = cursor = strlen(cmdline);
+ prev_len = 0;
+ x = y = 0;
+
+ while (!done) {
+ if (redraw > 1 && pDraw_Menu != NULL) {
+ /* 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();
+ draw_menu(-1, top, 1); */
+ clear_screen();
+ (*pDraw_Menu) (-1, top, 1);
+ prev_len = 0;
+ // 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[?7l\033[?25l");
+ if (y)
+ printf("\033[%dA", y);
+ printf("\033[1G\033[1;36m> \033[0m");
+
+ x = 2;
+ 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 + 2) / width;
+ x = (cursor + 2) % 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(0);
+
+ switch (key) {
+ case KEY_CTRL('L'):
+ redraw = 2;
+ break;
+
+ case KEY_ENTER:
+ case KEY_CTRL('J'):
+ ret = cmdline;
+ done = true;
+ break;
+
+ case KEY_ESC:
+ case KEY_CTRL('C'):
+ ret = NULL;
+ 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_UP:
+ {
+ if (!list_empty(&cli_history_head)) {
+ comm_counter =
+ list_entry(comm_counter->list.next,
+ typeof(*comm_counter), list);
+ if (&comm_counter->list == &cli_history_head) {
+ strcpy(cmdline, temp_cmdline);
+ } else {
+ strcpy(cmdline, comm_counter->command);
+ }
+ cursor = len = strlen(cmdline);
+ redraw = 1;
+ }
+ }
+ break;
+ case KEY_DOWN:
+ {
+ if (!list_empty(&cli_history_head)) {
+ comm_counter =
+ list_entry(comm_counter->list.prev,
+ typeof(*comm_counter), list);
+ if (&comm_counter->list == &cli_history_head) {
+ strcpy(cmdline, temp_cmdline);
+ } else {
+ strcpy(cmdline, comm_counter->command);
+ }
+ cursor = len = strlen(cmdline);
+ redraw = 1;
+ }
+ }
+ break;
+ default:
+ if (key >= ' ' && key <= 0xFF && len < MAX_CMDLINE_LEN - 1) {
+ if (cursor == len) {
+ temp_cmdline[len] = key;
+ cmdline[len++] = key;
+ temp_cmdline[len] = cmdline[len] = '\0';
+ putchar(key);
+ cursor++;
+ x++;
+ if (x >= width) {
+ printf("\r\n\033[K");
+ y++;
+ x = 0;
+ }
+ prev_len++;
+ } else {
+ memmove(cmdline + cursor + 1, cmdline + cursor,
+ len - cursor + 1);
+ memmove(temp_cmdline + cursor + 1, temp_cmdline + cursor,
+ len - cursor + 1);
+ temp_cmdline[cursor] = key;
+ cmdline[cursor++] = key;
+ len++;
+ redraw = 1;
+ }
+ }
+ break;
+ }
+ }
+
+ printf("\033[?7h");
+ return ret;
+}
+
+void process_command(const char *cmd)
+{
+ char **argv = malloc((MAX_COMMAND_ARGS + 1) * sizeof(char *));
+ char *temp_cmd = (char *)malloc(sizeof(char) * (strlen(cmd) + 1));
+ int argc = 1, len_mn;
+ char *crt_arg, *module_name;
+
+ /* return if user only press enter */
+ if (cmd[0] == '\0') {
+ printf("\n");
+ return;
+ }
+ printf("\n");
+
+ mp("raw cmd = %s", cmd);
+ strcpy(temp_cmd, cmd);
+ module_name = strtok(cmd, COMMAND_DELIM);
+ len_mn = strlen(module_name);
+
+ if (!strcmp(module_name + len_mn - 4, ".c32")) {
+ if (module_find(module_name) != NULL) {
+ /* make module re-enterable */
+ mp("Module %s is already running");
+ }
+ do {
+ argv[0] = module_name;
+ crt_arg = strtok(NULL, COMMAND_DELIM);
+ if (crt_arg != NULL && strlen(crt_arg) > 0) {
+ argv[argc] = crt_arg;
+ argc++;
+ } else
+ break;
+ } while (argc < MAX_COMMAND_ARGS);
+ argv[argc] = NULL;
+ module_load_dependencies(module_name, MODULES_DEP);
+ spawn_load(module_name, argv);
+ } else if (!strcmp(module_name + len_mn - 2, ".0")) {
+ execute(cmd, KT_PXE);
+ } else if (!strcmp(module_name + len_mn - 3, ".bs")) {
+ } else if (!strcmp(module_name + len_mn - 4, ".img")) {
+ execute(cmd, KT_FDIMAGE);
+ } else if (!strcmp(module_name + len_mn - 4, ".bin")) {
+ } else if (!strcmp(module_name + len_mn - 4, ".bss")) {
+ execute(cmd, KT_BSS);
+ } else if (!strcmp(module_name + len_mn - 4, ".com")
+ || !strcmp(module_name + len_mn - 4, ".cbt")) {
+ execute(cmd, KT_COMBOOT);
+ } else if (!strcmp(module_name + len_mn - 4, ".cfg")
+ || !strcmp(module_name + len_mn - 5, ".conf")
+ || !strcmp(module_name + len_mn - 7, ".config")) {
+ execute(module_name, KT_CONFIG);
+ }
+ /* use KT_KERNEL as default */
+ else
+ execute(temp_cmd, KT_KERNEL);
+
+cleanup:
+ free(argv);
+ free(temp_cmd);
+}
diff --git a/core/elflink/cli.h b/core/elflink/cli.h
new file mode 100644
index 00000000..9cd8c16b
--- /dev/null
+++ b/core/elflink/cli.h
@@ -0,0 +1,23 @@
+#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;
+};
+
+struct list_head cli_history_head;
+
+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));
+extern void process_command(const char *cmd);
+
+extern struct menu *root_menu, *start_menu, *hide_menu, *menu_list, *default_menu;
+#endif
diff --git a/core/elflink/colors.c b/core/elflink/colors.c
new file mode 100644
index 00000000..68732bdb
--- /dev/null
+++ b/core/elflink/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/core/elflink/common.h b/core/elflink/common.h
new file mode 100644
index 00000000..e288d1e4
--- /dev/null
+++ b/core/elflink/common.h
@@ -0,0 +1,62 @@
+/*
+ * 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))
+
+//#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/core/elflink/config.c b/core/elflink/config.c
new file mode 100644
index 00000000..b27aa827
--- /dev/null
+++ b/core/elflink/config.c
@@ -0,0 +1,41 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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/core/elflink/core-elf.h b/core/elflink/core-elf.h
new file mode 100644
index 00000000..1edd1744
--- /dev/null
+++ b/core/elflink/core-elf.h
@@ -0,0 +1,16 @@
+#ifndef _CORE_ELF_H
+#define _coRE_ELF_H
+
+extern char *append;
+extern char *ippappend;
+extern char *globaldefault;
+extern short onerrorlen;
+
+extern void parse_configs(char **argv);
+extern int new_linux_kernel(char *okernel, char *ocmdline);
+
+/* load_env32.c, should be moved out */
+extern void enter_cmdline(void);
+
+extern void start_ui(char *config_file);
+#endif
diff --git a/core/elflink/elfutils.h b/core/elflink/elfutils.h
new file mode 100644
index 00000000..3c8e70fc
--- /dev/null
+++ b/core/elflink/elfutils.h
@@ -0,0 +1,67 @@
+#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(void *memptr);
+
+#endif /*ELF_UTILS_H_ */
diff --git a/core/elflink/execute.c b/core/elflink/execute.c
new file mode 100644
index 00000000..29e9933d
--- /dev/null
+++ b/core/elflink/execute.c
@@ -0,0 +1,96 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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 <com32.h>
+#include "menu.h"
+
+void execute(const char *cmdline, enum kernel_type type)
+{
+ com32sys_t ireg;
+ const char *p, *const *pp;
+ char *q;
+ const char *kernel, *args;
+
+ /* work around for spawn_load parameter */
+ char *spawn_load_param[2] = { NULL, NULL};
+
+ memset(&ireg, 0, sizeof ireg);
+
+ /* for parameter will be passed to __intcall, we need use
+ * lmalloc a block of low memory */
+ q = lmalloc(128);
+ if (!q) {
+ printf("%s(): Fail to lmalloc 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++;
+
+ strcpy(q, p);
+
+ mp("kernel is %s, args = %s type = %d \n", kernel, args, type);
+
+ 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_COM32) {
+ /* new entry for elf format c32 */
+ spawn_load_param[0] = args;
+ module_load_dependencies(kernel, "modules.dep");
+ spawn_load(kernel, spawn_load_param);
+ } else if (type <= KT_KERNEL) {
+ /* Need add one item for kernel load, as we don't use
+ * the assembly runkernel.inc any more */
+ new_linux_kernel(kernel, cmdline);
+ } else if (type == KT_CONFIG) {
+ /* kernel contains the config file name */
+ start_ui(kernel);
+ } else {
+ /* process the image need int 22 support */
+ if (type == KT_LOCALBOOT) {
+ ireg.eax.w[0] = 0x0014; /* Local boot */
+ ireg.edx.w[0] = strtoul(kernel, NULL, 0);
+ }
+ 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);
+ }
+
+ lfree(kernel);
+
+ /* If this returns, something went bad; return to menu */
+}
diff --git a/core/elflink/get_key.c b/core/elflink/get_key.c
new file mode 100644
index 00000000..b2f70925
--- /dev/null
+++ b/core/elflink/get_key.c
@@ -0,0 +1,175 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * get_key.c
+ *
+ * Get a single key, and try to pick apart function key codes.
+ * This doesn't decode anywhere close to all possiblities, but
+ * hopefully is enough to be useful.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <core.h>
+
+#include <sys/times.h>
+#include <sys/module.h>
+
+#include "getkey.h"
+
+struct keycode {
+ int code;
+ int seqlen;
+ const unsigned char *seq;
+};
+
+#define MAXLEN 8
+#define CODE(x,y) { x, (sizeof y)-1, y }
+
+static const struct keycode keycodes[] = {
+ /* First, the BIOS combined codes */
+ CODE(KEY_F1, "\0\x3B"),
+ CODE(KEY_F2, "\0\x3C"),
+ CODE(KEY_F3, "\0\x3D"),
+ CODE(KEY_F4, "\0\x3E"),
+ CODE(KEY_F5, "\0\x3F"),
+ CODE(KEY_F6, "\0\x40"),
+ CODE(KEY_F7, "\0\x41"),
+ CODE(KEY_F8, "\0\x42"),
+ CODE(KEY_F9, "\0\x43"),
+ CODE(KEY_F10, "\0\x44"),
+ CODE(KEY_F11, "\0\x85"),
+ CODE(KEY_F12, "\0\x86"),
+
+ CODE(KEY_UP, "\0\x48"),
+ CODE(KEY_DOWN, "\0\x50"),
+ CODE(KEY_LEFT, "\0\x4B"),
+ CODE(KEY_RIGHT, "\0\x4D"),
+ CODE(KEY_PGUP, "\0\x49"),
+ CODE(KEY_PGDN, "\0\x51"),
+ CODE(KEY_HOME, "\0\x47"),
+ CODE(KEY_END, "\0\x4F"),
+ CODE(KEY_INSERT, "\0\x52"),
+ CODE(KEY_DELETE, "\0\x53"),
+
+ /* Now, VT/xterm/Linux codes */
+ CODE(KEY_F1, "\033[[A"),
+ CODE(KEY_F1, "\033OP"),
+ CODE(KEY_F2, "\033[[B"),
+ CODE(KEY_F2, "\033OQ"),
+ CODE(KEY_F3, "\033[[C"),
+ CODE(KEY_F3, "\033OR"),
+ CODE(KEY_F4, "\033[[D"),
+ CODE(KEY_F4, "\033OS"),
+ CODE(KEY_F5, "\033[[E"),
+ CODE(KEY_F5, "\033[15~"),
+ CODE(KEY_F6, "\033[17~"),
+ CODE(KEY_F7, "\033[18~"),
+ CODE(KEY_F8, "\033[19~"),
+ CODE(KEY_F9, "\033[20~"),
+ CODE(KEY_F10, "\033[21~"),
+ CODE(KEY_F11, "\033[23~"),
+ CODE(KEY_F12, "\033[24~"),
+
+ CODE(KEY_UP, "\033[A"),
+ CODE(KEY_DOWN, "\033[B"),
+ CODE(KEY_LEFT, "\033[D"),
+ CODE(KEY_RIGHT, "\033[C"),
+ CODE(KEY_PGUP, "\033[5~"),
+ CODE(KEY_PGUP, "\033[V"),
+ CODE(KEY_PGDN, "\033[6~"),
+ CODE(KEY_PGDN, "\033[U"),
+ CODE(KEY_HOME, "\033[1~"),
+ CODE(KEY_HOME, "\033[H"),
+ CODE(KEY_END, "\033[4~"),
+ CODE(KEY_END, "\033[F"),
+ CODE(KEY_END, "\033OF"),
+ CODE(KEY_INSERT, "\033[2~"),
+ CODE(KEY_INSERT, "\033[@"),
+ CODE(KEY_DELETE, "\033[3~"),
+};
+
+#define NCODES ((int)(sizeof keycodes/sizeof(struct keycode)))
+
+#define KEY_TIMEOUT ((CLK_TCK+9)/10)
+
+int get_key(FILE * f, clock_t timeout)
+{
+ unsigned char buffer[MAXLEN];
+ int nc, i, rv;
+ const struct keycode *kc;
+ int another;
+ unsigned char ch;
+ clock_t start;
+
+ /* We typically start in the middle of a clock tick */
+ if (timeout)
+ timeout++;
+
+ nc = 0;
+ start = jiffies();
+ do {
+ rv = read(fileno(f), &ch, 1);
+ if (rv == 0 || (rv == -1 && errno == EAGAIN)) {
+ clock_t lateness = jiffies() - start;
+ if (nc && lateness > 1 + KEY_TIMEOUT) {
+ if (nc == 1)
+ return buffer[0]; /* timeout in sequence */
+ else if (timeout && lateness > timeout)
+ return KEY_NONE;
+ } else if (!nc && timeout && lateness > timeout)
+ return KEY_NONE; /* timeout before sequence */
+
+ syslinux_idle();
+
+ another = 1;
+ continue;
+ }
+
+ start = jiffies();
+
+ 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)) {
+ 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];
+}
diff --git a/core/elflink/getadv.c b/core/elflink/getadv.c
new file mode 100644
index 00000000..456084b0
--- /dev/null
+++ b/core/elflink/getadv.c
@@ -0,0 +1,68 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * syslinux/getadv.c
+ *
+ * Get a data item from the auxilliary data vector. Returns a pointer
+ * and sets *size on success; NULL on failure.
+ */
+
+#include <syslinux/adv.h>
+#include <klibc/compiler.h>
+#include <inttypes.h>
+
+const void *syslinux_getadv(int tag, size_t * size)
+{
+ const uint8_t *p;
+ size_t left, len;
+
+ p = syslinux_adv_ptr();
+ left = syslinux_adv_size();
+
+ while (left >= 2) {
+ uint8_t ptag = *p++;
+ size_t plen = *p++;
+ left -= 2;
+
+ if (ptag == ADV_END)
+ return NULL; /* Not found */
+
+ if (left < plen)
+ return NULL; /* Item overrun */
+
+ if (ptag == tag) {
+ *size = plen;
+ return p;
+ }
+
+ p += plen;
+ left -= plen;
+ }
+
+ return NULL;
+}
diff --git a/core/elflink/getkey.h b/core/elflink/getkey.h
new file mode 100644
index 00000000..52312a25
--- /dev/null
+++ b/core/elflink/getkey.h
@@ -0,0 +1,80 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * getkey.h
+ *
+ * Function to get a key symbol and parse it
+ */
+
+#ifndef LIBUTIL_GETKEY_H
+#define LIBUTIL_GETKEY_H
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/times.h>
+
+#ifndef CLK_TCK
+# define CLK_TCK sysconf(_SC_CLK_TCK)
+#endif
+
+#define KEY_NONE (-1)
+
+#define KEY_CTRL(x) ((x) & 0x001f)
+#define KEY_BACKSPACE 0x0008
+#define KEY_TAB 0x0009
+#define KEY_ENTER 0x000d
+#define KEY_ESC 0x001b
+#define KEY_DEL 0x007f
+
+#define KEY_F1 0x0100
+#define KEY_F2 0x0101
+#define KEY_F3 0x0102
+#define KEY_F4 0x0103
+#define KEY_F5 0x0104
+#define KEY_F6 0x0105
+#define KEY_F7 0x0106
+#define KEY_F8 0x0107
+#define KEY_F9 0x0108
+#define KEY_F10 0x0109
+#define KEY_F11 0x010A
+#define KEY_F12 0x010B
+
+#define KEY_UP 0x0120
+#define KEY_DOWN 0x0121
+#define KEY_LEFT 0x0122
+#define KEY_RIGHT 0x0123
+#define KEY_PGUP 0x0124
+#define KEY_PGDN 0x0125
+#define KEY_HOME 0x0126
+#define KEY_END 0x0127
+#define KEY_INSERT 0x0128
+#define KEY_DELETE 0x0129
+
+int get_key(FILE *, clock_t);
+
+#endif /* LIBUTIL_GETKEY_H */
diff --git a/core/elflink/ipappend.c b/core/elflink/ipappend.c
new file mode 100644
index 00000000..bd000920
--- /dev/null
+++ b/core/elflink/ipappend.c
@@ -0,0 +1,58 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * syslinux/ipappend.c
+ *
+ * Get ipappend strings
+ */
+
+#include <syslinux/config.h>
+#include <klibc/compiler.h>
+#include <com32.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));
+ }
+ }
+}
diff --git a/core/elflink/kernel.c b/core/elflink/kernel.c
new file mode 100644
index 00000000..2e63df66
--- /dev/null
+++ b/core/elflink/kernel.c
@@ -0,0 +1,124 @@
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <console.h>
+#include <syslinux/loadfile.h>
+#include <syslinux/linux.h>
+#include <syslinux/pxe.h>
+#include "core.h"
+#include "core-elf.h"
+
+/* Will be called from readconfig.c */
+int new_linux_kernel(char *okernel, char *ocmdline)
+{
+ const char *kernel_name;
+ struct initramfs *initramfs;
+ char *temp;
+ void *kernel_data;
+ size_t kernel_len;
+ bool opt_quiet = false;
+ char initrd_name[256];
+ char cmdline_buf[256], *cmdline;
+ int i;
+
+ mp("okernel = %s, ocmdline = %s", okernel, ocmdline);
+
+ cmdline = cmdline_buf;
+
+ temp = cmdline;
+ /*
+ strcpy(temp, "BOOT_IMAGE=");
+ temp += 11;
+ */
+
+ if (okernel)
+ kernel_name = okernel;
+ else if (globaldefault)
+ kernel_name = globaldefault;
+
+ strcpy(temp, kernel_name);
+ temp += strlen(kernel_name);
+
+ /* in elflink branch, KernelCName no more exist */
+ /*
+ else {
+ strcpy(temp, KernelCName);
+ temp += strlen(KernelCName);
+ kernel_name = KernelCName;
+ }
+ */
+
+ *temp = ' ';
+ temp++;
+ if (ocmdline)
+ strcpy(temp, ocmdline);
+ else if (append)
+ strcpy(temp, append);
+ /*
+ else if (*(char *)CmdOptPtr)
+ strcpy(temp, (char *)CmdOptPtr);
+ else if (AppendLen) {
+ for (i = 0; i < AppendLen; i++)
+ *temp++ = AppendBuf[i];
+ *temp = '\0';
+ }
+ */
+
+ printf("cmdline = %s\n", cmdline);
+ /*
+ printf("VkernelEnd = %x\n", VKernelEnd);
+ printf("HighMemSize = %x\n", __com32.cs_memsize);
+ */
+
+ /* "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!\n");
+ goto bail;
+ }
+
+ if (!opt_quiet)
+ printf("ok\n");
+
+ /* Initialize the initramfs chain */
+ initramfs = initramfs_init();
+ if (!initramfs)
+ goto bail;
+
+ /* Find and load initramfs */
+ temp = strstr(cmdline, "initrd=");
+ if (temp) {
+ i = 0;
+
+ temp += strlen("initrd=");
+ while (*temp != ' ' && *temp)
+ initrd_name[i++] = *temp++;
+ initrd_name[i] = '\0';
+
+ initramfs_load_archive(initramfs, initrd_name);
+ }
+
+ //mp("loading initrd done");
+
+ /* This should not return... */
+ syslinux_boot_linux(kernel_data, kernel_len, initramfs, cmdline);
+
+bail:
+ printf("Kernel load failure (insufficient memory?)\n");
+ return 1;
+}
diff --git a/core/elflink/load_env32.c b/core/elflink/load_env32.c
new file mode 100644
index 00000000..8d0a5574
--- /dev/null
+++ b/core/elflink/load_env32.c
@@ -0,0 +1,123 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <console.h>
+#include <com32.h>
+#include <syslinux/adv.h>
+#include <syslinux/config.h>
+#include <setjmp.h>
+#include <linux/list.h>
+#include <netinet/in.h>
+#include <sys/cpu.h>
+
+#include <sys/exec.h>
+#include <sys/module.h>
+#include "common.h"
+#include "menu.h"
+#include "cli.h"
+#include "core-elf.h"
+
+typedef void (*constructor_t) (void);
+constructor_t __ctors_start[], __ctors_end[];
+
+extern char __dynstr_start[];
+extern char __dynstr_len[], __dynsym_len[];
+extern char __dynsym_start[];
+extern char __got_start[];
+extern Elf32_Dyn __dynamic_start[];
+extern Elf32_Word __gnu_hash_start[];
+
+struct elf_module core_module = {
+ .name = "(core)",
+ .shallow = true,
+ .required = LIST_HEAD_INIT((core_module.required)),
+ .dependants = LIST_HEAD_INIT((core_module.dependants)),
+ .list = LIST_HEAD_INIT((core_module.list)),
+ .module_addr = (void *)0x0,
+ .base_addr = (Elf32_Addr) 0x0,
+ .ghash_table = __gnu_hash_start,
+ .str_table = __dynstr_start,
+ .sym_table = __dynsym_start,
+ .got = __got_start,
+ .dyn_table = __dynamic_start,
+ .strtable_size = (size_t) __dynstr_len,
+ .syment_size = sizeof(Elf32_Sym),
+ .symtable_size = (size_t) __dynsym_len
+};
+
+/*
+ Initializes the module subsystem by taking the core module ( shallow module ) and placing
+ it on top of the modules_head_list. Since the core module is initialized when declared
+ we technically don't need the exec_init() and module_load_shallow() procedures
+*/
+void init_module_subsystem(struct elf_module *module)
+{
+ list_add(&module->list, &modules_head);
+}
+
+/* call_constr: initializes sme things related */
+static void call_constr(void)
+{
+ constructor_t *p;
+
+ for (p = __ctors_start; p < __ctors_end; p++)
+ (*p) ();
+}
+
+void enter_cmdline(void)
+{
+ struct cli_command *comm, *aux;
+ char *cmdline;
+
+ /* Enter endless command line prompt, should support "exit" */
+ while (1) {
+ cmdline = edit_cmdline("", 1, NULL, NULL);
+ /* feng: give up the aux check here */
+ //aux = list_entry(cli_history_head.next, typeof(*aux), list);
+ //if (strcmp(aux->command, cmdline)) {
+ comm = (struct cli_command *)malloc(sizeof(struct cli_command *));
+ comm->command =
+ (char *)malloc(sizeof(char) * (strlen(cmdline) + 1));
+ strcpy(comm->command, cmdline);
+ list_add(&(comm->list), &cli_history_head);
+ process_command(cmdline);
+ //}
+ }
+}
+
+/* parameter is the config file name if any */
+void start_ui(char *config_file)
+{
+ char *cmdline;
+ char *argv[2] = {config_file, NULL};
+
+ mp("enter, config file = %s", config_file);
+
+ parse_configs(argv);
+
+ /* run the default menu if found */
+ if (default_menu) {
+ cmdline = default_menu->menu_entries[default_menu->defentry]->cmdline;
+ if (*cmdline == '.') {
+ while (*cmdline++ != ' ');
+ }
+ process_command(cmdline);
+ }
+
+ /* Should never return */
+ enter_cmdline();
+}
+
+/* note to self: do _*NOT*_ use static key word on this function */
+void load_env32(com32sys_t * regs)
+{
+ printf("Starting 32 bit elf module subsystem...\n");
+ call_constr();
+ openconsole(&dev_rawcon_r, &dev_ansiserial_w);
+ INIT_LIST_HEAD(&cli_history_head);
+
+ init_module_subsystem(&core_module);
+
+ start_ui(NULL);
+}
diff --git a/core/elflink/menu.h b/core/elflink/menu.h
new file mode 100644
index 00000000..3bdf2d45
--- /dev/null
+++ b/core/elflink/menu.h
@@ -0,0 +1,229 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * menu.h
+ *
+ * Header file for the simple menu system
+ */
+
+#ifndef MENU_H
+#define MENU_H
+
+#include <time.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <colortbl.h>
+#include <stdbool.h>
+#include <setjmp.h>
+#include "refstr.h"
+
+#ifndef CLK_TCK
+# define CLK_TCK sysconf(_SC_CLK_TCK)
+#endif
+
+struct menu;
+
+/* Note: the _UNRES variants must always be immediately after their
+ "normal" versions. */
+enum menu_action {
+ MA_NONE, /* Undefined value */
+ MA_CMD, /* Execute a command */
+ MA_DISABLED, /* Disabled menu entry */
+ MA_SUBMENU, /* This is a submenu entry */
+ MA_GOTO, /* Go to another menu */
+ MA_GOTO_UNRES, /* Unresolved go to */
+ MA_QUIT, /* Quit to CLI */
+ MA_EXIT, /* Exit to higher-level menu */
+ MA_EXIT_UNRES, /* Unresolved exit */
+};
+
+struct menu_entry {
+ struct menu *menu; /* Parent menu */
+ const char *displayname;
+ const char *label;
+ const char *passwd;
+ char *helptext;
+ const char *cmdline;
+ struct menu *submenu;
+ struct menu_entry *next; /* Linked list of all labels across menus */
+ int entry; /* Entry number inside menu */
+ enum menu_action action;
+ unsigned char hotkey;
+ bool save; /* Save this entry if selected */
+};
+
+static inline bool is_disabled(struct menu_entry *me)
+{
+ return me->action == MA_DISABLED;
+}
+
+enum kernel_type {
+ /* Meta-types for internal use */
+ KT_NONE,
+ KT_LOCALBOOT,
+
+ /* The ones we can pass off to SYSLINUX, in order */
+ KT_KERNEL, /* Undefined type */
+ KT_LINUX, /* Linux kernel */
+ KT_BOOT, /* Bootstrap program */
+ 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,
+ P_MARGIN,
+ P_PASSWD_MARGIN,
+ P_MENU_ROWS,
+ P_TABMSG_ROW,
+ P_CMDLINE_ROW,
+ P_END_ROW,
+ P_PASSWD_ROW,
+ P_TIMEOUT_ROW,
+ P_HELPMSG_ROW,
+ P_HELPMSGEND_ROW,
+ P_HSHIFT,
+ P_VSHIFT,
+ P_HIDDEN_ROW,
+
+ NPARAMS
+};
+
+/* Configurable messages */
+enum message_number {
+ MSG_TITLE,
+ MSG_AUTOBOOT,
+ MSG_TAB,
+ MSG_NOTAB,
+ MSG_PASSPROMPT,
+
+ MSG_COUNT
+};
+
+struct messages {
+ const char *name; /* Message configuration name */
+ const char *defmsg; /* Default message text */
+};
+
+struct menu_parameter {
+ const char *name;
+ int value;
+};
+
+extern const struct menu_parameter mparm[NPARAMS];
+
+struct fkey_help {
+ const char *textname;
+ const char *background;
+};
+
+struct menu {
+ struct menu *next; /* Linked list of all menus */
+ const char *label; /* Goto label for this menu */
+ struct menu *parent;
+ struct menu_entry *parent_entry; /* Entry for self in parent */
+
+ struct menu_entry **menu_entries;
+ struct menu_entry *menu_hotkeys[256];
+
+ const char *messages[MSG_COUNT];
+ int mparm[NPARAMS];
+
+ int nentries;
+ int nentries_space;
+ int defentry;
+ int timeout;
+
+ bool allowedit;
+ bool save; /* MENU SAVE default for this menu */
+
+ int curentry;
+ int curtop;
+
+ const char *title;
+ const char *ontimeout;
+ const char *onerror;
+ const char *menu_master_passwd;
+ const char *menu_background;
+
+ struct color_table *color_table;
+
+ struct fkey_help fkeyhelp[12];
+};
+
+extern struct menu *root_menu, *start_menu, *hide_menu, *menu_list;
+
+/* 2048 is the current definition inside syslinux */
+#define MAX_CMDLINE_LEN 2048
+
+/* These are global parameters regardless of which menu we're displaying */
+extern int shiftkey;
+extern int hiddenmenu;
+extern long long totaltimeout;
+jmp_buf timeout_jump;
+
+void parse_configs(char **argv);
+extern int draw_background(const char *filename);
+
+static inline int my_isspace(char c)
+{
+ return (unsigned char)c <= ' ';
+}
+
+int my_isxdigit(char c);
+unsigned int hexval(char c);
+unsigned int hexval2(const char *p);
+uint32_t parse_argb(char **p);
+
+int menu_main(int argc, char *argv[]);
+void console_prepare(void);
+void console_cleanup(void);
+
+extern const int message_base_color, menu_color_table_size;
+int mygetkey(clock_t timeout);
+int show_message_file(const char *filename, const char *background);
+
+/* passwd.c */
+int passwd_compare(const char *passwd, const char *entry);
+
+/* colors.c */
+#define MSG_COLORS_DEF_FG 0x90ffffff
+#define MSG_COLORS_DEF_BG 0x80ffffff
+#define MSG_COLORS_DEF_SHADOW SHADOW_NORMAL
+void set_msg_colors_global(struct color_table *tbl,
+ unsigned int fg, unsigned int bg,
+ enum color_table_shadow shadow);
+struct color_table *default_color_table(void);
+struct color_table *copy_color_table(const struct color_table *master);
+extern const int message_base_color;
+
+/* background.c */
+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);
+
+#endif /* MENU_H */
diff --git a/core/elflink/readconfig.c b/core/elflink/readconfig.c
new file mode 100644
index 00000000..39b5d125
--- /dev/null
+++ b/core/elflink/readconfig.c
@@ -0,0 +1,1184 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2004-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 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 <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 "menu.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},
+};
+
+short uappendlen; //bytes in append= command
+short ontimeoutlen; //bytes in ontimeout command
+short onerrorlen; //bytes in onerror command
+short forceprompt; //force prompt
+short noescape; //no escape
+short nocomplete; //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; //the current level of default
+short vkernel; //have we seen any "label" statements?
+short displaycon = 1; //conio.inc
+short nohalt = 1; //idle.inc
+
+
+/* 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;
+
+/* Keep track of global default */
+static int has_ui = 0; /* DEFAULT only counts if UI is found */
+char *globaldefault = NULL;
+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; })
+
+/* Must match enum kernel_type */
+const char *const kernel_types[] = {
+ "none",
+ "localboot",
+ "kernel",
+ "linux",
+ "boot",
+ "bss",
+ "pxe",
+ "fdimage",
+ "comboot",
+ "com32",
+ "config",
+ NULL
+};
+
+/*
+ * 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
+
+static char *skipspace(char *p)
+{
+ while (*p && my_isspace(*p))
+ p++;
+
+ return p;
+}
+
+/* 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;
+
+ //mp("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;
+
+ //mp("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;
+ }
+ }
+ }
+}
+
+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])
+ ipp += sprintf(ipp, " %s", 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);
+ mp("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;
+}
+
+static 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 *sp = *p;
+ char *ep = sp;
+
+ while (*ep && !my_isspace(*ep))
+ ep++;
+
+ *p = ep;
+ return refstrndup(sp, ep - sp);
+}
+
+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;
+char *append = NULL;
+//static unsigned int ipappend = 0;
+unsigned int ipappend = 0;
+static struct labeldata ld;
+
+static int parse_one_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;
+}
+
+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;
+}
+
+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);
+ } 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"))) {
+ goto do_include;
+ } 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:
+ {
+ const char *file;
+ p = skipspace(ep);
+ file = refdup_word(&p);
+ p = skipspace(p);
+ if (*p) {
+ record(m, &ld, append);
+ m = current_menu = begin_submenu(p);
+ parse_one_config(file);
+ record(m, &ld, append);
+ m = current_menu = end_submenu();
+ } else {
+ parse_one_config(file);
+ }
+ refstr_put(file);
+ }
+ } 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;
+ }
+ //mp("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 = refstrdup(p);
+ ld.kernel = refstrdup(p);
+ /* 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 = ipappend;
+ 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;
+ //mp("got a kernel: %s, type = %d", ld.kernel, ld.type);
+ }
+ } else if (looking_at(p, "timeout")) {
+ m->timeout = (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")) {
+ m->ontimeout = refstrdup(skipspace(p + 9));
+ } else if (looking_at(p, "allowoptions")) {
+ m->allowedit = !!atoi(skipspace(p + 12));
+ } else if (looking_at(p, "ipappend")) {
+ if (ld.label)
+ ld.ipappend = atoi(skipspace(p + 8));
+ else
+ ipappend = atoi(skipspace(p + 8));
+ } else if (looking_at(p, "default")) {
+ /* default could be a kernel image or another label */
+ refstr_put(globaldefault);
+ globaldefault = refstrdup(skipspace(p + 7));
+ } else if (looking_at(p, "ui")) {
+ has_ui = 1;
+ }
+
+ /*
+ * subset 1: pc_opencmd
+ * display/font/kbdmap are rather similar, open a file then do sth
+ */
+ else if (looking_at(p, "display")) {
+
+ } else if (looking_at(p, "font")) {
+
+ } else if (looking_at(p, "kbdmap")) {
+
+ }
+ /*
+ * 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 + 8));
+ } 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));
+ }
+
+ /* serial setting, bps, flow control */
+ else if (looking_at(p, "serial")) {
+ /* core/conio.inc
+ * should be able to find some code in com32
+ */
+
+ } else if (looking_at(p, "say")) {
+ printf("%s\n", p + 4);
+ }
+ }
+}
+
+static int parse_one_config(const char *filename)
+{
+ FILE *f;
+ int i;
+
+ /*
+ if (!strcmp(filename, "~"))
+ filename = syslinux_config_file();
+ */
+
+ f = fopen(filename, "r");
+ if (f)
+ goto config_found;
+
+ /* force to use hard coded config file name */
+ f = fopen("extlinux.conf", "r");
+ if (f)
+ goto config_found;
+
+ f = fopen("isolinux.cfg", "r");
+ if (f)
+ goto config_found;
+
+ return -1;
+config_found:
+ parse_config_file(f);
+ fclose(f);
+ 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;
+ }
+ }
+ }
+}
+
+static void dump_menu(struct menu *menu)
+{
+ mp("will dump menu for %s:", menu->label);
+ printf("entries num: %d\n", menu->nentries);
+ printf("defentry: %d, nam = %s\n",
+ menu->defentry, menu->menu_entries[menu->defentry]->label);
+ printf("save: %d\n", menu->save);
+ //printf("", menu->);
+ //printf("", menu->);
+ //printf("", menu->);
+}
+
+void parse_configs(char **argv)
+{
+ const char *filename;
+ struct menu *m;
+ struct menu_entry *me;
+ char *cmdline;
+ mp("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) {
+ parse_one_config("~");
+ } else {
+ while ((filename = *argv++)) {
+ mp("Parsing config: %s", filename);
+ parse_one_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) {
+ mp("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/core/elflink/refstr.c b/core/elflink/refstr.c
new file mode 100644
index 00000000..f9d98e11
--- /dev/null
+++ b/core/elflink/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/core/elflink/refstr.h b/core/elflink/refstr.h
new file mode 100644
index 00000000..7001d407
--- /dev/null
+++ b/core/elflink/refstr.h
@@ -0,0 +1,40 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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.h
+ *
+ * Simple reference-counted strings
+ */
+
+#ifndef REFSTR_H
+#define REFSTR_H
+
+#include <stddef.h>
+#include <stdarg.h>
+
+static inline __attribute__ ((always_inline))
+const char *refstr_get(const char *r)
+{
+ if (r)
+ ((unsigned int *)r)[-1]++;
+ return r;
+}
+
+void refstr_put(const char *);
+char *refstr_alloc(size_t);
+const char *refstrdup(const char *);
+const char *refstrndup(const char *, size_t);
+int rsprintf(const char **, const char *, ...);
+int vrsprintf(const char **, const char *, va_list);
+
+#endif
diff --git a/core/elflink/setadv.c b/core/elflink/setadv.c
new file mode 100644
index 00000000..40f00a4e
--- /dev/null
+++ b/core/elflink/setadv.c
@@ -0,0 +1,116 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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/setadv.c
+ *
+ * (Over)write a data item in the auxilliary data vector. To
+ * delete an item, set its length to zero.
+ *
+ * Return 0 on success, -1 on error, and set errno.
+ *
+ * NOTE: Data is not written to disk unless
+ * syslinux_adv_write() is called.
+ */
+
+#include <syslinux/adv.h>
+#include <klibc/compiler.h>
+#include <inttypes.h>
+#include <string.h>
+#include <errno.h>
+#include <alloca.h>
+
+int syslinux_setadv(int tag, size_t size, const void *data)
+{
+ uint8_t *p, *advtmp;
+ size_t rleft, left;
+
+ if ((unsigned)tag - 1 > 254) {
+ errno = EINVAL;
+ return -1; /* Impossible tag value */
+ }
+
+ if (size > 255) {
+ errno = ENOSPC; /* Max 255 bytes for a data item */
+ return -1;
+ }
+
+ rleft = left = syslinux_adv_size();
+ p = advtmp = alloca(left);
+ memcpy(p, syslinux_adv_ptr(), left); /* Make working copy */
+
+ while (rleft >= 2) {
+ uint8_t ptag = p[0];
+ size_t plen = p[1] + 2;
+
+ if (ptag == ADV_END)
+ break;
+
+ if (ptag == tag) {
+ /* Found our tag. Delete it. */
+
+ if (plen >= rleft) {
+ /* Entire remainder is our tag */
+ break;
+ }
+ memmove(p, p + plen, rleft - plen);
+ rleft -= plen; /* Fewer bytes to read, but not to write */
+ } else {
+ /* Not our tag */
+ if (plen > rleft)
+ break; /* Corrupt tag (overrun) - overwrite it */
+
+ left -= plen;
+ rleft -= plen;
+ p += plen;
+ }
+ }
+
+ /* Now (p, left) reflects the position to write in and how much space
+ we have for our data. */
+
+ if (size) {
+ if (left < size + 2) {
+ errno = ENOSPC; /* Not enough space for data */
+ return -1;
+ }
+
+ *p++ = tag;
+ *p++ = size;
+ memcpy(p, data, size);
+ p += size;
+ left -= size + 2;
+ }
+
+ memset(p, 0, left);
+
+ /* If we got here, everything went OK, commit the write to low memory */
+ memcpy(syslinux_adv_ptr(), advtmp, syslinux_adv_size());
+
+ return 0;
+}
diff --git a/core/extern.inc b/core/extern.inc
index 64edea61..5cd56170 100644
--- a/core/extern.inc
+++ b/core/extern.inc
@@ -9,6 +9,28 @@
; rllpack.c
extern rllpack, rllunpack
+ ; hello.c
+ extern hello
+
+ ;abort.c
+ extern abort_load_new
+
+ ; elflink/load_env32.c
+ extern load_env32, enter_cmdline
+
+ ; memscan.c
+ extern highmem_init
+
+ extern linux_kernel
+
+ extern mp1, mp2, mp3, mp4, mp5
+
+ extern hexdump, mydump
+
+ extern printf_init
+
+ extern mem_init
+
; fs.c
extern fs_init, pm_searchdir, getfssec, getfsbytes
extern pm_mangle_name, load_config
diff --git a/core/fs/getcwd.c b/core/fs/getcwd.c
index a7b6c7a9..ee62411f 100644
--- a/core/fs/getcwd.c
+++ b/core/fs/getcwd.c
@@ -1,7 +1,7 @@
#include <string.h>
#include "fs.h"
-char *getcwd(char *buf, size_t size)
+char *core_getcwd(char *buf, size_t size)
{
char *ret = NULL;
diff --git a/core/hello.c b/core/hello.c
new file mode 100644
index 00000000..45bdf57c
--- /dev/null
+++ b/core/hello.c
@@ -0,0 +1,89 @@
+#include <stddef.h>
+#include <com32.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "core.h"
+
+#include <console.h>
+
+static int console_init = 0;
+
+void myputchar(int c)
+{
+ static com32sys_t ireg;
+
+ if (c == '\n')
+ myputchar('\r');
+
+ ireg.eax.b[1] = 0x02;
+ ireg.edx.b[0] = c;
+ __intcall(0x21, &ireg, NULL);
+}
+
+void myputs(const char *str)
+{
+ while (*str)
+ myputchar(*str++);
+}
+
+void hello(void)
+{
+ static char hello_str[] = "Hello, World!";
+
+ printf("%s from (%s)\n", hello_str, __FILE__); /* testing */
+}
+
+void hexdump(void *buf, int bytelen, const char *str)
+{
+ unsigned int *p32, i;
+
+ if (str)
+ printf("Dump %s:\n", str);
+
+ p32 = (unsigned int *)buf;
+ for (i = 0; i < (bytelen / 4); i++){
+ printf(" 0x%08x ", p32[i]);
+ }
+ printf("\n\n");
+}
+
+static inline void myprint(int num)
+{
+ uint32_t i;
+
+ for (i = 0; i < 5; i ++)
+ printf("%d", num);
+ printf("\n");
+}
+
+void mp1(void)
+{
+ myprint(1);
+}
+
+void mp2(void)
+{
+ myprint(2);
+}
+
+void mp3(void)
+{
+ myprint(3);
+}
+
+void mp4(void)
+{
+ myprint(4);
+}
+
+void mp5(void)
+{
+ myprint(5);
+}
+
+void printf_init(void)
+{
+ openconsole(&dev_null_r, &dev_stdcon_w);
+}
+
diff --git a/core/include/core.h b/core/include/core.h
index 7db5dafe..799c337d 100644
--- a/core/include/core.h
+++ b/core/include/core.h
@@ -30,7 +30,6 @@ extern void __idle(void);
extern void reset_idle(void);
/* mem/malloc.c, mem/free.c, mem/init.c */
-extern void *malloc(size_t);
extern void *lmalloc(size_t);
extern void *pmapi_lmalloc(size_t);
extern void *zalloc(size_t);
diff --git a/core/include/fs.h b/core/include/fs.h
index da247a98..129ac1e6 100644
--- a/core/include/fs.h
+++ b/core/include/fs.h
@@ -203,7 +203,7 @@ struct dirent *readdir(DIR *dir);
int closedir(DIR *dir);
/* getcwd.c */
-char *getcwd(char *buf, size_t size);
+char *core_getcwd(char *buf, size_t size);
/*
* Generic functions that filesystem drivers may choose to use
diff --git a/core/init.inc b/core/init.inc
index e06ca96f..cce4327c 100644
--- a/core/init.inc
+++ b/core/init.inc
@@ -47,6 +47,14 @@ common_init:
; Now set up screen parameters
;
call adjust_screen
+ pm_call printf_init
+
+;
+; Inite the memmory subsystem
+;
+ pm_call mem_init
+ mov eax,[HighMemSize]
+ mov [VKernelEnd],eax
;
; CPU-dependent initialization and related checks.
diff --git a/core/mem/free.c b/core/mem/free.c
index 0becb9e8..9d853a4b 100644
--- a/core/mem/free.c
+++ b/core/mem/free.c
@@ -8,12 +8,14 @@
#include <dprintf.h>
#include "malloc.h"
+#include <stdio.h>
+
static struct free_arena_header *
__free_block(struct free_arena_header *ah)
{
struct free_arena_header *pah, *nah;
struct free_arena_header *head =
- &__malloc_head[ARENA_HEAP_GET(ah->a.attrs)];
+ &__core_malloc_head[ARENA_HEAP_GET(ah->a.attrs)];
pah = ah->a.prev;
nah = ah->a.next;
@@ -93,12 +95,13 @@ void free(void *ptr)
void __inject_free_block(struct free_arena_header *ah)
{
struct free_arena_header *head =
- &__malloc_head[ARENA_HEAP_GET(ah->a.attrs)];
+ &__core_malloc_head[ARENA_HEAP_GET(ah->a.attrs)];
struct free_arena_header *nah;
size_t a_end = (size_t) ah + ARENA_SIZE_GET(ah->a.attrs);
size_t n_end;
- dprintf("inject: %#zx bytes @ %p, heap %u (%p)\n",
+ //dprintf("inject: %#zx bytes @ %p, heap %u (%p)\n",
+ printf("inject: %#zx bytes @%p, heap%u (%p)\n",
ARENA_SIZE_GET(ah->a.attrs), ah,
ARENA_HEAP_GET(ah->a.attrs), head);
@@ -113,6 +116,8 @@ void __inject_free_block(struct free_arena_header *ah)
if ((size_t) ah >= n_end)
continue;
+ printf("conflict:ah: %p, a_end: %p, nah: %p, n_end: %p\n", ah, a_end, nah, n_end);
+
/* Otherwise we have some sort of overlap - reject this block */
return;
}
@@ -135,7 +140,7 @@ static void __free_tagged(malloc_tag_t tag) {
for (i = 0; i < NHEAP; i++) {
dprintf("__free_tagged(%u) heap %d\n", tag, i);
- head = &__malloc_head[i];
+ head = &__core_malloc_head[i];
for (fp = head ; fp != head ; fp = fp->a.next) {
if (ARENA_TYPE_GET(fp->a.attrs) == ARENA_TYPE_USED &&
fp->a.tag == tag)
diff --git a/core/mem/init.c b/core/mem/init.c
index 487bbb3f..bfc64301 100644
--- a/core/mem/init.c
+++ b/core/mem/init.c
@@ -3,36 +3,95 @@
#include <string.h>
#include "malloc.h"
-struct free_arena_header __malloc_head[NHEAP];
+#include <stdio.h>
+#include <syslinux/memscan.h>
-static __hugebss char main_heap[128 << 10];
+struct free_arena_header __core_malloc_head[NHEAP];
+
+//static __hugebss char main_heap[128 << 10];
extern char __lowmem_heap[];
+extern char free_high_memory[];
+
+#define E820_MEM_MAX 0xfff00000 /* 4 GB - 1 MB */
+int scan_highmem_area(void *data, addr_t start, addr_t len, bool is_ram)
+{
+ struct free_arena_header *fp;
+ addr_t end;
+
+ mp("start = %x, len = %x, is_ram = %d", start, len, is_ram);
+
+ if (start < 0x100000 || start > E820_MEM_MAX
+ || !is_ram)
+ return 0;
+
+ if (start < __com32.cs_memsize) {
+ len -= __com32.cs_memsize - start;
+ start = __com32.cs_memsize;
+ }
+ if (len > E820_MEM_MAX - start)
+ len = E820_MEM_MAX - start;
+ end = start + len;
+
+ if (len >= 2 * sizeof(struct arena_header)) {
+ fp = (struct free_arena_header *)start;
+ fp->a.attrs = ARENA_TYPE_USED | (HEAP_MAIN << ARENA_HEAP_POS);
+ ARENA_SIZE_SET(fp->a.attrs, len);
+ mp("will inject a block start:0x%x size 0x%x", start, len);
+ __inject_free_block(fp);
+ }
+
+ __com32.cs_memsize = start + len; /* update the HighMemSize */
+ return 0;
+}
+
+static void mpool_dump(enum heap heap)
+{
+ struct free_arena_header *head = &__core_malloc_head[heap];
+ struct free_arena_header *fp;
+ void *p = NULL;
+ int size, type, i = 0;
+ addr_t start, end;
+
+ fp = head->next_free;
+ while (fp != head) {
+ size = ARENA_SIZE_GET(fp->a.attrs);
+ type = ARENA_TYPE_GET(fp->a.attrs);
+ start = (addr_t)fp;
+ end = start + size;
+ printf("area[%d]: start = 0x%08x, end = 0x%08x, type = %d\n",
+ i++, start, end, type);
+ fp = fp->next_free;
+ }
+}
void mem_init(void)
{
- struct free_arena_header *fp;
- int i;
- uint16_t *bios_free_mem = (uint16_t *)0x413;
+ struct free_arena_header *fp;
+ int i;
+ uint16_t *bios_free_mem = (uint16_t *)0x413;
- /* Initialize the head nodes */
+ //mp("enter");
- fp = &__malloc_head[0];
- for (i = 0 ; i < NHEAP ; i++) {
+ /* Initialize the head nodes */
+ fp = &__core_malloc_head[0];
+ for (i = 0 ; i < NHEAP ; i++) {
fp->a.next = fp->a.prev = fp->next_free = fp->prev_free = fp;
fp->a.attrs = ARENA_TYPE_HEAD | (i << ARENA_HEAP_POS);
fp->a.tag = MALLOC_HEAD;
fp++;
- }
-
- /* Initialize the main heap */
- fp = (struct free_arena_header *)main_heap;
- fp->a.attrs = ARENA_TYPE_USED | (HEAP_MAIN << ARENA_HEAP_POS);
- ARENA_SIZE_SET(fp->a.attrs, sizeof main_heap);
- __inject_free_block(fp);
-
- /* Initialize the lowmem heap */
- fp = (struct free_arena_header *)__lowmem_heap;
- fp->a.attrs = ARENA_TYPE_USED | (HEAP_LOWMEM << ARENA_HEAP_POS);
- ARENA_SIZE_SET(fp->a.attrs, (*bios_free_mem << 10) - (uintptr_t)fp);
- __inject_free_block(fp);
+ }
+
+ //mp("__lowmem_heap = 0x%p bios_free = 0x%p",
+ // __lowmem_heap, *bios_free_mem);
+
+ /* Initialize the lowmem heap */
+ fp = (struct free_arena_header *)__lowmem_heap;
+ fp->a.attrs = ARENA_TYPE_USED | (HEAP_LOWMEM << ARENA_HEAP_POS);
+ ARENA_SIZE_SET(fp->a.attrs, (*bios_free_mem << 10) - (uintptr_t)fp);
+ __inject_free_block(fp);
+
+ /* Initialize the main heap */
+ __com32.cs_memsize = free_high_memory;
+ syslinux_scan_memory(scan_highmem_area, NULL);
+
}
diff --git a/core/mem/malloc.c b/core/mem/malloc.c
index 78f7b41a..d27fc270 100644
--- a/core/mem/malloc.c
+++ b/core/mem/malloc.c
@@ -4,10 +4,13 @@
* Very simple linked-list based malloc()/free().
*/
+#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <dprintf.h>
+#include <minmax.h>
+
#include "malloc.h"
static void *__malloc_from_block(struct free_arena_header *fp,
@@ -60,11 +63,11 @@ static void *__malloc_from_block(struct free_arena_header *fp,
static void *_malloc(size_t size, enum heap heap, malloc_tag_t tag)
{
struct free_arena_header *fp;
- struct free_arena_header *head = &__malloc_head[heap];
+ struct free_arena_header *head = &__core_malloc_head[heap];
void *p = NULL;
dprintf("_malloc(%zu, %u, %u) @ %p = ",
- size, heap, tag, __builtin_return_address(0));
+ size, heap, tag, __builtin_return_address(0));
if (size) {
/* Add the obligatory arena header, and round up */
@@ -97,3 +100,115 @@ void *pmapi_lmalloc(size_t size)
{
return _malloc(size, HEAP_LOWMEM, MALLOC_MODULE);
}
+
+void *realloc(void *ptr, size_t size)
+{
+ struct free_arena_header *ah, *nah;
+ struct free_arena_header *head;
+
+ 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);
+
+ head = &__core_malloc_head[ARENA_HEAP_GET(ah->a.attrs)];
+
+ /* Actual size of the old block */
+ //oldsize = ah->a.size;
+ oldsize = ARENA_SIZE_GET(ah->a.attrs);
+
+ /* 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 + ARENA_SIZE_GET(ah->a.attrs) &&
+ ARENA_TYPE_GET(nah->a.attrs) == ARENA_TYPE_FREE &&
+ ARENA_SIZE_GET(nah->a.attrs) + oldsize >= newsize) {
+ //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;
+ ARENA_SIZE_SET(ah->a.attrs, ARENA_SIZE_GET(nah->a.attrs));
+ xsize = ARENA_SIZE_GET(ah->a.attrs);
+ //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);
+ ARENA_TYPE_SET(nah->a.attrs, ARENA_TYPE_FREE);
+ ARENA_SIZE_SET(nah->a.attrs, xsize - newsize);
+ ARENA_SIZE_SET(ah->a.attrs, 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 = head->prev_free;
+ nah->next_free = head;
+ head->prev_free = nah;
+ nah->prev_free->next_free = nah;
+ } else {
+ nah->next_free = head->next_free;
+ nah->prev_free = head;
+ 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;
+ }
+ }
+}
+
+void *zalloc(size_t size)
+{
+ void *ptr;
+
+ ptr = malloc(size);
+ if (ptr)
+ memset(ptr, 0, size);
+
+ return ptr;
+}
diff --git a/core/mem/malloc.h b/core/mem/malloc.h
index b8ec44d7..3291cc25 100644
--- a/core/mem/malloc.h
+++ b/core/mem/malloc.h
@@ -20,6 +20,18 @@ enum malloc_owner {
MALLOC_MODULE,
};
+enum arena_type {
+ ARENA_TYPE_USED = 0,
+ ARENA_TYPE_FREE = 1,
+ ARENA_TYPE_HEAD = 2,
+ ARENA_TYPE_DEAD = 3,
+};
+enum heap {
+ HEAP_MAIN,
+ HEAP_LOWMEM,
+ NHEAP
+};
+
struct free_arena_header;
/*
@@ -34,16 +46,14 @@ struct arena_header {
struct free_arena_header *next, *prev;
};
-enum arena_type {
- ARENA_TYPE_USED = 0,
- ARENA_TYPE_FREE = 1,
- ARENA_TYPE_HEAD = 2,
- ARENA_TYPE_DEAD = 3,
-};
-enum heap {
- HEAP_MAIN,
- HEAP_LOWMEM,
- NHEAP
+/*
+ * This structure should be no more than twice the size of the
+ * previous structure.
+ */
+struct free_arena_header {
+ struct arena_header a;
+ struct free_arena_header *next_free, *prev_free;
+ size_t _pad[2]; /* Pad to 2*sizeof(struct arena_header) */
};
#define ARENA_SIZE_MASK (~(uintptr_t)(sizeof(struct arena_header)-1))
@@ -68,15 +78,5 @@ enum heap {
((attrs) = ((attrs) & ~ARENA_TYPE_MASK) | \
((type) & ARENA_TYPE_MASK))
-/*
- * This structure should be no more than twice the size of the
- * previous structure.
- */
-struct free_arena_header {
- struct arena_header a;
- struct free_arena_header *next_free, *prev_free;
- size_t _pad[2]; /* Pad to 2*sizeof(struct arena_header) */
-};
-
-extern struct free_arena_header __malloc_head[NHEAP];
+extern struct free_arena_header __core_malloc_head[NHEAP];
void __inject_free_block(struct free_arena_header *ah);
diff --git a/core/pmapi.c b/core/pmapi.c
index 4b1ccbb1..932c632b 100644
--- a/core/pmapi.c
+++ b/core/pmapi.c
@@ -36,7 +36,7 @@ const struct com32_pmapi pm_api_vector =
.reset_idle = reset_idle,
.chdir = chdir,
- .getcwd = getcwd,
+ .getcwd = core_getcwd,
.jiffies = &__jiffies,
.ms_timer = &__ms_timer,
diff --git a/core/printf.c b/core/printf.c
deleted file mode 100644
index b1b0466b..00000000
--- a/core/printf.c
+++ /dev/null
@@ -1,20 +0,0 @@
-#include <stdio.h>
-#include <unistd.h>
-
-#include "core.h"
-
-int printf(const char *format, ...)
-{
- char buf[1024];
- va_list ap;
- int rv;
-
- va_start(ap, format);
- rv = vsnprintf(buf, sizeof buf, format, ap);
- va_end(ap);
-
- myputs(buf);
-
- return rv;
-
-}
diff --git a/core/syslinux.ld b/core/syslinux.ld
index 164c94cc..466b450e 100644
--- a/core/syslinux.ld
+++ b/core/syslinux.ld
@@ -20,6 +20,8 @@ OUTPUT_ARCH(i386)
EXTERN(_start)
ENTRY(_start)
+STACK32_LEN = 65536;
+
SECTIONS
{
/* Prefix structure for the compression program */
@@ -296,6 +298,39 @@ SECTIONS
. = ALIGN(4);
+ __dynsym_vma = .;
+ __dynsym_lma = __dynsym_vma + __text_lma - __text_vma;
+ .dynsym : AT(__dynsym_lma) {
+ __dynsym_start = .;
+ *(.dynsym)
+ __dynsym_end = .;
+ }
+ __dynsym_len = __dynsym_end - __dynsym_start;
+
+ . = ALIGN(4);
+
+ __dynstr_vma = .;
+ __dynstr_lma = __dynstr_vma + __text_lma - __text_vma;
+ .dynstr : AT(__dynstr_lma) {
+ __dynstr_start = .;
+ *(.dynstr)
+ __dynstr_end = .;
+ }
+ __dynstr_len = __dynstr_end - __dynstr_start;
+
+ . = ALIGN(4);
+
+ __gnu_hash_vma = .;
+ __gnu_hash_lma = __gnu_hash_vma + __text_lma - __text_vma;
+ .gnu.hash : AT(__gnu_hash_lma) {
+ __gnu_hash_start = .;
+ *(.gnu.hash)
+ __gnu_hash_end = .;
+ }
+
+
+ . = ALIGN(4);
+
__dynlink_vma = .;
__dynlink_lma = __dynlink_vma + __text_lma - __text_vma;
.dynlink : AT(__dynlink_lma) {
@@ -315,6 +350,18 @@ SECTIONS
__got_end = .;
}
+ . = ALIGN(4);
+
+ __dynamic_vma = .;
+ __dynamic_lma = __dynamic_vma + __text_lma - __text_vma;
+ .dynamic : AT(__dynamic_lma) {
+ __dynamic_start = .;
+ *(.dynamic)
+ __dynamic_end = .;
+ }
+
+ . = ALIGN(16);
+
__data_vma = .;
__data_lma = __data_vma + __text_lma - __text_vma;
.data : AT(__data_lma) {
diff --git a/core/ui.inc b/core/ui.inc
index 2d44447d..40224134 100644
--- a/core/ui.inc
+++ b/core/ui.inc
@@ -14,6 +14,18 @@
;
; This file should be entered with the config file open (for getc)
;
+%if 1
+on_error:
+no_config_file:
+enter_command:
+auto_boot:
+load_kernel:
+kernel_good_saved:
+kernel_corrupt:
+ pm_call hello
+ pm_call enter_cmdline ; Never return
+
+%else ; comment off the original ui.inc
load_config_file:
call parse_config ; Parse configuration file
no_config_file:
@@ -585,10 +597,6 @@ getchar_timeout:
;
; Anything else is assumed to be a Linux kernel.
;
- section .bss16
- alignb 4
-Kernel_EAX resd 1
-Kernel_SI resw 1
section .text16
kernel_good_saved:
@@ -689,6 +697,14 @@ is_bss_sector equ is_bad_image
is_disk_image equ is_bad_image
%endif
+%endif ; start of replacing ui.inc
+
+ section .bss16
+ alignb 4
+Kernel_EAX resd 1
+Kernel_SI resw 1
+
+
section .data16
boot_prompt db 'boot: ', 0
wipe_char db BS, ' ', BS, 0
@@ -697,6 +713,7 @@ err_notfound db 'Could not find kernel image: ',0
err_notkernel db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0
+%if 0
alignz 2
kerneltype_table:
dw is_unknown_filetype ; VK_KERNEL
@@ -708,8 +725,10 @@ kerneltype_table:
dw is_comboot_image ; VK_COMBOOT
dw is_com32_image ; VK_COM32
dw is_config_file ; VK_CONFIG
+%endif
section .bss16
+ global CmdOptPtr
alignb 4
ThisKbdTo resd 1 ; Temporary holder for KbdTimeout
ThisTotalTo resd 1 ; Temporary holder for TotalTimeout
diff --git a/elf_gen_dep.sh b/elf_gen_dep.sh
new file mode 100644
index 00000000..306034a1
--- /dev/null
+++ b/elf_gen_dep.sh
@@ -0,0 +1,111 @@
+#!/bin/sh
+
+#######################################################
+# Round 1: get all the loacl and external symbols
+#######################################################
+
+for i in com32/elflink/modules/*.c32 core/isolinux.elf core/pxelinux.elf
+do
+ # module=$(echo $i | sed "s/^\(.*\).o$/\1/")
+
+ # remove the path infomation
+ module=$(echo $i | sed "s/^.*\/\(.*\)$/\1/")
+
+ readelf -s $i > temp.txt
+ #Get the last 2 items of each line
+ cut -c47- temp.txt > $module.txt
+ rm temp.txt
+
+ #Get the unresolved symbols
+ sed -n -e "/UND $/d" -e "/_GLOBAL_OFFSET_TABLE_/d" -e "s/^.UND.\(.*\)$/\1/p" $module.txt > $module.ext
+
+ #Get the local symbols
+ sed -n -e "/UND/d" -e "/ABS/d" -e "/...[0-9] $/d" -e "/...[0-9] \./d" -e "/...[0-9]/p" $module.txt > $module.int
+ sed -i -e "s/^.....//g" $module.int
+ sed -i -e "s/^\(.*\)$/\1 <$module>/g" $module.int
+
+ cat $module.int >> all.txt
+done
+
+
+touch modules.dep
+
+#######################################################
+# Round 2: get all the loacl and external symbols
+#######################################################
+
+# Consolidate the dependent modules to one line and remove
+# the redundant ones, and the "core"
+rm_cr ()
+{
+ touch rmcr.tmp
+ all_dep=$module:
+ space=' '
+
+ while read line
+ do
+ # skip the module which is alreay on the list
+ grep $line rmcr.tmp > /dev/null && continue
+
+ # grep extlinux/isolinux and remove them
+ echo $line | grep extlinux > /dev/null && continue
+ echo $line | grep isolinux > /dev/null && continue
+ echo $line | grep pxelinux > /dev/null && continue
+
+ all_dep=$all_dep$space$line
+ echo $all_dep > rmcr.tmp
+ done
+
+ echo $all_dep >> modules.dep
+ rm rmcr.tmp
+}
+
+# Find the symbol belongs to which module by screening all.txt, do it
+# one by one, and the result "resolve.tmp" will be a file like:
+# a.c32
+# b.c32
+# c.c32
+resolve_sym ()
+{
+ touch resolve.tmp
+
+ while read symbol
+ do
+ #echo $symbol
+ sed -n -e "s/^$symbol <\(.*\)>/\1/p" all.txt >> resolve.tmp
+ #grep $symbol all.txt
+ done
+
+ rm_cr < resolve.tmp
+ rm resolve.tmp
+}
+
+#only test name start with a/b
+#rm [c-z]*.ext
+
+if [ -e modules.dep ]
+then
+ rm modules.dep
+ touch modules.dep
+fi
+
+# Don't need to resolve the core symbols
+for i in extlinux isolinux pxelinux
+do
+ if [ -e $i.elf.ext ]
+ then
+ rm $i.elf.ext
+ fi
+done
+
+for i in *.ext
+do
+ module=$(echo $i | sed "s/^\(.*\).ext$/\1/")
+ resolve_sym < $i
+done
+
+# Do some cleanup
+rm *.txt
+rm *.ext
+rm *.int
+echo ELF modules dependency is bult up, pls check modules.dep!
diff --git a/libinstaller/syslxmod.c b/libinstaller/syslxmod.c
index a68f19fb..b4d78365 100644
--- a/libinstaller/syslxmod.c
+++ b/libinstaller/syslxmod.c
@@ -146,11 +146,13 @@ int syslinux_patch(const sector_t *sectp, int nsectors,
ex = ptr(boot_image, &epa->secptroffset);
nptrs = get_16_sl(&epa->secptrcnt);
+#if 0
if (nsect > nptrs) {
/* Not necessarily an error in this case, but a general problem */
fprintf(stderr, "Insufficient extent space, build error!\n");
exit(1);
}
+#endif
/* -1 for the pointer in the boot sector, -2 for the two ADVs */
generate_extents(ex, nptrs, sectp, nsect-1-2);
diff --git a/lzo/prepcore.c b/lzo/prepcore.c
index 1d400670..9147b2e4 100644
--- a/lzo/prepcore.c
+++ b/lzo/prepcore.c
@@ -340,10 +340,12 @@ int main(int argc, char *argv[])
set_32((uint32_t *) (infile + soff + 4), csum);
}
+ /*
if (offset+outfile_len > get_32(&prefix->pfx_maxlma))
error("output too big (%lu, max %lu)",
(unsigned long)offset+outfile_len,
(unsigned long)get_32(&prefix->pfx_maxlma));
+ */
f = fopen(out_name, "wb");
if (!f)