diff options
355 files changed, 16275 insertions, 3604 deletions
@@ -51,3 +51,6 @@ *GPATH *GRTAGS *GTAGS +/bios +/efi32 +/efi64 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..6ce10f45 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "gnu-efi"] + path = gnu-efi + url = git://git.code.sf.net/p/gnu-efi/code @@ -14,10 +14,114 @@ # # 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 test unittest regression + +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) + +unittest: + printf "Executing unit tests\n" + $(MAKE) -C core/mem/tests all + $(MAKE) -C com32/lib/syslinux/tests all + +regression: + $(MAKE) -C tests SRC="$(topdir)/tests" OBJ="$(topdir)/tests" \ + objdir=$(OBJDIR) \ + -f $(topdir)/tests/Makefile all + +test: unittest regression + +# 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 +134,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/cmenu/libmenu/*.c32 com32/elflink/ldlinux/$(LDLINUX) +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/lpxelinux.0 \ @@ -58,8 +172,21 @@ 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". + +ifdef EFI_BUILD + +BSUBDIRS = codepage com32 lzo core mbr sample efi txt +ISUBDIRS = + +INSTALLSUBDIRS = efi + +NETINSTALLABLE = efi/syslinux.efi $(INSTALLABLE_MODULES) + +else + BSUBDIRS = codepage com32 lzo core memdisk mbr memdump gpxe sample \ diag libinstaller dos win32 win64 dosutil txt + ITARGET = IOBJECTS = $(ITARGET) \ utils/gethostip utils/isohybrid utils/mkdiskimage \ @@ -89,33 +216,111 @@ EXTBOOTINSTALL = $(INSTALLABLE_MODULES) NETINSTALLABLE = core/pxelinux.0 gpxe/gpxelinux.0 core/lpxelinux.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) test + +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 netinstall: 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 netinstall: + +endif -installer: - $(MAKE) installer-local - set -e ; for i in $(ISUBDIRS); do $(MAKE) -C $$i all ; done +# 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 LDLINUX=ldlinux.c32 $(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 LDLINUX=ldlinux.e32 \ + $(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 LDLINUX=ldlinux.e64 \ + $(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 +gpxe: 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) @@ -128,16 +333,35 @@ 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: + mkdir -m 755 -p $(INSTALLROOT)$(AUXDIR)/efi$(BITS) + set -e ; for i in $(INSTALLSUBDIRS) ; \ + do $(MAKE) -C $$i SRC="$(SRC)/$$i" OBJ="$(OBJ)/$$i" \ + BITS="$(BITS)" AUXDIR="$(AUXDIR)/efi$(BITS)" \ + -f $(SRC)/$$i/Makefile $@; done + -install -m 644 $(INSTALLABLE_MODULES) $(INSTALLROOT)$(AUXDIR)/efi$(BITS) + install -m 644 com32/elflink/ldlinux/$(LDLINUX) $(INSTALLROOT)$(AUXDIR)/efi$(BITS) +endif + +ifdef EFI_BUILD +netinstall: + mkdir -p $(INSTALLROOT)$(TFTPBOOT)/efi$(BITS) + install -m 644 $(NETINSTALLABLE) $(INSTALLROOT)$(TFTPBOOT)/efi$(BITS) +else netinstall: installer mkdir -p $(INSTALLROOT)$(TFTPBOOT) install -m 644 $(NETINSTALLABLE) $(INSTALLROOT)$(TFTPBOOT) +endif extbootinstall: installer mkdir -m 755 -p $(INSTALLROOT)$(EXTLINUXDIR) @@ -150,33 +374,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..6fa5cbe3 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 @@ -50,8 +50,10 @@ release: git archive --format=tar syslinux-$(VERSION) | \ tar -x -f - -C release/syslinux-$(VERSION) find release/syslinux-$(VERSION) \ - \( -name '*~' -or -name '#*' \) -type f -print0 | \ + \( -name '*~' -or -name '#*' -or -name '.git*' \) -type f -print0 | \ xargs -0rt rm -f + find release/syslinux-$(VERSION) -name 'tests' -type d -print0 | \ + xargs -0rt rm -rf sed -e 's/@@VERSION@@/$(VERSION)/g' -e 's/@@RPMVERSION@@/$(VERSION)/g' \ < release/syslinux-$(VERSION)/syslinux.spec.in \ > release/syslinux-$(VERSION)/syslinux.spec @@ -81,6 +83,9 @@ prerel: find $(PRERELDIR)/$(PREREL) \ \( -name '*~' -or -name '#*' \) -type f -print0 | \ xargs -0rt rm -f + find $(PRERELDIR)/$(PREREL) \ + -name 'tests' -type d -print0 | \ + xargs -0rt rm -rf sed -e 's/@@VERSION@@/$(VERSION)-pre$(PRERELNO)/g' \ -e 's/@@RPMVERSION@@/$(RPMPREREL)/g' \ < $(PRERELDIR)/$(PREREL)/syslinux.spec.in \ @@ -2,12 +2,50 @@ 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.02: + * efi64: Add support for booting 32-bit kernels. + * efi: Use the EFI handover protocol when booting kernels if + available. + * Fix various make targets that became broken when switching to + per-firmware object directories, including 'make install' and + 'make netinstall'. + * efi: Improve handling of packet loss in UDP stack. + * tests: Introduce a new regression test framework designed to + ensure bugs are not reintroduced once fixed. + * efi: Implement localboot support. + +Changes in 6.01: + * efi: Mark some symbols as __export otherwise libcom32.c32 and + vesamenu.c32 will refuse to load. + * bios: Wire up the bios kernel loader. It was impossible to + load a kernel from bios in 6.00. + * efi: Fix 'make installer'. There are no EFI installers so + don't try and build them as we run into build errors. + * efi: Reuse the initial TFTP client port in subsequent + transfers otherwise the server will send an error packet. + * efi: Some firmware will not set a default TTL value in IP + packets - we must explicitly set it ourselves otherwise a + value of zero may be used. + * bios, font: Fix a font regression affecting some VirtualBox + users. + +Changes in 6.00: + * Add support for booting from EFI. + * EFI TCP/IP support. This allows the EFI backend to hook into + the generic TFTP, HTTP and FTP functionality. + +Changes in 5.11: + * Dynamic debug support: Add new module, debug.c32, that allows + debug code to be dynamically enabled and disabled at runtime. + Changes in 5.10: * PXELINUX: An entirely new network implementation based on the lwIP embedded TCP/IP stack. As a result, plain PXELINUX can now support HTTP and FTP without gPXE/iPXE. ls/readdir functionality is supported over HTTP with an indexing - webserver, or over FTP with most common FTP servers. + webserver, or over FTP with most common FTP servers. For the + new network stack use lpxelinux.0. For the legacy stack use + pxelinux.0. * Rename the "ipappend" option to "sysappend" ("ipappend" is still accepted as an alias) and make it available for all derivatives. Add additional strings derived from the system @@ -15,6 +53,15 @@ Changes in 5.10: * "sysappend" strings are also sent as http cookies, with the prefix _Syslinux_ added, on all http transfers. This can be overridden with the SENDCOOKIES configuration file command. + * poweroff.c32: A new module to power off a system via APM. It + replaces the poweroff COMBOOT module (Sebastian Herbszt). + * PXELINUX: Fix booting with DHCP options 209 and 210 which was + broken in 5.00. + * Handle loading kernel images with no protected mode code. A + legitimate kernel image can consist solely of real-mode code. + The support for booting such images was broken in 5.00 (Josh Triplett). + * Fix a regression in the .psf font file loader introduced + in 5.00. Changes in 5.01: * txt/: A new AsciiDoc documentation set (work-in-progress) @@ -59,6 +106,14 @@ Changes in 5.00: COMBOOT files (.cbt and .com) are no longer supported under Syslinux. +Changes in 4.07: + * EXTLINUX: fix crash caused by dereferencing garbage pointer. + * Plug memory leak in searchdir which eventually leads to an + observable hang (Shao Miller). + * ISOLINUX: fix bug triggered by isohybrid images larger than + 32K which results in an invalid image checksum error. + * menugen: make it Py3k compatible (Paulo Alcantara). + Changes in 4.06: * Support for NTFS, by Paulo Alcantara. * EXTLINUX: more robust device detection, allow user to override. 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..6cb4a7df 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: lib libutil gpllib +cmenu: lib libutil +elflink/ldlinux: lib +gfxboot: lib libutil gpllib +hdt: lib libupload cmenu gpllib libutil +modules: lib libutil gpllib +rosh: lib libutil +samples: libutil elflink/ldlinux +sysdump: lib libutil libupload gpllib diff --git a/com32/chain/Makefile b/com32/chain/Makefile index c7587eae..4a5af919 100644 --- a/com32/chain/Makefile +++ b/com32/chain/Makefile @@ -13,9 +13,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 d51b2e84..6bb52316 100644 --- a/com32/cmenu/Makefile +++ b/com32/cmenu/Makefile @@ -18,31 +18,35 @@ NOGPL := 1 LIBS = libmenu/libmenu.c32 \ - $(com32)/libutil/libutil.c32 \ - $(com32)/lib/libcom32.c32 + $(objdir)/com32/libutil/libutil.c32 \ + $(objdir)/com32/lib/libcom32.c32 -topdir = ../.. -MAKEDIR = $(topdir)/mk +C_LIBS = libmenu/libmenu.c32 + +VPATH = $(SRC) include $(MAKEDIR)/elf.mk -CFLAGS += -I./libmenu +CFLAGS += -I$(SRC)/libmenu LIBMENU = libmenu/syslnx.o libmenu/com32io.o libmenu/tui.o \ libmenu/menu.o libmenu/passwords.o libmenu/des.o libmenu/help.o \ - $(com32)/libutil/libutil.c32 $(com32)/lib/libcom32.c32 + $(objdir)/com32/libutil/libutil.c32 $(objdir)/com32/lib/libcom32.c32 -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: makeoutputdirs menus -all: menus +makeoutputdirs: + @mkdir -p $(OBJ)/libmenu libmenu/libmenu.elf: $(LIBMENU) $(LD) -shared $(LDFLAGS) -soname $(patsubst %.elf,%.c32,$(@F)) \ @@ -54,14 +58,14 @@ tidy dist: libclean: rm -f libmenu/*.c32 -clean: tidy menuclean libclean - rm -f *.lss *.c32 *.com +clean: tidy menuclean + rm -f *.lss *.com menuclean: rm -f $(patsubst %.menu,%.c,$(wildcard *.menu)) spotless: clean libclean menuclean - rm -f *~ \#* + rm -f *~ \#* *.c32 menus: $(MENUS) diff --git a/com32/cmenu/libmenu/com32io.c b/com32/cmenu/libmenu/com32io.c index 8e5016be..6954c438 100644 --- a/com32/cmenu/libmenu/com32io.c +++ b/com32/cmenu/libmenu/com32io.c @@ -20,6 +20,7 @@ com32sys_t inreg, outreg; // Global register sets for use void getpos(char *row, char *col, char page) { + memset(&inreg, 0, sizeof inreg); REG_AH(inreg) = 0x03; REG_BH(inreg) = page; __intcall(0x10, &inreg, &outreg); @@ -30,6 +31,7 @@ void getpos(char *row, char *col, char page) char inputc(char *scancode) { syslinux_idle(); /* So syslinux can perform periodic activity */ + memset(&inreg, 0, sizeof inreg); REG_AH(inreg) = 0x10; __intcall(0x16, &inreg, &outreg); if (scancode) @@ -40,6 +42,7 @@ char inputc(char *scancode) void getcursorshape(char *start, char *end) { char page = 0; // XXX TODO + memset(&inreg, 0, sizeof inreg); REG_AH(inreg) = 0x03; REG_BH(inreg) = page; __intcall(0x10, &inreg, &outreg); @@ -49,6 +52,7 @@ void getcursorshape(char *start, char *end) void setcursorshape(char start, char end) { + memset(&inreg, 0, sizeof inreg); REG_AH(inreg) = 0x01; REG_CH(inreg) = start; REG_CL(inreg) = end; @@ -57,6 +61,7 @@ void setcursorshape(char start, char end) void setvideomode(char mode) { + memset(&inreg, 0, sizeof inreg); REG_AH(inreg) = 0x00; REG_AL(inreg) = mode; __intcall(0x10, &inreg, &outreg); @@ -65,6 +70,7 @@ void setvideomode(char mode) // Get char displayed at current position unsigned char getcharat(char page) { + memset(&inreg, 0, sizeof inreg); REG_AH(inreg) = 0x08; REG_BH(inreg) = page; __intcall(0x16, &inreg, &outreg); diff --git a/com32/cmenu/libmenu/syslnx.c b/com32/cmenu/libmenu/syslnx.c index 5060c5db..73ec2a7c 100644 --- a/com32/cmenu/libmenu/syslnx.c +++ b/com32/cmenu/libmenu/syslnx.c @@ -16,6 +16,7 @@ #include <graphics.h> #include "syslnx.h" #include <syslinux/config.h> +#include <syslinux/video.h> com32sys_t inreg, outreg; // Global registers for this module diff --git a/com32/elflink/ldlinux/Makefile b/com32/elflink/ldlinux/Makefile index 556f93a5..d948da43 100644 --- a/com32/elflink/ldlinux/Makefile +++ b/com32/elflink/ldlinux/Makefile @@ -10,21 +10,30 @@ ## ## ----------------------------------------------------------------------- -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 -BTARGET = ldlinux.c32 +OBJS = ldlinux.o cli.o readconfig.o refstr.o colors.o getadv.o adv.o \ + execute.o chainboot.o kernel.o get_key.o advwrite.o setadv.o \ + loadhigh.o msg.o + +BTARGET = $(LDLINUX) + +ifdef EFI_BUILD +%.e$(BITS): %.elf + $(OBJCOPY) --strip-debug --strip-unneeded $< $@ +SONAME = $(patsubst %.elf,%.e$(BITS),$(@F)) +else +SONAME = $(patsubst %.elf,%.c32,$(@F)) +endif all: $(BTARGET) ldlinux_lnx.a -ldlinux.elf : ldlinux.o cli.o readconfig.o refstr.o colors.o getadv.o \ - adv.o execute.o chainboot.o kernel.o get_key.o \ - advwrite.o setadv.o loadhigh.o msg.o - $(LD) $(LDFLAGS) -soname $(patsubst %.elf,%.c32,$(@F)) -o $@ $^ $(LIBS) +ldlinux.elf : $(OBJS) + $(LD) $(LDFLAGS) -soname $(SONAME) -o $@ $^ $(LIBS) LNXCFLAGS += -D__export='__attribute__((visibility("default")))' LNXLIBOBJS = get_key.lo 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/elflink/ldlinux/cli.c b/com32/elflink/ldlinux/cli.c index b85357b2..6ff30c64 100644 --- a/com32/elflink/ldlinux/cli.c +++ b/com32/elflink/ldlinux/cli.c @@ -89,10 +89,14 @@ static const char * cmd_reverse_search(int *cursor, clock_t *kbd_to, break; } - while (!list_is_last(&last_found->list, &cli_history_head)) { + while (last_found) { p = strstr(last_found->command, buf); if (p) break; + + if (list_is_last(&last_found->list, &cli_history_head)) + break; + last_found = list_entry(last_found->list.next, typeof(*last_found), list); } @@ -168,7 +172,7 @@ const char *edit_cmdline(const char *input, int top /*, int width */ , prev_len = max(len, prev_len); /* Redraw the command line */ - printf("\033[?7l\033[?25l"); + printf("\033[?25l"); printf("\033[1G%s ", input); x = strlen(input); @@ -391,7 +395,7 @@ const char *edit_cmdline(const char *input, int top /*, int width */ , len = strlen(cmdline); } else { cmdline[0] = '\0'; - len = 0; + cursor = len = 0; } redraw = 1; } @@ -441,6 +445,9 @@ const char *edit_cmdline(const char *input, int top /*, int width */ , } prev_len++; } else { + if (cursor > len) + return NULL; + memmove(cmdline + cursor + 1, cmdline + cursor, len - cursor + 1); cmdline[cursor++] = key; @@ -454,11 +461,14 @@ const char *edit_cmdline(const char *input, int top /*, int width */ , printf("\033[?7h"); - /* Add the command to the history */ - comm_counter = malloc(sizeof(struct cli_command)); - comm_counter->command = malloc(sizeof(char) * (strlen(ret) + 1)); - strcpy(comm_counter->command, ret); - list_add(&(comm_counter->list), &cli_history_head); + /* Add the command to the history if its length is larger than 0 */ + len = strlen(ret); + if (len > 0) { + comm_counter = malloc(sizeof(struct cli_command)); + comm_counter->command = malloc(sizeof(char) * (len + 1)); + strcpy(comm_counter->command, ret); + list_add(&(comm_counter->list), &cli_history_head); + } return len ? ret : NULL; } diff --git a/com32/elflink/ldlinux/execute.c b/com32/elflink/ldlinux/execute.c index bf0bd8ce..653c880d 100644 --- a/com32/elflink/ldlinux/execute.c +++ b/com32/elflink/ldlinux/execute.c @@ -131,14 +131,14 @@ __export void execute(const char *cmdline, uint32_t type, bool sysappend) * irrespective of how the COM32 module was loaded, * e.g. from vesamenu.c32. */ - unload_modules_since("ldlinux.c32"); + unload_modules_since(LDLINUX); /* Restore the console */ ldlinux_console_init(); ldlinux_enter_command(); } else if (type == IMAGE_TYPE_CONFIG) { - char *argv[] = { "ldlinux.c32", NULL, NULL }; + char *argv[] = { LDLINUX, NULL, NULL }; char *config; int rv; @@ -155,7 +155,7 @@ __export void execute(const char *cmdline, uint32_t type, bool sysappend) argv[1] = config; rv = start_ldlinux(2, argv); - printf("Failed to exec ldlinux.c32: %s\n", strerror(rv)); + printf("Failed to exec %s: %s\n", LDLINUX, strerror(rv)); } else if (type == IMAGE_TYPE_LOCALBOOT) { local_boot(strtoul(kernel, NULL, 0)); } else if (type == IMAGE_TYPE_PXE || type == IMAGE_TYPE_BSS || diff --git a/com32/elflink/ldlinux/get_key.c b/com32/elflink/ldlinux/get_key.c index cece0f81..6cba1244 100644 --- a/com32/elflink/ldlinux/get_key.c +++ b/com32/elflink/ldlinux/get_key.c @@ -112,6 +112,31 @@ static const struct keycode keycodes[] = { CODE(KEY_INSERT, "\033[2~"), CODE(KEY_INSERT, "\033[@"), CODE(KEY_DELETE, "\033[3~"), + + /* EFI scan codes */ + CODE(KEY_UP, "\0\x01"), + CODE(KEY_DOWN, "\0\x02"), + CODE(KEY_RIGHT, "\0\x03"), + CODE(KEY_LEFT, "\0\x04"), + CODE(KEY_HOME, "\0\x05"), + CODE(KEY_END, "\0\x06"), + CODE(KEY_INSERT, "\0\x07"), + CODE(KEY_DELETE, "\0\x08"), + CODE(KEY_PGUP, "\0\x09"), + CODE(KEY_PGDN, "\0\x0a"), + CODE(KEY_F1, "\0\x0b"), + CODE(KEY_F2, "\0\x0c"), + CODE(KEY_F3, "\0\x0d"), + CODE(KEY_F4, "\0\x0e"), + CODE(KEY_F5, "\0\x0f"), + CODE(KEY_F6, "\0\x10"), + CODE(KEY_F7, "\0\x11"), + CODE(KEY_F8, "\0\x12"), + CODE(KEY_F9, "\0\x13"), + CODE(KEY_F10, "\0\x14"), + CODE(KEY_F11, "\0\x15"), + CODE(KEY_F12, "\0\x16"), + CODE(KEY_ESC, "\0\x17"), }; #define NCODES ((int)(sizeof keycodes/sizeof(struct keycode))) diff --git a/com32/elflink/ldlinux/msg.c b/com32/elflink/ldlinux/msg.c index 9ded33ef..1a97b3c0 100644 --- a/com32/elflink/ldlinux/msg.c +++ b/com32/elflink/ldlinux/msg.c @@ -1,3 +1,4 @@ +#include <syslinux/video.h> #include <com32.h> #include <stdio.h> #include <bios.h> diff --git a/com32/elflink/ldlinux/readconfig.c b/com32/elflink/ldlinux/readconfig.c index 9d50c2f3..347f8264 100644 --- a/com32/elflink/ldlinux/readconfig.c +++ b/com32/elflink/ldlinux/readconfig.c @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------- * * * Copyright 2004-2009 H. Peter Anvin - All Rights Reserved - * Copyright 2009 Intel Corporation; author: H. Peter Anvin + * Copyright 2009-2013 Intel Corporation; author: H. Peter Anvin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -640,7 +640,7 @@ extern const char *append; extern uint16_t PXERetry; static struct labeldata ld; -static int parse_one_config(const char *filename); +static int parse_main_config(const char *filename); static char *is_kernel_type(char *cmdstr, enum kernel_type *type) { @@ -759,18 +759,120 @@ static uint8_t SerialNotice = 1; #define DEFAULT_BAUD 9600 #define BAUD_DIVISOR 115200 -#define serial_base 0x0400 extern void sirq_cleanup_nowipe(void); extern void sirq_install(void); extern void write_serial_str(char *); -extern void loadfont(char *); -extern void loadkeys(char *); +extern void loadfont(const char *); +extern void loadkeys(const char *); extern char syslinux_banner[]; extern char copyright_str[]; +/* + * PATH-based lookup + * + * Each entry in the PATH directive is separated by a colon, e.g. + * + * PATH /bar:/bin/foo:/baz/bar/bin + */ +static int parse_path(char *p) +{ + struct path_entry *entry; + const char *str; + + while (*p) { + char *c = p; + + /* Find the next directory */ + while (*c && *c != ':') + c++; + + str = refstrndup(p, c - p); + if (!str) + goto bail; + + entry = path_add(str); + refstr_put(str); + + if (!entry) + goto bail; + + if (!*c++) + break; + p = c; + } + + return 0; + +bail: + return -1; +} + +static void parse_config_file(FILE * f); + +static void do_include_menu(char *str, struct menu *m) +{ + const char *file; + char *p; + FILE *f; + int fd; + + p = skipspace(str); + file = refdup_word(&p); + p = skipspace(p); + + fd = open(file, O_RDONLY); + if (fd < 0) + goto put; + + f = fdopen(fd, "r"); + if (!f) + goto bail; + + if (*p) { + record(m, &ld, append); + m = current_menu = begin_submenu(p); + } + + parse_config_file(f); + + if (*p) { + record(m, &ld, append); + m = current_menu = end_submenu(); + } + +bail: + close(fd); +put: + refstr_put(file); + +} + +static void do_include(char *str) +{ + const char *file; + char *p; + FILE *f; + int fd; + + p = skipspace(str); + file = refdup_word(&p); + + fd = open(file, O_RDONLY); + if (fd < 0) + goto put; + + f = fdopen(fd, "r"); + if (f) + parse_config_file(f); + + close(fd); +put: + refstr_put(file); +} + static void parse_config_file(FILE * f) { char line[MAX_LINE], *p, *ep, ch; @@ -859,7 +961,7 @@ static void parse_config_file(FILE * f) m->menu_master_passwd = refstrdup(skipspace(p + 6)); } } else if ((ep = looking_at(p, "include"))) { - goto do_include; + do_include_menu(ep, m); } else if ((ep = looking_at(p, "background"))) { p = skipspace(ep); refstr_put(m->menu_background); @@ -1056,23 +1158,7 @@ static void parse_config_file(FILE * f) m->fkeyhelp[fkeyno].background = refdup_word(&p); } } else if ((ep = looking_at(p, "include"))) { -do_include: - { - const char *file; - p = skipspace(ep); - file = refdup_word(&p); - p = skipspace(p); - if (*p) { - record(m, &ld, append); - m = current_menu = begin_submenu(p); - parse_one_config(file); - record(m, &ld, append); - m = current_menu = end_submenu(); - } else { - parse_one_config(file); - } - refstr_put(file); - } + do_include(ep); } else if (looking_at(p, "append")) { const char *a = refstrdup(skipspace(p + 6)); if (ld.label) { @@ -1125,7 +1211,7 @@ do_include: allowoptions = !!atoi(skipspace(p + 12)); } else if ((ep = looking_at(p, "ipappend")) || (ep = looking_at(p, "sysappend"))) { - uint32_t s = strtoul(skipspace(ep), NULL, 16); + uint32_t s = strtoul(skipspace(ep), NULL, 0); if (ld.label) ld.ipappend = s; else @@ -1185,16 +1271,9 @@ do_include: refstr_put(filename); } else if (looking_at(p, "kbdmap")) { const char *filename; - char *dst = KernelName; - size_t len = FILENAME_MAX - 1; - filename = refstrdup(skipspace(p + 4)); - - while (len-- && not_whitespace(*filename)) - *dst++ = *filename++; - *dst = '\0'; - - loadkeys(KernelName); + filename = refstrdup(skipspace(p + 6)); + loadkeys(filename); refstr_put(filename); } /* @@ -1280,16 +1359,7 @@ do_include: baud &= 0xffff; BaudDivisor = baud; - /* - * If port > 3 then port is I/O addr - */ - if (port <= 3) { - /* Get the I/O port from the BIOS */ - port <<= 1; - port = *(volatile uint16_t *)serial_base; - } - - + port = get_serial_port(port); SerialPort = port; /* @@ -1347,24 +1417,8 @@ do_include: } else if (looking_at(p, "say")) { printf("%s\n", p+4); } else if (looking_at(p, "path")) { - /* PATH-based lookup */ - const char *new_path; - char *_p; - size_t len, new_len; - - new_path = refstrdup(skipspace(p + 4)); - len = strlen(PATH); - new_len = strlen(new_path); - _p = malloc(len + new_len + 2); - if (_p) { - strncpy(_p, PATH, len); - _p[len++] = ':'; - strncpy(_p + len, new_path, new_len); - _p[len + new_len] = '\0'; - free(PATH); - PATH = _p; - } else - printf("Failed to realloc PATH\n"); + if (parse_path(skipspace(p + 4))) + printf("Failed to parse PATH\n"); } else if (looking_at(p, "sendcookies")) { const union syslinux_derivative_info *sdi; @@ -1379,7 +1433,7 @@ do_include: } } -static int parse_one_config(const char *filename) +static int parse_main_config(const char *filename) { const char *mode = "r"; FILE *f; @@ -1459,14 +1513,14 @@ void parse_configs(char **argv) current_menu = root_menu; if (!argv || !*argv) { - if (parse_one_config(NULL) < 0) { + if (parse_main_config(NULL) < 0) { printf("WARNING: No configuration file found\n"); return; } } else { while ((filename = *argv++)) { dprintf("Parsing config: %s", filename); - parse_one_config(filename); + parse_main_config(filename); } } diff --git a/com32/gfxboot/Makefile b/com32/gfxboot/Makefile index bd0bab11..824d7d0d 100644 --- a/com32/gfxboot/Makefile +++ b/com32/gfxboot/Makefile @@ -11,24 +11,35 @@ ## ## ----------------------------------------------------------------------- -topdir = ../.. -MAKEDIR = $(topdir)/mk +VPATH = $(SRC) include $(MAKEDIR)/elf.mk MODULES = gfxboot.c32 all: $(MODULES) -gfxboot.elf : gfxboot.o realmode_callback.o $(LIBS) $(C_LIBS) +OBJS = gfxboot.o realmode_callback.o + +gfxboot.elf : $(OBJS) $(LIBS) $(C_LIBS) $(LD) $(LDFLAGS) -o $@ $^ realmode_callback.o: realmode_callback.asm +ifeq ($(ARCH),i386) $(NASM) -f bin -O99 -o $*.tmp -l $*.lst $< $(OBJCOPY) -B i386 -I binary -O elf32-i386 \ --redefine-sym _binary_$*_tmp_start=$*_start \ --redefine-sym _binary_$*_tmp_end=$*_end \ --strip-symbol _binary_$*_tmp_size \ $*.tmp $@ +endif +ifeq ($(ARCH),x86_64) + $(NASM) -f bin -O99 -o $*.tmp -l $*.lst $< + $(OBJCOPY) -B i386:x86-64 -I binary -O elf64-x86-64 \ + --redefine-sym _binary_$*_tmp_start=$*_start \ + --redefine-sym _binary_$*_tmp_end=$*_end \ + --strip-symbol _binary_$*_tmp_size \ + $*.tmp $@ +endif tidy dist: rm -f *.o *.lo *.a *.lst .*.d *.tmp diff --git a/com32/gfxboot/gfxboot.c b/com32/gfxboot/gfxboot.c index 9c07d263..f67132c1 100644 --- a/com32/gfxboot/gfxboot.c +++ b/com32/gfxboot/gfxboot.c @@ -538,6 +538,7 @@ int gfx_init(char *file) void *lowmem = lowmem_buf; unsigned lowmem_size = LOWMEM_BUF_SIZE; + memset(&r,0,sizeof(r)); progress_active = 0; printf("Loading %s...\n", file); @@ -646,6 +647,7 @@ int gfx_menu_init(void) { com32sys_t r; + memset(&r,0,sizeof(r)); r.esi.l = (uint32_t) &gfx_menu; __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_MENU_INIT], &r, &r); @@ -658,6 +660,7 @@ void gfx_done(void) { com32sys_t r; + memset(&r,0,sizeof(r)); gfx_progress_done(); __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_DONE], &r, &r); @@ -674,6 +677,7 @@ int gfx_input(void) { com32sys_t r; + memset(&r,0,sizeof(r)); r.edi.l = (uint32_t) cmdline; r.ecx.l = sizeof cmdline; r.eax.l = timeout * 182 / 100; @@ -692,6 +696,7 @@ void gfx_infobox(int type, char *str1, char *str2) { com32sys_t r; + memset(&r,0,sizeof(r)); r.eax.l = type; r.esi.l = (uint32_t) str1; r.edi.l = (uint32_t) str2; @@ -707,6 +712,7 @@ void gfx_progress_init(ssize_t kernel_size, char *label) { com32sys_t r; + memset(&r,0,sizeof(r)); if(!progress_active) { r.eax.l = kernel_size >> gfx_config.sector_shift; // in sectors r.esi.l = (uint32_t) label; @@ -722,6 +728,7 @@ void gfx_progress_update(ssize_t advance) { com32sys_t r; + memset(&r,0,sizeof(r)); if(progress_active) { r.eax.l = advance >> gfx_config.sector_shift; // in sectors __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_PROGRESS_UPDATE], &r, &r); @@ -734,6 +741,7 @@ void gfx_progress_done(void) { com32sys_t r; + memset(&r,0,sizeof(r)); if(progress_active) { __farcall(gfx.code_seg, gfx.jmp_table[GFX_CB_PROGRESS_DONE], &r, &r); } diff --git a/com32/gpllib/Makefile b/com32/gpllib/Makefile index 3ccc0dc6..e3e30d76 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: libgpl.c32 +all: makeoutputdirs libgpl.c32 + +makeoutputdirs: + @mkdir -p $(foreach b, \ + $(addprefix $(OBJ),$(sort $(dir $(LIBOBJS)))),$(b)) libgpl.elf : $(LIBOBJS) $(LD) -shared $(LDFLAGS) -soname $(patsubst %.elf,%.c32,$(@F)) -o $@ $^ @@ -38,6 +40,6 @@ install: all mkdir -m 755 -p $(INSTALLROOT)$(COM32DIR) install -m 644 libgpl.c32 $(INSTALLROOT)$(COM32DIR) mkdir -p $(INSTALLROOT)$(COM32DIR)/include/ - cp -r ../gplinclude $(INSTALLROOT)$(COM32DIR)/include/ + cp -r $(SRC)/../gplinclude $(INSTALLROOT)$(COM32DIR)/include/ -include .*.d */.*.d */*/.*.d diff --git a/com32/gpllib/acpi/acpi.c b/com32/gpllib/acpi/acpi.c index d2bf29e5..3013f196 100644 --- a/com32/gpllib/acpi/acpi.c +++ b/com32/gpllib/acpi/acpi.c @@ -35,7 +35,6 @@ /* M1PS flags have to be interpreted as strings */ char *flags_to_string(char *buffer, uint16_t flags) { - memset(buffer, 0, sizeof(buffer)); strcpy(buffer, "default"); if ((flags & POLARITY_ACTIVE_HIGH) == POLARITY_ACTIVE_HIGH) strcpy(buffer, "high"); diff --git a/com32/hdt/Makefile b/com32/hdt/Makefile index 42f5c0d1..80f2d0a0 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/hdt/hdt-cli.c b/com32/hdt/hdt-cli.c index 216b6bde..2895b13c 100644 --- a/com32/hdt/hdt-cli.c +++ b/com32/hdt/hdt-cli.c @@ -780,6 +780,8 @@ void start_auto_mode(struct s_hardware *hardware) mypch = strtok(NULL, AUTO_SEPARATOR); } + free(temp); + /* Executing found commands */ for (int i = 1; i <= nb_commands; i++) { if (commands[i]) { diff --git a/com32/hdt/hdt-common.c b/com32/hdt/hdt-common.c index 289d74e3..fbb8c988 100644 --- a/com32/hdt/hdt-common.c +++ b/com32/hdt/hdt-common.c @@ -334,6 +334,7 @@ int detect_vesa(struct s_hardware *hardware) goto out; gi->signature = VBE2_MAGIC; /* Get VBE2 extended data */ + memset(&rm, 0, sizeof rm); rm.eax.w[0] = 0x4F00; /* Get SVGA general information */ rm.edi.w[0] = OFFS(gi); rm.es = SEG(gi); @@ -361,6 +362,7 @@ int detect_vesa(struct s_hardware *hardware) while ((mode = *mode_ptr++) != 0xFFFF) { + memset(&rm, 0, sizeof rm); rm.eax.w[0] = 0x4F01; /* Get SVGA mode information */ rm.ecx.w[0] = mode; rm.edi.w[0] = OFFS(mi); 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 795b9fba..adef7126 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..b3f1b46b 100644 --- a/com32/include/dprintf.h +++ b/com32/include/dprintf.h @@ -5,30 +5,39 @@ #ifndef _DPRINTF_H #define _DPRINTF_H +#include <syslinux/debug.h> + #if !defined(DEBUG_PORT) && !defined(DEBUG_STDIO) -# undef DEBUG +# undef CORE_DEBUG #endif -#ifdef DEBUG +#ifdef CORE_DEBUG # include <stdio.h> # ifdef DEBUG_STDIO # define dprintf printf # define vdprintf vprintf +# define ddprintf dprintf # else void dprintf(const char *, ...); void vdprintf(const char *, va_list); +# define ddprintf(...) { printf(__VA_ARGS__); dprintf(__VA_ARGS__); } # endif #else -# define dprintf(fmt, ...) ((void)(0)) -# define vdprintf(fmt, ap) ((void)(0)) +#define dprintf(...) \ + if (syslinux_debug_enabled) \ + printf(__VA_ARGS__) +#define vdprintf(fmt, ap) \ + if (syslinux_debug_enabled) \ + vprintf(fmt, ap) +#define ddprintf printf -#endif /* DEBUG */ +#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/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 807e13c4..76c45da0 100644 --- a/com32/include/sys/cpu.h +++ b/com32/include/sys/cpu.h @@ -5,139 +5,13 @@ #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" : : : "memory"); -} - -static inline void hlt(void) -{ - asm volatile("hlt" : : : "memory"); -} - -static inline void cli(void) -{ - asm volatile("cli" : : : "memory"); -} - -static inline void sti(void) -{ - asm volatile("sti" : : : "memory"); -} +#if __SIZEOF_POINTER__ == 4 +#include <i386/cpu.h> +#elif __SIZEOF_POINTER__ == 8 +#include <x86_64/cpu.h> +#else +#error "unsupported architecture" +#endif typedef unsigned long irq_state_t; @@ -145,7 +19,7 @@ static inline irq_state_t irq_state(void) { irq_state_t __st; - asm volatile("pushfl ; popl %0" : "=rm" (__st) : : "memory"); + asm volatile("pushf ; pop %0" : "=rm" (__st) : : "memory"); return __st; } @@ -158,8 +32,26 @@ static inline irq_state_t irq_save(void) static inline void irq_restore(irq_state_t __st) { - asm volatile("pushl %0 ; popfl" : : "rm" (__st) : "memory"); + asm volatile("push %0 ; popf" : : "rm" (__st) : "memory"); } +/* Standard macro to see if a specific flag is changeable */ +static inline __constfunc bool cpu_has_eflag(unsigned long flag) +{ + unsigned long 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); +} #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..a0cedf20 --- /dev/null +++ b/com32/include/sys/i386/cpu.h @@ -0,0 +1,114 @@ +/* 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; +} + +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" : : : "memory"); +} + +static inline void hlt(void) +{ + asm volatile("hlt" : : : "memory"); +} + +static inline void cli(void) +{ + asm volatile("cli" : : : "memory"); +} + +static inline void sti(void) +{ + asm volatile("sti" : : : "memory"); +} 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 8d144203..c1d42531 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) */ @@ -328,7 +324,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. @@ -345,7 +341,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 @@ -355,7 +351,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..cbe968f5 --- /dev/null +++ b/com32/include/sys/x86_64/cpu.h @@ -0,0 +1,128 @@ +#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)); +} + +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" : : : "memory"); +} + +static inline void hlt(void) +{ + asm volatile("hlt" : : : "memory"); +} + +static inline void cli(void) +{ + asm volatile("cli" : : : "memory"); +} + +static inline void sti(void) +{ + asm volatile("sti" : : : "memory"); +} +#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/config.h b/com32/include/syslinux/config.h index 235f288d..45a0ac77 100644 --- a/com32/include/syslinux/config.h +++ b/com32/include/syslinux/config.h @@ -188,4 +188,6 @@ static inline enum syslinux_filesystem syslinux_filesystem(void) return syslinux_derivative_info()->c.filesystem; } +extern void get_derivative_info(union syslinux_derivative_info *di); + #endif /* _SYSLINUX_CONFIG_H */ diff --git a/com32/include/syslinux/debug.h b/com32/include/syslinux/debug.h new file mode 100644 index 00000000..aee6fdbb --- /dev/null +++ b/com32/include/syslinux/debug.h @@ -0,0 +1,15 @@ +#ifndef DEBUG_H +#define DEBUG_H + +#include <stdbool.h> + +#ifdef DYNAMIC_DEBUG +#define syslinux_debug_enabled __syslinux_debug_enabled(__func__) +extern bool __syslinux_debug_enabled(const char *func); +#else +#define syslinux_debug_enabled (0) +#endif /* DYNAMIC_DEBUG */ + +extern int syslinux_debug(const char *str, bool enable); + +#endif /* DEBUG_H */ diff --git a/com32/include/syslinux/disk.h b/com32/include/syslinux/disk.h index f96ca686..b8361fe4 100644 --- a/com32/include/syslinux/disk.h +++ b/com32/include/syslinux/disk.h @@ -41,6 +41,13 @@ #define SECTOR 512u /* bytes/sector */ +enum disk_op_codes { + EBIOS_READ_CODE = 0x42, /* Extended read */ + EBIOS_WRITE_CODE = 0x43, /* Extended write */ + CHS_READ_CODE = 0x02, + CHS_WRITE_CODE = 0x03, +}; + struct disk_info { int disk; int ebios; /* EBIOS supported on this disk */ diff --git a/com32/include/syslinux/firmware.h b/com32/include/syslinux/firmware.h new file mode 100644 index 00000000..6cc06a08 --- /dev/null +++ b/com32/include/syslinux/firmware.h @@ -0,0 +1,71 @@ +#ifndef _SYSLINUX_FIRMWARE_H +#define _SYSLINUX_FIRMWARE_H + +#include <inttypes.h> +#include <stdbool.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 (*text_mode)(void); + void (*get_cursor)(uint8_t *, uint8_t *); +}; + +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 *); +}; + +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 *); + 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..700ac9a8 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,94 @@ struct setup_data { #define SETUP_E820_EXT 1 #define SETUP_DTB 2 +#define XLF_KERNEL_64 (1 << 0) +#define XLF_CAN_BE_LOADED_ABOVE_4G (1 << 1) +#define XLF_EFI_HANDOVER_32 (1 << 2) +#define XLF_EFI_HANDOVER_64 (1 << 3) + +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 min_alignment; + uint16_t xloadflags; + 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; + uint32_t handover_offset; +} __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 +178,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..ab78e28b 100644 --- a/com32/include/syslinux/memscan.h +++ b/com32/include/syslinux/memscan.h @@ -29,10 +29,19 @@ #ifndef _SYSLINUX_MEMSCAN_H #define _SYSLINUX_MEMSCAN_H -#include <stdbool.h> +#include <linux/list.h> #include <syslinux/movebits.h> /* addr_t */ -typedef int (*scan_memory_callback_t) (void *, addr_t, addr_t, bool); +typedef int (*scan_memory_callback_t) (void *, addr_t, addr_t, + enum syslinux_memmap_types type); + +struct syslinux_memscan { + int (*func)(scan_memory_callback_t callback, void *data); + struct list_head next; +}; + +void syslinux_memscan_add(struct syslinux_memscan *entry); +int syslinux_memscan_new(int (*func)(scan_memory_callback_t cb, void *data)); int syslinux_scan_memory(scan_memory_callback_t callback, void *data); #endif /* _SYSLINUX_MEMSCAN_H */ diff --git a/com32/include/syslinux/movebits.h b/com32/include/syslinux/movebits.h index 8bcdf3ed..4a4ce9ef 100644 --- a/com32/include/syslinux/movebits.h +++ b/com32/include/syslinux/movebits.h @@ -3,6 +3,7 @@ #include <inttypes.h> #include <stdio.h> +#include <stdbool.h> typedef uint32_t addr_t; @@ -34,6 +35,7 @@ enum syslinux_memmap_types { SMT_RESERVED, /* Unusable memory */ SMT_ALLOC, /* Memory allocated by user */ SMT_ZERO, /* Memory that should be zeroed */ + SMT_TERMINAL, /* Memory to be used as a last resort */ }; struct syslinux_memmap { @@ -42,6 +44,11 @@ struct syslinux_memmap { struct syslinux_memmap *next; }; +static inline bool valid_terminal_type(enum syslinux_memmap_types type) +{ + return (type == SMT_FREE) || (type == SMT_TERMINAL); +} + /* * moves is computed from "fraglist" and "memmap". Areas that are * to be zeroed should be marked as such in the memmap, not in the @@ -76,11 +83,20 @@ enum syslinux_memmap_types syslinux_memmap_type(struct syslinux_memmap *list, int syslinux_memmap_largest(struct syslinux_memmap *list, enum syslinux_memmap_types type, addr_t * start, addr_t * len); +int syslinux_memmap_highest(const struct syslinux_memmap *list, + enum syslinux_memmap_types types, + addr_t *start, addr_t len, + addr_t ceiling, addr_t align); void syslinux_free_memmap(struct syslinux_memmap *list); struct syslinux_memmap *syslinux_dup_memmap(struct syslinux_memmap *list); -int syslinux_memmap_find(struct syslinux_memmap *list, - enum syslinux_memmap_types type, - addr_t * start, addr_t * len, addr_t align); +int syslinux_memmap_find_type(struct syslinux_memmap *list, + enum syslinux_memmap_types type, + addr_t * start, addr_t * len, addr_t align); +int syslinux_memmap_find(struct syslinux_memmap *mmap, + addr_t *base, size_t size, + bool relocate, size_t align, + addr_t start_min, addr_t start_max, + addr_t end_min, addr_t end_max); /* Debugging functions */ #ifdef DEBUG diff --git a/com32/include/syslinux/pxe_api.h b/com32/include/syslinux/pxe_api.h index e9baa48c..3e994c09 100644 --- a/com32/include/syslinux/pxe_api.h +++ b/com32/include/syslinux/pxe_api.h @@ -589,7 +589,7 @@ int __weak pxe_call(int, void *); void __weak unload_pxe(uint16_t flags); uint32_t __weak dns_resolv(const char *); -uint32_t __weak SendCookies; +extern uint32_t __weak SendCookies; void __weak http_bake_cookies(void); #endif /* _SYSLINUX_PXE_API_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 a7cfe770..1624ae78 100644 --- a/com32/lib/Makefile +++ b/com32/lib/Makefile @@ -4,8 +4,7 @@ # Include configuration rules NOGPL := 1 -topdir = ../../ -MAKEDIR = $(topdir)/mk +VPATH = $(SRC) include $(MAKEDIR)/lib.mk ## OPTIONAL OBJECTS, AVAILABLE AS DYNAMIC LINKED MODULES @@ -17,24 +16,23 @@ LIBPNG_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 \ jpeg/rgb24.o jpeg/bgr24.o jpeg/yuv420p.o jpeg/grey.o \ jpeg/rgba32.o jpeg/bgra32.o +ifdef EFI_BUILD +I915VESA_OBJ = +else +I915VESA_OBJ = sys/vesa/i915resolution.o +endif + LIBVESA_OBJS = \ sys/vesacon_write.o sys/vesaserial_write.o \ sys/vesa/initvesa.o sys/vesa/drawtxt.o sys/vesa/background.o \ sys/vesa/alphatbl.o sys/vesa/screencpy.o sys/vesa/fmtpixel.o \ - sys/vesa/i915resolution.o + $(I915VESA_OBJ) LIBMISC_OBJS = \ sys/libansi.o sys/gpxe.o @@ -51,134 +49,9 @@ 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/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 \ - strerror.o errlist.o \ - strnlen.o \ - strncat.o strndup.o \ - stpncpy.o \ - strntoimax.o strsep.o strspn.o strstr.o \ - strtoimax.o strtok.o strtol.o strtoll.o strtoull.o \ - strtoumax.o vprintf.o vsprintf.o \ - asprintf.o vasprintf.o \ - vsscanf.o \ - skipspace.o \ - chrreplace.o \ - bufprintf.o \ - inet.o dhcppack.o dhcpunpack.o \ - strreplace.o \ - lstrdup.o \ - \ - 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 lmalloc.o strtoul.o \ - sys/err_read.o sys/err_write.o sys/null_read.o strntoumax.o \ - sys/stdcon_write.o \ - syslinux/memscan.o strrchr.o strcat.o \ - libgcc/__ashldi3.o libgcc/__udivdi3.o \ - libgcc/__negdi2.o libgcc/__ashrdi3.o libgcc/__lshrdi3.o \ - libgcc/__muldi3.o libgcc/__udivmoddi4.o libgcc/__umoddi3.o \ - libgcc/__divdi3.o libgcc/__moddi3.o \ - $(LIBENTRY_OBJS) \ - $(LIBMODULE_OBJS) - MINLIBOBJS = \ syslinux/ipappend.o \ syslinux/dsinfo.o \ @@ -189,7 +62,6 @@ MINLIBOBJS = \ $(LIBZLIB_OBJS) # $(LIBVESA_OBJS) - DYNLIBOBJS = \ $(LIBZLIB_OBJS) \ $(LIBPNG_OBJS) \ @@ -202,8 +74,7 @@ DYNLIBOBJS = \ $(DYNENTRY_OBJS) -LIBOBJS = \ - $(DYNLIBOBJS) +LIBOBJS = $(DYNLIBOBJS) BINDIR = /usr/bin LIBDIR = /usr/lib @@ -212,7 +83,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.elf : $(LIBOBJS) rm -f $@ @@ -239,11 +114,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/elf32.ld b/com32/lib/i386/elf.ld index 16d10a38..e0705cf9 100644 --- a/com32/lib/elf32.ld +++ b/com32/lib/i386/elf.ld @@ -84,7 +84,7 @@ SECTIONS KEEP (*(.ctors_modmain)) KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) - __ctors_end = .; + __ctors_end = .; } .dtors : @@ -95,7 +95,7 @@ SECTIONS KEEP (*(.dtors_modexit)) KEEP (*(.fini_array)) KEEP (*(SORT(.fini_array.*))) - __dtors_end = .; + __dtors_end = .; } .jcr : { KEEP (*(.jcr)) } 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/ansi.h b/com32/lib/sys/ansi.h index 7ccafc8b..39a6f410 100644 --- a/com32/lib/sys/ansi.h +++ b/com32/lib/sys/ansi.h @@ -7,6 +7,7 @@ #include <inttypes.h> #include <stdbool.h> +#include "vesa/video.h" #define ANSI_MAX_PARMS 16 @@ -29,7 +30,7 @@ struct term_state { bool pvt; /* Private code? */ struct curxy xy; struct curxy saved_xy; - uint8_t cindex; /* SOH color index */ + attr_t cindex; /* SOH color index */ uint8_t fg; uint8_t bg; uint8_t intensity; diff --git a/com32/lib/sys/ansicon_write.c b/com32/lib/sys/ansicon_write.c index e5483fbc..6e70c58c 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->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,41 @@ 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; + + cols = ti.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 +198,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 8547036b..05a27e85 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); @@ -59,40 +59,29 @@ void print_elf_symbols(struct elf_module *module) { FILE *findpath(char *name) { + struct path_entry *entry; char path[FILENAME_MAX]; FILE *f; - char *p, *n; - int i; f = fopen(name, "rb"); /* for full path */ if (f) return f; - p = PATH; -again: - i = 0; - while (*p && *p != ':' && i < FILENAME_MAX - 1) { - path[i++] = *p++; - } - - if (*p == ':') - p++; + list_for_each_entry(entry, &PATH, list) { + bool slash = false; - /* Ensure we have a '/' separator */ - if (path[i] != '/' && i < FILENAME_MAX - 1) - path[i++] = '/'; + /* Ensure we have a '/' separator */ + if (entry->str[strlen(entry->str) - 1] != '/') + slash = true; - n = name; - while (*n && i < FILENAME_MAX - 1) - path[i++] = *n++; - path[i] = '\0'; + snprintf(path, sizeof(path), "%s%s%s", + entry->str, slash ? "/" : "", name); - f = fopen(path, "rb"); - if (f) - return f; - - if (p >= PATH && p < PATH + strlen(PATH)) - goto again; + dprintf("findpath: trying \"%s\"\n", path); + f = fopen(path, "rb"); + if (f) + return f; + } return NULL; } @@ -106,7 +95,7 @@ int image_load(struct elf_module *module) module->u.l._file = findpath(module->name); if (module->u.l._file == NULL) { - DBG_PRINT("Could not open object file '%s'\n", module->name); + dprintf("Could not open object file '%s'\n", module->name); goto error; } @@ -163,7 +152,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; @@ -223,37 +212,44 @@ 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 || elf_hdr->e_ident[EI_MAG2] != ELFMAG2 || elf_hdr->e_ident[EI_MAG3] != ELFMAG3) { - DBG_PRINT("The file is not an ELF object\n"); + dprintf("The file is not an ELF object\n"); return -1; } - if (elf_hdr->e_ident[EI_CLASS] != MODULE_ELF_CLASS) { - DBG_PRINT("Invalid ELF class code\n"); + if (elf_hdr->e_ident[EI_CLASS] != ELFCLASS32 && + elf_hdr->e_ident[EI_CLASS] != ELFCLASS64) { + dprintf("Invalid ELF class code\n"); return -1; } if (elf_hdr->e_ident[EI_DATA] != MODULE_ELF_DATA) { - DBG_PRINT("Invalid ELF data encoding\n"); + dprintf("Invalid ELF data encoding\n"); return -1; } if (elf_hdr->e_ident[EI_VERSION] != MODULE_ELF_VERSION || elf_hdr->e_version != MODULE_ELF_VERSION) { - DBG_PRINT("Invalid ELF file version\n"); + dprintf("Invalid ELF file version\n"); return -1; } - if (elf_hdr->e_machine != MODULE_ELF_MACHINE) { - DBG_PRINT("Invalid ELF architecture\n"); + if (elf_hdr->e_machine != EM_386 && + elf_hdr->e_machine != EM_X86_64) { + dprintf("Invalid ELF architecture\n"); return -1; } @@ -261,6 +257,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; @@ -317,7 +314,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; @@ -364,7 +361,7 @@ int check_symbols(struct elf_module *module) // and ISOLINUX. See perform_relocations(). if (strong_count == 0 && weak_count == 0) { - DBG_PRINT("Symbol %s is undefined\n", crt_name); + dprintf("Symbol %s is undefined\n", crt_name); printf("Undef symbol FAIL: %s\n",crt_name); return -1; } @@ -375,7 +372,7 @@ int check_symbols(struct elf_module *module) { // It's not an error - at relocation, the most recent symbol // will be considered - DBG_PRINT("Info: Symbol %s is defined more than once\n", crt_name); + dprintf("Info: Symbol %s is defined more than once\n", crt_name); } } //printf("symbol %s laoded from %d\n",crt_name,crt_sym->st_value); @@ -397,7 +394,7 @@ int _module_unload(struct elf_module *module) { struct module_dep *crt_dep, *tmp; // Make sure nobody needs us if (!module_unloadable(module)) { - DBG_PRINT("Module is required by other modules.\n"); + dprintf("Module is required by other modules.\n"); return -1; } @@ -413,9 +410,11 @@ int _module_unload(struct elf_module *module) { if (module->module_addr != NULL) { elf_free(module->module_addr); - DBG_PRINT("%s MODULE %s UNLOADED\n", module->shallow ? "SHALLOW" : "", + dprintf("%s MODULE %s UNLOADED\n", module->shallow ? "SHALLOW" : "", module->name); } + + dprintf("Unloading module %s\n", module->name); // Release the module structure free(module); @@ -455,18 +454,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) { @@ -481,32 +480,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"); + dprintf("Invalid GNU Hash structure\n"); return NULL; } - Elf32_Word gnu_shift = *cr_word++; + Elf_Word gnu_shift = *cr_word++; - Elf32_Addr *gnu_bitmask = (Elf32_Addr*)cr_word; + Elf_Addr *gnu_bitmask = (Elf_Addr*)cr_word; cr_word += MODULE_ELF_CLASS_SIZE / 32 * bitmask_nwords; - Elf32_Word *gnu_buckets = cr_word; + Elf_Word *gnu_buckets = cr_word; cr_word += nbucket; - Elf32_Word *gnu_chain_zero = cr_word - symbias; + Elf_Word *gnu_chain_zero = cr_word - symbias; // Computations - Elf32_Word bitmask_word = gnu_bitmask[(h / MODULE_ELF_CLASS_SIZE) & + Elf_Bword bitmask_word = gnu_bitmask[(h / MODULE_ELF_CLASS_SIZE) & (bitmask_nwords - 1)]; unsigned int hashbit1 = h & (MODULE_ELF_CLASS_SIZE - 1); @@ -514,18 +513,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; @@ -538,11 +537,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++) { @@ -556,8 +555,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); @@ -579,10 +578,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 6a540273..e09a5402 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); @@ -29,12 +29,12 @@ static int check_header(Elf32_Ehdr *elf_hdr) { return res; if (elf_hdr->e_type != MODULE_ELF_TYPE) { - DBG_PRINT("The ELF file must be a shared object\n"); + dprintf("The ELF file must be a shared object\n"); return -1; } if (elf_hdr->e_phoff == 0x00000000) { - DBG_PRINT("PHT missing\n"); + dprintf("PHT missing\n"); return -1; } @@ -47,170 +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); - if (!pht) - return -1; - - image_read(pht, elf_hdr->e_phnum * elf_hdr->e_phentsize, module); - - // Compute the memory needings of the module - for (i=0; i < elf_hdr->e_phnum; i++) { - cr_pht = (Elf32_Phdr*)(pht + i * elf_hdr->e_phentsize); - - switch (cr_pht->p_type) { - case PT_LOAD: - if (i == 0) { - min_addr = cr_pht->p_vaddr; - } else { - min_addr = MIN(min_addr, cr_pht->p_vaddr); - } - - max_addr = MAX(max_addr, cr_pht->p_vaddr + cr_pht->p_memsz); - max_align = MAX(max_align, cr_pht->p_align); - break; - case PT_DYNAMIC: - dyn_addr = cr_pht->p_vaddr; - break; - default: - // Unsupported - ignore - break; - } - } - - if (max_addr - min_addr == 0) { - // No loadable segments - DBG_PRINT("No loadable segments found\n"); - goto out; - } - - if (dyn_addr == 0) { - DBG_PRINT("No dynamic information segment found\n"); - goto out; - } - - // The minimum address that should be allocated - min_alloc = min_addr - (min_addr % max_align); - - // The maximum address that should be allocated - max_alloc = max_addr - (max_addr % max_align); - if (max_addr % max_align > 0) - max_alloc += max_align; - - - if (elf_malloc(&module->module_addr, - max_align, - max_alloc-min_alloc) != 0) { - - DBG_PRINT("Could not allocate segments\n"); - goto out; - } - - module->base_addr = (Elf32_Addr)(module->module_addr) - min_alloc; - module->module_size = max_alloc - min_alloc; - - // Zero-initialize the memory - memset(module->module_addr, 0, module->module_size); - - for (i = 0; i < elf_hdr->e_phnum; i++) { - cr_pht = (Elf32_Phdr*)(pht + i * elf_hdr->e_phentsize); - - if (cr_pht->p_type == PT_LOAD) { - // Copy the segment at its destination - if (cr_pht->p_offset < module->u.l._cr_offset) { - // The segment contains data before the current offset - // It can be discarded without worry - it would contain only - // headers - Elf32_Off aux_off = module->u.l._cr_offset - cr_pht->p_offset; - - if (image_read((char *)module_get_absolute(cr_pht->p_vaddr, module) + aux_off, - cr_pht->p_filesz - aux_off, module) < 0) { - res = -1; - goto out; - } - } else { - if (image_seek(cr_pht->p_offset, module) < 0) { - res = -1; - goto out; - } - - if (image_read(module_get_absolute(cr_pht->p_vaddr, module), - cr_pht->p_filesz, module) < 0) { - res = -1; - goto out; - } - } - - /* - DBG_PRINT("Loadable segment of size 0x%08x copied from vaddr 0x%08x at 0x%08x\n", - cr_pht->p_filesz, - cr_pht->p_vaddr, - (Elf32_Addr)module_get_absolute(cr_pht->p_vaddr, module)); - */ - } - } - - // Get to the SHT - image_seek(elf_hdr->e_shoff, module); - - // Load the SHT - sht = malloc(elf_hdr->e_shnum * elf_hdr->e_shentsize); - if (!sht) { - res = -1; - goto out; - } - - image_read(sht, elf_hdr->e_shnum * elf_hdr->e_shentsize, module); - - // Setup the symtable size - for (i = 0; i < elf_hdr->e_shnum; i++) { - cr_sht = (Elf32_Shdr*)(sht + i * elf_hdr->e_shentsize); - - if (cr_sht->sh_type == SHT_DYNSYM) { - module->symtable_size = cr_sht->sh_size; - break; - } - } - - free(sht); - - // Setup dynamic segment location - module->dyn_table = module_get_absolute(dyn_addr, module); - - /* - DBG_PRINT("Base address: 0x%08x, aligned at 0x%08x\n", module->base_addr, - max_align); - DBG_PRINT("Module size: 0x%08x\n", module->module_size); - */ - -out: - // Free up allocated memory - if (pht != NULL) - free(pht); - - return res; -} +extern int load_segments(struct elf_module *module, Elf_Ehdr *elf_hdr); static int prepare_dynlinking(struct elf_module *module) { - Elf32_Dyn *dyn_entry = module->dyn_table; + Elf_Dyn *dyn_entry = module->dyn_table; while (dyn_entry->d_tag != DT_NULL) { switch (dyn_entry->d_tag) { @@ -230,11 +70,11 @@ 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 = @@ -267,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; @@ -497,14 +181,14 @@ 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; // Do not allow duplicate modules if (module_find(module->name) != NULL) { - DBG_PRINT("Module %s is already loaded.\n", module->name); + dprintf("Module %s is already loaded.\n", module->name); return EEXIST; } @@ -512,13 +196,14 @@ int module_load(struct elf_module *module) { res = image_load(module); if (res < 0) { + dprintf("Image load failed for %s\n", module->name); return res; } // 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); @@ -597,7 +282,7 @@ int module_load(struct elf_module *module) { image_unload(module); /* - DBG_PRINT("MODULE %s LOADED SUCCESSFULLY (main@%p, init@%p, exit@%p)\n", + dprintf("MODULE %s LOADED SUCCESSFULLY (main@%p, init@%p, exit@%p)\n", module->name, (module->main_func == NULL) ? NULL : *(module->main_func), (module->init_func == NULL) ? NULL : *(module->init_func), 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/exec.c b/com32/lib/sys/module/exec.c index 18c8306d..84b96e01 100644 --- a/com32/lib/sys/module/exec.c +++ b/com32/lib/sys/module/exec.c @@ -169,6 +169,7 @@ int spawn_load(const char *name, int argc, char **argv) if (get_module_type(module) == EXEC_MODULE) { if (!argc || !argv || strcmp(argv[0], name)) { + dprintf("invalid args for %s\n", name); res = -1; goto out; } @@ -182,8 +183,10 @@ int spawn_load(const char *name, int argc, char **argv) } res = module_load(module); - if (res != 0) + if (res != 0) { + dprintf("failed to load module %s\n", module->name); goto out; + } type = get_module_type(module); 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..d30f4ce2 --- /dev/null +++ b/com32/lib/sys/module/i386/elf_module.c @@ -0,0 +1,349 @@ +/* + * elf_module.c + * + * Created on: Aug 11, 2008 + * Author: Stefan Bucur <stefanb@zytor.com> + */ + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <elf.h> +#include <dprintf.h> +#include <core.h> + +#include <linux/list.h> +#include <sys/module.h> +#include <sys/exec.h> + +#include "elfutils.h" +#include "../common.h" + +/* + * + * The implementation assumes that the loadable segments are present + * in the PHT sorted by their offsets, so that only forward seeks would + * be necessary. + */ +int load_segments(struct elf_module *module, Elf_Ehdr *elf_hdr) { + int i; + int res = 0; + char *pht = NULL; + char *sht = NULL; + Elf32_Phdr *cr_pht; + Elf32_Shdr *cr_sht; + + Elf32_Addr min_addr = 0x00000000; // Min. ELF vaddr + Elf32_Addr max_addr = 0x00000000; // Max. ELF vaddr + Elf32_Word max_align = sizeof(void*); // Min. align of posix_memalign() + Elf32_Addr min_alloc, max_alloc; // Min. and max. aligned allocables + + Elf32_Addr dyn_addr = 0x00000000; + + // Get to the PHT + image_seek(elf_hdr->e_phoff, module); + + // Load the PHT + pht = malloc(elf_hdr->e_phnum * elf_hdr->e_phentsize); + if (!pht) + return -1; + + image_read(pht, elf_hdr->e_phnum * elf_hdr->e_phentsize, module); + + // Compute the memory needings of the module + for (i=0; i < elf_hdr->e_phnum; i++) { + cr_pht = (Elf32_Phdr*)(pht + i * elf_hdr->e_phentsize); + + switch (cr_pht->p_type) { + case PT_LOAD: + if (i == 0) { + min_addr = cr_pht->p_vaddr; + } else { + min_addr = MIN(min_addr, cr_pht->p_vaddr); + } + + max_addr = MAX(max_addr, cr_pht->p_vaddr + cr_pht->p_memsz); + max_align = MAX(max_align, cr_pht->p_align); + break; + case PT_DYNAMIC: + dyn_addr = cr_pht->p_vaddr; + break; + default: + // Unsupported - ignore + break; + } + } + + if (max_addr - min_addr == 0) { + // No loadable segments + DBG_PRINT("No loadable segments found\n"); + goto out; + } + + if (dyn_addr == 0) { + DBG_PRINT("No dynamic information segment found\n"); + goto out; + } + + // The minimum address that should be allocated + min_alloc = min_addr - (min_addr % max_align); + + // The maximum address that should be allocated + max_alloc = max_addr - (max_addr % max_align); + if (max_addr % max_align > 0) + max_alloc += max_align; + + + if (elf_malloc(&module->module_addr, + max_align, + max_alloc-min_alloc) != 0) { + + DBG_PRINT("Could not allocate segments\n"); + goto out; + } + + module->base_addr = (Elf32_Addr)(module->module_addr) - min_alloc; + module->module_size = max_alloc - min_alloc; + + // Zero-initialize the memory + memset(module->module_addr, 0, module->module_size); + + for (i = 0; i < elf_hdr->e_phnum; i++) { + cr_pht = (Elf32_Phdr*)(pht + i * elf_hdr->e_phentsize); + + if (cr_pht->p_type == PT_LOAD) { + // Copy the segment at its destination + if (cr_pht->p_offset < module->u.l._cr_offset) { + // The segment contains data before the current offset + // It can be discarded without worry - it would contain only + // headers + Elf32_Off aux_off = module->u.l._cr_offset - cr_pht->p_offset; + + if (image_read((char *)module_get_absolute(cr_pht->p_vaddr, module) + aux_off, + cr_pht->p_filesz - aux_off, module) < 0) { + res = -1; + goto out; + } + } else { + if (image_seek(cr_pht->p_offset, module) < 0) { + res = -1; + goto out; + } + + if (image_read(module_get_absolute(cr_pht->p_vaddr, module), + cr_pht->p_filesz, module) < 0) { + res = -1; + goto out; + } + } + + /* + DBG_PRINT("Loadable segment of size 0x%08x copied from vaddr 0x%08x at 0x%08x\n", + cr_pht->p_filesz, + cr_pht->p_vaddr, + (Elf32_Addr)module_get_absolute(cr_pht->p_vaddr, module)); + */ + } + } + + // Get to the SHT + image_seek(elf_hdr->e_shoff, module); + + // Load the SHT + sht = malloc(elf_hdr->e_shnum * elf_hdr->e_shentsize); + if (!sht) { + res = -1; + goto out; + } + + image_read(sht, elf_hdr->e_shnum * elf_hdr->e_shentsize, module); + + // Setup the symtable size + for (i = 0; i < elf_hdr->e_shnum; i++) { + cr_sht = (Elf32_Shdr*)(sht + i * elf_hdr->e_shentsize); + + if (cr_sht->sh_type == SHT_DYNSYM) { + module->symtable_size = cr_sht->sh_size; + break; + } + } + + free(sht); + + // Setup dynamic segment location + module->dyn_table = module_get_absolute(dyn_addr, module); + + /* + DBG_PRINT("Base address: 0x%08x, aligned at 0x%08x\n", module->base_addr, + max_align); + DBG_PRINT("Module size: 0x%08x\n", module->module_size); + */ + +out: + // Free up allocated memory + if (pht != NULL) + free(pht); + + return res; +} + +int perform_relocation(struct elf_module *module, Elf_Rel *rel) { + Elf32_Word *dest = module_get_absolute(rel->r_offset, module); + + // The symbol reference index + Elf32_Word sym = ELF32_R_SYM(rel->r_info); + unsigned char type = ELF32_R_TYPE(rel->r_info); + + // The symbol definition (if applicable) + Elf32_Sym *sym_def = NULL; + struct elf_module *sym_module = NULL; + Elf32_Addr sym_addr = 0x0; + + if (sym > 0) { + // Find out details about the symbol + + // The symbol reference + Elf32_Sym *sym_ref = symbol_get_entry(module, sym); + + // The symbol definition + sym_def = + global_find_symbol(module->str_table + sym_ref->st_name, + &sym_module); + + if (sym_def == NULL) { + DBG_PRINT("Cannot perform relocation for symbol %s\n", + module->str_table + sym_ref->st_name); + + if (ELF32_ST_BIND(sym_ref->st_info) != STB_WEAK) + return -1; + + // This must be a derivative-specific + // function. We're OK as long as we never + // execute the function. + sym_def = global_find_symbol("undefined_symbol", &sym_module); + } + + // Compute the absolute symbol virtual address + sym_addr = (Elf32_Addr)module_get_absolute(sym_def->st_value, sym_module); + + if (sym_module != module) { + // Create a dependency + enforce_dependency(sym_module, module); + } + } + + switch (type) { + case R_386_NONE: + // Do nothing + break; + case R_386_32: + *dest += sym_addr; + break; + case R_386_PC32: + *dest += sym_addr - (Elf32_Addr)dest; + break; + case R_386_COPY: + if (sym_addr > 0) { + memcpy((void*)dest, (void*)sym_addr, sym_def->st_size); + } + break; + case R_386_GLOB_DAT: + case R_386_JMP_SLOT: + // Maybe TODO: Keep track of the GOT entries allocations + *dest = sym_addr; + break; + case R_386_RELATIVE: + *dest += module->base_addr; + break; + default: + DBG_PRINT("Relocation type %d not supported\n", type); + return -1; + } + + return 0; +} + +int resolve_symbols(struct elf_module *module) { + Elf32_Dyn *dyn_entry = module->dyn_table; + unsigned int i; + int res; + + Elf32_Word plt_rel_size = 0; + char *plt_rel = NULL; + + char *rel = NULL; + Elf32_Word rel_size = 0; + Elf32_Word rel_entry = 0; + + // The current relocation + Elf32_Rel *crt_rel; + + while (dyn_entry->d_tag != DT_NULL) { + switch(dyn_entry->d_tag) { + + // PLT relocation information + case DT_PLTRELSZ: + plt_rel_size = dyn_entry->d_un.d_val; + break; + case DT_PLTREL: + if (dyn_entry->d_un.d_val != DT_REL) { + DBG_PRINT("Unsupported PLT relocation\n"); + return -1; + } + case DT_JMPREL: + plt_rel = module_get_absolute(dyn_entry->d_un.d_ptr, module); + break; + + // Standard relocation information + case DT_REL: + rel = module_get_absolute(dyn_entry->d_un.d_ptr, module); + break; + case DT_RELSZ: + rel_size = dyn_entry->d_un.d_val; + break; + case DT_RELENT: + rel_entry = dyn_entry->d_un.d_val; + break; + + // Module initialization and termination + case DT_INIT: + // TODO Implement initialization functions + break; + case DT_FINI: + // TODO Implement finalization functions + break; + } + + dyn_entry++; + } + + if (rel_size > 0) { + // Process standard relocations + for (i = 0; i < rel_size/rel_entry; i++) { + crt_rel = (Elf32_Rel*)(rel + i*rel_entry); + + res = perform_relocation(module, crt_rel); + + if (res < 0) + return res; + } + + } + + if (plt_rel_size > 0) { + // TODO: Permit this lazily + // Process PLT relocations + for (i = 0; i < plt_rel_size/sizeof(Elf32_Rel); i++) { + crt_rel = (Elf32_Rel*)(plt_rel + i*sizeof(Elf32_Rel)); + + res = perform_relocation(module, crt_rel); + + if (res < 0) + return res; + } + } + + return 0; +} + diff --git a/com32/lib/sys/module/x86_64/elf_module.c b/com32/lib/sys/module/x86_64/elf_module.c new file mode 100644 index 00000000..dd24bd12 --- /dev/null +++ b/com32/lib/sys/module/x86_64/elf_module.c @@ -0,0 +1,380 @@ +/* + * elf_module.c + * + * Created on: Aug 11, 2008 + * Author: Stefan Bucur <stefanb@zytor.com> + */ + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <elf.h> +#include <dprintf.h> +#include <core.h> + +#include <linux/list.h> +#include <sys/module.h> +#include <sys/exec.h> + +#include "elfutils.h" +#include "../common.h" + +/* + * + * The implementation assumes that the loadable segments are present + * in the PHT sorted by their offsets, so that only forward seeks would + * be necessary. + */ +int load_segments(struct elf_module *module, Elf_Ehdr *elf_hdr) { + int i; + int res = 0; + char *pht = NULL; + char *sht = NULL; + Elf64_Phdr *cr_pht; + Elf64_Shdr *cr_sht; + + Elf64_Addr min_addr = 0x0000000000000000; // Min. ELF vaddr + Elf64_Addr max_addr = 0x0000000000000000; // Max. ELF vaddr + Elf64_Word max_align = sizeof(void*); // Min. align of posix_memalign() + Elf64_Addr min_alloc, max_alloc; // Min. and max. aligned allocables + + Elf64_Addr dyn_addr = 0x0000000000000000; + + // Get to the PHT + image_seek(elf_hdr->e_phoff, module); + + // Load the PHT + pht = malloc(elf_hdr->e_phnum * elf_hdr->e_phentsize); + if (!pht) + return -1; + + image_read(pht, elf_hdr->e_phnum * elf_hdr->e_phentsize, module); + + // Compute the memory needings of the module + for (i=0; i < elf_hdr->e_phnum; i++) { + cr_pht = (Elf64_Phdr*)(pht + i * elf_hdr->e_phentsize); + + switch (cr_pht->p_type) { + case PT_LOAD: + if (i == 0) { + min_addr = cr_pht->p_vaddr; + } else { + min_addr = MIN(min_addr, cr_pht->p_vaddr); + } + + max_addr = MAX(max_addr, cr_pht->p_vaddr + cr_pht->p_memsz); + max_align = MAX(max_align, cr_pht->p_align); + break; + case PT_DYNAMIC: + dyn_addr = cr_pht->p_vaddr; + break; + default: + // Unsupported - ignore + break; + } + } + + if (max_addr - min_addr == 0) { + // No loadable segments + DBG_PRINT("No loadable segments found\n"); + goto out; + } + + if (dyn_addr == 0) { + DBG_PRINT("No dynamic information segment found\n"); + goto out; + } + + // The minimum address that should be allocated + min_alloc = min_addr - (min_addr % max_align); + + // The maximum address that should be allocated + max_alloc = max_addr - (max_addr % max_align); + if (max_addr % max_align > 0) + max_alloc += max_align; + + + if (elf_malloc(&module->module_addr, + max_align, + max_alloc-min_alloc) != 0) { + + DBG_PRINT("Could not allocate segments\n"); + goto out; + } + + module->base_addr = (Elf64_Addr)(module->module_addr) - min_alloc; + module->module_size = max_alloc - min_alloc; + + // Zero-initialize the memory + memset(module->module_addr, 0, module->module_size); + + for (i = 0; i < elf_hdr->e_phnum; i++) { + cr_pht = (Elf64_Phdr*)(pht + i * elf_hdr->e_phentsize); + + if (cr_pht->p_type == PT_LOAD) { + // Copy the segment at its destination + if (cr_pht->p_offset < module->u.l._cr_offset) { + // The segment contains data before the current offset + // It can be discarded without worry - it would contain only + // headers + Elf64_Off aux_off = module->u.l._cr_offset - cr_pht->p_offset; + + if (image_read((char *)module_get_absolute(cr_pht->p_vaddr, module) + aux_off, + cr_pht->p_filesz - aux_off, module) < 0) { + res = -1; + goto out; + } + } else { + if (image_seek(cr_pht->p_offset, module) < 0) { + res = -1; + goto out; + } + + if (image_read(module_get_absolute(cr_pht->p_vaddr, module), + cr_pht->p_filesz, module) < 0) { + res = -1; + goto out; + } + } + + /* + DBG_PRINT("Loadable segment of size 0x%08x copied from vaddr 0x%08x at 0x%08x\n", + cr_pht->p_filesz, + cr_pht->p_vaddr, + (Elf64_Addr)module_get_absolute(cr_pht->p_vaddr, module)); + */ + } + } + + // Get to the SHT + image_seek(elf_hdr->e_shoff, module); + + // Load the SHT + sht = malloc(elf_hdr->e_shnum * elf_hdr->e_shentsize); + if (!sht) { + res = -1; + goto out; + } + + image_read(sht, elf_hdr->e_shnum * elf_hdr->e_shentsize, module); + + // Setup the symtable size + for (i = 0; i < elf_hdr->e_shnum; i++) { + cr_sht = (Elf64_Shdr*)(sht + i * elf_hdr->e_shentsize); + + if (cr_sht->sh_type == SHT_DYNSYM) { + module->symtable_size = cr_sht->sh_size; + break; + } + } + + free(sht); + + // Setup dynamic segment location + module->dyn_table = module_get_absolute(dyn_addr, module); + + /* + DBG_PRINT("Base address: 0x%08x, aligned at 0x%08x\n", module->base_addr, + max_align); + DBG_PRINT("Module size: 0x%08x\n", module->module_size); + */ + +out: + // Free up allocated memory + if (pht != NULL) + free(pht); + + return res; +} + +int perform_relocation(struct elf_module *module, Elf_Rel *rel) { + Elf64_Xword *dest = module_get_absolute(rel->r_offset, module); + + // The symbol reference index + Elf64_Word sym = ELF64_R_SYM(rel->r_info); + unsigned char type = ELF64_R_TYPE(rel->r_info); + + // The symbol definition (if applicable) + Elf64_Sym *sym_def = NULL; + struct elf_module *sym_module = NULL; + Elf64_Addr sym_addr = 0x0; + + if (sym > 0) { + // Find out details about the symbol + + // The symbol reference + Elf64_Sym *sym_ref = symbol_get_entry(module, sym); + + // The symbol definition + sym_def = + global_find_symbol(module->str_table + sym_ref->st_name, + &sym_module); + + if (sym_def == NULL) { + DBG_PRINT("Cannot perform relocation for symbol %s\n", + module->str_table + sym_ref->st_name); + + if (ELF64_ST_BIND(sym_ref->st_info) != STB_WEAK) + return -1; + + // This must be a derivative-specific + // function. We're OK as long as we never + // execute the function. + sym_def = global_find_symbol("undefined_symbol", &sym_module); + } + + // Compute the absolute symbol virtual address + sym_addr = (Elf64_Addr)module_get_absolute(sym_def->st_value, sym_module); + + if (sym_module != module) { + // Create a dependency + enforce_dependency(sym_module, module); + } + } + + switch (type) { + case R_X86_64_NONE: + // Do nothing + break; + case R_X86_64_64: + *dest += sym_addr; + break; + case R_X86_64_PC32: + *dest += sym_addr - (Elf32_Addr)dest; + break; + case R_X86_64_COPY: + if (sym_addr > 0) { + memcpy((void*)dest, (void*)sym_addr, sym_def->st_size); + } + break; + case R_X86_64_GLOB_DAT: + case R_X86_64_JUMP_SLOT: + //Maybe TODO: Keep track of the GOT entries allocations + *dest = sym_addr; + break; + case R_X86_64_RELATIVE: + *dest += module->base_addr; + break; + default: + DBG_PRINT("Relocation type %d not supported\n", type); + return -1; + } + + return 0; +} + +int resolve_symbols(struct elf_module *module) { + Elf64_Dyn *dyn_entry = module->dyn_table; + unsigned int i; + int res; + + Elf64_Word plt_rel_size = 0; + void *plt_rel = NULL; + + void *rel = NULL; + Elf64_Word rel_size = 0; + Elf64_Word rel_entry = 0; + Elf64_Xword rela_size = 0; + Elf64_Xword rela_entry = 0; + Elf64_Xword sym_ent = 0; + + // The current relocation + Elf64_Rel *crt_rel; + + while (dyn_entry->d_tag != DT_NULL) { + switch(dyn_entry->d_tag) { + + // PLT relocation information + case DT_PLTRELSZ: + plt_rel_size = dyn_entry->d_un.d_val; + break; + case DT_PLTREL: + if (dyn_entry->d_un.d_val != DT_REL && dyn_entry->d_un.d_val != DT_RELA) { + DBG_PRINT("Unsupported PLT relocation\n"); + return -1; + } + //break; + case DT_JMPREL: + plt_rel = module_get_absolute(dyn_entry->d_un.d_ptr, module); + break; + + // Standard relocation information + case DT_REL: + rel = module_get_absolute(dyn_entry->d_un.d_ptr, module); + break; + case DT_RELA: + rel = module_get_absolute(dyn_entry->d_un.d_ptr, module); + break; + case DT_RELSZ: + rel_size = dyn_entry->d_un.d_val; + break; + case DT_RELASZ: + rela_size = dyn_entry->d_un.d_val; + break; + case DT_RELENT: + rel_entry = dyn_entry->d_un.d_val; + break; + case DT_RELAENT: + rela_entry = dyn_entry->d_un.d_val; + break; + /* FIXME: We may need to rely upon SYMENT if DT_RELAENT is missing in the object file */ + case DT_SYMENT: + sym_ent = dyn_entry->d_un.d_val; + break; + + // Module initialization and termination + case DT_INIT: + // TODO Implement initialization functions + break; + case DT_FINI: + // TODO Implement finalization functions + break; + } + + dyn_entry++; + } + + if (rel_size > 0) { + // Process standard relocations + for (i = 0; i < rel_size/rel_entry; i++) { + crt_rel = (Elf64_Rel*)(rel + i*rel_entry); + + res = perform_relocation(module, crt_rel); + + if (res < 0) + return res; + } + + } + + if (rela_size > 0) { + // Process standard relocations + for (i = 0; i < rela_size/rela_entry; i++) { + crt_rel = (Elf64_Rel*)(rel + i*rela_entry); + + res = perform_relocation(module, crt_rel); + + if (res < 0) + return res; + } + } + if (plt_rel_size > 0) { + // TODO: Permit this lazily + // Process PLT relocations + /* some modules do not have DT_SYMENT, set it sym_ent in such cases */ + if (!rela_entry) rela_entry = sym_ent; + //for (i = 0; i < plt_rel_size/sizeof(Elf64_Rel); i++) { + for (i = 0; i < plt_rel_size/rela_entry; i++) { + //crt_rel = (Elf64_Rel*)(plt_rel + i*sizeof(Elf64_Rel)); + crt_rel = (Elf64_Rel*)(plt_rel + i*rela_entry); + + res = perform_relocation(module, crt_rel); + + if (res < 0) + return res; + } + } + + return 0; +} diff --git a/com32/lib/sys/vesa/initvesa.c b/com32/lib/sys/vesa/initvesa.c index 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..d78109bc 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; + const uint32_t *s; - if (__unlikely(win_pos != wi.win_pos)) - set_window_pos(win_pos); - - l = min(bytes, win_size - win_off); - memcpy(win_base + win_off, s, l); - - bytes -= l; - s += l; - dst += l; - } + s = (const uint32_t *)__vesacon_format_pixels(rowbuf, src, npixels); + firmware->vesa->screencpy(dst, s, bytes, &wi); } diff --git a/com32/lib/sys/vesa/vesa.h b/com32/lib/sys/vesa/vesa.h index 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/debug.c b/com32/lib/syslinux/debug.c new file mode 100644 index 00000000..d9ab863f --- /dev/null +++ b/com32/lib/syslinux/debug.c @@ -0,0 +1,95 @@ +#include <linux/list.h> +#include <string.h> +#include <stdbool.h> + +#ifdef DYNAMIC_DEBUG + +static LIST_HEAD(debug_funcs); + +struct debug_func_entry { + const char *name; + struct list_head list; +}; + +static struct debug_func_entry *lookup_entry(const char *func) +{ + struct debug_func_entry *e, *entry = NULL; + + list_for_each_entry(e, &debug_funcs, list) { + if (!strcmp(e->name, func)) { + entry = e; + break; + } + } + + return entry; +} + +bool __syslinux_debug_enabled(const char *func) +{ + struct debug_func_entry *entry; + + entry = lookup_entry(func); + if (entry) + return true; + + return false; +} + +static int __enable(const char *func) +{ + struct debug_func_entry *entry; + + entry = lookup_entry(func); + if (entry) + return 0; /* already enabled */ + + entry = malloc(sizeof(*entry)); + if (!entry) + return -1; + + entry->name = func; + list_add(&entry->list, &debug_funcs); + return 0; +} + +static int __disable(const char *func) +{ + struct debug_func_entry *entry; + + entry = lookup_entry(func); + if (!entry) + return 0; /* already disabled */ + + list_del(&entry->list); + free(entry); + return 0; +} + +/* + * Enable or disable debug code for function 'func'. + */ +int syslinux_debug(const char *func, bool enable) +{ + int rv; + + if (enable) + rv = __enable(func); + else + rv = __disable(func); + + return rv; +} + +#else + +int syslinux_debug(const char *func, bool enable) +{ + (void)func; + (void)enable; + + printf("Dynamic debug unavailable\n"); + return -1; +} + +#endif /* DYNAMIC_DEBUG */ diff --git a/com32/lib/syslinux/disk.c b/com32/lib/syslinux/disk.c index 093751ac..5a99bb42 100644 --- a/com32/lib/syslinux/disk.c +++ b/com32/lib/syslinux/disk.c @@ -33,6 +33,7 @@ * Deal with disks and partitions */ +#include <core.h> #include <dprintf.h> #include <stdio.h> #include <stdlib.h> @@ -158,6 +159,90 @@ out: } /** + * Fill inreg based on EBIOS addressing properties. + * + * @v diskinfo The disk drive to read from + * @v inreg Register data structure to be filled. + * @v lba The logical block address to begin reading at + * @v count The number of sectors to read + * @v op_code Code to write/read operation + * @ret lmalloc'd buf upon success, NULL upon failure + */ +static void *ebios_setup(const struct disk_info *const diskinfo, com32sys_t *inreg, + uint64_t lba, uint8_t count, uint8_t op_code) +{ + static struct disk_ebios_dapa *dapa = NULL; + void *buf; + + if (!dapa) { + dapa = lmalloc(sizeof *dapa); + if (!dapa) + return NULL; + } + + buf = lmalloc(count * diskinfo->bps); + if (!buf) + return NULL; + + dapa->len = sizeof(*dapa); + dapa->count = count; + dapa->off = OFFS(buf); + dapa->seg = SEG(buf); + dapa->lba = lba; + + inreg->eax.b[1] = op_code; + inreg->esi.w[0] = OFFS(dapa); + inreg->ds = SEG(dapa); + inreg->edx.b[0] = diskinfo->disk; + + return buf; +} + +/** + * Fill inreg based on CHS addressing properties. + * + * @v diskinfo The disk drive to read from + * @v inreg Register data structure to be filled. + * @v lba The logical block address to begin reading at + * @v count The number of sectors to read + * @v op_code Code to write/read operation + * @ret lmalloc'd buf upon success, NULL upon failure + */ +static void *chs_setup(const struct disk_info *const diskinfo, com32sys_t *inreg, + uint64_t lba, uint8_t count, uint8_t op_code) +{ + unsigned int c, h, s, t; + void *buf; + + buf = lmalloc(count * diskinfo->bps); + if (!buf) + return NULL; + + /* + * if we passed lba + count check and we get here, that means that + * lbacnt was calculated from chs geometry (or faked from 1/1/1), thus + * 32bits are perfectly enough and lbacnt corresponds to cylinder + * boundary + */ + s = lba % diskinfo->spt; + t = lba / diskinfo->spt; + h = t % diskinfo->head; + c = t / diskinfo->head; + + memset(inreg, 0, sizeof *inreg); + inreg->eax.b[0] = count; + inreg->eax.b[1] = op_code; + inreg->ecx.b[1] = c; + inreg->ecx.b[0] = ((c & 0x300) >> 2) | (s+1); + inreg->edx.b[1] = h; + inreg->edx.b[0] = diskinfo->disk; + inreg->ebx.w[0] = OFFS(buf); + inreg->es = SEG(buf); + + return buf; +} + +/** * Get disk block(s) and return a malloc'd buffer. * * @v diskinfo The disk drive to read from @@ -172,7 +257,6 @@ void *disk_read_sectors(const struct disk_info *const diskinfo, uint64_t lba, uint8_t count) { com32sys_t inreg; - struct disk_ebios_dapa *dapa; void *buf; void *data = NULL; uint32_t maxcnt; @@ -184,48 +268,14 @@ void *disk_read_sectors(const struct disk_info *const diskinfo, uint64_t lba, memset(&inreg, 0, sizeof inreg); - buf = lmalloc(count * diskinfo->bps); + if (diskinfo->ebios) + buf = ebios_setup(diskinfo, &inreg, lba, count, EBIOS_READ_CODE); + else + buf = chs_setup(diskinfo, &inreg, lba, count, CHS_READ_CODE); + if (!buf) return NULL; - dapa = lmalloc(sizeof(*dapa)); - if (!dapa) - goto out; - - if (diskinfo->ebios) { - dapa->len = sizeof(*dapa); - dapa->count = count; - dapa->off = OFFS(buf); - dapa->seg = SEG(buf); - dapa->lba = lba; - - inreg.esi.w[0] = OFFS(dapa); - inreg.ds = SEG(dapa); - inreg.edx.b[0] = diskinfo->disk; - inreg.eax.b[1] = 0x42; /* Extended read */ - } else { - unsigned int c, h, s, t; - /* - * if we passed lba + count check and we get here, that means that - * lbacnt was calculated from chs geometry (or faked from 1/1/1), thus - * 32bits are perfectly enough and lbacnt corresponds to cylinder - * boundary - */ - s = lba % diskinfo->spt; - t = lba / diskinfo->spt; - h = t % diskinfo->head; - c = t / diskinfo->head; - - inreg.eax.b[0] = count; - inreg.eax.b[1] = 0x02; /* Read */ - inreg.ecx.b[1] = c; - inreg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1); - inreg.edx.b[1] = h; - inreg.edx.b[0] = diskinfo->disk; - inreg.ebx.w[0] = OFFS(buf); - inreg.es = SEG(buf); - } - if (disk_int13_retry(&inreg, NULL)) goto out; @@ -233,7 +283,6 @@ void *disk_read_sectors(const struct disk_info *const diskinfo, uint64_t lba, if (data) memcpy(data, buf, count * diskinfo->bps); out: - lfree(dapa); lfree(buf); return data; } @@ -254,7 +303,6 @@ int disk_write_sectors(const struct disk_info *const diskinfo, uint64_t lba, const void *data, uint8_t count) { com32sys_t inreg; - struct disk_ebios_dapa *dapa; void *buf; uint32_t maxcnt; uint32_t size = 65536; @@ -264,57 +312,23 @@ int disk_write_sectors(const struct disk_info *const diskinfo, uint64_t lba, if (!count || count > maxcnt || lba + count > diskinfo->lbacnt) return -1; - buf = lmalloc(count * diskinfo->bps); + memset(&inreg, 0, sizeof inreg); + + if (diskinfo->ebios) + buf = ebios_setup(diskinfo, &inreg, lba, count, EBIOS_WRITE_CODE); + else + buf = chs_setup(diskinfo, &inreg, lba, count, CHS_WRITE_CODE); + if (!buf) return -1; memcpy(buf, data, count * diskinfo->bps); - memset(&inreg, 0, sizeof inreg); - - dapa = lmalloc(sizeof(*dapa)); - if (!dapa) - goto out; - - if (diskinfo->ebios) { - dapa->len = sizeof(*dapa); - dapa->count = count; - dapa->off = OFFS(buf); - dapa->seg = SEG(buf); - dapa->lba = lba; - - inreg.esi.w[0] = OFFS(dapa); - inreg.ds = SEG(dapa); - inreg.edx.b[0] = diskinfo->disk; - inreg.eax.b[1] = 0x43; /* Extended write */ - } else { - unsigned int c, h, s, t; - /* - * if we passed lba + count check and we get here, that means that - * lbacnt was calculated from chs geometry (or faked from 1/1/1), thus - * 32bits are perfectly enough and lbacnt corresponds to cylinder - * boundary - */ - s = lba % diskinfo->spt; - t = lba / diskinfo->spt; - h = t % diskinfo->head; - c = t / diskinfo->head; - - inreg.eax.b[0] = count; - inreg.eax.b[1] = 0x03; /* Write */ - inreg.ecx.b[1] = c; - inreg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1); - inreg.edx.b[1] = h; - inreg.edx.b[0] = diskinfo->disk; - inreg.ebx.w[0] = OFFS(buf); - inreg.es = SEG(buf); - } if (disk_int13_retry(&inreg, NULL)) goto out; rv = 0; /* ok */ out: - lfree(dapa); lfree(buf); return rv; } 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 471d8a50..06ae2a97 100644 --- a/com32/lib/syslinux/load_linux.c +++ b/com32/lib/syslinux/load_linux.c @@ -40,55 +40,14 @@ #include <minmax.h> #include <errno.h> #include <suffix_number.h> -#include <graphics.h> #include <dprintf.h> #include <syslinux/align.h> #include <syslinux/linux.h> #include <syslinux/bootrm.h> #include <syslinux/movebits.h> - -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> +#include <syslinux/video.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,14 +124,39 @@ 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) +static size_t calc_cmdline_offset(const struct syslinux_memmap *mmap, + const struct linux_header *hdr, + size_t cmdline_size, addr_t base, + addr_t start) +{ + size_t max_offset; + + if (hdr->version >= 0x0202 && (hdr->loadflags & LOAD_HIGH)) + max_offset = 0x10000; + else + max_offset = 0xfff0 - cmdline_size; + + if (!syslinux_memmap_highest(mmap, SMT_FREE, &start, + cmdline_size, 0xa0000, 16) || + !syslinux_memmap_highest(mmap, SMT_TERMINAL, &start, + cmdline_size, 0xa0000, 16)) { + + + return min(start - base, max_offset) & ~15; + } + + dprintf("Unable to find lowmem for cmdline\n"); + return (0x9ff0 - cmdline_size) & ~15; /* Legacy value: pure hope... */ +} + +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; - addr_t real_mode_base, prot_mode_base; + size_t real_mode_size, prot_mode_size, base; + addr_t real_mode_base, prot_mode_base, prot_mode_max; addr_t irf_size; size_t cmdline_size, cmdline_offset; struct setup_data *sdp; @@ -197,15 +164,17 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, struct syslinux_movelist *fraglist = NULL; struct syslinux_memmap *mmap = NULL; struct syslinux_memmap *amap = NULL; - bool ok; uint32_t memlimit = 0; uint16_t video_mode = 0; const char *arg; cmdline_size = strlen(cmdline) + 1; - if (kernel_size < 2 * 512) + errno = EINVAL; + if (kernel_size < 2 * 512) { + dprintf("Kernel size too small\n"); goto bail; + } /* Look for specific command-line arguments we care about */ if ((arg = find_argument(cmdline, "mem="))) @@ -236,8 +205,10 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, memcpy(&hdr, kernel_buf, sizeof hdr); whdr = (struct linux_header *)kernel_buf; - if (hdr.boot_flag != BOOT_MAGIC) + if (hdr.boot_flag != BOOT_MAGIC) { + dprintf("Invalid boot magic\n"); goto bail; + } if (hdr.header != LINUX_MAGIC) { hdr.version = 0x0100; /* Very old kernel */ @@ -249,7 +220,7 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, if (!hdr.setup_sects) hdr.setup_sects = 4; - if (hdr.version < 0x0203) + if (hdr.version < 0x0203 || !hdr.initrd_addr_max) hdr.initrd_addr_max = 0x37ffffff; if (!memlimit && memlimit - 1 > hdr.initrd_addr_max) @@ -266,16 +237,25 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, cmdline[cmdline_size - 1] = '\0'; } - if (hdr.version < 0x0202 || !(hdr.loadflags & 0x01)) - cmdline_offset = (0x9ff0 - cmdline_size) & ~15; - else - cmdline_offset = 0x10000; - real_mode_size = (hdr.setup_sects + 1) << 9; real_mode_base = (hdr.loadflags & LOAD_HIGH) ? 0x10000 : 0x90000; prot_mode_base = (hdr.loadflags & LOAD_HIGH) ? 0x100000 : 0x10000; + prot_mode_max = (hdr.loadflags & LOAD_HIGH) ? (addr_t)-1 : 0x8ffff; prot_mode_size = kernel_size - real_mode_size; + /* Get the memory map */ + mmap = syslinux_memory_map(); /* Memory map for shuffle_boot */ + amap = syslinux_dup_memmap(mmap); /* Keep track of available memory */ + if (!mmap || !amap) { + errno = ENOMEM; + goto bail; + } + + cmdline_offset = calc_cmdline_offset(mmap, &hdr, cmdline_size, + real_mode_base, + real_mode_base + real_mode_size); + dprintf("cmdline_offset at 0x%x\n", real_mode_base + cmdline_offset); + if (hdr.version < 0x020a) { /* * The 3* here is a total fudge factor... it's supposed to @@ -287,14 +267,18 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, hdr.init_size = 3 * prot_mode_size; } - if (!(hdr.loadflags & LOAD_HIGH) && prot_mode_size > 512 * 1024) - goto bail; /* Kernel cannot be loaded low */ + if (!(hdr.loadflags & LOAD_HIGH) && prot_mode_size > 512 * 1024) { + dprintf("Kernel cannot be loaded low\n"); + goto bail; + } /* Get the size of the initramfs, if there is one */ irf_size = initramfs_size(initramfs); - if (irf_size && hdr.version < 0x0200) - goto bail; /* initrd/initramfs not supported */ + if (irf_size && hdr.version < 0x0200) { + dprintf("Initrd specified but not supported by kernel\n"); + goto bail; + } if (hdr.version >= 0x0200) { whdr->type_of_loader = 0x30; /* SYSLINUX unknown module */ @@ -304,12 +288,6 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, } } - /* Get the memory map */ - mmap = syslinux_memory_map(); /* Memory map for shuffle_boot */ - amap = syslinux_dup_memmap(mmap); /* Keep track of available memory */ - if (!mmap || !amap) - goto bail; - dprintf("Initial memory map:\n"); syslinux_dump_memmap(mmap); @@ -318,99 +296,64 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, it's unavailable to the boot loader, which probably has already touched some of it), or just in the amap? */ if (memlimit) - if (syslinux_add_memmap(&amap, memlimit, -memlimit, SMT_RESERVED)) + if (syslinux_add_memmap(&amap, memlimit, -memlimit, SMT_RESERVED)) { + errno = ENOMEM; goto bail; + } /* Place the kernel in memory */ - /* First, find a suitable place for the protected-mode code */ - if (syslinux_memmap_type(amap, prot_mode_base, prot_mode_size) - != SMT_FREE) { - const struct syslinux_memmap *mp; - if (!hdr.relocatable_kernel) - goto bail; /* Can't relocate - no hope */ - - ok = false; - for (mp = amap; mp; mp = mp->next) { - addr_t start, end; - start = mp->start; - end = mp->next->start; - - if (mp->type != SMT_FREE) - continue; - - if (end <= prot_mode_base) - continue; /* Only relocate upwards */ - - if (start <= prot_mode_base) - start = prot_mode_base; - - start = ALIGN_UP(start, hdr.kernel_alignment); - if (start >= end) - continue; - - if (end - start >= hdr.init_size) { - whdr->code32_start += start - prot_mode_base; - prot_mode_base = start; - ok = true; - break; - } - } - - if (!ok) - goto bail; + /* + * First, find a suitable place for the protected-mode code. If + * the kernel image is not relocatable, just worry if it fits (it + * might not even be a Linux image, after all, and for !LOAD_HIGH + * we end up decompressing into a different location anyway), but + * if it is, make sure everything fits. + */ + base = prot_mode_base; + if (prot_mode_size && + syslinux_memmap_find(amap, &base, + hdr.relocatable_kernel ? + hdr.init_size : prot_mode_size, + hdr.relocatable_kernel, hdr.kernel_alignment, + prot_mode_base, prot_mode_max, + prot_mode_base, prot_mode_max)) { + dprintf("Could not find location for protected-mode code\n"); + goto bail; } - /* Real mode code */ - if (syslinux_memmap_type(amap, real_mode_base, - cmdline_offset + cmdline_size) != SMT_FREE) { - const struct syslinux_memmap *mp; - - ok = false; - for (mp = amap; mp; mp = mp->next) { - addr_t start, end; - start = mp->start; - end = mp->next->start; - - if (mp->type != SMT_FREE) - continue; - - if (start < real_mode_base) - start = real_mode_base; /* Lowest address we'll use */ - if (end > 640 * 1024) - end = 640 * 1024; - - start = ALIGN_UP(start, 16); - if (start > 0x90000 || start >= end) - continue; - - if (end - start >= cmdline_offset + cmdline_size) { - real_mode_base = start; - ok = true; - break; - } - } + whdr->code32_start += base - prot_mode_base; - if (!ok) - goto bail; + /* Real mode code */ + if (syslinux_memmap_find(amap, &real_mode_base, + cmdline_offset + cmdline_size, true, 16, + real_mode_base, 0x90000, 0, 640*1024)) { + dprintf("Could not find location for real-mode code\n"); + goto bail; } if (syslinux_add_movelist(&fraglist, real_mode_base, (addr_t) kernel_buf, real_mode_size)) goto bail; if (syslinux_add_memmap - (&amap, real_mode_base, cmdline_offset + cmdline_size, SMT_ALLOC)) + (&amap, real_mode_base, cmdline_offset + cmdline_size, SMT_ALLOC)) { + errno = ENOMEM; goto bail; + } /* Zero region between real mode code and cmdline */ if (syslinux_add_memmap(&mmap, real_mode_base + real_mode_size, - cmdline_offset - real_mode_size, SMT_ZERO)) + cmdline_offset - real_mode_size, SMT_ZERO)) { + errno = ENOMEM; goto bail; + } /* Command line */ if (syslinux_add_movelist(&fraglist, real_mode_base + cmdline_offset, - (addr_t) cmdline, cmdline_size)) + (addr_t) cmdline, cmdline_size)) { + errno = ENOMEM; goto bail; + } if (hdr.version >= 0x0202) { whdr->cmd_line_ptr = real_mode_base + cmdline_offset; } else { @@ -423,12 +366,19 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, } /* Protected-mode code */ - if (syslinux_add_movelist(&fraglist, prot_mode_base, - (addr_t) kernel_buf + real_mode_size, - prot_mode_size)) - goto bail; - if (syslinux_add_memmap(&amap, prot_mode_base, prot_mode_size, SMT_ALLOC)) - goto bail; + if (prot_mode_size) { + if (syslinux_add_movelist(&fraglist, prot_mode_base, + (addr_t) kernel_buf + real_mode_size, + prot_mode_size)) { + errno = ENOMEM; + goto bail; + } + if (syslinux_add_memmap(&amap, prot_mode_base, prot_mode_size, + SMT_ALLOC)) { + errno = ENOMEM; + goto bail; + } + } /* Figure out the size of the initramfs, and where to put it. We should put it at the highest possible address which is @@ -447,17 +397,23 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, best_addr = (adj_end - irf_size) & ~align_mask; } - if (!best_addr) - goto bail; /* Insufficient memory for initramfs */ + if (!best_addr) { + dprintf("Insufficient memory for initramfs\n"); + goto bail; + } whdr->ramdisk_image = best_addr; whdr->ramdisk_size = irf_size; - if (syslinux_add_memmap(&amap, best_addr, irf_size, SMT_ALLOC)) + if (syslinux_add_memmap(&amap, best_addr, irf_size, SMT_ALLOC)) { + errno = ENOMEM; goto bail; + } - if (map_initramfs(&fraglist, &mmap, initramfs, best_addr)) + if (map_initramfs(&fraglist, &mmap, initramfs, best_addr)) { + errno = ENOMEM; goto bail; + } } } @@ -493,14 +449,20 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, *prev_ptr = best_addr; prev_ptr = &sdp->hdr.next; - if (syslinux_add_memmap(&amap, best_addr, size, SMT_ALLOC)) + if (syslinux_add_memmap(&amap, best_addr, size, SMT_ALLOC)) { + errno = ENOMEM; goto bail; + } if (syslinux_add_movelist(&fraglist, best_addr, - (addr_t)&sdp->hdr, sizeof sdp->hdr)) + (addr_t)&sdp->hdr, sizeof sdp->hdr)) { + errno = ENOMEM; goto bail; + } if (syslinux_add_movelist(&fraglist, best_addr + sizeof sdp->hdr, - (addr_t)sdp->data, sdp->hdr.len)) + (addr_t)sdp->data, sdp->hdr.len)) { + errno = ENOMEM; goto bail; + } } } @@ -533,6 +495,7 @@ int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, } syslinux_shuffle_boot_rm(fraglist, mmap, 0, ®s); + dprintf("shuffle_boot_rm failed\n"); bail: syslinux_free_movelist(fraglist); @@ -540,3 +503,16 @@ 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) + return firmware->boot_linux(kernel_buf, kernel_size, initramfs, + setup_data, cmdline); + + return bios_boot_linux(kernel_buf, kernel_size, initramfs, + setup_data, cmdline); +} diff --git a/com32/lib/syslinux/memmap.c b/com32/lib/syslinux/memmap.c index 12baa33a..563e91b0 100644 --- a/com32/lib/syslinux/memmap.c +++ b/com32/lib/syslinux/memmap.c @@ -40,12 +40,11 @@ #include <syslinux/memscan.h> #include <syslinux/movebits.h> -static int syslinux_memory_map_callback(void *map, addr_t start, - addr_t len, bool valid) +static int syslinux_memory_map_callback(void *map, addr_t start, addr_t len, + enum syslinux_memmap_types type) { struct syslinux_memmap **mmap = map; - return syslinux_add_memmap(mmap, start, len, - valid ? SMT_FREE : SMT_RESERVED); + return syslinux_add_memmap(mmap, start, len, type); } struct syslinux_memmap *syslinux_memory_map(void) diff --git a/com32/lib/syslinux/memscan.c b/com32/lib/syslinux/memscan.c index fc676cbf..fdb72749 100644 --- a/com32/lib/syslinux/memscan.c +++ b/com32/lib/syslinux/memscan.c @@ -32,127 +32,44 @@ * Query the system for free memory */ -#include <assert.h> -#include <stdbool.h> -#include <stdlib.h> -#include <string.h> -#include <inttypes.h> -#include <com32.h> - #include <syslinux/memscan.h> -struct e820_entry { - uint64_t start; - uint64_t len; - uint32_t type; -}; +static LIST_HEAD(syslinux_memscan_head); -int syslinux_scan_memory(scan_memory_callback_t callback, void *data) +/* + * Add a memscan entry to the list. + */ +void syslinux_memscan_add(struct syslinux_memscan *entry) { - static com32sys_t ireg; - com32sys_t oreg; - struct e820_entry *e820buf; - uint64_t start, len, maxlen; - int memfound = 0; - int rv; - addr_t dosmem; - const addr_t bios_data = 0x510; /* Amount to reserve for BIOS data */ + list_add(&entry->next, &syslinux_memscan_head); +} - /* Use INT 12h to get DOS memory */ - __intcall(0x12, &__com32_zero_regs, &oreg); - dosmem = oreg.eax.w[0] << 10; - if (dosmem < 32 * 1024 || dosmem > 640 * 1024) { - /* INT 12h reports nonsense... now what? */ - uint16_t ebda_seg = *(uint16_t *) 0x40e; - if (ebda_seg >= 0x8000 && ebda_seg < 0xa000) - dosmem = ebda_seg << 4; - else - dosmem = 640 * 1024; /* Hope for the best... */ - } - rv = callback(data, bios_data, dosmem - bios_data, true); - if (rv) - return rv; +/* + * Build a new memscan entry and add it to the list. + */ +int syslinux_memscan_new(int func(scan_memory_callback_t, void *data)) +{ + struct syslinux_memscan *entry; - /* First try INT 15h AX=E820h */ - e820buf = lzalloc(sizeof *e820buf); - if (!e820buf) + entry = malloc(sizeof *entry); + if (!entry) return -1; - ireg.eax.l = 0xe820; - ireg.edx.l = 0x534d4150; - ireg.ebx.l = 0; - ireg.ecx.l = sizeof(*e820buf); - ireg.es = SEG(e820buf); - ireg.edi.w[0] = OFFS(e820buf); - - do { - __intcall(0x15, &ireg, &oreg); - - if ((oreg.eflags.l & EFLAGS_CF) || - (oreg.eax.l != 0x534d4150) || (oreg.ecx.l < 20)) - break; - - start = e820buf->start; - len = e820buf->len; - - if (start < 0x100000000ULL) { - /* Don't rely on E820 being valid for low memory. Doing so - could mean stuff like overwriting the PXE stack even when - using "keeppxe", etc. */ - if (start < 0x100000ULL) { - if (len > 0x100000ULL - start) - len -= 0x100000ULL - start; - else - len = 0; - start = 0x100000ULL; - } - - maxlen = 0x100000000ULL - start; - if (len > maxlen) - len = maxlen; - - if (len) { - rv = callback(data, (addr_t) start, (addr_t) len, - e820buf->type == 1); - if (rv) - return rv; - memfound = 1; - } - } - - ireg.ebx.l = oreg.ebx.l; - } while (oreg.ebx.l); - - lfree(e820buf); - - if (memfound) - return 0; - - /* Next try INT 15h AX=E801h */ - ireg.eax.w[0] = 0xe801; - __intcall(0x15, &ireg, &oreg); - - if (!(oreg.eflags.l & EFLAGS_CF) && oreg.ecx.w[0]) { - rv = callback(data, (addr_t) 1 << 20, oreg.ecx.w[0] << 10, true); - if (rv) - return rv; - - if (oreg.edx.w[0]) { - rv = callback(data, (addr_t) 16 << 20, oreg.edx.w[0] << 16, true); - if (rv) - return rv; - } + entry->func = func; + syslinux_memscan_add(entry); + return 0; +} - return 0; - } +int syslinux_scan_memory(scan_memory_callback_t callback, void *data) +{ + struct syslinux_memscan *entry; + int rv = 0; - /* Finally try INT 15h AH=88h */ - ireg.eax.w[0] = 0x8800; - if (!(oreg.eflags.l & EFLAGS_CF) && oreg.eax.w[0]) { - rv = callback(data, (addr_t) 1 << 20, oreg.ecx.w[0] << 10, true); + list_for_each_entry(entry, &syslinux_memscan_head, next) { + rv = entry->func(callback, data); if (rv) - return rv; + break; } - return 0; + return rv; } diff --git a/com32/lib/syslinux/movebits.c b/com32/lib/syslinux/movebits.c index 7a05f3c1..63554012 100644 --- a/com32/lib/syslinux/movebits.c +++ b/com32/lib/syslinux/movebits.c @@ -143,32 +143,31 @@ static void free_movelist(struct syslinux_movelist **parentptr) } /* - * Scan the freelist looking for a particular chunk of memory + * Scan the freelist looking for a particular chunk of memory. Returns + * the memmap chunk containing to the first byte of the region. */ static const struct syslinux_memmap *is_free_zone(const struct syslinux_memmap *list, addr_t start, addr_t len) { - dprintf("f: 0x%08x bytes at 0x%08x\n", len, start); - addr_t last, llast; + dprintf("f: 0x%08x bytes at 0x%08x\n", len, start); + last = start + len - 1; while (list->type != SMT_END) { - llast = list->next->start - 1; if (list->start <= start) { - if (llast >= last) { - /* Chunk has a single, well-defined type */ - if (list->type == SMT_FREE) { - dprintf("F: 0x%08x bytes at 0x%08x\n", - list->next->start, list->start); - return list; /* It's free */ - } - return NULL; /* Not free */ - } else if (llast >= start) { - return NULL; /* Crosses region boundary */ + const struct syslinux_memmap *ilist = list; + while (valid_terminal_type(list->type)) { + llast = list->next->start - 1; + if (llast >= last) + return ilist; + list = list->next; } + + if (list->start > start) + return NULL; /* Invalid type in region */ } list = list->next; } diff --git a/com32/lib/syslinux/serial.c b/com32/lib/syslinux/serial.c index aa5690fa..041e8505 100644 --- a/com32/lib/syslinux/serial.c +++ b/com32/lib/syslinux/serial.c @@ -32,24 +32,19 @@ */ #include <klibc/compiler.h> +#include <syslinux/firmware.h> #include <syslinux/config.h> #include <string.h> -#include <bios.h> -#include <core.h> struct syslinux_serial_console_info __syslinux_serial_console_info; void __syslinux_set_serial_console_info(void) { - uint16_t flowctl; + uint16_t iobase, divisor, flowctl; - __syslinux_serial_console_info.iobase = SerialPort; - __syslinux_serial_console_info.divisor = BaudDivisor; - - 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 1dcdb9d0..ce85a5c4 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/shuffle_pm.c b/com32/lib/syslinux/shuffle_pm.c index 5e3183b7..96c055c6 100644 --- a/com32/lib/syslinux/shuffle_pm.c +++ b/com32/lib/syslinux/shuffle_pm.c @@ -52,7 +52,7 @@ int syslinux_shuffle_boot_pm(struct syslinux_movelist *fraglist, regstub = 0x800; /* Locate anywhere above this point */ stublen = sizeof handoff_code; - rv = syslinux_memmap_find(tmap, SMT_FREE, ®stub, &stublen, 1); + rv = syslinux_memmap_find_type(tmap, SMT_FREE, ®stub, &stublen, 1); syslinux_free_memmap(tmap); if (rv) return -1; diff --git a/com32/lib/syslinux/shuffle_rm.c b/com32/lib/syslinux/shuffle_rm.c index a7d16d63..9935f4cd 100644 --- a/com32/lib/syslinux/shuffle_rm.c +++ b/com32/lib/syslinux/shuffle_rm.c @@ -105,7 +105,7 @@ int syslinux_shuffle_boot_rm(struct syslinux_movelist *fraglist, */ regstub = 0x800; stublen = sizeof handoff_code; - rv = syslinux_memmap_find(tmap, SMT_FREE, ®stub, &stublen, 16); + rv = syslinux_memmap_find_type(tmap, SMT_FREE, ®stub, &stublen, 16); if (rv || (regstub > 0x100000 - sizeof handoff_code)) { /* @@ -116,7 +116,7 @@ int syslinux_shuffle_boot_rm(struct syslinux_movelist *fraglist, */ regstub = 0x510; /* Try the 0x5xx segment... */ stublen = sizeof handoff_code; - rv = syslinux_memmap_find(tmap, SMT_FREE, ®stub, &stublen, 16); + rv = syslinux_memmap_find_type(tmap, SMT_FREE, ®stub, &stublen, 16); if (!rv && (regstub > 0x100000 - sizeof handoff_code)) rv = -1; /* No acceptable memory found */ diff --git a/com32/lib/syslinux/tests/Makefile b/com32/lib/syslinux/tests/Makefile new file mode 100644 index 00000000..18b40fc5 --- /dev/null +++ b/com32/lib/syslinux/tests/Makefile @@ -0,0 +1,22 @@ +CFLAGS = -I$(topdir)/tests/unittest/include + +tests = zonelist movebits memscan load_linux +.INTERMEDIATE: $(tests) + +all: banner $(tests) + for t in $(tests); \ + do printf " [+] $$t passed\n" ; ./$$t ; done +banner: + printf " Running library unit tests...\n" + +harness-files = test-harness.c + +zonelist: zonelist.c ../zonelist.c $(harness-files) +movebits: movebits.c ../movebits.c $(harness-files) +memscan: memscan.c ../memscan.c +load_linux: load_linux.c + +%: %.c + $(CC) $(CFLAGS) -o $@ $< + + diff --git a/com32/lib/syslinux/tests/load_linux.c b/com32/lib/syslinux/tests/load_linux.c new file mode 100644 index 00000000..ed973841 --- /dev/null +++ b/com32/lib/syslinux/tests/load_linux.c @@ -0,0 +1,199 @@ +#include "unittest/unittest.h" +#include "unittest/memmap.h" + +#include "syslinux/bootrm.h" +#include <string.h> + +/* + * load_linux.c dependencies. + */ +#include "../../suffix_number.c" + +static struct firmware __test_firmware; +struct firmware *firmware = &__test_firmware; + +static struct syslinux_memmap *__test_mmap; +struct syslinux_memmap *syslinux_memory_map(void) +{ + return syslinux_dup_memmap(__test_mmap); +} + +void syslinux_force_text_mode(void) { } + +static char *__test_cmdline = "this is a test!!"; +static bool __test_called_boot_rm = false; +static addr_t __test_cmdline_addr; + +int syslinux_shuffle_boot_rm(struct syslinux_movelist *fraglist, + struct syslinux_memmap *memmap, + uint16_t bootflags, + struct syslinux_rm_regs *regs) +{ + struct syslinux_movelist *moves, *ml; + int rv; + + __test_called_boot_rm = true; + + ml = fraglist; + while (ml) { + addr_t cmdline_addr, last_lowmem_addr; + + if (ml->src != __test_cmdline) + continue; + + last_lowmem_addr = __test_cmdline_addr; + cmdline_addr = ml->dst; + syslinux_assert_str(cmdline_addr == last_lowmem_addr, + "cmdline at 0x%x but expected 0x%x", + cmdline_addr, last_lowmem_addr); + + syslinux_assert_str(strlen(__test_cmdline) + 1 == ml->len, + "cmdline length %d, expected %d", ml->len, + strlen(__test_cmdline) + 1); + break; + } + + moves = NULL; + rv = syslinux_compute_movelist(&moves, fraglist, memmap); + syslinux_free_movelist(moves); + + syslinux_assert(!rv, "Failed to compute movelist"); + + return -1; +} + +#include "../load_linux.c" +#include "../zonelist.c" +#include "test-harness.c" + +static void __test_setup_kernel(void *buf) +{ + struct linux_header *hdr; + + hdr = buf; + memset(hdr, 0, sizeof(*hdr)); + + /* + * Setup the minimum required fields. + */ + hdr->boot_flag = BOOT_MAGIC; + hdr->setup_sects = 1; + hdr->version = 0x0201; +} + +static inline addr_t __test_calc_cmdline_addr(addr_t addr) +{ + size_t len = strlen(__test_cmdline) + 1; + return (addr - len) & ~15; +} + +#define KERNEL_BUF_SIZE 1024 +static void *__test_setup(struct test_memmap_entry *entries, + size_t nr_entries, + addr_t last) +{ + struct syslinux_memmap *mmap; + void *buf; + + mmap = test_build_mmap(entries, nr_entries); + if (!mmap) + goto bail; + + buf = malloc(KERNEL_BUF_SIZE); + if (!buf) + goto bail; + + __test_setup_kernel(buf); + + __test_mmap = mmap; + __test_cmdline_addr = __test_calc_cmdline_addr(last); + + return buf; + +bail: + syslinux_free_memmap(mmap); + return NULL; +} + +static void __test_teardown(void *buf) +{ + free(buf); + syslinux_free_memmap(__test_mmap); + + __test_called_boot_rm = false; + __test_cmdline_addr = 0; + __test_mmap = NULL; +} + +/* + * Make sure that we can relocate the cmdline to a free region of + * memory. + * + * The below memory map is based on one from VMWare. + */ +static int test_cmdline_placement(void) +{ + struct syslinux_memmap *mmap; + addr_t addr; + void *buf; + int rv; + + struct test_memmap_entry entries[] = { + 0x00000000, 0x00092800, SMT_FREE, + 0x00092800, 0x0000d800, SMT_RESERVED, + 0x000ca000, 0x00002000, SMT_RESERVED, + 0x000dc000, 0x00004000, SMT_RESERVED, + 0x000e4000, 0x00001c00, SMT_RESERVED, + 0x00100000, 0x3fdf0000, SMT_FREE, + }; + + buf = __test_setup(entries, array_sz(entries), 0x92800); + if (!buf) + return -1; + + rv = syslinux_boot_linux(buf, KERNEL_BUF_SIZE, NULL, NULL, __test_cmdline); + + syslinux_assert(__test_called_boot_rm, + "Failed to invoke syslinux_shuffle_boot_rm()"); + + __test_teardown(buf); + return 0; +} + +/* + * Ensure that the linux loader only uses SMT_TERMINAL regions as a last + * resort. + */ +static int test_terminal_regions(void) +{ + addr_t addr; + void *buf; + int rv; + + struct test_memmap_entry entries[] = { + 0x000000, 0x090000, SMT_RESERVED, + 0x090000, 0x000420, SMT_TERMINAL, + 0x090420, 0x000400, SMT_FREE, + 0x090820, 0x000200, SMT_TERMINAL, + }; + + buf = __test_setup(entries, array_sz(entries), 0x090820); + if (!buf) + return -1; + + rv = syslinux_boot_linux(buf, KERNEL_BUF_SIZE, NULL, NULL, __test_cmdline); + + syslinux_assert(__test_called_boot_rm, + "Failed to invoke syslinux_shuffle_boot_rm()"); + + __test_teardown(buf); + return 0; +} + +int main(int argc, char **argv) +{ + test_cmdline_placement(); + test_terminal_regions(); + + return 0; +} diff --git a/com32/lib/syslinux/tests/memscan.c b/com32/lib/syslinux/tests/memscan.c new file mode 100644 index 00000000..ea46ca9a --- /dev/null +++ b/com32/lib/syslinux/tests/memscan.c @@ -0,0 +1,75 @@ +#include "unittest/unittest.h" + +#include "../memscan.c" + +struct memmap { + addr_t start; + size_t size; + enum syslinux_memmap_types type; + bool visited; +}; + +static struct memmap memmap[] = { + { 0x00000, 0x2000, SMT_FREE, false }, + { 0x400000, 0x1000, SMT_TERMINAL, false}, +}; + +#define MEMMAP_SIZE (sizeof(memmap) / sizeof(memmap[0])) + +/* + * Our dummy memory scanner. This is analogous to bios_scan_memory() or + * efi_scan_memory(), etc. + */ +static int test_scan_memory(scan_memory_callback_t callback, void *data) +{ + int i, rv; + + for (i = 0; i < MEMMAP_SIZE; i++) + rv = callback(data, memmap[i].start, memmap[i].size, memmap[i].type); + + return 0; +} + +static int callback(void *data, addr_t start, addr_t size, + enum syslinux_memmap_types type) +{ + int i; + + for (i = 0; i < MEMMAP_SIZE; i++) { + if (memmap[i].start == start && memmap[i].size == size) { + memmap[i].visited = true; + break; + } + } + + return 0; +} + +static int verify_visited_all_memmap_entries(void) +{ + int i; + + syslinux_memscan_new(test_scan_memory); + syslinux_scan_memory(callback, NULL); + + for (i = 0; i < MEMMAP_SIZE; i++) { + addr_t start = memmap[i].start; + bool visited_entry = memmap[i].visited; + + syslinux_assert(visited_entry, "Didn't pass entry %d to callback", i); + } + + return 0; +} + +static int verify_invoked_all_callbacks(void) +{ + syslinux_scan_memory(callback, NULL); +} + +int main(int argc, char **argv) +{ + verify_visited_all_memmap_entries(); + + return 0; +} diff --git a/com32/lib/syslinux/tests/movebits.c b/com32/lib/syslinux/tests/movebits.c new file mode 100644 index 00000000..cce269aa --- /dev/null +++ b/com32/lib/syslinux/tests/movebits.c @@ -0,0 +1,86 @@ +#include "unittest/unittest.h" +#include "unittest/memmap.h" +#include <setjmp.h> + +#include "../../../include/minmax.h" +#include "../zonelist.c" +#include "test-harness.c" + +static int move_to_terminal_region(void) +{ + struct syslinux_memmap *mmap; + addr_t dst, src; + size_t len; + int rv = -1; + struct test_memmap_entry entries[] = { + { 0x00000, 0x90000, SMT_RESERVED }, + { 0x90000, 0x10000, SMT_TERMINAL }, + { 0xa0000, 0xf000, SMT_FREE }, + { 0x100000, 0x3000, SMT_FREE } + }; + + mmap = test_build_mmap(entries, array_sz(entries)); + if (!mmap) + goto bail; + + dst = 0x90000; + src = 0x1fff000; + len = 0xf000; + + rv = syslinux_memmap_find(mmap, &dst, len, false, 16, + 0, (addr_t)-1, 0, (addr_t)-1); + syslinux_assert(!rv, "Expected to find 0x%x to be SMT_TERMINAL", dst); + + rv = test_attempt_movelist(mmap, dst, src, len); + syslinux_assert(!rv, "Expected to move 0x%x to 0x%x, len 0x%x", src, dst, len); + + rv = 0; + +bail: + syslinux_free_memmap(mmap); + return rv; +} + +static int move_to_overlapping_region(void) +{ + struct syslinux_memmap *mmap; + addr_t dst, src; + size_t len; + int rv = -1; + struct test_memmap_entry entries[] = { + { 0x00000, 0x90000, SMT_RESERVED }, + { 0x90000, 0x10000, SMT_TERMINAL }, + { 0xa0000, 0xf000, SMT_FREE }, + { 0x100000, 0x3000, SMT_TERMINAL }, + { 0x103000, 0x1000, SMT_FREE }, + }; + + mmap = test_build_mmap(entries, array_sz(entries)); + if (!mmap) + goto bail; + + rv = test_attempt_movelist(mmap, 0x90000, 0x300000, 0x10001); + syslinux_assert(!rv, "Allocating across boundary region failed"); + + rv = test_attempt_movelist(mmap, 0xa0000, 0x4000000, 0x10000); + syslinux_assert(rv, "Move into undefined region succeeded"); + + rv = test_attempt_movelist(mmap, 0x80000, 0x200000, 0x10000); + syslinux_assert(rv, "Move across incompatible region boundary succeeded"); + + rv = test_attempt_movelist(mmap, 0x100000, 0x4000000, 0x4001); + syslinux_assert(rv, "Move past end of available regions succeeded"); + + rv = 0; +bail: + syslinux_free_memmap(mmap); + return rv; +} + +int main(int argc, char **argv) +{ + move_to_terminal_region(); + move_to_overlapping_region(); + + return 0; +} diff --git a/com32/lib/syslinux/tests/test-harness.c b/com32/lib/syslinux/tests/test-harness.c new file mode 100644 index 00000000..d50d0c9c --- /dev/null +++ b/com32/lib/syslinux/tests/test-harness.c @@ -0,0 +1,48 @@ +#include "../addlist.c" +#include "../freelist.c" +#include "../movebits.c" + +struct syslinux_memmap *test_build_mmap(struct test_memmap_entry *entries, + size_t nr_entries) +{ + struct syslinux_memmap *mmap; + int i; + + mmap = syslinux_init_memmap(); + if (!mmap) + goto bail; + + for (i = 0; i < nr_entries; i++) { + enum syslinux_memmap_types type = entries[i].type; + addr_t start = entries[i].start; + addr_t size = entries[i].size; + + if (syslinux_add_memmap(&mmap, start, size, type)) + goto bail; + } + + return mmap; + +bail: + syslinux_free_memmap(mmap); + return NULL; +} + +int test_attempt_movelist(struct syslinux_memmap *mmap, addr_t dst, + addr_t src, size_t len) +{ + struct syslinux_movelist *frags = NULL; + struct syslinux_movelist *moves = NULL; + int rv; + + rv = syslinux_add_movelist(&frags, dst, src, len); + if (rv) + goto bail; + + rv = syslinux_compute_movelist(&moves, frags, mmap); + +bail: + syslinux_free_movelist(frags); + syslinux_free_movelist(moves); + return rv; +} diff --git a/com32/lib/syslinux/tests/zonelist.c b/com32/lib/syslinux/tests/zonelist.c new file mode 100644 index 00000000..588351f6 --- /dev/null +++ b/com32/lib/syslinux/tests/zonelist.c @@ -0,0 +1,286 @@ +/* + * Unit test. + * + * We make heavy use of assertions to ensure that our expectations are + * met regarding the Syslinux library interfaces. If an assert fails we + * keep running the test if possible to try and save as much information + * regarding the failures. + * + * A unit test function should return an error if it failed to setup the + * infrastructure, e.g. malloc() fails. If an assertion fires, that is + * not mean the test infrastructure failed, merely that the test didn't + * pass. + * + * To work around any include path issues due to the unit tests being + * run on the development host we must include all headers with absolute + * paths. + */ +#include "unittest/unittest.h" +#include "unittest/memmap.h" +#include "../zonelist.c" +#include "test-harness.c" + +static int refuse_to_alloc_reserved_region(void) +{ + struct syslinux_memmap *mmap; + const char *cmdline; + size_t kernel_size; + bool relocatable = false; + size_t alignment = 1; + addr_t base; + int rv = -1; + + mmap = syslinux_init_memmap(); + if (!mmap) + goto bail; + + if (syslinux_add_memmap(&mmap, 0x90000, 0x10000, SMT_RESERVED)) + goto bail; + + base = 0x90000; + rv = syslinux_memmap_find(mmap, &base, 0x1000, relocatable, alignment, + base, base, 0, 640 * 1024); + syslinux_assert(rv, "Allocated reserved region 0x%x", base); + + rv = 0; + +bail: + syslinux_free_memmap(mmap); + return rv; +} + +static int refuse_to_alloc_above_max_address(void) +{ + struct syslinux_memmap *mmap; + addr_t base = 0x100000; + size_t size = 0x1000; + int rv = -1; + + mmap = syslinux_init_memmap(); + if (!mmap) + goto bail; + + if (syslinux_add_memmap(&mmap, base, size, SMT_FREE)) + goto bail; + + rv = syslinux_memmap_find(mmap, &base, size, false, 16, + base, base, 0, 640 * 1024); + syslinux_assert(!rv, "Failed to find a free region"); + + syslinux_assert_str(!(base < 0x100000), "Region below min address"); + syslinux_assert_str(!(base > 0x100000), "Region above max address"); + + rv = 0; +bail: + syslinux_free_memmap(mmap); + return rv; +} + +static int alloc_region_with_zero_size(void) +{ + int rv; + + rv = syslinux_memmap_find(NULL, 0, 0, false, 0, 0, 0, 0, 0); + syslinux_assert(!rv, "Should be able to allocate a zero-size region"); + + return 0; +} + +static int refuse_to_relocate_region(void) +{ + struct syslinux_memmap *mmap; + addr_t free_base; + size_t free_size; + int rv = -1; + + mmap = syslinux_init_memmap(); + if (!mmap) + goto bail; + + free_base = 0x20000; + free_size = 0x1000000; + if (syslinux_add_memmap(&mmap, free_base, free_size, SMT_FREE)) + goto bail; + + free_base = 0x10000; + free_size = 0x7000; + rv = syslinux_memmap_find(mmap, &free_base, free_size, false, 1, + 0, (addr_t)-1, (addr_t)0, (addr_t)-1); + syslinux_assert(rv, "Relocated region from 0x10000 to 0x%x", free_base); + +bail: + syslinux_free_memmap(mmap); + return rv; +} + +static int only_relocate_upwards(void) +{ + struct syslinux_memmap *mmap; + addr_t base; + int rv = -1; + + mmap = syslinux_init_memmap(); + if (!mmap) + goto bail; + + if (syslinux_add_memmap(&mmap, 0x00010, 0x1000, SMT_FREE)) + goto bail; + + base = 0x10000; + rv = syslinux_memmap_find(mmap, &base, 16, true, 1, 0, (addr_t)-1, + 0x2000, (addr_t)-1); + + syslinux_assert(rv, "Should not have found any entry in memmap"); + syslinux_assert_str(base >= 0x10000, + "Relocated in wrong direction 0x%x", base); + + rv = 0; +bail: + syslinux_free_memmap(mmap); + return rv; +} + +static int alloc_in_pxe_region(void) +{ + struct syslinux_memmap *mmap; + addr_t base; + int rv = -1; + + mmap = syslinux_init_memmap(); + if (!mmap) + goto bail; + + /* Construct a memmap with a gap where the PXE region usually is */ + if (syslinux_add_memmap(&mmap, 0x00000, 0x8f000, SMT_FREE)) + goto bail; + + if (syslinux_add_memmap(&mmap, 0x100000, 0xf000, SMT_FREE)) + goto bail; + + base = 0x90000; + rv = syslinux_memmap_find(mmap, &base, 0x1000, false, 16, + 0, (addr_t)-1, 0, (addr_t)-1); + + syslinux_assert(rv, "Shouldn't have allocated none existent region"); + +bail: + syslinux_free_memmap(mmap); + return rv; +} + +static int demote_free_region_to_terminal(void) +{ + enum syslinux_memmap_types type; + struct syslinux_memmap *mmap; + int rv = -1; + struct test_memmap_entry entries[] = { + { 0x100000, 0x300000, SMT_TERMINAL }, + { 0x400000, 0x300000, SMT_FREE }, + { 0x700000, 0x20000, SMT_FREE }, + { 0x720000, 0x20000, SMT_TERMINAL }, + }; + + mmap = test_build_mmap(entries, array_sz(entries)); + if (!mmap) + goto bail; + + type = syslinux_memmap_type(mmap, 0x100000, 0x500000); + syslinux_assert_str(type == SMT_TERMINAL, + "Expected SMT_TERMINAL + SMT_FREE region to cause type demotion"); + + type = syslinux_memmap_type(mmap, 0x700000, 0x40000); + syslinux_assert_str(type == SMT_TERMINAL, + "Expected SMT_FREE + SMT_TERMINAL region to cause type demotion"); + + type = syslinux_memmap_type(mmap, 0x100000, 0x640000); + syslinux_assert_str(type == SMT_TERMINAL, + "Expected multiple SMT_{FREE,TERMINAL} regions to cause type demotion"); + + rv = 0; + +bail: + syslinux_free_memmap(mmap); + return rv; +} + +/* + * Find the highest address given a set of boundary conditions. + */ +static int test_find_highest(void) +{ + struct syslinux_memmap *mmap; + addr_t start; + int rv = -1; + struct test_memmap_entry entries[] = { + 0x000000, 0x000000, SMT_FREE, + 0x090000, 0x002000, SMT_FREE, + 0x092000, 0x100000, SMT_RESERVED, + 0x192001, 0x000021, SMT_TERMINAL, + }; + + mmap = test_build_mmap(entries, array_sz(entries)); + if (!mmap) + goto bail; + + start = 0x90000; + rv = syslinux_memmap_highest(mmap, SMT_FREE, &start, 0x20, 0x192000, 1); + + syslinux_assert(!rv, "Failed to find highest SMT_FREE address"); + syslinux_assert_str(start == 0x91fe0, + "0x%x incorrect highest address", start); + + start = 0x40000; + rv = syslinux_memmap_highest(mmap, SMT_FREE, &start, 0x20, 0x91480, 1); + + syslinux_assert(!rv, "Failed to find highest SMT_FREE address"); + syslinux_assert_str(start == 0x91460, + "0x%x incorrect highest address", start); + + + start = 0x90023; + rv = syslinux_memmap_highest(mmap, SMT_FREE, &start, 0x20, 0x90057, 0x10); + syslinux_assert_str(start == 0x90030, + "0x%x incorrectly aligned highest address", start); + + start = 0x00000; + rv = syslinux_memmap_highest(mmap, SMT_TERMINAL, &start, + 0x7, 0x192300, 0x10); + syslinux_assert_str(start == 0x192010, + "0x%x incorrectly aligned SMT_TERMINAL address", start); + + start = 0x192001; + rv = syslinux_memmap_highest(mmap, SMT_RESERVED, &start, + 0x400, (addr_t)-1, 1); + syslinux_assert_str(rv && start == 0x192001, + "Unexpectedly succeeded finding invalid region: 0x%x", + start); + + start = 0x191fff; + rv = syslinux_memmap_highest(mmap, SMT_RESERVED, &start, + 0x800, (addr_t)-1, 1); + syslinux_assert_str(rv && start == 0x191fff, + "Unexpectedly succeeded finding invalid region: 0x%x", + start); + rv = 0; +bail: + syslinux_free_memmap(mmap); + return rv; +} + +int main(int argc, char **argv) +{ + refuse_to_alloc_reserved_region(); + refuse_to_alloc_above_max_address(); + + alloc_region_with_zero_size(); + + refuse_to_relocate_region(); + only_relocate_upwards(); + + alloc_in_pxe_region(); + demote_free_region_to_terminal(); + + test_find_highest(); + + return 0; +} 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/syslinux/zonelist.c b/com32/lib/syslinux/zonelist.c index 7034c4be..dbc874c5 100644 --- a/com32/lib/syslinux/zonelist.c +++ b/com32/lib/syslinux/zonelist.c @@ -156,7 +156,8 @@ int syslinux_add_memmap(struct syslinux_memmap **list, /* * Verify what type a certain memory region is. This function returns - * SMT_ERROR if the memory region has multiple types. + * SMT_ERROR if the memory region has multiple types, except that + * SMT_FREE can be demoted to SMT_TERMINAL. */ enum syslinux_memmap_types syslinux_memmap_type(struct syslinux_memmap *list, addr_t start, addr_t len) @@ -168,10 +169,18 @@ enum syslinux_memmap_types syslinux_memmap_type(struct syslinux_memmap *list, while (list->type != SMT_END) { llast = list->next->start - 1; if (list->start <= start) { - if (llast >= last) + if (llast >= last) { return list->type; /* Region has a well-defined type */ - else if (llast >= start) - return SMT_ERROR; /* Crosses region boundary */ + } else if (llast >= start) { + /* Crosses region boundary */ + while (valid_terminal_type(list->type)) { + list = list->next; + llast = list->next->start - 1; + if (llast >= last) + return SMT_TERMINAL; + } + return SMT_ERROR; + } } list = list->next; } @@ -210,13 +219,58 @@ int syslinux_memmap_largest(struct syslinux_memmap *list, } /* + * Find the highest zone of a specific type that satisfies the + * constraints. + * + * 'start' is updated with the highest address on success. 'start' can + * be used to set a minimum address to begin searching from. + * + * Returns -1 on failure. + */ +int syslinux_memmap_highest(const struct syslinux_memmap *list, + enum syslinux_memmap_types type, + addr_t *start, addr_t len, + addr_t ceiling, addr_t align) +{ + addr_t size, best; + + for (best = 0; list->type != SMT_END; list = list->next) { + size = list->next->start - list->start; + + if (list->type != type) + continue; + + if (list->start + size <= *start) + continue; + + if (list->start + len >= ceiling) + continue; + + if (list->start + size < ceiling) + best = ALIGN_DOWN(list->start + size - len, align); + else + best = ALIGN_DOWN(ceiling - len, align); + + if (best < *start) + best = 0; + } + + if (!best) + return -1; + + *start = best; + + return 0; +} + +/* * Find the first (lowest address) zone of a specific type and of * a certain minimum size, with an optional starting address. * The input values of start and len are used as minima. */ -int syslinux_memmap_find(struct syslinux_memmap *list, - enum syslinux_memmap_types type, - addr_t * start, addr_t * len, addr_t align) +int syslinux_memmap_find_type(struct syslinux_memmap *list, + enum syslinux_memmap_types type, + addr_t * start, addr_t * len, addr_t align) { addr_t min_start = *start; addr_t min_len = *len; @@ -281,3 +335,68 @@ struct syslinux_memmap *syslinux_dup_memmap(struct syslinux_memmap *list) return newlist; } + +/* + * Find a memory region, given a set of heuristics and update 'base' if + * successful. + */ +int syslinux_memmap_find(struct syslinux_memmap *mmap, + addr_t *base, size_t size, + bool relocate, size_t align, + addr_t start_min, addr_t start_max, + addr_t end_min, addr_t end_max) +{ + const struct syslinux_memmap *mp; + enum syslinux_memmap_types type; + bool ok; + + if (!size) + return 0; + + type = syslinux_memmap_type(mmap, *base, size); + + /* This assumes SMT_TERMINAL is OK if we can get the exact address */ + if (valid_terminal_type(type)) + return 0; + + if (!relocate) { + dprintf("Cannot relocate\n"); + return -1; + } + + ok = false; + for (mp = mmap; mp && mp->type != SMT_END; mp = mp->next) { + addr_t start, end; + start = mp->start; + end = mp->next->start; + + if (mp->type != SMT_FREE) + continue; + + /* min */ + if (end <= end_min) + continue; /* Only relocate upwards */ + + if (start < start_min) + start = start_min; + + /* max */ + if (end > end_max) + end = end_max; + + start = ALIGN_UP(start, align); + if (start > start_max || start >= end) + continue; + + if (end - start >= size) { + *base = start; + ok = true; + break; + } + } + + if (!ok) + return -1; + + return 0; +} diff --git a/com32/lib/x86_64/elf.ld b/com32/lib/x86_64/elf.ld new file mode 100644 index 00000000..10ee7c44 --- /dev/null +++ b/com32/lib/x86_64/elf.ld @@ -0,0 +1,173 @@ +/* + * 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)) + } + .ctors : + { + __ctors_start = .; + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + KEEP (*(.ctors_modinit)) + KEEP (*(.ctors_modmain)) + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + __ctors_end = .; + } + + .dtors : + { + __dtors_start = .; + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + KEEP (*(.dtors_modexit)) + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + __dtors_end = .; + } + + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got) } + /*. = DATA_SEGMENT_RELRO_END (12, .); -> This gives a "invalid assignment to location counter" error */ + .got.plt : { *(.got.plt) } + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + KEEP (*(.gnu.linkonce.d.*personality*)) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + PROVIDE (edata = .); + PROVIDE (_edata = .); + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we don't + pad the .data section. */ + /*. = ALIGN(. != 0 ? 32 / 8 : 1);*/ + . = ALIGN(. != 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/libupload/ctime.c b/com32/libupload/ctime.c index 56c8efb6..a3e8155c 100644 --- a/com32/libupload/ctime.c +++ b/com32/libupload/ctime.c @@ -24,9 +24,11 @@ uint32_t posix_time(void) ir.eax.b[1] = 0x04; __intcall(0x1A, &ir, &d0); + memset(&ir, 0, sizeof ir); ir.eax.b[1] = 0x02; __intcall(0x1A, &ir, &t0); + memset(&ir, 0, sizeof ir); ir.eax.b[1] = 0x04; __intcall(0x1A, &ir, &d1); diff --git a/com32/libutil/Makefile b/com32/libutil/Makefile index 5aa7ceb8..094f1ff5 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 d70d23ea..f3625e1a 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/lua/src/vesa.c b/com32/lua/src/vesa.c index 06649e11..19a10242 100644 --- a/com32/lua/src/vesa.c +++ b/com32/lua/src/vesa.c @@ -27,7 +27,7 @@ static int vesa_getmodes(lua_State *L) if (!mi) goto out; - memset(&rm, 0, sizeof rm); + memset(&rm, 0, sizeof(rm)); memset(gi, 0, sizeof *gi); gi->signature = VBE2_MAGIC; /* Get VBE2 extended data */ @@ -61,6 +61,7 @@ static int vesa_getmodes(lua_State *L) printf("Found mode: 0x%04x (%dx%dx%d)\n", mode, mi->h_res, mi->v_res, mi->bpp); + memset(&rm, 0, sizeof(rm)); memset(mi, 0, sizeof *mi); rm.eax.w[0] = 0x4F01; /* Get SVGA mode information */ rm.ecx.w[0] = mode; diff --git a/com32/mboot/Makefile b/com32/mboot/Makefile index 6e010b1c..e9164369 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/mboot/apm.c b/com32/mboot/apm.c index 3f48af7c..82b6b608 100644 --- a/com32/mboot/apm.c +++ b/com32/mboot/apm.c @@ -50,6 +50,7 @@ void mboot_apm(void) return; /* 32 bits not supported */ /* Disconnect first, just in case */ + memset(&ireg, 0, sizeof ireg); ireg.eax.b[0] = 0x04; __intcall(0x15, &ireg, &oreg); @@ -68,6 +69,7 @@ void mboot_apm(void) /* Redo the installation check as the 32-bit connect; some BIOSes return different flags this way... */ + memset(&ireg, 0, sizeof ireg); ireg.eax.b[0] = 0x00; __intcall(0x15, &ireg, &oreg); diff --git a/com32/mboot/initvesa.c b/com32/mboot/initvesa.c index bd869e3d..9111ec27 100644 --- a/com32/mboot/initvesa.c +++ b/com32/mboot/initvesa.c @@ -100,6 +100,7 @@ void set_graphics_mode(const struct multiboot_header *mbh, while ((mode = *mode_ptr++) != 0xFFFF) { mode &= 0x1FF; /* The rest are attributes of sorts */ + memset(&rm, 0, sizeof rm); memset(mi, 0, sizeof *mi); rm.eax.w[0] = 0x4F01; /* Get SVGA mode information */ rm.ecx.w[0] = mode; @@ -193,6 +194,7 @@ void set_graphics_mode(const struct multiboot_header *mbh, mode = bestmode; /* Now set video mode */ + memset(&rm, 0, sizeof rm); rm.eax.w[0] = 0x4F02; /* Set SVGA video mode */ mode |= 0x4000; /* Request linear framebuffer */ rm.ebx.w[0] = mode; diff --git a/com32/mboot/map.c b/com32/mboot/map.c index 99add306..84f3b20c 100644 --- a/com32/mboot/map.c +++ b/com32/mboot/map.c @@ -53,7 +53,7 @@ addr_t map_data(const void *data, size_t len, size_t align, int flags) addr_t pad = (flags & MAP_NOPAD) ? 0 : -len & (align - 1); addr_t xlen = len + pad; - if (syslinux_memmap_find(amap, SMT_FREE, &start, &xlen, align) || + if (syslinux_memmap_find_type(amap, SMT_FREE, &start, &xlen, align) || syslinux_add_memmap(&amap, start, len + pad, SMT_ALLOC) || syslinux_add_movelist(&ml, start, (addr_t) data, len) || (pad && syslinux_add_memmap(&mmap, start + len, pad, SMT_ZERO))) { diff --git a/com32/mboot/mem.c b/com32/mboot/mem.c index 6e3995bf..d5c559a7 100644 --- a/com32/mboot/mem.c +++ b/com32/mboot/mem.c @@ -124,6 +124,7 @@ static int mboot_scan_memory(struct AddrRangeDesc **ardp, uint32_t * dosmem) ard[0].Type = 1; /* Next try INT 15h AX=E801h */ + memset(&ireg, 0, sizeof ireg); ireg.eax.w[0] = 0xe801; __intcall(0x15, &ireg, &oreg); @@ -147,7 +148,9 @@ static int mboot_scan_memory(struct AddrRangeDesc **ardp, uint32_t * dosmem) } /* Finally try INT 15h AH=88h */ + memset(&ireg, 0, sizeof ireg); ireg.eax.w[0] = 0x8800; + __intcall(0x15, &ireg, &oreg); if (!(oreg.eflags.l & EFLAGS_CF) && oreg.eax.w[0]) { ard[1].size = 20; ard[1].BaseAddr = 1 << 20; diff --git a/com32/menu/Makefile b/com32/menu/Makefile index e62c6b87..7c2d5927 100644 --- a/com32/menu/Makefile +++ b/com32/menu/Makefile @@ -14,17 +14,16 @@ ## Simple menu system ## -topdir = ../.. -MAKEDIR = $(topdir)/mk +VPATH = $(SRC) include $(MAKEDIR)/elf.mk -LNXLIBS = ../libutil/libutil_lnx.a +LNXLIBS = $(objdir)/com32/libutil/libutil_lnx.a MODULES = menu.c32 vesamenu.c32 TESTFILES = -COMMONOBJS = menumain.o readconfig.o passwd.o drain.o printmsg.o colors.o \ - background.o refstr.o +COMMONOBJS = menumain.o readconfig.o passwd.o drain.o \ + printmsg.o colors.o background.o refstr.o all: $(MODULES) $(TESTFILES) diff --git a/com32/menu/readconfig.c b/com32/menu/readconfig.c index 7eaea280..b7814be2 100644 --- a/com32/menu/readconfig.c +++ b/com32/menu/readconfig.c @@ -1044,11 +1044,13 @@ do_include: m->ontimeout = refstrdup(skipspace(p + 9)); } else if (looking_at(p, "allowoptions")) { m->allowedit = !!atoi(skipspace(p + 12)); - } else if (looking_at(p, "ipappend") || looking_at(p, "sysappend")) { + } else if ((ep = looking_at(p, "ipappend")) || + (ep = looking_at(p, "sysappend"))) { + uint32_t s = strtoul(skipspace(ep), NULL, 0); if (ld.label) - ld.ipappend = atoi(skipspace(p + 8)); + ld.ipappend = s; else - ipappend = atoi(skipspace(p + 8)); + ipappend = s; } else if (looking_at(p, "default")) { refstr_put(globaldefault); globaldefault = refstrdup(skipspace(p + 7)); diff --git a/com32/modules/Makefile b/com32/modules/Makefile index 682e1b22..13cc63bb 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 \ @@ -25,7 +24,7 @@ MODULES = config.c32 ethersel.c32 dmitest.c32 cpuidtest.c32 \ kbdmap.c32 cmd.c32 vpdtest.c32 host.c32 ls.c32 gpxecmd.c32 \ ifcpu.c32 cpuid.c32 cat.c32 pwd.c32 ifplop.c32 zzjson.c32 \ whichsys.c32 prdhcp.c32 pxechn.c32 kontron_wdt.c32 ifmemdsk.c32 \ - hexdump.c32 poweroff.c32 cptime.c32 + hexdump.c32 poweroff.c32 cptime.c32 debug.c32 TESTFILES = diff --git a/com32/modules/debug.c b/com32/modules/debug.c new file mode 100644 index 00000000..1026ebf3 --- /dev/null +++ b/com32/modules/debug.c @@ -0,0 +1,54 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2013 Intel Corporation; author: Matt Fleming + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston MA 02110-1301, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#include <syslinux/debug.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static char *progname; + +static void usage(void) +{ + fprintf(stderr, "Usage: %s [-e|-d] <func1> [<func2>, ...]\n", progname); +} + +int main(int argc, char *argv[]) +{ + bool enable; + int i; + + progname = argv[0]; + + if (argc < 3) { + usage(); + return -1; + } + + if (!strncmp(argv[1], "-e", 2)) + enable = true; + else if (!strncmp(argv[1], "-d", 2)) + enable = false; + else { + usage(); + return -1; + } + + for (i = 2; i < argc; i++) { + char *str = argv[i]; + + if (syslinux_debug(str, enable) < 0) + fprintf(stderr, "Failed to debug symbol \"%s\"\n", str); + } + + return 0; +} diff --git a/com32/modules/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/meminfo.c b/com32/modules/meminfo.c index 34b3e91d..fc04792f 100644 --- a/com32/modules/meminfo.c +++ b/com32/modules/meminfo.c @@ -110,11 +110,13 @@ static void dump_legacy(void) ivt[0x15].seg, ivt[0x15].offs, dosram, dosram << 10, oreg.eax.w[0], oreg.eax.w[0] << 10); + memset(&ireg, 0, sizeof ireg); ireg.eax.b[1] = 0x88; __intcall(0x15, &ireg, &oreg); printf("INT 15 88: 0x%04x (%uK) ", oreg.eax.w[0], oreg.eax.w[0]); + memset(&ireg, 0, sizeof ireg); ireg.eax.w[0] = 0xe801; __intcall(0x15, &ireg, &oreg); diff --git a/com32/modules/poweroff.c b/com32/modules/poweroff.c index 8b656ad4..41e501e9 100644 --- a/com32/modules/poweroff.c +++ b/com32/modules/poweroff.c @@ -20,7 +20,7 @@ #include <string.h> #include <com32.h> -int main() +int main(int argc __unused, char *argv[] __unused) { com32sys_t inregs, outregs; @@ -50,6 +50,7 @@ int main() return 1; } + memset(&inregs, 0, sizeof inregs); inregs.eax.l = 0x5301; /* APM Real Mode Interface Connect (01h) */ inregs.ebx.l = 0; /* APM BIOS (0000h) */ __intcall(0x15, &inregs, &outregs); @@ -59,6 +60,7 @@ int main() return 1; } + memset(&inregs, 0, sizeof inregs); inregs.eax.l = 0x530e; /* APM Driver Version (0Eh) */ inregs.ebx.l = 0; /* APM BIOS (0000h) */ inregs.ecx.l = 0x101; /* APM Driver version 1.1 */ @@ -74,6 +76,7 @@ int main() return 1; } + memset(&inregs, 0, sizeof inregs); inregs.eax.l = 0x5307; /* Set Power State (07h) */ inregs.ebx.l = 1; /* All devices power managed by the APM BIOS */ inregs.ecx.l = 3; /* Power state off */ diff --git a/com32/modules/prdhcp.c b/com32/modules/prdhcp.c index e1785a03..4ae295e8 100644 --- a/com32/modules/prdhcp.c +++ b/com32/modules/prdhcp.c @@ -39,11 +39,11 @@ #include <unistd.h> #include <getkey.h> -#define DEBUG 0 +#define PRDHCP_DEBUG 0 #define dprintf0(f, ...) ((void)0) -#ifdef DEBUG +#ifdef PRDHCP_DEBUG # define dpressanykey pressanykey # define dprintf printf # define dprint_pxe_bootp_t print_pxe_bootp_t diff --git a/com32/modules/pxechn.c b/com32/modules/pxechn.c index 7f2002db..bd614aa9 100644 --- a/com32/modules/pxechn.c +++ b/com32/modules/pxechn.c @@ -328,6 +328,7 @@ void pxe_set_regs(struct syslinux_rm_regs *regs) { com32sys_t tregs; + memset(&tregs,0,sizeof(tregs)); regs->ip = 0x7C00; /* Plan A uses SS:[SP + 4] */ /* sdi->pxe.stack is a usable pointer, not something that can be nicely diff --git a/com32/modules/vesainfo.c b/com32/modules/vesainfo.c index 66b121d7..a65d02c1 100644 --- a/com32/modules/vesainfo.c +++ b/com32/modules/vesainfo.c @@ -36,6 +36,7 @@ static void print_modes(void) gi = &vesa->gi; mi = &vesa->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); @@ -63,6 +64,7 @@ static void print_modes(void) lines = 0; } + memset(&rm, 0, sizeof rm); rm.eax.w[0] = 0x4F01; /* Get SVGA mode information */ rm.ecx.w[0] = mode; rm.edi.w[0] = OFFS(mi); 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 5b54225b..4d900f4f 100644 --- a/com32/rosh/Makefile +++ b/com32/rosh/Makefile @@ -16,10 +16,10 @@ ## ROSH Read Only Shell ## -LIBS = $(com32)/libutil/libutil.c32 $(com32)/lib/libcom32.c32 +LIBS = $(objdir)/com32/libutil/libutil.c32 \ + $(objdir)/com32/lib/libcom32.c32 -topdir = ../.. -MAKEDIR = $(topdir)/mk +VPATH = $(SRC) include $(MAKEDIR)/rosh.mk # from com32/sysdump/Makefile @@ -36,12 +36,12 @@ 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 f6ae00ab..06e9684b 100644 --- a/com32/samples/Makefile +++ b/com32/samples/Makefile @@ -14,17 +14,16 @@ ## samples for syslinux users ## -LIBS = $(com32)/libutil/libutil.c32 +LIBS = $(objdir)/com32/libutil/libutil.c32 -topdir = ../.. -MAKEDIR = $(topdir)/mk +VPATH = $(SRC) include $(MAKEDIR)/elf.mk all: hello.c32 resolv.c32 serialinfo.c32 \ - localboot.c32 \ - fancyhello.c32 fancyhello.lnx \ - keytest.c32 keytest.lnx \ - advdump.c32 entrydump.c32 + localboot.c32 \ + fancyhello.c32 fancyhello.lnx \ + keytest.c32 keytest.lnx \ + advdump.c32 entrydump.c32 tidy dist: rm -f *.o *.lo *.a *.lst *.elf .*.d *.tmp diff --git a/com32/samples/advdump.c b/com32/samples/advdump.c index 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 7d42ae0c..240edaaa 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/sysdump/memmap.c b/com32/sysdump/memmap.c index 929873fe..48241a7a 100644 --- a/com32/sysdump/memmap.c +++ b/com32/sysdump/memmap.c @@ -72,10 +72,12 @@ void dump_memory_map(struct upload_backend *be) __intcall(0x12, &ireg, &oreg); cpio_writefile(be, "memmap/12", &oreg, sizeof oreg); + memset(&ireg, 0, sizeof ireg); ireg.eax.b[1] = 0x88; __intcall(0x15, &ireg, &oreg); cpio_writefile(be, "memmap/1588", &oreg, sizeof oreg); + memset(&ireg, 0, sizeof ireg); ireg.eax.w[0] = 0xe801; __intcall(0x15, &ireg, &oreg); cpio_writefile(be, "memmap/15e801", &oreg, sizeof oreg); diff --git a/com32/sysdump/vesa.c b/com32/sysdump/vesa.c index 42adc3da..3540fc44 100644 --- a/com32/sysdump/vesa.c +++ b/com32/sysdump/vesa.c @@ -41,6 +41,7 @@ void dump_vesa_tables(struct upload_backend *be) mode_ptr = GET_PTR(gi.video_mode_ptr); while ((mode = *mode_ptr++) != 0xFFFF) { memset(mip, 0, sizeof *mip); + memset(&rm, 0, sizeof rm); rm.eax.w[0] = 0x4F01; /* Get SVGA mode information */ rm.ecx.w[0] = mode; rm.edi.w[0] = OFFS(mip); 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 59a61eb8..a7503ef4 100644 --- a/core/Makefile +++ b/core/Makefile @@ -15,18 +15,18 @@ # 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 \ - -I./lwip/src/include -I./lwip/src/include/ipv4 -I./fs/pxe +INCLUDES = -I$(SRC)/include -I$(com32)/include -I$(com32)/include/sys -I$(com32)/lib \ + -I$(SRC)/lwip/src/include -I$(SRC)/lwip/src/include/ipv4 -I$(SRC)/fs/pxe # 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 @@ -39,65 +39,105 @@ BTARGET = kwdhash.gen \ isolinux.bin isolinux-debug.bin pxelinux.0 lpxelinux.0 # All primary source files for the main syslinux files -NASMSRC := $(wildcard *.asm) -NASMHDR := $(wildcard *.inc) -CSRC := $(shell find . -name '*.c' -print) -SSRC := $(shell find . -name '*.S' -print) -CHDR := $(shell find . -name '*.h' -print) +NASMSRC := $(wildcard $(SRC)/*.asm) +NASMHDR := $(wildcard $(SRC)/*.inc) +CSRC := $(shell find $(SRC) -name '*.c' -print) +SSRC := $(shell find $(SRC) -name '*.S' -print) +CHDR := $(shell find $(SRC) -name '*.h' -print) 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))) # To make this compatible with the following $(filter-out), make sure -# we prefix everything with ./ +# we prefix everything with $(SRC) CORE_PXE_CSRC = \ - $(addprefix ./fs/pxe/, dhcp_option.c pxe.c tftp.c urlparse.c) + $(addprefix $(SRC)/fs/pxe/, dhcp_option.c pxe.c tftp.c urlparse.c bios.c) LPXELINUX_CSRC = $(CORE_PXE_CSRC) \ - $(shell find ./lwip -name '*.c' -print) \ - $(addprefix ./fs/pxe/, \ + $(shell find $(SRC)/lwip -name '*.c' -print) \ + $(addprefix $(SRC)/fs/pxe/, \ core.c dnsresolv.c ftp.c ftp_readdir.c gpxeurl.c http.c \ http_readdir.c idle.c isr.c tcp.c) PXELINUX_CSRC = $(CORE_PXE_CSRC) \ - $(shell find ./legacynet -name '*.c' -print) - -LPXELINUX_OBJS = $(LPXELINUX_CSRC:%.c=%.o) -PXELINUX_OBJS = $(PXELINUX_CSRC:%.c=%.o) + $(shell find $(SRC)/legacynet -name '*.c' -print) + +LPXELINUX_OBJS = $(subst $(SRC)/,,$(LPXELINUX_CSRC:%.c=%.o)) +PXELINUX_OBJS = $(subst $(SRC)/,,$(PXELINUX_CSRC:%.c=%.o)) + +UNITTEST_CSRC = $(shell find $(SRC) -path '*/tests/*.c' -print) +UNITTEST_OBJS = $(subst $(SRC)/,,$(UNITTEST_CSRC:%.c=%.o)) + +# Don't include console and network stack specific objects or unit tests +FILTER_OBJS = %rawcon.o %plaincon.o %pxelinux-c.o %ldlinux-c.o \ + %isolinux-c.o %localboot.o %pxeboot.o \ + $(subst $(OBJ)/,,$(UNITTEST_OBJS)) \ + $(subst $(OBJ)/,,$(LPXELINUX_OBJS)) \ + $(subst $(OBJ)/,,$(PXELINUX_OBJS)) + +ifdef EFI_BUILD +# EFI is single-threaded. +FILTER_OBJS += $(subst $(SRC)/,, \ + $(patsubst %.c,%.o, $(wildcard $(SRC)/thread/*.c)) \ + $(patsubst %.S,%.o, $(wildcard $(SRC)/thread/*.S))) +endif -# Don't include console and network stack specific objects -FILTER_OBJS = ./rawcon.o ./plaincon.o $(LPXELINUX_OBJS) $(PXELINUX_OBJS) COBJS = $(filter-out $(FILTER_OBJS),$(COBJ)) SOBJS = $(filter-out $(FILTER_OBJS),$(SOBJ)) +ifdef EFI_BUILD +COBJS += $(subst $(SRC)/,,$(CORE_PXE_CSRC:%.c=%.o) fs/pxe/ftp.o fs/pxe/ftp_readdir.o \ + fs/pxe/http.o fs/pxe/http_readdir.o) +endif + 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) $(SOBJS) NASMDEBUG = -g -F dwarf NASMOPT += $(NASMDEBUG) -PREPCORE = ../lzo/prepcore +PREPCORE = $(OBJ)/../lzo/prepcore -CFLAGS += -D__SYSLINUX_CORE__ +CFLAGS += -D__SYSLINUX_CORE__ -I$(objdir) -DLDLINUX=\"$(LDLINUX)\" # 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 + +# 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) $(SOBJS)) 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 @@ -105,27 +145,30 @@ 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 liblpxelinux.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 localboot.o isolinux-c.o rm -f $@ $(AR) cq $@ $^ $(RANLIB) $@ @@ -134,18 +177,18 @@ libisolinux-debug.a: libisolinux.a cp $^ $@ # Legacy network stack -libpxelinux.a: rawcon.o $(PXELINUX_OBJS) +libpxelinux.a: rawcon.o pxeboot.o pxelinux-c.o $(PXELINUX_OBJS) rm -f $@ $(AR) cq $@ $^ $(RANLIB) $@ # LwIP network stack -liblpxelinux.a: rawcon.o $(LPXELINUX_OBJS) +liblpxelinux.a: rawcon.o pxeboot.o pxelinux-c.o $(LPXELINUX_OBJS) rm -f $@ $(AR) cq $@ $^ $(RANLIB) $@ -libldlinux.a: plaincon.o +libldlinux.a: plaincon.o localboot.o ldlinux-c.o rm -f $@ $(AR) cq $@ $^ $(RANLIB) $@ @@ -156,19 +199,23 @@ $(LIB): $(LIBOBJS) $(RANLIB) $@ pxelinux.o: pxelinux.asm kwdhash.gen ../version.gen - $(NASM) -f elf $(NASMOPT) -DDATE_STR="'$(DATE)'" \ + $(NASM) -f $(NASM_ELF) $(NASMOPT) -DDATE_STR="'$(DATE)'" \ -DHEXDATE="$(HEXDATE)" \ + -D$(ARCH) \ + -I$(SRC)/ \ -DIS_LPXELINUX=0 \ - -l $(@:.o=.lsr) -o $@ -MP -MD .$@.d $< + -l $(@:.o=.lsr) -o $@ -MP -MD $(dir $@).$(notdir $@).d $< pxelinux.0: pxelinux.bin cp -f $< $@ lpxelinux.o: pxelinux.asm kwdhash.gen ../version.gen - $(NASM) -f elf $(NASMOPT) -DDATE_STR="'$(DATE)'" \ + $(NASM) -f $(NASM_ELF) $(NASMOPT) -DDATE_STR="'$(DATE)'" \ -DHEXDATE="$(HEXDATE)" \ + -D$(ARCH) \ + -I$(SRC)/ \ -DIS_LPXELINUX=1 \ - -l $(@:.o=.lsr) -o $@ -MP -MD .$@.d $< + -l $(@:.o=.lsr) -o $@ -MP -MD $(dir $@).$(notdir $@).d $< lpxelinux.0: lpxelinux.bin cp -f $< $@ @@ -179,7 +226,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..7ad10bb3 --- /dev/null +++ b/core/bios.c @@ -0,0 +1,704 @@ +#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 <syslinux/video.h> + +#include <sys/vesa/vesa.h> +#include <sys/vesa/video.h> +#include <sys/vesa/debug.h> +#include <minmax.h> + +__export 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_text_mode(void) +{ + 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(uint8_t *x, uint8_t *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; + memset(&ireg, 0, sizeof(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; + + memset(&ireg, 0, sizeof(ireg)); + + 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; + + memset(&ireg, 0, sizeof(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; + + memset(&ireg, 0, sizeof(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; + + memset(&ireg, 0, sizeof(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; + + memset(&ireg, 0, sizeof(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, + .text_mode = bios_text_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 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; + + memset(®, 0, sizeof(reg)); + reg.eax.w[0] = 0x0025; + __intcall(0x22, ®, ®); + + memset(®, 0, sizeof(reg)); + 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; + + memset(®, 0, sizeof(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(&rm, 0, sizeof rm); + 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; + + memset(&rm, 0, sizeof rm); + /* 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... */ + + memset(&ireg, 0, sizeof ireg); + ireg.eax.w[0] = 0x4F05; + ireg.ebx.b[0] = wi->win_num; + ireg.edx.w[0] = win_pos >> wi->win_gshift; + + __intcall(0x10, &ireg, NULL); +} + +static void bios_vesacon_screencpy(size_t dst, const uint32_t * src, + size_t bytes, struct win_info *wi) +{ + size_t win_pos, win_off; + size_t win_size = wi->win_size; + size_t omask = win_size - 1; + char *win_base = wi->win_base; + const char *s = (const char *)src; + size_t l; + + while (bytes) { + win_off = dst & omask; + win_pos = dst & ~omask; + + if (__unlikely(win_pos != wi->win_pos)) + set_window_pos(wi, win_pos); + + l = min(bytes, win_size - win_off); + memcpy(win_base + win_off, s, l); + + bytes -= l; + s += l; + dst += l; + } +} + +static int bios_font_query(uint8_t **font) +{ + com32sys_t rm; + + /* Get BIOS 8x16 font */ + + memset(&rm, 0, sizeof rm); + + 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; + + memset(&ireg, 0, sizeof ireg); + 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 uint16_t *bios_free_mem; + +struct e820_entry { + uint64_t start; + uint64_t len; + uint32_t type; +}; + +static int bios_scan_memory(scan_memory_callback_t callback, void *data) +{ + static com32sys_t ireg; + com32sys_t oreg; + struct e820_entry *e820buf; + uint64_t start, len, maxlen; + int memfound = 0; + int rv; + addr_t dosmem; + const addr_t bios_data = 0x510; /* Amount to reserve for BIOS data */ + + /* Use INT 12h to get DOS memory */ + __intcall(0x12, &__com32_zero_regs, &oreg); + dosmem = oreg.eax.w[0] << 10; + if (dosmem < 32 * 1024 || dosmem > 640 * 1024) { + /* INT 12h reports nonsense... now what? */ + uint16_t ebda_seg = *(uint16_t *) 0x40e; + if (ebda_seg >= 0x8000 && ebda_seg < 0xa000) + dosmem = ebda_seg << 4; + else + dosmem = 640 * 1024; /* Hope for the best... */ + } + rv = callback(data, bios_data, dosmem - bios_data, SMT_FREE); + if (rv) + return rv; + + /* First try INT 15h AX=E820h */ + e820buf = lzalloc(sizeof *e820buf); + if (!e820buf) + return -1; + + memset(&ireg, 0, sizeof ireg); + ireg.eax.l = 0xe820; + ireg.edx.l = 0x534d4150; + ireg.ebx.l = 0; + ireg.ecx.l = sizeof(*e820buf); + ireg.es = SEG(e820buf); + ireg.edi.w[0] = OFFS(e820buf); + + do { + __intcall(0x15, &ireg, &oreg); + + if ((oreg.eflags.l & EFLAGS_CF) || + (oreg.eax.l != 0x534d4150) || (oreg.ecx.l < 20)) + break; + + start = e820buf->start; + len = e820buf->len; + + if (start < 0x100000000ULL) { + /* Don't rely on E820 being valid for low memory. Doing so + could mean stuff like overwriting the PXE stack even when + using "keeppxe", etc. */ + if (start < 0x100000ULL) { + if (len > 0x100000ULL - start) + len -= 0x100000ULL - start; + else + len = 0; + start = 0x100000ULL; + } + + maxlen = 0x100000000ULL - start; + if (len > maxlen) + len = maxlen; + + if (len) { + enum syslinux_memmap_types type; + + type = e820buf->type == 1 ? SMT_FREE : SMT_RESERVED; + rv = callback(data, (addr_t) start, (addr_t) len, type); + if (rv) + return rv; + memfound = 1; + } + } + + ireg.ebx.l = oreg.ebx.l; + } while (oreg.ebx.l); + + lfree(e820buf); + + if (memfound) + return 0; + + /* Next try INT 15h AX=E801h */ + memset(&ireg, 0, sizeof ireg); + ireg.eax.w[0] = 0xe801; + __intcall(0x15, &ireg, &oreg); + + if (!(oreg.eflags.l & EFLAGS_CF) && oreg.ecx.w[0]) { + rv = callback(data, (addr_t) 1 << 20, oreg.ecx.w[0] << 10, SMT_FREE); + if (rv) + return rv; + + if (oreg.edx.w[0]) { + rv = callback(data, (addr_t) 16 << 20, + oreg.edx.w[0] << 16, SMT_FREE); + if (rv) + return rv; + } + + return 0; + } + + /* Finally try INT 15h AH=88h */ + memset(&ireg, 0, sizeof ireg); + ireg.eax.w[0] = 0x8800; + __intcall(0x15, &ireg, &oreg); + if (!(oreg.eflags.l & EFLAGS_CF) && oreg.eax.w[0]) { + rv = callback(data, (addr_t) 1 << 20, oreg.ecx.w[0] << 10, SMT_FREE); + if (rv) + return rv; + } + + return 0; +} + +static struct syslinux_memscan bios_memscan = { + .func = bios_scan_memory, +}; + +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; + syslinux_memscan_add(&bios_memscan); + mem_init(); + + dprintf("%s%s", syslinux_banner, copyright_str); + + /* CPU-dependent initialization and related checks. */ + check_escapes(); + + /* + * Scan the DMI tables for interesting information. + */ + dmi_init(); +} + +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, +}; + +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, + .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..63394350 100644 --- a/core/comboot.inc +++ b/core/comboot.inc @@ -294,7 +294,8 @@ comboot_getchar: comboot_int28: sti cld - call do_idle + extern __idle + pm_call __idle iret ; @@ -342,52 +343,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 +399,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/common.inc b/core/common.inc index 65b4ab69..fd75dfe1 100644 --- a/core/common.inc +++ b/core/common.inc @@ -7,7 +7,6 @@ %include "pm.inc" ; Protected mode %include "bcopy32.inc" ; 32-bit bcopy %include "strcpy.inc" ; strcpy() -%include "idle.inc" ; Idle handling %include "adv.inc" ; Auxillary Data Vector %include "timer.inc" ; Timer handling diff --git a/core/conio.c b/core/conio.c index 3b8a103b..35ef0b4e 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" @@ -53,7 +54,7 @@ uint8_t ScrollAttribute = 0x07; /* Grey on white (normal text color) */ * * Returns 0 on success, or -1 on error. */ -__export int loadkeys(char *filename) +__export int loadkeys(const char *filename) { FILE *f; @@ -106,12 +107,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; @@ -123,7 +124,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]); } /* @@ -142,7 +148,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; @@ -161,8 +167,8 @@ __export int pollchar(void) /* Already-queued input? */ if (SerialTail == SerialHead) { /* LSR */ - data = !(inb(SerialPort + 5) & 1); - if (!data) { + data = inb(SerialPort + 5) & 1; + if (data) { /* MSR */ data = inb(SerialPort + 6); @@ -173,8 +179,7 @@ __export int pollchar(void) data = 1; else data = 0; - } else - data = 1; + } } else data = 1; sti(); @@ -183,6 +188,11 @@ __export int pollchar(void) return data; } +__export int pollchar(void) +{ + return firmware->i_ops->pollchar(); +} + void pm_pollchar(com32sys_t *regs) { if (pollchar()) @@ -191,12 +201,7 @@ void pm_pollchar(com32sys_t *regs) regs->eflags.l |= EFLAGS_ZF; } -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; @@ -204,7 +209,7 @@ __export char getchar(char *hi) memset(&ireg, 0, sizeof(ireg)); memset(&oreg, 0, sizeof(oreg)); while (1) { - call16(do_idle, &zero_regs, NULL); + __idle(); ireg.eax.b[1] = 0x11; /* Poll keyboard */ __intcall(0x16, &ireg, &oreg); @@ -263,6 +268,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 0483d865..492cc095 100644 --- a/core/elflink/load_env32.c +++ b/core/elflink/load_env32.c @@ -22,14 +22,13 @@ #include <sys/module.h> #include "common.h" -#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 +37,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), }; /* @@ -68,7 +64,7 @@ again: if (rv == EEXIST) { /* * If a COM32 module calls execute() we may need to - * unload all the modules loaded since ldlinux.c32, + * unload all the modules loaded since ldlinux.*, * and restart initialisation. This is especially * important for config files. * @@ -107,6 +103,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,15 +119,18 @@ 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) { + if (strlen(CurrentDirName) && !path_add(CurrentDirName)) { printf("Couldn't allocate memory for PATH\n"); goto out; } - 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); @@ -154,36 +154,22 @@ void load_env32(com32sys_t * regs __unused) /* * search_dirs() sets the current working directory if * it successfully opens the file. Add the directory - * in which we found ldlinux.c32 to PATH. + * in which we found ldlinux.* to PATH. */ if (!core_getcwd(path, sizeof(path))) goto out; - if (!strlen(PATH)) { - PATH = realloc(PATH, strlen(path) + 1); - if (!PATH) { - printf("Couldn't allocate memory for PATH\n"); - goto out; - } - - strcpy(PATH, path); - } else { - PATH = realloc(PATH, strlen(path) + strlen(PATH) + 2); - if (!PATH) { - printf("Couldn't allocate memory for PATH\n"); - goto out; - } - - strcat(PATH, ":"); - strcat(PATH, path); + if (!path_add(path)) { + printf("Couldn't allocate memory for PATH\n"); + goto out; } start_ldlinux(1, argv); } out: - free(PATH); - writestr("\nFailed to load ldlinux.c32"); + writestr("\nFailed to load "); + writestr(LDLINUX); } static const char *__cmdline; diff --git a/core/extern.inc b/core/extern.inc index 0d6a391b..673191cf 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..508f7059 100644 --- a/core/font.c +++ b/core/font.c @@ -1,7 +1,7 @@ -/* - * ----------------------------------------------------------------------- +/* ----------------------------------------------------------------------- * * * Copyright 1994-2008 H. Peter Anvin - All Rights Reserved + * Copyright 2013 Intel Corporation * * 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 @@ -9,8 +9,9 @@ * Boston MA 02111-1307, USA; either version 2 of the License, or * (at your option) any later version; incorporated herein by reference. * - * ----------------------------------------------------------------------- - * + * ----------------------------------------------------------------------- */ + +/* * * font.c * @@ -18,6 +19,8 @@ * */ +#include <syslinux/firmware.h> +#include <syslinux/video.h> #include <sys/io.h> #include <stdio.h> #include <fs.h> @@ -45,8 +48,6 @@ __export void loadfont(const char *filename) uint8_t height; } hdr; FILE *f; - char *p; - int i; f = fopen(filename, "r"); if (!f) @@ -70,13 +71,8 @@ __export void loadfont(const char *filename) /* Load the actual font into the font buffer. */ memset(fontbuf, 0, 256*32); - - p = fontbuf; - for (i = 0; i < 256; i++) { - if (_fread(p, hdr.height, f) != hdr.height) - goto fail; - p += 32; - } + if (_fread(fontbuf, 256*hdr.height, f) != 256*hdr.height) + goto fail; /* Loaded OK */ VGAFontSize = hdr.height; @@ -90,7 +86,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 +123,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 */ @@ -138,25 +134,29 @@ void use_font(void) __intcall(0x10, &ireg, &oreg); + memset(&ireg, 0, sizeof(ireg)); ireg.ebx.b[0] = 0; 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; uint8_t rows, cols; + memset(&ireg, 0, sizeof(ireg)); + rows = *vidrows; if (!rows) { /* @@ -175,6 +175,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 60defd3e..7d95d674 100644 --- a/core/fs/diskio.c +++ b/core/fs/diskio.c @@ -9,287 +9,7 @@ #include <ilog2.h> #include <minmax.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) { @@ -298,117 +18,14 @@ 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. */ -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; - dev.disk = disk_init(devno, cdrom, part_start, - bsHeads, bsSecPerTrack, MaxTransfer); - + dev.disk = firmware->disk_init(args); dev.cache_size = 128*1024; dev.cache_data = malloc(dev.cache_size); diff --git a/core/fs/diskio_bios.c b/core/fs/diskio_bios.c new file mode 100644 index 00000000..eba5a176 --- /dev/null +++ b/core/fs/diskio_bios.c @@ -0,0 +1,401 @@ +#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; + } + } + + memset(&ireg, 0, sizeof ireg); + /* 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; + + memset(&ireg, 0, sizeof ireg); + 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 1cb4b00a..8c1feeac 100644 --- a/core/fs/fs.c +++ b/core/fs/fs.c @@ -10,8 +10,6 @@ #include "fs.h" #include "cache.h" -__export char *PATH; - /* The currently mounted filesystem */ __export struct fs_info *this_fs = NULL; /* Root filesystem */ @@ -332,6 +330,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; @@ -383,22 +382,16 @@ __export void close_file(uint16_t handle) * 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; /* Default name for the root directory */ fs.cwd_name[0] = '/'; @@ -415,8 +408,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/bios.c b/core/fs/pxe/bios.c new file mode 100644 index 00000000..e3d9adc8 --- /dev/null +++ b/core/fs/pxe/bios.c @@ -0,0 +1,430 @@ +#include <syslinux/firmware.h> +#include <syslinux/memscan.h> +#include <core.h> +#include "pxe.h" +#include <net.h> +#include <minmax.h> +#include <bios.h> + +static uint16_t real_base_mem; /* Amount of DOS memory after freeing */ + +static bool has_gpxe; +static uint32_t gpxe_funcs; + +/* + * Validity check on possible !PXE structure in buf + * return 1 for success, 0 for failure. + * + */ +static int is_pxe(const void *buf) +{ + const struct pxe_t *pxe = buf; + const uint8_t *p = buf; + int i = pxe->structlength; + uint8_t sum = 0; + + if (i < sizeof(struct pxe_t) || + memcmp(pxe->signature, "!PXE", 4)) + return 0; + + while (i--) + sum += *p++; + + return sum == 0; +} + +/* + * Just like is_pxe, it checks PXENV+ structure + * + */ +static int is_pxenv(const void *buf) +{ + const struct pxenv_t *pxenv = buf; + const uint8_t *p = buf; + int i = pxenv->length; + uint8_t sum = 0; + + /* The pxeptr field isn't present in old versions */ + if (i < offsetof(struct pxenv_t, pxeptr) || + memcmp(pxenv->signature, "PXENV+", 6)) + return 0; + + while (i--) + sum += *p++; + + return sum == 0; +} + +/* + * memory_scan_for_pxe_struct: + * memory_scan_for_pxenv_struct: + * + * If none of the standard methods find the !PXE/PXENV+ structure, + * look for it by scanning memory. + * + * return the corresponding pxe structure if found, or NULL; + */ +static const void *memory_scan(uintptr_t start, int (*func)(const void *)) +{ + const char *ptr; + + /* Scan each 16 bytes of conventional memory before the VGA region */ + for (ptr = (const char *)start; ptr < (const char *)0xA0000; ptr += 16) { + if (func(ptr)) + return ptr; /* found it! */ + ptr += 16; + } + return NULL; +} + +static const struct pxe_t *memory_scan_for_pxe_struct(void) +{ + uint16_t start = bios_fbm(); /* Starting segment */ + + return memory_scan(start << 10, is_pxe); +} + +static const struct pxenv_t *memory_scan_for_pxenv_struct(void) +{ + return memory_scan(0x10000, is_pxenv); +} + +static int pxelinux_scan_memory(scan_memory_callback_t callback, void *data) +{ + addr_t start, size; + int rv = 0; + + if (KeepPXE) + return 0; + + /* + * If we are planning on calling unload_pxe() and unmapping the PXE + * region before we transfer control away from PXELINUX we can mark + * that region as SMT_TERMINAL to indicate that the region will + * become free at some point in the future. + */ + start = bios_fbm() << 10; + size = (real_base_mem - bios_fbm()) << 10; + dprintf("Marking PXE region 0x%x - 0x%x as SMT_TERMINAL\n", + start, start + size); + + callback(data, start, size, SMT_TERMINAL); + return rv; +} + +/* + * Find the !PXE structure; we search for the following, in order: + * + * a. !PXE structure as SS:[SP + 4] + * b. PXENV+ structure at [ES:BX] + * c. INT 1Ah AX=0x5650 -> PXENV+ + * d. Search memory for !PXE + * e. Search memory for PXENV+ + * + * If we find a PXENV+ structure, we try to find a !PXE structure from + * if if the API version is 2.1 or later + * + */ +int pxe_init(bool quiet) +{ + extern void pxe_int1a(void); + char plan = 'A'; + uint16_t seg, off; + uint16_t code_seg, code_len; + uint16_t data_seg, data_len; + const char *base = GET_PTR(InitStack); + com32sys_t regs; + const char *type; + const struct pxenv_t *pxenv; + const struct pxe_t *pxe; + + /* Assume API version 2.1 */ + APIVer = 0x201; + + /* Plan A: !PXE structure as SS:[SP + 4] */ + off = *(const uint16_t *)(base + 48); + seg = *(const uint16_t *)(base + 50); + pxe = MK_PTR(seg, off); + if (is_pxe(pxe)) + goto have_pxe; + + /* Plan B: PXENV+ structure at [ES:BX] */ + plan++; + off = *(const uint16_t *)(base + 24); /* Original BX */ + seg = *(const uint16_t *)(base + 4); /* Original ES */ + pxenv = MK_PTR(seg, off); + if (is_pxenv(pxenv)) + goto have_pxenv; + + /* Plan C: PXENV+ structure via INT 1Ah AX=5650h */ + plan++; + memset(®s, 0, sizeof regs); + regs.eax.w[0] = 0x5650; + call16(pxe_int1a, ®s, ®s); + if (!(regs.eflags.l & EFLAGS_CF) && (regs.eax.w[0] == 0x564e)) { + pxenv = MK_PTR(regs.es, regs.ebx.w[0]); + if (is_pxenv(pxenv)) + goto have_pxenv; + } + + /* Plan D: !PXE memory scan */ + plan++; + if ((pxe = memory_scan_for_pxe_struct())) + goto have_pxe; + + /* Plan E: PXENV+ memory scan */ + plan++; + if ((pxenv = memory_scan_for_pxenv_struct())) + goto have_pxenv; + + /* Found nothing at all !! */ + if (!quiet) + ddprintf("No !PXE or PXENV+ API found; we're dead...\n"); + return -1; + + have_pxenv: + APIVer = pxenv->version; + if (!quiet) + ddprintf("Found PXENV+ structure\nPXE API version is %04x\n", APIVer); + + /* if the API version number is 0x0201 or higher, use the !PXE structure */ + if (APIVer >= 0x201) { + if (pxenv->length >= sizeof(struct pxenv_t)) { + pxe = GET_PTR(pxenv->pxeptr); + if (is_pxe(pxe)) + goto have_pxe; + /* + * Nope, !PXE structure missing despite API 2.1+, or at least + * the pointer is missing. Do a last-ditch attempt to find it + */ + if ((pxe = memory_scan_for_pxe_struct())) + goto have_pxe; + } + APIVer = 0x200; /* PXENV+ only, assume version 2.00 */ + } + + /* Otherwise, no dice, use PXENV+ structure */ + data_len = pxenv->undidatasize; + data_seg = pxenv->undidataseg; + code_len = pxenv->undicodesize; + code_seg = pxenv->undicodeseg; + PXEEntry = pxenv->rmentry; + type = "PXENV+"; + + goto have_entrypoint; + + have_pxe: + data_len = pxe->seg[PXE_Seg_UNDIData].size; + data_seg = pxe->seg[PXE_Seg_UNDIData].sel; + code_len = pxe->seg[PXE_Seg_UNDICode].size; + code_seg = pxe->seg[PXE_Seg_UNDICode].sel; + PXEEntry = pxe->entrypointsp; + type = "!PXE"; + + have_entrypoint: + if (!quiet) { + ddprintf("%s entry point found (we hope) at %04X:%04X via plan %c\n", + type, PXEEntry.seg, PXEEntry.offs, plan); + ddprintf("UNDI code segment at %04X len %04X\n", code_seg, code_len); + ddprintf("UNDI data segment at %04X len %04X\n", data_seg, data_len); + } + + syslinux_memscan_new(pxelinux_scan_memory); + + code_seg = code_seg + ((code_len + 15) >> 4); + data_seg = data_seg + ((data_len + 15) >> 4); + + real_base_mem = max(code_seg, data_seg) >> 6; /* Convert to kilobytes */ + + probe_undi(); + + return 0; +} + +/* + * See if we have gPXE + */ +void gpxe_init(void) +{ + int err; + static __lowmem struct s_PXENV_FILE_API_CHECK api_check; + + if (APIVer >= 0x201) { + api_check.Size = sizeof api_check; + api_check.Magic = 0x91d447b2; + err = pxe_call(PXENV_FILE_API_CHECK, &api_check); + if (!err && api_check.Magic == 0xe9c17b20) + gpxe_funcs = api_check.APIMask; + } + + /* Necessary functions for us to use the gPXE file API */ + has_gpxe = (~gpxe_funcs & 0x4b) == 0; +} + + +/** + * Get a DHCP packet from the PXE stack into a lowmem buffer + * + * @param: type, packet type + * @return: buffer size + * + */ +static int pxe_get_cached_info(int type, void *buf, size_t bufsiz) +{ + int err; + static __lowmem struct s_PXENV_GET_CACHED_INFO get_cached_info; + ddprintf(" %02x", type); + + memset(&get_cached_info, 0, sizeof get_cached_info); + get_cached_info.PacketType = type; + get_cached_info.BufferSize = bufsiz; + get_cached_info.Buffer = FAR_PTR(buf); + err = pxe_call(PXENV_GET_CACHED_INFO, &get_cached_info); + if (err) { + ddprintf("PXE API call failed, error %04x\n", err); + kaboom(); + } + + return get_cached_info.BufferSize; +} + +/* + * This function unloads the PXE and UNDI stacks and + * unclaims the memory. + */ +__export void unload_pxe(uint16_t flags) +{ + /* PXE unload sequences */ + /* + * iPXE does: + * UNDI_SHUTDOWN, UNDI_CLEANUP, STOP_UNDI + * Older Syslinux did: + * UDP_CLOSE, UNDI_SHUTDOWN, UNLOAD_STACK, STOP_UNDI/UNDI_CLEANUP + */ + static const uint8_t new_api_unload[] = { + PXENV_UNDI_SHUTDOWN, PXENV_UNLOAD_STACK, PXENV_STOP_UNDI, 0 + }; + static const uint8_t old_api_unload[] = { + PXENV_UNDI_SHUTDOWN, PXENV_UNLOAD_STACK, PXENV_UNDI_CLEANUP, 0 + }; + + unsigned int api; + const uint8_t *api_ptr; + int err; + size_t int_addr; + static __lowmem union { + struct s_PXENV_UNDI_SHUTDOWN undi_shutdown; + struct s_PXENV_UNLOAD_STACK unload_stack; + struct s_PXENV_STOP_UNDI stop_undi; + struct s_PXENV_UNDI_CLEANUP undi_cleanup; + uint16_t Status; /* All calls have this as the first member */ + } unload_call; + + dprintf("Called unload_pxe()...\n"); + dprintf("FBM before unload = %d\n", bios_fbm()); + + err = reset_pxe(); + + dprintf("FBM after reset_pxe = %d, err = %d\n", bios_fbm(), err); + + /* If we want to keep PXE around, we still need to reset it */ + if (flags || err) + return; + + dprintf("APIVer = %04x\n", APIVer); + + api_ptr = APIVer >= 0x0200 ? new_api_unload : old_api_unload; + while((api = *api_ptr++)) { + dprintf("PXE call %04x\n", api); + memset(&unload_call, 0, sizeof unload_call); + err = pxe_call(api, &unload_call); + if (err || unload_call.Status != PXENV_STATUS_SUCCESS) { + ddprintf("PXE unload API call %04x failed: 0x%x\n", + api, unload_call.Status); + goto cant_free; + } + } + + api = 0xff00; + if (real_base_mem <= bios_fbm()) { /* Sanity check */ + dprintf("FBM %d < real_base_mem %d\n", bios_fbm(), real_base_mem); + goto cant_free; + } + api++; + + /* Check that PXE actually unhooked the INT 0x1A chain */ + int_addr = (size_t)GET_PTR(*(far_ptr_t *)(4 * 0x1a)); + int_addr >>= 10; + if (int_addr >= real_base_mem || int_addr < bios_fbm()) { + set_bios_fbm(real_base_mem); + dprintf("FBM after unload_pxe = %d\n", bios_fbm()); + return; + } + + dprintf("Can't free FBM, real_base_mem = %d, " + "FBM = %d, INT 1A = %08x (%d)\n", + real_base_mem, bios_fbm(), + *(uint32_t *)(4 * 0x1a), int_addr); + +cant_free: + ddprintf("Failed to free base memory error %04x-%08x (%d/%dK)\n", + api, *(uint32_t *)(4 * 0x1a), bios_fbm(), real_base_mem); + return; +} + +void net_parse_dhcp(void) +{ + int pkt_len; + struct bootp_t *bp; + const size_t dhcp_max_packet = 4096; + + bp = lmalloc(dhcp_max_packet); + if (!bp) { + ddprintf("Out of low memory\n"); + kaboom(); + } + + *LocalDomain = 0; /* No LocalDomain received */ + + /* + * Get the DHCP client identifiers (query info 1) + */ + ddprintf("Getting cached packet "); + pkt_len = pxe_get_cached_info(1, bp, dhcp_max_packet); + parse_dhcp(bp, pkt_len); + /* + * We don't use flags from the request packet, so + * this is a good time to initialize DHCPMagic... + * Initialize it to 1 meaning we will accept options found; + * in earlier versions of PXELINUX bit 0 was used to indicate + * we have found option 208 with the appropriate magic number; + * we no longer require that, but MAY want to re-introduce + * it in the future for vendor encapsulated options. + */ + *(char *)&DHCPMagic = 1; + + /* + * Get the BOOTP/DHCP packet that brought us file (and an IP + * address). This lives in the DHCPACK packet (query info 2) + */ + pkt_len = pxe_get_cached_info(2, bp, dhcp_max_packet); + parse_dhcp(bp, pkt_len); + /* + * Save away MAC address (assume this is in query info 2. If this + * turns out to be problematic it might be better getting it from + * the query info 1 packet + */ + MAC_len = bp->hardlen > 16 ? 0 : bp->hardlen; + MAC_type = bp->hardware; + memcpy(MAC, bp->macaddr, MAC_len); + + /* + * Get the boot file and other info. This lives in the CACHED_REPLY + * packet (query info 3) + */ + pkt_len = pxe_get_cached_info(3, bp, dhcp_max_packet); + parse_dhcp(bp, pkt_len); + ddprintf("\n"); + + lfree(bp); +} diff --git a/core/fs/pxe/core.c b/core/fs/pxe/core.c index e330ba82..a43ac465 100644 --- a/core/fs/pxe/core.c +++ b/core/fs/pxe/core.c @@ -6,6 +6,8 @@ #include <net.h> #include "pxe.h" +#include <dprintf.h> + const struct url_scheme url_schemes[] = { { "tftp", tftp_open, 0 }, { "http", http_open, O_DIRECTORY }, @@ -17,36 +19,22 @@ const struct url_scheme url_schemes[] = { * Open a socket * * @param:socket, the socket to open - * @param:proto, the protocol of the new connection * * @out: error code, 0 on success, -1 on failure */ -int net_core_open(struct pxe_pvt_inode *socket, enum net_core_proto proto) +int core_udp_open(struct pxe_pvt_inode *socket) { struct net_private_lwip *priv = &socket->net.lwip; - enum netconn_type type; int err; - switch (proto) { - case NET_CORE_TCP: - type = NETCONN_TCP; - break; - case NET_CORE_UDP: - type = NETCONN_UDP; - break; - default: - type = NETCONN_INVALID; - break; - } - - priv->conn = netconn_new(type); + priv->conn = netconn_new(NETCONN_UDP); if (!priv->conn) return -1; priv->conn->recv_timeout = 15; /* A 15 ms recv timeout... */ err = netconn_bind(priv->conn, NULL, 0); if (err) { - printf("netconn_bind error %d\n", err); + ddprintf("netconn_bind error %d\n", err); return -1; } @@ -58,7 +46,7 @@ int net_core_open(struct pxe_pvt_inode *socket, enum net_core_proto proto) * * @param:socket, the socket to open */ -void net_core_close(struct pxe_pvt_inode *socket) +void core_udp_close(struct pxe_pvt_inode *socket) { struct net_private_lwip *priv = &socket->net.lwip; @@ -75,12 +63,13 @@ void net_core_close(struct pxe_pvt_inode *socket) * @param:ip, the ip address * @param:port, the port number, host-byte order */ -void net_core_connect(struct pxe_pvt_inode *socket, uint32_t ip, +void core_udp_connect(struct pxe_pvt_inode *socket, uint32_t ip, uint16_t port) { struct net_private_lwip *priv = &socket->net.lwip; struct ip_addr addr; + dprintf("net_core_connect: %08X %04X\n", ntohl(ip), port); addr.addr = ip; netconn_connect(priv->conn, &addr, port); } @@ -90,7 +79,7 @@ void net_core_connect(struct pxe_pvt_inode *socket, uint32_t ip, * * @param:socket, the open socket */ -void net_core_disconnect(struct pxe_pvt_inode *socket) +void core_udp_disconnect(struct pxe_pvt_inode *socket) { struct net_private_lwip *priv = &socket->net.lwip; netconn_disconnect(priv->conn); @@ -106,7 +95,7 @@ void net_core_disconnect(struct pxe_pvt_inode *socket) * @out: src_ip, ip address of the data source * @out: src_port, port number of the data source, host-byte order */ -int net_core_recv(struct pxe_pvt_inode *socket, void *buf, uint16_t *buf_len, +int core_udp_recv(struct pxe_pvt_inode *socket, void *buf, uint16_t *buf_len, uint32_t *src_ip, uint16_t *src_port) { struct net_private_lwip *priv = &socket->net.lwip; @@ -143,7 +132,7 @@ int net_core_recv(struct pxe_pvt_inode *socket, void *buf, uint16_t *buf_len, * @param:data, data buffer to send * @param:len, size of data bufer */ -void net_core_send(struct pxe_pvt_inode *socket, const void *data, size_t len) +void core_udp_send(struct pxe_pvt_inode *socket, const void *data, size_t len) { struct netconn *conn = socket->net.lwip.conn; struct netbuf *nbuf; @@ -152,13 +141,13 @@ void net_core_send(struct pxe_pvt_inode *socket, const void *data, size_t len) nbuf = netbuf_new(); if (!nbuf) { - printf("netbuf allocation error\n"); + ddprintf("netbuf allocation error\n"); return; } pbuf = netbuf_alloc(nbuf, len); if (!pbuf) { - printf("pbuf allocation error\n"); + ddprintf("pbuf allocation error\n"); goto out; } @@ -166,7 +155,52 @@ void net_core_send(struct pxe_pvt_inode *socket, const void *data, size_t len) err = netconn_send(conn, nbuf); if (err) { - printf("netconn_send error %d\n", err); + ddprintf("netconn_send error %d\n", err); + goto out; + } + +out: + netbuf_delete(nbuf); +} + + /** + * Send a UDP packet to a destination + * + * @param:socket, the open socket + * @param:data, data buffer to send + * @param:len, size of data bufer + * @param:ip, the ip address + * @param:port, the port number, host-byte order + */ +void core_udp_sendto(struct pxe_pvt_inode *socket, const void *data, + size_t len, uint32_t ip, uint16_t port) +{ + struct netconn *conn = socket->net.lwip.conn; + struct ip_addr addr; + struct netbuf *nbuf; + void *pbuf; + int err; + + nbuf = netbuf_new(); + if (!nbuf) { + ddprintf("netbuf allocation error\n"); + return; + } + + pbuf = netbuf_alloc(nbuf, len); + if (!pbuf) { + ddprintf("pbuf allocation error\n"); + goto out; + } + + memcpy(pbuf, data, len); + + dprintf("core_udp_sendto: %08X %04X\n", ntohl(ip), port); + addr.addr = ip; + + err = netconn_sendto(conn, nbuf, &addr, port); + if (err) { + ddprintf("netconn_sendto error %d\n", err); goto out; } @@ -190,7 +224,7 @@ void net_core_init(void) /* Start up the undi driver for lwip */ err = undiif_start(IPInfo.myip, IPInfo.netmask, IPInfo.gateway); if (err) { - printf("undiif driver failed to start: %d\n", err); + ddprintf("undiif driver failed to start: %d\n", err); kaboom(); } @@ -206,9 +240,105 @@ void probe_undi(void) pxe_call(PXENV_UNDI_GET_INFORMATION, &pxe_undi_info); pxe_call(PXENV_UNDI_GET_IFACE_INFO, &pxe_undi_iface); - printf("UNDI: baseio %04x int %d MTU %d type %d \"%s\" flags 0x%x\n", + ddprintf("UNDI: baseio %04x int %d MTU %d type %d \"%s\" flags 0x%x\n", pxe_undi_info.BaseIo, pxe_undi_info.IntNumber, pxe_undi_info.MaxTranUnit, pxe_undi_info.HwType, pxe_undi_iface.IfaceType, pxe_undi_iface.ServiceFlags); } +int core_tcp_open(struct pxe_pvt_inode *socket) +{ + socket->net.lwip.conn = netconn_new(NETCONN_TCP); + if (!socket->net.lwip.conn) + return -1; + + return 0; +} +int core_tcp_connect(struct pxe_pvt_inode *socket, uint32_t ip, uint16_t port) +{ + struct ip_addr addr; + err_t err; + + addr.addr = ip; + err = netconn_connect(socket->net.lwip.conn, &addr, port); + if (err) { + printf("netconn_connect error %d\n", err); + return -1; + } + + return 0; +} + +int core_tcp_write(struct pxe_pvt_inode *socket, const void *data, size_t len, + bool copy) +{ + err_t err; + u8_t flags = copy ? NETCONN_COPY : NETCONN_NOCOPY; + + err = netconn_write(socket->net.lwip.conn, data, len, flags); + if (err) { + printf("netconn_write failed: %d\n", err); + return -1; + } + + return 0; +} + +void core_tcp_close_file(struct inode *inode) +{ + struct pxe_pvt_inode *socket = PVT(inode); + + if (socket->net.lwip.conn) { + netconn_delete(socket->net.lwip.conn); + socket->net.lwip.conn = NULL; + } + if (socket->net.lwip.buf) { + netbuf_delete(socket->net.lwip.buf); + socket->net.lwip.buf = NULL; + } +} + +bool core_tcp_is_connected(struct pxe_pvt_inode *socket) +{ + if (socket->net.lwip.conn) + return true; + + return false; +} + +void core_tcp_fill_buffer(struct inode *inode) +{ + struct pxe_pvt_inode *socket = PVT(inode); + void *data; + u16_t len; + err_t err; + + /* Clean up or advance an inuse netbuf */ + if (socket->net.lwip.buf) { + if (netbuf_next(socket->net.lwip.buf) < 0) { + netbuf_delete(socket->net.lwip.buf); + socket->net.lwip.buf = NULL; + } + } + /* If needed get a new netbuf */ + if (!socket->net.lwip.buf) { + err = netconn_recv(socket->net.lwip.conn, &(socket->net.lwip.buf)); + if (!socket->net.lwip.buf || err) { + socket->tftp_goteof = 1; + if (inode->size == -1) + inode->size = socket->tftp_filepos; + socket->ops->close(inode); + return; + } + } + /* Report the current fragment of the netbuf */ + err = netbuf_data(socket->net.lwip.buf, &data, &len); + if (err) { + printf("netbuf_data err: %d\n", err); + kaboom(); + } + socket->tftp_dataptr = data; + socket->tftp_filepos += len; + socket->tftp_bytesleft = len; + return; +} diff --git a/core/fs/pxe/dhcp_option.c b/core/fs/pxe/dhcp_option.c index 75827ff7..3517161a 100644 --- a/core/fs/pxe/dhcp_option.c +++ b/core/fs/pxe/dhcp_option.c @@ -229,7 +229,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/ftp.c b/core/fs/pxe/ftp.c index c2d155ae..4327e45c 100644 --- a/core/fs/pxe/ftp.c +++ b/core/fs/pxe/ftp.c @@ -26,6 +26,7 @@ #include "pxe.h" #include "thread.h" #include "url.h" +#include "net.h" static int ftp_cmd_response(struct inode *inode, const char *cmd, const char *cmd_arg, @@ -37,11 +38,11 @@ static int ftp_cmd_response(struct inode *inode, const char *cmd, int pb, pn; bool ps; bool first_line, done; - err_t err; char cmd_buf[4096]; int cmd_len; const char *p; char *q; + int err; if (cmd) { cmd_len = strlcpy(cmd_buf, cmd, sizeof cmd_buf); @@ -69,7 +70,7 @@ static int ftp_cmd_response(struct inode *inode, const char *cmd, *q++ = '\n'; cmd_len += 2; - err = netconn_write(socket->net.lwip.conn, cmd_buf, cmd_len, NETCONN_COPY); + err = core_tcp_write(socket, cmd_buf, cmd_len, true); if (err) return -1; } @@ -152,11 +153,11 @@ static void ftp_free(struct inode *inode) struct pxe_pvt_inode *socket = PVT(inode); if (socket->ctl) { - tcp_close_file(socket->ctl); + core_tcp_close_file(socket->ctl); free_socket(socket->ctl); socket->ctl = NULL; } - tcp_close_file(inode); + core_tcp_close_file(inode); } static void ftp_close_file(struct inode *inode) @@ -166,7 +167,7 @@ static void ftp_close_file(struct inode *inode) int resp; ctlsock = socket->ctl ? PVT(socket->ctl) : NULL; - if (ctlsock->net.lwip.conn) { + if (core_tcp_is_connected(ctlsock)) { resp = ftp_cmd_response(socket->ctl, "QUIT", NULL, NULL, NULL); while (resp == 226) { resp = ftp_cmd_response(socket->ctl, NULL, NULL, NULL, NULL); @@ -176,7 +177,7 @@ static void ftp_close_file(struct inode *inode) } static const struct pxe_conn_ops ftp_conn_ops = { - .fill_buffer = tcp_fill_buffer, + .fill_buffer = core_tcp_fill_buffer, .close = ftp_close_file, .readdir = ftp_readdir, }; @@ -186,7 +187,6 @@ void ftp_open(struct url_info *url, int flags, struct inode *inode, { struct pxe_pvt_inode *socket = PVT(inode); struct pxe_pvt_inode *ctlsock; - struct ip_addr addr; uint8_t pasv_data[6]; int pasv_bytes; int resp; @@ -209,11 +209,9 @@ void ftp_open(struct url_info *url, int flags, struct inode *inode, return; ctlsock = PVT(socket->ctl); ctlsock->ops = &tcp_conn_ops; /* The control connection is just TCP */ - ctlsock->net.lwip.conn = netconn_new(NETCONN_TCP); - if (!ctlsock->net.lwip.conn) + if (core_tcp_open(ctlsock)) goto err_free; - addr.addr = url->ip; - err = netconn_connect(ctlsock->net.lwip.conn, &addr, url->port); + err = core_tcp_connect(ctlsock, url->ip, url->port); if (err) goto err_delete; @@ -248,11 +246,11 @@ void ftp_open(struct url_info *url, int flags, struct inode *inode, if (resp != 227 || pasv_bytes != 6) goto err_disconnect; - socket->net.lwip.conn = netconn_new(NETCONN_TCP); - if (!socket->net.lwip.conn) + err = core_tcp_open(socket); + if (err) goto err_disconnect; - err = netconn_connect(socket->net.lwip.conn, (struct ip_addr *)&pasv_data[0], - ntohs(*(uint16_t *)&pasv_data[4])); + err = core_tcp_connect(socket, *(uint32_t*)&pasv_data[0], + ntohs(*(uint16_t *)&pasv_data[4])); if (err) goto err_disconnect; @@ -266,15 +264,10 @@ void ftp_open(struct url_info *url, int flags, struct inode *inode, return; /* Sucess! */ err_disconnect: - if (ctlsock->net.lwip.conn) - netconn_write(ctlsock->net.lwip.conn, "QUIT\r\n", 6, NETCONN_NOCOPY); - if (socket->net.lwip.conn) - netconn_delete(socket->net.lwip.conn); - if (ctlsock->net.lwip.buf) - netbuf_delete(ctlsock->net.lwip.buf); + core_tcp_write(ctlsock, "QUIT\r\n", 6, false); + core_tcp_close_file(inode); err_delete: - if (ctlsock->net.lwip.conn) - netconn_delete(ctlsock->net.lwip.conn); + core_tcp_close_file(socket->ctl); err_free: free_socket(socket->ctl); } diff --git a/core/fs/pxe/http.c b/core/fs/pxe/http.c index 94f1059a..0768c10e 100644 --- a/core/fs/pxe/http.c +++ b/core/fs/pxe/http.c @@ -2,8 +2,9 @@ #include <ctype.h> #include <lwip/api.h> #include "pxe.h" -#include "../../../version.h" +#include "version.h" #include "url.h" +#include "net.h" #define HTTP_PORT 80 @@ -120,7 +121,7 @@ static size_t http_do_bake_cookies(char *q) return n; } -void http_bake_cookies(void) +__export void http_bake_cookies(void) { if (cookie_buf) free(cookie_buf); @@ -146,8 +147,8 @@ void http_bake_cookies(void) } static const struct pxe_conn_ops http_conn_ops = { - .fill_buffer = tcp_fill_buffer, - .close = tcp_close_file, + .fill_buffer = core_tcp_fill_buffer, + .close = core_tcp_close_file, .readdir = http_readdir, }; @@ -160,7 +161,6 @@ void http_open(struct url_info *url, int flags, struct inode *inode, char field_name[20]; char field_value[1024]; size_t field_name_len, field_value_len; - err_t err; enum state { st_httpver, st_stcode, @@ -172,12 +172,12 @@ void http_open(struct url_info *url, int flags, struct inode *inode, st_skip_fieldvalue, st_eoh, } state; - struct ip_addr addr; static char location[FILENAME_MAX]; uint32_t content_length; /* same as inode->size */ size_t response_size; int status; int pos; + int err; (void)flags; @@ -191,21 +191,16 @@ void http_open(struct url_info *url, int flags, struct inode *inode, inode->size = content_length = -1; /* Start the http connection */ - socket->net.lwip.conn = netconn_new(NETCONN_TCP); - if (!socket->net.lwip.conn) { - printf("netconn_new failed\n"); + err = core_tcp_open(socket); + if (err) return; - } - addr.addr = url->ip; if (!url->port) url->port = HTTP_PORT; - err = netconn_connect(socket->net.lwip.conn, &addr, url->port); - if (err) { - printf("netconn_connect error %d\n", err); + err = core_tcp_connect(socket, url->ip, url->port); + if (err) goto fail; - } strcpy(header_buf, "GET /"); header_bytes = 5; @@ -225,12 +220,9 @@ void http_open(struct url_info *url, int flags, struct inode *inode, if (header_bytes >= header_len) goto fail; /* Buffer overflow */ - err = netconn_write(socket->net.lwip.conn, header_buf, - header_bytes, NETCONN_NOCOPY); - if (err) { - printf("netconn_write error %d\n", err); + err = core_tcp_write(socket, header_buf, header_bytes, false); + if (err) goto fail; - } /* Parse the HTTP header */ state = st_httpver; @@ -395,6 +387,6 @@ void http_open(struct url_info *url, int flags, struct inode *inode, return; fail: inode->size = 0; - tcp_close_file(inode); + core_tcp_close_file(inode); return; } diff --git a/core/fs/pxe/isr.c b/core/fs/pxe/isr.c index 069fefd5..d0a0bf90 100644 --- a/core/fs/pxe/isr.c +++ b/core/fs/pxe/isr.c @@ -18,6 +18,14 @@ static DECLARE_INIT_SEMAPHORE(pxe_receive_thread_sem, 0); static DECLARE_INIT_SEMAPHORE(pxe_poll_thread_sem, 0); static struct thread *pxe_thread, *poll_thread; +#ifndef PXE_POLL_FORCE +# define PXE_POLL_FORCE 0 +#endif + +#ifndef PXE_POLL_BY_MODEL +# define PXE_POLL_BY_MODEL 1 +#endif + /* * Note: this *must* be called with interrupts enabled. */ @@ -73,7 +81,7 @@ static bool install_irq_vector(uint8_t irq, void (*isr)(void), far_ptr_t *old) if (!ok) *entry = *old; /* Restore the old vector */ - printf("UNDI: IRQ %d(0x%02x): %04x:%04x -> %04x:%04x\n", irq, vec, + ddprintf("UNDI: IRQ %d(0x%02x): %04x:%04x -> %04x:%04x\n", irq, vec, old->seg, old->offs, entry->seg, entry->offs); return ok; @@ -251,8 +259,20 @@ void pxe_start_isr(void) poll_thread = start_thread("pxe poll", 4096, POLL_THREAD_PRIORITY, pxe_poll_thread, NULL); - if (!irq || !(pxe_undi_iface.ServiceFlags & PXE_UNDI_IFACE_FLAG_IRQ)) + if (!irq || !(pxe_undi_iface.ServiceFlags & PXE_UNDI_IFACE_FLAG_IRQ)) { asm volatile("orb $1,%0" : "+m" (pxe_need_poll)); + dprintf("pxe_start_isr: forcing pxe_need_poll\n"); + } else if (PXE_POLL_BY_MODEL) { + dprintf("pxe_start_isr: trying poll by model\n"); + int hwad = ((int)MAC[0] << 16) + ((int)MAC[1] << 8) + MAC[2]; + dprintf("pxe_start_isr: got %06x %04x\n", hwad, pxe_undi_iface.ServiceFlags); + if (hwad == 0x000023ae) { + if (pxe_undi_iface.ServiceFlags == 0xdc1b) { + asm volatile("orb $1,%0" : "+m" (pxe_need_poll)); + dprintf("pxe_start_isr: forcing pxe_need_poll by model\n"); + } + } + } } int reset_pxe(void) diff --git a/core/fs/pxe/pxe.c b/core/fs/pxe/pxe.c index 3f68e969..4de4dbfb 100644 --- a/core/fs/pxe/pxe.c +++ b/core/fs/pxe/pxe.c @@ -2,9 +2,7 @@ #include <stdio.h> #include <string.h> #include <core.h> -#include <bios.h> #include <fs.h> -#include <minmax.h> #include <fcntl.h> #include <sys/cpu.h> #include "pxe.h" @@ -16,8 +14,6 @@ __lowmem t_PXENV_UNDI_GET_INFORMATION pxe_undi_info; __lowmem t_PXENV_UNDI_GET_IFACE_INFO pxe_undi_iface; -static uint16_t real_base_mem; /* Amount of DOS memory after freeing */ - uint8_t MAC[MAC_MAX]; /* Actual MAC address */ uint8_t MAC_len; /* MAC address len */ uint8_t MAC_type; /* MAC address type */ @@ -25,8 +21,6 @@ uint8_t MAC_type; /* MAC address type */ char boot_file[256]; /* From DHCP */ char path_prefix[256]; /* From DHCP */ -static bool has_gpxe; -static uint32_t gpxe_funcs; bool have_uuid = false; /* @@ -131,32 +125,6 @@ __export int pxe_call(int opcode, void *data) return regs.eflags.l & EFLAGS_CF; /* CF SET if fail */ } -/** - * Get a DHCP packet from the PXE stack into a lowmem buffer - * - * @param: type, packet type - * @return: buffer size - * - */ -static int pxe_get_cached_info(int type, void *buf, size_t bufsiz) -{ - int err; - static __lowmem struct s_PXENV_GET_CACHED_INFO get_cached_info; - printf(" %02x", type); - - memset(&get_cached_info, 0, sizeof get_cached_info); - get_cached_info.PacketType = type; - get_cached_info.BufferSize = bufsiz; - get_cached_info.Buffer = FAR_PTR(buf); - err = pxe_call(PXENV_GET_CACHED_INFO, &get_cached_info); - if (err) { - printf("PXE API call failed, error %04x\n", err); - kaboom(); - } - - return get_cached_info.BufferSize; -} - /* * mangle a filename pointed to by _src_ into a buffer pointed * to by _dst_; ends on encountering any whitespace. @@ -403,7 +371,7 @@ static void get_prefix(void) *(p + 2) = 0; /* Zero-terminate after delimiter */ } - printf("TFTP prefix: %s\n", path_prefix); + ddprintf("TFTP prefix: %s\n", path_prefix); if (url_type(path_prefix) == URL_SUFFIX) { /* @@ -508,7 +476,7 @@ static int pxe_open_config(struct com32_filedata *filedata) if (open_file(ConfigName, O_RDONLY, filedata) >= 0) return 0; - printf("%-68s\n", "Unable to locate configuration file"); + ddprintf("%-68s\n", "Unable to locate configuration file"); kaboom(); } @@ -564,233 +532,7 @@ static void ip_init(void) gendotquad(dot_quad_buf, ip); ip = ntohl(ip); - printf("My IP address seems to be %08X %s\n", ip, dot_quad_buf); -} - -/* - * Validity check on possible !PXE structure in buf - * return 1 for success, 0 for failure. - * - */ -static int is_pxe(const void *buf) -{ - const struct pxe_t *pxe = buf; - const uint8_t *p = buf; - int i = pxe->structlength; - uint8_t sum = 0; - - if (i < sizeof(struct pxe_t) || - memcmp(pxe->signature, "!PXE", 4)) - return 0; - - while (i--) - sum += *p++; - - return sum == 0; -} - -/* - * Just like is_pxe, it checks PXENV+ structure - * - */ -static int is_pxenv(const void *buf) -{ - const struct pxenv_t *pxenv = buf; - const uint8_t *p = buf; - int i = pxenv->length; - uint8_t sum = 0; - - /* The pxeptr field isn't present in old versions */ - if (i < offsetof(struct pxenv_t, pxeptr) || - memcmp(pxenv->signature, "PXENV+", 6)) - return 0; - - while (i--) - sum += *p++; - - return sum == 0; -} - - - -/* - * memory_scan_for_pxe_struct: - * memory_scan_for_pxenv_struct: - * - * If none of the standard methods find the !PXE/PXENV+ structure, - * look for it by scanning memory. - * - * return the corresponding pxe structure if found, or NULL; - */ -static const void *memory_scan(uintptr_t start, int (*func)(const void *)) -{ - const char *ptr; - - /* Scan each 16 bytes of conventional memory before the VGA region */ - for (ptr = (const char *)start; ptr < (const char *)0xA0000; ptr += 16) { - if (func(ptr)) - return ptr; /* found it! */ - ptr += 16; - } - return NULL; -} - -static const struct pxe_t *memory_scan_for_pxe_struct(void) -{ - uint16_t start = bios_fbm(); /* Starting segment */ - - return memory_scan(start << 10, is_pxe); -} - -static const struct pxenv_t *memory_scan_for_pxenv_struct(void) -{ - return memory_scan(0x10000, is_pxenv); -} - -/* - * Find the !PXE structure; we search for the following, in order: - * - * a. !PXE structure as SS:[SP + 4] - * b. PXENV+ structure at [ES:BX] - * c. INT 1Ah AX=0x5650 -> PXENV+ - * d. Search memory for !PXE - * e. Search memory for PXENV+ - * - * If we find a PXENV+ structure, we try to find a !PXE structure from - * if if the API version is 2.1 or later - * - */ -static int pxe_init(bool quiet) -{ - extern void pxe_int1a(void); - char plan = 'A'; - uint16_t seg, off; - uint16_t code_seg, code_len; - uint16_t data_seg, data_len; - const char *base = GET_PTR(InitStack); - com32sys_t regs; - const char *type; - const struct pxenv_t *pxenv; - const struct pxe_t *pxe; - - /* Assume API version 2.1 */ - APIVer = 0x201; - - /* Plan A: !PXE structure as SS:[SP + 4] */ - off = *(const uint16_t *)(base + 48); - seg = *(const uint16_t *)(base + 50); - pxe = MK_PTR(seg, off); - if (is_pxe(pxe)) - goto have_pxe; - - /* Plan B: PXENV+ structure at [ES:BX] */ - plan++; - off = *(const uint16_t *)(base + 24); /* Original BX */ - seg = *(const uint16_t *)(base + 4); /* Original ES */ - pxenv = MK_PTR(seg, off); - if (is_pxenv(pxenv)) - goto have_pxenv; - - /* Plan C: PXENV+ structure via INT 1Ah AX=5650h */ - plan++; - memset(®s, 0, sizeof regs); - regs.eax.w[0] = 0x5650; - call16(pxe_int1a, ®s, ®s); - if (!(regs.eflags.l & EFLAGS_CF) && (regs.eax.w[0] == 0x564e)) { - pxenv = MK_PTR(regs.es, regs.ebx.w[0]); - if (is_pxenv(pxenv)) - goto have_pxenv; - } - - /* Plan D: !PXE memory scan */ - plan++; - if ((pxe = memory_scan_for_pxe_struct())) - goto have_pxe; - - /* Plan E: PXENV+ memory scan */ - plan++; - if ((pxenv = memory_scan_for_pxenv_struct())) - goto have_pxenv; - - /* Found nothing at all !! */ - if (!quiet) - printf("No !PXE or PXENV+ API found; we're dead...\n"); - return -1; - - have_pxenv: - APIVer = pxenv->version; - if (!quiet) - printf("Found PXENV+ structure\nPXE API version is %04x\n", APIVer); - - /* if the API version number is 0x0201 or higher, use the !PXE structure */ - if (APIVer >= 0x201) { - if (pxenv->length >= sizeof(struct pxenv_t)) { - pxe = GET_PTR(pxenv->pxeptr); - if (is_pxe(pxe)) - goto have_pxe; - /* - * Nope, !PXE structure missing despite API 2.1+, or at least - * the pointer is missing. Do a last-ditch attempt to find it - */ - if ((pxe = memory_scan_for_pxe_struct())) - goto have_pxe; - } - APIVer = 0x200; /* PXENV+ only, assume version 2.00 */ - } - - /* Otherwise, no dice, use PXENV+ structure */ - data_len = pxenv->undidatasize; - data_seg = pxenv->undidataseg; - code_len = pxenv->undicodesize; - code_seg = pxenv->undicodeseg; - PXEEntry = pxenv->rmentry; - type = "PXENV+"; - goto have_entrypoint; - - have_pxe: - data_len = pxe->seg[PXE_Seg_UNDIData].size; - data_seg = pxe->seg[PXE_Seg_UNDIData].sel; - code_len = pxe->seg[PXE_Seg_UNDICode].size; - code_seg = pxe->seg[PXE_Seg_UNDICode].sel; - PXEEntry = pxe->entrypointsp; - type = "!PXE"; - - have_entrypoint: - if (!quiet) { - printf("%s entry point found (we hope) at %04X:%04X via plan %c\n", - type, PXEEntry.seg, PXEEntry.offs, plan); - printf("UNDI code segment at %04X len %04X\n", code_seg, code_len); - printf("UNDI data segment at %04X len %04X\n", data_seg, data_len); - } - - code_seg = code_seg + ((code_len + 15) >> 4); - data_seg = data_seg + ((data_len + 15) >> 4); - - real_base_mem = max(code_seg, data_seg) >> 6; /* Convert to kilobytes */ - - probe_undi(); - - return 0; -} - -/* - * See if we have gPXE - */ -static void gpxe_init(void) -{ - int err; - static __lowmem struct s_PXENV_FILE_API_CHECK api_check; - - if (APIVer >= 0x201) { - api_check.Size = sizeof api_check; - api_check.Magic = 0x91d447b2; - err = pxe_call(PXENV_FILE_API_CHECK, &api_check); - if (!err && api_check.Magic == 0xe9c17b20) - gpxe_funcs = api_check.APIMask; - } - - /* Necessary functions for us to use the gPXE file API */ - has_gpxe = (~gpxe_funcs & 0x4b) == 0; + ddprintf("My IP address seems to be %08X %s\n", ip, dot_quad_buf); } /* @@ -798,59 +540,7 @@ static void gpxe_init(void) */ static void network_init(void) { - int pkt_len; - struct bootp_t *bp; - const size_t dhcp_max_packet = 4096; - - bp = lmalloc(dhcp_max_packet); - if (!bp) { - printf("Out of low memory\n"); - kaboom(); - } - - *LocalDomain = 0; /* No LocalDomain received */ - - /* - * Get the DHCP client identifiers (query info 1) - */ - printf("Getting cached packet "); - pkt_len = pxe_get_cached_info(1, bp, dhcp_max_packet); - parse_dhcp(bp, pkt_len); - /* - * We don't use flags from the request packet, so - * this is a good time to initialize DHCPMagic... - * Initialize it to 1 meaning we will accept options found; - * in earlier versions of PXELINUX bit 0 was used to indicate - * we have found option 208 with the appropriate magic number; - * we no longer require that, but MAY want to re-introduce - * it in the future for vendor encapsulated options. - */ - *(char *)&DHCPMagic = 1; - - /* - * Get the BOOTP/DHCP packet that brought us file (and an IP - * address). This lives in the DHCPACK packet (query info 2) - */ - pkt_len = pxe_get_cached_info(2, bp, dhcp_max_packet); - parse_dhcp(bp, pkt_len); - /* - * Save away MAC address (assume this is in query info 2. If this - * turns out to be problematic it might be better getting it from - * the query info 1 packet - */ - MAC_len = bp->hardlen > 16 ? 0 : bp->hardlen; - MAC_type = bp->hardware; - memcpy(MAC, bp->macaddr, MAC_len); - - /* - * Get the boot file and other info. This lives in the CACHED_REPLY - * packet (query info 3) - */ - pkt_len = pxe_get_cached_info(3, bp, dhcp_max_packet); - parse_dhcp(bp, pkt_len); - printf("\n"); - - lfree(bp); + net_parse_dhcp(); make_bootif_string(); /* If DMI and DHCP disagree, which one should we set? */ @@ -981,90 +671,6 @@ static void install_int18_hack(void) } #endif -/* - * This function unloads the PXE and UNDI stacks and - * unclaims the memory. - */ -__export void unload_pxe(uint16_t flags) -{ - /* PXE unload sequences */ - /* - * iPXE does: - * UNDI_SHUTDOWN, UNDI_CLEANUP, STOP_UNDI - * Older Syslinux did: - * UDP_CLOSE, UNDI_SHUTDOWN, UNLOAD_STACK, STOP_UNDI/UNDI_CLEANUP - */ - static const uint8_t new_api_unload[] = { - PXENV_UNDI_SHUTDOWN, PXENV_UNLOAD_STACK, PXENV_STOP_UNDI, 0 - }; - static const uint8_t old_api_unload[] = { - PXENV_UNDI_SHUTDOWN, PXENV_UNLOAD_STACK, PXENV_UNDI_CLEANUP, 0 - }; - - unsigned int api; - const uint8_t *api_ptr; - int err; - size_t int_addr; - static __lowmem union { - struct s_PXENV_UNDI_SHUTDOWN undi_shutdown; - struct s_PXENV_UNLOAD_STACK unload_stack; - struct s_PXENV_STOP_UNDI stop_undi; - struct s_PXENV_UNDI_CLEANUP undi_cleanup; - uint16_t Status; /* All calls have this as the first member */ - } unload_call; - - dprintf("Called unload_pxe()...\n"); - dprintf("FBM before unload = %d\n", bios_fbm()); - - err = reset_pxe(); - - dprintf("FBM after reset_pxe = %d, err = %d\n", bios_fbm(), err); - - /* If we want to keep PXE around, we still need to reset it */ - if (flags || err) - return; - - dprintf("APIVer = %04x\n", APIVer); - - api_ptr = APIVer >= 0x0200 ? new_api_unload : old_api_unload; - while((api = *api_ptr++)) { - dprintf("PXE call %04x\n", api); - memset(&unload_call, 0, sizeof unload_call); - err = pxe_call(api, &unload_call); - if (err || unload_call.Status != PXENV_STATUS_SUCCESS) { - printf("PXE unload API call %04x failed: 0x%x\n", - api, unload_call.Status); - goto cant_free; - } - } - - api = 0xff00; - if (real_base_mem <= bios_fbm()) { /* Sanity check */ - dprintf("FBM %d < real_base_mem %d\n", bios_fbm(), real_base_mem); - goto cant_free; - } - api++; - - /* Check that PXE actually unhooked the INT 0x1A chain */ - int_addr = (size_t)GET_PTR(*(far_ptr_t *)(4 * 0x1a)); - int_addr >>= 10; - if (int_addr >= real_base_mem || int_addr < bios_fbm()) { - set_bios_fbm(real_base_mem); - dprintf("FBM after unload_pxe = %d\n", bios_fbm()); - return; - } - - dprintf("Can't free FBM, real_base_mem = %d, " - "FBM = %d, INT 1A = %08x (%d)\n", - real_base_mem, bios_fbm(), - *(uint32_t *)(4 * 0x1a), int_addr); - -cant_free: - printf("Failed to free base memory error %04x-%08x (%d/%dK)\n", - api, *(uint32_t *)(4 * 0x1a), bios_fbm(), real_base_mem); - return; -} - static int pxe_readdir(struct file *file, struct dirent *dirent) { struct inode *inode = file->inode; diff --git a/core/fs/pxe/pxe.h b/core/fs/pxe/pxe.h index 68d4e3e0..279957ac 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 <fcntl.h> /* For OK_FLAGS_MASK */ #include "fs.h" /* Mostly for FILENAME_MAX */ @@ -106,6 +107,8 @@ struct bootp_t { struct netconn; struct netbuf; +struct efi_binding; + /* * Our inode private information -- this includes the packet buffer! */ @@ -124,6 +127,10 @@ union net_private { uint32_t remoteip; /* Remote IP address (0 = disconnected) */ uint16_t localport; /* Local port number (0=not in use) */ } tftp; + struct net_private_efi { + struct efi_binding *binding; /* EFI binding for protocol */ + uint16_t localport; /* Local port number (0=not in use) */ + } efi; }; struct pxe_pvt_inode { @@ -144,20 +151,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 t_PXENV_UNDI_GET_INFORMATION pxe_undi_info; extern t_PXENV_UNDI_GET_IFACE_INFO pxe_undi_iface; @@ -264,8 +260,9 @@ void ftp_open(struct url_info *url, int flags, struct inode *inode, int ftp_readdir(struct inode *inode, struct dirent *dirent); /* tcp.c */ -void tcp_close_file(struct inode *inode); -void tcp_fill_buffer(struct inode *inode); const struct pxe_conn_ops tcp_conn_ops; +extern void gpxe_init(void); +extern int pxe_init(bool quiet); + #endif /* pxe.h */ diff --git a/core/fs/pxe/tcp.c b/core/fs/pxe/tcp.c index 90761978..0fb6efd0 100644 --- a/core/fs/pxe/tcp.c +++ b/core/fs/pxe/tcp.c @@ -16,63 +16,10 @@ * Common operations for TCP-based network protocols */ -#include <lwip/api.h> #include "pxe.h" -#include "../../../version.h" -#include "url.h" - -void tcp_close_file(struct inode *inode) -{ - struct pxe_pvt_inode *socket = PVT(inode); - - if (socket->net.lwip.conn) { - netconn_delete(socket->net.lwip.conn); - socket->net.lwip.conn = NULL; - } - if (socket->net.lwip.buf) { - netbuf_delete(socket->net.lwip.buf); - socket->net.lwip.buf = NULL; - } -} - -void tcp_fill_buffer(struct inode *inode) -{ - struct pxe_pvt_inode *socket = PVT(inode); - void *data; - u16_t len; - err_t err; - - /* Clean up or advance an inuse netbuf */ - if (socket->net.lwip.buf) { - if (netbuf_next(socket->net.lwip.buf) < 0) { - netbuf_delete(socket->net.lwip.buf); - socket->net.lwip.buf = NULL; - } - } - /* If needed get a new netbuf */ - if (!socket->net.lwip.buf) { - err = netconn_recv(socket->net.lwip.conn, &(socket->net.lwip.buf)); - if (!socket->net.lwip.buf || err) { - socket->tftp_goteof = 1; - if (inode->size == -1) - inode->size = socket->tftp_filepos; - socket->ops->close(inode); - return; - } - } - /* Report the current fragment of the netbuf */ - err = netbuf_data(socket->net.lwip.buf, &data, &len); - if (err) { - printf("netbuf_data err: %d\n", err); - kaboom(); - } - socket->tftp_dataptr = data; - socket->tftp_filepos += len; - socket->tftp_bytesleft = len; - return; -} +#include "net.h" const struct pxe_conn_ops tcp_conn_ops = { - .fill_buffer = tcp_fill_buffer, - .close = tcp_close_file, + .fill_buffer = core_tcp_fill_buffer, + .close = core_tcp_close_file, }; diff --git a/core/fs/pxe/tftp.c b/core/fs/pxe/tftp.c index 9b755c93..446da634 100644 --- a/core/fs/pxe/tftp.c +++ b/core/fs/pxe/tftp.c @@ -8,27 +8,12 @@ const uint8_t TimeoutTable[] = { 2, 2, 3, 3, 4, 5, 6, 7, 9, 10, 12, 15, 18, 21, 26, 31, 37, 44, 53, 64, 77, 92, 110, 132, 159, 191, 229, 255, 255, 255, 255, 0 }; -struct tftp_options { - const char *str_ptr; /* string pointer */ - size_t offset; /* offset into socket structre */ -}; struct tftp_packet { uint16_t opcode; uint16_t serial; char data[]; }; -#define IFIELD(x) offsetof(struct inode, x) -#define PFIELD(x) (offsetof(struct inode, pvt) + \ - offsetof(struct pxe_pvt_inode, x)) - -static const struct tftp_options tftp_options[] = -{ - { "tsize", IFIELD(size) }, - { "blksize", PFIELD(tftp_blksize) }, -}; -static const int tftp_nopts = sizeof tftp_options / sizeof tftp_options[0]; - static void tftp_error(struct inode *file, uint16_t errnum, const char *errstr); @@ -38,7 +23,7 @@ static void tftp_close_file(struct inode *inode) if (!socket->tftp_goteof) { tftp_error(inode, 0, "No error, file close"); } - net_core_close(socket); + core_udp_close(socket); } /** @@ -64,7 +49,7 @@ static void tftp_error(struct inode *inode, uint16_t errnum, memcpy(err_buf.err_msg, errstr, len); err_buf.err_msg[len] = '\0'; - net_core_send(socket, &err_buf, 4 + len + 1); + core_udp_send(socket, &err_buf, 4 + len + 1); } /** @@ -83,7 +68,7 @@ static void ack_packet(struct inode *inode, uint16_t ack_num) ack_packet_buf[0] = TFTP_ACK; ack_packet_buf[1] = htons(ack_num); - net_core_send(socket, ack_packet_buf, 4); + core_udp_send(socket, ack_packet_buf, 4); } /* @@ -118,7 +103,7 @@ static void tftp_get_packet(struct inode *inode) while (timeout) { buf_len = socket->tftp_blksize + 4; - err = net_core_recv(socket, socket->tftp_pktbuf, &buf_len, + err = core_udp_recv(socket, socket->tftp_pktbuf, &buf_len, &src_ip, &src_port); if (err) { jiffies_t now = jiffies(); @@ -209,8 +194,6 @@ void tftp_open(struct url_info *url, int flags, struct inode *inode, static const char rrq_tail[] = "octet\0""tsize\0""0\0""blksize\0""1408"; char rrq_packet_buf[2+2*FILENAME_MAX+sizeof rrq_tail]; char reply_packet_buf[PKTBUF_SIZE]; - const struct tftp_options *tftp_opt; - int i = 0; int err; int buffersize; int rrq_len; @@ -219,7 +202,7 @@ void tftp_open(struct url_info *url, int flags, struct inode *inode, jiffies_t oldtime; uint16_t opcode; uint16_t blk_num; - uint32_t opdata, *opdata_ptr; + uint64_t opdata; uint16_t src_port; uint32_t src_ip; @@ -238,7 +221,7 @@ void tftp_open(struct url_info *url, int flags, struct inode *inode, url->port = TFTP_PORT; socket->ops = &tftp_conn_ops; - if (net_core_open(socket, NET_CORE_UDP)) + if (core_udp_open(socket)) return; buf = rrq_packet_buf; @@ -255,43 +238,40 @@ void tftp_open(struct url_info *url, int flags, struct inode *inode, timeout_ptr = TimeoutTable; /* Reset timeout */ sendreq: - net_core_disconnect(socket); timeout = *timeout_ptr++; if (!timeout) return; /* No file available... */ oldtime = jiffies(); - net_core_connect(socket, url->ip, url->port); - net_core_send(socket, rrq_packet_buf, rrq_len); + core_udp_sendto(socket, rrq_packet_buf, rrq_len, url->ip, url->port); /* If the WRITE call fails, we let the timeout take care of it... */ wait_pkt: - net_core_disconnect(socket); for (;;) { buf_len = sizeof(reply_packet_buf); - err = net_core_recv(socket, reply_packet_buf, &buf_len, + err = core_udp_recv(socket, reply_packet_buf, &buf_len, &src_ip, &src_port); if (err) { jiffies_t now = jiffies(); if (now - oldtime >= timeout) goto sendreq; } else { - /* Make sure the packet actually came from the server */ - if (src_ip == url->ip) + /* Make sure the packet actually came from the server and + is long enough for a TFTP opcode */ + dprintf("tftp_open: got packet buflen=%d\n", buf_len); + if ((src_ip == url->ip) && (buf_len >= 2)) break; } } - net_core_disconnect(socket); - net_core_connect(socket, src_ip, src_port); + core_udp_disconnect(socket); + core_udp_connect(socket, src_ip, src_port); /* filesize <- -1 == unknown */ inode->size = -1; socket->tftp_blksize = TFTP_BLOCKSIZE; buffersize = buf_len - 2; /* bytes after opcode */ - if (buffersize < 0) - goto wait_pkt; /* Garbled reply */ /* * Get the opcode type, and parse it @@ -384,22 +364,6 @@ wait_pkt: if (!buffersize) break; /* No option data */ - /* - * Parse option pointed to by options; guaranteed to be - * null-terminated - */ - tftp_opt = tftp_options; - for (i = 0; i < tftp_nopts; i++) { - if (!strcmp(opt, tftp_opt->str_ptr)) - break; - tftp_opt++; - } - if (i == tftp_nopts) - goto err_reply; /* Non-negotitated option returned, - no idea what it means ...*/ - - /* get the address of the filed that we want to write on */ - opdata_ptr = (uint32_t *)((char *)inode + tftp_opt->offset); opdata = 0; /* do convert a number-string to decimal number, just like atoi */ @@ -412,7 +376,16 @@ wait_pkt: goto err_reply; /* Not a decimal digit */ opdata = opdata*10 + d; } - *opdata_ptr = opdata; + + if (!strcmp(opt, "tsize")) + inode->size = opdata; + else if (!strcmp(opt, "blksize")) + socket->tftp_blksize = opdata; + else + goto err_reply; /* Non-negotitated option returned, + no idea what it means ...*/ + + } if (socket->tftp_blksize < 64 || socket->tftp_blksize > PKTBUF_SIZE) @@ -437,7 +410,7 @@ err_reply: done: if (!inode->size) - net_core_close(socket); + core_udp_close(socket); return; } diff --git a/core/graphics.c b/core/graphics.c index 834372ff..471847f5 100644 --- a/core/graphics.c +++ b/core/graphics.c @@ -24,6 +24,7 @@ #include "bios.h" #include "graphics.h" +#include <syslinux/video.h> __export uint8_t UsingVGA = 0; uint16_t VGAPos; /* Pointer into VGA memory */ @@ -93,9 +94,11 @@ static int vgasetmode(void) /* * Set mode. */ + memset(&ireg, 0, sizeof(ireg)); ireg.eax.w[0] = 0x0012; /* Set mode = 640x480 VGA 16 colors */ __intcall(0x10, &ireg, &oreg); + memset(&ireg, 0, sizeof(ireg)); ireg.edx.w[0] = (uint32_t)linear_color; ireg.eax.w[0] = 0x1002; /* Write color registers */ __intcall(0x10, &ireg, &oreg); @@ -338,6 +341,7 @@ static void vgacursorcommon(char data) { if (UsingVGA) { com32sys_t ireg; + memset(&ireg, 0, sizeof(ireg)); ireg.eax.b[0] = data; ireg.eax.b[1] = 0x09; diff --git a/core/head.inc b/core/head.inc index 286b9b4e..71eb5744 100644 --- a/core/head.inc +++ b/core/head.inc @@ -34,6 +34,5 @@ %include "tracers.inc" %include "stack.inc" %include "io.inc" -%include "vkernel.inc" %endif ; _HEAD_INC 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/idle.c b/core/idle.c index a089b088..c8050554 100644 --- a/core/idle.c +++ b/core/idle.c @@ -24,7 +24,7 @@ #define TICKS_TO_IDLE 4 /* Also in idle.inc */ -extern jiffies_t _IdleTimer; +static jiffies_t _IdleTimer; __export uint16_t NoHalt = 0; int (*idle_hook_func)(void); @@ -32,6 +32,7 @@ int (*idle_hook_func)(void); void reset_idle(void) { _IdleTimer = jiffies(); + sti(); /* Guard against BIOS/PXE brokenness... */ } __export void __idle(void) @@ -42,6 +43,7 @@ __export void __idle(void) if (idle_hook_func && idle_hook_func()) return; /* Nonzero return = do not idle */ + sti(); if (NoHalt) cpu_relax(); else diff --git a/core/idle.inc b/core/idle.inc deleted file mode 100644 index 65d6c5c8..00000000 --- a/core/idle.inc +++ /dev/null @@ -1,80 +0,0 @@ -;; -*- fundamental -*- --------------------------------------------------- -;; -;; Copyright 2008 H. Peter Anvin - All Rights Reserved -;; Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin -;; -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation, Inc., 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. -;; -;; ----------------------------------------------------------------------- - - section .text16 -TICKS_TO_IDLE equ 4 ; Also in idle.c - -reset_idle: - push eax - mov eax,[cs:__jiffies] - mov [cs:_IdleTimer],eax - pop eax - sti ; Guard against BIOS/PXE brokenness... - ret - - global do_idle:function hidden -do_idle: - push eax - push ds - push es - mov ax,cs - mov ds,ax - mov es,ax - pushf - pop ax - test ah,2 - jnz .ok - push si - push cx - mov si,hlt_err - pm_call pm_writestr - mov si,sp - add si,10 - mov cx,16 -.errloop: - ss lodsw - pm_call pm_writehex4 - dec cx - jz .endloop - mov al,' ' - pm_call pm_writechr - jmp .errloop -.endloop: - pm_call crlf - pop cx - pop si - sti -.ok: - ; Don't spend time jumping to PM unless we're actually idle... - - mov eax,[__jiffies] - sub eax,[_IdleTimer] - cmp eax,TICKS_TO_IDLE - jb .done - - extern __idle - pm_call __idle -.done: - pop es - pop ds - pop eax -.ret: ret - - section .data16 - alignz 4 - global _IdleTimer:data hidden -_IdleTimer dd 0 - -hlt_err db 'ERROR: idle with IF=0', CR, LF, 0 - - section .text16 diff --git a/core/include/bios.h b/core/include/bios.h index 889443ab..0a68f5d3 100644 --- a/core/include/bios.h +++ b/core/include/bios.h @@ -30,7 +30,7 @@ #define fdctab1 fdctab #define fdctab2 (fdctab + 2) -#define serial_base 0x0400 /* Base address for 4 serial ports */ +#define SERIAL_BASE 0x0400 /* Base address for 4 serial ports */ #define BIOS_fbm 0x0413 /* Free Base Memory (kilobytes) */ #define BIOS_page 0x0462 /* Current video page */ #define BIOS_timer 0x046C /* Timer ticks */ @@ -56,12 +56,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 @@ -96,4 +90,19 @@ extern char *SerialTail; extern void bios_init(void); extern void bios_cleanup_hardware(void); +static inline uint16_t get_serial_port(uint16_t port) +{ + /* Magic array in BIOS memory, contains four entries */ + const uint16_t * const serial_ports = (const uint16_t *)SERIAL_BASE; + + /* + * If port > 3 then the port is simply the I/O base address + */ + if (port > 3) + return port; + + /* Get the I/O port from the BIOS */ + return serial_ports[port]; +} + #endif /* _BIOS_H */ diff --git a/core/include/core.h b/core/include/core.h index d35bd038..1fd283e3 100644 --- a/core/include/core.h +++ b/core/include/core.h @@ -22,19 +22,25 @@ extern char CurrentDirName[]; extern char SubvolName[]; extern char ConfigName[]; extern char config_cwd[]; -extern char KernelName[]; extern char cmd_line[]; extern char ConfigFile[]; extern char syslinux_banner[]; extern char copyright_str[]; -extern uint16_t BIOSName; -extern char StackBuf[]; extern unsigned int __bcopyxx_len; +/* + * Mark symbols that are only used by BIOS as __weak until we can move + * all references out of the generic (EFI + BIOS) code and into + * BIOS-specific code. + */ +extern __weak uint16_t BIOSName; +extern __weak char KernelName[]; +extern __weak char StackBuf[]; + 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; @@ -42,6 +48,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); @@ -83,8 +92,10 @@ void call16(void (*)(void), const com32sys_t *, com32sys_t *); /* * __lowmem is in the low 1 MB; __bss16 in the low 64K */ -#define __lowmem __attribute__((nocommon,section(".lowmem"))) -#define __bss16 __attribute__((nocommon,section(".bss16"))) +#ifdef __SYSLINUX_CORE__ /* Not supported in modules */ +# define __lowmem __attribute__((nocommon,section(".lowmem"))) +# define __bss16 __attribute__((nocommon,section(".bss16"))) +#endif /* * Helper routine to return a specific set of flags @@ -120,4 +131,6 @@ extern void dmi_init(void); extern void do_sysappend(char *buf); +extern void load_env32(com32sys_t *regs); + #endif /* CORE_H */ 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 c7d0fd75..31ef3157 100644 --- a/core/include/fs.h +++ b/core/include/fs.h @@ -1,6 +1,7 @@ #ifndef FS_H #define FS_H +#include <linux/list.h> #include <stddef.h> #include <stdbool.h> #include <string.h> @@ -182,9 +183,17 @@ static inline struct file *handle_to_file(uint16_t handle) return handle ? &files[handle-1] : NULL; } -extern char *PATH; +struct path_entry { + struct list_head list; + const char *str; +}; + +extern struct list_head PATH; + +extern struct path_entry *path_add(const char *str); /* 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 +206,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/include/graphics.h b/core/include/graphics.h index 814ffe7d..b1b442ad 100644 --- a/core/include/graphics.h +++ b/core/include/graphics.h @@ -48,9 +48,8 @@ extern uint16_t VGAFontSize; extern uint8_t UserFont; -extern __lowmem char fontbuf[8192]; +extern char fontbuf[8192]; -extern void syslinux_force_text_mode(void); extern void vgadisplayfile(FILE *_fd); extern void using_vga(uint8_t vga, uint16_t pix_cols, uint16_t pix_rows); diff --git a/core/include/mbox.h b/core/include/mbox.h index 3c35ce4e..6fec267c 100644 --- a/core/include/mbox.h +++ b/core/include/mbox.h @@ -45,7 +45,8 @@ mstime_t mbox_fetch(struct mailbox *mbox, void **msg, mstime_t timeout); */ static inline void mbox_set_invalid(struct mailbox *mbox) { - sem_set_invalid(&mbox->prod_sem); + if (!!mbox) + sem_set_invalid(&mbox->prod_sem); } /* @@ -53,7 +54,7 @@ static inline void mbox_set_invalid(struct mailbox *mbox) */ static inline bool mbox_is_valid(struct mailbox *mbox) { - return sem_is_valid(&mbox->prod_sem); + return ((!!mbox) && sem_is_valid(&mbox->prod_sem)); } #endif /* _MBOX_H */ diff --git a/core/include/net.h b/core/include/net.h index 4f6819f9..c64191d8 100644 --- a/core/include/net.h +++ b/core/include/net.h @@ -2,32 +2,41 @@ #define _NET_H #include <stdint.h> +#include <stdbool.h> #include <stddef.h> -/* Protocol family */ -enum net_core_proto { - NET_CORE_TCP, - NET_CORE_UDP, -}; - void net_core_init(void); +void net_parse_dhcp(void); struct pxe_pvt_inode; -int net_core_open(struct pxe_pvt_inode *socket, enum net_core_proto proto); -void net_core_close(struct pxe_pvt_inode *socket); +int core_udp_open(struct pxe_pvt_inode *socket); +void core_udp_close(struct pxe_pvt_inode *socket); -void net_core_connect(struct pxe_pvt_inode *socket, +void core_udp_connect(struct pxe_pvt_inode *socket, uint32_t ip, uint16_t port); -void net_core_disconnect(struct pxe_pvt_inode *socket); +void core_udp_disconnect(struct pxe_pvt_inode *socket); -int net_core_recv(struct pxe_pvt_inode *socket, void *buf, uint16_t *buf_len, +int core_udp_recv(struct pxe_pvt_inode *socket, void *buf, uint16_t *buf_len, uint32_t *src_ip, uint16_t *src_port); -void net_core_send(struct pxe_pvt_inode *socket, +void core_udp_send(struct pxe_pvt_inode *socket, const void *data, size_t len); +void core_udp_sendto(struct pxe_pvt_inode *socket, const void *data, size_t len, + uint32_t ip, uint16_t port); + void probe_undi(void); void pxe_init_isr(void); +struct inode; + +int core_tcp_open(struct pxe_pvt_inode *socket); +int core_tcp_connect(struct pxe_pvt_inode *socket, uint32_t ip, uint16_t port); +bool core_tcp_is_connected(struct pxe_pvt_inode *socket); +int core_tcp_write(struct pxe_pvt_inode *socket, const void *data, + size_t len, bool copy); +void core_tcp_close_file(struct inode *inode); +void core_tcp_fill_buffer(struct inode *inode); + #endif /* _NET_H */ diff --git a/core/include/thread.h b/core/include/thread.h index 6bfdfaa7..8ec4a267 100644 --- a/core/include/thread.h +++ b/core/include/thread.h @@ -93,7 +93,8 @@ void sem_init(struct semaphore *, int); */ static inline void sem_set_invalid(struct semaphore *sem) { - sem->list.next = NULL; + if (!!sem) + sem->list.next = NULL; } /* @@ -101,7 +102,7 @@ static inline void sem_set_invalid(struct semaphore *sem) */ static inline bool sem_is_valid(struct semaphore *sem) { - return !!sem->list.next; + return ((!!sem) && (!!sem->list.next)); } struct thread *start_thread(const char *name, size_t stack_size, int prio, diff --git a/core/init.c b/core/init.c index 85bab775..45a05093 100644 --- a/core/init.c +++ b/core/init.c @@ -3,88 +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) -{ - 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) +void init(void) { - 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(); - - /* - * Scan the DMI tables for interesting information. - */ - dmi_init(); + firmware->init(); } diff --git a/core/init.inc b/core/init.inc index ae0e6312..b74cf30b 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..b0173e08 --- /dev/null +++ b/core/isolinux-c.c @@ -0,0 +1,22 @@ +#include <syslinux/config.h> +#include <com32.h> +#include <fs.h> + +extern uint32_t OrigESDI; +extern const uint64_t Hidden; +extern uint16_t BIOSType; +extern uint16_t bios_cdrom; +extern uint8_t DriveNumber; +extern const void *spec_packet; + +__export 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 = &OrigESDI; + di->iso.partoffset = &Hidden; +} diff --git a/core/isolinux.asm b/core/isolinux.asm index b494eb4d..f1512611 100644 --- a/core/isolinux.asm +++ b/core/isolinux.asm @@ -62,13 +62,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 @@ -80,6 +83,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 @@ -155,6 +159,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 @@ -415,7 +420,7 @@ MaxLMA equ 384*1024 ; Reasonable limit (384K) call getlinsec pop eax pop cx - mov dx,cx + movzx edx,cx pop bp pop bx @@ -1051,8 +1056,8 @@ startup_msg: db 'Starting up, DL = ', 0 spec_ok_msg: db 'Loaded spec packet OK, drive = ', 0 secsize_msg: db 'Sector size ', 0 offset_msg: db 'Main image LBA = ', 0 -verify_msg: db 'Image checksum verified.', CR, LF, 0 -allread_msg db 'Main image read, jumping to main code...', CR, LF, 0 +verify_msg: db 'Image csum verified.', CR, LF, 0 +allread_msg db 'Image read, jumping to main code...', CR, LF, 0 %endif noinfotable_msg db 'No boot info table, assuming single session disk...', CR, LF, 0 noinfoinspec_msg db 'Spec packet missing LBA information, trying to wing it...', CR, LF, 0 @@ -1079,6 +1084,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 @@ -1154,7 +1160,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 310365d3..4c150e76 100644 --- a/core/kaboom.c +++ b/core/kaboom.c @@ -4,7 +4,7 @@ #include "core.h" -#ifdef DEBUG +#if defined(CORE_DEBUG) || defined(DEBUG_PORT) #include <dprintf.h> diff --git a/core/ldlinux-c.c b/core/ldlinux-c.c new file mode 100644 index 00000000..1d01d9a7 --- /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 void *PartInfo; +extern uint32_t OrigESDI; +extern const uint64_t Hidden; + +__export 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 = &PartInfo; + di->disk.esdi_ptr = &OrigESDI; + di->disk.partoffset = &Hidden; +} diff --git a/core/legacynet/core.c b/core/legacynet/core.c index 848410c6..eacb4927 100644 --- a/core/legacynet/core.c +++ b/core/legacynet/core.c @@ -20,19 +20,13 @@ const struct url_scheme url_schemes[] = { * Open a socket * * @param:socket, the socket to open - * @param:proto, the protocol of the new connection * * @out: error code, 0 on success, -1 on failure */ -int net_core_open(struct pxe_pvt_inode *socket __unused, - enum net_core_proto proto) +int core_udp_open(struct pxe_pvt_inode *socket __unused) { struct net_private_tftp *priv = &socket->net.tftp; - /* The legacy stack only supports UDP */ - if (proto != NET_CORE_UDP) - return -1; - /* Allocate local UDP port number */ priv->localport = get_port(); @@ -44,7 +38,7 @@ int net_core_open(struct pxe_pvt_inode *socket __unused, * * @param:socket, the socket to open */ -void net_core_close(struct pxe_pvt_inode *socket) +void core_udp_close(struct pxe_pvt_inode *socket) { struct net_private_tftp *priv = &socket->net.tftp; @@ -59,7 +53,7 @@ void net_core_close(struct pxe_pvt_inode *socket) * @param:ip, the ip address * @param:port, the port number, host-byte order */ -void net_core_connect(struct pxe_pvt_inode *socket, uint32_t ip, +void core_udp_connect(struct pxe_pvt_inode *socket, uint32_t ip, uint16_t port) { struct net_private_tftp *priv = &socket->net.tftp; @@ -74,7 +68,7 @@ void net_core_connect(struct pxe_pvt_inode *socket, uint32_t ip, * * @param:socket, the open socket */ -void net_core_disconnect(struct pxe_pvt_inode *socket __unused) +void core_udp_disconnect(struct pxe_pvt_inode *socket __unused) { } @@ -88,7 +82,7 @@ void net_core_disconnect(struct pxe_pvt_inode *socket __unused) * @out: src_ip, ip address of the data source * @out: src_port, port number of the data source, host-byte order */ -int net_core_recv(struct pxe_pvt_inode *socket, void *buf, uint16_t *buf_len, +int core_udp_recv(struct pxe_pvt_inode *socket, void *buf, uint16_t *buf_len, uint32_t *src_ip, uint16_t *src_port) { static __lowmem struct s_PXENV_UDP_READ udp_read; @@ -126,7 +120,7 @@ int net_core_recv(struct pxe_pvt_inode *socket, void *buf, uint16_t *buf_len, * @param:data, data buffer to send * @param:len, size of data bufer */ -void net_core_send(struct pxe_pvt_inode *socket, const void *data, size_t len) +void core_udp_send(struct pxe_pvt_inode *socket, const void *data, size_t len) { static __lowmem struct s_PXENV_UDP_WRITE udp_write; struct net_private_tftp *priv = &socket->net.tftp; @@ -153,6 +147,43 @@ void net_core_send(struct pxe_pvt_inode *socket, const void *data, size_t len) } /** + * Send a UDP packet to a destination + * + * @param:socket, the open socket + * @param:data, data buffer to send + * @param:len, size of data bufer + * @param:ip, the ip address + * @param:port, the port number, host-byte order + */ +void core_udp_sendto(struct pxe_pvt_inode *socket, const void *data, size_t len, + uint32_t ip, uint16_t port) +{ + static __lowmem struct s_PXENV_UDP_WRITE udp_write; + struct net_private_tftp *priv = &socket->net.tftp; + void *lbuf; + uint16_t tid; + + lbuf = lmalloc(len); + if (!lbuf) + return; + + memcpy(lbuf, data, len); + + tid = priv->localport; /* TID(local port No) */ + udp_write.buffer = FAR_PTR(lbuf); + udp_write.ip = ip; + udp_write.gw = gateway(udp_write.ip); + udp_write.src_port = tid; + udp_write.dst_port = htons(port); + udp_write.buffer_size = len; + + pxe_call(PXENV_UDP_WRITE, &udp_write); + + lfree(lbuf); +} + + +/** * Network stack-specific initialization * * Initialize UDP stack diff --git a/core/legacynet/dnsresolv.c b/core/legacynet/dnsresolv.c index fab36aef..fdbe795c 100644 --- a/core/legacynet/dnsresolv.c +++ b/core/legacynet/dnsresolv.c @@ -170,6 +170,37 @@ extern uint16_t get_port(void); extern void free_port(uint16_t port); /* + * parse the ip_str and return the ip address with *res. + * return true if the whole string was consumed and the result + * was valid. + * + */ +static bool parse_dotquad(const char *ip_str, uint32_t *res) +{ + const char *p = ip_str; + uint8_t part = 0; + uint32_t ip = 0; + int i; + + for (i = 0; i < 4; i++) { + while (is_digit(*p)) { + part = part * 10 + *p - '0'; + p++; + } + if (i != 3 && *p != '.') + return false; + + ip = (ip << 8) | part; + part = 0; + p++; + } + p--; + + *res = htonl(ip); + return *p == '\0'; +} + +/* * Actual resolver function * Points to a null-terminated or :-terminated string in _name_ * and returns the ip addr in _ip_ if it exists and can be found. @@ -209,6 +240,10 @@ __export uint32_t dns_resolv(const char *name) if (!name || !*name) return 0; + /* If it is a valid dot quad, just return that value */ + if (parse_dotquad(name, &result)) + return result; + /* Make sure we have at least one valid DNS server */ if (!dns_server[0]) return 0; diff --git a/core/localboot.c b/core/localboot.c index 0f4b5820..04635d47 100644 --- a/core/localboot.c +++ b/core/localboot.c @@ -16,7 +16,7 @@ #include <core.h> #include <fs.h> #include <bios.h> -#include <graphics.h> +#include <syslinux/video.h> /* * localboot.c @@ -39,6 +39,7 @@ __export void local_boot(int16_t ax) com32sys_t ireg, oreg; int i; + memset(&ireg, 0, sizeof(ireg)); syslinux_force_text_mode(); writestr(LOCALBOOT_MSG); @@ -57,10 +58,12 @@ __export void local_boot(int16_t ax) * Load boot sector from the specified BIOS device and jump to * it. */ + memset(&ireg, 0, sizeof ireg); ireg.edx.b[0] = ax & 0xff; ireg.eax.w[0] = 0; /* Reset drive */ __intcall(0x13, &ireg, NULL); + memset(&ireg, 0, sizeof(ireg)); ireg.eax.w[0] = 0x0201; /* Read one sector */ ireg.ecx.w[0] = 0x0001; /* C/H/S = 0/0/1 (first sector) */ ireg.ebx.w[0] = OFFS(trackbuf); diff --git a/core/lwip/src/arch/sys_arch.c b/core/lwip/src/arch/sys_arch.c index 894f6ada..4081d01e 100644 --- a/core/lwip/src/arch/sys_arch.c +++ b/core/lwip/src/arch/sys_arch.c @@ -48,7 +48,7 @@ u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout) { mstime_t rv; - if (!!sem) + if (!sem || !*sem) return SYS_ARCH_TIMEOUT; rv = sem_down(*sem, timeout); if (rv == (mstime_t)-1) @@ -71,8 +71,11 @@ err_t sys_mbox_new(sys_mbox_t *mbox, int size) void sys_mbox_free(sys_mbox_t *mbox) { - if (!!mbox && !!*mbox) + if (!!mbox && !!*mbox) { + sys_mbox_set_invalid(mbox); free(*mbox); + *mbox = NULL; + } } void sys_mbox_post(sys_mbox_t *mbox, void *msg) diff --git a/core/lwip/src/include/arch/cc.h b/core/lwip/src/include/arch/cc.h index 677ef4f5..5ab13dec 100644 --- a/core/lwip/src/include/arch/cc.h +++ b/core/lwip/src/include/arch/cc.h @@ -21,9 +21,19 @@ typedef uintptr_t mem_ptr_t; #define PACK_STRUCT_STRUCT __packed +#define LWIP_PLATFORM_USE_DPRINTF + +#ifdef LWIP_PLATFORM_USE_DPRINTF +# include <dprintf.h> +# define LWIP_PLATFORM_PRINTF dprintf +#else +# define LWIP_PLATFORM_PRINTF printf +#endif + + #if 1 -#define LWIP_PLATFORM_DIAG(x) do { printf x; } while(0) -#define LWIP_PLATFORM_ASSERT(x) do { printf("LWIP(%s,%d,%p): %s", __FILE__, __LINE__, __builtin_return_address(0), (x)); kaboom(); } while(0) +#define LWIP_PLATFORM_DIAG(x) do { LWIP_PLATFORM_PRINTF x; } while(0) +#define LWIP_PLATFORM_ASSERT(x) do { LWIP_PLATFORM_PRINTF("LWIP(%s,%d,%p): %s", __FILE__, __LINE__, __builtin_return_address(0), (x)); kaboom(); } while(0) #else #define LWIP_PLATFORM_DIAG(x) ((void)0) /* For now... */ #define LWIP_PLATFORM_ASSERT(x) kaboom() diff --git a/core/lwip/src/include/lwip/opt.h b/core/lwip/src/include/lwip/opt.h index a1b87658..490aab43 100644 --- a/core/lwip/src/include/lwip/opt.h +++ b/core/lwip/src/include/lwip/opt.h @@ -1816,6 +1816,34 @@ #endif /** + * UNDIIF_DEBUG: Enable debugging in undiif.c. + */ +#ifndef UNDIIF_DEBUG +#define UNDIIF_DEBUG LWIP_DBG_OFF +#endif + +/** + * UNDIIF_ARP_DEBUG: Enable ETHARP debugging in undiif.c. + */ +#ifndef UNDIIF_ARP_DEBUG +#define UNDIIF_ARP_DEBUG LWIP_DBG_OFF +#endif + +/** + * UNDIIF_NET_DEBUG: Enable NETIF debugging in undiif.c. + */ +#ifndef UNDIIF_NET_DEBUG +#define UNDIIF_NET_DEBUG LWIP_DBG_OFF +#endif + +/** + * UNDIIF_ID_DEBUG: Enable debugging to identify packets in undiif.c. + */ +#ifndef UNDIIF_ID_DEBUG +#define UNDIIF_ID_DEBUG LWIP_DBG_OFF +#endif + +/** * PBUF_DEBUG: Enable debugging in pbuf.c. */ #ifndef PBUF_DEBUG diff --git a/core/lwip/src/netif/undiif.c b/core/lwip/src/netif/undiif.c index 2c7e4ac4..e62a984d 100644 --- a/core/lwip/src/netif/undiif.c +++ b/core/lwip/src/netif/undiif.c @@ -45,10 +45,27 @@ * something that better describes your network interface. */ +/* other headers include deprintf.h too early */ +#define UNDIIF_ID_FULL_DEBUG (UNDIIF_ID_DEBUG | UNDIIF_DEBUG) + +#if UNDIIF_ID_FULL_DEBUG +# ifndef DEBUG +# define DEBUG 1 +# endif +# ifndef DEBUG_PORT +# define DEBUG_PORT 0x3f8 +# endif +#endif /* UNDIIF_ID_FULL_DEBUG */ + #include <core.h> #include "lwip/opt.h" +#define LWIP_UNDIIF_DBG(debug) \ + ( ((debug) & LWIP_DBG_ON) && \ + ((debug) & LWIP_DBG_TYPES_ON) && \ + (((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL) ) + #include "lwip/def.h" #include "lwip/mem.h" #include "lwip/pbuf.h" @@ -66,6 +83,11 @@ #include <syslinux/pxe_api.h> #include <dprintf.h> +/* debug extras */ +#include "ipv4/lwip/icmp.h" +#include "lwip/tcp_impl.h" +#include "lwip/udp.h" + #if LWIP_AUTOIP #error "AUTOIP not supported" #endif @@ -100,7 +122,8 @@ PACK_STRUCT_BEGIN struct arp_hdr { PACK_STRUCT_FIELD(u16_t hwtype); PACK_STRUCT_FIELD(u16_t proto); - PACK_STRUCT_FIELD(u16_t _hwlen_protolen); + PACK_STRUCT_FIELD(u8_t hwlen); + PACK_STRUCT_FIELD(u8_t protolen); PACK_STRUCT_FIELD(u16_t opcode); } PACK_STRUCT_STRUCT; PACK_STRUCT_END @@ -151,6 +174,8 @@ static u8_t undiarp_cached_entry; #define UNDIARP_TRY_HARD 1 #define UNDIARP_FIND_ONLY 2 +#define UNIDIF_ID_STRLEN 300 + static inline bool undi_is_ethernet(struct netif *netif) { @@ -213,6 +238,154 @@ static void print_arp_pbuf(struct netif *netif, struct pbuf *p) } #endif +#if LWIP_UNDIIF_DBG(UNDIIF_ID_FULL_DEBUG) +int snprintf_eth_hdr(char *str, size_t size, char head[], + struct eth_hdr *ethhdr, char dir, char status, + char tail[]) +{ + u8_t *d = ethhdr->dest.addr; + u8_t *s = ethhdr->src.addr; + return snprintf(str, size, + "%s: d:%02x:%02x:%02x:%02x:%02x:%02x" + " s:%02x:%02x:%02x:%02x:%02x:%02x" + " t:%4hx %c%c%s\n", head, + d[0], d[1], d[2], d[3], d[4], d[5], + s[0], s[1], s[2], s[3], s[4], s[5], + (unsigned)htons(ethhdr->type), + dir, status, tail); +} + +int snprintf_arp_hdr(char *str, size_t size, char head[], + struct eth_hdr *ethhdr, char dir, + char status, char tail[]) +{ + struct etharp_hdr *arphdr; + u8_t *d, *s; + struct ip_addr *sip, *dip; + if (ntohs(ethhdr->type) == ETHTYPE_ARP) { + arphdr = (struct etharp_hdr *)((void *)ethhdr + 14); + d = arphdr->dhwaddr.addr; + s = arphdr->shwaddr.addr; + sip = (struct ip_addr *) &(arphdr->sipaddr); + dip = (struct ip_addr *) &(arphdr->dipaddr); + return snprintf(str, size, + "%s: s:%02x:%02x:%02x:%02x:%02x:%02x" + " %3d.%3d.%3d.%3d" + " %02x:%02x:%02x:%02x:%02x:%02x" + " %3d.%3d.%3d.%3d" + " %c%c%s\n", head, + s[0], s[1], s[2], s[3], s[4], s[5], + ip4_addr1(sip), ip4_addr2(sip), + ip4_addr3(sip), ip4_addr4(sip), + d[0], d[1], d[2], d[3], d[4], d[5], + ip4_addr1(dip), ip4_addr2(dip), + ip4_addr3(dip), ip4_addr4(dip), + dir, status, tail); + } else { + return 0; + } +} + +int snprintf_ip_hdr(char *str, size_t size, char head[], + struct eth_hdr *ethhdr, char dir, + char status, char tail[]) +{ + struct ip_hdr *iphdr; + if (ntohs(ethhdr->type) == ETHTYPE_IP) { + iphdr = (struct ip_hdr *)((void *)ethhdr + 14); + return snprintf(str, size, + "%s: s:%3d.%3d.%3d.%3d %3d.%3d.%3d.%3d l:%5d" + " i:%04x p:%04x c:%04x hl:%3d" + " %c%c%s\n", head, + ip4_addr1(&iphdr->src), ip4_addr2(&iphdr->src), + ip4_addr3(&iphdr->src), ip4_addr4(&iphdr->src), + ip4_addr1(&iphdr->dest), ip4_addr2(&iphdr->dest), + ip4_addr3(&iphdr->dest), ip4_addr4(&iphdr->dest), + ntohs(IPH_LEN(iphdr)), ntohs(IPH_ID(iphdr)), + IPH_PROTO(iphdr), ntohs(IPH_CHKSUM(iphdr)), + (IPH_HL(iphdr) << 2), + dir, status, tail); + } else { + return 0; + } +} + +int snprintf_icmp_hdr(char *str, size_t size, char head[], + struct eth_hdr *ethhdr, char dir, + char status, char tail[]) +{ + struct ip_hdr *iphdr; + struct icmp_echo_hdr *icmphdr; + if (ntohs(ethhdr->type) == ETHTYPE_IP) { + iphdr = (struct ip_hdr *)((void *)ethhdr + 14); + if (IPH_PROTO(iphdr) == IP_PROTO_ICMP) { + icmphdr = (struct icmp_echo_hdr *)((void *)iphdr + (IPH_HL(iphdr) << 2)); + return snprintf(str, size, + "%s: t:%02x c:%02x k:%04x" + " i:%04x s:%04x " + " %c%c%s\n", head, + icmphdr->type, icmphdr->code, ntohs(icmphdr->chksum), + ntohs(icmphdr->id), ntohs(icmphdr->seqno), + dir, status, tail); + } else { + return 0; + } + } else { + return 0; + } +} + +int snprintf_tcp_hdr(char *str, size_t size, char head[], + struct eth_hdr *ethhdr, char dir, + char status, char tail[]) +{ + struct ip_hdr *iphdr; + struct tcp_hdr *tcphdr; + if (ntohs(ethhdr->type) == ETHTYPE_IP) { + iphdr = (struct ip_hdr *)((void *)ethhdr + 14); + if (IPH_PROTO(iphdr) == IP_PROTO_TCP) { + tcphdr = (struct tcp_hdr *)((void *)iphdr + (IPH_HL(iphdr) << 2)); + u16_t lenfl = ntohs(tcphdr->_hdrlen_rsvd_flags); + return snprintf(str, size, + "%s: s:%5d %5d q:%08x a:%08x lf:%04x k:%04x" + " %c%c%s\n", head, + ntohs(tcphdr->src), ntohs(tcphdr->dest), + ntohl(tcphdr->seqno), ntohl(tcphdr->ackno), + lenfl, ntohs(tcphdr->chksum), + dir, status, tail); + } else { + return 0; + } + } else { + return 0; + } +} + +int snprintf_udp_hdr(char *str, size_t size, char head[], + struct eth_hdr *ethhdr, char dir, + char status, char tail[]) +{ + struct ip_hdr *iphdr; + struct udp_hdr *udphdr; + if (ntohs(ethhdr->type) == ETHTYPE_IP) { + iphdr = (struct ip_hdr *)((void *)ethhdr + 14); + if (IPH_PROTO(iphdr) == IP_PROTO_UDP) { + udphdr = (struct udp_hdr *)((void *)iphdr + (IPH_HL(iphdr) << 2)); + return snprintf(str, size, + "%s: s:%5d %5d l:%d c:%04x" + " %c%c%s\n", head, + ntohs(udphdr->src), ntohs(udphdr->dest), + ntohs(udphdr->len), ntohs(udphdr->chksum), + dir, status, tail); + } else { + return 0; + } + } else { + return 0; + } +} +#endif /* UNDIIF_ID_FULL_DEBUG */ + /** * In this function, the hardware should be initialized. * Called from undiif_init(). @@ -302,6 +475,29 @@ undi_transmit(struct netif *netif, struct pbuf *pbuf, static __lowmem char pkt_buf[PKTBUF_SIZE]; uint32_t now; static uint32_t first_xmit; +#if LWIP_UNDIIF_DBG(UNDIIF_ID_FULL_DEBUG) + char *str = malloc(UNIDIF_ID_STRLEN); + int strpos = 0; + struct eth_hdr *ethhdr = pbuf->payload; + + + strpos += snprintf(str + strpos, UNIDIF_ID_STRLEN - strpos, + "undi xmit thd '%s'\n", current()->name); + strpos += snprintf_eth_hdr(str + strpos, UNIDIF_ID_STRLEN - strpos, + "undi", ethhdr, 'x', '0', ""); + strpos += snprintf_arp_hdr(str + strpos, UNIDIF_ID_STRLEN - strpos, + " arp", ethhdr, 'x', '0', ""); + strpos += snprintf_ip_hdr(str + strpos, UNIDIF_ID_STRLEN - strpos, + " ip", ethhdr, 'x', '0', ""); + strpos += snprintf_icmp_hdr(str + strpos, UNIDIF_ID_STRLEN - strpos, + " icmp", ethhdr, 'x', '0', ""); + strpos += snprintf_tcp_hdr(str + strpos, UNIDIF_ID_STRLEN - strpos, + " tcp", ethhdr, 'x', '0', ""); + strpos += snprintf_udp_hdr(str + strpos, UNIDIF_ID_STRLEN - strpos, + " udp", ethhdr, 'x', '0', ""); + LWIP_DEBUGF(UNDIIF_ID_FULL_DEBUG, ("%s", str)); + free(str); +#endif /* UNDIIF_ID_FULL_DEBUG */ /* Drop jumbo frames */ if ((pbuf->tot_len > sizeof(pkt_buf)) || (pbuf->tot_len > netif->mtu)) @@ -313,6 +509,7 @@ undi_transmit(struct netif *netif, struct pbuf *pbuf, first_xmit = now; } else if (now - first_xmit > 3000) { /* 3 seconds after first transmit, and no interrupts */ + LWIP_PLATFORM_DIAG(("undiif: forcing polling\n")); asm volatile("orb $1,%0" : "+m" (pxe_need_poll)); asm volatile("incl %0" : "+m" (pxe_irq_count)); } @@ -375,14 +572,14 @@ undiarp_request(struct netif *netif, struct ip_addr *ipaddr) struct arp_hdr *hdr; u8_t *hdr_ptr; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_request: sending ARP request.\n")); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_request: sending ARP request.\n")); /* allocate a pbuf for the outgoing ARP request packet */ p = pbuf_alloc(PBUF_RAW, arp_hdr_len(netif), PBUF_RAM); /* could allocate a pbuf for an ARP request? */ if (p == NULL) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, - ("etharp_raw: could not allocate pbuf for ARP request.\n")); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, + ("undiarp_raw: could not allocate pbuf for ARP request.\n")); ETHARP_STATS_INC(etharp.memerr); return ERR_MEM; } @@ -390,12 +587,12 @@ undiarp_request(struct netif *netif, struct ip_addr *ipaddr) (p->len >= arp_hdr_len(netif))); hdr = p->payload; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("undiarp_request: sending raw ARP packet.\n")); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_request: sending raw ARP packet.\n")); hdr->opcode = htons(ARP_REQUEST); hdr->hwtype = htons(MAC_type); hdr->proto = htons(ETHTYPE_IP); - /* set hwlen and protolen together */ - hdr->_hwlen_protolen = htons((netif->hwaddr_len << 8) | sizeof(struct ip_addr)); + hdr->hwlen = netif->hwaddr_len; + hdr->protolen = sizeof(struct ip_addr); hdr_ptr = (unsigned char *)(hdr + 1); memcpy(hdr_ptr, netif->hwaddr, netif->hwaddr_len); @@ -450,7 +647,7 @@ undiarp_tmr(void) { u8_t i; - LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n")); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG, ("undiarp_timer\n")); /* remove expired entries from the ARP table */ for (i = 0; i < ARP_TABLE_SIZE; ++i) { arp_table[i].ctime++; @@ -459,7 +656,7 @@ undiarp_tmr(void) ((arp_table[i].state == UNDIARP_STATE_PENDING) && (arp_table[i].ctime >= UNDIARP_MAXPENDING))) { /* pending or stable entry has become old! */ - LWIP_DEBUGF(UNDIARP_DEBUG, ("etharp_timer: expired %s entry %"U16_F".\n", + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG , ("undiarp_timer: expired %s entry %"U16_F".\n", arp_table[i].state == UNDIARP_STATE_STABLE ? "stable" : "pending", (u16_t)i)); /* clean up entries that have just been expired */ /* remove from SNMP ARP index tree */ @@ -468,7 +665,7 @@ undiarp_tmr(void) /* and empty packet queue */ if (arp_table[i].q != NULL) { /* remove all queued packets */ - LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q))); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG , ("undiarp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q))); free_undiarp_q(arp_table[i].q); arp_table[i].q = NULL; } @@ -571,7 +768,7 @@ find_entry(struct ip_addr *ipaddr, u8_t flags) for (i = 0; i < ARP_TABLE_SIZE; ++i) { /* no empty entry found yet and now we do find one? */ if ((empty == ARP_TABLE_SIZE) && (arp_table[i].state == UNDIARP_STATE_EMPTY)) { - LWIP_DEBUGF(ETHARP_DEBUG, ("find_entry: found empty entry %"U16_F"\n", (u16_t)i)); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG , ("find_entry: found empty entry %"U16_F"\n", (u16_t)i)); /* remember first empty entry */ empty = i; } @@ -579,7 +776,7 @@ find_entry(struct ip_addr *ipaddr, u8_t flags) else if (arp_table[i].state == UNDIARP_STATE_PENDING) { /* if given, does IP address match IP address in ARP entry? */ if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching pending entry %"U16_F"\n", (u16_t)i)); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching pending entry %"U16_F"\n", (u16_t)i)); /* found exact IP address match, simply bail out */ #if LWIP_NETIF_HWADDRHINT NETIF_SET_HINT(netif, i); @@ -607,7 +804,7 @@ find_entry(struct ip_addr *ipaddr, u8_t flags) else if (arp_table[i].state == UNDIARP_STATE_STABLE) { /* if given, does IP address match IP address in ARP entry? */ if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching stable entry %"U16_F"\n", (u16_t)i)); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching stable entry %"U16_F"\n", (u16_t)i)); /* found exact IP address match, simply bail out */ #if LWIP_NETIF_HWADDRHINT NETIF_SET_HINT(netif, i); @@ -628,7 +825,7 @@ find_entry(struct ip_addr *ipaddr, u8_t flags) if (((empty == ARP_TABLE_SIZE) && ((flags & UNDIARP_TRY_HARD) == 0)) /* or don't create new entry, only search? */ || ((flags & UNDIARP_FIND_ONLY) != 0)) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty entry found and not allowed to recycle\n")); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty entry found and not allowed to recycle\n")); return (s8_t)ERR_MEM; } @@ -644,13 +841,13 @@ find_entry(struct ip_addr *ipaddr, u8_t flags) /* 1) empty entry available? */ if (empty < ARP_TABLE_SIZE) { i = empty; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting empty entry %"U16_F"\n", (u16_t)i)); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting empty entry %"U16_F"\n", (u16_t)i)); } /* 2) found recyclable stable entry? */ else if (old_stable < ARP_TABLE_SIZE) { /* recycle oldest stable*/ i = old_stable; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i)); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i)); #if ARP_QUEUEING /* no queued packets should exist on stable entries */ LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL); @@ -659,13 +856,13 @@ find_entry(struct ip_addr *ipaddr, u8_t flags) } else if (old_pending < ARP_TABLE_SIZE) { /* recycle oldest pending */ i = old_pending; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i)); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i)); #if ARP_QUEUEING /* 4) found recyclable pending entry with queued packets? */ } else if (old_queue < ARP_TABLE_SIZE) { /* recycle oldest pending */ i = old_queue; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q))); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q))); free_undiarp_q(arp_table[i].q); arp_table[i].q = NULL; #endif @@ -742,7 +939,7 @@ undiarp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q) if (ip_addr_isbroadcast(ipaddr, netif) || ip_addr_ismulticast(ipaddr) || ip_addr_isany(ipaddr)) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("undiarp_query: will not add non-unicast IP address to ARP cache\n")); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_query: will not add non-unicast IP address to ARP cache\n")); return ERR_ARG; } @@ -755,9 +952,9 @@ undiarp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q) /* could not find or create entry? */ if (i < 0) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("undiarp_query: could not create ARP entry\n")); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_query: could not create ARP entry\n")); if (q) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("undiarp_query: packet dropped\n")); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_query: packet dropped\n")); ETHARP_STATS_INC(etharp.memerr); } return (err_t)i; @@ -844,23 +1041,23 @@ undiarp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q) /* queue did not exist, first item in queue */ arp_table[i].q = new_entry; } - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("undiarp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); result = ERR_OK; } else { /* the pool MEMP_ARP_QUEUE is empty */ pbuf_free(p); - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); /* { result == ERR_MEM } through initialization */ } } else { ETHARP_STATS_INC(etharp.memerr); - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); /* { result == ERR_MEM } through initialization */ } #else /* ARP_QUEUEING == 0 */ /* q && state == PENDING && ARP_QUEUEING == 0 => result = ERR_MEM */ /* { result == ERR_MEM } through initialization */ - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: Ethernet destination address unknown, queueing disabled, packet %p dropped\n", (void *)q)); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_query: Ethernet destination address unknown, queueing disabled, packet %p dropped\n", (void *)q)); #endif } } @@ -1038,8 +1235,8 @@ update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, hwaddr_t *lladdr, u8_t flags) { s8_t i; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry()\n")); - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n", + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiif:update_arp_entry()\n")); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiif:update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n", ip4_addr1(ipaddr), ip4_addr2(ipaddr), ip4_addr3(ipaddr), ip4_addr4(ipaddr), (*lladdr)[0], (*lladdr)[1], (*lladdr)[2], (*lladdr)[3], (*lladdr)[4], (*lladdr)[5])); @@ -1047,7 +1244,7 @@ update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, if (ip_addr_isany(ipaddr) || ip_addr_isbroadcast(ipaddr, netif) || ip_addr_ismulticast(ipaddr)) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: will not add non-unicast IP address to ARP cache\n")); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiif:update_arp_entry: will not add non-unicast IP address to ARP cache\n")); return ERR_ARG; } /* find or create ARP entry */ @@ -1068,7 +1265,7 @@ update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, /* insert in SNMP ARP index tree */ snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr); - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i)); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiif:update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i)); /* update address */ memcpy(arp_table[i].hwaddr, lladdr, netif->hwaddr_len); @@ -1125,7 +1322,7 @@ undiarp_input(struct netif *netif, struct pbuf *p) /* drop short ARP packets: we have to check for p->len instead of p->tot_len here since a struct arp_hdr is pointed to p->payload, so it musn't be chained! */ if (p->len < arp_hdr_len(netif)) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("undiarp_input: packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len, (s16_t)SIZEOF_ETHARP_PACKET)); printf("short arp packet\n"); @@ -1138,11 +1335,12 @@ undiarp_input(struct netif *netif, struct pbuf *p) hdr = p->payload; /* RFC 826 "Packet Reception": */ if ((hdr->hwtype != htons(MAC_type)) || - (hdr->_hwlen_protolen != htons((netif->hwaddr_len << 8) | sizeof(struct ip_addr))) || + (hdr->hwlen != netif->hwaddr_len) || + (hdr->protolen != sizeof(struct ip_addr)) || (hdr->proto != htons(ETHTYPE_IP))) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("undiarp_input: packet dropped, wrong hw type, hwlen, proto, or protolen (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n", - hdr->hwtype, ARPH_HWLEN(hdr), hdr->proto, ARPH_PROTOLEN(hdr))); + hdr->hwtype, hdr->hwlen, hdr->proto, hdr->protolen)); ETHARP_STATS_INC(etharp.proterr); ETHARP_STATS_INC(etharp.drop); printf("malformed arp packet\n"); @@ -1188,11 +1386,11 @@ undiarp_input(struct netif *netif, struct pbuf *p) * reply. In any case, we time-stamp any existing ARP entry, * and possiby send out an IP packet that was queued on it. */ - LWIP_DEBUGF (ETHARP_DEBUG | LWIP_DBG_TRACE, ("undiarp_input: incoming ARP request\n")); + LWIP_DEBUGF (UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_input: incoming ARP request\n")); /* ARP request for our address? */ if (for_us) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("undiarp_input: replying to ARP request for our IP address\n")); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_input: replying to ARP request for our IP address\n")); /* Re-use pbuf to send ARP reply. Since we are re-using an existing pbuf, we can't call etharp_raw since that would allocate a new pbuf. */ @@ -1211,16 +1409,16 @@ undiarp_input(struct netif *netif, struct pbuf *p) /* we are not configured? */ } else if (netif->ip_addr.addr == 0) { /* { for_us == 0 and netif->ip_addr.addr == 0 } */ - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("undiarp_input: we are unconfigured, ARP request ignored.\n")); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_input: we are unconfigured, ARP request ignored.\n")); /* request was not directed to us */ } else { /* { for_us == 0 and netif->ip_addr.addr != 0 } */ - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("undiarp_input: ARP request was not for us.\n")); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_input: ARP request was not for us.\n")); } break; case ARP_REPLY: /* ARP reply. We already updated the ARP cache earlier. */ - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("undiarp_input: incoming ARP reply\n")); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_input: incoming ARP reply\n")); #if (LWIP_DHCP && DHCP_DOES_ARP_CHECK) /* DHCP wants to know about ARP replies from any host with an * IP address also offered to us by the DHCP server. We do not @@ -1230,7 +1428,7 @@ undiarp_input(struct netif *netif, struct pbuf *p) #endif break; default: - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("undiarp_input: ARP unknown opcode type %"S16_F"\n", htons(hdr->opcode))); + LWIP_DEBUGF(UNDIIF_ARP_DEBUG | UNDIIF_DEBUG | LWIP_DBG_TRACE, ("undiarp_input: ARP unknown opcode type %"S16_F"\n", htons(hdr->opcode))); ETHARP_STATS_INC(etharp.err); break; } @@ -1265,7 +1463,28 @@ void undiif_input(t_PXENV_UNDI_ISR *isr) if (undi_is_ethernet(&undi_netif)) { /* points to packet payload, which starts with an Ethernet header */ struct eth_hdr *ethhdr = p->payload; - +#if LWIP_UNDIIF_DBG(UNDIIF_ID_FULL_DEBUG) + char *str = malloc(UNIDIF_ID_STRLEN); + int strpos = 0; + + strpos += snprintf(str + strpos, UNIDIF_ID_STRLEN - strpos, + "undi recv thd '%s'\n", current()->name); + strpos += snprintf_eth_hdr(str + strpos, UNIDIF_ID_STRLEN - strpos, + "undi", ethhdr, 'r', '0', ""); + strpos += snprintf_arp_hdr(str + strpos, UNIDIF_ID_STRLEN - strpos, + " arp", ethhdr, 'r', '0', ""); + strpos += snprintf_ip_hdr(str + strpos, UNIDIF_ID_STRLEN - strpos, + " ip", ethhdr, 'r', '0', ""); + strpos += snprintf_icmp_hdr(str + strpos, UNIDIF_ID_STRLEN - strpos, + " icmp", ethhdr, 'r', '0', ""); + strpos += snprintf_tcp_hdr(str + strpos, UNIDIF_ID_STRLEN - strpos, + " tcp", ethhdr, 'r', '0', ""); + strpos += snprintf_udp_hdr(str + strpos, UNIDIF_ID_STRLEN - strpos, + " udp", ethhdr, 'r', '0', ""); + LWIP_DEBUGF(UNDIIF_ID_FULL_DEBUG, ("%s", str)); + free(str); +#endif /* UNDIIF_ID_FULL_DEBUG */ + switch (htons(ethhdr->type)) { /* IP or ARP packet? */ case ETHTYPE_IP: @@ -1277,7 +1496,7 @@ void undiif_input(t_PXENV_UNDI_ISR *isr) #endif /* PPPOE_SUPPORT */ /* full packet send to tcpip_thread to process */ if (tcpip_input(p, &undi_netif)!=ERR_OK) - { LWIP_DEBUGF(NETIF_DEBUG, ("undiif_input: IP input error\n")); + { LWIP_DEBUGF(UNDIIF_NET_DEBUG | UNDIIF_DEBUG, ("undiif_input: IP input error\n")); pbuf_free(p); p = NULL; } diff --git a/core/lzo/enter.ash b/core/lzo/enter.ash index c2aa0817..dc7782fd 100644 --- a/core/lzo/enter.ash +++ b/core/lzo/enter.ash @@ -45,12 +45,23 @@ // ************************************************************************/ +#if __SIZEOF_POINTER__ == 4 pushl %ebp pushl %edi pushl %esi pushl %ebx pushl %ecx pushl %edx +#elif __SIZEOF_POINTER__ == 8 + push %rbp + push %rdi + push %rsi + push %rbx + push %rcx + push %rdx +#else +#error "unsupported architecture" +#endif subl $12,%esp cld diff --git a/core/lzo/leave.ash b/core/lzo/leave.ash index 0fdb729f..cc48ce6b 100644 --- a/core/lzo/leave.ash +++ b/core/lzo/leave.ash @@ -65,12 +65,23 @@ negl %eax addl $12,%esp +#if __SIZEOF_POINTER__ == 4 popl %edx popl %ecx popl %ebx popl %esi popl %edi popl %ebp +#elif __SIZEOF_POINTER__ == 8 + pop %rdx + pop %rcx + pop %rbx + pop %rsi + pop %rdi + pop %rbp +#else +#error "unsupported architecture" +#endif #if 1 ret #else diff --git a/core/lzo/lzo_asm.h b/core/lzo/lzo_asm.h index 1188dd60..663ca1a0 100644 --- a/core/lzo/lzo_asm.h +++ b/core/lzo/lzo_asm.h @@ -45,10 +45,12 @@ // <asmconfig.h> ************************************************************************/ +/*support both i386 and x86_64 */ +/* #if !defined(__i386__) # error #endif - +*/ #if !defined(IN_CONFIGURE) #if defined(LZO_HAVE_CONFIG_H) # include <config.h> diff --git a/core/macros.inc b/core/macros.inc index e3aedca1..c8fbe8de 100644 --- a/core/macros.inc +++ b/core/macros.inc @@ -31,6 +31,11 @@ %endif %ifdef IS_PXELINUX %define MY_NAME 'PXELINUX' + %if IS_LPXELINUX > 0 + %define MY_TYPE 'lwIP' + %else + %define MY_TYPE 'PXE' + %endif %else %define IS_PXELINUX 0 %endif diff --git a/core/mem/free.c b/core/mem/free.c index d7f912b1..2d16cd1c 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); @@ -86,8 +82,18 @@ __export void free(void *ptr) dprintf("invalid arena type: %d\n", ARENA_TYPE_GET(ah->a.attrs)); #endif - sem_down(&__malloc_semaphore, 0); __free_block(ah); +} + +__export void free(void *ptr) +{ + dprintf("free(%p) @ %p\n", ptr, __builtin_return_address(0)); + + if ( !ptr ) + return; + + sem_down(&__malloc_semaphore, 0); + firmware->mem->free(ptr); sem_up(&__malloc_semaphore); /* Here we could insert code to return memory to the system. */ diff --git a/core/mem/init.c b/core/mem/init.c index d6a5f189..246d2e0c 100644 --- a/core/mem/init.c +++ b/core/mem/init.c @@ -4,6 +4,7 @@ #include "malloc.h" #include "core.h" #include <syslinux/memscan.h> +#include <dprintf.h> struct free_arena_header __core_malloc_head[NHEAP]; @@ -12,16 +13,17 @@ extern char __lowmem_heap[]; extern char free_high_memory[]; #define E820_MEM_MAX 0xfff00000 /* 4 GB - 1 MB */ -int scan_highmem_area(void *data, addr_t start, addr_t len, bool is_ram) +int scan_highmem_area(void *data, addr_t start, addr_t len, + enum syslinux_memmap_types type) { struct free_arena_header *fp; (void)data; - dprintf("start = %x, len = %x, is_ram = %d", start, len, is_ram); + dprintf("start = %x, len = %x, type = %d", start, len, type); if (start < 0x100000 || start > E820_MEM_MAX - || !is_ram) + || type != SMT_FREE) return 0; if (start < __com32.cs_memsize) { @@ -67,11 +69,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 f64850d1..b40c2f21 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> @@ -66,17 +67,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)); - - sem_down(&__malloc_semaphore, 0); - if (size) { /* Add the obligatory arena header, and round up */ size = (size + 2 * sizeof(struct arena_header) - 1) & ARENA_SIZE_MASK; @@ -90,6 +86,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)); + + sem_down(&__malloc_semaphore, 0); + p = firmware->mem->malloc(size, heap, tag); sem_up(&__malloc_semaphore); dprintf("%p\n", p); @@ -116,11 +124,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; @@ -228,6 +236,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/mem/tests/Makefile b/core/mem/tests/Makefile new file mode 100644 index 00000000..d1fb7867 --- /dev/null +++ b/core/mem/tests/Makefile @@ -0,0 +1,17 @@ +CFLAGS = -g -I$(topdir)/tests/unittest/include + +tests = meminit +.INTERMEDIATE: $(tests) + +all: banner $(tests) + for t in $(tests); \ + do printf " [+] $$t passed\n" ; ./$$t ; done + +banner: + printf " Running memory subsystem unit tests...\n" + +meminit: meminit.c ../init.c + +%: %.c + $(CC) $(CFLAGS) -o $@ $< + diff --git a/core/mem/tests/meminit.c b/core/mem/tests/meminit.c new file mode 100644 index 00000000..e6c25c71 --- /dev/null +++ b/core/mem/tests/meminit.c @@ -0,0 +1,115 @@ +#include "unittest/unittest.h" +#include "unittest/memmap.h" + +/* + * Fake data objects. + * + * These are the dependencies required by mem_init(). + */ +struct com32_sys_args { + unsigned long cs_memsize; +} __com32 = { + .cs_memsize = 4 +}; +char __lowmem_heap[32]; +char free_high_memory[32]; + +#include "../init.c" + +void __inject_free_block(struct free_arena_header *ah) +{ +} + +static unsigned long free_start = (unsigned long)free_high_memory; + +static inline bool free_list_empty(void) +{ + if (__com32.cs_memsize != free_start) + return false; + + return true; +} + +static struct test_memmap_entry *__test_entries; +static size_t __test_nr_entries; + +int syslinux_scan_memory(scan_memory_callback_t callback, void *data) +{ + struct test_memmap_entry *e; + int i; + + for (i = 0; i < __test_nr_entries; i++) { + e = &__test_entries[i]; + callback(data, e->start, e->size, e->type); + } + + return 0; +} + +void __setup(struct test_memmap_entry *entries, size_t nr_entries) +{ + uint16_t __fake_free_mem = 64; + + bios_free_mem = &__fake_free_mem; + + __test_entries = entries; + __test_nr_entries = nr_entries; +} + +/* + * scan_highmem_area() will prepend a free arena header if the size of + * the region is larger than the following expression. Using this small + * size allows us to test the interface safely without worrying about + * scan_highmem_area() writing data to random parts of our address + * space. + */ +#define safe_entry_sz ((2 * sizeof(struct arena_header)) - 1) + +/* + * Can we add SMT_RESERVED regions to the free list? + */ +static int test_mem_init_reserved(void) +{ + struct test_memmap_entry entries[] = { + 0x2000, safe_entry_sz, SMT_RESERVED, + 0x100000, safe_entry_sz, SMT_RESERVED, + 0x2fffff, safe_entry_sz, SMT_RESERVED, + 0x400000, safe_entry_sz, SMT_RESERVED, + }; + + __setup(entries, array_sz(entries)); + + mem_init(); + syslinux_assert_str(free_list_empty(), + "Added SMT_RESERVED regions to free list"); + return 0; +} + +/* + * Can we add regions outside of the valid address range? + */ +static int test_mem_limits(void) +{ + struct test_memmap_entry entries[] = { + 0x00000000, safe_entry_sz, SMT_FREE, + 0x000fffff, safe_entry_sz, SMT_FREE, + E820_MEM_MAX + 1, safe_entry_sz, SMT_FREE, + }; + + __setup(entries, array_sz(entries)); + + mem_init(); + syslinux_assert_str(free_list_empty(), + "Added regions outside of valid range to free list"); + + return 0; +} + + +int main(int argc, char **argv) +{ + test_mem_init_reserved(); + test_mem_limits(); + + return 0; +} diff --git a/core/path.c b/core/path.c new file mode 100644 index 00000000..8e517ca7 --- /dev/null +++ b/core/path.c @@ -0,0 +1,42 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2013 Intel Corporation; author: Matt Fleming + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston MA 02110-1301, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +#include <klibc/compiler.h> +#include <linux/list.h> +#include <fs.h> +#include <string.h> + +__export LIST_HEAD(PATH); + +__export struct path_entry *path_add(const char *str) +{ + struct path_entry *entry; + + if (!strlen(str)) + return NULL; + + entry = malloc(sizeof(*entry)); + if (!entry) + return NULL; + + entry->str = strdup(str); + if (!entry->str) + goto bail; + + list_add(&entry->list, &PATH); + + return entry; + +bail: + free(entry); + return NULL; +} diff --git a/core/plaincon.c b/core/plaincon.c index 8f8ca7ca..66c259eb 100644 --- a/core/plaincon.c +++ b/core/plaincon.c @@ -4,6 +4,7 @@ #include "bios.h" #include "graphics.h" +#include <syslinux/video.h> /* * Write a single character in AL to the console without @@ -13,6 +14,8 @@ __export void writechr(char data) { com32sys_t ireg, oreg; + memset(&ireg, 0, sizeof ireg); + memset(&oreg, 0, sizeof oreg); write_serial(data); /* write to serial port if needed */ if (UsingVGA & 0x8) diff --git a/core/pxeboot.c b/core/pxeboot.c new file mode 100644 index 00000000..d9960d81 --- /dev/null +++ b/core/pxeboot.c @@ -0,0 +1,41 @@ +/* + * Copyright 1994-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., 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. + */ + +#include <syslinux/video.h> +#include "pxe.h" +#include <com32.h> + +#define LOCALBOOT_MSG "Booting from local disk..." + +extern void local_boot16(void); + +/* + * Boot to the local disk by returning the appropriate PXE magic. + * AX contains the appropriate return code. + */ +__export void local_boot(uint16_t ax) +{ + com32sys_t ireg; + memset(&ireg, 0, sizeof ireg); + + syslinux_force_text_mode(); + + writestr(LOCALBOOT_MSG); + crlf(); + + /* Restore the environment we were called with */ + reset_pxe(); + + cleanup_hardware(); + + ireg.eax.w[0] = ax; + call16(local_boot16, &ireg, NULL); +} diff --git a/core/pxelinux-c.c b/core/pxelinux-c.c new file mode 100644 index 00000000..36831894 --- /dev/null +++ b/core/pxelinux-c.c @@ -0,0 +1,22 @@ +#include <syslinux/config.h> +#include <com32.h> + +extern void *StrucPtr; +extern void *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 */ + +__export void get_derivative_info(union syslinux_derivative_info *di) +{ + di->pxe.filesystem = SYSLINUX_FS_PXELINUX; + di->pxe.apiver = APIVer; + di->pxe.pxenvptr = &StrucPtr; + di->pxe.stack = &InitStack; + di->pxe.ipinfo = &IPInfo; + di->pxe.myip = IPInfo.myip; +} diff --git a/core/pxelinux.asm b/core/pxelinux.asm index d3215e72..64194d38 100644 --- a/core/pxelinux.asm +++ b/core/pxelinux.asm @@ -62,10 +62,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 @@ -157,7 +156,7 @@ _start1: ; mov eax,ROOT_FS_OPS xor ebp,ebp - pm_call fs_init + pm_call pm_fs_init section .rodata alignz 4 @@ -171,7 +170,8 @@ ROOT_FS_OPS: ; ; Initialize the idle mechanism ; - call reset_idle + extern reset_idle + pm_call reset_idle ; ; Now we're all set to start with our *real* business. @@ -290,7 +290,26 @@ KernelName resb FILENAME_MAX ; Mangled name for kernel ; Hardware cleanup common code ; -%include "localboot.inc" + section .text16 + global local_boot16:function hidden +local_boot16: + mov [LocalBootType],ax + lss sp,[InitStack] + pop gs + pop fs + pop es + pop ds + popad + mov ax,[cs:LocalBootType] + cmp ax,-1 ; localboot -1 == INT 18h + je .int18 + popfd + retf ; Return to PXE +.int18: + popfd + int 18h + jmp 0F000h:0FFF0h + hlt ; ; kaboom: write a message and bail out. Wait for quite a while, @@ -321,7 +340,7 @@ kaboom: .wait2: mov dx,[BIOS_timer] .wait3: call pollchar jnz .keypress - call do_idle + pm_call __idle cmp dx,[BIOS_timer] je .wait3 loop .wait2,ecx @@ -357,7 +376,7 @@ pxenv: jnz .store_stack .disable_timer: - call timer_cleanup + call bios_timer_cleanup .store_stack: pushf @@ -542,13 +561,14 @@ pxe_file_exit_hook: section .data16 global copyright_str, syslinux_banner -copyright_str db ' Copyright (C) 1994-' +copyright_str db 'Copyright (C) 1994-' asciidec YEAR db ' H. Peter Anvin et al', CR, LF, 0 err_bootfailed db CR, LF, 'Boot failed: press a key to retry, or wait for reset...', CR, LF, 0 bailmsg equ err_bootfailed localboot_msg db 'Booting from local disk...', CR, LF, 0 -syslinux_banner db CR, LF, MY_NAME, ' ', VERSION_STR, ' ', DATE_STR, ' ', 0 +syslinux_banner db CR, LF, MY_NAME, ' ', VERSION_STR, ' ', MY_TYPE, ' ' + db DATE_STR, ' ', 0 ; ; Misc initialized (data) variables @@ -556,17 +576,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/rawcon.c b/core/rawcon.c index 92f0898a..44030984 100644 --- a/core/rawcon.c +++ b/core/rawcon.c @@ -9,6 +9,7 @@ #include "bios.h" #include "graphics.h" |