aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--.gitmodules3
-rw-r--r--Makefile292
-rw-r--r--Makefile.private15
-rw-r--r--NEWS57
-rw-r--r--codepage/Makefile8
-rw-r--r--com32/Makefile21
-rw-r--r--com32/chain/Makefile4
-rw-r--r--com32/cmenu/Makefile32
-rw-r--r--com32/cmenu/libmenu/com32io.c6
-rw-r--r--com32/cmenu/libmenu/syslnx.c1
-rw-r--r--com32/elflink/ldlinux/Makefile25
-rw-r--r--com32/elflink/ldlinux/adv.c15
-rw-r--r--com32/elflink/ldlinux/advwrite.c10
-rw-r--r--com32/elflink/ldlinux/cli.c26
-rw-r--r--com32/elflink/ldlinux/execute.c6
-rw-r--r--com32/elflink/ldlinux/get_key.c25
-rw-r--r--com32/elflink/ldlinux/msg.c1
-rw-r--r--com32/elflink/ldlinux/readconfig.c182
-rw-r--r--com32/gfxboot/Makefile17
-rw-r--r--com32/gfxboot/gfxboot.c8
-rw-r--r--com32/gpllib/Makefile16
-rw-r--r--com32/gpllib/acpi/acpi.c1
-rw-r--r--com32/hdt/Makefile9
-rw-r--r--com32/hdt/hdt-cli.c2
-rw-r--r--com32/hdt/hdt-common.c2
-rw-r--r--com32/include/bitsize/limits.h12
-rw-r--r--com32/include/bitsize/stddef.h14
-rw-r--r--com32/include/bitsize/stdint.h25
-rw-r--r--com32/include/bitsize/stdintconst.h18
-rw-r--r--com32/include/bitsize/stdintlimits.h22
-rw-r--r--com32/include/bitsize32/limits.h14
-rw-r--r--com32/include/bitsize32/stddef.h9
-rw-r--r--com32/include/bitsize32/stdint.h24
-rw-r--r--com32/include/bitsize32/stdintconst.h13
-rw-r--r--com32/include/bitsize32/stdintlimits.h23
-rw-r--r--com32/include/bitsize64/limits.h14
-rw-r--r--com32/include/bitsize64/stddef.h10
-rw-r--r--com32/include/bitsize64/stdint.h24
-rw-r--r--com32/include/bitsize64/stdintconst.h13
-rw-r--r--com32/include/bitsize64/stdintlimits.h23
-rw-r--r--com32/include/com32.h4
-rw-r--r--com32/include/dprintf.h21
-rw-r--r--com32/include/klibc/i386/archsetjmp.h19
-rw-r--r--com32/include/klibc/x86_64/archsetjmp.h21
-rw-r--r--com32/include/setjmp.h8
-rw-r--r--com32/include/sys/bitops.h30
-rw-r--r--com32/include/sys/cpu.h162
-rw-r--r--com32/include/sys/elfcommon.h50
-rw-r--r--com32/include/sys/i386/bitops.h54
-rw-r--r--com32/include/sys/i386/cpu.h114
-rw-r--r--com32/include/sys/i386/module.h35
-rw-r--r--com32/include/sys/module.h46
-rw-r--r--com32/include/sys/x86_64/bitops.h55
-rw-r--r--com32/include/sys/x86_64/cpu.h128
-rw-r--r--com32/include/sys/x86_64/module.h35
-rw-r--r--com32/include/syslinux/config.h2
-rw-r--r--com32/include/syslinux/debug.h15
-rw-r--r--com32/include/syslinux/disk.h7
-rw-r--r--com32/include/syslinux/firmware.h71
-rw-r--r--com32/include/syslinux/linux.h106
-rw-r--r--com32/include/syslinux/memscan.h13
-rw-r--r--com32/include/syslinux/movebits.h22
-rw-r--r--com32/include/syslinux/pxe_api.h2
-rw-r--r--com32/include/syslinux/version.h6
-rw-r--r--com32/lib/Makefile159
-rw-r--r--com32/lib/i386/elf.ld (renamed from com32/lib/elf32.ld)4
-rw-r--r--com32/lib/i386/setjmp.S63
-rw-r--r--com32/lib/libgcc/__muldi3.S49
-rw-r--r--com32/lib/memcpy.S4
-rw-r--r--com32/lib/memcpy.c29
-rw-r--r--com32/lib/memmove.S4
-rw-r--r--com32/lib/memmove.c36
-rw-r--r--com32/lib/mempcpy.S4
-rw-r--r--com32/lib/mempcpy.c14
-rw-r--r--com32/lib/memset.S4
-rw-r--r--com32/lib/memset.c30
-rw-r--r--com32/lib/setjmp.S11
-rw-r--r--com32/lib/sys/ansi.h3
-rw-r--r--com32/lib/sys/ansicon_write.c89
-rw-r--r--com32/lib/sys/farcall.c10
-rw-r--r--com32/lib/sys/i386/x86_init_fpu.c58
-rw-r--r--com32/lib/sys/module/common.c141
-rw-r--r--com32/lib/sys/module/common.h11
-rw-r--r--com32/lib/sys/module/elf_module.c349
-rw-r--r--com32/lib/sys/module/elfutils.h19
-rw-r--r--com32/lib/sys/module/exec.c5
-rw-r--r--com32/lib/sys/module/i386/elf_module.c349
-rw-r--r--com32/lib/sys/module/x86_64/elf_module.c380
-rw-r--r--com32/lib/sys/vesa/initvesa.c218
-rw-r--r--com32/lib/sys/vesa/screencpy.c50
-rw-r--r--com32/lib/sys/vesa/vesa.h1
-rw-r--r--com32/lib/sys/vesa/video.h10
-rw-r--r--com32/lib/sys/vesacon_write.c3
-rw-r--r--com32/lib/sys/x86_64/x86_init_fpu.c58
-rw-r--r--com32/lib/sys/x86_init_fpu.c22
-rw-r--r--com32/lib/syslinux/cleanup.c2
-rw-r--r--com32/lib/syslinux/debug.c95
-rw-r--r--com32/lib/syslinux/disk.c180
-rw-r--r--com32/lib/syslinux/dsinfo.c9
-rw-r--r--com32/lib/syslinux/load_linux.c314
-rw-r--r--com32/lib/syslinux/memmap.c7
-rw-r--r--com32/lib/syslinux/memscan.c137
-rw-r--r--com32/lib/syslinux/movebits.c27
-rw-r--r--com32/lib/syslinux/serial.c15
-rw-r--r--com32/lib/syslinux/shuffle.c9
-rw-r--r--com32/lib/syslinux/shuffle_pm.c2
-rw-r--r--com32/lib/syslinux/shuffle_rm.c4
-rw-r--r--com32/lib/syslinux/tests/Makefile22
-rw-r--r--com32/lib/syslinux/tests/load_linux.c199
-rw-r--r--com32/lib/syslinux/tests/memscan.c75
-rw-r--r--com32/lib/syslinux/tests/movebits.c86
-rw-r--r--com32/lib/syslinux/tests/test-harness.c48
-rw-r--r--com32/lib/syslinux/tests/zonelist.c286
-rw-r--r--com32/lib/syslinux/version.c2
-rw-r--r--com32/lib/syslinux/zonelist.c133
-rw-r--r--com32/lib/x86_64/elf.ld173
-rw-r--r--com32/lib/x86_64/setjmp.S54
-rw-r--r--com32/libupload/Makefile10
-rw-r--r--com32/libupload/ctime.c2
-rw-r--r--com32/libutil/Makefile3
-rw-r--r--com32/lua/src/Makefile3
-rw-r--r--com32/lua/src/vesa.c3
-rw-r--r--com32/mboot/Makefile5
-rw-r--r--com32/mboot/apm.c2
-rw-r--r--com32/mboot/initvesa.c2
-rw-r--r--com32/mboot/map.c2
-rw-r--r--com32/mboot/mem.c3
-rw-r--r--com32/menu/Makefile9
-rw-r--r--com32/menu/readconfig.c8
-rw-r--r--com32/modules/Makefile5
-rw-r--r--com32/modules/debug.c54
-rw-r--r--com32/modules/ls.c2
-rw-r--r--com32/modules/meminfo.c2
-rw-r--r--com32/modules/poweroff.c5
-rw-r--r--com32/modules/prdhcp.c4
-rw-r--r--com32/modules/pxechn.c1
-rw-r--r--com32/modules/vesainfo.c2
-rw-r--r--com32/modules/zzjson.c6
-rw-r--r--com32/rosh/Makefile10
-rw-r--r--com32/rosh/rosh.c2
-rw-r--r--com32/samples/Makefile13
-rw-r--r--com32/samples/advdump.c6
-rw-r--r--com32/samples/entrydump.c6
-rw-r--r--com32/samples/resolv.c6
-rw-r--r--com32/samples/serialinfo.c6
-rw-r--r--com32/sysdump/Makefile11
-rw-r--r--com32/sysdump/cpuid.c11
-rw-r--r--com32/sysdump/memmap.c2
-rw-r--r--com32/sysdump/vesa.c1
-rw-r--r--com32/tools/Makefile4
-rw-r--r--core/Makefile139
-rw-r--r--core/bios.c704
-rw-r--r--core/call16.c10
-rw-r--r--core/cleanup.c23
-rw-r--r--core/comboot.inc51
-rw-r--r--core/common.inc1
-rw-r--r--core/conio.c47
-rw-r--r--core/diskboot.inc2
-rw-r--r--core/diskstart.inc2
-rw-r--r--core/elflink/load_env32.c54
-rw-r--r--core/extern.inc2
-rw-r--r--core/font.c42
-rw-r--r--core/fs/diskio.c389
-rw-r--r--core/fs/diskio_bios.c401
-rw-r--r--core/fs/fat/fat.c3
-rw-r--r--core/fs/fs.c18
-rw-r--r--core/fs/pxe/bios.c430
-rw-r--r--core/fs/pxe/core.c184
-rw-r--r--core/fs/pxe/dhcp_option.c2
-rw-r--r--core/fs/pxe/ftp.c39
-rw-r--r--core/fs/pxe/http.c34
-rw-r--r--core/fs/pxe/isr.c24
-rw-r--r--core/fs/pxe/pxe.c402
-rw-r--r--core/fs/pxe/pxe.h25
-rw-r--r--core/fs/pxe/tcp.c59
-rw-r--r--core/fs/pxe/tftp.c77
-rw-r--r--core/graphics.c4
-rw-r--r--core/head.inc1
-rw-r--r--core/i386/syslinux.ld428
-rw-r--r--core/idle.c4
-rw-r--r--core/idle.inc80
-rw-r--r--core/include/bios.h23
-rw-r--r--core/include/core.h25
-rw-r--r--core/include/disk.h10
-rw-r--r--core/include/fs.h13
-rw-r--r--core/include/graphics.h3
-rw-r--r--core/include/mbox.h5
-rw-r--r--core/include/net.h33
-rw-r--r--core/include/thread.h5
-rw-r--r--core/init.c86
-rw-r--r--core/init.inc4
-rw-r--r--core/isolinux-c.c22
-rw-r--r--core/isolinux.asm14
-rw-r--r--core/kaboom.c2
-rw-r--r--core/ldlinux-c.c19
-rw-r--r--core/legacynet/core.c55
-rw-r--r--core/legacynet/dnsresolv.c35
-rw-r--r--core/localboot.c5
-rw-r--r--core/lwip/src/arch/sys_arch.c7
-rw-r--r--core/lwip/src/include/arch/cc.h14
-rw-r--r--core/lwip/src/include/lwip/opt.h28
-rw-r--r--core/lwip/src/netif/undiif.c301
-rw-r--r--core/lzo/enter.ash11
-rw-r--r--core/lzo/leave.ash11
-rw-r--r--core/lzo/lzo_asm.h4
-rw-r--r--core/macros.inc5
-rw-r--r--core/mem/free.c20
-rw-r--r--core/mem/init.c10
-rw-r--r--core/mem/malloc.c29
-rw-r--r--core/mem/tests/Makefile17
-rw-r--r--core/mem/tests/meminit.c115
-rw-r--r--core/path.c42
-rw-r--r--core/plaincon.c3
-rw-r--r--core/pxeboot.c41
-rw-r--r--core/pxelinux-c.c22
-rw-r--r--core/pxelinux.asm52
-rw-r--r--core/rawcon.c2
-rw-r--r--core/syslinux.ld1
-rw-r--r--core/thread/mbox.c22
-rw-r--r--core/thread/semaphore.c28
-rw-r--r--core/timer.inc4
-rw-r--r--core/vkernel.inc35
-rw-r--r--core/x86_64/syslinux.ld428
-rw-r--r--diag/Makefile5
-rw-r--r--diag/geodsp/Makefile11
-rw-r--r--diag/geodsp/README32
-rw-r--r--diag/mbr/Makefile5
-rw-r--r--doc/building.txt40
-rw-r--r--doc/syslinux.txt8
-rw-r--r--dos/Makefile18
-rw-r--r--dos/getsetsl.c17
-rw-r--r--dos/stdlib.h7
-rw-r--r--dos/syslinux.c46
-rw-r--r--dosutil/Makefile8
-rw-r--r--efi/Makefile107
-rw-r--r--efi/adv.c297
-rw-r--r--efi/adv.h27
-rwxr-xr-xefi/build-gnu-efi.sh40
-rwxr-xr-xefi/check-gnu-efi.sh36
-rw-r--r--efi/console.c312
-rw-r--r--efi/cp865_8x16.h293
-rw-r--r--efi/derivative.c23
-rw-r--r--efi/diskio.c92
-rw-r--r--efi/efi.h83
-rw-r--r--efi/fio.c283
-rw-r--r--efi/fio.h43
-rw-r--r--efi/i386/linux.S50
-rw-r--r--efi/i386/syslinux.ld173
-rw-r--r--efi/main.c1351
-rw-r--r--efi/mem.c27
-rw-r--r--efi/pxe.c140
-rw-r--r--efi/syslinux.ld176
-rw-r--r--efi/tcp.c254
-rw-r--r--efi/udp.c417
-rw-r--r--efi/vesa.c310
-rw-r--r--efi/wrapper.c361
-rw-r--r--efi/wrapper.h166
-rw-r--r--efi/x86_64/linux.S63
-rw-r--r--efi/x86_64/syslinux.ld173
-rw-r--r--extlinux/Makefile8
-rw-r--r--extlinux/main.c18
m---------gnu-efi0
-rw-r--r--gpxe/Makefile21
-rw-r--r--libinstaller/Makefile26
-rw-r--r--libinstaller/syslinux.h12
-rw-r--r--libinstaller/syslxint.h97
-rw-r--r--libinstaller/syslxmod.c40
-rw-r--r--libinstaller/syslxopt.c4
-rw-r--r--linux/Makefile8
-rwxr-xr-xlinux/syslinux.c12
-rw-r--r--lzo/Makefile12
-rw-r--r--man/isohybrid.164
-rw-r--r--man/memdiskfind.110
-rw-r--r--mbr/Makefile15
-rw-r--r--mbr/gptmbr.S2
-rw-r--r--mbr/i386/mbr.ld73
-rw-r--r--mbr/x86_64/mbr.ld72
-rw-r--r--memdisk/Makefile18
-rw-r--r--memdisk/conio.c1
-rw-r--r--memdisk/i386/memdisk.ld140
-rw-r--r--memdisk/memcpy.c29
-rw-r--r--memdisk/memdisk.h3
-rw-r--r--memdisk/memmove.c36
-rw-r--r--memdisk/memset.c30
-rw-r--r--memdisk/setup.c9
-rw-r--r--memdisk/start32.S6
-rw-r--r--memdisk/x86_64/memdisk.ld140
-rw-r--r--memdump/Makefile11
-rw-r--r--memdump/code16.h2
-rw-r--r--mk/com32.mk42
-rw-r--r--mk/devel.mk7
-rw-r--r--mk/efi.mk67
-rw-r--r--mk/elf.mk46
-rw-r--r--mk/embedded.mk31
-rw-r--r--mk/lib.mk190
-rw-r--r--mk/syslinux.mk6
-rwxr-xr-xmtools/Makefile10
-rwxr-xr-xmtools/syslinux.c12
-rw-r--r--sample/Makefile3
-rw-r--r--tests/Makefile79
-rw-r--r--tests/README15
-rwxr-xr-xtests/build-pxelinux51
-rwxr-xr-xtests/build-syslinux70
-rw-r--r--tests/com32/Makefile35
-rw-r--r--tests/com32/chaindisk.cfg7
-rw-r--r--tests/com32/chaindisk.results1
-rw-r--r--tests/com32/hdt.cfg5
-rw-r--r--tests/com32/hdt.results2
-rw-r--r--tests/linux/Makefile49
-rw-r--r--tests/linux/cmdline.cfg5
-rw-r--r--tests/linux/cmdline.results3
-rw-r--r--tests/linux/empty-vmlinuz0
-rw-r--r--tests/linux/empty.cfg3
-rw-r--r--tests/linux/empty.results2
-rw-r--r--tests/linux/kernelhello-vmlinuzbin0 -> 6843584 bytes
-rw-r--r--tests/linux/kernelhello.cfg5
-rw-r--r--tests/linux/kernelhello.results1
-rw-r--r--tests/linux/pxetest.cfg12
-rw-r--r--tests/linux/pxetest.results3
-rw-r--r--tests/recipes.mk71
-rw-r--r--tests/test.cfg6
-rw-r--r--tests/unittest/include/com32.h1
-rw-r--r--tests/unittest/include/core.h8
-rw-r--r--tests/unittest/include/dprintf.h6
-rw-r--r--tests/unittest/include/klibc/compiler.h15
-rw-r--r--tests/unittest/include/linux/list.h9
-rw-r--r--tests/unittest/include/minmax.h1
-rw-r--r--tests/unittest/include/pxe.h3
-rw-r--r--tests/unittest/include/suffix_number.h1
-rw-r--r--tests/unittest/include/syslinux/align.h1
-rw-r--r--tests/unittest/include/syslinux/bootrm.h1
-rw-r--r--tests/unittest/include/syslinux/firmware.h1
-rw-r--r--tests/unittest/include/syslinux/linux.h1
-rw-r--r--tests/unittest/include/syslinux/memscan.h1
-rw-r--r--tests/unittest/include/syslinux/movebits.h1
-rw-r--r--tests/unittest/include/syslinux/video.h1
-rw-r--r--tests/unittest/include/thread.h0
-rw-r--r--tests/unittest/include/unittest/memmap.h17
-rw-r--r--tests/unittest/include/unittest/unittest.h29
-rw-r--r--txt/Makefile19
-rw-r--r--txt/com-derv.txt11
-rw-r--r--txt/isolinux.txt116
-rw-r--r--txt/pxelinux.txt461
-rw-r--r--txt/syslinux-cli.txt30
-rw-r--r--txt/syslinux.cfg.txt169
-rw-r--r--txt/syslinux.txt14
-rw-r--r--utils/Makefile22
-rw-r--r--utils/isohybrid.c4
-rw-r--r--version2
-rw-r--r--win/syslinux.c8
-rw-r--r--win32/Makefile15
-rw-r--r--win32/ntfstest/Makefile2
-rw-r--r--win64/Makefile15
-rw-r--r--win64/ntfstest/Makefile2
355 files changed, 16275 insertions, 3604 deletions
diff --git a/.gitignore b/.gitignore
index 867e8220..35a3c187 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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
diff --git a/Makefile b/Makefile
index be3425b8..cceb66ef 100644
--- a/Makefile
+++ b/Makefile
@@ -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 \
diff --git a/NEWS b/NEWS
index 299028dc..6468951d 100644
--- a/NEWS
+++ b/NEWS
@@ -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, &reg, NULL);
-
- reg.eax.w[0] = 0x001c;
- __intcall(0x22, &reg, &reg);
- __syslinux_adv_ptr = MK_PTR(reg.es, reg.ebx.w[0]);
- __syslinux_adv_size = reg.ecx.w[0];
+ firmware->adv_ops->init();
}
diff --git a/com32/elflink/ldlinux/advwrite.c b/com32/elflink/ldlinux/advwrite.c
index 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, &reg, &reg);
- 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, &regs);
+ 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, &regstub, &stublen, 1);
+ rv = syslinux_memmap_find_type(tmap, SMT_FREE, &regstub, &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, &regstub, &stublen, 16);
+ rv = syslinux_memmap_find_type(tmap, SMT_FREE, &regstub, &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, &regstub, &stublen, 16);
+ rv = syslinux_memmap_find_type(tmap, SMT_FREE, &regstub, &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(&reg, 0, sizeof(reg));
+ reg.eax.w[0] = 0x0025;
+ __intcall(0x22, &reg, &reg);
+
+ memset(&reg, 0, sizeof(reg));
+ reg.eax.w[0] = 0x001c;
+ __intcall(0x22, &reg, &reg);
+ __syslinux_adv_ptr = MK_PTR(reg.es, reg.ebx.w[0]);
+ __syslinux_adv_size = reg.ecx.w[0];
+}
+
+int bios_adv_write(void)
+{
+ static com32sys_t reg;
+
+ memset(&reg, 0, sizeof(reg));
+ reg.eax.w[0] = 0x001d;
+ __intcall(0x22, &reg, &reg);
+ return (reg.eflags.l & EFLAGS_CF) ? -1 : 0;
+}
+
+struct adv_ops bios_adv_ops = {
+ .init = bios_adv_init,
+ .write = bios_adv_write,
+};
+
+
+static int __constfunc is_power_of_2(unsigned int x)
+{
+ return x && !(x & (x - 1));
+}
+
+static int vesacon_paged_mode_ok(const struct vesa_mode_info *mi)
+{
+ int i;
+
+ if (!is_power_of_2(mi->win_size) ||
+ !is_power_of_2(mi->win_grain) || mi->win_grain > mi->win_size)
+ return 0; /* Impossible... */
+
+ for (i = 0; i < 2; i++) {
+ if ((mi->win_attr[i] & 0x05) == 0x05 && mi->win_seg[i])
+ return 1; /* Usable window */
+ }
+
+ return 0; /* Nope... */
+}
+
+static int bios_vesacon_set_mode(struct vesa_info *vesa_info, int *px, int *py,
+ enum vesa_pixel_format *bestpxf)
+{
+ com32sys_t rm;
+ uint16_t mode, bestmode, *mode_ptr;
+ struct vesa_info *vi;
+ struct vesa_general_info *gi;
+ struct vesa_mode_info *mi;
+ enum vesa_pixel_format pxf;
+ int x = *px, y = *py;
+ int err = 0;
+
+ /* Allocate space in the bounce buffer for these structures */
+ vi = lzalloc(sizeof *vi);
+ if (!vi) {
+ err = 10; /* Out of memory */
+ goto exit;
+ }
+ gi = &vi->gi;
+ mi = &vi->mi;
+
+ memset(&rm, 0, sizeof rm);
+
+ gi->signature = VBE2_MAGIC; /* Get VBE2 extended data */
+ rm.eax.w[0] = 0x4F00; /* Get SVGA general information */
+ rm.edi.w[0] = OFFS(gi);
+ rm.es = SEG(gi);
+ __intcall(0x10, &rm, &rm);
+
+ if (rm.eax.w[0] != 0x004F) {
+ err = 1; /* Function call failed */
+ goto exit;
+ }
+ if (gi->signature != VESA_MAGIC) {
+ err = 2; /* No magic */
+ goto exit;
+ }
+ if (gi->version < 0x0102) {
+ err = 3; /* VESA 1.2+ required */
+ goto exit;
+ }
+
+ /* Copy general info */
+ memcpy(&vesa_info->gi, gi, sizeof *gi);
+
+ /* Search for the proper mode with a suitable color and memory model... */
+
+ mode_ptr = GET_PTR(gi->video_mode_ptr);
+ bestmode = 0;
+ *bestpxf = PXF_NONE;
+
+ while ((mode = *mode_ptr++) != 0xFFFF) {
+ mode &= 0x1FF; /* The rest are attributes of sorts */
+
+ debug("Found mode: 0x%04x\r\n", mode);
+
+ memset(&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(&regs->eax.w[0], &regs->ecx.w[0], &regs->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 *)&regs->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(&regs, 0, sizeof regs);
+ regs.eax.w[0] = 0x5650;
+ call16(pxe_int1a, &regs, &regs);
+ 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(&regs, 0, sizeof regs);
- regs.eax.w[0] = 0x5650;
- call16(pxe_int1a, &regs, &regs);
- 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"