Merge tag 'syslinux-5.01' into firmware

Conflicts:
	Makefile
	NEWS
	com32/cmenu/Makefile
	com32/elflink/ldlinux/Makefile
	com32/gfxboot/Makefile
	com32/gpllib/Makefile
	com32/include/sys/module.h
	com32/lib/Makefile
	com32/lib/sys/module/elf_module.c
	com32/menu/Makefile
	com32/rosh/Makefile
	com32/samples/Makefile
	core/init.c
	mk/elf.mk

Signed-off-by: Matt Fleming <matt.fleming@intel.com>
diff --git a/Makefile b/Makefile
index c241df0..e7d89d9 100644
--- a/Makefile
+++ b/Makefile
@@ -14,10 +14,102 @@
 #
 # Main Makefile for SYSLINUX
 #
-topdir = .
+
+#
+# topdir is only set when we are doing a recursive make. Do a bunch of
+# initialisation if it's unset since this is the first invocation.
+#
+ifeq ($(topdir),)
+
+topdir = $(CURDIR)
+
+#
+# Because we need to build modules multiple times, e.g. for BIOS,
+# efi32, efi64, we output all object and executable files to a
+# separate object directory for each firmware.
+#
+# The output directory can be customised by setting the O=/obj/path/
+# variable when invoking make. If no value is specified the default
+# directory is the top-level of the Syslinux source.
+#
+ifeq ("$(origin O)", "command line")
+	OBJDIR := $(O)
+else
+	OBJDIR = $(topdir)
+endif
+
+# If the output directory does not exist we bail because that is the
+# least surprising thing to do.
+cd-output := $(shell cd $(OBJDIR) && /bin/pwd)
+$(if $(cd-output),, \
+	$(error output directory "$(OBJDIR)" does not exist))
+
+#
+# These environment variables are exported to every invocation of
+# make,
+#
+# 'topdir' - the top-level directory containing the Syslinux source
+# 'objdir' - the top-level directory of output files for this firmware
+# 'MAKEDIR' - contains Makefile fragments
+# 'OBJDIR' - the top-level directory of output files
+#
+# There are also a handful of variables that are passed to each
+# sub-make,
+#
+# SRC - source tree location of the module being compiled
+# OBJ - output tree location of the module being compiled
+#
+# A couple of rules for writing Makefiles,
+#
+# - Do not use relative paths, use the above variables
+# - You can write $(SRC) a lot less if you add it to VPATH
+#
+
 MAKEDIR = $(topdir)/mk
+export MAKEDIR topdir OBJDIR
+
 include $(MAKEDIR)/syslinux.mk
--include $(topdir)/version.mk
+-include $(OBJDIR)/version.mk
+
+private-targets = prerel unprerel official release burn isolinux.iso \
+		  preupload upload
+
+ifeq ($(MAKECMDGOALS),)
+	MAKECMDGOALS += all
+endif
+
+#
+# The 'bios', 'efi32' and 'efi64' are dummy targets. Their only
+# purpose is to instruct us which output directories need
+# creating. Which means that we always need a *real* target, such as
+# 'all', appended to the make goals.
+#
+firmware = bios efi32 efi64
+real-target := $(filter-out $(firmware), $(MAKECMDGOALS))
+real-firmware := $(filter $(firmware), $(MAKECMDGOALS))
+
+ifeq ($(real-target),)
+	real-target = all
+endif
+
+ifeq ($(real-firmware),)
+	real-firmware = $(firmware)
+endif
+
+.PHONY: $(filter-out $(private-targets), $(MAKECMDGOALS))
+$(filter-out $(private-targets), $(MAKECMDGOALS)):
+	$(MAKE) -C $(OBJDIR) -f $(CURDIR)/Makefile SRC="$(topdir)" \
+		OBJ=$(OBJDIR) objdir=$(OBJDIR) $(MAKECMDGOALS)
+
+# Hook to add private Makefile targets for the maintainer.
+-include $(topdir)/Makefile.private
+
+else # ifeq ($(topdir),)
+
+include $(MAKEDIR)/syslinux.mk
+
+# Hook to add private Makefile targets for the maintainer.
+-include $(topdir)/Makefile.private
 
 #
 # The BTARGET refers to objects that are derived from ldlinux.asm; we
@@ -30,19 +122,29 @@
 # directories.
 #
 
+ifndef EFI_BUILD
 MODULES = memdisk/memdisk memdump/memdump.com \
 	com32/menu/*.c32 com32/modules/*.c32 com32/mboot/*.c32 \
 	com32/hdt/*.c32 com32/rosh/*.c32 com32/gfxboot/*.c32 \
 	com32/sysdump/*.c32 com32/lua/src/*.c32 com32/chain/*.c32 \
 	com32/lib/*.c32 com32/libutil/*.c32 com32/gpllib/*.c32 \
 	com32/elflink/ldlinux/*.c32 com32/cmenu/libmenu/*.c32
+else
+# memdump is BIOS specific code exclude it for EFI
+# FIXME: Prune other BIOS-centric modules
+MODULES = com32/menu/*.c32 com32/modules/*.c32 com32/mboot/*.c32 \
+	com32/hdt/*.c32 com32/rosh/*.c32 com32/gfxboot/*.c32 \
+	com32/sysdump/*.c32 com32/lua/src/*.c32 com32/chain/*.c32 \
+	com32/lib/*.c32 com32/libutil/*.c32 com32/gpllib/*.c32 \
+	com32/elflink/ldlinux/*.c32 com32/cmenu/libmenu/*.c32
+endif
 
 # List of module objects that should be installed for all derivatives
 INSTALLABLE_MODULES = $(MODULES)
 
 # syslinux.exe is BTARGET so as to not require everyone to have the
 # mingw suite installed
-BTARGET  = version.gen version.h version.mk
+BTARGET  = version.gen version.h $(OBJDIR)/version.mk
 BOBJECTS = $(BTARGET) \
 	mbr/*.bin \
 	core/pxelinux.0 core/isolinux.bin core/isolinux-debug.bin \
@@ -57,8 +159,19 @@
 # Note: libinstaller is both a BSUBDIR and an ISUBDIR.  It contains
 # files that depend only on the B phase, but may have to be regenerated
 # for "make installer".
+
+ifdef EFI_BUILD
+
+BSUBDIRS = codepage com32 lzo core mbr sample efi txt
+ISUBDIRS = efi utils
+
+INSTALLSUBDIRS = efi
+
+else
+
 BSUBDIRS = codepage com32 lzo core memdisk mbr memdump gpxe sample \
 	   diag libinstaller dos win32 win64 dosutil txt
+
 ITARGET  =
 IOBJECTS = $(ITARGET) \
 	utils/gethostip utils/isohybrid utils/mkdiskimage \
@@ -88,33 +201,108 @@
 NETINSTALLABLE = core/pxelinux.0 gpxe/gpxelinux.0 \
 		 $(INSTALLABLE_MODULES)
 
-all:
-	$(MAKE) all-local
-	set -e ; for i in $(BSUBDIRS) $(ISUBDIRS) ; do $(MAKE) -C $$i $@ ; done
-	-ls -l $(BOBJECTS) $(IOBJECTS)
+endif # ifdef EFI_BUILD
+
+.PHONY: subdirs $(BSUBDIRS) $(ISUBDIRS)
+
+ifeq ($(HAVE_FIRMWARE),)
+
+firmware = bios efi32 efi64
+
+# If no firmware was specified the rest of MAKECMDGOALS applies to all
+# firmware.
+ifeq ($(filter $(firmware),$(MAKECMDGOALS)),)
+all strip tidy clean dist spotless install installer: bios efi32 efi64
+
+else
+
+# Don't do anything for the rest of MAKECMDGOALS at this level. It
+# will be handled for each of $(firmware).
+strip tidy clean dist spotless install installer:
+
+endif
+
+# Convert 'make bios strip' to 'make strip', etc for rest of the Makefiles.
+MAKECMDGOALS := $(filter-out $(firmware),$(MAKECMDGOALS))
+ifeq ($(MAKECMDGOALS),)
+	MAKECMDGOALS += all
+endif
+
+#
+# You'd think that we'd be able to use the 'define' directive to
+# abstract the code for invoking make(1) in the output directory, but
+# by using 'define' we lose the ability to build in parallel.
+#
+.PHONY: $(firmware)
+bios:
+	@mkdir -p $(OBJ)/bios
+	$(MAKE) -C $(OBJ)/bios -f $(SRC)/Makefile SRC="$(SRC)" \
+		objdir=$(OBJ)/bios OBJ=$(OBJ)/bios HAVE_FIRMWARE=1 \
+		ARCH=i386 $(MAKECMDGOALS)
+
+efi32:
+	@mkdir -p $(OBJ)/efi32
+	$(MAKE) -C $(OBJ)/efi32 -f $(SRC)/Makefile SRC="$(SRC)" \
+		objdir=$(OBJ)/efi32 OBJ=$(OBJ)/efi32 HAVE_FIRMWARE=1 \
+		ARCH=i386 BITS=32 EFI_BUILD=1 $(MAKECMDGOALS)
+
+efi64:
+	@mkdir -p $(OBJ)/efi64
+	$(MAKE) -C $(OBJ)/efi64 -f $(SRC)/Makefile SRC="$(SRC)" \
+		objdir=$(OBJ)/efi64 OBJ=$(OBJ)/efi64 HAVE_FIRMWARE=1 \
+		ARCH=x86_64 BITS=64 EFI_BUILD=1 $(MAKECMDGOALS)
+
+else # ifeq($(HAVE_FIRMWARE),)
+
+all: all-local subdirs
 
 all-local: $(BTARGET) $(ITARGET)
-
-installer:
-	$(MAKE) installer-local
-	set -e ; for i in $(ISUBDIRS); do $(MAKE) -C $$i all ; done
 	-ls -l $(BOBJECTS) $(IOBJECTS)
+subdirs: $(BSUBDIRS) $(ISUBDIRS)
+
+$(sort $(ISUBDIRS) $(BSUBDIRS)):
+	@mkdir -p $@
+	$(MAKE) -C $@ SRC="$(SRC)/$@" OBJ="$(OBJ)/$@" \
+		-f $(SRC)/$@/Makefile $(MAKECMDGOALS)
+
+$(ITARGET):
+	@mkdir -p $@
+	$(MAKE) -C $@ SRC="$(SRC)/$@" OBJ="$(OBJ)/$@" \
+		-f $(SRC)/$@/Makefile $(MAKECMDGOALS)
+
+$(BINFILES):
+	@mkdir -p $@
+	$(MAKE) -C $@ SRC="$(SRC)/$@" OBJ="$(OBJ)/$@" \
+		-f $(SRC)/$@/Makefile $(MAKECMDGOALS)
+
+#
+# List the dependencies to help out parallel builds.
+dos extlinux linux mtools win32 win64: libinstaller
+libinstaller: core
+utils: mbr
+core: com32
+efi: core
+
+installer: installer-local
+	set -e; for i in $(ISUBDIRS); \
+		do $(MAKE) -C $$i SRC="$(SRC)/$$i" OBJ="$(OBJ)/$$i" \
+		-f $(SRC)/$$i/Makefile all; done
+
 
 installer-local: $(ITARGET) $(BINFILES)
 
-strip:
-	$(MAKE) strip-local
-	set -e ; for i in $(ISUBDIRS); do $(MAKE) -C $$i strip ; done
+strip: strip-local
+	set -e; for i in $(ISUBDIRS); \
+		do $(MAKE) -C $$i SRC="$(SRC)/$$i" OBJ="$(OBJ)/$$i" \
+		-f $(SRC)/$$i/Makefile strip; done
 	-ls -l $(BOBJECTS) $(IOBJECTS)
 
 strip-local:
 
-version.gen: version version.pl
-	$(PERL) version.pl $< $@ '%define < @'
-version.h: version version.pl
-	$(PERL) version.pl $< $@ '#define < @'
-version.mk: version version.pl
-	$(PERL) version.pl $< $@ '< := @'
+version.gen: $(topdir)/version $(topdir)/version.pl
+	$(PERL) $(topdir)/version.pl $< $@ '%define < @'
+version.h: $(topdir)/version $(topdir)/version.pl
+	$(PERL) $(topdir)/version.pl $< $@ '#define < @'
 
 local-install: installer
 	mkdir -m 755 -p $(INSTALLROOT)$(BINDIR)
@@ -127,12 +315,24 @@
 	mkdir -m 755 -p $(INSTALLROOT)$(DIAGDIR)
 	install -m 644 -c $(INSTALL_DIAG) $(INSTALLROOT)$(DIAGDIR)
 	mkdir -m 755 -p $(INSTALLROOT)$(MANDIR)/man1
-	install -m 644 -c man/*.1 $(INSTALLROOT)$(MANDIR)/man1
+	install -m 644 -c $(topdir)/man/*.1 $(INSTALLROOT)$(MANDIR)/man1
 	: mkdir -m 755 -p $(INSTALLROOT)$(MANDIR)/man8
 	: install -m 644 -c man/*.8 $(INSTALLROOT)$(MANDIR)/man8
 
+ifndef EFI_BUILD
 install: local-install
-	set -e ; for i in $(INSTALLSUBDIRS) ; do $(MAKE) -C $$i $@ ; done
+	set -e ; for i in $(INSTALLSUBDIRS) ; \
+		do $(MAKE) -C $$i SRC="$(SRC)/$$i" OBJ="$(OBJ)/$$i" \
+		-f $(SRC)/$$i/Makefile $@; done
+else
+install:
+	set -e ; for i in $(INSTALLSUBDIRS) ; \
+		do $(MAKE) -C $$i SRC="$(SRC)/$$i" OBJ="$(OBJ)/$$i" \
+		BITS="$(BITS)" -f $(SRC)/$$i/Makefile $@; done
+
+	mkdir -m 755 -p $(INSTALLROOT)$(AUXDIR)/efi$(BITS)
+	install -m 755 $(MODULES) $(INSTALLROOT)$(AUXDIR)/efi$(BITS)
+endif
 
 netinstall: installer
 	mkdir -p $(INSTALLROOT)$(TFTPBOOT)
@@ -149,33 +349,35 @@
 	rm -f *.lsr *.lst *.map *.sec *.tmp
 	rm -f $(OBSOLETE)
 
-tidy: local-tidy
-	set -e ; for i in $(BESUBDIRS) $(IESUBDIRS) $(BSUBDIRS) $(ISUBDIRS) ; do $(MAKE) -C $$i $@ ; done
+tidy: local-tidy $(BESUBDIRS) $(IESUBDIRS) $(BSUBDIRS) $(ISUBDIRS)
 
 local-clean:
 	rm -f $(ITARGET)
 
-clean: local-tidy local-clean
-	set -e ; for i in $(BESUBDIRS) $(IESUBDIRS) $(BSUBDIRS) $(ISUBDIRS) ; do $(MAKE) -C $$i $@ ; done
+clean: local-tidy local-clean $(BESUBDIRS) $(IESUBDIRS) $(BSUBDIRS) $(ISUBDIRS)
 
 local-dist:
 	find . \( -name '*~' -o -name '#*' -o -name core \
 		-o -name '.*.d' -o -name .depend \) -type f -print0 \
 	| xargs -0rt rm -f
 
-dist: local-dist local-tidy
-	set -e ; for i in $(BESUBDIRS) $(IESUBDIRS) $(BSUBDIRS) $(ISUBDIRS) ; do $(MAKE) -C $$i $@ ; done
+dist: local-dist local-tidy $(BESUBDIRS) $(IESUBDIRS) $(BSUBDIRS) $(ISUBDIRS)
 
 local-spotless:
 	rm -f $(BTARGET) .depend *.so.*
 
-spotless: local-clean local-dist local-spotless
-	set -e ; for i in $(BESUBDIRS) $(IESUBDIRS) $(BSUBDIRS) $(ISUBDIRS) ; do $(MAKE) -C $$i $@ ; done
+spotless: local-clean local-dist local-spotless $(BESUBDIRS) $(IESUBDIRS) $(ISUBDIRS) $(BSUBDIRS)
 
 # Shortcut to build linux/syslinux using klibc
 klibc:
 	$(MAKE) clean
 	$(MAKE) CC=klcc ITARGET= ISUBDIRS='linux extlinux' BSUBDIRS=
+endif # ifeq ($(HAVE_FIRMWARE),)
 
-# Hook to add private Makefile targets for the maintainer.
--include Makefile.private
+endif # ifeq ($(topdir),)
+
+#
+# Common rules that are needed by every invocation of make.
+#
+$(OBJDIR)/version.mk: $(topdir)/version $(topdir)/version.pl
+	$(PERL) $(topdir)/version.pl $< $@ '< := @'
diff --git a/Makefile.private b/Makefile.private
index 92127e9..37dd259 100644
--- a/Makefile.private
+++ b/Makefile.private
@@ -36,10 +36,10 @@
 	cdrecord -v blank=fast isolinux.iso
 
 official:
-	$(MAKE) spotless CC='$(CC) -m32'
-	$(MAKE) all CC='$(CC) -m32'
-	$(MAKE) strip CC='$(CC) -m32'
-	$(MAKE) dist CC='$(CC) -m32'
+	$(MAKE) spotless CC='$(CC) -m32' SRC=$(topdir) OBJ=$(CURDIR)
+	$(MAKE) all CC='$(CC) -m32' SRC=$(topdir) OBJ=$(CURDIR)
+	$(MAKE) strip CC='$(CC) -m32' SRC=$(topdir) OBJ=$(CURDIR)
+	$(MAKE) dist CC='$(CC) -m32' SRC=$(topdir) OBJ=$(CURDIR)
 
 release:
 	test -d release
diff --git a/NEWS b/NEWS
index c754631..11e692d 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,9 @@
 or EXTLINUX apply to that specific program only; other changes apply
 to all derivatives.
 
+Changes in 6.00:
+	* Add support for booting from EFI.
+
 Changes in 5.01:
 	* txt/: A new AsciiDoc documentation set (work-in-progress)
 	  (Gene Cumm).
diff --git a/codepage/Makefile b/codepage/Makefile
index 2a6fd12..18a590f 100644
--- a/codepage/Makefile
+++ b/codepage/Makefile
@@ -1,6 +1,8 @@
+VPATH		= $(SRC)
 PERL		= perl
-CPSRC		= $(wildcard *.txt)
-GENFILES	= $(patsubst %.txt,%.cp,$(CPSRC))
+CPSRC		= $(wildcard $(SRC)/*.txt)
+CPOBJ		= $(notdir $(CPSRC))
+GENFILES	= $(patsubst %.txt,%.cp,$(CPOBJ))
 
 .SUFFIXES: .txt .cp
 
@@ -9,7 +11,7 @@
 # This generates codepage files where the display and filesystem
 # codepages are both the same.
 %.cp: %.txt cptable.pl UnicodeData
-	$(PERL) cptable.pl UnicodeData $< $< $@
+	$(PERL) $(SRC)/cptable.pl $(SRC)/UnicodeData $< $< $@
 
 tidy:
 	rm -f *.cp *.bin
diff --git a/com32/Makefile b/com32/Makefile
index c4699cf..7ea1b01 100644
--- a/com32/Makefile
+++ b/com32/Makefile
@@ -1,5 +1,22 @@
 SUBDIRS = libupload tools lib elflink/ldlinux gpllib libutil modules mboot \
 	  menu samples elflink rosh cmenu hdt gfxboot sysdump lua/src chain
 
-all tidy dist clean spotless install:
-	set -e; for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done
+.PHONY: subdirs $(SUBDIRS)
+subdirs: $(SUBDIRS)
+$(SUBDIRS):
+	@mkdir -p $(OBJ)/$@
+	$(MAKE) -C $(OBJ)/$@ SRC="$(SRC)"/$@ OBJ="$(OBJ)"/$@/ \
+		-f $(SRC)/$@/Makefile $(MAKECMDGOALS)
+
+all tidy dist clean spotless install: subdirs
+
+# Parallel dependencies
+chain lua/src mboot menu: libutil gpllib
+cmenu: lib libutil
+elflink/ldlinux: lib
+gfxboot: libutil
+hdt: lib libupload cmenu gpllib libutil
+modules: lib libutil gpllib
+rosh: lib libutil
+samples: libutil elflink/ldlinux
+sysdump: libupload gpllib
diff --git a/com32/chain/Makefile b/com32/chain/Makefile
index ed37ffa..1a7ac9e 100644
--- a/com32/chain/Makefile
+++ b/com32/chain/Makefile
@@ -11,9 +11,7 @@
 ##
 ## -----------------------------------------------------------------------
 
-
-topdir = ../..
-MAKEDIR = $(topdir)/mk
+VPATH = $(SRC)
 include $(MAKEDIR)/elf.mk
 
 OBJS = chain.o partiter.o utility.o options.o mangle.o
diff --git a/com32/cmenu/Makefile b/com32/cmenu/Makefile
index d51b2e8..f432136 100644
--- a/com32/cmenu/Makefile
+++ b/com32/cmenu/Makefile
@@ -18,31 +18,34 @@
 NOGPL := 1
 
 LIBS  = libmenu/libmenu.c32 \
-        $(com32)/libutil/libutil.c32 \
-        $(com32)/lib/libcom32.c32
+        $(objdir)/com32/libutil/libutil.c32 \
+        $(objdir)/com32/lib/libcom32.c32
 
-topdir = ../..
-MAKEDIR = $(topdir)/mk
+VPATH = $(SRC)
 include $(MAKEDIR)/elf.mk
 
-CFLAGS	  += -I./libmenu
+CFLAGS	  += -I$(SRC)/libmenu
 
-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.c32 $(com32)/lib/libcom32.c32
+LIBMENU = $(objdir)/com32/libutil/libutil.c32 \
+	$(objdir)/com32/lib/libcom32.c32 \
+	libmenu/syslnx.o libmenu/com32io.o libmenu/tui.o \
+	libmenu/menu.o libmenu/passwords.o libmenu/des.o libmenu/help.o
 
-CMENUS = $(patsubst %.c,%.c32,$(wildcard *.c))
-IMENUS = $(patsubst %.menu,%.c32,$(wildcard *.menu))
+CMENUS = $(patsubst %.c,%.c32,$(wildcard $(SRC)/*.c))
+IMENUS = $(patsubst %.menu,%.c32,$(wildcard $(SRC)/*.menu))
 
-MENUS = $(LIBS) $(CMENUS) $(IMENUS)
+MENUS = $(LIBS) $(subst $(SRC)/,,$(CMENUS) $(IMENUS))
 
 .SUFFIXES: .S .c .o .elf .c32 .menu
 
 .PRECIOUS: %.c
 %.c: %.menu adv_menu.tpl
-	$(PYTHON) menugen.py --input=$< --output=$@ --template=adv_menu.tpl
+	$(PYTHON) $(SRC)/menugen.py --input=$< --output=$@ --template=$(SRC)/adv_menu.tpl
 
-all:	menus
+all:	makeoutputdirs menus
+
+makeoutputdirs:
+	@mkdir -p $(OBJ)/libmenu
 
 libmenu/libmenu.elf: $(LIBMENU)
 	$(LD) -shared $(LDFLAGS) -soname $(patsubst %.elf,%.c32,$(@F)) \
diff --git a/com32/elflink/ldlinux/Makefile b/com32/elflink/ldlinux/Makefile
index 556f93a..bfec450 100644
--- a/com32/elflink/ldlinux/Makefile
+++ b/com32/elflink/ldlinux/Makefile
@@ -10,20 +10,21 @@
 ##
 ## -----------------------------------------------------------------------
 
-topdir = ../../..
-MAKEDIR = $(topdir)/mk
+VPATH = $(SRC)
 include $(MAKEDIR)/elf.mk
 
 CFLAGS += -I$(topdir)/core/elflink -I$(topdir)/core/include -I$(topdir)/com32/lib -fvisibility=hidden
-LIBS = --whole-archive $(com32)/lib/libcom32min.a
+LIBS = --whole-archive $(objdir)/com32/lib/libcom32min.a
+
+OBJS = ldlinux.o cli.o readconfig.o refstr.o colors.o getadv.o adv.o \
+	execute.o chainboot.o kernel.o get_key.o advwrite.o setadv.o \
+	loadhigh.o msg.o
 
 BTARGET = ldlinux.c32
 
 all: $(BTARGET) ldlinux_lnx.a
 
-ldlinux.elf : ldlinux.o cli.o readconfig.o refstr.o colors.o getadv.o \
-		adv.o execute.o chainboot.o kernel.o get_key.o \
-		advwrite.o setadv.o loadhigh.o msg.o
+ldlinux.elf : $(OBJS)
 	$(LD) $(LDFLAGS) -soname $(patsubst %.elf,%.c32,$(@F)) -o $@ $^ $(LIBS)
 
 LNXCFLAGS += -D__export='__attribute__((visibility("default")))'
diff --git a/com32/elflink/ldlinux/adv.c b/com32/elflink/ldlinux/adv.c
index 4c3ad50..677fe92 100644
--- a/com32/elflink/ldlinux/adv.c
+++ b/com32/elflink/ldlinux/adv.c
@@ -32,24 +32,13 @@
  */
 
 #include <syslinux/adv.h>
+#include <syslinux/firmware.h>
 #include <klibc/compiler.h>
-#include <inttypes.h>
-#include <com32.h>
 
 __export void *__syslinux_adv_ptr;
 __export size_t __syslinux_adv_size;
 
-extern void adv_init(void);
 void __constructor __syslinux_init(void)
 {
-    static com32sys_t reg;
-
-    /* Initialize the ADV structure */
-    reg.eax.w[0] = 0x0025;
-    __intcall(0x22, &reg, NULL);
-
-    reg.eax.w[0] = 0x001c;
-    __intcall(0x22, &reg, &reg);
-    __syslinux_adv_ptr = MK_PTR(reg.es, reg.ebx.w[0]);
-    __syslinux_adv_size = reg.ecx.w[0];
+	firmware->adv_ops->init();
 }
diff --git a/com32/elflink/ldlinux/advwrite.c b/com32/elflink/ldlinux/advwrite.c
index 35829c1..47e4553 100644
--- a/com32/elflink/ldlinux/advwrite.c
+++ b/com32/elflink/ldlinux/advwrite.c
@@ -31,15 +31,11 @@
  * Write back the ADV
  */
 
-#include <syslinux/adv.h>
 #include <klibc/compiler.h>
-#include <com32.h>
+#include <syslinux/adv.h>
+#include <syslinux/firmware.h>
 
 __export 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;
+    return firmware->adv_ops->write();
 }
diff --git a/com32/elflink/ldlinux/get_key.c b/com32/elflink/ldlinux/get_key.c
index cece0f8..6cba124 100644
--- a/com32/elflink/ldlinux/get_key.c
+++ b/com32/elflink/ldlinux/get_key.c
@@ -112,6 +112,31 @@
     CODE(KEY_INSERT, "\033[2~"),
     CODE(KEY_INSERT, "\033[@"),
     CODE(KEY_DELETE, "\033[3~"),
+
+    /* EFI scan codes */
+    CODE(KEY_UP, "\0\x01"),
+    CODE(KEY_DOWN, "\0\x02"),
+    CODE(KEY_RIGHT, "\0\x03"),
+    CODE(KEY_LEFT, "\0\x04"),
+    CODE(KEY_HOME, "\0\x05"),
+    CODE(KEY_END, "\0\x06"),
+    CODE(KEY_INSERT, "\0\x07"),
+    CODE(KEY_DELETE, "\0\x08"),
+    CODE(KEY_PGUP, "\0\x09"),
+    CODE(KEY_PGDN, "\0\x0a"),
+    CODE(KEY_F1, "\0\x0b"),
+    CODE(KEY_F2, "\0\x0c"),
+    CODE(KEY_F3, "\0\x0d"),
+    CODE(KEY_F4, "\0\x0e"),
+    CODE(KEY_F5, "\0\x0f"),
+    CODE(KEY_F6, "\0\x10"),
+    CODE(KEY_F7, "\0\x11"),
+    CODE(KEY_F8, "\0\x12"),
+    CODE(KEY_F9, "\0\x13"),
+    CODE(KEY_F10, "\0\x14"),
+    CODE(KEY_F11, "\0\x15"),
+    CODE(KEY_F12, "\0\x16"),
+    CODE(KEY_ESC, "\0\x17"),
 };
 
 #define NCODES ((int)(sizeof keycodes/sizeof(struct keycode)))
diff --git a/com32/gfxboot/Makefile b/com32/gfxboot/Makefile
index bd0bab1..824d7d0 100644
--- a/com32/gfxboot/Makefile
+++ b/com32/gfxboot/Makefile
@@ -11,24 +11,35 @@
 ##
 ## -----------------------------------------------------------------------
 
-topdir = ../..
-MAKEDIR = $(topdir)/mk
+VPATH = $(SRC)
 include $(MAKEDIR)/elf.mk
 
 MODULES	  = gfxboot.c32
 
 all: $(MODULES)
 
-gfxboot.elf : gfxboot.o realmode_callback.o $(LIBS) $(C_LIBS)
+OBJS = gfxboot.o realmode_callback.o
+
+gfxboot.elf : $(OBJS) $(LIBS) $(C_LIBS)
 	$(LD) $(LDFLAGS) -o $@ $^
 
 realmode_callback.o: realmode_callback.asm
+ifeq ($(ARCH),i386)
 	$(NASM) -f bin -O99 -o $*.tmp -l $*.lst $<
 	$(OBJCOPY) -B i386 -I binary -O elf32-i386 \
 	  --redefine-sym _binary_$*_tmp_start=$*_start \
 	  --redefine-sym _binary_$*_tmp_end=$*_end \
 	  --strip-symbol _binary_$*_tmp_size \
 	  $*.tmp $@
+endif
+ifeq ($(ARCH),x86_64)
+	$(NASM) -f bin -O99 -o $*.tmp -l $*.lst $<
+	$(OBJCOPY) -B i386:x86-64 -I binary -O elf64-x86-64 \
+	  --redefine-sym _binary_$*_tmp_start=$*_start \
+	  --redefine-sym _binary_$*_tmp_end=$*_end \
+	  --strip-symbol _binary_$*_tmp_size \
+	  $*.tmp $@
+endif
 
 tidy dist:
 	rm -f *.o *.lo *.a *.lst .*.d *.tmp
diff --git a/com32/gpllib/Makefile b/com32/gpllib/Makefile
index 3ccc0dc..e3e30d7 100644
--- a/com32/gpllib/Makefile
+++ b/com32/gpllib/Makefile
@@ -3,14 +3,12 @@
 #
 
 # Include configuration rules
-topdir = ../..
-MAKEDIR = $(topdir)/mk
 include $(MAKEDIR)/lib.mk
 
-REQFLAGS += -I../gplinclude -I../gplinclude/zzjson
+REQFLAGS += -I$(SRC)/../gplinclude -I$(SRC)/../gplinclude/zzjson
 
-GPLDIRS := . disk dmi vpd acpi zzjson
-LIBOBJS := $(foreach dir,$(GPLDIRS),$(patsubst %.c,%.o,$(wildcard $(dir)/*.c)))
+GPLDIRS := $(SRC) $(addprefix $(SRC)/,disk dmi vpd acpi zzjson)
+LIBOBJS := $(subst $(SRC)/,,$(foreach dir,$(GPLDIRS),$(patsubst %.c,%.o,$(wildcard $(dir)/*.c))))
 
 BINDIR   = /usr/bin
 LIBDIR   = /usr/lib
@@ -19,7 +17,11 @@
 INCDIR   = /usr/include
 COM32DIR = $(AUXDIR)/com32
 
-all: libgpl.c32
+all: makeoutputdirs libgpl.c32
+
+makeoutputdirs:
+	@mkdir -p $(foreach b, \
+		$(addprefix $(OBJ),$(sort $(dir $(LIBOBJS)))),$(b))
 
 libgpl.elf : $(LIBOBJS)
 	$(LD) -shared $(LDFLAGS) -soname $(patsubst %.elf,%.c32,$(@F)) -o $@ $^
@@ -38,6 +40,6 @@
 	mkdir -m 755 -p $(INSTALLROOT)$(COM32DIR)
 	install -m 644 libgpl.c32 $(INSTALLROOT)$(COM32DIR)
 	mkdir -p $(INSTALLROOT)$(COM32DIR)/include/
-	cp -r ../gplinclude $(INSTALLROOT)$(COM32DIR)/include/
+	cp -r $(SRC)/../gplinclude $(INSTALLROOT)$(COM32DIR)/include/
 
 -include .*.d */.*.d */*/.*.d
diff --git a/com32/hdt/Makefile b/com32/hdt/Makefile
index 42f5c0d..80f2d0a 100644
--- a/com32/hdt/Makefile
+++ b/com32/hdt/Makefile
@@ -15,18 +15,17 @@
 ## Hardware Detection Tool
 ##
 
-topdir = ../..
-MAKEDIR = $(topdir)/mk
+VPATH = $(SRC)
 include $(MAKEDIR)/elf.mk
 
-LIBS      = ../libupload/libcom32upload.a
-C_LIBS    += $(com32)/cmenu/libmenu/libmenu.c32
+LIBS      = $(objdir)/com32/libupload/libcom32upload.a
+C_LIBS    += $(objdir)/com32/cmenu/libmenu/libmenu.c32
 CFLAGS    += -I$(com32)/cmenu/libmenu -I$(com32)
 
 MODULES	  = hdt.c32
 TESTFILES =
 
-OBJS	  = $(patsubst %.c,%.o,$(wildcard *.c))
+OBJS	  = $(subst $(SRC)/,,$(patsubst %.c,%.o,$(wildcard $(SRC)/*.c)))
 VERSION   = $(shell $(SED) -n 's/\#define VERSION \"\(.*\)\"/\1/p' hdt.h)
 CODENAME  = $(shell $(SED) -n 's/\#define CODENAME \"\(.*\)\"/\1/p' hdt.h)
 NODASH_VERSION = $(shell echo $(VERSION) | $(SED) -e 's/-/_/g' | $(SED) -e 's/\./_/g')
diff --git a/com32/include/bitsize/limits.h b/com32/include/bitsize/limits.h
index f90e524..7129c4a 100644
--- a/com32/include/bitsize/limits.h
+++ b/com32/include/bitsize/limits.h
@@ -5,10 +5,12 @@
 #ifndef _BITSIZE_LIMITS_H
 #define _BITSIZE_LIMITS_H
 
-#define LONG_BIT	32
-
-#define LONG_MIN	(-2147483647L-1)
-#define LONG_MAX	2147483647L
-#define ULONG_MAX	4294967295UL
+#if __SIZEOF_POINTER__ == 4
+#include <bitsize32/limits.h>
+#elif __SIZEOF_POINTER__ == 8
+#include <bitsize64/limits.h>
+#else
+#error "Unable to build for to-be-defined architecture type"
+#endif
 
 #endif /* _BITSIZE_LIMITS_H */
diff --git a/com32/include/bitsize/stddef.h b/com32/include/bitsize/stddef.h
index 213e8ab..04418a0 100644
--- a/com32/include/bitsize/stddef.h
+++ b/com32/include/bitsize/stddef.h
@@ -1,14 +1,16 @@
 /*
- * bits32/stddef.h
+ * Include stddef.h as appropriate for architecture
  */
 
 #ifndef _BITSIZE_STDDEF_H
 #define _BITSIZE_STDDEF_H
 
-#define _SIZE_T
-typedef unsigned int size_t;
-
-#define _PTRDIFF_T
-typedef signed long ptrdiff_t;
+#if __SIZEOF_POINTER__ == 4
+#include <bitsize32/stddef.h>
+#elif __SIZEOF_POINTER__ == 8
+#include <bitsize64/stddef.h>
+#else
+#error "Unable to build for to-be-defined architecture type"
+#endif
 
 #endif /* _BITSIZE_STDDEF_H */
diff --git a/com32/include/bitsize/stdint.h b/com32/include/bitsize/stdint.h
index 8e444b6..7e7b235 100644
--- a/com32/include/bitsize/stdint.h
+++ b/com32/include/bitsize/stdint.h
@@ -8,27 +8,16 @@
 typedef signed char		int8_t;
 typedef short int		int16_t;
 typedef int			int32_t;
-typedef long long int		int64_t;
 
 typedef unsigned char		uint8_t;
 typedef unsigned short int	uint16_t;
 typedef unsigned int		uint32_t;
-typedef unsigned long long int	uint64_t;
 
-typedef int			int_fast16_t;
-typedef int			int_fast32_t;
-
-typedef unsigned int		uint_fast16_t;
-typedef unsigned int		uint_fast32_t;
-
-typedef int			intptr_t;
-typedef unsigned int		uintptr_t;
-
-#define __INT64_C(c)   c ## LL
-#define __UINT64_C(c)  c ## ULL
-
-#define __PRI64_RANK   "ll"
-#define __PRIFAST_RANK ""
-#define __PRIPTR_RANK  ""
-
+#if __SIZEOF_POINTER__ == 4
+#include <bitsize32/stdint.h>
+#elif __SIZEOF_POINTER__ == 8
+#include <bitsize64/stdint.h>
+#else
+#error "Unable to build for to-be-defined architecture type"
+#endif
 #endif				/* _BITSIZE_STDINT_H */
diff --git a/com32/include/bitsize/stdintconst.h b/com32/include/bitsize/stdintconst.h
index 7db63bd..b2f3141 100644
--- a/com32/include/bitsize/stdintconst.h
+++ b/com32/include/bitsize/stdintconst.h
@@ -1,18 +1,16 @@
 /*
- * bits32/stdintconst.h
+ * bitsize/stdintconst.h
  */
 
 #ifndef _BITSIZE_STDINTCONST_H
 #define _BITSIZE_STDINTCONST_H
 
-#define INT_FAST16_C(c)	 INT32_C(c)
-#define INT_FAST32_C(c)  INT32_C(c)
-
-#define UINT_FAST16_C(c) UINT32_C(c)
-#define UINT_FAST32_C(c) UINT32_C(c)
-
-#define INTPTR_C(c)	 INT32_C(c)
-#define UINTPTR_C(c)	 UINT32_C(c)
-#define PTRDIFF_C(c)     INT32_C(c)
+#if __SIZEOF_POINTER__ == 4
+#include <bitsize32/stdintconst.h>
+#elif __SIZEOF_POINTER__ == 8
+#include <bitsize64/stdintconst.h>
+#else
+#error "Unable to build for to-be-defined architecture type"
+#endif
 
 #endif				/* _BITSIZE_STDINTCONST_H */
diff --git a/com32/include/bitsize/stdintlimits.h b/com32/include/bitsize/stdintlimits.h
index d85094d..c342c44 100644
--- a/com32/include/bitsize/stdintlimits.h
+++ b/com32/include/bitsize/stdintlimits.h
@@ -1,22 +1,16 @@
 /*
- * bits32/stdintlimits.h
+ * bitsize/stdintlimits.h
  */
 
 #ifndef _BITSIZE_STDINTLIMITS_H
 #define _BITSIZE_STDINTLIMITS_H
 
-#define INT_FAST16_MIN	INT32_MIN
-#define INT_FAST32_MIN	INT32_MIN
-#define INT_FAST16_MAX	INT32_MAX
-#define INT_FAST32_MAX	INT32_MAX
-#define UINT_FAST16_MAX UINT32_MAX
-#define UINT_FAST32_MAX UINT32_MAX
-
-#define INTPTR_MIN	INT32_MIN
-#define INTPTR_MAX	INT32_MAX
-#define UINTPTR_MAX	UINT32_MAX
-
-#define PTRDIFF_MIN	INT32_MIN
-#define PTRDIFF_MAX	INT32_MAX
+#if __SIZEOF_POINTER__ == 4
+#include <bitsize32/stdintlimits.h>
+#elif __SIZEOF_POINTER__ == 8
+#include <bitsize64/stdintlimits.h>
+#else
+#error "Unable to build for to-be-defined architecture type"
+#endif
 
 #endif				/* _BITSIZE_STDINTLIMITS_H */
diff --git a/com32/include/bitsize32/limits.h b/com32/include/bitsize32/limits.h
new file mode 100644
index 0000000..f19205f
--- /dev/null
+++ b/com32/include/bitsize32/limits.h
@@ -0,0 +1,14 @@
+/*
+ * bits32/limits.h
+ */
+
+#ifndef _BITSIZE32_LIMITS_H
+#define _BITSIZE32_LIMITS_H
+
+#define LONG_BIT	32
+
+#define LONG_MIN	(-2147483647L-1)
+#define LONG_MAX	2147483647L
+#define ULONG_MAX	4294967295UL
+
+#endif				/* _BITSIZE_LIMITS_H */
diff --git a/com32/include/bitsize32/stddef.h b/com32/include/bitsize32/stddef.h
new file mode 100644
index 0000000..c34c675
--- /dev/null
+++ b/com32/include/bitsize32/stddef.h
@@ -0,0 +1,9 @@
+/*
+ * bits32/stddef.h
+ */
+
+#define _SIZE_T
+typedef unsigned int size_t;
+
+#define _PTRDIFF_T
+typedef signed long ptrdiff_t;
diff --git a/com32/include/bitsize32/stdint.h b/com32/include/bitsize32/stdint.h
new file mode 100644
index 0000000..bdc6970
--- /dev/null
+++ b/com32/include/bitsize32/stdint.h
@@ -0,0 +1,24 @@
+/*
+ * bits32/stdint.h
+ */
+
+
+typedef long long int		int64_t;
+
+typedef unsigned long long int	uint64_t;
+
+typedef int			int_fast16_t;
+typedef int			int_fast32_t;
+
+typedef unsigned int		uint_fast16_t;
+typedef unsigned int		uint_fast32_t;
+
+typedef int			intptr_t;
+typedef unsigned int		uintptr_t;
+
+#define __INT64_C(c)   c ## LL
+#define __UINT64_C(c)  c ## ULL
+
+#define __PRI64_RANK   "ll"
+#define __PRIFAST_RANK ""
+#define __PRIPTR_RANK  ""
diff --git a/com32/include/bitsize32/stdintconst.h b/com32/include/bitsize32/stdintconst.h
new file mode 100644
index 0000000..71ece42
--- /dev/null
+++ b/com32/include/bitsize32/stdintconst.h
@@ -0,0 +1,13 @@
+/*
+ * bits32/stdintconst.h
+ */
+
+#define INT_FAST16_C(c)	 INT32_C(c)
+#define INT_FAST32_C(c)  INT32_C(c)
+
+#define UINT_FAST16_C(c) UINT32_C(c)
+#define UINT_FAST32_C(c) UINT32_C(c)
+
+#define INTPTR_C(c)	 INT32_C(c)
+#define UINTPTR_C(c)	 UINT32_C(c)
+#define PTRDIFF_C(c)     INT32_C(c)
diff --git a/com32/include/bitsize32/stdintlimits.h b/com32/include/bitsize32/stdintlimits.h
new file mode 100644
index 0000000..175cdcd
--- /dev/null
+++ b/com32/include/bitsize32/stdintlimits.h
@@ -0,0 +1,23 @@
+/*
+ * bits32/stdintlimits.h
+ */
+
+#define INT_FAST16_MIN	INT32_MIN
+#define INT_FAST32_MIN	INT32_MIN
+#define INT_FAST16_MAX	INT32_MAX
+#define INT_FAST32_MAX	INT32_MAX
+#define UINT_FAST16_MAX UINT32_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+
+#define INTPTR_MIN	INT32_MIN
+#define INTPTR_MAX	INT32_MAX
+#define UINTPTR_MAX	UINT32_MAX
+
+#define PTRDIFF_MIN	INT32_MIN
+#define PTRDIFF_MAX	INT32_MAX
+
+/* sig_atomic_t limit */
+# define SIG_ATOMIC_MIN         INT32_MIN //(-2147483647-1)
+# define SIG_ATOMIC_MAX         INT32_MAX //(2147483647)
+/* size_t limit */
+# define SIZE_MAX		UINT32_MAX //(4294967295U)
diff --git a/com32/include/bitsize64/limits.h b/com32/include/bitsize64/limits.h
new file mode 100644
index 0000000..1acb1bc
--- /dev/null
+++ b/com32/include/bitsize64/limits.h
@@ -0,0 +1,14 @@
+/*
+ * bits64/limits.h
+ */
+
+#ifndef _BITSIZE64_LIMITS_H
+#define _BITSIZE64_LIMITS_H
+
+#define LONG_BIT	64
+
+#define LONG_MIN	(-9223372036854775807L-1)
+#define LONG_MAX	9223372036854775807L
+#define ULONG_MAX	18446744073709551615UL
+
+#endif				/* _BITSIZE_LIMITS_H */
diff --git a/com32/include/bitsize64/stddef.h b/com32/include/bitsize64/stddef.h
new file mode 100644
index 0000000..c61bf8c
--- /dev/null
+++ b/com32/include/bitsize64/stddef.h
@@ -0,0 +1,10 @@
+/*
+ * bits64/stddef.h
+ */
+
+#define _SIZE_T
+typedef unsigned long size_t;
+
+#define _PTRDIFF_T
+typedef signed long ptrdiff_t;
+
diff --git a/com32/include/bitsize64/stdint.h b/com32/include/bitsize64/stdint.h
new file mode 100644
index 0000000..9193000
--- /dev/null
+++ b/com32/include/bitsize64/stdint.h
@@ -0,0 +1,24 @@
+/*
+ * bits64/stdint.h
+ */
+
+
+typedef long int		int64_t;
+
+typedef unsigned long int	uint64_t;
+
+typedef long int		int_fast16_t;
+typedef long int		int_fast32_t;
+
+typedef unsigned long int	uint_fast16_t;
+typedef unsigned long int	uint_fast32_t;
+
+typedef long int		intptr_t;
+typedef unsigned long int	uintptr_t;
+
+#define __INT64_C(c)  c ## L
+#define __UINT64_C(c) c ## UL
+
+#define __PRI64_RANK	"l"
+#define __PRIFAST_RANK  "l"
+#define __PRIPTR_RANK	"l"
diff --git a/com32/include/bitsize64/stdintconst.h b/com32/include/bitsize64/stdintconst.h
new file mode 100644
index 0000000..139ab20
--- /dev/null
+++ b/com32/include/bitsize64/stdintconst.h
@@ -0,0 +1,13 @@
+/*
+ * bits64/stdintconst.h
+ */
+
+#define INT_FAST16_C(c)	 INT64_C(c)
+#define INT_FAST32_C(c)  INT64_C(c)
+
+#define UINT_FAST16_C(c) UINT64_C(c)
+#define UINT_FAST32_C(c) UINT64_C(c)
+
+#define INTPTR_C(c)	 INT64_C(c)
+#define UINTPTR_C(c)	 UINT64_C(c)
+#define PTRDIFF_C(c)     INT64_C(c)
diff --git a/com32/include/bitsize64/stdintlimits.h b/com32/include/bitsize64/stdintlimits.h
new file mode 100644
index 0000000..a775a7f
--- /dev/null
+++ b/com32/include/bitsize64/stdintlimits.h
@@ -0,0 +1,23 @@
+/*
+ * bits64/stdintlimits.h
+ */
+
+#define INT_FAST16_MIN	INT64_MIN
+#define INT_FAST32_MIN	INT64_MIN
+#define INT_FAST16_MAX	INT64_MAX
+#define INT_FAST32_MAX	INT64_MAX
+#define UINT_FAST16_MAX UINT64_MAX
+#define UINT_FAST32_MAX UINT64_MAX
+
+#define INTPTR_MIN	INT64_MIN
+#define INTPTR_MAX	INT64_MAX
+#define UINTPTR_MAX	UINT64_MAX
+
+#define PTRDIFF_MIN	INT64_MIN
+#define PTRDIFF_MAX	INT64_MAX
+
+/* sig_atomic_t limit */
+# define SIG_ATOMIC_MAX         INT32_MAX //(2147483647)
+# define SIG_ATOMIC_MIN         (-SIG_ATOMIC_MAX-1) //(-2147483647-1)
+/* size_t limit */
+# define SIZE_MAX		UINT64_MAX
diff --git a/com32/include/com32.h b/com32/include/com32.h
index 148d08e..c5d6017 100644
--- a/com32/include/com32.h
+++ b/com32/include/com32.h
@@ -135,7 +135,7 @@
  * specific segment.  OFFS_VALID() will return whether or not the
  * pointer is actually reachable from the target segment.
  */
-#if defined(DEBUG) && (defined(__COM32__) || defined(__SYSLINUX_CORE__))
+#if defined(CORE_DEBUG) && (defined(__COM32__) || defined(__SYSLINUX_CORE__))
 __noreturn __bad_SEG(const volatile void *);
 
 static inline uint16_t SEG(const volatile void *__p)
@@ -176,7 +176,7 @@
 
 static inline void *MK_PTR(uint16_t __seg, uint16_t __offs)
 {
-    return (void *)((__seg << 4) + __offs);
+    return (void *)(unsigned long)((__seg << 4) + __offs);
 }
 
 /* Some tools to handle 16:16 far pointers in memory */
diff --git a/com32/include/dprintf.h b/com32/include/dprintf.h
index 26ca734..de4625b 100644
--- a/com32/include/dprintf.h
+++ b/com32/include/dprintf.h
@@ -6,10 +6,10 @@
 #define _DPRINTF_H
 
 #if !defined(DEBUG_PORT) && !defined(DEBUG_STDIO)
-# undef DEBUG
+# undef CORE_DEBUG
 #endif
 
-#ifdef DEBUG
+#ifdef CORE_DEBUG
 
 # include <stdio.h>
 
@@ -26,9 +26,9 @@
 # define dprintf(fmt, ...)	((void)(0))
 # define vdprintf(fmt, ap)	((void)(0))
 
-#endif /* DEBUG */
+#endif /* CORE_DEBUG */
 
-# if DEBUG >= 2
+# if CORE_DEBUG >= 2
 /* Really verbose debugging... */
 #  define dprintf2  dprintf
 #  define vdprintf2 vdprintf
diff --git a/com32/include/klibc/i386/archsetjmp.h b/com32/include/klibc/i386/archsetjmp.h
new file mode 100644
index 0000000..a0def6a
--- /dev/null
+++ b/com32/include/klibc/i386/archsetjmp.h
@@ -0,0 +1,19 @@
+/*
+ * arch/i386/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+    unsigned int __ebx;
+    unsigned int __esp;
+    unsigned int __ebp;
+    unsigned int __esi;
+    unsigned int __edi;
+    unsigned int __eip;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif /* _SETJMP_H */
diff --git a/com32/include/klibc/x86_64/archsetjmp.h b/com32/include/klibc/x86_64/archsetjmp.h
new file mode 100644
index 0000000..454fc60
--- /dev/null
+++ b/com32/include/klibc/x86_64/archsetjmp.h
@@ -0,0 +1,21 @@
+/*
+ * arch/x86_64/include/klibc/archsetjmp.h
+ */
+
+#ifndef _KLIBC_ARCHSETJMP_H
+#define _KLIBC_ARCHSETJMP_H
+
+struct __jmp_buf {
+	unsigned long __rbx;
+	unsigned long __rsp;
+	unsigned long __rbp;
+	unsigned long __r12;
+	unsigned long __r13;
+	unsigned long __r14;
+	unsigned long __r15;
+	unsigned long __rip;
+};
+
+typedef struct __jmp_buf jmp_buf[1];
+
+#endif				/* _SETJMP_H */
diff --git a/com32/include/netinet/in.h b/com32/include/netinet/in.h
index d2af351..d3fba17 100644
--- a/com32/include/netinet/in.h
+++ b/com32/include/netinet/in.h
@@ -27,8 +27,16 @@
 
 static inline __constfunc uint32_t __htonl(uint32_t v)
 {
+#if __SIZEOF_POINTER__ == 4
     asm("xchgb %h0,%b0 ; roll $16,%0 ; xchgb %h0,%b0"
 	: "+q" (v));
+#elif __SIZEOF_POINTER__ == 8
+    asm("bswap	%0"
+	: "=r" (v)
+	: "0" (v));
+#else
+#error "unable to build for architecture"
+#endif
     return v;
 }
 
diff --git a/com32/include/setjmp.h b/com32/include/setjmp.h
index 11b18fb..e709095 100644
--- a/com32/include/setjmp.h
+++ b/com32/include/setjmp.h
@@ -9,7 +9,13 @@
 #include <klibc/compiler.h>
 #include <stddef.h>
 
-#include <klibc/archsetjmp.h>
+#if __SIZEOF_POINTER__ == 4
+#include <klibc/i386/archsetjmp.h>
+#elif __SIZEOF_POINTER__ == 8
+#include <klibc/x86_64/archsetjmp.h>
+#else
+#error "unsupported architecture"
+#endif
 
 __extern int setjmp(jmp_buf);
 __extern __noreturn longjmp(jmp_buf, int);
diff --git a/com32/include/sys/bitops.h b/com32/include/sys/bitops.h
index 40e09fe..de30d93 100644
--- a/com32/include/sys/bitops.h
+++ b/com32/include/sys/bitops.h
@@ -36,27 +36,11 @@
 
 #include <klibc/compiler.h>
 
-static inline void set_bit(long __bit, void *__bitmap)
-{
-    asm volatile("btsl %1,%0"
-		 : "+m" (*(unsigned char *)__bitmap)
-		 : "Ir" (__bit) : "memory");
-}
-
-static inline void clr_bit(long __bit, void *__bitmap)
-{
-    asm volatile("btcl %1,%0"
-		 : "+m" (*(unsigned char *)__bitmap)
-		 : "Ir" (__bit) : "memory");
-}
-
-static inline int __purefunc test_bit(long __bit, const void *__bitmap)
-{
-    unsigned char __r;
-    asm("btl %2,%1; setc %0"
-	: "=qm" (__r)
-	: "m" (*(const unsigned char *)__bitmap), "Ir" (__bit));
-    return __r;
-}
-
+#if __SIZEOF_POINTER__ == 4
+#include <i386/bitops.h>
+#elif __SIZEOF_POINTER__ == 8
+#include <x86_64/bitops.h>
+#else
+#error "Unable to build for to-be-defined architecture type"
+#endif
 #endif /* _BITOPS_H */
diff --git a/com32/include/sys/cpu.h b/com32/include/sys/cpu.h
index 53a6250..05c9884 100644
--- a/com32/include/sys/cpu.h
+++ b/com32/include/sys/cpu.h
@@ -5,138 +5,12 @@
 #include <stdint.h>
 #include <klibc/compiler.h>
 
-static inline uint64_t rdtsc(void)
-{
-    uint64_t v;
-    asm volatile("rdtsc" : "=A" (v));
-    return v;
-}
-
-static inline uint32_t rdtscl(void)
-{
-    uint32_t v;
-    asm volatile("rdtsc" : "=a" (v) : : "edx");
-    return v;
-}
-
-static inline void cpuid_count(uint32_t op, uint32_t cnt,
-			       uint32_t * eax, uint32_t * ebx,
-			       uint32_t * ecx, uint32_t * edx)
-{
-    asm volatile("movl %%ebx,%1 ; "
-		 "cpuid ; "
-		 "xchgl %1,%%ebx"
-		 : "=a" (*eax), "=SD" (*ebx), "=c" (*ecx), "=d" (*edx)
-		 : "a"(op), "c"(cnt));
-}
-
-static inline void cpuid(uint32_t op, uint32_t * eax, uint32_t * ebx,
-			 uint32_t * ecx, uint32_t * edx)
-{
-    cpuid_count(op, 0, eax, ebx, ecx, edx);
-}
-
-static inline __constfunc uint32_t cpuid_eax(uint32_t level)
-{
-    uint32_t v;
-
-    asm volatile("pushl %%ebx ; "
-		 "cpuid ; "
-		 "popl %%ebx"
-		 : "=a" (v)
-		 : "a"(level)
-		 : "ecx", "edx");
-    return v;
-}
-
-static inline __constfunc uint32_t cpuid_ebx(uint32_t level)
-{
-    uint32_t v;
-
-    asm volatile("movl %%ebx,%0 ; "
-		 "cpuid ; "
-		 "xchgl %0,%%ebx"
-		 : "=SD" (v), "+a" (level)
-		 : : "ecx", "edx");
-    return v;
-}
-
-static inline __constfunc uint32_t cpuid_ecx(uint32_t level)
-{
-    uint32_t v;
-
-    asm volatile("pushl %%ebx ; "
-		 "cpuid ; "
-		 "popl %%ebx"
-		 : "=c" (v), "+a" (level)
-		 : : "edx");
-    return v;
-}
-
-static inline __constfunc uint32_t cpuid_edx(uint32_t level)
-{
-    uint32_t v;
-
-    asm volatile("pushl %%ebx ; "
-		 "cpuid ; "
-		 "popl %%ebx"
-		 : "=d" (v), "+a" (level)
-		 : : "ecx");
-    return v;
-}
-
-/* Standard macro to see if a specific flag is changeable */
-static inline __constfunc bool cpu_has_eflag(uint32_t flag)
-{
-	uint32_t f0, f1;
-
-	asm("pushfl ; "
-	    "pushfl ; "
-	    "popl %0 ; "
-	    "movl %0,%1 ; "
-	    "xorl %2,%1 ; "
-	    "pushl %1 ; "
-	    "popfl ; "
-	    "pushfl ; "
-	    "popl %1 ; "
-	    "popfl"
-	    : "=&r" (f0), "=&r" (f1)
-	    : "ri" (flag));
-
-	return !!((f0^f1) & flag);
-}
-
-static inline uint64_t rdmsr(uint32_t msr)
-{
-    uint64_t v;
-
-    asm volatile("rdmsr" : "=A" (v) : "c"(msr));
-    return v;
-}
-
-static inline void wrmsr(uint64_t v, uint32_t msr)
-{
-    asm volatile("wrmsr" : : "A" (v), "c" (msr));
-}
-
-static inline void cpu_relax(void)
-{
-    asm volatile("rep ; nop");
-}
-
-static inline void hlt(void)
-{
-    asm volatile("hlt");
-}
-
-static inline void cli(void)
-{
-    asm volatile("cli");
-}
-
-static inline void sti(void)
-{
-    asm volatile("sti");
-}
+#if __SIZEOF_POINTER__ == 4
+#include <i386/cpu.h>
+#elif __SIZEOF_POINTER__ == 8
+#include <x86_64/cpu.h>
+#else 
+#error "unsupported architecture"
+#endif
 
 #endif
diff --git a/com32/include/sys/elfcommon.h b/com32/include/sys/elfcommon.h
index 8d6ddb0..99b5ad1 100644
--- a/com32/include/sys/elfcommon.h
+++ b/com32/include/sys/elfcommon.h
@@ -361,4 +361,54 @@
 /* Keep this the last entry.  */
 #define R_386_NUM	   38
 
+/* AMD x86-64 relocations.  */
+#define R_X86_64_NONE		0	/* No reloc */
+#define R_X86_64_64		1	/* Direct 64 bit  */
+#define R_X86_64_PC32		2	/* PC relative 32 bit signed */
+#define R_X86_64_GOT32		3	/* 32 bit GOT entry */
+#define R_X86_64_PLT32		4	/* 32 bit PLT address */
+#define R_X86_64_COPY		5	/* Copy symbol at runtime */
+#define R_X86_64_GLOB_DAT	6	/* Create GOT entry */
+#define R_X86_64_JUMP_SLOT	7	/* Create PLT entry */
+#define R_X86_64_RELATIVE	8	/* Adjust by program base */
+#define R_X86_64_GOTPCREL	9	/* 32 bit signed PC relative
+					   offset to GOT */
+#define R_X86_64_32		10	/* Direct 32 bit zero extended */
+#define R_X86_64_32S		11	/* Direct 32 bit sign extended */
+#define R_X86_64_16		12	/* Direct 16 bit zero extended */
+#define R_X86_64_PC16		13	/* 16 bit sign extended pc relative */
+#define R_X86_64_8		14	/* Direct 8 bit sign extended  */
+#define R_X86_64_PC8		15	/* 8 bit sign extended pc relative */
+#define R_X86_64_DTPMOD64	16	/* ID of module containing symbol */
+#define R_X86_64_DTPOFF64	17	/* Offset in module's TLS block */
+#define R_X86_64_TPOFF64	18	/* Offset in initial TLS block */
+#define R_X86_64_TLSGD		19	/* 32 bit signed PC relative offset
+					   to two GOT entries for GD symbol */
+#define R_X86_64_TLSLD		20	/* 32 bit signed PC relative offset
+					   to two GOT entries for LD symbol */
+#define R_X86_64_DTPOFF32	21	/* Offset in TLS block */
+#define R_X86_64_GOTTPOFF	22	/* 32 bit signed PC relative offset
+					   to GOT entry for IE symbol */
+#define R_X86_64_TPOFF32	23	/* Offset in initial TLS block */
+#define R_X86_64_PC64		24	/* PC relative 64 bit */
+#define R_X86_64_GOTOFF64	25	/* 64 bit offset to GOT */
+#define R_X86_64_GOTPC32	26	/* 32 bit signed pc relative
+					   offset to GOT */
+#define R_X86_64_GOT64		27	/* 64-bit GOT entry offset */
+#define R_X86_64_GOTPCREL64	28	/* 64-bit PC relative offset
+					   to GOT entry */
+#define R_X86_64_GOTPC64	29	/* 64-bit PC relative offset to GOT */
+#define R_X86_64_GOTPLT64	30 	/* like GOT64, says PLT entry needed */
+#define R_X86_64_PLTOFF64	31	/* 64-bit GOT relative offset
+					   to PLT entry */
+#define R_X86_64_SIZE32		32	/* Size of symbol plus 32-bit addend */
+#define R_X86_64_SIZE64		33	/* Size of symbol plus 64-bit addend */
+#define R_X86_64_GOTPC32_TLSDESC 34	/* GOT offset for TLS descriptor.  */
+#define R_X86_64_TLSDESC_CALL   35	/* Marker for call through TLS
+					   descriptor.  */
+#define R_X86_64_TLSDESC        36	/* TLS descriptor.  */
+#define R_X86_64_IRELATIVE	37	/* Adjust indirectly by program base */
+
+#define R_X86_64_NUM		38
+
 #endif				/* _SYS_ELFCOMMON_H */
diff --git a/com32/include/sys/i386/bitops.h b/com32/include/sys/i386/bitops.h
new file mode 100644
index 0000000..663b267
--- /dev/null
+++ b/com32/include/sys/i386/bitops.h
@@ -0,0 +1,54 @@
+/* ----------------------------------------------------------------------- *
+ *   
+ *   Copyright 2010-2011 Intel Corporation; author: H. Peter Anvin
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *   
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *   
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * i386 bitops.h
+ *
+ * Simple bitwise operations
+ */
+static inline void set_bit(long __bit, void *__bitmap)
+{
+    asm volatile("btsl %1,%0"
+		 : "+m" (*(unsigned char *)__bitmap)
+		 : "Ir" (__bit) : "memory");
+}
+
+static inline void clr_bit(long __bit, void *__bitmap)
+{
+    asm volatile("btcl %1,%0"
+		 : "+m" (*(unsigned char *)__bitmap)
+		 : "Ir" (__bit) : "memory");
+}
+
+static inline int __purefunc test_bit(long __bit, const void *__bitmap)
+{
+    unsigned char __r;
+    asm("btl %2,%1; setc %0"
+	: "=qm" (__r)
+	: "m" (*(const unsigned char *)__bitmap), "Ir" (__bit));
+    return __r;
+}
diff --git a/com32/include/sys/i386/cpu.h b/com32/include/sys/i386/cpu.h
new file mode 100644
index 0000000..63d0f5e
--- /dev/null
+++ b/com32/include/sys/i386/cpu.h
@@ -0,0 +1,135 @@
+/* i386 cpu.h */
+
+static inline uint64_t rdtsc(void)
+{
+    uint64_t v;
+    asm volatile("rdtsc" : "=A" (v));
+    return v;
+}
+
+static inline uint32_t rdtscl(void)
+{
+    uint32_t v;
+    asm volatile("rdtsc" : "=a" (v) : : "edx");
+    return v;
+}
+
+static inline void cpuid_count(uint32_t op, uint32_t cnt,
+			       uint32_t * eax, uint32_t * ebx,
+			       uint32_t * ecx, uint32_t * edx)
+{
+    asm volatile("movl %%ebx,%1 ; "
+		 "cpuid ; "
+		 "xchgl %1,%%ebx"
+		 : "=a" (*eax), "=SD" (*ebx), "=c" (*ecx), "=d" (*edx)
+		 : "a"(op), "c"(cnt));
+}
+
+static inline void cpuid(uint32_t op, uint32_t * eax, uint32_t * ebx,
+			 uint32_t * ecx, uint32_t * edx)
+{
+    cpuid_count(op, 0, eax, ebx, ecx, edx);
+}
+
+static inline __constfunc uint32_t cpuid_eax(uint32_t level)
+{
+    uint32_t v;
+
+    asm volatile("pushl %%ebx ; "
+		 "cpuid ; "
+		 "popl %%ebx"
+		 : "=a" (v)
+		 : "a"(level)
+		 : "ecx", "edx");
+    return v;
+}
+
+static inline __constfunc uint32_t cpuid_ebx(uint32_t level)
+{
+    uint32_t v;
+
+    asm volatile("movl %%ebx,%0 ; "
+		 "cpuid ; "
+		 "xchgl %0,%%ebx"
+		 : "=SD" (v), "+a" (level)
+		 : : "ecx", "edx");
+    return v;
+}
+
+static inline __constfunc uint32_t cpuid_ecx(uint32_t level)
+{
+    uint32_t v;
+
+    asm volatile("pushl %%ebx ; "
+		 "cpuid ; "
+		 "popl %%ebx"
+		 : "=c" (v), "+a" (level)
+		 : : "edx");
+    return v;
+}
+
+static inline __constfunc uint32_t cpuid_edx(uint32_t level)
+{
+    uint32_t v;
+
+    asm volatile("pushl %%ebx ; "
+		 "cpuid ; "
+		 "popl %%ebx"
+		 : "=d" (v), "+a" (level)
+		 : : "ecx");
+    return v;
+}
+
+/* Standard macro to see if a specific flag is changeable */
+static inline __constfunc bool cpu_has_eflag(uint32_t flag)
+{
+	uint32_t f0, f1;
+
+	asm("pushfl ; "
+	    "pushfl ; "
+	    "popl %0 ; "
+	    "movl %0,%1 ; "
+	    "xorl %2,%1 ; "
+	    "pushl %1 ; "
+	    "popfl ; "
+	    "pushfl ; "
+	    "popl %1 ; "
+	    "popfl"
+	    : "=&r" (f0), "=&r" (f1)
+	    : "ri" (flag));
+
+	return !!((f0^f1) & flag);
+}
+
+static inline uint64_t rdmsr(uint32_t msr)
+{
+    uint64_t v;
+
+    asm volatile("rdmsr" : "=A" (v) : "c"(msr));
+    return v;
+}
+
+static inline void wrmsr(uint64_t v, uint32_t msr)
+{
+    asm volatile("wrmsr" : : "A" (v), "c" (msr));
+}
+
+static inline void cpu_relax(void)
+{
+    asm volatile("rep ; nop");
+}
+
+static inline void hlt(void)
+{
+    asm volatile("hlt");
+}
+
+static inline void cli(void)
+{
+    asm volatile("cli");
+}
+
+static inline void sti(void)
+{
+    asm volatile("sti");
+}
diff --git a/com32/include/sys/i386/module.h b/com32/include/sys/i386/module.h
new file mode 100644
index 0000000..21988ea
--- /dev/null
+++ b/com32/include/sys/i386/module.h
@@ -0,0 +1,35 @@
+/**
+ * syslinux/module.h
+ *
+ * Dynamic ELF modules definitions and services.
+ */
+
+#ifndef I386_MODULE_H_
+#define I386_MODULE_H_
+
+#include <elf.h>
+
+/*
+ * 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
+
+#define ELF_MOD_SYS		"32 bit"
+
+typedef Elf32_Addr		Elf_Addr;
+typedef Elf32_Dyn		Elf_Dyn;
+typedef Elf32_Word		Elf_Word;
+typedef Elf32_Off		Elf_Off;
+typedef Elf32_Sym		Elf_Sym;
+typedef Elf32_Ehdr		Elf_Ehdr;
+typedef Elf32_Phdr		Elf_Phdr;
+typedef Elf32_Rel		Elf_Rel;
+typedef Elf32_Word		Elf_Bword;
+
+#endif // I386_MODULE_H_
diff --git a/com32/include/sys/module.h b/com32/include/sys/module.h
index 8d14420..c1d4253 100644
--- a/com32/include/sys/module.h
+++ b/com32/include/sys/module.h
@@ -4,7 +4,6 @@
  * Dynamic ELF modules definitions and services.
  */
 
-
 #ifndef MODULE_H_
 #define MODULE_H_
 
@@ -15,6 +14,14 @@
 #include <stdbool.h>
 #include <linux/list.h>
 
+#if __SIZEOF_POINTER__ == 4
+#include <i386/module.h>
+#elif __SIZEOF_POINTER__ == 8
+#include <x86_64/module.h>
+#else
+#error "unsupported architecture"
+#endif
+
 /*
  * The maximum length of the module file name (including path), stored
  * in the struct module descriptor.
@@ -91,26 +98,26 @@
 	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
+	Elf_Addr			base_addr;	// The base address of the module
+	Elf_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
+	Elf_Word			*hash_table;	// The symbol hash table
+	Elf_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
+	Elf_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
+	Elf_Word			strtable_size;	// The size of the string table
+	Elf_Word			syment_size;	// The size of a symbol entry
+	Elf_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
+			Elf_Off	_cr_offset;	// The current offset in the open file
 		} l;
 
 		// Process execution data
@@ -122,7 +129,7 @@
 
 	// ELF DT_NEEDED entries for this module
 	int				nr_needed;
-	Elf32_Word			needed[MAX_NR_DEPS];
+	Elf_Word			needed[MAX_NR_DEPS];
 };
 
 /**
@@ -167,17 +174,6 @@
  * 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)
  */
@@ -328,7 +324,7 @@
  *  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);
+extern Elf_Sym *module_find_symbol(const char *name, struct elf_module *module);
 
 /**
  * global_find_symbol - searches for a symbol definition in the entire module namespace.
@@ -345,7 +341,7 @@
  * 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);
+extern Elf_Sym *global_find_symbol(const char *name, struct elf_module **module);
 
 /**
  * module_get_absolute - converts an memory address relative to a module base address
@@ -355,7 +351,7 @@
  *
  * The function returns a pointer to the absolute memory address.
  */
-static inline void *module_get_absolute(Elf32_Addr addr, struct elf_module *module) {
+static inline void *module_get_absolute(Elf_Addr addr, struct elf_module *module) {
 	return (void*)(module->base_addr + addr);
 }
 
diff --git a/com32/include/sys/x86_64/bitops.h b/com32/include/sys/x86_64/bitops.h
new file mode 100644
index 0000000..7b1cc2b
--- /dev/null
+++ b/com32/include/sys/x86_64/bitops.h
@@ -0,0 +1,55 @@
+/* ----------------------------------------------------------------------- *
+ *   
+ *   Copyright 2010-2011 Intel Corporation; author: H. Peter Anvin
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *   
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *   
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * bitops.h - i386
+ *
+ * Simple bitwise operations
+ */
+
+static inline void set_bit(long __bit, void *__bitmap)
+{
+    asm volatile("bts %1,%0"
+		 : "+m" (*(unsigned char *)__bitmap)
+		 : "Ir" (__bit) : "memory");
+}
+
+static inline void clr_bit(long __bit, void *__bitmap)
+{
+    asm volatile("btcl %1,%0"
+		 : "+m" (*(unsigned char *)__bitmap)
+		 : "Ir" (__bit) : "memory");
+}
+
+static inline int __purefunc test_bit(long __bit, const void *__bitmap)
+{
+    unsigned char __r;
+    asm("bt %2,%1; setc %0"
+	: "=qm" (__r)
+	: "m" (*(const unsigned char *)__bitmap), "Ir" (__bit));
+    return __r;
+}
diff --git a/com32/include/sys/x86_64/cpu.h b/com32/include/sys/x86_64/cpu.h
new file mode 100644
index 0000000..89d7915
--- /dev/null
+++ b/com32/include/sys/x86_64/cpu.h
@@ -0,0 +1,148 @@
+#ifndef _CPU_X86_64_H
+#define _CPU_X86_64_H
+
+/* x86_64 cpu.h  */
+
+static inline uint64_t rdtsc(void)
+{
+    uint64_t v;
+    asm volatile("rdtsc" : "=A" (v));
+    return v;
+}
+
+static inline uint32_t rdtscl(void)
+{
+    uint32_t v;
+    asm volatile("rdtsc" : "=a" (v) : : "edx");
+    return v;
+}
+
+static inline void native_cpuid(unsigned int *eax, unsigned int *ebx,
+                                unsigned int *ecx, unsigned int *edx)
+{
+        /* ecx is often an input as well as an output. */
+        asm volatile("cpuid"
+            : "=a" (*eax),
+              "=b" (*ebx),
+              "=c" (*ecx),
+              "=d" (*edx)
+            : "0" (*eax), "2" (*ecx)
+            : "memory");
+}
+/*
+ * Generic CPUID function
+ * clear %ecx since some cpus (Cyrix MII) do not set or clear %ecx
+ * resulting in stale register contents being returned.
+ */
+static inline void cpuid(uint32_t op,
+                         uint32_t *eax, uint32_t *ebx,
+                         uint32_t *ecx, uint32_t *edx)
+{
+        *eax = op;
+        *ecx = 0;
+        native_cpuid(eax, ebx, ecx, edx);
+}
+
+/*
+ * CPUID functions returning a single datum
+ */
+static inline uint32_t cpuid_eax(uint32_t op)
+{
+        uint32_t eax, ebx, ecx, edx;
+
+        cpuid(op, &eax, &ebx, &ecx, &edx);
+
+        return eax;
+}
+
+static inline uint32_t cpuid_ebx(uint32_t op)
+{
+        uint32_t eax, ebx, ecx, edx;
+
+        cpuid(op, &eax, &ebx, &ecx, &edx);
+
+        return ebx;
+}
+
+static inline uint32_t cpuid_ecx(uint32_t op)
+{
+        uint32_t eax, ebx, ecx, edx;
+
+        cpuid(op, &eax, &ebx, &ecx, &edx);
+
+        return ecx;
+}
+
+static inline uint32_t cpuid_edx(uint32_t op)
+{
+        uint32_t eax, ebx, ecx, edx;
+
+        cpuid(op, &eax, &ebx, &ecx, &edx);
+
+        return edx;
+}
+
+static inline void cpuid_count(uint32_t op, uint32_t cnt,
+			       uint32_t * eax, uint32_t * ebx,
+			       uint32_t * ecx, uint32_t * edx)
+{
+    asm volatile("movl %%ebx,%1 ; "
+		 "cpuid ; "
+		 "xchgl %1,%%ebx"
+		 : "=a" (*eax), "=SD" (*ebx), "=c" (*ecx), "=d" (*edx)
+		 : "a"(op), "c"(cnt));
+}
+
+/* Standard macro to see if a specific flag is changeable */
+static inline __constfunc bool cpu_has_eflag(uint32_t flag)
+{
+	/* x86_64 */
+	uint64_t f0, f1;
+	asm("pushf ; "
+	    "pushf ; "
+	    "pop %0 ; "
+	    "mov %0,%1 ; "
+	    "xor %2,%1 ; "
+	    "push %1 ; "
+	    "popf ; "
+	    "pushf ; "
+	    "pop %1 ; "
+	    "popf"
+	    : "=&r" (f0), "=&r" (f1)
+	    : "ri" (flag));
+	return !!((f0^f1) & flag);
+}
+
+static inline uint64_t rdmsr(uint32_t msr)
+{
+    uint64_t v;
+
+    asm volatile("rdmsr" : "=A" (v) : "c"(msr));
+    return v;
+}
+
+static inline void wrmsr(uint64_t v, uint32_t msr)
+{
+    asm volatile("wrmsr" : : "A" (v), "c" (msr));
+}
+
+static inline void cpu_relax(void)
+{
+    asm volatile("rep ; nop");
+}
+
+static inline void hlt(void)
+{
+    asm volatile("hlt");
+}
+
+static inline void cli(void)
+{
+    asm volatile("cli");
+}
+
+static inline void sti(void)
+{
+    asm volatile("sti");
+}
+#endif
diff --git a/com32/include/sys/x86_64/module.h b/com32/include/sys/x86_64/module.h
new file mode 100644
index 0000000..203a6cd
--- /dev/null
+++ b/com32/include/sys/x86_64/module.h
@@ -0,0 +1,35 @@
+/**
+ * syslinux/module.h
+ *
+ * Dynamic ELF64 modules definitions and services.
+ */
+
+#ifndef _X86_64_MODULE_H_
+#define _X86_64_MODULE_H_
+
+#include <elf.h>
+
+/*
+ * Accepted values for various ELF header parameters found in an ELF dynamic
+ * object.
+ */
+#define MODULE_ELF_CLASS		ELFCLASS64		// 64-bit modules
+#define MODULE_ELF_CLASS_SIZE		64			// 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_X86_64		// Target architecture
+
+#define ELF_MOD_SYS		"64 bit"
+
+typedef Elf64_Addr		Elf_Addr;
+typedef Elf64_Dyn		Elf_Dyn;
+typedef Elf64_Word		Elf_Word;
+typedef Elf64_Off		Elf_Off;
+typedef Elf64_Sym		Elf_Sym;
+typedef Elf64_Ehdr		Elf_Ehdr;
+typedef Elf64_Phdr		Elf_Phdr;
+typedef Elf64_Rel		Elf_Rel;
+typedef Elf64_Xword		Elf_Bword;
+
+#endif // _X86_64_MODULE_H_
diff --git a/com32/include/syslinux/firmware.h b/com32/include/syslinux/firmware.h
new file mode 100644
index 0000000..13ba159
--- /dev/null
+++ b/com32/include/syslinux/firmware.h
@@ -0,0 +1,72 @@
+#ifndef _SYSLINUX_FIRMWARE_H
+#define _SYSLINUX_FIRMWARE_H
+
+#include <syslinux/memscan.h>
+
+struct term_state;
+
+struct output_ops {
+	void (*erase) (int, int, int, int, uint8_t);
+	void (*write_char) (uint8_t, uint8_t);
+	void (*showcursor) (const struct term_state *);
+	void (*scroll_up) (uint8_t, uint8_t, uint8_t);
+	void (*set_cursor) (int, int, bool);
+	void (*beep) (void);
+	void (*get_mode)(int *, int *);
+	void (*set_mode)(uint16_t);
+	void (*get_cursor)(int *, int *);
+};
+
+struct input_ops {
+	char (*getchar)(char *);
+	int (*pollchar)(void);
+};
+
+struct adv_ops {
+	void (*init)(void);
+	int (*write)(void);
+};
+
+struct vesa_info;
+enum vesa_pixel_format;
+struct win_info;
+
+struct vesa_ops {
+	int (*set_mode)(struct vesa_info *, int *, int *, enum vesa_pixel_format *);
+	void (*screencpy)(size_t, const uint32_t *, size_t, struct win_info *);
+	int (*font_query)(uint8_t **);
+};
+
+enum heap;
+struct mem_ops {
+	void *(*malloc)(size_t, enum heap, size_t);
+	void *(*realloc)(void *, size_t);
+	void (*free)(void *);
+	int (*scan_memory)(scan_memory_callback_t, void *);
+};
+
+struct initramfs;
+struct setup_data;
+
+struct firmware {
+	void (*init)(void);
+	void (*adjust_screen)(void);
+	void (*cleanup)(void);
+	struct disk *(*disk_init)(void *);
+	struct output_ops *o_ops;
+	struct input_ops *i_ops;
+	void (*get_serial_console_info)(uint16_t *, uint16_t *, uint16_t *);
+	bool (*ipappend_strings)(char **, int *);
+	struct adv_ops *adv_ops;
+	int (*boot_linux)(void *, size_t, struct initramfs *,
+			  struct setup_data *, char *);
+	struct vesa_ops *vesa;
+	struct mem_ops *mem;
+};
+
+extern struct firmware *firmware;
+
+extern void syslinux_register_bios(void);
+extern void init(void);
+
+#endif /* _SYSLINUX_FIRMWARE_H */
diff --git a/com32/include/syslinux/linux.h b/com32/include/syslinux/linux.h
index f5f95fb..a8c6f2f 100644
--- a/com32/include/syslinux/linux.h
+++ b/com32/include/syslinux/linux.h
@@ -37,6 +37,7 @@
 
 #include <stddef.h>
 #include <stdint.h>
+#include <klibc/compiler.h>
 
 /* A chunk of an initramfs.  These are kept as a doubly-linked
    circular list with headnode; the headnode is distinguished by
@@ -68,6 +69,87 @@
 #define SETUP_E820_EXT	1
 #define SETUP_DTB	2
 
+struct linux_header {
+    uint8_t boot_sector_1[0x0020];
+    uint16_t old_cmd_line_magic;
+    uint16_t old_cmd_line_offset;
+    uint8_t boot_sector_2[0x01f1 - 0x0024];
+    uint8_t setup_sects;
+    uint16_t root_flags;
+    uint32_t syssize;
+    uint16_t ram_size;
+    uint16_t vid_mode;
+    uint16_t root_dev;
+    uint16_t boot_flag;
+    uint16_t jump;
+    uint32_t header;
+    uint16_t version;
+    uint32_t realmode_swtch;
+    uint16_t start_sys;
+    uint16_t kernel_version;
+    uint8_t type_of_loader;
+    uint8_t loadflags;
+    uint16_t setup_move_size;
+    uint32_t code32_start;
+    uint32_t ramdisk_image;
+    uint32_t ramdisk_size;
+    uint32_t bootsect_kludge;
+    uint16_t heap_end_ptr;
+    uint16_t pad1;
+    uint32_t cmd_line_ptr;
+    uint32_t initrd_addr_max;
+    uint32_t kernel_alignment;
+    uint8_t relocatable_kernel;
+    uint8_t pad2[3];
+    uint32_t cmdline_max_len;
+    uint32_t hardware_subarch;
+    uint64_t hardware_subarch_data;
+    uint32_t payload_offset;
+    uint32_t payload_length;
+    uint64_t setup_data;
+    uint64_t pref_address;
+    uint32_t init_size;
+} __packed;
+
+struct screen_info {
+	uint8_t  orig_x;		/* 0x00 */
+	uint8_t  orig_y;		/* 0x01 */
+	uint16_t ext_mem_k;	/* 0x02 */
+	uint16_t orig_video_page;	/* 0x04 */
+	uint8_t  orig_video_mode;	/* 0x06 */
+	uint8_t  orig_video_cols;	/* 0x07 */
+	uint8_t  flags;		/* 0x08 */
+	uint8_t  unused2;		/* 0x09 */
+	uint16_t orig_video_ega_bx;/* 0x0a */
+	uint16_t unused3;		/* 0x0c */
+	uint8_t  orig_video_lines;	/* 0x0e */
+	uint8_t  orig_video_isVGA;	/* 0x0f */
+	uint16_t orig_video_points;/* 0x10 */
+
+	/* VESA graphic mode -- linear frame buffer */
+	uint16_t lfb_width;	/* 0x12 */
+	uint16_t lfb_height;	/* 0x14 */
+	uint16_t lfb_depth;	/* 0x16 */
+	uint32_t lfb_base;		/* 0x18 */
+	uint32_t lfb_size;		/* 0x1c */
+	uint16_t cl_magic, cl_offset; /* 0x20 */
+	uint16_t lfb_linelength;	/* 0x24 */
+	uint8_t  red_size;		/* 0x26 */
+	uint8_t  red_pos;		/* 0x27 */
+	uint8_t  green_size;	/* 0x28 */
+	uint8_t  green_pos;	/* 0x29 */
+	uint8_t  blue_size;	/* 0x2a */
+	uint8_t  blue_pos;		/* 0x2b */
+	uint8_t  rsvd_size;	/* 0x2c */
+	uint8_t  rsvd_pos;		/* 0x2d */
+	uint16_t vesapm_seg;	/* 0x2e */
+	uint16_t vesapm_off;	/* 0x30 */
+	uint16_t pages;		/* 0x32 */
+	uint16_t vesa_attributes;	/* 0x34 */
+	uint32_t capabilities;     /* 0x36 */
+	uint8_t  _reserved[6];	/* 0x3a */
+} __packed;
+
 int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
 			struct initramfs *initramfs,
 			struct setup_data *setup_data,
@@ -89,6 +171,23 @@
 int initramfs_add_trailer(struct initramfs *ihead);
 int initramfs_load_archive(struct initramfs *ihead, const char *filename);
 
+/* Get the combined size of the initramfs */
+static inline uint32_t initramfs_size(struct initramfs *initramfs)
+{
+    struct initramfs *ip;
+    uint32_t size = 0;
+
+    if (!initramfs)
+	return 0;
+
+    for (ip = initramfs->next; ip->len; ip = ip->next) {
+	size = (size + ip->align - 1) & ~(ip->align - 1);	/* Alignment */
+	size += ip->len;
+    }
+
+    return size;
+}
+
 /* Setup data manipulation functions */
 
 struct setup_data *setup_data_init(void);
diff --git a/com32/include/syslinux/memscan.h b/com32/include/syslinux/memscan.h
index db79543..c3ebf84 100644
--- a/com32/include/syslinux/memscan.h
+++ b/com32/include/syslinux/memscan.h
@@ -34,5 +34,6 @@
 
 typedef int (*scan_memory_callback_t) (void *, addr_t, addr_t, bool);
 int syslinux_scan_memory(scan_memory_callback_t callback, void *data);
+int bios_scan_memory(scan_memory_callback_t callback, void *data);
 
 #endif /* _SYSLINUX_MEMSCAN_H */
diff --git a/com32/include/syslinux/version.h b/com32/include/syslinux/version.h
new file mode 100644
index 0000000..762db37
--- /dev/null
+++ b/com32/include/syslinux/version.h
@@ -0,0 +1,6 @@
+#ifndef _SYSLINUX_VERSION_H
+#define _SYSLINUX_VERSION_H
+
+#define __STDC_VERSION__ 200000L
+
+#endif /* _SYSLINUX_VERSION_H */
diff --git a/com32/lib/Makefile b/com32/lib/Makefile
index 49a3aaf..1624ae7 100644
--- a/com32/lib/Makefile
+++ b/com32/lib/Makefile
@@ -4,8 +4,7 @@
 
 # Include configuration rules
 NOGPL := 1
-topdir = ../../
-MAKEDIR = $(topdir)/mk
+VPATH = $(SRC)
 include $(MAKEDIR)/lib.mk
 
 ## OPTIONAL OBJECTS, AVAILABLE AS DYNAMIC LINKED MODULES
@@ -17,24 +16,23 @@
 	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					
 
+ifdef EFI_BUILD
+I915VESA_OBJ =
+else
+I915VESA_OBJ = sys/vesa/i915resolution.o
+endif
+
 LIBVESA_OBJS = \
 	sys/vesacon_write.o sys/vesaserial_write.o			\
 	sys/vesa/initvesa.o sys/vesa/drawtxt.o	sys/vesa/background.o	\
 	sys/vesa/alphatbl.o sys/vesa/screencpy.o sys/vesa/fmtpixel.o	\
-	sys/vesa/i915resolution.o
+	$(I915VESA_OBJ)
 
 LIBMISC_OBJS = \
 	sys/libansi.o sys/gpxe.o
@@ -51,134 +49,9 @@
 	syslinux/pxe_dns.o						\
 	syslinux/video/fontquery.o syslinux/video/reportmode.o
 
-LIBLOAD_OBJS = \
-	syslinux/addlist.o syslinux/freelist.o syslinux/memmap.o	\
-	syslinux/movebits.o syslinux/shuffle.o syslinux/shuffle_pm.o	\
-	syslinux/shuffle_rm.o syslinux/zonelist.o			\
-	syslinux/dump_mmap.o syslinux/dump_movelist.o			\
-	\
-	syslinux/run_default.o syslinux/run_command.o			\
-	syslinux/cleanup.o syslinux/localboot.o	syslinux/runimage.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/argv.o sys/sleep.o						\
-	sys/fileinfo.o sys/opendev.o sys/read.o sys/write.o sys/ftell.o \
-	sys/close.o sys/open.o sys/fileread.o sys/fileclose.o		\
-	sys/openmem.o					\
-	sys/isatty.o sys/fstat.o					\
-	\
-	dprintf.o vdprintf.o						\
-	\
-	syslinux/idle.o							\
-	\
-	exit.o
-
-LIBMODULE_OBJS = \
-	sys/module/common.o sys/module/elf_module.o		\
-	sys/module/elfutils.o					\
-	sys/module/exec.o
-
-LIBGCC_OBJS = \
-	libgcc/__ashldi3.o libgcc/__udivdi3.o			\
-	libgcc/__negdi2.o libgcc/__ashrdi3.o libgcc/__lshrdi3.o		\
-	libgcc/__muldi3.o libgcc/__udivmoddi4.o libgcc/__umoddi3.o	\
-	libgcc/__divdi3.o libgcc/__moddi3.o
-
-LIBCONSOLE_OBJS = \
-	\
-	sys/openconsole.o sys/line_input.o				\
-	sys/colortable.o sys/screensize.o				\
-	\
-	sys/stdcon_read.o sys/rawcon_read.o		\
-	sys/rawcon_write.o						\
-	sys/null_write.o sys/serial_write.o		\
-	\
-	sys/xserial_write.o						\
-	\
-	sys/ansi.o							\
-	\
-	sys/ansicon_write.o sys/ansiserial_write.o	\
-	\
-	syslinux/serial.o
-
-LIBOTHER_OBJS = \
-	atoi.o atol.o atoll.o calloc.o creat.o		\
-	fgets.o fprintf.o fputc.o	\
-	putchar.o				\
-	getopt.o getopt_long.o						\
-	lrand48.o stack.o memccpy.o memchr.o 		\
-	mempcpy.o memmem.o memmove.o memswap.o	\
-	perror.o qsort.o seed48.o \
-	srand48.o sscanf.o strcasecmp.o strcat.o	\
-	strerror.o errlist.o		\
-	strnlen.o							\
-	strncat.o strndup.o		\
-	stpncpy.o						\
-	strntoimax.o strntoumax.o strsep.o strspn.o strstr.o	\
-	strtoimax.o strtok.o strtol.o strtoll.o strtoul.o strtoull.o	\
-	strtoumax.o vprintf.o vsprintf.o		\
-	asprintf.o vasprintf.o			\
-	vsscanf.o							\
-	skipspace.o							\
-	chrreplace.o							\
-	bufprintf.o							\
-	inet.o dhcppack.o dhcpunpack.o					\
-	strreplace.o							\
-	lstrdup.o						\
-	\
-	suffix_number.o							\
-	\
-	getcwd.o fdopendir.o	\
-	\
-	sys/line_input.o				\
-	sys/colortable.o sys/screensize.o				\
-	\
-	sys/stdcon_read.o sys/stdcon_write.o sys/rawcon_read.o		\
-	sys/rawcon_write.o		\
-	sys/null_read.o sys/null_write.o sys/serial_write.o		\
-	\
-	sys/xserial_write.o						\
-	\
-	sys/ansi.o							\
-	\
-	sys/ansicon_write.o sys/ansiserial_write.o			\
-	\
-	pci/cfgtype.o pci/scan.o pci/bios.o					\
-	pci/readb.o pci/readw.o pci/readl.o			\
-	pci/writeb.o pci/writew.o pci/writel.o	\
-	\
-	sys/x86_init_fpu.o math/pow.o math/strtod.o			\
-	syslinux/disk.o							\
-	\
-	syslinux/setup_data.o
-
-CORELIBOBJS = \
-	memcpy.o memset.o memcmp.o printf.o strncmp.o vfprintf.o 	\
-	strlen.o vsnprintf.o snprintf.o stpcpy.o strcmp.o strdup.o 	\
-	strcpy.o strncpy.o setjmp.o fopen.o fread.o fread2.o puts.o 	\
-	sprintf.o strlcat.o strchr.o strlcpy.o strncasecmp.o ctypes.o 	\
-	fputs.o fwrite2.o fwrite.o fgetc.o fclose.o errno.o lmalloc.o 	\
-	sys/err_read.o sys/err_write.o sys/null_read.o 			\
-	sys/stdcon_write.o						\
-	syslinux/memscan.o strrchr.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				\
-	$(LIBENTRY_OBJS) \
-	$(LIBMODULE_OBJS)
-
 MINLIBOBJS = \
 	syslinux/ipappend.o \
 	syslinux/dsinfo.o \
@@ -189,7 +62,6 @@
 	$(LIBZLIB_OBJS)
 #	$(LIBVESA_OBJS)
 
-
 DYNLIBOBJS = \
 	$(LIBZLIB_OBJS) \
 	$(LIBPNG_OBJS) \
@@ -202,8 +74,7 @@
 	$(DYNENTRY_OBJS)
 
 
-LIBOBJS = \
-	$(DYNLIBOBJS)
+LIBOBJS = $(DYNLIBOBJS)
 
 BINDIR   = /usr/bin
 LIBDIR   = /usr/lib
@@ -212,7 +83,11 @@
 INCDIR   = /usr/include
 COM32DIR = $(AUXDIR)/com32
 
-all: libcom32.c32 libcom32min.a libcom32core.a
+all: makeoutputdirs libcom32.c32 libcom32min.a libcom32core.a
+
+makeoutputdirs:
+	@mkdir -p $(foreach b, \
+		$(addprefix $(OBJ)/,$(sort $(dir $(LIBOBJS) $(MINLIBOBJS) $(CORELIBOBJS)))),$(b))
 
 libcom32.elf : $(LIBOBJS)
 	rm -f $@
@@ -239,11 +114,11 @@
 
 install: all
 	mkdir -m 755 -p $(INSTALLROOT)$(COM32DIR)
-	install -m 644 com32.ld $(INSTALLROOT)$(COM32DIR)
+	install -m 644 $(SRC)/com32.ld $(INSTALLROOT)$(COM32DIR)
 	-rm -rf $(INSTALLROOT)$(COM32DIR)/include
-	cp -r ../include $(INSTALLROOT)$(COM32DIR)
+	cp -r $(SRC)/../include $(INSTALLROOT)$(COM32DIR)
 
-errlist.c: makeerrlist.pl ../include/errno.h
+errlist.c: makeerrlist.pl $(SRC)/../include/errno.h
 	$(PERL) $<  $(CFLAGS) -errlist > $@ || rm -f $@
 
 # These files are performance critical, and doesn't compile well with -Os
diff --git a/com32/lib/i386/elf.ld b/com32/lib/i386/elf.ld
new file mode 100644
index 0000000..fc2e7db
--- /dev/null
+++ b/com32/lib/i386/elf.ld
@@ -0,0 +1,178 @@
+/*
+ * 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))
+    KEEP (*(.ctors_modinit))
+    KEEP (*(.ctors_modmain))
+	__ctors_end = .;
+  }
+  
+  .dtors          :
+  {
+  	__dtors_start = .;
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+    KEEP (*(.dtors_modexit))
+	__dtors_end = .;
+  }
+  
+  .jcr            : { KEEP (*(.jcr)) }
+  .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
+  .dynamic        : { *(.dynamic) }
+  .got            : { *(.got) }
+  /*. = DATA_SEGMENT_RELRO_END (12, .); -> This gives a "invalid assignment to location counter" error */
+  .got.plt        : { *(.got.plt) }
+  .data           :
+  {
+    *(.data .data.* .gnu.linkonce.d.*)
+    KEEP (*(.gnu.linkonce.d.*personality*))
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  PROVIDE (edata = .);
+  PROVIDE (_edata = .); 
+  .bss            :
+  {
+   *(.dynbss)
+   *(.bss .bss.* .gnu.linkonce.b.*)
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.
+      FIXME: Why do we need it? When there is no .bss section, we don't
+      pad the .data section.  */
+   . = ALIGN(. != 0 ? 32 / 8 : 1);
+  }
+  . = ALIGN(32 / 8);
+  . = ALIGN(32 / 8);
+  PROVIDE (_end = .); 
+  PROVIDE (end = .);
+  /*. = DATA_SEGMENT_END (.); -> This gives a "invalid assignment to location counter" error */
+  /* Stabs debugging sections.  */
+  .stab          0 : { *(.stab) }
+  .stabstr       0 : { *(.stabstr) }
+  .stab.excl     0 : { *(.stab.excl) }
+  .stab.exclstr  0 : { *(.stab.exclstr) }
+  .stab.index    0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment       0 : { *(.comment) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  /* DWARF 3 */
+  .debug_pubtypes 0 : { *(.debug_pubtypes) }
+  .debug_ranges   0 : { *(.debug_ranges) }
+  .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
+  /DISCARD/ : { *(.eh_frame) }
+}
diff --git a/com32/lib/i386/setjmp.S b/com32/lib/i386/setjmp.S
new file mode 100644
index 0000000..658df48
--- /dev/null
+++ b/com32/lib/i386/setjmp.S
@@ -0,0 +1,63 @@
+/*
+ * arch/i386/setjmp.S
+ *
+ * setjmp/longjmp for the i386 architecture
+ *
+ *
+ *
+ * The jmp_buf is assumed to contain the following, in order:
+ *	%ebx
+ *	%esp
+ *	%ebp
+ *	%esi
+ *	%edi
+ *	<return address>
+ */
+
+	.text
+	.align 4
+
+	.globl _setjmp
+	.type _setjmp, @function
+_setjmp:				# gcc 4.0.1 wants this as an alias?
+
+	.globl setjmp
+	.type setjmp, @function
+setjmp:
+#ifdef REGPARM
+	movl %eax,%edx
+#else
+	movl 4(%esp),%edx
+#endif
+	popl %ecx			# Return address, and adjust the stack
+	xorl %eax,%eax			# Return value
+	movl %ebx,(%edx)
+	movl %esp,4(%edx)		# Post-return %esp!
+	pushl %ecx			# Make the call/return stack happy
+	movl %ebp,8(%edx)
+	movl %esi,12(%edx)
+	movl %edi,16(%edx)
+	movl %ecx,20(%edx)		# Return address
+	ret
+
+	.size setjmp,.-setjmp
+
+	.text
+	.align 4
+	.globl longjmp
+	.type longjmp, @function
+longjmp:
+#ifdef REGPARM
+	xchgl %eax,%edx
+#else
+	movl 4(%esp),%edx		# jmp_ptr address
+	movl 8(%esp),%eax		# Return value
+#endif
+	movl (%edx),%ebx
+	movl 4(%edx),%esp
+	movl 8(%edx),%ebp
+	movl 12(%edx),%esi
+	movl 16(%edx),%edi
+	jmp *20(%edx)
+
+	.size longjmp,.-longjmp
diff --git a/com32/lib/libgcc/__muldi3.S b/com32/lib/libgcc/__muldi3.S
index 648a88a..424787c 100644
--- a/com32/lib/libgcc/__muldi3.S
+++ b/com32/lib/libgcc/__muldi3.S
@@ -9,6 +9,8 @@
 	.globl __muldi3
 	.type __muldi3,@function
 __muldi3:
+#if __SIZEOF_POINTER__ == 4
+	/* i386 */
 	push  %esi
 #ifndef REGPARM
 	movl  8(%esp),%eax
@@ -31,4 +33,51 @@
 #endif
 	pop   %esi
 	ret
+#elif __SIZEOF_POINTER__ == 8
+	/* x86_64 */
+	push  %rsi
+#ifndef REGPARM
+/*
+	movl  8(%esp),%eax
+	movl %eax,%esi
+	movl  16(%esp),%ecx
+	mull  %ecx
+	imull 12(%esp),%ecx
+	imull 20(%esp),%esi
+	addl  %ecx,%edx
+	addl  %esi,%edx
+*/
+	movq  8(%rsp),%rax
+	movq %rax,%rsi
+	movq  16(%rsp),%rcx
+	mulq  %rcx
+	imulq 12(%rsp),%rcx
+	imulq 20(%rsp),%rsi
+	addq  %rcx,%rdx
+	addq  %rsi,%rdx
+#else
+/*
+	movl  %eax,%esi
+	push  %edx
+	mull  %ecx
+	imull 8(%esp),%esi
+	addl  %esi,%edx
+	pop   %rsi
+	imull %esi,%ecx
+	addl  %ecx,%edx
+*/
+	movq  %rax,%rsi
+	pushq  %rdx
+	mulq  %rcx
+	imulq 8(%rsp),%rsi
+	addq  %rsi,%rdx
+	popq  %rsi
+	imulq %rsi,%rcx
+	addq  %rcx,%rdx
+#endif
+	pop   %rsi
+	ret
+#else
+#error "Unsupported architecture for __muldi3.S"
+#endif
 	.size __muldi3,.-__muldi3
diff --git a/com32/lib/memcpy.S b/com32/lib/memcpy.S
index 6b986a0..9b5306d 100644
--- a/com32/lib/memcpy.S
+++ b/com32/lib/memcpy.S
@@ -36,6 +36,10 @@
 	.globl	memcpy
 	.type	memcpy, @function
 memcpy:
+	movl	0xc(%esp),%ecx
+	movl	0x8(%esp),%edx
+	movl	0x4(%esp),%eax
+
 	jecxz	1f
 
 	pushl	%esi
diff --git a/com32/lib/memcpy.c b/com32/lib/memcpy.c
new file mode 100644
index 0000000..5ce206d
--- /dev/null
+++ b/com32/lib/memcpy.c
@@ -0,0 +1,29 @@
+/*
+ * memcpy.c
+ */
+
+#include <string.h>
+#include <stdint.h>
+
+void *memcpy(void *dst, const void *src, size_t n)
+{
+	const char *p = src;
+	char *q = dst;
+#if defined(__i386__)
+	size_t nl = n >> 2;
+	asm volatile ("cld ; rep ; movsl ; movl %3,%0 ; rep ; movsb":"+c" (nl),
+		      "+S"(p), "+D"(q)
+		      :"r"(n & 3));
+#elif defined(__x86_64__)
+	size_t nq = n >> 3;
+	asm volatile ("cld ; rep ; movsq ; movl %3,%%ecx ; rep ; movsb":"+c"
+		      (nq), "+S"(p), "+D"(q)
+		      :"r"((uint32_t) (n & 7)));
+#else
+	while (n--) {
+		*q++ = *p++;
+	}
+#endif
+
+	return dst;
+}
diff --git a/com32/lib/memmove.S b/com32/lib/memmove.S
index e97299f..2094e4a 100644
--- a/com32/lib/memmove.S
+++ b/com32/lib/memmove.S
@@ -37,6 +37,10 @@
 	.type	memmove,@function
 	.text
 memmove:
+	movl	0xc(%esp),%ecx
+	movl	0x8(%esp),%edx
+	movl	0x4(%esp),%eax
+
 	jecxz	4f
 
 	pushl	%esi
diff --git a/com32/lib/memmove.c b/com32/lib/memmove.c
new file mode 100644
index 0000000..a398cd8
--- /dev/null
+++ b/com32/lib/memmove.c
@@ -0,0 +1,36 @@
+/*
+ * memmove.c
+ */
+
+#include <string.h>
+
+void *memmove(void *dst, const void *src, size_t n)
+{
+	const char *p = src;
+	char *q = dst;
+#if defined(__i386__) || defined(__x86_64__)
+	if (q < p) {
+		asm volatile("cld; rep; movsb"
+			     : "+c" (n), "+S"(p), "+D"(q));
+	} else {
+		p += (n - 1);
+		q += (n - 1);
+		asm volatile("std; rep; movsb; cld"
+			     : "+c" (n), "+S"(p), "+D"(q));
+	}
+#else
+	if (q < p) {
+		while (n--) {
+			*q++ = *p++;
+		}
+	} else {
+		p += n;
+		q += n;
+		while (n--) {
+			*--q = *--p;
+		}
+	}
+#endif
+
+	return dst;
+}
diff --git a/com32/lib/mempcpy.S b/com32/lib/mempcpy.S
index cad7b98..2096f13 100644
--- a/com32/lib/mempcpy.S
+++ b/com32/lib/mempcpy.S
@@ -36,6 +36,10 @@
 	.globl	mempcpy
 	.type	mempcpy, @function
 mempcpy:
+	movl	0xc(%esp),%ecx
+	movl	0x8(%esp),%edx
+	movl	0x4(%esp),%eax
+
 	jecxz	1f
 
 	pushl	%esi
diff --git a/com32/lib/mempcpy.c b/com32/lib/mempcpy.c
new file mode 100644
index 0000000..be23b66
--- /dev/null
+++ b/com32/lib/mempcpy.c
@@ -0,0 +1,14 @@
+/*
+ * mempcpy.c
+ */
+
+#include <string.h>
+#include <stdint.h>
+
+/* simply a wrapper around memcpy implementation */
+
+void *mempcpy(void *dst, const void *src, size_t n)
+{
+
+	return (char *)memcpy(dst, src, n) + n;
+}
diff --git a/com32/lib/memset.S b/com32/lib/memset.S
index e641415..fd42842 100644
--- a/com32/lib/memset.S
+++ b/com32/lib/memset.S
@@ -36,6 +36,10 @@
 	.type	memset,@function
 	.text
 memset:
+	movl	0xc(%esp),%ecx
+	movl	0x8(%esp),%edx
+	movl	0x4(%esp),%eax
+
 	jecxz	6f
 
 	pushl	%edi
diff --git a/com32/lib/memset.c b/com32/lib/memset.c
new file mode 100644
index 0000000..aa00b5b
--- /dev/null
+++ b/com32/lib/memset.c
@@ -0,0 +1,30 @@
+/*
+ * memset.c
+ */
+
+#include <string.h>
+#include <stdint.h>
+
+void *memset(void *dst, int c, size_t n)
+{
+	char *q = dst;
+
+#if defined(__i386__)
+	size_t nl = n >> 2;
+	asm volatile ("cld ; rep ; stosl ; movl %3,%0 ; rep ; stosb"
+		      : "+c" (nl), "+D" (q)
+		      : "a" ((unsigned char)c * 0x01010101U), "r" (n & 3));
+#elif defined(__x86_64__)
+	size_t nq = n >> 3;
+	asm volatile ("cld ; rep ; stosq ; movl %3,%%ecx ; rep ; stosb"
+		      :"+c" (nq), "+D" (q)
+		      : "a" ((unsigned char)c * 0x0101010101010101U),
+			"r" ((uint32_t) n & 7));
+#else
+	while (n--) {
+		*q++ = c;
+	}
+#endif
+
+	return dst;
+}
diff --git a/com32/lib/setjmp.S b/com32/lib/setjmp.S
index 658df48..2fb5c23 100644
--- a/com32/lib/setjmp.S
+++ b/com32/lib/setjmp.S
@@ -13,7 +13,7 @@
  *	%edi
  *	<return address>
  */
-
+/*
 	.text
 	.align 4
 
@@ -61,3 +61,12 @@
 	jmp *20(%edx)
 
 	.size longjmp,.-longjmp
+*/
+#if __SIZEOF_POINTER__ == 4
+#include <i386/setjmp.S>
+#elif __SIZEOF_POINTER__ == 8
+#include <x86_64/setjmp.S>
+#else
+#error "Unable to build for to-be-defined architecture type"
+#endif
+
diff --git a/com32/lib/sys/ansicon_write.c b/com32/lib/sys/ansicon_write.c
index e5483fb..74add71 100644
--- a/com32/lib/sys/ansicon_write.c
+++ b/com32/lib/sys/ansicon_write.c
@@ -35,13 +35,13 @@
 
 #include <errno.h>
 #include <string.h>
-#include <com32.h>
 #include <minmax.h>
 #include <colortbl.h>
 #include <klibc/compiler.h>
 #include <syslinux/config.h>
 #include "file.h"
 #include "ansi.h"
+#include <syslinux/firmware.h>
 #include "graphics.h"
 
 static void ansicon_erase(const struct term_state *, int, int, int, int);
@@ -66,23 +66,15 @@
     .op = &__ansicon_ops
 };
 
-#define BIOS_CURXY ((struct curxy *)0x450)	/* Array for each page */
-#define BIOS_ROWS (*(uint8_t *)0x484)	/* Minus one; if zero use 24 (= 25 lines) */
-#define BIOS_COLS (*(uint16_t *)0x44A)
-#define BIOS_PAGE (*(uint8_t *)0x462)
+#define TEXT_MODE 0x0005
 
 /* Reference counter to the screen, to keep track of if we need
    reinitialization. */
 static int ansicon_counter = 0;
 
-static uint16_t cursor_type;	/* Saved cursor pattern */
-
 /* Common setup */
 int __ansicon_open(struct file_info *fp)
 {
-    static com32sys_t ireg;	/* Auto-initalized to all zero */
-    com32sys_t oreg;
-
     if (!ansicon_counter) {
 	/* Are we disabled? */
 	if (syslinux_serial_console_info()->flowctl & 0x8000) {
@@ -91,20 +83,14 @@
 	    ti.cols = 80;
 	} else {
 	    /* Force text mode */
-	    syslinux_force_text_mode();
+	    firmware->o_ops->set_mode(TEXT_MODE);
 
 	    /* Initial state */
-	    ti.rows = BIOS_ROWS ? BIOS_ROWS + 1 : 25;
-	    ti.cols = BIOS_COLS;
+	    firmware->o_ops->get_mode(&ti.cols, &ti.rows);
 	    __ansi_init(&ti);
 
 	    /* Get cursor shape and position */
-	    ireg.eax.b[1] = 0x03;
-	    ireg.ebx.b[1] = BIOS_PAGE;
-	    __intcall(0x10, &ireg, &oreg);
-	    cursor_type = oreg.ecx.w[0];
-	    ti.ts->xy.x = oreg.edx.b[0];
-	    ti.ts->xy.y = oreg.edx.b[1];
+	    firmware->o_ops->get_cursor(&ti.ts->xy.x, &ti.ts->xy.y);
 	}
     }
 
@@ -155,69 +141,45 @@
 static void ansicon_erase(const struct term_state *st,
 			  int x0, int y0, int x1, int y1)
 {
-    static com32sys_t ireg;
+    uint8_t attribute = ansicon_attribute(st);
 
-    ireg.eax.w[0] = 0x0600;	/* Clear window */
-    ireg.ebx.b[1] = ansicon_attribute(st);
-    ireg.ecx.b[0] = x0;
-    ireg.ecx.b[1] = y0;
-    ireg.edx.b[0] = x1;
-    ireg.edx.b[1] = y1;
-    __intcall(0x10, &ireg, NULL);
+    if (firmware->o_ops->erase)
+	firmware->o_ops->erase(x0, y0, x1, y1, attribute);
 }
 
 /* Show or hide the cursor */
 static void ansicon_showcursor(const struct term_state *st)
 {
-    static com32sys_t ireg;
-
-    ireg.eax.b[1] = 0x01;
-    ireg.ecx.w[0] = st->cursor ? cursor_type : 0x2020;
-    __intcall(0x10, &ireg, NULL);
+    firmware->o_ops->showcursor(st);
 }
 
 static void ansicon_set_cursor(int x, int y, bool visible)
 {
-    const int page = BIOS_PAGE;
-    struct curxy xy = BIOS_CURXY[page];
-    static com32sys_t ireg;
-
-    (void)visible;
-
-    if (xy.x != x || xy.y != y) {
-	ireg.eax.b[1] = 0x02;
-	ireg.ebx.b[1] = page;
-	ireg.edx.b[1] = y;
-	ireg.edx.b[0] = x;
-	__intcall(0x10, &ireg, NULL);
-    }
+    firmware->o_ops->set_cursor(x, y, visible);
 }
 
 static void ansicon_write_char(int x, int y, uint8_t ch,
 			       const struct term_state *st)
 {
-    static com32sys_t ireg;
-
+    uint8_t attribute = ansicon_attribute(st);
     ansicon_set_cursor(x, y, false);
 
-    ireg.eax.b[1] = 0x09;
-    ireg.eax.b[0] = ch;
-    ireg.ebx.b[1] = BIOS_PAGE;
-    ireg.ebx.b[0] = ansicon_attribute(st);
-    ireg.ecx.w[0] = 1;
-    __intcall(0x10, &ireg, NULL);
+    firmware->o_ops->write_char(ch, attribute);
 }
 
 static void ansicon_scroll_up(const struct term_state *st)
 {
-    static com32sys_t ireg;
+    uint8_t rows, cols, attribute;
 
-    ireg.eax.w[0] = 0x0601;
-    ireg.ebx.b[1] = ansicon_attribute(st);
-    ireg.ecx.w[0] = 0;
-    ireg.edx.b[1] = ti.rows - 1;
-    ireg.edx.b[0] = ti.cols - 1;
-    __intcall(0x10, &ireg, NULL);	/* Scroll */
+    /*
+     * Earlier code set ti.cols to 1 causing console output one char
+     * per line.
+     */
+    cols = 1;
+    rows = ti.rows - 1;
+    attribute = ansicon_attribute(st);
+
+    firmware->o_ops->scroll_up(cols, rows, attribute);
 }
 
 ssize_t __ansicon_write(struct file_info *fp, const void *buf, size_t count)
@@ -240,11 +202,8 @@
 
 void __ansicon_beep(void)
 {
-    static com32sys_t ireg;
-
-    ireg.eax.w[0] = 0x0e07;
-    ireg.ebx.b[1] = BIOS_PAGE;
-    __intcall(0x10, &ireg, NULL);
+    if (firmware->o_ops->beep)
+	firmware->o_ops->beep();
 }
 
 const struct output_dev dev_ansicon_w = {
diff --git a/com32/lib/sys/farcall.c b/com32/lib/sys/farcall.c
index 988ee6d..2749083 100644
--- a/com32/lib/sys/farcall.c
+++ b/com32/lib/sys/farcall.c
@@ -6,9 +6,17 @@
 
 static inline uint32_t eflags(void)
 {
-    uint32_t v;
+    //uint32_t v;
 
+#if __SIZEOF_POINTER__ == 4
+    uint32_t v;
     asm volatile("pushfl ; popl %0" : "=rm" (v));
+#elif __SIZEOF_POINTER__ == 8
+    uint64_t v;
+    asm volatile("pushfq ; pop %0" : "=rm" (v));
+#else
+#error "Unable to build for to-be-defined architecture type"
+#endif
     return v;
 }
 
diff --git a/com32/lib/sys/i386/x86_init_fpu.c b/com32/lib/sys/i386/x86_init_fpu.c
new file mode 100644
index 0000000..cf33693
--- /dev/null
+++ b/com32/lib/sys/i386/x86_init_fpu.c
@@ -0,0 +1,58 @@
+/*
+ * x86_has_fpu.c
+ *
+ * Test for an x86 FPU, and do any necessary setup.
+ */
+
+#include <inttypes.h>
+#include <sys/fpu.h>
+
+static inline uint64_t get_cr0(void)
+{
+    uint32_t v;
+asm("movl %%cr0,%0":"=r"(v));
+    return v;
+}
+
+static inline void set_cr0(uint32_t v)
+{
+    asm volatile ("movl %0,%%cr0"::"r" (v));
+}
+
+#define CR0_PE	0x00000001
+#define CR0_MP  0x00000002
+#define CR0_EM  0x00000004
+#define CR0_TS  0x00000008
+#define CR0_ET  0x00000010
+#define CR0_NE  0x00000020
+#define CR0_WP  0x00010000
+#define CR0_AM  0x00040000
+#define CR0_NW  0x20000000
+#define CR0_CD  0x40000000
+#define CR0_PG  0x80000000
+
+int x86_init_fpu(void)
+{
+    uint32_t cr0;
+    uint16_t fsw = 0xffff;
+    uint16_t fcw = 0xffff;
+
+    cr0 = get_cr0();
+    cr0 &= ~(CR0_EM | CR0_TS);
+    cr0 |= CR0_MP;
+    set_cr0(cr0);
+
+    asm volatile ("fninit");
+    asm volatile ("fnstsw %0":"+m" (fsw));
+    if (fsw != 0)
+	return -1;
+
+    asm volatile ("fnstcw %0":"+m" (fcw));
+    if ((fcw & 0x103f) != 0x3f)
+	return -1;
+
+    /* Techically, this could be a 386 with a 287.  We could add a check
+       for that here... */
+
+    return 0;
+}
diff --git a/com32/lib/sys/module/common.c b/com32/lib/sys/module/common.c
index 8547036..4c83789 100644
--- a/com32/lib/sys/module/common.c
+++ b/com32/lib/sys/module/common.c
@@ -23,7 +23,7 @@
 
 // User-space debugging routines
 #ifdef ELF_DEBUG
-void print_elf_ehdr(Elf32_Ehdr *ehdr) {
+void print_elf_ehdr(Elf_Ehdr *ehdr) {
 	int i;
 
 	fprintf(stderr, "Identification:\t");
@@ -38,18 +38,18 @@
 	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, "Header size:\t%u (Structure size: %u)\n", ehdr->e_ehsize,sizeof(Elf_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;
+	Elf_Sym *crt_sym;
 
 	for (i = 1; i < module->symtable_size/module->syment_size; i++)
 	{
-		crt_sym = (Elf32_Sym*)(module->sym_table + i*module->syment_size);
+		crt_sym = (Elf_Sym*)(module->sym_table + i*module->syment_size);
 
 		fprintf(stderr,"%s %d\n", module->str_table + crt_sym->st_name, crt_sym->st_value);
 
@@ -163,7 +163,7 @@
 	return 0;
 }
 
-int image_seek(Elf32_Off offset, struct elf_module *module) {
+int image_seek(Elf_Off offset, struct elf_module *module) {
 	if (offset < module->u.l._cr_offset) // Cannot seek backwards
 		return -1;
 
@@ -223,9 +223,14 @@
 }
 
 
+// Mouli: This is checking the header for 32bit machine
+// Support 64bit architecture as well.
+// Parts of the ELF header checked are common to both ELF32 and ELF64
+// Adding simple checks for both 32bit and 64bit should work (hopefully)
+//
 // 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) {
+int check_header_common(Elf_Ehdr *elf_hdr) {
 	// Check the header magic
 	if (elf_hdr->e_ident[EI_MAG0] != ELFMAG0 ||
 		elf_hdr->e_ident[EI_MAG1] != ELFMAG1 ||
@@ -236,7 +241,8 @@
 		return -1;
 	}
 
-	if (elf_hdr->e_ident[EI_CLASS] != MODULE_ELF_CLASS) {
+	if (elf_hdr->e_ident[EI_CLASS] != ELFCLASS32 &&
+	    elf_hdr->e_ident[EI_CLASS] != ELFCLASS64) {
 		DBG_PRINT("Invalid ELF class code\n");
 		return -1;
 	}
@@ -252,7 +258,8 @@
 		return -1;
 	}
 
-	if (elf_hdr->e_machine != MODULE_ELF_MACHINE) {
+	if (elf_hdr->e_machine != EM_386 &&
+		elf_hdr->e_machine != EM_X86_64) {
 		DBG_PRINT("Invalid ELF architecture\n");
 		return -1;
 	}
@@ -261,6 +268,7 @@
 }
 
 
+
 int enforce_dependency(struct elf_module *req, struct elf_module *dep) {
 	struct module_dep *crt_dep;
 	struct module_dep *new_dep;
@@ -317,7 +325,7 @@
 int check_symbols(struct elf_module *module)
 {
 	unsigned int i;
-	Elf32_Sym *crt_sym = NULL, *ref_sym = NULL;
+	Elf_Sym *crt_sym = NULL, *ref_sym = NULL;
 	char *crt_name;
 	struct elf_module *crt_module;
 
@@ -455,18 +463,18 @@
 	return begin;
 }
 
-static Elf32_Sym *module_find_symbol_sysv(const char *name, struct elf_module *module) {
+static Elf_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;
+	Elf_Word *cr_word = module->hash_table;
 
-	Elf32_Word nbucket = *cr_word++;
+	Elf_Word nbucket = *cr_word++;
 	cr_word++; // Skip nchain
 
-	Elf32_Word *bkt = cr_word;
-	Elf32_Word *chn = cr_word + nbucket;
+	Elf_Word *bkt = cr_word;
+	Elf_Word *chn = cr_word + nbucket;
 
-	Elf32_Word crt_index = bkt[h % module->hash_table[0]];
-	Elf32_Sym *crt_sym;
+	Elf_Word crt_index = bkt[h % module->hash_table[0]];
+	Elf_Sym *crt_sym;
 
 
 	while (crt_index != STN_UNDEF) {
@@ -481,32 +489,32 @@
 	return NULL;
 }
 
-static Elf32_Sym *module_find_symbol_gnu(const char *name, struct elf_module *module) {
+static Elf_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++;
+	Elf_Word *cr_word = module->ghash_table;
+	Elf_Word nbucket = *cr_word++;
+	Elf_Word symbias = *cr_word++;
+	Elf_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++;
+	Elf_Word gnu_shift = *cr_word++;
 
-	Elf32_Addr *gnu_bitmask = (Elf32_Addr*)cr_word;
+	Elf_Addr *gnu_bitmask = (Elf_Addr*)cr_word;
 	cr_word += MODULE_ELF_CLASS_SIZE / 32 * bitmask_nwords;
 
-	Elf32_Word *gnu_buckets = cr_word;
+	Elf_Word *gnu_buckets = cr_word;
 	cr_word += nbucket;
 
-	Elf32_Word *gnu_chain_zero = cr_word - symbias;
+	Elf_Word *gnu_chain_zero = cr_word - symbias;
 
 	// Computations
-	Elf32_Word bitmask_word = gnu_bitmask[(h / MODULE_ELF_CLASS_SIZE) &
+	Elf_Bword bitmask_word = gnu_bitmask[(h / MODULE_ELF_CLASS_SIZE) &
 	                                       (bitmask_nwords - 1)];
 
 	unsigned int hashbit1 = h & (MODULE_ELF_CLASS_SIZE - 1);
@@ -514,18 +522,18 @@
 
 	if ((bitmask_word >> hashbit1) & (bitmask_word >> hashbit2) & 1) {
 		unsigned long rem;
-		Elf32_Word bucket;
+		Elf_Word bucket;
 
 		rem = h % nbucket;
 
 		bucket = gnu_buckets[rem];
 
 		if (bucket != 0) {
-			const Elf32_Word* hasharr = &gnu_chain_zero[bucket];
+			const Elf_Word* hasharr = &gnu_chain_zero[bucket];
 
 			do {
 				if (((*hasharr ^ h ) >> 1) == 0) {
-					Elf32_Sym *crt_sym = symbol_get_entry(module, (hasharr - gnu_chain_zero));
+					Elf_Sym *crt_sym = symbol_get_entry(module, (hasharr - gnu_chain_zero));
 
 					if (strcmp(name, module->str_table + crt_sym->st_name) == 0) {
 						return crt_sym;
@@ -538,11 +546,11 @@
 	return NULL;
 }
 
-static Elf32_Sym *module_find_symbol_iterate(const char *name,struct elf_module *module)
+static Elf_Sym *module_find_symbol_iterate(const char *name,struct elf_module *module)
 {
 
 	unsigned int i;
-	Elf32_Sym *crt_sym;
+	Elf_Sym *crt_sym;
 
 	for (i = 1; i < module->symtable_size/module->syment_size; i++)
 	{
@@ -556,8 +564,8 @@
 	return NULL;
 }
 
-Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module) {
-	Elf32_Sym *result = NULL;
+Elf_Sym *module_find_symbol(const char *name, struct elf_module *module) {
+	Elf_Sym *result = NULL;
 
 	if (module->ghash_table != NULL)
 		result = module_find_symbol_gnu(name, module);
@@ -579,10 +587,10 @@
 	return result;
 }
 
-Elf32_Sym *global_find_symbol(const char *name, struct elf_module **module) {
+Elf_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;
+	Elf_Sym *crt_sym = NULL;
+	Elf_Sym *result = NULL;
 
 	for_each_module(crt_module) {
 		crt_sym = module_find_symbol(name, crt_module);
diff --git a/com32/lib/sys/module/common.h b/com32/lib/sys/module/common.h
index 54f0ec4..652c973 100644
--- a/com32/lib/sys/module/common.h
+++ b/com32/lib/sys/module/common.h
@@ -15,7 +15,6 @@
 
 #include "elfutils.h"
 
-
 // Performs an operation and jumps to a given label if an error occurs
 #define CHECKED(res, expr, error)		\
 	do { 								\
@@ -27,12 +26,12 @@
 #define MIN(x,y)	(((x) < (y)) ? (x) : (y))
 #define MAX(x,y)	(((x) > (y)) ? (x) : (y))
 
-static inline Elf32_Sym *symbol_get_entry(struct elf_module *module, int entry)
+static inline Elf_Sym *symbol_get_entry(struct elf_module *module, int entry)
 {
 	char *sym_table = (char *)module->sym_table;
 	int index = entry * module->syment_size;
 
-	return (Elf32_Sym *)(sym_table + index);
+	return (Elf_Sym *)(sym_table + index);
 }
 
 //#define ELF_DEBUG
@@ -45,7 +44,7 @@
 
 // User-space debugging routines
 #ifdef ELF_DEBUG
-extern void print_elf_ehdr(Elf32_Ehdr *ehdr);
+extern void print_elf_ehdr(Elf_Ehdr *ehdr);
 extern void print_elf_symbols(struct elf_module *module);
 #endif //ELF_DEBUG
 
@@ -58,11 +57,11 @@
 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 int image_seek(Elf_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 check_header_common(Elf_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);
diff --git a/com32/lib/sys/module/elf_module.c b/com32/lib/sys/module/elf_module.c
index 6a54027..e3d9928 100644
--- a/com32/lib/sys/module/elf_module.c
+++ b/com32/lib/sys/module/elf_module.c
@@ -20,7 +20,7 @@
 #include "elfutils.h"
 #include "common.h"
 
-static int check_header(Elf32_Ehdr *elf_hdr) {
+static int check_header(Elf_Ehdr *elf_hdr) {
 	int res;
 
 	res = check_header_common(elf_hdr);
@@ -47,170 +47,10 @@
  * in the PHT sorted by their offsets, so that only forward seeks would
  * be necessary.
  */
-static int load_segments(struct elf_module *module, Elf32_Ehdr *elf_hdr) {
-	int i;
-	int res = 0;
-	char *pht = NULL;
-	char *sht = NULL;
-	Elf32_Phdr *cr_pht;
-	Elf32_Shdr *cr_sht;
-
-	Elf32_Addr min_addr  = 0x00000000; // Min. ELF vaddr
-	Elf32_Addr max_addr  = 0x00000000; // Max. ELF vaddr
-	Elf32_Word max_align = sizeof(void*); // Min. align of posix_memalign()
-	Elf32_Addr min_alloc, max_alloc;   // Min. and max. aligned allocables
-
-	Elf32_Addr dyn_addr = 0x00000000;
-
-	// Get to the PHT
-	image_seek(elf_hdr->e_phoff, module);
-
-	// Load the PHT
-	pht = malloc(elf_hdr->e_phnum * elf_hdr->e_phentsize);
-	if (!pht)
-		return -1;
-
-	image_read(pht, elf_hdr->e_phnum * elf_hdr->e_phentsize, module);
-
-	// Compute the memory needings of the module
-	for (i=0; i < elf_hdr->e_phnum; i++) {
-		cr_pht = (Elf32_Phdr*)(pht + i * elf_hdr->e_phentsize);
-
-		switch (cr_pht->p_type) {
-		case PT_LOAD:
-			if (i == 0) {
-				min_addr = cr_pht->p_vaddr;
-			} else {
-				min_addr = MIN(min_addr, cr_pht->p_vaddr);
-			}
-
-			max_addr = MAX(max_addr, cr_pht->p_vaddr + cr_pht->p_memsz);
-			max_align = MAX(max_align, cr_pht->p_align);
-			break;
-		case PT_DYNAMIC:
-			dyn_addr = cr_pht->p_vaddr;
-			break;
-		default:
-			// Unsupported - ignore
-			break;
-		}
-	}
-
-	if (max_addr - min_addr == 0) {
-		// No loadable segments
-		DBG_PRINT("No loadable segments found\n");
-		goto out;
-	}
-
-	if (dyn_addr == 0) {
-		DBG_PRINT("No dynamic information segment found\n");
-		goto out;
-	}
-
-	// The minimum address that should be allocated
-	min_alloc = min_addr - (min_addr % max_align);
-
-	// The maximum address that should be allocated
-	max_alloc = max_addr - (max_addr % max_align);
-	if (max_addr % max_align > 0)
-		max_alloc += max_align;
-
-
-	if (elf_malloc(&module->module_addr,
-			max_align,
-			max_alloc-min_alloc) != 0) {
-
-		DBG_PRINT("Could not allocate segments\n");
-		goto out;
-	}
-
-	module->base_addr = (Elf32_Addr)(module->module_addr) - min_alloc;
-	module->module_size = max_alloc - min_alloc;
-
-	// Zero-initialize the memory
-	memset(module->module_addr, 0, module->module_size);
-
-	for (i = 0; i < elf_hdr->e_phnum; i++) {
-		cr_pht = (Elf32_Phdr*)(pht + i * elf_hdr->e_phentsize);
-
-		if (cr_pht->p_type == PT_LOAD) {
-			// Copy the segment at its destination
-			if (cr_pht->p_offset < module->u.l._cr_offset) {
-				// The segment contains data before the current offset
-				// It can be discarded without worry - it would contain only
-				// headers
-				Elf32_Off aux_off = module->u.l._cr_offset - cr_pht->p_offset;
-
-				if (image_read((char *)module_get_absolute(cr_pht->p_vaddr, module) + aux_off,
-					       cr_pht->p_filesz - aux_off, module) < 0) {
-					res = -1;
-					goto out;
-				}
-			} else {
-				if (image_seek(cr_pht->p_offset, module) < 0) {
-					res = -1;
-					goto out;
-				}
-
-				if (image_read(module_get_absolute(cr_pht->p_vaddr, module),
-						cr_pht->p_filesz, module) < 0) {
-					res = -1;
-					goto out;
-				}
-			}
-
-			/*
-			DBG_PRINT("Loadable segment of size 0x%08x copied from vaddr 0x%08x at 0x%08x\n",
-					cr_pht->p_filesz,
-					cr_pht->p_vaddr,
-					(Elf32_Addr)module_get_absolute(cr_pht->p_vaddr, module));
-			*/
-		}
-	}
-
-	// Get to the SHT
-	image_seek(elf_hdr->e_shoff, module);
-
-	// Load the SHT
-	sht = malloc(elf_hdr->e_shnum * elf_hdr->e_shentsize);
-	if (!sht) {
-		res = -1;
-		goto out;
-	}
-
-	image_read(sht, elf_hdr->e_shnum * elf_hdr->e_shentsize, module);
-
-	// Setup the symtable size
-	for (i = 0; i < elf_hdr->e_shnum; i++) {
-		cr_sht = (Elf32_Shdr*)(sht + i * elf_hdr->e_shentsize);
-
-		if (cr_sht->sh_type == SHT_DYNSYM) {
-			module->symtable_size = cr_sht->sh_size;
-			break;
-		}
-	}
-
-	free(sht);
-
-	// Setup dynamic segment location
-	module->dyn_table = module_get_absolute(dyn_addr, module);
-
-	/*
-	DBG_PRINT("Base address: 0x%08x, aligned at 0x%08x\n", module->base_addr,
-			max_align);
-	DBG_PRINT("Module size: 0x%08x\n", module->module_size);
-	*/
-
-out:
-	// Free up allocated memory
-	if (pht != NULL)
-		free(pht);
-
-	return res;
-}
+extern int load_segments(struct elf_module *module, Elf_Ehdr *elf_hdr);
 
 static int prepare_dynlinking(struct elf_module *module) {
-	Elf32_Dyn  *dyn_entry = module->dyn_table;
+	Elf_Dyn  *dyn_entry = module->dyn_table;
 
 	while (dyn_entry->d_tag != DT_NULL) {
 		switch (dyn_entry->d_tag) {
@@ -230,11 +70,11 @@
 			break;
 		case DT_HASH:
 			module->hash_table =
-				(Elf32_Word*)module_get_absolute(dyn_entry->d_un.d_ptr, module);
+				(Elf_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);
+				(Elf_Word*)module_get_absolute(dyn_entry->d_un.d_ptr, module);
 			break;
 		case DT_STRTAB:
 			module->str_table =
@@ -267,168 +107,12 @@
 	kaboom();
 }
 
-static int perform_relocation(struct elf_module *module, Elf32_Rel *rel) {
-	Elf32_Word *dest = module_get_absolute(rel->r_offset, module);
-
-	// The symbol reference index
-	Elf32_Word sym = ELF32_R_SYM(rel->r_info);
-	unsigned char type = ELF32_R_TYPE(rel->r_info);
-
-	// The symbol definition (if applicable)
-	Elf32_Sym *sym_def = NULL;
-	struct elf_module *sym_module = NULL;
-	Elf32_Addr sym_addr = 0x0;
-
-	if (sym > 0) {
-		// Find out details about the symbol
-
-		// The symbol reference
-		Elf32_Sym *sym_ref = symbol_get_entry(module, sym);
-
-		// The symbol definition
-		sym_def =
-			global_find_symbol(module->str_table + sym_ref->st_name,
-					&sym_module);
-
-		if (sym_def == NULL) {
-			DBG_PRINT("Cannot perform relocation for symbol %s\n",
-					module->str_table + sym_ref->st_name);
-
-			if (ELF32_ST_BIND(sym_ref->st_info) != STB_WEAK)
-				return -1;
-
-			// This must be a derivative-specific
-			// function. We're OK as long as we never
-			// execute the function.
-			sym_def = global_find_symbol("undefined_symbol", &sym_module);
-		}
-
-		// Compute the absolute symbol virtual address
-		sym_addr = (Elf32_Addr)module_get_absolute(sym_def->st_value, sym_module);
-
-		if (sym_module != module) {
-			// Create a dependency
-			enforce_dependency(sym_module, module);
-		}
-	}
-
-	switch (type) {
-	case R_386_NONE:
-		// Do nothing
-		break;
-	case R_386_32:
-		*dest += sym_addr;
-		break;
-	case R_386_PC32:
-		*dest += sym_addr - (Elf32_Addr)dest;
-		break;
-	case R_386_COPY:
-		if (sym_addr > 0) {
-			memcpy((void*)dest, (void*)sym_addr, sym_def->st_size);
-		}
-		break;
-	case R_386_GLOB_DAT:
-	case R_386_JMP_SLOT:
-		// Maybe TODO: Keep track of the GOT entries allocations
-		*dest = sym_addr;
-		break;
-	case R_386_RELATIVE:
-		*dest += module->base_addr;
-		break;
-	default:
-		DBG_PRINT("Relocation type %d not supported\n", type);
-		return -1;
-	}
-
-	return 0;
-}
-
-static int resolve_symbols(struct elf_module *module) {
-	Elf32_Dyn  *dyn_entry = module->dyn_table;
-	unsigned int i;
-	int res;
-
-	Elf32_Word plt_rel_size = 0;
-	char *plt_rel = NULL;
-
-	char *rel = NULL;
-	Elf32_Word rel_size = 0;
-	Elf32_Word rel_entry = 0;
-
-	// The current relocation
-	Elf32_Rel *crt_rel;
-
-	while (dyn_entry->d_tag != DT_NULL) {
-		switch(dyn_entry->d_tag) {
-
-		// PLT relocation information
-		case DT_PLTRELSZ:
-			plt_rel_size = dyn_entry->d_un.d_val;
-			break;
-		case DT_PLTREL:
-			if (dyn_entry->d_un.d_val != DT_REL) {
-				DBG_PRINT("Unsupported PLT relocation\n");
-				return -1;
-			}
-		case DT_JMPREL:
-			plt_rel = module_get_absolute(dyn_entry->d_un.d_ptr, module);
-			break;
-
-		// Standard relocation information
-		case DT_REL:
-			rel = module_get_absolute(dyn_entry->d_un.d_ptr, module);
-			break;
-		case DT_RELSZ:
-			rel_size = dyn_entry->d_un.d_val;
-			break;
-		case DT_RELENT:
-			rel_entry = dyn_entry->d_un.d_val;
-			break;
-
-		// Module initialization and termination
-		case DT_INIT:
-			// TODO Implement initialization functions
-			break;
-		case DT_FINI:
-			// TODO Implement finalization functions
-			break;
-		}
-
-		dyn_entry++;
-	}
-
-	if (rel_size > 0) {
-		// Process standard relocations
-		for (i = 0; i < rel_size/rel_entry; i++) {
-			crt_rel = (Elf32_Rel*)(rel + i*rel_entry);
-
-			res = perform_relocation(module, crt_rel);
-
-			if (res < 0)
-				return res;
-		}
-
-	}
-
-	if (plt_rel_size > 0) {
-		// TODO: Permit this lazily
-		// Process PLT relocations
-		for (i = 0; i < plt_rel_size/sizeof(Elf32_Rel); i++) {
-			crt_rel = (Elf32_Rel*)(plt_rel + i*sizeof(Elf32_Rel));
-
-			res = perform_relocation(module, crt_rel);
-
-			if (res < 0)
-				return res;
-		}
-	}
-
-	return 0;
-}
+extern int perform_relocation(struct elf_module *module, Elf_Rel *rel);
+extern int resolve_symbols(struct elf_module *module);
 
 static int extract_operations(struct elf_module *module) {
-	Elf32_Sym *ctors_start, *ctors_end;
-	Elf32_Sym *dtors_start, *dtors_end;
+	Elf_Sym *ctors_start, *ctors_end;
+	Elf_Sym *dtors_start, *dtors_end;
 	module_ctor_t *ctors = NULL;
 	module_ctor_t *dtors = NULL;
 
@@ -497,8 +181,8 @@
 // Loads the module into the system
 int module_load(struct elf_module *module) {
 	int res;
-	Elf32_Sym *main_sym;
-	Elf32_Ehdr elf_hdr;
+	Elf_Sym *main_sym;
+	Elf_Ehdr elf_hdr;
 	module_ctor_t *ctor;
 	struct elf_module *head = NULL;
 
@@ -518,7 +202,7 @@
 	// The module is a fully featured dynamic library
 	module->shallow = 0;
 
-	CHECKED(res, image_read(&elf_hdr, sizeof(Elf32_Ehdr), module), error);
+	CHECKED(res, image_read(&elf_hdr, sizeof(Elf_Ehdr), module), error);
 	//printf("check... 1\n");
 	
 	//print_elf_ehdr(&elf_hdr);
diff --git a/com32/lib/sys/module/elfutils.h b/com32/lib/sys/module/elfutils.h
index a901ff4..91bdcb3 100644
--- a/com32/lib/sys/module/elfutils.h
+++ b/com32/lib/sys/module/elfutils.h
@@ -3,23 +3,24 @@
 
 #include <elf.h>
 #include <stdlib.h>
+#include <sys/module.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;
+static inline Elf_Ehdr *elf_get_header(void *elf_image) {
+	return (Elf_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);
+static inline Elf_Phdr *elf_get_pht(void *elf_image) {
+	Elf_Ehdr *elf_hdr = elf_get_header(elf_image);
 
-	return (Elf32_Phdr*)((Elf32_Off)elf_hdr + elf_hdr->e_phoff);
+	return (Elf_Phdr*)((Elf_Off)elf_hdr + elf_hdr->e_phoff);
 }
 
 //
@@ -28,11 +29,11 @@
  * @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);
+static inline Elf_Phdr *elf_get_ph(void *elf_image, int index) {
+	Elf_Phdr *elf_pht = elf_get_pht(elf_image);
+	Elf_Ehdr *elf_hdr = elf_get_header(elf_image);
 
-	return (Elf32_Phdr*)((Elf32_Off)elf_pht + index * elf_hdr->e_phentsize);
+	return (Elf_Phdr*)((Elf_Off)elf_pht + index * elf_hdr->e_phentsize);
 }
 
 /**
diff --git a/com32/lib/sys/module/i386/elf_module.c b/com32/lib/sys/module/i386/elf_module.c
new file mode 100644
index 0000000..d30f4ce
--- /dev/null
+++ b/com32/lib/sys/module/i386/elf_module.c
@@ -0,0 +1,349 @@
+/*
+ * elf_module.c
+ *
+ *  Created on: Aug 11, 2008
+ *      Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <elf.h>
+#include <dprintf.h>
+#include <core.h>
+
+#include <linux/list.h>
+#include <sys/module.h>
+#include <sys/exec.h>
+
+#include "elfutils.h"
+#include "../common.h"
+
+/*
+ *
+ * The implementation assumes that the loadable segments are present
+ * in the PHT sorted by their offsets, so that only forward seeks would
+ * be necessary.
+ */
+int load_segments(struct elf_module *module, Elf_Ehdr *elf_hdr) {
+	int i;
+	int res = 0;
+	char *pht = NULL;
+	char *sht = NULL;
+	Elf32_Phdr *cr_pht;
+	Elf32_Shdr *cr_sht;
+
+	Elf32_Addr min_addr  = 0x00000000; // Min. ELF vaddr
+	Elf32_Addr max_addr  = 0x00000000; // Max. ELF vaddr
+	Elf32_Word max_align = sizeof(void*); // Min. align of posix_memalign()
+	Elf32_Addr min_alloc, max_alloc;   // Min. and max. aligned allocables
+
+	Elf32_Addr dyn_addr = 0x00000000;
+
+	// Get to the PHT
+	image_seek(elf_hdr->e_phoff, module);
+
+	// Load the PHT
+	pht = malloc(elf_hdr->e_phnum * elf_hdr->e_phentsize);
+	if (!pht)
+		return -1;
+
+	image_read(pht, elf_hdr->e_phnum * elf_hdr->e_phentsize, module);
+
+	// Compute the memory needings of the module
+	for (i=0; i < elf_hdr->e_phnum; i++) {
+		cr_pht = (Elf32_Phdr*)(pht + i * elf_hdr->e_phentsize);
+
+		switch (cr_pht->p_type) {
+		case PT_LOAD:
+			if (i == 0) {
+				min_addr = cr_pht->p_vaddr;
+			} else {
+				min_addr = MIN(min_addr, cr_pht->p_vaddr);
+			}
+
+			max_addr = MAX(max_addr, cr_pht->p_vaddr + cr_pht->p_memsz);
+			max_align = MAX(max_align, cr_pht->p_align);
+			break;
+		case PT_DYNAMIC:
+			dyn_addr = cr_pht->p_vaddr;
+			break;
+		default:
+			// Unsupported - ignore
+			break;
+		}
+	}
+
+	if (max_addr - min_addr == 0) {
+		// No loadable segments
+		DBG_PRINT("No loadable segments found\n");
+		goto out;
+	}
+
+	if (dyn_addr == 0) {
+		DBG_PRINT("No dynamic information segment found\n");
+		goto out;
+	}
+
+	// The minimum address that should be allocated
+	min_alloc = min_addr - (min_addr % max_align);
+
+	// The maximum address that should be allocated
+	max_alloc = max_addr - (max_addr % max_align);
+	if (max_addr % max_align > 0)
+		max_alloc += max_align;
+
+
+	if (elf_malloc(&module->module_addr,
+			max_align,
+			max_alloc-min_alloc) != 0) {
+
+		DBG_PRINT("Could not allocate segments\n");
+		goto out;
+	}
+
+	module->base_addr = (Elf32_Addr)(module->module_addr) - min_alloc;
+	module->module_size = max_alloc - min_alloc;
+
+	// Zero-initialize the memory
+	memset(module->module_addr, 0, module->module_size);
+
+	for (i = 0; i < elf_hdr->e_phnum; i++) {
+		cr_pht = (Elf32_Phdr*)(pht + i * elf_hdr->e_phentsize);
+
+		if (cr_pht->p_type == PT_LOAD) {
+			// Copy the segment at its destination
+			if (cr_pht->p_offset < module->u.l._cr_offset) {
+				// The segment contains data before the current offset
+				// It can be discarded without worry - it would contain only
+				// headers
+				Elf32_Off aux_off = module->u.l._cr_offset - cr_pht->p_offset;
+
+				if (image_read((char *)module_get_absolute(cr_pht->p_vaddr, module) + aux_off,
+					       cr_pht->p_filesz - aux_off, module) < 0) {
+					res = -1;
+					goto out;
+				}
+			} else {
+				if (image_seek(cr_pht->p_offset, module) < 0) {
+					res = -1;
+					goto out;
+				}
+
+				if (image_read(module_get_absolute(cr_pht->p_vaddr, module),
+						cr_pht->p_filesz, module) < 0) {
+					res = -1;
+					goto out;
+				}
+			}
+
+			/*
+			DBG_PRINT("Loadable segment of size 0x%08x copied from vaddr 0x%08x at 0x%08x\n",
+					cr_pht->p_filesz,
+					cr_pht->p_vaddr,
+					(Elf32_Addr)module_get_absolute(cr_pht->p_vaddr, module));
+			*/
+		}
+	}
+
+	// Get to the SHT
+	image_seek(elf_hdr->e_shoff, module);
+
+	// Load the SHT
+	sht = malloc(elf_hdr->e_shnum * elf_hdr->e_shentsize);
+	if (!sht) {
+		res = -1;
+		goto out;
+	}
+
+	image_read(sht, elf_hdr->e_shnum * elf_hdr->e_shentsize, module);
+
+	// Setup the symtable size
+	for (i = 0; i < elf_hdr->e_shnum; i++) {
+		cr_sht = (Elf32_Shdr*)(sht + i * elf_hdr->e_shentsize);
+
+		if (cr_sht->sh_type == SHT_DYNSYM) {
+			module->symtable_size = cr_sht->sh_size;
+			break;
+		}
+	}
+
+	free(sht);
+
+	// Setup dynamic segment location
+	module->dyn_table = module_get_absolute(dyn_addr, module);
+
+	/*
+	DBG_PRINT("Base address: 0x%08x, aligned at 0x%08x\n", module->base_addr,
+			max_align);
+	DBG_PRINT("Module size: 0x%08x\n", module->module_size);
+	*/
+
+out:
+	// Free up allocated memory
+	if (pht != NULL)
+		free(pht);
+
+	return res;
+}
+
+int perform_relocation(struct elf_module *module, Elf_Rel *rel) {
+	Elf32_Word *dest = module_get_absolute(rel->r_offset, module);
+
+	// The symbol reference index
+	Elf32_Word sym = ELF32_R_SYM(rel->r_info);
+	unsigned char type = ELF32_R_TYPE(rel->r_info);
+
+	// The symbol definition (if applicable)
+	Elf32_Sym *sym_def = NULL;
+	struct elf_module *sym_module = NULL;
+	Elf32_Addr sym_addr = 0x0;
+
+	if (sym > 0) {
+		// Find out details about the symbol
+
+		// The symbol reference
+		Elf32_Sym *sym_ref = symbol_get_entry(module, sym);
+
+		// The symbol definition
+		sym_def =
+			global_find_symbol(module->str_table + sym_ref->st_name,
+					&sym_module);
+
+		if (sym_def == NULL) {
+			DBG_PRINT("Cannot perform relocation for symbol %s\n",
+					module->str_table + sym_ref->st_name);
+
+			if (ELF32_ST_BIND(sym_ref->st_info) != STB_WEAK)
+				return -1;
+
+			// This must be a derivative-specific
+			// function. We're OK as long as we never
+			// execute the function.
+			sym_def = global_find_symbol("undefined_symbol", &sym_module);
+		}
+
+		// Compute the absolute symbol virtual address
+		sym_addr = (Elf32_Addr)module_get_absolute(sym_def->st_value, sym_module);
+
+		if (sym_module != module) {
+			// Create a dependency
+			enforce_dependency(sym_module, module);
+		}
+	}
+
+	switch (type) {
+	case R_386_NONE:
+		// Do nothing
+		break;
+	case R_386_32:
+		*dest += sym_addr;
+		break;
+	case R_386_PC32:
+		*dest += sym_addr - (Elf32_Addr)dest;
+		break;
+	case R_386_COPY:
+		if (sym_addr > 0) {
+			memcpy((void*)dest, (void*)sym_addr, sym_def->st_size);
+		}
+		break;
+	case R_386_GLOB_DAT:
+	case R_386_JMP_SLOT:
+		// Maybe TODO: Keep track of the GOT entries allocations
+		*dest = sym_addr;
+		break;
+	case R_386_RELATIVE:
+		*dest += module->base_addr;
+		break;
+	default:
+		DBG_PRINT("Relocation type %d not supported\n", type);
+		return -1;
+	}
+
+	return 0;
+}
+
+int resolve_symbols(struct elf_module *module) {
+	Elf32_Dyn  *dyn_entry = module->dyn_table;
+	unsigned int i;
+	int res;
+
+	Elf32_Word plt_rel_size = 0;
+	char *plt_rel = NULL;
+
+	char *rel = NULL;
+	Elf32_Word rel_size = 0;
+	Elf32_Word rel_entry = 0;
+
+	// The current relocation
+	Elf32_Rel *crt_rel;
+
+	while (dyn_entry->d_tag != DT_NULL) {
+		switch(dyn_entry->d_tag) {
+
+		// PLT relocation information
+		case DT_PLTRELSZ:
+			plt_rel_size = dyn_entry->d_un.d_val;
+			break;
+		case DT_PLTREL:
+			if (dyn_entry->d_un.d_val != DT_REL) {
+				DBG_PRINT("Unsupported PLT relocation\n");
+				return -1;
+			}
+		case DT_JMPREL:
+			plt_rel = module_get_absolute(dyn_entry->d_un.d_ptr, module);
+			break;
+
+		// Standard relocation information
+		case DT_REL:
+			rel = module_get_absolute(dyn_entry->d_un.d_ptr, module);
+			break;
+		case DT_RELSZ:
+			rel_size = dyn_entry->d_un.d_val;
+			break;
+		case DT_RELENT:
+			rel_entry = dyn_entry->d_un.d_val;
+			break;
+
+		// Module initialization and termination
+		case DT_INIT:
+			// TODO Implement initialization functions
+			break;
+		case DT_FINI:
+			// TODO Implement finalization functions
+			break;
+		}
+
+		dyn_entry++;
+	}
+
+	if (rel_size > 0) {
+		// Process standard relocations
+		for (i = 0; i < rel_size/rel_entry; i++) {
+			crt_rel = (Elf32_Rel*)(rel + i*rel_entry);
+
+			res = perform_relocation(module, crt_rel);
+
+			if (res < 0)
+				return res;
+		}
+
+	}
+
+	if (plt_rel_size > 0) {
+		// TODO: Permit this lazily
+		// Process PLT relocations
+		for (i = 0; i < plt_rel_size/sizeof(Elf32_Rel); i++) {
+			crt_rel = (Elf32_Rel*)(plt_rel + i*sizeof(Elf32_Rel));
+
+			res = perform_relocation(module, crt_rel);
+
+			if (res < 0)
+				return res;
+		}
+	}
+
+	return 0;
+}
+
diff --git a/com32/lib/sys/module/x86_64/elf_module.c b/com32/lib/sys/module/x86_64/elf_module.c
new file mode 100644
index 0000000..dd24bd1
--- /dev/null
+++ b/com32/lib/sys/module/x86_64/elf_module.c
@@ -0,0 +1,380 @@
+/*
+ * elf_module.c
+ *
+ *  Created on: Aug 11, 2008
+ *      Author: Stefan Bucur <stefanb@zytor.com>
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <elf.h>
+#include <dprintf.h>
+#include <core.h>
+
+#include <linux/list.h>
+#include <sys/module.h>
+#include <sys/exec.h>
+
+#include "elfutils.h"
+#include "../common.h"
+
+/*
+ *
+ * The implementation assumes that the loadable segments are present
+ * in the PHT sorted by their offsets, so that only forward seeks would
+ * be necessary.
+ */
+int load_segments(struct elf_module *module, Elf_Ehdr *elf_hdr) {
+	int i;
+	int res = 0;
+	char *pht = NULL;
+	char *sht = NULL;
+	Elf64_Phdr *cr_pht;
+	Elf64_Shdr *cr_sht;
+
+	Elf64_Addr min_addr  = 0x0000000000000000; // Min. ELF vaddr
+	Elf64_Addr max_addr  = 0x0000000000000000; // Max. ELF vaddr
+	Elf64_Word max_align = sizeof(void*); // Min. align of posix_memalign()
+	Elf64_Addr min_alloc, max_alloc;   // Min. and max. aligned allocables
+
+	Elf64_Addr dyn_addr = 0x0000000000000000;
+
+	// Get to the PHT
+	image_seek(elf_hdr->e_phoff, module);
+
+	// Load the PHT
+	pht = malloc(elf_hdr->e_phnum * elf_hdr->e_phentsize);
+	if (!pht)
+		return -1;
+
+	image_read(pht, elf_hdr->e_phnum * elf_hdr->e_phentsize, module);
+
+	// Compute the memory needings of the module
+	for (i=0; i < elf_hdr->e_phnum; i++) {
+		cr_pht = (Elf64_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 = (Elf64_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 = (Elf64_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
+				Elf64_Off aux_off = module->u.l._cr_offset - cr_pht->p_offset;
+
+				if (image_read((char *)module_get_absolute(cr_pht->p_vaddr, module) + aux_off,
+					       cr_pht->p_filesz - aux_off, module) < 0) {
+					res = -1;
+					goto out;
+				}
+			} else {
+				if (image_seek(cr_pht->p_offset, module) < 0) {
+					res = -1;
+					goto out;
+				}
+
+				if (image_read(module_get_absolute(cr_pht->p_vaddr, module),
+						cr_pht->p_filesz, module) < 0) {
+					res = -1;
+					goto out;
+				}
+			}
+
+			/*
+			DBG_PRINT("Loadable segment of size 0x%08x copied from vaddr 0x%08x at 0x%08x\n",
+					cr_pht->p_filesz,
+					cr_pht->p_vaddr,
+					(Elf64_Addr)module_get_absolute(cr_pht->p_vaddr, module));
+			*/
+		}
+	}
+
+	// Get to the SHT
+	image_seek(elf_hdr->e_shoff, module);
+
+	// Load the SHT
+	sht = malloc(elf_hdr->e_shnum * elf_hdr->e_shentsize);
+	if (!sht) {
+		res = -1;
+		goto out;
+	}
+
+	image_read(sht, elf_hdr->e_shnum * elf_hdr->e_shentsize, module);
+
+	// Setup the symtable size
+	for (i = 0; i < elf_hdr->e_shnum; i++) {
+		cr_sht = (Elf64_Shdr*)(sht + i * elf_hdr->e_shentsize);
+
+		if (cr_sht->sh_type == SHT_DYNSYM) {
+			module->symtable_size = cr_sht->sh_size;
+			break;
+		}
+	}
+
+	free(sht);
+
+	// Setup dynamic segment location
+	module->dyn_table = module_get_absolute(dyn_addr, module);
+
+	/*
+	DBG_PRINT("Base address: 0x%08x, aligned at 0x%08x\n", module->base_addr,
+			max_align);
+	DBG_PRINT("Module size: 0x%08x\n", module->module_size);
+	*/
+
+out:
+	// Free up allocated memory
+	if (pht != NULL)
+		free(pht);
+
+	return res;
+}
+
+int perform_relocation(struct elf_module *module, Elf_Rel *rel) {
+	Elf64_Xword *dest = module_get_absolute(rel->r_offset, module);
+
+	// The symbol reference index
+	Elf64_Word sym = ELF64_R_SYM(rel->r_info);
+	unsigned char type = ELF64_R_TYPE(rel->r_info);
+
+	// The symbol definition (if applicable)
+	Elf64_Sym *sym_def = NULL;
+	struct elf_module *sym_module = NULL;
+	Elf64_Addr sym_addr = 0x0;
+
+	if (sym > 0) {
+		// Find out details about the symbol
+
+		// The symbol reference
+		Elf64_Sym *sym_ref = symbol_get_entry(module, sym);
+
+		// The symbol definition
+		sym_def =
+			global_find_symbol(module->str_table + sym_ref->st_name,
+					&sym_module);
+
+		if (sym_def == NULL) {
+			DBG_PRINT("Cannot perform relocation for symbol %s\n",
+					module->str_table + sym_ref->st_name);
+
+			if (ELF64_ST_BIND(sym_ref->st_info) != STB_WEAK)
+				return -1;
+
+			// This must be a derivative-specific
+			// function. We're OK as long as we never
+			// execute the function.
+			sym_def = global_find_symbol("undefined_symbol", &sym_module);
+		}
+
+		// Compute the absolute symbol virtual address
+		sym_addr = (Elf64_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_X86_64_NONE:
+		// Do nothing
+		break;
+	case R_X86_64_64:
+		*dest += sym_addr;
+		break;
+	case R_X86_64_PC32:
+		*dest += sym_addr - (Elf32_Addr)dest;
+		break;
+	case R_X86_64_COPY:
+		if (sym_addr > 0) {
+			memcpy((void*)dest, (void*)sym_addr, sym_def->st_size);
+		}
+		break;
+	case R_X86_64_GLOB_DAT:
+	case R_X86_64_JUMP_SLOT:
+		 //Maybe TODO: Keep track of the GOT entries allocations
+		*dest = sym_addr;
+		break;
+	case R_X86_64_RELATIVE:
+		*dest += module->base_addr;
+		break;
+	default:
+		DBG_PRINT("Relocation type %d not supported\n", type);
+		return -1;
+	}
+
+	return 0;
+}
+
+int resolve_symbols(struct elf_module *module) {
+	Elf64_Dyn  *dyn_entry = module->dyn_table;
+	unsigned int i;
+	int res;
+
+	Elf64_Word plt_rel_size = 0;
+	void *plt_rel = NULL;
+
+	void *rel = NULL;
+	Elf64_Word rel_size = 0;
+	Elf64_Word rel_entry = 0;
+	Elf64_Xword rela_size = 0;
+	Elf64_Xword rela_entry = 0;
+	Elf64_Xword sym_ent = 0;
+
+	// The current relocation
+	Elf64_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 && dyn_entry->d_un.d_val != DT_RELA) {
+				DBG_PRINT("Unsupported PLT relocation\n");
+				return -1;
+			}
+			//break;
+		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_RELA:
+			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_RELASZ:
+			rela_size = dyn_entry->d_un.d_val;
+			break;
+		case DT_RELENT:
+			rel_entry = dyn_entry->d_un.d_val;
+			break;
+		case DT_RELAENT:
+			rela_entry = dyn_entry->d_un.d_val;
+			break;
+		/* FIXME: We may need to rely upon SYMENT if DT_RELAENT is missing in the object file */
+		case DT_SYMENT:
+			sym_ent = 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 = (Elf64_Rel*)(rel + i*rel_entry);
+
+			res = perform_relocation(module, crt_rel);
+
+			if (res < 0)
+				return res;
+		}
+
+	}
+
+	if (rela_size > 0) {
+		// Process standard relocations
+		for (i = 0; i < rela_size/rela_entry; i++) {
+			crt_rel = (Elf64_Rel*)(rel + i*rela_entry);
+
+			res = perform_relocation(module, crt_rel);
+
+			if (res < 0)
+				return res;
+		}
+	}
+	if (plt_rel_size > 0) {
+		// TODO: Permit this lazily
+		// Process PLT relocations
+		/* some modules do not have DT_SYMENT, set it sym_ent in such cases */
+		if (!rela_entry) rela_entry = sym_ent; 
+		//for (i = 0; i < plt_rel_size/sizeof(Elf64_Rel); i++) {
+		for (i = 0; i < plt_rel_size/rela_entry; i++) {
+			//crt_rel = (Elf64_Rel*)(plt_rel + i*sizeof(Elf64_Rel));
+			crt_rel = (Elf64_Rel*)(plt_rel + i*rela_entry);
+
+			res = perform_relocation(module, crt_rel);
+
+			if (res < 0)
+				return res;
+		}
+	}
+
+	return 0;
+}
diff --git a/com32/lib/sys/vesa/initvesa.c b/com32/lib/sys/vesa/initvesa.c
index 9a1ae38..c2721b8 100644
--- a/com32/lib/sys/vesa/initvesa.c
+++ b/com32/lib/sys/vesa/initvesa.c
@@ -69,37 +69,12 @@
     }
 }
 
-static int __constfunc is_power_of_2(unsigned int x)
+static int vesacon_set_mode(int *x, int *y)
 {
-    return x && !(x & (x - 1));
-}
-
-static int vesacon_paged_mode_ok(const struct vesa_mode_info *mi)
-{
-    int i;
-
-    if (!is_power_of_2(mi->win_size) ||
-	!is_power_of_2(mi->win_grain) || mi->win_grain > mi->win_size)
-	return 0;		/* Impossible... */
-
-    for (i = 0; i < 2; i++) {
-	if ((mi->win_attr[i] & 0x05) == 0x05 && mi->win_seg[i])
-	    return 1;		/* Usable window */
-    }
-
-    return 0;			/* Nope... */
-}
-
-static int vesacon_set_mode(int x, int y)
-{
-    com32sys_t rm;
     uint8_t *rom_font;
-    uint16_t mode, bestmode, *mode_ptr;
-    struct vesa_info *vi;
-    struct vesa_general_info *gi;
     struct vesa_mode_info *mi;
-    enum vesa_pixel_format pxf, bestpxf;
-    int err = 0;
+    enum vesa_pixel_format bestpxf;
+    int rv;
 
     debug("Hello, World!\r\n");
 
@@ -113,172 +88,22 @@
 	__vesacon_shadowfb = NULL;
     }
 
-    /* Allocate space in the bounce buffer for these structures */
-    vi = lzalloc(sizeof *vi);
-    if (!vi) {
-	err = 10;		/* Out of memory */
-	goto exit;
-    }
-    gi = &vi->gi;
-    mi = &vi->mi;
-
-    memset(&rm, 0, sizeof rm);
-
-    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) {
-	err = 1;		/* Function call failed */
-	goto exit;
-    }
-    if (gi->signature != VESA_MAGIC) {
-	err = 2;		/* No magic */
-	goto exit;
-    }
-    if (gi->version < 0x0102) {
-	err = 3;		/* VESA 1.2+ required */
-	goto exit;
-    }
-
-    /* Copy general info */
-    memcpy(&__vesa_info.gi, gi, sizeof *gi);
-
-    /* Search for the proper mode with a suitable color and memory model... */
-
-    mode_ptr = GET_PTR(gi->video_mode_ptr);
-    bestmode = 0;
-    bestpxf = PXF_NONE;
-
-    while ((mode = *mode_ptr++) != 0xFFFF) {
-	mode &= 0x1FF;		/* The rest are attributes of sorts */
-
-	debug("Found mode: 0x%04x\r\n", mode);
-
-	memset(mi, 0, sizeof *mi);
-	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;
-
-	debug
-	    ("mode_attr 0x%04x, h_res = %4d, v_res = %4d, bpp = %2d, layout = %d (%d,%d,%d)\r\n",
-	     mi->mode_attr, mi->h_res, mi->v_res, mi->bpp, mi->memory_layout,
-	     mi->rpos, mi->gpos, mi->bpos);
-
-	/* Must be an LFB color graphics mode supported by the hardware.
-
-	   The bits tested are:
-	   4 - graphics mode
-	   3 - color mode
-	   1 - mode information available (mandatory in VBE 1.2+)
-	   0 - mode supported by hardware
-	 */
-	if ((mi->mode_attr & 0x001b) != 0x001b)
-	    continue;
-
-	/* Must be the chosen size */
-	if (mi->h_res != x || mi->v_res != y)
-	    continue;
-
-	/* We don't support multibank (interlaced memory) modes */
-	/*
-	 *  Note: The Bochs VESA BIOS (vbe.c 1.58 2006/08/19) violates the
-	 * specification which states that banks == 1 for unbanked modes;
-	 * fortunately it does report bank_size == 0 for those.
-	 */
-	if (mi->banks > 1 && mi->bank_size) {
-	    debug("bad: banks = %d, banksize = %d, pages = %d\r\n",
-		  mi->banks, mi->bank_size, mi->image_pages);
-	    continue;
-	}
-
-	/* Must be either a flat-framebuffer mode, or be an acceptable
-	   paged mode */
-	if (!(mi->mode_attr & 0x0080) && !vesacon_paged_mode_ok(mi)) {
-	    debug("bad: invalid paged mode\r\n");
-	    continue;
-	}
-
-	/* Must either be a packed-pixel mode or a direct color mode
-	   (depending on VESA version ); must be a supported pixel format */
-	pxf = PXF_NONE;		/* Not usable */
-
-	if (mi->bpp == 32 &&
-	    (mi->memory_layout == 4 ||
-	     (mi->memory_layout == 6 && mi->rpos == 16 && mi->gpos == 8 &&
-	      mi->bpos == 0)))
-	    pxf = PXF_BGRA32;
-	else if (mi->bpp == 24 &&
-		 (mi->memory_layout == 4 ||
-		  (mi->memory_layout == 6 && mi->rpos == 16 && mi->gpos == 8 &&
-		   mi->bpos == 0)))
-	    pxf = PXF_BGR24;
-	else if (mi->bpp == 16 &&
-		 (mi->memory_layout == 4 ||
-		  (mi->memory_layout == 6 && mi->rpos == 11 && mi->gpos == 5 &&
-		   mi->bpos == 0)))
-	    pxf = PXF_LE_RGB16_565;
-	else if (mi->bpp == 15 &&
-		 (mi->memory_layout == 4 ||
-		  (mi->memory_layout == 6 && mi->rpos == 10 && mi->gpos == 5 &&
-		   mi->bpos == 0)))
-	    pxf = PXF_LE_RGB15_555;
-
-	if (pxf < bestpxf) {
-	    debug("Best mode so far, pxf = %d\r\n", pxf);
-
-	    /* Best mode so far... */
-	    bestmode = mode;
-	    bestpxf = pxf;
-
-	    /* Copy mode info */
-	    memcpy(&__vesa_info.mi, mi, sizeof *mi);
-	}
-    }
-
-    if (bestpxf == PXF_NONE) {
-	err = 4;		/* No mode found */
-	goto exit;
-    }
+    rv = firmware->vesa->set_mode(&__vesa_info, x, y, &bestpxf);
+    if (rv)
+	return rv;
 
     mi = &__vesa_info.mi;
-    mode = bestmode;
     __vesacon_bytes_per_pixel = (mi->bpp + 7) >> 3;
     __vesacon_format_pixels = __vesacon_format_pixels_list[bestpxf];
 
-    /* Download the SYSLINUX- or BIOS-provided font */
+    /* Download the SYSLINUX- or firmware-provided font */
     __vesacon_font_height = syslinux_font_query(&rom_font);
-    if (!__vesacon_font_height) {
-	/* Get BIOS 8x16 font */
+    if (!__vesacon_font_height)
+	__vesacon_font_height = firmware->vesa->font_query(&rom_font);
 
-	rm.eax.w[0] = 0x1130;	/* Get Font Information */
-	rm.ebx.w[0] = 0x0600;	/* Get 8x16 ROM font */
-	__intcall(0x10, &rm, &rm);
-	rom_font = MK_PTR(rm.es, rm.ebp.w[0]);
-	__vesacon_font_height = 16;
-    }
     unpack_font((uint8_t *) __vesacon_graphics_font, rom_font,
 		__vesacon_font_height);
 
-    /* Now set video mode */
-    rm.eax.w[0] = 0x4F02;	/* Set SVGA video mode */
-    if (mi->mode_attr & 0x0080)
-	mode |= 0x4000;		/* Request linear framebuffer if supported */
-    rm.ebx.w[0] = mode;
-    __intcall(0x10, &rm, &rm);
-    if (rm.eax.w[0] != 0x004F) {
-	err = 9;		/* Failed to set mode */
-	goto exit;
-    }
-
     __vesacon_background = calloc(mi->h_res*mi->v_res, 4);
     __vesacon_shadowfb = calloc(mi->h_res*mi->v_res, 4);
 
@@ -295,13 +120,17 @@
 
     __vesacon_pixel_format = bestpxf;
 
-exit:
-    if (vi)
-	lfree(vi);
-
-    return err;
+    return 0;
 }
 
+/* FIXME:
+ * Does init_text_display need an EFI counterpart?
+ * e.g. vesa_char may need to setup UNICODE char for EFI
+ * and the number of screen chars may need to be sized up
+ * accordingly. This may also require turning byte strings
+ * into unicode strings in the framebuffer
+ * Possibly, revisit vesacon_fill() for EFI.
+ */
 static int init_text_display(void)
 {
     size_t nchars;
@@ -329,7 +158,12 @@
     return 0;
 }
 
-int __vesacon_init(int x, int y)
+/*
+ * On input, VESA initialization is passed a desirable resolution. On
+ * return, either the requested resolution is set or the system
+ * supported default resolution is set and returned to the caller.
+ */
+int __vesacon_init(int *x, int *y)
 {
     int rv;
 
@@ -340,7 +174,7 @@
     rv = vesacon_set_mode(x, y);
     if (rv) {
 	/* Try to see if we can just patch the BIOS... */
-	if (__vesacon_i915resolution(x, y))
+	if (__vesacon_i915resolution(*x, *y))
 	    return rv;
 	if (vesacon_set_mode(x, y))
 	    return rv;
diff --git a/com32/lib/sys/vesa/screencpy.c b/com32/lib/sys/vesa/screencpy.c
index 32dce9e..d78109b 100644
--- a/com32/lib/sys/vesa/screencpy.c
+++ b/com32/lib/sys/vesa/screencpy.c
@@ -34,13 +34,8 @@
 #include "vesa.h"
 #include "video.h"
 
-static struct win_info {
-    char *win_base;
-    size_t win_pos;
-    size_t win_size;
-    int win_gshift;
-    int win_num;
-} wi;
+
+static struct win_info wi;
 
 void __vesacon_init_copy_to_screen(void)
 {
@@ -71,47 +66,12 @@
     }
 }
 
-static void set_window_pos(size_t win_pos)
-{
-    static com32sys_t ireg;
-
-    wi.win_pos = win_pos;
-
-    if (wi.win_num < 0)
-	return;			/* This should never happen... */
-
-    ireg.eax.w[0] = 0x4F05;
-    ireg.ebx.b[0] = wi.win_num;
-    ireg.edx.w[0] = win_pos >> wi.win_gshift;
-
-    __intcall(0x10, &ireg, NULL);
-}
-
 void __vesacon_copy_to_screen(size_t dst, const uint32_t * src, size_t npixels)
 {
-    size_t win_pos, win_off;
-    size_t win_size = wi.win_size;
-    size_t omask = win_size - 1;
-    char *win_base = wi.win_base;
-    size_t l;
     size_t bytes = npixels * __vesacon_bytes_per_pixel;
     char rowbuf[bytes + 4] __aligned(4);
-    const char *s;
+    const uint32_t *s;
 
-    s = (const char *)__vesacon_format_pixels(rowbuf, src, npixels);
-
-    while (bytes) {
-	win_off = dst & omask;
-	win_pos = dst & ~omask;
-
-	if (__unlikely(win_pos != wi.win_pos))
-	    set_window_pos(win_pos);
-
-	l = min(bytes, win_size - win_off);
-	memcpy(win_base + win_off, s, l);
-
-	bytes -= l;
-	s += l;
-	dst += l;
-    }
+    s = (const uint32_t *)__vesacon_format_pixels(rowbuf, src, npixels);
+    firmware->vesa->screencpy(dst, s, bytes, &wi);
 }
diff --git a/com32/lib/sys/vesa/vesa.h b/com32/lib/sys/vesa/vesa.h
index 3926c32..7a3d87a 100644
--- a/com32/lib/sys/vesa/vesa.h
+++ b/com32/lib/sys/vesa/vesa.h
@@ -28,6 +28,7 @@
 #ifndef LIB_SYS_VESA_H
 #define LIB_SYS_VESA_H
 
+#include <syslinux/firmware.h>
 #include <inttypes.h>
 #include <com32.h>
 
diff --git a/com32/lib/sys/vesa/video.h b/com32/lib/sys/vesa/video.h
index d14494b..f57e34f 100644
--- a/com32/lib/sys/vesa/video.h
+++ b/com32/lib/sys/vesa/video.h
@@ -51,6 +51,14 @@
     attr_t attr;		/* Color table index */
 };
 
+struct win_info {
+    char *win_base;
+    size_t win_pos;
+    size_t win_size;
+    int win_gshift;
+    int win_num;
+};
+
 /* Pixel formats in order of decreasing preference; PXF_NONE should be last */
 /* BGR24 is preferred over BGRA32 since the I/O overhead is smaller. */
 enum vesa_pixel_format {
@@ -81,7 +89,7 @@
 
 int __vesacon_init_background(void);
 int vesacon_load_background(const char *);
-int __vesacon_init(int, int);
+int __vesacon_init(int *, int *);
 void __vesacon_init_cursor(int);
 void __vesacon_erase(int, int, int, int, attr_t);
 void __vesacon_scroll_up(int, attr_t);
diff --git a/com32/lib/sys/vesacon_write.c b/com32/lib/sys/vesacon_write.c
index 3769317..823a66a 100644
--- a/com32/lib/sys/vesacon_write.c
+++ b/com32/lib/sys/vesacon_write.c
@@ -98,7 +98,8 @@
 	    ti.cols = 80;
 	} else {
 	    /* Switch mode */
-	    if (__vesacon_init(vesacon_resolution.x, vesacon_resolution.y)) {
+	    /* Deal with a resolution different from default build */
+	    if (__vesacon_init(&vesacon_resolution.x, &vesacon_resolution.y)) {
 		vesacon_counter = -1;
 		return EAGAIN;
 	    }
diff --git a/com32/lib/sys/x86_64/x86_init_fpu.c b/com32/lib/sys/x86_64/x86_init_fpu.c
new file mode 100644
index 0000000..c5d3946
--- /dev/null
+++ b/com32/lib/sys/x86_64/x86_init_fpu.c
@@ -0,0 +1,58 @@
+/*
+ * x86_has_fpu.c
+ *
+ * Test for an x86 FPU, and do any necessary setup.
+ */
+
+#include <inttypes.h>
+#include <sys/fpu.h>
+
+static inline uint64_t get_cr0(void)
+{
+    uint64_t v;
+asm("movq %%cr0,%0":"=r"(v));
+    return v;
+}
+
+static inline void set_cr0(uint32_t v)
+{
+    asm volatile ("movq %0,%%cr0"::"r" ((uint64_t)v));
+}
+
+#define CR0_PE	0x00000001
+#define CR0_MP  0x00000002
+#define CR0_EM  0x00000004
+#define CR0_TS  0x00000008
+#define CR0_ET  0x00000010
+#define CR0_NE  0x00000020
+#define CR0_WP  0x00010000
+#define CR0_AM  0x00040000
+#define CR0_NW  0x20000000
+#define CR0_CD  0x40000000
+#define CR0_PG  0x80000000
+
+int x86_init_fpu(void)
+{
+    uint32_t cr0;
+    uint16_t fsw = 0xffff;
+    uint16_t fcw = 0xffff;
+
+    cr0 = get_cr0();
+    cr0 &= ~(CR0_EM | CR0_TS);
+    cr0 |= CR0_MP;
+    set_cr0(cr0);
+
+    asm volatile ("fninit");
+    asm volatile ("fnstsw %0":"+m" (fsw));
+    if (fsw != 0)
+	return -1;
+
+    asm volatile ("fnstcw %0":"+m" (fcw));
+    if ((fcw & 0x103f) != 0x3f)
+	return -1;
+
+    /* Techically, this could be a 386 with a 287.  We could add a check
+       for that here... */
+
+    return 0;
+}
diff --git a/com32/lib/sys/x86_init_fpu.c b/com32/lib/sys/x86_init_fpu.c
index cf33693..cacb4ea 100644
--- a/com32/lib/sys/x86_init_fpu.c
+++ b/com32/lib/sys/x86_init_fpu.c
@@ -4,19 +4,40 @@
  * Test for an x86 FPU, and do any necessary setup.
  */
 
+#if __SIZEOF_POINTER__ == 4
+#include <i386/x86_init_fpu.c>
+#elif __SIZEOF_POINTER__ == 8
+#include <x86_64/x86_init_fpu.c>
+#else
+#error "Unable to build for to-be-defined architecture type"
+#endif
+#if 0
 #include <inttypes.h>
 #include <sys/fpu.h>
 
 static inline uint64_t get_cr0(void)
 {
+#if __SIZEOF_POINTER__ == 4
     uint32_t v;
 asm("movl %%cr0,%0":"=r"(v));
+#elif __SIZEOF_POINTER__ == 8
+    uint64_t v;
+asm("movq %%cr0,%0":"=r"(v));
+#else
+#error "Unable to build for to-be-defined architecture type"
+#endif
     return v;
 }
 
 static inline void set_cr0(uint32_t v)
 {
+#if __SIZEOF_POINTER__ == 4
     asm volatile ("movl %0,%%cr0"::"r" (v));
+#elif __SIZEOF_POINTER__ == 8
+    asm volatile ("movq %0,%%cr0"::"r" ((uint64_t)v));
+#else
+#error "Unable to build for to-be-defined architecture type"
+#endif
 }
 
 #define CR0_PE	0x00000001
@@ -56,3 +77,4 @@
 
     return 0;
 }
+#endif
diff --git a/com32/lib/syslinux/cleanup.c b/com32/lib/syslinux/cleanup.c
index 066f174..7d8581e 100644
--- a/com32/lib/syslinux/cleanup.c
+++ b/com32/lib/syslinux/cleanup.c
@@ -29,8 +29,6 @@
 #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)
diff --git a/com32/lib/syslinux/dsinfo.c b/com32/lib/syslinux/dsinfo.c
index c1f02a5..f7126bf 100644
--- a/com32/lib/syslinux/dsinfo.c
+++ b/com32/lib/syslinux/dsinfo.c
@@ -34,12 +34,5 @@
 
 void __constructor __syslinux_get_derivative_info(void)
 {
-    com32sys_t *const r = &__syslinux_derivative_info.rr.r;
-
-    r->eax.w[0] = 0x000A;
-    __intcall(0x22, r, r);
-
-    __syslinux_derivative_info.r.esbx = MK_PTR(r->es, r->ebx.w[0]);
-    __syslinux_derivative_info.r.fssi = MK_PTR(r->fs, r->esi.w[0]);
-    __syslinux_derivative_info.r.gsdi = MK_PTR(r->gs, r->edi.w[0]);
+    get_derivative_info(&__syslinux_derivative_info);
 }
diff --git a/com32/lib/syslinux/load_linux.c b/com32/lib/syslinux/load_linux.c
index c0335dc..4a8a1fd 100644
--- a/com32/lib/syslinux/load_linux.c
+++ b/com32/lib/syslinux/load_linux.c
@@ -47,48 +47,7 @@
 #include <syslinux/linux.h>
 #include <syslinux/bootrm.h>
 #include <syslinux/movebits.h>
-
-struct linux_header {
-    uint8_t boot_sector_1[0x0020];
-    uint16_t old_cmd_line_magic;
-    uint16_t old_cmd_line_offset;
-    uint8_t boot_sector_2[0x01f1 - 0x0024];
-    uint8_t setup_sects;
-    uint16_t root_flags;
-    uint32_t syssize;
-    uint16_t ram_size;
-    uint16_t vid_mode;
-    uint16_t root_dev;
-    uint16_t boot_flag;
-    uint16_t jump;
-    uint32_t header;
-    uint16_t version;
-    uint32_t realmode_swtch;
-    uint16_t start_sys;
-    uint16_t kernel_version;
-    uint8_t type_of_loader;
-    uint8_t loadflags;
-    uint16_t setup_move_size;
-    uint32_t code32_start;
-    uint32_t ramdisk_image;
-    uint32_t ramdisk_size;
-    uint32_t bootsect_kludge;
-    uint16_t heap_end_ptr;
-    uint16_t pad1;
-    uint32_t cmd_line_ptr;
-    uint32_t initrd_addr_max;
-    uint32_t kernel_alignment;
-    uint8_t relocatable_kernel;
-    uint8_t pad2[3];
-    uint32_t cmdline_max_len;
-    uint32_t hardware_subarch;
-    uint64_t hardware_subarch_data;
-    uint32_t payload_offset;
-    uint32_t payload_length;
-    uint64_t setup_data;
-    uint64_t pref_address;
-    uint32_t init_size;
-} __packed;
+#include <syslinux/firmware.h>
 
 #define BOOT_MAGIC 0xAA55
 #define LINUX_MAGIC ('H' + ('d' << 8) + ('r' << 16) + ('S' << 24))
@@ -130,23 +89,6 @@
     return (v > 0xffffffff) ? 0xffffffff : (uint32_t) v;
 }
 
-/* Get the combined size of the initramfs */
-static addr_t initramfs_size(struct initramfs *initramfs)
-{
-    struct initramfs *ip;
-    addr_t size = 0;
-
-    if (!initramfs)
-	return 0;
-
-    for (ip = initramfs->next; ip->len; ip = ip->next) {
-	size = (size + ip->align - 1) & ~(ip->align - 1);	/* Alignment */
-	size += ip->len;
-    }
-
-    return size;
-}
-
 /* Create the appropriate mappings for the initramfs */
 static int map_initramfs(struct syslinux_movelist **fraglist,
 			 struct syslinux_memmap **mmap,
@@ -182,10 +124,10 @@
     return 0;
 }
 
-int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
-			struct initramfs *initramfs,
-			struct setup_data *setup_data,
-			char *cmdline)
+int bios_boot_linux(void *kernel_buf, size_t kernel_size,
+		    struct initramfs *initramfs,
+		    struct setup_data *setup_data,
+		    char *cmdline)
 {
     struct linux_header hdr, *whdr;
     size_t real_mode_size, prot_mode_size;
@@ -534,3 +476,17 @@
     syslinux_free_memmap(amap);
     return -1;
 }
+
+int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
+			struct initramfs *initramfs,
+			struct setup_data *setup_data,
+			char *cmdline)
+{
+    if (!firmware->boot_linux) {
+	printf("No linux boot function registered for firmware\n");
+	return -1;
+    }
+
+    firmware->boot_linux(kernel_buf, kernel_size, initramfs,
+			 setup_data, cmdline);
+}
diff --git a/com32/lib/syslinux/memscan.c b/com32/lib/syslinux/memscan.c
index fc676cb..0ff25d7 100644
--- a/com32/lib/syslinux/memscan.c
+++ b/com32/lib/syslinux/memscan.c
@@ -40,6 +40,7 @@
 #include <com32.h>
 
 #include <syslinux/memscan.h>
+#include <syslinux/firmware.h>
 
 struct e820_entry {
     uint64_t start;
@@ -47,7 +48,7 @@
     uint32_t type;
 };
 
-int syslinux_scan_memory(scan_memory_callback_t callback, void *data)
+int bios_scan_memory(scan_memory_callback_t callback, void *data)
 {
     static com32sys_t ireg;
     com32sys_t oreg;
@@ -156,3 +157,8 @@
 
     return 0;
 }
+
+int syslinux_scan_memory(scan_memory_callback_t callback, void *data)
+{
+	return firmware->mem->scan_memory(callback, data);
+}
diff --git a/com32/lib/syslinux/serial.c b/com32/lib/syslinux/serial.c
index aa5690f..041e850 100644
--- a/com32/lib/syslinux/serial.c
+++ b/com32/lib/syslinux/serial.c
@@ -32,24 +32,19 @@
  */
 
 #include <klibc/compiler.h>
+#include <syslinux/firmware.h>
 #include <syslinux/config.h>
 #include <string.h>
-#include <bios.h>
-#include <core.h>
 
 struct syslinux_serial_console_info __syslinux_serial_console_info;
 
 void __syslinux_set_serial_console_info(void)
 {
-    uint16_t flowctl;
+    uint16_t iobase, divisor, flowctl;
 
-    __syslinux_serial_console_info.iobase = SerialPort;
-    __syslinux_serial_console_info.divisor = BaudDivisor;
+    firmware->get_serial_console_info(&iobase, &divisor, &flowctl);
 
-    flowctl = FlowOutput | FlowInput | (FlowIgnore << 4);
-
-    if (!DisplayCon)
-	flowctl |= (0x80 << 8);
-
+    __syslinux_serial_console_info.iobase = iobase;
+    __syslinux_serial_console_info.divisor = divisor;
     __syslinux_serial_console_info.flowctl = flowctl;
 }
diff --git a/com32/lib/syslinux/shuffle.c b/com32/lib/syslinux/shuffle.c
index 544915a..d014340 100644
--- a/com32/lib/syslinux/shuffle.c
+++ b/com32/lib/syslinux/shuffle.c
@@ -50,10 +50,12 @@
 
 static int shuffler_size;
 
-static void __constructor __syslinux_get_shuffer_size(void)
+static void __syslinux_get_shuffer_size(void)
 {
-    /* +15 padding is to guarantee alignment */
-    shuffler_size = __bcopyxx_len + 15;
+    if (!shuffler_size) {
+	/* +15 padding is to guarantee alignment */
+	shuffler_size = __bcopyxx_len + 15;
+    }
 }
 
 /*
@@ -114,6 +116,7 @@
     if (!rxmap)
 	goto bail;
 
+    __syslinux_get_shuffer_size();
     desc_blocks = (nzero + DESC_BLOCK_SIZE - 1) / DESC_BLOCK_SIZE;
     for (;;) {
 	/* We want (desc_blocks) allocation blocks, plus the terminating
diff --git a/com32/lib/syslinux/version.c b/com32/lib/syslinux/version.c
index 1cd2efd..6f0554d 100644
--- a/com32/lib/syslinux/version.c
+++ b/com32/lib/syslinux/version.c
@@ -28,7 +28,7 @@
 #include <syslinux/config.h>
 #include <klibc/compiler.h>
 #include <core.h>
-#include <../../../version.h>
+#include <version.h>
 
 struct syslinux_version __syslinux_version;
 
diff --git a/com32/lib/x86_64/elf.ld b/com32/lib/x86_64/elf.ld
new file mode 100644
index 0000000..4e88bcb
--- /dev/null
+++ b/com32/lib/x86_64/elf.ld
@@ -0,0 +1,180 @@
+/*
+ * Linker script for ELF dynamic loaded modules.
+ * This simply mirrors the 32bit linker script with minimal x86_64 changes
+ */
+
+/* Script for --shared -z combreloc: shared library, combine & sort relocs */
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+OUTPUT_ARCH(i386:x86-64)
+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) }
+/* mouli: introduce alignment for various segments */
+  .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))
+    KEEP (*(.ctors_modinit))
+    KEEP (*(.ctors_modmain))
+	__ctors_end = .;
+  }
+  
+  .dtors          :
+  {
+  	__dtors_start = .;
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+    KEEP (*(.dtors_modexit))
+	__dtors_end = .;
+  }
+  
+  .jcr            : { KEEP (*(.jcr)) }
+  .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
+  .dynamic        : { *(.dynamic) }
+  .got            : { *(.got) }
+  /*. = DATA_SEGMENT_RELRO_END (12, .); -> This gives a "invalid assignment to location counter" error */
+  .got.plt        : { *(.got.plt) }
+  .data           :
+  {
+    *(.data .data.* .gnu.linkonce.d.*)
+    KEEP (*(.gnu.linkonce.d.*personality*))
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  PROVIDE (edata = .);
+  PROVIDE (_edata = .); 
+  .bss            :
+  {
+   *(.dynbss)
+   *(.bss .bss.* .gnu.linkonce.b.*)
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.
+      FIXME: Why do we need it? When there is no .bss section, we don't
+      pad the .data section.  */
+   /*. = ALIGN(. != 0 ? 32 / 8 : 1);*/
+   . = ALIGN(. != 0 ? 64 / 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/x86_64/setjmp.S b/com32/lib/x86_64/setjmp.S
new file mode 100644
index 0000000..45f547b
--- /dev/null
+++ b/com32/lib/x86_64/setjmp.S
@@ -0,0 +1,54 @@
+#
+# arch/x86_64/setjmp.S
+#
+# setjmp/longjmp for the x86-64 architecture
+#
+
+#
+# The jmp_buf is assumed to contain the following, in order:
+#	%rbx
+#	%rsp (post-return)
+#	%rbp
+#	%r12
+#	%r13
+#	%r14
+#	%r15
+#	<return address>
+#
+
+	.text
+	.align 4
+	.globl setjmp
+	.type setjmp, @function
+setjmp:
+	pop  %rsi			# Return address, and adjust the stack
+	xorl %eax,%eax			# Return value
+	movq %rbx,(%rdi)
+	movq %rsp,8(%rdi)		# Post-return %rsp!
+	push %rsi			# Make the call/return stack happy
+	movq %rbp,16(%rdi)
+	movq %r12,24(%rdi)
+	movq %r13,32(%rdi)
+	movq %r14,40(%rdi)
+	movq %r15,48(%rdi)
+	movq %rsi,56(%rdi)		# Return address
+	ret
+
+	.size setjmp,.-setjmp
+
+	.text
+	.align 4
+	.globl longjmp
+	.type longjmp, @function
+longjmp:
+	movl %esi,%eax			# Return value (int)
+	movq (%rdi),%rbx
+	movq 8(%rdi),%rsp
+	movq 16(%rdi),%rbp
+	movq 24(%rdi),%r12
+	movq 32(%rdi),%r13
+	movq 40(%rdi),%r14
+	movq 48(%rdi),%r15
+	jmp *56(%rdi)
+
+	.size longjmp,.-longjmp
diff --git a/com32/libupload/Makefile b/com32/libupload/Makefile
index 8305335..f9440c5 100644
--- a/com32/libupload/Makefile
+++ b/com32/libupload/Makefile
@@ -1,12 +1,10 @@
 # Include configuration rules
-topdir = ../..
-MAKEDIR = $(topdir)/mk
+VPATH = $(SRC)
 include $(MAKEDIR)/com32.mk
 
-REQFLAGS += -I./
+REQFLAGS += -I$(SRC)
 
-SUBDIRS := . 
-LIBOBJS := $(foreach dir,$(SUBDIRS),$(patsubst %.c,%.o,$(wildcard $(dir)/*.c)))
+LIBOBJS := $(notdir $(patsubst %.c,%.o,$(wildcard $(SRC)/*.c)))
 
 BINDIR   = /usr/bin
 LIBDIR   = /usr/lib
@@ -34,6 +32,6 @@
 	mkdir -m 755 -p $(INSTALLROOT)$(COM32DIR)
 	install -m 644 libcom32upload.a $(INSTALLROOT)$(COM32DIR)
 	mkdir -p $(INSTALLROOT)$(COM32DIR)/include/
-	cp -r *.h $(INSTALLROOT)$(COM32DIR)/include/
+	cp -r $(SRC)/*.h $(INSTALLROOT)$(COM32DIR)/include/
 
 -include .*.d */.*.d */*/.*.d
diff --git a/com32/libutil/Makefile b/com32/libutil/Makefile
index 5aa7ceb..094f1ff 100644
--- a/com32/libutil/Makefile
+++ b/com32/libutil/Makefile
@@ -29,8 +29,7 @@
 ## Utility companion library for the COM32 library
 ##
 
-topdir = ../..
-MAKEDIR = $(topdir)/mk
+VPATH = $(SRC)
 include $(MAKEDIR)/elf.mk
 
 LIBOBJS	   = ansiline.o ansiraw.o keyname.o \
diff --git a/com32/lua/src/Makefile b/com32/lua/src/Makefile
index d70d23e..f3625e1 100644
--- a/com32/lua/src/Makefile
+++ b/com32/lua/src/Makefile
@@ -15,8 +15,7 @@
 ## Lua Makefile
 ##
 
-topdir = ../../..
-MAKEDIR = $(topdir)/mk
+VPATH = $(SRC)
 include $(MAKEDIR)/elf.mk
 
 LNXLIBS	   = 
diff --git a/com32/mboot/Makefile b/com32/mboot/Makefile
index 6e010b1..e916436 100644
--- a/com32/mboot/Makefile
+++ b/com32/mboot/Makefile
@@ -15,11 +15,10 @@
 ## Multiboot module
 ##
 
-topdir = ../..
-MAKEDIR = $(topdir)/mk
+VPATH = $(SRC)
 include $(MAKEDIR)/elf.mk
 
-LNXLIBS	   = ../libutil/libutil_lnx.a
+LNXLIBS	   = $(objdir)/com32/libutil/libutil_lnx.a
 
 MODULES	  = mboot.c32
 TESTFILES =
diff --git a/com32/menu/Makefile b/com32/menu/Makefile
index e62c6b8..7c2d592 100644
--- a/com32/menu/Makefile
+++ b/com32/menu/Makefile
@@ -14,17 +14,16 @@
 ## Simple menu system
 ##
 
-topdir = ../..
-MAKEDIR = $(topdir)/mk
+VPATH = $(SRC)
 include $(MAKEDIR)/elf.mk
 
-LNXLIBS	   = ../libutil/libutil_lnx.a
+LNXLIBS	   = $(objdir)/com32/libutil/libutil_lnx.a
 
 MODULES	  = menu.c32 vesamenu.c32
 TESTFILES =
 
-COMMONOBJS = menumain.o readconfig.o passwd.o drain.o printmsg.o colors.o \
-	background.o refstr.o
+COMMONOBJS = menumain.o readconfig.o passwd.o drain.o \
+		printmsg.o colors.o background.o refstr.o
 
 all: $(MODULES) $(TESTFILES)
 
diff --git a/com32/modules/Makefile b/com32/modules/Makefile
index 628fa5d..8965f5f 100644
--- a/com32/modules/Makefile
+++ b/com32/modules/Makefile
@@ -15,8 +15,7 @@
 ## COM32 standard modules
 ##
 
-topdir = ../..
-MAKEDIR = $(topdir)/mk
+VPATH = $(SRC)
 include $(MAKEDIR)/elf.mk
 
 MODULES	  = config.c32 ethersel.c32 dmitest.c32 cpuidtest.c32 \
diff --git a/com32/modules/ls.c b/com32/modules/ls.c
index 11c18ae..47eacdb 100644
--- a/com32/modules/ls.c
+++ b/com32/modules/ls.c
@@ -172,4 +172,4 @@
 
     return rv ? 1 : 0;
 }
-  
+ 
diff --git a/com32/modules/zzjson.c b/com32/modules/zzjson.c
index e2516fa..a126b8f 100644
--- a/com32/modules/zzjson.c
+++ b/com32/modules/zzjson.c
@@ -21,7 +21,13 @@
 
 int main(int argc, char *argv[])
 {
+#if 0
+	/* this hangs! */
     openconsole(&dev_rawcon_r, &dev_stdcon_w);
+#else
+	/* this works */
+    openconsole(&dev_rawcon_r, &dev_ansiserial_w);
+#endif
     (void) argc;
     (void) argv;
     ZZJSON  *tmp;
diff --git a/com32/rosh/Makefile b/com32/rosh/Makefile
index 5b54225..4d900f4 100644
--- a/com32/rosh/Makefile
+++ b/com32/rosh/Makefile
@@ -16,10 +16,10 @@
 ## ROSH Read Only Shell
 ##
 
-LIBS = $(com32)/libutil/libutil.c32 $(com32)/lib/libcom32.c32
+LIBS = $(objdir)/com32/libutil/libutil.c32 \
+	$(objdir)/com32/lib/libcom32.c32
 
-topdir = ../..
-MAKEDIR = $(topdir)/mk
+VPATH = $(SRC)
 include $(MAKEDIR)/rosh.mk
 
 # from com32/sysdump/Makefile
@@ -36,12 +36,12 @@
 CFLAGS		+= -DDATE='"$(DATE)"'
 LNXCFLAGS	+= -DDATE='"$(DATE)"'
 
+all:	rosh.c32
+
 rosh.o:	rosh.h
 
 rosh.lo:	rosh.h
 
-all:	rosh.c32
-
 allgrc:	rosh.c32 rosh.lnx
 
 tidy dist:
diff --git a/com32/rosh/rosh.c b/com32/rosh/rosh.c
index 68dad3f..8198a2b 100644
--- a/com32/rosh/rosh.c
+++ b/com32/rosh/rosh.c
@@ -37,7 +37,7 @@
  * debugging enabled; Comment to remove.
  */
 #include "rosh.h"
-#include "../../version.h"
+#include "version.h"
 
 #define APP_LONGNAME	"Read-Only Shell"
 #define APP_NAME	"rosh"
diff --git a/com32/samples/Makefile b/com32/samples/Makefile
index f6ae00a..06e9684 100644
--- a/com32/samples/Makefile
+++ b/com32/samples/Makefile
@@ -14,17 +14,16 @@
 ## samples for syslinux users
 ##
 
-LIBS = $(com32)/libutil/libutil.c32
+LIBS = $(objdir)/com32/libutil/libutil.c32
 
-topdir = ../..
-MAKEDIR = $(topdir)/mk
+VPATH = $(SRC)
 include $(MAKEDIR)/elf.mk
 
 all:	hello.c32 resolv.c32 serialinfo.c32 \
-	localboot.c32 \
-	fancyhello.c32 fancyhello.lnx \
-	keytest.c32 keytest.lnx \
-	advdump.c32 entrydump.c32
+		localboot.c32 \
+		fancyhello.c32 fancyhello.lnx \
+		keytest.c32 keytest.lnx \
+		advdump.c32 entrydump.c32
 
 tidy dist:
 	rm -f *.o *.lo *.a *.lst *.elf .*.d *.tmp
diff --git a/com32/samples/advdump.c b/com32/samples/advdump.c
index 2c78641..83fe838 100644
--- a/com32/samples/advdump.c
+++ b/com32/samples/advdump.c
@@ -27,7 +27,13 @@
     size_t s = syslinux_adv_size();
     char buf[256];
 
+#if 0
+	/* this hangs! */
     openconsole(&dev_stdcon_r, &dev_stdcon_w);
+#else
+	/* this works */
+    openconsole(&dev_rawcon_r, &dev_ansiserial_w);
+#endif
 
     p = syslinux_adv_ptr();
 
diff --git a/com32/samples/entrydump.c b/com32/samples/entrydump.c
index d50859f..56a683e 100644
--- a/com32/samples/entrydump.c
+++ b/com32/samples/entrydump.c
@@ -36,7 +36,13 @@
     const union syslinux_derivative_info *di;
     const struct stack_frame *sf;
 
+#if 0
+	/* this hangs! */
     openconsole(&dev_null_r, &dev_stdcon_w);
+#else
+	/* this works */
+    openconsole(&dev_rawcon_r, &dev_ansiserial_w);
+#endif
 
     di = syslinux_derivative_info();
 
diff --git a/com32/samples/resolv.c b/com32/samples/resolv.c
index f4a0e52..8f062d1 100644
--- a/com32/samples/resolv.c
+++ b/com32/samples/resolv.c
@@ -32,7 +32,13 @@
 {
     uint32_t ip;
 
+#if 0
+	/* this hangs! */
     openconsole(&dev_null_r, &dev_stdcon_w);
+#else
+	/* this works */
+    openconsole(&dev_rawcon_r, &dev_ansiserial_w);
+#endif
 
     if (argc < 2) {
 	fputs("Usage: resolv hostname\n", stderr);
diff --git a/com32/samples/serialinfo.c b/com32/samples/serialinfo.c
index 10d0252..2936b4e 100644
--- a/com32/samples/serialinfo.c
+++ b/com32/samples/serialinfo.c
@@ -25,7 +25,13 @@
 {
     const struct syslinux_serial_console_info *si;
 
+#if 0
+	/* this hangs! */
     openconsole(&dev_null_r, &dev_stdcon_w);
+#else
+	/* this works */
+    openconsole(&dev_rawcon_r, &dev_ansiserial_w);
+#endif
 
     si = syslinux_serial_console_info();
 
diff --git a/com32/sysdump/Makefile b/com32/sysdump/Makefile
index 7d42ae0..240edaa 100644
--- a/com32/sysdump/Makefile
+++ b/com32/sysdump/Makefile
@@ -15,21 +15,20 @@
 ## Simple menu system
 ##
 
-topdir = ../..
-MAKEDIR = $(topdir)/mk
+VPATH = $(SRC)
 include $(MAKEDIR)/elf.mk
 -include $(topdir)/version.mk
 
-LIBS	   = ../libupload/libcom32upload.a
-LNXLIBS	   = ../libutil/libutil_lnx.a
+LIBS	   = $(objdir)/com32/libupload/libcom32upload.a
+LNXLIBS	   = $(objdir)/com32/libutil/libutil_lnx.a
 
 CFLAGS += -I$(com32) -I$(topdir)
 
 MODULES	  = sysdump.c32
 TESTFILES =
 
-SRCS = $(wildcard *.c)
-OBJS = $(patsubst %.c,%.o,$(SRCS))
+SRCS = $(wildcard $(SRC)/*.c)
+OBJS = $(subst $(SRC)/,,$(patsubst %.c,%.o,$(SRCS)))
 
 # The DATE is set on the make command line when building binaries for
 # official release.  Otherwise, substitute a hex string that is pretty much
diff --git a/com32/sysdump/cpuid.c b/com32/sysdump/cpuid.c
index e7fc576..846b540 100644
--- a/com32/sysdump/cpuid.c
+++ b/com32/sysdump/cpuid.c
@@ -20,10 +20,21 @@
 
 static void get_cpuid(uint32_t eax, uint32_t ecx, struct cpuid_data *data)
 {
+#if __SIZEOF_POINTER__ == 4
     asm("pushl %%ebx ; cpuid ; movl %%ebx,%1 ; popl %%ebx"
 	: "=a" (data->eax), "=r" (data->ebx),
 	  "=c" (data->ecx), "=d" (data->edx)
 	: "a" (eax), "c" (ecx));
+#elif __SIZEOF_POINTER__ == 8
+        asm volatile("push %%rbx; cpuid; movl %%ebx, %1; pop %%rbx"
+            : "=a" (data->eax),
+              "=b" (data->ebx),
+              "=c" (data->ecx),
+              "=d" (data->edx)
+            : "a" (eax), "c" (ecx));
+#else
+#error "unsupported architecture"
+#endif
 }
 
 #define CPUID_CHUNK 128
diff --git a/com32/tools/Makefile b/com32/tools/Makefile
index 0161baf..9c0ea70 100644
--- a/com32/tools/Makefile
+++ b/com32/tools/Makefile
@@ -10,12 +10,12 @@
 ##
 ## -----------------------------------------------------------------------
 
-MAKEDIR = ../../mk
+VPATH = $(SRC)
 include $(MAKEDIR)/build.mk
 
 BINS    = relocs
 
-INCLUDES += -I./include
+INCLUDES += -I$(SRC)/include
 
 all : $(BINS)
 
diff --git a/core/Makefile b/core/Makefile
index a01d83a..14590eb 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -15,17 +15,17 @@
 # Makefile for the SYSLINUX core
 #
 
+VPATH = $(SRC)
+
 # No builtin rules
 MAKEFLAGS += -r
 MAKE      += -r
 
-topdir = ..
-MAKEDIR = $(topdir)/mk
 include $(MAKEDIR)/embedded.mk
--include $(topdir)/version.mk
+-include $(objdir)/version.mk
 
 OPTFLAGS =
-INCLUDES = -I./include -I$(com32)/include -I$(com32)/lib
+INCLUDES = -I$(SRC)/include -I$(com32)/include -I$(com32)/include/sys -I$(com32)/lib
 
 # This is very similar to cp437; technically it's for Norway and Denmark,
 # but it's unlikely the characters that are different will be used in
@@ -38,29 +38,29 @@
 	   isolinux.bin isolinux-debug.bin pxelinux.0
 
 # All primary source files for the main syslinux files
-NASMSRC	 := $(wildcard *.asm)
-NASMHDR  := $(wildcard *.inc)
-CSRC	 := $(wildcard *.c */*.c */*/*.c)
-SSRC	 := $(wildcard *.S */*.S */*/*.S)
-CHDR	 := $(wildcard *.h */*.h */*/*.h)
+NASMSRC	 := $(wildcard $(SRC)/*.asm)
+NASMHDR  := $(wildcard $(SRC)/*.inc)
+CSRC	 := $(wildcard $(SRC)/*.c $(SRC)/*/*.c $(SRC)/*/*/*.c)
+SSRC	 := $(wildcard $(SRC)/*.S $(SRC)/*/*.S $(SRC)/*/*/*.S)
+CHDR	 := $(wildcard $(SRC)/*.h $(SRC)/*/*.h $(SRC)/*/*/*.h)
 OTHERSRC := keywords
 ALLSRC    = $(NASMSRC) $(NASMHDR) $(CSRC) $(SSRC) $(CHDR) $(OTHERSRC)
 
-COBJ	 := $(patsubst %.c,%.o,$(CSRC))
-SOBJ	 := $(patsubst %.S,%.o,$(SSRC))
+COBJ	 := $(subst $(SRC)/,,$(patsubst %.c,%.o,$(CSRC)))
+SOBJ	 := $(subst $(SRC)/,,$(patsubst %.S,%.o,$(SSRC)))
 
-# Don't include console objects
-COBJS	 = $(filter-out rawcon.o plaincon.o,$(COBJ))
+# Don't include derivative-specific objects
+COBJS	 = $(filter-out %rawcon.o %plaincon.o %pxelinux-c.o %ldlinux-c.o %isolinux-c.o,$(COBJ))
 
 LIB	 = libcom32.a
-LIBS	 = $(LIB) --whole-archive $(com32)/lib/libcom32core.a
+LIBS	 = $(LIB) --whole-archive $(objdir)/com32/lib/libcom32core.a
 LIBDEP   = $(filter-out -% %start%,$(LIBS))
-LIBOBJS	 = $(COBJS) $(SOBJ)
+LIBOBJS  = $(COBJS) $(SOBJ)
 
 NASMDEBUG = -g -F dwarf
 NASMOPT  += $(NASMDEBUG)
 
-PREPCORE = ../lzo/prepcore
+PREPCORE = $(OBJ)/../lzo/prepcore
 
 CFLAGS += -D__SYSLINUX_CORE__
 
@@ -68,16 +68,36 @@
 # official release.  Otherwise, substitute a hex string that is pretty much
 # guaranteed to be unique to be unique from build to build.
 ifndef HEXDATE
-HEXDATE := $(shell $(PERL) ../now.pl $(SRCS))
+HEXDATE := $(shell $(PERL) $(SRC)/../now.pl $(SRCS))
 endif
 ifndef DATE
-DATE    := $(shell sh ../gen-id.sh $(VERSION) $(HEXDATE))
+DATE    := $(shell sh $(SRC)/../gen-id.sh $(VERSION) $(HEXDATE))
 endif
 
-all: $(BTARGET)
+# Set up the NASM and LD options for the architecture
+NASM_ELF = "unknown"
+LD_PIE = "unknown"
+ifeq ($(ARCH),i386)
+	NASM_ELF = elf
+	LD_PIE = -pie
+endif
+ifeq ($(ARCH),x86_64)
+	NASM_ELF = elf64
+	#LD_PIE = --pic-executable
+	LD_PIE = 
+endif
+
+ifdef EFI_BUILD
+all: makeoutputdirs $(filter-out %bios.o,$(COBJS)) codepage.o
+else
+all: makeoutputdirs $(BTARGET)
+endif
+
+makeoutputdirs:
+	@mkdir -p $(sort $(dir $(COBJ) $(SOBJ)))
 
 kwdhash.gen: keywords genhash.pl
-	$(PERL) genhash.pl < keywords > kwdhash.gen
+	$(PERL) $(SRC)/genhash.pl < $(SRC)/keywords > $(OBJ)/kwdhash.gen
 
 .PRECIOUS: %.elf
 
@@ -85,26 +105,29 @@
 	$(OBJCOPY) -O binary -S $< $(@:.bin=.raw)
 
 # GNU make 3.82 gets confused by the first form
-.PRECIOUS: %.raw
+.PRECIOUS: $(OBJ)/%.raw
 
 %.bin: %.raw $(PREPCORE)
 	$(PREPCORE) $< $@
 
-%.o: %.asm kwdhash.gen ../version.gen
-	$(NASM) -f elf $(NASMOPT) -DDATE_STR="'$(DATE)'" \
+%.o: %.asm kwdhash.gen $(OBJ)/../version.gen
+	$(NASM) -f $(NASM_ELF) $(NASMOPT) -DDATE_STR="'$(DATE)'" \
 		-DHEXDATE="$(HEXDATE)" \
-		-l $(@:.o=.lsr) -o $@ -MP -MD .$@.d $<
+		-D$(ARCH) \
+		-I$(SRC)/ \
+		-l $(@:.o=.lsr) -o $@ -MP -MD $(dir $@).$(notdir $@).d $<
 
 AUXLIBS = libisolinux.a libisolinux-debug.a libldlinux.a libpxelinux.a
+LDSCRIPT = $(SRC)/$(ARCH)/syslinux.ld
 
-%.elf: %.o $(LIBDEP) syslinux.ld $(AUXLIBS)
-	$(LD) $(LDFLAGS) -Bsymbolic -pie -E --hash-style=gnu -T syslinux.ld -M -o $@ $< \
-		--start-group $(LIBS) lib$(patsubst %.elf,%.a,$@) --end-group \
+%.elf: %.o $(LIBDEP) $(LDSCRIPT) $(AUXLIBS)
+	$(LD) $(LDFLAGS) -Bsymbolic $(LD_PIE) -E --hash-style=gnu -T $(LDSCRIPT) -M -o $@ $< \
+		--start-group $(LIBS) $(subst $(*F).elf,lib$(*F).a,$@) --end-group \
 		> $(@:.elf=.map)
 	$(OBJDUMP) -h $@ > $(@:.elf=.sec)
-	$(PERL) lstadjust.pl $(@:.elf=.lsr) $(@:.elf=.sec) $(@:.elf=.lst)
+	$(PERL) $(SRC)/lstadjust.pl $(@:.elf=.lsr) $(@:.elf=.sec) $(@:.elf=.lst)
 
-libisolinux.a: rawcon.o
+libisolinux.a: rawcon.o isolinux-c.o
 	rm -f $@
 	$(AR) cq $@ $^
 	$(RANLIB) $@
@@ -112,10 +135,12 @@
 libisolinux-debug.a: libisolinux.a
 	cp $^ $@
 
-libpxelinux.a: libisolinux.a
-	cp $^ $@
+libpxelinux.a: rawcon.o pxelinux-c.o
+	rm -f $@
+	$(AR) cq $@ $^
+	$(RANLIB) $@
 
-libldlinux.a: plaincon.o
+libldlinux.a: plaincon.o ldlinux-c.o
 	rm -f $@
 	$(AR) cq $@ $^
 	$(RANLIB) $@
@@ -134,7 +159,7 @@
 ldlinux.sys: ldlinux.bin
 	dd if=$< of=$@ bs=512 skip=2
 
-codepage.cp: ../codepage/$(CODEPAGE).cp
+codepage.cp: $(OBJ)/../codepage/$(CODEPAGE).cp
 	cp -f $< $@
 
 codepage.o: codepage.S codepage.cp
diff --git a/core/bios.c b/core/bios.c
new file mode 100644
index 0000000..bd8b4d8
--- /dev/null
+++ b/core/bios.c
@@ -0,0 +1,573 @@
+#include <sys/ansi.h>
+#include <sys/io.h>
+#include <fs.h>
+#include <bios.h>
+#include <com32.h>
+#include <graphics.h>
+#include <syslinux/memscan.h>
+#include <syslinux/firmware.h>
+
+#include <sys/vesa/vesa.h>
+#include <sys/vesa/video.h>
+#include <sys/vesa/debug.h>
+#include <minmax.h>
+
+struct firmware *firmware = NULL;
+
+extern struct ansi_ops bios_ansi_ops;
+
+#define BIOS_CURXY ((struct curxy *)0x450)	/* Array for each page */
+#define BIOS_ROWS (*(uint8_t *)0x484)	/* Minus one; if zero use 24 (= 25 lines) */
+#define BIOS_COLS (*(uint16_t *)0x44A)
+#define BIOS_PAGE (*(uint8_t *)0x462)
+
+static void bios_set_mode(uint16_t mode)
+{
+    syslinux_force_text_mode();
+}
+
+static void bios_get_mode(int *cols, int *rows)
+{
+    *rows = BIOS_ROWS ? BIOS_ROWS + 1 : 25;
+    *cols = BIOS_COLS;
+}
+
+static uint16_t cursor_type;	/* Saved cursor pattern */
+
+static void bios_get_cursor(int *x, int *y)
+{
+    com32sys_t ireg, oreg;
+
+    memset(&ireg, 0, sizeof(ireg));
+
+    ireg.eax.b[1] = 0x03;
+    ireg.ebx.b[1] = BIOS_PAGE;
+    __intcall(0x10, &ireg, &oreg);
+    cursor_type = oreg.ecx.w[0];
+    *x = oreg.edx.b[0];
+    *y = oreg.edx.b[1];
+}
+
+static void bios_erase(int x0, int y0, int x1, int y1, uint8_t attribute)
+{
+    static com32sys_t ireg;
+
+    ireg.eax.w[0] = 0x0600;	/* Clear window */
+    ireg.ebx.b[1] = attribute;
+    ireg.ecx.b[0] = x0;
+    ireg.ecx.b[1] = y0;
+    ireg.edx.b[0] = x1;
+    ireg.edx.b[1] = y1;
+    __intcall(0x10, &ireg, NULL);
+}
+
+static void bios_showcursor(const struct term_state *st)
+{
+    static com32sys_t ireg;
+    uint16_t cursor = st->cursor ? cursor_type : 0x2020;
+
+    ireg.eax.b[1] = 0x01;
+    ireg.ecx.w[0] = cursor;
+    __intcall(0x10, &ireg, NULL);
+}
+
+static void bios_set_cursor(int x, int y, bool visible)
+{
+    const int page = BIOS_PAGE;
+    struct curxy xy = BIOS_CURXY[page];
+    static com32sys_t ireg;
+
+    (void)visible;
+
+    if (xy.x != x || xy.y != y) {
+	ireg.eax.b[1] = 0x02;
+	ireg.ebx.b[1] = page;
+	ireg.edx.b[1] = y;
+	ireg.edx.b[0] = x;
+	__intcall(0x10, &ireg, NULL);
+    }
+}
+
+static void bios_write_char(uint8_t ch, uint8_t attribute)
+{
+    static com32sys_t ireg;
+
+    ireg.eax.b[1] = 0x09;
+    ireg.eax.b[0] = ch;
+    ireg.ebx.b[1] = BIOS_PAGE;
+    ireg.ebx.b[0] = attribute;
+    ireg.ecx.w[0] = 1;
+    __intcall(0x10, &ireg, NULL);
+}
+
+static void bios_scroll_up(uint8_t cols, uint8_t rows, uint8_t attribute)
+{
+    static com32sys_t ireg;
+
+    ireg.eax.w[0] = 0x0601;
+    ireg.ebx.b[1] = attribute;
+    ireg.ecx.w[0] = 0;
+    ireg.edx.b[1] = rows;
+    ireg.edx.b[0] = cols;
+    __intcall(0x10, &ireg, NULL);	/* Scroll */
+}
+
+static void bios_beep(void)
+{
+    static com32sys_t ireg;
+
+    ireg.eax.w[0] = 0x0e07;
+    ireg.ebx.b[1] = BIOS_PAGE;
+    __intcall(0x10, &ireg, NULL);
+}
+
+struct output_ops bios_output_ops = {
+	.erase = bios_erase,
+	.write_char = bios_write_char,
+	.showcursor = bios_showcursor,
+	.set_cursor = bios_set_cursor,
+	.scroll_up = bios_scroll_up,
+	.beep = bios_beep,
+	.get_mode = bios_get_mode,
+	.set_mode = bios_set_mode,
+	.get_cursor = bios_get_cursor,
+};
+
+extern char bios_getchar(char *);
+extern int bios_pollchar(void);
+
+struct input_ops bios_input_ops = {
+	.getchar = bios_getchar,
+	.pollchar = bios_pollchar,
+};
+
+static const char *syslinux_ipappend_string_list[32];
+bool bios_ipappend_strings(char **list, int *count)
+{
+    static com32sys_t reg;
+    int i;
+
+    reg.eax.w[0] = 0x000f;
+    __intcall(0x22, &reg, &reg);
+
+    if (reg.eflags.l & EFLAGS_CF)
+	return false;
+
+    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));
+    }
+
+    *list = syslinux_ipappend_string_list;
+    *count = reg.ecx.w[0];
+
+    return true;
+}
+
+static void bios_get_serial_console_info(uint16_t *iobase, uint16_t *divisor,
+					 uint16_t *flowctl)
+{
+    *iobase = SerialPort;
+    *divisor = BaudDivisor;
+
+    *flowctl = FlowOutput | FlowInput | (FlowIgnore << 4);
+
+    if (!DisplayCon)
+	*flowctl |= (0x80 << 8);
+}
+
+void *__syslinux_adv_ptr;
+size_t __syslinux_adv_size;
+
+void bios_adv_init(void)
+{
+    static com32sys_t reg;
+
+    reg.eax.w[0] = 0x0025;
+    __intcall(0x22, &reg, &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];
+}
+
+int bios_adv_write(void)
+{
+    static com32sys_t reg;
+
+    reg.eax.w[0] = 0x001d;
+    __intcall(0x22, &reg, &reg);
+    return (reg.eflags.l & EFLAGS_CF) ? -1 : 0;
+}
+
+struct adv_ops bios_adv_ops = {
+	.init = bios_adv_init,
+	.write = bios_adv_write,
+};
+
+
+static int __constfunc is_power_of_2(unsigned int x)
+{
+    return x && !(x & (x - 1));
+}
+
+static int vesacon_paged_mode_ok(const struct vesa_mode_info *mi)
+{
+    int i;
+
+    if (!is_power_of_2(mi->win_size) ||
+	!is_power_of_2(mi->win_grain) || mi->win_grain > mi->win_size)
+	return 0;		/* Impossible... */
+
+    for (i = 0; i < 2; i++) {
+	if ((mi->win_attr[i] & 0x05) == 0x05 && mi->win_seg[i])
+	    return 1;		/* Usable window */
+    }
+
+    return 0;			/* Nope... */
+}
+
+static int bios_vesacon_set_mode(struct vesa_info *vesa_info, int *px, int *py,
+				 enum vesa_pixel_format *bestpxf)
+{
+    com32sys_t rm;
+    uint16_t mode, bestmode, *mode_ptr;
+    struct vesa_info *vi;
+    struct vesa_general_info *gi;
+    struct vesa_mode_info *mi;
+    enum vesa_pixel_format pxf;
+    int x = *px, y = *py;
+    int err = 0;
+
+    /* Allocate space in the bounce buffer for these structures */
+    vi = lzalloc(sizeof *vi);
+    if (!vi) {
+	err = 10;		/* Out of memory */
+	goto exit;
+    }
+    gi = &vi->gi;
+    mi = &vi->mi;
+
+    memset(&rm, 0, sizeof rm);
+
+    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) {
+	err = 1;		/* Function call failed */
+	goto exit;
+    }
+    if (gi->signature != VESA_MAGIC) {
+	err = 2;		/* No magic */
+	goto exit;
+    }
+    if (gi->version < 0x0102) {
+	err = 3;		/* VESA 1.2+ required */
+	goto exit;
+    }
+
+    /* Copy general info */
+    memcpy(&vesa_info->gi, gi, sizeof *gi);
+
+    /* Search for the proper mode with a suitable color and memory model... */
+
+    mode_ptr = GET_PTR(gi->video_mode_ptr);
+    bestmode = 0;
+    *bestpxf = PXF_NONE;
+
+    while ((mode = *mode_ptr++) != 0xFFFF) {
+	mode &= 0x1FF;		/* The rest are attributes of sorts */
+
+	debug("Found mode: 0x%04x\r\n", mode);
+
+	memset(mi, 0, sizeof *mi);
+	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;
+
+	debug
+	    ("mode_attr 0x%04x, h_res = %4d, v_res = %4d, bpp = %2d, layout = %d (%d,%d,%d)\r\n",
+	     mi->mode_attr, mi->h_res, mi->v_res, mi->bpp, mi->memory_layout,
+	     mi->rpos, mi->gpos, mi->bpos);
+
+	/* Must be an LFB color graphics mode supported by the hardware.
+
+	   The bits tested are:
+	   4 - graphics mode
+	   3 - color mode
+	   1 - mode information available (mandatory in VBE 1.2+)
+	   0 - mode supported by hardware
+	 */
+	if ((mi->mode_attr & 0x001b) != 0x001b)
+	    continue;
+
+	/* Must be the chosen size */
+	if (mi->h_res != x || mi->v_res != y)
+	    continue;
+
+	/* We don't support multibank (interlaced memory) modes */
+	/*
+	 *  Note: The Bochs VESA BIOS (vbe.c 1.58 2006/08/19) violates the
+	 * specification which states that banks == 1 for unbanked modes;
+	 * fortunately it does report bank_size == 0 for those.
+	 */
+	if (mi->banks > 1 && mi->bank_size) {
+	    debug("bad: banks = %d, banksize = %d, pages = %d\r\n",
+		  mi->banks, mi->bank_size, mi->image_pages);
+	    continue;
+	}
+
+	/* Must be either a flat-framebuffer mode, or be an acceptable
+	   paged mode */
+	if (!(mi->mode_attr & 0x0080) && !vesacon_paged_mode_ok(mi)) {
+	    debug("bad: invalid paged mode\r\n");
+	    continue;
+	}
+
+	/* Must either be a packed-pixel mode or a direct color mode
+	   (depending on VESA version ); must be a supported pixel format */
+	pxf = PXF_NONE;		/* Not usable */
+
+	if (mi->bpp == 32 &&
+	    (mi->memory_layout == 4 ||
+	     (mi->memory_layout == 6 && mi->rpos == 16 && mi->gpos == 8 &&
+	      mi->bpos == 0)))
+	    pxf = PXF_BGRA32;
+	else if (mi->bpp == 24 &&
+		 (mi->memory_layout == 4 ||
+		  (mi->memory_layout == 6 && mi->rpos == 16 && mi->gpos == 8 &&
+		   mi->bpos == 0)))
+	    pxf = PXF_BGR24;
+	else if (mi->bpp == 16 &&
+		 (mi->memory_layout == 4 ||
+		  (mi->memory_layout == 6 && mi->rpos == 11 && mi->gpos == 5 &&
+		   mi->bpos == 0)))
+	    pxf = PXF_LE_RGB16_565;
+	else if (mi->bpp == 15 &&
+		 (mi->memory_layout == 4 ||
+		  (mi->memory_layout == 6 && mi->rpos == 10 && mi->gpos == 5 &&
+		   mi->bpos == 0)))
+	    pxf = PXF_LE_RGB15_555;
+
+	if (pxf < *bestpxf) {
+	    debug("Best mode so far, pxf = %d\r\n", pxf);
+
+	    /* Best mode so far... */
+	    bestmode = mode;
+	    *bestpxf = pxf;
+
+	    /* Copy mode info */
+	    memcpy(&vesa_info->mi, mi, sizeof *mi);
+	}
+    }
+
+    if (*bestpxf == PXF_NONE) {
+	err = 4;		/* No mode found */
+	goto exit;
+    }
+
+    mi = &vesa_info->mi;
+    mode = bestmode;
+
+    /* Now set video mode */
+    rm.eax.w[0] = 0x4F02;	/* Set SVGA video mode */
+    if (mi->mode_attr & 0x0080)
+	mode |= 0x4000;		/* Request linear framebuffer if supported */
+    rm.ebx.w[0] = mode;
+    __intcall(0x10, &rm, &rm);
+    if (rm.eax.w[0] != 0x004F) {
+	err = 9;		/* Failed to set mode */
+	goto exit;
+    }
+
+exit:
+    if (vi)
+	lfree(vi);
+
+    return err;
+}
+
+static void set_window_pos(struct win_info *wi, size_t win_pos)
+{
+    static com32sys_t ireg;
+
+    wi->win_pos = win_pos;
+
+    if (wi->win_num < 0)
+	return;			/* This should never happen... */
+
+    ireg.eax.w[0] = 0x4F05;
+    ireg.ebx.b[0] = wi->win_num;
+    ireg.edx.w[0] = win_pos >> wi->win_gshift;
+
+    __intcall(0x10, &ireg, NULL);
+}
+
+static void bios_vesacon_screencpy(size_t dst, const uint32_t * src,
+				   size_t bytes, struct win_info *wi)
+{
+    size_t win_pos, win_off;
+    size_t win_size = wi->win_size;
+    size_t omask = win_size - 1;
+    char *win_base = wi->win_base;
+    const char *s = (const char *)src;
+    size_t l;
+
+    while (bytes) {
+	win_off = dst & omask;
+	win_pos = dst & ~omask;
+
+	if (__unlikely(win_pos != wi->win_pos))
+	    set_window_pos(wi, win_pos);
+
+	l = min(bytes, win_size - win_off);
+	memcpy(win_base + win_off, s, l);
+
+	bytes -= l;
+	s += l;
+	dst += l;
+    }
+}
+
+static int bios_font_query(uint8_t **font)
+{
+    com32sys_t rm;
+
+    /* Get BIOS 8x16 font */
+
+    rm.eax.w[0] = 0x1130;	/* Get Font Information */
+    rm.ebx.w[0] = 0x0600;	/* Get 8x16 ROM font */
+    __intcall(0x10, &rm, &rm);
+    *font = MK_PTR(rm.es, rm.ebp.w[0]);
+
+    return 16;
+
+}
+struct vesa_ops bios_vesa_ops = {
+	.set_mode  = bios_vesacon_set_mode,
+	.screencpy = bios_vesacon_screencpy,
+	.font_query = bios_font_query,
+};
+
+static uint32_t min_lowmem_heap = 65536;
+extern char __lowmem_heap[];
+uint8_t KbdFlags;		/* Check for keyboard escapes */
+__export uint8_t KbdMap[256];	/* Keyboard map */
+
+__export uint16_t PXERetry;
+
+static inline void check_escapes(void)
+{
+	com32sys_t ireg, oreg;
+
+	ireg.eax.b[1] = 0x02;	/* Check keyboard flags */
+	__intcall(0x16, &ireg, &oreg);
+
+	KbdFlags = oreg.eax.b[0];
+
+	/* Ctrl->skip 386 check */
+	if (oreg.eax.b[0] & 0x04) {
+		/*
+		 * Now check that there is sufficient low (DOS) memory
+		 *
+		 * NOTE: Linux doesn't use all of real_mode_seg, but we use
+		 * the same segment for COMBOOT images, which can use all 64K.
+		 */
+		uint16_t mem;
+
+		__intcall(0x12, &ireg, &oreg);
+
+		mem = ((uint32_t)__lowmem_heap) + min_lowmem_heap + 1023;
+		mem = mem >> 10;
+
+		if (mem < oreg.eax.w[0]) {
+			char buf[256];
+
+			snprintf(buf, sizeof(buf),
+				 "It appears your computer has only "
+				 "%dK of low (\"DOS\") RAM.\n"
+				 "This version of Syslinux needs "
+				 "%dK to boot.  "
+				 "If you get this\nmessage in error, "
+				 "hold down the Ctrl key while booting, "
+				 "and I\nwill take your word for it.\n",
+				 oreg.eax.w[0], mem);
+			writestr(buf);
+			kaboom();
+		}
+	}
+}
+
+extern uint32_t BIOS_timer_next;
+extern uint32_t timer_irq;
+static inline void bios_timer_init(void)
+{
+	unsigned long next;
+	uint32_t *hook = (uint32_t *)BIOS_timer_hook;
+
+	next = *hook;
+	BIOS_timer_next = next;
+	*hook = (uint32_t)&timer_irq;
+}
+
+extern uint8_t bios_free_mem;
+
+void bios_init(void)
+{
+	int i;
+
+	/* Initialize timer */
+	bios_timer_init();
+
+	for (i = 0; i < 256; i++)
+		KbdMap[i] = i;
+
+	bios_adjust_screen();
+
+	/* Init the memory subsystem */
+	bios_free_mem = (uint16_t *)0x413;
+
+	/* CPU-dependent initialization and related checks. */
+	check_escapes();
+}
+
+extern void *bios_malloc(size_t, enum heap, size_t);
+extern void *bios_realloc(void *, size_t);
+extern void bios_free(void *);
+
+struct mem_ops bios_mem_ops = {
+	.malloc = bios_malloc,
+	.realloc = bios_realloc,
+	.free = bios_free,
+	.scan_memory = bios_scan_memory,
+};
+
+struct firmware bios_fw = {
+	.init = bios_init,
+	.adjust_screen = bios_adjust_screen,
+	.cleanup = bios_cleanup_hardware,
+	.disk_init = bios_disk_init,
+	.o_ops = &bios_output_ops,
+	.i_ops = &bios_input_ops,
+	.ipappend_strings = bios_ipappend_strings,
+	.get_serial_console_info = bios_get_serial_console_info,
+	.adv_ops = &bios_adv_ops,
+	.vesa = &bios_vesa_ops,
+	.mem = &bios_mem_ops,
+};
+
+void syslinux_register_bios(void)
+{
+	firmware = &bios_fw;
+}
diff --git a/core/call16.c b/core/call16.c
index 3ef6690..471aef9 100644
--- a/core/call16.c
+++ b/core/call16.c
@@ -24,9 +24,17 @@
 
 static inline uint32_t eflags(void)
 {
-    uint32_t v;
+    //uint32_t v;
 
+#if __SIZEOF_POINTER__ == 4
+    uint32_t v;
     asm volatile("pushfl ; popl %0" : "=rm" (v));
+#elif __SIZEOF_POINTER__ == 8
+    uint64_t v;
+    asm volatile("pushfq ; pop %0" : "=rm" (v));
+#else
+#error "Unable to build for to-be-defined architecture type"
+#endif
     return v;
 }
 
diff --git a/core/cleanup.c b/core/cleanup.c
index 73b63db..de318d9 100644
--- a/core/cleanup.c
+++ b/core/cleanup.c
@@ -12,9 +12,11 @@
  */
 #include <com32.h>
 #include <core.h>
+#include <syslinux/memscan.h>
+#include <syslinux/firmware.h>
 
-extern void timer_cleanup(void);
 extern void comboot_cleanup_api(void);
+extern void bios_timer_cleanup(void);
 
 /*
  * cleanup.c
@@ -22,12 +24,7 @@
  * Some final tidying before jumping to a kernel or bootsector
  */
 
-/*
- * cleanup_hardware:
- *
- *	Shut down anything transient.
- */
-__export void cleanup_hardware(void)
+void bios_cleanup_hardware(void)
 {
 	/*
 	 * TODO
@@ -39,8 +36,18 @@
 	__intcall(0x13, &zero_regs, NULL);
 
 	call16(comboot_cleanup_api, &zero_regs, NULL);
-	call16(timer_cleanup, &zero_regs, NULL);
+	call16(bios_timer_cleanup, &zero_regs, NULL);
 
 	/* If we enabled serial port interrupts, clean them up now */
 	sirq_cleanup();
 }
+
+/*
+ * cleanup_hardware:
+ *
+ *	Shut down anything transient.
+ */
+__export void cleanup_hardware(void)
+{
+	firmware->cleanup();
+}
diff --git a/core/comboot.inc b/core/comboot.inc
index e5afbe2..3197c8a 100644
--- a/core/comboot.inc
+++ b/core/comboot.inc
@@ -342,52 +342,6 @@
 		ret
 
 ;
-; INT 22h AX=000Ah	Get Derivative-Specific Info
-;
-comapi_derinfo:
-		mov P_AL,my_id
-%if IS_PXELINUX
-		mov ax,[APIVer]
-		mov P_DX,ax
-		mov ax,[StrucPtr]
-		mov P_BX,ax
-		mov ax,[StrucPtr+2]
-		mov P_ES,ax
-		mov ax,[InitStack]
-		mov P_SI,ax
-		mov ax,[InitStack+2]
-		mov P_FS,ax
-		mov eax,[IPInfo.MyIP]
-		mov P_ECX,eax
-		mov P_GS,0
-		mov P_DI,IPInfo
-%else
-		; Physical medium...
-
-		mov al,[SectorShift]
-		mov P_CL,al
-		mov al,[DriveNumber]
-		mov P_DL,al
-		mov P_FS,cs
-		mov P_SI,OrigESDI
-		mov P_GS,cs
-		mov P_DI,Hidden
-%if IS_SYSLINUX || IS_EXTLINUX
-		mov P_ES,cs
-		mov P_BX,PartInfo
-%elif IS_ISOLINUX
-		mov P_ES,cs
-		mov P_BX,spec_packet
-		mov ax,[BIOSType]
-		sub ax,bios_cdrom
-		shr ax,2
-		mov P_CH,al		; Mode (el torito/cbios/ebios)
-%endif
-%endif
-		clc
-		ret
-
-;
 ; INT 22h AX=001Ch	Get pointer to auxillary data vector
 ;
 comapi_getadv:
@@ -444,7 +398,7 @@
 		dw comapi_err		; 0007 read file
 		dw comapi_err		; 0008 close file
 		dw comapi_err		; 0009 call PXE stack
-		dw comapi_derinfo	; 000A derivative-specific info
+		dw comapi_err		; 000A derivative-specific info
 		dw comapi_err		; 000B get serial port config
 		dw comapi_err		; 000C perform final cleanup
 		dw comapi_err		; 000D clean up then bootstrap
diff --git a/core/conio.c b/core/conio.c
index 3b8a103..5587203 100644
--- a/core/conio.c
+++ b/core/conio.c
@@ -27,6 +27,7 @@
 #include <fs.h>
 #include <com32.h>
 #include <sys/cpu.h>
+#include <syslinux/firmware.h>
 
 #include "bios.h"
 #include "graphics.h"
@@ -106,12 +107,12 @@
 	write_serial(regs->eax.b[0]);
 }
 
-void pm_serialcfg(com32sys_t *regs)
+void serialcfg(uint16_t *iobase, uint16_t *divisor, uint16_t *flowctl)
 {
 	uint8_t al, ah;
 
-	regs->eax.w[0] = SerialPort;
-	regs->ecx.w[0] = BaudDivisor;
+	*iobase = SerialPort;
+	*divisor = BaudDivisor;
 
 	al = FlowOutput;
 	ah = FlowInput;
@@ -123,7 +124,12 @@
 	if (!DisplayCon)
 		ah |= 0x80;
 
-	regs->ebx.w[0] = al | (ah << 8);
+	*flowctl = al | (ah << 8);
+}
+
+void pm_serialcfg(com32sys_t *regs)
+{
+	serialcfg(&regs->eax.w[0], &regs->ecx.w[0], &regs->ebx.w[0]);
 }
 
 /*
@@ -142,7 +148,7 @@
  *
  * Returns 1 if character pending.
  */
-__export int pollchar(void)
+int bios_pollchar(void)
 {
 	com32sys_t ireg, oreg;
 	uint8_t data = 0;
@@ -183,6 +189,11 @@
 	return data;
 }
 
+__export int pollchar(void)
+{
+	return firmware->i_ops->pollchar();
+}
+
 void pm_pollchar(com32sys_t *regs)
 {
 	if (pollchar())
@@ -193,10 +204,7 @@
 
 extern void do_idle(void);
 
-/*
- * getchar: Read a character from keyboard or serial port
- */
-__export char getchar(char *hi)
+char bios_getchar(char *hi)
 {
 	com32sys_t ireg, oreg;
 	unsigned char data;
@@ -263,6 +271,14 @@
 	return data;
 }
 
+/*
+ * getchar: Read a character from keyboard or serial port
+ */
+__export char getchar(char *hi)
+{
+	return firmware->i_ops->getchar(hi);
+}
+
 void pm_getchar(com32sys_t *regs)
 {
 	regs->eax.b[0] = getchar((char *)&regs->eax.b[1]);
diff --git a/core/diskboot.inc b/core/diskboot.inc
index 89bdd96..ce75b8c 100644
--- a/core/diskboot.inc
+++ b/core/diskboot.inc
@@ -28,7 +28,7 @@
 ; reduce the code size...
 ;
 
-		global StackBuf
+		global StackBuf, PartInfo, Hidden, OrigESDI, DriveNumber
 StackBuf	equ STACK_TOP-44-92	; Start the stack here (grow down - 4K)
 PartInfo	equ StackBuf
 .mbr		equ PartInfo
diff --git a/core/diskstart.inc b/core/diskstart.inc
index a2ede95..875b409 100644
--- a/core/diskstart.inc
+++ b/core/diskstart.inc
@@ -504,7 +504,7 @@
 		mov si,[bsHeads]
 		mov di,[bsSecPerTrack]
 		movzx ebp,word [MaxTransfer]
-		pm_call fs_init
+		pm_call pm_fs_init
 		pm_call load_env32
 		popad
 
diff --git a/core/elflink/load_env32.c b/core/elflink/load_env32.c
index 3ddbfec..b277877 100644
--- a/core/elflink/load_env32.c
+++ b/core/elflink/load_env32.c
@@ -25,11 +25,12 @@
 #define LDLINUX	"ldlinux.c32"
 
 extern char __dynstr_start[];
-extern char __dynstr_len[], __dynsym_len[];
+extern char __dynstr_end[], __dynsym_end[];
 extern char __dynsym_start[];
 extern char __got_start[];
-extern Elf32_Dyn __dynamic_start[];
-extern Elf32_Word __gnu_hash_start[];
+extern Elf_Dyn __dynamic_start[];
+extern Elf_Word __gnu_hash_start[];
+extern char __module_start[];
 
 struct elf_module core_module = {
     .name		= "(core)",
@@ -38,15 +39,12 @@
     .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
+    .syment_size	= sizeof(Elf_Sym),
 };
 
 /*
@@ -107,6 +105,7 @@
 	int fd;
 	char *argv[] = { LDLINUX, NULL };
 	char realname[FILENAME_MAX];
+	size_t size;
 
 	static const char *search_directories[] = {
 		"/boot/isolinux",
@@ -122,7 +121,7 @@
 		NULL
 	};
 
-	dprintf("Starting 32 bit elf module subsystem...\n");
+	dprintf("Starting %s elf module subsystem...\n", ELF_MOD_SYS);
 
 	PATH = malloc(strlen(CurrentDirName) + 1);
 	if (!PATH) {
@@ -132,6 +131,12 @@
 
 	strcpy(PATH, CurrentDirName);
 
+	size = (size_t)__dynstr_end - (size_t)__dynstr_start;
+	core_module.strtable_size = size;
+	size = (size_t)__dynsym_end - (size_t)__dynsym_start;
+	core_module.symtable_size = size;
+	core_module.base_addr = (Elf_Addr)__module_start;
+
 	init_module_subsystem(&core_module);
 
 	start_ldlinux(argv);
diff --git a/core/extern.inc b/core/extern.inc
index 953be42..a159000 100644
--- a/core/extern.inc
+++ b/core/extern.inc
@@ -30,7 +30,7 @@
 	extern mem_init
 
 	; fs.c
-	extern fs_init, pm_searchdir, getfssec, getfsbytes
+	extern pm_fs_init, pm_searchdir, getfssec, getfsbytes
 	extern pm_mangle_name, pm_load_config
         extern pm_open_file, pm_close_file
 	extern SectorSize, SectorShift
diff --git a/core/font.c b/core/font.c
index 8533080..edc9de8 100644
--- a/core/font.c
+++ b/core/font.c
@@ -18,6 +18,7 @@
  *
  */
 
+#include <syslinux/firmware.h>
 #include <sys/io.h>
 #include <stdio.h>
 #include <fs.h>
@@ -90,7 +91,7 @@
 /*
  * use_font:
  *	This routine activates whatever font happens to be in the
- *	vgafontbuf, and updates the adjust_screen data.
+ *	vgafontbuf, and updates the bios_adjust_screen data.
  *      Must be called with CS = DS
  */
 void use_font(void)
@@ -127,7 +128,7 @@
 			/* 8 pixels/character */
 			VidCols = ((GXPixCols >> 3) - 1);
 
-			/* No need to call adjust_screen */
+			/* No need to call bios_adjust_screen */
 			return;
 		} else {
 			ireg.eax.w[0] = 0x1110;	/* Load into VGA RAM */
@@ -142,16 +143,17 @@
 			ireg.eax.w[0] = 0x1103; /* Select page 0 */
 			__intcall(0x10, &ireg, NULL);
 		}
+
 	}
 
-	adjust_screen();
+	bios_adjust_screen();
 }
 
 /*
- * adjust_screen: Set the internal variables associated with the screen size.
+ * bios_adjust_screen: Set the internal variables associated with the screen size.
  *		This is a subroutine in case we're loading a custom font.
  */
-void adjust_screen(void)
+void bios_adjust_screen(void)
 {
 	com32sys_t ireg, oreg;
 	volatile uint8_t *vidrows = (volatile uint8_t *)BIOS_vidrows;
@@ -175,6 +177,12 @@
 	VidCols = --cols;	/* Store count-1 (same as rows) */
 }
 
+void adjust_screen(void)
+{
+	if (firmware->adjust_screen)
+		firmware->adjust_screen();
+}
+
 void pm_adjust_screen(com32sys_t *regs __unused)
 {
 	adjust_screen();
diff --git a/core/fs/diskio.c b/core/fs/diskio.c
index 6683816..afe4e58 100644
--- a/core/fs/diskio.c
+++ b/core/fs/diskio.c
@@ -8,287 +8,7 @@
 #include <disk.h>
 #include <ilog2.h>
 
-#define RETRY_COUNT 6
-
-static inline sector_t chs_max(const struct disk *disk)
-{
-    return (sector_t)disk->secpercyl << 10;
-}
-
-static int chs_rdwr_sectors(struct disk *disk, void *buf,
-			    sector_t lba, size_t count, bool is_write)
-{
-    char *ptr = buf;
-    char *tptr;
-    size_t chunk, freeseg;
-    int sector_shift = disk->sector_shift;
-    uint32_t xlba = lba + disk->part_start; /* Truncated LBA (CHS is << 2 TB) */
-    uint32_t t;
-    uint32_t c, h, s;
-    com32sys_t ireg, oreg;
-    size_t done = 0;
-    size_t bytes;
-    int retry;
-    uint32_t maxtransfer = disk->maxtransfer;
-
-    if (lba + disk->part_start >= chs_max(disk))
-	return 0;		/* Impossible CHS request */
-
-    memset(&ireg, 0, sizeof ireg);
-
-    ireg.eax.b[1] = 0x02 + is_write;
-    ireg.edx.b[0] = disk->disk_number;
-
-    while (count) {
-	chunk = count;
-	if (chunk > maxtransfer)
-	    chunk = maxtransfer;
-
-	freeseg = (0x10000 - ((size_t)ptr & 0xffff)) >> sector_shift;
-
-	if ((size_t)buf <= 0xf0000 && freeseg) {
-	    /* Can do a direct load */
-	    tptr = ptr;
-	} else {
-	    /* Either accessing high memory or we're crossing a 64K line */
-	    tptr = core_xfer_buf;
-	    freeseg = (0x10000 - ((size_t)tptr & 0xffff)) >> sector_shift;
-	}
-	if (chunk > freeseg)
-	    chunk = freeseg;
-
-	s = xlba % disk->s;
-	t = xlba / disk->s;
-	h = t % disk->h;
-	c = t / disk->h;
-
-	if (chunk > (disk->s - s))
-	    chunk = disk->s - s;
-
-	bytes = chunk << sector_shift;
-
-	if (tptr != ptr && is_write)
-	    memcpy(tptr, ptr, bytes);
-
-	ireg.eax.b[0] = chunk;
-	ireg.ecx.b[1] = c;
-	ireg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1);
-	ireg.edx.b[1] = h;
-	ireg.ebx.w[0] = OFFS(tptr);
-	ireg.es       = SEG(tptr);
-
-	retry = RETRY_COUNT;
-
-        for (;;) {
-	    if (c < 1024) {
-		dprintf("CHS[%02x]: %u @ %llu (%u/%u/%u) %04x:%04x %s %p\n",
-			ireg.edx.b[0], chunk, xlba, c, h, s+1,
-			ireg.es, ireg.ebx.w[0],
-			(ireg.eax.b[1] & 1) ? "<-" : "->",
-			ptr);
-
-		__intcall(0x13, &ireg, &oreg);
-		if (!(oreg.eflags.l & EFLAGS_CF))
-		    break;
-
-		dprintf("CHS: error AX = %04x\n", oreg.eax.w[0]);
-
-		if (retry--)
-		    continue;
-
-		/*
-		 * For any starting value, this will always end with
-		 * ..., 1, 0
-		 */
-		chunk >>= 1;
-		if (chunk) {
-		    maxtransfer = chunk;
-		    retry = RETRY_COUNT;
-		    ireg.eax.b[0] = chunk;
-		    continue;
-		}
-	    }
-
-	    printf("CHS: Error %04x %s sector %llu (%u/%u/%u)\n",
-		   oreg.eax.w[0],
-		   is_write ? "writing" : "reading",
-		   lba, c, h, s+1);
-	    return done;	/* Failure */
-	}
-
-	bytes = chunk << sector_shift;
-
-	if (tptr != ptr && !is_write)
-	    memcpy(ptr, tptr, bytes);
-
-	/* If we dropped maxtransfer, it eventually worked, so remember it */
-	disk->maxtransfer = maxtransfer;
-
-	ptr   += bytes;
-	xlba  += chunk;
-	count -= chunk;
-	done  += chunk;
-    }
-
-    return done;
-}
-
-struct edd_rdwr_packet {
-    uint16_t size;
-    uint16_t blocks;
-    far_ptr_t buf;
-    uint64_t lba;
-};
-
-static int edd_rdwr_sectors(struct disk *disk, void *buf,
-			    sector_t lba, size_t count, bool is_write)
-{
-    static __lowmem struct edd_rdwr_packet pkt;
-    char *ptr = buf;
-    char *tptr;
-    size_t chunk, freeseg;
-    int sector_shift = disk->sector_shift;
-    com32sys_t ireg, oreg, reset;
-    size_t done = 0;
-    size_t bytes;
-    int retry;
-    uint32_t maxtransfer = disk->maxtransfer;
-
-    memset(&ireg, 0, sizeof ireg);
-
-    ireg.eax.b[1] = 0x42 + is_write;
-    ireg.edx.b[0] = disk->disk_number;
-    ireg.ds       = SEG(&pkt);
-    ireg.esi.w[0] = OFFS(&pkt);
-
-    memset(&reset, 0, sizeof reset);
-
-    lba += disk->part_start;
-    while (count) {
-	chunk = count;
-	if (chunk > maxtransfer)
-	    chunk = maxtransfer;
-
-	freeseg = (0x10000 - ((size_t)ptr & 0xffff)) >> sector_shift;
-
-	if ((size_t)ptr <= 0xf0000 && freeseg) {
-	    /* Can do a direct load */
-	    tptr = ptr;
-	} else {
-	    /* Either accessing high memory or we're crossing a 64K line */
-	    tptr = core_xfer_buf;
-	    freeseg = (0x10000 - ((size_t)tptr & 0xffff)) >> sector_shift;
-	}
-	if (chunk > freeseg)
-	    chunk = freeseg;
-
-	bytes = chunk << sector_shift;
-
-	if (tptr != ptr && is_write)
-	    memcpy(tptr, ptr, bytes);
-
-	retry = RETRY_COUNT;
-
-	for (;;) {
-	    pkt.size   = sizeof pkt;
-	    pkt.blocks = chunk;
-	    pkt.buf    = FAR_PTR(tptr);
-	    pkt.lba    = lba;
-
-	    dprintf("EDD[%02x]: %u @ %llu %04x:%04x %s %p\n",
-		    ireg.edx.b[0], pkt.blocks, pkt.lba,
-		    pkt.buf.seg, pkt.buf.offs,
-		    (ireg.eax.b[1] & 1) ? "<-" : "->",
-		    ptr);
-
-	    __intcall(0x13, &ireg, &oreg);
-	    if (!(oreg.eflags.l & EFLAGS_CF))
-		break;
-
-	    dprintf("EDD: error AX = %04x\n", oreg.eax.w[0]);
-
-	    if (retry--)
-		continue;
-
-	    /*
-	     * Some systems seem to get "stuck" in an error state when
-	     * using EBIOS.  Doesn't happen when using CBIOS, which is
-	     * good, since some other systems get timeout failures
-	     * waiting for the floppy disk to spin up.
-	     */
-	    __intcall(0x13, &reset, NULL);
-
-	    /* For any starting value, this will always end with ..., 1, 0 */
-	    chunk >>= 1;
-	    if (chunk) {
-		maxtransfer = chunk;
-		retry = RETRY_COUNT;
-		continue;
-	    }
-
-	    /*
-	     * Total failure.  There are systems which identify as
-	     * EDD-capable but aren't; the known such systems return
-	     * error code AH=1 (invalid function), but let's not
-	     * assume that for now.
-	     *
-	     * Try to fall back to CHS.  If the LBA is absurd, the
-	     * chs_max() test in chs_rdwr_sectors() will catch it.
-	     */
-	    done = chs_rdwr_sectors(disk, buf, lba - disk->part_start,
-				    count, is_write);
-	    if (done == (count << sector_shift)) {
-		/* Successful, assume this is a CHS disk */
-		disk->rdwr_sectors = chs_rdwr_sectors;
-		return done;
-	    }
-	    printf("EDD: Error %04x %s sector %llu\n",
-		   oreg.eax.w[0],
-		   is_write ? "writing" : "reading",
-		   lba);
-	    return done;	/* Failure */
-	}
-
-	bytes = chunk << sector_shift;
-
-	if (tptr != ptr && !is_write)
-	    memcpy(ptr, tptr, bytes);
-
-	/* If we dropped maxtransfer, it eventually worked, so remember it */
-	disk->maxtransfer = maxtransfer;
-
-	ptr   += bytes;
-	lba   += chunk;
-	count -= chunk;
-	done  += chunk;
-    }
-    return done;
-}
-
-struct edd_disk_params {
-    uint16_t  len;
-    uint16_t  flags;
-    uint32_t  phys_c;
-    uint32_t  phys_h;
-    uint32_t  phys_s;
-    uint64_t  sectors;
-    uint16_t  sector_size;
-    far_ptr_t dpte;
-    uint16_t  devpath_key;
-    uint8_t   devpath_len;
-    uint8_t   _pad1[3];
-    char      bus_type[4];
-    char      if_type[8];
-    uint8_t   if_path[8];
-    uint8_t   dev_path[16];
-    uint8_t   _pad2;
-    uint8_t   devpath_csum;	/* Depends on devpath_len! */
-} __attribute__((packed));
-
-static inline bool is_power_of_2(uint32_t x)
-{
-    return !(x & (x-1));
-}
+#include <syslinux/firmware.h>
 
 void getoneblk(struct disk *disk, char *buf, block_t block, int block_size)
 {
@@ -297,121 +17,17 @@
     disk->rdwr_sectors(disk, buf, block * sec_per_block, sec_per_block, 0);
 }
 
-
-struct disk *disk_init(uint8_t devno, bool cdrom, sector_t part_start,
-                       uint16_t bsHeads, uint16_t bsSecPerTrack,
-		       uint32_t MaxTransfer)
-{
-    static struct disk disk;
-    static __lowmem struct edd_disk_params edd_params;
-    com32sys_t ireg, oreg;
-    bool ebios;
-    int sector_size;
-    unsigned int hard_max_transfer;
-
-    memset(&ireg, 0, sizeof ireg);
-    ireg.edx.b[0] = devno;
-
-    if (cdrom) {
-	/*
-	 * The query functions don't work right on some CD-ROM stacks.
-	 * Known affected systems: ThinkPad T22, T23.
-	 */
-	sector_size = 2048;
-	ebios = true;
-	hard_max_transfer = 32;
-    } else {
-	sector_size = 512;
-	ebios = false;
-	hard_max_transfer = 63;
-
-	/* CBIOS parameters */
-	disk.h = bsHeads;
-	disk.s = bsSecPerTrack;
-
-	if ((int8_t)devno < 0) {
-	    /* Get hard disk geometry from BIOS */
-	    
-	    ireg.eax.b[1] = 0x08;
-	    __intcall(0x13, &ireg, &oreg);
-	    
-	    if (!(oreg.eflags.l & EFLAGS_CF)) {
-		disk.h = oreg.edx.b[1] + 1;
-		disk.s = oreg.ecx.b[0] & 63;
-	    }
-	}
-
-	/* Get EBIOS support */
-	ireg.eax.b[1] = 0x41;
-	ireg.ebx.w[0] = 0x55aa;
-	ireg.eflags.b[0] = 0x3;	/* CF set */
-
-	__intcall(0x13, &ireg, &oreg);
-	
-	if (!(oreg.eflags.l & EFLAGS_CF) &&
-	    oreg.ebx.w[0] == 0xaa55 && (oreg.ecx.b[0] & 1)) {
-	    ebios = true;
-	    hard_max_transfer = 127;
-
-	    /* Query EBIOS parameters */
-	    /* The memset() is needed once this function can be called
-	       more than once */
-	    /* memset(&edd_params, 0, sizeof edd_params);  */
-	    edd_params.len = sizeof edd_params;
-
-	    ireg.eax.b[1] = 0x48;
-	    ireg.ds = SEG(&edd_params);
-	    ireg.esi.w[0] = OFFS(&edd_params);
-	    __intcall(0x13, &ireg, &oreg);
-
-	    if (!(oreg.eflags.l & EFLAGS_CF) && oreg.eax.b[1] == 0) {
-		if (edd_params.len < sizeof edd_params)
-		    memset((char *)&edd_params + edd_params.len, 0,
-			   sizeof edd_params - edd_params.len);
-
-		if (edd_params.sector_size >= 512 &&
-		    is_power_of_2(edd_params.sector_size))
-		    sector_size = edd_params.sector_size;
-	    }
-	}
-
-    }
-
-    disk.disk_number   = devno;
-    disk.sector_size   = sector_size;
-    disk.sector_shift  = ilog2(sector_size);
-    disk.part_start    = part_start;
-    disk.secpercyl     = disk.h * disk.s;
-    disk.rdwr_sectors  = ebios ? edd_rdwr_sectors : chs_rdwr_sectors;
-
-    if (!MaxTransfer || MaxTransfer > hard_max_transfer)
-	MaxTransfer = hard_max_transfer;
-
-    disk.maxtransfer   = MaxTransfer;
-
-    dprintf("disk %02x cdrom %d type %d sector %u/%u offset %llu limit %u\n",
-	    devno, cdrom, ebios, sector_size, disk.sector_shift,
-	    part_start, disk.maxtransfer);
-
-    return &disk;
-}
-
-
 /*
  * Initialize the device structure.
  *
  * NOTE: the disk cache needs to be revamped to support multiple devices...
  */
-struct device * device_init(uint8_t devno, bool cdrom, sector_t part_start,
-                            uint16_t bsHeads, uint16_t bsSecPerTrack,
-			    uint32_t MaxTransfer)
+struct device * device_init(void *args)
 {
     static struct device dev;
     static __hugebss char diskcache[128*1024];
 
-    dev.disk = disk_init(devno, cdrom, part_start,
-			 bsHeads, bsSecPerTrack, MaxTransfer);
-
+    dev.disk = firmware->disk_init(args);
     dev.cache_data = diskcache;
     dev.cache_size = sizeof diskcache;
 
diff --git a/core/fs/diskio_bios.c b/core/fs/diskio_bios.c
new file mode 100644
index 0000000..9b935fe
--- /dev/null
+++ b/core/fs/diskio_bios.c
@@ -0,0 +1,399 @@
+#include <core.h>
+#include <com32.h>
+#include <fs.h>
+#include <ilog2.h>
+
+#define RETRY_COUNT 6
+
+static inline sector_t chs_max(const struct disk *disk)
+{
+    return (sector_t)disk->secpercyl << 10;
+}
+
+struct edd_rdwr_packet {
+    uint16_t size;
+    uint16_t blocks;
+    far_ptr_t buf;
+    uint64_t lba;
+};
+
+struct edd_disk_params {
+    uint16_t  len;
+    uint16_t  flags;
+    uint32_t  phys_c;
+    uint32_t  phys_h;
+    uint32_t  phys_s;
+    uint64_t  sectors;
+    uint16_t  sector_size;
+    far_ptr_t dpte;
+    uint16_t  devpath_key;
+    uint8_t   devpath_len;
+    uint8_t   _pad1[3];
+    char      bus_type[4];
+    char      if_type[8];
+    uint8_t   if_path[8];
+    uint8_t   dev_path[16];
+    uint8_t   _pad2;
+    uint8_t   devpath_csum;	/* Depends on devpath_len! */
+} __attribute__((packed));
+
+static inline bool is_power_of_2(uint32_t x)
+{
+    return !(x & (x-1));
+}
+
+static int chs_rdwr_sectors(struct disk *disk, void *buf,
+			    sector_t lba, size_t count, bool is_write)
+{
+    char *ptr = buf;
+    char *tptr;
+    size_t chunk, freeseg;
+    int sector_shift = disk->sector_shift;
+    uint32_t xlba = lba + disk->part_start; /* Truncated LBA (CHS is << 2 TB) */
+    uint32_t t;
+    uint32_t c, h, s;
+    com32sys_t ireg, oreg;
+    size_t done = 0;
+    size_t bytes;
+    int retry;
+    uint32_t maxtransfer = disk->maxtransfer;
+
+    if (lba + disk->part_start >= chs_max(disk))
+	return 0;		/* Impossible CHS request */
+
+    memset(&ireg, 0, sizeof ireg);
+
+    ireg.eax.b[1] = 0x02 + is_write;
+    ireg.edx.b[0] = disk->disk_number;
+
+    while (count) {
+	chunk = count;
+	if (chunk > maxtransfer)
+	    chunk = maxtransfer;
+
+	freeseg = (0x10000 - ((size_t)ptr & 0xffff)) >> sector_shift;
+
+	if ((size_t)buf <= 0xf0000 && freeseg) {
+	    /* Can do a direct load */
+	    tptr = ptr;
+	} else {
+	    /* Either accessing high memory or we're crossing a 64K line */
+	    tptr = core_xfer_buf;
+	    freeseg = (0x10000 - ((size_t)tptr & 0xffff)) >> sector_shift;
+	}
+	if (chunk > freeseg)
+	    chunk = freeseg;
+
+	s = xlba % disk->s;
+	t = xlba / disk->s;
+	h = t % disk->h;
+	c = t / disk->h;
+
+	if (chunk > (disk->s - s))
+	    chunk = disk->s - s;
+
+	bytes = chunk << sector_shift;
+
+	if (tptr != ptr && is_write)
+	    memcpy(tptr, ptr, bytes);
+
+	ireg.eax.b[0] = chunk;
+	ireg.ecx.b[1] = c;
+	ireg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1);
+	ireg.edx.b[1] = h;
+	ireg.ebx.w[0] = OFFS(tptr);
+	ireg.es       = SEG(tptr);
+
+	retry = RETRY_COUNT;
+
+        for (;;) {
+	    if (c < 1024) {
+		dprintf("CHS[%02x]: %u @ %llu (%u/%u/%u) %04x:%04x %s %p\n",
+			ireg.edx.b[0], chunk, xlba, c, h, s+1,
+			ireg.es, ireg.ebx.w[0],
+			(ireg.eax.b[1] & 1) ? "<-" : "->",
+			ptr);
+
+		__intcall(0x13, &ireg, &oreg);
+		if (!(oreg.eflags.l & EFLAGS_CF))
+		    break;
+
+		dprintf("CHS: error AX = %04x\n", oreg.eax.w[0]);
+
+		if (retry--)
+		    continue;
+
+		/*
+		 * For any starting value, this will always end with
+		 * ..., 1, 0
+		 */
+		chunk >>= 1;
+		if (chunk) {
+		    maxtransfer = chunk;
+		    retry = RETRY_COUNT;
+		    ireg.eax.b[0] = chunk;
+		    continue;
+		}
+	    }
+
+	    printf("CHS: Error %04x %s sector %llu (%u/%u/%u)\n",
+		   oreg.eax.w[0],
+		   is_write ? "writing" : "reading",
+		   lba, c, h, s+1);
+	    return done;	/* Failure */
+	}
+
+	bytes = chunk << sector_shift;
+
+	if (tptr != ptr && !is_write)
+	    memcpy(ptr, tptr, bytes);
+
+	/* If we dropped maxtransfer, it eventually worked, so remember it */
+	disk->maxtransfer = maxtransfer;
+
+	ptr   += bytes;
+	xlba  += chunk;
+	count -= chunk;
+	done  += chunk;
+    }
+
+    return done;
+}
+
+static int edd_rdwr_sectors(struct disk *disk, void *buf,
+			    sector_t lba, size_t count, bool is_write)
+{
+    static __lowmem struct edd_rdwr_packet pkt;
+    char *ptr = buf;
+    char *tptr;
+    size_t chunk, freeseg;
+    int sector_shift = disk->sector_shift;
+    com32sys_t ireg, oreg, reset;
+    size_t done = 0;
+    size_t bytes;
+    int retry;
+    uint32_t maxtransfer = disk->maxtransfer;
+
+    memset(&ireg, 0, sizeof ireg);
+
+    ireg.eax.b[1] = 0x42 + is_write;
+    ireg.edx.b[0] = disk->disk_number;
+    ireg.ds       = SEG(&pkt);
+    ireg.esi.w[0] = OFFS(&pkt);
+
+    memset(&reset, 0, sizeof reset);
+
+    lba += disk->part_start;
+    while (count) {
+	chunk = count;
+	if (chunk > maxtransfer)
+	    chunk = maxtransfer;
+
+	freeseg = (0x10000 - ((size_t)ptr & 0xffff)) >> sector_shift;
+
+	if ((size_t)ptr <= 0xf0000 && freeseg) {
+	    /* Can do a direct load */
+	    tptr = ptr;
+	} else {
+	    /* Either accessing high memory or we're crossing a 64K line */
+	    tptr = core_xfer_buf;
+	    freeseg = (0x10000 - ((size_t)tptr & 0xffff)) >> sector_shift;
+	}
+	if (chunk > freeseg)
+	    chunk = freeseg;
+
+	bytes = chunk << sector_shift;
+
+	if (tptr != ptr && is_write)
+	    memcpy(tptr, ptr, bytes);
+
+	retry = RETRY_COUNT;
+
+	for (;;) {
+	    pkt.size   = sizeof pkt;
+	    pkt.blocks = chunk;
+	    pkt.buf    = FAR_PTR(tptr);
+	    pkt.lba    = lba;
+
+	    dprintf("EDD[%02x]: %u @ %llu %04x:%04x %s %p\n",
+		    ireg.edx.b[0], pkt.blocks, pkt.lba,
+		    pkt.buf.seg, pkt.buf.offs,
+		    (ireg.eax.b[1] & 1) ? "<-" : "->",
+		    ptr);
+
+	    __intcall(0x13, &ireg, &oreg);
+	    if (!(oreg.eflags.l & EFLAGS_CF))
+		break;
+
+	    dprintf("EDD: error AX = %04x\n", oreg.eax.w[0]);
+
+	    if (retry--)
+		continue;
+
+	    /*
+	     * Some systems seem to get "stuck" in an error state when
+	     * using EBIOS.  Doesn't happen when using CBIOS, which is
+	     * good, since some other systems get timeout failures
+	     * waiting for the floppy disk to spin up.
+	     */
+	    __intcall(0x13, &reset, NULL);
+
+	    /* For any starting value, this will always end with ..., 1, 0 */
+	    chunk >>= 1;
+	    if (chunk) {
+		maxtransfer = chunk;
+		retry = RETRY_COUNT;
+		continue;
+	    }
+
+	    /*
+	     * Total failure.  There are systems which identify as
+	     * EDD-capable but aren't; the known such systems return
+	     * error code AH=1 (invalid function), but let's not
+	     * assume that for now.
+	     *
+	     * Try to fall back to CHS.  If the LBA is absurd, the
+	     * chs_max() test in chs_rdwr_sectors() will catch it.
+	     */
+	    done = chs_rdwr_sectors(disk, buf, lba - disk->part_start,
+				    count, is_write);
+	    if (done == (count << sector_shift)) {
+		/* Successful, assume this is a CHS disk */
+		disk->rdwr_sectors = chs_rdwr_sectors;
+		return done;
+	    }
+	    printf("EDD: Error %04x %s sector %llu\n",
+		   oreg.eax.w[0],
+		   is_write ? "writing" : "reading",
+		   lba);
+	    return done;	/* Failure */
+	}
+
+	bytes = chunk << sector_shift;
+
+	if (tptr != ptr && !is_write)
+	    memcpy(ptr, tptr, bytes);
+
+	/* If we dropped maxtransfer, it eventually worked, so remember it */
+	disk->maxtransfer = maxtransfer;
+
+	ptr   += bytes;
+	lba   += chunk;
+	count -= chunk;
+	done  += chunk;
+    }
+    return done;
+}
+
+struct disk *bios_disk_init(void *private)
+{
+    static struct disk disk;
+    struct bios_disk_private *priv = (struct bios_disk_private *)private;
+    com32sys_t *regs = priv->regs;
+    static __lowmem struct edd_disk_params edd_params;
+    com32sys_t ireg, oreg;
+    uint8_t devno = regs->edx.b[0];
+    bool cdrom = regs->edx.b[1];
+    sector_t part_start = regs->ecx.l | ((sector_t)regs->ebx.l << 32);
+    uint16_t bsHeads = regs->esi.w[0];
+    uint16_t bsSecPerTrack = regs->edi.w[0];
+    uint32_t MaxTransfer = regs->ebp.l;
+    bool ebios;
+    int sector_size;
+    unsigned int hard_max_transfer;
+
+    memset(&ireg, 0, sizeof ireg);
+    ireg.edx.b[0] = devno;
+
+    if (cdrom) {
+	/*
+	 * The query functions don't work right on some CD-ROM stacks.
+	 * Known affected systems: ThinkPad T22, T23.
+	 */
+	sector_size = 2048;
+	ebios = true;
+	hard_max_transfer = 32;
+    } else {
+	sector_size = 512;
+	ebios = false;
+	hard_max_transfer = 63;
+
+	/* CBIOS parameters */
+	disk.h = bsHeads;
+	disk.s = bsSecPerTrack;
+
+	if ((int8_t)devno < 0) {
+	    /* Get hard disk geometry from BIOS */
+	    
+	    ireg.eax.b[1] = 0x08;
+	    __intcall(0x13, &ireg, &oreg);
+	    
+	    if (!(oreg.eflags.l & EFLAGS_CF)) {
+		disk.h = oreg.edx.b[1] + 1;
+		disk.s = oreg.ecx.b[0] & 63;
+	    }
+	}
+
+	/* Get EBIOS support */
+	ireg.eax.b[1] = 0x41;
+	ireg.ebx.w[0] = 0x55aa;
+	ireg.eflags.b[0] = 0x3;	/* CF set */
+
+	__intcall(0x13, &ireg, &oreg);
+	
+	if (!(oreg.eflags.l & EFLAGS_CF) &&
+	    oreg.ebx.w[0] == 0xaa55 && (oreg.ecx.b[0] & 1)) {
+	    ebios = true;
+	    hard_max_transfer = 127;
+
+	    /* Query EBIOS parameters */
+	    /* The memset() is needed once this function can be called
+	       more than once */
+	    /* memset(&edd_params, 0, sizeof edd_params);  */
+	    edd_params.len = sizeof edd_params;
+
+	    ireg.eax.b[1] = 0x48;
+	    ireg.ds = SEG(&edd_params);
+	    ireg.esi.w[0] = OFFS(&edd_params);
+	    __intcall(0x13, &ireg, &oreg);
+
+	    if (!(oreg.eflags.l & EFLAGS_CF) && oreg.eax.b[1] == 0) {
+		if (edd_params.len < sizeof edd_params)
+		    memset((char *)&edd_params + edd_params.len, 0,
+			   sizeof edd_params - edd_params.len);
+
+		if (edd_params.sector_size >= 512 &&
+		    is_power_of_2(edd_params.sector_size))
+		    sector_size = edd_params.sector_size;
+	    }
+	}
+
+    }
+
+    disk.disk_number   = devno;
+    disk.sector_size   = sector_size;
+    disk.sector_shift  = ilog2(sector_size);
+    disk.part_start    = part_start;
+    disk.secpercyl     = disk.h * disk.s;
+    disk.rdwr_sectors  = ebios ? edd_rdwr_sectors : chs_rdwr_sectors;
+
+    if (!MaxTransfer || MaxTransfer > hard_max_transfer)
+	MaxTransfer = hard_max_transfer;
+
+    disk.maxtransfer   = MaxTransfer;
+
+    dprintf("disk %02x cdrom %d type %d sector %u/%u offset %llu limit %u\n",
+	    devno, cdrom, ebios, sector_size, disk.sector_shift,
+	    part_start, disk.maxtransfer);
+
+    disk.private = private;
+    return &disk;
+}
+
+void pm_fs_init(com32sys_t *regs)
+{
+	static struct bios_disk_private priv;
+
+	priv.regs = regs;
+	fs_init((const struct fs_ops **)regs->eax.l, (void *)&priv);
+}
diff --git a/core/fs/fat/fat.c b/core/fs/fat/fat.c
index b2c20ee..d7346ae 100644
--- a/core/fs/fat/fat.c
+++ b/core/fs/fat/fat.c
@@ -140,6 +140,7 @@
     return 0;
 
 err:
+    dprintf("fat_next_extent: return error\n");
     return -1;
 }
 
@@ -325,7 +326,7 @@
     unsigned char c = -1;	/* Nonzero: we have not yet seen NUL */
     uint16_t cp;
 
-    dprintf("Matching: %s\n", str);
+    dprintf("Matching: %s len %d\n", str, len);
 
     while (len) {
 	cp = *match++;
diff --git a/core/fs/fs.c b/core/fs/fs.c
index 2c10fe9..adcee91 100644
--- a/core/fs/fs.c
+++ b/core/fs/fs.c
@@ -331,6 +331,7 @@
     return file_to_handle(file);
 
 err:
+    dprintf("serachdir: error seraching file %s\n", name);
     _close_file(file);
 err_no_close:
     return -1;
@@ -382,22 +383,16 @@
  *    invoke the fs-specific init function;
  *    initialize the cache if we need one;
  *    finally, get the current inode for relative path looking.
+ *
+ * ops is a ptr list for several fs_ops
  */
 __bss16 uint16_t SectorSize, SectorShift;
 
-void fs_init(com32sys_t *regs)
+void fs_init(const struct fs_ops **ops, void *priv)
 {
     static struct fs_info fs;	/* The actual filesystem buffer */
-    uint8_t disk_devno = regs->edx.b[0];
-    uint8_t disk_cdrom = regs->edx.b[1];
-    sector_t disk_offset = regs->ecx.l | ((sector_t)regs->ebx.l << 32);
-    uint16_t disk_heads = regs->esi.w[0];
-    uint16_t disk_sectors = regs->edi.w[0];
-    uint32_t maxtransfer = regs->ebp.l;
     int blk_shift = -1;
     struct device *dev = NULL;
-    /* ops is a ptr list for several fs_ops */
-    const struct fs_ops **ops = (const struct fs_ops **)regs->eax.l;
 
     /* Initialize malloc() */
     mem_init();
@@ -417,8 +412,7 @@
 	    fs.fs_dev = NULL;
 	} else {
 	    if (!dev)
-		dev = device_init(disk_devno, disk_cdrom, disk_offset,
-				  disk_heads, disk_sectors, maxtransfer);
+		dev = device_init(priv);
 	    fs.fs_dev = dev;
 	}
 	/* invoke the fs-specific init code */
diff --git a/core/fs/pxe/dhcp_option.c b/core/fs/pxe/dhcp_option.c
index f63d4a9..f2a9612 100644
--- a/core/fs/pxe/dhcp_option.c
+++ b/core/fs/pxe/dhcp_option.c
@@ -233,7 +233,7 @@
     const struct bootp_t *dhcp = (const struct bootp_t *)pkt;
     int opt_len;
 
-    IPInfo.ipv4 = 4;		/* This is IPv4 only for now... */
+    IPInfo.ipver = 4;		/* This is IPv4 only for now... */
 
     over_load = 0;
     if (ip_ok(dhcp->yip))
diff --git a/core/fs/pxe/pxe.h b/core/fs/pxe/pxe.h
index d437758..3439dd6 100644
--- a/core/fs/pxe/pxe.h
+++ b/core/fs/pxe/pxe.h
@@ -21,6 +21,7 @@
 #define PXE_H
 
 #include <syslinux/pxe_api.h>
+#include <syslinux/config.h>
 #include "fs.h"			/* For MAX_OPEN, should go away */
 
 /*
@@ -169,20 +170,9 @@
 #define PVT(i) ((struct pxe_pvt_inode *)((i)->pvt))
 
 /*
- * Network boot information
- */
-struct ip_info {
-    uint32_t ipv4;
-    uint32_t myip;
-    uint32_t serverip;
-    uint32_t gateway;
-    uint32_t netmask;
-};
-
-/*
  * Variable externs
  */
-extern struct ip_info IPInfo;
+extern struct syslinux_ipinfo IPInfo;
 
 extern uint8_t MAC[];
 extern char BOOTIFStr[];
diff --git a/core/i386/syslinux.ld b/core/i386/syslinux.ld
new file mode 100644
index 0000000..7b4e012
--- /dev/null
+++ b/core/i386/syslinux.ld
@@ -0,0 +1,428 @@
+/* -----------------------------------------------------------------------
+ *   
+ *   Copyright 2008-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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Linker script for the SYSLINUX core
+ */
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+EXTERN(_start)
+ENTRY(_start)
+
+STACK32_LEN = 65536;
+
+SECTIONS
+{
+	/* Prefix structure for the compression program */
+	. = 0;
+	__module_start = .;
+	.prefix : {
+		*(.prefix)
+	}
+
+	/* "Early" sections (before the load) */
+	. = 0x1000;
+
+	.earlybss (NOLOAD) : {
+		__earlybss_start = .;
+		*(.earlybss)
+		__earlybss_end = .;
+	}
+	__earlybss_len = ABSOLUTE(__earlybss_end) - ABSOLUTE(__earlybss_start);
+	__earlybss_dwords = (__earlybss_len + 3) >> 2;
+
+	. = ALIGN(4);
+	.bss16 (NOLOAD) : {
+		__bss16_start = .;
+		*(.bss16)
+		__bss16_end = .;
+	}
+	__bss16_len = ABSOLUTE(__bss16_end) - ABSOLUTE(__bss16_start);
+	__bss16_dwords = (__bss16_len + 3) >> 2;
+
+	. = ALIGN(4);
+ 	.config : AT (__config_lma) {
+		__config_start = .;
+		*(.config)
+		__config_end = .;
+	}
+	__config_len = ABSOLUTE(__config_end) - ABSOLUTE(__config_start);
+	__config_dwords = (__config_len + 3) >> 2;
+
+	/* Generated and/or copied code */
+
+	. = ALIGN(128);		/* Minimum separation from mutable data */
+ 	.replacestub : AT (__replacestub_lma) {
+		__replacestub_start = .;
+		*(.replacestub)
+		__replacestub_end = .;
+	}
+	__replacestub_len = ABSOLUTE(__replacestub_end) - ABSOLUTE(__replacestub_start);
+	__replacestub_dwords = (__replacestub_len + 3) >> 2;
+
+	. = ALIGN(16);
+	__gentextnr_lma = .;
+	.gentextnr : AT(__gentextnr_lma) {
+		__gentextnr_start = .;
+		*(.gentextnr)
+		__gentextnr_end = .;
+	}
+	__gentextnr_len = ABSOLUTE(__gentextnr_end) - ABSOLUTE(__gentextnr_start);
+	__gentextnr_dwords = (__gentextnr_len + 3) >> 2;
+
+	. = STACK_BASE;
+	.stack16 : AT(STACK_BASE) {
+		__stack16_start = .;
+		. += STACK_LEN;
+		__stack16_end = .;
+	}
+	__stack16_len = ABSOLUTE(__stack16_end) - ABSOLUTE(__stack16_start);
+	__stack16_dwords = (__stack16_len + 3) >> 2;
+
+	/* Initialized sections */
+
+	. = 0x7c00;
+	.init : {
+		FILL(0x90909090)
+		__init_start = .;
+		*(.init)
+		__init_end = .;
+	}
+	__init_len = ABSOLUTE(__init_end) - ABSOLUTE(__init_start);
+	__init_dwords = (__init_len + 3) >> 2;
+
+	.text16 : {
+		FILL(0x90909090)
+		__text16_start = .;
+		*(.text16)
+		__text16_end = .;
+	}
+	__text16_len = ABSOLUTE(__text16_end) - ABSOLUTE(__text16_start);
+	__text16_dwords = (__text16_len + 3) >> 2;
+
+	/*
+	 * .textnr is used for 32-bit code that is used on the code
+	 * path to initialize the .text segment
+	 */
+	. = ALIGN(16);
+	.textnr : {
+		FILL(0x90909090)
+		__textnr_start = .;
+		*(.textnr)
+		__textnr_end = .;
+	}
+	__textnr_len = ABSOLUTE(__textnr_end) - ABSOLUTE(__textnr_start);
+	__textnr_dwords = (__textnr_len + 3) >> 2;
+
+	. = ALIGN(16);
+	__bcopyxx_start = .;
+
+	.bcopyxx.text : {
+		FILL(0x90909090)
+		__bcopyxx_text_start = .;
+		*(.bcopyxx.text)
+		__bcopyxx_text_end = .;
+	}
+	__bcopyxx_text_len = ABSOLUTE(__bcopyxx_text_end) - ABSOLUTE(__bcopyxx_text_start);
+	__bcopyxx_text_dwords = (__bcopyxx_text_len + 3) >> 2;
+
+	.bcopyxx.data : {
+		__bcopyxx_data_start = .;
+		*(.bcopyxx.text)
+		__bcopyxx_data_end = .;
+	}
+	__bcopyxx_data_len = ABSOLUTE(__bcopyxx_data_end) - ABSOLUTE(__bcopyxx_data_start);
+	__bcopyxx_data_dwords = (__bcopyxx_data_len + 3) >> 2;
+
+	__bcopyxx_end = .;
+	__bcopyxx_len = ABSOLUTE(__bcopyxx_end) - ABSOLUTE(__bcopyxx_start);
+	__bcopyxx_dwords = (__bcopyxx_len + 3) >> 2;
+
+	. = ALIGN(4);
+	.data16 : {
+	      __data16_start = .;
+	      *(.data16)
+	      __data16_end = .;
+	}
+	__data16_len = ABSOLUTE(__data16_end) - ABSOLUTE(__data16_start);
+	__data16_dwords = (__data16_len + 3) >> 2;
+
+	. = ALIGN(4);
+	__config_lma = .;
+	. += SIZEOF(.config);
+
+	. = ALIGN(4);
+	__replacestub_lma = .;
+	. += SIZEOF(.replacestub);
+
+	/* The 32-bit code loads above the non-progbits sections */
+
+	. = ALIGN(16);
+	__pm_code_lma = .;
+
+	__high_clear_start = .;
+
+	. = ALIGN(512);
+	.adv (NOLOAD) : {
+		__adv_start = .;
+		*(.adv)
+		__adv_end = .;
+	}
+	__adv_len = ABSOLUTE(__adv_end) - ABSOLUTE(__adv_start);
+	__adv_dwords = (__adv_len + 3) >> 2;
+
+	/* Late uninitialized sections */
+
+	. = ALIGN(4);
+	.uibss (NOLOAD) : {
+		__uibss_start = .;
+		*(.uibss)
+		__uibss_end = .;
+	}
+	__uibss_len = ABSOLUTE(__uibss_end) - ABSOLUTE(__uibss_start);
+	__uibss_dwords = (__uibss_len + 3) >> 2;
+
+	_end16 = .;
+	__assert_end16 = ASSERT(_end16 <= 0x10000, "64K overflow");
+
+	/*
+	 * Special 16-bit segments
+	 */
+
+	. = ALIGN(65536);
+	.real_mode (NOLOAD) : {
+		*(.real_mode)
+	}
+	real_mode_seg = core_real_mode >> 4;
+
+	. = ALIGN(65536);
+	.xfer_buf (NOLOAD) : {
+		*(.xfer_buf)
+	}
+	xfer_buf_seg = core_xfer_buf >> 4;
+
+	/*
+	 * The auxilliary data segment is used by the 16-bit code
+	 * for items that don't need to live in the bottom 64K.
+	 */
+
+	. = ALIGN(16);
+	.auxseg (NOLOAD) : {
+		__auxseg_start = .;
+		*(.auxseg)
+		__auxseg_end = .;
+	}
+	__auxseg_len = ABSOLUTE(__auxseg_end) - ABSOLUTE(__auxseg_start);
+	__auxseg_dwords = (__auxseg_len + 3) >> 2;
+	aux_seg = __auxseg_start >> 4;
+
+	/*
+	 * Used to allocate lowmem buffers from 32-bit code
+	 */
+	.lowmem (NOLOAD) : {
+		__lowmem_start = .;
+		*(.lowmem)
+		__lowmem_end = .;
+	}
+	__lowmem_len = ABSOLUTE(__lowmem_end) - ABSOLUTE(__lowmem_start);
+	__lowmem_dwords = (__lowmem_len + 3) >> 2;
+
+	__high_clear_end = .;
+
+	__high_clear_len = ABSOLUTE(__high_clear_end) - ABSOLUTE(__high_clear_start);
+	__high_clear_dwords = (__high_clear_len + 3) >> 2;
+
+	/* Start of the lowmem heap */
+	. = ALIGN(16);
+	__lowmem_heap = .;
+
+	/*
+	 * 32-bit code.  This is a hack for the moment due to the
+	 * real-mode segments also allocated.
+	 */
+
+	. = 0x100000;
+
+	__pm_code_start = .;
+
+	__text_vma = .;
+	__text_lma = __pm_code_lma;
+	.text : AT(__text_lma) {
+		FILL(0x90909090)
+		__text_start = .;
+		*(.text)
+		*(.text.*)
+		__text_end = .;
+	}
+
+	. = ALIGN(16);
+
+	__rodata_vma = .;
+	__rodata_lma = __rodata_vma + __text_lma - __text_vma;
+	.rodata : AT(__rodata_lma) {
+		__rodata_start = .;
+		*(.rodata)
+		*(.rodata.*)
+		__rodata_end = .;
+	}
+
+	. = ALIGN(4);
+
+	__ctors_vma = .;
+	__ctors_lma = __ctors_vma + __text_lma - __text_vma;
+	.ctors : AT(__ctors_lma) {
+		__ctors_start = .;
+		KEEP (*(SORT(.ctors.*)))
+		KEEP (*(.ctors))
+		__ctors_end = .;
+	}
+
+	__dtors_vma = .;
+	__dtors_lma = __dtors_vma + __text_lma - __text_vma;
+	.dtors : AT(__dtors_lma) {
+		__dtors_start = .;
+		KEEP (*(SORT(.dtors.*)))
+		KEEP (*(.dtors))
+		__dtors_end = .;
+	}
+
+	. = 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) {
+		__dynlink_start = .;
+		*(.dynlink)
+		__dynlink_end = .;
+	}
+
+	. = ALIGN(4);
+
+	__got_vma = .;
+	__got_lma = __got_vma + __text_lma - __text_vma;
+	.got : AT(__got_lma) {
+		__got_start = .;
+		KEEP (*(.got.plt))
+		KEEP (*(.got))
+		__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) {
+		__data_start = .;
+		*(.data)
+		*(.data.*)
+		__data_end = .;
+	}
+
+	__pm_code_end = .;
+	__pm_code_len = ABSOLUTE(__pm_code_end) - ABSOLUTE(__pm_code_start);
+	__pm_code_dwords = (__pm_code_len + 3) >> 2;
+
+	. = ALIGN(128);
+	
+	__bss_vma = .;
+	__bss_lma = .;		/* Dummy */
+	.bss (NOLOAD) : AT (__bss_lma) {
+		__bss_start = .;
+		*(.bss)
+		*(.bss.*)
+		*(COMMON)
+		__bss_end = .;
+	}
+	__bss_len = ABSOLUTE(__bss_end) - ABSOLUTE(__bss_start);
+	__bss_dwords = (__bss_len + 3) >> 2;
+
+	/* Very large objects which don't need to be zeroed */
+
+	__hugebss_vma = .;
+	__hugebss_lma = .;		/* Dummy */
+	.hugebss (NOLOAD) : AT (__hugebss_lma) {
+		__hugebss_start = .;
+		*(.hugebss)
+		*(.hugebss.*)
+		__hugebss_end = .;
+	}
+	__hugebss_len = ABSOLUTE(__hugebss_end) - ABSOLUTE(__hugebss_start);
+	__hugebss_dwords = (__hugebss_len + 3) >> 2;
+
+
+	/* XXX: This stack should be unified with the COM32 stack */
+	__stack_vma = .;
+	__stack_lma = .;	/* Dummy */
+	.stack (NOLOAD) : AT(__stack_lma) {
+		__stack_start = .;
+		*(.stack)
+		__stack_end = .;
+	}
+	__stack_len = ABSOLUTE(__stack_end) - ABSOLUTE(__stack_start);
+	__stack_dwords = (__stack_len + 3) >> 2;
+
+	_end = .;
+
+	/* COM32R and kernels are loaded after our own PM code */
+	. = ALIGN(65536);
+	free_high_memory = .;
+
+	/* Stuff we don't need... */
+	/DISCARD/ : {
+		*(.eh_frame)
+	}
+}
diff --git a/core/include/bios.h b/core/include/bios.h
index 889443a..7bbd274 100644
--- a/core/include/bios.h
+++ b/core/include/bios.h
@@ -56,12 +56,6 @@
 	outb(0x0, IO_DELAY_PORT);
 }
 
-/* conio.c */
-extern unsigned short SerialPort;
-extern unsigned char FlowIgnore;
-extern uint8_t ScrollAttribute;
-extern uint16_t DisplayCon;
-
 /*
  * Sometimes we need to access screen coordinates as separate 8-bit
  * entities and sometimes we need to use them as 16-bit entities. Using
diff --git a/core/include/core.h b/core/include/core.h
index a6ecbc4..aa3bfb7 100644
--- a/core/include/core.h
+++ b/core/include/core.h
@@ -31,7 +31,7 @@
 extern uint8_t KbdMap[256];
 
 extern const uint16_t IPAppends[];
-extern const char numIPAppends[];
+extern size_t numIPAppends;
 
 extern uint16_t SerialPort;
 extern uint16_t BaudDivisor;
@@ -39,6 +39,9 @@
 extern uint8_t FlowInput;
 extern uint8_t FlowIgnore;
 
+extern uint8_t ScrollAttribute;
+extern uint16_t DisplayCon;
+
 /* diskstart.inc isolinux.asm*/
 extern void getlinsec(void);
 
diff --git a/core/include/disk.h b/core/include/disk.h
index ac23e92..0a19e8a 100644
--- a/core/include/disk.h
+++ b/core/include/disk.h
@@ -4,15 +4,21 @@
 #include <stddef.h>
 #include <stdint.h>
 #include <stdbool.h>
+#include <core.h>
 
 typedef uint64_t sector_t;
 typedef uint64_t block_t;
 
+struct bios_disk_private {
+	com32sys_t *regs;
+};
+
 /*
  * struct disk: contains the information about a specific disk and also
  * contains the I/O function.
  */
 struct disk {
+    void *private;	/* Firmware-private disk info */
     unsigned int disk_number;	/* in BIOS style */
     unsigned int sector_size;	/* gener512B or 2048B */
     unsigned int sector_shift;
@@ -31,7 +37,7 @@
 extern void getoneblk(struct disk *, char *, block_t, int);
 
 /* diskio.c */
-struct disk *disk_init(uint8_t, bool, sector_t, uint16_t, uint16_t, uint32_t);
-struct device *device_init(uint8_t, bool, sector_t, uint16_t, uint16_t, uint32_t);
+struct disk *bios_disk_init(void *);
+struct device *device_init(void *);
 
 #endif /* DISK_H */
diff --git a/core/include/fs.h b/core/include/fs.h
index 5c13f5b..560458b 100644
--- a/core/include/fs.h
+++ b/core/include/fs.h
@@ -188,6 +188,7 @@
 extern char *PATH;
 
 /* fs.c */
+void fs_init(const struct fs_ops **ops, void *priv);
 void pm_mangle_name(com32sys_t *);
 void pm_searchdir(com32sys_t *);
 void mangle_name(char *, const char *);
@@ -200,6 +201,8 @@
 void pm_close_file(com32sys_t *);
 int open_config(void);
 
+extern uint16_t SectorShift;
+
 /* chdir.c */
 void pm_realpath(com32sys_t *regs);
 size_t realpath(char *dst, const char *src, size_t bufsize);
diff --git a/core/init.c b/core/init.c
index ab2e271..45a0509 100644
--- a/core/init.c
+++ b/core/init.c
@@ -3,80 +3,10 @@
 #include <sys/io.h>
 #include <fs.h>
 #include <bios.h>
+#include <syslinux/memscan.h>
+#include <syslinux/firmware.h>
 
-static uint32_t min_lowmem_heap = 65536;
-extern char __lowmem_heap[];
-uint8_t KbdFlags;		/* Check for keyboard escapes */
-__export uint8_t KbdMap[256];	/* Keyboard map */
-
-__export uint16_t PXERetry;
-
-static inline void check_escapes(void)
+void init(void)
 {
-	com32sys_t ireg, oreg;
-
-	ireg.eax.b[1] = 0x02;	/* Check keyboard flags */
-	__intcall(0x16, &ireg, &oreg);
-
-	KbdFlags = oreg.eax.b[0];
-
-	/* Ctrl->skip 386 check */
-	if (oreg.eax.b[0] & 0x04) {
-		/*
-		 * Now check that there is sufficient low (DOS) memory
-		 *
-		 * NOTE: Linux doesn't use all of real_mode_seg, but we use
-		 * the same segment for COMBOOT images, which can use all 64K.
-		 */
-		uint16_t mem;
-
-		__intcall(0x12, &ireg, &oreg);
-
-		mem = ((uint32_t)__lowmem_heap) + min_lowmem_heap + 1023;
-		mem = mem >> 10;
-
-		if (mem < oreg.eax.w[0]) {
-			char buf[256];
-
-			snprintf(buf, sizeof(buf),
-				 "It appears your computer has only "
-				 "%dK of low (\"DOS\") RAM.\n"
-				 "This version of Syslinux needs "
-				 "%dK to boot.  "
-				 "If you get this\nmessage in error, "
-				 "hold down the Ctrl key while booting, "
-				 "and I\nwill take your word for it.\n",
-				 oreg.eax.w[0], mem);
-			writestr(buf);
-			kaboom();
-		}
-	}
-}
-
-extern uint32_t BIOS_timer_next;
-extern uint32_t timer_irq;
-static inline void bios_timer_init(void)
-{
-	unsigned long next;
-	uint32_t *hook = (uint32_t *)BIOS_timer_hook;
-
-	next = *hook;
-	BIOS_timer_next = next;
-	*hook = (uint32_t)&timer_irq;
-}
-
-void init(com32sys_t *regs __unused)
-{
-	int i;
-
-	/* Initialize timer */
-	bios_timer_init();
-
-	for (i = 0; i < 256; i++)
-		KbdMap[i] = i;
-
-	adjust_screen();
-
-	/* CPU-dependent initialization and related checks. */
-	check_escapes();
+	firmware->init();
 }
diff --git a/core/init.inc b/core/init.inc
index ae0e631..b74cf30 100644
--- a/core/init.inc
+++ b/core/init.inc
@@ -33,7 +33,9 @@
 		cmp eax,__pm_code_len
 		jne kaboom
 
-		extern init
+		extern syslinux_register_bios, init
+
+		pm_call syslinux_register_bios
 		pm_call init
 
 ;
diff --git a/core/isolinux-c.c b/core/isolinux-c.c
new file mode 100644
index 0000000..bdc7df5
--- /dev/null
+++ b/core/isolinux-c.c
@@ -0,0 +1,22 @@
+#include <syslinux/config.h>
+#include <com32.h>
+#include <fs.h>
+
+extern far_ptr_t OrigESDI;
+extern uint64_t Hidden;
+extern uint16_t BIOSType;
+extern uint16_t bios_cdrom;
+extern uint8_t DriveNumber;
+extern uint8_t spec_packet;
+
+void get_derivative_info(union syslinux_derivative_info *di)
+{
+	di->iso.filesystem = SYSLINUX_FS_ISOLINUX;
+	di->iso.sector_shift = SectorShift;
+	di->iso.drive_number = DriveNumber;
+	di->iso.cd_mode = (BIOSType - bios_cdrom >> 2);
+
+	di->iso.spec_packet = spec_packet;
+	di->iso.esdi_ptr = GET_PTR(OrigESDI);
+	di->iso.partoffset = Hidden;
+}
diff --git a/core/isolinux.asm b/core/isolinux.asm
index b292d8f..b54beb4 100644
--- a/core/isolinux.asm
+++ b/core/isolinux.asm
@@ -79,13 +79,16 @@
 GetlinsecPtr	resw 1			; The sector-read pointer
 BIOSName	resw 1			; Display string for BIOS type
 %define HAVE_BIOSNAME 1
+		global BIOSType
 BIOSType	resw 1
 DiskError	resb 1			; Error code for disk I/O
+		global DriveNumber
 DriveNumber	resb 1			; CD-ROM BIOS drive number
 ISOFlags	resb 1			; Flags for ISO directory search
 RetryCount      resb 1			; Used for disk access retries
 
 		alignb 8
+		global Hidden
 Hidden		resq 1			; Used in hybrid mode
 bsSecPerTrack	resw 1			; Used in hybrid mode
 bsHeads		resw 1			; Used in hybrid mode
@@ -97,6 +100,7 @@
 
 		alignb 8
 _spec_start	equ $
+		global spec_packet
 spec_packet:	resb 1				; Size of packet
 sp_media:	resb 1				; Media type
 sp_drive:	resb 1				; Drive number
@@ -172,6 +176,7 @@
 StackBuf	equ STACK_TOP-44	; 44 bytes needed for
 					; the bootsector chainloading
 					; code!
+		global OrigESDI
 OrigESDI	equ StackBuf-4          ; The high dword on the stack
 StackHome	equ OrigESDI
 
@@ -1096,6 +1101,7 @@
 %endif
 
 		alignz 4
+		global bios_cdrom
 bios_cdrom:	dw getlinsec_cdrom, bios_cdrom_str
 %ifndef DEBUG_MESSAGES
 bios_cbios:	dw getlinsec_cbios, bios_cbios_str
@@ -1171,7 +1177,7 @@
 	        mov ebx,[Hidden+4]
                 mov si,[bsHeads]
 		mov di,[bsSecPerTrack]
-		pm_call fs_init
+		pm_call pm_fs_init
 		pm_call load_env32
 enter_command:
 auto_boot:
diff --git a/core/kaboom.c b/core/kaboom.c
index 310365d..474b8ab 100644
--- a/core/kaboom.c
+++ b/core/kaboom.c
@@ -4,7 +4,7 @@
 
 #include "core.h"
 
-#ifdef DEBUG
+#ifdef CORE_DEBUG
 
 #include <dprintf.h>
 
diff --git a/core/ldlinux-c.c b/core/ldlinux-c.c
new file mode 100644
index 0000000..3d15cef
--- /dev/null
+++ b/core/ldlinux-c.c
@@ -0,0 +1,19 @@
+#include <syslinux/config.h>
+#include <com32.h>
+#include <fs.h>
+
+extern uint8_t DriveNumber;
+extern far_ptr_t PartInfo;
+extern far_ptr_t OrigESDI;
+extern uint64_t Hidden;
+
+void get_derivative_info(union syslinux_derivative_info *di)
+{
+	di->disk.filesystem = SYSLINUX_FS_SYSLINUX;
+	di->disk.sector_shift = SectorShift;
+	di->disk.drive_number = DriveNumber;
+
+	di->disk.ptab_ptr = GET_PTR(PartInfo);
+	di->disk.esdi_ptr = GET_PTR(OrigESDI);
+	di->disk.partoffset = Hidden;
+}
diff --git a/core/lzo/enter.ash b/core/lzo/enter.ash
index c2aa081..dc7782f 100644
--- a/core/lzo/enter.ash
+++ b/core/lzo/enter.ash
@@ -45,12 +45,23 @@
 //
 ************************************************************************/
 
+#if __SIZEOF_POINTER__ == 4
         pushl   %ebp
         pushl   %edi
         pushl   %esi
         pushl   %ebx
         pushl   %ecx
         pushl   %edx
+#elif __SIZEOF_POINTER__ == 8
+        push   %rbp
+        push   %rdi
+        push   %rsi
+        push   %rbx
+        push   %rcx
+        push   %rdx
+#else
+#error "unsupported architecture"
+#endif
         subl    $12,%esp
 
         cld
diff --git a/core/lzo/leave.ash b/core/lzo/leave.ash
index 0fdb729..cc48ce6 100644
--- a/core/lzo/leave.ash
+++ b/core/lzo/leave.ash
@@ -65,12 +65,23 @@
 
         negl    %eax
         addl    $12,%esp
+#if __SIZEOF_POINTER__ == 4
         popl    %edx
         popl    %ecx
         popl    %ebx
         popl    %esi
         popl    %edi
         popl    %ebp
+#elif __SIZEOF_POINTER__ == 8
+        pop    %rdx
+        pop    %rcx
+        pop    %rbx
+        pop    %rsi
+        pop    %rdi
+        pop    %rbp
+#else
+#error "unsupported architecture"
+#endif
 #if 1
         ret
 #else
diff --git a/core/lzo/lzo_asm.h b/core/lzo/lzo_asm.h
index 1188dd6..663ca1a 100644
--- a/core/lzo/lzo_asm.h
+++ b/core/lzo/lzo_asm.h
@@ -45,10 +45,12 @@
 // <asmconfig.h>
 ************************************************************************/
 
+/*support both i386 and x86_64 */
+/*
 #if !defined(__i386__)
 #  error
 #endif
-
+*/
 #if !defined(IN_CONFIGURE)
 #if defined(LZO_HAVE_CONFIG_H)
 #  include <config.h>
diff --git a/core/mem/free.c b/core/mem/free.c
index 9c28e14..6fb8cfd 100644
--- a/core/mem/free.c
+++ b/core/mem/free.c
@@ -4,6 +4,7 @@
  * Very simple linked-list based malloc()/free().
  */
 
+#include <syslinux/firmware.h>
 #include <stdlib.h>
 #include <dprintf.h>
 #include "malloc.h"
@@ -66,15 +67,10 @@
     return ah;
 }
 
-__export void free(void *ptr)
+void bios_free(void *ptr)
 {
     struct free_arena_header *ah;
 
-    dprintf("free(%p) @ %p\n", ptr, __builtin_return_address(0));
-
-    if ( !ptr )
-        return;
-
     ah = (struct free_arena_header *)
         ((struct arena_header *)ptr - 1);
 
@@ -83,6 +79,16 @@
 #endif
 
     __free_block(ah);
+}
+
+__export void free(void *ptr)
+{
+    dprintf("free(%p) @ %p\n", ptr, __builtin_return_address(0));
+
+    if ( !ptr )
+        return;
+
+    firmware->mem->free(ptr);
 
   /* Here we could insert code to return memory to the system. */
 }
diff --git a/core/mem/init.c b/core/mem/init.c
index abfe23a..0526dfb 100644
--- a/core/mem/init.c
+++ b/core/mem/init.c
@@ -64,11 +64,11 @@
 }
 #endif
 
+uint16_t *bios_free_mem;
 void mem_init(void)
 {
 	struct free_arena_header *fp;
 	int i;
-	uint16_t *bios_free_mem = (uint16_t *)0x413;
 
 	//dprintf("enter");
 
diff --git a/core/mem/malloc.c b/core/mem/malloc.c
index 3825f2a..c439dcb 100644
--- a/core/mem/malloc.c
+++ b/core/mem/malloc.c
@@ -4,6 +4,7 @@
  * Very simple linked-list based malloc()/free().
  */
 
+#include <syslinux/firmware.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
@@ -60,15 +61,12 @@
     return (void *)(&fp->a + 1);
 }
 
-static void *_malloc(size_t size, enum heap heap, malloc_tag_t tag)
+void *bios_malloc(size_t size, enum heap heap, malloc_tag_t tag)
 {
     struct free_arena_header *fp;
     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));
-
     if (size) {
 	/* Add the obligatory arena header, and round up */
 	size = (size + 2 * sizeof(struct arena_header) - 1) & ARENA_SIZE_MASK;
@@ -82,6 +80,18 @@
         }
     }
 
+    return p;
+}
+
+static void *_malloc(size_t size, enum heap heap, malloc_tag_t tag)
+{
+    void *p;
+
+    dprintf("_malloc(%zu, %u, %u) @ %p = ",
+	size, heap, tag, __builtin_return_address(0));
+
+    p = firmware->mem->malloc(size, heap, tag);
+
     dprintf("%p\n", p);
     return p;
 }
@@ -106,11 +116,11 @@
     return _malloc(size, HEAP_LOWMEM, MALLOC_MODULE);
 }
 
-__export void *realloc(void *ptr, size_t size)
+void *bios_realloc(void *ptr, size_t size)
 {
     struct free_arena_header *ah, *nah;
     struct free_arena_header *head;
-	
+
     void *newptr;
     size_t newsize, oldsize, xsize;
 
@@ -209,6 +219,11 @@
     }
 }
 
+__export void *realloc(void *ptr, size_t size)
+{
+    return firmware->mem->realloc(ptr, size);
+}
+
 __export void *zalloc(size_t size)
 {
     void *ptr;
diff --git a/core/pxelinux-c.c b/core/pxelinux-c.c
new file mode 100644
index 0000000..a0f0bc8
--- /dev/null
+++ b/core/pxelinux-c.c
@@ -0,0 +1,22 @@
+#include <syslinux/config.h>
+#include <com32.h>
+
+extern far_ptr_t StrucPtr;
+extern far_ptr_t InitStack;
+
+/*
+ * IP information.  Note that the field are in the same order as the
+ * Linux kernel expects in the ip= option.
+ */
+struct syslinux_ipinfo IPInfo;
+uint16_t APIVer;		/* PXE API version found */
+
+void get_derivative_info(union syslinux_derivative_info *di)
+{
+	di->pxe.filesystem = SYSLINUX_FS_PXELINUX;
+	di->pxe.apiver = APIVer;
+	di->pxe.pxenvptr = GET_PTR(StrucPtr);
+	di->pxe.stack = GET_PTR(InitStack);
+	di->pxe.ipinfo = &IPInfo;
+	di->pxe.myip = IPInfo.myip;
+}
diff --git a/core/pxelinux.asm b/core/pxelinux.asm
index a7333ce..841f69f 100644
--- a/core/pxelinux.asm
+++ b/core/pxelinux.asm
@@ -81,10 +81,9 @@
 PXEStack	resd 1			; Saved stack during PXE call
 
 		alignb 4
-                global DHCPMagic, RebootTime, APIVer, BIOSName
+                global DHCPMagic, RebootTime, StrucPtr, BIOSName
 RebootTime	resd 1			; Reboot timeout, if set by option
 StrucPtr	resw 2			; Pointer to PXENV+ or !PXE structure
-APIVer		resw 1			; PXE API version found
 LocalBootType	resw 1			; Local boot return code
 DHCPMagic	resb 1			; PXELINUX magic flags
 BIOSName	resw 1			; Dummy variable - always 0
@@ -176,7 +175,7 @@
 ;
 	        mov eax,ROOT_FS_OPS
 		xor ebp,ebp
-                pm_call fs_init
+                pm_call pm_fs_init
 
 		section .rodata
 		alignz 4
@@ -384,7 +383,7 @@
 		jnz .store_stack
 
 .disable_timer:
-		call timer_cleanup
+		call bios_timer_cleanup
 
 .store_stack:
 		mov [cs:PXEStack],sp
@@ -554,17 +553,3 @@
 		section .data16
                 global KeepPXE
 KeepPXE		db 0			; Should PXE be kept around?
-
-;
-; IP information.  Note that the field are in the same order as the
-; Linux kernel expects in the ip= option.
-;
-		section .bss16
-		alignb 4
-		global IPInfo
-IPInfo:
-.IPv4		resd 1			; IPv4 information
-.MyIP		resd 1			; My IP address 
-.ServerIP	resd 1
-.GatewayIP	resd 1
-.Netmask	resd 1
diff --git a/core/syslinux.ld b/core/syslinux.ld
index f024b92..edd89e8 100644
--- a/core/syslinux.ld
+++ b/core/syslinux.ld
@@ -26,6 +26,7 @@
 {
 	/* Prefix structure for the compression program */
 	. = 0;
+	__module_start = .;
 	.prefix : {
 		*(.prefix)
 	}
diff --git a/core/timer.inc b/core/timer.inc
index 64f81a7..8064798 100644
--- a/core/timer.inc
+++ b/core/timer.inc
@@ -32,8 +32,8 @@
 		mov dword [BIOS_timer_hook],timer_irq
 		ret
 
-		global timer_cleanup:function hidden
-timer_cleanup:
+		global bios_timer_cleanup:function hidden
+bios_timer_cleanup:
 		; Unhook INT 1Ch
 		mov eax,[BIOS_timer_next]
 		mov [BIOS_timer_hook],eax
diff --git a/core/x86_64/syslinux.ld b/core/x86_64/syslinux.ld
new file mode 100644
index 0000000..1057112
--- /dev/null
+++ b/core/x86_64/syslinux.ld
@@ -0,0 +1,428 @@
+/* -----------------------------------------------------------------------
+ *   
+ *   Copyright 2008-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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Linker script for the SYSLINUX core
+ */
+
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+OUTPUT_ARCH(i386:x86-64)
+EXTERN(_start)
+ENTRY(_start)
+
+STACK32_LEN = 65536;
+
+SECTIONS
+{
+	/* Prefix structure for the compression program */
+	. = 0;
+	__module_start = .;
+	.prefix : {
+		*(.prefix)
+	}
+
+	/* "Early" sections (before the load) */
+	. = 0x1000;
+
+	.earlybss (NOLOAD) : {
+		__earlybss_start = .;
+		*(.earlybss)
+		__earlybss_end = .;
+	}
+	__earlybss_len = ABSOLUTE(__earlybss_end) - ABSOLUTE(__earlybss_start);
+	__earlybss_dwords = (__earlybss_len + 3) >> 2;
+
+	. = ALIGN(4);
+	.bss16 (NOLOAD) : {
+		__bss16_start = .;
+		*(.bss16)
+		__bss16_end = .;
+	}
+	__bss16_len = ABSOLUTE(__bss16_end) - ABSOLUTE(__bss16_start);
+	__bss16_dwords = (__bss16_len + 3) >> 2;
+
+	. = ALIGN(4);
+ 	.config : AT (__config_lma) {
+		__config_start = .;
+		*(.config)
+		__config_end = .;
+	}
+	__config_len = ABSOLUTE(__config_end) - ABSOLUTE(__config_start);
+	__config_dwords = (__config_len + 3) >> 2;
+
+	/* Generated and/or copied code */
+
+	. = ALIGN(128);		/* Minimum separation from mutable data */
+ 	.replacestub : AT (__replacestub_lma) {
+		__replacestub_start = .;
+		*(.replacestub)
+		__replacestub_end = .;
+	}
+	__replacestub_len = ABSOLUTE(__replacestub_end) - ABSOLUTE(__replacestub_start);
+	__replacestub_dwords = (__replacestub_len + 3) >> 2;
+
+	. = ALIGN(16);
+	__gentextnr_lma = .;
+	.gentextnr : AT(__gentextnr_lma) {
+		__gentextnr_start = .;
+		*(.gentextnr)
+		__gentextnr_end = .;
+	}
+	__gentextnr_len = ABSOLUTE(__gentextnr_end) - ABSOLUTE(__gentextnr_start);
+	__gentextnr_dwords = (__gentextnr_len + 3) >> 2;
+
+	. = STACK_BASE;
+	.stack16 : AT(STACK_BASE) {
+		__stack16_start = .;
+		. += STACK_LEN;
+		__stack16_end = .;
+	}
+	__stack16_len = ABSOLUTE(__stack16_end) - ABSOLUTE(__stack16_start);
+	__stack16_dwords = (__stack16_len + 3) >> 2;
+
+	/* Initialized sections */
+
+	. = 0x7c00;
+	.init : {
+		FILL(0x90909090)
+		__init_start = .;
+		*(.init)
+		__init_end = .;
+	}
+	__init_len = ABSOLUTE(__init_end) - ABSOLUTE(__init_start);
+	__init_dwords = (__init_len + 3) >> 2;
+
+	.text16 : {
+		FILL(0x90909090)
+		__text16_start = .;
+		*(.text16)
+		__text16_end = .;
+	}
+	__text16_len = ABSOLUTE(__text16_end) - ABSOLUTE(__text16_start);
+	__text16_dwords = (__text16_len + 3) >> 2;
+
+	/*
+	 * .textnr is used for 32-bit code that is used on the code
+	 * path to initialize the .text segment
+	 */
+	. = ALIGN(16);
+	.textnr : {
+		FILL(0x90909090)
+		__textnr_start = .;
+		*(.textnr)
+		__textnr_end = .;
+	}
+	__textnr_len = ABSOLUTE(__textnr_end) - ABSOLUTE(__textnr_start);
+	__textnr_dwords = (__textnr_len + 3) >> 2;
+
+	. = ALIGN(16);
+	__bcopyxx_start = .;
+
+	.bcopyxx.text : {
+		FILL(0x90909090)
+		__bcopyxx_text_start = .;
+		*(.bcopyxx.text)
+		__bcopyxx_text_end = .;
+	}
+	__bcopyxx_text_len = ABSOLUTE(__bcopyxx_text_end) - ABSOLUTE(__bcopyxx_text_start);
+	__bcopyxx_text_dwords = (__bcopyxx_text_len + 3) >> 2;
+
+	.bcopyxx.data : {
+		__bcopyxx_data_start = .;
+		*(.bcopyxx.text)
+		__bcopyxx_data_end = .;
+	}
+	__bcopyxx_data_len = ABSOLUTE(__bcopyxx_data_end) - ABSOLUTE(__bcopyxx_data_start);
+	__bcopyxx_data_dwords = (__bcopyxx_data_len + 3) >> 2;
+
+	__bcopyxx_end = .;
+	__bcopyxx_len = ABSOLUTE(__bcopyxx_end) - ABSOLUTE(__bcopyxx_start);
+	__bcopyxx_dwords = (__bcopyxx_len + 3) >> 2;
+
+	. = ALIGN(4);
+	.data16 : {
+	      __data16_start = .;
+	      *(.data16)
+	      __data16_end = .;
+	}
+	__data16_len = ABSOLUTE(__data16_end) - ABSOLUTE(__data16_start);
+	__data16_dwords = (__data16_len + 3) >> 2;
+
+	. = ALIGN(4);
+	__config_lma = .;
+	. += SIZEOF(.config);
+
+	. = ALIGN(4);
+	__replacestub_lma = .;
+	. += SIZEOF(.replacestub);
+
+	/* The 32-bit code loads above the non-progbits sections */
+
+	. = ALIGN(16);
+	__pm_code_lma = .;
+
+	__high_clear_start = .;
+
+	. = ALIGN(512);
+	.adv (NOLOAD) : {
+		__adv_start = .;
+		*(.adv)
+		__adv_end = .;
+	}
+	__adv_len = ABSOLUTE(__adv_end) - ABSOLUTE(__adv_start);
+	__adv_dwords = (__adv_len + 3) >> 2;
+
+	/* Late uninitialized sections */
+
+	. = ALIGN(4);
+	.uibss (NOLOAD) : {
+		__uibss_start = .;
+		*(.uibss)
+		__uibss_end = .;
+	}
+	__uibss_len = ABSOLUTE(__uibss_end) - ABSOLUTE(__uibss_start);
+	__uibss_dwords = (__uibss_len + 3) >> 2;
+
+	_end16 = .;
+	__assert_end16 = ASSERT(_end16 <= 0x10000, "64K overflow");
+
+	/*
+	 * Special 16-bit segments
+	 */
+
+	. = ALIGN(65536);
+	.real_mode (NOLOAD) : {
+		*(.real_mode)
+	}
+	real_mode_seg = core_real_mode >> 4;
+
+	. = ALIGN(65536);
+	.xfer_buf (NOLOAD) : {
+		*(.xfer_buf)
+	}
+	xfer_buf_seg = core_xfer_buf >> 4;
+
+	/*
+	 * The auxilliary data segment is used by the 16-bit code
+	 * for items that don't need to live in the bottom 64K.
+	 */
+
+	. = ALIGN(16);
+	.auxseg (NOLOAD) : {
+		__auxseg_start = .;
+		*(.auxseg)
+		__auxseg_end = .;
+	}
+	__auxseg_len = ABSOLUTE(__auxseg_end) - ABSOLUTE(__auxseg_start);
+	__auxseg_dwords = (__auxseg_len + 3) >> 2;
+	aux_seg = __auxseg_start >> 4;
+
+	/*
+	 * Used to allocate lowmem buffers from 32-bit code
+	 */
+	.lowmem (NOLOAD) : {
+		__lowmem_start = .;
+		*(.lowmem)
+		__lowmem_end = .;
+	}
+	__lowmem_len = ABSOLUTE(__lowmem_end) - ABSOLUTE(__lowmem_start);
+	__lowmem_dwords = (__lowmem_len + 3) >> 2;
+
+	__high_clear_end = .;
+
+	__high_clear_len = ABSOLUTE(__high_clear_end) - ABSOLUTE(__high_clear_start);
+	__high_clear_dwords = (__high_clear_len + 3) >> 2;
+
+	/* Start of the lowmem heap */
+	. = ALIGN(16);
+	__lowmem_heap = .;
+
+	/*
+	 * 32-bit code.  This is a hack for the moment due to the
+	 * real-mode segments also allocated.
+	 */
+
+	. = 0x100000;
+
+	__pm_code_start = .;
+
+	__text_vma = .;
+	__text_lma = __pm_code_lma;
+	.text : AT(__text_lma) {
+		FILL(0x90909090)
+		__text_start = .;
+		*(.text)
+		*(.text.*)
+		__text_end = .;
+	}
+
+	. = ALIGN(16);
+
+	__rodata_vma = .;
+	__rodata_lma = __rodata_vma + __text_lma - __text_vma;
+	.rodata : AT(__rodata_lma) {
+		__rodata_start = .;
+		*(.rodata)
+		*(.rodata.*)
+		__rodata_end = .;
+	}
+
+	. = ALIGN(4);
+
+	__ctors_vma = .;
+	__ctors_lma = __ctors_vma + __text_lma - __text_vma;
+	.ctors : AT(__ctors_lma) {
+		__ctors_start = .;
+		KEEP (*(SORT(.ctors.*)))
+		KEEP (*(.ctors))
+		__ctors_end = .;
+	}
+
+	__dtors_vma = .;
+	__dtors_lma = __dtors_vma + __text_lma - __text_vma;
+	.dtors : AT(__dtors_lma) {
+		__dtors_start = .;
+		KEEP (*(SORT(.dtors.*)))
+		KEEP (*(.dtors))
+		__dtors_end = .;
+	}
+
+	. = 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) {
+		__dynlink_start = .;
+		*(.dynlink)
+		__dynlink_end = .;
+	}
+
+	. = ALIGN(4);
+
+	__got_vma = .;
+	__got_lma = __got_vma + __text_lma - __text_vma;
+	.got : AT(__got_lma) {
+		__got_start = .;
+		KEEP (*(.got.plt))
+		KEEP (*(.got))
+		__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) {
+		__data_start = .;
+		*(.data)
+		*(.data.*)
+		__data_end = .;
+	}
+
+	__pm_code_end = .;
+	__pm_code_len = ABSOLUTE(__pm_code_end) - ABSOLUTE(__pm_code_start);
+	__pm_code_dwords = (__pm_code_len + 3) >> 2;
+
+	. = ALIGN(128);
+	
+	__bss_vma = .;
+	__bss_lma = .;		/* Dummy */
+	.bss (NOLOAD) : AT (__bss_lma) {
+		__bss_start = .;
+		*(.bss)
+		*(.bss.*)
+		*(COMMON)
+		__bss_end = .;
+	}
+	__bss_len = ABSOLUTE(__bss_end) - ABSOLUTE(__bss_start);
+	__bss_dwords = (__bss_len + 3) >> 2;
+
+	/* Very large objects which don't need to be zeroed */
+
+	__hugebss_vma = .;
+	__hugebss_lma = .;		/* Dummy */
+	.hugebss (NOLOAD) : AT (__hugebss_lma) {
+		__hugebss_start = .;
+		*(.hugebss)
+		*(.hugebss.*)
+		__hugebss_end = .;
+	}
+	__hugebss_len = ABSOLUTE(__hugebss_end) - ABSOLUTE(__hugebss_start);
+	__hugebss_dwords = (__hugebss_len + 3) >> 2;
+
+
+	/* XXX: This stack should be unified with the COM32 stack */
+	__stack_vma = .;
+	__stack_lma = .;	/* Dummy */
+	.stack (NOLOAD) : AT(__stack_lma) {
+		__stack_start = .;
+		*(.stack)
+		__stack_end = .;
+	}
+	__stack_len = ABSOLUTE(__stack_end) - ABSOLUTE(__stack_start);
+	__stack_dwords = (__stack_len + 3) >> 2;
+
+	_end = .;
+
+	/* COM32R and kernels are loaded after our own PM code */
+	. = ALIGN(65536);
+	free_high_memory = .;
+
+	/* Stuff we don't need... */
+	/DISCARD/ : {
+		*(.eh_frame)
+	}
+}
diff --git a/diag/Makefile b/diag/Makefile
index 969acbb..e335375 100644
--- a/diag/Makefile
+++ b/diag/Makefile
@@ -1,4 +1,7 @@
 SUBDIRS = mbr geodsp
 
 all tidy dist clean spotless install:
-	set -e; for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done
+	@mkdir -p $(addprefix $(OBJ)/,$(SUBDIRS))
+	set -e; for d in $(SUBDIRS); \
+		do $(MAKE) -C $(OBJ)/$$d -f $(SRC)/$$d/Makefile \
+		SRC="$(SRC)"/$$d OBJ="$(OBJ)"/$$d $@; done
diff --git a/diag/geodsp/Makefile b/diag/geodsp/Makefile
index 91225b1..2fd05c9 100644
--- a/diag/geodsp/Makefile
+++ b/diag/geodsp/Makefile
@@ -18,15 +18,14 @@
 # Makefile for the SYSLINUX geometry display for diagnostics
 #
 
-topdir = ../..
-MAKEDIR = $(topdir)/mk
 include $(MAKEDIR)/embedded.mk
 coredir = $(topdir)/core
+VPATH = $(SRC)
 
 BTARGET = geodsp1s.bin geodspms.bin \
 	geodsp1s.img.xz geodspms.img.xz
 
-NASMOPT = -i $(coredir)/ -Ox -f bin -dBINFMT
+NASMOPT = -i $(coredir)/ -i $(SRC)/ -Ox -f bin -dBINFMT
 NASMOPT += -w+orphan-labels
 CFLAGS = -g -O
 
@@ -34,10 +33,10 @@
 
 # Higher compression levels result in larger files
 %.img.xz: %.bin mk-lba-img.pl
-	$(PERL) mk-lba-img $< | $(XZ) -0 > $@ || ( rm -f $@ ; false )
+	$(PERL) $(SRC)/mk-lba-img $< | $(XZ) -0 > $@ || ( rm -f $@ ; false )
 
 %.img.gz: %.bin mk-lba-img.pl
-	$(PERL) mk-lba-img $< | $(GZIPPROG) -9 > $@ || ( rm -f $@ ; false )
+	$(PERL) $(SRC)/mk-lba-img $< | $(GZIPPROG) -9 > $@ || ( rm -f $@ ; false )
 
 # in case someone really wants these without needing a decompressor
 %.img: %.bin mk-lba-img.pl
diff --git a/diag/mbr/Makefile b/diag/mbr/Makefile
index 79ff9f0..5b7153c 100644
--- a/diag/mbr/Makefile
+++ b/diag/mbr/Makefile
@@ -15,10 +15,9 @@
 # Makefile for MBR
 #
 
-topdir = ../..
 mbrdir = $(topdir)/mbr
-MAKEDIR = $(topdir)/mk
 include $(MAKEDIR)/embedded.mk
+VPATH = $(SRC)
 
 all:	handoff.bin
 
@@ -27,7 +26,7 @@
 
 .PRECIOUS: %.elf
 %.elf: %.o $(mbrdir)/mbr.ld
-	$(LD) $(LDFLAGS) -T $(mbrdir)/mbr.ld -e _start -o $@ $<
+	$(LD) $(LDFLAGS) -T $(mbrdir)/$(ARCH)/mbr.ld -e _start -o $@ $<
 
 %.bin: %.elf $(mbrdir)/checksize.pl
 	$(OBJCOPY) -O binary $< $@
diff --git a/doc/building.txt b/doc/building.txt
new file mode 100644
index 0000000..d0f5068
--- /dev/null
+++ b/doc/building.txt
@@ -0,0 +1,40 @@
+			Building Syslinux
+
+From Syslinux 6.0 onwards there is support for three different
+firmware backends, BIOS, 32-bit EFI and 64-bit EFI. To allow users the
+flexibility to build only the firmware they need the Syslinux make
+infrastructure has become more complex.
+
+The Syslinux make infrastructure understands the following syntax,
+
+	make [firmware[,firwmware]] [target[,target]]
+
+If no firmware is specified then any targets will be applied to all
+three firmware backends. If no target is specified then the 'all'
+target is implicitly built.
+
+For example, to build the installers for BIOS, 32-bit EFI and 64-bit
+EFI type,
+
+	make installer
+
+TO build the BIOS and 64-bit EFI installers type,
+
+	make bios efi64 installer
+
+To delete all object files and build the installer for 32-bit EFI
+type,
+
+	make efi32 spotless installer
+
+
+      ++++ THE OBJECT DIRECTORY ++++
+
+A custom top-level object directory can be specified on the make
+command-line by using the O= variable, e.g.
+
+	make O=/tmp/syslinux-obj efi32
+
+will build the 32-bit object files under /tmp/syslinux-obj/efi32. If
+no object directory is specified then object files will be written to
+an 'obj' directory in the top-level of the Syslinux source.
diff --git a/dos/Makefile b/dos/Makefile
index f942008..6cf81b7 100644
--- a/dos/Makefile
+++ b/dos/Makefile
@@ -14,17 +14,17 @@
 ## MS-DOS FAT installer
 ##
 
-topdir = ..
-MAKEDIR = $(topdir)/mk
 include $(MAKEDIR)/embedded.mk
 
-CFLAGS	+= -D__MSDOS__
+CFLAGS	+= -D__MSDOS__ -mregparm=3 -DREGPARM=3
 # CFLAGS  += -DDEBUG
 
-LDFLAGS	 = -T dosexe.ld
+LDFLAGS	 = -T $(SRC)/dosexe.ld
 OPTFLAGS = -g
 INCLUDES = -include code16.h -nostdinc -iwithprefix include \
-	   -I. -I.. -I../libfat -I ../libinstaller -I ../libinstaller/getopt
+	   -I$(SRC) -I$(SRC)/.. -I$(SRC)/../libfat \
+	   -I $(SRC)/../libinstaller -I $(SRC)/../libinstaller/getopt \
+	   -I$(objdir)
 
 SRCS     = syslinux.c \
 	   ../libinstaller/fs.c \
@@ -34,14 +34,14 @@
 	   ../libinstaller/getopt/getopt_long.c \
 	   ../libinstaller/bootsect_bin.c \
 	   ../libinstaller/mbr_bin.c \
-           $(wildcard ../libfat/*.c)
+           $(wildcard $(SRC)/../libfat/*.c)
 OBJS	 = header.o crt0.o ldlinux.o \
 	   $(patsubst %.c,%.o,$(notdir $(SRCS)))
 LIBOBJS	 = int2526.o conio.o memcpy.o memset.o memmove.o skipatou.o atou.o \
 	   malloc.o free.o getopt_long.o getsetsl.o strchr.o strtoul.o \
 	   strntoumax.o argv.o printf.o __divdi3.o __udivmoddi4.o
 
-VPATH = .:../libfat:../libinstaller:../libinstaller/getopt
+VPATH = $(SRC):$(SRC)/../libfat:$(SRC)/../libinstaller:$(SRC)/../libinstaller/getopt:$(OBJ)/../libinstaller
 
 TARGETS = syslinux.com
 
@@ -74,6 +74,6 @@
 %.com: %.asm
 	$(NASM) $(NASMOPT) -f bin -o $@ -MP -MD .$@.d -l $*.lst $<
 
-ldlinux.o: ldlinux.S ../core/ldlinux.sys
+ldlinux.o: ldlinux.S $(OBJ)/../core/ldlinux.sys
 
 -include .*.d *.tmp
diff --git a/dos/stdlib.h b/dos/stdlib.h
index d346705..d982670 100644
--- a/dos/stdlib.h
+++ b/dos/stdlib.h
@@ -2,7 +2,14 @@
 #define STDLIB_H
 
 typedef int ssize_t;
+/* size_t is defined elsewhere */
+#if __SIZEOF_POINTER__ == 4
 typedef unsigned int size_t;
+#elif __SIZEOF_POINTER__ == 8
+typedef unsigned long size_t;
+#else
+#error "unsupported architecture"
+#endif
 
 void __attribute__ ((noreturn)) exit(int);
 
diff --git a/dosutil/Makefile b/dosutil/Makefile
index 6bce624..9dc88d1 100644
--- a/dosutil/Makefile
+++ b/dosutil/Makefile
@@ -1,8 +1,7 @@
 #
 # OpenWatcom compile and link utility
 #
-topdir = ..
-MAKEDIR = $(topdir)/mk
+VPATH = $(SRC)
 include $(MAKEDIR)/syslinux.mk
 
 WCL	= wcl
@@ -15,6 +14,8 @@
 
 WCTARGETS = mdiskchk.com
 NSTARGETS = eltorito.sys copybs.com
+WCOBJS    = $(addprefix $(SRC)/,$(WCTARGETS))
+NSOBJS    = $(addprefix $(OBJ)/,$(NSTARGETS))
 TARGETS   = $(WCTARGETS) $(NSTARGETS)
 
 %.obj: %.c
@@ -58,4 +59,5 @@
 
 install: installer
 	mkdir -m 755 -p $(INSTALLROOT)$(AUXDIR)/dosutil
-	install -m 644 $(TARGETS) $(INSTALLROOT)$(AUXDIR)/dosutil
+	install -m 644 $(WCOBJS) $(INSTALLROOT)$(AUXDIR)/dosutil
+	install -m 644 $(NSOBJS) $(INSTALLROOT)$(AUXDIR)/dosutil
diff --git a/efi/Makefile b/efi/Makefile
new file mode 100644
index 0000000..11ea9c2
--- /dev/null
+++ b/efi/Makefile
@@ -0,0 +1,73 @@
+## -----------------------------------------------------------------------
+##
+##   Copyright 2011 Intel Corporation; author: Matt Fleming
+##
+##   This program is free software; you can redistribute it and/or modify
+##   it under the terms of the GNU General Public License as published by
+##   the Free Software Foundation, Inc., 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.
+##
+## -----------------------------------------------------------------------
+
+VPATH = $(SRC)
+include $(MAKEDIR)/lib.mk
+include $(MAKEDIR)/efi.mk
+
+CORE_CSRC := $(wildcard $(core)/*.c $(core)/*/*.c $(core)/*/*/*.c)
+CORE_COBJ := $(subst $(core),$(OBJ)/../core/,$(patsubst %.c,%.o,$(CORE_CSRC)))
+
+# Don't include console objects
+CORE_OBJS = $(filter-out %hello.o %rawcon.o %plaincon.o %strcasecmp.o %bios.o \
+	%diskio_bios.o %ldlinux-c.o %isolinux-c.o %pxelinux-c.o,$(CORE_COBJ))
+
+LIB_OBJS = $(addprefix $(objdir)/com32/lib/,$(CORELIBOBJS))
+
+CSRC = $(wildcard $(SRC)/*.c)
+OBJS = $(subst $(SRC)/,,$(filter-out %wrapper.o, $(patsubst %.c,%.o,$(CSRC))))
+
+OBJS += $(objdir)/core/codepage.o
+
+# The targets to build in this directory
+BTARGET  = syslinux.efi
+
+syslinux.so: $(OBJS) $(CORE_OBJS) $(LIB_OBJS)
+	$(LD) $(LDFLAGS) -o $@ $^ -lgnuefi -lefi
+
+# We need to rename the .hash section because the EFI firmware
+# linker really doesn't like it.
+# $(OBJCOPY) --rename-section .gnu.hash=.sdata,load,data,alloc $^ $@
+#syslinux.so: syslinux1.so
+#	cp $^ $@
+
+wrapper: wrapper.c
+	$(CC) $^ -o $@
+
+#
+# Build the wrapper app and wrap our .so to produce a .efi
+syslinux.efi: syslinux.so wrapper
+	$(OBJ)/wrapper syslinux.so $@
+
+all: $(BTARGET)
+
+codepage.o: ../codepage/cp865.cp
+	cp $(objdir)/../codepage/cp865.cp codepage.cp
+	$(CC) $(SFLAGS) -c -o $@ $(core)/codepage.S
+
+installer: syslinux.efi
+
+install: all
+	mkdir -m 755 -p $(INSTALLROOT)$(AUXDIR)/efi$(BITS)
+	install -m 755 $(BTARGET) $(INSTALLROOT)$(AUXDIR)/efi$(BITS)
+
+strip:
+
+tidy dist:
+	rm -f *.so *.o wrapper
+	find . \( -name \*.o -o -name \*.a -o -name .\*.d -o -name \*.tmp \) -print0 | \
+		xargs -0r rm -f
+
+clean: tidy
+
+spotless: clean
+	rm -f $(BTARGET)
diff --git a/efi/adv.c b/efi/adv.c
new file mode 100644
index 0000000..3dec3cc
--- /dev/null
+++ b/efi/adv.c
@@ -0,0 +1,362 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2012 Intel Corporation; author: H. Peter Anvin
+ *   Chandramouli Narayanan
+ *
+ *   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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * adv.c
+ *
+ * Core ADV I/O
+ * Code consolidated from libinstaller/adv*.c and core/adv.inc with the
+ * addition of EFI support
+ *
+ * Return 0 on success, -1 on error, and set errno.
+ *
+ */
+#define  _GNU_SOURCE
+
+#include "adv.h"
+
+#define IS_SYSLINUX	/* remove this: test build only */
+
+unsigned char syslinux_adv[2 * ADV_SIZE];
+
+static void cleanup_adv(unsigned char *advbuf)
+{
+    int i;
+    uint32_t csum;
+
+    /* Make sure both copies agree, and update the checksum */
+    *(uint32_t *)advbuf =  ADV_MAGIC1;
+
+    csum = ADV_MAGIC2;
+    for (i = 8; i < ADV_SIZE - 4; i += 4)
+	csum -= *(uint32_t *)(advbuf + i);
+
+    *(uint32_t *)(advbuf + 4) =  csum;
+    *(uint32_t *)(advbuf + ADV_SIZE - 4) =  ADV_MAGIC3;
+
+    memcpy(advbuf + ADV_SIZE, advbuf, ADV_SIZE);
+}
+
+void syslinux_reset_adv(unsigned char *advbuf)
+{
+    /* Create an all-zero ADV */
+    memset(advbuf + 2 * 4, 0, ADV_LEN);
+    cleanup_adv(advbuf);
+}
+
+static int adv_consistent(const unsigned char *p)
+{
+    int i;
+    uint32_t csum;
+
+    if (*(uint32_t *)p != ADV_MAGIC1 ||
+	*(uint32_t *)(p + ADV_SIZE - 4) != ADV_MAGIC3)
+	return 0;
+
+    csum = 0;
+    for (i = 4; i < ADV_SIZE - 4; i += 4)
+	csum += *(uint32_t *)(p + i);
+
+    return csum == ADV_MAGIC2;
+}
+
+/*
+ * Verify that an in-memory ADV is consistent, making the copies consistent.
+ * If neither copy is OK, return -1 and call syslinux_reset_adv().
+ */
+int syslinux_validate_adv(unsigned char *advbuf)
+{
+    if (adv_consistent(advbuf + 0 * ADV_SIZE)) {
+	memcpy(advbuf + ADV_SIZE, advbuf, ADV_SIZE);
+	return 0;
+    } else if (adv_consistent(advbuf + 1 * ADV_SIZE)) {
+	memcpy(advbuf, advbuf + ADV_SIZE, ADV_SIZE);
+	return 0;
+    } else {
+	syslinux_reset_adv(advbuf);
+	return -1;
+    }
+}
+
+/*
+ * Read the ADV from an existing instance, or initialize if invalid.
+ * Returns -1 on fatal errors, 0 if ADV is okay, 1 if the ADV is
+ * invalid, and 2 if the file does not exist.
+ */
+
+/* make_filespec
+ * Take the ASCII pathname and filename and concatenate them
+ * into an allocated memory space as unicode file specification string.
+ * The path and cfg ASCII strings are assumed to be null-terminated.
+ * For EFI, the separation character in the path name is '\'
+ * and therefore it is assumed that the file spec uses '\' as separation char
+ *
+ * The function returns
+ * 	 0  if successful and fspec is a valid allocated CHAR16 pointer
+ * 	    Caller is responsible to free up the allocated filespec string
+ * 	-1  otherwise
+ *
+ */
+static int make_filespec(CHAR16 **fspec, const char *path, const char *cfg)
+{
+	CHAR16 *p;
+	int size, append;
+
+	/* allocate size for a CHAR16 string */
+	size = sizeof(CHAR16) * (strlena((CHAR8 *)path)+strlena((CHAR8 *)cfg)+2);	/* including null */
+	*fspec = malloc(size);
+	if (!*fspec) return -1;
+
+	append = path[strlena((CHAR8 *)path) - 1] != '\\';
+	for (p = *fspec; *path; path++, p++)
+		*p = (CHAR16)*path;
+	/* append the separation character to the path if need be */
+	if (append) *p++ = (CHAR16)'\\';
+	for (; *cfg; cfg++, p++)
+		*p = (CHAR16)*cfg;
+	*p = (CHAR16)CHAR_NULL;
+
+	return 0;
+}
+
+
+/* TODO:
+ * set_attributes() and clear_attributes() are supported for VFAT only
+ */
+int read_adv(const char *path, const char *cfg)
+{
+    CHAR16 *file;
+    EFI_FILE_HANDLE fd;
+    EFI_FILE_INFO st;
+    int err = 0;
+    int rv;
+
+    rv = make_filespec(&file, path, cfg);
+    if (rv < 0 || !file) {
+	efi_perror(L"read_adv");
+	return -1;
+    }
+
+    /* TBD: Not sure if EFI accepts the attribute read only
+     * even if an existing file is opened for read access
+     */
+    fd = efi_open(file, EFI_FILE_MODE_READ);
+    if (!fd) {
+	if (efi_errno != EFI_NOT_FOUND) {
+	    err = -1;
+	} else {
+	    syslinux_reset_adv(syslinux_adv);
+	    err = 2;		/* Nonexistence is not a fatal error */
+	}
+    } else if (!efi_fstat(fd, &st)) {
+	err = -1;
+    } else if (st.FileSize < 2 * ADV_SIZE) {
+	/* Too small to be useful */
+	syslinux_reset_adv(syslinux_adv);
+	err = 0;		/* Nothing to read... */
+    } else if (efi_xpread(fd, syslinux_adv, 2 * ADV_SIZE,
+		      st.FileSize - 2 * ADV_SIZE) != 2 * ADV_SIZE) {
+	err = -1;
+    } else {
+	/* We got it... maybe? */
+	err = syslinux_validate_adv(syslinux_adv) ? 1 : 0;
+    }
+
+    if (err < 0)
+	efi_perror(file);
+    if (fd)
+	efi_close(fd);
+    free(file);
+
+    return err;
+}
+
+/* For EFI platform, initialize ADV by opening ldlinux.sys or extlinux.sys
+ * as configured and return the primary (adv0) and alternate (adv1)
+ * data into caller's buffer. File remains open for subsequent
+ * operations. This routine is to be called from comboot
+ * vector. Currently only IS_SYSLINUX or IS_EXTLINUX is supported
+ *
+ * TODO:
+ * 1. Need to set the path to ldlinux.sys or extlinux.sys; currently null
+ * 2. What if there are errors?
+ */
+void efi_adv_init(void)
+{
+    char *name;
+    int rv;
+    int err = 0;
+    unsigned char *advbuf = syslinux_adv;
+    EFI_FILE_HANDLE	fd;	/* handle to ldlinux.sys or extlinux.sys */
+    CHAR16 *file;
+    EFI_FILE_INFO st, xst;
+
+#if defined IS_SYSLINUX
+    name = SYSLINUX_FILE;
+#elif defined IS_EXTLINUX
+    name = EXTLINUX_FILE;
+#else
+	#error "IS_SYSLINUX or IS_EXTLINUX must be specified to build ADV"
+#endif
+	/* FIXME: No path defined to syslinux/extlinux file */
+    rv = make_filespec(&file, "", name);
+    if (rv < 0 || !file) {
+	efi_errno = EFI_OUT_OF_RESOURCES;
+	efi_perror(L"efi_adv_init:");
+	return;
+    }
+
+    fd = efi_open(file, EFI_FILE_MODE_READ);
+    if (fd == (EFI_FILE_HANDLE)NULL) {
+	err = -1;
+	efi_printerr(L"efi_adv_init: Unable to open file %s\n", file);
+    } else if (efi_fstat(fd, &st)) {
+	err = -1;
+	efi_printerr(L"efi_adv_init: Unable to get info for file %s\n", file);
+    } else if (st.FileSize < 2 * ADV_SIZE) {
+	/* Too small to be useful */
+	err = -2;
+	efi_printerr(L"efi_adv_init: File %s size too small to be useful %s\n", file);
+    } else if (efi_xpread(fd, advbuf, 2 * ADV_SIZE,
+		      st.FileSize - 2 * ADV_SIZE) != 2 * ADV_SIZE) {
+	err = -1;
+	efi_printerr(L"efi_adv_init: Error reading ADV data from file %s\n", file);
+    } else {
+	/* We got it... maybe? */
+	__syslinux_adv_ptr = &syslinux_adv[8]; /* skip head, csum */
+	__syslinux_adv_size = ADV_LEN;
+
+	err = syslinux_validate_adv(advbuf) ? -2 : 0;
+	if (!err) {
+	    /* Got a good one*/
+	    efi_clear_attributes(fd);
+
+	    /* Need to re-open read-write */
+	    efi_close(fd);
+		/* There is no SYNC attribute with EFI open */
+	    fd = efi_open(file, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE);
+		/* on error, only explicit comparison with null handle works */
+	    if (fd == (EFI_FILE_HANDLE)NULL) {
+		err = -1;
+		efi_perror(L"efi_adv_init:");
+	    } else if (efi_fstat(fd, &xst) || xst.FileSize != st.FileSize) {
+			/* device/inode info don't exist in the EFI file info structure */
+		efi_perror(L"efi_adv_init: file status error/mismatch");
+		err = -2;
+	    }
+		/* TODO: Do we need to set attributes of the sys file? */
+	}
+     }
+     if (file)
+	free(file);
+     if (fd != 0)
+	efi_close(fd);
+	/* TODO: In case of errors, we could set efi_errno to EFI_LOAD_ERROR
+	 * to mean that ADV could not be loaded up
+	 */
+}
+
+/* For EFI platform, write 2 * ADV_SIZE data to the file opened
+ * at ADV initialization. (i.e ldlinux.sys or extlinux.sys).
+ *
+ * TODO:
+ * 1. Validate assumption: write back to file from __syslinux_adv_ptr
+ * 2. What if there errors?
+ * 3. Do we need to set the attributes of the sys file?
+ *
+ */
+int efi_adv_write(void)
+{
+    char *name;
+    unsigned char advtmp[2 * ADV_SIZE];
+    unsigned char *advbuf = syslinux_adv;
+    int rv;
+    int err = 0;
+    EFI_FILE_HANDLE	fd;	/* handle to ldlinux.sys or extlinux.sys */
+    CHAR16 *file;
+    EFI_FILE_INFO st, xst;
+
+#if defined IS_SYSLINUX
+    name = SYSLINUX_FILE;
+#elif defined IS_EXTLINUX
+    name = EXTLINUX_FILE;
+#else
+	#error "IS_SYSLINUX or IS_EXTLINUX must be specified to build ADV"
+#endif
+    rv = make_filespec(&file, "", name);
+    if (rv < 0 || !file) {
+	efi_errno = EFI_OUT_OF_RESOURCES;
+	efi_perror(L"efi_adv_write:");
+	return -1;
+    }
+
+    fd = efi_open(file, EFI_FILE_MODE_READ);
+    if (fd == (EFI_FILE_HANDLE)NULL) {
+	err = -1;
+	efi_printerr(L"efi_adv_write: Unable to open file %s\n", file);
+    } else if (efi_fstat(fd, &st)) {
+	err = -1;
+	efi_printerr(L"efi_adv_write: Unable to get info for file %s\n", file);
+    } else if (st.FileSize < 2 * ADV_SIZE) {
+	/* Too small to be useful */
+	err = -2;
+	efi_printerr(L"efi_adv_write: File size too small to be useful for file %s\n", file);
+    } else if (efi_xpread(fd, advtmp, 2 * ADV_SIZE,
+		      st.FileSize - 2 * ADV_SIZE) != 2 * ADV_SIZE) {
+	err = -1;
+	efi_printerr(L"efi_adv_write: Error reading ADV data from file %s\n", file);
+    } else {
+	cleanup_adv(advbuf);
+	err = syslinux_validate_adv(advbuf) ? -2 : 0;
+
+	if (!err) {
+	    /* Got a good one, write our own ADV here */
+	    efi_clear_attributes(fd);
+
+	    /* Need to re-open read-write */
+	    efi_close(fd);
+		/* There is no SYNC attribute with EFI open */
+	    fd = efi_open(file, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE);
+	    if (fd == (EFI_FILE_HANDLE)NULL) {
+		err = -1;
+	    } else if (efi_fstat(fd, &xst) || xst.FileSize != st.FileSize) {
+		efi_perror(L"efi_adv_write: file status error/mismatch");
+		err = -2;
+	    }
+	    /* Write our own version ... */
+	    if (efi_xpwrite(fd, advbuf, 2 * ADV_SIZE,
+			st.FileSize - 2 * ADV_SIZE) != 2 * ADV_SIZE) {
+		err = -1;
+		efi_printerr(L"efi_adv_write: Error write ADV data to file %s\n", file);
+	    }
+	    if (!err) {
+		efi_sync(fd);
+		efi_set_attributes(fd);
+	    }
+	}
+    }
+
+    if (err == -2)
+	efi_printerr(L"%s: cannot write auxilliary data (need --update)?\n",
+		file);
+    else if (err == -1)
+	efi_perror(L"efi_adv_write:");
+
+    if (fd)
+	efi_close(fd);
+    if (file)
+	free(file);
+
+    return err;
+}
diff --git a/efi/adv.h b/efi/adv.h
new file mode 100644
index 0000000..e8ccb35
--- /dev/null
+++ b/efi/adv.h
@@ -0,0 +1,29 @@
+#ifndef _H_EFI_ADV_
+#define _H_EFI_ADV_
+
+#include "efi.h"
+#include "fio.h"
+#include <syslinux/firmware.h>
+
+/* ADV information */
+#define ADV_SIZE	512	/* Total size */
+#define ADV_LEN		(ADV_SIZE-3*4)	/* Usable data size */
+/* Currently, one of IS_SYSLINUX or IS_EXTLINUX	must be defined for ADV */
+#define SYSLINUX_FILE	"ldlinux.sys"
+#define EXTLINUX_FILE	"extlinux.sys"
+
+#define ADV_MAGIC1	0x5a2d2fa5	/* Head signature */
+#define ADV_MAGIC2	0xa3041767	/* Total checksum */
+#define ADV_MAGIC3	0xdd28bf64	/* Tail signature */
+
+extern unsigned char syslinux_adv[2 * ADV_SIZE];
+extern void *__syslinux_adv_ptr;
+extern ssize_t __syslinux_adv_size;
+
+/* TODO: Revisit to ensure if these functions need to be exported */
+void syslinux_reset_adv(unsigned char *advbuf);
+int syslinux_validate_adv(unsigned char *advbuf);
+int read_adv(const char *path, const char *cfg);
+int write_adv(const char *path, const char *cfg);
+
+#endif
diff --git a/efi/console.c b/efi/console.c
new file mode 100644
index 0000000..1f09c5a
--- /dev/null
+++ b/efi/console.c
@@ -0,0 +1,279 @@
+#include <syslinux/linux.h>
+#include "efi.h"
+
+extern EFI_GUID GraphicsOutputProtocol;
+
+void writechr(char data)
+{
+	efi_write_char(data, 0);
+}
+
+static inline EFI_STATUS open_protocol(EFI_HANDLE handle, EFI_GUID *protocol,
+				       void **interface, EFI_HANDLE agent,
+				       EFI_HANDLE controller, UINT32 attributes)
+{
+	return uefi_call_wrapper(BS->OpenProtocol, 6, handle, protocol,
+				 interface, agent, controller, attributes);
+}
+
+static inline EFI_STATUS
+gop_query_mode(EFI_GRAPHICS_OUTPUT_PROTOCOL *gop, UINTN *size,
+	       EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **info)
+{
+	return uefi_call_wrapper(gop->QueryMode, 4, gop,
+				 gop->Mode->Mode, size, info);
+}
+
+static inline void bit_mask(uint32_t mask, uint8_t *pos, uint8_t *size)
+{
+	*pos = 0;
+	*size = 0;
+
+	if (mask) {
+		while (!(mask & 0x1)) {
+			mask >>= 1;
+			(*pos)++;
+		}
+
+		while (mask & 0x1) {
+			mask >>= 1;
+			(*size)++;
+		}
+	}
+}
+
+static int setup_gop(struct screen_info *si)
+{
+	EFI_HANDLE *handles = NULL;
+	EFI_STATUS status;
+	EFI_GRAPHICS_OUTPUT_PROTOCOL *gop, *found;
+	EFI_GRAPHICS_PIXEL_FORMAT pixel_fmt;
+	EFI_PIXEL_BITMASK pixel_info;
+	uint32_t pixel_scanline;
+	UINTN nr_handles;
+	UINTN size;
+	uint16_t lfb_width, lfb_height;
+	uint32_t lfb_base, lfb_size;
+	int i, err = 0;
+	void **gop_handle = NULL;
+
+	size = 0;
+	status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &GraphicsOutputProtocol,
+				NULL, &size, gop_handle);
+	/* LibLocateHandle handle already returns the number of handles.
+	 * There is no need to divide by sizeof(EFI_HANDLE)
+	 */
+	status = LibLocateHandle(ByProtocol, &GraphicsOutputProtocol,
+				 NULL, &nr_handles, &handles);
+	if (status == EFI_BUFFER_TOO_SMALL) {
+
+		handles = AllocatePool(nr_handles);
+		if (!handles)
+			return 0;
+
+		status = LibLocateHandle(ByProtocol, &GraphicsOutputProtocol,
+					 NULL, &nr_handles, &handles);
+	}
+	if (status != EFI_SUCCESS)
+		goto out;
+
+	found = NULL;
+	for (i = 0; i < nr_handles; i++) {
+		EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info;
+		EFI_PCI_IO *pciio = NULL;
+		EFI_HANDLE *h = handles[i];
+
+		status = uefi_call_wrapper(BS->HandleProtocol, 3, h, &GraphicsOutputProtocol, &gop);
+		if (status != EFI_SUCCESS)
+			continue;
+		uefi_call_wrapper(BS->HandleProtocol, 3, h, &PciIoProtocol, &pciio);
+		status = gop_query_mode(gop, &size, &info);
+		if (status == EFI_SUCCESS && (!found || pciio)) {
+			lfb_width = info->HorizontalResolution;
+			lfb_height = info->VerticalResolution;
+			lfb_base = gop->Mode->FrameBufferBase;
+			lfb_size = gop->Mode->FrameBufferSize;
+			pixel_fmt = info->PixelFormat;
+			pixel_info = info->PixelInformation;
+			pixel_scanline = info->PixelsPerScanLine;
+			if (pciio)
+				break;
+			found = gop;
+		}
+	}
+
+	if (!found)
+		goto out;
+
+	err = 1;
+
+	dprintf("setup_screen: set up screen parameters for EFI GOP\n");
+	si->orig_video_isVGA = 0x70; /* EFI framebuffer */
+
+	si->lfb_base = lfb_base;
+	si->lfb_size = lfb_size;
+	si->lfb_width = lfb_width;
+	si->lfb_height = lfb_height;
+	si->pages = 1;
+
+	dprintf("setup_screen: lfb_base 0x%x lfb_size %d lfb_width %d lfb_height %d\n", lfb_base, lfb_size, lfb_width, lfb_height);
+	switch (pixel_fmt) {
+	case PixelRedGreenBlueReserved8BitPerColor:
+		si->lfb_depth = 32;
+		si->lfb_linelength = pixel_scanline * 4;
+		si->red_size = 8;
+		si->red_pos = 0;
+		si->green_size = 8;
+		si->green_pos = 8;
+		si->blue_size = 8;
+		si->blue_pos = 16;
+		si->rsvd_size = 8;
+		si->rsvd_pos = 24;
+		break;
+	case PixelBlueGreenRedReserved8BitPerColor:
+		si->lfb_depth = 32;
+		si->lfb_linelength = pixel_scanline * 4;
+		si->red_size = 8;
+		si->red_pos = 16;
+		si->green_size = 8;
+		si->green_pos = 8;
+		si->blue_size = 8;
+		si->blue_pos = 0;
+		si->rsvd_size = 8;
+		si->rsvd_pos = 24;
+		break;
+	case PixelBitMask:
+		bit_mask(pixel_info.RedMask, &si->red_pos,
+			 &si->red_size);
+		bit_mask(pixel_info.GreenMask, &si->green_pos,
+			 &si->green_size);
+		bit_mask(pixel_info.BlueMask, &si->blue_pos,
+			 &si->blue_size);
+		bit_mask(pixel_info.ReservedMask, &si->rsvd_pos,
+			 &si->rsvd_size);
+		si->lfb_depth = si->red_size + si->green_size +
+			si->blue_size + si->rsvd_size;
+		si->lfb_linelength = (pixel_scanline * si->lfb_depth) / 8;
+		break;
+	default:
+		si->lfb_depth = 4;;
+		si->lfb_linelength = si->lfb_width / 2;
+		si->red_size = 0;
+		si->red_pos = 0;
+		si->green_size = 0;
+		si->green_pos = 0;
+		si->blue_size = 0;
+		si->blue_pos = 0;
+		si->rsvd_size = 0;
+		si->rsvd_pos = 0;
+		break;
+	}
+	dprintf("setup_screen: depth %d line %d rpos %d rsize %d gpos %d gsize %d bpos %d bsize %d rsvpos %d rsvsize %d\n",
+		si->lfb_depth, si->lfb_linelength,
+		si->red_pos, si->red_size,
+		si->green_pos, si->green_size,
+		si->blue_pos, si->blue_size,
+		si->blue_pos, si->blue_size,
+		si->rsvd_pos, si->rsvd_size);
+	
+out:
+	if (handles) FreePool(handles);
+
+	return err;
+}
+
+#define EFI_UGA_PROTOCOL_GUID \
+  { \
+    0x982c298b, 0xf4fa, 0x41cb, {0xb8, 0x38, 0x77, 0xaa, 0x68, 0x8f, 0xb8, 0x39 } \
+  }
+
+typedef struct _EFI_UGA_DRAW_PROTOCOL EFI_UGA_DRAW_PROTOCOL;
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_UGA_DRAW_PROTOCOL_GET_MODE) (
+  IN  EFI_UGA_DRAW_PROTOCOL *This,
+  OUT UINT32 *Width,
+  OUT UINT32 *Height,
+  OUT UINT32 *Depth,
+  OUT UINT32 *Refresh
+  )
+;
+
+struct _EFI_UGA_DRAW_PROTOCOL {
+	EFI_UGA_DRAW_PROTOCOL_GET_MODE	GetMode;
+	void	*SetMode;
+	void	*Blt;
+};
+
+static int setup_uga(struct screen_info *si)
+{
+	EFI_UGA_DRAW_PROTOCOL *uga, *first;
+	EFI_GUID UgaProtocol = EFI_UGA_PROTOCOL_GUID;
+	UINT32 width, height;
+	EFI_STATUS status;
+	EFI_HANDLE *handles;
+	UINTN nr_handles;
+	int i, rv = 0;
+
+	status = LibLocateHandle(ByProtocol, &UgaProtocol,
+				 NULL, &nr_handles, &handles);
+	if (status != EFI_SUCCESS)
+		return rv;
+
+	for (i = 0; i < nr_handles; i++) {
+		EFI_PCI_IO *pciio = NULL;
+		EFI_HANDLE *handle = handles[i];
+		UINT32 w, h, depth, refresh;
+
+		status = uefi_call_wrapper(BS->HandleProtocol, 3, handle,
+					   &UgaProtocol, &uga);
+		if (status != EFI_SUCCESS)
+			continue;
+
+		uefi_call_wrapper(BS->HandleProtocol, 3, handle,
+				  &PciIoProtocol, &pciio);
+
+		status = uefi_call_wrapper(uga->GetMode, 5, uga, &w, &h,
+					   &depth, &refresh);
+
+		if (status == EFI_SUCCESS && (!first || pciio)) {
+			width = w;
+			height = h;
+
+			if (pciio)
+				break;
+
+			first = uga;
+		}
+	}
+
+	if (!first)
+		goto out;
+	rv = 1;
+
+	si->orig_video_isVGA = 0x70; /* EFI framebuffer */
+
+	si->lfb_depth = 32;
+	si->lfb_width = width;
+	si->lfb_height = height;
+
+	si->red_size = 8;
+	si->red_pos = 16;
+	si->green_size = 8;
+	si->green_pos = 8;
+	si->blue_size = 8;
+	si->blue_pos = 0;
+	si->rsvd_size = 8;
+	si->rsvd_pos = 24;
+
+out:
+	FreePool(handles);
+	return rv;
+}
+
+void setup_screen(struct screen_info *si)
+{
+	if (!setup_gop(si))
+		setup_uga(si);
+}
diff --git a/efi/cp865_8x16.h b/efi/cp865_8x16.h
new file mode 100644
index 0000000..358a563
--- /dev/null
+++ b/efi/cp865_8x16.h
@@ -0,0 +1,293 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 1999-2012 H. Peter Anvin - All Rights Reserved
+ *   Chandramouli Narayanan - extended for EFI support
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+#ifndef CP865_8x16
+#define CP865_8x16
+
+static const short cp865_8x16_font_magic = 0x436;
+static const unsigned cp865_8x16_font_mode = 0x0;
+static const int cp865_8x16_font_height = 0x10;
+static const uint8_t cp865_8x16_font_data[] = {
+	
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 
+	0x00, 0x00, 0x1e, 0x0e, 0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x7f, 0x63, 0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x02, 0x06, 0x0e, 0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x6c, 0xfe, 0x6c, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
+	0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 0x18, 0x18, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xd6, 0xd6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x7c, 0xc6, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xde, 0xde, 0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0xf8, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x1e, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x0c, 0x0e, 0x00, 0x00, 
+	0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x7e, 0x7e, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xfe, 0xee, 0x6c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x7c, 0x38, 0x38, 0x7c, 0x6c, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0xfe, 0xc6, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc2, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+	0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 
+	0x00, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0xe0, 0x60, 0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x1c, 0x36, 0x32, 0x30, 0x78, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 
+	0x00, 0x00, 0xe0, 0x60, 0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 
+	0x00, 0x00, 0xe0, 0x60, 0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0xfe, 0xd6, 0xd6, 0xd6, 0xd6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x10, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xd6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x18, 0x70, 0x00, 0x00, 
+	0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x10, 0x38, 0x6c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x38, 0x6c, 0x38, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x18, 0x70, 0x00, 0x00, 
+	0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x18, 0x3c, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+	0x38, 0x6c, 0x38, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+	0x0c, 0x18, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x36, 0x36, 0x7e, 0xd8, 0xd8, 0x6e, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x3e, 0x6c, 0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0xc6, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, 
+	0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xce, 0xd6, 0xe6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x04, 0x7c, 0xce, 0xce, 0xd6, 0xd6, 0xd6, 0xd6, 0xe6, 0xe6, 0x7c, 0x40, 0x00, 0x00, 0x00, 
+	0x00, 0xf8, 0xcc, 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0xcc, 0xcc, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x0c, 0x18, 0x30, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x76, 0xdc, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
+	0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x60, 0xe0, 0x62, 0x66, 0x6c, 0x18, 0x30, 0x60, 0xdc, 0x86, 0x0c, 0x18, 0x3e, 0x00, 0x00, 
+	0x00, 0x60, 0xe0, 0x62, 0x66, 0x6c, 0x18, 0x30, 0x66, 0xce, 0x9a, 0x3f, 0x06, 0x06, 0x00, 0x00, 
+	0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+	0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 
+	0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 
+	0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+	0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+	0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+	0x36, 0x36, 0x36, 0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+	0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+	0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+	0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+	0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+	0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+	0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+	0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 
+	0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
+	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+	0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x6c, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x3c, 0x66, 0x0c, 0x18, 0x32, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+};
+#endif /* CP865_8x16 */
diff --git a/efi/derivative.c b/efi/derivative.c
new file mode 100644
index 0000000..aa72fb1
--- /dev/null
+++ b/efi/derivative.c
@@ -0,0 +1,20 @@
+/*
+ * We don't have separate boot loader derivatives under EFI, rather,
+ * the derivative info reflects the capabilities of the machine. For
+ * instance, if we have the PXE Base Code Protocol, then we support
+ * PXELINUX, if we have the Disk I/O Protocol, we support SYSLINUX,
+ * etc.
+ */
+#include <syslinux/config.h>
+
+/*
+ * IP information.  Note that the field are in the same order as the
+ * Linux kernel expects in the ip= option.
+ */
+struct syslinux_ipinfo IPInfo;
+uint16_t APIVer;		/* PXE API version found */
+
+void get_derivative_info(union syslinux_derivative_info *di)
+{
+	di->disk.filesystem = SYSLINUX_FS_SYSLINUX;
+}
diff --git a/efi/diskio.c b/efi/diskio.c
new file mode 100644
index 0000000..01ab2a0
--- /dev/null
+++ b/efi/diskio.c
@@ -0,0 +1,88 @@
+#include <fs.h>
+#include <ilog2.h>
+#include <disk.h>
+#include <dprintf.h>
+#include "efi.h"
+
+static inline EFI_STATUS read_blocks(EFI_BLOCK_IO *bio, uint32_t id, 
+				     sector_t lba, UINTN bytes, void *buf)
+{
+	return uefi_call_wrapper(bio->ReadBlocks, 5, bio, id, lba, bytes, buf);
+}
+
+static inline EFI_STATUS write_blocks(EFI_BLOCK_IO *bio, uint32_t id, 
+				     sector_t lba, UINTN bytes, void *buf)
+{
+	return uefi_call_wrapper(bio->WriteBlocks, 5, bio, id, lba, bytes, buf);
+}
+
+static int efi_rdwr_sectors(struct disk *disk, void *buf,
+			    sector_t lba, size_t count, bool is_write)
+{
+	struct efi_disk_private *priv = (struct efi_disk_private *)disk->private;
+	EFI_BLOCK_IO *bio = priv->bio;
+	EFI_STATUS status;
+	UINTN bytes = count * disk->sector_size;
+
+	if (is_write)
+		status = write_blocks(bio, disk->disk_number, lba, bytes, buf);
+	else
+		status = read_blocks(bio, disk->disk_number, lba, bytes, buf);
+
+	if (status != EFI_SUCCESS)
+		Print(L"Failed to %s blocks: 0x%x\n",
+			is_write ? L"write" : L"read",
+			status);
+
+	return count << disk->sector_shift;
+}
+
+struct disk *efi_disk_init(void *private)
+{
+    static struct disk disk;
+    struct efi_disk_private *priv = (struct efi_disk_private *)private;
+    EFI_HANDLE handle = priv->dev_handle;
+    EFI_BLOCK_IO *bio;
+    EFI_DISK_IO *dio;
+    EFI_STATUS status;
+
+    status = uefi_call_wrapper(BS->HandleProtocol, 3, handle,
+			       &DiskIoProtocol, (void **)&dio);
+    if (status != EFI_SUCCESS)
+	    return NULL;
+
+    status = uefi_call_wrapper(BS->HandleProtocol, 3, handle,
+			       &BlockIoProtocol, (void **)&bio);
+    if (status != EFI_SUCCESS)
+	    return NULL;
+
+    /*
+     * XXX Do we need to map this to a BIOS disk number?
+     */
+    disk.disk_number   = bio->Media->MediaId;
+
+    disk.sector_size   = bio->Media->BlockSize;
+    disk.rdwr_sectors  = efi_rdwr_sectors;
+    disk.sector_shift  = ilog2(disk.sector_size);
+
+    dprintf("sector_size=%d, disk_number=%d\n", disk.sector_size,
+	    disk.disk_number);
+
+    priv->bio = bio;
+    priv->dio = dio;
+    disk.private = private;
+#if 0
+
+    disk.part_start    = part_start;
+    disk.secpercyl     = disk.h * disk.s;
+
+
+    disk.maxtransfer   = MaxTransfer;
+
+    dprintf("disk %02x cdrom %d type %d sector %u/%u offset %llu limit %u\n",
+	    media_id, cdrom, ebios, sector_size, disk.sector_shift,
+	    part_start, disk.maxtransfer);
+#endif
+
+    return &disk;
+}
diff --git a/efi/efi.h b/efi/efi.h
new file mode 100644
index 0000000..6472d6a
--- /dev/null
+++ b/efi/efi.h
@@ -0,0 +1,29 @@
+#ifndef _SYSLINUX_EFI_H
+#define _SYSLINUX_EFI_H
+
+#include <core.h>
+#include <sys/types.h>	/* needed for off_t */
+//#include <syslinux/version.h> /* avoid redefinition of __STDC_VERSION__ */
+#include <efi.h>
+#include <efilib.h>
+#include <efistdarg.h>
+
+struct efi_disk_private {
+	EFI_HANDLE dev_handle;
+	EFI_BLOCK_IO *bio;
+	EFI_DISK_IO *dio;
+};
+
+extern EFI_HANDLE image_handle;
+
+struct screen_info;
+extern void setup_screen(struct screen_info *);
+
+extern void efi_write_char(uint8_t, uint8_t);
+
+enum heap;
+extern void *efi_malloc(size_t, enum heap, size_t);
+extern void *efi_realloc(void *, size_t);
+extern void efi_free(void *);
+
+#endif /* _SYSLINUX_EFI_H */
diff --git a/efi/find-gnu-efi.sh b/efi/find-gnu-efi.sh
new file mode 100755
index 0000000..bf203d8
--- /dev/null
+++ b/efi/find-gnu-efi.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+# Find where the gnu-efi package has been installed as this location
+# differs across distributions.
+
+include_dirs="/usr/include /usr/local/include"
+lib_dirs="/usr/lib /usr/lib64 /usr/local/lib /usr/lib32"
+
+find_include()
+{
+    for d in $include_dirs; do
+	found=`find $d -name efi -type d 2> /dev/null`
+	if [ "$found"x != "x" ] && [ -e $found/$ARCH/efibind.h ]; then
+	    echo $found
+	    break;
+	fi
+    done
+}
+
+find_lib()
+{
+    for d in $lib_dirs; do
+	found=`find $d -name libgnuefi.a 2> /dev/null`
+	if [ "$found"x != "x" ]; then
+	    crt_name='crt0-efi-'$ARCH'.o'
+	    crt=`find $d -name $crt_name 2> /dev/null`
+	    if [ "$crt"x != "x" ]; then
+		echo $d
+		break;
+	    fi
+	fi
+    done
+}
+
+ARCH=$2
+case $1 in
+    include)
+	find_include
+	;;
+    lib)
+	find_lib
+	;;
+esac
diff --git a/efi/fio.c b/efi/fio.c
new file mode 100644
index 0000000..f56cd5b
--- /dev/null
+++ b/efi/fio.c
@@ -0,0 +1,283 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2012 Intel Corporation; author: H. Peter Anvin
+ *   Chandramouli Narayanan
+ *
+ *   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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/* Miscellaneous functions for UEFI support
+ * We assume that EFI library initialization has completed
+ * and we have access to the global EFI exported variables
+ *
+ */
+#include "efi.h"
+#include "fio.h"
+
+/* Variables that need to be exported
+ * efi_errno - maintains the errors from EFI calls to display error messages.
+ */
+EFI_STATUS efi_errno = EFI_SUCCESS;
+
+/* Locals
+ * vol_root - handle to the root device for file operations
+ */
+static EFI_FILE_HANDLE vol_root;
+
+/* Table of UEFI error messages to be indexed with the EFI errno
+ * Update error message list as needed
+ */
+static CHAR16 *uefi_errmsg[] = {
+	L"EFI_UNDEFINED",	/* should not get here */
+	L"EFI_LOAD_ERROR",
+	L"EFI_INVALID_PARAMETER",
+	L"EFI_UNSUPPORTED",
+	L"EFI_BAD_BUFFER_SIZE",
+	L"EFI_BUFFER_TOO_SMALL",
+	L"EFI_NOT_READY",
+	L"EFI_DEVICE_ERROR",
+	L"EFI_WRITE_PROTECTED",
+	L"EFI_OUT_OF_RESOURCES",
+	L"EFI_VOLUME_CORRUPTED",
+	L"EFI_VOLUME_FULL",
+	L"EFI_NO_MEDIA",
+	L"EFI_MEDIA_CHANGED",
+	L"EFI_NOT_FOUND",
+	L"EFI_ACCESS_DENIED",
+	L"EFI_NO_RESPONSE",
+	L"EFI_NO_MAPPING",
+	L"EFI_TIMEOUT",
+	L"EFI_NOT_STARTED",
+	L"EFI_ALREADY_STARTED",
+	L"EFI_ABORTED",
+	L"EFI_ICMP_ERROR",
+	L"EFI_TFTP_ERROR",
+	L"EFI_PROTOCOL_ERROR"
+};
+
+static UINTN nerrs = sizeof(uefi_errmsg)/sizeof(CHAR16 *);
+
+
+/* Generic write error message; there is no gnu lib api to write to StdErr
+ * For now, everything goes ConOut
+ */
+void efi_printerr(
+    CHAR16   *fmt,
+    ...
+    )
+{
+    va_list     args;
+    va_start (args, fmt);
+    VPrint (fmt, args);
+    va_end (args);
+}
+
+/* Simple console logger of efi-specific error messages. It uses
+ * gnu-efi library Print function to do the job.
+ */
+
+void efi_perror(CHAR16 *prog)
+{
+	/* Ensure that the err number lies within range
+	 * Beware: unsigned comparisons fail on efi, signed comparisons work
+	 */
+	if (EFI_ERROR(efi_errno) && (INTN)efi_errno < (INTN)nerrs)
+		efi_printerr(L"%s: %s\n", prog, uefi_errmsg[efi_errno]);
+}
+
+/* Write to UEFI ConOut */
+void efi_printout(
+    CHAR16   *fmt,
+    ...
+    )
+{
+    va_list     args;
+    va_start (args, fmt);
+    VPrint (fmt, args);
+    va_end (args);
+}
+
+/* IMPORTANT:
+ * efi_setvol_root() needs to be called from efi main.
+ * The rest of the ADV support relies on the file i/o environment
+ * setup here. In order to use the EFI file support, we need
+ * to set up the volume root. Subsequent file operations need the root to
+ * access the interface routines.
+ *
+ */
+
+EFI_STATUS efi_set_volroot(EFI_HANDLE device_handle)
+{
+	vol_root = LibOpenRoot(device_handle);
+	if (!vol_root) {
+		return EFI_DEVICE_ERROR;
+	}
+	return EFI_SUCCESS;
+}
+
+/* File operations using EFI runtime services */
+
+/* Open the file using EFI runtime service
+ * Opening a file in EFI requires a handle to the device
+ * root in order to use the interface to the file operations supported by UEFI.
+ * For now, assume device volume root handle from the loaded image
+ *
+ * Return a valid handle if open succeeded and null otherwise.
+ * UEFI returns a bogus handle on error, so return null handle on error.
+ *
+ * TODO:
+ * 1. Validate the assumption about the root device
+ * 2. Can EFI open a file with full path name specification?
+ * 3. Look into gnu-efi helper functions for dealing with device path/file path
+ * 4. Consider utilizing EFI file open attributes.
+ * 5. In EFI, file attributes can be specified only at the time of creation.
+ * How do we support the equivalent of set_attributes() and clear_attributes()
+ */
+EFI_FILE_HANDLE efi_open(CHAR16 *file, UINT64 mode)
+{
+	/* initialize with NULL handle since EFI open returns bogus */
+	EFI_FILE_HANDLE	fd = NULL;
+
+	ASSERT(vol_root);
+
+	/* Note that the attributes parameter is none for now */
+	efi_errno = uefi_call_wrapper(vol_root->Open,
+					5,
+					vol_root,
+					&fd,
+					file,
+					mode,
+					0);
+	return fd;
+}
+
+/*
+ * read/write wrapper functions for UEFI
+ *
+ * Read or write the specified number of bytes starting at the
+ * offset specified.
+ *
+ * Returns:
+ * number of bytes read/written on success
+ * -1 on error
+ */
+/* Wrapper function to read from a file */
+size_t efi_xpread(EFI_FILE_HANDLE fd, void *buf, size_t count, off_t offset)
+{
+	ASSERT(fd);
+	efi_errno = uefi_call_wrapper(fd->SetPosition,
+					2,
+				    fd,
+				    offset);
+	if (EFI_ERROR(efi_errno)) return -1;
+	efi_errno = uefi_call_wrapper(fd->Read,
+					3,
+				    fd,
+				    &count,
+					buf);
+	if (EFI_ERROR(efi_errno)) return -1;
+	return count;
+}
+
+/* Wrapper function to write */
+size_t efi_xpwrite(EFI_FILE_HANDLE fd, void *buf, size_t count, off_t offset)
+{
+	ASSERT(fd);
+	efi_errno = uefi_call_wrapper(fd->SetPosition,
+					2,
+				    fd,
+				    offset);
+	if (EFI_ERROR(efi_errno)) return -1;
+	efi_errno = uefi_call_wrapper(fd->Write,
+					3,
+				    fd,
+				    &count,
+					buf);
+	if (EFI_ERROR(efi_errno)) return -1;
+	return count;
+}
+
+/* For an open handle, return the generic file info excluding
+ * the variable-length filename in the EFI_FILE_INFO structure.
+ */
+int efi_fstat(EFI_FILE_HANDLE fd, EFI_FILE_INFO *st)
+{
+	EFI_FILE_INFO *finfo;
+
+	ASSERT(fd);
+	finfo = LibFileInfo(fd);
+	if (finfo) {
+		uefi_call_wrapper(BS->CopyMem, 3, (VOID *)st, (VOID *)finfo, SIZE_OF_EFI_FILE_INFO);
+		FreePool(finfo);
+		return 0;
+	}
+	/* gnu-efi lib does not return EFI status; export a generic device error for now */
+	efi_errno = EFI_DEVICE_ERROR;
+	return -1;
+}
+
+/* set/clear_attributes()
+ * 	Currently handles only VFAT filesystem
+ * TODO:
+ *    1. Assumes VFAT file system.
+ *    2. How do we support other file systems?
+ */
+void efi_set_attributes(EFI_FILE_HANDLE fd)
+{
+	EFI_FILE_INFO *finfo;
+
+	ASSERT(fd);
+	finfo = LibFileInfo(fd);
+	if (finfo) {
+		/* Hidden+System+Readonly */
+		finfo->Attribute = EFI_FILE_READ_ONLY|EFI_FILE_HIDDEN|EFI_FILE_SYSTEM;
+		efi_errno = uefi_call_wrapper(fd->SetInfo,
+					4,
+					fd,
+					&GenericFileInfo,
+					finfo->Size,
+					finfo);
+		FreePool(finfo);
+	} else efi_errno = EFI_NOT_FOUND;
+}
+
+void efi_clear_attributes(EFI_FILE_HANDLE fd)
+{
+	EFI_FILE_INFO *finfo;
+
+	ASSERT(fd);
+	finfo = LibFileInfo(fd);
+	if (finfo) {
+		finfo->Attribute = 0; /* no attributes */
+		efi_errno = uefi_call_wrapper(fd->SetInfo, 
+					4, 
+					fd,
+					&GenericFileInfo,
+					finfo->Size,
+					finfo);
+		FreePool(finfo);
+	} else efi_errno = EFI_NOT_FOUND;
+}
+
+/* Implement the sync operation using the EFI Flush file operation*/
+void efi_sync(EFI_FILE_HANDLE fd)
+{
+	ASSERT(fd);
+	efi_errno = uefi_call_wrapper(fd->Flush, 1, fd);
+	return;
+}
+
+/* Close the file */
+void efi_close(EFI_FILE_HANDLE fd)
+{
+
+	ASSERT(fd);
+	efi_errno = uefi_call_wrapper(fd->Close, 1, fd);
+	return;
+}
diff --git a/efi/fio.h b/efi/fio.h
new file mode 100644
index 0000000..65fff8d
--- /dev/null
+++ b/efi/fio.h
@@ -0,0 +1,43 @@
+#ifndef _H_EFI_FIO_
+#define _H_EFI_FIO_
+
+/*
+ * Friendly interfaces for EFI file I/O and various EFI support functions
+ */
+
+/* MAX_EFI_ARGS - command line args for EFI executable
+ * WS(c16) 	- check for CHAR16 white space
+ */
+#define MAX_EFI_ARGS		64
+#define WS(c16)         (c16 == L' ' || c16 == CHAR_TAB)
+
+/* VPrint is not in export declarations in gnu-efi lib yet
+ * although it is a global function; declare it here
+ */
+extern UINTN
+VPrint (
+    IN CHAR16   *fmt,
+    va_list     args
+    );
+
+extern EFI_STATUS efi_errno;
+
+void efi_memcpy(unsigned char *dst, unsigned char *src, size_t len);
+void efi_memmove(unsigned char *dst, unsigned char *src, size_t len);
+void efi_memset(unsigned char *dst, unsigned char val, size_t len);
+void *efi_alloc(int size);
+void efi_free(void *ptr);
+void efi_perror(CHAR16 *str);
+void efi_printerr(IN CHAR16 *fmt, ...);
+void efi_printout(IN CHAR16 *fmt, ...);
+EFI_STATUS efi_set_volroot(EFI_HANDLE device_handle);
+EFI_FILE_HANDLE efi_open(CHAR16 *file, UINT64 mode);
+void efi_close(EFI_FILE_HANDLE fd);
+void efi_sync(EFI_FILE_HANDLE fd);
+size_t efi_xpread(EFI_FILE_HANDLE fd, void *buf, size_t count, off_t offset);
+size_t efi_xpwrite(EFI_FILE_HANDLE fd, void *buf, size_t count, off_t offset);
+int efi_fstat(EFI_FILE_HANDLE fd, EFI_FILE_INFO *st);
+void efi_set_attributes(EFI_FILE_HANDLE fd);
+void efi_clear_attributes(EFI_FILE_HANDLE fd);
+
+#endif
diff --git a/efi/i386/syslinux.ld b/efi/i386/syslinux.ld
new file mode 100644
index 0000000..e027053
--- /dev/null
+++ b/efi/i386/syslinux.ld
@@ -0,0 +1,176 @@
+/* -----------------------------------------------------------------------
+ *   
+ *   Copyright 2008-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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Linker script for the SYSLINUX core
+ */
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+
+SECTIONS
+{
+	. = 0;
+	ImageBase = .;		/* For gnu-efi's crt0 */
+	__module_start = .;
+	. = SEGMENT_START("text-segment", 0) + SIZEOF_HEADERS;
+	.text : {
+		FILL(0x90909090)
+		__text_start = .;
+		*(.text)
+		*(.text.*)
+		__text_end = .;
+	}
+
+	. = ALIGN(16);
+
+	.rodata : {
+		__rodata_start = .;
+		*(.rodata)
+		*(.rodata.*)
+		__rodata_end = .;
+	}
+
+	. = ALIGN(4);
+
+	.ctors : {
+		__ctors_start = .;
+		KEEP (*(SORT(.ctors.*)))
+		KEEP (*(.ctors))
+		__ctors_end = .;
+	}
+
+	.dtors : {
+		__dtors_start = .;
+		KEEP (*(SORT(.dtors.*)))
+		KEEP (*(.dtors))
+		__dtors_end = .;
+	}
+
+	. = ALIGN(4096);
+	.rel : {
+		*(.rel.got)
+		*(.rel.data)
+		*(.rel.data.*)
+		*(.rel.ctors)
+	}
+
+	. = ALIGN(4);
+
+	.gnu.hash : {
+		__gnu_hash_start = .;
+		*(.gnu.hash)
+		__gnu_hash_end = .;
+	}
+
+
+	.dynsym : {
+		__dynsym_start = .;
+		*(.dynsym)
+		__dynsym_end = .;
+	}
+
+	. = ALIGN(4);
+
+	.dynstr : {
+		__dynstr_start = .;
+		*(.dynstr)
+		__dynstr_end = .;
+	}
+
+	. = ALIGN(4);
+
+	.dynlink : {
+		__dynlink_start = .;
+		*(.dynlink)
+		__dynlink_end = .;
+	}
+
+	. = ALIGN(4);
+
+	.got : {
+		__got_start = .;
+		KEEP (*(.got.plt))
+		KEEP (*(.got))
+		__got_end = .;
+	}
+
+	. = ALIGN(4);
+
+	.dynamic : {
+		__dynamic_start = .;
+		*(.dynamic)
+		__dynamic_end = .;
+	}
+
+	. = ALIGN(16);
+
+	.data : {
+		__data_start = .;
+		*(.data)
+		*(.data.*)
+		*(.lowmem)
+		__data_end = .;
+	}
+
+	.reloc : {
+		*(.reloc)
+	}
+
+	.comment : {
+		*(.commet)
+	}
+
+	.symtab : {
+		*(.symtab)
+	}
+
+	.strtab : {
+		*(.strtab)
+	}
+
+	.bss : {
+		/* the EFI loader doesn't seem to like a .bss section,
+		   so we stick it all into .data: */
+		__bss_start = .;
+		*(.bss)
+		*(.bss.*)
+		*(.bss16)
+		*(.hugebss)
+		*(COMMON)
+		__bss_end = .;
+		*(.sbss)
+		*(.scommon)
+	}
+	__bss_len = ABSOLUTE(__bss_end) - ABSOLUTE(__bss_start);
+	__bss_dwords = (__bss_len + 3) >> 2;
+
+	. = ALIGN(128);
+	
+	/* Very large objects which don't need to be zeroed */
+
+	.hugebss : {
+		__hugebss_start = .;
+		*(.hugebss)
+		*(.hugebss.*)
+		__hugebss_end = .;
+	}
+
+	_end = .;
+
+	/* Stuff we don't need... */
+	/DISCARD/ : {
+		*(.eh_frame)
+	}
+}
diff --git a/efi/main.c b/efi/main.c
new file mode 100644
index 0000000..db2b687
--- /dev/null
+++ b/efi/main.c
@@ -0,0 +1,1161 @@
+#include <codepage.h>
+#include <core.h>
+#include <fs.h>
+#include <com32.h>
+#include <syslinux/memscan.h>
+#include <syslinux/firmware.h>
+#include <syslinux/linux.h>
+#include <sys/ansi.h>
+
+#include "efi.h"
+#include "fio.h"
+
+char KernelName[FILENAME_MAX];
+uint16_t PXERetry;
+char copyright_str[] = "Copyright (C) 2011\n";
+uint8_t SerialNotice = 1;
+char syslinux_banner[] = "Syslinux 5.x (EFI)\n";
+char CurrentDirName[CURRENTDIR_MAX];
+struct com32_sys_args __com32;
+
+uint32_t _IdleTimer = 0;
+char __lowmem_heap[32];
+uint32_t BIOS_timer_next;
+uint32_t timer_irq;
+uint8_t KbdMap[256];
+char aux_seg[256];
+uint16_t BIOSName;
+
+#undef kaboom
+void kaboom(void)
+{
+}
+
+void comboot_cleanup_api(void)
+{
+}
+
+void printf_init(void)
+{
+}
+
+void local_boot16(void)
+{
+}
+
+void bios_timer_cleanup(void)
+{
+}
+
+char trackbuf[4096];
+
+void __cdecl core_farcall(uint32_t c, const com32sys_t *a, com32sys_t *b)
+{
+}
+
+struct firmware *firmware = NULL;
+void *__syslinux_adv_ptr;
+size_t __syslinux_adv_size;
+char core_xfer_buf[65536];
+struct iso_boot_info {
+	uint32_t pvd;               /* LBA of primary volume descriptor */
+	uint32_t file;              /* LBA of boot file */
+	uint32_t length;            /* Length of boot file */
+	uint32_t csum;              /* Checksum of boot file */
+	uint32_t reserved[10];      /* Currently unused */
+} iso_boot_info;
+
+uint8_t DHCPMagic;
+uint32_t RebootTime;
+
+void pxenv(void)
+{
+}
+
+size_t numIPAppends = 0;
+const uint16_t IPAppends[32];
+uint16_t BIOS_fbm = 1;
+far_ptr_t InitStack;
+char StackBuf[4096];
+far_ptr_t PXEEntry;
+unsigned int __bcopyxx_len = 0;
+
+void gpxe_unload(void)
+{
+}
+
+void do_idle(void)
+{
+}
+
+void pxe_int1a(void)
+{
+}
+
+uint8_t KeepPXE;
+
+
+volatile uint32_t __ms_timer = 0;
+volatile uint32_t __jiffies = 0;
+
+void efi_write_char(uint8_t ch, uint8_t attribute)
+{
+	SIMPLE_TEXT_OUTPUT_INTERFACE *out = ST->ConOut;
+	uint16_t c[2];
+
+	uefi_call_wrapper(out->SetAttribute, 2, out, attribute);
+
+	/* Lookup primary Unicode encoding in the system codepage */
+	c[0] = codepage.uni[0][ch];
+	c[1] = '\0';
+
+	uefi_call_wrapper(out->OutputString, 2, out, c);
+}
+
+static void efi_showcursor(const struct term_state *st)
+{
+	SIMPLE_TEXT_OUTPUT_INTERFACE *out = ST->ConOut;
+	bool cursor = st->cursor ? true : false;
+
+	uefi_call_wrapper(out->EnableCursor, 2, out, cursor);
+}
+
+static void efi_set_cursor(int x, int y, bool visible)
+{
+	SIMPLE_TEXT_OUTPUT_INTERFACE *out = ST->ConOut;
+
+	uefi_call_wrapper(out->SetCursorPosition, 3, out, x, y);
+}
+
+static void efi_scroll_up(uint8_t cols, uint8_t rows, uint8_t attribute)
+{
+	efi_write_char('\n', 0);
+	efi_write_char('\r', 0);
+}
+
+static void efi_get_mode(int *cols, int *rows)
+{
+	SIMPLE_TEXT_OUTPUT_INTERFACE *out = ST->ConOut;
+	UINTN c, r;
+
+	uefi_call_wrapper(out->QueryMode, 4, out, out->Mode->Mode, &c, &r);
+	*rows = r;
+	*cols = c;
+}
+
+static void efi_erase(const struct term_state *st,
+		       int x0, int y0, int x1, int y1)
+{
+	SIMPLE_TEXT_OUTPUT_INTERFACE *out = ST->ConOut;
+	int cols, rows;
+
+	efi_get_mode(&cols, &rows);
+
+	/*
+	 * The BIOS version of this function has the ability to erase
+	 * parts or all of the screen - the UEFI console doesn't
+	 * support this so we just set the cursor position unless
+	 * we're clearing the whole screen.
+	 */
+	if (!x0 && y0 == (cols - 1)) {
+		/* Really clear the screen */
+		uefi_call_wrapper(out->ClearScreen, 1, out);
+	} else {
+		uefi_call_wrapper(out->SetCursorPosition, 3, out, y1, x1);
+	}
+}
+
+static void efi_set_mode(uint16_t mode)
+{
+}
+
+static void efi_get_cursor(int *x, int *y)
+{
+	SIMPLE_TEXT_OUTPUT_INTERFACE *out = ST->ConOut;
+	*x = out->Mode->CursorColumn;
+	*y = out->Mode->CursorRow;
+}
+
+struct output_ops efi_ops = {
+	.erase = efi_erase,
+	.write_char = efi_write_char,
+	.showcursor = efi_showcursor,
+	.set_cursor = efi_set_cursor,
+	.scroll_up = efi_scroll_up,
+	.get_mode = efi_get_mode,
+	.set_mode = efi_set_mode,
+	.get_cursor = efi_get_cursor,
+};
+
+char SubvolName[2];
+static inline EFI_MEMORY_DESCRIPTOR *
+get_memory_map(UINTN *nr_entries, UINTN *key, UINTN *desc_sz,
+	       uint32_t *desc_ver)
+{
+	return LibMemoryMap(nr_entries, key, desc_sz, desc_ver);
+}
+
+
+int efi_scan_memory(scan_memory_callback_t callback, void *data)
+{
+	UINTN nr_entries, key, desc_sz;
+	UINTN buf, bufpos;
+	UINT32 desc_ver;
+	int rv = 0;
+	int i;
+
+	buf = (UINTN)get_memory_map(&nr_entries, &key, &desc_sz, &desc_ver);
+	if (!buf)
+		return -1;
+	bufpos = buf;
+
+	for (i = 0; i < nr_entries; bufpos += desc_sz, i++) {
+		EFI_MEMORY_DESCRIPTOR *m;
+		UINT64 region_sz;
+		int valid;
+
+		m = (EFI_MEMORY_DESCRIPTOR *)bufpos;
+		region_sz = m->NumberOfPages * EFI_PAGE_SIZE;
+
+		switch (m->Type) {
+                case EfiConventionalMemory:
+			valid = 1;
+                        break;
+		default:
+			valid = 0;
+			break;
+		}
+
+		rv = callback(data, m->PhysicalStart, region_sz, valid);
+		if (rv)
+			break;
+	}
+
+	FreePool((void *)buf);
+	return rv;
+}
+
+extern uint16_t *bios_free_mem;
+void efi_init(void)
+{
+	/* XXX timer */
+	*bios_free_mem = 0;
+	mem_init();
+}
+
+char efi_getchar(char *hi)
+{
+	SIMPLE_INPUT_INTERFACE *in = ST->ConIn;
+	EFI_INPUT_KEY key;
+	EFI_STATUS status;
+
+	do {
+		status = uefi_call_wrapper(in->ReadKeyStroke, 2, in, &key);
+	} while (status == EFI_NOT_READY);
+
+	if (!key.ScanCode)
+		return (char)key.UnicodeChar;
+
+	/*
+	 * We currently only handle scan codes that fit in 8 bits.
+	 */
+	*hi = (char)key.ScanCode;
+	return 0;
+}
+
+int efi_pollchar(void)
+{
+	SIMPLE_INPUT_INTERFACE *in = ST->ConIn;
+	EFI_STATUS status;
+
+	status = WaitForSingleEvent(in->WaitForKey, 1);
+	return status != EFI_TIMEOUT;
+}
+
+struct input_ops efi_iops = {
+	.getchar = efi_getchar,
+	.pollchar = efi_pollchar,
+};
+
+bool efi_ipappend_strings(char **list, int *count)
+{
+	*count = numIPAppends;
+	*list = (char *)IPAppends;
+}
+
+extern void efi_adv_init(void);
+extern int efi_adv_write(void);
+
+struct adv_ops efi_adv_ops = {
+	.init = efi_adv_init,
+	.write = efi_adv_write,
+};
+
+struct efi_info {
+	uint32_t load_signature;
+	uint32_t systab;
+	uint32_t desc_size;
+	uint32_t desc_version;
+	uint32_t memmap;
+	uint32_t memmap_size;
+	uint32_t systab_hi;
+	uint32_t memmap_hi;
+};
+
+#define E820MAX	128
+#define E820_RAM	1
+#define E820_RESERVED	2
+#define E820_ACPI	3
+#define E820_NVS	4
+#define E820_UNUSABLE	5
+
+#define BOOT_SIGNATURE	0xaa55
+#define SYSLINUX_EFILDR	0x30	/* Is this published value? */
+#define DEFAULT_TIMER_TICK_DURATION 	500000 /* 500000 == 500000 * 100 * 10^-9 == 50 msec */
+#define DEFAULT_MSTIMER_INC		0x32	/* 50 msec */
+struct e820_entry {
+	uint64_t start;
+	uint64_t len;
+	uint32_t type;
+} __packed;
+
+struct boot_params {
+	struct screen_info screen_info;
+	uint8_t _pad[0x1c0 - sizeof(struct screen_info)];
+	struct efi_info efi;
+	uint8_t _pad2[8];
+	uint8_t e820_entries;
+	uint8_t _pad3[0x2d0 - 0x1e8 - sizeof(uint8_t)];
+	struct e820_entry e820_map[E820MAX];
+} __packed;
+
+/* Allocate boot parameter block aligned to page */
+#define BOOT_PARAM_BLKSIZE	EFI_SIZE_TO_PAGES(sizeof(struct boot_params)) * EFI_PAGE_SIZE
+
+/* Routines in support of efi boot loader were obtained from
+ * http://git.kernel.org/?p=boot/efilinux/efilinux.git:
+ * kernel_jump(), handover_jump(),
+ * emalloc()/efree, alloc_pages/free_pages
+ * allocate_pool()/free_pool()
+ * memory_map()
+ */ 
+#if __SIZEOF_POINTER__ == 4
+#define EFI_LOAD_SIG	"EL32"
+static inline void kernel_jump(EFI_PHYSICAL_ADDRESS kernel_start,
+			       struct boot_params *boot_params)
+{
+	asm volatile ("cli		\n"
+		      "movl %0, %%esi	\n"
+		      "movl %1, %%ecx	\n"
+		      "jmp *%%ecx	\n"
+		      :: "m" (boot_params), "m" (kernel_start));
+}
+
+static inline void handover_jump(EFI_HANDLE image, struct boot_params *bp,
+				 EFI_PHYSICAL_ADDRESS kernel_start)
+{
+	/* handover protocol not implemented yet; the linux header needs to be updated */
+#if 0
+	kernel_start += hdr->handover_offset;
+
+	asm volatile ("cli		\n"
+		      "pushl %0         \n"
+		      "pushl %1         \n"
+		      "pushl %2         \n"
+		      "movl %3, %%ecx	\n"
+		      "jmp *%%ecx	\n"
+		      :: "m" (bp), "m" (ST),
+		         "m" (image), "m" (kernel_start));
+#endif
+}
+#elif __SIZEOF_POINTER__ == 8
+#define EFI_LOAD_SIG	"EL64"
+typedef void(*kernel_func)(void *, struct boot_params *);
+typedef void(*handover_func)(void *, EFI_SYSTEM_TABLE *, struct boot_params *);
+static inline void kernel_jump(EFI_PHYSICAL_ADDRESS kernel_start,
+			       struct boot_params *boot_params)
+{
+	kernel_func kf;
+
+	asm volatile ("cli");
+
+	/* The 64-bit kernel entry is 512 bytes after the start. */
+	kf = (kernel_func)kernel_start + 512;
+
+	/*
+	 * The first parameter is a dummy because the kernel expects
+	 * boot_params in %[re]si.
+	 */
+	kf(NULL, boot_params);
+}
+
+static inline void handover_jump(EFI_HANDLE image, struct boot_params *bp,
+				 EFI_PHYSICAL_ADDRESS kernel_start)
+{
+#if 0
+	/* handover protocol not implemented yet the linux header needs to be updated */
+
+	UINT32 offset = bp->hdr.handover_offset;
+	handover_func hf;
+
+	asm volatile ("cli");
+
+	/* The 64-bit kernel entry is 512 bytes after the start. */
+	kernel_start += 512;
+
+	hf = (handover_func)(kernel_start + offset);
+	hf(image, ST, bp);
+#endif
+}
+#else
+#error "unsupported architecture"
+#endif
+
+struct dt_desc {
+	uint16_t limit;
+	uint64_t *base;
+} __packed;
+
+struct dt_desc gdt = { 0x800, (uint64_t *)0 };
+struct dt_desc idt = { 0, 0 };
+
+static inline EFI_MEMORY_DESCRIPTOR *
+get_mem_desc(addr_t memmap, UINTN desc_sz, int i)
+{
+	return (EFI_MEMORY_DESCRIPTOR *)(memmap + (i * desc_sz));
+}
+
+EFI_HANDLE image_handle;
+
+static inline UINT64 round_up(UINT64 x, UINT64 y)
+{
+	return (((x - 1) | (y - 1)) + 1);
+}
+
+static inline UINT64 round_down(UINT64 x, UINT64 y)
+{
+	return (x & ~(y - 1));
+}
+
+static void find_addr(EFI_PHYSICAL_ADDRESS *first,
+		      EFI_PHYSICAL_ADDRESS *last,
+		      EFI_PHYSICAL_ADDRESS min,
+		      EFI_PHYSICAL_ADDRESS max,
+		      size_t size, size_t align)
+{
+	EFI_MEMORY_DESCRIPTOR *map;
+	EFI_STATUS status;
+	UINT32 desc_ver;
+	UINTN nr_entries, key, desc_sz;
+	UINT64 addr;
+	int i;
+
+	map = get_memory_map(&nr_entries, &key, &desc_sz, &desc_ver);
+	if (!map)
+		return;
+
+	for (i = 0; i < nr_entries; i++) {
+		EFI_MEMORY_DESCRIPTOR *m;
+		EFI_PHYSICAL_ADDRESS best;
+		UINT64 start, end;
+
+		m = get_mem_desc((addr_t)map, desc_sz, i);
+		if (m->Type != EfiConventionalMemory)
+			continue;
+
+		if (m->NumberOfPages < EFI_SIZE_TO_PAGES(size))
+			continue;
+
+		start = m->PhysicalStart;
+		end = m->PhysicalStart + (m->NumberOfPages << EFI_PAGE_SHIFT);
+		if (first) {
+			if (end < min)
+				continue;
+
+			/* What's the best address? */
+			if (start < min && min < end)
+				best = min;
+			else
+				best = m->PhysicalStart;
+
+			start = round_up(best, align);
+			if (start > max)
+				continue;
+
+			/* Have we run out of space in this region? */
+			if (end < start || (start + size) > end)
+				continue;
+
+			if (start < *first)
+				*first = start;
+		}
+
+		if (last) {
+			if (start > max)
+				continue;
+
+			/* What's the best address? */
+			if (start < max && max < end)
+				best = max - size;
+			else
+				best = end - size;
+
+			start = round_down(best, align);
+			if (start < min || start < m->PhysicalStart)
+				continue;
+
+			if (start > *last)
+				*last = start;
+		}
+	}
+
+	FreePool(map);
+}
+
+/**
+ * allocate_pages - Allocate memory pages from the system
+ * @atype: type of allocation to perform
+ * @mtype: type of memory to allocate
+ * @num_pages: number of contiguous 4KB pages to allocate
+ * @memory: used to return the address of allocated pages
+ *
+ * Allocate @num_pages physically contiguous pages from the system
+ * memory and return a pointer to the base of the allocation in
+ * @memory if the allocation succeeds. On success, the firmware memory
+ * map is updated accordingly.
+ *
+ * If @atype is AllocateAddress then, on input, @memory specifies the
+ * address at which to attempt to allocate the memory pages.
+ */
+static inline EFI_STATUS
+allocate_pages(EFI_ALLOCATE_TYPE atype, EFI_MEMORY_TYPE mtype,
+	       UINTN num_pages, EFI_PHYSICAL_ADDRESS *memory)
+{
+	return uefi_call_wrapper(BS->AllocatePages, 4, atype,
+				 mtype, num_pages, memory);
+}
+/**
+ * free_pages - Return memory allocated by allocate_pages() to the firmware
+ * @memory: physical base address of the page range to be freed
+ * @num_pages: number of contiguous 4KB pages to free
+ *
+ * On success, the firmware memory map is updated accordingly.
+ */
+static inline EFI_STATUS
+free_pages(EFI_PHYSICAL_ADDRESS memory, UINTN num_pages)
+{
+	return uefi_call_wrapper(BS->FreePages, 2, memory, num_pages);
+}
+
+static EFI_STATUS allocate_addr(EFI_PHYSICAL_ADDRESS *addr, size_t size)
+{
+	UINTN npages = EFI_SIZE_TO_PAGES(size);
+
+	return uefi_call_wrapper(BS->AllocatePages, 4,
+				   AllocateAddress,
+				   EfiLoaderData, npages,
+				   addr);
+}
+/**
+ * allocate_pool - Allocate pool memory
+ * @type: the type of pool to allocate
+ * @size: number of bytes to allocate from pool of @type
+ * @buffer: used to return the address of allocated memory
+ *
+ * Allocate memory from pool of @type. If the pool needs more memory
+ * pages are allocated from EfiConventionalMemory in order to grow the
+ * pool.
+ *
+ * All allocations are eight-byte aligned.
+ */
+static inline EFI_STATUS
+allocate_pool(EFI_MEMORY_TYPE type, UINTN size, void **buffer)
+{
+	return uefi_call_wrapper(BS->AllocatePool, 3, type, size, buffer);
+}
+
+/**
+ * free_pool - Return pool memory to the system
+ * @buffer: the buffer to free
+ *
+ * Return @buffer to the system. The returned memory is marked as
+ * EfiConventionalMemory.
+ */
+static inline EFI_STATUS free_pool(void *buffer)
+{
+	return uefi_call_wrapper(BS->FreePool, 1, buffer);
+}
+
+static void free_addr(EFI_PHYSICAL_ADDRESS addr, size_t size)
+{
+	UINTN npages = EFI_SIZE_TO_PAGES(size);
+
+	uefi_call_wrapper(BS->FreePages, 2, addr, npages);
+}
+
+/* cancel the established timer */
+static EFI_STATUS cancel_timer(EFI_EVENT ev)
+{
+	return uefi_call_wrapper(BS->SetTimer, 3, ev, TimerCancel, 0);
+}
+
+/* Check if timer went off and update default timer counter */
+void timer_handler(EFI_EVENT ev, VOID *ctx)
+{
+	__ms_timer += DEFAULT_MSTIMER_INC;
+	++__jiffies;
+}
+
+/* Setup a default periodic timer */
+static EFI_STATUS setup_default_timer(EFI_EVENT *ev)
+{
+	EFI_STATUS efi_status;
+
+	*ev = NULL;
+	efi_status = uefi_call_wrapper( BS->CreateEvent, 5, EVT_TIMER|EVT_NOTIFY_SIGNAL, TPL_NOTIFY, (EFI_EVENT_NOTIFY)timer_handler, NULL, ev);
+	if (efi_status == EFI_SUCCESS) {
+		efi_status = uefi_call_wrapper(BS->SetTimer, 3, *ev, TimerPeriodic, DEFAULT_TIMER_TICK_DURATION);
+	}
+	return efi_status;
+}
+
+/**
+ * emalloc - Allocate memory with a strict alignment requirement
+ * @size: size in bytes of the requested allocation
+ * @align: the required alignment of the allocation
+ * @addr: a pointer to the allocated address on success
+ *
+ * If we cannot satisfy @align we return 0.
+ */
+EFI_STATUS emalloc(UINTN size, UINTN align, EFI_PHYSICAL_ADDRESS *addr)
+{
+	UINTN nr_entries, map_key, desc_size;
+	EFI_MEMORY_DESCRIPTOR *map_buf;
+	UINTN d;
+	UINT32 desc_version;
+	EFI_STATUS err;
+	UINTN nr_pages = EFI_SIZE_TO_PAGES(size);
+	int i;
+
+	map_buf = get_memory_map(&nr_entries, &map_key,
+				 &desc_size, &desc_version);
+	if (!map_buf)
+		goto fail;
+
+	d = (UINTN)map_buf;
+
+	for (i = 0; i < nr_entries; i++, d += desc_size) {
+		EFI_MEMORY_DESCRIPTOR *desc;
+		EFI_PHYSICAL_ADDRESS start, end, aligned;
+
+		desc = (EFI_MEMORY_DESCRIPTOR *)d;
+		if (desc->Type != EfiConventionalMemory)
+			continue;
+
+		if (desc->NumberOfPages < nr_pages)
+			continue;
+
+		start = desc->PhysicalStart;
+		end = start + (desc->NumberOfPages << EFI_PAGE_SHIFT);
+
+		/* Low-memory is super-precious! */
+		if (end <= 1 << 20)
+			continue;
+		if (start < 1 << 20) {
+			size -= (1 << 20) - start;
+			start = (1 << 20);
+		}
+
+		aligned = (start + align -1) & ~(align -1);
+
+		if ((aligned + size) <= end) {
+			err = allocate_pages(AllocateAddress, EfiLoaderData,
+					     nr_pages, &aligned);
+			if (err == EFI_SUCCESS) {
+				*addr = aligned;
+				break;
+			}
+		}
+	}
+
+	if (i == nr_entries)
+		err = EFI_OUT_OF_RESOURCES;
+
+	free_pool(map_buf);
+fail:
+	return err;
+}
+/**
+ * efree - Return memory allocated with emalloc
+ * @memory: the address of the emalloc() allocation
+ * @size: the size of the allocation
+ */
+void efree(EFI_PHYSICAL_ADDRESS memory, UINTN size)
+{
+	UINTN nr_pages = EFI_SIZE_TO_PAGES(size);
+
+	free_pages(memory, nr_pages);
+}
+
+/* efi_boot_linux: 
+ * Boots the linux kernel using the image and parameters to boot with.
+ * The EFI boot loader is reworked taking the cue from
+ * http://git.kernel.org/?p=boot/efilinux/efilinux.git on the need to
+ * cap key kernel data structures at * 0x3FFFFFFF.
+ * The kernel image, kernel command line and boot parameter block are copied
+ * into allocated memory areas that honor the address capping requirement
+ * prior to kernel handoff. 
+ *
+ * FIXME
+ * Can we move this allocation requirement to com32 linux loader in order
+ * to avoid double copying kernel image?
+ */
+int efi_boot_linux(void *kernel_buf, size_t kernel_size,
+		   struct initramfs *initramfs,
+		   struct setup_data *setup_data,
+		   char *cmdline)
+{
+	EFI_MEMORY_DESCRIPTOR *map;
+	struct linux_header *hdr, *bhdr;
+	struct boot_params *bp;
+	struct boot_params *_bp; /* internal, in efi_physical below 0x3FFFFFFF */
+	struct screen_info *si;
+	struct e820_entry *e820buf, *e;
+	EFI_STATUS status;
+	EFI_PHYSICAL_ADDRESS last, addr, pref_address, kernel_start = 0;
+	UINT64 setup_sz, init_size = 0;
+	UINTN nr_entries, key, desc_sz;
+	UINT32 desc_ver;
+	uint32_t e820_type;
+	addr_t irf_size;
+	int i;
+	char *_cmdline = NULL; /* internal, in efi_physical below 0x3FFFFFFF */
+
+	hdr = (struct linux_header *)kernel_buf;
+	bp = (struct boot_params *)hdr;
+	/*
+	 * We require a relocatable kernel because we have no control
+	 * over free memory in the memory map.
+	 */
+	if (hdr->version < 0x20a || !hdr->relocatable_kernel) {
+		printf("bzImage version 0x%x unsupported\n", hdr->version);
+		goto bail;
+	}
+
+	/* FIXME: check boot sector signature */
+	if (hdr->boot_flag != BOOT_SIGNATURE) {
+		printf("Invalid Boot signature 0x%x, bailing out\n", hdr->boot_flag);
+		goto bail;
+	}
+
+	setup_sz = (hdr->setup_sects + 1) * 512;
+	if (hdr->version >= 0x20a) {
+		pref_address = hdr->pref_address;
+		init_size = hdr->init_size;
+	} else {
+		pref_address = 0x100000;
+
+		/*
+		 * We need to account for the fact that the kernel
+		 * needs room for decompression, otherwise we could
+		 * end up trashing other chunks of allocated memory.
+		 */
+		init_size = (kernel_size - setup_sz) * 3;
+	}
+	hdr->type_of_loader = SYSLINUX_EFILDR;	/* SYSLINUX boot loader module */
+	/*
+	 * The kernel expects cmdline to be allocated pretty low,
+	 * Documentation/x86/boot.txt says,
+	 *
+	 *	"The kernel command line can be located anywhere
+	 *	between the end of the setup heap and 0xA0000"
+	 */
+	addr = 0xA0000;
+	status = allocate_pages(AllocateMaxAddress, EfiLoaderData,
+			     EFI_SIZE_TO_PAGES(strlen(cmdline) + 1),
+			     &addr);
+	if (status != EFI_SUCCESS) {
+		printf("Failed to allocate memory for kernel command line, bailing out\n");
+		goto bail;
+	}
+	_cmdline = (char *)(UINTN)addr;
+	memcpy(_cmdline, cmdline, strlen(cmdline) + 1);
+	hdr->cmd_line_ptr = (UINT32)(UINTN)_cmdline;
+	memset((char *)&bp->screen_info, 0x0, sizeof(bp->screen_info));
+
+	addr = pref_address;
+	status = allocate_pages(AllocateAddress, EfiLoaderData,
+			     EFI_SIZE_TO_PAGES(init_size), &addr);
+	if (status != EFI_SUCCESS) {
+		/*
+		 * We failed to allocate the preferred address, so
+		 * just allocate some memory and hope for the best.
+		 */
+		status = emalloc(init_size, hdr->kernel_alignment, &addr);
+		if (status != EFI_SUCCESS) {
+			printf("Failed to allocate memory for kernel image, bailing out\n");
+			goto free_map;
+		}
+	}
+	kernel_start = addr;
+	/* FIXME: we copy the kernel into the physical memory allocated here
+	 * The syslinux kernel image load elsewhere could allocate the EFI memory from here
+	 * prior to copying kernel and save an extra copy
+	 */
+	memcpy((void *)(UINTN)kernel_start, kernel_buf+setup_sz, kernel_size-setup_sz);
+
+	/* allocate for boot parameter block */
+	addr = 0x3FFFFFFF;
+	status = allocate_pages(AllocateMaxAddress, EfiLoaderData,
+			     BOOT_PARAM_BLKSIZE, &addr);
+	if (status != EFI_SUCCESS) {
+		printf("Failed to allocate memory for kernel boot parameter block, bailing out\n");
+		goto free_map;
+	}
+
+	_bp = (struct boot_params *)(UINTN)addr;
+
+	memset((void *)_bp, 0x0, BOOT_PARAM_BLKSIZE);
+	/* Copy the first two sectors to boot_params */
+	memcpy((char *)_bp, kernel_buf, 2 * 512);
+	bhdr = (struct linux_header *)_bp;
+	bhdr->code32_start = (UINT32)((UINT64)kernel_start);
+
+	dprintf("efi_boot_linux: kernel_start 0x%x kernel_size 0x%x initramfs 0x%x setup_data 0x%x cmdline 0x%x\n",
+	kernel_start, kernel_size, initramfs, setup_data, _cmdline);
+	si = &_bp->screen_info;
+	memset(si, 0, sizeof(*si));
+	setup_screen(si);
+
+	/*
+	 * FIXME: implement handover protocol 
+	 * Use the kernel's EFI boot stub by invoking the handover
+	 * protocol.
+	 */
+	/* Allocate gdt consistent with the alignment for architecture */
+	status = emalloc(gdt.limit, __SIZEOF_POINTER__ , (EFI_PHYSICAL_ADDRESS *)&gdt.base);
+	if (status != EFI_SUCCESS) {
+		printf("Failed to allocate memory for GDT, bailing out\n");
+		goto free_map;
+	}
+	memset(gdt.base, 0x0, gdt.limit);
+
+	/*
+         * 4Gb - (0x100000*0x1000 = 4Gb)
+         * base address=0
+         * code read/exec
+         * granularity=4096, 386 (+5th nibble of limit)
+         */
+        gdt.base[2] = 0x00cf9a000000ffff;
+
+        /*
+         * 4Gb - (0x100000*0x1000 = 4Gb)
+         * base address=0
+         * data read/write
+         * granularity=4096, 386 (+5th nibble of limit)
+         */
+        gdt.base[3] = 0x00cf92000000ffff;
+
+        /* Task segment value */
+        gdt.base[4] = 0x0080890000000000;
+
+	dprintf("efi_boot_linux: setup_sects %d kernel_size %d\n", hdr->setup_sects, kernel_size);
+
+	/*
+	 * Figure out the size of the initramfs, and where to put it.
+	 * We should put it at the highest possible address which is
+	 * <= hdr->initrd_addr_max, which fits the entire initramfs.
+	 */
+	irf_size = initramfs_size(initramfs);	/* Handles initramfs == NULL */
+	if (irf_size) {
+		struct initramfs *ip;
+		addr_t next_addr, len, pad;
+
+		last = 0;
+		find_addr(NULL, &last, 0x1000, hdr->initrd_addr_max,
+			  irf_size, INITRAMFS_MAX_ALIGN);
+		if (last)
+			status = allocate_addr(&last, irf_size);
+
+		if (!last || status != EFI_SUCCESS) {
+			printf("Failed to allocate initramfs memory, bailing out\n");
+			goto free_map;
+		}
+
+		bhdr->ramdisk_image = (uint32_t)last;
+		bhdr->ramdisk_size = irf_size;
+
+		/* Copy initramfs into allocated memory */
+		for (ip = initramfs->next; ip->len; ip = ip->next) {
+			len = ip->len;
+			next_addr = last + len;
+
+			/*
+			 * If this isn't the last entry, extend the
+			 * zero-pad region to enforce the alignment of
+			 * the next chunk.
+			 */
+			if (ip->next->len) {
+				pad = -next_addr & (ip->next->align - 1);
+				len += pad;
+				next_addr += pad;
+			}
+
+			if (ip->data_len)
+				memcpy((void *)(UINTN)last, ip->data, ip->data_len);
+
+			if (len > ip->data_len)
+				memset((void *)(UINTN)(last + ip->data_len), 0,
+				       len - ip->data_len);
+
+			last = next_addr;
+		}
+	}
+
+	/* Build efi memory map */
+	map = get_memory_map(&nr_entries, &key, &desc_sz, &desc_ver);
+	if (!map)
+		goto free_map;
+
+	_bp->efi.memmap = (uint32_t)(uint64_t)map;
+	_bp->efi.memmap_size = nr_entries * desc_sz;
+	_bp->efi.systab = (uint32_t)(uint64_t)ST;
+	_bp->efi.desc_size = desc_sz;
+	_bp->efi.desc_version = desc_ver;
+#if defined(__x86_64__)
+        _bp->efi.systab_hi = ((unsigned long)ST) >> 32;
+        _bp->efi.memmap_hi = ((unsigned long)map) >> 32;
+#endif
+
+
+	/*
+	 * Even though 'memmap' contains the memory map we provided
+	 * previously in efi_scan_memory(), we should recalculate the
+	 * e820 map because it will most likely have changed in the
+	 * interim.
+	 */
+	e = e820buf = _bp->e820_map;
+	for (i = 0; i < nr_entries && i < E820MAX; i++) {
+		struct e820_entry *prev = NULL;
+
+		if (e > e820buf)
+			prev = e - 1;
+
+		map = get_mem_desc(_bp->efi.memmap, desc_sz, i);
+		e->start = map->PhysicalStart;
+		e->len = map->NumberOfPages << EFI_PAGE_SHIFT;
+
+		switch (map->Type) {
+		case EfiReservedMemoryType:
+                case EfiRuntimeServicesCode:
+                case EfiRuntimeServicesData:
+                case EfiMemoryMappedIO:
+                case EfiMemoryMappedIOPortSpace:
+                case EfiPalCode:
+                        e820_type = E820_RESERVED;
+                        break;
+
+                case EfiUnusableMemory:
+                        e820_type = E820_UNUSABLE;
+                        break;
+
+                case EfiACPIReclaimMemory:
+                        e820_type = E820_ACPI;
+                        break;
+
+                case EfiLoaderCode:
+                case EfiLoaderData:
+                case EfiBootServicesCode:
+                case EfiBootServicesData:
+                case EfiConventionalMemory:
+			e820_type = E820_RAM;
+			break;
+
+		case EfiACPIMemoryNVS:
+			e820_type = E820_NVS;
+			break;
+		default:
+			continue;
+		}
+
+		e->type = e820_type;
+
+		/* Check for adjacent entries we can merge. */
+		if (prev && (prev->start + prev->len) == e->start &&
+		    prev->type == e->type)
+			prev->len += e->len;
+		else
+			e++;
+	}
+
+	_bp->e820_entries = e - e820buf;
+
+	dprintf("efi_boot_linux: exit boot services\n");
+	status = uefi_call_wrapper(BS->ExitBootServices, 2, image_handle, key);
+	if (status != EFI_SUCCESS) {
+		printf("Failed to exit boot services: 0x%016lx\n", status);
+		goto free_map;
+	}
+	memcpy(&_bp->efi.load_signature, EFI_LOAD_SIG, sizeof(uint32_t));
+
+	asm volatile ("lidt %0" :: "m" (idt));
+	asm volatile ("lgdt %0" :: "m" (gdt));
+
+	kernel_jump(kernel_start, _bp);
+
+	/* NOTREACHED */
+
+free_map:
+	if (_cmdline) efree((EFI_PHYSICAL_ADDRESS)_cmdline, strlen(_cmdline) + 1);
+	if (_bp) efree((EFI_PHYSICAL_ADDRESS)_bp, BOOT_PARAM_BLKSIZE);
+	if (kernel_start) efree(kernel_start, init_size);
+	FreePool(map);
+	if (irf_size)
+		free_addr(last, irf_size);
+bail:
+	return -1;
+}
+
+extern struct disk *efi_disk_init(EFI_HANDLE);
+extern void serialcfg(uint16_t *, uint16_t *, uint16_t *);
+
+extern struct vesa_ops efi_vesa_ops;
+
+struct mem_ops efi_mem_ops = {
+	.malloc = efi_malloc,
+	.realloc = efi_realloc,
+	.free = efi_free,
+	.scan_memory = efi_scan_memory,
+};
+
+struct firmware efi_fw = {
+	.init = efi_init,
+	.disk_init = efi_disk_init,
+	.o_ops = &efi_ops,
+	.i_ops = &efi_iops,
+	.get_serial_console_info = serialcfg,
+	.ipappend_strings = efi_ipappend_strings,
+	.adv_ops = &efi_adv_ops,
+	.boot_linux = efi_boot_linux,
+	.vesa = &efi_vesa_ops,
+	.mem = &efi_mem_ops,
+};
+
+static inline void syslinux_register_efi(void)
+{
+	firmware = &efi_fw;
+}
+
+extern void init(void);
+extern const struct fs_ops vfat_fs_ops;
+
+char free_high_memory[4096];
+
+extern char __bss_start[];
+extern char __bss_end[];
+
+static void efi_setcwd(CHAR16 *dp)
+{
+	CHAR16 *c16;
+	char *c8;
+	int i, j;
+
+	/* Search for the start of the last path component */
+	for (i = StrLen(dp) - 1; i >= 0; i--) {
+		if (dp[i] == '\\' || dp[i] == '/')
+			break;
+	}
+
+	if (i < 0 || i > CURRENTDIR_MAX) {
+		dp = L"\\";
+		i = 1;
+	}
+
+	c8 = CurrentDirName;
+	c16 = dp;
+
+	for (j = 0; j < i; j++) {
+		if (*c16 == '\\') {
+			*c8++ = '/';
+			c16++;
+		} else
+			*c8++ = *c16++;
+	}
+
+	*c8 = '\0';
+}
+
+EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *table)
+{
+	EFI_LOADED_IMAGE *info;
+	EFI_STATUS status = EFI_SUCCESS;
+	const struct fs_ops *ops[] = { &vfat_fs_ops, NULL };
+	unsigned long len = (unsigned long)__bss_end - (unsigned long)__bss_start;
+	static struct efi_disk_private priv;
+	SIMPLE_INPUT_INTERFACE *in;
+	EFI_INPUT_KEY key;
+	EFI_EVENT timer_ev;
+
+	memset(__bss_start, 0, len);
+	InitializeLib(image, table);
+
+	image_handle = image;
+	syslinux_register_efi();
+	init();
+
+	status = uefi_call_wrapper(BS->HandleProtocol, 3, image,
+				   &LoadedImageProtocol, (void **)&info);
+	if (status != EFI_SUCCESS) {
+		Print(L"Failed to lookup LoadedImageProtocol\n");
+		goto out;
+	}
+
+	/* Use device handle to set up the volume root to proceed with ADV init */
+	if (EFI_ERROR(efi_set_volroot(info->DeviceHandle))) {
+		Print(L"Failed to locate root device to prep for file operations & ADV initialization\n");
+		goto out;
+	}
+	/* setup timer for boot menu system support */
+	status = setup_default_timer(&timer_ev);
+	if (status != EFI_SUCCESS) {
+		printf("Failed to set up EFI timer support, bailing out\n");
+		goto out;
+	}
+
+	/* TODO: once all errors are captured in efi_errno, bail out if necessary */
+
+	/* XXX figure out what file system we're on */
+	priv.dev_handle = info->DeviceHandle;
+
+	/*
+	 * Set the current working directory, which should be the
+	 * directory that syslinux.efi resides in.
+	 */
+	efi_setcwd(DevicePathToStr(info->FilePath));
+
+	fs_init(ops, (void *)&priv);
+
+	/*
+	 * There may be pending user input that wasn't processed by
+	 * whatever application invoked us. Consume and discard that
+	 * data now.
+	 */
+	in = ST->ConIn;
+	do {
+		status = uefi_call_wrapper(in->ReadKeyStroke, 2, in, &key);
+	} while (status != EFI_NOT_READY);
+
+	load_env32();
+
+	/* load_env32() failed.. cancel timer and bailout */
+	status = cancel_timer(timer_ev);
+	if (status != EFI_SUCCESS)
+		Print(L"Failed to cancel EFI timer: %x\n", status);
+
+	/*
+	 * Tell the firmware that Syslinux failed to load.
+	 */
+	status = EFI_LOAD_ERROR;
+out:
+	return status;
+}
diff --git a/efi/mem.c b/efi/mem.c
new file mode 100644
index 0000000..6203ff2
--- /dev/null
+++ b/efi/mem.c
@@ -0,0 +1,22 @@
+#include <mem/malloc.h>
+#include "efi.h"
+
+void *efi_malloc(size_t size, enum heap heap, malloc_tag_t tag)
+{
+	return AllocatePool(size);
+}
+
+void *efi_realloc(void *ptr, size_t size)
+{
+	void *newptr;
+
+	newptr = AllocatePool(size);
+	memcpy(newptr, ptr, size);
+	FreePool(ptr);
+	return newptr;
+}
+
+void efi_free(void *ptr)
+{
+	FreePool(ptr);
+}
diff --git a/efi/syslinux.ld b/efi/syslinux.ld
new file mode 100644
index 0000000..e027053
--- /dev/null
+++ b/efi/syslinux.ld
@@ -0,0 +1,176 @@
+/* -----------------------------------------------------------------------
+ *   
+ *   Copyright 2008-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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Linker script for the SYSLINUX core
+ */
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_start)
+
+SECTIONS
+{
+	. = 0;
+	ImageBase = .;		/* For gnu-efi's crt0 */
+	__module_start = .;
+	. = SEGMENT_START("text-segment", 0) + SIZEOF_HEADERS;
+	.text : {
+		FILL(0x90909090)
+		__text_start = .;
+		*(.text)
+		*(.text.*)
+		__text_end = .;
+	}
+
+	. = ALIGN(16);
+
+	.rodata : {
+		__rodata_start = .;
+		*(.rodata)
+		*(.rodata.*)
+		__rodata_end = .;
+	}
+
+	. = ALIGN(4);
+
+	.ctors : {
+		__ctors_start = .;
+		KEEP (*(SORT(.ctors.*)))
+		KEEP (*(.ctors))
+		__ctors_end = .;
+	}
+
+	.dtors : {
+		__dtors_start = .;
+		KEEP (*(SORT(.dtors.*)))
+		KEEP (*(.dtors))
+		__dtors_end = .;
+	}
+
+	. = ALIGN(4096);
+	.rel : {
+		*(.rel.got)
+		*(.rel.data)
+		*(.rel.data.*)
+		*(.rel.ctors)
+	}
+
+	. = ALIGN(4);
+
+	.gnu.hash : {
+		__gnu_hash_start = .;
+		*(.gnu.hash)
+		__gnu_hash_end = .;
+	}
+
+
+	.dynsym : {
+		__dynsym_start = .;
+		*(.dynsym)
+		__dynsym_end = .;
+	}
+
+	. = ALIGN(4);
+
+	.dynstr : {
+		__dynstr_start = .;
+		*(.dynstr)
+		__dynstr_end = .;
+	}
+
+	. = ALIGN(4);
+
+	.dynlink : {
+		__dynlink_start = .;
+		*(.dynlink)
+		__dynlink_end = .;
+	}
+
+	. = ALIGN(4);
+
+	.got : {
+		__got_start = .;
+		KEEP (*(.got.plt))
+		KEEP (*(.got))
+		__got_end = .;
+	}
+
+	. = ALIGN(4);
+
+	.dynamic : {
+		__dynamic_start = .;
+		*(.dynamic)
+		__dynamic_end = .;
+	}
+
+	. = ALIGN(16);
+
+	.data : {
+		__data_start = .;
+		*(.data)
+		*(.data.*)
+		*(.lowmem)
+		__data_end = .;
+	}
+
+	.reloc : {
+		*(.reloc)
+	}
+
+	.comment : {
+		*(.commet)
+	}
+
+	.symtab : {
+		*(.symtab)
+	}
+
+	.strtab : {
+		*(.strtab)
+	}
+
+	.bss : {
+		/* the EFI loader doesn't seem to like a .bss section,
+		   so we stick it all into .data: */
+		__bss_start = .;
+		*(.bss)
+		*(.bss.*)
+		*(.bss16)
+		*(.hugebss)
+		*(COMMON)
+		__bss_end = .;
+		*(.sbss)
+		*(.scommon)
+	}
+	__bss_len = ABSOLUTE(__bss_end) - ABSOLUTE(__bss_start);
+	__bss_dwords = (__bss_len + 3) >> 2;
+
+	. = ALIGN(128);
+	
+	/* Very large objects which don't need to be zeroed */
+
+	.hugebss : {
+		__hugebss_start = .;
+		*(.hugebss)
+		*(.hugebss.*)
+		__hugebss_end = .;
+	}
+
+	_end = .;
+
+	/* Stuff we don't need... */
+	/DISCARD/ : {
+		*(.eh_frame)
+	}
+}
diff --git a/efi/vesa.c b/efi/vesa.c
new file mode 100644
index 0000000..e3e9e0f
--- /dev/null
+++ b/efi/vesa.c
@@ -0,0 +1,312 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 1999-2012 H. Peter Anvin - All Rights Reserved
+ *   Chandramouli Narayanan - extended for EFI support
+ *
+ *   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 <inttypes.h>
+#include <com32.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/fpu.h>
+#include <syslinux/video.h>
+#include <dprintf.h>
+#include <efi.h>
+#include <efilib.h>
+#include <efistdarg.h>
+/* We use cp865_8x16.psf as the standard font for EFI implementation
+ * the header file below contains raw data parsed from cp865_8x16.psf
+ */
+#include "cp865_8x16.h"
+#include "sys/vesa/vesa.h"
+#include "sys/vesa/video.h"
+#include "sys/vesa/fill.h"
+#include "sys/vesa/debug.h"
+
+/* EFI GOP support
+ * Note GOP support uses the VESA info structure as much as possible and
+ * extends it as needed for EFI support. Not all of the vesa info structure
+ * is populated. Care must be taken in the routines that rely the vesa
+ * informataion structure
+ */
+static void find_pixmask_bits(uint32_t mask, uint8_t *first_bit, uint8_t *len) {
+    uint8_t bit_pos = 0, bit_len = 0;
+
+    *first_bit = 0;
+    *len = 0;
+    if (mask == 0)
+	return;
+    while (!(mask & 0x1)) {
+	mask = mask >> 1;
+	bit_pos++;
+    }
+    while (mask & 0x1) {
+	mask = mask >> 1;
+	bit_len++;
+    }
+    *first_bit = bit_pos;
+    *len = bit_len;
+}
+
+unsigned long lfb_size;
+uint16_t lfb_line_size;
+uint8_t lfb_rsize;
+uint8_t lfb_gsize;
+uint8_t lfb_bsize;
+uint8_t lfb_resv_size;
+
+static int efi_vesacon_set_mode(struct vesa_info *vesa_info, int *x, int *y,
+				enum vesa_pixel_format *bestpxf)
+{
+    EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
+    EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL;
+    EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *gop_mode;
+    EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *mode_info;
+    EFI_STATUS st;
+    UINT32 mode_num = 0, bestmode;
+    BOOLEAN mode_match = FALSE;
+    UINTN sz_info;
+    struct vesa_info *vi;
+    struct vesa_mode_info *mi;
+    int err = 0;
+
+    //debug("Hello, World!\r\n");
+    /* At this point, we assume that gnu-efi library is initialized */
+    st = LibLocateProtocol(&GraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);
+    if (EFI_ERROR(st)) {
+	debug("LiblocateProtocol for GOP failed %d\n", st);
+	return 1; /* function call failed */
+    }
+
+    /* We use the VESA info structure to store relevant GOP info as much as possible */
+    gop_mode = GraphicsOutput->Mode;
+
+    mode_info = gop_mode->Info;
+    dprintf("mode %d version %d pixlfmt %d hres=%d vres=%d\n", mode_num, 
+			mode_info->Version, mode_info->PixelFormat,
+			mode_info->HorizontalResolution, mode_info->VerticalResolution);
+    
+    /* simply pick the best mode that suits the caller's resolution */
+    for (mode_num = 0; mode_num < gop_mode->MaxMode; mode_num++) {
+	st = uefi_call_wrapper(GraphicsOutput->QueryMode, 4, GraphicsOutput, mode_num, &sz_info, &mode_info);
+	debug("mode_num = %d query_status %d\n", mode_num, st);
+	if (st == EFI_SUCCESS && sz_info >= sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)) {
+
+		/* For now, simply pick the best mode that suits caller's resolution (x,y)
+		 * FIXME: Consider any additional criteria for matching mode
+		 */
+		mode_match = ((uint32_t)*x == mode_info->HorizontalResolution && (uint32_t)*y == mode_info->VerticalResolution);
+		debug("mode %d hres=%d vres=%d\n", mode_num, mode_info->HorizontalResolution, mode_info->VerticalResolution);
+		if (mode_match) {
+			bestmode = mode_num;
+			break;
+		}
+	}
+    }
+
+    if (!mode_match) {
+	/* Instead of bailing out, set the mode to the system default.
+ 	 * Some systems do not have support for 640x480 for instance
+ 	 * This code deals with such cases.
+ 	 */
+	mode_info = gop_mode->Info;
+	*x = mode_info->HorizontalResolution;
+	*y = mode_info->VerticalResolution;
+	bestmode = gop_mode->Mode;
+	debug("No matching mode, setting to available default mode %d (x=%d, y=%d)\n", bestmode, *x, *y);
+    }
+
+    /* Allocate space in the bounce buffer for these structures */
+    vi = malloc(sizeof(*vi));
+    if (!vi) {
+	err = 10;		/* Out of memory */
+	goto exit;
+    }
+    /* Note that the generic info is untouched as we don't find any relevance to EFI */
+    mi = &vi->mi;
+    /* Set up mode-specific information */
+    mi->h_res = *x;
+    mi->v_res = *y;
+    mi->lfb_ptr = (uint8_t *)(VOID *)(UINTN)gop_mode->FrameBufferBase;
+    lfb_size = gop_mode->FrameBufferSize;
+
+    /* FIXME: 
+     * The code below treats bpp == lfb_depth ; verify
+     */
+
+    switch (mode_info->PixelFormat) {
+    case PixelRedGreenBlueReserved8BitPerColor:
+	dprintf("RGB8bit ");
+	mi->mode_attr = 0x0080;		/* supports physical frame buffer */
+	mi->bpp = sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * 8;
+	mi->rpos = 0;
+	mi->gpos = 8;
+	mi->bpos = 16;
+	mi->resv_pos = 24;
+	lfb_resv_size = 8;
+	mi->logical_scan = lfb_line_size = (mode_info->PixelsPerScanLine * mi->bpp) / 8;
+	*bestpxf = PXF_BGRA32;
+	dprintf("bpp %d pixperScanLine %d logical_scan %d bytesperPix %d\n", mi->bpp, mode_info->PixelsPerScanLine, 
+		mi->logical_scan, (mi->bpp + 7)>>3);
+	break;
+    case PixelBlueGreenRedReserved8BitPerColor:
+	dprintf("BGR8bit ");
+	mi->mode_attr = 0x0080;		/* supports physical frame buffer */
+	mi->bpp = sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * 8;
+	mi->bpos = 0;
+	mi->gpos = 8;
+	mi->rpos = 16;
+	mi->resv_pos = 24;
+	lfb_resv_size = 8;
+	mi->logical_scan = lfb_line_size = (mode_info->PixelsPerScanLine * mi->bpp) / 8;
+	*bestpxf = PXF_BGRA32;
+	dprintf("bpp %d pixperScanLine %d logical_scan %d bytesperPix %d\n", mi->bpp, mode_info->PixelsPerScanLine, 
+		mi->logical_scan, (mi->bpp + 7)>>3);
+	break;
+    case PixelBitMask:
+	mi->mode_attr = 0x0080;		/* supports physical frame buffer */
+	dprintf("RedMask 0x%x GrnMask 0x%x BluMask 0x%x RsvMask 0x%x\n",
+		mode_info->PixelInformation.RedMask,
+		mode_info->PixelInformation.GreenMask,
+		mode_info->PixelInformation.BlueMask,
+		mode_info->PixelInformation.ReservedMask);
+	find_pixmask_bits(mode_info->PixelInformation.RedMask,
+                          &mi->rpos, &lfb_rsize);
+	find_pixmask_bits(mode_info->PixelInformation.GreenMask,
+                          &mi->gpos, &lfb_gsize);
+	find_pixmask_bits(mode_info->PixelInformation.BlueMask,
+                          &mi->bpos, &lfb_bsize);
+	find_pixmask_bits(mode_info->PixelInformation.ReservedMask,
+                          &mi->resv_pos, &lfb_resv_size);
+	mi->bpp = lfb_rsize + lfb_gsize +
+                                  lfb_bsize + lfb_resv_size;
+	mi->logical_scan = lfb_line_size = (mode_info->PixelsPerScanLine * mi->bpp) / 8;
+	dprintf("RPos %d Rsize %d GPos %d Gsize %d\n", mi->rpos, lfb_rsize, mi->gpos, lfb_gsize);
+	dprintf("BPos %d Bsize %d RsvP %d RsvSz %d\n", mi->bpos, lfb_bsize, mi->resv_pos, lfb_resv_size);
+	dprintf("bpp %d logical_scan %d bytesperPix %d\n", mi->bpp, mi->logical_scan, (mi->bpp + 7)>>3);
+	switch (mi->bpp) {
+	case 32:
+		*bestpxf = PXF_BGRA32;
+		break;
+	case 24:
+		*bestpxf = PXF_BGR24;
+		break;
+	case 16:
+		*bestpxf = PXF_LE_RGB16_565;
+		break;
+	default:
+		dprintf("Unable to handle bits per pixel %d, bailing out\n", mi->bpp);
+		err = 4;
+		goto exit;
+	}
+	break;
+    case PixelBltOnly:
+	/* FIXME: unsupported */
+	mi->mode_attr = 0x0000;		/* no support for physical frame buffer */
+	err = 4; /* no mode found */
+	goto exit;
+	break;
+    default:
+	/* should not get here, but let's error out */
+	err = 4; /* no mode found */
+	goto exit;
+	break;
+    }		   
+    
+    memcpy(&vesa_info->mi, mi, sizeof *mi);
+
+    /* Now set video mode */
+    st = uefi_call_wrapper(GraphicsOutput->SetMode, 2, GraphicsOutput, bestmode);
+    if (EFI_ERROR(st)) {
+	err = 9;		/* Failed to set mode */
+	dprintf("Failed to set mode %d\n", bestmode);
+	goto exit;
+    }	
+
+    /* TODO: Follow the code usage of vesacon_background & vesacon_shadowfb */
+    /*
+     __vesacon_background = calloc(mi->h_res*mi->v_res, 4);
+     __vesacon_shadowfb = calloc(mi->h_res*mi->v_res, 4);
+     */
+     /* FIXME: the allocation takes the possible padding into account
+      * whereas   BIOS code simply allocates hres * vres bytes.
+      * Which is correct?
+      */
+     /*
+      * For performance reasons, or due to hardware restrictions, scan lines
+      * may be padded to an amount of memory alignment. These padding pixel elements
+      * are outside the area covered by HorizontalResolution and are not visible.
+      * For direct frame buffer access, this number is used as a span between starts
+      * of pixel lines in video memory. Based on the size of an individual pixel element
+      * and PixelsPerScanline, the offset in video memory from pixel element (x, y)
+      * to pixel element (x, y+1) has to be calculated as 
+      * "sizeof( PixelElement ) * PixelsPerScanLine", and not 
+      * "sizeof( PixelElement ) * HorizontalResolution", though in many cases
+      * those values can coincide.
+      */
+
+exit:
+    if (vi)
+	free(vi);
+
+    return err;
+}
+
+static void efi_vesacon_screencpy(size_t dst, const uint32_t *s,
+				  size_t bytes, struct win_info *wi)
+{
+    size_t win_off;
+    char *win_base = wi->win_base;
+ 
+    /* For EFI, we simply take the offset from the framebuffer and write to it
+     * FIXME: any gotchas?
+     */
+    win_off = dst;
+    memcpy(win_base + win_off, s, bytes);
+}
+
+static int efi_vesacon_font_query(uint8_t **font)
+{
+    /* set up font info
+     * For now, font info is stored as raw data and used
+     * as such. Altenatively, the font data stored in a file 
+     * could be read and parsed. (note: for this, EFI
+     * file support should be exposed via firmware structure)
+     */
+    *font = (uint8_t *)cp865_8x16_font_data;
+    return cp865_8x16_font_height;
+}
+
+int __vesacon_i915resolution(int x, int y)
+{
+	/* We don't support this function */
+	return 1;
+}
+
+struct vesa_ops efi_vesa_ops = {
+	.set_mode = efi_vesacon_set_mode,
+	.screencpy = efi_vesacon_screencpy,
+	.font_query = efi_vesacon_font_query,
+};
diff --git a/efi/wrapper.c b/efi/wrapper.c
new file mode 100644
index 0000000..0943534
--- /dev/null
+++ b/efi/wrapper.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2011 Intel Corporation; author Matt Fleming
+ *
+ * Wrap the ELF shared library in a PE32 (32bit) or PE32+ (64bit) suit.
+ *
+ * Syslinux plays some games with the ELF sections that are not easily
+ * converted to a PE32 executable. For instance, Syslinux requires
+ * that a symbol hash table be present (GNU hash or SysV) so that
+ * symbols in ELF modules can be resolved at runtime but the EFI
+ * firmware loader doesn't like that and refuses to load the file.
+ *
+ * We pretend that we have an EFI executable with a single .text
+ * section so that the EFI loader will load it and jump to the entry
+ * point. Once the Syslinux ELF shared object has control we can do
+ * whatever we want.
+ */
+#include <linux/elf.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "wrapper.h"
+
+#if __SIZEOF_POINTER__ == 4
+typedef Elf32_Ehdr Elf_Ehdr;
+typedef Elf32_Addr Elf_Addr;
+#elif __SIZEOF_POINTER__ == 8
+typedef Elf64_Ehdr Elf_Ehdr;
+typedef Elf64_Addr Elf_Addr;
+#else
+#error "unsupported architecture"
+#endif
+
+/*
+ * 'so_size' is the file size of the ELF shared object.
+ *  'class' dictates how the header is written
+ * 	For 32bit machines (class == ELFCLASS32), the optional
+ * 	header includes PE32 header fields
+ * 	For 64bit machines (class == ELFCLASS64), the optional
+ * 	header includes PE32+header fields
+ */
+static void write_header(FILE *f, __uint32_t entry, __uint32_t so_size, __uint8_t class)
+{
+	struct optional_hdr o_hdr;
+	struct optional_hdr_pe32p o_hdr_pe32p;
+	struct section t_sec, r_sec;
+	struct extra_hdr e_hdr;
+	struct extra_hdr_pe32p e_hdr_pe32p;
+	struct coff_hdr c_hdr;
+	struct header hdr;
+	struct coff_reloc c_rel;
+	__uint32_t total_sz = so_size;
+	__uint32_t dummy = 0;
+	__uint32_t hdr_sz;
+	__uint32_t reloc_start, reloc_end;
+
+
+	memset(&hdr, 0, sizeof(hdr));
+	hdr.msdos_signature = MSDOS_SIGNATURE;
+	hdr.pe_hdr = OFFSETOF(struct header, pe_signature);
+	hdr.pe_signature = PE_SIGNATURE;
+	fwrite(&hdr, sizeof(hdr), 1, f);
+
+	memset(&c_hdr, 0, sizeof(c_hdr));
+	c_hdr.nr_sections = 2;
+	c_hdr.nr_syms = 1;
+	if (class == ELFCLASS32) {
+		hdr_sz = sizeof(o_hdr) + sizeof(t_sec) + sizeof(e_hdr) +
+				sizeof(r_sec) + sizeof(c_hdr) + sizeof(hdr) + sizeof(c_rel)
+				+ sizeof(dummy);
+		total_sz += hdr_sz;
+		entry += hdr_sz;
+		c_hdr.arch = IMAGE_FILE_MACHINE_I386;
+		c_hdr.characteristics = IMAGE_FILE_32BIT_MACHINE |
+			IMAGE_FILE_DEBUG_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE |
+			IMAGE_FILE_LINE_NUMBERS_STRIPPED;
+		c_hdr.optional_hdr_sz = sizeof(o_hdr) + sizeof(e_hdr);
+		fwrite(&c_hdr, sizeof(c_hdr), 1, f);
+		memset(&o_hdr, 0, sizeof(o_hdr));
+		o_hdr.format = PE32_FORMAT;
+		o_hdr.major_linker_version = 0x02;
+		o_hdr.minor_linker_version = 0x14;
+		o_hdr.code_sz = total_sz;
+		o_hdr.entry_point = entry;
+		fwrite(&o_hdr, sizeof(o_hdr), 1, f);
+		memset(&e_hdr, 0, sizeof(e_hdr));
+		e_hdr.section_align = 4096;
+		e_hdr.file_align = 512;
+		e_hdr.image_sz = total_sz;
+		e_hdr.headers_sz = 512;
+		e_hdr.subsystem = IMAGE_SUBSYSTEM_EFI_APPLICATION;
+		e_hdr.rva_and_sizes_nr = 1;
+		fwrite(&e_hdr, sizeof(e_hdr), 1, f);
+	}
+	else if (class == ELFCLASS64) {
+		hdr_sz = sizeof(o_hdr_pe32p) + sizeof(t_sec) + sizeof(e_hdr_pe32p) +
+				sizeof(r_sec) + sizeof(c_hdr) + sizeof(hdr) + sizeof(c_rel)
+				+ sizeof(dummy);
+		total_sz += hdr_sz;
+		entry += hdr_sz;
+		c_hdr.arch = IMAGE_FILE_MACHINE_X86_64;
+		c_hdr.characteristics = IMAGE_FILE_DEBUG_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE |
+			IMAGE_FILE_LINE_NUMBERS_STRIPPED;
+		c_hdr.optional_hdr_sz = sizeof(o_hdr_pe32p) + sizeof(e_hdr_pe32p);
+		fwrite(&c_hdr, sizeof(c_hdr), 1, f);
+		memset(&o_hdr_pe32p, 0, sizeof(o_hdr_pe32p));
+		o_hdr_pe32p.format = PE32P_FORMAT;
+		o_hdr_pe32p.major_linker_version = 0x02;
+		o_hdr_pe32p.minor_linker_version = 0x14;
+		o_hdr_pe32p.code_sz = total_sz;
+		o_hdr_pe32p.entry_point = entry;
+		fwrite(&o_hdr_pe32p, sizeof(o_hdr_pe32p), 1, f);
+		memset(&e_hdr_pe32p, 0, sizeof(e_hdr));
+		e_hdr_pe32p.section_align = 4096;
+		e_hdr_pe32p.file_align = 512;
+		e_hdr_pe32p.image_sz = total_sz;
+		e_hdr_pe32p.headers_sz = 512;
+		e_hdr_pe32p.subsystem = IMAGE_SUBSYSTEM_EFI_APPLICATION;
+		e_hdr_pe32p.rva_and_sizes_nr = 1;
+		fwrite(&e_hdr_pe32p, sizeof(e_hdr_pe32p), 1, f);
+	}
+
+	memset(&t_sec, 0, sizeof(t_sec));
+	strcpy((char *)t_sec.name, ".text");
+	t_sec.virtual_sz = total_sz;
+	t_sec.raw_data_sz = total_sz;
+	t_sec.characteristics = IMAGE_SCN_CNT_CODE |
+		IMAGE_SCN_ALIGN_16BYTES | IMAGE_SCN_MEM_EXECUTE |
+		IMAGE_SCN_MEM_READ;
+	fwrite(&t_sec, sizeof(t_sec), 1, f);
+
+	/*
+	 * Write our dummy relocation and reloc section.
+	 */
+	memset(&r_sec, 0, sizeof(r_sec));
+	strcpy((char *)r_sec.name, ".reloc");
+	r_sec.virtual_sz = sizeof(c_rel);
+	r_sec.virtual_address = ftell(f) + sizeof(r_sec);
+	r_sec.raw_data_sz = r_sec.virtual_sz;
+	r_sec.raw_data = r_sec.virtual_address;
+	r_sec.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA |
+		IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_DISCARDABLE |
+		IMAGE_SCN_MEM_READ;
+	fwrite(&r_sec, sizeof(r_sec), 1, f);
+
+	memset(&c_rel, 0, sizeof(c_rel));
+	c_rel.virtual_address = ftell(f) + sizeof(c_rel);
+	c_rel.symtab_index = 10;
+	fwrite(&c_rel, sizeof(c_rel), 1, f);
+	fwrite(&dummy, sizeof(dummy), 1, f);
+
+}
+
+static void usage(char *progname)
+{
+	fprintf(stderr,	"usage: %s <ELF shared object> <output file>\n",
+		progname);
+}
+
+int main(int argc, char **argv)
+{
+	struct stat st;
+	Elf32_Ehdr e32_hdr;
+	Elf64_Ehdr e64_hdr;
+	__uint32_t entry;
+	__uint8_t class;
+	unsigned char *id;
+	FILE *f_in, *f_out;
+	void *buf;
+	size_t rv;
+
+	if (argc < 3) {
+		usage(argv[0]);
+		exit(0);
+	}
+
+	f_in = fopen(argv[1], "r");
+	if (!f_in) {
+		perror("fopen");
+		exit(EXIT_FAILURE);
+	}
+
+	if (stat(argv[1], &st) != 0) {
+		perror("stat");
+		exit(EXIT_FAILURE);
+	}
+
+	f_out = fopen(argv[2], "w");
+	if (!f_out) {
+		perror("fopen");
+		exit(EXIT_FAILURE);
+	}
+
+	/*
+	 * Parse the ELF header and find the entry point.
+	 */
+ 	fread((void *)&e32_hdr, sizeof(e32_hdr), 1, f_in);
+	if (e32_hdr.e_ident[EI_CLASS] == ELFCLASS32) {
+		id = e32_hdr.e_ident;
+		class = ELFCLASS32;
+		entry = e32_hdr.e_entry;
+	}
+	else if (e32_hdr.e_ident[EI_CLASS] == ELFCLASS64) {
+		/* read the header again for x86_64 
+		 * note that the elf header entry point is 64bit whereas
+		 * the entry point in PE/COFF format is 32bit!*/
+		class = ELFCLASS64;
+		rewind(f_in);
+		fread((void *)&e64_hdr, sizeof(e64_hdr), 1, f_in);
+		id = e64_hdr.e_ident;
+		entry = e64_hdr.e_entry;
+	} else {
+		fprintf(stderr, "Unsupported architecture\n");
+		exit(EXIT_FAILURE);
+	}
+		
+	if (id[EI_MAG0] != ELFMAG0 ||
+	    id[EI_MAG1] != ELFMAG1 ||
+	    id[EI_MAG2] != ELFMAG2 ||
+	    id[EI_MAG3] != ELFMAG3) {
+		fprintf(stderr, "Input file not ELF shared object\n");
+		exit(EXIT_FAILURE);
+	}
+
+	buf = malloc(st.st_size);
+	if (!buf) {
+		perror("malloc");
+		exit(EXIT_FAILURE);
+	}
+
+	write_header(f_out, entry, st.st_size, class);
+
+	/* Write out the entire ELF shared object */
+	rewind(f_in);
+	rv = fread(buf, st.st_size, 1, f_in);
+	if (!rv && ferror(f_in)) {
+		fprintf(stderr, "Failed to read all bytes from input\n");
+		exit(EXIT_FAILURE);
+	}
+
+	fwrite(buf, st.st_size, rv, f_out);
+	return 0;
+}
diff --git a/efi/wrapper.h b/efi/wrapper.h
new file mode 100644
index 0000000..492c262
--- /dev/null
+++ b/efi/wrapper.h
@@ -0,0 +1,164 @@
+#ifndef EFI_WRAPPER_H
+#define EFI_WRAPPER_H
+
+#define MSDOS_SIGNATURE	0x5a4d
+#define PE_SIGNATURE	0x4550
+#define PE32_FORMAT	0x10b
+#define PE32P_FORMAT	0x20b	/* PE32+ */
+
+#define IMAGE_FILE_MACHINE_I386			0x14c
+#define IMAGE_FILE_MACHINE_X86_64		0x8664
+#define IMAGE_FILE_EXECUTABLE_IMAGE		0x0002
+#define IMAGE_FILE_LINE_NUMBERS_STRIPPED	0x0004
+#define IMAGE_FILE_32BIT_MACHINE		0x0100
+#define IMAGE_FILE_DEBUG_STRIPPED		0x0200
+
+#define IMAGE_SUBSYSTEM_EFI_APPLICATION		0x0a
+
+#define IMAGE_SCN_CNT_CODE		0x00000020
+#define IMAGE_SCN_CNT_INITIALIZED_DATA	0x00000040
+#define IMAGE_SCN_ALIGN_1BYTES		0x00100000
+#define IMAGE_SCN_ALIGN_16BYTES		0x00500000
+#define IMAGE_SCN_MEM_DISCARDABLE	0x02000000
+#define IMAGE_SCN_MEM_EXECUTE		0x20000000
+#define IMAGE_SCN_MEM_READ		0x40000000
+
+#define __packed	__attribute__((packed))
+#define OFFSETOF(t,m)	((size_t)&((t *)0)->m)
+
+struct header {
+	__uint16_t msdos_signature;
+	__uint8_t _pad1[0x3c - 2];
+	__uint32_t pe_hdr;
+	__uint16_t pe_signature;
+	__uint16_t _pad2;
+} __packed;
+
+/* FIXME: when setting up coff_hdr, set up optional_hdr_sz
+ * based on PE32 or PE32+ format
+ */
+/*
+ * COFF header
+ */
+struct coff_hdr {
+	__uint16_t arch;
+	__uint16_t nr_sections;
+	__uint32_t timedatestamp;
+	__uint32_t symtab;
+	__uint32_t nr_syms;
+	__uint16_t optional_hdr_sz;
+	__uint16_t characteristics;
+} __packed;
+
+struct optional_hdr {
+	__uint16_t format;
+	__uint8_t major_linker_version;
+	__uint8_t minor_linker_version;
+	__uint32_t code_sz;
+	__uint32_t initialized_data_sz;
+	__uint32_t uninitialized_data_sz;
+	__uint32_t entry_point;
+	__uint32_t base_code;
+	__uint32_t data;
+} __packed;
+
+/* For PE32+, the optional_header does NOT have
+ * data after base_code
+ */
+struct optional_hdr_pe32p {
+	__uint16_t format;
+	__uint8_t major_linker_version;
+	__uint8_t minor_linker_version;
+	__uint32_t code_sz;
+	__uint32_t initialized_data_sz;
+	__uint32_t uninitialized_data_sz;
+	__uint32_t entry_point;
+	__uint32_t base_code;
+} __packed;
+/*
+ * Extra header fields
+ */
+struct extra_hdr {
+	__uint32_t image_base;
+	__uint32_t section_align;
+	__uint32_t file_align;
+	__uint16_t major_os_version;
+	__uint16_t minor_os_version;
+	__uint16_t major_image_version;
+	__uint16_t minor_image_version;
+	__uint16_t major_subsystem_version;
+	__uint16_t minor_subsystem_version;
+	__uint32_t win32_version;
+	__uint32_t image_sz;
+	__uint32_t headers_sz;
+	__uint32_t checksum;
+	__uint16_t subsystem;
+	__uint16_t dll_characteristics;
+	__uint32_t stack_reserve_sz;
+	__uint32_t stack_commit_sz;
+	__uint32_t heap_reserve_sz;
+	__uint32_t heap_commit_sz;
+	__uint32_t loader_flags;
+	__uint32_t rva_and_sizes_nr;
+	__uint64_t export_table;
+	__uint64_t import_table;
+	__uint64_t resource_table;
+	__uint64_t exception_table;
+	__uint64_t certification_table;
+	__uint64_t base_relocation_table;
+} __packed;
+
+/* Extra header for PE32+ format 
+ * FIXME: There are additional fields in Microsoft PE COFF v8
+ */
+
+struct extra_hdr_pe32p {
+	__uint64_t image_base;
+	__uint32_t section_align;
+	__uint32_t file_align;
+	__uint16_t major_os_version;
+	__uint16_t minor_os_version;
+	__uint16_t major_image_version;
+	__uint16_t minor_image_version;
+	__uint16_t major_subsystem_version;
+	__uint16_t minor_subsystem_version;
+	__uint32_t win32_version;
+	__uint32_t image_sz;
+	__uint32_t headers_sz;
+	__uint32_t checksum;
+	__uint16_t subsystem;
+	__uint16_t dll_characteristics;
+	__uint64_t stack_reserve_sz;
+	__uint64_t stack_commit_sz;
+	__uint64_t heap_reserve_sz;
+	__uint64_t heap_commit_sz;
+	__uint32_t loader_flags;
+	__uint32_t rva_and_sizes_nr;
+	__uint64_t export_table;
+	__uint64_t import_table;
+	__uint64_t resource_table;
+	__uint64_t exception_table;
+	__uint64_t certification_table;
+	__uint64_t base_relocation_table;
+} __packed;
+
+struct section {
+	__uint8_t name[8];
+	__uint32_t virtual_sz;
+	__uint32_t virtual_address;
+	__uint32_t raw_data_sz;
+	__uint32_t raw_data;
+	__uint32_t relocs;
+	__uint32_t line_numbers;
+	__uint16_t relocs_nr;
+	__uint16_t line_numbers_nr;
+	__uint32_t characteristics;
+} __packed;
+
+struct coff_reloc {
+	__uint32_t virtual_address;
+	__uint32_t symtab_index;
+	__uint16_t type;
+};
+
+#endif /* EFI_WRAPPER_H */
diff --git a/efi/x86_64/syslinux.ld b/efi/x86_64/syslinux.ld
new file mode 100644
index 0000000..3c8c7c3
--- /dev/null
+++ b/efi/x86_64/syslinux.ld
@@ -0,0 +1,176 @@
+/* -----------------------------------------------------------------------
+ *   
+ *   Copyright 2008-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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Linker script for the SYSLINUX core
+ */
+
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+OUTPUT_ARCH(i386:x86-64)
+ENTRY(_start)
+
+SECTIONS
+{
+	. = 0;
+	ImageBase = .;		/* For gnu-efi's crt0 */
+	__module_start = .;
+	. = SEGMENT_START("text-segment", 0) + SIZEOF_HEADERS;
+	.text : {
+		FILL(0x90909090)
+		__text_start = .;
+		*(.text)
+		*(.text.*)
+		__text_end = .;
+	}
+
+	. = ALIGN(16);
+
+	.rodata : {
+		__rodata_start = .;
+		*(.rodata)
+		*(.rodata.*)
+		__rodata_end = .;
+	}
+
+	. = ALIGN(4);
+
+	.ctors : {
+		__ctors_start = .;
+		KEEP (*(SORT(.ctors.*)))
+		KEEP (*(.ctors))
+		__ctors_end = .;
+	}
+
+	.dtors : {
+		__dtors_start = .;
+		KEEP (*(SORT(.dtors.*)))
+		KEEP (*(.dtors))
+		__dtors_end = .;
+	}
+
+	. = ALIGN(4096);
+	.rel : {
+		*(.rel.got)
+		*(.rel.data)
+		*(.rel.data.*)
+		*(.rel.ctors)
+	}
+
+	. = ALIGN(4);
+
+	.gnu.hash : {
+		__gnu_hash_start = .;
+		*(.gnu.hash)
+		__gnu_hash_end = .;
+	}
+
+
+	.dynsym : {
+		__dynsym_start = .;
+		*(.dynsym)
+		__dynsym_end = .;
+	}
+
+	. = ALIGN(4);
+
+	.dynstr : {
+		__dynstr_start = .;
+		*(.dynstr)
+		__dynstr_end = .;
+	}
+
+	. = ALIGN(4);
+
+	.dynlink : {
+		__dynlink_start = .;
+		*(.dynlink)
+		__dynlink_end = .;
+	}
+
+	. = ALIGN(4);
+
+	.got : {
+		__got_start = .;
+		KEEP (*(.got.plt))
+		KEEP (*(.got))
+		__got_end = .;
+	}
+
+	. = ALIGN(4);
+
+	.dynamic : {
+		__dynamic_start = .;
+		*(.dynamic)
+		__dynamic_end = .;
+	}
+
+	. = ALIGN(16);
+
+	.data : {
+		__data_start = .;
+		*(.data)
+		*(.data.*)
+		*(.lowmem)
+		__data_end = .;
+	}
+
+	.reloc : {
+		*(.reloc)
+	}
+
+	.comment : {
+		*(.commet)
+	}
+
+	.symtab : {
+		*(.symtab)
+	}
+
+	.strtab : {
+		*(.strtab)
+	}
+
+	.bss : {
+		/* the EFI loader doesn't seem to like a .bss section,
+		   so we stick it all into .data: */
+		__bss_start = .;
+		*(.bss)
+		*(.bss.*)
+		*(.bss16)
+		*(.hugebss)
+		*(COMMON)
+		__bss_end = .;
+		*(.sbss)
+		*(.scommon)
+	}
+	__bss_len = ABSOLUTE(__bss_end) - ABSOLUTE(__bss_start);
+	__bss_dwords = (__bss_len + 3) >> 2;
+
+	. = ALIGN(128);
+	
+	/* Very large objects which don't need to be zeroed */
+
+	.hugebss : {
+		__hugebss_start = .;
+		*(.hugebss)
+		*(.hugebss.*)
+		__hugebss_end = .;
+	}
+
+	_end = .;
+
+	/* Stuff we don't need... */
+	/DISCARD/ : {
+		*(.eh_frame)
+	}
+}
diff --git a/extlinux/Makefile b/extlinux/Makefile
index f20a71d..9148688 100644
--- a/extlinux/Makefile
+++ b/extlinux/Makefile
@@ -14,12 +14,10 @@
 ## Linux vfat, ntfs, ext2/ext3/ext4 and btrfs installer
 ##
 
-topdir = ..
-MAKEDIR = $(topdir)/mk
 include $(MAKEDIR)/syslinux.mk
 
 OPTFLAGS = -g -Os
-INCLUDES = -I. -I.. -I../libinstaller
+INCLUDES = -I$(SRC) -I$(objdir) -I$(SRC)/../libinstaller
 CFLAGS	 = $(GCCWARN) -Wno-sign-compare -D_FILE_OFFSET_BITS=64 \
 	   $(OPTFLAGS) $(INCLUDES)
 LDFLAGS	 = 
@@ -38,7 +36,7 @@
 
 .SUFFIXES: .c .o .i .s .S
 
-VPATH = .:../libinstaller
+VPATH = $(SRC):$(SRC)/../libinstaller:$(OBJ)/../libinstaller
 
 all: installer
 
diff --git a/extlinux/main.c b/extlinux/main.c
index aa20e1b..9ee9abb 100644
--- a/extlinux/main.c
+++ b/extlinux/main.c
@@ -51,7 +51,7 @@
 #include "xfs_types.h"
 #include "xfs_sb.h"
 #include "misc.h"
-#include "../version.h"
+#include "version.h"
 #include "syslxint.h"
 #include "syslxcom.h" /* common functions shared with extlinux and syslinux */
 #include "syslxfs.h"
diff --git a/gpxe/Makefile b/gpxe/Makefile
index 8bce8d1..d2f5e75 100644
--- a/gpxe/Makefile
+++ b/gpxe/Makefile
@@ -17,9 +17,10 @@
 # Very simple, really...
 #
 
+VPATH = $(SRC)
 TARGETS	= gpxelinux.0 gpxelinuxk.0
 
-PXEMAKE = $(MAKE) -C src NO_WERROR=1
+PXEMAKE = $(MAKE) -C $(SRC)/src NO_WERROR=1
 
 all: $(TARGETS)
 
@@ -28,9 +29,11 @@
 clean: tidy
 
 dist:
-	$(MAKE) -C src veryclean > /dev/null 2>&1
+	$(MAKE) -C $(SRC)/src veryclean > /dev/null 2>&1
 
-spotless: clean dist
+#spotless: clean dist
+#Including 'dist' errors out for make ARCH=x86_64 spotless
+spotless: clean
 	rm -f $(TARGETS)
 
 installer:
@@ -40,14 +43,14 @@
 src/bin/blib.a:
 	$(PXEMAKE) bin/blib.a
 
-src/bin/undionly.kkpxe: src/bin/blib.a pxelinux.gpxe ../core/pxelinux.0
-	$(PXEMAKE) bin/undionly.kkpxe EMBEDDED_IMAGE=../pxelinux.gpxe,../../core/pxelinux.0
+src/bin/undionly.kkpxe: src/bin/blib.a pxelinux.gpxe $(objdir)/core/pxelinux.0
+	$(PXEMAKE) bin/undionly.kkpxe EMBEDDED_IMAGE=$(SRC)/pxelinux.gpxe,$(objdir)/core/pxelinux.0
 
 gpxelinux.0: src/bin/undionly.kkpxe
-	cp -f $< $@
+	cp -f $(SRC)/$< $@
 
-src/bin/undionly.kpxe: src/bin/blib.a pxelinuxk.gpxe ../core/pxelinux.0
-	$(PXEMAKE) bin/undionly.kpxe EMBEDDED_IMAGE=../pxelinuxk.gpxe,../../core/pxelinux.0
+src/bin/undionly.kpxe: src/bin/blib.a pxelinuxk.gpxe $(objdir)/core/pxelinux.0
+	$(PXEMAKE) bin/undionly.kpxe EMBEDDED_IMAGE=$(SRC)/pxelinuxk.gpxe,$(objdir)/core/pxelinux.0
 
 gpxelinuxk.0: src/bin/undionly.kpxe
-	cp -f $< $@
+	cp -f $(SRC)/$< $@
diff --git a/libinstaller/Makefile b/libinstaller/Makefile
index 63446a1..48a8fd3 100644
--- a/libinstaller/Makefile
+++ b/libinstaller/Makefile
@@ -4,22 +4,26 @@
 
 PERL	 = perl
 
-all: $(BINFILES)
+VPATH = $(SRC)
 
-bootsect_bin.c: ../core/ldlinux.bss bin2c.pl
-	$(PERL) bin2c.pl syslinux_bootsect < $< > $@
+all: installer
 
-ldlinux_bin.c: ../core/ldlinux.sys bin2c.pl
-	$(PERL) bin2c.pl syslinux_ldlinux 512 < $< > $@
+bootsect_bin.c: $(OBJ)/../core/ldlinux.bss bin2c.pl
+	$(PERL) $(SRC)/bin2c.pl syslinux_bootsect < $< > $@
 
-mbr_bin.c: ../mbr/mbr.bin bin2c.pl
-	$(PERL) bin2c.pl syslinux_mbr < $< > $@
+ldlinux_bin.c: $(OBJ)/../core/ldlinux.sys bin2c.pl
+	$(PERL) $(SRC)/bin2c.pl syslinux_ldlinux 512 < $< > $@
 
-gptmbr_bin.c: ../mbr/gptmbr.bin bin2c.pl
-	$(PERL) bin2c.pl syslinux_gptmbr < $< > $@
+mbr_bin.c: $(OBJ)/../mbr/mbr.bin bin2c.pl
+	$(PERL) $(SRC)/bin2c.pl syslinux_mbr < $< > $@
 
-ldlinuxc32_bin.c: ../com32/elflink/ldlinux/ldlinux.c32 bin2c.pl
-	$(PERL) bin2c.pl syslinux_ldlinuxc32 < $< > $@
+gptmbr_bin.c: $(OBJ)/../mbr/gptmbr.bin bin2c.pl
+	$(PERL) $(SRC)/bin2c.pl syslinux_gptmbr < $< > $@
+
+installer: $(BINFILES)
+
+ldlinuxc32_bin.c: $(OBJ)/../com32/elflink/ldlinux/ldlinux.c32 bin2c.pl
+	$(PERL) $(SRC)/bin2c.pl syslinux_ldlinuxc32 < $< > $@
 
 tidy:
 	rm -f $(BINFILES)
diff --git a/libinstaller/syslxopt.c b/libinstaller/syslxopt.c
index b739752..a73cd10 100644
--- a/libinstaller/syslxopt.c
+++ b/libinstaller/syslxopt.c
@@ -23,7 +23,7 @@
 #include <string.h>
 #include <getopt.h>
 #include <sysexits.h>
-#include "../version.h"
+#include "version.h"
 #include "syslxcom.h"
 #include "syslxfs.h"
 #include "syslxopt.h"
diff --git a/linux/Makefile b/linux/Makefile
index d7facaf..f88a6cb 100644
--- a/linux/Makefile
+++ b/linux/Makefile
@@ -14,12 +14,10 @@
 ## Linux FAT/NTFS installer
 ##
 
-topdir = ..
-MAKEDIR = $(topdir)/mk
 include $(MAKEDIR)/syslinux.mk
 
 OPTFLAGS = -g -Os
-INCLUDES = -I. -I.. -I../libinstaller
+INCLUDES = -I$(SRC) -I$(objdir) -I$(SRC)/../libinstaller
 CFLAGS	 = $(GCCWARN) -D_FILE_OFFSET_BITS=64 $(OPTFLAGS) $(INCLUDES)
 LDFLAGS	 = 
 
@@ -37,7 +35,7 @@
 
 .SUFFIXES: .c .o .i .s .S
 
-VPATH = .:../libinstaller
+VPATH = $(SRC):$(SRC)/../libinstaller:$(OBJ)/../libinstaller
 
 all: installer
 
diff --git a/lzo/Makefile b/lzo/Makefile
index cf8f985..0c5d296 100644
--- a/lzo/Makefile
+++ b/lzo/Makefile
@@ -10,17 +10,19 @@
 ##
 ## -----------------------------------------------------------------------
 
-topdir = ..
-MAKEDIR = $(topdir)/mk
+VPATH = $(SRC)
 include $(MAKEDIR)/build.mk
 
-INCLUDES += -I./include
+INCLUDES += -I$(SRC)/include
 
-LIBOBJS = $(patsubst %.c,%.o,$(wildcard src/*.c))
+LIBOBJS = $(patsubst %.c,%.o,$(subst $(SRC)/,,$(wildcard $(SRC)/src/*.c)))
 LIB     = lzo.a
 BINS    = prepcore
 
-all : $(BINS)
+all : makeoutputdirs $(BINS)
+
+makeoutputdirs:
+	@mkdir -p $(OBJ)/src
 
 $(LIB) : $(LIBOBJS)
 	rm -f $@
diff --git a/mbr/Makefile b/mbr/Makefile
index 993bb10..be2bded 100644
--- a/mbr/Makefile
+++ b/mbr/Makefile
@@ -15,8 +15,8 @@
 # Makefile for MBR
 #
 
-topdir = ..
-MAKEDIR = $(topdir)/mk
+VPATH = $(SRC)
+
 include $(MAKEDIR)/embedded.mk
 
 all:	mbr.bin   altmbr.bin   gptmbr.bin   isohdpfx.bin   isohdppx.bin \
@@ -33,16 +33,19 @@
 	$(CC) $(MAKEDEPS) $(SFLAGS) -Wa,-a=$*_f.lst -DFORCE_80 -c -o $@ $<
 
 .PRECIOUS: %.elf
-%.elf: %.o mbr.ld
-	$(LD) $(LDFLAGS) -T mbr.ld -e _start -o $@ $<
+#%.elf: %.o mbr.ld
+%.elf: %.o $(SRC)/$(ARCH)/mbr.ld
+	$(LD) $(LDFLAGS) -T $(SRC)/$(ARCH)/mbr.ld -e _start -o $@ $<
 
-%.bin: %.elf checksize.pl
+%.bin: %.elf $(SRC)/checksize.pl
 	$(OBJCOPY) -O binary $< $@
-	$(PERL) checksize.pl $@
+	$(PERL) $(SRC)/checksize.pl $@
 	$(CHMOD) -x $@
 
 mbr_bin.c: mbr.bin
 
+install:
+
 tidy dist:
 	rm -f *.o *.elf *.lst .*.d
 
diff --git a/mbr/i386/mbr.ld b/mbr/i386/mbr.ld
new file mode 100644
index 0000000..d14ba80
--- /dev/null
+++ b/mbr/i386/mbr.ld
@@ -0,0 +1,73 @@
+/*
+ * Linker script for MBR
+ */
+
+/* Script for -z combreloc: combine and sort reloc sections */
+OUTPUT_FORMAT("elf32-i386", "elf32-i386",
+	      "elf32-i386")
+OUTPUT_ARCH(i386)
+EXTERN(_start)
+ENTRY(_start)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = 0x600;
+  .text           :
+  {
+    *(.text*)
+    *(.rodata*)
+  } =0x90909090
+
+  . = ALIGN(4);
+  .data		  :
+  {
+    *(.data*)
+  }
+
+  . = ALIGN(128);
+  .bss		  :
+  {
+    *(.bss*)
+  }
+
+  . = 0x7c00;
+  .bootsec	  :
+  {
+    *(.bootsec)
+  }
+
+  /* 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) }
+  /DISCARD/ : { *(.note.GNU-stack) }
+}
diff --git a/mbr/x86_64/mbr.ld b/mbr/x86_64/mbr.ld
new file mode 100644
index 0000000..ae27d49
--- /dev/null
+++ b/mbr/x86_64/mbr.ld
@@ -0,0 +1,72 @@
+/*
+ * Linker script for MBR
+ */
+
+/* Script for -z combreloc: combine and sort reloc sections */
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+OUTPUT_ARCH(i386:x86-64)
+EXTERN(_start)
+ENTRY(_start)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = 0x600;
+  .text           :
+  {
+    *(.text*)
+    *(.rodata*)
+  } =0x90909090
+
+  . = ALIGN(4);
+  .data		  :
+  {
+    *(.data*)
+  }
+
+  . = ALIGN(128);
+  .bss		  :
+  {
+    *(.bss*)
+  }
+
+  . = 0x7c00;
+  .bootsec	  :
+  {
+    *(.bootsec)
+  }
+
+  /* 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) }
+  /DISCARD/ : { *(.note.GNU-stack) }
+}
diff --git a/memdisk/Makefile b/memdisk/Makefile
index b5cd52c..e6557d8 100644
--- a/memdisk/Makefile
+++ b/memdisk/Makefile
@@ -11,29 +11,28 @@
 ##
 ## -----------------------------------------------------------------------
 
-topdir = ..
-MAKEDIR = $(topdir)/mk
 include $(MAKEDIR)/embedded.mk
 -include $(topdir)/version.mk
 
-INCLUDES = -I$(topdir)/com32/include
-CFLAGS  += -D__MEMDISK__ -DDATE='"$(DATE)"'
+INCLUDES = -I$(topdir)/com32/include -I$(objdir)
+CFLAGS  += -D__MEMDISK__ -DDATE='"$(DATE)"' -mregparm=3 -DREGPARM=3
 LDFLAGS  = $(GCCOPT) -g
 NASM     = nasm
 NASMOPT  = -Ox
 NFLAGS   = -dDATE='"$(DATE)"'
-NINCLUDE =
+NINCLUDE = -I$(SRC)/
 
+VPATH = $(SRC)
 SRCS	 = $(wildcard *.asm *.c *.h)
 
 # The DATE is set on the make command line when building binaries for
 # official release.  Otherwise, substitute a hex string that is pretty much
 # guaranteed to be unique to be unique from build to build.
 ifndef HEXDATE
-HEXDATE := $(shell $(PERL) ../now.pl $(SRCS))
+HEXDATE := $(shell $(PERL) $(SRC)/../now.pl $(SRCS))
 endif
 ifndef DATE
-DATE    := $(shell sh ../gen-id.sh $(VERSION) $(HEXDATE))
+DATE    := $(shell sh $(SRC)/../gen-id.sh $(VERSION) $(HEXDATE))
 endif
 
 # Important: init.o16 must be first!!
@@ -84,14 +83,15 @@
 memdisk16.elf: $(OBJS16)
 	$(LD) -Ttext 0 -o $@ $^
 
-memdisk32.elf: memdisk.ld $(OBJS32)
+#memdisk32.elf: memdisk.ld $(OBJS32)
+memdisk32.elf: $(ARCH)/memdisk.ld $(OBJS32)
 	$(LD) -o $@ -T $^
 
 %.bin: %.elf
 	$(OBJCOPY) -O binary $< $@
 
 memdisk: memdisk16.bin memdisk32.bin postprocess.pl
-	$(PERL) postprocess.pl $@ memdisk16.bin memdisk32.bin
+	$(PERL) $(SRC)/postprocess.pl $@ memdisk16.bin memdisk32.bin
 
 e820test: e820test.c e820func.c msetup.c
 	$(CC) -m32 -g $(GCCWARN) -DTEST -o $@ $^
diff --git a/memdisk/i386/memdisk.ld b/memdisk/i386/memdisk.ld
new file mode 100644
index 0000000..51c3e35
--- /dev/null
+++ b/memdisk/i386/memdisk.ld
@@ -0,0 +1,140 @@
+/* -----------------------------------------------------------------------
+ *   
+ *   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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Linker script for MEMDISK
+ */
+
+/* Script for -z combreloc: combine and sort reloc sections */
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+EXTERN(_start)
+ENTRY(_start)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = 0x100000;
+  PROVIDE (__executable_start = .);
+
+  .init           :
+  {
+    KEEP (*(.init))
+  } =0x90909090
+  .text           :
+  {
+    *(.text .stub .text.* .gnu.linkonce.t.*)
+    /* .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) }
+
+  /* Ensure the __preinit_array_start label is properly aligned.  We
+     could instead move the label definition inside the section, but
+     the linker would then create the section even if it turns out to
+     be empty, which isn't pretty.  */
+  . = ALIGN(4);
+  PROVIDE (__preinit_array_start = .);
+  .preinit_array     : { *(.preinit_array) }
+  PROVIDE (__preinit_array_end = .);
+  PROVIDE (__init_array_start = .);
+  .init_array     : { *(.init_array) }
+  PROVIDE (__init_array_end = .);
+  PROVIDE (__fini_array_start = .);
+  .fini_array     : { *(.fini_array) }
+  PROVIDE (__fini_array_end = .);
+  PROVIDE (__ctors_start = .);
+  .ctors          :
+  {
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  PROVIDE (__ctors_end = .);
+  PROVIDE (__dtors_start = .);
+  .dtors          :
+  {
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  PROVIDE (__dtors_end = .);
+
+  /* Adjust the address for the data segment.  Avoid mixing code and
+     data within same 128-byte chunk. */
+  . = ALIGN(128);
+
+  .data           :
+  {
+    *(.data .data.* .gnu.linkonce.d.*)
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  _edata = .;
+  PROVIDE (edata = .);
+  . = ALIGN(16);
+  .bss            :
+  {
+   __bss_start = .;
+   *(.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.  */
+   . = ALIGN(4);
+   __bss_end = .;
+  }
+  _end = .;
+  PROVIDE (end = .);
+
+
+  /* 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) }
+  /DISCARD/ : { *(.note.GNU-stack) }
+}
diff --git a/memdisk/memcpy.c b/memdisk/memcpy.c
new file mode 100644
index 0000000..5ce206d
--- /dev/null
+++ b/memdisk/memcpy.c
@@ -0,0 +1,29 @@
+/*
+ * memcpy.c
+ */
+
+#include <string.h>
+#include <stdint.h>
+
+void *memcpy(void *dst, const void *src, size_t n)
+{
+	const char *p = src;
+	char *q = dst;
+#if defined(__i386__)
+	size_t nl = n >> 2;
+	asm volatile ("cld ; rep ; movsl ; movl %3,%0 ; rep ; movsb":"+c" (nl),
+		      "+S"(p), "+D"(q)
+		      :"r"(n & 3));
+#elif defined(__x86_64__)
+	size_t nq = n >> 3;
+	asm volatile ("cld ; rep ; movsq ; movl %3,%%ecx ; rep ; movsb":"+c"
+		      (nq), "+S"(p), "+D"(q)
+		      :"r"((uint32_t) (n & 7)));
+#else
+	while (n--) {
+		*q++ = *p++;
+	}
+#endif
+
+	return dst;
+}
diff --git a/memdisk/memdisk.h b/memdisk/memdisk.h
index b6b277a..6da5aff 100644
--- a/memdisk/memdisk.h
+++ b/memdisk/memdisk.h
@@ -24,7 +24,10 @@
 /* We use the com32 interface for calling 16-bit code */
 #include <com32.h>
 
+/* define it only for i386 */
+#if __SIZEOF_POINTER__ == 4
 #define __cdecl __attribute__((cdecl,regparm(0)))
+#endif
 
 void __cdecl intcall(uint8_t, com32sys_t *, com32sys_t *);
 
diff --git a/memdisk/memmove.c b/memdisk/memmove.c
new file mode 100644
index 0000000..a398cd8
--- /dev/null
+++ b/memdisk/memmove.c
@@ -0,0 +1,36 @@
+/*
+ * memmove.c
+ */
+
+#include <string.h>
+
+void *memmove(void *dst, const void *src, size_t n)
+{
+	const char *p = src;
+	char *q = dst;
+#if defined(__i386__) || defined(__x86_64__)
+	if (q < p) {
+		asm volatile("cld; rep; movsb"
+			     : "+c" (n), "+S"(p), "+D"(q));
+	} else {
+		p += (n - 1);
+		q += (n - 1);
+		asm volatile("std; rep; movsb; cld"
+			     : "+c" (n), "+S"(p), "+D"(q));
+	}
+#else
+	if (q < p) {
+		while (n--) {
+			*q++ = *p++;
+		}
+	} else {
+		p += n;
+		q += n;
+		while (n--) {
+			*--q = *--p;
+		}
+	}
+#endif
+
+	return dst;
+}
diff --git a/memdisk/memset.c b/memdisk/memset.c
new file mode 100644
index 0000000..aa00b5b
--- /dev/null
+++ b/memdisk/memset.c
@@ -0,0 +1,30 @@
+/*
+ * memset.c
+ */
+
+#include <string.h>
+#include <stdint.h>
+
+void *memset(void *dst, int c, size_t n)
+{
+	char *q = dst;
+
+#if defined(__i386__)
+	size_t nl = n >> 2;
+	asm volatile ("cld ; rep ; stosl ; movl %3,%0 ; rep ; stosb"
+		      : "+c" (nl), "+D" (q)
+		      : "a" ((unsigned char)c * 0x01010101U), "r" (n & 3));
+#elif defined(__x86_64__)
+	size_t nq = n >> 3;
+	asm volatile ("cld ; rep ; stosq ; movl %3,%%ecx ; rep ; stosb"
+		      :"+c" (nq), "+D" (q)
+		      : "a" ((unsigned char)c * 0x0101010101010101U),
+			"r" ((uint32_t) n & 7));
+#else
+	while (n--) {
+		*q++ = c;
+	}
+#endif
+
+	return dst;
+}
diff --git a/memdisk/setup.c b/memdisk/setup.c
index bc79e12..72c6785 100644
--- a/memdisk/setup.c
+++ b/memdisk/setup.c
@@ -22,7 +22,7 @@
 #include "conio.h"
 #include "version.h"
 #include "memdisk.h"
-#include "../version.h"
+#include <version.h>
 
 const char memdisk_version[] = "MEMDISK " VERSION_STR " " DATE;
 const char copyright[] =
@@ -671,7 +671,13 @@
     set_seg_base(gdt_base, 0x10, rm_args.rm_base);
     set_seg_base(gdt_base, 0x18, rm_args.rm_base);
 
+#if __SIZEOF_POINTER__ == 4
     asm volatile ("lgdtl %0"::"m" (*(char *)gdt_base));
+#elif __SIZEOF_POINTER__ == 8
+    asm volatile ("lgdt %0"::"m" (*(char *)gdt_base));
+#else
+#error "unsupported architecture"
+#endif
 
     *(uint32_t *) rm_args.rm_pmjmp += delta;
     *(uint16_t *) rm_args.rm_rmjmp += delta >> 4;
diff --git a/memdisk/start32.S b/memdisk/start32.S
index 4fb0537..ecebe68 100644
--- a/memdisk/start32.S
+++ b/memdisk/start32.S
@@ -62,7 +62,13 @@
 	addl	$8, %edi
 	loop	1b
 
+#if __SIZEOF_POINTER__ == 4
 	lidtl	idt_ptr
+#elif __SIZEOF_POINTER__ == 8
+	lidt	idt_ptr
+#else
+#error "unsupported architecture"
+#endif
 	
 	/* Save arguments, switch stacks */
 	movl	%esp, %eax		/* Pointer to arguments */
diff --git a/memdisk/x86_64/memdisk.ld b/memdisk/x86_64/memdisk.ld
new file mode 100644
index 0000000..76abb0c
--- /dev/null
+++ b/memdisk/x86_64/memdisk.ld
@@ -0,0 +1,140 @@
+/* -----------------------------------------------------------------------
+ *   
+ *   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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Linker script for MEMDISK
+ */
+
+/* Script for -z combreloc: combine and sort reloc sections */
+OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
+OUTPUT_ARCH(i386:x86-64)
+EXTERN(_start)
+ENTRY(_start)
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  . = 0x100000;
+  PROVIDE (__executable_start = .);
+
+  .init           :
+  {
+    KEEP (*(.init))
+  } =0x90909090
+  .text           :
+  {
+    *(.text .stub .text.* .gnu.linkonce.t.*)
+    /* .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) }
+
+  /* Ensure the __preinit_array_start label is properly aligned.  We
+     could instead move the label definition inside the section, but
+     the linker would then create the section even if it turns out to
+     be empty, which isn't pretty.  */
+  . = ALIGN(4);
+  PROVIDE (__preinit_array_start = .);
+  .preinit_array     : { *(.preinit_array) }
+  PROVIDE (__preinit_array_end = .);
+  PROVIDE (__init_array_start = .);
+  .init_array     : { *(.init_array) }
+  PROVIDE (__init_array_end = .);
+  PROVIDE (__fini_array_start = .);
+  .fini_array     : { *(.fini_array) }
+  PROVIDE (__fini_array_end = .);
+  PROVIDE (__ctors_start = .);
+  .ctors          :
+  {
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  PROVIDE (__ctors_end = .);
+  PROVIDE (__dtors_start = .);
+  .dtors          :
+  {
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  PROVIDE (__dtors_end = .);
+
+  /* Adjust the address for the data segment.  Avoid mixing code and
+     data within same 128-byte chunk. */
+  . = ALIGN(128);
+
+  .data           :
+  {
+    *(.data .data.* .gnu.linkonce.d.*)
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  _edata = .;
+  PROVIDE (edata = .);
+  . = ALIGN(16);
+  .bss            :
+  {
+   __bss_start = .;
+   *(.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.  */
+   . = ALIGN(4);
+   __bss_end = .;
+  }
+  _end = .;
+  PROVIDE (end = .);
+
+
+  /* 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) }
+  /DISCARD/ : { *(.note.GNU-stack) }
+}
diff --git a/memdump/Makefile b/memdump/Makefile
index 6a30431..ae2b3f0 100644
--- a/memdump/Makefile
+++ b/memdump/Makefile
@@ -14,13 +14,14 @@
 ## memory dump utility
 ##
 
-topdir = ..
-MAKEDIR = $(topdir)/mk
+VPATH = $(SRC)
 include $(MAKEDIR)/embedded.mk
 
+CFLAGS += -mregparm=3 -DREGPARM=3
+
 OPTFLAGS = 
-INCLUDES = -include code16.h -I.
-LDFLAGS	 = -T com16.ld
+INCLUDES = -include $(SRC)/code16.h -I$(SRC)
+LDFLAGS	 = -T $(SRC)/com16.ld
 
 SRCS     = main.c serial.c ymsend.c srecsend.c
 OBJS	 = crt0.o $(patsubst %.c,%.o,$(notdir $(SRCS)))
diff --git a/memdump/code16.h b/memdump/code16.h
index ca76565..ebf5ff4 100644
--- a/memdump/code16.h
+++ b/memdump/code16.h
@@ -1,6 +1,8 @@
 /* Must be included first of all */
+#if __SIZEOF_POINTER__ == 4
 #ifdef __ASSEMBLY__
 	.code16
 #else
 __asm__ (".code16gcc");
 #endif
+#endif
diff --git a/mk/com32.mk b/mk/com32.mk
index bfba0e1..89ede83 100644
--- a/mk/com32.mk
+++ b/mk/com32.mk
@@ -17,13 +17,29 @@
 
 include $(MAKEDIR)/syslinux.mk
 
+# Support IA32 and x86_64 platforms with one build
+# Set up architecture specifics; for cross compilation, set ARCH as apt
 GCCOPT := $(call gcc_ok,-std=gnu99,)
-GCCOPT += $(call gcc_ok,-m32,)
+ifeq ($(strip $(ARCH)),i386)
+	GCCOPT += $(call gcc_ok,-m32,)
+	GCCOPT += $(call gcc_ok,-march=i386)
+	GCCOPT += $(call gcc_ok,-mpreferred-stack-boundary=2,)
+	GCCOPT += $(call gcc_ok,-incoming-stack-boundary=2,)
+endif
+ifeq ($(strip $(ARCH)),x86_64)
+	GCCOPT += $(call gcc_ok,-m64,)
+	GCCOPT += $(call gcc_ok,-march=x86-64)
+	#let the stack-boundary default to whatever it is on 64bit
+	#GCCOPT += $(call gcc_ok,-mpreferred-stack-boundary=8,)
+	#GCCOPT += $(call gcc_ok,-incoming-stack-boundary=8,)
+endif
 GCCOPT += $(call gcc_ok,-fno-stack-protector,)
 GCCOPT += $(call gcc_ok,-fwrapv,)
 GCCOPT += $(call gcc_ok,-freg-struct-return,)
-GCCOPT += -mregparm=3 -DREGPARM=3 -march=i386 -Os
-GCCOPT += $(call gcc_ok,-fPIE,-fPIC)
+GCCOPT += -Os
+# Note -fPIE does not work with ld on x86_64, try -fPIC instead
+# Does BIOS build require -fPIE?
+GCCOPT += $(call gcc_ok,-fPIC)
 GCCOPT += $(call gcc_ok,-fno-exceptions,)
 GCCOPT += $(call gcc_ok,-fno-asynchronous-unwind-tables,)
 GCCOPT += $(call gcc_ok,-fno-strict-aliasing,)
@@ -31,8 +47,6 @@
 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,)
-GCCOPT += $(call gcc_ok,-incoming-stack-boundary=2,)
 
 com32  := $(topdir)/com32
 RELOCS := $(com32)/tools/relocs
@@ -45,17 +59,19 @@
 GPLINCLUDE =
 endif
 
-CFLAGS     = $(GCCOPT) $(GCCWARN) -march=i386 \
+CFLAGS     = $(GCCOPT) $(GCCWARN) \
 	     -fomit-frame-pointer -D__COM32__ \
 	     -nostdinc -iwithprefix include \
-	     -I$(com32)/libutil/include -I$(com32)/include $(GPLINCLUDE)
-SFLAGS     = $(GCCOPT) $(GCCWARN) -march=i386 \
+	     -I$(com32)/libutil/include -I$(com32)/include \
+	     -I$(com32)/include/sys $(GPLINCLUDE)
+SFLAGS     = $(GCCOPT) $(GCCWARN) \
 	     -fomit-frame-pointer -D__COM32__ \
 	     -nostdinc -iwithprefix include \
-	     -I$(com32)/libutil/include -I$(com32)/include $(GPLINCLUDE)
+	     -I$(com32)/libutil/include -I$(com32)/include \
+	     -I$(com32)/include/sys $(GPLINCLUDE)
 
-COM32LD	   = $(com32)/lib/elf32.ld
-LDFLAGS    = -m elf_i386 -shared --hash-style=gnu -T $(COM32LD)
+COM32LD	   = $(com32)/lib/$(ARCH)/elf.ld
+LDFLAGS    = -m elf_$(ARCH) -shared --hash-style=gnu -T $(COM32LD)
 LIBGCC    := $(shell $(CC) $(GCCOPT) --print-libgcc)
 
 LNXCFLAGS  = -I$(com32)/libutil/include $(GCCWARN) -O -g \
diff --git a/mk/devel.mk b/mk/devel.mk
index 8184c30..fb4af67 100644
--- a/mk/devel.mk
+++ b/mk/devel.mk
@@ -1,3 +1,3 @@
 # Useful while doing development, but not for production.
 GCCWARN += -Wno-clobbered 
-# GCCWARN += -DDEBUG_PORT=0x3f8 -DDEBUG=1 
+# GCCWARN += -DDEBUG_PORT=0x3f8 -DCORE_DEBUG=1
diff --git a/mk/efi.mk b/mk/efi.mk
new file mode 100644
index 0000000..0281795
--- /dev/null
+++ b/mk/efi.mk
@@ -0,0 +1,67 @@
+include $(MAKEDIR)/syslinux.mk
+
+com32 = $(topdir)/com32
+core = $(topdir)/core
+
+# Support IA32 and x86_64 platforms with one build
+# Set up architecture specifics; for cross compilation, set ARCH as apt
+# gnuefi sets up architecture specifics in ia32 or x86_64 sub directories
+# set up the LIBDIR and EFIINC for building for the appropriate architecture
+# For now, the following assumptions are made:
+# 1. gnu-efi lib for IA32 is installed in /usr/local/lib
+# and the include files in /usr/local/include/efi.
+# 2. gnu-efi lib for x86_64 is installed in /usr/lib
+# and the include files in /usr/include/efi.
+ifeq ($(ARCH),i386)
+	SARCHOPT = -march=i386
+	CARCHOPT = -m32 -march=i386
+	EFI_SUBARCH = ia32
+endif
+ifeq ($(ARCH),x86_64)
+	SARCHOPT = -march=x86-64
+	CARCHOPT = -m64 -march=x86-64
+	EFI_SUBARCH = $(ARCH)
+endif
+
+EFIINC = $(shell $(topdir)/efi//find-gnu-efi.sh include $(EFI_SUBARCH))
+$(if $(EFIINC),, \
+	$(error Missing $(EFI_SUBARCH) gnu-efi header files))
+
+LIBDIR = $(shell $(topdir)/efi/find-gnu-efi.sh lib $(EFI_SUBARCH))
+$(if $(LIBDIR),, \
+	$(error Missing $(EFI_SUBARCH) gnu-efi libraries))
+
+#LIBDIR=/usr/lib
+FORMAT=efi-app-$(EFI_SUBARCH)
+
+CFLAGS = -I$(EFIINC) -I$(EFIINC)/$(EFI_SUBARCH) \
+		-DEFI_FUNCTION_WRAPPER -fPIC -fshort-wchar -ffreestanding \
+		-Wall -I$(com32)/include -I$(com32)/include/sys \
+		-I$(core)/include -I$(core)/ $(CARCHOPT) \
+		-I$(com32)/lib/ -I$(com32)/libutil/include -std=gnu99 \
+		-DELF_DEBUG -DSYSLINUX_EFI \
+		$(GCCWARN) -D__COM32__ -mno-red-zone
+
+# gnuefi sometimes installs these under a gnuefi/ directory, and sometimes not
+CRT0 := $(shell find $(LIBDIR) -name crt0-efi-$(EFI_SUBARCH).o 2>/dev/null | tail -n1)
+LDSCRIPT := $(shell find $(LIBDIR) -name elf_$(EFI_SUBARCH)_efi.lds 2>/dev/null | tail -n1)
+
+LDFLAGS = -T $(SRC)/$(ARCH)/syslinux.ld -Bsymbolic -pie -nostdlib -znocombreloc \
+		-L$(LIBDIR) --hash-style=gnu -m elf_$(ARCH) $(CRT0) -E
+
+SFLAGS     = $(GCCOPT) $(GCCWARN) $(SARCHOPT) \
+	     -fomit-frame-pointer -D__COM32__ \
+	     -nostdinc -iwithprefix include \
+	     -I$(com32)/libutil/include -I$(com32)/include -I$(com32)/include/sys $(GPLINCLUDE)
+
+.PRECIOUS: %.o
+%.o: %.S
+	$(CC) $(SFLAGS) -c -o $@ $<
+
+.PRECIOUS: %.o
+%.o: %.c
+	$(CC) $(CFLAGS) -c -o $@ $<
+
+#%.efi: %.so
+#	$(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel \
+#		-j .rela -j .reloc --target=$(FORMAT) $*.so $@
diff --git a/mk/elf.mk b/mk/elf.mk
index 109e0a6..bd8775c 100644
--- a/mk/elf.mk
+++ b/mk/elf.mk
@@ -16,48 +16,62 @@
 
 include $(MAKEDIR)/syslinux.mk
 
+# Support IA32 and x86_64 platforms with one build
+# Set up architecture specifics; for cross compilation, set ARCH as apt
 GCCOPT := $(call gcc_ok,-std=gnu99,)
-GCCOPT += $(call gcc_ok,-m32,)
+ifeq ($(ARCH),i386)
+	GCCOPT += $(call gcc_ok,-m32,)
+	GCCOPT += $(call gcc_ok,-march=i386)
+	GCCOPT += $(call gcc_ok,-mpreferred-stack-boundary=2,)
+endif
+ifeq ($(ARCH),x86_64)
+	GCCOPT += $(call gcc_ok,-m64,)
+	GCCOPT += $(call gcc_ok,-march=x86-64)
+	#let preferred-stack-boundary be default (=4)
+endif
+GCCOPT += -Os -fomit-frame-pointer
 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)
+# Note -fPIE does not work with ld on x86_64, try -fPIC instead
+# Does BIOS build depend on -fPIE?
+GCCOPT += $(call gcc_ok,-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
 core = $(topdir)/core
 
 ifneq ($(NOGPL),1)
-GPLLIB     = $(com32)/gpllib/libgpl.c32
+GPLLIB     = $(objdir)/com32/gpllib/libgpl.c32
 GPLINCLUDE = -I$(com32)/gplinclude
 else
 GPLLIB     =
 GPLINCLUDE =
 endif
 
-CFLAGS     = $(GCCOPT) -W -Wall -march=i386 \
+CFLAGS     = $(GCCOPT) -W -Wall \
 	     -fomit-frame-pointer -D__COM32__ -DDYNAMIC_MODULE \
 	     -nostdinc -iwithprefix include \
-	     -I$(com32)/libutil/include -I$(com32)/include $(GPLINCLUDE) \
-	     -I$(core)/include
-SFLAGS     = $(GCCOPT) -D__COM32__ -march=i386
-LDFLAGS    = -m elf_i386 -shared --hash-style=gnu -T $(com32)/lib/elf32.ld --as-needed
+	     -I$(com32)/libutil/include -I$(com32)/include \
+		-I$(com32)/include/sys $(GPLINCLUDE) -I$(core)/include \
+		-I$(objdir)
+SFLAGS     = $(GCCOPT) -D__COM32__ 
+LDFLAGS    = -m elf_$(ARCH) -shared --hash-style=gnu -T $(com32)/lib/$(ARCH)/elf.ld --as-needed
+LIBGCC    := $(shell $(CC) $(GCCOPT) --print-libgcc)
 
 LNXCFLAGS  = -I$(com32)/libutil/include -W -Wall -O -g -D_GNU_SOURCE
 LNXSFLAGS  = -g
 LNXLDFLAGS = -g
 
-C_LIBS	   = $(com32)/libutil/libutil.c32 $(GPLLIB) \
-	     $(com32)/lib/libcom32.c32
-C_LNXLIBS  = $(com32)/libutil/libutil_lnx.a \
-	     $(com32)/elflink/ldlinux/ldlinux_lnx.a
+C_LIBS	   = $(objdir)/com32/libutil/libutil.c32 $(GPLLIB) \
+	     $(objdir)/com32/lib/libcom32.c32
+C_LNXLIBS  = $(objdir)/com32/libutil/libutil_lnx.a \
+	     $(objdir)/com32/elflink/ldlinux/ldlinux_lnx.a
 
 .SUFFIXES: .lss .c .o
 
diff --git a/mk/embedded.mk b/mk/embedded.mk
index c2f4edf..5a7632e 100644
--- a/mk/embedded.mk
+++ b/mk/embedded.mk
@@ -16,13 +16,29 @@
 
 include $(MAKEDIR)/syslinux.mk
 
-GCCOPT    := $(call gcc_ok,-m32,)
+# Support IA32 and x86_64 platforms with one build
+# Set up architecture specifics; for cross compilation, set ARCH as apt
+# Initialize GCCOPT to null to begin with. Without this, make generates
+# recursive error for GCCOPT
+GCCOPT :=
+ifeq ($(ARCH),i386)
+	GCCOPT := $(call gcc_ok,-m32)
+	GCCOPT += $(call gcc_ok,-march=i386)
+	GCCOPT    += $(call gcc_ok,-mpreferred-stack-boundary=2,)
+	GCCOPT    += $(call gcc_ok,-mincoming-stack-boundary=2,)
+endif
+ifeq ($(ARCH),x86_64)
+	GCCOPT := $(call gcc_ok,-m64)
+	GCCOPT += $(call gcc_ok,-march=x86-64)
+	#let preferred-stack-boundary and incoming-stack-boundary be default(=4)
+# Somewhere down the line ld barfs requiring -fPIC
+	GCCOPT += $(call gcc_ok,-fPIC)
+endif
 GCCOPT    += $(call gcc_ok,-ffreestanding,)
 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 \
-	     -msoft-float
+GCCOPT    += -Os -fomit-frame-pointer -msoft-float
 GCCOPT    += $(call gcc_ok,-fno-exceptions,)
 GCCOPT	  += $(call gcc_ok,-fno-asynchronous-unwind-tables,)
 GCCOPT	  += $(call gcc_ok,-fno-strict-aliasing,)
@@ -30,13 +46,11 @@
 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,)
-GCCOPT    += $(call gcc_ok,-mincoming-stack-boundary=2,)
 GCCOPT    += $(call gcc_ok,-fvisibility=hidden)
 
 LIBGCC    := $(shell $(CC) $(GCCOPT) --print-libgcc)
 
-LD        += -m elf_i386
+LD        += -m elf_$(ARCH)
 
 # Note: use += for CFLAGS and SFLAGS in case something is set in MCONFIG.local
 CFLAGS    += $(GCCOPT) -g $(GCCWARN) -Wno-sign-compare $(OPTFLAGS) $(INCLUDES)
diff --git a/mk/lib.mk b/mk/lib.mk
index ca8e41b..9450277 100644
--- a/mk/lib.mk
+++ b/mk/lib.mk
@@ -2,12 +2,25 @@
 
 include $(MAKEDIR)/syslinux.mk
 
+# Support IA32 and x86_64 platforms with one build
+# Set up architecture specifics; for cross compilation, set ARCH as apt
 GCCOPT := $(call gcc_ok,-std=gnu99,)
-GCCOPT += $(call gcc_ok,-m32,)
+ifeq ($(ARCH),i386)
+	GCCOPT += $(call gcc_ok,-m32,)
+	GCCOPT += $(call gcc_ok,-mpreferred-stack-boundary=2,)
+	MARCH = i386
+endif
+ifeq ($(ARCH),x86_64)
+	GCCOPT += $(call gcc_ok,-m64,)
+	#let preferred-stack-boundary be default(=4)
+	MARCH = x86-64
+endif
 GCCOPT += $(call gcc_ok,-fno-stack-protector,)
 GCCOPT += $(call gcc_ok,-fwrapv,)
 GCCOPT += $(call gcc_ok,-freg-struct-return,)
-GCCOPT += $(call gcc_ok,-fPIE,-fPIC)
+# Note -fPIE does not work with ld on x86_64, try -fPIC instead
+# Does BIOS build require -fPIE?
+GCCOPT += $(call gcc_ok,-fPIC)
 GCCOPT += $(call gcc_ok,-fno-exceptions,)
 GCCOPT += $(call gcc_ok,-fno-asynchronous-unwind-tables,)
 GCCOPT += $(call gcc_ok,-fno-strict-aliasing,)
@@ -15,9 +28,8 @@
 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,)
 
-INCLUDE	= -I.
+INCLUDE	= -I$(SRC)
 STRIP	= strip --strip-all -R .comment -R .note
 
 # zlib and libpng configuration flags
@@ -31,15 +43,161 @@
 # fallback anyway, just use that on old machines...
 # LIBFLAGS += -DPNG_NO_FLOATING_POINT_SUPPORTED
 
-REQFLAGS  = $(GCCOPT) -g -mregparm=3 -DREGPARM=3 -D__COM32__ \
-	    -nostdinc -iwithprefix include -I. -I./sys -I../include \
-	    -I../../core/include
-OPTFLAGS  = -Os -march=i386 -falign-functions=0 -falign-jumps=0 \
+REQFLAGS  = $(GCCOPT) -g -D__COM32__ \
+	    -nostdinc -iwithprefix include -I. -I$(SRC)/sys \
+	    -I$(SRC)/../include -I$(com32)/include/sys \
+	    -I$(topdir)/core/include -I$(com32)/lib/ \
+	    -I$(com32)/lib/sys/module -I$(OBJ)/../..
+OPTFLAGS  = -Os -march=$(MARCH) -falign-functions=0 -falign-jumps=0 \
 	    -falign-labels=0 -ffast-math -fomit-frame-pointer
 WARNFLAGS = $(GCCWARN) -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Winline
 
 CFLAGS  = $(OPTFLAGS) $(REQFLAGS) $(WARNFLAGS) $(LIBFLAGS)
-LDFLAGS	= -m elf_i386 --hash-style=gnu -T $(com32)/lib/elf32.ld
+
+VPATH = $(SRC)
+LIBOTHER_OBJS = \
+	atoi.o atol.o atoll.o calloc.o creat.o		\
+	fgets.o fprintf.o fputc.o	\
+	putchar.o				\
+	getopt.o getopt_long.o						\
+	lrand48.o stack.o memccpy.o memchr.o 		\
+	mempcpy.o memmem.o memmove.o memswap.o	\
+	perror.o qsort.o seed48.o \
+	srand48.o sscanf.o strcasecmp.o strcat.o	\
+	strerror.o errlist.o		\
+	strnlen.o							\
+	strncat.o strndup.o		\
+	stpncpy.o						\
+	strntoimax.o strntoumax.o strsep.o strspn.o strstr.o	\
+	strtoimax.o strtok.o strtol.o strtoll.o strtoul.o strtoull.o	\
+	strtoumax.o vprintf.o vsprintf.o		\
+	asprintf.o vasprintf.o			\
+	vsscanf.o							\
+	skipspace.o							\
+	chrreplace.o							\
+	bufprintf.o							\
+	inet.o dhcppack.o dhcpunpack.o					\
+	strreplace.o							\
+	lstrdup.o						\
+	\
+	suffix_number.o							\
+	\
+	getcwd.o fdopendir.o	\
+	\
+	sys/line_input.o				\
+	sys/colortable.o sys/screensize.o				\
+	\
+	sys/stdcon_read.o sys/stdcon_write.o sys/rawcon_read.o		\
+	sys/rawcon_write.o		\
+	sys/null_read.o sys/null_write.o sys/serial_write.o		\
+	\
+	sys/xserial_write.o						\
+	\
+	sys/ansi.o							\
+	\
+	sys/ansicon_write.o sys/ansiserial_write.o			\
+	\
+	pci/cfgtype.o pci/scan.o pci/bios.o					\
+	pci/readb.o pci/readw.o pci/readl.o			\
+	pci/writeb.o pci/writew.o pci/writel.o	\
+	\
+	sys/x86_init_fpu.o math/pow.o math/strtod.o			\
+	syslinux/disk.o							\
+	\
+	syslinux/setup_data.o
+
+## CORE OBJECTS, INCLUDED IN THE ROOT COM32 MODULE
+LIBENTRY_OBJS = \
+	sys/intcall.o sys/farcall.o sys/cfarcall.o sys/zeroregs.o	\
+	sys/argv.o sys/sleep.o						\
+	sys/fileinfo.o sys/opendev.o sys/read.o sys/write.o sys/ftell.o \
+	sys/close.o sys/open.o sys/fileread.o sys/fileclose.o		\
+	sys/openmem.o					\
+	sys/isatty.o sys/fstat.o					\
+	\
+	dprintf.o vdprintf.o						\
+	\
+	syslinux/idle.o							\
+	\
+	exit.o
+
+LIBGCC_OBJS = \
+	libgcc/__ashldi3.o libgcc/__udivdi3.o			\
+	libgcc/__negdi2.o libgcc/__ashrdi3.o libgcc/__lshrdi3.o		\
+	libgcc/__muldi3.o libgcc/__udivmoddi4.o libgcc/__umoddi3.o	\
+	libgcc/__divdi3.o libgcc/__moddi3.o
+
+LIBCONSOLE_OBJS = \
+	\
+	sys/openconsole.o sys/line_input.o				\
+	sys/colortable.o sys/screensize.o				\
+	\
+	sys/stdcon_read.o sys/rawcon_read.o		\
+	sys/rawcon_write.o						\
+	sys/null_write.o sys/serial_write.o		\
+	\
+	sys/xserial_write.o						\
+	\
+	sys/ansi.o							\
+	\
+	sys/ansicon_write.o sys/ansiserial_write.o	\
+	\
+	syslinux/serial.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			\
+	\
+	syslinux/run_default.o syslinux/run_command.o			\
+	syslinux/cleanup.o syslinux/localboot.o	syslinux/runimage.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
+
+LIBMODULE_OBJS = \
+	sys/module/common.o sys/module/$(ARCH)/elf_module.o		\
+	sys/module/elfutils.o	\
+	sys/module/exec.o sys/module/elf_module.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
+
+MINLIBOBJS = \
+	$(addprefix $(OBJ)/,syslinux/ipappend.o \
+	syslinux/dsinfo.o \
+	$(LIBOTHER_OBJS) \
+	$(LIBGCC_OBJS) \
+	$(LIBCONSOLE_OBJS) \
+	$(LIBLOAD_OBJS) \
+	$(LIBZLIB_OBJS))
+#	$(LIBVESA_OBJS)
+
+CORELIBOBJS = \
+	memcpy.o memset.o memcmp.o printf.o strncmp.o vfprintf.o 	\
+	strlen.o vsnprintf.o snprintf.o stpcpy.o strcmp.o strdup.o 	\
+	strcpy.o strncpy.o setjmp.o fopen.o fread.o fread2.o puts.o 	\
+	sprintf.o strlcat.o strchr.o strlcpy.o strncasecmp.o ctypes.o 	\
+	fputs.o fwrite2.o fwrite.o fgetc.o fclose.o errno.o lmalloc.o 	\
+	sys/err_read.o sys/err_write.o sys/null_read.o 			\
+	sys/stdcon_write.o						\
+	syslinux/memscan.o strrchr.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				\
+	$(LIBENTRY_OBJS) \
+	$(LIBMODULE_OBJS)
+
+LDFLAGS	= -m elf_$(ARCH) --hash-style=gnu -T $(com32)/lib/$(ARCH)/elf.ld
 
 .SUFFIXES: .c .o .a .so .lo .i .S .s .ls .ss .lss
 
@@ -47,16 +205,16 @@
 
 % : %.S
 
-.c.o:
+%.o: %.c
 	$(CC) $(MAKEDEPS) $(CFLAGS) -c -o $@ $<
 
 .c.i:
 	$(CC) $(MAKEDEPS) $(CFLAGS) -E -o $@ $<
 
-.c.s:
+%.s: %.c
 	$(CC) $(MAKEDEPS) $(CFLAGS) -S -o $@ $<
 
-.S.o:
+%.o: %.S
 	$(CC) $(MAKEDEPS) $(CFLAGS) -D__ASSEMBLY__ -c -o $@ $<
 
 .S.s:
@@ -68,7 +226,7 @@
 .S.ls:
 	$(CC) $(MAKEDEPS) $(CFLAGS) $(SOFLAGS) -D__ASSEMBLY__ -E -o $@ $<
 
-.s.o:
+%(OBJ)/%.o: $(SRC)/%.s
 	$(CC) $(MAKEDEPS) $(CFLAGS) -x assembler -c -o $@ $<
 
 .ls.lo:
diff --git a/mk/syslinux.mk b/mk/syslinux.mk
index 1378b6d..484afb2 100644
--- a/mk/syslinux.mk
+++ b/mk/syslinux.mk
@@ -67,6 +67,12 @@
 
 com32    = $(topdir)/com32
 
+# Architecture definition
+SUBARCH := $(shell uname -m | sed -e s/i.86/i386/) 
+# on x86_64, ARCH has trailing whitespace
+# strip white spaces in ARCH
+ARCH ?= $(strip $(SUBARCH))
+
 # Common warnings we want for all gcc-generated code
 GCCWARN := -W -Wall -Wstrict-prototypes
 # Extremely useful variant for debugging...
diff --git a/mtools/Makefile b/mtools/Makefile
index 6df18b5..3f9c42b 100755
--- a/mtools/Makefile
+++ b/mtools/Makefile
@@ -1,9 +1,7 @@
-topdir = ..
-MAKEDIR = $(topdir)/mk
 include $(MAKEDIR)/syslinux.mk
 
 OPTFLAGS = -g -Os
-INCLUDES = -I. -I.. -I../libfat -I../libinstaller
+INCLUDES = -I$(SRC) -I$(objdir) -I$(SRC)/../libfat -I$(SRC)/../libinstaller
 CFLAGS	 = $(GCCWARN) -D_FILE_OFFSET_BITS=64 $(OPTFLAGS) $(INCLUDES)
 LDFLAGS	 = 
 
@@ -15,12 +13,12 @@
 	   ../libinstaller/bootsect_bin.c \
 	   ../libinstaller/ldlinux_bin.c \
 	   ../libinstaller/ldlinuxc32_bin.c \
-	   $(wildcard ../libfat/*.c)
+	   $(wildcard $(SRC)/../libfat/*.c)
 OBJS	 = $(patsubst %.c,%.o,$(notdir $(SRCS)))
 
 .SUFFIXES: .c .o .i .s .S
 
-VPATH = .:../libfat:../libinstaller
+VPATH = $(SRC):$(SRC)/../libfat:$(SRC)/../libinstaller:$(OBJ)/../libinstaller
 
 all: installer
 
diff --git a/sample/Makefile b/sample/Makefile
index 9e504d9..1515a06 100644
--- a/sample/Makefile
+++ b/sample/Makefile
@@ -14,9 +14,8 @@
 ## samples for syslinux users
 ##
 
-topdir = ..
-MAKEDIR = $(topdir)/mk
 include $(MAKEDIR)/embedded.mk
+VPATH = $(SRC)
 
 PPMTOLSS16 = $(topdir)/utils/ppmtolss16
 
diff --git a/txt/Makefile b/txt/Makefile
index 0365577..0e4cfb4 100644
--- a/txt/Makefile
+++ b/txt/Makefile
@@ -22,6 +22,8 @@
 MAKEDIR = $(topdir)/mk
 # include $(MAKEDIR)/embedded.mk
 
+VPATH = $(SRC)
+
 A2X_OPTS	 = -k
 # A2X_OPTS	+= -v
 A2X_MAN_OPTS	 = -D man -f manpage
diff --git a/utils/Makefile b/utils/Makefile
index be73993..dfe6259 100644
--- a/utils/Makefile
+++ b/utils/Makefile
@@ -14,23 +14,23 @@
 # SYSLINUX utilities
 #
 
-topdir = ..
-MAKEDIR = $(topdir)/mk
+VPATH = $(SRC)
 include $(MAKEDIR)/syslinux.mk
 
-CFLAGS   = $(GCCWARN) -Os -fomit-frame-pointer -D_FILE_OFFSET_BITS=64
+CFLAGS   = $(GCCWARN) -Os -fomit-frame-pointer -D_FILE_OFFSET_BITS=64 -I$(SRC)
 LDFLAGS  = -O2
 
 C_TARGETS	 = isohybrid gethostip memdiskfind
 SCRIPT_TARGETS	 = mkdiskimage
 SCRIPT_TARGETS	+= isohybrid.pl  # about to be obsoleted
-ASIS		 = keytab-lilo lss16toppm md5pass ppmtolss16 sha1pass \
-		   syslinux2ansi pxelinux-options
+ASIS		 = $(addprefix $(SRC)/,keytab-lilo lss16toppm md5pass \
+		   ppmtolss16 sha1pass syslinux2ansi pxelinux-options)
 
 TARGETS = $(C_TARGETS) $(SCRIPT_TARGETS)
 
-ISOHDPFX = ../mbr/isohdpfx.bin ../mbr/isohdpfx_f.bin ../mbr/isohdpfx_c.bin \
-	   ../mbr/isohdppx.bin ../mbr/isohdppx_f.bin ../mbr/isohdppx_c.bin
+ISOHDPFX = $(addprefix $(OBJ)/,../mbr/isohdpfx.bin ../mbr/isohdpfx_f.bin \
+	   ../mbr/isohdpfx_c.bin \
+	   ../mbr/isohdppx.bin ../mbr/isohdppx_f.bin ../mbr/isohdppx_c.bin)
 
 all: $(TARGETS)
 
@@ -38,17 +38,17 @@
 	$(CC) $(UMAKEDEPS) $(CFLAGS) -c -o $@ $<
 
 mkdiskimage: mkdiskimage.in ../mbr/mbr.bin bin2hex.pl
-	$(PERL) bin2hex.pl < ../mbr/mbr.bin | cat mkdiskimage.in - > $@
+	$(PERL) $(SRC)/bin2hex.pl < $(OBJ)/../mbr/mbr.bin | cat $(SRC)/mkdiskimage.in - > $@
 	chmod a+x $@
 
 # Works on anything with a Perl interpreter...
 isohybrid.pl: isohybrid.in $(ISOHDPFX) bin2hex.pl
-	cp -f isohybrid.in $@
-	for f in $(ISOHDPFX) ; do $(PERL) bin2hex.pl < $$f >> $@ ; done
+	cp -f $(SRC)/isohybrid.in $@
+	for f in $(ISOHDPFX) ; do $(PERL) $(SRC)/bin2hex.pl < $$f >> $@ ; done
 	chmod a+x $@
 
 isohdpfx.c: $(ISOHDPFX) isohdpfxarray.pl
-	$(PERL) isohdpfxarray.pl $(ISOHDPFX) > $@
+	$(PERL) $(SRC)/isohdpfxarray.pl $(ISOHDPFX) > $@
 
 isohybrid: isohybrid.o isohdpfx.o
 	$(CC) $(LDFLAGS) -o $@ $^ -luuid
diff --git a/version b/version
index 9440979..792ea10 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-5.01 2013
+6.00 2012
diff --git a/win32/Makefile b/win32/Makefile
index 9ff8a45..a417a4b 100644
--- a/win32/Makefile
+++ b/win32/Makefile
@@ -29,21 +29,22 @@
 ifeq ($(findstring MINGW32,$(OSTYPE)),MINGW32)
 WINPREFIX  :=
 else
-WINPREFIX  := $(shell ./find-mingw32.sh gcc)
+WINPREFIX  := $(shell $(SRC)/find-mingw32.sh gcc)
 endif
 WINCFLAGS  := $(GCCWARN) -Wno-sign-compare -Os -fomit-frame-pointer \
 	      -D_FILE_OFFSET_BITS=64
 WINLDFLAGS := -Os -s
 endif
-WINCFLAGS += -I. -I../win -I.. -I../libfat -I../libinstaller \
-	     -I../libinstaller/getopt
+WINCFLAGS += -I$(SRC) -I$(SRC)/../win -I$(objdir) \
+	     -I$(SRC)/../libfat -I$(SRC)/../libinstaller \
+	     -I$(SRC)/../libinstaller/getopt
 
 WINCC      := $(WINPREFIX)gcc
 WINAR	   := $(WINPREFIX)ar
 WINRANLIB  := $(WINPREFIX)ranlib
 
 WINCC_IS_GOOD := $(shell $(WINCC) $(WINCFLAGS) $(WINLDFLAGS) \
-	-o hello.exe ../win/hello.c >/dev/null 2>&1 ; echo $$?)
+	-o hello.exe $(SRC)/../win/hello.c >/dev/null 2>&1 ; echo $$?)
 
 .SUFFIXES: .c .obj .lib .exe .i .s .S
 
@@ -58,12 +59,12 @@
 	   ../libinstaller/ldlinux_bin.c \
 	   ../libinstaller/ldlinuxc32_bin.c \
 	   ../libinstaller/mbr_bin.c \
-	   $(wildcard ../libfat/*.c)
+	   $(wildcard $(SRC)/../libfat/*.c)
 LIBOBJS  = $(patsubst %.c,%.obj,$(notdir $(LIBSRC)))
 
 LIB	 = syslinux.lib
 
-VPATH = .:../win:../libfat:../libinstaller:../libinstaller/getopt
+VPATH = $(SRC):$(SRC)/../win:$(SRC)/../libfat:$(SRC)/../libinstaller:$(SRC)/../libinstaller/getopt:$(OBJ)/../libinstaller
 
 TARGETS = syslinux.exe
 
diff --git a/win64/Makefile b/win64/Makefile
index 50132d4..176f848 100644
--- a/win64/Makefile
+++ b/win64/Makefile
@@ -20,20 +20,21 @@
 
 OSTYPE   = $(shell uname -msr)
 # Don't know how to do a native compile here...
-WINPREFIX  := $(shell ./find-mingw64.sh gcc)
+WINPREFIX  := $(shell $(SRC)/find-mingw64.sh gcc)
 WINCFLAGS  := $(GCCWARN) -Wno-sign-compare -Os -fomit-frame-pointer \
 	      -D_FILE_OFFSET_BITS=64
 WINLDFLAGS := -Os -s
 
-WINCFLAGS += -I. -I../win -I.. -I../libfat -I../libinstaller \
-	     -I../libinstaller/getopt
+WINCFLAGS += -I$(SRC) -I$(SRC)/../win -I$(objdir) \
+	     -I$(SRC)/../libfat -I$(SRC)/../libinstaller \
+	     -I$(SRC)/../libinstaller/getopt
 
 WINCC      := $(WINPREFIX)gcc
 WINAR	   := $(WINPREFIX)ar
 WINRANLIB  := $(WINPREFIX)ranlib
 
 WINCC_IS_GOOD := $(shell $(WINCC) $(WINCFLAGS) $(WINLDFLAGS) \
-	-o hello.exe ../win/hello.c >/dev/null 2>&1 ; echo $$?)
+	-o hello.exe $(SRC)/../win/hello.c >/dev/null 2>&1 ; echo $$?)
 
 .SUFFIXES: .c .obj .lib .exe .i .s .S
 
@@ -48,12 +49,12 @@
 	   ../libinstaller/ldlinux_bin.c \
 	   ../libinstaller/ldlinuxc32_bin.c \
 	   ../libinstaller/mbr_bin.c \
-	   $(wildcard ../libfat/*.c)
+	   $(wildcard $(SRC)/../libfat/*.c)
 LIBOBJS  = $(patsubst %.c,%.obj,$(notdir $(LIBSRC)))
 
 LIB	 = syslinux.lib
 
-VPATH = .:../win:../libfat:../libinstaller:../libinstaller/getopt
+VPATH = $(SRC):$(SRC)/../win:$(SRC)/../libfat:$(SRC)/../libinstaller:$(SRC)/../libinstaller/getopt:$(OBJ)/../libinstaller
 
 TARGETS = syslinux64.exe