diff options
206 files changed, 10649 insertions, 2093 deletions
@@ -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 @@ include $(MAKEDIR)/syslinux.mk # 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 @@ BOBJECTS = $(BTARGET) \ # 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". -BSUBDIRS = codepage com32 lzo core memdisk mbr memdump gpxe sample \ - diag libinstaller dos win32 win64 dosutil + +ifdef EFI_BUILD + +BSUBDIRS = codepage com32 lzo core mbr sample efi +ISUBDIRS = efi utils + +INSTALLSUBDIRS = efi + +else + +BSUBDIRS = codepage com32 lzo core memdisk sample diag mbr memdump dos \ + gpxe libinstaller win32 win64 dosutil + ITARGET = IOBJECTS = $(ITARGET) \ utils/gethostip utils/isohybrid utils/mkdiskimage \ @@ -88,33 +201,108 @@ EXTBOOTINSTALL = $(INSTALLABLE_MODULES) 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 -all-local: $(BTARGET) $(ITARGET) +.PHONY: subdirs $(BSUBDIRS) $(ISUBDIRS) -installer: - $(MAKE) installer-local - set -e ; for i in $(ISUBDIRS); do $(MAKE) -C $$i all ; done +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) -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 @@ local-install: installer 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 @@ local-tidy: 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 92127e98..37dd259a 100644 --- a/Makefile.private +++ b/Makefile.private @@ -36,10 +36,10 @@ burn: isolinux.iso 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 @@ -2,6 +2,9 @@ Starting with 1.47, changes marked with SYSLINUX, PXELINUX, ISOLINUX 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.00: * com32: Switched from the COM32 object format to ELF as it is a much more powerful format that allows undefined symbols to diff --git a/codepage/Makefile b/codepage/Makefile index 2a6fd126..18a590f3 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 @@ all: $(GENFILES) # 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 c4699cfd..7ea1b01c 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 9a298fae..32385509 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 181937bd..7ff1ff6e 100644 --- a/com32/cmenu/Makefile +++ b/com32/cmenu/Makefile @@ -18,31 +18,34 @@ NOGPL := 1 LIBS = libmenu/libmenu.c32 \ - $(com32)/libutil/libutil_com.c32 \ - $(com32)/lib/libcom32.c32 + $(objdir)/com32/libutil/libutil_com.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_com.c32 $(com32)/lib/libcom32.c32 +LIBMENU = $(objdir)/com32/libutil/libutil_com.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.c32: $(LIBMENU) $(LD) -shared $(LDFLAGS) -o $@ $^ diff --git a/com32/elflink/ldlinux/Makefile b/com32/elflink/ldlinux/Makefile index 93ca127d..aa35f475 100644 --- a/com32/elflink/ldlinux/Makefile +++ b/com32/elflink/ldlinux/Makefile @@ -10,18 +10,19 @@ ## ## ----------------------------------------------------------------------- -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 \ + eprintf.o loadhigh.o msg.o all: ldlinux.c32 ldlinux_lnx.a -ldlinux.c32 : 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 eprintf.o loadhigh.o msg.o +ldlinux.c32 : $(OBJS) $(LD) $(LDFLAGS) -o $@ $^ $(LIBS) LNXCFLAGS += -D__export='__attribute__((visibility("default")))' diff --git a/com32/elflink/ldlinux/adv.c b/com32/elflink/ldlinux/adv.c index 4c3ad508..677fe92d 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, ®, NULL); - - reg.eax.w[0] = 0x001c; - __intcall(0x22, ®, ®); - __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 35829c1c..47e45534 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, ®, ®); - return (reg.eflags.l & EFLAGS_CF) ? -1 : 0; + return firmware->adv_ops->write(); } diff --git a/com32/gfxboot/Makefile b/com32/gfxboot/Makefile index f2a73762..98d6a032 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.c32 : gfxboot.o realmode_callback.o $(LIBS) $(C_LIBS) +OBJS = gfxboot.o realmode_callback.o + +gfxboot.c32 : $(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 92dd20f2..71f335da 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 @@ AUXDIR = $(DATADIR)/syslinux INCDIR = /usr/include COM32DIR = $(AUXDIR)/com32 -all: libcom32gpl.c32 +all: makeoutputdirs libcom32gpl.c32 + +makeoutputdirs: + @mkdir -p $(foreach b, \ + $(addprefix $(OBJ),$(sort $(dir $(LIBOBJS)))),$(b)) libcom32gpl.c32 : $(LIBOBJS) $(LD) -shared $(LDFLAGS) -o $@ $^ @@ -38,6 +40,6 @@ install: all mkdir -m 755 -p $(INSTALLROOT)$(COM32DIR) install -m 644 libcom32gpl.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 d264b5ba..362b4874 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 f90e524b..7129c4a6 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 213e8ab7..04418a04 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 8e444b6d..7e7b2355 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 7db63bdf..b2f3141a 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 d85094d9..c342c448 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 00000000..f19205fe --- /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 00000000..c34c675c --- /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 00000000..bdc69705 --- /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 00000000..71ece423 --- /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 00000000..175cdcd4 --- /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 00000000..1acb1bc8 --- /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 00000000..c61bf8ce --- /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 00000000..91930003 --- /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 00000000..139ab203 --- /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 00000000..a775a7fd --- /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 148d08eb..c5d60176 100644 --- a/com32/include/com32.h +++ b/com32/include/com32.h @@ -135,7 +135,7 @@ char *lstrdup(const char *); * specific segment. OFFS_VALID() will return whether or not the * pointer is actually reachable from the target segment. */ -#if defined(DEBUG) && (defined(__COM32__) || defined(__SYSLINUX_CORE__)) +#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 bool _OFFS_VALID(const volatile void *__p, size_t __s, 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 26ca734b..de4625bc 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 @@ void vdprintf(const char *, va_list); # 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 00000000..a0def6a1 --- /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 00000000..454fc60a --- /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 d2af351f..d3fba17f 100644 --- a/com32/include/netinet/in.h +++ b/com32/include/netinet/in.h @@ -27,8 +27,16 @@ static inline __constfunc uint16_t __htons(uint16_t v) 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 11b18fbd..e7090955 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 40e09fe7..de30d932 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 53a6250e..05c98843 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 8d6ddb05..99b5ad10 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 00000000..663b267a --- /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 00000000..63d0f5ed --- /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 00000000..21988ead --- /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 ea11a88f..02778fbf 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 @@ struct elf_module { 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 @@ struct elf_module { // 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 @@ extern FILE *findpath(char *name); * 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) */ @@ -255,7 +251,7 @@ extern int module_load(struct elf_module *module); * Its current use is to describe the root COM32 module to the rest of the * module subsystem. */ -extern int module_load_shallow(struct elf_module *module, Elf32_Addr base_addr); +extern int module_load_shallow(struct elf_module *module, Elf_Addr base_addr); /** * module_unload - unloads the module from the system. @@ -329,7 +325,7 @@ extern struct elf_module *module_find(const char *name); * 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. @@ -346,7 +342,7 @@ extern Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module * 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 @@ -356,7 +352,7 @@ extern Elf32_Sym *global_find_symbol(const char *name, struct elf_module **modul * * 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 00000000..7b1cc2b6 --- /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 00000000..89d79154 --- /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 00000000..203a6cd0 --- /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 00000000..13ba1591 --- /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 f5f95fb0..a8c6f2f5 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 @@ struct setup_data { #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_load_file(struct initramfs *ihead, const char *src_filename, 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 db795439..c3ebf847 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 00000000..762db371 --- /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 84f65c1f..46a53b5c 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,13 +16,6 @@ LIBPNG_OBJS = \ 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 \ @@ -33,7 +25,7 @@ LIBJPG_OBJS = \ 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/alphatbl.o sys/vesa/fmtpixel.o \ sys/vesa/i915resolution.o LIBMISC_OBJS = \ @@ -51,134 +43,9 @@ LIBSYSLINUX_OBJS = \ 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/shallow_module.o sys/module/elfutils.o \ - sys/module/exec.o - -LIBGCC_OBJS = \ - libgcc/__ashldi3.o libgcc/__udivdi3.o \ - libgcc/__negdi2.o libgcc/__ashrdi3.o libgcc/__lshrdi3.o \ - libgcc/__muldi3.o libgcc/__udivmoddi4.o libgcc/__umoddi3.o \ - libgcc/__divdi3.o libgcc/__moddi3.o - -LIBCONSOLE_OBJS = \ - \ - sys/openconsole.o sys/line_input.o \ - sys/colortable.o sys/screensize.o \ - \ - 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 +56,6 @@ MINLIBOBJS = \ $(LIBZLIB_OBJS) # $(LIBVESA_OBJS) - DYNLIBOBJS = \ $(LIBZLIB_OBJS) \ $(LIBPNG_OBJS) \ @@ -202,8 +68,7 @@ DYNLIBOBJS = \ $(DYNENTRY_OBJS) -LIBOBJS = \ - $(DYNLIBOBJS) +LIBOBJS = $(DYNLIBOBJS) BINDIR = /usr/bin LIBDIR = /usr/lib @@ -212,7 +77,11 @@ AUXDIR = $(DATADIR)/syslinux 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.c32 : $(LIBOBJS) rm -f $@ @@ -239,11 +108,11 @@ spotless: clean 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 00000000..fc2e7db5 --- /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 00000000..658df485 --- /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 648a88ad..424787c8 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 @@ __muldi3: #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 6b986a0d..9b5306dd 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 00000000..5ce206d0 --- /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 e97299f2..2094e4aa 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 00000000..a398cd8d --- /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 cad7b983..2096f132 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 00000000..be23b667 --- /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 e641415d..fd42842a 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 00000000..aa00b5b1 --- /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 658df485..2fb5c234 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 @@ longjmp: 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 e5483fbc..74add717 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 @@ static struct term_info ti = { .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 @@ int __ansicon_open(struct file_info *fp) 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 uint8_t ansicon_attribute(const struct term_state *st) static void ansicon_erase(const struct term_state *st, int x0, int y0, int x1, int y1) { - static com32sys_t ireg; - - 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); + uint8_t attribute = ansicon_attribute(st); + + 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; - - 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 */ + uint8_t rows, cols, attribute; + + /* + * 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 @@ ssize_t __ansicon_write(struct file_info *fp, const void *buf, size_t count) 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 988ee6d2..2749083e 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 00000000..cf336932 --- /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 d72dd702..5b0d9ee8 100644 --- a/com32/lib/sys/module/common.c +++ b/com32/lib/sys/module/common.c @@ -23,7 +23,7 @@ LIST_HEAD(modules_head); // 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 @@ void print_elf_ehdr(Elf32_Ehdr *ehdr) { 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 @@ int image_skip(size_t size, struct elf_module *module) { 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; @@ -218,9 +218,14 @@ struct elf_module *module_find(const char *name) { } +// 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 || @@ -231,7 +236,8 @@ int check_header_common(Elf32_Ehdr *elf_hdr) { 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; } @@ -247,7 +253,8 @@ int check_header_common(Elf32_Ehdr *elf_hdr) { 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; } @@ -256,6 +263,7 @@ int check_header_common(Elf32_Ehdr *elf_hdr) { } + int enforce_dependency(struct elf_module *req, struct elf_module *dep) { struct module_dep *crt_dep; struct module_dep *new_dep; @@ -312,7 +320,7 @@ int clear_dependency(struct elf_module *req, struct elf_module *dep) { 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; @@ -360,7 +368,6 @@ int check_symbols(struct elf_module *module) if (strong_count == 0 && weak_count == 0) { DBG_PRINT("Symbol %s is undefined\n", crt_name); - printf("Undef symbol FAIL: %s\n",crt_name); return -1; } } @@ -420,7 +427,7 @@ int _module_unload(struct elf_module *module) { int module_unload(struct elf_module *module) { module_ctor_t *dtor; - for (dtor = module->dtors; *dtor; dtor++) + for (dtor = module->dtors; dtor && *dtor; dtor++) (*dtor) (); return _module_unload(module); @@ -450,18 +457,18 @@ struct elf_module *unload_modules_since(const char *name) { 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) { @@ -476,32 +483,32 @@ static Elf32_Sym *module_find_symbol_sysv(const char *name, struct elf_module *m 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); @@ -509,18 +516,18 @@ static Elf32_Sym *module_find_symbol_gnu(const char *name, struct elf_module *mo 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; @@ -533,11 +540,11 @@ static Elf32_Sym *module_find_symbol_gnu(const char *name, struct elf_module *mo 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++) { @@ -551,8 +558,8 @@ static Elf32_Sym *module_find_symbol_iterate(const char *name,struct elf_module 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); @@ -574,10 +581,10 @@ Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module) { 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 54f0ec4b..652c9735 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 @@ static inline Elf32_Sym *symbol_get_entry(struct elf_module *module, int entry) // 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_load(struct elf_module *module); extern int image_unload(struct elf_module *module); extern int image_read(void *buff, size_t size, struct elf_module *module); extern int image_skip(size_t size, struct elf_module *module); -extern int image_seek(Elf32_Off offset, struct elf_module *module); +extern 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 24da2209..0d27c92b 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,162 +47,10 @@ static int check_header(Elf32_Ehdr *elf_hdr) { * 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); - 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); - 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) { @@ -222,11 +70,11 @@ static int prepare_dynlinking(struct elf_module *module) { 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 = @@ -259,168 +107,12 @@ void undefined_symbol(void) 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; @@ -489,8 +181,8 @@ static int extract_operations(struct elf_module *module) { // 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; @@ -510,7 +202,7 @@ int module_load(struct elf_module *module) { // 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); @@ -596,7 +288,7 @@ int module_load(struct elf_module *module) { (module->exit_func == NULL) ? NULL : *(module->exit_func)); */ - for (ctor = module->ctors; *ctor; ctor++) + for (ctor = module->ctors; ctor && *ctor; ctor++) (*ctor) (); return 0; diff --git a/com32/lib/sys/module/elfutils.h b/com32/lib/sys/module/elfutils.h index a901ff48..91bdcb3f 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 @@ static inline Elf32_Phdr *elf_get_pht(void *elf_image) { * @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 00000000..a3792554 --- /dev/null +++ b/com32/lib/sys/module/i386/elf_module.c @@ -0,0 +1,341 @@ +/* + * 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); + 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); + 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/i386/shallow_module.c b/com32/lib/sys/module/i386/shallow_module.c new file mode 100644 index 00000000..fbcf781b --- /dev/null +++ b/com32/lib/sys/module/i386/shallow_module.c @@ -0,0 +1,161 @@ +/* + * shallow_module.c + * + * Created on: Aug 11, 2008 + * Author: Stefan Bucur <stefanb@zytor.com> + */ + + +#include <string.h> +#include <sys/module.h> + +#include "common.h" +#include "elfutils.h" + + +static int check_header_shallow(Elf32_Ehdr *elf_hdr) { + int res; + + res = check_header_common(elf_hdr); + + if (res != 0) + return res; + + if (elf_hdr->e_shoff == 0x00000000) { + DBG_PRINT("SHT missing\n"); + return -1; + } + + return 0; +} + +static int load_shallow_sections(struct elf_module *module, Elf32_Ehdr *elf_hdr) { + int i; + int res = 0; + void *sht = NULL; + void *buffer = NULL; + Elf32_Shdr *crt_sht; + Elf32_Off buff_offset; + + Elf32_Off min_offset = 0xFFFFFFFF; + Elf32_Off max_offset = 0x00000000; + Elf32_Word max_align = 0x1; + + Elf32_Off sym_offset = 0xFFFFFFFF; + Elf32_Off str_offset = 0xFFFFFFFF; + + + char *sh_strtable; + + // We buffer the data up to the SHT + buff_offset = module->u.l._cr_offset; + + buffer = malloc(elf_hdr->e_shoff - buff_offset); + // Get to the SHT + image_read(buffer, elf_hdr->e_shoff - buff_offset, module); + + // Load the SHT + sht = malloc(elf_hdr->e_shnum * elf_hdr->e_shentsize); + image_read(sht, elf_hdr->e_shnum * elf_hdr->e_shentsize, module); + + // Get the string table of the section names + crt_sht = (Elf32_Shdr*)(sht + elf_hdr->e_shstrndx * elf_hdr->e_shentsize); + sh_strtable = (char*)(buffer + (crt_sht->sh_offset - buff_offset)); + + for (i = 0; i < elf_hdr->e_shnum; i++) { + crt_sht = (Elf32_Shdr*)(sht + i*elf_hdr->e_shentsize); + + if (strcmp(".symtab", sh_strtable + crt_sht->sh_name) == 0) { + // We found the symbol table + min_offset = MIN(min_offset, crt_sht->sh_offset); + max_offset = MAX(max_offset, crt_sht->sh_offset + crt_sht->sh_size); + max_align = MAX(max_align, crt_sht->sh_addralign); + + sym_offset = crt_sht->sh_offset; + + module->syment_size = crt_sht->sh_entsize; + module->symtable_size = crt_sht->sh_size / crt_sht->sh_entsize; + } + if (strcmp(".strtab", sh_strtable + crt_sht->sh_name) == 0) { + // We found the string table + min_offset = MIN(min_offset, crt_sht->sh_offset); + max_offset = MAX(max_offset, crt_sht->sh_offset + crt_sht->sh_size); + max_align = MAX(max_align, crt_sht->sh_addralign); + + str_offset = crt_sht->sh_offset; + + module->strtable_size = crt_sht->sh_size; + } + } + + if (elf_malloc(&module->module_addr, max_align, + max_offset - min_offset) != 0) { + DBG_PRINT("Could not allocate sections\n"); + goto out; + } + + // Copy the data + image_seek(min_offset, module); + image_read(module->module_addr, max_offset - min_offset, module); + + // Setup module information + module->module_size = max_offset - min_offset; + module->str_table = (char*)(module->module_addr + (str_offset - min_offset)); + module->sym_table = module->module_addr + (sym_offset - min_offset); + +out: + // Release the SHT + if (sht != NULL) + free(sht); + + // Release the buffer + if (buffer != NULL) + free(buffer); + + return res; +} + + +int module_load_shallow(struct elf_module *module, Elf32_Addr base_addr) { + int res; + Elf32_Ehdr elf_hdr; + + // Do not allow duplicate modules + if (module_find(module->name) != NULL) { + DBG_PRINT("Module already loaded.\n"); + return -1; + } + + res = image_load(module); + + if (res < 0) + return res; + + module->shallow = 1; + + CHECKED(res, image_read(&elf_hdr, sizeof(Elf32_Ehdr), module), error); + + // Checking the header signature and members + CHECKED(res, check_header_shallow(&elf_hdr), error); + + CHECKED(res, load_shallow_sections(module, &elf_hdr), error); + module->base_addr = base_addr; + + // Check the symbols for duplicates / missing definitions + CHECKED(res, check_symbols(module), error); + + // Add the module at the beginning of the module list + list_add(&module->list, &modules_head); + + // The file image is no longer needed + image_unload(module); + + DBG_PRINT("SHALLOW MODULE %s LOADED SUCCESSFULLY\n", module->name); + + return 0; + +error: + image_unload(module); + + return res; +} diff --git a/com32/lib/sys/module/x86_64/elf_module.c b/com32/lib/sys/module/x86_64/elf_module.c new file mode 100644 index 00000000..64404a17 --- /dev/null +++ b/com32/lib/sys/module/x86_64/elf_module.c @@ -0,0 +1,372 @@ +/* + * 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); + 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); + 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/module/x86_64/shallow_module.c b/com32/lib/sys/module/x86_64/shallow_module.c new file mode 100644 index 00000000..b7248150 --- /dev/null +++ b/com32/lib/sys/module/x86_64/shallow_module.c @@ -0,0 +1,161 @@ +/* + * shallow_module.c + * + * Created on: Aug 11, 2008 + * Author: Stefan Bucur <stefanb@zytor.com> + */ + + +#include <string.h> +#include <sys/module.h> + +#include "common.h" +#include "elfutils.h" + + +static int check_header_shallow(Elf64_Ehdr *elf_hdr) { + int res; + + res = check_header_common(elf_hdr); + + if (res != 0) + return res; + + if (elf_hdr->e_shoff == 0x00000000) { + DBG_PRINT("SHT missing\n"); + return -1; + } + + return 0; +} + +static int load_shallow_sections(struct elf_module *module, Elf64_Ehdr *elf_hdr) { + int i; + int res = 0; + void *sht = NULL; + void *buffer = NULL; + Elf64_Shdr *crt_sht; + Elf64_Off buff_offset; + + Elf64_Off min_offset = 0xFFFFFFFFFFFFFFFF; + Elf64_Off max_offset = 0x0000000000000000; + Elf64_Word max_align = 0x1; + + Elf64_Off sym_offset = 0xFFFFFFFFFFFFFFFF; + Elf64_Off str_offset = 0xFFFFFFFFFFFFFFFF; + + + char *sh_strtable; + + // We buffer the data up to the SHT + buff_offset = module->u.l._cr_offset; + + buffer = malloc(elf_hdr->e_shoff - buff_offset); + // Get to the SHT + image_read(buffer, elf_hdr->e_shoff - buff_offset, module); + + // Load the SHT + sht = malloc(elf_hdr->e_shnum * elf_hdr->e_shentsize); + image_read(sht, elf_hdr->e_shnum * elf_hdr->e_shentsize, module); + + // Get the string table of the section names + crt_sht = (Elf64_Shdr*)(sht + elf_hdr->e_shstrndx * elf_hdr->e_shentsize); + sh_strtable = (char*)(buffer + (crt_sht->sh_offset - buff_offset)); + + for (i = 0; i < elf_hdr->e_shnum; i++) { + crt_sht = (Elf64_Shdr*)(sht + i*elf_hdr->e_shentsize); + + if (strcmp(".symtab", sh_strtable + crt_sht->sh_name) == 0) { + // We found the symbol table + min_offset = MIN(min_offset, crt_sht->sh_offset); + max_offset = MAX(max_offset, crt_sht->sh_offset + crt_sht->sh_size); + max_align = MAX(max_align, crt_sht->sh_addralign); + + sym_offset = crt_sht->sh_offset; + + module->syment_size = crt_sht->sh_entsize; + module->symtable_size = crt_sht->sh_size / crt_sht->sh_entsize; + } + if (strcmp(".strtab", sh_strtable + crt_sht->sh_name) == 0) { + // We found the string table + min_offset = MIN(min_offset, crt_sht->sh_offset); + max_offset = MAX(max_offset, crt_sht->sh_offset + crt_sht->sh_size); + max_align = MAX(max_align, crt_sht->sh_addralign); + + str_offset = crt_sht->sh_offset; + + module->strtable_size = crt_sht->sh_size; + } + } + + if (elf_malloc(&module->module_addr, max_align, + max_offset - min_offset) != 0) { + DBG_PRINT("Could not allocate sections\n"); + goto out; + } + + // Copy the data + image_seek(min_offset, module); + image_read(module->module_addr, max_offset - min_offset, module); + + // Setup module information + module->module_size = max_offset - min_offset; + module->str_table = (char*)(module->module_addr + (str_offset - min_offset)); + module->sym_table = module->module_addr + (sym_offset - min_offset); + +out: + // Release the SHT + if (sht != NULL) + free(sht); + + // Release the buffer + if (buffer != NULL) + free(buffer); + + return res; +} + + +int module_load_shallow(struct elf_module *module, Elf64_Addr base_addr) { + int res; + Elf64_Ehdr elf_hdr; + + // Do not allow duplicate modules + if (module_find(module->name) != NULL) { + DBG_PRINT("Module already loaded.\n"); + return -1; + } + + res = image_load(module); + + if (res < 0) + return res; + + module->shallow = 1; + + CHECKED(res, image_read(&elf_hdr, sizeof(Elf64_Ehdr), module), error); + + // Checking the header signature and members + CHECKED(res, check_header_shallow(&elf_hdr), error); + + CHECKED(res, load_shallow_sections(module, &elf_hdr), error); + module->base_addr = base_addr; + + // Check the symbols for duplicates / missing definitions + CHECKED(res, check_symbols(module), error); + + // Add the module at the beginning of the module list + list_add(&module->list, &modules_head); + + // The file image is no longer needed + image_unload(module); + + DBG_PRINT("SHALLOW MODULE %s LOADED SUCCESSFULLY\n", module->name); + + return 0; + +error: + image_unload(module); + + return res; +} diff --git a/com32/lib/sys/vesa/initvesa.c b/com32/lib/sys/vesa/initvesa.c index 9a1ae384..c2721b8d 100644 --- a/com32/lib/sys/vesa/initvesa.c +++ b/com32/lib/sys/vesa/initvesa.c @@ -69,37 +69,12 @@ static void unpack_font(uint8_t * dst, uint8_t * src, int height) } } -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 @@ static int vesacon_set_mode(int x, int y) __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 */ - - 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; - } + if (!__vesacon_font_height) + __vesacon_font_height = firmware->vesa->font_query(&rom_font); + 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 @@ static int vesacon_set_mode(int x, int y) __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 @@ static int init_text_display(void) 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 @@ int __vesacon_init(int x, int y) 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 32dce9e6..5c6d9151 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 @@ void __vesacon_init_copy_to_screen(void) } } -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; 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; - } + firmware->vesa->screencpy(dst, s, bytes, &wi); } diff --git a/com32/lib/sys/vesa/vesa.h b/com32/lib/sys/vesa/vesa.h index 3926c329..7a3d87ae 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 d14494b1..f57e34f9 100644 --- a/com32/lib/sys/vesa/video.h +++ b/com32/lib/sys/vesa/video.h @@ -51,6 +51,14 @@ struct vesa_char { 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 @@ extern const uint8_t __vesacon_linear_to_srgb[4080]; 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 37693177..823a66af 100644 --- a/com32/lib/sys/vesacon_write.c +++ b/com32/lib/sys/vesacon_write.c @@ -98,7 +98,8 @@ int __vesacon_open(struct file_info *fp) 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 00000000..c5d3946c --- /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 cf336932..cacb4ea3 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 @@ int x86_init_fpu(void) return 0; } +#endif diff --git a/com32/lib/syslinux/cleanup.c b/com32/lib/syslinux/cleanup.c index 066f174f..7d8581e4 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 c1f02a59..f7126bfe 100644 --- a/com32/lib/syslinux/dsinfo.c +++ b/com32/lib/syslinux/dsinfo.c @@ -34,12 +34,5 @@ union syslinux_derivative_info __syslinux_derivative_info; 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 c0335dc9..4a8a1fd3 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 @@ static inline uint32_t saturate32(unsigned long long v) 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 @@ static int map_initramfs(struct syslinux_movelist **fraglist, 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 @@ bail: 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 fc676cbf..0ff25d7f 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 @@ struct e820_entry { 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 @@ int syslinux_scan_memory(scan_memory_callback_t callback, void *data) 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 bb92222f..bc41acfc 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 __constructor __syslinux_get_serial_console_info(void) { - uint16_t flowctl; + uint16_t iobase, divisor, flowctl; - __syslinux_serial_console_info.iobase = SerialPort; - __syslinux_serial_console_info.divisor = BaudDivisor; - - flowctl = FlowOutput | FlowInput | (FlowIgnore << 4); - - if (!DisplayCon) - flowctl |= (0x80 << 8); + firmware->get_serial_console_info(&iobase, &divisor, &flowctl); + __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 544915a3..d014340c 100644 --- a/com32/lib/syslinux/shuffle.c +++ b/com32/lib/syslinux/shuffle.c @@ -50,10 +50,12 @@ struct shuffle_descriptor { 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 @@ int syslinux_do_shuffle(struct syslinux_movelist *fraglist, 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 1cd2efd3..6f0554d5 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 00000000..4e88bcb0 --- /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 00000000..45f547b4 --- /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 83053350..f9440c57 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 @@ install: all 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 93c0c11c..535b4aba 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 01d1f81c..70a7e808 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 02e9f49e..a3f61ba8 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 b7719456..9f7a0e46 100644 --- a/com32/menu/Makefile +++ b/com32/menu/Makefile @@ -14,24 +14,23 @@ ## 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) -menu.c32 : menu.o $(COMMONOBJS) $(C_LIBS) +vesamenu.c32: vesamenu.o $(COMMONOBJS) $(C_LIBS) $(LD) $(LDFLAGS) -o $@ $^ -vesamenu.c32 : vesamenu.o $(COMMONOBJS) $(C_LIBS) +menu.c32: menu.o $(COMMONOBJS) $(C_LIBS) $(LD) $(LDFLAGS) -o $@ $^ tidy dist: diff --git a/com32/modules/Makefile b/com32/modules/Makefile index 9cf4da8e..e794b3b9 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 11c18ae0..47eacdbc 100644 --- a/com32/modules/ls.c +++ b/com32/modules/ls.c @@ -172,4 +172,4 @@ int main(int argc, char *argv[]) return rv ? 1 : 0; } - + diff --git a/com32/modules/zzjson.c b/com32/modules/zzjson.c index e2516fa1..a126b8f0 100644 --- a/com32/modules/zzjson.c +++ b/com32/modules/zzjson.c @@ -21,7 +21,13 @@ static void myerror(void *ehandle, const char *format, ...) { 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 a894c847..a4c0bc28 100644 --- a/com32/rosh/Makefile +++ b/com32/rosh/Makefile @@ -16,10 +16,10 @@ ## ROSH Read Only Shell ## -LIBS = $(com32)/libutil/libutil_com.c32 $(com32)/lib/libcom32.c32 +LIBS = $(objdir)/com32/libutil/libutil_com.c32 \ + $(objdir)/com32/lib/libcom32.c32 -topdir = ../.. -MAKEDIR = $(topdir)/mk +VPATH = $(SRC) include $(MAKEDIR)/rosh.mk # from com32/sysdump/Makefile @@ -36,12 +36,12 @@ endif 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 68dad3f3..8198a2ba 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 c7abaddb..ca04f644 100644 --- a/com32/samples/Makefile +++ b/com32/samples/Makefile @@ -14,17 +14,16 @@ ## samples for syslinux users ## -LIBS = $(com32)/libutil/libutil_com.c32 +LIBS = $(objdir)/com32/libutil/libutil_com.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 2c786416..83fe8381 100644 --- a/com32/samples/advdump.c +++ b/com32/samples/advdump.c @@ -27,7 +27,13 @@ int main(void) 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 d50859f4..56a683e3 100644 --- a/com32/samples/entrydump.c +++ b/com32/samples/entrydump.c @@ -36,7 +36,13 @@ int main(void) 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 f4a0e52a..8f062d19 100644 --- a/com32/samples/resolv.c +++ b/com32/samples/resolv.c @@ -32,7 +32,13 @@ int main(int argc, char *argv[]) { 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 10d02521..2936b4e5 100644 --- a/com32/samples/serialinfo.c +++ b/com32/samples/serialinfo.c @@ -25,7 +25,13 @@ int main(void) { 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 8763b3c8..dca5d717 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 e7fc5767..846b5408 100644 --- a/com32/sysdump/cpuid.c +++ b/com32/sysdump/cpuid.c @@ -20,10 +20,21 @@ struct cpuid_info { 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 0161baf1..9c0ea708 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 a01d83a4..14590eb6 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 @@ BTARGET = kwdhash.gen \ 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 @@ CFLAGS += -D__SYSLINUX_CORE__ # 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 + +# 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 -all: $(BTARGET) +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 @@ kwdhash.gen: keywords genhash.pl $(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.a: rawcon.o 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.bss: ldlinux.bin 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 00000000..7b41f398 --- /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, ®, ®); + + 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.eax.w[0] = 0x001c; + __intcall(0x22, ®, ®); + __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, ®, ®); + 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; + 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, src, l); + + bytes -= l; + src += 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; + mem_init(); + + /* 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 3ef6690c..471aef96 100644 --- a/core/call16.c +++ b/core/call16.c @@ -24,9 +24,17 @@ __export const com32sys_t zero_regs; /* Common all-zero register set */ 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 73b63dbf..de318d98 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 @@ extern void comboot_cleanup_api(void); * 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 @@ __export void cleanup_hardware(void) __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 e5afbe25..3197c8a7 100644 --- a/core/comboot.inc +++ b/core/comboot.inc @@ -342,52 +342,6 @@ comapi_err: 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 @@ int22_table: 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 abfceb88..a351fd14 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" @@ -101,12 +102,12 @@ void pm_write_serial(com32sys_t *regs) 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; @@ -118,7 +119,12 @@ void pm_serialcfg(com32sys_t *regs) if (!DisplayCon) ah |= 0x80; - regs->ebx.w[0] = al | (ah << 8); + *flowctl = al | (ah << 8); +} + +void pm_serialcfg(com32sys_t *regs) +{ + serialcfg(®s->eax.w[0], ®s->ecx.w[0], ®s->ebx.w[0]); } /* @@ -137,7 +143,7 @@ __export void write_serial_str(char *data) * * Returns 1 if character pending. */ -__export int pollchar(void) +int bios_pollchar(void) { com32sys_t ireg, oreg; uint8_t data = 0; @@ -177,6 +183,11 @@ __export int pollchar(void) return data; } +__export int pollchar(void) +{ + return firmware->i_ops->pollchar(); +} + void pm_pollchar(com32sys_t *regs) { if (pollchar()) @@ -187,10 +198,7 @@ void pm_pollchar(com32sys_t *regs) 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; @@ -256,6 +264,14 @@ __export char getchar(char *hi) 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 *)®s->eax.b[1]); diff --git a/core/diskboot.inc b/core/diskboot.inc index 89bdd968..ce75b8c9 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 a2ede959..875b4093 100644 --- a/core/diskstart.inc +++ b/core/diskstart.inc @@ -504,7 +504,7 @@ expand_super: 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 7c0afacf..1fa43bd6 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 @@ struct elf_module core_module = { .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 @@ void load_env32(com32sys_t * regs __unused) int fd; char *argv[] = { LDLINUX, NULL }; char realname[FILENAME_MAX]; + size_t size; static const char *search_directories[] = { "/boot/isolinux", @@ -122,7 +121,7 @@ void load_env32(com32sys_t * regs __unused) 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 @@ void load_env32(com32sys_t * regs __unused) 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 953be42b..a159000b 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 85330808..edc9de8e 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 @@ fail: /* * 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 @@ void use_font(void) /* 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 @@ void use_font(void) 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 @@ void adjust_screen(void) 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 66838161..afe4e58c 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 @@ void getoneblk(struct disk *disk, char *buf, block_t block, int block_size) 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 00000000..9b935fe2 --- /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 b2c20ee0..d7346ae1 100644 --- a/core/fs/fat/fat.c +++ b/core/fs/fat/fat.c @@ -140,6 +140,7 @@ static int fat_next_extent(struct inode *inode, uint32_t lstart) return 0; err: + dprintf("fat_next_extent: return error\n"); return -1; } @@ -325,7 +326,7 @@ static bool vfat_match_longname(const char *str, const uint16_t *match, 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 2ad33755..40f97d5e 100644 --- a/core/fs/fs.c +++ b/core/fs/fs.c @@ -410,6 +410,7 @@ err_path: return file_to_handle(file); err: + dprintf("serachdir: error seraching file %s\n", name); _close_file(file); err_no_close: return -1; @@ -488,22 +489,16 @@ void pm_close_file(com32sys_t *regs) * 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(); @@ -523,8 +518,7 @@ void fs_init(com32sys_t *regs) 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 f63d4a91..f2a96129 100644 --- a/core/fs/pxe/dhcp_option.c +++ b/core/fs/pxe/dhcp_option.c @@ -233,7 +233,7 @@ void parse_dhcp(const void *pkt, size_t pkt_len) 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 d4377581..3439dd6a 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 @@ struct pxe_pvt_inode { #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 00000000..7b4e012c --- /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 d38f6692..9334c41a 100644 --- a/core/include/bios.h +++ b/core/include/bios.h @@ -54,12 +54,6 @@ static inline void io_delay(void) 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 a6ecbc4a..aa3bfb7a 100644 --- a/core/include/core.h +++ b/core/include/core.h @@ -31,7 +31,7 @@ extern unsigned int __bcopyxx_len; 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 FlowOutput; 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 ac23e921..0a19e8a1 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 read_sectors(char *, sector_t, int); 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 9d552787..554dc97f 100644 --- a/core/include/fs.h +++ b/core/include/fs.h @@ -185,6 +185,7 @@ static inline struct file *handle_to_file(uint16_t handle) 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 *); @@ -197,6 +198,8 @@ void close_file(uint16_t handle); 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 a1412252..45a05093 100644 --- a/core/init.c +++ b/core/init.c @@ -3,83 +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(); - - /* Init the memory subsystem */ - mem_init(); - - /* CPU-dependent initialization and related checks. */ - check_escapes(); + firmware->init(); } diff --git a/core/init.inc b/core/init.inc index 5cb8e49a..995f9825 100644 --- a/core/init.inc +++ b/core/init.inc @@ -33,7 +33,9 @@ common_init: 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 00000000..bdc7df5a --- /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 8866298e..673134b0 100644 --- a/core/isolinux.asm +++ b/core/isolinux.asm @@ -79,13 +79,16 @@ ImageSectors resw 1 ; isolinux.bin size, sectors 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 @@ bsHeads resw 1 ; Used in hybrid mode 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 @@ _spec_len equ _spec_end - _spec_start 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 @@ -1093,6 +1098,7 @@ bios_ebios_str db 'EHDD' ,0 %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 @@ -1168,7 +1174,7 @@ init_fs: 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 03dd917b..0b025dd0 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 00000000..3d15cefb --- /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 49c455d6..e865c4cb 100644 --- a/core/lzo/enter.ash +++ b/core/lzo/enter.ash @@ -42,12 +42,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 9550b46f..f77e2efd 100644 --- a/core/lzo/leave.ash +++ b/core/lzo/leave.ash @@ -62,12 +62,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 55fdf6d1..5e870b85 100644 --- a/core/lzo/lzo_asm.h +++ b/core/lzo/lzo_asm.h @@ -42,10 +42,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 9c28e144..6fb8cfdd 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 @@ __free_block(struct free_arena_header *ah) 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 @@ __export void free(void *ptr) #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 abfe23ae..0526dfbf 100644 --- a/core/mem/init.c +++ b/core/mem/init.c @@ -64,11 +64,11 @@ static void mpool_dump(enum heap heap) } #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 02e60614..a3d6b45d 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 @@ static void *__malloc_from_block(struct free_arena_header *fp, 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 @@ static void *_malloc(size_t size, enum heap heap, malloc_tag_t tag) } } + 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 @@ void *pmapi_lmalloc(size_t size) 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; @@ -207,6 +217,11 @@ __export void *realloc(void *ptr, size_t size) } } +__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 00000000..a0f0bc84 --- /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 097b856c..95f76617 100644 --- a/core/pxelinux.asm +++ b/core/pxelinux.asm @@ -81,10 +81,9 @@ InitStack resd 1 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 @@ _start1: ; mov eax,ROOT_FS_OPS xor ebp,ebp - pm_call fs_init + pm_call pm_fs_init section .rodata alignz 4 @@ -382,7 +381,7 @@ pxenv: jnz .store_stack .disable_timer: - call timer_cleanup + call bios_timer_cleanup .store_stack: mov [cs:PXEStack],sp @@ -552,17 +551,3 @@ syslinux_banner db CR, LF, MY_NAME, ' ', VERSION_STR, ' ', DATE_STR, ' ', 0 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 f024b92d..edd89e86 100644 --- a/core/syslinux.ld +++ b/core/syslinux.ld @@ -26,6 +26,7 @@ SECTIONS { /* Prefix structure for the compression program */ . = 0; + __module_start = .; .prefix : { *(.prefix) } diff --git a/core/timer.inc b/core/timer.inc index 64f81a72..80647983 100644 --- a/core/timer.inc +++ b/core/timer.inc @@ -32,8 +32,8 @@ timer_init: 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 00000000..10571120 --- /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 969acbb3..e3353753 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 91225b18..2fd05c96 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 @@ all: $(BTARGET) # 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 79ff9f01..5b7153c9 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 @@ all: handoff.bin .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 00000000..d0f50680 --- /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 f9420084..1371205e 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 += -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 @@ SRCS = syslinux.c \ ../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 @@ syslinux.com: syslinux.elf %.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 d3467056..d9826706 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 6bce6248..9dc88d1f 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 @@ NASMOPT = -Ox 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 @@ installer: all 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 00000000..11ea9c2d --- /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 00000000..3dec3cc8 --- /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 00000000..e8ccb352 --- /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 00000000..1f09c5a6 --- /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 00000000..358a5638 --- /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 00000000..aa72fb11 --- /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 00000000..01ab2a0e --- /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 00000000..6472d6ab --- /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 00000000..bf203d84 --- /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 00000000..f56cd5b4 --- /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 00000000..65fff8df --- /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 00000000..e0270537 --- /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/keymap.h b/efi/keymap.h new file mode 100644 index 00000000..f44a40cb --- /dev/null +++ b/efi/keymap.h @@ -0,0 +1,82 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2004-2008 H. Peter Anvin - All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * keymap.h + * + * Map scan codes to key codes that key processing in com32/libutil expects to rely on. + * Scan codes that are part of EFI spec but not included in the map are: + * F13..F24 + * VOLUME UP/DOWN + * BRIGHTNESS UP/DOWN + * SUSPEND/HIBERNATE + * TOGGLE DISPLAY + * RECOVERY + * EJECT + */ + +#ifndef SCANKEY_MAP +#define SCANKEY_MAP + +#include <getkey.h> + +struct keycode { + int code; + int seqlen; + const unsigned char *seq; +}; + +#define CODE(x,y) { x, (sizeof y)-1, (const unsigned char *)(y) } + +const struct keycode keycodes[] = { + /* First, the BIOS combined codes */ + CODE(KEY_UP, "\0\x48"), + CODE(KEY_DOWN, "\0\x50"), + CODE(KEY_RIGHT, "\0\x4D"), + CODE(KEY_LEFT, "\0\x4B"), + CODE(KEY_HOME, "\0\x47"), + CODE(KEY_END, "\0\x4F"), + CODE(KEY_INSERT, "\0\x52"), + CODE(KEY_DELETE, "\0\x53"), + CODE(KEY_PGUP, "\0\x49"), + CODE(KEY_PGDN, "\0\x51"), + CODE(KEY_F1, "\0\x3B"), + CODE(KEY_F2, "\0\x3C"), + CODE(KEY_F3, "\0\x3D"), + CODE(KEY_F4, "\0\x3E"), + CODE(KEY_F5, "\0\x3F"), + CODE(KEY_F6, "\0\x40"), + CODE(KEY_F7, "\0\x41"), + CODE(KEY_F8, "\0\x42"), + CODE(KEY_F9, "\0\x43"), + CODE(KEY_F10, "\0\x44"), + CODE(KEY_F11, "\0\x85"), + CODE(KEY_F12, "\0\x86"), +}; + +#define NCODES ((int)(sizeof keycodes/sizeof(struct keycode))) +#endif /* SCANKEY_MAP */ diff --git a/efi/main.c b/efi/main.c new file mode 100644 index 00000000..754cbc53 --- /dev/null +++ b/efi/main.c @@ -0,0 +1,1183 @@ +#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 "keymap.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]; + + c[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; + + uefi_call_wrapper(out->EnableCursor, 2, out, true); +} + +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 && x1 == (rows - 1) && y1 == (cols - 1)) { + /* Really clear the screen */ + uefi_call_wrapper(out->ClearScreen, 1, out); + } else + uefi_call_wrapper(out->SetCursorPosition, 3, out, y0, x0); +} + +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(); +} + +static int seq_len = 0; +static char *key_seq = NULL; + +char efi_getchar(char *hi) +{ + SIMPLE_INPUT_INTERFACE *in = ST->ConIn; + EFI_INPUT_KEY key; + EFI_STATUS status; + char c; + + if (seq_len) { + /* We are in the middle of key sequence for the scan code */ + c = *key_seq++; + seq_len--; + if (!seq_len) { + /* end of key sequene, reset state */ + seq_len = 0; + key_seq = NULL; + } + return c; + } + /* Fresh key processing */ + do { + status = uefi_call_wrapper(in->ReadKeyStroke, 2, in, &key); + } while (status == EFI_NOT_READY); + + if (!key.ScanCode) + return (char)key.UnicodeChar; + + /* We need to generate a key sequence for the scan code */ + if (key.ScanCode <= NCODES) { + key_seq = (char *)keycodes[key.ScanCode-1].seq; + seq_len = keycodes[key.ScanCode-1].seqlen; + seq_len--; + c = *key_seq++; + } else c = '\0'; + + return c; +} + +int efi_pollchar(void) +{ + SIMPLE_INPUT_INTERFACE *in = ST->ConIn; + EFI_STATUS status; + + if (seq_len) { + /* we are in the middle of a key sequence .. say so */ + return 1; + } + 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; + } + if (hdr->version >= 0x20b) { + printf("bzImage version 0x%x handover protocol unimplemented \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 00000000..6203ff21 --- /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 00000000..e0270537 --- /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 00000000..473d3a55 --- /dev/null +++ b/efi/vesa.c @@ -0,0 +1,306 @@ +/* ----------------------------------------------------------------------- * + * + * 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 char *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; +} + +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 00000000..0943534c --- /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 00000000..492c262b --- /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 00000000..3c8c7c34 --- /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 f20a71db..91486880 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 @@ OBJS = $(patsubst %.c,%.o,$(notdir $(SRCS))) .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 0204caa1..e925a1d8 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 8bce8d12..d2f5e756 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 @@ tidy: 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 @@ installer: 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 63446a10..48a8fd3a 100644 --- a/libinstaller/Makefile +++ b/libinstaller/Makefile @@ -4,22 +4,26 @@ BINFILES = bootsect_bin.c ldlinux_bin.c \ 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 b739752f..a73cd10a 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 d7facaf4..f88a6cb3 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 @@ OBJS = $(patsubst %.c,%.o,$(notdir $(SRCS))) .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 cf8f985a..0c5d2965 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 993bb100..be2bded7 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 @@ all: mbr.bin altmbr.bin gptmbr.bin isohdpfx.bin isohdppx.bin \ $(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 00000000..d14ba802 --- /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 00000000..ae27d49a --- /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 b5cd52ce..4ae08554 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 +INCLUDES = -I$(topdir)/com32/include -I$(objdir) CFLAGS += -D__MEMDISK__ -DDATE='"$(DATE)"' 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 @@ memdisk_%.o: memdisk_%.bin 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 00000000..51c3e35c --- /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 00000000..5ce206d0 --- /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 b6b277a8..6da5aff9 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 00000000..a398cd8d --- /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 00000000..aa00b5b1 --- /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 bc79e127..72c67852 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 @@ static void relocate_rm_code(uint32_t newbase) 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 4fb05374..ecebe684 100644 --- a/memdisk/start32.S +++ b/memdisk/start32.S @@ -62,7 +62,13 @@ _start: 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 00000000..76abb0c0 --- /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 6a30431a..e5c27969 100644 --- a/memdump/Makefile +++ b/memdump/Makefile @@ -14,13 +14,12 @@ ## memory dump utility ## -topdir = .. -MAKEDIR = $(topdir)/mk +VPATH = $(SRC) include $(MAKEDIR)/embedded.mk 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 ca765651..ebf5ff49 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 bfba0e1b..89ede83e 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-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,) -GCCOPT += $(call gcc_ok,-incoming-stack-boundary=2,) com32 := $(topdir)/com32 RELOCS := $(com32)/tools/relocs @@ -45,17 +59,19 @@ GPLLIB = 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 8184c30f..fb4af678 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 00000000..02817953 --- /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 $@ @@ -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/libcom32gpl.c32 +GPLLIB = $(objdir)/com32/gpllib/libcom32gpl.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_com.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_com.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 c2f4edf3..ffebe83c 100644 --- a/mk/embedded.mk +++ b/mk/embedded.mk @@ -16,12 +16,30 @@ 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 \ +# FIXME: regparam for i386 and x86_64 could be different +GCCOPT += -Os -fomit-frame-pointer -mregparm=3 -DREGPARM=3 \ -msoft-float GCCOPT += $(call gcc_ok,-fno-exceptions,) GCCOPT += $(call gcc_ok,-fno-asynchronous-unwind-tables,) @@ -30,13 +48,11 @@ 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,) -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) @@ -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-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,) -INCLUDE = -I. +INCLUDE = -I$(SRC) STRIP = strip --strip-all -R .comment -R .note # zlib and libpng configuration flags @@ -31,15 +43,161 @@ LIBFLAGS = -DDYNAMIC_CRC_TABLE -DPNG_NO_CONSOLE_IO \ # 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/$(ARCH)/shallow_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 @@ LDFLAGS = -m elf_i386 --hash-style=gnu -T $(com32)/lib/elf32.ld % : %.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 @@ LDFLAGS = -m elf_i386 --hash-style=gnu -T $(com32)/lib/elf32.ld .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 1378b6d5..484afb2a 100644 --- a/mk/syslinux.mk +++ b/mk/syslinux.mk @@ -67,6 +67,12 @@ WGET = wget 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 6df18b52..3f9c42b3 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 @@ SRCS = syslinux.c \ ../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 9e504d96..1515a068 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/utils/Makefile b/utils/Makefile index be739935..dfe62590 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 @@ all: $(TARGETS) $(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 @@ -1 +1 @@ -5.00 2012 +6.00 2012 diff --git a/win32/Makefile b/win32/Makefile index 9ff8a453..a417a4b8 100644 --- a/win32/Makefile +++ b/win32/Makefile @@ -29,21 +29,22 @@ else 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 @@ LIBSRC = ../libinstaller/fs.c \ ../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 50132d48..176f8482 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 @@ LIBSRC = ../libinstaller/fs.c \ ../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 |