[syslinux] [GIT PULL] elflink fixes

Matt Fleming matt at console-pimps.org
Tue Aug 14 05:18:03 PDT 2012


Hi Peter,

The main part of this pull request includes commits that try to replace
as many __intcall() invocations as possible. Some remain, but not many
(and eventually they'll be gone too). There's also a patch to make
better use of ld's --as-needed option and various other bug
fixes/cleanups.

The following changes since commit ff7334a2ce536b7f4b1f6d6f93ff4e285a3bd45a:

  Only compile dprintf/vdprintf if DEBUG_PORT is defined (2012-07-19 08:42:32 -0700)

are available in the git repository at:
  git://git.zytor.com/users/mfleming/syslinux.git elflink

Matt Fleming (9):
      core/elflink: Delete ADV code that's already in ldlinux
      ldlinux: Stop using the internal KT_* image types
      lib/sys/module: Add support for weak symbols
      elflink: Replace __intcall() with direct function calls
      Use pxe_call() instead of COMBOOT API
      com32: Use --as-needed for LDFLAGS
      ldlinux: Return to command prompt after loading COM32
      rawcon_read: Fix reading high part of input keys
      ldlinux: Use findpath() to lookup filenames

 com32/chain/utility.c                 |   30 ++-------
 com32/cmenu/Makefile                  |    8 +-
 com32/cmenu/libmenu/syslnx.c          |   22 +++----
 com32/elflink/ldlinux/chainboot.c     |    5 +-
 com32/elflink/ldlinux/config.h        |    2 +
 com32/elflink/ldlinux/execute.c       |   62 ++++++++++-------
 com32/elflink/ldlinux/ldlinux.c       |  113 ++++++++++++++++----------------
 com32/elflink/ldlinux/readconfig.c    |   16 +++++
 com32/include/menu.h                  |    7 --
 com32/include/sys/module.h            |   10 +++
 com32/include/syslinux/boot.h         |   10 +++
 com32/include/syslinux/config.h       |    5 ++
 com32/include/syslinux/features.h     |   10 +--
 com32/include/syslinux/pxe_api.h      |    4 +
 com32/lib/Makefile                    |    1 -
 com32/lib/sys/ansicon_write.c         |    4 +-
 com32/lib/sys/gpxe.c                  |   14 +---
 com32/lib/sys/module/common.c         |   36 ++++++++++-
 com32/lib/sys/module/elf_module.c     |   15 ++++-
 com32/lib/sys/rawcon_read.c           |   25 +++++---
 com32/lib/sys/rawcon_write.c          |    8 +--
 com32/lib/sys/serial_write.c          |    8 +--
 com32/lib/sys/stdcon_write.c          |   15 ++---
 com32/lib/sys/xserial_write.c         |    8 +--
 com32/lib/syslinux/cleanup.c          |   12 ++--
 com32/lib/syslinux/features.c         |   51 --------------
 com32/lib/syslinux/ipappend.c         |   20 ++----
 com32/lib/syslinux/keyboard.c         |   14 +---
 com32/lib/syslinux/pxe_dns.c          |   14 +---
 com32/lib/syslinux/pxe_get_cached.c   |   11 +---
 com32/lib/syslinux/pxe_get_nic.c      |   12 +---
 com32/lib/syslinux/run_command.c      |    9 +--
 com32/lib/syslinux/run_default.c      |   10 +--
 com32/lib/syslinux/runimage.c         |   19 ++---
 com32/lib/syslinux/serial.c           |   19 +++--
 com32/lib/syslinux/shuffle.c          |    9 +--
 com32/lib/syslinux/version.c          |   21 ++++---
 com32/lib/syslinux/video/fontquery.c  |   16 ++---
 com32/lib/syslinux/video/reportmode.c |   11 +--
 com32/libupload/upload_tftp.c         |   18 +----
 com32/menu/menumain.c                 |    6 +-
 com32/menu/readconfig.c               |    2 +-
 com32/modules/Makefile                |   18 +----
 com32/modules/gpxecmd.c               |   11 +---
 com32/modules/pxechn.c                |   16 +----
 com32/modules/sanboot.c               |   11 +---
 com32/rosh/Makefile                   |    4 +-
 com32/samples/Makefile                |    5 +-
 com32/samples/resolv.c                |   17 +----
 core/comboot.inc                      |    1 +
 core/console.c                        |    7 +--
 core/diskfs.inc                       |    2 +-
 core/elflink/advwrite.c               |   45 -------------
 core/elflink/load_env32.c             |   19 +-----
 core/elflink/setadv.c                 |  116 ---------------------------------
 core/font.c                           |    4 +-
 core/fs/pxe/pxe.c                     |    7 +--
 core/fs/pxe/pxe.h                     |    2 -
 core/hello.c                          |    6 +--
 core/include/bios.h                   |    1 -
 core/include/core.h                   |   16 +++++
 core/include/graphics.h               |    5 ++
 core/isolinux.asm                     |    2 +-
 mk/elf.mk                             |    2 +-
 64 files changed, 375 insertions(+), 654 deletions(-)
 delete mode 100644 com32/lib/syslinux/features.c
 delete mode 100644 core/elflink/advwrite.c
 delete mode 100644 core/elflink/setadv.c

diff --git a/com32/chain/utility.c b/com32/chain/utility.c
index b54e0cd..cb88272 100644
--- a/com32/chain/utility.c
+++ b/com32/chain/utility.c
@@ -4,7 +4,9 @@
 #include <errno.h>
 #include <unistd.h>
 #include <string.h>
+#include <fs.h>
 #include <syslinux/disk.h>
+#include <syslinux/pmapi.h>
 #include "utility.h"
 
 static const char *bpbtypes[] = {
@@ -93,14 +95,11 @@ void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, uint32_t m
 
 uint32_t get_file_lba(const char *filename)
 {
-    com32sys_t inregs;
+    struct com32_filedata fd;
     uint32_t lba = 0;
     int size = 65536;
     char *buf;
 
-    /* Start with clean registers */
-    memset(&inregs, 0, sizeof(com32sys_t));
-
     buf = lmalloc(size);
     if (!buf)
 	return 0;
@@ -108,32 +107,15 @@ uint32_t get_file_lba(const char *filename)
     /* Put the filename in the bounce buffer */
     strlcpy(buf, filename, size);
 
-    /* Call comapi_open() which returns a structure pointer in SI
-     * to a structure whose first member happens to be the LBA.
-     */
-    inregs.eax.w[0] = 0x0006;
-    inregs.esi.w[0] = OFFS(buf);
-    inregs.es = SEG(buf);
-    __com32.cs_intcall(0x22, &inregs, &inregs);
-
-    if ((inregs.eflags.l & EFLAGS_CF) || inregs.esi.w[0] == 0) {
+    if (open_file(buf, &fd) <= 0) {
 	goto fail;		/* Filename not found */
     }
 
     /* Since the first member is the LBA, we simply cast */
-    lba = *((uint32_t *) MK_PTR(inregs.ds, inregs.esi.w[0]));
-
-    /* Clean the registers for the next call */
-    memset(&inregs, 0, sizeof(com32sys_t));
-
-    /* Put the filename in the bounce buffer */
-    strlcpy(buf, filename, size);
+    lba = *((uint32_t *) MK_PTR(0, fd.handle));
 
     /* Call comapi_close() to free the structure */
-    inregs.eax.w[0] = 0x0008;
-    inregs.esi.w[0] = OFFS(buf);
-    inregs.es = SEG(buf);
-    __com32.cs_intcall(0x22, &inregs, &inregs);
+    close_file(fd.handle);
 
 fail:
     lfree(buf);
diff --git a/com32/cmenu/Makefile b/com32/cmenu/Makefile
index c6e0cae..beb8dd2 100644
--- a/com32/cmenu/Makefile
+++ b/com32/cmenu/Makefile
@@ -17,16 +17,16 @@
 
 NOGPL := 1
 
+LIBS  = libmenu/libmenu.c32 \
+        $(com32)/libutil/libutil_com.c32 \
+        $(com32)/lib/libcom32.c32
+
 topdir = ../..
 MAKEDIR = $(topdir)/mk
 include $(MAKEDIR)/elf.mk
 
 CFLAGS	  += -I./libmenu
 
-LIBS  = libmenu/libmenu.c32 \
-        $(com32)/libutil/libutil_com.c32 \
-        $(com32)/lib/libcom32.c32
-
 LIBMENU = libmenu/syslnx.o libmenu/com32io.o libmenu/tui.o \
 	libmenu/menu.o libmenu/passwords.o libmenu/des.o libmenu/help.o \
 	$(com32)/libutil/libutil_com.c32 $(com32)/lib/libcom32.c32
diff --git a/com32/cmenu/libmenu/syslnx.c b/com32/cmenu/libmenu/syslnx.c
index 27823df..c681f58 100644
--- a/com32/cmenu/libmenu/syslnx.c
+++ b/com32/cmenu/libmenu/syslnx.c
@@ -12,7 +12,10 @@
 
 #include <string.h>
 #include <com32.h>
+#include <core.h>
+#include <graphics.h>
 #include "syslnx.h"
+#include <syslinux/config.h>
 
 com32sys_t inreg, outreg;	// Global registers for this module
 
@@ -35,33 +38,26 @@ void runsyslinuxcmd(const char *cmd)
 	return;
 
     strcpy(bounce, cmd);
-    REG_AX(inreg) = 0x0003;	// Run command
-    REG_BX(inreg) = OFFS(bounce);
-    REG_ES(inreg) = SEG(bounce);
-    __intcall(0x22, &inreg, &outreg);
+    load_kernel(bounce);
 }
 
 void gototxtmode(void)
 {
-    REG_AX(inreg) = 0x0005;
-    __intcall(0x22, &inreg, &outreg);
+    syslinux_force_text_mode();
 }
 
 void syslinux_idle(void)
 {
-    REG_AX(inreg) = 0x0013;
-    __intcall(0x22, &inreg, &outreg);
+    __idle();
 }
 
 unsigned int getversion(char *deriv, unsigned int *numfun)
 {
-    REG_AX(inreg) = 0x0001;
-    __intcall(0x22, &inreg, &outreg);
     if (deriv)
-	*deriv = REG_DL(outreg);
+	*deriv = __syslinux_version.filesystem;
     if (numfun)
-	*numfun = REG_AX(outreg);
-    return REG_CX(outreg);
+	*numfun = __syslinux_version.max_api;
+    return __syslinux_version.version;
 }
 
 void runsyslinuximage(const char *cmd, long ipappend)
diff --git a/com32/elflink/ldlinux/chainboot.c b/com32/elflink/ldlinux/chainboot.c
index c1efadf..4a4a2e1 100644
--- a/com32/elflink/ldlinux/chainboot.c
+++ b/com32/elflink/ldlinux/chainboot.c
@@ -30,11 +30,12 @@
 #include "localboot.h"
 #include "bios.h"
 
+#include <syslinux/boot.h>
 #include <syslinux/bootrm.h>
 #include <syslinux/movebits.h>
 #include <syslinux/config.h>
 
-void chainboot_file(const char *file, enum kernel_type type)
+void chainboot_file(const char *file, uint32_t type)
 {
     uint8_t keeppxe = 0;
     const union syslinux_derivative_info *sdi;
@@ -97,7 +98,7 @@ void chainboot_file(const char *file, enum kernel_type type)
      * superblock.
      */
     if (sdi->c.filesystem == SYSLINUX_FS_SYSLINUX &&
-	type == KT_BSS && this_fs->fs_ops->copy_super(buf))
+	type == IMAGE_TYPE_BSS && this_fs->fs_ops->copy_super(buf))
 	goto bail;
 
     if (sdi->c.filesystem == SYSLINUX_FS_PXELINUX) {
diff --git a/com32/elflink/ldlinux/config.h b/com32/elflink/ldlinux/config.h
index 4583202..ea4736e 100644
--- a/com32/elflink/ldlinux/config.h
+++ b/com32/elflink/ldlinux/config.h
@@ -47,4 +47,6 @@ extern int new_linux_kernel(char *okernel, char *ocmdline);
 
 extern void pm_load_high(com32sys_t *regs);
 
+extern void ldlinux_enter_command(bool prompt);
+
 #endif /* __CONFIG_H__ */
diff --git a/com32/elflink/ldlinux/execute.c b/com32/elflink/ldlinux/execute.c
index 5d128cb..e7969c2 100644
--- a/com32/elflink/ldlinux/execute.c
+++ b/com32/elflink/ldlinux/execute.c
@@ -18,6 +18,7 @@
 #include <com32.h>
 #include <sys/exec.h>
 #include <sys/io.h>
+#include <sys/module.h>
 #include "core.h"
 #include "menu.h"
 #include "fs.h"
@@ -28,29 +29,28 @@
 #include <syslinux/bootrm.h>
 #include <syslinux/movebits.h>
 #include <syslinux/config.h>
-
-/* Must match enum kernel_type */
-const char *const kernel_types[] = {
-    "none",
-    "localboot",
-    "kernel",
-    "linux",
-    "boot",
-    "bss",
-    "pxe",
-    "fdimage",
-    "comboot",
-    "com32",
-    "config",
-    NULL
+#include <syslinux/boot.h>
+
+const struct image_types image_boot_types[] = {
+    { "localboot", IMAGE_TYPE_LOCALBOOT },
+    { "kernel", IMAGE_TYPE_KERNEL },
+    { "linux", IMAGE_TYPE_LINUX },
+    { "boot", IMAGE_TYPE_BOOT },
+    { "bss", IMAGE_TYPE_BSS },
+    { "pxe", IMAGE_TYPE_PXE },
+    { "fdimage", IMAGE_TYPE_FDIMAGE },
+    { "comboot", IMAGE_TYPE_COMBOOT },
+    { "com32", IMAGE_TYPE_COM32 },
+    { "config", IMAGE_TYPE_CONFIG },
+    { NULL, 0 },
 };
 
 extern int create_args_and_load(char *);
 
-void execute(const char *cmdline, enum kernel_type type)
+void execute(const char *cmdline, uint32_t type)
 {
-	const char *p, *const *pp;
 	const char *kernel, *args;
+	const char *p;
 	com32sys_t ireg;
 	char *q;
 
@@ -79,22 +79,31 @@ void execute(const char *cmdline, enum kernel_type type)
 
 	dprintf("kernel is %s, args = %s  type = %d \n", kernel, args, type);
 
-	if (kernel[0] == '.' && type == KT_NONE) {
+	if (kernel[0] == '.') {
 		/* It might be a type specifier */
-		enum kernel_type type = KT_NONE;
-		for (pp = kernel_types; *pp; pp++, type++) {
-			if (!strcmp(kernel + 1, *pp)) {
+		const struct image_types *t;
+		for (t = image_boot_types; t->name; t++) {
+			if (!strcmp(kernel + 1, t->name)) {
 				/* Strip the type specifier and retry */
-				execute(p, type);
+				execute(p, t->type);
 				return;
 			}
 		}
 	}
 
-	if (type == KT_COM32) {
+	if (type == IMAGE_TYPE_COM32) {
 		/* new entry for elf format c32 */
 		create_args_and_load((char *)cmdline);
-	} else if (type == KT_CONFIG) {
+
+		/*
+		 * The old COM32 module code would run the module then
+		 * drop the user back at the command prompt,
+		 * irrespective of how the COM32 module was loaded,
+		 * e.g. from vesamenu.c32.
+		 */
+		unload_modules_since("ldlinux.c32");
+		ldlinux_enter_command(!noescape);
+	} else if (type == IMAGE_TYPE_CONFIG) {
 		char *argv[] = { "ldlinux.c32", NULL };
 
 		/* kernel contains the config file name */
@@ -105,9 +114,10 @@ void execute(const char *cmdline, enum kernel_type type)
 			mangle_name(config_cwd, args);
 
 		start_ldlinux(argv);
-	} else if (type == KT_LOCALBOOT) {
+	} else if (type == IMAGE_TYPE_LOCALBOOT) {
 		local_boot(strtoul(kernel, NULL, 0));
-	} else if (type == KT_PXE || type == KT_BSS || type == KT_BOOT) {
+	} else if (type == IMAGE_TYPE_PXE || type == IMAGE_TYPE_BSS ||
+		   type == IMAGE_TYPE_BOOT) {
 		chainboot_file(kernel, type);
 	} else {
 		/* Need add one item for kernel load, as we don't use
diff --git a/com32/elflink/ldlinux/ldlinux.c b/com32/elflink/ldlinux/ldlinux.c
index f56f2c0..1c261cd 100644
--- a/com32/elflink/ldlinux/ldlinux.c
+++ b/com32/elflink/ldlinux/ldlinux.c
@@ -11,6 +11,7 @@
 #include "menu.h"
 #include "config.h"
 #include "syslinux/adv.h"
+#include "syslinux/boot.h"
 
 #include <sys/module.h>
 
@@ -20,15 +21,15 @@ struct file_ext {
 };
 
 static const struct file_ext file_extensions[] = {
-	{ ".com", KT_COMBOOT },
-	{ ".cbt", KT_COMBOOT },
-	{ ".c32", KT_COM32 },
-	{ ".img", KT_FDIMAGE },
-	{ ".bss", KT_BSS },
-	{ ".bin", KT_BOOT },
-	{ ".bs", KT_BOOT },
-	{ ".0", KT_PXE },
-	{ NULL, KT_NONE },
+	{ ".com", IMAGE_TYPE_COMBOOT },
+	{ ".cbt", IMAGE_TYPE_COMBOOT },
+	{ ".c32", IMAGE_TYPE_COM32 },
+	{ ".img", IMAGE_TYPE_FDIMAGE },
+	{ ".bss", IMAGE_TYPE_BSS },
+	{ ".bin", IMAGE_TYPE_BOOT },
+	{ ".bs", IMAGE_TYPE_BOOT },
+	{ ".0", IMAGE_TYPE_PXE },
+	{ NULL, 0 },
 };
 
 /*
@@ -45,7 +46,7 @@ static inline const char *find_command(const char *str)
 	return p;
 }
 
-enum kernel_type parse_kernel_type(const char *kernel)
+uint32_t parse_image_type(const char *kernel)
 {
 	const struct file_ext *ext;
 	const char *p;
@@ -62,8 +63,8 @@ enum kernel_type parse_kernel_type(const char *kernel)
 			return ext->type;
 	}
 
-	/* use KT_KERNEL as default */
-	return KT_KERNEL;
+	/* use IMAGE_TYPE_KERNEL as default */
+	return IMAGE_TYPE_KERNEL;
 }
 
 /*
@@ -82,19 +83,20 @@ static const char *get_extension(const char *kernel)
 	for (ext = file_extensions; ext->name; ext++) {
 		char *str;
 		int elen = strlen(ext->name);
-		int fd;
+		FILE *f;
 
 		str = malloc(len + elen + 1);
 
 		strncpy(str, kernel, len);
 		strncpy(str + len, ext->name, elen);
 		str[len + elen] = '\0';
-
-		fd = searchdir(str);
+		f = findpath(str);
 		free(str);
 
-		if (fd >= 0)
+		if (f) {
+			fclose(f);
 			return ext->name;
+		}
 	}
 
 	return NULL;
@@ -136,12 +138,12 @@ static const char *apply_extension(const char *kernel, const char *ext)
  * the the kernel. If we return the caller should call enter_cmdline()
  * so that the user can help us out.
  */
-static void load_kernel(const char *command_line)
+void load_kernel(const char *command_line)
 {
 	struct menu_entry *me;
-	enum kernel_type type;
 	const char *cmdline;
 	const char *kernel;
+	uint32_t type;
 
 	kernel = strdup(command_line);
 	if (!kernel)
@@ -150,11 +152,7 @@ static void load_kernel(const char *command_line)
 	/* Virtual kernel? */
 	me = find_label(kernel);
 	if (me) {
-		type = parse_kernel_type(me->cmdline);
-
-		/* cmdline contains type specifier */
-		if (me->cmdline[0] == '.')
-			type = KT_NONE;
+		type = parse_image_type(me->cmdline);
 
 		execute(me->cmdline, type);
 		/* We shouldn't return */
@@ -170,8 +168,8 @@ static void load_kernel(const char *command_line)
 		*p = '\0';
 	}
 
-	type = parse_kernel_type(kernel);
-	if (type == KT_KERNEL) {
+	type = parse_image_type(kernel);
+	if (type == IMAGE_TYPE_KERNEL) {
 		const char *ext;
 
 		/*
@@ -189,7 +187,7 @@ static void load_kernel(const char *command_line)
 			free((void *)kernel);
 			kernel = k;
 
-			type = parse_kernel_type(kernel);
+			type = parse_image_type(kernel);
 		}
 	}
 
@@ -204,7 +202,7 @@ bad_kernel:
 	 */
 	if (onerrorlen) {
 		rsprintf(&cmdline, "%s %s", onerror, default_cmd);
-		execute(cmdline, KT_COM32);
+		execute(cmdline, IMAGE_TYPE_COM32);
 	}
 }
 
@@ -225,6 +223,35 @@ static void enter_cmdline(void)
 	}
 }
 
+void ldlinux_enter_command(bool prompt)
+{
+	const char *cmdline = default_cmd;
+
+	if (prompt)
+		goto cmdline;
+auto_boot:
+	/*
+	 * Auto boot
+	 */
+	if (defaultlevel || noescape) {
+		if (defaultlevel) {
+			load_kernel(cmdline); /* Shouldn't return */
+		} else {
+			printf("No DEFAULT or UI configuration directive found!\n");
+
+			if (noescape)
+				kaboom();
+		}
+	}
+
+cmdline:
+	/* Only returns if the user pressed enter or input timed out */
+	enter_cmdline();
+
+	cmdline = ontimeoutlen ? ontimeout : default_cmd;
+
+	goto auto_boot;
+}
 int main(int argc __unused, char **argv __unused)
 {
 	const void *adv;
@@ -252,7 +279,7 @@ int main(int argc __unused, char **argv __unused)
 		cmdline = dst = malloc(count + 1);
 		if (!dst) {
 			printf("Failed to allocate memory for ADV\n");
-			goto cmdline;
+			ldlinux_enter_command(true);
 		}
 
 		for (i = 0; i < count; i++)
@@ -264,37 +291,11 @@ int main(int argc __unused, char **argv __unused)
 			syslinux_adv_write();
 
 		load_kernel(cmdline); /* Shouldn't return */
-		goto cmdline;
+		ldlinux_enter_command(true);
 	}
 
 	/* TODO: Check KbdFlags? */
 
-	if (forceprompt)
-		goto cmdline;
-
-	cmdline = default_cmd;
-auto_boot:
-	/*
-	 * Auto boot
-	 */
-	if (defaultlevel || noescape) {
-		if (defaultlevel) {
-			load_kernel(cmdline); /* Shouldn't return */
-		} else {
-			printf("No DEFAULT or UI configuration directive found!\n");
-
-			if (noescape)
-				kaboom();
-		}
-	}
-
-cmdline:
-	/* Only returns if the user pressed enter or input timed out */
-	enter_cmdline();
-
-	cmdline = ontimeoutlen ? ontimeout : default_cmd;
-
-	goto auto_boot;
-
+	ldlinux_enter_command(forceprompt);
 	return 0;
 }
diff --git a/com32/elflink/ldlinux/readconfig.c b/com32/elflink/ldlinux/readconfig.c
index 1a8434c..1db397a 100644
--- a/com32/elflink/ldlinux/readconfig.c
+++ b/com32/elflink/ldlinux/readconfig.c
@@ -52,6 +52,22 @@ const struct menu_parameter mparm[NPARAMS] = {
     [P_HIDDEN_ROW] = {"hiddenrow", -2},
 };
 
+/* Must match enum kernel_type */
+static const char *const kernel_types[] = {
+    "none",
+    "localboot",
+    "kernel",
+    "linux",
+    "boot",
+    "bss",
+    "pxe",
+    "fdimage",
+    "comboot",
+    "com32",
+    "config",
+    NULL
+};
+
 short uappendlen = 0;		//bytes in append= command
 short ontimeoutlen = 0;		//bytes in ontimeout command
 short onerrorlen = 0;		//bytes in onerror command
diff --git a/com32/include/menu.h b/com32/include/menu.h
index a3e9cd6..5a4c901 100644
--- a/com32/include/menu.h
+++ b/com32/include/menu.h
@@ -92,10 +92,6 @@ enum kernel_type {
     KT_CONFIG,			/* Configuration file */
 };
 
-extern const char *const kernel_types[];
-
-extern enum kernel_type parse_kernel_type(const char *kernel);
-
 /* Configurable integer parameters */
 enum parameter_number {
     P_WIDTH,
@@ -230,9 +226,6 @@ extern const int message_base_color;
 extern const char *current_background;
 void set_background(const char *new_background);
 
-/* execute.c */
-void execute(const char *cmdline, enum kernel_type type);
-
 /* drain.c */
 void drain_keyboard(void);
 
diff --git a/com32/include/sys/module.h b/com32/include/sys/module.h
index eabc9e0..ea11a88 100644
--- a/com32/include/sys/module.h
+++ b/com32/include/sys/module.h
@@ -138,6 +138,16 @@ struct module_dep {
 };
 
 
+/**
+ * Unload all modules that have been loaded since @name.
+ *
+ * Returns the struct elf_module * for @name or %NULL if no modules
+ * have been loaded since @name.
+ */
+extern struct elf_module *unload_modules_since(const char *name);
+
+extern FILE *findpath(char *name);
+
 
 #ifdef DYNAMIC_MODULE
 
diff --git a/com32/include/syslinux/boot.h b/com32/include/syslinux/boot.h
index 870cff3..aea32d9 100644
--- a/com32/include/syslinux/boot.h
+++ b/com32/include/syslinux/boot.h
@@ -48,6 +48,13 @@ void syslinux_chain_bootstrap(uint16_t flags, const void *bootstrap,
 			      uint32_t bootstrap_len, uint32_t edx,
 			      uint32_t esi, uint16_t ds);
 
+struct image_types {
+    const char *name;
+    uint32_t type;
+};
+
+extern const struct image_types image_boot_types[];
+
 #define IMAGE_TYPE_KERNEL	0
 #define IMAGE_TYPE_LINUX	1
 #define IMAGE_TYPE_BOOT		2
@@ -57,6 +64,9 @@ void syslinux_chain_bootstrap(uint16_t flags, const void *bootstrap,
 #define IMAGE_TYPE_COMBOOT	6
 #define IMAGE_TYPE_COM32	7
 #define IMAGE_TYPE_CONFIG	8
+#define IMAGE_TYPE_LOCALBOOT	9
+
+uint32_t parse_image_type(const char *cmdline);
 void syslinux_run_kernel_image(const char *filename, const char *cmdline,
 			       uint32_t ipappend_flags, uint32_t type);
 
diff --git a/com32/include/syslinux/config.h b/com32/include/syslinux/config.h
index 50bd52f..7bdcdd6 100644
--- a/com32/include/syslinux/config.h
+++ b/com32/include/syslinux/config.h
@@ -181,4 +181,9 @@ static inline const struct syslinux_ipappend_strings
     return &__syslinux_ipappend_strings;
 }
 
+static inline enum syslinux_filesystem syslinux_filesystem(void)
+{
+    return syslinux_derivative_info()->c.filesystem;
+}
+
 #endif /* _SYSLINUX_CONFIG_H */
diff --git a/com32/include/syslinux/features.h b/com32/include/syslinux/features.h
index 4bebda4..d25d08d 100644
--- a/com32/include/syslinux/features.h
+++ b/com32/include/syslinux/features.h
@@ -31,18 +31,16 @@
 #define SYSLINUX_FEATURE_LOCAL_BOOT	(0*8+0)
 #define SYSLINUX_FEATURE_NOOP_IDLE	(0*8+1)
 
-extern struct __syslinux_feature_flags {
-    unsigned int len;
-    const unsigned char *ptr;
-} __syslinux_feature_flags;
+extern uint8_t feature_flags;
+extern uint8_t feature_flags_len;
 
 static inline int syslinux_has_feature(unsigned int __flag)
 {
     unsigned int __byte = __flag >> 3;
     unsigned int __bit = __flag & 7;
 
-    if (__byte <= __syslinux_feature_flags.len)
-	return (__syslinux_feature_flags.ptr[__byte] >> __bit) & 1;
+    if (__byte <= feature_flags_len)
+	return (feature_flags[__byte] >> __bit) & 1;
     else
 	return 0;
 }
diff --git a/com32/include/syslinux/pxe_api.h b/com32/include/syslinux/pxe_api.h
index 27166b0..203ab38 100644
--- a/com32/include/syslinux/pxe_api.h
+++ b/com32/include/syslinux/pxe_api.h
@@ -568,4 +568,8 @@ typedef struct s_PXENV_UNLOAD_STACK {
 #define PXENV_STATUS_LOADER_UNDI_START			 0xca
 #define PXENV_STATUS_LOADER_BC_START			 0xcb
 
+int __weak pxe_call(int, void *);
+void __weak unload_pxe(uint16_t flags);
+uint32_t __weak dns_resolv(const char *);
+
 #endif /* _SYSLINUX_PXE_API_H */
diff --git a/com32/lib/Makefile b/com32/lib/Makefile
index b83ae6b..5d270a4 100644
--- a/com32/lib/Makefile
+++ b/com32/lib/Makefile
@@ -46,7 +46,6 @@ LIBPCI_OBJS = \
 
 LIBSYSLINUX_OBJS = \
 	syslinux/reboot.o syslinux/keyboard.o				\
-	syslinux/features.o 						\
 	syslinux/version.o						\
 	syslinux/pxe_get_cached.o syslinux/pxe_get_nic.o		\
 	syslinux/pxe_dns.o						\
diff --git a/com32/lib/sys/ansicon_write.c b/com32/lib/sys/ansicon_write.c
index b25f2d2..e5483fb 100644
--- a/com32/lib/sys/ansicon_write.c
+++ b/com32/lib/sys/ansicon_write.c
@@ -42,6 +42,7 @@
 #include <syslinux/config.h>
 #include "file.h"
 #include "ansi.h"
+#include "graphics.h"
 
 static void ansicon_erase(const struct term_state *, int, int, int, int);
 static void ansicon_write_char(int, int, uint8_t, const struct term_state *);
@@ -90,8 +91,7 @@ int __ansicon_open(struct file_info *fp)
 	    ti.cols = 80;
 	} else {
 	    /* Force text mode */
-	    ireg.eax.w[0] = 0x0005;
-	    __intcall(0x22, &ireg, NULL);
+	    syslinux_force_text_mode();
 
 	    /* Initial state */
 	    ti.rows = BIOS_ROWS ? BIOS_ROWS + 1 : 25;
diff --git a/com32/lib/sys/gpxe.c b/com32/lib/sys/gpxe.c
index 06c4510..3cc2b84 100644
--- a/com32/lib/sys/gpxe.c
+++ b/com32/lib/sys/gpxe.c
@@ -7,9 +7,9 @@
 bool is_gpxe(void)
 {
     const struct syslinux_version *sv;
-    com32sys_t reg;
     struct s_PXENV_FILE_CHECK_API *fca;
     bool gpxe;
+    int err;
 
     sv = syslinux_version();
     if (sv->filesystem != SYSLINUX_FS_PXELINUX)
@@ -22,20 +22,14 @@ bool is_gpxe(void)
     fca->Size = sizeof *fca;
     fca->Magic = 0x91d447b2;
 
-    memset(&reg, 0, sizeof reg);
-    reg.eax.w[0] = 0x0009;
-    reg.ebx.w[0] = PXENV_FILE_API_CHECK;
-    /* reg.edi.w[0] = OFFS(fca); */
-    reg.es = SEG(fca);
-
-    __intcall(0x22, &reg, &reg);
+    err = pxe_call(PXENV_FILE_API_CHECK, fca);
 
     gpxe = true;
 
-    if (reg.eflags.l & EFLAGS_CF)
+    if (err)
 	gpxe = false;           /* Cannot invoke PXE stack */
 
-    if (reg.eax.w[0] || fca->Status)
+    if (fca->Status)
         gpxe = false;           /* PXE failure */
 
     if (fca->Magic != 0xe9c17b20)
diff --git a/com32/lib/sys/module/common.c b/com32/lib/sys/module/common.c
index 19742e6..6e63907 100644
--- a/com32/lib/sys/module/common.c
+++ b/com32/lib/sys/module/common.c
@@ -57,7 +57,7 @@ void print_elf_symbols(struct elf_module *module) {
 }
 #endif //ELF_DEBUG
 
-static FILE *findpath(char *name)
+FILE *findpath(char *name)
 {
 	char path[FILENAME_MAX];
 	FILE *f;
@@ -321,7 +321,7 @@ int check_symbols(struct elf_module *module)
 		crt_name = module->str_table + crt_sym->st_name;
 
 		strong_count = 0;
-		weak_count = 0;
+		weak_count = (ELF32_ST_BIND(crt_sym->st_info) == STB_WEAK);
 
 		for_each_module(crt_module)
 		{
@@ -345,6 +345,14 @@ int check_symbols(struct elf_module *module)
 		if (crt_sym->st_shndx == SHN_UNDEF)
 		{
 			// We have an undefined symbol
+			//
+			// We use the weak_count to differentiate
+			// between Syslinux-derivative-specific
+			// functions. For example, unload_pxe() is
+			// only provided by PXELINUX, so we mark it as
+			// __weak and replace it with a reference to
+			// undefined_symbol() on SYSLINUX, EXTLINUX,
+			// and ISOLINUX. See perform_relocations().
 			if (strong_count == 0 && weak_count == 0)
 			{
 				DBG_PRINT("Symbol %s is undefined\n", crt_name);
@@ -414,6 +422,30 @@ int module_unload(struct elf_module *module) {
 	return _module_unload(module);
 }
 
+struct elf_module *unload_modules_since(const char *name) {
+	struct elf_module *m, *mod, *begin = NULL;
+
+	for_each_module(mod) {
+		if (!strcmp(mod->name, name)) {
+			begin = mod;
+			break;
+		}
+	}
+
+	if (!begin)
+		return begin;
+
+	for_each_module_safe(mod, m) {
+		if (mod == begin)
+			break;
+
+		if (mod != begin)
+			module_unload(mod);
+	}
+
+	return begin;
+}
+
 static Elf32_Sym *module_find_symbol_sysv(const char *name, struct elf_module *module) {
 	unsigned long h = elf_hash((const unsigned char*)name);
 	Elf32_Word *cr_word = module->hash_table;
diff --git a/com32/lib/sys/module/elf_module.c b/com32/lib/sys/module/elf_module.c
index dbb5afe..b220e1a 100644
--- a/com32/lib/sys/module/elf_module.c
+++ b/com32/lib/sys/module/elf_module.c
@@ -11,6 +11,7 @@
 #include <stdio.h>
 #include <elf.h>
 #include <dprintf.h>
+#include <core.h>
 
 #include <linux/list.h>
 #include <sys/module.h>
@@ -238,6 +239,11 @@ static int prepare_dynlinking(struct elf_module *module) {
 	return 0;
 }
 
+void undefined_symbol(void)
+{
+	printf("Error: An undefined symbol was referenced\n");
+	kaboom();
+}
 
 static int perform_relocation(struct elf_module *module, Elf32_Rel *rel) {
 	Elf32_Word *dest = module_get_absolute(rel->r_offset, module);
@@ -263,11 +269,16 @@ static int perform_relocation(struct elf_module *module, Elf32_Rel *rel) {
 					&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;
+			if (ELF32_ST_BIND(sym_ref->st_info) != STB_WEAK)
+				return -1;
+
+			// This must be a derivative-specific
+			// function. We're OK as long as we never
+			// execute the function.
+			sym_def = global_find_symbol("undefined_symbol", &sym_module);
 		}
 
 		// Compute the absolute symbol virtual address
diff --git a/com32/lib/sys/rawcon_read.c b/com32/lib/sys/rawcon_read.c
index fbcd936..51bb953 100644
--- a/com32/lib/sys/rawcon_read.c
+++ b/com32/lib/sys/rawcon_read.c
@@ -35,31 +35,38 @@
 #include <errno.h>
 #include <string.h>
 #include <com32.h>
+#include <core.h>
 #include <minmax.h>
 #include "file.h"
 
 /* Global, since it's used by stdcon_read */
 ssize_t __rawcon_read(struct file_info *fp, void *buf, size_t count)
 {
-    com32sys_t ireg, oreg;
     char *bufp = buf;
     size_t n = 0;
+    static char hi = 0;
+    static bool hi_key = false;
 
     (void)fp;
 
-    memset(&ireg, 0, sizeof ireg);
-
     while (n < count) {
+	if (hi_key) {
+	    *bufp++ = hi;
+	    n++;
+	    hi_key = false;
+	    continue;
+	}
+
 	/* Poll */
-	ireg.eax.b[1] = 0x0B;
-	__intcall(0x21, &ireg, &oreg);
-	if (!oreg.eax.b[0])
+	if (!pollchar())
 	    break;
 
 	/* We have data, go get it */
-	ireg.eax.b[1] = 0x08;
-	__intcall(0x21, &ireg, &oreg);
-	*bufp++ = oreg.eax.b[0];
+	*bufp = getchar(&hi);
+	if (!*bufp)
+		hi_key = true;
+
+	bufp++;
 	n++;
     }
 
diff --git a/com32/lib/sys/rawcon_write.c b/com32/lib/sys/rawcon_write.c
index 2d45a7b..1f7920b 100644
--- a/com32/lib/sys/rawcon_write.c
+++ b/com32/lib/sys/rawcon_write.c
@@ -34,24 +34,20 @@
 #include <errno.h>
 #include <string.h>
 #include <com32.h>
+#include <core.h>
 #include <minmax.h>
 #include "file.h"
 
 static ssize_t __rawcon_write(struct file_info *fp, const void *buf,
 			      size_t count)
 {
-    com32sys_t ireg;
     const char *bufp = buf;
     size_t n = 0;
 
     (void)fp;
 
-    memset(&ireg, 0, sizeof ireg);
-    ireg.eax.b[1] = 0x02;
-
     while (count--) {
-	ireg.edx.b[0] = *bufp++;
-	__intcall(0x21, &ireg, NULL);
+	writechr(*bufp++);
 	n++;
     }
 
diff --git a/com32/lib/sys/serial_write.c b/com32/lib/sys/serial_write.c
index fa0f4f4..3f949fb 100644
--- a/com32/lib/sys/serial_write.c
+++ b/com32/lib/sys/serial_write.c
@@ -34,13 +34,13 @@
 #include <errno.h>
 #include <string.h>
 #include <com32.h>
+#include <core.h>
 #include <minmax.h>
 #include <syslinux/config.h>
 #include "file.h"
 
 ssize_t __serial_write(struct file_info *fp, const void *buf, size_t count)
 {
-    com32sys_t ireg;
     const char *bufp = buf;
     size_t n = 0;
 
@@ -49,12 +49,8 @@ ssize_t __serial_write(struct file_info *fp, const void *buf, size_t count)
     if (!syslinux_serial_console_info()->iobase)
 	return count;		/* Nothing to do */
 
-    memset(&ireg, 0, sizeof ireg);
-    ireg.eax.b[1] = 0x04;
-
     while (count--) {
-	ireg.edx.b[0] = *bufp++;
-	__intcall(0x21, &ireg, NULL);
+	write_serial(*bufp++);
 	n++;
     }
 
diff --git a/com32/lib/sys/stdcon_write.c b/com32/lib/sys/stdcon_write.c
index 9cb2f7d..9bd225f 100644
--- a/com32/lib/sys/stdcon_write.c
+++ b/com32/lib/sys/stdcon_write.c
@@ -34,6 +34,7 @@
 #include <errno.h>
 #include <string.h>
 #include <com32.h>
+#include <core.h>
 #include <minmax.h>
 #include "file.h"
 
@@ -57,22 +58,16 @@ static int __stdcon_open(struct file_info *fp)
 static ssize_t __stdcon_write(struct file_info *fp, const void *buf,
 			      size_t count)
 {
-    com32sys_t ireg;
     const char *bufp = buf;
     size_t n = 0;
 
     (void)fp;
 
-    memset(&ireg, 0, sizeof ireg);
-    ireg.eax.b[1] = 0x02;
-
     while (count--) {
-	if (*bufp == '\n') {
-	    ireg.edx.b[0] = '\r';
-	    __intcall(0x21, &ireg, NULL);
-	}
-	ireg.edx.b[0] = *bufp++;
-	__intcall(0x21, &ireg, NULL);
+	if (*bufp == '\n')
+	    writechr('\r');
+
+	writechr(*bufp++);
 	n++;
     }
 
diff --git a/com32/lib/sys/xserial_write.c b/com32/lib/sys/xserial_write.c
index e399f5f..8a4fb9e 100644
--- a/com32/lib/sys/xserial_write.c
+++ b/com32/lib/sys/xserial_write.c
@@ -35,6 +35,7 @@
 #include <errno.h>
 #include <string.h>
 #include <com32.h>
+#include <core.h>
 #include <minmax.h>
 #include <colortbl.h>
 #include <syslinux/config.h>
@@ -42,12 +43,7 @@
 
 static void emit(char ch)
 {
-    static com32sys_t ireg;	/* Zeroed with the BSS */
-
-    ireg.eax.b[1] = 0x04;
-    ireg.edx.b[0] = ch;
-
-    __intcall(0x21, &ireg, NULL);
+    write_serial(ch);
 }
 
 ssize_t __xserial_write(struct file_info *fp, const void *buf, size_t count)
diff --git a/com32/lib/syslinux/cleanup.c b/com32/lib/syslinux/cleanup.c
index 12140e5..066f174 100644
--- a/com32/lib/syslinux/cleanup.c
+++ b/com32/lib/syslinux/cleanup.c
@@ -26,15 +26,17 @@
  * ----------------------------------------------------------------------- */
 
 #include <syslinux/boot.h>
+#include <syslinux/config.h>
+#include <syslinux/pxe_api.h>
 #include <stddef.h>
+#include <bios.h>
 #include <com32.h>
+#include <core.h>
 
 void syslinux_final_cleanup(uint16_t flags)
 {
-    static com32sys_t ireg;
+    if (syslinux_filesystem() == SYSLINUX_FS_PXELINUX)
+	unload_pxe(flags);
 
-    ireg.eax.w[0] = 0x000c;
-    ireg.edx.w[0] = flags;
-
-    __intcall(0x22, &ireg, NULL);
+    cleanup_hardware();
 }
diff --git a/com32/lib/syslinux/features.c b/com32/lib/syslinux/features.c
deleted file mode 100644
index c88aef3..0000000
--- a/com32/lib/syslinux/features.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/* ----------------------------------------------------------------------- *
- *
- *   Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
- *
- *   Permission is hereby granted, free of charge, to any person
- *   obtaining a copy of this software and associated documentation
- *   files (the "Software"), to deal in the Software without
- *   restriction, including without limitation the rights to use,
- *   copy, modify, merge, publish, distribute, sublicense, and/or
- *   sell copies of the Software, and to permit persons to whom
- *   the Software is furnished to do so, subject to the following
- *   conditions:
- *
- *   The above copyright notice and this permission notice shall
- *   be included in all copies or substantial portions of the Software.
- *
- *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *   OTHER DEALINGS IN THE SOFTWARE.
- *
- * ----------------------------------------------------------------------- */
-
-/*
- * syslinux/features.c
- *
- * SYSLINUX feature flag query
- */
-
-#include <klibc/compiler.h>
-#include <syslinux/features.h>
-#include <string.h>
-#include <com32.h>
-
-struct __syslinux_feature_flags __syslinux_feature_flags;
-
-void __constructor __syslinux_detect_features(void)
-{
-    static com32sys_t reg;
-
-    memset(&reg, 0, sizeof reg);
-    reg.eax.w[0] = 0x0015;
-    __intcall(0x22, &reg, &reg);
-
-    __syslinux_feature_flags.len = reg.ecx.w[0];
-    __syslinux_feature_flags.ptr = MK_PTR(reg.es, reg.ebx.w[0]);
-}
diff --git a/com32/lib/syslinux/ipappend.c b/com32/lib/syslinux/ipappend.c
index bd00092..3eda48c 100644
--- a/com32/lib/syslinux/ipappend.c
+++ b/com32/lib/syslinux/ipappend.c
@@ -33,26 +33,18 @@
 
 #include <syslinux/config.h>
 #include <klibc/compiler.h>
-#include <com32.h>
+#include <core.h>
 
 struct syslinux_ipappend_strings __syslinux_ipappend_strings;
 static const char *syslinux_ipappend_string_list[32];
 
 void __constructor __syslinux_get_ipappend_strings(void)
 {
-    static com32sys_t reg;
-    int i;
+    unsigned int i;
 
-    reg.eax.w[0] = 0x000f;
-    __intcall(0x22, &reg, &reg);
+    __syslinux_ipappend_strings.count = (size_t)numIPAppends;
+    __syslinux_ipappend_strings.ptr = syslinux_ipappend_string_list;
 
-    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));
-	}
-    }
+    for (i = 0; i < (size_t)numIPAppends; i++)
+	syslinux_ipappend_string_list[i] = (const char *)(size_t)IPAppends[i];
 }
diff --git a/com32/lib/syslinux/keyboard.c b/com32/lib/syslinux/keyboard.c
index feafde0..03bd216 100644
--- a/com32/lib/syslinux/keyboard.c
+++ b/com32/lib/syslinux/keyboard.c
@@ -26,19 +26,13 @@
  * ----------------------------------------------------------------------- */
 
 #include <syslinux/keyboard.h>
-#include <com32.h>
+#include <core.h>
 
 struct syslinux_keyboard_map __syslinux_keyboard_map;
 
 void __constructor __syslinux_get_keyboard_map(void)
 {
-    static com32sys_t reg;
-
-    reg.eax.w[0] = 0x001e;
-    __intcall(0x22, &reg, &reg);
-    if (!(reg.eflags.l & EFLAGS_CF)) {
-	__syslinux_keyboard_map.version = reg.eax.w[0];
-	__syslinux_keyboard_map.length = reg.ecx.w[0];
-	__syslinux_keyboard_map.map = MK_PTR(reg.es, reg.ebx.w[0]);
-    }
+    __syslinux_keyboard_map.version = 1;
+    __syslinux_keyboard_map.length = sizeof(KbdMap);
+    __syslinux_keyboard_map.map = (void *)KbdMap;
 }
diff --git a/com32/lib/syslinux/pxe_dns.c b/com32/lib/syslinux/pxe_dns.c
index 6620396..b813b54 100644
--- a/com32/lib/syslinux/pxe_dns.c
+++ b/com32/lib/syslinux/pxe_dns.c
@@ -43,12 +43,12 @@
    or -1 on invocation failure */
 uint32_t pxe_dns(const char *hostname)
 {
-    com32sys_t regs;
     union {
 	unsigned char b[4];
 	uint32_t ip;
     } q;
     char *lm_hostname;
+    uint32_t status;
 
     /* Is this a dot-quad? */
     if (sscanf(hostname, "%hhu.%hhu.%hhu.%hhu",
@@ -59,17 +59,9 @@ uint32_t pxe_dns(const char *hostname)
     if (!lm_hostname)
 	return 0;
 
-    memset(&regs, 0, sizeof regs);
-    regs.eax.w[0] = 0x0010;
-    regs.es = SEG(lm_hostname);
-    /* regs.ebx.w[0] = OFFS(lm_hostname); */
-
-    __intcall(0x22, &regs, &regs);
+    status = dns_resolv(lm_hostname);
 
     lfree(lm_hostname);
 
-    if (regs.eflags.l & EFLAGS_CF)
-	return 0;
-
-    return regs.eax.l;
+    return status;
 }
diff --git a/com32/lib/syslinux/pxe_get_cached.c b/com32/lib/syslinux/pxe_get_cached.c
index 4704037..a090a4c 100644
--- a/com32/lib/syslinux/pxe_get_cached.c
+++ b/com32/lib/syslinux/pxe_get_cached.c
@@ -43,7 +43,6 @@
 int pxe_get_cached_info(int level, void **buf, size_t * len)
 {
     const int max_dhcp_packet = 2048;
-    com32sys_t regs;
     t_PXENV_GET_CACHED_INFO *gci;
     void *bbuf, *nbuf;
     int err;
@@ -52,12 +51,6 @@ int pxe_get_cached_info(int level, void **buf, size_t * len)
     if (!gci)
 	return -1;
 
-    memset(&regs, 0, sizeof regs);
-    regs.eax.w[0] = 0x0009;
-    regs.ebx.w[0] = PXENV_GET_CACHED_INFO;
-    regs.es = SEG(gci);
-    /* regs.edi.w[0] = OFFS(gci); */
-
     bbuf = &gci[1];
 
     gci->Status = PXENV_STATUS_FAILURE;
@@ -66,9 +59,9 @@ int pxe_get_cached_info(int level, void **buf, size_t * len)
     gci->Buffer.seg = SEG(bbuf);
     gci->Buffer.offs = OFFS(bbuf);
 
-    __intcall(0x22, &regs, &regs);
+    err = pxe_call(PXENV_GET_CACHED_INFO, gci);
 
-    if (regs.eflags.l & EFLAGS_CF) {
+    if (err) {
 	err = -1;
 	goto exit;
     }
diff --git a/com32/lib/syslinux/pxe_get_nic.c b/com32/lib/syslinux/pxe_get_nic.c
index b301a75..6e256f9 100644
--- a/com32/lib/syslinux/pxe_get_nic.c
+++ b/com32/lib/syslinux/pxe_get_nic.c
@@ -42,25 +42,19 @@
    or -1 on invocation failure */
 int pxe_get_nic_type(t_PXENV_UNDI_GET_NIC_TYPE *gnt)
 {
-    com32sys_t regs;
     t_PXENV_UNDI_GET_NIC_TYPE *lgnt;
+    int err;
 
     lgnt = lzalloc(sizeof *lgnt);
     if (!lgnt)
 	return -1;
 
-    memset(&regs, 0, sizeof regs);
-    regs.eax.w[0] = 0x0009;
-    regs.ebx.w[0] = PXENV_UNDI_GET_NIC_TYPE;
-    regs.es = SEG(lgnt);
-    /* regs.edi.w[0] = OFFS(lgnt); */
-
-    __intcall(0x22, &regs, &regs);
+    err = pxe_call(PXENV_UNDI_GET_NIC_TYPE, lgnt);
 
     memcpy(gnt, lgnt, sizeof(t_PXENV_UNDI_GET_NIC_TYPE));
     lfree(lgnt);
 
-    if (regs.eflags.l & EFLAGS_CF)
+    if (err)
 	return -1;
 
     return gnt->Status;
diff --git a/com32/lib/syslinux/run_command.c b/com32/lib/syslinux/run_command.c
index a0ac9a0..0efb61f 100644
--- a/com32/lib/syslinux/run_command.c
+++ b/com32/lib/syslinux/run_command.c
@@ -28,21 +28,16 @@
 #include <syslinux/boot.h>
 #include <stddef.h>
 #include <string.h>
-#include <com32.h>
+#include <core.h>
 
 int syslinux_run_command(const char *command)
 {
-    static com32sys_t ireg;
     char *lm_command = lstrdup(command);
 
     if (!lm_command)
 	return -1;
     
-    ireg.eax.w[0] = 0x0003;
-    ireg.es = SEG(lm_command);
-    /* ireg.ebx.w[0] = OFFS(lm_command); */
-
-    __intcall(0x22, &ireg, NULL);
+    create_args_and_load(lm_command);
 
     /* Should not return even on failure, but in case... */
     lfree(lm_command);
diff --git a/com32/lib/syslinux/run_default.c b/com32/lib/syslinux/run_default.c
index 8dc9fbe..0cfa547 100644
--- a/com32/lib/syslinux/run_default.c
+++ b/com32/lib/syslinux/run_default.c
@@ -26,16 +26,14 @@
  * ----------------------------------------------------------------------- */
 
 #include <syslinux/boot.h>
+#include <core.h>
 #include <stddef.h>
-#include <com32.h>
+
+extern const char *default_cmd;
 
 __noreturn syslinux_run_default(void)
 {
-    static com32sys_t ireg;
-
-    ireg.eax.w[0] = 0x0004;
-    __intcall(0x22, &ireg, NULL);
-
+    load_kernel(default_cmd);
     /* Should not return even on failure */
     for (;;) ;
 }
diff --git a/com32/lib/syslinux/runimage.c b/com32/lib/syslinux/runimage.c
index d5cdbc6..4391114 100644
--- a/com32/lib/syslinux/runimage.c
+++ b/com32/lib/syslinux/runimage.c
@@ -34,15 +34,18 @@
 #include <stdlib.h>
 #include <string.h>
 #include <syslinux/boot.h>
-#include <com32.h>
+#include <syslinux/config.h>
+#include <core.h>
+
+extern unsigned int ipappend;
 
 void syslinux_run_kernel_image(const char *filename, const char *cmdline,
 			       uint32_t ipappend_flags, uint32_t type)
 {
-    static com32sys_t ireg;
     char *bbfilename = NULL;
     char *bbcmdline  = NULL;
 
+
     bbfilename = lstrdup(filename);
     if (!bbfilename)
 	goto fail;
@@ -51,16 +54,10 @@ void syslinux_run_kernel_image(const char *filename, const char *cmdline,
     if (!bbcmdline)
 	goto fail;
 
+    if (syslinux_filesystem() == SYSLINUX_FS_PXELINUX)
+	ipappend = ipappend_flags;
 
-    ireg.eax.w[0] = 0x0016;
-    ireg.ds = SEG(bbfilename);
-    /* ireg.esi.w[0] = OFFS(bbfilename); */
-    ireg.es = SEG(bbcmdline);
-    /* ireg.ebx.w[0] = OFFS(bbcmdline); */
-    ireg.ecx.l = ipappend_flags;
-    ireg.edx.l = type;
-
-    __intcall(0x22, &ireg, 0);
+    execute(bbfilename, type);
 
 fail:
     if (bbcmdline)
diff --git a/com32/lib/syslinux/serial.c b/com32/lib/syslinux/serial.c
index f06e8c8..bb92222 100644
--- a/com32/lib/syslinux/serial.c
+++ b/com32/lib/syslinux/serial.c
@@ -34,19 +34,22 @@
 #include <klibc/compiler.h>
 #include <syslinux/config.h>
 #include <string.h>
-#include <com32.h>
+#include <bios.h>
+#include <core.h>
 
 struct syslinux_serial_console_info __syslinux_serial_console_info;
 
 void __constructor __syslinux_get_serial_console_info(void)
 {
-    static com32sys_t reg;
+    uint16_t flowctl;
 
-    memset(&reg, 0, sizeof reg);
-    reg.eax.w[0] = 0x000b;
-    __intcall(0x22, &reg, &reg);
+    __syslinux_serial_console_info.iobase = SerialPort;
+    __syslinux_serial_console_info.divisor = BaudDivisor;
 
-    __syslinux_serial_console_info.iobase = reg.edx.w[0];
-    __syslinux_serial_console_info.divisor = reg.ecx.w[0];
-    __syslinux_serial_console_info.flowctl = reg.ebx.w[0];
+    flowctl = FlowOutput | FlowInput | (FlowIgnore << 4);
+
+    if (!DisplayCon)
+	flowctl |= (0x80 << 8);
+
+    __syslinux_serial_console_info.flowctl = flowctl;
 }
diff --git a/com32/lib/syslinux/shuffle.c b/com32/lib/syslinux/shuffle.c
index e9ee6aa..544915a 100644
--- a/com32/lib/syslinux/shuffle.c
+++ b/com32/lib/syslinux/shuffle.c
@@ -38,6 +38,7 @@
 #include <string.h>
 #include <inttypes.h>
 #include <com32.h>
+#include <core.h>
 #include <minmax.h>
 #include <dprintf.h>
 #include <syslinux/movebits.h>
@@ -51,12 +52,8 @@ static int shuffler_size;
 
 static void __constructor __syslinux_get_shuffer_size(void)
 {
-    static com32sys_t reg;
-
-    reg.eax.w[0] = 0x0023;
-    __intcall(0x22, &reg, &reg);
-
-    shuffler_size = (reg.eflags.l & EFLAGS_CF) ? 2048 : reg.ecx.w[0];
+    /* +15 padding is to guarantee alignment */
+    shuffler_size = __bcopyxx_len + 15;
 }
 
 /*
diff --git a/com32/lib/syslinux/version.c b/com32/lib/syslinux/version.c
index 15b617b..1cd2efd 100644
--- a/com32/lib/syslinux/version.c
+++ b/com32/lib/syslinux/version.c
@@ -27,20 +27,23 @@
 
 #include <syslinux/config.h>
 #include <klibc/compiler.h>
-#include <com32.h>
+#include <core.h>
+#include <../../../version.h>
 
 struct syslinux_version __syslinux_version;
 
 void __constructor __syslinux_get_version(void)
 {
-    static com32sys_t reg;
+    __syslinux_version.version = (VERSION_MAJOR << 8) + VERSION_MINOR;
 
-    reg.eax.w[0] = 0x0001;
-    __intcall(0x22, &reg, &reg);
+    /* We no longer support the COMBOOT API  */
+    __syslinux_version.max_api = 0xffff;
 
-    __syslinux_version.version = reg.ecx.w[0];
-    __syslinux_version.max_api = reg.eax.w[0];
-    __syslinux_version.filesystem = reg.edx.b[0];
-    __syslinux_version.version_string = MK_PTR(reg.es, reg.esi.w[0]);
-    __syslinux_version.copyright_string = MK_PTR(reg.es, reg.edi.w[0]);
+    __syslinux_version.filesystem = syslinux_filesystem();
+
+    /* Skip leading CR LF */
+    __syslinux_version.version_string = &syslinux_banner[2];
+
+    /* Skip leading space */
+    __syslinux_version.copyright_string = &copyright_str[1];
 }
diff --git a/com32/lib/syslinux/video/fontquery.c b/com32/lib/syslinux/video/fontquery.c
index dd5d86e..ac1fab3 100644
--- a/com32/lib/syslinux/video/fontquery.c
+++ b/com32/lib/syslinux/video/fontquery.c
@@ -31,24 +31,18 @@
  */
 
 #include <syslinux/video.h>
-#include <com32.h>
+#include <graphics.h>
 
 /*
  * Returns height of font or zero if no custom font loaded
  */
 int syslinux_font_query(uint8_t **font)
 {
-    static com32sys_t ireg;
-    com32sys_t oreg;
-    int height;
+    if (!UserFont)
+	return 0;
 
-    ireg.eax.w[0] = 0x0018;
-    __intcall(0x22, &ireg, &oreg);
+    *font = (uint8_t *)fontbuf;
 
-    height = !(oreg.eflags.l & EFLAGS_CF) ? oreg.eax.b[0] : 0;
-    if (height)
-	*font = MK_PTR(oreg.es, oreg.ebx.w[0]);
-
-    return height;
+    return VGAFontSize;
 }
 
diff --git a/com32/lib/syslinux/video/reportmode.c b/com32/lib/syslinux/video/reportmode.c
index 57fd6fd..2a2c577 100644
--- a/com32/lib/syslinux/video/reportmode.c
+++ b/com32/lib/syslinux/video/reportmode.c
@@ -31,15 +31,12 @@
  */
 
 #include <syslinux/video.h>
-#include <com32.h>
+#include <graphics.h>
 
 void syslinux_report_video_mode(uint16_t flags, uint16_t xsize, uint16_t ysize)
 {
-    static com32sys_t ireg;
+    if (flags > 0x0f)
+	return;
 
-    ireg.eax.w[0] = 0x0017;
-    ireg.ebx.w[0] = flags;
-    ireg.ecx.w[0] = xsize;
-    ireg.edx.w[0] = ysize;
-    __intcall(0x22, &ireg, NULL);
+    using_vga(flags, xsize, ysize);
 }
diff --git a/com32/libupload/upload_tftp.c b/com32/libupload/upload_tftp.c
index 5e73c1c..6a0dacb 100644
--- a/com32/libupload/upload_tftp.c
+++ b/com32/libupload/upload_tftp.c
@@ -53,7 +53,6 @@ const char *tftp_string_error_message[]={
 static int send_ack_packet(struct tftp_state *tftp,
 			   const void *pkt, size_t len)
 {
-    com32sys_t ireg, oreg;
     t_PXENV_UDP_WRITE *uw;
     t_PXENV_UDP_READ  *ur;
     clock_t start;
@@ -67,9 +66,6 @@ static int send_ack_packet(struct tftp_state *tftp,
     uw = lmalloc(sizeof *uw + len);
     ur = lmalloc(sizeof *ur + RCV_BUF);
 
-    memset(&ireg, 0, sizeof ireg);
-    ireg.eax.w[0] = 0x0009;
-
     for (timeout = timeouts ; *timeout ; timeout++) {
 	memset(uw, 0, sizeof *uw);
 	memcpy(uw+1, pkt, len);
@@ -80,11 +76,7 @@ static int send_ack_packet(struct tftp_state *tftp,
 	uw->buffer_size = len;
 	uw->buffer = FAR_PTR(uw+1);
 
-	ireg.ebx.w[0] = PXENV_UDP_WRITE;
-	ireg.es = SEG(uw);
-	ireg.edi.w[0] = OFFS(uw);
-
-	__intcall(0x22, &ireg, &oreg);
+	pxe_call(PXENV_UDP_WRITE, uw);
 
 	start = times(NULL);
 
@@ -97,13 +89,9 @@ static int send_ack_packet(struct tftp_state *tftp,
 	    ur->buffer_size = RCV_BUF;
 	    ur->buffer = FAR_PTR(ur+1);
 
-	    ireg.ebx.w[0] = PXENV_UDP_READ;
-	    ireg.es = SEG(ur);
-	    ireg.edi.w[0] = OFFS(ur);
-	    __intcall(0x22, &ireg, &oreg);
+	    err = pxe_call(PXENV_UDP_READ, ur);
 
-	    if (!(oreg.eflags.l & EFLAGS_CF) &&
-		ur->status == PXENV_STATUS_SUCCESS &&
+	    if (!err &&	ur->status == PXENV_STATUS_SUCCESS &&
 		tftp->srv_ip == ur->src_ip &&
 		(tftp->srv_port == 0 ||
 		 tftp->srv_port == ur->s_port)) {
diff --git a/com32/menu/menumain.c b/com32/menu/menumain.c
index 53bc6c6..c9762b2 100644
--- a/com32/menu/menumain.c
+++ b/com32/menu/menumain.c
@@ -28,7 +28,9 @@
 #include <setjmp.h>
 #include <limits.h>
 #include <com32.h>
+#include <core.h>
 #include <syslinux/adv.h>
+#include <syslinux/boot.h>
 
 #include "menu.h"
 
@@ -1161,11 +1163,11 @@ int main(int argc, char *argv[])
 	printf("\033[?25h\033[%d;1H\033[0m", cursorrow);
 
 	if (cmdline) {
-	    enum kernel_type type = parse_kernel_type(cmdline);
+	    uint32_t type = parse_image_type(cmdline);
 
 	    execute(cmdline, type);
 	    if (cm->onerror) {
-		type = parse_kernel_type(cm->onerror);
+		type = parse_image_type(cm->onerror);
 		execute(cm->onerror, type);
 	    }
 	} else {
diff --git a/com32/menu/readconfig.c b/com32/menu/readconfig.c
index 8f9d237..69f524c 100644
--- a/com32/menu/readconfig.c
+++ b/com32/menu/readconfig.c
@@ -62,7 +62,7 @@ static const struct messages messages[MSG_COUNT] = {
                       __p; })
 
 /* Must match enum kernel_type */
-const char *const kernel_types[] = {
+static const char *const kernel_types[] = {
     "none",
     "localboot",
     "kernel",
diff --git a/com32/modules/Makefile b/com32/modules/Makefile
index 8d94cfe..8f5b769 100644
--- a/com32/modules/Makefile
+++ b/com32/modules/Makefile
@@ -15,6 +15,9 @@
 ## COM32 standard modules
 ##
 
+LIBS = $(com32)/gpllib/libcom32gpl.c32 $(com32)/lib/libcom32.c32 \
+	$(com32)/libutil/libutil_com.c32
+
 topdir = ../..
 MAKEDIR = $(topdir)/mk
 include $(MAKEDIR)/elf.mk
@@ -28,21 +31,6 @@ MODULES	  = config.c32 ethersel.c32 dmitest.c32 cpuidtest.c32 \
 
 TESTFILES =
 
-LDFLAGS_cpuidtest.o = $(com32)/gpllib/libcom32gpl.c32
-LDFLAGS_disk.o = $(com32)/gpllib/libcom32gpl.c32
-LDFLAGS_ethersel.o = $(com32)/lib/libcom32.c32
-LDFLAGS_gpxecmd.o = $(com32)/lib/libcom32.c32
-LDFLAGS_host.o = $(com32)/lib/libcom32.c32
-LDFLAGS_ifcpu.o = $(com32)/libutil/libutil_com.c32 \
-		  $(com32)/gpllib/libcom32gpl.c32
-LDFLAGS_kbdmap.o = $(com32)/lib/libcom32.c32
-LDFLAGS_linux.o = $(com32)/lib/libcom32.c32
-LDFLAGS_pxechn.o = $(com32)/lib/libcom32.c32 \
-	$(com32)/libutil/libutil_com.c32
-LDFLAGS_sanboot.o = $(com32)/lib/libcom32.c32
-LDFLAGS_vpdtest.o = $(com32)/gpllib/libcom32gpl.c32
-LDFLAGS_zzjson.o = $(com32)/gpllib/libcom32gpl.c32
-
 all: $(MODULES) $(TESTFILES)
 
 .PRECIOUS: %.o
diff --git a/com32/modules/gpxecmd.c b/com32/modules/gpxecmd.c
index 9d4f456..d2d90a2 100644
--- a/com32/modules/gpxecmd.c
+++ b/com32/modules/gpxecmd.c
@@ -39,9 +39,6 @@ static void gpxecmd(const char **args)
 {
     char *q;
     struct s_PXENV_FILE_EXEC *fx;
-    com32sys_t reg;
-
-    memset(&reg, 0, sizeof reg);
 
     fx = lmalloc(sizeof *fx);
     if (!fx)
@@ -60,13 +57,7 @@ static void gpxecmd(const char **args)
     }
     *--q = '\0';
 
-    memset(&reg, 0, sizeof reg);
-    reg.eax.w[0] = 0x0009;
-    reg.ebx.w[0] = PXENV_FILE_EXEC;
-    reg.edi.w[0] = OFFS(fx);
-    reg.es = SEG(fx);
-
-    __intcall(0x22, &reg, &reg);
+    pxe_call(PXENV_FILE_EXEC, fx);
 
     /* This should not return... */
 }
diff --git a/com32/modules/pxechn.c b/com32/modules/pxechn.c
index 1902d4e..39ac72e 100644
--- a/com32/modules/pxechn.c
+++ b/com32/modules/pxechn.c
@@ -845,7 +845,6 @@ int pxechn_args(int argc, char *argv[], struct pxelinux_opt *pxe)
  */
 int dhcp_pkt2pxe(pxe_bootp_t *p, size_t len, int ptype)
 {
-    com32sys_t reg;
     t_PXENV_GET_CACHED_INFO *ci;
     void *cp;
     int rv = -1;
@@ -857,12 +856,7 @@ int dhcp_pkt2pxe(pxe_bootp_t *p, size_t len, int ptype)
     }
     ci->Status = PXENV_STATUS_FAILURE;
     ci->PacketType = ptype;
-    memset(&reg, 0, sizeof(reg));
-    reg.eax.w[0] = 0x0009;
-    reg.ebx.w[0] = PXENV_GET_CACHED_INFO;
-    reg.edi.w[0] = OFFS(ci);
-    reg.es = SEG(ci);
-    __intcall(0x22, &reg, &reg);
+    pxe_call(PXENV_GET_CACHED_INFO, ci);
 
     if (ci->Status != PXENV_STATUS_SUCCESS) {
 	dprintf("PXE Get Cached Info failed: %d\n", ci->Status);
@@ -1015,7 +1009,6 @@ int pxe_restart(char *ifn)
 {
     int rv = 0;
     struct pxelinux_opt pxe;
-    com32sys_t reg;
     t_PXENV_RESTART_TFTP *pxep;	/* PXENV callback Parameter */
 
     pxe.fn = ifn;
@@ -1030,7 +1023,6 @@ int pxe_restart(char *ifn)
 	goto ret;
     }
     printf("  Attempting to boot '%s'...\n\n", pxe.fn);
-    memset(&reg, 0, sizeof reg);
     if (!(pxep = lzalloc(sizeof(t_PXENV_RESTART_TFTP)))){
 	dprintf("Unable to lzalloc() for PXE call structure\n");
 	goto ret;
@@ -1044,12 +1036,8 @@ int pxe_restart(char *ifn)
 	pxep->ServerIPAddress, (unsigned int)pxep,
 	pxep->BufferSize, (unsigned int)pxep->Buffer);
     dprintf("PXENV_RESTART_TFTP status %d\n", pxep->Status);
-    reg.eax.w[0] = 0x0009;
-    reg.ebx.w[0] = PXENV_RESTART_TFTP;
-    reg.edi.w[0] = OFFS(pxep);
-    reg.es = SEG(pxep);
 
-    __intcall(0x22, &reg, &reg);
+    pxe_call(PXENV_RESTART_TFTP, pxep);
 
     printf("PXENV_RESTART_TFTP returned %d\n", pxep->Status);
     lfree(pxep);
diff --git a/com32/modules/sanboot.c b/com32/modules/sanboot.c
index d55fbc0..ff55f68 100644
--- a/com32/modules/sanboot.c
+++ b/com32/modules/sanboot.c
@@ -39,9 +39,6 @@ static void sanboot(const char **args)
 {
     char *q;
     struct s_PXENV_FILE_EXEC *fx;
-    com32sys_t reg;
-
-    memset(&reg, 0, sizeof reg);
 
     fx = lmalloc(sizeof *fx);
     if (!fx)
@@ -61,13 +58,7 @@ static void sanboot(const char **args)
 	args++;
     }
 
-    memset(&reg, 0, sizeof reg);
-    reg.eax.w[0] = 0x0009;
-    reg.ebx.w[0] = PXENV_FILE_EXEC;
-    reg.edi.w[0] = OFFS(fx);
-    reg.es = SEG(fx);
-
-    __intcall(0x22, &reg, &reg);
+    pxe_call(PXENV_FILE_EXEC, fx);
 
     /* This should not return... */
 }
diff --git a/com32/rosh/Makefile b/com32/rosh/Makefile
index f328395..a894c84 100644
--- a/com32/rosh/Makefile
+++ b/com32/rosh/Makefile
@@ -16,6 +16,8 @@
 ## ROSH Read Only Shell
 ##
 
+LIBS = $(com32)/libutil/libutil_com.c32 $(com32)/lib/libcom32.c32
+
 topdir = ../..
 MAKEDIR = $(topdir)/mk
 include $(MAKEDIR)/rosh.mk
@@ -34,8 +36,6 @@ endif
 CFLAGS		+= -DDATE='"$(DATE)"'
 LNXCFLAGS	+= -DDATE='"$(DATE)"'
 
-LDFLAGS_rosh.o = $(com32)/libutil/libutil_com.c32 $(com32)/lib/libcom32.c32
-
 rosh.o:	rosh.h
 
 rosh.lo:	rosh.h
diff --git a/com32/samples/Makefile b/com32/samples/Makefile
index bca197e..c7abadd 100644
--- a/com32/samples/Makefile
+++ b/com32/samples/Makefile
@@ -14,13 +14,12 @@
 ## samples for syslinux users
 ##
 
+LIBS = $(com32)/libutil/libutil_com.c32
+
 topdir = ../..
 MAKEDIR = $(topdir)/mk
 include $(MAKEDIR)/elf.mk
 
-LDFLAGS_fancyhello.o = $(com32)/libutil/libutil_com.c32
-LDFLAGS_keytest.o = $(com32)/libutil/libutil_com.c32
-
 all:	hello.c32 resolv.c32 serialinfo.c32 \
 	localboot.c32 \
 	fancyhello.c32 fancyhello.lnx \
diff --git a/com32/samples/resolv.c b/com32/samples/resolv.c
index bd49d9f..f4a0e52 100644
--- a/com32/samples/resolv.c
+++ b/com32/samples/resolv.c
@@ -16,6 +16,7 @@
  * Resolve an IP address
  */
 
+#include <syslinux/pxe_api.h>
 #include <string.h>
 #include <stdio.h>
 #include <console.h>
@@ -24,21 +25,7 @@
 
 uint32_t resolv(const char *name)
 {
-    com32sys_t reg;
-
-    strcpy((char *)__com32.cs_bounce, name);
-
-    memset(&reg, 0, sizeof reg);
-    reg.eax.w[0] = 0x0010;
-    reg.ebx.w[0] = OFFS(__com32.cs_bounce);
-    reg.es = SEG(__com32.cs_bounce);
-
-    __intcall(0x22, &reg, &reg);
-
-    if (reg.eflags.l & EFLAGS_CF)
-	return 0;
-    else
-	return reg.eax.l;
+    return dns_resolv(name);
 }
 
 int main(int argc, char *argv[])
diff --git a/core/comboot.inc b/core/comboot.inc
index 1e19d28..175c50c 100644
--- a/core/comboot.inc
+++ b/core/comboot.inc
@@ -842,6 +842,7 @@ zero_string	db 0			; Empty, null-terminated string
 ; Note: PXELINUX clears the idle is noop flag if appropriate
 ; in pxe_detect_nic_type
 ;
+		global feature_flags, feature_flags_len
 feature_flags:
 		db 1			; Have local boot, idle is not noop
 feature_flags_len equ ($-feature_flags)
diff --git a/core/console.c b/core/console.c
index 282c57f..3b545bb 100644
--- a/core/console.c
+++ b/core/console.c
@@ -1,18 +1,15 @@
 #include <stddef.h>
 #include <com32.h>
+#include <core.h>
 #include <stdio.h>
 #include <string.h>
 
 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);
+    writechr(c);
 }
 
 void myputs(const char *str)
diff --git a/core/diskfs.inc b/core/diskfs.inc
index 02382cc..dcbc924 100644
--- a/core/diskfs.inc
+++ b/core/diskfs.inc
@@ -109,9 +109,9 @@ PXERetry	dw 0			; Extra PXE retries
 		section .data16
 		global SerialNotice
 SerialNotice	db 1			; Only print this once
+		global IPAppends, numIPAppends
 %if IS_PXELINUX
 		extern IPOption
-		global IPAppends, numIPAppends
 		alignz 2
 IPAppends	dw IPOption
 numIPAppends	equ ($-IPAppends)/2
diff --git a/core/elflink/advwrite.c b/core/elflink/advwrite.c
deleted file mode 100644
index 4152eea..0000000
--- a/core/elflink/advwrite.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/* ----------------------------------------------------------------------- *
- *
- *   Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
- *
- *   Permission is hereby granted, free of charge, to any person
- *   obtaining a copy of this software and associated documentation
- *   files (the "Software"), to deal in the Software without
- *   restriction, including without limitation the rights to use,
- *   copy, modify, merge, publish, distribute, sublicense, and/or
- *   sell copies of the Software, and to permit persons to whom
- *   the Software is furnished to do so, subject to the following
- *   conditions:
- *
- *   The above copyright notice and this permission notice shall
- *   be included in all copies or substantial portions of the Software.
- *
- *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *   OTHER DEALINGS IN THE SOFTWARE.
- *
- * ----------------------------------------------------------------------- */
-
-/*
- * 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/load_env32.c b/core/elflink/load_env32.c
index b15cdbb..8e124a0 100644
--- a/core/elflink/load_env32.c
+++ b/core/elflink/load_env32.c
@@ -66,28 +66,15 @@ int start_ldlinux(char **argv)
 again:
 	rv = spawn_load(LDLINUX, 1, argv);
 	if (rv == EEXIST) {
-		struct elf_module *m, *mod, *begin = NULL;
-
 		/*
 		 * If a COM32 module calls execute() we may need to
 		 * unload all the modules loaded since ldlinux.c32,
 		 * and restart initialisation. This is especially
 		 * important for config files.
 		 */
-		for_each_module(mod) {
-			if (!strcmp(mod->name, LDLINUX)) {
-				begin = mod;
-				break;
-			}
-		}
+		struct elf_module *ldlinux;
 
-		for_each_module_safe(mod, m) {
-			if (mod == begin)
-				break;
-
-			if (mod != begin)
-				module_unload(mod);
-		}
+		ldlinux = unload_modules_since(LDLINUX);
 
 		/*
 		 * Finally unload LDLINUX.
@@ -96,7 +83,7 @@ again:
 		 * cause all the initialsation steps to be executed
 		 * again.
 		 */
-		module_unload(begin);
+		module_unload(ldlinux);
 		goto again;
 	}
 
diff --git a/core/elflink/setadv.c b/core/elflink/setadv.c
deleted file mode 100644
index 40f00a4..0000000
--- a/core/elflink/setadv.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/* ----------------------------------------------------------------------- *
- *
- *   Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
- *   Copyright 2009 Intel Corporation; author: H. Peter Anvin
- *
- *   Permission is hereby granted, free of charge, to any person
- *   obtaining a copy of this software and associated documentation
- *   files (the "Software"), to deal in the Software without
- *   restriction, including without limitation the rights to use,
- *   copy, modify, merge, publish, distribute, sublicense, and/or
- *   sell copies of the Software, and to permit persons to whom
- *   the Software is furnished to do so, subject to the following
- *   conditions:
- *
- *   The above copyright notice and this permission notice shall
- *   be included in all copies or substantial portions of the Software.
- *
- *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *   OTHER DEALINGS IN THE SOFTWARE.
- *
- * ----------------------------------------------------------------------- */
-
-/*
- * syslinux/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/font.c b/core/font.c
index 31fb29e..9e7aa8f 100644
--- a/core/font.c
+++ b/core/font.c
@@ -26,9 +26,7 @@
 #include "graphics.h"
 #include "core.h"
 
-static __lowmem char fontbuf[8192];
-
-extern uint8_t UserFont;
+__lowmem char fontbuf[8192];
 
 uint16_t GXPixCols = 1;		/* Graphics mode pixel columns */
 uint16_t GXPixRows = 1;		/* Graphics mode pixel rows */
diff --git a/core/fs/pxe/pxe.c b/core/fs/pxe/pxe.c
index 8c95623..6f490ce 100644
--- a/core/fs/pxe/pxe.c
+++ b/core/fs/pxe/pxe.c
@@ -1187,9 +1187,6 @@ static void ip_init(void)
 /*
  * Print the IPAPPEND strings, in order
  */
-extern const uint16_t IPAppends[];
-extern const char numIPAppends[];
-
 static void print_ipappend(void)
 {
     size_t i;
@@ -1656,7 +1653,7 @@ int reset_pxe(void)
  * This function unloads the PXE and UNDI stacks and
  * unclaims the memory.
  */
-void unload_pxe(void)
+void unload_pxe(uint16_t flags)
 {
     /* PXE unload sequences */
     static const uint8_t new_api_unload[] = {
@@ -1685,7 +1682,7 @@ void unload_pxe(void)
     dprintf("FBM after reset_pxe = %d, err = %d\n", BIOS_fbm, err);
 
     /* If we want to keep PXE around, we still need to reset it */
-    if (KeepPXE || err)
+    if (flags || err)
 	return;
 
     dprintf("APIVer = %04x\n", APIVer);
diff --git a/core/fs/pxe/pxe.h b/core/fs/pxe/pxe.h
index 47ed8f0..c754106 100644
--- a/core/fs/pxe/pxe.h
+++ b/core/fs/pxe/pxe.h
@@ -232,14 +232,12 @@ static inline uint32_t gateway(uint32_t ip)
 
 /* pxe.c */
 bool ip_ok(uint32_t);
-int pxe_call(int, void *);
 
 /* dhcp_options.c */
 void parse_dhcp(const void *, size_t);
 
 /* dnsresolv.c */
 int dns_mangle(char **, const char *);
-uint32_t dns_resolv(const char *);
 
 /* idle.c */
 void pxe_idle_init(void);
diff --git a/core/hello.c b/core/hello.c
index 5b22478..d30fc3b 100644
--- a/core/hello.c
+++ b/core/hello.c
@@ -9,14 +9,10 @@
 
 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);
+    writechr(c);
 }
 
 void myputs(const char *str)
diff --git a/core/include/bios.h b/core/include/bios.h
index 4bf6bc4..42a9768 100644
--- a/core/include/bios.h
+++ b/core/include/bios.h
@@ -74,7 +74,6 @@ extern union screen _screensize;
 #define VidRows		_screensize.b.row
 
 /* font.c */
-extern uint16_t VGAFontSize;
 extern void use_font(void);
 extern void bios_adjust_screen(void);
 
diff --git a/core/include/core.h b/core/include/core.h
index e19f2f1..da94dbf 100644
--- a/core/include/core.h
+++ b/core/include/core.h
@@ -25,9 +25,19 @@ extern char ConfigFile[];
 extern char syslinux_banner[];
 extern char copyright_str[];
 extern char StackBuf[];
+extern unsigned int __bcopyxx_len;
 
 extern uint8_t KbdMap[256];
 
+extern const uint16_t IPAppends[];
+extern const char numIPAppends[];
+
+extern uint16_t SerialPort;
+extern uint16_t BaudDivisor;
+extern uint8_t FlowOutput;
+extern uint8_t FlowInput;
+extern uint8_t FlowIgnore;
+
 /* diskstart.inc isolinux.asm*/
 extern void getlinsec(void);
 
@@ -101,14 +111,20 @@ static inline void set_flags(com32sys_t *regs, uint32_t flags)
 }
 
 extern int start_ldlinux(char **argv);
+extern int create_args_and_load(char *);
 
 extern void write_serial(char data);
 extern void writestr(char *str);
 extern void writechr(char data);
 extern void crlf(void);
+extern int pollchar(void);
+extern char getchar(char *hi);
 
 extern void cleanup_hardware(void);
 extern void sirq_cleanup(void);
 extern void adjust_screen(void);
 
+extern void execute(const char *cmdline, uint32_t type);
+extern void load_kernel(const char *cmdline);
+
 #endif /* CORE_H */
diff --git a/core/include/graphics.h b/core/include/graphics.h
index 897103e..814ffe7 100644
--- a/core/include/graphics.h
+++ b/core/include/graphics.h
@@ -44,6 +44,11 @@ extern uint16_t VGAPos;
 extern uint16_t *VGAFilePtr;
 extern char VGAFileBuf[VGA_FILE_BUF_SIZE];
 extern char VGAFileMBuf[];
+extern uint16_t VGAFontSize;
+
+extern uint8_t UserFont;
+
+extern __lowmem char fontbuf[8192];
 
 extern void syslinux_force_text_mode(void);
 extern void vgadisplayfile(FILE *_fd);
diff --git a/core/isolinux.asm b/core/isolinux.asm
index 4790887..5930a1e 100644
--- a/core/isolinux.asm
+++ b/core/isolinux.asm
@@ -1219,9 +1219,9 @@ PXERetry	dw 0			; Extra PXE retries
 		section .data16
 		global SerialNotice
 SerialNotice	db 1			; Only print this once
+		global IPAppends, numIPAppends
 %if IS_PXELINUX
 		extern IPOption
-		global IPAppends, numIPAppends
 		alignz 2
 IPAppends	dw IPOption
 numIPAppends	equ ($-IPAppends)/2
diff --git a/mk/elf.mk b/mk/elf.mk
index bc2948a..4e76c71 100644
--- a/mk/elf.mk
+++ b/mk/elf.mk
@@ -82,4 +82,4 @@ C_LNXLIBS  = $(com32)/libutil/libutil_lnx.a \
 	$(CC) $(LNXCFLAGS) -o $@ $^
 
 %.c32: %.o $(LIBS)
-	$(LD) $(LDFLAGS_$^) $(LDFLAGS) -o $@ $^
+	$(LD) $(LDFLAGS) -o $@ $^





More information about the Syslinux mailing list