aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2012-07-27 10:41:30 +0100
committerMatt Fleming <matt.fleming@intel.com>2012-07-30 09:51:36 +0100
commit0d6f330878173c7ba45b884f3e41ce40b917c73c (patch)
tree0a887066d35d8b01914330d6ab6818fe015a5a9d
parent0fcd9a48603497dcc2727570a50a4401bb0fd085 (diff)
parentf0bbf9dd40f37f8c4870a33784996efd56955a75 (diff)
downloadsyslinux-0d6f330878173c7ba45b884f3e41ce40b917c73c.tar.gz
syslinux-0d6f330878173c7ba45b884f3e41ce40b917c73c.tar.xz
syslinux-0d6f330878173c7ba45b884f3e41ce40b917c73c.zip
Merge remote-tracking branch 'mfleming/elflink' into for-hpa/elflink/firmware
Conflicts: Makefile com32/elflink/ldlinux/adv.c com32/elflink/ldlinux/kernel.c com32/elflink/ldlinux/ldlinux.c com32/include/bitsize/stddef.h com32/include/bitsize/stdint.h com32/include/stdint.h com32/include/sys/module.h com32/include/sys/x86_64/bitops.h com32/include/syslinux/linux.h com32/lib/Makefile com32/lib/sys/ansicon_write.c com32/lib/sys/module/elfutils.h com32/lib/sys/vesa/efi/fill.h com32/lib/syslinux/load_linux.c com32/lib/syslinux/serial.c com32/lib/syslinux/shuffle.c core/conio.c core/elflink/config.c core/elflink/load_env32.c core/graphics.c core/include/graphics.h core/init.c core/pxelinux.asm mk/elf.mk mk/lib.mk
-rw-r--r--Makefile15
-rw-r--r--Makefile.private5
-rw-r--r--NEWS11
-rw-r--r--com32/Makefile5
-rw-r--r--com32/chain/Makefile42
-rw-r--r--com32/chain/chain.c658
-rw-r--r--com32/chain/chain.h14
-rw-r--r--com32/chain/common.h9
-rw-r--r--com32/chain/mangle.c618
-rw-r--r--com32/chain/mangle.h32
-rw-r--r--com32/chain/options.c376
-rw-r--r--com32/chain/options.h47
-rw-r--r--com32/chain/partiter.c805
-rw-r--r--com32/chain/partiter.h107
-rw-r--r--com32/chain/utility.c204
-rw-r--r--com32/chain/utility.h30
-rw-r--r--com32/cmenu/Makefile14
-rw-r--r--com32/cmenu/libmenu/syslnx.c43
-rw-r--r--com32/elflink/Makefile8
-rw-r--r--com32/elflink/ldlinux/Makefile7
-rw-r--r--com32/elflink/ldlinux/adv.c6
-rw-r--r--com32/elflink/ldlinux/chainboot.c157
-rw-r--r--com32/elflink/ldlinux/cli.c103
-rw-r--r--com32/elflink/ldlinux/config.h7
-rw-r--r--com32/elflink/ldlinux/eprintf.c1
-rw-r--r--com32/elflink/ldlinux/execute.c102
-rw-r--r--com32/elflink/ldlinux/get_key.c10
-rw-r--r--com32/elflink/ldlinux/kernel.c54
-rw-r--r--com32/elflink/ldlinux/ldlinux.c235
-rw-r--r--com32/elflink/ldlinux/loadhigh.c (renamed from core/fs/loadhigh.c)2
-rw-r--r--com32/elflink/ldlinux/readconfig.c47
-rw-r--r--com32/gfxboot/gfxboot.c2
-rw-r--r--com32/gpllib/disk/geom.c11
-rw-r--r--com32/gpllib/disk/labels.c179
-rw-r--r--com32/gpllib/disk/read.c25
-rw-r--r--com32/gpllib/disk/write.c26
-rw-r--r--com32/gpllib/memory.c15
-rw-r--r--com32/hdt/.gitignore1
-rw-r--r--com32/hdt/Makefile13
-rw-r--r--com32/hdt/floppy/hdt.cfg9
-rw-r--r--com32/hdt/hdt-cli-acpi.c2
-rw-r--r--com32/hdt/hdt-cli-disk.c3
-rw-r--r--com32/hdt/hdt-cli-dmi.c15
-rw-r--r--com32/hdt/hdt-cli-hdt.c87
-rw-r--r--com32/hdt/hdt-cli-memory.c5
-rw-r--r--com32/hdt/hdt-cli-pci.c3
-rw-r--r--com32/hdt/hdt-cli-vesa.c5
-rw-r--r--com32/hdt/hdt-cli.c47
-rw-r--r--com32/hdt/hdt-cli.h2
-rw-r--r--com32/hdt/hdt-common.c47
-rw-r--r--com32/hdt/hdt-common.h5
-rw-r--r--com32/hdt/hdt-dump-disks.c12
-rw-r--r--com32/hdt/hdt-dump.c192
-rw-r--r--com32/hdt/hdt-menu-summary.c3
-rw-r--r--com32/hdt/hdt.c15
-rw-r--r--com32/hdt/hdt.h4
-rw-r--r--com32/include/bitsize/stddef.h14
-rw-r--r--com32/include/bitsize/stdint.h71
-rw-r--r--com32/include/bitsize/stdintconst.h2
-rw-r--r--com32/include/bitsize/stdintlimits.h2
-rw-r--r--com32/include/bitsize32/limits.h4
-rw-r--r--com32/include/bitsize32/stddef.h6
-rw-r--r--com32/include/bitsize32/stdint.h17
-rw-r--r--com32/include/bitsize64/limits.h4
-rw-r--r--com32/include/bitsize64/stddef.h2
-rw-r--r--com32/include/bitsize64/stdint.h17
-rw-r--r--com32/include/com32.h14
-rw-r--r--com32/include/dhcp.h40
-rw-r--r--com32/include/dprintf.h24
-rw-r--r--com32/include/hw/vga.h104
-rw-r--r--com32/include/klibc/compiler.h7
-rw-r--r--com32/include/linux/list.h13
-rw-r--r--com32/include/menu.h9
-rw-r--r--com32/include/stdint.h192
-rw-r--r--com32/include/string.h1
-rw-r--r--com32/include/sys/exec.h23
-rw-r--r--com32/include/sys/i386/module.h360
-rw-r--r--com32/include/sys/module.h345
-rw-r--r--com32/include/sys/x86_64/module.h360
-rw-r--r--com32/include/syslinux/boot.h12
-rw-r--r--com32/include/syslinux/config.h9
-rw-r--r--com32/include/syslinux/disk.h180
-rw-r--r--com32/include/syslinux/features.h10
-rw-r--r--com32/include/syslinux/firmware.h12
-rw-r--r--com32/include/syslinux/linux.h29
-rw-r--r--com32/include/syslinux/movebits.h9
-rw-r--r--com32/include/syslinux/pxe_api.h4
-rw-r--r--com32/lib/Makefile23
-rw-r--r--com32/lib/com32.ld33
-rw-r--r--com32/lib/dhcppack.c166
-rw-r--r--com32/lib/dhcpunpack.c116
-rw-r--r--com32/lib/dprintf.c8
-rw-r--r--com32/lib/elf32.ld10
-rw-r--r--com32/lib/getcwd.c1
-rw-r--r--com32/lib/lmalloc.c9
-rw-r--r--com32/lib/lstrdup.c2
-rw-r--r--com32/lib/pci/scan.c13
-rw-r--r--com32/lib/strreplace.c (renamed from com32/lib/syslinux/features.c)45
-rw-r--r--com32/lib/sys/ansicon_write.c115
-rw-r--r--com32/lib/sys/fileclose.c1
-rw-r--r--com32/lib/sys/fileread.c1
-rw-r--r--com32/lib/sys/gpxe.c19
-rw-r--r--com32/lib/sys/module/common.c115
-rw-r--r--com32/lib/sys/module/common.h14
-rw-r--r--com32/lib/sys/module/elf_module.c169
-rw-r--r--com32/lib/sys/module/elfutils.c4
-rw-r--r--com32/lib/sys/module/elfutils.h72
-rw-r--r--com32/lib/sys/module/exec.c87
-rw-r--r--com32/lib/sys/module/i386/common.c571
-rw-r--r--com32/lib/sys/module/i386/elf_module.c176
-rw-r--r--com32/lib/sys/module/i386/elfutils.h64
-rw-r--r--com32/lib/sys/module/shallow_module.c8
-rw-r--r--com32/lib/sys/module/x86_64/common.c567
-rw-r--r--com32/lib/sys/module/x86_64/elf_module.c190
-rw-r--r--com32/lib/sys/open.c1
-rw-r--r--com32/lib/sys/rawcon_read.c35
-rw-r--r--com32/lib/sys/rawcon_write.c8
-rw-r--r--com32/lib/sys/serial_write.c8
-rw-r--r--com32/lib/sys/stdcon_write.c15
-rw-r--r--com32/lib/sys/xserial_write.c8
-rw-r--r--com32/lib/syslinux/cleanup.c12
-rw-r--r--com32/lib/syslinux/disk.c569
-rw-r--r--com32/lib/syslinux/dump_mmap.c12
-rw-r--r--com32/lib/syslinux/dump_movelist.c9
-rw-r--r--com32/lib/syslinux/idle.c1
-rw-r--r--com32/lib/syslinux/ipappend.c (renamed from com32/elflink/ldlinux/ipappend.c)18
-rw-r--r--com32/lib/syslinux/keyboard.c14
-rw-r--r--com32/lib/syslinux/load_linux.c97
-rw-r--r--com32/lib/syslinux/localboot.c10
-rw-r--r--com32/lib/syslinux/movebits.c42
-rw-r--r--com32/lib/syslinux/pxe_dns.c14
-rw-r--r--com32/lib/syslinux/pxe_get_cached.c11
-rw-r--r--com32/lib/syslinux/pxe_get_nic.c12
-rw-r--r--com32/lib/syslinux/run_command.c9
-rw-r--r--com32/lib/syslinux/run_default.c10
-rw-r--r--com32/lib/syslinux/runimage.c19
-rw-r--r--com32/lib/syslinux/serial.c25
-rw-r--r--com32/lib/syslinux/setup_data.c47
-rw-r--r--com32/lib/syslinux/shuffle.c27
-rw-r--r--com32/lib/syslinux/version.c21
-rw-r--r--com32/lib/syslinux/video/fontquery.c16
-rw-r--r--com32/lib/syslinux/video/reportmode.c11
-rw-r--r--com32/lib/syslinux/zonelist.c24
-rw-r--r--com32/lib/vdprintf.c17
-rw-r--r--com32/libupload/cpio.c2
-rw-r--r--com32/libupload/upload_tftp.c18
-rw-r--r--com32/libutil/Makefile2
-rw-r--r--com32/lua/src/Makefile1
-rw-r--r--com32/lua/src/dhcp.c358
-rw-r--r--com32/lua/src/dhcp.h (renamed from com32/lib/syslinux/config.c)34
-rw-r--r--com32/lua/src/linit.c1
-rw-r--r--com32/lua/src/lualib.h3
-rw-r--r--com32/lua/src/syslinux.c4
-rw-r--r--com32/lua/src/vesa.c31
-rw-r--r--com32/mboot/initvesa.c43
-rw-r--r--com32/mboot/map.c5
-rw-r--r--com32/mboot/mem.c35
-rw-r--r--com32/menu/Makefile6
-rw-r--r--com32/menu/execute.c69
-rw-r--r--com32/menu/menumain.c22
-rw-r--r--com32/menu/readconfig.c6
-rw-r--r--com32/modules/Makefile21
-rw-r--r--com32/modules/chain.c1868
-rw-r--r--com32/modules/elf.c16
-rw-r--r--com32/modules/ethersel.c7
-rw-r--r--com32/modules/gpxecmd.c16
-rw-r--r--com32/modules/hello.c2
-rw-r--r--com32/modules/host.c46
-rw-r--r--com32/modules/ifcpu.c25
-rw-r--r--com32/modules/ifmemdsk.c392
-rw-r--r--com32/modules/linux.c95
-rw-r--r--com32/modules/meminfo.c10
-rw-r--r--com32/modules/pcitest.c7
-rw-r--r--com32/modules/pmload.c16
-rw-r--r--com32/modules/pxechn.c1106
-rw-r--r--com32/modules/sanboot.c16
-rw-r--r--com32/modules/vesainfo.c4
-rw-r--r--com32/rosh/Makefile2
-rw-r--r--com32/samples/Makefile3
-rw-r--r--com32/samples/resolv.c17
-rw-r--r--com32/tools/Makefile2
-rw-r--r--com32/tools/include/tools/le_byteshift.h70
-rw-r--r--com32/tools/relocs.c305
-rw-r--r--core/Makefile6
-rw-r--r--core/bios.c217
-rw-r--r--core/comboot.inc15
-rw-r--r--core/conio.c28
-rw-r--r--core/console.c7
-rw-r--r--core/diskboot.inc1
-rw-r--r--core/diskfs.inc57
-rw-r--r--core/elflink/load_env32.c86
-rw-r--r--core/extern.inc4
-rw-r--r--core/font.c90
-rw-r--r--core/fs/btrfs/btrfs.c5
-rw-r--r--core/fs/cache.c4
-rw-r--r--core/fs/chdir.c110
-rw-r--r--core/fs/fat/fat.c64
-rw-r--r--core/fs/fs.c16
-rw-r--r--core/fs/iso9660/iso9660.c2
-rw-r--r--core/fs/lib/chdir.c1
-rw-r--r--core/fs/lib/loadconfig.c2
-rw-r--r--core/fs/lib/searchconfig.c20
-rw-r--r--core/fs/ntfs/ntfs.c1388
-rw-r--r--core/fs/ntfs/ntfs.h485
-rw-r--r--core/fs/ntfs/runlist.h83
-rw-r--r--core/fs/pxe/dhcp_option.c6
-rw-r--r--core/fs/pxe/dnsresolv.c6
-rw-r--r--core/fs/pxe/pxe.c40
-rw-r--r--core/fs/pxe/pxe.h4
-rw-r--r--core/graphics.c92
-rw-r--r--core/hello.c8
-rw-r--r--core/include/bios.h28
-rw-r--r--core/include/core.h34
-rw-r--r--core/include/fs.h10
-rw-r--r--core/include/graphics.h (renamed from core/elflink/config.c)46
-rw-r--r--core/include/localboot.h (renamed from com32/lib/syslinux/video/forcetext.c)19
-rw-r--r--core/init.c81
-rw-r--r--core/init.inc7
-rw-r--r--core/isolinux.asm60
-rw-r--r--core/kaboom.c12
-rw-r--r--core/layout.inc17
-rw-r--r--core/ldlinux.asm2
-rw-r--r--core/localboot.c10
-rw-r--r--core/mem/init.c2
-rw-r--r--core/mem/malloc.c7
-rw-r--r--core/plaincon.c12
-rw-r--r--core/pxelinux.asm174
-rw-r--r--core/rawcon.c4
-rw-r--r--core/serirq.c10
-rw-r--r--core/syslinux.ld39
-rw-r--r--core/ui.inc763
-rw-r--r--core/writestr.c1
-rw-r--r--diag/geodsp/Makefile29
-rwxr-xr-xdiag/geodsp/mk-lba-img.pl94
-rw-r--r--diag/mbr/README4
-rw-r--r--diag/mbr/handoff.S4
-rw-r--r--doc/chain.txt327
-rw-r--r--doc/gpt.txt2
-rw-r--r--doc/logo/LICENSE5
-rw-r--r--doc/logo/syslinux-100.pngbin0 -> 131308 bytes
-rw-r--r--doc/pxechn.txt94
-rw-r--r--dos/Makefile2
-rw-r--r--dos/syslinux.c5
-rw-r--r--dosutil/Makefile2
-rw-r--r--efi/Makefile2
-rw-r--r--efi/diskio.c2
-rw-r--r--efi/main.c30
-rw-r--r--extlinux/Makefile8
-rw-r--r--extlinux/btrfs.h179
-rw-r--r--[-rwxr-xr-x]extlinux/main.c609
-rw-r--r--extlinux/mountinfo.c277
-rw-r--r--extlinux/mountinfo.h35
-rw-r--r--extlinux/ntfs.h19
-rw-r--r--libinstaller/Makefile2
-rw-r--r--libinstaller/ext2fs/ext2_fs.h856
-rw-r--r--libinstaller/fs.c (renamed from libinstaller/fat.c)120
-rw-r--r--libinstaller/linuxioctl.h26
-rw-r--r--libinstaller/setadv.c1
-rw-r--r--libinstaller/syslinux.h4
-rw-r--r--libinstaller/syslxcom.c18
-rw-r--r--libinstaller/syslxcom.h9
-rw-r--r--libinstaller/syslxfs.h26
-rw-r--r--libinstaller/syslxint.h77
-rw-r--r--libinstaller/syslxmod.c2
-rw-r--r--libinstaller/syslxopt.c10
-rw-r--r--libinstaller/syslxopt.h1
-rw-r--r--linux/Makefile9
-rwxr-xr-xlinux/syslinux.c24
-rw-r--r--man/extlinux.111
-rw-r--r--mbr/altmbr.S2
-rw-r--r--mbr/isohdpfx.S31
-rw-r--r--memdisk/Makefile2
-rw-r--r--mk/com32.mk3
-rw-r--r--mk/devel.mk1
-rw-r--r--mk/elf.mk11
-rw-r--r--mk/lib.mk79
-rw-r--r--mk/syslinux.mk6
-rwxr-xr-xmtools/Makefile7
-rwxr-xr-xmtools/syslinux.c5
-rw-r--r--utils/Makefile18
-rw-r--r--utils/isohybrid.c612
-rw-r--r--utils/isohybrid.h2
-rw-r--r--version2
-rw-r--r--win/ntfssect.c355
-rw-r--r--win/ntfssect.h152
-rw-r--r--win/ntfstest.c163
-rw-r--r--win/ntfstest.rc26
-rw-r--r--win/syslinux.c56
-rw-r--r--win32/Makefile4
-rwxr-xr-xwin32/find-mingw32.sh3
-rw-r--r--win32/ntfstest/Makefile87
-rw-r--r--win64/Makefile4
-rwxr-xr-xwin64/find-mingw64.sh4
-rw-r--r--win64/ntfstest/Makefile76
294 files changed, 16305 insertions, 7321 deletions
diff --git a/Makefile b/Makefile
index 45d0b193..e0294280 100644
--- a/Makefile
+++ b/Makefile
@@ -35,14 +35,18 @@ ifndef EFI_BUILD
MODULES = memdisk/memdisk memdump/memdump.com modules/*.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/sysdump/*.c32 com32/lua/src/*.c32 com32/chain/*.c32 \
+ com32/lib/*.c32 com32/libutil/*.c32 com32/gpllib/*.c32 \
+ com32/elflink/ldlinux/*.c32
else
# memdump is BIOS specific code exclude it for EFI
# FIXME: Prune other BIOS-centric modules
MODULES = memdisk/memdisk modules/*.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/sysdump/*.c32 com32/lua/src/*.c32 com32/chain/*.c32 \
+ com32/lib/*.c32 com32/libutil/*.c32 com32/gpllib/*.c32 \
+ com32/elflink/ldlinux/*.c32
endif
# syslinux.exe is BTARGET so as to not require everyone to have the
@@ -114,6 +118,13 @@ installer:
installer-local: $(ITARGET) $(BINFILES)
+strip:
+ $(MAKE) strip-local
+ set -e ; for i in $(ISUBDIRS); do $(MAKE) -C $$i strip ; done
+ -ls -l $(BOBJECTS) $(IOBJECTS)
+
+strip-local:
+
version.gen: version version.pl
$(PERL) version.pl $< $@ '%define < @'
version.h: version version.pl
diff --git a/Makefile.private b/Makefile.private
index 6ca0598f..92127e98 100644
--- a/Makefile.private
+++ b/Makefile.private
@@ -38,6 +38,7 @@ burn: isolinux.iso
official:
$(MAKE) spotless CC='$(CC) -m32'
$(MAKE) all CC='$(CC) -m32'
+ $(MAKE) strip CC='$(CC) -m32'
$(MAKE) dist CC='$(CC) -m32'
release:
@@ -99,7 +100,3 @@ LATEST_PREREL := syslinux-$(VERSION)-pre$(LATEST_PRERELNO)
unprerel:
echo $(LATEST_PRERELNO) > $(PRERELDIR)/.prerel
@echo Next release will be $(LATEST_PREREL)
-
-preupload:
- scp $(PRERELDIR)/$(LATEST_PREREL).* $(UPLOAD)/Testing
- git push --tags
diff --git a/NEWS b/NEWS
index 443e1a51..863b8676 100644
--- a/NEWS
+++ b/NEWS
@@ -2,12 +2,23 @@ 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 4.06:
+ * Support for NTFS, by Paulo Alcantara.
+ * EXTLINUX: more robust device detection, allow user to override.
+
Changes in 4.05:
* HDT updated, and now supports uploading data to a TFTP
server.
* ISOLINUX: remove the .img file support; it has been broken
on virtually all systems since the beginning, and has been
totally broken since 4.00 at least. Use MEMDISK instead.
+ * chain.c32: Support chaining ReactOS' FreeLdr (Shao Miller)
+ * isohybrid: -m option to add support for Mac EFI booting.
+ * ifmemdsk.c32: Choose boot option based on presence of
+ MEMDISK.
+ * Remove bogus distributed mk-lba-img binary.
+ * The Syslinux project has a new, cool logo by Abi
+ "ixxvil" Rasheed (doc/logo/*).
Changes in 4.04:
* PXELINUX: Fix handling of unqualified DNS names.
diff --git a/com32/Makefile b/com32/Makefile
index debfe473..c4699cfd 100644
--- a/com32/Makefile
+++ b/com32/Makefile
@@ -1,4 +1,5 @@
-SUBDIRS = elflink/ldlinux libupload tools lib gpllib libutil modules mboot menu samples \
- elflink rosh cmenu hdt gfxboot sysdump lua/src
+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
diff --git a/com32/chain/Makefile b/com32/chain/Makefile
new file mode 100644
index 00000000..9a298fae
--- /dev/null
+++ b/com32/chain/Makefile
@@ -0,0 +1,42 @@
+## -----------------------------------------------------------------------
+##
+## Copyright 2001-2010 H. Peter Anvin - All Rights Reserved
+## Copyright 2010 Michal Soltys
+##
+## 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.
+##
+## -----------------------------------------------------------------------
+
+
+topdir = ../..
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/elf.mk
+
+OBJS = chain.o partiter.o utility.o options.o mangle.o
+
+all: chain.c32
+
+chain.c32: $(OBJS) $(C_LIBS)
+ $(LD) $(LDFLAGS) -o $@ $^
+
+%.o: %.c
+ $(CC) $(MAKEDEPS) $(CFLAGS) $(CHAINEXTOPT) -c -o $@ $<
+
+tidy dist:
+ rm -f *.o *.lo *.a *.lst *.elf .*.d *.tmp
+
+clean: tidy
+ rm -f *.lnx
+
+spotless: clean
+ rm -f *.lss *.c32 *.com
+ rm -f *~ \#*
+
+install:
+
+
+-include .*.d
diff --git a/com32/chain/chain.c b/com32/chain/chain.c
new file mode 100644
index 00000000..30153c4d
--- /dev/null
+++ b/com32/chain/chain.c
@@ -0,0 +1,658 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ * Copyright 2010 Shao Miller
+ * Copyright 2010 Michal Soltys
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Please see doc/chain.txt for the detailed documentation.
+ */
+
+#include <com32.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <console.h>
+#include <consoles.h>
+#include <minmax.h>
+#include <stdbool.h>
+#include <dprintf.h>
+#include <errno.h>
+#include <unistd.h>
+#include <syslinux/loadfile.h>
+#include <syslinux/bootrm.h>
+#include <syslinux/config.h>
+#include <syslinux/disk.h>
+#include <syslinux/video.h>
+#include "common.h"
+#include "chain.h"
+#include "utility.h"
+#include "options.h"
+#include "partiter.h"
+#include "mangle.h"
+
+static int fixed_cnt = 128; /* see comments in main() */
+
+static int overlap(const struct data_area *a, const struct data_area *b)
+{
+ return
+ a->base + a->size > b->base &&
+ b->base + b->size > a->base;
+}
+
+static int is_phys(uint8_t sdifs)
+{
+ return
+ sdifs == SYSLINUX_FS_SYSLINUX ||
+ sdifs == SYSLINUX_FS_EXTLINUX ||
+ sdifs == SYSLINUX_FS_ISOLINUX;
+}
+
+/*
+ * Search for a specific drive, based on the MBR signature.
+ * Return drive and iterator at 0th position.
+ */
+static int find_by_sig(uint32_t mbr_sig,
+ struct part_iter **_boot_part)
+{
+ struct part_iter *boot_part = NULL;
+ struct disk_info diskinfo;
+ int drive;
+
+ for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) {
+ if (disk_get_params(drive, &diskinfo))
+ continue; /* Drive doesn't exist */
+ if (!(boot_part = pi_begin(&diskinfo, 0)))
+ continue;
+ /* Check for a MBR disk */
+ if (boot_part->type != typedos) {
+ pi_del(&boot_part);
+ continue;
+ }
+ if (boot_part->sub.dos.disk_sig == mbr_sig) {
+ goto ok;
+ }
+ }
+ drive = -1;
+ok:
+ *_boot_part = boot_part;
+ return drive;
+}
+
+/*
+ * Search for a specific drive/partition, based on the GPT GUID.
+ * Return drive and iterator at proper position.
+ */
+static int find_by_guid(const struct guid *gpt_guid,
+ struct part_iter **_boot_part)
+{
+ struct part_iter *boot_part = NULL;
+ struct disk_info diskinfo;
+ int drive;
+
+ for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) {
+ if (disk_get_params(drive, &diskinfo))
+ continue; /* Drive doesn't exist */
+ if (!(boot_part = pi_begin(&diskinfo, 0)))
+ continue;
+ /* Check for a GPT disk */
+ if (boot_part->type != typegpt) {
+ pi_del(&boot_part);
+ continue;
+ }
+ /* Check for a matching GPT disk guid */
+ if (!memcmp(&boot_part->sub.gpt.disk_guid, gpt_guid, sizeof(*gpt_guid))) {
+ goto ok;
+ }
+ /* disk guid doesn't match, maybe partition guid will */
+ while (!pi_next(&boot_part)) {
+ if (!memcmp(&boot_part->sub.gpt.part_guid, gpt_guid, sizeof(*gpt_guid)))
+ goto ok;
+ }
+ }
+ drive = -1;
+ok:
+ *_boot_part = boot_part;
+ return drive;
+}
+
+/*
+ * Search for a specific drive/partition, based on the GPT label.
+ * Return drive and iterator at proper position.
+ */
+static int find_by_label(const char *label, struct part_iter **_boot_part)
+{
+ struct part_iter *boot_part = NULL;
+ struct disk_info diskinfo;
+ int drive;
+
+ for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) {
+ if (disk_get_params(drive, &diskinfo))
+ continue; /* Drive doesn't exist */
+ if (!(boot_part = pi_begin(&diskinfo, 0)))
+ continue;
+ /* Check for a GPT disk */
+ if (!(boot_part->type == typegpt)) {
+ pi_del(&boot_part);
+ continue;
+ }
+ /* Check for a matching partition */
+ while (!pi_next(&boot_part)) {
+ if (!strcmp(label, boot_part->sub.gpt.part_label))
+ goto ok;
+ }
+ }
+ drive = -1;
+ok:
+ *_boot_part = boot_part;
+ return drive;
+}
+
+static void do_boot(struct data_area *data, int ndata)
+{
+ uint16_t *const bios_fbm = (uint16_t *) 0x413;
+ addr_t dosmem = (addr_t)(*bios_fbm << 10); /* Technically a low bound */
+ struct syslinux_memmap *mmap;
+ struct syslinux_movelist *mlist = NULL;
+ addr_t endimage;
+ uint8_t driveno = opt.regs.edx.b[0];
+ uint8_t swapdrive = driveno & 0x80;
+ int i;
+
+ mmap = syslinux_memory_map();
+
+ if (!mmap) {
+ error("Cannot read system memory map\n");
+ return;
+ }
+
+ endimage = 0;
+ for (i = 0; i < ndata; i++) {
+ if (data[i].base + data[i].size > endimage)
+ endimage = data[i].base + data[i].size;
+ }
+ if (endimage > dosmem)
+ goto too_big;
+
+ for (i = 0; i < ndata; i++) {
+ if (syslinux_add_movelist(&mlist, data[i].base,
+ (addr_t) data[i].data, data[i].size))
+ goto enomem;
+ }
+
+ if (opt.swap && driveno != swapdrive) {
+ static const uint8_t swapstub_master[] = {
+ /* The actual swap code */
+ 0x53, /* 00: push bx */
+ 0x0f, 0xb6, 0xda, /* 01: movzx bx,dl */
+ 0x2e, 0x8a, 0x57, 0x60, /* 04: mov dl,[cs:bx+0x60] */
+ 0x5b, /* 08: pop bx */
+ 0xea, 0, 0, 0, 0, /* 09: jmp far 0:0 */
+ 0x90, 0x90, /* 0E: nop; nop */
+ /* Code to install this in the right location */
+ /* Entry with DS = CS; ES = SI = 0; CX = 256 */
+ 0x26, 0x66, 0x8b, 0x7c, 0x4c, /* 10: mov edi,[es:si+4*0x13] */
+ 0x66, 0x89, 0x3e, 0x0a, 0x00, /* 15: mov [0x0A],edi */
+ 0x26, 0x8b, 0x3e, 0x13, 0x04, /* 1A: mov di,[es:0x413] */
+ 0x4f, /* 1F: dec di */
+ 0x26, 0x89, 0x3e, 0x13, 0x04, /* 20: mov [es:0x413],di */
+ 0x66, 0xc1, 0xe7, 0x16, /* 25: shl edi,16+6 */
+ 0x26, 0x66, 0x89, 0x7c, 0x4c, /* 29: mov [es:si+4*0x13],edi */
+ 0x66, 0xc1, 0xef, 0x10, /* 2E: shr edi,16 */
+ 0x8e, 0xc7, /* 32: mov es,di */
+ 0x31, 0xff, /* 34: xor di,di */
+ 0xf3, 0x66, 0xa5, /* 36: rep movsd */
+ 0xbe, 0, 0, /* 39: mov si,0 */
+ 0xbf, 0, 0, /* 3C: mov di,0 */
+ 0x8e, 0xde, /* 3F: mov ds,si */
+ 0x8e, 0xc7, /* 41: mov es,di */
+ 0x66, 0xb9, 0, 0, 0, 0, /* 43: mov ecx,0 */
+ 0x66, 0xbe, 0, 0, 0, 0, /* 49: mov esi,0 */
+ 0x66, 0xbf, 0, 0, 0, 0, /* 4F: mov edi,0 */
+ 0xea, 0, 0, 0, 0, /* 55: jmp 0:0 */
+ /* pad out to segment boundary */
+ 0x90, 0x90, /* 5A: ... */
+ 0x90, 0x90, 0x90, 0x90, /* 5C: ... */
+ };
+ static uint8_t swapstub[1024];
+ uint8_t *p;
+
+ /* Note: we can't rely on either INT 13h nor the dosmem
+ vector to be correct at this stage, so we have to use an
+ installer stub to put things in the right place.
+ Round the installer location to a 1K boundary so the only
+ possible overlap is the identity mapping. */
+ endimage = (endimage + 1023u) & ~1023u;
+
+ /* Create swap stub */
+ memcpy(swapstub, swapstub_master, sizeof swapstub_master);
+ *(uint16_t *) & swapstub[0x3a] = opt.regs.ds;
+ *(uint16_t *) & swapstub[0x3d] = opt.regs.es;
+ *(uint32_t *) & swapstub[0x45] = opt.regs.ecx.l;
+ *(uint32_t *) & swapstub[0x4b] = opt.regs.esi.l;
+ *(uint32_t *) & swapstub[0x51] = opt.regs.edi.l;
+ *(uint16_t *) & swapstub[0x56] = opt.regs.ip;
+ *(uint16_t *) & swapstub[0x58] = opt.regs.cs;
+ p = &swapstub[sizeof swapstub_master];
+
+ /* Mapping table; start out with identity mapping everything */
+ for (i = 0; i < 256; i++)
+ p[i] = (uint8_t)i;
+
+ /* And the actual swap */
+ p[driveno] = swapdrive;
+ p[swapdrive] = driveno;
+
+ /* Adjust registers */
+ opt.regs.ds = opt.regs.cs = (uint16_t)(endimage >> 4);
+ opt.regs.esi.l = opt.regs.es = 0;
+ opt.regs.ecx.l = sizeof swapstub >> 2;
+ opt.regs.ip = 0x10; /* Installer offset */
+ opt.regs.ebx.b[0] = opt.regs.edx.b[0] = swapdrive;
+
+ if (syslinux_add_movelist(&mlist, endimage, (addr_t) swapstub,
+ sizeof swapstub))
+ goto enomem;
+
+ endimage += sizeof swapstub;
+ }
+
+ /* Tell the shuffler not to muck with this area... */
+ syslinux_add_memmap(&mmap, endimage, 0xa0000 - endimage, SMT_RESERVED);
+
+ /* Force text mode */
+ syslinux_force_text_mode();
+
+ fputs("Booting...\n", stdout);
+ syslinux_shuffle_boot_rm(mlist, mmap, opt.keeppxe, &opt.regs);
+ error("Chainboot failed!\n");
+ return;
+
+too_big:
+ error("Loader file too large\n");
+ return;
+
+enomem:
+ error("Out of memory\n");
+ return;
+}
+
+int find_dp(struct part_iter **_iter)
+{
+ struct part_iter *iter = NULL;
+ struct disk_info diskinfo;
+ struct guid gpt_guid;
+ uint64_t fs_lba;
+ int drive, hd, partition;
+ const union syslinux_derivative_info *sdi;
+
+ sdi = syslinux_derivative_info();
+
+ if (!strncmp(opt.drivename, "mbr", 3)) {
+ if (find_by_sig(strtoul(opt.drivename + 4, NULL, 0), &iter) < 0) {
+ error("Unable to find requested MBR signature.\n");
+ goto bail;
+ }
+ } else if (!strncmp(opt.drivename, "guid", 4)) {
+ if (str_to_guid(opt.drivename + 5, &gpt_guid))
+ goto bail;
+ if (find_by_guid(&gpt_guid, &iter) < 0) {
+ error("Unable to find requested GPT disk or partition by guid.\n");
+ goto bail;
+ }
+ } else if (!strncmp(opt.drivename, "label", 5)) {
+ if (!opt.drivename[6]) {
+ error("No label specified.\n");
+ goto bail;
+ }
+ if (find_by_label(opt.drivename + 6, &iter) < 0) {
+ error("Unable to find requested GPT partition by label.\n");
+ goto bail;
+ }
+ } else if ((opt.drivename[0] == 'h' || opt.drivename[0] == 'f') &&
+ opt.drivename[1] == 'd') {
+ hd = opt.drivename[0] == 'h' ? 0x80 : 0;
+ opt.drivename += 2;
+ drive = hd | strtol(opt.drivename, NULL, 0);
+
+ if (disk_get_params(drive, &diskinfo))
+ goto bail;
+ /* this will start iteration over FDD, possibly raw */
+ if (!(iter = pi_begin(&diskinfo, 0)))
+ goto bail;
+
+ } else if (!strcmp(opt.drivename, "boot") || !strcmp(opt.drivename, "fs")) {
+ if (!is_phys(sdi->c.filesystem)) {
+ error("When syslinux is not booted from physical disk (or its emulation),\n"
+ "'boot' and 'fs' are meaningless.\n");
+ goto bail;
+ }
+ /* offsets match, but in case it changes in the future */
+ if (sdi->c.filesystem == SYSLINUX_FS_ISOLINUX) {
+ drive = sdi->iso.drive_number;
+ fs_lba = *sdi->iso.partoffset;
+ } else {
+ drive = sdi->disk.drive_number;
+ fs_lba = *sdi->disk.partoffset;
+ }
+ if (disk_get_params(drive, &diskinfo))
+ goto bail;
+ /* this will start iteration over disk emulation, possibly raw */
+ if (!(iter = pi_begin(&diskinfo, 0)))
+ goto bail;
+
+ /* 'fs' => we should lookup the syslinux partition number and use it */
+ if (!strcmp(opt.drivename, "fs")) {
+ while (!pi_next(&iter)) {
+ if (iter->start_lba == fs_lba)
+ break;
+ }
+ /* broken part structure or other problems */
+ if (iter->status) {
+ error("Can't find myself on the drive I booted from.\n");
+ goto bail;
+ }
+ }
+ } else {
+ error("Unparsable drive specification.\n");
+ goto bail;
+ }
+ /* main options done - only thing left is explicit partition specification,
+ * if we're still at the disk stage with the iterator AND user supplied
+ * partition number (including disk pseudo-partition).
+ */
+ if (!iter->index && opt.partition) {
+ partition = strtol(opt.partition, NULL, 0);
+ /* search for matching part#, including disk */
+ do {
+ if (iter->index == partition)
+ break;
+ } while (!pi_next(&iter));
+ if (iter->status) {
+ error("Requested disk / partition combination not found.\n");
+ goto bail;
+ }
+ }
+
+ if (!(iter->di.disk & 0x80) && iter->index) {
+ error("WARNING: Partitions on floppy devices may not work.\n");
+ }
+
+ *_iter = iter;
+
+ return 0;
+
+bail:
+ pi_del(&iter);
+ return -1;
+}
+
+static int setup_handover(const struct part_iter *iter,
+ struct data_area *data)
+{
+ struct disk_dos_part_entry *ha;
+ uint32_t synth_size;
+ uint32_t *plen;
+
+ if (!iter->index) { /* implies typeraw or non-iterated */
+ uint32_t len;
+ /* RAW handover protocol */
+ synth_size = sizeof(struct disk_dos_part_entry);
+ ha = malloc(synth_size);
+ if (!ha) {
+ error("Could not build RAW hand-over record!\n");
+ goto bail;
+ }
+ len = ~0u;
+ if (iter->length < len)
+ len = (uint32_t)iter->length;
+ lba2chs(&ha->start, &iter->di, 0, l2c_cadd);
+ lba2chs(&ha->end, &iter->di, len - 1, l2c_cadd);
+ ha->active_flag = 0x80;
+ ha->ostype = 0xDA; /* "Non-FS Data", anything is good here though ... */
+ ha->start_lba = 0;
+ ha->length = len;
+ } else if (iter->type == typegpt) {
+ /* GPT handover protocol */
+ synth_size = sizeof(struct disk_dos_part_entry) +
+ sizeof(uint32_t) + (uint32_t)iter->sub.gpt.pe_size;
+ ha = malloc(synth_size);
+ if (!ha) {
+ error("Could not build GPT hand-over record!\n");
+ goto bail;
+ }
+ lba2chs(&ha->start, &iter->di, iter->start_lba, l2c_cadd);
+ lba2chs(&ha->end, &iter->di, iter->start_lba + iter->length - 1, l2c_cadd);
+ ha->active_flag = 0x80;
+ ha->ostype = 0xED;
+ /* All bits set by default */
+ ha->start_lba = ~0u;
+ ha->length = ~0u;
+ /* If these fit the precision, pass them on */
+ if (iter->start_lba < ha->start_lba)
+ ha->start_lba = (uint32_t)iter->start_lba;
+ if (iter->length < ha->length)
+ ha->length = (uint32_t)iter->length;
+ /* Next comes the GPT partition record length */
+ plen = (uint32_t *) (ha + 1);
+ plen[0] = (uint32_t)iter->sub.gpt.pe_size;
+ /* Next comes the GPT partition record copy */
+ memcpy(plen + 1, iter->record, plen[0]);
+#ifdef DEBUG
+ dprintf("GPT handover:\n");
+ disk_dos_part_dump(ha);
+ disk_gpt_part_dump((struct disk_gpt_part_entry *)(plen + 1));
+#endif
+ } else if (iter->type == typedos) {
+ /* MBR handover protocol */
+ synth_size = sizeof(struct disk_dos_part_entry);
+ ha = malloc(synth_size);
+ if (!ha) {
+ error("Could not build MBR hand-over record!\n");
+ goto bail;
+ }
+ memcpy(ha, iter->record, synth_size);
+ /* make sure these match bios imaginations and are ebr agnostic */
+ lba2chs(&ha->start, &iter->di, iter->start_lba, l2c_cadd);
+ lba2chs(&ha->end, &iter->di, iter->start_lba + iter->length - 1, l2c_cadd);
+ ha->start_lba = (uint32_t)iter->start_lba;
+ ha->length = (uint32_t)iter->length;
+
+#ifdef DEBUG
+ dprintf("MBR handover:\n");
+ disk_dos_part_dump(ha);
+#endif
+ } else {
+ /* shouldn't ever happen */
+ goto bail;
+ }
+
+ data->base = 0x7be;
+ data->size = synth_size;
+ data->data = (void *)ha;
+
+ return 0;
+bail:
+ return -1;
+}
+
+int main(int argc, char *argv[])
+{
+ struct part_iter *iter = NULL;
+ void *sbck = NULL;
+ struct data_area fdat, hdat, sdat, data[3];
+ int ndata = 0;
+
+ console_ansi_raw();
+
+ memset(&fdat, 0, sizeof(fdat));
+ memset(&hdat, 0, sizeof(hdat));
+ memset(&sdat, 0, sizeof(sdat));
+
+ opt_set_defs();
+ if (opt_parse_args(argc, argv))
+ goto bail;
+
+#if 0
+ /* Get max fixed disk number */
+ fixed_cnt = *(uint8_t *)(0x475);
+
+ /*
+ * hmm, looks like we can't do that -
+ * some bioses/vms just set it to 1
+ * and go on living happily
+ * any better options than hardcoded 0x80 - 0xFF ?
+ */
+#endif
+
+ /* Get disk/part iterator matching user supplied options */
+ if (find_dp(&iter))
+ goto bail;
+
+ /* Perform initial partition entry mangling */
+ if (manglepe_fixchs(iter))
+ goto bail;
+ if (manglepe_hide(iter))
+ goto bail;
+
+ /* Load the boot file */
+ if (opt.file) {
+ fdat.base = (opt.fseg << 4) + opt.foff;
+
+ if (loadfile(opt.file, &fdat.data, &fdat.size)) {
+ error("Couldn't read the boot file.\n");
+ goto bail;
+ }
+ if (fdat.base + fdat.size - 1 > ADDRMAX) {
+ error("The boot file is too big to load at this address.\n");
+ goto bail;
+ }
+ }
+
+ /* Load the sector */
+ if (opt.sect) {
+ sdat.base = (opt.sseg << 4) + opt.soff;
+ sdat.size = iter->di.bps;
+
+ if (sdat.base + sdat.size - 1 > ADDRMAX) {
+ error("The sector cannot be loaded at such high address.\n");
+ goto bail;
+ }
+ if (!(sdat.data = disk_read_sectors(&iter->di, iter->start_lba, 1))) {
+ error("Couldn't read the sector.\n");
+ goto bail;
+ }
+ if (opt.save) {
+ if (!(sbck = malloc(sdat.size))) {
+ error("Couldn't allocate cmp-buf for option 'save'.\n");
+ goto bail;
+ }
+ memcpy(sbck, sdat.data, sdat.size);
+ }
+ if (opt.file && opt.maps && overlap(&fdat, &sdat)) {
+ error("WARNING: The sector won't be mmapped, as it would conflict with the boot file.\n");
+ opt.maps = false;
+ }
+ }
+
+ /* Prep the handover */
+ if (opt.hand) {
+ if (setup_handover(iter, &hdat))
+ goto bail;
+ /* Verify possible conflicts */
+ if ( ( opt.file && overlap(&fdat, &hdat)) ||
+ ( opt.maps && overlap(&sdat, &hdat)) ) {
+ error("WARNING: Handover area won't be prepared,\n"
+ "as it would conflict with the boot file and/or the sector.\n");
+ opt.hand = false;
+ }
+ }
+
+ /* Adjust registers */
+
+ mangler_init(iter);
+ mangler_handover(iter, &hdat);
+ mangler_grldr(iter);
+
+ /* Patching functions */
+
+ if (manglef_isolinux(&fdat))
+ goto bail;
+
+ if (manglef_grub(iter, &fdat))
+ goto bail;
+#if 0
+ if (manglef_drmk(&fdat))
+ goto bail;
+#endif
+ if (manglef_bpb(iter, &fdat))
+ goto bail;
+
+ if (mangles_bpb(iter, &sdat))
+ goto bail;
+
+ if (mangles_save(iter, &sdat, sbck))
+ goto bail;
+
+ if (manglesf_bss(&sdat, &fdat))
+ goto bail;
+
+ /* This *must* be after BPB saving or copying */
+ if (mangles_cmldr(&sdat))
+ goto bail;
+
+ /*
+ * Prepare boot-time mmap data. We should to it here, as manglers could
+ * potentially alter some of the data.
+ */
+
+ if (opt.file)
+ memcpy(data + ndata++, &fdat, sizeof(fdat));
+ if (opt.maps)
+ memcpy(data + ndata++, &sdat, sizeof(sdat));
+ if (opt.hand)
+ memcpy(data + ndata++, &hdat, sizeof(hdat));
+
+#ifdef DEBUG
+ printf("iter->di dsk, bps: %X, %u\niter->di lbacnt, C*H*S: %"PRIu64", %u\n"
+ "iter->di C, H, S: %u, %u, %u\n",
+ iter->di.disk, iter->di.bps,
+ iter->di.lbacnt, iter->di.cyl * iter->di.head * iter->di.spt,
+ iter->di.cyl, iter->di.head, iter->di.spt);
+ printf("iter idx: %d\n", iter->index);
+ printf("iter lba: %"PRIu64"\n", iter->start_lba);
+ if (opt.hand)
+ printf("hand lba: %u\n",
+ ((struct disk_dos_part_entry *)hdat.data)->start_lba);
+#endif
+
+ if (opt.warn) {
+ puts("Press any key to continue booting...");
+ wait_key();
+ }
+
+ if (ndata && !opt.brkchain) /* boot only if we actually chainload */
+ do_boot(data, ndata);
+ else
+ error("Service-only run completed, exiting.\n");
+bail:
+ pi_del(&iter);
+ /* Free allocated areas */
+ free(fdat.data);
+ free(sdat.data);
+ free(hdat.data);
+ free(sbck);
+ return 255;
+}
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/chain.h b/com32/chain/chain.h
new file mode 100644
index 00000000..fc481bc6
--- /dev/null
+++ b/com32/chain/chain.h
@@ -0,0 +1,14 @@
+#ifndef _COM32_CHAIN_CHAIN_H
+#define _COM32_CHAIN_CHAIN_H
+
+#include <syslinux/movebits.h>
+
+struct data_area {
+ void *data;
+ addr_t base;
+ addr_t size;
+};
+
+#endif
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/common.h b/com32/chain/common.h
new file mode 100644
index 00000000..b170a732
--- /dev/null
+++ b/com32/chain/common.h
@@ -0,0 +1,9 @@
+#ifndef _COM32_CHAIN_COMMON_H
+#define _COM32_CHAIN_COMMON_H
+
+#define ADDRMAX 0x9EFFFu
+#define ADDRMIN 0x500u
+
+#endif
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/mangle.c b/com32/chain/mangle.c
new file mode 100644
index 00000000..8358106e
--- /dev/null
+++ b/com32/chain/mangle.c
@@ -0,0 +1,618 @@
+#include <com32.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <dprintf.h>
+#include <syslinux/config.h>
+#include "common.h"
+#include "chain.h"
+#include "options.h"
+#include "utility.h"
+#include "partiter.h"
+#include "mangle.h"
+
+static const char cmldr_signature[8] = "cmdcons";
+
+/* Create boot info table: needed when you want to chainload
+ * another version of ISOLINUX (or another bootlaoder that needs
+ * the -boot-info-table switch of mkisofs)
+ * (will only work when run from ISOLINUX)
+ */
+int manglef_isolinux(struct data_area *data)
+{
+ const union syslinux_derivative_info *sdi;
+ unsigned char *isolinux_bin;
+ uint32_t *checksum, *chkhead, *chktail;
+ uint32_t file_lba = 0;
+
+ if (!(opt.file && opt.isolinux))
+ return 0;
+
+ sdi = syslinux_derivative_info();
+
+ if (sdi->c.filesystem != SYSLINUX_FS_ISOLINUX) {
+ error ("The isolinux= option is only valid when run from ISOLINUX.\n");
+ goto bail;
+ }
+
+ /* Boot info table info (integers in little endian format)
+
+ Offset Name Size Meaning
+ 8 bi_pvd 4 bytes LBA of primary volume descriptor
+ 12 bi_file 4 bytes LBA of boot file
+ 16 bi_length 4 bytes Boot file length in bytes
+ 20 bi_csum 4 bytes 32-bit checksum
+ 24 bi_reserved 40 bytes Reserved
+
+ The 32-bit checksum is the sum of all the 32-bit words in the
+ boot file starting at byte offset 64. All linear block
+ addresses (LBAs) are given in CD sectors (normally 2048 bytes).
+
+ LBA of primary volume descriptor should already be set to 16.
+ */
+
+ isolinux_bin = (unsigned char *)data->data;
+
+ /* Get LBA address of bootfile */
+ file_lba = get_file_lba(opt.file);
+
+ if (file_lba == 0) {
+ error("Failed to find LBA offset of the boot file\n");
+ goto bail;
+ }
+ /* Set it */
+ *((uint32_t *) & isolinux_bin[12]) = file_lba;
+
+ /* Set boot file length */
+ *((uint32_t *) & isolinux_bin[16]) = data->size;
+
+ /* Calculate checksum */
+ checksum = (uint32_t *) & isolinux_bin[20];
+ chkhead = (uint32_t *) & isolinux_bin[64];
+ chktail = (uint32_t *) & isolinux_bin[data->size & ~3u];
+ *checksum = 0;
+ while (chkhead < chktail)
+ *checksum += *chkhead++;
+
+ /*
+ * Deal with possible fractional dword at the end;
+ * this *should* never happen...
+ */
+ if (data->size & 3) {
+ uint32_t xword = 0;
+ memcpy(&xword, chkhead, data->size & 3);
+ *checksum += xword;
+ }
+ return 0;
+bail:
+ return -1;
+}
+
+/*
+ * Legacy grub's stage2 chainloading
+ */
+int manglef_grub(const struct part_iter *iter, struct data_area *data)
+{
+ /* Layout of stage2 file (from byte 0x0 to 0x270) */
+ struct grub_stage2_patch_area {
+ /* 0x0 to 0x205 */
+ char unknown[0x206];
+ /* 0x206: compatibility version number major */
+ uint8_t compat_version_major;
+ /* 0x207: compatibility version number minor */
+ uint8_t compat_version_minor;
+
+ /* 0x208: install_partition variable */
+ struct {
+ /* 0x208: sub-partition in sub-partition part2 */
+ uint8_t part3;
+ /* 0x209: sub-partition in top-level partition */
+ uint8_t part2;
+ /* 0x20a: top-level partiton number */
+ uint8_t part1;
+ /* 0x20b: BIOS drive number (must be 0) */
+ uint8_t drive;
+ } __attribute__ ((packed)) install_partition;
+
+ /* 0x20c: deprecated (historical reason only) */
+ uint32_t saved_entryno;
+ /* 0x210: stage2_ID: will always be STAGE2_ID_STAGE2 = 0 in stage2 */
+ uint8_t stage2_id;
+ /* 0x211: force LBA */
+ uint8_t force_lba;
+ /* 0x212: version string (will probably be 0.97) */
+ char version_string[5];
+ /* 0x217: config filename */
+ char config_file[89];
+ /* 0x270: start of code (after jump from 0x200) */
+ char codestart[1];
+ } __attribute__ ((packed)) *stage2;
+
+ if (!(opt.file && opt.grub))
+ return 0;
+
+ if (data->size < sizeof(struct grub_stage2_patch_area)) {
+ error("The file specified by grub=<loader> is too small to be stage2 of GRUB Legacy.\n");
+ goto bail;
+ }
+ stage2 = data->data;
+
+ /*
+ * Check the compatibility version number to see if we loaded a real
+ * stage2 file or a stage2 file that we support.
+ */
+ if (stage2->compat_version_major != 3
+ || stage2->compat_version_minor != 2) {
+ error("The file specified by grub=<loader> is not a supported stage2 GRUB Legacy binary.\n");
+ goto bail;
+ }
+
+ /*
+ * GRUB Legacy wants the partition number in the install_partition
+ * variable, located at offset 0x208 of stage2.
+ * When GRUB Legacy is loaded, it is located at memory address 0x8208.
+ *
+ * It looks very similar to the "boot information format" of the
+ * Multiboot specification:
+ * http://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Boot-information-format
+ *
+ * 0x208 = part3: sub-partition in sub-partition part2
+ * 0x209 = part2: sub-partition in top-level partition
+ * 0x20a = part1: top-level partition number
+ * 0x20b = drive: BIOS drive number (must be 0)
+ *
+ * GRUB Legacy doesn't store the BIOS drive number at 0x20b, but at
+ * another location.
+ *
+ * Partition numbers always start from zero.
+ * Unused partition bytes must be set to 0xFF.
+ *
+ * We only care about top-level partition, so we only need to change
+ * "part1" to the appropriate value:
+ * -1: whole drive (default) (-1 = 0xFF)
+ * 0-3: primary partitions
+ * 4-*: logical partitions
+ */
+ stage2->install_partition.part1 = (uint8_t)(iter->index - 1);
+
+ /*
+ * Grub Legacy reserves 89 bytes (from 0x8217 to 0x826f) for the
+ * config filename. The filename passed via grubcfg= will overwrite
+ * the default config filename "/boot/grub/menu.lst".
+ */
+ if (opt.grubcfg) {
+ if (strlen(opt.grubcfg) > sizeof(stage2->config_file) - 1) {
+ error ("The config filename length can't exceed 88 characters.\n");
+ goto bail;
+ }
+
+ strcpy((char *)stage2->config_file, opt.grubcfg);
+ }
+
+ return 0;
+bail:
+ return -1;
+}
+#if 0
+/*
+ * Dell's DRMK chainloading.
+ */
+int manglef_drmk(struct data_area *data)
+{
+ /*
+ * DRMK entry is different than MS-DOS/PC-DOS
+ * A new size, aligned to 16 bytes to ease use of ds:[bp+28].
+ * We only really need 4 new, usable bytes at the end.
+ */
+
+ if (!(opt.file && opt.drmk))
+ return 0;
+
+ uint32_t tsize = (data->size + 19) & 0xfffffff0;
+ const union syslinux_derivative_info *sdi;
+ uint64_t fs_lba;
+
+ sdi = syslinux_derivative_info();
+ /* We should lookup the Syslinux partition offset and use it */
+ fs_lba = *sdi->disk.partoffset;
+
+ /*
+ * fs_lba should be verified against the disk as some DRMK
+ * variants will check and fail if it does not match
+ */
+ dprintf(" fs_lba offset is %d\n", fs_lba);
+ /* DRMK only uses a DWORD */
+ if (fs_lba > 0xffffffff) {
+ error("LBA very large; Only using lower 32 bits; DRMK will probably fail\n");
+ }
+ opt.regs.ss = opt.regs.fs = opt.regs.gs = 0; /* Used before initialized */
+ if (!realloc(data->data, tsize)) {
+ error("Failed to realloc for DRMK.\n");
+ goto bail;
+ }
+ data->size = tsize;
+ /* ds:bp is assumed by DRMK to be the boot sector */
+ /* offset 28 is the FAT HiddenSectors value */
+ opt.regs.ds = (uint16_t)((tsize >> 4) + (opt.fseg - 2));
+ /* "Patch" into tail of the new space */
+ *(uint32_t *)((char*)data->data + tsize - 4) = (uint32_t)fs_lba;
+
+ return 0;
+bail:
+ return -1;
+}
+#endif
+/* Adjust BPB common function */
+static int mangle_bpb(const struct part_iter *iter, struct data_area *data, const char *tag)
+{
+ unsigned int off;
+ int type = bpb_detect(data->data, tag);
+
+ /* BPB: hidden sectors 32bit*/
+ if (type >= bpbV34) {
+ if (iter->start_lba < ~0u)
+ *(uint32_t *) ((char *)data->data + 0x1c) = (uint32_t)iter->start_lba;
+ else
+ /* won't really help much, but ... */
+ *(uint32_t *) ((char *)data->data + 0x1c) = ~0u;
+ }
+ /* BPB: hidden sectors 16bit*/
+ if (bpbV30 <= type && type <= bpbV32) {
+ if (iter->start_lba < 0xFFFF)
+ *(uint16_t *) ((char *)data->data + 0x1c) = (uint16_t)iter->start_lba;
+ else
+ /* won't really help much, but ... */
+ *(uint16_t *) ((char *)data->data + 0x1c) = (uint16_t)~0u;
+ }
+ /* BPB: legacy geometry */
+ if (type >= bpbV30) {
+ if (iter->di.cbios)
+ *(uint32_t *)((char *)data->data + 0x18) = (uint32_t)((iter->di.head << 16) | iter->di.spt);
+ else {
+ if (iter->di.disk & 0x80)
+ *(uint32_t *)((char *)data->data + 0x18) = 0x00FF003F;
+ else
+ *(uint32_t *)((char *)data->data + 0x18) = 0x00020012;
+ }
+ }
+ /* BPB: drive */
+ if (drvoff_detect(type, &off)) {
+ *(uint8_t *)((char *)data->data + off) = (uint8_t)
+ (opt.swap ? iter->di.disk & 0x80 : iter->di.disk);
+ }
+
+ return 0;
+}
+
+/*
+ * Adjust BPB of a BPB-compatible file
+ */
+int manglef_bpb(const struct part_iter *iter, struct data_area *data)
+{
+ if (!(opt.file && opt.filebpb))
+ return 0;
+
+ return mangle_bpb(iter, data, "file");
+}
+
+/*
+ * Adjust BPB of a sector
+ */
+int mangles_bpb(const struct part_iter *iter, struct data_area *data)
+{
+ if (!(opt.sect && opt.setbpb))
+ return 0;
+
+ return mangle_bpb(iter, data, "sect");
+}
+
+/*
+ * This function performs full BPB patching, analogously to syslinux's
+ * native BSS.
+ */
+int manglesf_bss(struct data_area *sec, struct data_area *fil)
+{
+ int type1, type2;
+ unsigned int cnt = 0;
+
+ if (!(opt.sect && opt.file && opt.bss))
+ return 0;
+
+ type1 = bpb_detect(fil->data, "bss/file");
+ type2 = bpb_detect(sec->data, "bss/sect");
+
+ if (!type1 || !type2) {
+ error("Couldn't determine the BPB type for option 'bss'.\n");
+ goto bail;
+ }
+ if (type1 != type2) {
+ error("Option 'bss' can't be used,\n"
+ "when a sector and a file have incompatible BPBs.\n");
+ goto bail;
+ }
+
+ /* Copy common 2.0 data */
+ memcpy((char *)fil->data + 0x0B, (char *)sec->data + 0x0B, 0x0D);
+
+ /* Copy 3.0+ data */
+ if (type1 <= bpbV30) {
+ cnt = 0x06;
+ } else if (type1 <= bpbV32) {
+ cnt = 0x08;
+ } else if (type1 <= bpbV34) {
+ cnt = 0x0C;
+ } else if (type1 <= bpbV40) {
+ cnt = 0x2E;
+ } else if (type1 <= bpbVNT) {
+ cnt = 0x3C;
+ } else if (type1 <= bpbV70) {
+ cnt = 0x42;
+ }
+ memcpy((char *)fil->data + 0x18, (char *)sec->data + 0x18, cnt);
+
+ return 0;
+bail:
+ return -1;
+}
+
+/*
+ * Save sector.
+ */
+int mangles_save(const struct part_iter *iter, const struct data_area *data, void *org)
+{
+ if (!(opt.sect && opt.save))
+ return 0;
+
+ if (memcmp(org, data->data, data->size)) {
+ if (disk_write_sectors(&iter->di, iter->start_lba, data->data, 1)) {
+ error("Cannot write the updated sector.\n");
+ goto bail;
+ }
+ /* function can be called again */
+ memcpy(org, data->data, data->size);
+ }
+
+ return 0;
+bail:
+ return -1;
+}
+
+/*
+ * To boot the Recovery Console of Windows NT/2K/XP we need to write
+ * the string "cmdcons\0" to memory location 0000:7C03.
+ * Memory location 0000:7C00 contains the bootsector of the partition.
+ */
+int mangles_cmldr(struct data_area *data)
+{
+ if (!(opt.sect && opt.cmldr))
+ return 0;
+
+ memcpy((char *)data->data + 3, cmldr_signature, sizeof(cmldr_signature));
+ return 0;
+}
+
+/* Set common registers */
+int mangler_init(const struct part_iter *iter)
+{
+ /* Set initial registry values */
+ if (opt.file) {
+ opt.regs.cs = opt.regs.ds = opt.regs.ss = (uint16_t)opt.fseg;
+ opt.regs.ip = (uint16_t)opt.fip;
+ } else {
+ opt.regs.cs = opt.regs.ds = opt.regs.ss = (uint16_t)opt.sseg;
+ opt.regs.ip = (uint16_t)opt.sip;
+ }
+
+ if (opt.regs.ip == 0x7C00 && !opt.regs.cs)
+ opt.regs.esp.l = 0x7C00;
+
+ /* DOS kernels want the drive number in BL instead of DL. Indulge them. */
+ opt.regs.ebx.b[0] = opt.regs.edx.b[0] = (uint8_t)iter->di.disk;
+
+ return 0;
+}
+
+/* ds:si & ds:bp */
+int mangler_handover(const struct part_iter *iter, const struct data_area *data)
+{
+ if (opt.file && opt.maps && !opt.hptr) {
+ opt.regs.esi.l = opt.regs.ebp.l = opt.soff;
+ opt.regs.ds = (uint16_t)opt.sseg;
+ opt.regs.eax.l = 0;
+ } else if (opt.hand) {
+ /* base is really 0x7be */
+ opt.regs.esi.l = opt.regs.ebp.l = data->base;
+ opt.regs.ds = 0;
+ if (iter->index && iter->type == typegpt) /* must be iterated and GPT */
+ opt.regs.eax.l = 0x54504721; /* '!GPT' */
+ else
+ opt.regs.eax.l = 0;
+ }
+
+ return 0;
+}
+
+/*
+ * GRLDR of GRUB4DOS wants the partition number in DH:
+ * -1: whole drive (default)
+ * 0-3: primary partitions
+ * 4-*: logical partitions
+ */
+int mangler_grldr(const struct part_iter *iter)
+{
+ if (opt.grldr)
+ opt.regs.edx.b[1] = (uint8_t)(iter->index - 1);
+
+ return 0;
+}
+
+/*
+ * try to copy values from temporary iterator, if positions match
+ */
+static void push_embr(struct part_iter *diter, struct part_iter *siter)
+{
+ if (diter->sub.dos.cebr_lba == siter->sub.dos.cebr_lba &&
+ diter->di.disk == siter->di.disk) {
+ memcpy(diter->data, siter->data, sizeof(struct disk_dos_mbr));
+ }
+}
+
+static int mpe_sethide(struct part_iter *iter, struct part_iter *miter)
+{
+ struct disk_dos_part_entry *dp;
+ static const uint16_t mask =
+ (1 << 0x01) | (1 << 0x04) | (1 << 0x06) |
+ (1 << 0x07) | (1 << 0x0b) | (1 << 0x0c) | (1 << 0x0e);
+ uint8_t t;
+
+ dp = (struct disk_dos_part_entry *)iter->record;
+ t = dp->ostype;
+
+ if ((t <= 0x1f) && ((mask >> (t & ~0x10u)) & 1)) {
+ /* It's a hideable partition type */
+ if (miter->index == iter->index || opt.hide & 4)
+ t &= (uint8_t)(~0x10u); /* unhide */
+ else
+ t |= 0x10u; /* hide */
+ }
+ if (dp->ostype != t) {
+ dp->ostype = t;
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * miter - iterator we match against
+ * hide bits meaning:
+ * ..| - enable (1) / disable (0)
+ * .|. - all (1) / pri (0)
+ * |.. - unhide (1) / hide (0)
+ */
+int manglepe_hide(struct part_iter *miter)
+{
+ int wb = 0, werr = 0;
+ struct part_iter *iter = NULL;
+ struct disk_dos_part_entry *dp;
+ int ridx;
+
+ if (!opt.hide)
+ return 0;
+
+ if (miter->type != typedos) {
+ error("Options '*hide*' is meaningful only for legacy partition scheme.\n");
+ return -1;
+ }
+
+ if (miter->index < 1)
+ error("WARNING: It's impossible to unhide a disk.\n");
+
+ if (miter->index > 4 && !(opt.hide & 2))
+ error("WARNING: your partition is beyond mbr, so it can't be unhidden without '*hideall'.\n");
+
+ if (!(iter = pi_begin(&miter->di, 1))) /* turn stepall on */
+ return -1;
+
+ while (!pi_next(&iter) && !werr) {
+ ridx = iter->rawindex;
+ if (!(opt.hide & 2) && ridx > 4)
+ break; /* skip when we're constrained to pri only */
+
+ dp = (struct disk_dos_part_entry *)iter->record;
+ if (dp->ostype)
+ wb |= mpe_sethide(iter, miter);
+
+ if (ridx >= 4 && wb && !werr) {
+ push_embr(miter, iter);
+ werr |= disk_write_sectors(&iter->di, iter->sub.dos.cebr_lba, iter->data, 1);
+ wb = 0;
+ }
+ }
+
+ if (iter->status > PI_DONE)
+ goto bail;
+
+ /* last write */
+ if (wb && !werr) {
+ push_embr(miter, iter);
+ werr |= disk_write_sectors(&iter->di, iter->sub.dos.cebr_lba, iter->data, 1);
+ }
+ if (werr)
+ error("WARNING: failed to write E/MBR during '*hide*'\n");
+
+bail:
+ pi_del(&iter);
+ return 0;
+}
+
+static int mpe_setchs(const struct disk_info *di,
+ struct disk_dos_part_entry *dp,
+ uint32_t lba1)
+{
+ uint32_t ochs1, ochs2;
+
+ ochs1 = *(uint32_t *)dp->start;
+ ochs2 = *(uint32_t *)dp->end;
+
+ lba2chs(&dp->start, di, lba1, l2c_cadd);
+ lba2chs(&dp->end, di, lba1 + dp->length - 1, l2c_cadd);
+
+ return
+ *(uint32_t *)dp->start != ochs1 ||
+ *(uint32_t *)dp->end != ochs2;
+}
+
+/*
+ * miter - iterator we match against
+ */
+int manglepe_fixchs(struct part_iter *miter)
+{
+ int wb = 0, werr = 0;
+ struct part_iter *iter = NULL;
+ struct disk_dos_part_entry *dp;
+ int ridx;
+
+ if (!opt.fixchs)
+ return 0;
+
+ if (miter->type != typedos) {
+ error("Options 'fixchs' is meaningful only for legacy partition scheme.\n");
+ return -1;
+ }
+
+ if (!(iter = pi_begin(&miter->di, 1))) /* turn stepall on */
+ return -1;
+
+ while (!pi_next(&iter) && !werr) {
+ ridx = iter->rawindex;
+ dp = (struct disk_dos_part_entry *)iter->record;
+
+ wb |= mpe_setchs(&iter->di, dp, (uint32_t)iter->start_lba);
+ if (ridx > 4)
+ wb |= mpe_setchs(&iter->di, dp + 1, iter->sub.dos.nebr_lba);
+
+ if (ridx >= 4 && wb && !werr) {
+ push_embr(miter, iter);
+ werr |= disk_write_sectors(&iter->di, iter->sub.dos.cebr_lba, iter->data, 1);
+ wb = 0;
+ }
+ }
+
+ if (iter->status > PI_DONE)
+ goto bail;
+
+ /* last write */
+ if (wb && !werr) {
+ push_embr(miter, iter);
+ werr |= disk_write_sectors(&iter->di, iter->sub.dos.cebr_lba, iter->data, 1);
+ }
+ if (werr)
+ error("WARNING: failed to write E/MBR during 'fixchs'\n");
+
+bail:
+ pi_del(&iter);
+ return 0;
+}
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/mangle.h b/com32/chain/mangle.h
new file mode 100644
index 00000000..bcefea3b
--- /dev/null
+++ b/com32/chain/mangle.h
@@ -0,0 +1,32 @@
+#ifndef _COM32_CHAIN_MANGLE_H
+#define _COM32_CHAIN_MANGLE_H
+
+#include "chain.h"
+#include "partiter.h"
+
+/* file's manglers */
+int manglef_isolinux(struct data_area *data);
+int manglef_grub(const struct part_iter *iter, struct data_area *data);
+int manglef_bpb(const struct part_iter *iter, struct data_area *data);
+/* int manglef_drmk(struct data_area *data);*/
+
+/* sector's manglers */
+int mangles_bpb(const struct part_iter *iter, struct data_area *data);
+int mangles_save(const struct part_iter *iter, const struct data_area *data, void *org);
+int mangles_cmldr(struct data_area *data);
+
+/* sector + file's manglers */
+int manglesf_bss(struct data_area *sec, struct data_area *fil);
+
+/* registers' manglers */
+int mangler_init(const struct part_iter *iter);
+int mangler_handover(const struct part_iter *iter, const struct data_area *data);
+int mangler_grldr(const struct part_iter *iter);
+
+/* partition layout's manglers */
+int manglepe_fixchs(struct part_iter *miter);
+int manglepe_hide(struct part_iter *miter);
+
+#endif
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/options.c b/com32/chain/options.c
new file mode 100644
index 00000000..658a45ca
--- /dev/null
+++ b/com32/chain/options.c
@@ -0,0 +1,376 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include "common.h"
+#include "chain.h"
+#include "utility.h"
+#include "options.h"
+
+struct options opt;
+
+static int soi_s2n(char *ptr, unsigned int *seg,
+ unsigned int *off,
+ unsigned int *ip,
+ unsigned int def)
+{
+ unsigned int segval = 0, offval, ipval, val;
+ char *p;
+
+ offval = def;
+ ipval = def;
+
+ segval = strtoul(ptr, &p, 0);
+ if (p[0] == ':' && p[1] && p[1] != ':')
+ offval = strtoul(p+1, &p, 0);
+ if (p[0] == ':' && p[1] && p[1] != ':')
+ ipval = strtoul(p+1, NULL, 0);
+
+ val = (segval << 4) + offval;
+
+ if (val < ADDRMIN || val > ADDRMAX) {
+ error("Invalid seg:off:* address specified..\n");
+ goto bail;
+ }
+
+ val = (segval << 4) + ipval;
+
+ if (ipval > 0xFFFE || val < ADDRMIN || val > ADDRMAX) {
+ error("Invalid seg:*:ip address specified.\n");
+ goto bail;
+ }
+
+ if (seg)
+ *seg = segval;
+ if (off)
+ *off = offval;
+ if (ip)
+ *ip = ipval;
+
+ return 0;
+bail:
+ return -1;
+}
+
+static void usage(void)
+{
+ unsigned int i;
+ static const char key[] = "Press any key...\n";
+ static const char *const usage[] = {
+"\
+Usage:\n\
+ chain.c32 [options]\n\
+ chain.c32 {fd|hd}<disk#>{,| }[<part#>] [options]\n\
+ chain.c32 mbr{:|=}<id>{,| }[<part#>] [options]\n\
+ chain.c32 guid{:|=}<guid>{,| }[<part#>] [options]\n\
+ chain.c32 label{:|=}<label> [<part#>] [options]\n\
+ chain.c32 boot{,| }[<part#>] [options]\n\
+ chain.c32 fs [options]\n\
+", "\
+\nOptions ('no' prefix specifies default value):\n\
+ sect[=<s[:o[:i]]>] Load sector at <s:o>, jump to <s:i>\n\
+ - defaults to 0:0x7C00:0x7C00\n\
+ - ommited o/i values default to 0\n\
+ maps Map loaded sector into real memory\n\
+ nosetbpb Fix BPB fields in loaded sector\n\
+ nofilebpb Apply 'setbpb' to loaded file\n\
+ nosave Write adjusted sector back to disk\n\
+ hand Prepare handover area\n\
+ nohptr Force ds:si and ds:bp to point to handover area\n\
+ noswap Swap drive numbers, if bootdisk is not fd0/hd0\n\
+ nohide Disable all hide variations (also the default)\n\
+ hide Hide primary partitions, unhide selected partition\n\
+ hideall Hide *all* partitions, unhide selected partition\n\
+ unhide Unhide primary partitions\n\
+ unhideall Unhide *all* partitions\n\
+ nofixchs Walk *all* partitions and fix E/MBRs' chs values\n\
+ nokeeppxe Keep the PXE and UNDI stacks in memory (PXELINUX)\n\
+ nowarn Wait for a keypress to continue chainloading\n\
+ - useful to see emited warnings\n\
+ nobreak Actually perform the chainloading\n\
+", "\
+\nOptions continued ...\n\
+ file=<file> Load and execute <file>\n\
+ seg=<s[:o[:i]]> Load file at <s:o>, jump to <s:i>\n\
+ - defaults to 0:0x7C00:0x7C00\n\
+ - ommited o/i values default to 0\n\
+ isolinux=<loader> Load another version of ISOLINUX\n\
+ ntldr=<loader> Load Windows NTLDR, SETUPLDR.BIN or BOOTMGR\n\
+ reactos=<loader> Load ReactOS's loader\n\
+ cmldr=<loader> Load Recovery Console of Windows NT/2K/XP/2003\n\
+ freedos=<loader> Load FreeDOS KERNEL.SYS\n\
+ msdos=<loader> Load MS-DOS 2.xx - 6.xx IO.SYS\n\
+ msdos7=<loader> Load MS-DOS 7+ IO.SYS\n\
+ pcdos=<loader> Load PC-DOS IBMBIO.COM\n\
+ drmk=<loader> Load DRMK DELLBIO.BIN\n\
+ grub=<loader> Load GRUB Legacy stage2\n\
+ grubcfg=<filename> Set alternative config filename for GRUB Legacy\n\
+ grldr=<loader> Load GRUB4DOS grldr\n\
+ bss=<filename> Emulate syslinux's BSS\n\
+ bs=<filename> Emulate syslinux's BS\n\
+\nPlease see doc/chain.txt for the detailed documentation.\n\
+"
+ };
+ for (i = 0; i < sizeof(usage)/sizeof(usage[0]); i++) {
+ if (i) {
+ error(key);
+ wait_key();
+ }
+ error(usage[i]);
+ }
+}
+
+void opt_set_defs(void)
+{
+ memset(&opt, 0, sizeof(opt));
+ opt.sect = true; /* by def. load sector */
+ opt.maps = true; /* by def. map sector */
+ opt.hand = true; /* by def. prepare handover */
+ opt.brkchain = false; /* by def. do chainload */
+ opt.foff = opt.soff = opt.fip = opt.sip = 0x7C00;
+ opt.drivename = "boot";
+#ifdef DEBUG
+ opt.warn = true;
+#endif
+}
+
+int opt_parse_args(int argc, char *argv[])
+{
+ int i;
+ unsigned int v;
+ char *p;
+
+ for (i = 1; i < argc; i++) {
+ if (!strncmp(argv[i], "file=", 5)) {
+ opt.file = argv[i] + 5;
+ } else if (!strcmp(argv[i], "nofile")) {
+ opt.file = NULL;
+ } else if (!strncmp(argv[i], "seg=", 4)) {
+ if (soi_s2n(argv[i] + 4, &opt.fseg, &opt.foff, &opt.fip, 0))
+ goto bail;
+ } else if (!strncmp(argv[i], "bss=", 4)) {
+ opt.file = argv[i] + 4;
+ opt.bss = true;
+ opt.maps = false;
+ opt.setbpb = true;
+ /* opt.save = true; */
+ } else if (!strncmp(argv[i], "bs=", 3)) {
+ opt.file = argv[i] + 3;
+ opt.sect = false;
+ opt.filebpb = true;
+ } else if (!strncmp(argv[i], "isolinux=", 9)) {
+ opt.file = argv[i] + 9;
+ opt.isolinux = true;
+ opt.hand = false;
+ opt.sect = false;
+ } else if (!strncmp(argv[i], "ntldr=", 6)) {
+ opt.fseg = 0x2000; /* NTLDR wants this address */
+ opt.foff = 0;
+ opt.fip = 0;
+ opt.file = argv[i] + 6;
+ opt.setbpb = true;
+ /* opt.save = true; */
+ opt.hand = false;
+ } else if (!strncmp(argv[i], "reactos=", 8)) {
+ /*
+ * settings based on commit
+ * ad4cf1470977f648ee1dd45e97939589ccb0393c
+ * note, conflicts with:
+ * http://reactos.freedoors.org/Reactos%200.3.13/ReactOS-0.3.13-REL-src/boot/freeldr/notes.txt
+ */
+ opt.fseg = 0;
+ opt.foff = 0x8000;
+ opt.fip = 0x8100;
+ opt.file = argv[i] + 8;
+ opt.setbpb = true;
+ /* opt.save = true; */
+ opt.hand = false;
+ } else if (!strncmp(argv[i], "cmldr=", 6)) {
+ opt.fseg = 0x2000; /* CMLDR wants this address */
+ opt.foff = 0;
+ opt.fip = 0;
+ opt.file = argv[i] + 6;
+ opt.cmldr = true;
+ opt.setbpb = true;
+ /* opt.save = true; */
+ opt.hand = false;
+ } else if (!strncmp(argv[i], "freedos=", 8)) {
+ opt.fseg = 0x60; /* FREEDOS wants this address */
+ opt.foff = 0;
+ opt.fip = 0;
+ opt.sseg = 0x1FE0;
+ opt.file = argv[i] + 8;
+ opt.setbpb = true;
+ /* opt.save = true; */
+ opt.hand = false;
+ } else if ( (v = 6, !strncmp(argv[i], "msdos=", v) ||
+ !strncmp(argv[i], "pcdos=", v)) ||
+ (v = 7, !strncmp(argv[i], "msdos7=", v)) ) {
+ opt.fseg = 0x70; /* MS-DOS 2.00 .. 6.xx wants this address */
+ opt.foff = 0;
+ opt.fip = v == 7 ? 0x200 : 0; /* MS-DOS 7.0+ wants this ip */
+ opt.sseg = 0x8000;
+ opt.file = argv[i] + v;
+ opt.setbpb = true;
+ /* opt.save = true; */
+ opt.hand = false;
+ } else if (!strncmp(argv[i], "drmk=", 5)) {
+ opt.fseg = 0x70; /* DRMK wants this address */
+ opt.foff = 0;
+ opt.fip = 0;
+ opt.sseg = 0x2000;
+ opt.soff = 0;
+ opt.sip = 0;
+ opt.file = argv[i] + 5;
+ /* opt.drmk = true; */
+ opt.setbpb = true;
+ /* opt.save = true; */
+ opt.hand = false;
+ } else if (!strncmp(argv[i], "grub=", 5)) {
+ opt.fseg = 0x800; /* stage2 wants this address */
+ opt.foff = 0;
+ opt.fip = 0x200;
+ opt.file = argv[i] + 5;
+ opt.grub = true;
+ opt.hand = false;
+ opt.sect = false;
+ } else if (!strncmp(argv[i], "grubcfg=", 8)) {
+ opt.grubcfg = argv[i] + 8;
+ } else if (!strncmp(argv[i], "grldr=", 6)) {
+ opt.file = argv[i] + 6;
+ opt.grldr = true;
+ opt.hand = false;
+ opt.sect = false;
+ } else if (!strcmp(argv[i], "keeppxe")) {
+ opt.keeppxe = 3;
+ } else if (!strcmp(argv[i], "nokeeppxe")) {
+ opt.keeppxe = 0;
+ } else if (!strcmp(argv[i], "maps")) {
+ opt.maps = true;
+ } else if (!strcmp(argv[i], "nomaps")) {
+ opt.maps = false;
+ } else if (!strcmp(argv[i], "hand")) {
+ opt.hand = true;
+ } else if (!strcmp(argv[i], "nohand")) {
+ opt.hand = false;
+ } else if (!strcmp(argv[i], "hptr")) {
+ opt.hptr = true;
+ } else if (!strcmp(argv[i], "nohptr")) {
+ opt.hptr = false;
+ } else if (!strcmp(argv[i], "swap")) {
+ opt.swap = true;
+ } else if (!strcmp(argv[i], "noswap")) {
+ opt.swap = false;
+ } else if (!strcmp(argv[i], "nohide")) {
+ opt.hide = 0;
+ } else if (!strcmp(argv[i], "hide")) {
+ opt.hide = 1; /* 001b */
+ } else if (!strcmp(argv[i], "hideall")) {
+ opt.hide = 2; /* 010b */
+ } else if (!strcmp(argv[i], "unhide")) {
+ opt.hide = 5; /* 101b */
+ } else if (!strcmp(argv[i], "unhideall")) {
+ opt.hide = 6; /* 110b */
+ } else if (!strcmp(argv[i], "setbpb")) {
+ opt.setbpb = true;
+ } else if (!strcmp(argv[i], "nosetbpb")) {
+ opt.setbpb = false;
+ } else if (!strcmp(argv[i], "filebpb")) {
+ opt.filebpb = true;
+ } else if (!strcmp(argv[i], "nofilebpb")) {
+ opt.filebpb = false;
+ } else if (!strncmp(argv[i], "sect=", 5) ||
+ !strcmp(argv[i], "sect")) {
+ if (argv[i][4]) {
+ if (soi_s2n(argv[i] + 5, &opt.sseg, &opt.soff, &opt.sip, 0))
+ goto bail;
+ }
+ opt.sect = true;
+ } else if (!strcmp(argv[i], "nosect")) {
+ opt.sect = false;
+ opt.maps = false;
+ } else if (!strcmp(argv[i], "save")) {
+ opt.save = true;
+ } else if (!strcmp(argv[i], "nosave")) {
+ opt.save = false;
+ } else if (!strcmp(argv[i], "fixchs")) {
+ opt.fixchs = true;
+ } else if (!strcmp(argv[i], "nofixchs")) {
+ opt.fixchs = false;
+ } else if (!strcmp(argv[i], "warn")) {
+ opt.warn = true;
+ } else if (!strcmp(argv[i], "nowarn")) {
+ opt.warn = false;
+ } else if (!strcmp(argv[i], "nobreak")) {
+ opt.brkchain = false;
+ } else if (!strcmp(argv[i], "break")) {
+ opt.brkchain = true;
+ opt.file = NULL;
+ opt.maps = false;
+ opt.hand = false;
+ } else if (((argv[i][0] == 'h' || argv[i][0] == 'f')
+ && argv[i][1] == 'd')
+ || !strncmp(argv[i], "mbr:", 4)
+ || !strncmp(argv[i], "mbr=", 4)
+ || !strncmp(argv[i], "guid:", 5)
+ || !strncmp(argv[i], "guid=", 5)
+ || !strncmp(argv[i], "label:", 6)
+ || !strncmp(argv[i], "label=", 6)
+ || !strcmp(argv[i], "boot")
+ || !strncmp(argv[i], "boot,", 5)
+ || !strcmp(argv[i], "fs")) {
+ opt.drivename = argv[i];
+ if (strncmp(argv[i], "label", 5))
+ p = strchr(opt.drivename, ',');
+ else
+ p = NULL;
+ if (p) {
+ *p = '\0';
+ opt.partition = p + 1;
+ } else if (argv[i + 1] && argv[i + 1][0] >= '0'
+ && argv[i + 1][0] <= '9') {
+ opt.partition = argv[++i];
+ }
+ } else {
+ usage();
+ goto bail;
+ }
+ }
+
+ if (opt.grubcfg && !opt.grub) {
+ error("grubcfg=<filename> must be used together with grub=<loader>.\n");
+ goto bail;
+ }
+
+#if 0
+ if ((!opt.maps || !opt.sect) && !opt.file) {
+ error("You have to load something.\n");
+ goto bail;
+ }
+#endif
+
+ if (opt.filebpb && !opt.file) {
+ error("Option 'filebpb' requires a file.\n");
+ goto bail;
+ }
+
+ if (opt.save && !opt.sect) {
+ error("Option 'save' requires a sector.\n");
+ goto bail;
+ }
+
+ if (opt.setbpb && !opt.sect) {
+ error("Option 'setbpb' requires a sector.\n");
+ goto bail;
+ }
+
+ if (opt.maps && !opt.sect) {
+ error("Option 'maps' requires a sector.\n");
+ goto bail;
+ }
+
+ return 0;
+bail:
+ return -1;
+}
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/options.h b/com32/chain/options.h
new file mode 100644
index 00000000..4493ef1f
--- /dev/null
+++ b/com32/chain/options.h
@@ -0,0 +1,47 @@
+#ifndef _COM32_CHAIN_OPTIONS_H
+#define _COM32_CHAIN_OPTIONS_H
+
+#include <stdint.h>
+#include <syslinux/bootrm.h>
+
+struct options {
+ unsigned int fseg;
+ unsigned int foff;
+ unsigned int fip;
+ unsigned int sseg;
+ unsigned int soff;
+ unsigned int sip;
+ const char *drivename;
+ const char *partition;
+ const char *file;
+ const char *grubcfg;
+ bool isolinux;
+ bool cmldr;
+ bool drmk;
+ bool grub;
+ bool grldr;
+ bool maps;
+ bool hand;
+ bool hptr;
+ bool swap;
+ int hide;
+ bool sect;
+ bool save;
+ bool bss;
+ bool setbpb;
+ bool filebpb;
+ bool fixchs;
+ bool warn;
+ bool brkchain;
+ uint16_t keeppxe;
+ struct syslinux_rm_regs regs;
+};
+
+extern struct options opt;
+
+void opt_set_defs(void);
+int opt_parse_args(int argc, char *argv[]);
+
+#endif
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/partiter.c b/com32/chain/partiter.c
new file mode 100644
index 00000000..1acd1958
--- /dev/null
+++ b/com32/chain/partiter.c
@@ -0,0 +1,805 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2003-2010 H. Peter Anvin - All Rights Reserved
+ * Copyright 2010 Shao Miller
+ * Copyright 2010 Michal Soltys
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * partiter.c
+ *
+ * Provides disk / partition iteration.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <zlib.h>
+#include <syslinux/disk.h>
+#include "common.h"
+#include "partiter.h"
+#include "utility.h"
+
+#define ost_is_ext(type) ((type) == 0x05 || (type) == 0x0F || (type) == 0x85)
+#define ost_is_nondata(type) (ost_is_ext(type) || (type) == 0x00)
+#define sane(s,l) ((s)+(l) > (s))
+
+/* forwards */
+
+static int iter_ctor(struct part_iter *, va_list *);
+static int iter_dos_ctor(struct part_iter *, va_list *);
+static int iter_gpt_ctor(struct part_iter *, va_list *);
+static void iter_dtor(struct part_iter *);
+static struct part_iter *pi_dos_next(struct part_iter *);
+static struct part_iter *pi_gpt_next(struct part_iter *);
+static struct part_iter *pi_raw_next(struct part_iter *);
+
+static struct itertype types[] = {
+ [0] = {
+ .ctor = &iter_dos_ctor,
+ .dtor = &iter_dtor,
+ .next = &pi_dos_next,
+}, [1] = {
+ .ctor = &iter_gpt_ctor,
+ .dtor = &iter_dtor,
+ .next = &pi_gpt_next,
+}, [2] = {
+ .ctor = &iter_ctor,
+ .dtor = &iter_dtor,
+ .next = &pi_raw_next,
+}};
+
+const struct itertype * const typedos = types;
+const struct itertype * const typegpt = types+1;
+const struct itertype * const typeraw = types+2;
+
+#ifdef DEBUG
+static int inv_type(const void *type)
+{
+ int i, cnt = sizeof(types)/sizeof(types[0]);
+ for (i = 0; i < cnt; i++) {
+ if (type == types + i)
+ return 0;
+ }
+ return -1;
+}
+#endif
+
+/**
+ * iter_ctor() - common iterator initialization
+ * @iter: iterator pointer
+ * @args(0): disk_info structure used for disk functions
+ * @args(1): stepall modifier
+ *
+ * Second and further arguments are passed as a pointer to va_list
+ **/
+static int iter_ctor(struct part_iter *iter, va_list *args)
+{
+ const struct disk_info *di = va_arg(*args, const struct disk_info *);
+ int stepall = va_arg(*args, int);
+
+#ifdef DEBUG
+ if (!di)
+ return -1;
+#endif
+
+ memcpy(&iter->di, di, sizeof(struct disk_info));
+ iter->stepall = stepall;
+ iter->index0 = -1;
+ iter->length = di->lbacnt;
+
+ return 0;
+}
+
+/**
+ * iter_dtor() - common iterator cleanup
+ * @iter: iterator pointer
+ *
+ **/
+static void iter_dtor(struct part_iter *iter)
+{
+ free(iter->data);
+}
+
+/**
+ * iter_dos_ctor() - MBR/EBR iterator specific initialization
+ * @iter: iterator pointer
+ * @args(0): disk_info structure used for disk functions
+ * @args(1): pointer to buffer with loaded valid MBR
+ *
+ * Second and further arguments are passed as a pointer to va_list.
+ * This function only makes rudimentary checks. If user uses
+ * pi_new(), he/she is responsible for doing proper sanity checks.
+ **/
+static int iter_dos_ctor(struct part_iter *iter, va_list *args)
+{
+ const struct disk_dos_mbr *mbr;
+
+ /* uses args(0) */
+ if (iter_ctor(iter, args))
+ return -1;
+
+ mbr = va_arg(*args, const struct disk_dos_mbr *);
+
+#ifdef DEBUG
+ if (!mbr)
+ goto bail;
+#endif
+
+ if (!(iter->data = malloc(sizeof(struct disk_dos_mbr))))
+ goto bail;
+
+ memcpy(iter->data, mbr, sizeof(struct disk_dos_mbr));
+
+ iter->sub.dos.bebr_index0 = -1;
+ iter->sub.dos.disk_sig = mbr->disk_sig;
+
+ return 0;
+bail:
+ iter->type->dtor(iter);
+ return -1;
+}
+
+/**
+ * iter_gpt_ctor() - GPT iterator specific initialization
+ * @iter: iterator pointer
+ * @args(0): ptr to disk_info structure
+ * @args(1): ptr to buffer with GPT header
+ * @args(2): ptr to buffer with GPT partition list
+ *
+ * Second and further arguments are passed as a pointer to va_list.
+ * This function only makes rudimentary checks. If user uses
+ * pi_new(), he/she is responsible for doing proper sanity checks.
+ **/
+static int iter_gpt_ctor(struct part_iter *iter, va_list *args)
+{
+ uint64_t siz;
+ const struct disk_gpt_header *gpth;
+ const struct disk_gpt_part_entry *gptl;
+
+ /* uses args(0) */
+ if (iter_ctor(iter, args))
+ return -1;
+
+ gpth = va_arg(*args, const struct disk_gpt_header *);
+ gptl = va_arg(*args, const struct disk_gpt_part_entry *);
+
+#ifdef DEBUG
+ if (!gpth || !gptl)
+ goto bail;
+#endif
+
+ siz = (uint64_t)gpth->part_count * gpth->part_size;
+
+#ifdef DEBUG
+ if (!siz || (siz + iter->di.bps - 1) / iter->di.bps > 255u ||
+ gpth->part_size < sizeof(struct disk_gpt_part_entry)) {
+ goto bail;
+ }
+#endif
+
+ if (!(iter->data = malloc((size_t)siz)))
+ goto bail;
+
+ memcpy(iter->data, gptl, (size_t)siz);
+
+ iter->sub.gpt.pe_count = (int)gpth->part_count;
+ iter->sub.gpt.pe_size = (int)gpth->part_size;
+ iter->sub.gpt.ufirst = gpth->lba_first_usable;
+ iter->sub.gpt.ulast = gpth->lba_last_usable;
+
+ memcpy(&iter->sub.gpt.disk_guid, &gpth->disk_guid, sizeof(struct guid));
+
+ return 0;
+bail:
+ iter->type->dtor(iter);
+ return -1;
+}
+
+/* Logical partition must be sane, meaning:
+ * - must be data or empty
+ * - must have non-0 start and length
+ * - values must not wrap around 32bit
+ * - must be inside current EBR frame
+ */
+
+static int notsane_logical(const struct part_iter *iter)
+{
+ const struct disk_dos_part_entry *dp;
+ uint32_t end_log;
+
+ dp = ((struct disk_dos_mbr *)iter->data)->table;
+
+ if (!dp[0].ostype)
+ return 0;
+
+ if (ost_is_ext(dp[0].ostype)) {
+ error("1st EBR entry must be data or empty.\n");
+ return -1;
+ }
+
+ end_log = dp[0].start_lba + dp[0].length;
+
+ if (!dp[0].start_lba ||
+ !dp[0].length ||
+ !sane(dp[0].start_lba, dp[0].length) ||
+ end_log > iter->sub.dos.ebr_size) {
+
+ error("Insane logical partition.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Extended partition must be sane, meaning:
+ * - must be extended or empty
+ * - must have non-0 start and length
+ * - values must not wrap around 32bit
+ * - must be inside base EBR frame
+ */
+
+static int notsane_extended(const struct part_iter *iter)
+{
+ const struct disk_dos_part_entry *dp;
+ uint32_t end_ebr;
+
+ dp = ((struct disk_dos_mbr *)iter->data)->table;
+
+ if (!dp[1].ostype)
+ return 0;
+
+ if (!ost_is_nondata(dp[1].ostype)) {
+ error("2nd EBR entry must be extended or empty.\n");
+ return -1;
+ }
+
+ end_ebr = dp[1].start_lba + dp[1].length;
+
+ if (!dp[1].start_lba ||
+ !dp[1].length ||
+ !sane(dp[1].start_lba, dp[1].length) ||
+ end_ebr > iter->sub.dos.bebr_size) {
+
+ error("Insane extended partition.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Primary partition must be sane, meaning:
+ * - must have non-0 start and length
+ * - values must not wrap around 32bit
+ */
+
+static int notsane_primary(const struct part_iter *iter)
+{
+ const struct disk_dos_part_entry *dp;
+ dp = ((struct disk_dos_mbr *)iter->data)->table + iter->index0;
+
+ if (!dp->ostype)
+ return 0;
+
+ if (!dp->start_lba ||
+ !dp->length ||
+ !sane(dp->start_lba, dp->length) ||
+ dp->start_lba + dp->length > iter->di.lbacnt) {
+ error("Insane primary (MBR) partition.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int notsane_gpt(const struct part_iter *iter)
+{
+ const struct disk_gpt_part_entry *gp;
+ gp = (const struct disk_gpt_part_entry *)
+ (iter->data + iter->index0 * iter->sub.gpt.pe_size);
+
+ if (guid_is0(&gp->type))
+ return 0;
+
+ if (gp->lba_first < iter->sub.gpt.ufirst ||
+ gp->lba_last > iter->sub.gpt.ulast) {
+ error("Insane GPT partition.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int pi_dos_next_mbr(struct part_iter *iter, uint32_t *lba,
+ struct disk_dos_part_entry **_dp)
+{
+ struct disk_dos_part_entry *dp;
+
+ while (++iter->index0 < 4) {
+ dp = ((struct disk_dos_mbr *)iter->data)->table + iter->index0;
+
+ if (notsane_primary(iter)) {
+ iter->status = PI_INSANE;
+ goto bail;
+ }
+
+ if (ost_is_ext(dp->ostype)) {
+ if (iter->sub.dos.bebr_index0 >= 0) {
+ error("You have more than 1 extended partition.\n");
+ iter->status = PI_INSANE;
+ goto bail;
+ }
+ /* record base EBR index */
+ iter->sub.dos.bebr_index0 = iter->index0;
+ }
+ if (!ost_is_nondata(dp->ostype) || iter->stepall) {
+ *lba = dp->start_lba;
+ *_dp = dp;
+ break;
+ }
+ }
+
+ return 0;
+bail:
+ return -1;
+}
+
+static int prep_base_ebr(struct part_iter *iter)
+{
+ struct disk_dos_part_entry *dp;
+
+ if (iter->sub.dos.bebr_index0 < 0) /* if we don't have base extended partition at all */
+ return -1;
+ else if (!iter->sub.dos.bebr_start) { /* if not initialized yet */
+ dp = ((struct disk_dos_mbr *)iter->data)->table + iter->sub.dos.bebr_index0;
+
+ iter->sub.dos.bebr_start = dp->start_lba;
+ iter->sub.dos.bebr_size = dp->length;
+
+ iter->sub.dos.ebr_start = 0;
+ iter->sub.dos.ebr_size = iter->sub.dos.bebr_size;
+
+ iter->sub.dos.cebr_lba = 0;
+ iter->sub.dos.nebr_lba = iter->sub.dos.bebr_start;
+
+ iter->index0--;
+ }
+ return 0;
+}
+
+static int pi_dos_next_ebr(struct part_iter *iter, uint32_t *lba,
+ struct disk_dos_part_entry **_dp)
+{
+ struct disk_dos_part_entry *dp;
+
+ if (prep_base_ebr(iter)) {
+ iter->status = PI_DONE;
+ return -1;
+ }
+
+ while (++iter->index0 < 1024 && iter->sub.dos.nebr_lba) {
+ free(iter->data);
+ if (!(iter->data =
+ disk_read_sectors(&iter->di, iter->sub.dos.nebr_lba, 1))) {
+ error("Couldn't load EBR.\n");
+ iter->status = PI_ERRLOAD;
+ return -1;
+ }
+
+ if (notsane_logical(iter) || notsane_extended(iter)) {
+ iter->status = PI_INSANE;
+ return -1;
+ }
+
+ dp = ((struct disk_dos_mbr *)iter->data)->table;
+
+ iter->sub.dos.cebr_lba = iter->sub.dos.nebr_lba;
+
+ /* setup next frame values */
+ if (dp[1].ostype) {
+ iter->sub.dos.ebr_start = dp[1].start_lba;
+ iter->sub.dos.ebr_size = dp[1].length;
+ iter->sub.dos.nebr_lba = iter->sub.dos.bebr_start + dp[1].start_lba;
+ } else {
+ iter->sub.dos.ebr_start = 0;
+ iter->sub.dos.ebr_size = 0;
+ iter->sub.dos.nebr_lba = 0;
+ }
+
+ if (!dp[0].ostype)
+ iter->sub.dos.skipcnt++;
+
+ if (dp[0].ostype || iter->stepall) {
+ *lba = iter->sub.dos.cebr_lba + dp[0].start_lba;
+ *_dp = dp;
+ return 0;
+ }
+ /*
+ * This way it's possible to continue, if some crazy soft left a "hole"
+ * - EBR with a valid extended partition without a logical one. In
+ * such case, linux will not reserve a number for such hole - so we
+ * don't increase index0. If stepall flag is set, we will never reach
+ * this place.
+ */
+ }
+ iter->status = PI_DONE;
+ return -1;
+}
+
+static struct part_iter *pi_dos_next(struct part_iter *iter)
+{
+ uint32_t start_lba = 0;
+ struct disk_dos_part_entry *dos_part = NULL;
+
+ if (iter->status)
+ goto bail;
+
+ /* look for primary partitions */
+ if (iter->index0 < 4 &&
+ pi_dos_next_mbr(iter, &start_lba, &dos_part))
+ goto bail;
+
+ /* look for logical partitions */
+ if (iter->index0 >= 4 &&
+ pi_dos_next_ebr(iter, &start_lba, &dos_part))
+ goto bail;
+
+ /*
+ * note special index handling, if we have stepall set -
+ * this is made to keep index consistent with non-stepall
+ * iterators
+ */
+
+ if (iter->index0 >= 4 && !dos_part->ostype)
+ iter->index = -1;
+ else
+ iter->index = iter->index0 - iter->sub.dos.skipcnt + 1;
+ iter->rawindex = iter->index0 + 1;
+ iter->start_lba = start_lba;
+ iter->length = dos_part->length;
+ iter->record = (char *)dos_part;
+
+#ifdef DEBUG
+ disk_dos_part_dump(dos_part);
+#endif
+
+ return iter;
+bail:
+ return NULL;
+}
+
+static void gpt_conv_label(struct part_iter *iter)
+{
+ const struct disk_gpt_part_entry *gp;
+ const int16_t *orig_lab;
+
+ gp = (const struct disk_gpt_part_entry *)
+ (iter->data + iter->index0 * iter->sub.gpt.pe_size);
+ orig_lab = (const int16_t *)gp->name;
+
+ /* caveat: this is very crude conversion */
+ for (int i = 0; i < PI_GPTLABSIZE/2; i++) {
+ iter->sub.gpt.part_label[i] = (char)orig_lab[i];
+ }
+ iter->sub.gpt.part_label[PI_GPTLABSIZE/2] = 0;
+}
+
+static struct part_iter *pi_gpt_next(struct part_iter *iter)
+{
+ const struct disk_gpt_part_entry *gpt_part = NULL;
+
+ if (iter->status)
+ goto bail;
+
+ while (++iter->index0 < iter->sub.gpt.pe_count) {
+ gpt_part = (const struct disk_gpt_part_entry *)
+ (iter->data + iter->index0 * iter->sub.gpt.pe_size);
+
+ if (notsane_gpt(iter)) {
+ iter->status = PI_INSANE;
+ goto bail;
+ }
+
+ if (!guid_is0(&gpt_part->type) || iter->stepall)
+ break;
+ }
+ /* no more partitions ? */
+ if (iter->index0 == iter->sub.gpt.pe_count) {
+ iter->status = PI_DONE;
+ goto bail;
+ }
+ /* gpt_part is guaranteed to be valid here */
+ iter->index = iter->index0 + 1;
+ iter->rawindex = iter->index0 + 1;
+ iter->start_lba = gpt_part->lba_first;
+ iter->length = gpt_part->lba_last - gpt_part->lba_first + 1;
+ iter->record = (char *)gpt_part;
+ memcpy(&iter->sub.gpt.part_guid, &gpt_part->uid, sizeof(struct guid));
+ gpt_conv_label(iter);
+
+#ifdef DEBUG
+ disk_gpt_part_dump(gpt_part);
+#endif
+
+ return iter;
+bail:
+ return NULL;
+}
+
+static struct part_iter *pi_raw_next(struct part_iter *iter)
+{
+ iter->status = PI_DONE;
+ return NULL;
+}
+
+static int check_crc(uint32_t crc_match, const uint8_t *buf, unsigned int siz)
+{
+ uint32_t crc;
+
+ crc = crc32(0, NULL, 0);
+ crc = crc32(crc, buf, siz);
+
+ return crc_match != crc;
+}
+
+static int gpt_check_hdr_crc(const struct disk_info * const diskinfo, struct disk_gpt_header **_gh)
+{
+ struct disk_gpt_header *gh = *_gh;
+ uint64_t lba_alt;
+ uint32_t hold_crc32;
+
+ hold_crc32 = gh->chksum;
+ gh->chksum = 0;
+ if (check_crc(hold_crc32, (const uint8_t *)gh, gh->hdr_size)) {
+ error("WARNING: Primary GPT header checksum invalid.\n");
+ /* retry with backup */
+ lba_alt = gh->lba_alt;
+ free(gh);
+ if (!(gh = *_gh = disk_read_sectors(diskinfo, lba_alt, 1))) {
+ error("Couldn't read backup GPT header.\n");
+ return -1;
+ }
+ hold_crc32 = gh->chksum;
+ gh->chksum = 0;
+ if (check_crc(hold_crc32, (const uint8_t *)gh, gh->hdr_size)) {
+ error("Secondary GPT header checksum invalid.\n");
+ return -1;
+ }
+ }
+ /* restore old checksum */
+ gh->chksum = hold_crc32;
+
+ return 0;
+}
+
+/*
+ * ----------------------------------------------------------------------------
+ * Following functions are for users to call.
+ * ----------------------------------------------------------------------------
+ */
+
+
+int pi_next(struct part_iter **_iter)
+{
+ struct part_iter *iter;
+
+ if(!_iter || !*_iter)
+ return 0;
+ iter = *_iter;
+#ifdef DEBUG
+ if (inv_type(iter->type)) {
+ error("This is not a valid iterator.\n");
+ return 0;
+ }
+#endif
+ if ((iter = iter->type->next(iter))) {
+ *_iter = iter;
+ }
+ return (*_iter)->status;
+}
+
+/**
+ * pi_new() - get new iterator
+ * @itertype: iterator type
+ * @...: variable arguments passed to ctors
+ *
+ * Variable arguments depend on the type. Please see functions:
+ * iter_gpt_ctor() and iter_dos_ctor() for details.
+ **/
+struct part_iter *pi_new(const struct itertype *type, ...)
+{
+ int badctor = 0;
+ struct part_iter *iter = NULL;
+ va_list ap;
+
+ va_start(ap, type);
+
+#ifdef DEBUG
+ if (inv_type(type)) {
+ error("Unknown iterator requested.\n");
+ goto bail;
+ }
+#endif
+
+ if (!(iter = malloc(sizeof(struct part_iter)))) {
+ error("Couldn't allocate memory for the iterator.\n");
+ goto bail;
+ }
+
+ memset(iter, 0, sizeof(struct part_iter));
+ iter->type = type;
+
+ if (type->ctor(iter, &ap)) {
+ badctor = -1;
+ error("Cannot initialize the iterator.\n");
+ goto bail;
+ }
+
+bail:
+ va_end(ap);
+ if (badctor) {
+ free(iter);
+ iter = NULL;
+ }
+ return iter;
+}
+
+/**
+ * pi_del() - delete iterator
+ * @iter: iterator double pointer
+ *
+ **/
+
+void pi_del(struct part_iter **_iter)
+{
+ struct part_iter *iter;
+
+ if(!_iter || !*_iter)
+ return;
+ iter = *_iter;
+
+#ifdef DEBUG
+ if (inv_type(iter->type)) {
+ error("This is not a valid iterator.\n");
+ return;
+ }
+#endif
+
+ iter->type->dtor(iter);
+ free(iter);
+ *_iter = NULL;
+}
+
+/**
+ * pi_begin() - check disk, validate, and get proper iterator
+ * @di: diskinfo struct pointer
+ *
+ * This function checks the disk for GPT or legacy partition table and allocates
+ * an appropriate iterator.
+ **/
+struct part_iter *pi_begin(const struct disk_info *di, int stepall)
+{
+ int setraw = 0;
+ struct part_iter *iter = NULL;
+ struct disk_dos_mbr *mbr = NULL;
+ struct disk_gpt_header *gpth = NULL;
+ struct disk_gpt_part_entry *gptl = NULL;
+
+ /* Read MBR */
+ if (!(mbr = disk_read_sectors(di, 0, 1))) {
+ error("Couldn't read first disk sector.\n");
+ goto bail;
+ }
+
+ setraw = -1;
+
+ /* Check for MBR magic*/
+ if (mbr->sig != disk_mbr_sig_magic) {
+ error("No MBR magic.\n");
+ goto bail;
+ }
+
+ /* Check for GPT protective MBR */
+ if (mbr->table[0].ostype == 0xEE) {
+ if (!(gpth = disk_read_sectors(di, 1, 1))) {
+ error("Couldn't read potential GPT header.\n");
+ goto bail;
+ }
+ }
+
+ if (gpth && gpth->rev.uint32 == 0x00010000 &&
+ !memcmp(gpth->sig, disk_gpt_sig_magic, sizeof(disk_gpt_sig_magic))) {
+ /* looks like GPT v1.0 */
+ uint64_t gpt_loff; /* offset to GPT partition list in sectors */
+ uint64_t gpt_lsiz; /* size of GPT partition list in bytes */
+ uint64_t gpt_lcnt; /* size of GPT partition in sectors */
+#ifdef DEBUG
+ puts("Looks like a GPT v1.0 disk.");
+ disk_gpt_header_dump(gpth);
+#endif
+ /* Verify checksum, fallback to backup, then bail if invalid */
+ if (gpt_check_hdr_crc(di, &gpth))
+ goto bail;
+
+ gpt_loff = gpth->lba_table;
+ gpt_lsiz = (uint64_t)gpth->part_size * gpth->part_count;
+ gpt_lcnt = (gpt_lsiz + di->bps - 1) / di->bps;
+
+ /*
+ * disk_read_sectors allows reading of max 255 sectors, so we use
+ * it as a sanity check base. EFI doesn't specify max (AFAIK).
+ * Apart from that, some extensive sanity checks.
+ */
+ if (!gpt_loff || !gpt_lsiz || gpt_lcnt > 255u ||
+ gpth->lba_first_usable > gpth->lba_last_usable ||
+ !sane(gpt_loff, gpt_lcnt) ||
+ gpt_loff + gpt_lcnt > gpth->lba_first_usable ||
+ !sane(gpth->lba_last_usable, gpt_lcnt) ||
+ gpth->lba_last_usable + gpt_lcnt >= gpth->lba_alt ||
+ gpth->lba_alt >= di->lbacnt ||
+ gpth->part_size < sizeof(struct disk_gpt_part_entry)) {
+ error("Invalid GPT header's values.\n");
+ goto bail;
+ }
+ if (!(gptl = disk_read_sectors(di, gpt_loff, (uint8_t)gpt_lcnt))) {
+ error("Couldn't read GPT partition list.\n");
+ goto bail;
+ }
+ /* Check array checksum(s). */
+ if (check_crc(gpth->table_chksum, (const uint8_t *)gptl, (unsigned int)gpt_lsiz)) {
+ error("WARNING: GPT partition list checksum invalid, trying backup.\n");
+ free(gptl);
+ /* secondary array directly precedes secondary header */
+ if (!(gptl = disk_read_sectors(di, gpth->lba_alt - gpt_lcnt, (uint8_t)gpt_lcnt))) {
+ error("Couldn't read backup GPT partition list.\n");
+ goto bail;
+ }
+ if (check_crc(gpth->table_chksum, (const uint8_t *)gptl, (unsigned int)gpt_lsiz)) {
+ error("Backup GPT partition list checksum invalid.\n");
+ goto bail;
+ }
+ }
+ /* allocate iterator and exit */
+ iter = pi_new(typegpt, di, stepall, gpth, gptl);
+ } else {
+ /* looks like MBR */
+ iter = pi_new(typedos, di, stepall, mbr);
+ }
+
+ setraw = 0;
+bail:
+ if (setraw) {
+ error("WARNING: treating disk as raw.\n");
+ iter = pi_new(typeraw, di, stepall);
+ }
+ free(mbr);
+ free(gpth);
+ free(gptl);
+
+ return iter;
+}
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/partiter.h b/com32/chain/partiter.h
new file mode 100644
index 00000000..7deeb534
--- /dev/null
+++ b/com32/chain/partiter.h
@@ -0,0 +1,107 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2003-2010 H. Peter Anvin - All Rights Reserved
+ * Copyright 2010 Michal Soltys
+ * Copyright 2010 Shao Miller
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * partiter.h
+ *
+ * Provides disk / partition iteration.
+ */
+
+#ifndef _COM32_CHAIN_PARTITER_H
+#define _COM32_CHAIN_PARTITER_H
+
+#include <stdint.h>
+#include <syslinux/disk.h>
+
+#define PI_ERRLOAD 3
+#define PI_INSANE 2
+#define PI_DONE 1
+#define PI_OK 0
+
+struct itertype;
+struct part_iter;
+
+struct itertype {
+ int (*ctor)(struct part_iter *, va_list *);
+ void (*dtor)(struct part_iter *);
+ struct part_iter *(*next) (struct part_iter *);
+};
+
+#define PI_GPTLABSIZE ((int)sizeof(((struct disk_gpt_part_entry *)0)->name))
+
+struct part_iter {
+ const struct itertype *type;
+ char *data;
+ char *record;
+ uint64_t start_lba;
+ uint64_t length;
+ int index;
+ int rawindex;
+ struct disk_info di;
+ int stepall;
+ int status;
+ /* internal */
+ int index0;
+ union _sub {
+ struct _dos {
+ uint32_t disk_sig;
+ uint32_t nebr_lba;
+ uint32_t cebr_lba;
+ /* internal */
+ uint32_t ebr_start;
+ uint32_t ebr_size;
+ uint32_t bebr_start;
+ uint32_t bebr_size;
+ int bebr_index0;
+ int skipcnt;
+ } dos;
+ struct _gpt {
+ struct guid disk_guid;
+ struct guid part_guid;
+ char part_label[PI_GPTLABSIZE/2+1];
+ int pe_count;
+ int pe_size;
+ uint64_t ufirst;
+ uint64_t ulast;
+ } gpt;
+ } sub;
+};
+
+extern const struct itertype * const typedos;
+extern const struct itertype * const typegpt;
+extern const struct itertype * const typeraw;
+
+struct part_iter *pi_begin(const struct disk_info *, int stepall);
+struct part_iter *pi_new(const struct itertype *, ...);
+void pi_del(struct part_iter **);
+int pi_next(struct part_iter **);
+
+#endif
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/utility.c b/com32/chain/utility.c
new file mode 100644
index 00000000..cb882722
--- /dev/null
+++ b/com32/chain/utility.c
@@ -0,0 +1,204 @@
+#include <com32.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <fs.h>
+#include <syslinux/disk.h>
+#include <syslinux/pmapi.h>
+#include "utility.h"
+
+static const char *bpbtypes[] = {
+ [0] = "unknown",
+ [1] = "2.0",
+ [2] = "3.0",
+ [3] = "3.2",
+ [4] = "3.4",
+ [5] = "4.0",
+ [6] = "8.0 (NT+)",
+ [7] = "7.0",
+};
+
+void error(const char *msg)
+{
+ fputs(msg, stderr);
+}
+
+int guid_is0(const struct guid *guid)
+{
+ return !*(const uint64_t *)guid && !*((const uint64_t *)guid + 1);
+}
+
+void wait_key(void)
+{
+ int cnt;
+ char junk;
+
+ /* drain */
+ do {
+ errno = 0;
+ cnt = read(0, &junk, 1);
+ } while (cnt > 0 || (cnt < 0 && errno == EAGAIN));
+
+ /* wait */
+ do {
+ errno = 0;
+ cnt = read(0, &junk, 1);
+ } while (!cnt || (cnt < 0 && errno == EAGAIN));
+}
+
+void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, uint32_t mode)
+{
+ uint32_t c, h, s, t;
+ uint32_t cs, hs, ss;
+
+ /*
+ * Not much reason here, but if we have no valid CHS geometry, we assume
+ * "typical" ones to have something to return.
+ */
+ if (di->cbios) {
+ cs = di->cyl;
+ hs = di->head;
+ ss = di->spt;
+ if (mode == l2c_cadd && cs < 1024 && di->lbacnt > cs*hs*ss)
+ cs++;
+ else if (mode == l2c_cmax)
+ cs = 1024;
+ } else {
+ if (di->disk & 0x80) {
+ cs = 1024;
+ hs = 255;
+ ss = 63;
+ } else {
+ cs = 80;
+ hs = 2;
+ ss = 18;
+ }
+ }
+
+ if (lba >= cs*hs*ss) {
+ s = ss;
+ h = hs - 1;
+ c = cs - 1;
+ } else {
+ s = ((uint32_t)lba % ss) + 1;
+ t = (uint32_t)lba / ss;
+ h = t % hs;
+ c = t / hs;
+ }
+
+ (*dst)[0] = h;
+ (*dst)[1] = s | ((c & 0x300) >> 2);
+ (*dst)[2] = c;
+}
+
+uint32_t get_file_lba(const char *filename)
+{
+ struct com32_filedata fd;
+ uint32_t lba = 0;
+ int size = 65536;
+ char *buf;
+
+ buf = lmalloc(size);
+ if (!buf)
+ return 0;
+
+ /* Put the filename in the bounce buffer */
+ strlcpy(buf, filename, size);
+
+ if (open_file(buf, &fd) <= 0) {
+ goto fail; /* Filename not found */
+ }
+
+ /* Since the first member is the LBA, we simply cast */
+ lba = *((uint32_t *) MK_PTR(0, fd.handle));
+
+ /* Call comapi_close() to free the structure */
+ close_file(fd.handle);
+
+fail:
+ lfree(buf);
+ return lba;
+}
+
+/* drive offset detection */
+int drvoff_detect(int type, unsigned int *off)
+{
+ if (bpbV40 <= type && type <= bpbVNT) {
+ *off = 0x24;
+ } else if (type == bpbV70) {
+ *off = 0x40;
+ } else
+ return 0;
+
+ return -1;
+}
+
+/*
+ * heuristics could certainly be improved
+ */
+int bpb_detect(const uint8_t *sec, const char *tag)
+{
+ int a, b, c, jmp = -1, rev = 0;
+
+ /* media descriptor check */
+ if ((sec[0x15] & 0xF0) != 0xF0)
+ goto out;
+
+ if (sec[0] == 0xEB) /* jump short */
+ jmp = 2 + *(int8_t *)(sec + 1);
+ else if (sec[0] == 0xE9) /* jump near */
+ jmp = 3 + *(int16_t *)(sec + 1);
+
+ if (jmp < 0) /* no boot code at all ? */
+ goto nocode;
+
+ /* sanity */
+ if (jmp < 0x18 || jmp > 0x1F0)
+ goto out;
+
+ /* detect by jump */
+ if (jmp >= 0x18 && jmp < 0x1E)
+ rev = bpbV20;
+ else if (jmp >= 0x1E && jmp < 0x20)
+ rev = bpbV30;
+ else if (jmp >= 0x20 && jmp < 0x24)
+ rev = bpbV32;
+ else if (jmp >= 0x24 && jmp < 0x46)
+ rev = bpbV34;
+
+ /* TODO: some better V2 - V3.4 checks ? */
+
+ if (rev)
+ goto out;
+ /*
+ * BPB info:
+ * 2.0 == 0x0B - 0x17
+ * 3.0 == 2.0 + 0x18 - 0x1D
+ * 3.2 == 3.0 + 0x1E - 0x1F
+ * 3.4 ==!2.0 + 0x18 - 0x23
+ * 4.0 == 3.4 + 0x24 - 0x45
+ * NT ==~3.4 + 0x24 - 0x53
+ * 7.0 == 3.4 + 0x24 - 0x59
+ */
+
+nocode:
+ a = memcmp(sec + 0x03, "NTFS", 4);
+ b = memcmp(sec + 0x36, "FAT", 3);
+ c = memcmp(sec + 0x52, "FAT", 3); /* ext. DOS 7+ bs */
+
+ if ((sec[0x26] & 0xFE) == 0x28 && !b) {
+ rev = bpbV40;
+ } else if (sec[0x26] == 0x80 && !a) {
+ rev = bpbVNT;
+ } else if ((sec[0x42] & 0xFE) == 0x28 && !c) {
+ rev = bpbV70;
+ }
+
+out:
+ printf("BPB detection (%s): %s\n", tag, bpbtypes[rev]);
+ return rev;
+}
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/utility.h b/com32/chain/utility.h
new file mode 100644
index 00000000..8a08be71
--- /dev/null
+++ b/com32/chain/utility.h
@@ -0,0 +1,30 @@
+#ifndef _COM32_CHAIN_UTILITY_H
+#define _COM32_CHAIN_UTILITY_H
+
+#include <stdint.h>
+#include <syslinux/disk.h>
+
+#define bpbUNK 0
+#define bpbV20 1
+#define bpbV30 2
+#define bpbV32 3
+#define bpbV34 4
+#define bpbV40 5
+#define bpbVNT 6
+#define bpbV70 7
+
+#define l2c_cnul 0
+#define l2c_cadd 1
+#define l2c_cmax 2
+
+void error(const char *msg);
+int guid_is0(const struct guid *guid);
+void wait_key(void);
+void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, uint32_t mode);
+uint32_t get_file_lba(const char *filename);
+int drvoff_detect(int type, unsigned int *off);
+int bpb_detect(const uint8_t *bpb, const char *tag);
+
+#endif
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/cmenu/Makefile b/com32/cmenu/Makefile
index 00825b46..c6e0cae3 100644
--- a/com32/cmenu/Makefile
+++ b/com32/cmenu/Makefile
@@ -17,22 +17,24 @@
NOGPL := 1
-# This must be defined before com32.mk is included
-LIBS = libmenu/libmenu.c32
-
topdir = ../..
MAKEDIR = $(topdir)/mk
include $(MAKEDIR)/elf.mk
CFLAGS += -I./libmenu
+LIBS = libmenu/libmenu.c32 \
+ $(com32)/libutil/libutil_com.c32 \
+ $(com32)/lib/libcom32.c32
+
LIBMENU = libmenu/syslnx.o libmenu/com32io.o libmenu/tui.o \
- libmenu/menu.o libmenu/passwords.o libmenu/des.o libmenu/help.o
+ libmenu/menu.o libmenu/passwords.o libmenu/des.o libmenu/help.o \
+ $(com32)/libutil/libutil_com.c32 $(com32)/lib/libcom32.c32
CMENUS = $(patsubst %.c,%.c32,$(wildcard *.c))
IMENUS = $(patsubst %.menu,%.c32,$(wildcard *.menu))
-MENUS = $(CMENUS) $(IMENUS) $(LIBS)
+MENUS = $(LIBS) $(CMENUS) $(IMENUS)
.SUFFIXES: .S .c .o .elf .c32 .menu
@@ -40,7 +42,7 @@ MENUS = $(CMENUS) $(IMENUS) $(LIBS)
%.c: %.menu adv_menu.tpl
python menugen.py --input=$< --output=$@ --template=adv_menu.tpl
-all: menus
+all: menus
libmenu/libmenu.c32: $(LIBMENU)
$(LD) -shared $(LDFLAGS) -o $@ $^
diff --git a/com32/cmenu/libmenu/syslnx.c b/com32/cmenu/libmenu/syslnx.c
index 53e2401b..c681f585 100644
--- a/com32/cmenu/libmenu/syslnx.c
+++ b/com32/cmenu/libmenu/syslnx.c
@@ -12,7 +12,10 @@
#include <string.h>
#include <com32.h>
+#include <core.h>
+#include <graphics.h>
#include "syslnx.h"
+#include <syslinux/config.h>
com32sys_t inreg, outreg; // Global registers for this module
@@ -28,40 +31,40 @@ char issyslinux(void)
void runsyslinuxcmd(const char *cmd)
{
- strcpy(__com32.cs_bounce, cmd);
- REG_AX(inreg) = 0x0003; // Run command
- REG_BX(inreg) = OFFS(__com32.cs_bounce);
- REG_ES(inreg) = SEG(__com32.cs_bounce);
- __intcall(0x22, &inreg, &outreg);
+ char *bounce;
+
+ bounce = lmalloc(strlen(cmd) + 1);
+ if (!bounce)
+ return;
+
+ strcpy(bounce, cmd);
+ load_kernel(bounce);
}
void gototxtmode(void)
{
- REG_AX(inreg) = 0x0005;
- __intcall(0x22, &inreg, &outreg);
+ syslinux_force_text_mode();
}
void syslinux_idle(void)
{
- REG_AX(inreg) = 0x0013;
- __intcall(0x22, &inreg, &outreg);
+ __idle();
}
unsigned int getversion(char *deriv, unsigned int *numfun)
{
- REG_AX(inreg) = 0x0001;
- __intcall(0x22, &inreg, &outreg);
if (deriv)
- *deriv = REG_DL(outreg);
+ *deriv = __syslinux_version.filesystem;
if (numfun)
- *numfun = REG_AX(outreg);
- return REG_CX(outreg);
+ *numfun = __syslinux_version.max_api;
+ return __syslinux_version.version;
}
void runsyslinuximage(const char *cmd, long ipappend)
{
unsigned int numfun = 0;
char *ptr, *cmdline;
+ char *bounce;
(void)ipappend; // XXX: Unused?!
@@ -71,8 +74,12 @@ void runsyslinuximage(const char *cmd, long ipappend)
runsyslinuxcmd(cmd);
// Try the Run Kernel Image function
// Split command line into
- strcpy(__com32.cs_bounce, cmd);
- ptr = __com32.cs_bounce;
+ bounce = lmalloc(strlen(cmd) + 1);
+ if (!bounce)
+ return;
+
+ strcpy(bounce, cmd);
+ ptr = bounce;
// serach for first space or end of string
while ((*ptr) && (*ptr != ' '))
ptr++;
@@ -87,8 +94,8 @@ void runsyslinuximage(const char *cmd, long ipappend)
// Now call the interrupt
REG_BX(inreg) = OFFS(cmdline);
REG_ES(inreg) = SEG(cmdline);
- REG_SI(inreg) = OFFS(__com32.cs_bounce);
- REG_DS(inreg) = SEG(__com32.cs_bounce);
+ REG_SI(inreg) = OFFS(bounce);
+ REG_DS(inreg) = SEG(bounce);
REG_EDX(inreg) = 0;
__intcall(0x22, &inreg, &outreg); // If successful does not return
diff --git a/com32/elflink/Makefile b/com32/elflink/Makefile
index aca37438..fce1be8c 100644
--- a/com32/elflink/Makefile
+++ b/com32/elflink/Makefile
@@ -19,8 +19,8 @@ test_memalign.elf : test_memalign.o $(LIBS) $(C_LIBS)
$(LD) $(LDFLAGS) -o $@ $^
test_com32.elf: CFLAGS += -DELF_DEBUG
-test_com32.elf: test_com32.o ../libutil/libutil_com.a ../lib/libcom32min.a $(LIBGCC)
- $(LD) -n $(LDFLAGS) -o $@ test_com32.o ../libutil/libutil_com.a $(LIBGCC) --whole-archive ../lib/libcom32min.a -Map test_com32.map
+test_com32.elf: test_com32.o ../lib/libcom32min.a $(LIBGCC)
+ $(LD) -n $(LDFLAGS) -o $@ test_com32.o $(LIBGCC) --whole-archive ../lib/libcom32min.a -Map test_com32.map
tidy dist:
rm -f *.o *.lo *.a *.lst *.elf .*.d *.map
@@ -31,8 +31,6 @@ clean: tidy
spotless: clean
rm -f *~ \#*
-install: all
- mkdir -m 755 -p $(INSTALLROOT)$(AUXDIR)
- install -m 644 $(MODULES) $(INSTALLROOT)$(AUXDIR)
+install:
-include .*.d
diff --git a/com32/elflink/ldlinux/Makefile b/com32/elflink/ldlinux/Makefile
index 5927e500..dc48ca97 100644
--- a/com32/elflink/ldlinux/Makefile
+++ b/com32/elflink/ldlinux/Makefile
@@ -15,13 +15,14 @@ MAKEDIR = $(topdir)/mk
include $(MAKEDIR)/elf.mk
CFLAGS += -I$(topdir)/core/elflink -I$(topdir)/core/include
+LIBS = --whole-archive $(com32)/lib/libcom32min.a
all: ldlinux.c32 ldlinux_lnx.a
ldlinux.c32 : ldlinux.o cli.o readconfig.o refstr.o colors.o getadv.o \
- adv.o ipappend.o execute.o kernel.o get_key.o \
- advwrite.o setadv.o eprintf.o
- $(LD) $(LDFLAGS) -o $@ $^
+ adv.o execute.o chainboot.o kernel.o get_key.o \
+ advwrite.o setadv.o eprintf.o loadhigh.o
+ $(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
LNXLIBOBJS = get_key.lo
ldlinux_lnx.a: $(LNXLIBOBJS)
diff --git a/com32/elflink/ldlinux/adv.c b/com32/elflink/ldlinux/adv.c
index cf02d129..ae473908 100644
--- a/com32/elflink/ldlinux/adv.c
+++ b/com32/elflink/ldlinux/adv.c
@@ -33,8 +33,12 @@
#include <syslinux/adv.h>
#include <syslinux/firmware.h>
+#include <klibc/compiler.h>
-void __syslinux_init(void)
+void *__syslinux_adv_ptr;
+size_t __syslinux_adv_size;
+
+void __constructor __syslinux_init(void)
{
firmware->adv_ops->init();
}
diff --git a/com32/elflink/ldlinux/chainboot.c b/com32/elflink/ldlinux/chainboot.c
new file mode 100644
index 00000000..4a4a2e1a
--- /dev/null
+++ b/com32/elflink/ldlinux/chainboot.c
@@ -0,0 +1,157 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2012 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * chainbooting - replace the current bootloader completely. This
+ * is BIOS-specific.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <dprintf.h>
+
+#include <com32.h>
+#include <sys/exec.h>
+#include <sys/io.h>
+#include "core.h"
+#include "menu.h"
+#include "fs.h"
+#include "config.h"
+#include "localboot.h"
+#include "bios.h"
+
+#include <syslinux/boot.h>
+#include <syslinux/bootrm.h>
+#include <syslinux/movebits.h>
+#include <syslinux/config.h>
+
+void chainboot_file(const char *file, uint32_t type)
+{
+ uint8_t keeppxe = 0;
+ const union syslinux_derivative_info *sdi;
+ struct syslinux_rm_regs regs;
+ struct syslinux_movelist *fraglist = NULL;
+ struct syslinux_memmap *mmap = NULL;
+ struct com32_filedata fd;
+ com32sys_t reg;
+ char *stack;
+ void *buf;
+ int rv, max, size;
+
+ max = 0xA0000; /* Maximum load */
+ buf = malloc(max);
+ if (!buf)
+ goto bail;
+
+ rv = open_file(file, &fd);
+ if (rv == -1) {
+ free(buf);
+ goto bail;
+ }
+
+ reg.eax.l = max;
+ reg.ebx.l = 0;
+ reg.edx.w[0] = 0;
+ reg.edi.l = (uint32_t)buf;
+ reg.ebp.l = -1; /* XXX: limit? */
+ reg.esi.w[0] = rv;
+
+ pm_load_high(&reg);
+
+ size = reg.edi.l - (unsigned long)buf;
+ if (size > 0xA0000 - 0x7C00) {
+ printf("Too large for a boostrap (need LINUX instead of KERNEL?)\n");
+ goto bail;
+ }
+
+ mmap = syslinux_memory_map();
+ if (!mmap)
+ goto bail;
+
+ sdi = syslinux_derivative_info();
+
+ memset(&regs, 0, sizeof(regs));
+ regs.ip = 0x7c00;
+
+ if (sdi->c.filesystem == SYSLINUX_FS_SYSLINUX ||
+ sdi->c.filesystem == SYSLINUX_FS_EXTLINUX) {
+ if (syslinux_add_movelist(&fraglist, 0x800 - 18,
+ (addr_t)sdi->r.esbx, 16))
+ goto bail;
+
+ /* DS:SI points to partition info */
+ regs.esi.l = 0x800 - 18;
+ }
+
+ /*
+ * For a BSS boot sector we have to transfer the
+ * superblock.
+ */
+ if (sdi->c.filesystem == SYSLINUX_FS_SYSLINUX &&
+ type == IMAGE_TYPE_BSS && this_fs->fs_ops->copy_super(buf))
+ goto bail;
+
+ if (sdi->c.filesystem == SYSLINUX_FS_PXELINUX) {
+ keeppxe = 0x03; /* Chainloading + keep PXE */
+ stack = (char *)sdi->r.fssi;
+
+ /*
+ * Set up the registers with their initial values
+ */
+
+ regs.eax.l = *(uint32_t *)&stack[36];
+ regs.ecx.l = *(uint32_t *)&stack[32];
+ regs.edx.l = *(uint32_t *)&stack[28];
+ regs.ebx.l = *(uint32_t *)&stack[24];
+ regs.esp.l = sdi->rr.r.esi.w[0] + 44;
+ regs.ebp.l = *(uint32_t *)&stack[16];
+ regs.esi.l = *(uint32_t *)&stack[12];
+ regs.edi.l = *(uint32_t *)&stack[8];
+ regs.es = *(uint16_t *)&stack[4];
+ regs.ss = sdi->rr.r.fs;
+ regs.ds = *(uint16_t *)&stack[6];
+ regs.fs = *(uint16_t *)&stack[2];
+ regs.gs = *(uint16_t *)&stack[0];
+ } else {
+ const uint16_t *esdi = (const uint16_t *)sdi->disk.esdi_ptr;
+
+ regs.esp.l = (uint16_t)(unsigned long)StackBuf + 44;
+
+ /*
+ * DON'T DO THIS FOR PXELINUX...
+ * For PXE, ES:BX -> PXENV+, and this would
+ * corrupt that use.
+ *
+ * Restore ES:DI -> $PnP (if we were ourselves
+ * called that way...)
+ */
+ regs.edi.w[0] = esdi[0]; /* New DI */
+ regs.es = esdi[2]; /* New ES */
+
+ regs.edx.l = sdi->rr.r.edx.b[0]; /* Drive number -> DL */
+ }
+
+ if (syslinux_add_movelist(&fraglist, 0x7c00, (addr_t)buf, size))
+ goto bail;
+
+ syslinux_shuffle_boot_rm(fraglist, mmap, keeppxe, &regs);
+
+bail:
+ if (fraglist)
+ syslinux_free_movelist(fraglist);
+ if (mmap)
+ syslinux_free_memmap(mmap);
+ if (buf)
+ free(buf);
+ return;
+}
diff --git a/com32/elflink/ldlinux/cli.c b/com32/elflink/ldlinux/cli.c
index 7b2da880..a1cf50cc 100644
--- a/com32/elflink/ldlinux/cli.c
+++ b/com32/elflink/ldlinux/cli.c
@@ -19,8 +19,6 @@
#include "cli.h"
#include "config.h"
-static jmp_buf timeout_jump;
-
static struct list_head cli_history_head;
void clear_screen(void)
@@ -29,71 +27,37 @@ void clear_screen(void)
fputs("\033e\033%@\033)0\033(B\1#0\033[?25l\033[2J", stdout);
}
-static int __get_key(void)
-{
- unsigned char buffer[KEY_MAXLEN];
- int another;
- int nc, rv;
- int code;
-
- nc = 0;
- do {
- buffer[nc++] = getchar();
-
- another = 0;
- rv = get_key_decode(buffer, nc, &code);
- if (!rv)
- return code;
- else if (rv == 1)
- another = 1;
-
- } while (another);
-
- /* We got an unrecognized sequence; return the first character */
- /* We really should remember this and return subsequent characters later */
- return buffer[0];
-}
-
-int mygetkey(clock_t timeout)
+static int mygetkey_timeout(clock_t *kbd_to, clock_t *tto)
{
- clock_t t0, t;
- clock_t tto, to;
+ clock_t t0, t1;
int key;
- //dprintf("enter");
- if (!totaltimeout)
- return __get_key();
-
- for (;;) {
- tto = min(totaltimeout, INT_MAX);
- to = timeout ? min(tto, timeout) : tto;
+ t0 = times(NULL);
+ key = get_key(stdin, *kbd_to ? *kbd_to : *tto);
- t0 = 0;
- key = __get_key();
- t = 0 - t0;
+ /* kbdtimeout only applies to the first character */
+ if (*kbd_to)
+ *kbd_to = 0;
- if (totaltimeout <= t)
- longjmp(timeout_jump, 1);
+ t1 = times(NULL) - t0;
+ if (*tto) {
+ /* Timed out. */
+ if (*tto <= (long long)t1)
+ key = KEY_NONE;
+ else {
+ /* Did it wrap? */
+ if (*tto > totaltimeout)
+ key = KEY_NONE;
- totaltimeout -= t;
-
- if (key != KEY_NONE) {
- //dprintf("get key 0x%x", key);
- return key;
- }
-
- if (timeout) {
- if (timeout <= t) {
- //dprintf("timeout");
- return KEY_NONE;
- }
-
- timeout -= t;
+ *tto -= t1;
}
}
+
+ return key;
}
-static const char * cmd_reverse_search(int *cursor)
+static const char * cmd_reverse_search(int *cursor, clock_t *kbd_to,
+ clock_t *tto)
{
int key;
int i = 0;
@@ -108,7 +72,7 @@ static const char * cmd_reverse_search(int *cursor)
eprintf("\033[1G\033[1;36m(reverse-i-search)`': \033[0m");
while (1) {
- key = mygetkey(0);
+ key = mygetkey_timeout(kbd_to, tto);
if (key == KEY_CTRL('C')) {
return NULL;
@@ -124,7 +88,7 @@ static const char * cmd_reverse_search(int *cursor)
break;
}
- while (last_found != &cli_history_head) {
+ while (!list_is_last(&last_found->list, &cli_history_head)) {
p = strstr(last_found->command, buf);
if (p)
break;
@@ -164,7 +128,9 @@ const char *edit_cmdline(const char *input, int top /*, int width */ ,
bool done = false;
const char *ret;
int width = 0;
- struct cli_command *comm_counter;
+ struct cli_command *comm_counter = NULL;
+ clock_t kbd_to = kbdtimeout;
+ clock_t tto = totaltimeout;
if (!width) {
int height;
@@ -199,7 +165,7 @@ const char *edit_cmdline(const char *input, int top /*, int width */ ,
eprintf("\033[?7l\033[?25l");
if (y)
eprintf("\033[%dA", y);
- eprintf("\033[1G\033[1;36m%s \033[0m", input);
+ eprintf("\033[1G%s ", input);
x = strlen(input);
y = 0;
@@ -230,9 +196,13 @@ const char *edit_cmdline(const char *input, int top /*, int width */ ,
redraw = 0;
}
- key = mygetkey(0);
+ key = mygetkey_timeout(&kbd_to, &tto);
switch (key) {
+ case KEY_NONE:
+ /* We timed out. */
+ return NULL;
+
case KEY_CTRL('L'):
redraw = 2;
break;
@@ -406,7 +376,7 @@ const char *edit_cmdline(const char *input, int top /*, int width */ ,
* Handle this case in another function, since it's
* a kind of special.
*/
- const char *p = cmd_reverse_search(&cursor);
+ const char *p = cmd_reverse_search(&cursor, &kbd_to, &tto);
if (p) {
strcpy(cmdline, p);
len = strlen(cmdline);
@@ -479,17 +449,14 @@ const char *edit_cmdline(const char *input, int top /*, int width */ ,
return len ? ret : NULL;
}
-static int cli_init(void)
+static int __constructor cli_init(void)
{
INIT_LIST_HEAD(&cli_history_head);
return 0;
}
-static void cli_exit(void)
+static void __destructor cli_exit(void)
{
/* Nothing to do */
}
-
-MODULE_INIT(cli_init);
-MODULE_EXIT(cli_exit);
diff --git a/com32/elflink/ldlinux/config.h b/com32/elflink/ldlinux/config.h
index c34b2cc6..45832022 100644
--- a/com32/elflink/ldlinux/config.h
+++ b/com32/elflink/ldlinux/config.h
@@ -35,9 +35,16 @@ extern short nohalt; //idle.inc
extern const char *default_cmd; //"default" command line
extern const char *onerror; //"onerror" command line
+extern const char *ontimeout; //"ontimeout" command line
extern void cat_help_file(int key);
+extern struct menu_entry *find_label(const char *str);
+extern void print_labels(const char *prefix, size_t len);
extern void eprintf(const char *filename, ...);
+extern int new_linux_kernel(char *okernel, char *ocmdline);
+
+extern void pm_load_high(com32sys_t *regs);
+
#endif /* __CONFIG_H__ */
diff --git a/com32/elflink/ldlinux/eprintf.c b/com32/elflink/ldlinux/eprintf.c
index d8858ff9..f15edc6e 100644
--- a/com32/elflink/ldlinux/eprintf.c
+++ b/com32/elflink/ldlinux/eprintf.c
@@ -1,6 +1,7 @@
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
+#include <core.h>
#define BUFFER_SIZE 4096
diff --git a/com32/elflink/ldlinux/execute.c b/com32/elflink/ldlinux/execute.c
index 2b265a11..77d268c8 100644
--- a/com32/elflink/ldlinux/execute.c
+++ b/com32/elflink/ldlinux/execute.c
@@ -17,31 +17,39 @@
#include <com32.h>
#include <sys/exec.h>
+#include <sys/io.h>
#include "core.h"
#include "menu.h"
-
-/* Must match enum kernel_type */
-const char *const kernel_types[] = {
- "none",
- "localboot",
- "kernel",
- "linux",
- "boot",
- "bss",
- "pxe",
- "fdimage",
- "comboot",
- "com32",
- "config",
- NULL
+#include "fs.h"
+#include "config.h"
+#include "localboot.h"
+#include "bios.h"
+
+#include <syslinux/bootrm.h>
+#include <syslinux/movebits.h>
+#include <syslinux/config.h>
+#include <syslinux/boot.h>
+
+const struct image_types image_boot_types[] = {
+ { "localboot", IMAGE_TYPE_LOCALBOOT },
+ { "kernel", IMAGE_TYPE_KERNEL },
+ { "linux", IMAGE_TYPE_LINUX },
+ { "boot", IMAGE_TYPE_BOOT },
+ { "bss", IMAGE_TYPE_BSS },
+ { "pxe", IMAGE_TYPE_PXE },
+ { "fdimage", IMAGE_TYPE_FDIMAGE },
+ { "comboot", IMAGE_TYPE_COMBOOT },
+ { "com32", IMAGE_TYPE_COM32 },
+ { "config", IMAGE_TYPE_CONFIG },
+ { NULL, 0 },
};
extern int create_args_and_load(char *);
-void execute(const char *cmdline, enum kernel_type type)
+void execute(const char *cmdline, uint32_t type)
{
- const char *p, *const *pp;
const char *kernel, *args;
+ const char *p;
com32sys_t ireg;
char *q;
@@ -70,46 +78,44 @@ void execute(const char *cmdline, enum kernel_type type)
dprintf("kernel is %s, args = %s type = %d \n", kernel, args, type);
- if (kernel[0] == '.' && type == KT_NONE) {
+ if (kernel[0] == '.') {
/* It might be a type specifier */
- enum kernel_type type = KT_NONE;
- for (pp = kernel_types; *pp; pp++, type++) {
- if (!strcmp(kernel + 1, *pp))
- execute(p, type); /* Strip the type specifier and retry */
+ const struct image_types *t;
+ for (t = image_boot_types; t->name; t++) {
+ if (!strcmp(kernel + 1, t->name)) {
+ /* Strip the type specifier and retry */
+ execute(p, t->type);
+ return;
+ }
}
}
- if (type == KT_COM32) {
+ if (type == IMAGE_TYPE_COM32) {
/* new entry for elf format c32 */
- lfree(kernel);
- create_args_and_load(cmdline);
- } else if (type == KT_KERNEL) {
- /* Need add one item for kernel load, as we don't use
- * the assembly runkernel.inc any more */
- new_linux_kernel(kernel, cmdline);
- } else if (type == KT_CONFIG) {
+ create_args_and_load((char *)cmdline);
+ } else if (type == IMAGE_TYPE_CONFIG) {
+ char *argv[] = { "ldlinux.c32", NULL };
+
/* kernel contains the config file name */
- char *spawn_load_param[2] = { args, NULL };
- spawn_load(kernel, 1, spawn_load_param);
+ realpath(ConfigName, kernel, FILENAME_MAX);
+
+ /* If we got anything on the command line, do a chdir */
+ if (*args)
+ mangle_name(config_cwd, args);
+
+ start_ldlinux(argv);
+ } else if (type == IMAGE_TYPE_LOCALBOOT) {
+ local_boot(strtoul(kernel, NULL, 0));
+ } else if (type == IMAGE_TYPE_PXE || type == IMAGE_TYPE_BSS ||
+ type == IMAGE_TYPE_BOOT) {
+ chainboot_file(kernel, type);
} else {
- /* process the image need int 22 support */
- if (type == KT_LOCALBOOT) {
- ireg.eax.w[0] = 0x0014; /* Local boot */
- ireg.edx.w[0] = strtoul(kernel, NULL, 0);
- } else {
- ireg.eax.w[0] = 0x0016; /* Run kernel image */
- ireg.esi.w[0] = OFFS(kernel);
- ireg.ds = SEG(kernel);
- ireg.ebx.w[0] = OFFS(args);
- ireg.es = SEG(args);
- ireg.edx.l = type - KT_KERNEL;
- /* ireg.ecx.l = 0; *//* We do ipappend "manually" */
- }
-
- __intcall(0x22, &ireg, NULL);
+ /* Need add one item for kernel load, as we don't use
+ * the assembly runkernel.inc any more */
+ new_linux_kernel((char *)kernel, (char *)cmdline);
}
- lfree(kernel);
+ lfree((void *)kernel);
/* If this returns, something went bad; return to menu */
}
diff --git a/com32/elflink/ldlinux/get_key.c b/com32/elflink/ldlinux/get_key.c
index 42ff5c12..0be06b98 100644
--- a/com32/elflink/ldlinux/get_key.c
+++ b/com32/elflink/ldlinux/get_key.c
@@ -148,10 +148,10 @@ int get_key_decode(char *buffer, int nc, int *code)
int get_key(FILE * f, clock_t timeout)
{
- unsigned char buffer[KEY_MAXLEN];
- int nc, i, rv;
+ char buffer[KEY_MAXLEN];
+ int nc, rv;
int another;
- unsigned char ch;
+ char ch;
clock_t start;
int code;
@@ -167,7 +167,7 @@ int get_key(FILE * f, clock_t timeout)
clock_t lateness = times(NULL) - start;
if (nc && lateness > 1 + KEY_TIMEOUT) {
if (nc == 1)
- return buffer[0]; /* timeout in sequence */
+ return (unsigned char)buffer[0]; /* timeout */
else if (timeout && lateness > timeout)
return KEY_NONE;
} else if (!nc && timeout && lateness > timeout)
@@ -194,5 +194,5 @@ int get_key(FILE * f, clock_t timeout)
/* We got an unrecognized sequence; return the first character */
/* We really should remember this and return subsequent characters later */
- return buffer[0];
+ return (unsigned char)buffer[0];
}
diff --git a/com32/elflink/ldlinux/kernel.c b/com32/elflink/ldlinux/kernel.c
index bdcd3cb1..b8f9cb8d 100644
--- a/com32/elflink/ldlinux/kernel.c
+++ b/com32/elflink/ldlinux/kernel.c
@@ -15,15 +15,14 @@ const char *append = NULL;
/* Will be called from readconfig.c */
int new_linux_kernel(char *okernel, char *ocmdline)
{
- const char *kernel_name;
- struct initramfs *initramfs;
+ const char *kernel_name = NULL;
+ struct initramfs *initramfs = NULL;
char *temp;
void *kernel_data;
size_t kernel_len;
bool opt_quiet = false;
char initrd_name[256];
char cmdline_buf[256], *cmdline;
- int i;
dprintf("okernel = %s, ocmdline = %s", okernel, ocmdline);
@@ -98,36 +97,41 @@ int new_linux_kernel(char *okernel, char *ocmdline)
if (!opt_quiet)
printf("ok\n");
- /* Initialize the initramfs chain */
- initramfs = initramfs_init();
- if (!initramfs)
- goto bail;
-
/* Find and load initramfs */
temp = strstr(cmdline, "initrd=");
if (temp) {
- char *p;
+ /* Initialize the initramfs chain */
+ initramfs = initramfs_init();
+ if (!initramfs)
+ goto bail;
- temp += strlen("initrd=");
+ temp += 6; /* strlen("initrd") */
do {
- p = strchr(temp, ',');
- if (p)
- *p = '\0';
-
- if (initramfs_load_archive(initramfs, temp)) {
- printf("failed!\n");
- goto bail;
- }
-
- if (p)
- *p++ = ',';
- } while ((temp = p));
- }
+ char *p = initrd_name;
+
+ temp++; /* Skip = or , */
- //dprintf("loading initrd done");
+ while (*temp != ' ' && *temp != ',' && *temp)
+ *p++ = *temp++;
+ *p = '\0';
+
+ if (!opt_quiet)
+ printf("Loading %s...", initrd_name);
+
+ if (initramfs_load_archive(initramfs, initrd_name)) {
+ if (opt_quiet)
+ printf("Loading %s ", initrd_name);
+ printf("failed!\n");
+ goto bail;
+ }
+
+ if (!opt_quiet)
+ printf("ok\n");
+ } while (*temp == ',');
+ }
/* This should not return... */
- syslinux_boot_linux(kernel_data, kernel_len, initramfs, cmdline);
+ syslinux_boot_linux(kernel_data, kernel_len, initramfs, NULL, cmdline);
bail:
printf("Kernel load failure (insufficient memory?)\n");
diff --git a/com32/elflink/ldlinux/ldlinux.c b/com32/elflink/ldlinux/ldlinux.c
index 53604179..073f1116 100644
--- a/com32/elflink/ldlinux/ldlinux.c
+++ b/com32/elflink/ldlinux/ldlinux.c
@@ -1,16 +1,135 @@
#include <linux/list.h>
#include <sys/times.h>
+#include <fcntl.h>
#include <stdbool.h>
+#include <string.h>
#include <core.h>
+#include <fs.h>
#include "cli.h"
#include "console.h"
#include "com32.h"
#include "menu.h"
#include "config.h"
#include "syslinux/adv.h"
+#include "syslinux/boot.h"
#include <sys/module.h>
+struct file_ext {
+ const char *name;
+ enum kernel_type type;
+};
+
+static const struct file_ext file_extensions[] = {
+ { ".com", IMAGE_TYPE_COMBOOT },
+ { ".cbt", IMAGE_TYPE_COMBOOT },
+ { ".c32", IMAGE_TYPE_COM32 },
+ { ".img", IMAGE_TYPE_FDIMAGE },
+ { ".bss", IMAGE_TYPE_BSS },
+ { ".bin", IMAGE_TYPE_BOOT },
+ { ".bs", IMAGE_TYPE_BOOT },
+ { ".0", IMAGE_TYPE_PXE },
+ { NULL, 0 },
+};
+
+/*
+ * Return a pointer to one byte after the last character of the
+ * command.
+ */
+static inline const char *find_command(const char *str)
+{
+ const char *p;
+
+ p = str;
+ while (*p && !my_isspace(*p))
+ p++;
+ return p;
+}
+
+uint32_t parse_image_type(const char *kernel)
+{
+ const struct file_ext *ext;
+ const char *p;
+ int len;
+
+ /* Find the end of the command */
+ p = find_command(kernel);
+ len = p - kernel;
+
+ for (ext = file_extensions; ext->name; ext++) {
+ int elen = strlen(ext->name);
+
+ if (!strncmp(kernel + len - elen, ext->name, elen))
+ return ext->type;
+ }
+
+ /* use IMAGE_TYPE_KERNEL as default */
+ return IMAGE_TYPE_KERNEL;
+}
+
+/*
+ * Returns the kernel name with file extension if one wasn't present.
+ */
+static const char *get_extension(const char *kernel)
+{
+ const struct file_ext *ext;
+ const char *p;
+ int len;
+
+ /* Find the end of the command */
+ p = find_command(kernel);
+ len = p - kernel;
+
+ for (ext = file_extensions; ext->name; ext++) {
+ char *str;
+ int elen = strlen(ext->name);
+ int fd;
+
+ str = malloc(len + elen + 1);
+
+ strncpy(str, kernel, len);
+ strncpy(str + len, ext->name, elen);
+ str[len + elen] = '\0';
+
+ fd = searchdir(str);
+ free(str);
+
+ if (fd >= 0)
+ return ext->name;
+ }
+
+ return NULL;
+}
+
+static const char *apply_extension(const char *kernel, const char *ext)
+{
+ const char *p;
+ char *k;
+ int len = strlen(kernel);
+ int elen = strlen(ext);
+
+ k = malloc(len + elen + 1);
+ if (!k)
+ return NULL;
+
+ p = find_command(kernel);
+
+ len = p - kernel;
+
+ /* Copy just the kernel name */
+ memcpy(k, kernel, len);
+
+ /* Append the extension */
+ memcpy(k + len, ext, elen);
+
+ /* Copy the rest of the command line */
+ strcpy(k + len + elen, p);
+
+ k[len + elen + strlen(p)] = '\0';
+
+ return k;
+}
+
/*
* Attempt to load a kernel after deciding what type of image it is.
*
@@ -18,21 +137,21 @@
* the the kernel. If we return the caller should call enter_cmdline()
* so that the user can help us out.
*/
-static void load_kernel(const char *kernel)
+void load_kernel(const char *command_line)
{
struct menu_entry *me;
- enum kernel_type type;
- const char *cmdline, *p;
- int len;
+ const char *cmdline;
+ const char *kernel;
+ uint32_t type;
+
+ kernel = strdup(command_line);
+ if (!kernel)
+ goto bad_kernel;
/* Virtual kernel? */
me = find_label(kernel);
if (me) {
- enum kernel_type type = KT_KERNEL;
-
- /* cmdline contains type specifier */
- if (me->cmdline[0] == '.')
- type = KT_NONE;
+ type = parse_image_type(me->cmdline);
execute(me->cmdline, type);
/* We shouldn't return */
@@ -42,33 +161,37 @@ static void load_kernel(const char *kernel)
if (!allowimplicit)
goto bad_implicit;
- p = kernel;
- /* Find the end of the command */
- while (*p && !my_isspace(*p))
- p++;
+ /* Insert a null character to ignore any user-specified options */
+ if (!allowoptions) {
+ char *p = (char *)find_command(kernel);
+ *p = '\0';
+ }
- len = p - kernel;
- if (!strncmp(kernel + len - 4, ".c32", 4)) {
- type = KT_COM32;
- } else if (!strncmp(kernel + len - 2, ".0", 2)) {
- type = KT_PXE;
- } else if (!strncmp(kernel + len - 3, ".bs", 3)) {
- type = KT_BOOT;
- } else if (!strncmp(kernel + len - 4, ".img", 4)) {
- type = KT_FDIMAGE;
- } else if (!strncmp(kernel + len - 4, ".bin", 4)) {
- type = KT_BOOT;
- } else if (!strncmp(kernel + len - 4, ".bss", 4)) {
- type = KT_BSS;
- } else if (!strncmp(kernel + len - 4, ".com", 4) ||
- !strncmp(kernel + len - 4, ".cbt", 4)) {
- type = KT_COMBOOT;
+ type = parse_image_type(kernel);
+ if (type == IMAGE_TYPE_KERNEL) {
+ const char *ext;
+
+ /*
+ * Automatically lookup the extension if one wasn't
+ * supplied by the user.
+ */
+ ext = get_extension(kernel);
+ if (ext) {
+ const char *k;
+
+ k = apply_extension(kernel, ext);
+ if (!k)
+ goto bad_kernel;
+
+ free((void *)kernel);
+ kernel = k;
+
+ type = parse_image_type(kernel);
+ }
}
- /* use KT_KERNEL as default */
- else
- type = KT_KERNEL;
execute(kernel, type);
+ free((void *)kernel);
bad_implicit:
bad_kernel:
@@ -78,7 +201,7 @@ bad_kernel:
*/
if (onerrorlen) {
rsprintf(&cmdline, "%s %s", onerror, default_cmd);
- execute(cmdline, KT_COM32);
+ execute(cmdline, IMAGE_TYPE_COM32);
}
}
@@ -88,43 +211,41 @@ static void enter_cmdline(void)
/* Enter endless command line prompt, should support "exit" */
while (1) {
- cmdline = edit_cmdline("syslinux$", 1, NULL, cat_help_file);
- if (!cmdline)
- continue;
-
- /* return if user only press enter */
- if (cmdline[0] == '\0') {
- printf("\n");
- continue;
- }
+ cmdline = edit_cmdline("boot:", 1, NULL, cat_help_file);
printf("\n");
+ /* return if user only press enter or we timed out */
+ if (!cmdline || cmdline[0] == '\0')
+ return;
+
load_kernel(cmdline);
}
}
-int main(int argc, char **argv)
+int main(int argc __unused, char **argv __unused)
{
- com32sys_t ireg, oreg;
- uint8_t *adv;
- int count = 0;
+ const void *adv;
+ const char *cmdline;
+ size_t count = 0;
+ char *config_argv[2] = { NULL, NULL };
openconsole(&dev_rawcon_r, &dev_ansiserial_w);
- __syslinux_get_ipappend_strings();
- parse_configs(NULL);
+ if (ConfigName[0])
+ config_argv[0] = ConfigName;
+
+ parse_configs(config_argv);
- __syslinux_init();
adv = syslinux_getadv(ADV_BOOTONCE, &count);
if (adv && count) {
/*
* We apparently have a boot-once set; clear it and
* then execute the boot-once.
*/
- uint8_t *src, *dst, *cmdline;
- int i;
+ char *src, *dst;
+ size_t i;
- src = adv;
+ src = (char *)adv;
cmdline = dst = malloc(count + 1);
if (!dst) {
printf("Failed to allocate memory for ADV\n");
@@ -148,12 +269,14 @@ int main(int argc, char **argv)
if (forceprompt)
goto cmdline;
+ cmdline = default_cmd;
+auto_boot:
/*
* Auto boot
*/
if (defaultlevel || noescape) {
if (defaultlevel) {
- load_kernel(default_cmd); /* Shouldn't return */
+ load_kernel(cmdline); /* Shouldn't return */
} else {
printf("No DEFAULT or UI configuration directive found!\n");
@@ -163,8 +286,12 @@ int main(int argc, char **argv)
}
cmdline:
- /* Should never return */
+ /* Only returns if the user pressed enter or input timed out */
enter_cmdline();
+ cmdline = ontimeoutlen ? ontimeout : default_cmd;
+
+ goto auto_boot;
+
return 0;
}
diff --git a/core/fs/loadhigh.c b/com32/elflink/ldlinux/loadhigh.c
index bd9d3535..0f2f8428 100644
--- a/core/fs/loadhigh.c
+++ b/com32/elflink/ldlinux/loadhigh.c
@@ -37,7 +37,7 @@
#include "core.h"
#include "fs.h"
-#define MAX_CHUNK (1 << 20) /* 1 MB */
+#define MAX_CHUNK (1UL << 20) /* 1 MB */
void pm_load_high(com32sys_t *regs)
{
diff --git a/com32/elflink/ldlinux/readconfig.c b/com32/elflink/ldlinux/readconfig.c
index 564cbeff..1db397a1 100644
--- a/com32/elflink/ldlinux/readconfig.c
+++ b/com32/elflink/ldlinux/readconfig.c
@@ -52,6 +52,22 @@ const struct menu_parameter mparm[NPARAMS] = {
[P_HIDDEN_ROW] = {"hiddenrow", -2},
};
+/* Must match enum kernel_type */
+static const char *const kernel_types[] = {
+ "none",
+ "localboot",
+ "kernel",
+ "linux",
+ "boot",
+ "bss",
+ "pxe",
+ "fdimage",
+ "comboot",
+ "com32",
+ "config",
+ NULL
+};
+
short uappendlen = 0; //bytes in append= command
short ontimeoutlen = 0; //bytes in ontimeout command
short onerrorlen = 0; //bytes in onerror command
@@ -68,6 +84,7 @@ short nohalt = 1; //idle.inc
const char *default_cmd = NULL; //"default" command line
const char *onerror = NULL; //"onerror" command line
+const char *ontimeout = NULL; //"ontimeout" command line
/* Empty refstring */
const char *empty_string;
@@ -79,6 +96,7 @@ struct menu *root_menu, *start_menu, *hide_menu, *menu_list, *default_menu;
int shiftkey = 0; /* Only display menu if shift key pressed */
int hiddenmenu = 0;
long long totaltimeout = 0;
+unsigned int kbdtimeout = 0;
/* Keep track of global default */
static int has_ui = 0; /* DEFAULT only counts if UI is found */
@@ -1081,13 +1099,14 @@ do_include:
//dprintf("got a kernel: %s, type = %d", ld.kernel, ld.type);
}
} else if (looking_at(p, "timeout")) {
- m->timeout = (atoi(skipspace(p + 7)) * CLK_TCK + 9) / 10;
+ kbdtimeout = (atoi(skipspace(p + 7)) * CLK_TCK + 9) / 10;
} else if (looking_at(p, "totaltimeout")) {
totaltimeout = (atoll(skipspace(p + 13)) * CLK_TCK + 9) / 10;
} else if (looking_at(p, "ontimeout")) {
- m->ontimeout = refstrdup(skipspace(p + 9));
+ ontimeout = refstrdup(skipspace(p + 9));
+ ontimeoutlen = strlen(ontimeout);
} else if (looking_at(p, "allowoptions")) {
- m->allowedit = !!atoi(skipspace(p + 12));
+ allowoptions = !!atoi(skipspace(p + 12));
} else if (looking_at(p, "ipappend")) {
if (ld.label)
ld.ipappend = atoi(skipspace(p + 8));
@@ -1121,7 +1140,8 @@ do_include:
* display/font/kbdmap are rather similar, open a file then do sth
*/
else if (looking_at(p, "display")) {
- char *filename, *dst = KernelName;
+ const char *filename;
+ char *dst = KernelName;
size_t len = FILENAME_MAX - 1;
filename = refstrdup(skipspace(p + 7));
@@ -1133,7 +1153,8 @@ do_include:
get_msg_file(KernelName);
refstr_put(filename);
} else if (looking_at(p, "font")) {
- char *filename, *dst = KernelName;
+ const char *filename;
+ char *dst = KernelName;
size_t len = FILENAME_MAX - 1;
filename = refstrdup(skipspace(p + 4));
@@ -1145,8 +1166,8 @@ do_include:
loadfont(KernelName);
refstr_put(filename);
} else if (looking_at(p, "kbdmap")) {
- com32sys_t reg;
- char *filename, *dst = KernelName;
+ const char *filename;
+ char *dst = KernelName;
size_t len = FILENAME_MAX - 1;
filename = refstrdup(skipspace(p + 4));
@@ -1189,7 +1210,6 @@ do_include:
/* serial setting, bps, flow control */
else if (looking_at(p, "serial")) {
- com32sys_t ireg;
uint16_t port, flow;
uint32_t baud;
@@ -1309,18 +1329,20 @@ do_include:
eprintf("%s\n", p+4);
} else if (looking_at(p, "path")) {
/* PATH-based lookup */
- char *new_path, *_p;
+ 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 = realloc(PATH, len + new_len + 2);
+ _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
eprintf("Failed to realloc PATH\n");
@@ -1345,6 +1367,11 @@ static int parse_one_config(const char *filename)
f = fdopen(fd, mode);
parse_config_file(f);
+ if (config_cwd[0]) {
+ chdir(config_cwd);
+ config_cwd[0] = '\0';
+ }
+
return 0;
}
diff --git a/com32/gfxboot/gfxboot.c b/com32/gfxboot/gfxboot.c
index 35d180a6..aa05caf8 100644
--- a/com32/gfxboot/gfxboot.c
+++ b/com32/gfxboot/gfxboot.c
@@ -962,7 +962,7 @@ void boot_entry(menu_t *menu_ptr, char *arg)
gfx_done();
- syslinux_boot_linux(kernel, kernel_size, initrd, arg);
+ syslinux_boot_linux(kernel, kernel_size, initrd, NULL, arg);
}
diff --git a/com32/gpllib/disk/geom.c b/com32/gpllib/disk/geom.c
index 9e673ed4..e1095200 100644
--- a/com32/gpllib/disk/geom.c
+++ b/com32/gpllib/disk/geom.c
@@ -120,7 +120,7 @@ static int detect_extensions(struct driveinfo *drive_info)
static int get_drive_parameters_with_extensions(struct driveinfo *drive_info)
{
com32sys_t inreg, outreg;
- struct edd_device_parameters *dp = __com32.cs_bounce;
+ struct edd_device_parameters *dp;
memset(&inreg, 0, sizeof inreg);
@@ -134,6 +134,10 @@ static int get_drive_parameters_with_extensions(struct driveinfo *drive_info)
* If the buffer length is less than 26 on entry an error shall be
* returned.
*/
+ dp = lmalloc(sizeof *dp);
+ if (!dp)
+ return -1;
+
dp->len = sizeof(struct edd_device_parameters);
inreg.esi.w[0] = OFFS(dp);
@@ -144,10 +148,13 @@ static int get_drive_parameters_with_extensions(struct driveinfo *drive_info)
__intcall(0x13, &inreg, &outreg);
/* CF set on error */
- if (outreg.eflags.l & EFLAGS_CF)
+ if (outreg.eflags.l & EFLAGS_CF) {
+ lfree(dp);
return outreg.eax.b[1];
+ }
memcpy(&drive_info->edd_params, dp, sizeof drive_info->edd_params);
+ lfree(dp);
return 0;
}
diff --git a/com32/gpllib/disk/labels.c b/com32/gpllib/disk/labels.c
index ad3d33b3..f27ff655 100644
--- a/com32/gpllib/disk/labels.c
+++ b/com32/gpllib/disk/labels.c
@@ -36,29 +36,29 @@ void get_label(int label, char **buffer_label)
strlcpy(buffer, "DOS 3.31+ 16-bit FAT (over 32M)", buffer_size);
break;
case 0x07:
- strlcpy(buffer, "OS/2 IFS (e.g., HPFS)", buffer_size);
- break;
+ strlcpy(buffer, "NTFS/exFAT/HPFS", buffer_size);
//case 0x07: strlcpy(buffer, "Advanced Unix", buffer_size); break;
//case 0x07: strlcpy(buffer, "Windows NT NTFS", buffer_size); break;
//case 0x07: strlcpy(buffer, "QNX2.x (pre-1988)", buffer_size); break;
- case 0x08:
- strlcpy(buffer, "OS/2 (v1.0-1.3 only)", buffer_size);
break;
+ case 0x08:
+ strlcpy(buffer, "AIX", buffer_size);
//case 0x08: strlcpy(buffer, "AIX boot partition", buffer_size); break;
//case 0x08: strlcpy(buffer, "SplitDrive", buffer_size); break;
//case 0x08: strlcpy(buffer, "DELL partition spanning multiple drives", buffer_size); break;
//case 0x08: strlcpy(buffer, "Commodore DOS", buffer_size); break;
//case 0x08: strlcpy(buffer, "QNX 1.x and 2.x ("qny")", buffer_size); break;
- case 0x09:
- strlcpy(buffer, "AIX data partition", buffer_size);
break;
+ case 0x09:
+ strlcpy(buffer, "AIX bootable partition", buffer_size);
//case 0x09: strlcpy(buffer, "Coherent filesystem", buffer_size); break;
//case 0x09: strlcpy(buffer, "QNX 1.x and 2.x ("qnz")", buffer_size); break;
+ break;
case 0x0a:
strlcpy(buffer, "OS/2 Boot Manager", buffer_size);
- break;
//case 0x0a: strlcpy(buffer, "Coherent swap partition", buffer_size); break;
//case 0x0a: strlcpy(buffer, "OPUS", buffer_size); break;
+ break;
case 0x0b:
strlcpy(buffer, "WIN95 OSR2 32-bit FAT", buffer_size);
break;
@@ -72,13 +72,13 @@ void get_label(int label, char **buffer_label)
strlcpy(buffer, "WIN95: Extended partition, LBA-mapped", buffer_size);
break;
case 0x10:
- strlcpy(buffer, "OPUS (?)", buffer_size);
+ strlcpy(buffer, "OPUS", buffer_size);
break;
case 0x11:
strlcpy(buffer, "Hidden DOS 12-bit FAT", buffer_size);
break;
case 0x12:
- strlcpy(buffer, "Compaq config partition", buffer_size);
+ strlcpy(buffer, "Compaq diagnostic partition", buffer_size);
break;
case 0x14:
strlcpy(buffer, "Hidden DOS 16-bit FAT <32M", buffer_size);
@@ -87,7 +87,7 @@ void get_label(int label, char **buffer_label)
strlcpy(buffer, "Hidden DOS 16-bit FAT >=32M", buffer_size);
break;
case 0x17:
- strlcpy(buffer, "Hidden IFS (e.g., HPFS)", buffer_size);
+ strlcpy(buffer, "Hidden HPFS/exFAT/NTFS", buffer_size);
break;
case 0x18:
strlcpy(buffer, "AST SmartSleep Partition", buffer_size);
@@ -111,8 +111,8 @@ void get_label(int label, char **buffer_label)
break;
case 0x21:
strlcpy(buffer, "Reserved", buffer_size);
- break;
//case 0x21: strlcpy(buffer, "Unused", buffer_size); break;
+ break;
case 0x22:
strlcpy(buffer, "Unused", buffer_size);
break;
@@ -125,6 +125,18 @@ void get_label(int label, char **buffer_label)
case 0x26:
strlcpy(buffer, "Reserved", buffer_size);
break;
+ case 0x27:
+ strlcpy(buffer, "PQService (Acer laptop hidden rescue partition)", buffer_size);
+ //Windows RE hidden partition
+ //MirOS BSD partition
+ //RouterBOOT kernel partition
+ break;
+ case 0x2a:
+ strlcpy(buffer, "AtheOS File System (AFS)", buffer_size);
+ break;
+ case 0x2b:
+ strlcpy(buffer, "SyllableSecure (SylStor)", buffer_size);
+ break;
case 0x31:
strlcpy(buffer, "Reserved", buffer_size);
break;
@@ -148,8 +160,8 @@ void get_label(int label, char **buffer_label)
break;
case 0x39:
strlcpy(buffer, "Plan 9 partition", buffer_size);
- break;
//case 0x39: strlcpy(buffer, "THEOS ver 4 spanned partition", buffer_size); break;
+ break;
case 0x3a:
strlcpy(buffer, "THEOS ver 4 4gb partition", buffer_size);
break;
@@ -166,15 +178,15 @@ void get_label(int label, char **buffer_label)
strlcpy(buffer, "Venix 80286", buffer_size);
break;
case 0x41:
- strlcpy(buffer, "Linux/MINIX (sharing disk with DRDOS)", buffer_size);
- break;
+ strlcpy(buffer, "PPC PReP Boot", buffer_size); break;
//case 0x41: strlcpy(buffer, "Personal RISC Boot", buffer_size); break;
- //case 0x41: strlcpy(buffer, "PPC PReP (Power PC Reference Platform) Boot", buffer_size); break;
- case 0x42:
- strlcpy(buffer, "Linux swap (sharing disk with DRDOS)", buffer_size);
+ // strlcpy(buffer, "Linux/MINIX (sharing disk with DRDOS)", buffer_size);
break;
- //case 0x42: strlcpy(buffer, "SFS (Secure Filesystem)", buffer_size); break;
+ case 0x42:
+ strlcpy(buffer, "SFS (Secure Filesystem)", buffer_size); break;
+ // strlcpy(buffer, "Linux swap (sharing disk with DRDOS)", buffer_size);
//case 0x42: strlcpy(buffer, "Windows 2000 marker", buffer_size); break;
+ break;
case 0x43:
strlcpy(buffer, "Linux native (sharing disk with DRDOS)", buffer_size);
break;
@@ -183,9 +195,9 @@ void get_label(int label, char **buffer_label)
break;
case 0x45:
strlcpy(buffer, "Boot-US boot manager", buffer_size);
- break;
//case 0x45: strlcpy(buffer, "Priam", buffer_size); break;
//case 0x45: strlcpy(buffer, "EUMEL/Elan", buffer_size); break;
+ break;
case 0x46:
strlcpy(buffer, "EUMEL/Elan", buffer_size);
break;
@@ -197,8 +209,8 @@ void get_label(int label, char **buffer_label)
break;
case 0x4a:
strlcpy(buffer, "AdaOS Aquila (Default)", buffer_size);
- break;
//case 0x4a: strlcpy(buffer, "ALFS/THIN lightweight filesystem for DOS", buffer_size); break;
+ break;
case 0x4c:
strlcpy(buffer, "Oberon partition", buffer_size);
break;
@@ -210,22 +222,22 @@ void get_label(int label, char **buffer_label)
break;
case 0x4f:
strlcpy(buffer, "QNX4.x 3rd part", buffer_size);
- break;
//case 0x4f: strlcpy(buffer, "Oberon partition", buffer_size); break;
+ break;
case 0x50:
strlcpy(buffer, "OnTrack Disk Manager (older versions) RO",
buffer_size);
- break;
//case 0x50: strlcpy(buffer, "Lynx RTOS", buffer_size); break;
//case 0x50: strlcpy(buffer, "Native Oberon (alt)", buffer_size); break;
+ break;
case 0x51:
strlcpy(buffer, "OnTrack Disk Manager RW (DM6 Aux1)", buffer_size);
- break;
//case 0x51: strlcpy(buffer, "Novell", buffer_size); break;
+ break;
case 0x52:
strlcpy(buffer, "CP/M", buffer_size);
- break;
//case 0x52: strlcpy(buffer, "Microport SysV/AT", buffer_size); break;
+ break;
case 0x53:
strlcpy(buffer, "Disk Manager 6.0 Aux3", buffer_size);
break;
@@ -237,12 +249,12 @@ void get_label(int label, char **buffer_label)
break;
case 0x56:
strlcpy(buffer, "Golden Bow VFeature Partitioned Volume.", buffer_size);
- break;
//case 0x56: strlcpy(buffer, "DM converted to EZ-BIOS", buffer_size); break;
+ break;
case 0x57:
strlcpy(buffer, "DrivePro", buffer_size);
- break;
//case 0x57: strlcpy(buffer, "VNDI Partition", buffer_size); break;
+ break;
case 0x5c:
strlcpy(buffer, "Priam EDisk", buffer_size);
break;
@@ -255,9 +267,9 @@ void get_label(int label, char **buffer_label)
buffer_size);
break;
case 0x64:
- strlcpy(buffer, "PC-ARMOUR protected partition", buffer_size);
+ strlcpy(buffer, "Novell Netware 286, 2.xx", buffer_size); break;
+ //strlcpy(buffer, "PC-ARMOUR protected partition", buffer_size);
break;
- //case 0x64: strlcpy(buffer, "Novell Netware 286, 2.xx", buffer_size); break;
case 0x65:
strlcpy(buffer, "Novell Netware 386, 3.xx or 4.xx", buffer_size);
break;
@@ -280,13 +292,15 @@ void get_label(int label, char **buffer_label)
case 0x71:
strlcpy(buffer, "Reserved", buffer_size);
break;
+ case 0x72:
+ strlcpy(buffer, "V7/x86", buffer_size);
+ break;
case 0x73:
strlcpy(buffer, "Reserved", buffer_size);
break;
case 0x74:
- strlcpy(buffer, "Reserved", buffer_size);
- break;
- //case 0x74: strlcpy(buffer, "Scramdisk partition", buffer_size); break;
+ //strlcpy(buffer, "Reserved", buffer_size);
+ strlcpy(buffer, "Scramdisk partition", buffer_size); break;
case 0x75:
strlcpy(buffer, "IBM PC/IX", buffer_size);
break;
@@ -301,37 +315,40 @@ void get_label(int label, char **buffer_label)
strlcpy(buffer, "XOSL FS", buffer_size);
break;
case 0x7E:
- strlcpy(buffer, " ", buffer_size);
+ strlcpy(buffer, "Unused", buffer_size);
break;
case 0x80:
strlcpy(buffer, "MINIX until 1.4a", buffer_size);
break;
case 0x81:
strlcpy(buffer, "MINIX since 1.4b, early Linux", buffer_size);
- break;
//case 0x81: strlcpy(buffer, "Mitac disk manager", buffer_size); break;
- //case 0x82: strlcpy(buffer, "Prime", buffer_size); break;
- //case 0x82: strlcpy(buffer, "Solaris x86", buffer_size); break;
+ break;
case 0x82:
strlcpy(buffer, "Linux swap", buffer_size);
+ //case 0x82: strlcpy(buffer, "Prime", buffer_size); break;
+ //case 0x82: strlcpy(buffer, "Solaris x86", buffer_size); break;
break;
case 0x83:
strlcpy(buffer, "Linux native (usually ext2fs)", buffer_size);
break;
case 0x84:
strlcpy(buffer, "OS/2 hidden C: drive", buffer_size);
- break;
//case 0x84: strlcpy(buffer, "Hibernation partition", buffer_size); break;
+ break;
case 0x85:
strlcpy(buffer, "Linux extended partition", buffer_size);
break;
- //case 0x86: strlcpy(buffer, "Old Linux RAID partition superblock", buffer_size); break;
case 0x86:
strlcpy(buffer, "NTFS volume set", buffer_size);
+ //case 0x86: strlcpy(buffer, "Old Linux RAID partition superblock", buffer_size); break;
break;
case 0x87:
strlcpy(buffer, "NTFS volume set", buffer_size);
break;
+ case 0x88:
+ strlcpy(buffer, "Linux Plaintext", buffer_size);
+ break;
case 0x8a:
strlcpy(buffer, "Linux Kernel Partition (used by AiR-BOOT)",
buffer_size);
@@ -349,7 +366,7 @@ void get_label(int label, char **buffer_label)
buffer_size);
break;
case 0x8e:
- strlcpy(buffer, "Linux Logical Volume Manager partition", buffer_size);
+ strlcpy(buffer, "Linux LVM partition", buffer_size);
break;
case 0x90:
strlcpy(buffer, "Free FDISK hidden Primary DOS FAT16 partitition",
@@ -365,14 +382,17 @@ void get_label(int label, char **buffer_label)
break;
case 0x93:
strlcpy(buffer, "Hidden Linux native partition", buffer_size);
- break;
//case 0x93: strlcpy(buffer, "Amoeba", buffer_size); break;
+ break;
case 0x94:
strlcpy(buffer, "Amoeba bad block table", buffer_size);
break;
case 0x95:
strlcpy(buffer, "MIT EXOPC native partitions", buffer_size);
break;
+ case 0x96:
+ strlcpy(buffer, "CHRP ISO-9660 filesystem", buffer_size);
+ break;
case 0x97:
strlcpy(buffer, "Free FDISK hidden Primary DOS FAT32 partitition",
buffer_size);
@@ -392,6 +412,9 @@ void get_label(int label, char **buffer_label)
strlcpy(buffer, "Free FDISK hidden DOS extended partitition (LBA)",
buffer_size);
break;
+ case 0x9e:
+ strlcpy(buffer, "ForthOS partition", buffer_size);
+ break;
case 0x9f:
strlcpy(buffer, "BSD/OS", buffer_size);
break;
@@ -400,13 +423,13 @@ void get_label(int label, char **buffer_label)
break;
case 0xa1:
strlcpy(buffer, "Laptop hibernation partition", buffer_size);
- break;
//case 0xa1: strlcpy(buffer, "HP Volume Expansion (SpeedStor variant)", buffer_size); break;
+ break;
case 0xa3:
- strlcpy(buffer, "Reserved", buffer_size);
+ strlcpy(buffer, "HP Volume Expansion (SpeedStor variant)", buffer_size);
break;
case 0xa4:
- strlcpy(buffer, "Reserved", buffer_size);
+ strlcpy(buffer, "HP Volume Expansion (SpeedStor variant)", buffer_size);
break;
case 0xa5:
strlcpy(buffer, "BSD/386, 386BSD, NetBSD, FreeBSD", buffer_size);
@@ -415,7 +438,7 @@ void get_label(int label, char **buffer_label)
strlcpy(buffer, "OpenBSD", buffer_size);
break;
case 0xa7:
- strlcpy(buffer, "NEXTSTEP", buffer_size);
+ strlcpy(buffer, "NeXTSTEP", buffer_size);
break;
case 0xa8:
strlcpy(buffer, "Mac OS-X", buffer_size);
@@ -429,8 +452,8 @@ void get_label(int label, char **buffer_label)
break;
case 0xab:
strlcpy(buffer, "Mac OS-X Boot partition", buffer_size);
- break;
//case 0xab: strlcpy(buffer, "GO! partition", buffer_size); break;
+ break;
case 0xae:
strlcpy(buffer, "ShagOS filesystem", buffer_size);
break;
@@ -441,16 +464,19 @@ void get_label(int label, char **buffer_label)
strlcpy(buffer, "BootStar Dummy", buffer_size);
break;
case 0xb1:
- strlcpy(buffer, "Reserved", buffer_size);
+ strlcpy(buffer, "HP Volume Expansion (SpeedStor variant)", buffer_size);
+ break;
+ case 0xb2:
+ strlcpy(buffer, "QNX Neutrino Power-Safe filesystem", buffer_size);
break;
case 0xb3:
- strlcpy(buffer, "Reserved", buffer_size);
+ strlcpy(buffer, "HP Volume Expansion (SpeedStor variant)", buffer_size);
break;
case 0xb4:
- strlcpy(buffer, "Reserved", buffer_size);
+ strlcpy(buffer, "HP Volume Expansion (SpeedStor variant)", buffer_size);
break;
case 0xb6:
- strlcpy(buffer, "Reserved", buffer_size);
+ strlcpy(buffer, "HP Volume Expansion (SpeedStor variant)", buffer_size);
break;
case 0xb7:
strlcpy(buffer, "BSDI BSD/386 filesystem", buffer_size);
@@ -461,21 +487,27 @@ void get_label(int label, char **buffer_label)
case 0xbb:
strlcpy(buffer, "Boot Wizard hidden", buffer_size);
break;
+ case 0xbc:
+ strlcpy(buffer, "Acronis backup partition", buffer_size);
+ break;
case 0xbe:
strlcpy(buffer, "Solaris 8 boot partition", buffer_size);
break;
+ case 0xbf:
+ strlcpy(buffer, "Solaris partition", buffer_size);
+ break;
case 0xc0:
strlcpy(buffer, "CTOS", buffer_size);
- break;
//case 0xc0: strlcpy(buffer, "REAL/32 secure small partition", buffer_size); break;
//case 0xc0: strlcpy(buffer, "NTFT Partition", buffer_size); break;
+ break;
case 0xc1:
strlcpy(buffer, "DRDOS/secured (FAT-12)", buffer_size);
break;
case 0xc2:
- strlcpy(buffer, "Reserved for DR-DOS 7+", buffer_size);
+ strlcpy(buffer, "Hidden Linux", buffer_size); break;
+ //strlcpy(buffer, "Reserved for DR-DOS 7+", buffer_size);
break;
- //case 0xc2: strlcpy(buffer, "Hidden Linux", buffer_size); break;
case 0xc3:
strlcpy(buffer, "Hidden Linux swap", buffer_size);
break;
@@ -487,21 +519,21 @@ void get_label(int label, char **buffer_label)
break;
case 0xc6:
strlcpy(buffer, "DRDOS/secured (FAT-16, >= 32M)", buffer_size);
- break;
//case 0xc6: strlcpy(buffer, "Windows NT corrupted FAT16 volume/stripe set", buffer_size); break;
+ break;
case 0xc7:
strlcpy(buffer, "Windows NT corrupted NTFS volume/stripe set",
buffer_size);
- break;
//case 0xc7: strlcpy(buffer, "Syrinx boot", buffer_size); break;
+ break;
case 0xc8:
- strlcpy(buffer, "(See also ID c2.)", buffer_size);
+ strlcpy(buffer, "Reserved for DR-DOS 8.0+", buffer_size);
break;
case 0xc9:
- strlcpy(buffer, "(See also ID c2.)", buffer_size);
+ strlcpy(buffer, "Reserved for DR-DOS 8.0+", buffer_size);
break;
case 0xca:
- strlcpy(buffer, "(See also ID c2.)", buffer_size);
+ strlcpy(buffer, "Reserved for DR-DOS 8.0+", buffer_size);
break;
case 0xcb:
strlcpy(buffer, "reserved for DRDOS/secured (FAT32)", buffer_size);
@@ -515,6 +547,9 @@ void get_label(int label, char **buffer_label)
case 0xce:
strlcpy(buffer, "reserved for DRDOS/secured (FAT16, LBA)", buffer_size);
break;
+ case 0xcf:
+ strlcpy(buffer, "DR-DOS 7.04+ secured EXT DOS (LBA)", buffer_size);
+ break;
case 0xd0:
strlcpy(buffer, "REAL/32 secure big partition", buffer_size);
break;
@@ -541,9 +576,9 @@ void get_label(int label, char **buffer_label)
strlcpy(buffer,
"Digital Research CP/M, Concurrent CP/M, Concurrent DOS",
buffer_size);
- break;
//case 0xdb: strlcpy(buffer, "CTOS (Convergent Technologies OS -Unisys)", buffer_size); break;
//case 0xdb: strlcpy(buffer, "KDG Telemetry SCPU boot", buffer_size); break;
+ break;
case 0xdd:
strlcpy(buffer, "Hidden CTOS Memdump?", buffer_size);
break;
@@ -575,24 +610,30 @@ void get_label(int label, char **buffer_label)
strlcpy(buffer,
"Tandy DOS with logical sectored FAT (According to Powerquest.)",
buffer_size);
- break;
//case 0xe5: strlcpy(buffer, "Reserved", buffer_size); break;
+ break;
case 0xe6:
- strlcpy(buffer, "Reserved", buffer_size);
+ strlcpy(buffer, "Storage Dimensions SpeedStor", buffer_size);
+ break;
+ case 0xe8:
+ strlcpy(buffer, "LUKS", buffer_size);
break;
case 0xeb:
- strlcpy(buffer, "BFS (aka BeFS)", buffer_size);
+ strlcpy(buffer, "BeOS", buffer_size);
+ break;
+ case 0xec:
+ strlcpy(buffer, "SkyOS SkyFS", buffer_size);
break;
case 0xed:
strlcpy(buffer, "Reserved for Matthias Paul's Sprytix", buffer_size);
break;
case 0xee:
strlcpy(buffer,
- "Indication that this legacy MBR is followed by an EFI header",
+ "GPT",
buffer_size);
break;
case 0xef:
- strlcpy(buffer, "Partition that contains an EFI file system",
+ strlcpy(buffer, "EFI file system",
buffer_size);
break;
case 0xf0:
@@ -613,8 +654,8 @@ void get_label(int label, char **buffer_label)
break;
case 0xf4:
strlcpy(buffer, "SpeedStor large partition", buffer_size);
- break;
//case 0xf4: strlcpy(buffer, "Prologue single-volume partition", buffer_size); break;
+ break;
case 0xf5:
strlcpy(buffer, "Prologue multi-volume partition", buffer_size);
break;
@@ -623,6 +664,12 @@ void get_label(int label, char **buffer_label)
"Reserved (Powerquest writes: Storage Dimensions SpeedStor. )",
buffer_size);
break;
+ case 0xf7:
+ strlcpy(buffer, "DDRdrive Solid State File System", buffer_size);
+ break;
+ case 0xf9:
+ strlcpy(buffer, "pCache", buffer_size);
+ break;
case 0xfa:
strlcpy(buffer, "Bochs", buffer_size);
break;
@@ -638,12 +685,12 @@ void get_label(int label, char **buffer_label)
buffer_size);
break;
case 0xfe:
- strlcpy(buffer, "SpeedStor > 1024 cyl.", buffer_size);
- break;
- //case 0xfe: strlcpy(buffer, "LANstep", buffer_size); break;
+ strlcpy(buffer, "LANstep", buffer_size); break;
+ //strlcpy(buffer, "SpeedStor > 1024 cyl.", buffer_size);
//case 0xfe: strlcpy(buffer, "IBM PS/2 IML (Initial Microcode Load) partition, located at the end of the disk.", buffer_size); break;
//case 0xfe: strlcpy(buffer, "Windows NT Disk Administrator hidden partition", buffer_size); break;
//case 0xfe: strlcpy(buffer, "Linux Logical Volume Manager partition (old)", buffer_size); break;
+ break;
case 0xff:
strlcpy(buffer, "Xenix Bad Block Table ", buffer_size);
break;
diff --git a/com32/gpllib/disk/read.c b/com32/gpllib/disk/read.c
index 7a6cc430..541957f9 100644
--- a/com32/gpllib/disk/read.c
+++ b/com32/gpllib/disk/read.c
@@ -76,13 +76,22 @@ int read_sectors(struct driveinfo *drive_info, void *data,
const unsigned int lba, const int sectors)
{
com32sys_t inreg, outreg;
- struct ebios_dapa *dapa = __com32.cs_bounce;
- void *buf = (char *)__com32.cs_bounce + sectors * SECTOR;
+ struct ebios_dapa *dapa;
+ void *buf;
char *bufp = data;
+ int rv = -1;
if (get_drive_parameters(drive_info) == -1)
return -1;
+ buf = lmalloc(sectors * SECTOR);
+ if (!buf)
+ return -1;
+
+ dapa = lmalloc(sizeof(*dapa));
+ if (!dapa)
+ goto fail;
+
memset(&inreg, 0, sizeof inreg);
if (drive_info->ebios) {
@@ -102,7 +111,7 @@ int read_sectors(struct driveinfo *drive_info, void *data,
if (!drive_info->cbios) { // XXX errno
/* We failed to get the geometry */
if (lba)
- return -1; /* Can only read MBR */
+ goto fail; /* Can only read MBR */
s = 1;
h = 0;
@@ -112,7 +121,7 @@ int read_sectors(struct driveinfo *drive_info, void *data,
// XXX errno
if (s > 63 || h > 256 || c > 1023)
- return -1;
+ goto fail;
inreg.eax.w[0] = 0x0201; /* Read one sector */
inreg.ecx.b[1] = c & 0xff;
@@ -126,10 +135,14 @@ int read_sectors(struct driveinfo *drive_info, void *data,
/* Perform the read */
if (int13_retry(&inreg, &outreg)) {
errno_disk = outreg.eax.b[1];
- return -1; /* Give up */
+ goto fail; /* Give up */
}
memcpy(bufp, buf, sectors * SECTOR);
+ rv = sectors;
- return sectors;
+fail:
+ lfree(dapa);
+ lfree(buf);
+ return rv;
}
diff --git a/com32/gpllib/disk/write.c b/com32/gpllib/disk/write.c
index 89e530d9..d183adef 100644
--- a/com32/gpllib/disk/write.c
+++ b/com32/gpllib/disk/write.c
@@ -36,8 +36,17 @@ int write_sectors(const struct driveinfo *drive_info, const unsigned int lba,
const void *data, const int size)
{
com32sys_t inreg, outreg;
- struct ebios_dapa *dapa = __com32.cs_bounce;
- void *buf = (char *)__com32.cs_bounce + size;
+ struct ebios_dapa *dapa;
+ void *buf;
+ int rv = -1;
+
+ buf = lmalloc(size);
+ if (!buf)
+ return -1;
+
+ dapa = lmalloc(sizeof(*dapa));
+ if (!dapa)
+ goto out;
memcpy(buf, data, size);
memset(&inreg, 0, sizeof inreg);
@@ -59,7 +68,7 @@ int write_sectors(const struct driveinfo *drive_info, const unsigned int lba,
if (!drive_info->cbios) { // XXX errno
/* We failed to get the geometry */
if (lba)
- return -1; /* Can only write MBR */
+ goto out; /* Can only write MBR */
s = 1;
h = 0;
@@ -69,7 +78,7 @@ int write_sectors(const struct driveinfo *drive_info, const unsigned int lba,
// XXX errno
if (s > 63 || h > 256 || c > 1023)
- return -1;
+ goto out;
inreg.eax.w[0] = 0x0301; /* Write one sector */
inreg.ecx.b[1] = c & 0xff;
@@ -82,10 +91,13 @@ int write_sectors(const struct driveinfo *drive_info, const unsigned int lba,
/* Perform the write */
if (int13_retry(&inreg, &outreg)) {
- errno_disk = outreg.eax.b[1];
- return -1; /* Give up */
+ errno_disk = outreg.eax.b[1]; /* Give up */
} else
- return size;
+ rv = size;
+out:
+ lfree(dapa);
+ lfree(buf);
+ return rv;
}
/**
diff --git a/com32/gpllib/memory.c b/com32/gpllib/memory.c
index 28a95ff4..06c746da 100644
--- a/com32/gpllib/memory.c
+++ b/com32/gpllib/memory.c
@@ -87,15 +87,20 @@ void detect_memory_e820(struct e820entry *desc, int size_map, int *size_found)
{
int count = 0;
static struct e820_ext_entry buf; /* static so it is zeroed */
+ void *bounce;
com32sys_t ireg, oreg;
memset(&ireg, 0, sizeof ireg);
+ bounce = lmalloc(sizeof buf);
+ if (!bounce)
+ goto out;
+
ireg.eax.w[0] = 0xe820;
ireg.edx.l = SMAP;
ireg.ecx.l = sizeof(struct e820_ext_entry);
- ireg.edi.w[0] = OFFS(__com32.cs_bounce);
- ireg.es = SEG(__com32.cs_bounce);
+ ireg.edi.w[0] = OFFS(bounce);
+ ireg.es = SEG(bounce);
/*
* Set this here so that if the BIOS doesn't change this field
@@ -105,7 +110,7 @@ void detect_memory_e820(struct e820entry *desc, int size_map, int *size_found)
buf.ext_flags = 1;
do {
- memcpy(__com32.cs_bounce, &buf, sizeof buf);
+ memcpy(bounce, &buf, sizeof buf);
/* Important: %edx and %esi are clobbered by some BIOSes,
so they must be either used for the error output
@@ -126,7 +131,7 @@ void detect_memory_e820(struct e820entry *desc, int size_map, int *size_found)
if (oreg.eflags.l & EFLAGS_CF || oreg.ecx.l < 20)
break;
- memcpy(&buf, __com32.cs_bounce, sizeof buf);
+ memcpy(&buf, bounce, sizeof buf);
/*
* ACPI 3.0 added the extended flags support. If bit 0
@@ -143,6 +148,8 @@ void detect_memory_e820(struct e820entry *desc, int size_map, int *size_found)
ireg.ebx.l = oreg.ebx.l;
} while (ireg.ebx.l && count < size_map);
+out:
+ lfree(bounce);
*size_found = count;
}
diff --git a/com32/hdt/.gitignore b/com32/hdt/.gitignore
index 98927943..82d5b472 100644
--- a/com32/hdt/.gitignore
+++ b/com32/hdt/.gitignore
@@ -5,3 +5,4 @@ floppy/syslinux.cfg
*.iso
iso/
*gz
+hdt*checksums
diff --git a/com32/hdt/Makefile b/com32/hdt/Makefile
index 934ad25f..ff0fa2e2 100644
--- a/com32/hdt/Makefile
+++ b/com32/hdt/Makefile
@@ -20,6 +20,9 @@ MAKEDIR = $(topdir)/mk
include $(MAKEDIR)/elf.mk
LIBS = ../libupload/libcom32upload.a
+C_LIBS += $(com32)/cmenu/libmenu/libmenu.c32 \
+ $(com32)/libutil/libutil_com.c32 \
+ $(com32)/lib/libcom32.c32 $(com32)/gpllib/libcom32gpl.c32
CFLAGS += -I$(com32)/cmenu/libmenu -I$(com32)
MODULES = hdt.c32
@@ -45,7 +48,7 @@ FLOPPY_DIR ?= floppy
PCI_IDS_FILE ?= $(PWD)/$(FLOPPY_DIR)/pci.ids
GZ_PCI_IDS_FILE ?= $(PCI_IDS_FILE).gz
MENU_COM32 ?= $(com32)/menu/menu.c32
-CHAIN_COM32 ?= $(com32)/modules/chain.c32
+CHAIN_COM32 ?= $(com32)/chain/chain.c32
ART_DIR ?= art/
QEMU ?= qemu-kvm
@@ -110,10 +113,16 @@ hdt.iso: hdt.c32 $(topdir)/core/isolinux.bin $(FLOPPY_DIR)/hdt.cfg memtest
mv hdt.iso hdt-$(VERSION).iso
ln -sf hdt-$(VERSION).iso hdt.iso
-release: spotless hdt.c32 hdt.img hdt.img.gz hdt.iso
+hdt-hybrid.iso: hdt.iso ../../utils/isohybrid
+ cp hdt-$(VERSION).iso hdt-hybrid-$(VERSION).iso
+ ../../utils/isohybrid --partok hdt-hybrid-$(VERSION).iso
+ ln -sf hdt-hybrid-$(VERSION).iso hdt-hybrid.iso
+
+release: spotless hdt.c32 hdt.img hdt.img.gz hdt.iso hdt-hybrid.iso
mv hdt.c32 hdt_$(NODASH_VERSION).c32
md5sum hdt_$(NODASH_VERSION).c32 >$(SUM_FILE)
md5sum hdt-$(VERSION).iso >>$(SUM_FILE)
+ md5sum hdt-hybrid-$(VERSION).iso >>$(SUM_FILE)
md5sum hdt-$(VERSION).img >>$(SUM_FILE)
md5sum hdt-$(VERSION).img.gz >>$(SUM_FILE)
diff --git a/com32/hdt/floppy/hdt.cfg b/com32/hdt/floppy/hdt.cfg
index c876d239..e5f3b0a0 100644
--- a/com32/hdt/floppy/hdt.cfg
+++ b/com32/hdt/floppy/hdt.cfg
@@ -86,6 +86,15 @@ ENDTEXT
COM32 hdt.c32
APPEND modules_pcimap=modules.pcimap modules_alias=modules.alias pciids=pci.ids quiet vesa nomenu auto='dump'
+LABEL postexec
+MENU LABEL Dump memory info, sleep 5 and start memtest entry
+TEXT HELP
+ Starts HDT using the Command Line Interface (CLI), show an item, say a message reboot and start memtest
+ VESA mode is enabled
+ENDTEXT
+COM32 hdt.c32
+APPEND modules_pcimap=modules.pcimap modules_alias=modules.alias pciids=pci.ids quiet vesa nomenu auto='show memory;say `########`;say `Starting memtest in 5 sec`%5;exit' postexec='memtest'
+
MENU SEPARATOR
LABEL memtest
diff --git a/com32/hdt/hdt-cli-acpi.c b/com32/hdt/hdt-cli-acpi.c
index a978bb36..55b0c3c7 100644
--- a/com32/hdt/hdt-cli-acpi.c
+++ b/com32/hdt/hdt-cli-acpi.c
@@ -267,10 +267,12 @@ struct cli_callback_descr list_acpi_show_modules[] = {
{
.name = "apic",
.exec = show_acpi_apic,
+ .nomodule = false,
},
{
.name = NULL,
.exec = NULL,
+ .nomodule = false,
},
};
diff --git a/com32/hdt/hdt-cli-disk.c b/com32/hdt/hdt-cli-disk.c
index 24fce676..10c95d7d 100644
--- a/com32/hdt/hdt-cli-disk.c
+++ b/com32/hdt/hdt-cli-disk.c
@@ -225,14 +225,17 @@ struct cli_callback_descr list_disk_show_modules[] = {
{
.name = "disks",
.exec = main_show_disks,
+ .nomodule = false,
},
{
.name = "disk",
.exec = main_show_disk,
+ .nomodule = false,
},
{
.name = NULL,
.exec = NULL,
+ .nomodule = false,
},
};
diff --git a/com32/hdt/hdt-cli-dmi.c b/com32/hdt/hdt-cli-dmi.c
index 45cbb240..02bea0f7 100644
--- a/com32/hdt/hdt-cli-dmi.c
+++ b/com32/hdt/hdt-cli-dmi.c
@@ -617,62 +617,77 @@ struct cli_callback_descr list_dmi_show_modules[] = {
{
.name = CLI_DMI_BASE_BOARD,
.exec = show_dmi_base_board,
+ .nomodule = false,
},
{
.name = CLI_DMI_BIOS,
.exec = show_dmi_bios,
+ .nomodule = false,
},
{
.name = CLI_DMI_BATTERY,
.exec = show_dmi_battery,
+ .nomodule = false,
},
{
.name = CLI_DMI_CHASSIS,
.exec = show_dmi_chassis,
+ .nomodule = false,
},
{
.name = CLI_DMI_MEMORY,
.exec = show_dmi_memory_modules,
+ .nomodule = false,
},
{
.name = CLI_DMI_MEMORY_BANK,
.exec = show_dmi_memory_bank,
+ .nomodule = false,
},
{
.name = "module",
.exec = show_dmi_memory_module,
+ .nomodule = false,
},
{
.name = CLI_DMI_PROCESSOR,
.exec = show_dmi_cpu,
+ .nomodule = false,
},
{
.name = CLI_DMI_SYSTEM,
.exec = show_dmi_system,
+ .nomodule = false,
},
{
.name = CLI_DMI_OEM,
.exec = show_dmi_oem_strings,
+ .nomodule = false,
},
{
.name = CLI_DMI_SECURITY,
.exec = show_dmi_hardware_security,
+ .nomodule = false,
},
{
.name = CLI_DMI_IPMI,
.exec = show_dmi_ipmi,
+ .nomodule = false,
},
{
.name = CLI_DMI_CACHE,
.exec = show_dmi_cache,
+ .nomodule = false,
},
{
.name = CLI_DMI_LIST,
.exec = show_dmi_modules,
+ .nomodule = false,
},
{
.name = NULL,
.exec = NULL,
+ .nomodule = false,
},
};
diff --git a/com32/hdt/hdt-cli-hdt.c b/com32/hdt/hdt-cli-hdt.c
index e9752612..f7f7e949 100644
--- a/com32/hdt/hdt-cli-hdt.c
+++ b/com32/hdt/hdt-cli-hdt.c
@@ -259,101 +259,184 @@ static void do_dump(int argc __unused, char **argv __unused,
dump(hardware);
}
+/**
+ * do_say - say message to user
+ **/
+static void do_say(int argc , char **argv ,
+ struct s_hardware *hardware)
+{
+ (void) hardware;
+ if (argc == 0) return;
+
+ char text_to_say[255]={0};
+ int arg=0;
+ int sleep_time=0;
+#if DEBUG
+ for (int i=0; i<argc;i++) dprintf("SAY: arg[%d]={%s}\n",i,argv[i]);
+#endif
+ char *argument = strchr(argv[arg],'`');
+ if ( argument != NULL) {
+ argument++;
+ strcat(text_to_say, argument);
+
+ while ((strchr(argument, '`') == NULL) && (arg+1<argc)) {
+ arg++;
+ argument = (char *)argv[arg];
+ strcat(text_to_say, " ");
+ strcat(text_to_say, argument);
+ }
+
+ /* Removing last ` if any */
+ char *last_quote = strrchr(text_to_say,'`');
+ if ( last_quote != NULL ) {
+ *last_quote='\0';
+ dprintf("SAY CMD = [%s]\n",text_to_say);
+ }
+
+ /* The % char can be in the same argument, let's consider it again */
+ arg--;
+
+ /* Searching for a % argument to determine the time to show the message */
+ char *time_to_display = NULL;
+ /* Search for a requested time to display */
+ while ( ((time_to_display=strchr(argument, '%')) == NULL) && (arg+1<argc)) {
+ arg++;
+ argument = (char *)argv[arg];
+ }
+
+ if (time_to_display != NULL) {
+ sleep_time=atoi(time_to_display+1);
+ dprintf("SAY CMD :Time to display = %d\n",sleep_time);
+ }
+
+ printf("%s\n",text_to_say);
+ sleep(sleep_time);
+ }
+}
+
/* Default hdt mode */
struct cli_callback_descr list_hdt_default_modules[] = {
{
.name = CLI_CLEAR,
.exec = cli_clear_screen,
+ .nomodule = false,
},
{
.name = CLI_EXIT,
.exec = do_exit,
+ .nomodule = false,
},
{
.name = CLI_HELP,
.exec = show_cli_help,
+ .nomodule = false,
},
{
.name = CLI_MENU,
.exec = goto_menu,
+ .nomodule = false,
},
{
.name = CLI_REBOOT,
.exec = do_reboot,
+ .nomodule = false,
},
{
.name = CLI_HISTORY,
.exec = print_history,
+ .nomodule = false,
},
{
.name = CLI_DUMP,
.exec = do_dump,
+ .nomodule = false,
+ },
+ {
+ .name = CLI_SAY,
+ .exec = do_say,
+ .nomodule = true,
},
{
.name = NULL,
- .exec = NULL},
+ .exec = NULL,
+ .nomodule = false},
};
struct cli_callback_descr list_hdt_show_modules[] = {
{
.name = CLI_SUMMARY,
.exec = main_show_summary,
+ .nomodule = false,
},
{
.name = CLI_PCI,
.exec = main_show_pci,
+ .nomodule = false,
},
{
.name = CLI_DMI,
.exec = main_show_dmi,
+ .nomodule = false,
},
{
.name = CLI_CPU,
.exec = main_show_cpu,
+ .nomodule = false,
},
{
.name = CLI_DISK,
.exec = disks_summary,
+ .nomodule = false,
},
{
.name = CLI_PXE,
.exec = main_show_pxe,
+ .nomodule = false,
},
{
.name = CLI_SYSLINUX,
.exec = main_show_syslinux,
+ .nomodule = false,
},
{
.name = CLI_KERNEL,
.exec = main_show_kernel,
+ .nomodule = false,
},
{
.name = CLI_VESA,
.exec = main_show_vesa,
+ .nomodule = false,
},
{
.name = CLI_HDT,
.exec = main_show_hdt,
+ .nomodule = false,
},
{
.name = CLI_VPD,
.exec = main_show_vpd,
+ .nomodule = false,
},
{
.name = CLI_MEMORY,
.exec = show_dmi_memory_modules,
+ .nomodule = false,
},
{
.name = CLI_ACPI,
.exec = main_show_acpi,
+ .nomodule = false,
},
{
.name = "modes",
.exec = main_show_modes,
+ .nomodule = false,
},
{
.name = NULL,
.exec = NULL,
+ .nomodule = false,
},
};
@@ -361,10 +444,12 @@ struct cli_callback_descr list_hdt_set_modules[] = {
{
.name = CLI_MODE,
.exec = cli_set_mode,
+ .nomodule = false,
},
{
.name = NULL,
.exec = NULL,
+ .nomodule = false,
},
};
diff --git a/com32/hdt/hdt-cli-memory.c b/com32/hdt/hdt-cli-memory.c
index 51d087e8..c05b7cd6 100644
--- a/com32/hdt/hdt-cli-memory.c
+++ b/com32/hdt/hdt-cli-memory.c
@@ -101,22 +101,27 @@ struct cli_callback_descr list_memory_show_modules[] = {
{
.name = "e820",
.exec = show_memory_e820,
+ .nomodule=false,
},
{
.name = "e801",
.exec = show_memory_e801,
+ .nomodule=false,
},
{
.name = "88",
.exec = show_memory_88,
+ .nomodule=false,
},
{
.name = CLI_DMI_MEMORY_BANK,
.exec = show_dmi_memory_bank,
+ .nomodule=false,
},
{
.name = NULL,
.exec = NULL,
+ .nomodule=false,
},
};
diff --git a/com32/hdt/hdt-cli-pci.c b/com32/hdt/hdt-cli-pci.c
index 07c079d5..75fc0011 100644
--- a/com32/hdt/hdt-cli-pci.c
+++ b/com32/hdt/hdt-cli-pci.c
@@ -266,14 +266,17 @@ struct cli_callback_descr list_pci_show_modules[] = {
{
.name = CLI_IRQ,
.exec = show_pci_irq,
+ .nomodule=false,
},
{
.name = CLI_PCI_DEVICE,
.exec = show_pci_device,
+ .nomodule=false,
},
{
.name = NULL,
.exec = NULL,
+ .nomodule=false,
},
};
diff --git a/com32/hdt/hdt-cli-vesa.c b/com32/hdt/hdt-cli-vesa.c
index 702f8bd6..ca44987a 100644
--- a/com32/hdt/hdt-cli-vesa.c
+++ b/com32/hdt/hdt-cli-vesa.c
@@ -98,10 +98,12 @@ struct cli_callback_descr list_vesa_show_modules[] = {
{
.name = CLI_MODES,
.exec = show_vesa_modes,
+ .nomodule=false,
},
{
.name = NULL,
.exec = NULL,
+ .nomodule=false,
},
};
@@ -109,15 +111,18 @@ struct cli_callback_descr list_vesa_commands[] = {
{
.name = CLI_ENABLE,
.exec = enable_vesa,
+ .nomodule=false,
},
{
.name = CLI_DISABLE,
.exec = disable_vesa,
+ .nomodule=false,
},
{
.name = NULL,
.exec = NULL,
+ .nomodule=false,
},
};
diff --git a/com32/hdt/hdt-cli.c b/com32/hdt/hdt-cli.c
index 330f93c4..11984e5a 100644
--- a/com32/hdt/hdt-cli.c
+++ b/com32/hdt/hdt-cli.c
@@ -365,14 +365,14 @@ static void parse_command_line(char *line, char **command, char **module,
*command = malloc((token_len + 1) * sizeof(char));
strlcpy(*command, pch, token_len);
(*command)[token_len] = '\0';
- dprintf("CLI DEBUG: command = %s\n", *command);
+ dprintf("CLI DEBUG parse: command = %s\n", *command);
args_pos += args_len;
} else if (token_found == 1) {
/* Module */
*module = malloc((token_len + 1) * sizeof(char));
strlcpy(*module, pch, token_len);
(*module)[token_len] = '\0';
- dprintf("CLI DEBUG: module = %s\n", *module);
+ dprintf("CLI DEBUG parse: module = %s\n", *module);
args_pos += args_len;
} else
(*argc)++;
@@ -380,7 +380,7 @@ static void parse_command_line(char *line, char **command, char **module,
token_found++;
pch = pch_next;
}
- dprintf("CLI DEBUG: argc = %d\n", *argc);
+ dprintf("CLI DEBUG parse: argc = %d\n", *argc);
/* Skip arguments handling if none is supplied */
if (!*argc)
@@ -390,9 +390,9 @@ static void parse_command_line(char *line, char **command, char **module,
*argv = malloc(*argc * sizeof(char *));
pch = strtok(line + args_pos, CLI_SPACE);
while (pch != NULL) {
- dprintf("CLI DEBUG: argv[%d] = %s\n", argc_iter, pch);
- argv[argc_iter] = malloc(sizeof(pch) * sizeof(char));
- strlcpy(argv[argc_iter], pch, sizeof(pch));
+ dprintf("CLI DEBUG parse: argv[%d] = %s\n", argc_iter, pch);
+ argv[argc_iter] = malloc(strlen(pch) * sizeof(char));
+ strlcpy(argv[argc_iter], pch, strlen(pch));
argc_iter++;
pch = strtok(NULL, CLI_SPACE);
/*
@@ -585,6 +585,7 @@ static void autocomplete(char *line)
parse_command_line(line, &command, &module, &argc, argv);
+ dprintf("CLI DEBUG autocomplete: before checking args\n");
/* If the user specified arguments, there is nothing we can complete */
if (argc != 0)
goto out;
@@ -625,22 +626,43 @@ static void exec_command(char *line, struct s_hardware *hardware)
/* This will allocate memory for command and module */
parse_command_line(line, &command, &module, &argc, argv);
+ dprintf("CLI DEBUG exec: Checking for aliases\n");
/*
* Expand shortcuts, if needed
* This will allocate memory for argc/argv
*/
expand_aliases(line, &command, &module, &argc, argv);
+
+ find_cli_callback_descr(command, current_mode->default_modules,
+ &current_module);
- if (module == NULL) {
- dprintf("CLI DEBUG: single command detected\n");
+ if ((module == NULL) || (current_module->nomodule == true)) {
+ dprintf("CLI DEBUG exec : single command detected\n");
/*
* A single word was specified: look at the list of default
* commands in the current mode to see if there is a match.
* If not, it may be a generic function (exit, help, ...). These
* are stored in the list of default commands of the hdt mode.
*/
- find_cli_callback_descr(command, current_mode->default_modules,
- &current_module);
+
+ /* First of all it the command doesn't need module, let's rework the arguments */
+ if ((current_module->nomodule == true) && ( module != NULL)) {
+ dprintf("CLI_DEBUG exec: Reworking arguments with argc=%d\n",argc);
+ char **new_argv=NULL;
+ new_argv=malloc((argc + 2)*sizeof(char));
+ for (int argc_iter=0; argc_iter<argc; argc_iter++) {
+ dprintf("CLI_DEBUG exec rework : copy %d to %d (%s)\n",argc_iter,argc_iter+1,argv[argc_iter]);
+ new_argv[argc_iter+1] = malloc(strlen(argv[argc_iter]));
+ strlcpy(new_argv[argc_iter+1], argv[argc_iter], strlen(argv[argc_iter]));
+ free(argv[argc_iter]);
+ }
+ new_argv[0] = malloc(strlen(module)*sizeof(char));
+ strlcpy(new_argv[0], module, strlen(module));
+ argc++;
+ free(argv);
+ argv=new_argv;
+ }
+
if (current_module != NULL)
current_module->exec(argc, argv, hardware);
else if (!strncmp(command, CLI_SHOW, sizeof(CLI_SHOW) - 1) &&
@@ -673,7 +695,7 @@ static void exec_command(char *line, struct s_hardware *hardware)
* hdt> set mode dmi
*/
if (!strncmp(command, CLI_SHOW, sizeof(CLI_SHOW) - 1)) {
- dprintf("CLI DEBUG: %s command detected\n", CLI_SHOW);
+ dprintf("CLI DEBUG exec: %s command detected\n", CLI_SHOW);
/* Look first for a 'show' callback in the current mode */
find_cli_callback_descr(module, current_mode->show_modules,
&current_module);
@@ -681,6 +703,7 @@ static void exec_command(char *line, struct s_hardware *hardware)
if (current_module != NULL)
current_module->exec(argc, argv, hardware);
else {
+ dprintf("CLI DEBUG exec: Looking for callback\n");
/* Look now for a 'show' callback in the hdt mode */
find_cli_callback_descr(module, hdt_mode.show_modules,
&current_module);
@@ -691,7 +714,7 @@ static void exec_command(char *line, struct s_hardware *hardware)
printf("unknown module: '%s'\n", module);
}
} else if (!strncmp(command, CLI_SET, sizeof(CLI_SET) - 1)) {
- dprintf("CLI DEBUG: %s command detected\n", CLI_SET);
+ dprintf("CLI DEBUG exec : %s command detected\n", CLI_SET);
/* Look now for a 'set' callback in the hdt mode */
find_cli_callback_descr(module, current_mode->set_modules,
&current_module);
diff --git a/com32/hdt/hdt-cli.h b/com32/hdt/hdt-cli.h
index 68b33158..30fe5187 100644
--- a/com32/hdt/hdt-cli.h
+++ b/com32/hdt/hdt-cli.h
@@ -66,6 +66,7 @@
#define CLI_ENABLE "enable"
#define CLI_DISABLE "disable"
#define CLI_DUMP "dump"
+#define CLI_SAY "say"
typedef enum {
INVALID_MODE,
@@ -120,6 +121,7 @@ struct cli_module_descr {
struct cli_callback_descr {
const char *name;
void (*exec) (int argc, char **argv, struct s_hardware * hardware);
+ bool nomodule;
};
/* Manage aliases */
diff --git a/com32/hdt/hdt-common.c b/com32/hdt/hdt-common.c
index aac50eb9..f729a107 100644
--- a/com32/hdt/hdt-common.c
+++ b/com32/hdt/hdt-common.c
@@ -106,12 +106,36 @@ void detect_parameters(const int argc, const char *argv[],
max_console_lines = MAX_CLI_LINES;
} else if (!strncmp(argv[i], "nomenu", 6)) {
menumode = false;
+ } else if (!strncmp(argv[i], "dump_filename=", 14)) {
+ strlcpy(hardware->dump_filename, argv[i] + 14,
+ sizeof(hardware->dump_filename));
} else if (!strncmp(argv[i], "dump_path=", 10)) {
strlcpy(hardware->dump_path, argv[i] + 10,
sizeof(hardware->dump_path));
} else if (!strncmp(argv[i], "tftp_ip=", 8)) {
strlcpy(hardware->tftp_ip, argv[i] + 8,
sizeof(hardware->tftp_ip));
+ } else if (!strncmp(argv[i], "postexec=", 9)) {
+ /* The postexec= parameter is separated in several argv[]
+ * as it can contains spaces.
+ * We use the AUTO_DELIMITER char to define the limits
+ * of this parameter.
+ * i.e postexec='linux memtest.bin'
+ */
+
+ char *argument = (char*)argv[i]+10;
+ /* Extracting the first parameter */
+ strcpy(hardware->postexec, argument);
+
+ /* While we can't find the other AUTO_DELIMITER, let's process the argv[] */
+ while ((strchr(argument, AUTO_DELIMITER) == NULL) && (i+1<argc)) {
+ i++;
+ argument = (char *)argv[i];
+ strcat(hardware->postexec, " ");
+ strcat(hardware->postexec, argument);
+ }
+
+ hardware->postexec[strlen(hardware->postexec) - 1] = 0;
} else if (!strncmp(argv[i], "auto=", 5)) {
/* The auto= parameter is separated in several argv[]
* as it can contains spaces.
@@ -204,9 +228,12 @@ void init_hardware(struct s_hardware *hardware)
memset(hardware->memtest_label, 0, sizeof hardware->memtest_label);
memset(hardware->auto_label, 0, sizeof hardware->auto_label);
memset(hardware->dump_path, 0, sizeof hardware->dump_path);
+ memset(hardware->dump_filename, 0, sizeof hardware->dump_filename);
memset(hardware->vesa_background, 0, sizeof hardware->vesa_background);
memset(hardware->tftp_ip, 0, sizeof hardware->tftp_ip);
+ memset(hardware->postexec, 0, sizeof hardware->postexec);
strcat(hardware->dump_path, "hdt");
+ strcat(hardware->dump_filename, "%{m}+%{p}+%{v}");
strcat(hardware->pciids_path, "pci.ids");
strcat(hardware->modules_pcimap_path, "modules.pcimap");
strcat(hardware->modules_alias_path, "modules.alias");
@@ -285,6 +312,7 @@ int detect_vesa(struct s_hardware *hardware)
struct vesa_mode_info *mi;
uint16_t mode, *mode_ptr;
char *oem_ptr;
+ int rv = -1;
if (hardware->vesa_detection == true)
return -1;
@@ -292,9 +320,13 @@ int detect_vesa(struct s_hardware *hardware)
hardware->vesa_detection = true;
hardware->is_vesa_valid = false;
- /* Allocate space in the bounce buffer for these structures */
- gi = &((struct vesa_info *)__com32.cs_bounce)->gi;
- mi = &((struct vesa_info *)__com32.cs_bounce)->mi;
+ gi = lmalloc(sizeof(*gi));
+ if (!gi)
+ return -1;
+
+ mi = lmalloc(sizeof(*mi));
+ if (!mi)
+ goto out;
gi->signature = VBE2_MAGIC; /* Get VBE2 extended data */
rm.eax.w[0] = 0x4F00; /* Get SVGA general information */
@@ -303,7 +335,7 @@ int detect_vesa(struct s_hardware *hardware)
__intcall(0x10, &rm, &rm);
if (rm.eax.w[0] != 0x004F) {
- return -1;
+ goto out;
};
mode_ptr = GET_PTR(gi->video_mode_ptr);
@@ -342,7 +374,12 @@ int detect_vesa(struct s_hardware *hardware)
hardware->vesa.vmi_count++;
}
hardware->is_vesa_valid = true;
- return 0;
+
+ rv = 0;
+out:
+ lfree(mi);
+ lfree(gi);
+ return rv;
}
/* Try to detect disks from port 0x80 to 0xff */
diff --git a/com32/hdt/hdt-common.h b/com32/hdt/hdt-common.h
index d37fcc8a..4a288b44 100644
--- a/com32/hdt/hdt-common.h
+++ b/com32/hdt/hdt-common.h
@@ -54,9 +54,6 @@
#include <acpi/acpi.h>
#include <libupload/upload_backend.h>
-/* Declare a variable or data structure as unused. */
-#define __unused __attribute__ (( unused ))
-
/* This two values are used for switching for the menu to the CLI mode */
#define HDT_SWITCH_TO_CLI "hdt_switch_to_cli"
#define HDT_DUMP "hdt_dump"
@@ -214,10 +211,12 @@ struct s_hardware {
char modules_alias_path[255];
char pciids_path[255];
char dump_path[255]; /* Dump path on the tftp server */
+ char dump_filename[255]; /* Dump filename on the tftp server */
char tftp_ip[255]; /* IP address of tftp server (dump mode) */
char memtest_label[255];
char auto_label[AUTO_COMMAND_SIZE];
char vesa_background[255];
+ char postexec[255];
};
void reset_more_printf(void);
diff --git a/com32/hdt/hdt-dump-disks.c b/com32/hdt/hdt-dump-disks.c
index dcbcaa9e..ff744b30 100644
--- a/com32/hdt/hdt-dump-disks.c
+++ b/com32/hdt/hdt-dump-disks.c
@@ -42,6 +42,7 @@ static void show_partition_information(struct driveinfo *drive_info,
char ostype[64]={0};
char *parttype;
unsigned int start, end;
+ char bootable[6] = {0};
int i = nb_partitions_seen;
start = partition_offset;
@@ -52,6 +53,10 @@ static void show_partition_information(struct driveinfo *drive_info,
get_label(ptab->ostype, &parttype);
get_bootloader_string(drive_info, ptab, bootloader_name, 9);
+ if (ptab->active_flag == 0x80)
+ snprintf(bootable,sizeof(bootable),"%s","true");
+ else
+ snprintf(bootable,sizeof(bootable),"%s","false");
snprintf(ostype,sizeof(ostype),"%02X",ptab->ostype);
@@ -62,6 +67,7 @@ static void show_partition_information(struct driveinfo *drive_info,
add_as("partition->size",size)
add_as("partition->type",parttype)
add_as("partition->os_type",ostype)
+ add_as("partition->boot_flag",bootable)
END_OF_APPEND;
free(parttype);
}
@@ -117,7 +123,9 @@ void show_disk(struct s_hardware *hardware, ZZJSON_CONFIG *conf, ZZJSON **it, in
void dump_disks(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
bool found=false;
- for (int drive = 0x80; drive < 0xff; drive++) {
+
+ if (hardware->disks_count > 0)
+ for (int drive = 0x80; drive < 0xff; drive++) {
if (hardware->disk_info[drive - 0x80].cbios) {
if (found==false) {
CREATE_NEW_OBJECT;
@@ -131,7 +139,7 @@ void dump_disks(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **ite
if (found==false) {
CREATE_NEW_OBJECT;
add_b("disks->is_valid",false);
- FLUSH_OBJECT;
}
+ FLUSH_OBJECT;
to_cpio("disks");
}
diff --git a/com32/hdt/hdt-dump.c b/com32/hdt/hdt-dump.c
index 8c221405..b963e19b 100644
--- a/com32/hdt/hdt-dump.c
+++ b/com32/hdt/hdt-dump.c
@@ -37,56 +37,117 @@
struct print_buf p_buf;
-void compute_filename(struct s_hardware *hardware, char *filename, int size) {
-
- snprintf(filename,size,"%s/",hardware->dump_path);
-
- if (hardware->is_pxe_valid) {
- strncat(filename, hardware->pxe.mac_addr, sizeof(hardware->pxe.mac_addr));
- strncat(filename, "+", 1);
- }
-
- if (hardware->is_dmi_valid) {
- strncat(filename, remove_spaces(hardware->dmi.system.product_name), sizeof(hardware->dmi.system.manufacturer));
- strncat(filename, "+", 1);
- strncat(filename, remove_spaces(hardware->dmi.system.manufacturer), sizeof(hardware->dmi.system.product_name));
+struct dump_option {
+ char *flag;
+ char *item;
+};
+
+char *get_value_from_option(struct s_hardware *hardware, char *option)
+{
+ struct dump_option dump_options[10];
+ dump_options[0].flag = "%{m}";
+ dump_options[0].item = hardware->pxe.mac_addr;
+
+ dump_options[1].flag = "%{v}";
+ dump_options[1].item = hardware->dmi.system.manufacturer;
+
+ dump_options[2].flag = "%{p}";
+ dump_options[2].item = hardware->dmi.system.product_name;
+
+ dump_options[3].flag = "%{ba}";
+ dump_options[3].item = hardware->dmi.base_board.asset_tag;
+
+ dump_options[4].flag = "%{bs}";
+ dump_options[4].item = hardware->dmi.base_board.serial;
+
+ dump_options[5].flag = "%{ca}";
+ dump_options[5].item = hardware->dmi.chassis.asset_tag;
+
+ dump_options[6].flag = "%{cs}";
+ dump_options[6].item = hardware->dmi.chassis.serial;
+
+ dump_options[7].flag = "%{sk}";
+ dump_options[7].item = hardware->dmi.system.sku_number;
+
+ dump_options[8].flag = "%{ss}";
+ dump_options[8].item = hardware->dmi.system.serial;
+
+ dump_options[9].flag = NULL;
+ dump_options[9].item = NULL;
+
+ for (int i = 0; i < 9; i++) {
+ if (strcmp(option, dump_options[i].flag) == 0) {
+ return remove_spaces(dump_options[i].item);
+ }
+ }
+
+ return NULL;
+}
+
+char *compute_filename(struct s_hardware *hardware)
+{
+
+ char *filename = malloc(512);
+ snprintf(filename, 512, "%s/%s", hardware->dump_path,
+ hardware->dump_filename);
+
+ /* Until we found some dump parameters */
+ char *buffer;
+ while ((buffer = strstr(filename, "%{"))) {
+ // Find the end of the parameter
+ char *buffer_end = strstr(buffer, "}");
+
+ // Extracting the parameter between %{ and }
+ char option[8] = { 0 };
+ strncpy(option, buffer, buffer_end - buffer + 1);
+
+ /* Replace this option by its value in the filename
+ * Filename is longer than the previous filename we had
+ * so let's restart from the beginning */
+ filename =
+ strreplace(filename, option,
+ get_value_from_option(hardware, option));
}
/* We replace the ":" in the filename by some "-"
* This will avoid Microsoft FS turning crazy */
- chrreplace(filename,':','-');
+ chrreplace(filename, ':', '-');
/* Avoid space to make filename easier to manipulate */
- chrreplace(filename,' ','_');
+ chrreplace(filename, ' ', '_');
+ return filename;
}
-int dumpprintf(FILE *p, const char *format, ...) {
- va_list ap;
- int rv;
-
- (void) p;
- va_start(ap, format);
- rv = vbufprintf(&p_buf,format, ap);
- va_end(ap);
- return rv;
+int dumpprintf(FILE * p, const char *format, ...)
+{
+ va_list ap;
+ int rv;
+
+ (void)p;
+ va_start(ap, format);
+ rv = vbufprintf(&p_buf, format, ap);
+ va_end(ap);
+ return rv;
}
-void to_cpio(char *filename) {
- cpio_writefile(upload,filename,p_buf.buf,p_buf.len);
- if ((p_buf.buf) && (p_buf.len > 0)){
- memset(p_buf.buf,0,p_buf.len);
- free(p_buf.buf);
- p_buf.buf=NULL;
- p_buf.size=0;
- p_buf.len=0;
- }
+void to_cpio(char *filename)
+{
+ cpio_writefile(upload, filename, p_buf.buf, p_buf.len);
+ if ((p_buf.buf) && (p_buf.len > 0)) {
+ memset(p_buf.buf, 0, p_buf.len);
+ free(p_buf.buf);
+ p_buf.buf = NULL;
+ p_buf.size = 0;
+ p_buf.len = 0;
+ }
}
-void flush (ZZJSON_CONFIG *config, ZZJSON ** item) {
- zzjson_print(config, *item);
- zzjson_free(config, *item);
- *item=NULL;
+void flush(ZZJSON_CONFIG * config, ZZJSON ** item)
+{
+ zzjson_print(config, *item);
+ zzjson_free(config, *item);
+ *item = NULL;
}
/**
@@ -94,53 +155,52 @@ void flush (ZZJSON_CONFIG *config, ZZJSON ** item) {
**/
void dump(struct s_hardware *hardware)
{
- if (hardware->is_pxe_valid==false) {
- printf("PXE stack was not detected, Dump feature is not available\n");
- return;
+ if (hardware->is_pxe_valid == false) {
+ printf("PXE stack was not detected, Dump feature is not available\n");
+ return;
}
const union syslinux_derivative_info *sdi = syslinux_derivative_info();
- int err=0;
+ int err = 0;
ZZJSON *json = NULL;
ZZJSON_CONFIG config = { ZZJSON_VERY_STRICT, NULL,
- (int(*)(void*)) fgetc,
- NULL,
- malloc, calloc, free, realloc,
- stderr, NULL, stdout,
- (int(*)(void *,const char*,...)) dumpprintf,
- (int(*)(int,void*)) fputc
+ (int (*)(void *))fgetc,
+ NULL,
+ malloc, calloc, free, realloc,
+ stderr, NULL, stdout,
+ (int (*)(void *, const char *,...))dumpprintf,
+ (int (*)(int, void *))fputc
};
- memset(&p_buf,0,sizeof(p_buf));
+ memset(&p_buf, 0, sizeof(p_buf));
/* By now, we only support TFTP reporting */
- upload=&upload_tftp;
- upload->name="tftp";
+ upload = &upload_tftp;
+ upload->name = "tftp";
/* The following defines the behavior of the reporting */
char *arg[64];
- char filename[512]={0};
- compute_filename(hardware, filename, sizeof(filename));
+ char *filename = compute_filename(hardware);
/* The filename */
arg[0] = filename;
/* The server to upload the file */
if (strlen(hardware->tftp_ip) != 0) {
- arg[1] = hardware->tftp_ip;
- arg[2] = NULL;
+ arg[1] = hardware->tftp_ip;
+ arg[2] = NULL;
} else {
- arg[1] = NULL;
- snprintf(hardware->tftp_ip, sizeof(hardware->tftp_ip),
- "%u.%u.%u.%u",
- ((uint8_t *)&sdi->pxe.ipinfo->serverip)[0],
- ((uint8_t *)&sdi->pxe.ipinfo->serverip)[1],
- ((uint8_t *)&sdi->pxe.ipinfo->serverip)[2],
- ((uint8_t *)&sdi->pxe.ipinfo->serverip)[3]);
+ arg[1] = NULL;
+ snprintf(hardware->tftp_ip, sizeof(hardware->tftp_ip),
+ "%u.%u.%u.%u",
+ ((uint8_t *) & sdi->pxe.ipinfo->serverip)[0],
+ ((uint8_t *) & sdi->pxe.ipinfo->serverip)[1],
+ ((uint8_t *) & sdi->pxe.ipinfo->serverip)[2],
+ ((uint8_t *) & sdi->pxe.ipinfo->serverip)[3]);
}
/* We initiate the cpio to send */
- cpio_init(upload,(const char **)arg);
+ cpio_init(upload, (const char **)arg);
dump_cpu(hardware, &config, &json);
dump_pxe(hardware, &config, &json);
@@ -158,12 +218,12 @@ void dump(struct s_hardware *hardware)
/* We close & flush the file to send */
cpio_close(upload);
- if ((err=flush_data(upload)) != TFTP_OK) {
+ if ((err = flush_data(upload)) != TFTP_OK) {
/* As we manage a tftp connection, let's display the associated error message */
more_printf("Dump failed !\n");
- more_printf("TFTP ERROR on : %s:/%s \n",hardware->tftp_ip, filename);
- more_printf("TFTP ERROR msg : %s \n",tftp_string_error_message[-err]);
+ more_printf("TFTP ERROR on : %s:/%s \n", hardware->tftp_ip, filename);
+ more_printf("TFTP ERROR msg : %s \n", tftp_string_error_message[-err]);
} else {
- more_printf("Dump file sent at %s:/%s\n",hardware->tftp_ip, filename);
+ more_printf("Dump file sent at %s:/%s\n", hardware->tftp_ip, filename);
}
}
diff --git a/com32/hdt/hdt-menu-summary.c b/com32/hdt/hdt-menu-summary.c
index ad87c299..cef7e69e 100644
--- a/com32/hdt/hdt-menu-summary.c
+++ b/com32/hdt/hdt-menu-summary.c
@@ -52,8 +52,7 @@ void compute_summarymenu(struct s_my_menu *menu, struct s_hardware *hardware)
add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0);
menu->items_count++;
- char features[SUBMENULEN + 1];
- memset(features, 0, sizeof(features));
+ char features[255]={0};
if (hardware->dmi.processor.thread_count != 0)
sprintf(buffer, ", %d thread", hardware->dmi.processor.thread_count);
else
diff --git a/com32/hdt/hdt.c b/com32/hdt/hdt.c
index a1e3923c..851b0462 100644
--- a/com32/hdt/hdt.c
+++ b/com32/hdt/hdt.c
@@ -74,14 +74,21 @@ int main(const int argc, const char *argv[])
printf("%s\n", version_string);
+ int return_code = 0;
+
if (!menumode || automode)
start_cli_mode(&hardware);
else {
- int return_code = start_menu_mode(&hardware, version_string);
+ return_code = start_menu_mode(&hardware, version_string);
if (return_code == HDT_RETURN_TO_CLI)
start_cli_mode(&hardware);
- else
- return return_code;
}
- return 0;
+
+ /* Do we got request to do something at exit time ? */
+ if (strlen(hardware.postexec)>0) {
+ printf("Executing postexec instructions : %s\n",hardware.postexec);
+ runsyslinuxcmd(hardware.postexec);
+ }
+
+ return return_code;
}
diff --git a/com32/hdt/hdt.h b/com32/hdt/hdt.h
index 7b35236e..041d726d 100644
--- a/com32/hdt/hdt.h
+++ b/com32/hdt/hdt.h
@@ -33,8 +33,8 @@
#define AUTHOR "Erwan Velu"
#define CORE_DEVELOPER "Pierre-Alexandre Meyer"
#define CONTACT "hdt@zytor.com"
-#define VERSION "0.5.0"
-#define CODENAME "Van De Keizer"
+#define VERSION "0.5.2-pre2"
+#define CODENAME "Manon"
#define NB_CONTRIBUTORS 3
#define CONTRIBUTORS {"Sebastien Gonzalve (Patches)", "Gert Hulselmans (Tests)", "Alexander Andino (Design)"}
#define WEBSITE_URL "http://hdt-project.org"
diff --git a/com32/include/bitsize/stddef.h b/com32/include/bitsize/stddef.h
index 3d5c3e7a..04418a04 100644
--- a/com32/include/bitsize/stddef.h
+++ b/com32/include/bitsize/stddef.h
@@ -5,7 +5,6 @@
#ifndef _BITSIZE_STDDEF_H
#define _BITSIZE_STDDEF_H
-#define _SIZE_T
#if __SIZEOF_POINTER__ == 4
#include <bitsize32/stddef.h>
#elif __SIZEOF_POINTER__ == 8
@@ -13,18 +12,5 @@
#else
#error "Unable to build for to-be-defined architecture type"
#endif
-/* Original definitions below */
-/*
-#if defined(__s390__) || defined(__hppa__) || defined(__cris__)
-typedef unsigned long size_t;
-#else
-typedef unsigned int size_t;
-#endif
-#define _PTRDIFF_T
-typedef signed int ptrdiff_t;
-*/
-
-#else
-#error "BITSIZE_STDDEF already defined"
#endif /* _BITSIZE_STDDEF_H */
diff --git a/com32/include/bitsize/stdint.h b/com32/include/bitsize/stdint.h
index 854c5430..7e7b2355 100644
--- a/com32/include/bitsize/stdint.h
+++ b/com32/include/bitsize/stdint.h
@@ -5,71 +5,14 @@
#ifndef _BITSIZE_STDINT_H
#define _BITSIZE_STDINT_H
-/*
-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 ""
-*/
-
-/* Exact types */
-
-typedef signed char int8_t;
-typedef signed short int16_t;
-typedef signed int int32_t;
-typedef signed long long int64_t;
-
-typedef unsigned char uint8_t;
-typedef unsigned short uint16_t;
-typedef unsigned int uint32_t;
-typedef unsigned long long uint64_t;
-
-/* Small types */
-
-typedef signed char int_least8_t;
-typedef signed short int_least16_t;
-typedef signed int int_least32_t;
-typedef signed long long int_least64_t;
-
-typedef unsigned char uint_least8_t;
-typedef unsigned short uint_least16_t;
-typedef unsigned int uint_least32_t;
-typedef unsigned long long uint_least64_t;
-
-/* Fast types */
-
-typedef signed char int_fast8_t;
-typedef signed long long int_fast64_t;
-
-typedef unsigned char uint_fast8_t;
-typedef unsigned int uint_fast32_t;
-typedef unsigned long long uint_fast64_t;
+typedef signed char int8_t;
+typedef short int int16_t;
+typedef int int32_t;
-/* Maximal types */
+typedef unsigned char uint8_t;
+typedef unsigned short int uint16_t;
+typedef unsigned int uint32_t;
-typedef int64_t intmax_t;
-typedef uint64_t uintmax_t;
#if __SIZEOF_POINTER__ == 4
#include <bitsize32/stdint.h>
#elif __SIZEOF_POINTER__ == 8
@@ -77,4 +20,4 @@ typedef uint64_t uintmax_t;
#else
#error "Unable to build for to-be-defined architecture type"
#endif
-#endif /* _BITSIZE_STDINT_H */
+#endif /* _BITSIZE_STDINT_H */
diff --git a/com32/include/bitsize/stdintconst.h b/com32/include/bitsize/stdintconst.h
index ae4e9fc0..b2f3141a 100644
--- a/com32/include/bitsize/stdintconst.h
+++ b/com32/include/bitsize/stdintconst.h
@@ -13,4 +13,4 @@
#error "Unable to build for to-be-defined architecture type"
#endif
-#endif /* _BITSIZE_STDINTCONST_H */
+#endif /* _BITSIZE_STDINTCONST_H */
diff --git a/com32/include/bitsize/stdintlimits.h b/com32/include/bitsize/stdintlimits.h
index 9f3657d2..c342c448 100644
--- a/com32/include/bitsize/stdintlimits.h
+++ b/com32/include/bitsize/stdintlimits.h
@@ -13,4 +13,4 @@
#error "Unable to build for to-be-defined architecture type"
#endif
-#endif /* _BITSIZE_STDINTLIMITS_H */
+#endif /* _BITSIZE_STDINTLIMITS_H */
diff --git a/com32/include/bitsize32/limits.h b/com32/include/bitsize32/limits.h
index 8eb97d6d..f19205fe 100644
--- a/com32/include/bitsize32/limits.h
+++ b/com32/include/bitsize32/limits.h
@@ -2,8 +2,8 @@
* bits32/limits.h
*/
-#ifndef _BITSIZE_LIMITS_H
-#define _BITSIZE_LIMITS_H
+#ifndef _BITSIZE32_LIMITS_H
+#define _BITSIZE32_LIMITS_H
#define LONG_BIT 32
diff --git a/com32/include/bitsize32/stddef.h b/com32/include/bitsize32/stddef.h
index e5d49376..c34c675c 100644
--- a/com32/include/bitsize32/stddef.h
+++ b/com32/include/bitsize32/stddef.h
@@ -3,11 +3,7 @@
*/
#define _SIZE_T
-#if defined(__s390__) || defined(__hppa__) || defined(__cris__)
-typedef unsigned long size_t;
-#else
typedef unsigned int size_t;
-#endif
#define _PTRDIFF_T
-typedef signed int ptrdiff_t;
+typedef signed long ptrdiff_t;
diff --git a/com32/include/bitsize32/stdint.h b/com32/include/bitsize32/stdint.h
index c886a4c2..bdc69705 100644
--- a/com32/include/bitsize32/stdint.h
+++ b/com32/include/bitsize32/stdint.h
@@ -3,15 +3,8 @@
*/
-/*
-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;
@@ -29,13 +22,3 @@ typedef unsigned int uintptr_t;
#define __PRI64_RANK "ll"
#define __PRIFAST_RANK ""
#define __PRIPTR_RANK ""
-*/
-
-/* changes made according compiler output */
-typedef signed int int_fast16_t; /* was short */
-typedef signed int int_fast32_t;
-typedef unsigned int uint_fast16_t; /* was ushort */
-/* Pointer types */
-
-typedef int32_t intptr_t;
-typedef uint32_t uintptr_t;
diff --git a/com32/include/bitsize64/limits.h b/com32/include/bitsize64/limits.h
index f5bbf830..1acb1bc8 100644
--- a/com32/include/bitsize64/limits.h
+++ b/com32/include/bitsize64/limits.h
@@ -2,8 +2,8 @@
* bits64/limits.h
*/
-#ifndef _BITSIZE_LIMITS_H
-#define _BITSIZE_LIMITS_H
+#ifndef _BITSIZE64_LIMITS_H
+#define _BITSIZE64_LIMITS_H
#define LONG_BIT 64
diff --git a/com32/include/bitsize64/stddef.h b/com32/include/bitsize64/stddef.h
index 057a721f..c61bf8ce 100644
--- a/com32/include/bitsize64/stddef.h
+++ b/com32/include/bitsize64/stddef.h
@@ -2,9 +2,9 @@
* 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
index 32de44c5..91930003 100644
--- a/com32/include/bitsize64/stdint.h
+++ b/com32/include/bitsize64/stdint.h
@@ -3,15 +3,8 @@
*/
-/*
-typedef signed char int8_t;
-typedef short int int16_t;
-typedef int int32_t;
typedef long int int64_t;
-typedef unsigned char uint8_t;
-typedef unsigned short int uint16_t;
-typedef unsigned int uint32_t;
typedef unsigned long int uint64_t;
typedef long int int_fast16_t;
@@ -29,13 +22,3 @@ typedef unsigned long int uintptr_t;
#define __PRI64_RANK "l"
#define __PRIFAST_RANK "l"
#define __PRIPTR_RANK "l"
-*/
-
-/* based on compiler output */
-typedef signed long int_fast16_t;
-typedef signed long int int_fast32_t;
-typedef unsigned long int uint_fast16_t;
-/* Pointer types */
-
-typedef long int intptr_t;
-typedef long unsigned int uintptr_t;
diff --git a/com32/include/com32.h b/com32/include/com32.h
index f49f9eab..148d08eb 100644
--- a/com32/include/com32.h
+++ b/com32/include/com32.h
@@ -120,7 +120,7 @@ extern const com32sys_t __com32_zero_regs;
/*
* Lowmem allocation functions
*/
-void *clmalloc(size_t);
+void *lmalloc(size_t);
void *lzalloc(size_t);
void lfree(void *);
char *lstrdup(const char *);
@@ -135,10 +135,22 @@ 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__))
+__noreturn __bad_SEG(const volatile void *);
+
+static inline uint16_t SEG(const volatile void *__p)
+{
+ if (__unlikely((uintptr_t)__p > 0xfffff))
+ __bad_SEG(__p);
+
+ return (uint16_t) (((uintptr_t) __p) >> 4);
+}
+#else
static inline uint16_t SEG(const volatile void *__p)
{
return (uint16_t) (((uintptr_t) __p) >> 4);
}
+#endif
static inline uint16_t OFFS(const volatile void *__p)
{
diff --git a/com32/include/dhcp.h b/com32/include/dhcp.h
new file mode 100644
index 00000000..afef9242
--- /dev/null
+++ b/com32/include/dhcp.h
@@ -0,0 +1,40 @@
+#ifndef DHCP_H
+#define DHCP_H
+
+#include <inttypes.h>
+
+struct dhcp_option {
+ void *data;
+ int len;
+};
+
+struct dhcp_packet {
+ uint8_t op; /* 0 */
+ uint8_t htype; /* 1 */
+ uint8_t hlen; /* 2 */
+ uint8_t hops; /* 3 */
+ uint32_t xid; /* 4 */
+ uint16_t secs; /* 8 */
+ uint16_t flags; /* 10 */
+ uint32_t ciaddr; /* 12 */
+ uint32_t yiaddr; /* 16 */
+ uint32_t siaddr; /* 20 */
+ uint32_t giaddr; /* 24 */
+ uint8_t chaddr[16]; /* 28 */
+ uint8_t sname[64]; /* 44 */
+ uint8_t file[128]; /* 108 */
+ uint32_t magic; /* 236 */
+ uint8_t options[4]; /* 240 */
+};
+
+#define DHCP_VENDOR_MAGIC 0x63825363
+
+int dhcp_pack_packet(void *packet, size_t *len,
+ const struct dhcp_option opt[256]);
+
+int dhcp_unpack_packet(const void *packet, size_t len,
+ struct dhcp_option opt[256]);
+
+#endif /* DHCP_H */
+
+
diff --git a/com32/include/dprintf.h b/com32/include/dprintf.h
index 30a21ada..26ca734b 100644
--- a/com32/include/dprintf.h
+++ b/com32/include/dprintf.h
@@ -5,18 +5,36 @@
#ifndef _DPRINTF_H
#define _DPRINTF_H
+#if !defined(DEBUG_PORT) && !defined(DEBUG_STDIO)
+# undef DEBUG
+#endif
+
#ifdef DEBUG
-#include <stdio.h>
+# include <stdio.h>
+# ifdef DEBUG_STDIO
+# define dprintf printf
+# define vdprintf vprintf
+# else
void dprintf(const char *, ...);
void vdprintf(const char *, va_list);
+# endif
#else
-#define dprintf(fmt, ...) ((void)(0))
-#define vdprintf(fmt, ap) ((void)(0))
+# define dprintf(fmt, ...) ((void)(0))
+# define vdprintf(fmt, ap) ((void)(0))
#endif /* DEBUG */
+# if DEBUG >= 2
+/* Really verbose debugging... */
+# define dprintf2 dprintf
+# define vdprintf2 vdprintf
+# else
+# define dprintf2(fmt, ...) ((void)(0))
+# define vdprintf2(fmt, ap) ((void)(0))
+# endif
+
#endif /* _DPRINTF_H */
diff --git a/com32/include/hw/vga.h b/com32/include/hw/vga.h
new file mode 100644
index 00000000..0ebd2e25
--- /dev/null
+++ b/com32/include/hw/vga.h
@@ -0,0 +1,104 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2012 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef _HW_VGA_H
+#define _HW_VGA_H 1
+
+#include <sys/io.h>
+
+/* These are relative to the CRTC base address */
+#define VGA_CRTC_ADDR 0x4
+#define VGA_CRTC_DATA 0x5
+#define VGA_CRTC_IX_HORIZ_TOTAL 0x00
+#define VGA_CRTC_IX_END_HORIZ_DISPLAY 0x01
+#define VGA_CRTC_IX_START_HORIZ_BLANK 0x02
+#define VGA_CRTC_IX_END_HORIZ_BLANK 0x03
+#define VGA_CRTC_IX_START_HORIZ_RETR 0x04
+#define VGA_CRTC_IX_END_HORIZ_RETR 0x05
+#define VGA_CRTC_IX_VERT_TOTAL 0x06
+#define VGA_CRTC_IX_OVERFLOW 0x07
+#define VGA_CRTC_IX_PRESET_ROW_SCAN 0x08
+#define VGA_CRTC_IX_MAX_SCAN_LINE 0x09
+#define VGA_CRTC_IX_CURSOR_START 0x0a
+#define VGA_CRTC_IX_CURSOR_END 0x0b
+#define VGA_CRTC_IX_START_ADDR_HIGH 0x0c
+#define VGA_CRTC_IX_START_ADDR_LOW 0x0d
+#define VGA_CRTC_IX_CURSOR_POS_HIGH 0x0e
+#define VGA_CRTC_IX_CURSOR_POS_LOW 0x0f
+#define VGA_CRTC_IX_START_VERT_RETR 0x10
+#define VGA_CRTC_IX_END_VERT_RETR 0x11
+#define VGA_CRTC_IX_END_VERT_DISPLAY 0x12
+#define VGA_CRTC_IX_OFFSET 0x13
+#define VGA_CRTC_IX_UNDERLINE 0x14
+#define VGA_CRTC_IX_START_VERT_BLANK 0x15
+#define VGA_CRTC_IX_END_VERT_BLANK 0x16
+#define VGA_CRTC_IX_MODE_CONTROL 0x17
+#define VGA_CRTC_IX_LINE_COMPARE 0x18
+#define VGA_CRTC_INPUT_STATUS_1 0xa
+#define VGA_CRTC_FEATURE_CONTROL_WRITE 0xa
+
+#define VGA_ATTR_ADDR_DATA 0x3c0
+#define VGA_ATTR_DATA_READ 0x3c1
+/* 0x00-0x0f are 16->64 palette registers */
+#define VGA_ATTR_IX_MODE_CONTROL 0x10
+#define VGA_ATTR_IX_OVERSCAN 0x11
+#define VGA_ATTR_IX_COLOR_PLANE_ENABLE 0x12
+#define VGA_ATTR_IX_HORIZ_PIXEL_PAN 0x13
+#define VGA_ADDR_IX_COLOR_SELECT 0x14
+#define VGA_INPUT_STATUS_0 0x3c2
+#define VGA_MISC_OUTPUT_WRITE 0x3c2
+#define VGA_SEQ_ADDR 0x3c4
+#define VGA_SEQ_DATA 0x3c5
+#define VGA_SEQ_IX_RESET 0
+#define VGA_SEQ_IX_CLOCKMODE 1
+#define VGA_SEQ_IX_MAP_MASK 2
+#define VGA_SEQ_IX_CHAR_MAP 3
+#define VGA_SEQ_IX_SEQ_MEM_MODE 4
+#define VGA_DAC_STATE 0x3c7
+#define VGA_DAC_ADDR_READ_MODE 0x3c7
+#define VGA_DAC_ADDR_WRITE_MODE 0x3c8
+#define VGA_DAC_DATA 0x3c9
+#define VGA_FEATURE_CONTROL_READ 0x3ca
+#define VGA_MISC_OUTPUT_READ 0x3cc
+#define VGA_GC_ADDR 0x3ce
+#define VGA_GC_DATA 0x3cf
+#define VGA_GC_IX_SET_RESET 0
+#define VGA_GC_IX_ENABLE_SET_RESET 1
+#define VGA_GC_IX_COLOR_COMPARE 2
+#define VGA_GC_IX_DATA_ROTATE 3
+#define VGA_GC_IX_READ_MAP_SELECT 4
+#define VGA_GC_IX_GRAPHICS_MODE 5
+#define VGA_GC_IX_MISC_GRAPHICS 6
+#define VGA_GC_IX_COLOR_DONT_CARE 7
+#define VGA_GC_IX_BIT_MASK 8
+
+static inline uint16_t vga_crtc_base(void)
+{
+ return 0x3b0 + ((inb(VGA_MISC_OUTPUT_READ) & 1) << 5);
+}
+
+#endif /* _HW_VGA_H */
diff --git a/com32/include/klibc/compiler.h b/com32/include/klibc/compiler.h
index b5919d67..210971f1 100644
--- a/com32/include/klibc/compiler.h
+++ b/com32/include/klibc/compiler.h
@@ -108,6 +108,13 @@
# define __unusedfunc
#endif
+/* Declare a variable or data structure as unused. */
+#ifdef __GNUC__
+# define __unused __attribute__((unused))
+#else
+# define __unused
+#endif
+
/* Used symbol */
#define __used __attribute__((used))
diff --git a/com32/include/linux/list.h b/com32/include/linux/list.h
index 3b92e254..afe89808 100644
--- a/com32/include/linux/list.h
+++ b/com32/include/linux/list.h
@@ -338,6 +338,19 @@ static inline void list_splice_init(struct list_head *list,
pos = list_entry(pos->member.next, typeof(*pos), member))
/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+* @pos: the type * to use as a loop cursor.
+* @n: another type * to use as temporary storage
+* @head: the head for your list.
+* @member: the name of the list_struct within the struct.
+*/
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
* list_for_each_entry_reverse - iterate backwards over list of given type.
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
diff --git a/com32/include/menu.h b/com32/include/menu.h
index 1db4d7c9..5a4c901e 100644
--- a/com32/include/menu.h
+++ b/com32/include/menu.h
@@ -92,8 +92,6 @@ enum kernel_type {
KT_CONFIG, /* Configuration file */
};
-extern const char *const kernel_types[];
-
/* Configurable integer parameters */
enum parameter_number {
P_WIDTH,
@@ -187,6 +185,7 @@ extern int shiftkey;
extern int hiddenmenu;
extern int clearmenu;
extern long long totaltimeout;
+extern clock_t kbdtimeout;
extern const char *hide_key[KEY_MAX];
void parse_configs(char **argv);
@@ -227,10 +226,10 @@ extern const int message_base_color;
extern const char *current_background;
void set_background(const char *new_background);
-/* execute.c */
-void execute(const char *cmdline, enum kernel_type type);
-
/* drain.c */
void drain_keyboard(void);
+/* chainboot.c */
+void chainboot_file(const char *file, enum kernel_type type);
+
#endif /* MENU_H */
diff --git a/com32/include/stdint.h b/com32/include/stdint.h
index 0d0e8f69..f64f0278 100644
--- a/com32/include/stdint.h
+++ b/com32/include/stdint.h
@@ -5,151 +5,87 @@
#ifndef _STDINT_H
#define _STDINT_H
-/* FIXME: Move common typedefs to bitsize/stdint.h
- * and architecture specificis to bitsize32/64
- */
#include <bitsize/stdint.h>
-#if 0
-/* Exact types */
-typedef signed char int8_t;
-typedef signed short int16_t;
-typedef signed int int32_t;
-typedef signed long long int64_t;
+typedef int8_t int_least8_t;
+typedef int16_t int_least16_t;
+typedef int32_t int_least32_t;
+typedef int64_t int_least64_t;
-typedef unsigned char uint8_t;
-typedef unsigned short uint16_t;
-typedef unsigned int uint32_t;
-typedef unsigned long long uint64_t;
+typedef uint8_t uint_least8_t;
+typedef uint16_t uint_least16_t;
+typedef uint32_t uint_least32_t;
+typedef uint64_t uint_least64_t;
-/* Small types */
+typedef int8_t int_fast8_t;
+typedef int64_t int_fast64_t;
-typedef signed char int_least8_t;
-typedef signed short int_least16_t;
-typedef signed int int_least32_t;
-typedef signed long long int_least64_t;
+typedef uint8_t uint_fast8_t;
+typedef uint64_t uint_fast64_t;
-typedef unsigned char uint_least8_t;
-typedef unsigned short uint_least16_t;
-typedef unsigned int uint_least32_t;
-typedef unsigned long long uint_least64_t;
+typedef int64_t intmax_t;
+typedef uint64_t uintmax_t;
-/* Fast types */
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)
-typedef signed char int_fast8_t;
-typedef signed short int_fast16_t; /* ?? 32: int 64: long */
-typedef signed int int_fast32_t; /* ?? 64: long int */
-typedef signed long long int_fast64_t; /* 64: long int */
+#define INT8_MIN (-128)
+#define INT16_MIN (-32768)
+#define INT32_MIN (-2147483647-1)
+#define INT64_MIN (__INT64_C(-9223372036854775807)-1)
-typedef unsigned char uint_fast8_t;
-typedef unsigned short uint_fast16_t; /* 32: unsigned int 64: short unsigned int */
-typedef unsigned int uint_fast32_t;
-typedef unsigned long long uint_fast64_t;/* 64: long unsigned int */
+#define INT8_MAX (127)
+#define INT16_MAX (32767)
+#define INT32_MAX (2147483647)
+#define INT64_MAX (__INT64_C(9223372036854775807))
-/* Pointer types */
+#define UINT8_MAX (255U)
+#define UINT16_MAX (65535U)
+#define UINT32_MAX (4294967295U)
+#define UINT64_MAX (__UINT64_C(18446744073709551615))
-typedef int32_t intptr_t; /* 64: long int */
-typedef uint32_t uintptr_t; /* 64: long unsigned int */
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST64_MIN INT64_MIN
-/* Maximal types */
+#define INT_LEAST8_MAX INT8_MAX
+#define INT_LEAST16_MAX INT16_MAX
+#define INT_LEAST32_MAX INT32_MAX
+#define INT_LEAST64_MAX INT64_MAX
-typedef int64_t intmax_t;
-typedef uint64_t uintmax_t;
-#endif
-/* FIXME: move common definitions to bitsize/stdint.h and
- * architecture specifics to bitsize32/64/stdintlimits.h as appropriate
- */
-/*
- * To be strictly correct...
- */
-#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)
+#define UINT_LEAST8_MAX UINT8_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
-# define INT8_MIN (-128)
-# define INT16_MIN (-32767-1)
-# define INT32_MIN (-2147483647-1)
-# define INT64_MIN (-9223372036854775807LL-1)
-
-# define INT8_MAX (127)
-# define INT16_MAX (32767)
-# define INT32_MAX (2147483647)
-# define INT64_MAX (9223372036854775807LL)
-
-# define UINT8_MAX (255U)
-# define UINT16_MAX (65535U)
-# define UINT32_MAX (4294967295U)
-# define UINT64_MAX (18446744073709551615ULL)
-
-# define INT_LEAST8_MIN INT8_MIN //(-128)
-# define INT_LEAST16_MIN INT16_MIN //(-32767-1)
-# define INT_LEAST32_MIN INT32_MIN //(-2147483647-1)
-# define INT_LEAST64_MIN INT64_MIN //(-9223372036854775807LL-1)
-
-# define INT_LEAST8_MAX INT8_MAX //(127)
-# define INT_LEAST16_MAX INT16_MAX //(32767)
-# define INT_LEAST32_MAX INT32_MAX //(2147483647)
-# define INT_LEAST64_MAX INT64_MAX //(9223372036854775807LL)
-
-# define UINT_LEAST8_MAX UINT8_MAX //(255U)
-# define UINT_LEAST16_MAX UINT16_MAX //(65535U)
-# define UINT_LEAST32_MAX UINT32_MAX //(4294967295U)
-# define UINT_LEAST64_MAX UINT64_MAX //(18446744073709551615ULL)
-
-# define INT_FAST8_MIN INT8_MIN //(-128)
-//# define INT_FAST16_MIN (-32767-1)
-//# define INT_FAST32_MIN (-2147483647-1)
-# define INT_FAST64_MIN INT64_MIN //(-9223372036854775807LL-1)
-
-# define INT_FAST8_MAX INT8_MAX //(127)
-//# define INT_FAST16_MAX (32767)
-//# define INT_FAST32_MAX (2147483647)
-# define INT_FAST64_MAX INT64_MAX //(9223372036854775807LL)
-
-# define UINT_FAST8_MAX UINT8_MAX //(255U)
-//# define UINT_FAST16_MAX (65535U)
-//# define UINT_FAST32_MAX (4294967295U)
-# define UINT_FAST64_MAX UINT64_MAX //(18446744073709551615ULL)
-
-//FIXME: Move *INTPTR to architecture specific as they vary
-//# define INTPTR_MIN (-2147483647-1)
-//# define INTPTR_MAX (2147483647)
-//# define UINTPTR_MAX (4294967295U)
-
-# define INTMAX_MIN (-9223372036854775807LL-1)
-# define INTMAX_MAX (9223372036854775807LL)
-# define UINTMAX_MAX (18446744073709551615ULL)
-
-/* FIXME: include the architecture specific limits from bitsizexx/stdintlimits.h */
-/* ptrdiff_t limit */
-//# define PTRDIFF_MIN (-2147483647-1)
-//# define PTRDIFF_MAX (2147483647)
-
-/* sig_atomic_t limit */
-//# define SIG_ATOMIC_MIN (-2147483647-1)
-//# define SIG_ATOMIC_MAX (2147483647)
-
-/* size_t limit */
-//# define SIZE_MAX (4294967295U)
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST64_MIN INT64_MIN
-#include <bitsize/stdintlimits.h>
+#define INT_FAST8_MAX INT8_MAX
+#define INT_FAST64_MAX INT64_MAX
-#endif /* STDC_LIMIT_MACROS */
+#define UINT_FAST8_MAX UINT8_MAX
+#define UINT_FAST64_MAX UINT64_MAX
-#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS)
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+
+#include <bitsize/stdintlimits.h>
-# define INT8_C(n) n
-# define INT16_C(n) n
-# define INT32_C(n) n
-# define INT64_C(n) n ## LL
+#endif
-# define UINT8_C(n) n ## U
-# define UINT16_C(n) n ## U
-# define UINT32_C(n) n ## U
-# define UINT64_C(n) n ## ULL
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS)
-//# define INTMAX_C(n) n ## LL
-//# define UINTMAX_C(n) n ## ULL
+#define INT8_C(c) c
+#define INT16_C(c) c
+#define INT32_C(c) c
+#define INT64_C(c) __INT64_C(c)
-/* included from klibc/usr/include/stdint.h */
+#define UINT8_C(c) c ## U
+#define UINT16_C(c) c ## U
+#define UINT32_C(c) c ## U
+#define UINT64_C(c) __UINT64_C(c)
#define INT_LEAST8_C(c) INT8_C(c)
#define INT_LEAST16_C(c) INT16_C(c)
@@ -171,6 +107,10 @@ typedef uint64_t uintmax_t;
#define UINTMAX_C(c) UINT64_C(c)
#include <bitsize/stdintconst.h>
-#endif /* STDC_CONSTANT_MACROS */
-#endif /* _STDINT_H */
+#endif
+
+/* Keep the kernel from trying to define these types... */
+#define __BIT_TYPES_DEFINED__
+
+#endif /* _STDINT_H */
diff --git a/com32/include/string.h b/com32/include/string.h
index af9792b6..d847440d 100644
--- a/com32/include/string.h
+++ b/com32/include/string.h
@@ -42,5 +42,6 @@ __extern char *strsep(char **, const char *);
__extern size_t strspn(const char *, const char *);
__extern char *strstr(const char *, const char *);
__extern char *strtok(char *, const char *);
+__extern char *strreplace(const char *, const char *, const char *);
#endif /* _STRING_H */
diff --git a/com32/include/sys/exec.h b/com32/include/sys/exec.h
index 9c00e4a5..ac05c276 100644
--- a/com32/include/sys/exec.h
+++ b/com32/include/sys/exec.h
@@ -55,29 +55,6 @@ extern int exec_init(void);
/**
- * load_library - Loads a dynamic library into the environment.
- * @name: the name of the library to load, including the extension
- * (e.g. 'sort.c32')
- *
- * A dynamic library is an ELF module that may contain initialization and
- * termination routines, but not a main routine. At the same time, any memory
- * allocations using malloc() and its derivatives are made on behalf of the
- * currently executing program or the COM32 root module. If the library
- * is unloaded, no memory cleanup is performed.
- */
-extern int load_library(const char *name);
-
-/**
- * unload_library - unloads a library from the environment.
- * @name: the name of the library to unload, including the extension
- * (e.g. 'sort.c32')
- *
- * Note that no memory allocated by the library code is cleaned up, as the
- * allocations belong to the innermost calling program in the call stack.
- */
-extern int unload_library(const char *name);
-
-/**
* spawnv - Executes a program in the current environment.
* @name: the name of the program to spawn, including the extension
* (e.g. 'hello.c32')
diff --git a/com32/include/sys/i386/module.h b/com32/include/sys/i386/module.h
index 5890d771..21988ead 100644
--- a/com32/include/sys/i386/module.h
+++ b/com32/include/sys/i386/module.h
@@ -4,179 +4,10 @@
* Dynamic ELF modules definitions and services.
*/
+#ifndef I386_MODULE_H_
+#define I386_MODULE_H_
-#include <stdio.h>
#include <elf.h>
-#include <stdint.h>
-#include <setjmp.h>
-#include <stdbool.h>
-#include <linux/list.h>
-
-/*
- * The maximum length of the module file name (including path), stored
- * in the struct module descriptor.
- */
-#define MODULE_NAME_SIZE 256
-
-/*
- * Some common information about what kind of modules we're dealing with
- */
-#define UNKNOWN_MODULE -1
-#define EXEC_MODULE 0
-#define LIB_MODULE 1
-
-/*
- * Initialization and finalization function signatures
- */
-
-
-/**
- * module_init_t - pointer to a initialization routine
- *
- * The initialization routine is called after all module constructors were invoked.
- * It takes no parameters and returns 0 if the module was initialized successfully,
- * or a non-zero value if errors have occurred.
- */
-typedef int (*module_init_t)(void);
-
-/**
- * module_exit_t - pointer to a finalization routine
- *
- * The finalization routine is called before the module destructors are to be invoked.
- * It simply executes some cleanup code, without error reporting.
- */
-typedef void (*module_exit_t)(void);
-
-/**
- * module_main_t - pointer to an entry routine
- *
- * The entry routine is present only in executable modules, and represents
- * the entry point for the program.
- */
-typedef int (*module_main_t)(int, char**);
-
-
-/**
- * struct elf_module - structure encapsulating a module loaded in memory.
- *
- * Each SYSLINUX ELF module must have an associated struct elf_module descriptor
- * that keeps track of memory allocations, symbol information, and various other
- * resources needed by the module itself or by other modules that depend on it.
- *
- * There are two types of modules:
- * - regular modules, which are actual memory images of a loaded & linked shared
- * object (ELF file). Memory is reserved for the struct elf_module structure itself
- * and for the object loadable sections read from the file.
- * - shallow modules, which are not associated with an ELF shared object, but contain
- * metainformation about a memory region already present and containing the
- * actual code and data. One particular usage of shallow modules is to access
- * symbol information from the root COM32 module loaded by the SYSLINUX core.
- * As their name suggests, memory is reserved only for the elf_module structure
- * itself and optionally for a usually small memory region containing metainformation
- * (symbol information).
- *
- * Module descriptors are related to each other through dependency information. A module
- * can depend on symbols from other modules, and in turn it can provide symbols used
- * by other dependant modules. This relationship can be described as a directed
- * acyclic graph (DAG). The graph is stored using double linked lists of
- * predecessors and successors. There is also a global linked list containing all
- * the modules currently loaded.
- */
-struct atexit;
-struct elf_module {
- char name[MODULE_NAME_SIZE]; // The module name
-
- bool shallow; // Whether the module contains any code
-
- struct list_head required; // Head of the required modules list
- struct list_head dependants; // Head of module dependants list
- struct list_head list; // The list entry in the module list
-
- module_init_t *init_func; // The initialization entry point
- module_exit_t *exit_func; // The module finalization code
- 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
-
- Elf32_Word *hash_table; // The symbol hash table
- Elf32_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
-
- 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
-
-
- 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
- } l;
-
- // Process execution data
- struct {
- jmp_buf process_exit; // Exit state
- struct atexit *atexit_list; // atexit() chain
- } x;
- } u;
-
-};
-
-static inline void dump_elf_module(struct elf_module *module)
-{
- /*
- dprintf("module name = %s", module->name);
- printf("base_addr = 0x%p, module_size = %d\n", module->base_addr, module->module_size);
- printf("hash tlb = 0x%p, ghash tbl = 0x%p\n", module->hash_table, module->ghash_table);
- printf("str tbl = 0x%p, size = %d\n", module->str_table, module->strtable_size);
- printf("sym tbl = 0x%p, entry = %d, size = %d\n", module->sym_table, module->syment_size, module->symtable_size);
- printf("init: %p", module->init_func);
- printf("main: %p", module->main_func);
- printf("exit: %p", module->exit_func);
- printf("", module->base_addr);
- printf("", module->base_addr);
- printf("", module->base_addr);
- */
-}
-
-/**
- * struct module_dep - structure encapsulating a module dependency need
- *
- * This structure represents an item in a double linked list of predecessors or
- * successors. The item contents is a pointer to the corresponding module descriptor.
- */
-struct module_dep {
- struct list_head list; // The list entry in the dependency list
-
- struct elf_module *module; // The target module descriptor
-};
-
-
-
-#ifdef DYNAMIC_MODULE
-
-/*
- * This portion is included by dynamic (ELF) module source files.
- */
-
-#define MODULE_INIT(fn) static module_init_t __module_init \
- __used __attribute__((section(".ctors_modinit"))) = fn
-
-#define MODULE_EXIT(fn) static module_exit_t __module_exit \
- __used __attribute__((section(".dtors_modexit"))) = fn
-
-#else
-
-/*
- * This portion is included by the core COM32 module.
- */
/*
* Accepted values for various ELF header parameters found in an ELF dynamic
@@ -189,181 +20,16 @@ struct module_dep {
#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)
- */
-#define MODULE_ELF_INIT_PTR "__module_init_ptr" // Initialization pointer symbol name
-#define MODULE_ELF_EXIT_PTR "__module_exit_ptr" // Finalization pointer symbol name
-#define MODULE_ELF_MAIN_PTR "__module_main_ptr" // Entry pointer symbol name
-
-/**
- * modules_head - A global linked list containing all the loaded modules.
- */
-extern struct list_head modules_head;
-
-
-/**
- * for_each_module - iterator loop through the list of loaded modules.
- */
-#define for_each_module(m) list_for_each_entry(m, &modules_head, list)
-
-/**
- * modules_init - initialize the module subsystem.
- *
- * This function must be called before any module operation is to be performed.
- */
-extern int modules_init(void);
-
-
-/**
- * modules_term - releases all resources pertaining to the module subsystem.
- *
- * This function should be called after all module operations.
- */
-extern void modules_term(void);
-
-
-/**
- * module_alloc - reserves space for a new module descriptor.
- * @name: the file name of the module to be loaded.
- *
- * The function simply allocates a new module descriptor and initializes its fields
- * in order to be used by subsequent loading operations.
- */
-extern struct elf_module *module_alloc(const char *name);
-
-
-/**
- * module_load - loads a regular ELF module into memory.
- * @module: the module descriptor returned by module_alloc.
- *
- * The function reads the module file, checks whether the file has a
- * valid structure, then loads into memory the code and the data and performs
- * any symbol relocations. A module dependency is created automatically when the
- * relocated symbol is defined in a different module.
- *
- * The function returns 0 if the operation is completed successfully, and
- * a non-zero value if an error occurs. Possible errors include invalid module
- * structure, missing symbol definitions (unsatisfied dependencies) and memory
- * allocation issues.
- */
-extern int module_load(struct elf_module *module);
-
-
-/**
- * module_load_shallow - loads a shallow ELF module into memory.
- * @module: the module descriptor returned by module_alloc.
- *
- * The function reads the module file, checks whether the file has a valid
- * structure, then loads into memory the module metadata. The metadata currently
- * contains a symbol table that describes code & data allocated by other means.
- * Its current use is to describe the root COM32 module to the rest of the
- * module subsystem.
- */
-extern int module_load_shallow(struct elf_module *module, Elf32_Addr base_addr);
-
-/**
- * module_unload - unloads the module from the system.
- * @module: the module descriptor structure.
- *
- * The function checks to see whether the module can be safely removed, then
- * it releases all the associated memory. This function can be applied both
- * for standard modules and for shallow modules.
- *
- * A module can be safely removed from the system when no other modules reference
- * symbols from it.
- */
-extern int module_unload(struct elf_module *module);
-
-/**
- * module_unload - unloads the module from the system.
- * @module: the module descriptor structure.
- *
- * This function returns the type of module we're dealing with
- * either a library module ( LIB_MODULE ), executable module ( EXEC_MODULE ),
- * or an error ( UNKNOWN_MODULE ). The way it checks teh type is by checking to see
- * if the module has its main_func set ( in which case it's an executable ). In case
- * it doesn't it then checks to see if init_func is set ( in which case it's a
- * library module. If this isn't the case either we don't know what it is so bail out
- */
-extern int get_module_type(struct elf_module *module);
-
-/**
- * module_unloadable - checks whether the given module can be unloaded.
- * @module: the module descriptor structure
- *
- * A module can be unloaded from the system when no other modules depend on it,
- * that is, no symbols are referenced from it.
- */
-extern int module_unloadable(struct elf_module *module);
-
-/**
- * module_find - searches for a module by its name.
- * @name: the name of the module, as it was specified in module_alloc.
- *
- * The function returns a pointer to the module descriptor, if found, or
- * NULL otherwise.
- */
-extern struct elf_module *module_find(const char *name);
-
-/**
- * module_find_symbol - searches for a symbol definition in a given module.
- * @name: the name of the symbol to be found.
- * @module: the module descriptor structure.
- *
- * The function searches the module symbol table for a symbol matching exactly
- * the name provided. The operation uses the following search algorithms, in this
- * order:
- * - If a GNU hash table is present in the module, it is used to find the symbol.
- * - If the symbol cannot be found with the first method (either the hash table
- * is not present or the symbol is not found) and if a regular (SysV) hash table
- * is present, a search is performed on the SysV hash table. If the symbol is not
- * found, NULL is returned.
- * - If the second method cannot be applied, a linear search is performed by
- * inspecting every symbol in the symbol table.
- *
- * 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);
-
-/**
- * global_find_symbol - searches for a symbol definition in the entire module namespace.
- * @name: the name of the symbol to be found.
- * @module: an optional (may be NULL) pointer to a module descriptor variable that
- * will hold the module where the symbol was found.
- *
- * The function search for the given symbol name in all the modules currently
- * loaded in the system, in the reverse module loading order. That is, the most
- * recently loaded module is searched first, followed by the previous one, until
- * the first loaded module is reached.
- *
- * If no module contains the symbol, NULL is returned, otherwise the return value is
- * 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);
-
-/**
- * module_get_absolute - converts an memory address relative to a module base address
- * to its absolute value in RAM.
- * @addr: the relative address to convert.
- * @module: the module whose base address is used for the conversion.
- *
- * The function returns a pointer to the absolute memory address.
- */
-static inline void *module_get_absolute(Elf32_Addr addr, struct elf_module *module) {
- return (void*)(module->base_addr + addr);
-}
-
-/**
- * syslinux_current - get the current module process
- */
-extern struct elf_module *__syslinux_current;
-static inline const struct elf_module *syslinux_current(void)
-{
- return __syslinux_current;
-}
+#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 // DYNAMIC_MODULE
+#endif // I386_MODULE_H_
diff --git a/com32/include/sys/module.h b/com32/include/sys/module.h
index 7fcd00a5..88c8f8ec 100644
--- a/com32/include/sys/module.h
+++ b/com32/include/sys/module.h
@@ -7,6 +7,13 @@
#ifndef MODULE_H_
#define MODULE_H_
+#include <stdio.h>
+#include <elf.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <stdbool.h>
+#include <linux/list.h>
+
#if __SIZEOF_POINTER__ == 4
#include <i386/module.h>
#elif __SIZEOF_POINTER__ == 8
@@ -15,4 +22,340 @@
#error "unsupported architecture"
#endif
-#endif
+/*
+ * The maximum length of the module file name (including path), stored
+ * in the struct module descriptor.
+ */
+#define MODULE_NAME_SIZE 256
+
+/*
+ * Some common information about what kind of modules we're dealing with
+ */
+#define EXEC_MODULE 0
+#define LIB_MODULE 1
+
+#define MAX_NR_DEPS 64
+
+/*
+ * Initialization and finalization function signatures
+ */
+
+/**
+ * module_main_t - pointer to an entry routine
+ *
+ * The entry routine is present only in executable modules, and represents
+ * the entry point for the program.
+ */
+typedef int (*module_main_t)(int, char**);
+
+/**
+ * module_ctor_t - pointer to a constructor or destructor routine
+ *
+ * A module may have multiple routines that need to be executed before
+ * or after the main routine. These are the constructors and
+ * destructors, respectively.
+ */
+typedef void (*module_ctor_t) (void);
+
+/**
+ * struct elf_module - structure encapsulating a module loaded in memory.
+ *
+ * Each SYSLINUX ELF module must have an associated struct elf_module descriptor
+ * that keeps track of memory allocations, symbol information, and various other
+ * resources needed by the module itself or by other modules that depend on it.
+ *
+ * There are two types of modules:
+ * - regular modules, which are actual memory images of a loaded & linked shared
+ * object (ELF file). Memory is reserved for the struct elf_module structure itself
+ * and for the object loadable sections read from the file.
+ * - shallow modules, which are not associated with an ELF shared object, but contain
+ * metainformation about a memory region already present and containing the
+ * actual code and data. One particular usage of shallow modules is to access
+ * symbol information from the root COM32 module loaded by the SYSLINUX core.
+ * As their name suggests, memory is reserved only for the elf_module structure
+ * itself and optionally for a usually small memory region containing metainformation
+ * (symbol information).
+ *
+ * Module descriptors are related to each other through dependency information. A module
+ * can depend on symbols from other modules, and in turn it can provide symbols used
+ * by other dependant modules. This relationship can be described as a directed
+ * acyclic graph (DAG). The graph is stored using double linked lists of
+ * predecessors and successors. There is also a global linked list containing all
+ * the modules currently loaded.
+ */
+struct atexit;
+struct elf_module {
+ char name[MODULE_NAME_SIZE]; // The module name
+
+ bool shallow; // Whether the module contains any code
+
+ struct list_head required; // Head of the required modules list
+ struct list_head dependants; // Head of module dependants list
+ struct list_head list; // The list entry in the module list
+
+ module_ctor_t *ctors; // module constructors
+ module_ctor_t *dtors; // module destructors
+ module_main_t main_func; // The main function (for executable modules)
+
+ void *module_addr; // The module location in the memory
+ Elf_Addr base_addr; // The base address of the module
+ Elf_Word module_size; // The module size in memory
+
+ 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
+ Elf_Dyn *dyn_table; // Dynamic loading information 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
+ Elf_Off _cr_offset; // The current offset in the open file
+ } l;
+
+ // Process execution data
+ struct {
+ jmp_buf process_exit; // Exit state
+ struct atexit *atexit_list; // atexit() chain
+ } x;
+ } u;
+
+ // ELF DT_NEEDED entries for this module
+ int nr_needed;
+ Elf_Word needed[MAX_NR_DEPS];
+};
+
+/**
+ * struct module_dep - structure encapsulating a module dependency need
+ *
+ * This structure represents an item in a double linked list of predecessors or
+ * successors. The item contents is a pointer to the corresponding module descriptor.
+ */
+struct module_dep {
+ struct list_head list; // The list entry in the dependency list
+
+ struct elf_module *module; // The target module descriptor
+};
+
+
+
+#ifdef DYNAMIC_MODULE
+
+/*
+ * This portion is included by dynamic (ELF) module source files.
+ */
+
+#define MODULE_INIT(fn) static module_init_t __module_init \
+ __used __attribute__((section(".ctors_modinit"))) = fn
+
+#define MODULE_EXIT(fn) static module_exit_t __module_exit \
+ __used __attribute__((section(".dtors_modexit"))) = fn
+
+#else
+
+/*
+ * This portion is included by the core COM32 module.
+ */
+
+/**
+ * Names of symbols with special meaning (treated as special cases at linking)
+ */
+#define MODULE_ELF_INIT_PTR "__module_init_ptr" // Initialization pointer symbol name
+#define MODULE_ELF_EXIT_PTR "__module_exit_ptr" // Finalization pointer symbol name
+#define MODULE_ELF_MAIN_PTR "__module_main_ptr" // Entry pointer symbol name
+
+/**
+ * modules_head - A global linked list containing all the loaded modules.
+ */
+extern struct list_head modules_head;
+
+
+/**
+ * for_each_module - iterator loop through the list of loaded modules.
+ */
+#define for_each_module(m) list_for_each_entry(m, &modules_head, list)
+
+/**
+ * for_each_module - iterator loop through the list of loaded modules safe against removal.
+ */
+#define for_each_module_safe(m, n) \
+ list_for_each_entry_safe(m, n, &modules_head, list)
+
+/**
+ * modules_init - initialize the module subsystem.
+ *
+ * This function must be called before any module operation is to be performed.
+ */
+extern int modules_init(void);
+
+
+/**
+ * modules_term - releases all resources pertaining to the module subsystem.
+ *
+ * This function should be called after all module operations.
+ */
+extern void modules_term(void);
+
+
+/**
+ * module_alloc - reserves space for a new module descriptor.
+ * @name: the file name of the module to be loaded.
+ *
+ * The function simply allocates a new module descriptor and initializes its fields
+ * in order to be used by subsequent loading operations.
+ */
+extern struct elf_module *module_alloc(const char *name);
+
+
+/**
+ * module_load - loads a regular ELF module into memory.
+ * @module: the module descriptor returned by module_alloc.
+ *
+ * The function reads the module file, checks whether the file has a
+ * valid structure, then loads into memory the code and the data and performs
+ * any symbol relocations. A module dependency is created automatically when the
+ * relocated symbol is defined in a different module.
+ *
+ * The function returns 0 if the operation is completed successfully, and
+ * a non-zero value if an error occurs. Possible errors include invalid module
+ * structure, missing symbol definitions (unsatisfied dependencies) and memory
+ * allocation issues.
+ */
+extern int module_load(struct elf_module *module);
+
+
+/**
+ * module_load_shallow - loads a shallow ELF module into memory.
+ * @module: the module descriptor returned by module_alloc.
+ *
+ * The function reads the module file, checks whether the file has a valid
+ * structure, then loads into memory the module metadata. The metadata currently
+ * contains a symbol table that describes code & data allocated by other means.
+ * Its current use is to describe the root COM32 module to the rest of the
+ * module subsystem.
+ */
+extern int module_load_shallow(struct elf_module *module, Elf_Addr base_addr);
+
+/**
+ * module_unload - unloads the module from the system.
+ * @module: the module descriptor structure.
+ *
+ * The function checks to see whether the module can be safely
+ * removed, then it executes any destructors and releases all the
+ * associated memory. This function can be applied both for standard
+ * modules and for shallow modules.
+ *
+ * A module can be safely removed from the system when no other modules reference
+ * symbols from it.
+ */
+extern int module_unload(struct elf_module *module);
+
+/**
+ * _module_unload - unloads the module without running destructors
+ *
+ * This function is the same as module_unload(), except that the
+ * module's destructors are not executed.
+ */
+extern int _module_unload(struct elf_module *module);
+
+/**
+ * module_unload - unloads the module from the system.
+ * @module: the module descriptor structure.
+ *
+ * This function returns the type of module we're dealing with
+ * either a library module ( LIB_MODULE ), executable module ( EXEC_MODULE ),
+ * or an error ( UNKNOWN_MODULE ). The way it checks teh type is by checking to see
+ * if the module has its main_func set ( in which case it's an executable ). In case
+ * it doesn't it then checks to see if init_func is set ( in which case it's a
+ * library module. If this isn't the case either we don't know what it is so bail out
+ */
+extern int get_module_type(struct elf_module *module);
+
+/**
+ * module_unloadable - checks whether the given module can be unloaded.
+ * @module: the module descriptor structure
+ *
+ * A module can be unloaded from the system when no other modules depend on it,
+ * that is, no symbols are referenced from it.
+ */
+extern int module_unloadable(struct elf_module *module);
+
+/**
+ * module_find - searches for a module by its name.
+ * @name: the name of the module, as it was specified in module_alloc.
+ *
+ * The function returns a pointer to the module descriptor, if found, or
+ * NULL otherwise.
+ */
+extern struct elf_module *module_find(const char *name);
+
+/**
+ * module_find_symbol - searches for a symbol definition in a given module.
+ * @name: the name of the symbol to be found.
+ * @module: the module descriptor structure.
+ *
+ * The function searches the module symbol table for a symbol matching exactly
+ * the name provided. The operation uses the following search algorithms, in this
+ * order:
+ * - If a GNU hash table is present in the module, it is used to find the symbol.
+ * - If the symbol cannot be found with the first method (either the hash table
+ * is not present or the symbol is not found) and if a regular (SysV) hash table
+ * is present, a search is performed on the SysV hash table. If the symbol is not
+ * found, NULL is returned.
+ * - If the second method cannot be applied, a linear search is performed by
+ * inspecting every symbol in the symbol table.
+ *
+ * If the symbol is found, a pointer to its descriptor structure is returned, and
+ * NULL otherwise.
+ */
+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.
+ * @name: the name of the symbol to be found.
+ * @module: an optional (may be NULL) pointer to a module descriptor variable that
+ * will hold the module where the symbol was found.
+ *
+ * The function search for the given symbol name in all the modules currently
+ * loaded in the system, in the reverse module loading order. That is, the most
+ * recently loaded module is searched first, followed by the previous one, until
+ * the first loaded module is reached.
+ *
+ * If no module contains the symbol, NULL is returned, otherwise the return value is
+ * 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 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
+ * to its absolute value in RAM.
+ * @addr: the relative address to convert.
+ * @module: the module whose base address is used for the conversion.
+ *
+ * The function returns a pointer to the absolute memory address.
+ */
+static inline void *module_get_absolute(Elf_Addr addr, struct elf_module *module) {
+ return (void*)(module->base_addr + addr);
+}
+
+/**
+ * syslinux_current - get the current module process
+ */
+extern struct elf_module *__syslinux_current;
+static inline const struct elf_module *syslinux_current(void)
+{
+ return __syslinux_current;
+}
+
+
+#endif // DYNAMIC_MODULE
+
+#endif // MODULE_H_
diff --git a/com32/include/sys/x86_64/module.h b/com32/include/sys/x86_64/module.h
index 032fd549..203a6cd0 100644
--- a/com32/include/sys/x86_64/module.h
+++ b/com32/include/sys/x86_64/module.h
@@ -4,179 +4,10 @@
* Dynamic ELF64 modules definitions and services.
*/
+#ifndef _X86_64_MODULE_H_
+#define _X86_64_MODULE_H_
-#include <stdio.h>
#include <elf.h>
-#include <stdint.h>
-#include <setjmp.h>
-#include <stdbool.h>
-#include <linux/list.h>
-
-/*
- * The maximum length of the module file name (including path), stored
- * in the struct module descriptor.
- */
-#define MODULE_NAME_SIZE 256
-
-/*
- * Some common information about what kind of modules we're dealing with
- */
-#define UNKNOWN_MODULE -1
-#define EXEC_MODULE 0
-#define LIB_MODULE 1
-
-/*
- * Initialization and finalization function signatures
- */
-
-
-/**
- * module_init_t - pointer to a initialization routine
- *
- * The initialization routine is called after all module constructors were invoked.
- * It takes no parameters and returns 0 if the module was initialized successfully,
- * or a non-zero value if errors have occurred.
- */
-typedef int64_t (*module_init_t)(void);
-
-/**
- * module_exit_t - pointer to a finalization routine
- *
- * The finalization routine is called before the module destructors are to be invoked.
- * It simply executes some cleanup code, without error reporting.
- */
-typedef void (*module_exit_t)(void);
-
-/**
- * module_main_t - pointer to an entry routine
- *
- * The entry routine is present only in executable modules, and represents
- * the entry point for the program.
- */
-typedef int64_t (*module_main_t)(int, char**);
-
-
-/**
- * struct elf_module - structure encapsulating a module loaded in memory.
- *
- * Each SYSLINUX ELF module must have an associated struct elf_module descriptor
- * that keeps track of memory allocations, symbol information, and various other
- * resources needed by the module itself or by other modules that depend on it.
- *
- * There are two types of modules:
- * - regular modules, which are actual memory images of a loaded & linked shared
- * object (ELF file). Memory is reserved for the struct elf_module structure itself
- * and for the object loadable sections read from the file.
- * - shallow modules, which are not associated with an ELF shared object, but contain
- * metainformation about a memory region already present and containing the
- * actual code and data. One particular usage of shallow modules is to access
- * symbol information from the root COM32 module loaded by the SYSLINUX core.
- * As their name suggests, memory is reserved only for the elf_module structure
- * itself and optionally for a usually small memory region containing metainformation
- * (symbol information).
- *
- * Module descriptors are related to each other through dependency information. A module
- * can depend on symbols from other modules, and in turn it can provide symbols used
- * by other dependant modules. This relationship can be described as a directed
- * acyclic graph (DAG). The graph is stored using double linked lists of
- * predecessors and successors. There is also a global linked list containing all
- * the modules currently loaded.
- */
-struct atexit;
-struct elf_module {
- char name[MODULE_NAME_SIZE]; // The module name
-
- bool shallow; // Whether the module contains any code
-
- struct list_head required; // Head of the required modules list
- struct list_head dependants; // Head of module dependants list
- struct list_head list; // The list entry in the module list
-
- module_init_t *init_func; // The initialization entry point
- module_exit_t *exit_func; // The module finalization code
- module_main_t main_func; // The main function (for executable modules)
-
-
- void *module_addr; // The module location in the memory
- Elf64_Addr base_addr; // The base address of the module
- Elf64_Word module_size; // The module size in memory
-
- Elf64_Word *hash_table; // The symbol hash table
- Elf64_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
- Elf64_Dyn *dyn_table; // Dynamic loading information table
-
- Elf64_Word strtable_size; // The size of the string table
- Elf64_Word syment_size; // The size of a symbol entry
- Elf64_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
- Elf64_Off _cr_offset; // The current offset in the open file
- } l;
-
- // Process execution data
- struct {
- jmp_buf process_exit; // Exit state
- struct atexit *atexit_list; // atexit() chain
- } x;
- } u;
-
-};
-
-static inline void dump_elf_module(struct elf_module *module)
-{
- /*
- dprintf("module name = %s", module->name);
- printf("base_addr = 0x%p, module_size = %d\n", module->base_addr, module->module_size);
- printf("hash tlb = 0x%p, ghash tbl = 0x%p\n", module->hash_table, module->ghash_table);
- printf("str tbl = 0x%p, size = %d\n", module->str_table, module->strtable_size);
- printf("sym tbl = 0x%p, entry = %d, size = %d\n", module->sym_table, module->syment_size, module->symtable_size);
- printf("init: %p", module->init_func);
- printf("main: %p", module->main_func);
- printf("exit: %p", module->exit_func);
- printf("", module->base_addr);
- printf("", module->base_addr);
- printf("", module->base_addr);
- */
-}
-
-/**
- * struct module_dep - structure encapsulating a module dependency need
- *
- * This structure represents an item in a double linked list of predecessors or
- * successors. The item contents is a pointer to the corresponding module descriptor.
- */
-struct module_dep {
- struct list_head list; // The list entry in the dependency list
-
- struct elf_module *module; // The target module descriptor
-};
-
-
-
-#ifdef DYNAMIC_MODULE
-
-/*
- * This portion is included by dynamic (ELF) module source files.
- */
-
-#define MODULE_INIT(fn) static module_init_t __module_init \
- __used __attribute__((section(".ctors_modinit"))) = fn
-
-#define MODULE_EXIT(fn) static module_exit_t __module_exit \
- __used __attribute__((section(".dtors_modexit"))) = fn
-
-#else
-
-/*
- * This portion is included by the core COM32 module.
- */
/*
* Accepted values for various ELF header parameters found in an ELF dynamic
@@ -189,181 +20,16 @@ struct module_dep {
#define MODULE_ELF_TYPE ET_DYN // Executable type (shared object - .so)
#define MODULE_ELF_MACHINE EM_X86_64 // Target architecture
-/**
- * Names of symbols with special meaning (treated as special cases at linking)
- */
-#define MODULE_ELF_INIT_PTR "__module_init_ptr" // Initialization pointer symbol name
-#define MODULE_ELF_EXIT_PTR "__module_exit_ptr" // Finalization pointer symbol name
-#define MODULE_ELF_MAIN_PTR "__module_main_ptr" // Entry pointer symbol name
-
-/**
- * modules_head - A global linked list containing all the loaded modules.
- */
-extern struct list_head modules_head;
-
-
-/**
- * for_each_module - iterator loop through the list of loaded modules.
- */
-#define for_each_module(m) list_for_each_entry(m, &modules_head, list)
-
-/**
- * modules_init - initialize the module subsystem.
- *
- * This function must be called before any module operation is to be performed.
- */
-extern int modules_init(void);
-
-
-/**
- * modules_term - releases all resources pertaining to the module subsystem.
- *
- * This function should be called after all module operations.
- */
-extern void modules_term(void);
-
-
-/**
- * module_alloc - reserves space for a new module descriptor.
- * @name: the file name of the module to be loaded.
- *
- * The function simply allocates a new module descriptor and initializes its fields
- * in order to be used by subsequent loading operations.
- */
-extern struct elf_module *module_alloc(const char *name);
-
-
-/**
- * module_load - loads a regular ELF module into memory.
- * @module: the module descriptor returned by module_alloc.
- *
- * The function reads the module file, checks whether the file has a
- * valid structure, then loads into memory the code and the data and performs
- * any symbol relocations. A module dependency is created automatically when the
- * relocated symbol is defined in a different module.
- *
- * The function returns 0 if the operation is completed successfully, and
- * a non-zero value if an error occurs. Possible errors include invalid module
- * structure, missing symbol definitions (unsatisfied dependencies) and memory
- * allocation issues.
- */
-extern int module_load(struct elf_module *module);
-
-
-/**
- * module_load_shallow - loads a shallow ELF module into memory.
- * @module: the module descriptor returned by module_alloc.
- *
- * The function reads the module file, checks whether the file has a valid
- * structure, then loads into memory the module metadata. The metadata currently
- * contains a symbol table that describes code & data allocated by other means.
- * Its current use is to describe the root COM32 module to the rest of the
- * module subsystem.
- */
-extern int module_load_shallow(struct elf_module *module, Elf64_Addr base_addr);
-
-/**
- * module_unload - unloads the module from the system.
- * @module: the module descriptor structure.
- *
- * The function checks to see whether the module can be safely removed, then
- * it releases all the associated memory. This function can be applied both
- * for standard modules and for shallow modules.
- *
- * A module can be safely removed from the system when no other modules reference
- * symbols from it.
- */
-extern int module_unload(struct elf_module *module);
-
-/**
- * module_unload - unloads the module from the system.
- * @module: the module descriptor structure.
- *
- * This function returns the type of module we're dealing with
- * either a library module ( LIB_MODULE ), executable module ( EXEC_MODULE ),
- * or an error ( UNKNOWN_MODULE ). The way it checks teh type is by checking to see
- * if the module has its main_func set ( in which case it's an executable ). In case
- * it doesn't it then checks to see if init_func is set ( in which case it's a
- * library module. If this isn't the case either we don't know what it is so bail out
- */
-extern int get_module_type(struct elf_module *module);
-
-/**
- * module_unloadable - checks whether the given module can be unloaded.
- * @module: the module descriptor structure
- *
- * A module can be unloaded from the system when no other modules depend on it,
- * that is, no symbols are referenced from it.
- */
-extern int module_unloadable(struct elf_module *module);
-
-/**
- * module_find - searches for a module by its name.
- * @name: the name of the module, as it was specified in module_alloc.
- *
- * The function returns a pointer to the module descriptor, if found, or
- * NULL otherwise.
- */
-extern struct elf_module *module_find(const char *name);
-
-/**
- * module_find_symbol - searches for a symbol definition in a given module.
- * @name: the name of the symbol to be found.
- * @module: the module descriptor structure.
- *
- * The function searches the module symbol table for a symbol matching exactly
- * the name provided. The operation uses the following search algorithms, in this
- * order:
- * - If a GNU hash table is present in the module, it is used to find the symbol.
- * - If the symbol cannot be found with the first method (either the hash table
- * is not present or the symbol is not found) and if a regular (SysV) hash table
- * is present, a search is performed on the SysV hash table. If the symbol is not
- * found, NULL is returned.
- * - If the second method cannot be applied, a linear search is performed by
- * inspecting every symbol in the symbol table.
- *
- * If the symbol is found, a pointer to its descriptor structure is returned, and
- * NULL otherwise.
- */
-extern Elf64_Sym *module_find_symbol(const char *name, struct elf_module *module);
-
-/**
- * global_find_symbol - searches for a symbol definition in the entire module namespace.
- * @name: the name of the symbol to be found.
- * @module: an optional (may be NULL) pointer to a module descriptor variable that
- * will hold the module where the symbol was found.
- *
- * The function search for the given symbol name in all the modules currently
- * loaded in the system, in the reverse module loading order. That is, the most
- * recently loaded module is searched first, followed by the previous one, until
- * the first loaded module is reached.
- *
- * If no module contains the symbol, NULL is returned, otherwise the return value is
- * 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 Elf64_Sym *global_find_symbol(const char *name, struct elf_module **module);
-
-/**
- * module_get_absolute - converts an memory address relative to a module base address
- * to its absolute value in RAM.
- * @addr: the relative address to convert.
- * @module: the module whose base address is used for the conversion.
- *
- * The function returns a pointer to the absolute memory address.
- */
-static inline void *module_get_absolute(Elf64_Addr addr, struct elf_module *module) {
- return (void*)(module->base_addr + addr);
-}
-
-/**
- * syslinux_current - get the current module process
- */
-extern struct elf_module *__syslinux_current;
-static inline const struct elf_module *syslinux_current(void)
-{
- return __syslinux_current;
-}
+#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 // DYNAMIC_MODULE
+#endif // _X86_64_MODULE_H_
diff --git a/com32/include/syslinux/boot.h b/com32/include/syslinux/boot.h
index 21bea01a..aea32d9c 100644
--- a/com32/include/syslinux/boot.h
+++ b/com32/include/syslinux/boot.h
@@ -40,7 +40,7 @@
int syslinux_run_command(const char *);
__noreturn syslinux_run_default(void);
-void syslinux_local_boot(uint16_t flags);
+void syslinux_local_boot(int16_t flags);
void syslinux_final_cleanup(uint16_t flags);
@@ -48,6 +48,13 @@ void syslinux_chain_bootstrap(uint16_t flags, const void *bootstrap,
uint32_t bootstrap_len, uint32_t edx,
uint32_t esi, uint16_t ds);
+struct image_types {
+ const char *name;
+ uint32_t type;
+};
+
+extern const struct image_types image_boot_types[];
+
#define IMAGE_TYPE_KERNEL 0
#define IMAGE_TYPE_LINUX 1
#define IMAGE_TYPE_BOOT 2
@@ -57,6 +64,9 @@ void syslinux_chain_bootstrap(uint16_t flags, const void *bootstrap,
#define IMAGE_TYPE_COMBOOT 6
#define IMAGE_TYPE_COM32 7
#define IMAGE_TYPE_CONFIG 8
+#define IMAGE_TYPE_LOCALBOOT 9
+
+uint32_t parse_image_type(const char *cmdline);
void syslinux_run_kernel_image(const char *filename, const char *cmdline,
uint32_t ipappend_flags, uint32_t type);
diff --git a/com32/include/syslinux/config.h b/com32/include/syslinux/config.h
index 79a4750e..7bdcdd6b 100644
--- a/com32/include/syslinux/config.h
+++ b/com32/include/syslinux/config.h
@@ -164,10 +164,10 @@ static inline const struct syslinux_serial_console_info
return &__syslinux_serial_console_info;
}
-extern __nocommon const char *__syslinux_config_file;
+extern char ConfigName[];
static inline const char *syslinux_config_file(void)
{
- return __syslinux_config_file;
+ return ConfigName;
}
struct syslinux_ipappend_strings {
@@ -181,4 +181,9 @@ static inline const struct syslinux_ipappend_strings
return &__syslinux_ipappend_strings;
}
+static inline enum syslinux_filesystem syslinux_filesystem(void)
+{
+ return syslinux_derivative_info()->c.filesystem;
+}
+
#endif /* _SYSLINUX_CONFIG_H */
diff --git a/com32/include/syslinux/disk.h b/com32/include/syslinux/disk.h
new file mode 100644
index 00000000..f96ca686
--- /dev/null
+++ b/com32/include/syslinux/disk.h
@@ -0,0 +1,180 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ * Copyright (C) 2010 Shao Miller
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/**
+ * @file syslinux/disk.h
+ *
+ * Deal with disks and partitions
+ */
+
+#ifndef _SYSLINUX_DISK_H
+#define _SYSLINUX_DISK_H
+
+#include <com32.h>
+#include <stdint.h>
+
+#define SECTOR 512u /* bytes/sector */
+
+struct disk_info {
+ int disk;
+ int ebios; /* EBIOS supported on this disk */
+ int cbios; /* CHS geometry is valid */
+ uint32_t bps; /* bytes per sector */
+ uint64_t lbacnt; /* total amount of sectors */
+ uint32_t cyl;
+ uint32_t head;
+ uint32_t spt;
+};
+
+struct disk_ebios_dapa {
+ uint16_t len;
+ uint16_t count;
+ uint16_t off;
+ uint16_t seg;
+ uint64_t lba;
+} __attribute__ ((packed));
+
+struct disk_ebios_eparam {
+ uint16_t len;
+ uint16_t info;
+ uint32_t cyl;
+ uint32_t head;
+ uint32_t spt;
+ uint64_t lbacnt;
+ uint16_t bps; /* bytes per sector */
+ uint32_t edd;
+ uint16_t dpi_sig;
+ uint8_t dpi_len;
+ char reserved1[3];
+ char hostbus[4];
+ char if_type[8];
+ char if_path[8];
+ char dev_path[8];
+ char reserved2;
+ uint8_t checksum;
+} __attribute__ ((packed));
+
+/**
+ * CHS (cylinder, head, sector) value extraction macros.
+ * Taken from WinVBlock. None expand to an lvalue.
+*/
+#define chs_head(chs) chs[0]
+#define chs_sector(chs) (chs[1] & 0x3F)
+#define chs_cyl_high(chs) (((uint16_t)(chs[1] & 0xC0)) << 2)
+#define chs_cyl_low(chs) ((uint16_t)chs[2])
+#define chs_cylinder(chs) (chs_cyl_high(chs) | chs_cyl_low(chs))
+typedef uint8_t disk_chs[3];
+
+/* A DOS partition table entry */
+struct disk_dos_part_entry {
+ uint8_t active_flag; /* 0x80 if "active" */
+ disk_chs start;
+ uint8_t ostype;
+ disk_chs end;
+ uint32_t start_lba;
+ uint32_t length;
+} __attribute__ ((packed));
+
+/* A DOS MBR */
+struct disk_dos_mbr {
+ char code[440];
+ uint32_t disk_sig;
+ char pad[2];
+ struct disk_dos_part_entry table[4];
+ uint16_t sig;
+} __attribute__ ((packed));
+#define disk_mbr_sig_magic 0xAA55
+
+/**
+ * A GPT disk/partition GUID
+ *
+ * Be careful with endianness, you must adjust it yourself
+ * iff you are directly using the fourth data chunk.
+ * There might be a better header for this...
+ */
+struct guid {
+ uint32_t data1;
+ uint16_t data2;
+ uint16_t data3;
+ uint64_t data4;
+} __attribute__ ((packed));
+
+/* A GPT partition */
+struct disk_gpt_part_entry {
+ struct guid type;
+ struct guid uid;
+ uint64_t lba_first;
+ uint64_t lba_last;
+ uint64_t attribs;
+ char name[72];
+} __attribute__ ((packed));
+
+/* A GPT header */
+struct disk_gpt_header {
+ char sig[8];
+ union {
+ struct {
+ uint16_t minor;
+ uint16_t major;
+ } fields __attribute__ ((packed));
+ uint32_t uint32;
+ char raw[4];
+ } rev __attribute__ ((packed));
+ uint32_t hdr_size;
+ uint32_t chksum;
+ char reserved1[4];
+ uint64_t lba_cur;
+ uint64_t lba_alt;
+ uint64_t lba_first_usable;
+ uint64_t lba_last_usable;
+ struct guid disk_guid;
+ uint64_t lba_table;
+ uint32_t part_count;
+ uint32_t part_size;
+ uint32_t table_chksum;
+ char reserved2[1];
+} __attribute__ ((packed));
+static const char disk_gpt_sig_magic[] = "EFI PART";
+
+extern int disk_int13_retry(const com32sys_t * inreg, com32sys_t * outreg);
+extern int disk_get_params(int disk, struct disk_info *const diskinfo);
+extern void *disk_read_sectors(const struct disk_info *const diskinfo,
+ uint64_t lba, uint8_t count);
+extern int disk_write_sectors(const struct disk_info *const diskinfo,
+ uint64_t lba, const void *data, uint8_t count);
+extern int disk_write_verify_sectors(const struct disk_info *const diskinfo,
+ uint64_t lba, const void *buf, uint8_t count);
+extern void disk_dos_part_dump(const struct disk_dos_part_entry *const part);
+extern void guid_to_str(char *buf, const struct guid *const id);
+extern int str_to_guid(const char *buf, struct guid *const id);
+extern void disk_gpt_part_dump(const struct disk_gpt_part_entry *const
+ gpt_part);
+extern void disk_gpt_header_dump(const struct disk_gpt_header *const gpt);
+
+#endif /* _SYSLINUX_DISK_H */
diff --git a/com32/include/syslinux/features.h b/com32/include/syslinux/features.h
index 4bebda49..d25d08d5 100644
--- a/com32/include/syslinux/features.h
+++ b/com32/include/syslinux/features.h
@@ -31,18 +31,16 @@
#define SYSLINUX_FEATURE_LOCAL_BOOT (0*8+0)
#define SYSLINUX_FEATURE_NOOP_IDLE (0*8+1)
-extern struct __syslinux_feature_flags {
- unsigned int len;
- const unsigned char *ptr;
-} __syslinux_feature_flags;
+extern uint8_t feature_flags;
+extern uint8_t feature_flags_len;
static inline int syslinux_has_feature(unsigned int __flag)
{
unsigned int __byte = __flag >> 3;
unsigned int __bit = __flag & 7;
- if (__byte <= __syslinux_feature_flags.len)
- return (__syslinux_feature_flags.ptr[__byte] >> __bit) & 1;
+ if (__byte <= feature_flags_len)
+ return (feature_flags[__byte] >> __bit) & 1;
else
return 0;
}
diff --git a/com32/include/syslinux/firmware.h b/com32/include/syslinux/firmware.h
index 456ba662..05f97630 100644
--- a/com32/include/syslinux/firmware.h
+++ b/com32/include/syslinux/firmware.h
@@ -3,10 +3,12 @@
#include <syslinux/memscan.h>
+struct term_state;
+
struct output_ops {
void (*erase) (int, int, int, int, uint8_t);
void (*write_char) (uint8_t, uint8_t);
- void (*showcursor) (uint16_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);
@@ -16,7 +18,8 @@ struct output_ops {
};
struct input_ops {
- char (*getchar)(void);
+ char (*getchar)(char *);
+ int (*pollchar)(void);
};
struct adv_ops {
@@ -26,6 +29,7 @@ struct adv_ops {
struct disk_private;
struct initramfs;
+struct setup_data;
struct firmware {
void (*init)(void);
@@ -35,11 +39,11 @@ struct firmware {
struct disk *(*disk_init)(void *);
struct output_ops *o_ops;
struct input_ops *i_ops;
- char *(*get_config_file_name)(void);
void (*get_serial_console_info)(uint16_t *, uint16_t *, uint16_t *);
bool (*ipappend_strings)(char **, int *);
struct adv_ops *adv_ops;
- int (*boot_linux)(void *, size_t, struct initramfs *, char *);
+ int (*boot_linux)(void *, size_t, struct initramfs *,
+ struct setup_data *, char *);
};
extern struct firmware *firmware;
diff --git a/com32/include/syslinux/linux.h b/com32/include/syslinux/linux.h
index abc71dc1..a8c6f2f5 100644
--- a/com32/include/syslinux/linux.h
+++ b/com32/include/syslinux/linux.h
@@ -1,6 +1,7 @@
/* ----------------------------------------------------------------------- *
*
* Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2012 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
@@ -52,6 +53,22 @@ struct initramfs {
};
#define INITRAMFS_MAX_ALIGN 4096
+struct setup_data_header {
+ uint64_t next;
+ uint32_t type;
+ uint32_t len;
+} __packed;
+
+struct setup_data {
+ struct setup_data *prev, *next;
+ const void *data;
+ struct setup_data_header hdr;
+};
+
+#define SETUP_NONE 0
+#define SETUP_E820_EXT 1
+#define SETUP_DTB 2
+
struct linux_header {
uint8_t boot_sector_1[0x0020];
uint16_t old_cmd_line_magic;
@@ -134,7 +151,9 @@ struct screen_info {
} __packed;
int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
- struct initramfs *initramfs, char *cmdline);
+ struct initramfs *initramfs,
+ struct setup_data *setup_data,
+ char *cmdline);
/* Initramfs manipulation functions */
@@ -169,4 +188,12 @@ static inline uint32_t initramfs_size(struct initramfs *initramfs)
return size;
}
+/* Setup data manipulation functions */
+
+struct setup_data *setup_data_init(void);
+int setup_data_add(struct setup_data *head, uint32_t type,
+ const void *data, size_t data_len);
+int setup_data_load(struct setup_data *head, uint32_t type,
+ const char *filename);
+
#endif /* _SYSLINUX_LINUX_H */
diff --git a/com32/include/syslinux/movebits.h b/com32/include/syslinux/movebits.h
index 54ee7ff9..8bcdf3ed 100644
--- a/com32/include/syslinux/movebits.h
+++ b/com32/include/syslinux/movebits.h
@@ -83,7 +83,12 @@ int syslinux_memmap_find(struct syslinux_memmap *list,
addr_t * start, addr_t * len, addr_t align);
/* Debugging functions */
-void syslinux_dump_movelist(FILE * file, struct syslinux_movelist *ml);
-void syslinux_dump_memmap(FILE * file, struct syslinux_memmap *memmap);
+#ifdef DEBUG
+void syslinux_dump_movelist(struct syslinux_movelist *ml);
+void syslinux_dump_memmap(struct syslinux_memmap *memmap);
+#else
+#define syslinux_dump_movelist(x) ((void)0)
+#define syslinux_dump_memmap(x) ((void)0)
+#endif
#endif /* _SYSLINUX_MOVEBITS_H */
diff --git a/com32/include/syslinux/pxe_api.h b/com32/include/syslinux/pxe_api.h
index 27166b0b..203ab38f 100644
--- a/com32/include/syslinux/pxe_api.h
+++ b/com32/include/syslinux/pxe_api.h
@@ -568,4 +568,8 @@ typedef struct s_PXENV_UNLOAD_STACK {
#define PXENV_STATUS_LOADER_UNDI_START 0xca
#define PXENV_STATUS_LOADER_BC_START 0xcb
+int __weak pxe_call(int, void *);
+void __weak unload_pxe(uint16_t flags);
+uint32_t __weak dns_resolv(const char *);
+
#endif /* _SYSLINUX_PXE_API_H */
diff --git a/com32/lib/Makefile b/com32/lib/Makefile
index 616a5506..705feb3f 100644
--- a/com32/lib/Makefile
+++ b/com32/lib/Makefile
@@ -47,16 +47,24 @@ LIBPCI_OBJS = \
LIBSYSLINUX_OBJS = \
syslinux/reboot.o syslinux/keyboard.o \
- syslinux/features.o syslinux/config.o \
- syslinux/dsinfo.o syslinux/version.o \
+ syslinux/version.o \
syslinux/pxe_get_cached.o syslinux/pxe_get_nic.o \
syslinux/pxe_dns.o \
- syslinux/video/fontquery.o syslinux/video/forcetext.o \
- syslinux/video/reportmode.o
+ syslinux/video/fontquery.o syslinux/video/reportmode.o
DYNENTRY_OBJS = \
atexit.o onexit.o abort.o
+MINLIBOBJS = \
+ syslinux/ipappend.o \
+ syslinux/dsinfo.o \
+ $(LIBOTHER_OBJS) \
+ $(LIBGCC_OBJS) \
+ $(LIBCONSOLE_OBJS) \
+ $(LIBLOAD_OBJS) \
+ $(LIBZLIB_OBJS)
+# $(LIBVESA_OBJS)
+
DYNLIBOBJS = \
$(LIBZLIB_OBJS) \
$(LIBPNG_OBJS) \
@@ -79,7 +87,7 @@ AUXDIR = $(DATADIR)/syslinux
INCDIR = /usr/include
COM32DIR = $(AUXDIR)/com32
-all: libcom32.c32 libcom32min.a
+all: libcom32.c32 libcom32min.a libcom32core.a
libcom32.c32 : $(LIBOBJS)
rm -f $@
@@ -90,6 +98,11 @@ libcom32min.a : $(MINLIBOBJS)
$(AR) cq $@ $^
$(RANLIB) $@
+libcom32core.a : $(CORELIBOBJS)
+ rm -f $@
+ $(AR) cq $@ $^
+ $(RANLIB) $@
+
tidy dist clean:
rm -f sys/vesa/alphatbl.c
find . \( -name \*.o -o -name \*.a -o -name .\*.d -o -name \*.tmp \) -print0 | \
diff --git a/com32/lib/com32.ld b/com32/lib/com32.ld
index 37ee46cf..008e4ceb 100644
--- a/com32/lib/com32.ld
+++ b/com32/lib/com32.ld
@@ -36,36 +36,23 @@ SECTIONS
.rodata1 : { *(.rodata1) }
__rodata_end = .;
- /* Ensure the __preinit_array_start label is properly aligned. We
- could instead move the label definition inside the section, but
- the linker would then create the section even if it turns out to
- be empty, which isn't pretty. */
+ /*
+ * The difference betwee .ctors/.dtors and .init_array/.fini_array
+ * is the ordering, but we don't use prioritization for libcom32, so
+ * just lump them all together and hope that's okay.
+ */
. = ALIGN(4);
- .preinit_array : {
- PROVIDE (__preinit_array_start = .);
- *(.preinit_array)
- PROVIDE (__preinit_array_end = .);
- }
- .init_array : {
- PROVIDE (__init_array_start = .);
- *(.init_array)
- PROVIDE (__init_array_end = .);
- }
- .fini_array : {
- PROVIDE (__fini_array_start = .);
- *(.fini_array)
- PROVIDE (__fini_array_end = .);
- }
.ctors : {
PROVIDE (__ctors_start = .);
- KEEP (*(SORT(.ctors.*)))
- KEEP (*(.ctors))
+ KEEP (*(SORT(.preinit_array*)))
+ KEEP (*(SORT(.init_array*)))
+ KEEP (*(SORT(.ctors*)))
PROVIDE (__ctors_end = .);
}
.dtors : {
PROVIDE (__dtors_start = .);
- KEEP (*(SORT(.dtors.*)))
- KEEP (*(.dtors))
+ KEEP (*(SORT(.fini_array*)))
+ KEEP (*(SORT(.dtors*)))
PROVIDE (__dtors_end = .);
}
diff --git a/com32/lib/dhcppack.c b/com32/lib/dhcppack.c
new file mode 100644
index 00000000..a08583c4
--- /dev/null
+++ b/com32/lib/dhcppack.c
@@ -0,0 +1,166 @@
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+// #include <arpa/inet.h>
+#include <netinet/in.h>
+
+// #include "dhcp.h"
+#include <dhcp.h>
+
+/*
+ * Pack DHCP options into an option field, without overload support.
+ * On return, len contains the number of active bytes, and the full
+ * field is zero-padded.
+ *
+ * Options which are successfully placed have their length zeroed out.
+ */
+static int dhcp_pack_field_zero(void *field, size_t *len,
+ struct dhcp_option opt[256])
+{
+ int i;
+ size_t xlen, plen;
+ const uint8_t *p;
+ uint8_t *q = field;
+ size_t spc = *len;
+ int err = 0;
+
+ if (!*len)
+ return ENOSPC;
+
+ for (i = 1; i < 255; i++) {
+ if (opt[i].len < 0)
+ continue;
+
+ /* We need to handle the 0 case as well as > 255 */
+ if (opt[i].len <= 255)
+ xlen = opt[i].len + 2;
+ else
+ xlen = opt[i].len + 2*((opt[i].len+254)/255);
+
+ p = opt[i].data;
+
+ if (xlen >= spc) {
+ /* This option doesn't fit... */
+ err++;
+ continue;
+ }
+
+ xlen = opt[i].len;
+ do {
+ *q++ = i;
+ *q++ = plen = xlen > 255 ? 255 : xlen;
+ if (plen)
+ memcpy(q, p, plen);
+ q += plen;
+ p += plen;
+ spc -= plen+2;
+ xlen -= plen;
+ } while (xlen);
+
+ opt[i].len = -1;
+ }
+
+ *q++ = 255; /* End marker */
+ memset(q, 0, spc); /* Zero-pad the rest of the field */
+
+ *len = xlen = q - (uint8_t *)field;
+ return err;
+}
+
+/*
+ * Pack DHCP options into an option field, without overload support.
+ * On return, len contains the number of active bytes, and the full
+ * field is zero-padded.
+ *
+ * Use this to encode encapsulated option fields.
+ */
+int dhcp_pack_field(void *field, size_t *len,
+ struct dhcp_option opt[256])
+{
+ struct dhcp_option ox[256];
+
+ memcpy(ox, opt, sizeof ox);
+ return dhcp_pack_field_zero(field, len, ox);
+}
+
+/*
+ * Pack DHCP options into a packet.
+ * Apply overloading if (and only if) the "file" or "sname" option
+ * doesn't fit in the respective dedicated fields.
+ */
+int dhcp_pack_packet(void *packet, size_t *len,
+ const struct dhcp_option opt[256])
+{
+ struct dhcp_packet *pkt = packet;
+ size_t spc = *len;
+ uint8_t overload;
+ struct dhcp_option ox[256];
+ uint8_t *q;
+ int err;
+
+ if (spc < sizeof(struct dhcp_packet))
+ return ENOSPC; /* Buffer impossibly small */
+
+ pkt->magic = htonl(DHCP_VENDOR_MAGIC);
+
+ memcpy(ox, opt, sizeof ox);
+
+ /* Figure out if we should do overloading or not */
+ overload = 0;
+
+ if (opt[67].len > 128)
+ overload |= 1;
+ else
+ ox[67].len = -1;
+
+ if (opt[66].len > 64)
+ overload |= 2;
+ else
+ ox[66].len = -1;
+
+ /* Kill any passed-in overload option */
+ ox[52].len = -1;
+
+ q = pkt->options;
+ spc -= 240;
+
+ /* Force option 53 (DHCP packet type) first */
+ if (ox[53].len == 1) {
+ *q++ = 53;
+ *q++ = 1;
+ *q++ = *(uint8_t *)ox[53].data;
+ spc -= 3;
+ ox[53].len = -1;
+ }
+
+ /* Follow with the overload option, if applicable */
+ if (overload) {
+ *q++ = 52;
+ *q++ = 1;
+ *q++ = overload;
+ spc -= 3;
+ }
+
+ err = dhcp_pack_field_zero(q, &spc, ox);
+ *len = spc + (q-(uint8_t *)packet);
+
+ if (overload & 1) {
+ spc = 128;
+ err = dhcp_pack_field_zero(pkt->file, &spc, ox);
+ } else {
+ memset(pkt->file, 0, 128);
+ if (opt[67].len > 0)
+ memcpy(pkt->file, opt[67].data, opt[67].len);
+ }
+
+ if (overload & 2) {
+ spc = 64;
+ err = dhcp_pack_field_zero(pkt->sname, &spc, ox);
+ } else {
+ memset(pkt->sname, 0, 64);
+ if (opt[66].len > 0)
+ memcpy(pkt->sname, opt[66].data, opt[66].len);
+ }
+
+ return err;
+}
diff --git a/com32/lib/dhcpunpack.c b/com32/lib/dhcpunpack.c
new file mode 100644
index 00000000..248173a8
--- /dev/null
+++ b/com32/lib/dhcpunpack.c
@@ -0,0 +1,116 @@
+#define _GNU_SOURCE /* For strnlen() */
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+// #include <arpa/inet.h>
+#include <netinet/in.h>
+
+// #include "dhcp.h"
+#include <dhcp.h>
+
+/*
+ * Unpack DHCP options from a field. Assumes opt is pre-initalized
+ * (to all zero in the common case.)
+ */
+int dhcp_unpack_field(const void *field, size_t len,
+ struct dhcp_option opt[256])
+{
+ const uint8_t *p = field;
+ int err = 0;
+
+ while (len > 1) {
+ uint8_t op;
+ size_t xlen;
+
+ op = *p++; len--;
+ if (op == 0)
+ continue;
+ else if (op == 255)
+ break;
+
+ xlen = *p++; len--;
+ if (xlen > len)
+ break;
+ if (opt[op].len < 0)
+ opt[op].len = 0;
+ if (xlen) {
+ opt[op].data = realloc(opt[op].data,
+ opt[op].len + xlen + 1);
+ if (!opt[op].data) {
+ err = ENOMEM;
+ continue;
+ }
+ memcpy((char *)opt[op].data + opt[op].len, p, xlen);
+ opt[op].len += xlen;
+ /* Null-terminate as a courtesy to users */
+ *((char *)opt[op].data + opt[op].len) = 0;
+ p += xlen;
+ len -= xlen;
+ }
+ }
+
+ return err;
+}
+
+/*
+ * Unpack a DHCP packet, with overload support. Do not use this
+ * to unpack an encapsulated option set.
+ */
+int dhcp_unpack_packet(const void *packet, size_t len,
+ struct dhcp_option opt[256])
+{
+ const struct dhcp_packet *pkt = packet;
+ int err;
+ uint8_t overload;
+ int i;
+
+ if (len < 240 || pkt->magic != htonl(DHCP_VENDOR_MAGIC))
+ return EINVAL; /* Bogus packet */
+
+ for (i = 0; i < 256; i++) {
+ opt[i].len = -1; /* Option not present */
+ opt[i].data = NULL;
+ }
+
+ err = dhcp_unpack_field(pkt->options, len-240, opt);
+
+ overload = 0;
+ if (opt[52].len == 1) {
+ overload = *(uint8_t *)opt[52].data;
+ free(opt[52].data);
+ opt[52].len = -1;
+ opt[52].data = NULL;
+ }
+
+ if (overload & 1) {
+ err |= dhcp_unpack_field(pkt->file, 128, opt);
+ } else {
+ opt[67].len = strnlen((const char *)pkt->file, 128);
+ if (opt[67].len) {
+ opt[67].data = malloc(opt[67].len + 1);
+ if (opt[67].data) {
+ memcpy(opt[67].data, pkt->file, opt[67].len);
+ *((char *)opt[67].data + opt[67].len) = 0;
+ } else {
+ err |= ENOMEM;
+ }
+ }
+ }
+
+ if (overload & 2) {
+ err |= dhcp_unpack_field(pkt->sname, 64, opt);
+ } else {
+ opt[66].len = strnlen((const char *)pkt->sname, 64);
+ if (opt[66].len) {
+ opt[66].data = malloc(opt[66].len + 1);
+ if (opt[66].data) {
+ memcpy(opt[66].data, pkt->file, opt[66].len);
+ *((char *)opt[66].data + opt[66].len) = 0;
+ } else {
+ err |= ENOMEM;
+ }
+ }
+ }
+
+ return err;
+}
diff --git a/com32/lib/dprintf.c b/com32/lib/dprintf.c
index 900c0a47..dea77b39 100644
--- a/com32/lib/dprintf.c
+++ b/com32/lib/dprintf.c
@@ -5,9 +5,9 @@
#include <stdio.h>
#include <stdarg.h>
-#undef DEBUG
-#define DEBUG 1
-#include <dprintf.h>
+#ifdef DEBUG_PORT
+
+void vdprintf(const char *, va_list);
void dprintf(const char *format, ...)
{
@@ -17,3 +17,5 @@ void dprintf(const char *format, ...)
vdprintf(format, ap);
va_end(ap);
}
+
+#endif /* DEBUG_PORT */
diff --git a/com32/lib/elf32.ld b/com32/lib/elf32.ld
index 158badbb..ddf6e048 100644
--- a/com32/lib/elf32.ld
+++ b/com32/lib/elf32.ld
@@ -91,13 +91,9 @@ SECTIONS
__ctors_start = .;
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
- LONG(0x00000000)
- __module_init_ptr = .;
KEEP (*(.ctors_modinit))
- LONG(0x00000000)
- __module_main_ptr = .;
KEEP (*(.ctors_modmain))
- LONG(0x00000000)
+ __ctors_end = .;
}
.dtors :
@@ -105,10 +101,8 @@ SECTIONS
__dtors_start = .;
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
- LONG(0x00000000)
- __module_exit_ptr = .;
KEEP (*(.dtors_modexit))
- LONG(0x00000000)
+ __dtors_end = .;
}
.jcr : { KEEP (*(.jcr)) }
diff --git a/com32/lib/getcwd.c b/com32/lib/getcwd.c
index 2939c07c..d5fa9d7d 100644
--- a/com32/lib/getcwd.c
+++ b/com32/lib/getcwd.c
@@ -4,6 +4,7 @@
#include <com32.h>
#include <syslinux/pmapi.h>
+#include <fs.h>
char *getcwd(char *buf, size_t size)
{
diff --git a/com32/lib/lmalloc.c b/com32/lib/lmalloc.c
index 9d532c80..3e69ac1d 100644
--- a/com32/lib/lmalloc.c
+++ b/com32/lib/lmalloc.c
@@ -31,15 +31,6 @@
#include <string.h>
#include <syslinux/pmapi.h>
-void *clmalloc(size_t size)
-{
- void *p;
- p = lmalloc(size);
- if (!p)
- errno = ENOMEM;
- return p;
-}
-
void *lzalloc(size_t size)
{
void *p;
diff --git a/com32/lib/lstrdup.c b/com32/lib/lstrdup.c
index 6747ef3a..d11efe7e 100644
--- a/com32/lib/lstrdup.c
+++ b/com32/lib/lstrdup.c
@@ -9,7 +9,7 @@
char *lstrdup(const char *s)
{
int l = strlen(s) + 1;
- char *d = clmalloc(l);
+ char *d = lmalloc(l);
if (d)
memcpy(d, s, l);
diff --git a/com32/lib/pci/scan.c b/com32/lib/pci/scan.c
index 4e5635f6..fe00fc25 100644
--- a/com32/lib/pci/scan.c
+++ b/com32/lib/pci/scan.c
@@ -41,12 +41,7 @@
#include <stdbool.h>
#include <ctype.h>
#include <syslinux/zio.h>
-
-#ifdef DEBUG
-# define dprintf printf
-#else
-# define dprintf(...) ((void)0)
-#endif
+#include <dprintf.h>
#define MAX_LINE 512
@@ -584,14 +579,14 @@ void free_pci_domain(struct pci_domain *domain)
free(func->dev_info);
free(func);
}
- free(slot);
}
+ free(slot);
}
- free(bus);
}
+ free(bus);
}
- free(domain);
}
+ free(domain);
}
}
diff --git a/com32/lib/syslinux/features.c b/com32/lib/strreplace.c
index c88aef30..d59efe0e 100644
--- a/com32/lib/syslinux/features.c
+++ b/com32/lib/strreplace.c
@@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- *
*
- * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2011 Erwan Velu - All Rights Reserved
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -23,29 +23,36 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
- * ----------------------------------------------------------------------- */
-
-/*
- * syslinux/features.c
- *
- * SYSLINUX feature flag query
+ * -----------------------------------------------------------------------
*/
-#include <klibc/compiler.h>
-#include <syslinux/features.h>
#include <string.h>
-#include <com32.h>
-
-struct __syslinux_feature_flags __syslinux_feature_flags;
+#include <stdlib.h>
-void __constructor __syslinux_detect_features(void)
+char *strreplace(const char *string, const char *string_to_replace,
+ const char *string_to_insert)
{
- static com32sys_t reg;
+ char *token = NULL;
+ char *out = NULL;
+
+ size_t slen, srlen, silen;
+
+ token = strstr(string, string_to_replace);
+ if (!token)
+ return strdup(string);
- memset(&reg, 0, sizeof reg);
- reg.eax.w[0] = 0x0015;
- __intcall(0x22, &reg, &reg);
+ slen = strlen(string);
+ srlen = strlen(string_to_replace);
+ silen = strlen(string_to_insert);
+
+ out = malloc(slen - srlen + silen + 1);
+ if (!out)
+ return NULL;
+
+ memcpy(out, string, token - string);
+ memcpy(out + (token - string), string_to_insert, silen);
+ memcpy(out + (token - string) + silen, token + srlen,
+ slen - srlen - (token - string) + 1);
- __syslinux_feature_flags.len = reg.ecx.w[0];
- __syslinux_feature_flags.ptr = MK_PTR(reg.es, reg.ebx.w[0]);
+ return out;
}
diff --git a/com32/lib/sys/ansicon_write.c b/com32/lib/sys/ansicon_write.c
index a963923d..74add717 100644
--- a/com32/lib/sys/ansicon_write.c
+++ b/com32/lib/sys/ansicon_write.c
@@ -35,7 +35,6 @@
#include <errno.h>
#include <string.h>
-#include <com32.h>
#include <minmax.h>
#include <colortbl.h>
#include <klibc/compiler.h>
@@ -43,6 +42,7 @@
#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);
static void ansicon_write_char(int, int, uint8_t, const struct term_state *);
@@ -66,53 +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 */
-
-void bios_set_mode(uint16_t mode)
-{
- com32sys_t ireg;
-
- ireg.eax.w[0] = mode;
- __intcall(0x22, &ireg, NULL);
-}
-
-void bios_get_mode(int *cols, int *rows)
-{
- *rows = BIOS_ROWS ? BIOS_ROWS + 1 : 25;
- *cols = BIOS_COLS;
-}
-
-void bios_get_cursor(int *x, int *y)
-{
- com32sys_t ireg, oreg;
-
- memset(&ireg, 0, sizeof(ireg));
-
- ireg.eax.b[1] = 0x03;
- ireg.ebx.b[1] = BIOS_PAGE;
- __intcall(0x10, &ireg, &oreg);
- cursor_type = oreg.ecx.w[0];
- *x = oreg.edx.b[0];
- *y = oreg.edx.b[1];
-}
-
/* 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) {
@@ -175,19 +137,6 @@ static uint8_t ansicon_attribute(const struct term_state *st)
return (bg << 4) | fg;
}
-void bios_erase(int x0, int y0, int x1, int y1, uint8_t attribute)
-{
- static com32sys_t ireg;
-
- ireg.eax.w[0] = 0x0600; /* Clear window */
- ireg.ebx.b[1] = attribute;
- ireg.ecx.b[0] = x0;
- ireg.ecx.b[1] = y0;
- ireg.edx.b[0] = x1;
- ireg.edx.b[1] = y1;
- __intcall(0x10, &ireg, NULL);
-}
-
/* Erase a region of the screen */
static void ansicon_erase(const struct term_state *st,
int x0, int y0, int x1, int y1)
@@ -198,37 +147,10 @@ static void ansicon_erase(const struct term_state *st,
firmware->o_ops->erase(x0, y0, x1, y1, attribute);
}
-void bios_showcursor(uint16_t cursor)
-{
- static com32sys_t ireg;
-
- ireg.eax.b[1] = 0x01;
- ireg.ecx.w[0] = cursor;
- __intcall(0x10, &ireg, NULL);
-}
-
/* Show or hide the cursor */
static void ansicon_showcursor(const struct term_state *st)
{
- uint16_t cursor = st->cursor ? cursor_type : 0x2020;
- firmware->o_ops->showcursor(cursor);
-}
-
-void bios_set_cursor(int x, int y, bool visible)
-{
- const int page = BIOS_PAGE;
- struct curxy xy = BIOS_CURXY[page];
- static com32sys_t ireg;
-
- (void)visible;
-
- if (xy.x != x || xy.y != y) {
- ireg.eax.b[1] = 0x02;
- ireg.ebx.b[1] = page;
- ireg.edx.b[1] = y;
- ireg.edx.b[0] = x;
- __intcall(0x10, &ireg, NULL);
- }
+ firmware->o_ops->showcursor(st);
}
static void ansicon_set_cursor(int x, int y, bool visible)
@@ -236,18 +158,6 @@ static void ansicon_set_cursor(int x, int y, bool visible)
firmware->o_ops->set_cursor(x, y, visible);
}
-void bios_write_char(uint8_t ch, uint8_t attribute)
-{
- static com32sys_t ireg;
-
- ireg.eax.b[1] = 0x09;
- ireg.eax.b[0] = ch;
- ireg.ebx.b[1] = BIOS_PAGE;
- ireg.ebx.b[0] = attribute;
- ireg.ecx.w[0] = 1;
- __intcall(0x10, &ireg, NULL);
-}
-
static void ansicon_write_char(int x, int y, uint8_t ch,
const struct term_state *st)
{
@@ -257,18 +167,6 @@ static void ansicon_write_char(int x, int y, uint8_t ch,
firmware->o_ops->write_char(ch, attribute);
}
-void bios_scroll_up(uint8_t cols, uint8_t rows, uint8_t attribute)
-{
- static com32sys_t ireg;
-
- ireg.eax.w[0] = 0x0601;
- ireg.ebx.b[1] = attribute;
- ireg.ecx.w[0] = 0;
- ireg.edx.b[1] = rows;
- ireg.edx.b[0] = cols;
- __intcall(0x10, &ireg, NULL); /* Scroll */
-}
-
static void ansicon_scroll_up(const struct term_state *st)
{
uint8_t rows, cols, attribute;
@@ -302,15 +200,6 @@ ssize_t __ansicon_write(struct file_info *fp, const void *buf, size_t count)
return n;
}
-void bios_beep(void)
-{
- static com32sys_t ireg;
-
- ireg.eax.w[0] = 0x0e07;
- ireg.ebx.b[1] = BIOS_PAGE;
- __intcall(0x10, &ireg, NULL);
-}
-
void __ansicon_beep(void)
{
if (firmware->o_ops->beep)
diff --git a/com32/lib/sys/fileclose.c b/com32/lib/sys/fileclose.c
index 26e15082..699dbe32 100644
--- a/com32/lib/sys/fileclose.c
+++ b/com32/lib/sys/fileclose.c
@@ -34,6 +34,7 @@
#include <errno.h>
#include <com32.h>
#include <string.h>
+#include <fs.h>
#include "file.h"
int __file_close(struct file_info *fp)
diff --git a/com32/lib/sys/fileread.c b/com32/lib/sys/fileread.c
index 7d9e1b91..26b0ceb6 100644
--- a/com32/lib/sys/fileread.c
+++ b/com32/lib/sys/fileread.c
@@ -34,6 +34,7 @@
#include <errno.h>
#include <string.h>
#include <com32.h>
+#include <pmapi.h>
#include <syslinux/pmapi.h>
#include <minmax.h>
#include "file.h"
diff --git a/com32/lib/sys/gpxe.c b/com32/lib/sys/gpxe.c
index d86da42a..3cc2b845 100644
--- a/com32/lib/sys/gpxe.c
+++ b/com32/lib/sys/gpxe.c
@@ -1,13 +1,15 @@
+#include <string.h>
+
#include <sys/gpxe.h>
#include <syslinux/config.h>
-#include <string.h>
+#include <syslinux/pxe_api.h>
bool is_gpxe(void)
{
const struct syslinux_version *sv;
- com32sys_t reg;
struct s_PXENV_FILE_CHECK_API *fca;
bool gpxe;
+ int err;
sv = syslinux_version();
if (sv->filesystem != SYSLINUX_FS_PXELINUX)
@@ -16,23 +18,18 @@ bool is_gpxe(void)
fca = lzalloc(sizeof *fca);
if (!fca)
return false;
+
fca->Size = sizeof *fca;
fca->Magic = 0x91d447b2;
- memset(&reg, 0, sizeof reg);
- reg.eax.w[0] = 0x0009;
- reg.ebx.w[0] = 0x00e6; /* PXENV_FILE_API_CHECK */
- /* reg.edi.w[0] = OFFS(fca); */
- reg.es = SEG(fca);
-
- __intcall(0x22, &reg, &reg);
+ err = pxe_call(PXENV_FILE_API_CHECK, fca);
gpxe = true;
- if (reg.eflags.l & EFLAGS_CF)
+ if (err)
gpxe = false; /* Cannot invoke PXE stack */
- if (reg.eax.w[0] || fca->Status)
+ if (fca->Status)
gpxe = false; /* PXE failure */
if (fca->Magic != 0xe9c17b20)
diff --git a/com32/lib/sys/module/common.c b/com32/lib/sys/module/common.c
index 1e33db8e..bc058a66 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; 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);
@@ -64,6 +64,10 @@ static FILE *findpath(char *name)
char *p, *n;
int i;
+ f = fopen(name, "rb"); /* for full path */
+ if (f)
+ return f;
+
p = PATH;
again:
i = 0;
@@ -74,15 +78,6 @@ again:
if (*p == ':')
p++;
- if (!strcmp(path, ".")) {
- if (!core_getcwd(path, sizeof(path))) {
- DBG_PRINT("Could not get cwd\n");
- return NULL;
- }
-
- i = strlen(path);
- }
-
n = name;
while (*n && i < FILENAME_MAX)
path[i++] = *n++;
@@ -164,7 +159,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;
@@ -226,7 +221,7 @@ struct elf_module *module_find(const char *name) {
//
// 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 ||
@@ -237,7 +232,7 @@ int check_header_common(Elf32_Ehdr *elf_hdr) {
return -1;
}
- if (elf_hdr->e_ident[EI_CLASS] != ELFCLASS32 ||
+ if (elf_hdr->e_ident[EI_CLASS] != ELFCLASS32 &&
elf_hdr->e_ident[EI_CLASS] != ELFCLASS64) {
DBG_PRINT("Invalid ELF class code\n");
return -1;
@@ -254,15 +249,17 @@ int check_header_common(Elf32_Ehdr *elf_hdr) {
return -1;
}
- if (elf_hdr->e_machine != EM_386 ||
+ if (elf_hdr->e_machine != EM_386 &&
elf_hdr->e_machine != EM_X86_64) {
DBG_PRINT("Invalid ELF architecture\n");
return -1;
+ }
return 0;
}
+
int enforce_dependency(struct elf_module *req, struct elf_module *dep) {
struct module_dep *crt_dep;
struct module_dep *new_dep;
@@ -319,7 +316,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;
@@ -328,11 +325,11 @@ int check_symbols(struct elf_module *module)
for(i = 1; i < module->symtable_size; i++)
{
- crt_sym = (Elf32_Sym*)(module->sym_table + i * module->syment_size);
+ crt_sym = symbol_get_entry(module, i);
crt_name = module->str_table + crt_sym->st_name;
strong_count = 0;
- weak_count = 0;
+ weak_count = (ELF32_ST_BIND(crt_sym->st_info) == STB_WEAK);
for_each_module(crt_module)
{
@@ -356,10 +353,17 @@ int check_symbols(struct elf_module *module)
if (crt_sym->st_shndx == SHN_UNDEF)
{
// We have an undefined symbol
+ //
+ // We use the weak_count to differentiate
+ // between Syslinux-derivative-specific
+ // functions. For example, unload_pxe() is
+ // only provided by PXELINUX, so we mark it as
+ // __weak and replace it with a reference to
+ // undefined_symbol() on SYSLINUX, EXTLINUX,
+ // and ISOLINUX. See perform_relocations().
if (strong_count == 0 && weak_count == 0)
{
DBG_PRINT("Symbol %s is undefined\n", crt_name);
- printf("Undef symbol FAIL: %s\n",crt_name);
return -1;
}
}
@@ -387,7 +391,7 @@ int module_unloadable(struct elf_module *module) {
// Unloads the module from the system and releases all the associated memory
-int module_unload(struct elf_module *module) {
+int _module_unload(struct elf_module *module) {
struct module_dep *crt_dep, *tmp;
// Make sure nobody needs us
if (!module_unloadable(module)) {
@@ -416,23 +420,31 @@ int module_unload(struct elf_module *module) {
return 0;
}
+int module_unload(struct elf_module *module) {
+ module_ctor_t *dtor;
+
+ for (dtor = module->dtors; *dtor; dtor++)
+ (*dtor) ();
+
+ return _module_unload(module);
+}
-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) {
- crt_sym = (Elf32_Sym*)(module->sym_table + crt_index*module->syment_size);
+ crt_sym = symbol_get_entry(module, crt_index);
if (strcmp(name, module->str_table + crt_sym->st_name) == 0)
return crt_sym;
@@ -443,32 +455,32 @@ static Elf32_Sym *module_find_symbol_sysv(const char *name, struct elf_module *m
return NULL;
}
-static Elf32_Sym *module_find_symbol_gnu(const char *name, struct elf_module *module) {
+static Elf_Sym *module_find_symbol_gnu(const char *name, struct elf_module *module) {
unsigned long h = elf_gnu_hash((const unsigned char*)name);
// Setup code (TODO: Optimize this by computing only once)
- Elf32_Word *cr_word = module->ghash_table;
- Elf32_Word nbucket = *cr_word++;
- Elf32_Word symbias = *cr_word++;
- Elf32_Word bitmask_nwords = *cr_word++;
+ Elf_Word *cr_word = module->ghash_table;
+ Elf_Word nbucket = *cr_word++;
+ Elf_Word symbias = *cr_word++;
+ Elf_Word bitmask_nwords = *cr_word++;
if ((bitmask_nwords & (bitmask_nwords - 1)) != 0) {
DBG_PRINT("Invalid GNU Hash structure\n");
return NULL;
}
- Elf32_Word gnu_shift = *cr_word++;
+ Elf_Word gnu_shift = *cr_word++;
- Elf32_Addr *gnu_bitmask = (Elf32_Addr*)cr_word;
+ Elf_Addr *gnu_bitmask = (Elf_Addr*)cr_word;
cr_word += MODULE_ELF_CLASS_SIZE / 32 * bitmask_nwords;
- Elf32_Word *gnu_buckets = cr_word;
+ Elf_Word *gnu_buckets = cr_word;
cr_word += nbucket;
- Elf32_Word *gnu_chain_zero = cr_word - symbias;
+ Elf_Word *gnu_chain_zero = cr_word - symbias;
// Computations
- Elf32_Word bitmask_word = gnu_bitmask[(h / MODULE_ELF_CLASS_SIZE) &
+ Elf_Bword bitmask_word = gnu_bitmask[(h / MODULE_ELF_CLASS_SIZE) &
(bitmask_nwords - 1)];
unsigned int hashbit1 = h & (MODULE_ELF_CLASS_SIZE - 1);
@@ -476,19 +488,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 = (Elf32_Sym*)(module->sym_table +
- (hasharr - gnu_chain_zero) * module->syment_size);
+ 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;
@@ -501,15 +512,15 @@ 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; i++)
{
- crt_sym = (Elf32_Sym*)(module->sym_table + i*module->syment_size);
+ crt_sym = symbol_get_entry(module, i);
if (strcmp(name, module->str_table + crt_sym->st_name) == 0)
{
return crt_sym;
@@ -519,8 +530,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);
@@ -542,10 +553,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 928fe139..652c9735 100644
--- a/com32/lib/sys/module/common.h
+++ b/com32/lib/sys/module/common.h
@@ -26,6 +26,14 @@
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
#define MAX(x,y) (((x) > (y)) ? (x) : (y))
+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 (Elf_Sym *)(sym_table + index);
+}
+
//#define ELF_DEBUG
#ifdef ELF_DEBUG
@@ -36,7 +44,7 @@
// User-space debugging routines
#ifdef ELF_DEBUG
-extern void print_elf_ehdr(Elf32_Ehdr *ehdr);
+extern void print_elf_ehdr(Elf_Ehdr *ehdr);
extern void print_elf_symbols(struct elf_module *module);
#endif //ELF_DEBUG
@@ -49,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 7d8dad42..b220e1ad 100644
--- a/com32/lib/sys/module/elf_module.c
+++ b/com32/lib/sys/module/elf_module.c
@@ -5,21 +5,21 @@
* 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"
-#define MAX_NR_DEPS 64
-
static int check_header(Elf32_Ehdr *elf_hdr) {
int res;
@@ -50,7 +50,7 @@ static int check_header(Elf32_Ehdr *elf_hdr) {
static int load_segments(struct elf_module *module, Elf32_Ehdr *elf_hdr) {
int i;
int res = 0;
- void *pht = NULL;
+ char *pht = NULL;
Elf32_Phdr *cr_pht;
Elf32_Addr min_addr = 0x00000000; // Min. ELF vaddr
@@ -136,8 +136,8 @@ static int load_segments(struct elf_module *module, Elf32_Ehdr *elf_hdr) {
// headers
Elf32_Off aux_off = module->u.l._cr_offset - cr_pht->p_offset;
- if (image_read(module_get_absolute(cr_pht->p_vaddr, module) + aux_off,
- cr_pht->p_filesz - aux_off, module) < 0) {
+ 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;
}
@@ -180,9 +180,6 @@ out:
return res;
}
-static int nr_needed;
-static Elf32_Word needed[MAX_NR_DEPS];;
-
static int prepare_dynlinking(struct elf_module *module) {
Elf32_Dyn *dyn_entry = module->dyn_table;
@@ -195,8 +192,8 @@ static int prepare_dynlinking(struct elf_module *module) {
* are then inform the user that we ran out of
* space.
*/
- if (nr_needed < MAX_NR_DEPS)
- needed[nr_needed++] = dyn_entry->d_un.d_ptr;
+ if (module->nr_needed < MAX_NR_DEPS)
+ module->needed[module->nr_needed++] = dyn_entry->d_un.d_ptr;
else {
printf("Too many dependencies!\n");
return -1;
@@ -242,6 +239,11 @@ static int prepare_dynlinking(struct elf_module *module) {
return 0;
}
+void undefined_symbol(void)
+{
+ printf("Error: An undefined symbol was referenced\n");
+ kaboom();
+}
static int perform_relocation(struct elf_module *module, Elf32_Rel *rel) {
Elf32_Word *dest = module_get_absolute(rel->r_offset, module);
@@ -259,8 +261,7 @@ static int perform_relocation(struct elf_module *module, Elf32_Rel *rel) {
// Find out details about the symbol
// The symbol reference
- Elf32_Sym *sym_ref =
- (Elf32_Sym*)(module->sym_table + sym * module->syment_size);
+ Elf32_Sym *sym_ref = symbol_get_entry(module, sym);
// The symbol definition
sym_def =
@@ -268,11 +269,16 @@ static int perform_relocation(struct elf_module *module, Elf32_Rel *rel) {
&sym_module);
if (sym_def == NULL) {
- // This should never happen
DBG_PRINT("Cannot perform relocation for symbol %s\n",
module->str_table + sym_ref->st_name);
- return -1;
+ if (ELF32_ST_BIND(sym_ref->st_info) != STB_WEAK)
+ return -1;
+
+ // This must be a derivative-specific
+ // function. We're OK as long as we never
+ // execute the function.
+ sym_def = global_find_symbol("undefined_symbol", &sym_module);
}
// Compute the absolute symbol virtual address
@@ -321,9 +327,9 @@ static int resolve_symbols(struct elf_module *module) {
int res;
Elf32_Word plt_rel_size = 0;
- void *plt_rel = NULL;
+ char *plt_rel = NULL;
- void *rel = NULL;
+ char *rel = NULL;
Elf32_Word rel_size = 0;
Elf32_Word rel_entry = 0;
@@ -398,32 +404,70 @@ static int resolve_symbols(struct elf_module *module) {
return 0;
}
+static int extract_operations(struct elf_module *module) {
+ Elf32_Sym *ctors_start, *ctors_end;
+ Elf32_Sym *dtors_start, *dtors_end;
+ module_ctor_t *ctors = NULL;
+ module_ctor_t *dtors = NULL;
+ ctors_start = module_find_symbol("__ctors_start", module);
+ ctors_end = module_find_symbol("__ctors_end", module);
-static int extract_operations(struct elf_module *module) {
- Elf32_Sym *init_sym = module_find_symbol(MODULE_ELF_INIT_PTR, module);
- Elf32_Sym *exit_sym = module_find_symbol(MODULE_ELF_EXIT_PTR, module);
- Elf32_Sym *main_sym = module_find_symbol("main", module);
-
- if (init_sym) {
- module->init_func = (module_init_t*)module_get_absolute(
- init_sym->st_value, module);
- if (*(module->init_func) == NULL) {
- module->init_func = NULL;
+ if (ctors_start && ctors_end) {
+ module_ctor_t *start, *end;
+ int nr_ctors = 0;
+ int i, size;
+
+ start = module_get_absolute(ctors_start->st_value, module);
+ end = module_get_absolute(ctors_end->st_value, module);
+
+ nr_ctors = end - start;
+
+ size = nr_ctors * sizeof(module_ctor_t);
+ size += sizeof(module_ctor_t); /* NULL entry */
+
+ ctors = malloc(size);
+ if (!ctors) {
+ printf("Unable to alloc memory for ctors\n");
+ return -1;
}
+
+ memset(ctors, 0, size);
+ for (i = 0; i < nr_ctors; i++)
+ ctors[i] = start[i];
+
+ module->ctors = ctors;
}
- if (exit_sym) {
- module->exit_func = (module_exit_t*)module_get_absolute(
- exit_sym->st_value, module);
- if (*(module->exit_func) == NULL) {
- module->exit_func = NULL;
+ dtors_start = module_find_symbol("__dtors_start", module);
+ dtors_end = module_find_symbol("__dtors_end", module);
+
+ if (dtors_start && dtors_end) {
+ module_ctor_t *start, *end;
+ int nr_dtors = 0;
+ int i, size;
+
+ start = module_get_absolute(dtors_start->st_value, module);
+ end = module_get_absolute(dtors_end->st_value, module);
+
+ nr_dtors = end - start;
+
+ size = nr_dtors * sizeof(module_ctor_t);
+ size += sizeof(module_ctor_t); /* NULL entry */
+
+ dtors = malloc(size);
+ if (!dtors) {
+ printf("Unable to alloc memory for dtors\n");
+ free(ctors);
+ return -1;
}
- }
- if (main_sym)
- module->main_func =
- module_get_absolute(main_sym->st_value, module);
+ memset(dtors, 0, size);
+ for (i = 0; i < nr_dtors; i++)
+ dtors[i] = start[i];
+
+ module->dtors = dtors;
+ }
return 0;
}
@@ -431,12 +475,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;
+ module_ctor_t *ctor;
// Do not allow duplicate modules
if (module_find(module->name) != NULL) {
DBG_PRINT("Module %s is already loaded.\n", module->name);
- return -1;
+ return EEXIST;
}
// Get a mapping/copy of the ELF file in memory
@@ -462,42 +508,35 @@ int module_load(struct elf_module *module) {
CHECKED(res, load_segments(module, &elf_hdr), error);
//printf("bleah... 3\n");
// Obtain dynamic linking information
- nr_needed = 0;
CHECKED(res, prepare_dynlinking(module), error);
//printf("check... 4\n");
- //
- //dump_elf_module(module);
/* Find modules we need to load as dependencies */
if (module->str_table) {
- int i, n;
+ int i;
/*
- * nr_needed can be modified by recursive calls to
- * module_load() so keep a local copy on the stack.
+ * Note that we have to load the dependencies in
+ * reverse order.
*/
- n = nr_needed;
- for (i = 0; i < n; i++) {
- size_t len, j;
+ for (i = module->nr_needed - 1; i >= 0; i--) {
char *dep, *p;
+ char *argv[2] = { NULL, NULL };
- dep = module->str_table + needed[i];
+ dep = module->str_table + module->needed[i];
/* strip everything but the last component */
- j = len = strlen(dep);
- if (!len)
+ if (!strlen(dep))
continue;
- p = dep + len - 1;
- while (j > 0 && *p && *p != '/') {
- p--;
- j--;
- }
+ if (strchr(dep, '/')) {
+ p = strrchr(dep, '/');
+ p++;
+ } else
+ p = dep;
- if (*p++ == '/') {
- char argv[2] = { p, NULL };
- spawn_load(p, 1, argv);
- }
+ argv[0] = p;
+ spawn_load(p, 1, argv);
}
}
@@ -505,8 +544,11 @@ int module_load(struct elf_module *module) {
CHECKED(res, check_symbols(module), error);
//printf("check... 5\n");
- // Obtain constructors and destructors
- CHECKED(res, extract_operations(module), error);
+ main_sym = module_find_symbol("main", module);
+ if (main_sym)
+ module->main_func =
+ module_get_absolute(main_sym->st_value, module);
+
//printf("check... 6\n");
// Add the module at the beginning of the module list
@@ -515,6 +557,9 @@ int module_load(struct elf_module *module) {
// Perform the relocations
resolve_symbols(module);
+ // Obtain constructors and destructors
+ CHECKED(res, extract_operations(module), error);
+
//dprintf("module->symtable_size = %d\n", module->symtable_size);
//print_elf_symbols(module);
@@ -529,6 +574,10 @@ int module_load(struct elf_module *module) {
(module->init_func == NULL) ? NULL : *(module->init_func),
(module->exit_func == NULL) ? NULL : *(module->exit_func));
*/
+
+ for (ctor = module->ctors; *ctor; ctor++)
+ (*ctor) ();
+
return 0;
error:
diff --git a/com32/lib/sys/module/elfutils.c b/com32/lib/sys/module/elfutils.c
index 64be0770..b7d760b4 100644
--- a/com32/lib/sys/module/elfutils.c
+++ b/com32/lib/sys/module/elfutils.c
@@ -37,7 +37,7 @@ struct memalign_info {
};
int elf_malloc(void **memptr, size_t alignment, size_t size) {
- void *start_addr = NULL;
+ char *start_addr = NULL;
struct memalign_info *info;
if ((alignment & (alignment - 1)) != 0)
@@ -63,7 +63,7 @@ int elf_malloc(void **memptr, size_t alignment, size_t size) {
return 0;
}
-void elf_free(void *memptr) {
+void elf_free(char *memptr) {
struct memalign_info *info = (struct memalign_info*)(memptr -
sizeof(struct memalign_info));
diff --git a/com32/lib/sys/module/elfutils.h b/com32/lib/sys/module/elfutils.h
index b6750ae7..91bdcb3f 100644
--- a/com32/lib/sys/module/elfutils.h
+++ b/com32/lib/sys/module/elfutils.h
@@ -1,7 +1,65 @@
-#if __SIZEOF_POINTER__ == 4
-#include <i386/elfutils.h>
-#elif __SIZEOF_POINTER__ == 8
-#include <x86_64/elfutils.h>
-#else
-#error "unsupported architecture"
-#endif
+#ifndef ELF_UTILS_H_
+#define ELF_UTILS_H_
+
+#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 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 Elf_Phdr *elf_get_pht(void *elf_image) {
+ Elf_Ehdr *elf_hdr = elf_get_header(elf_image);
+
+ return (Elf_Phdr*)((Elf_Off)elf_hdr + elf_hdr->e_phoff);
+}
+
+//
+/**
+ * elf_get_ph - Returns the element with the given index in the PTH
+ * @elf_image: pointer to the ELF file image in memory
+ * @index: the index of the PHT entry to look for
+ */
+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 (Elf_Phdr*)((Elf_Off)elf_pht + index * elf_hdr->e_phentsize);
+}
+
+/**
+ * elf_hash - Returns the index in a SysV hash table for the symbol name.
+ * @name: the name of the symbol to look for
+ */
+extern unsigned long elf_hash(const unsigned char *name);
+
+/**
+ * elf_gnu_hash - Returns the index in a GNU hash table for the symbol name.
+ * @name: the name of the symbol to look for
+ */
+extern unsigned long elf_gnu_hash(const unsigned char *name);
+
+/**
+ * elf_malloc - Allocates memory to be used by ELF module contents.
+ * @memptr: pointer to a variable to hold the address of the allocated block.
+ * @alignment: alignment constraints of the block
+ * @size: the required size of the block
+ */
+extern int elf_malloc(void **memptr, size_t alignment, size_t size);
+
+/**
+ * elf_free - Releases memory previously allocated by elf_malloc.
+ * @memptr: the address of the allocated block
+ */
+extern void elf_free(char *memptr);
+
+#endif /*ELF_UTILS_H_*/
diff --git a/com32/lib/sys/module/exec.c b/com32/lib/sys/module/exec.c
index 71d31929..29d0a2fd 100644
--- a/com32/lib/sys/module/exec.c
+++ b/com32/lib/sys/module/exec.c
@@ -47,64 +47,7 @@ int exec_init(void)
int get_module_type(struct elf_module *module)
{
if(module->main_func) return EXEC_MODULE;
- else if(module->init_func) return LIB_MODULE;
- return UNKNOWN_MODULE;
-}
-
-int load_library(const char *name)
-{
- int res;
- struct elf_module *module = module_alloc(name);
-
- if (module == NULL)
- return -1;
-
- res = module_load(module);
- if (res != 0) {
- module_unload(module);
- return res;
- }
-
- if (module->main_func != NULL) {
- DBG_PRINT("Cannot load executable module as library.\n");
- module_unload(module);
- return -1;
- }
-
- if (module->init_func != NULL) {
- res = (*(module->init_func))();
- if (res)
- DBG_PRINT("Initialization error! function returned: %d\n", res);
- } else {
- DBG_PRINT("No initialization function present.\n");
- }
-
- if (res != 0) {
- module_unload(module);
- return res;
- }
-
- return 0;
-}
-
-int unload_library(const char *name)
-{
- int res;
- struct elf_module *module = module_find(name);
-
- if (module == NULL)
- return -1;
-
- if (!module_unloadable(module)) {
- return -1;
- }
-
- if (module->exit_func != NULL) {
- (*(module->exit_func))();
- }
-
- res = module_unload(module);
- return res;
+ return LIB_MODULE;
}
jmp_buf __process_exit_jmp;
@@ -243,7 +186,6 @@ int spawn_load(const char *name, int argc, char **argv)
//malloc_tag_t prev_mem_tag;
struct elf_module *module = module_alloc(name);
struct elf_module *prev_module;
-
int type;
dprintf("enter: name = %s", name);
@@ -277,7 +219,7 @@ int spawn_load(const char *name, int argc, char **argv)
res = module_load(module);
if (res != 0) {
- module_unload(module);
+ _module_unload(module);
return res;
}
@@ -288,23 +230,7 @@ int spawn_load(const char *name, int argc, char **argv)
dprintf("type = %d, prev = %s, cur = %s",
type, prev_module->name, cur_module->name);
- if(type==LIB_MODULE)
- {
- if (module->init_func != NULL) {
- res = (*(module->init_func))();
- DBG_PRINT("Initialization function returned: %d\n", res);
- } else {
- DBG_PRINT("No initialization function present.\n");
- }
-
- if (res != 0) {
- cur_module = prev_module;
- module_unload(module);
- return res;
- }
- return 0;
- }
- else if(type==EXEC_MODULE)
+ if(type==EXEC_MODULE)
{
previous = __syslinux_current;
//prev_mem_tag = __mem_get_tag_global();
@@ -323,7 +249,6 @@ int spawn_load(const char *name, int argc, char **argv)
else
exit((module->main_func)(argc, argv)); /* Actually run! */
-
// Clean up the allocation context
//__free_tagged(module);
// Restore the allocation context
@@ -340,10 +265,8 @@ int spawn_load(const char *name, int argc, char **argv)
return ((unsigned int)ret_val & 0xFF);
}
- /*
- module_unload(module);
- return -1;
- */
+
+ return 0;
}
void exec_term(void)
diff --git a/com32/lib/sys/module/i386/common.c b/com32/lib/sys/module/i386/common.c
deleted file mode 100644
index 41e71e83..00000000
--- a/com32/lib/sys/module/i386/common.c
+++ /dev/null
@@ -1,571 +0,0 @@
-/*
- * common.c
- *
- * Created on: Aug 11, 2008
- * Author: Stefan Bucur <stefanb@zytor.com>
- */
-
-#include <stdio.h>
-#include <elf.h>
-#include <string.h>
-#include <fs.h>
-
-#include <linux/list.h>
-#include <sys/module.h>
-
-#include "elfutils.h"
-#include "common.h"
-
-/**
- * The one and only list of loaded modules
- */
-LIST_HEAD(modules_head);
-
-// User-space debugging routines
-#ifdef ELF_DEBUG
-void print_elf_ehdr(Elf32_Ehdr *ehdr) {
- int i;
-
- fprintf(stderr, "Identification:\t");
- for (i=0; i < EI_NIDENT; i++) {
- printf("%d ", ehdr->e_ident[i]);
- }
- fprintf(stderr, "\n");
- fprintf(stderr, "Type:\t\t%u\n", ehdr->e_type);
- fprintf(stderr, "Machine:\t%u\n", ehdr->e_machine);
- fprintf(stderr, "Version:\t%u\n", ehdr->e_version);
- fprintf(stderr, "Entry:\t\t0x%08x\n", ehdr->e_entry);
- 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, "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;
-
- for (i = 1; i < module->symtable_size; i++)
- {
- crt_sym = (Elf32_Sym*)(module->sym_table + i*module->syment_size);
-
- fprintf(stderr,"%s %d\n", module->str_table + crt_sym->st_name, crt_sym->st_value);
-
- }
-}
-#endif //ELF_DEBUG
-
-static FILE *findpath(char *name)
-{
- char path[FILENAME_MAX];
- FILE *f;
- char *p, *n;
- int i;
-
- p = PATH;
-again:
- memset(path, '\0', sizeof(path));
- i = 0;
- while (*p && *p != ':' && i < FILENAME_MAX) {
- path[i++] = *p++;
- }
- //path[i] = '\0'; // without null the strcmp will fail
-
- if (*p == ':')
- p++;
-
- if (!strcmp(path, ".")) {
- if (!core_getcwd(path, sizeof(path))) {
- DBG_PRINT("Could not get cwd\n");
- return NULL;
- }
- i = strlen(path);
- }
-
- n = name;
- while (*n && i < FILENAME_MAX)
- path[i++] = *n++;
- path[i] = '\0';
-
- f = fopen(path, "rb");
- if (f)
- return f;
-
- if (p >= PATH && p < PATH + strlen(PATH))
- goto again;
-
- return NULL;
-}
-
-/*
- * Image files manipulation routines
- */
-
-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);
- goto error;
- }
-
- module->u.l._cr_offset = 0;
-
- return 0;
-
-error:
- if (module->u.l._file != NULL) {
- fclose(module->u.l._file);
- module->u.l._file = NULL;
- }
-
- return -1;
-}
-
-
-int image_unload(struct elf_module *module) {
- if (module->u.l._file != NULL) {
- fclose(module->u.l._file);
- module->u.l._file = NULL;
-
- }
- module->u.l._cr_offset = 0;
-
- return 0;
-}
-
-int image_read(void *buff, size_t size, struct elf_module *module) {
- size_t result = fread(buff, size, 1, module->u.l._file);
-
- if (result < 1)
- return -1;
-
- module->u.l._cr_offset += size;
- return 0;
-}
-
-int image_skip(size_t size, struct elf_module *module) {
- void *skip_buff = NULL;
- size_t result;
-
- if (size == 0)
- return 0;
-
- skip_buff = malloc(size);
- result = fread(skip_buff, size, 1, module->u.l._file);
- free(skip_buff);
-
- if (result < 1)
- return -1;
-
- module->u.l._cr_offset += size;
- return 0;
-}
-
-int image_seek(Elf32_Off offset, struct elf_module *module) {
- if (offset < module->u.l._cr_offset) // Cannot seek backwards
- return -1;
-
- return image_skip(offset - module->u.l._cr_offset, module);
-}
-
-
-// Initialization of the module subsystem
-int modules_init(void) {
- return 0;
-}
-
-// Termination of the module subsystem
-void modules_term(void) {
-
-}
-
-// Allocates the structure for a new module
-struct elf_module *module_alloc(const char *name) {
- struct elf_module *result = malloc(sizeof(struct elf_module));
-
- memset(result, 0, sizeof(struct elf_module));
-
- INIT_LIST_HEAD(&result->list);
- INIT_LIST_HEAD(&result->required);
- INIT_LIST_HEAD(&result->dependants);
-
- strncpy(result->name, name, MODULE_NAME_SIZE);
-
- return result;
-}
-
-struct module_dep *module_dep_alloc(struct elf_module *module) {
- struct module_dep *result = malloc(sizeof(struct module_dep));
-
- INIT_LIST_HEAD (&result->list);
-
- result->module = module;
-
- return result;
-}
-
-struct elf_module *module_find(const char *name) {
- struct elf_module *cr_module;
-
- for_each_module(cr_module) {
- if (strcmp(cr_module->name, name) == 0)
- return cr_module;
- }
-
- return NULL;
-}
-
-
-// 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) {
- // 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");
- return -1;
- }
-
- if (elf_hdr->e_ident[EI_CLASS] != MODULE_ELF_CLASS) {
- DBG_PRINT("Invalid ELF class code\n");
- return -1;
- }
-
- if (elf_hdr->e_ident[EI_DATA] != MODULE_ELF_DATA) {
- DBG_PRINT("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");
- return -1;
- }
-
- if (elf_hdr->e_machine != MODULE_ELF_MACHINE) {
- DBG_PRINT("Invalid ELF architecture\n");
- return -1;
- }
-
- return 0;
-}
-
-
-int enforce_dependency(struct elf_module *req, struct elf_module *dep) {
- struct module_dep *crt_dep;
- struct module_dep *new_dep;
-
- list_for_each_entry(crt_dep, &req->dependants, list) {
- if (crt_dep->module == dep) {
- // The dependency is already enforced
- return 0;
- }
- }
-
- new_dep = module_dep_alloc(req);
- list_add(&new_dep->list, &dep->required);
-
- new_dep = module_dep_alloc(dep);
- list_add(&new_dep->list, &req->dependants);
-
- return 0;
-}
-
-int clear_dependency(struct elf_module *req, struct elf_module *dep) {
- struct module_dep *crt_dep = NULL;
- int found = 0;
-
- list_for_each_entry(crt_dep, &req->dependants, list) {
- if (crt_dep->module == dep) {
- found = 1;
- break;
- }
- }
-
- if (found) {
- list_del(&crt_dep->list);
- free(crt_dep);
- }
-
- found = 0;
-
- list_for_each_entry(crt_dep, &dep->required, list) {
- if (crt_dep->module == req) {
- found = 1;
- break;
- }
- }
-
- if (found) {
- list_del(&crt_dep->list);
- free(crt_dep);
- }
-
- return 0;
-}
-
-int check_symbols(struct elf_module *module)
-{
- unsigned int i;
- Elf32_Sym *crt_sym = NULL, *ref_sym = NULL;
- char *crt_name;
- struct elf_module *crt_module;
-
- int strong_count;
- int weak_count;
-
- for(i = 1; i < module->symtable_size; i++)
- {
- crt_sym = (Elf32_Sym*)(module->sym_table + i * module->syment_size);
- crt_name = module->str_table + crt_sym->st_name;
-
- strong_count = 0;
- weak_count = 0;
-
- for_each_module(crt_module)
- {
- ref_sym = module_find_symbol(crt_name, crt_module);
-
- // If we found a definition for our symbol...
- if (ref_sym != NULL && ref_sym->st_shndx != SHN_UNDEF)
- {
- switch (ELF32_ST_BIND(ref_sym->st_info))
- {
- case STB_GLOBAL:
- strong_count++;
- break;
- case STB_WEAK:
- weak_count++;
- break;
- }
- }
- }
-
- if (crt_sym->st_shndx == SHN_UNDEF)
- {
- // We have an undefined symbol
- if (strong_count == 0 && weak_count == 0)
- {
- DBG_PRINT("Symbol %s is undefined\n", crt_name);
- //printf("Undef symbol FAIL: %s\n",crt_name);
- return -1;
- }
- }
- else
- {
- if (strong_count > 0 && ELF32_ST_BIND(ref_sym->st_info) == STB_GLOBAL)
- {
- // 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);
- }
- }
- //printf("symbol %s laoded from %d\n",crt_name,crt_sym->st_value);
- }
-
- return 0;
-}
-
-int module_unloadable(struct elf_module *module) {
- if (!list_empty(&module->dependants))
- return 0;
-
- return 1;
-}
-
-
-// Unloads the module from the system and releases all the associated memory
-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");
- return -1;
- }
-
- // Remove any dependency information
- list_for_each_entry_safe(crt_dep, tmp, &module->required, list) {
- clear_dependency(crt_dep->module, module);
- }
-
- // Remove the module from the module list
- list_del_init(&module->list);
-
- // Release the loaded segments or sections
- if (module->module_addr != NULL) {
- elf_free(module->module_addr);
-
- DBG_PRINT("%s MODULE %s UNLOADED\n", module->shallow ? "SHALLOW" : "",
- module->name);
- }
- // Release the module structure
- free(module);
-
- return 0;
-}
-
-
-static Elf32_Sym *module_find_symbol_sysv(const char *name, struct elf_module *module) {
- unsigned long h = elf_hash((const unsigned char*)name);
- Elf32_Word *cr_word = module->hash_table;
-
- Elf32_Word nbucket = *cr_word++;
- cr_word++; // Skip nchain
-
- Elf32_Word *bkt = cr_word;
- Elf32_Word *chn = cr_word + nbucket;
-
- Elf32_Word crt_index = bkt[h % module->hash_table[0]];
- Elf32_Sym *crt_sym;
-
-
- while (crt_index != STN_UNDEF) {
- crt_sym = (Elf32_Sym*)(module->sym_table + crt_index*module->syment_size);
-
- if (strcmp(name, module->str_table + crt_sym->st_name) == 0)
- return crt_sym;
-
- crt_index = chn[crt_index];
- }
-
- return NULL;
-}
-
-static Elf32_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++;
-
-
- if ((bitmask_nwords & (bitmask_nwords - 1)) != 0) {
- DBG_PRINT("Invalid GNU Hash structure\n");
- return NULL;
- }
-
- Elf32_Word gnu_shift = *cr_word++;
-
- Elf32_Addr *gnu_bitmask = (Elf32_Addr*)cr_word;
- cr_word += MODULE_ELF_CLASS_SIZE / 32 * bitmask_nwords;
-
- Elf32_Word *gnu_buckets = cr_word;
- cr_word += nbucket;
-
- Elf32_Word *gnu_chain_zero = cr_word - symbias;
-
- // Computations
- Elf32_Word bitmask_word = gnu_bitmask[(h / MODULE_ELF_CLASS_SIZE) &
- (bitmask_nwords - 1)];
-
- unsigned int hashbit1 = h & (MODULE_ELF_CLASS_SIZE - 1);
- unsigned int hashbit2 = (h >> gnu_shift) & (MODULE_ELF_CLASS_SIZE - 1);
-
- if ((bitmask_word >> hashbit1) & (bitmask_word >> hashbit2) & 1) {
- unsigned long rem;
- Elf32_Word bucket;
-
- rem = h % nbucket;
-
- bucket = gnu_buckets[rem];
-
- if (bucket != 0) {
- const Elf32_Word* hasharr = &gnu_chain_zero[bucket];
-
- do {
- if (((*hasharr ^ h ) >> 1) == 0) {
- Elf32_Sym *crt_sym = (Elf32_Sym*)(module->sym_table +
- (hasharr - gnu_chain_zero) * module->syment_size);
-
- if (strcmp(name, module->str_table + crt_sym->st_name) == 0) {
- return crt_sym;
- }
- }
- } while ((*hasharr++ & 1u) == 0);
- }
- }
-
- return NULL;
-}
-
-static Elf32_Sym *module_find_symbol_iterate(const char *name,struct elf_module *module)
-{
-
- unsigned int i;
- Elf32_Sym *crt_sym;
-
- for (i=1; i < module->symtable_size; i++)
- {
- crt_sym = (Elf32_Sym*)(module->sym_table + i*module->syment_size);
- if (strcmp(name, module->str_table + crt_sym->st_name) == 0)
- {
- return crt_sym;
- }
- }
-
- return NULL;
-}
-
-Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module) {
- Elf32_Sym *result = NULL;
-
-
- if (module->ghash_table != NULL)
- result = module_find_symbol_gnu(name, module);
-
- if (result == NULL)
- {
- if (module->hash_table != NULL)
- {
- //printf("Attempting SYSV Symbol search\n");
- result = module_find_symbol_sysv(name, module);
- }
- else
- {
- //printf("Attempting Iterative Symbol search\n");
- result = module_find_symbol_iterate(name, module);
- }
- }
-
- return result;
-}
-
-Elf32_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;
-
- for_each_module(crt_module) {
- crt_sym = module_find_symbol(name, crt_module);
-
- if (crt_sym != NULL && crt_sym->st_shndx != SHN_UNDEF) {
- switch (ELF32_ST_BIND(crt_sym->st_info)) {
- case STB_GLOBAL:
- if (module != NULL) {
- *module = crt_module;
- }
- return crt_sym;
- case STB_WEAK:
- // Consider only the first weak symbol
- if (result == NULL) {
- if (module != NULL) {
- *module = crt_module;
- }
- result = crt_sym;
- }
- break;
- }
- }
- }
-
- return result;
-}
diff --git a/com32/lib/sys/module/i386/elf_module.c b/com32/lib/sys/module/i386/elf_module.c
index 864344a7..f4a8618a 100644
--- a/com32/lib/sys/module/i386/elf_module.c
+++ b/com32/lib/sys/module/i386/elf_module.c
@@ -5,20 +5,20 @@
* 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"
-
-#define MAX_NR_DEPS 64
+#include "../common.h"
static int check_header(Elf32_Ehdr *elf_hdr) {
int res;
@@ -50,7 +50,7 @@ static int check_header(Elf32_Ehdr *elf_hdr) {
static int load_segments(struct elf_module *module, Elf32_Ehdr *elf_hdr) {
int i;
int res = 0;
- void *pht = NULL;
+ char *pht = NULL;
Elf32_Phdr *cr_pht;
Elf32_Addr min_addr = 0x00000000; // Min. ELF vaddr
@@ -136,8 +136,8 @@ static int load_segments(struct elf_module *module, Elf32_Ehdr *elf_hdr) {
// headers
Elf32_Off aux_off = module->u.l._cr_offset - cr_pht->p_offset;
- if (image_read(module_get_absolute(cr_pht->p_vaddr, module) + aux_off,
- cr_pht->p_filesz - aux_off, module) < 0) {
+ 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;
}
@@ -180,9 +180,6 @@ out:
return res;
}
-static int nr_needed;
-static Elf32_Word needed[MAX_NR_DEPS];;
-
static int prepare_dynlinking(struct elf_module *module) {
Elf32_Dyn *dyn_entry = module->dyn_table;
@@ -195,8 +192,8 @@ static int prepare_dynlinking(struct elf_module *module) {
* are then inform the user that we ran out of
* space.
*/
- if (nr_needed < MAX_NR_DEPS)
- needed[nr_needed++] = dyn_entry->d_un.d_ptr;
+ if (module->nr_needed < MAX_NR_DEPS)
+ module->needed[module->nr_needed++] = dyn_entry->d_un.d_ptr;
else {
printf("Too many dependencies!\n");
return -1;
@@ -242,6 +239,11 @@ static int prepare_dynlinking(struct elf_module *module) {
return 0;
}
+void undefined_symbol(void)
+{
+ printf("Error: An undefined symbol was referenced\n");
+ kaboom();
+}
static int perform_relocation(struct elf_module *module, Elf32_Rel *rel) {
Elf32_Word *dest = module_get_absolute(rel->r_offset, module);
@@ -259,8 +261,7 @@ static int perform_relocation(struct elf_module *module, Elf32_Rel *rel) {
// Find out details about the symbol
// The symbol reference
- Elf32_Sym *sym_ref =
- (Elf32_Sym*)(module->sym_table + sym * module->syment_size);
+ Elf32_Sym *sym_ref = symbol_get_entry(module, sym);
// The symbol definition
sym_def =
@@ -268,15 +269,16 @@ static int perform_relocation(struct elf_module *module, Elf32_Rel *rel) {
&sym_module);
if (sym_def == NULL) {
- // This should never happen
DBG_PRINT("Cannot perform relocation for symbol %s\n",
module->str_table + sym_ref->st_name);
- /*
- printf("Cannot perform relocation for symbol %s\n",
- module->str_table + sym_ref->st_name);
- */
- return -1;
+ if (ELF32_ST_BIND(sym_ref->st_info) != STB_WEAK)
+ return -1;
+
+ // This must be a derivative-specific
+ // function. We're OK as long as we never
+ // execute the function.
+ sym_def = global_find_symbol("undefined_symbol", &sym_module);
}
// Compute the absolute symbol virtual address
@@ -325,9 +327,9 @@ static int resolve_symbols(struct elf_module *module) {
int res;
Elf32_Word plt_rel_size = 0;
- void *plt_rel = NULL;
+ char *plt_rel = NULL;
- void *rel = NULL;
+ char *rel = NULL;
Elf32_Word rel_size = 0;
Elf32_Word rel_entry = 0;
@@ -346,7 +348,6 @@ static int resolve_symbols(struct elf_module *module) {
DBG_PRINT("Unsupported PLT relocation\n");
return -1;
}
- //break; // mouli: wasn't there before
case DT_JMPREL:
plt_rel = module_get_absolute(dyn_entry->d_un.d_ptr, module);
break;
@@ -403,32 +404,70 @@ static int resolve_symbols(struct elf_module *module) {
return 0;
}
+static int extract_operations(struct elf_module *module) {
+ Elf32_Sym *ctors_start, *ctors_end;
+ Elf32_Sym *dtors_start, *dtors_end;
+ module_ctor_t *ctors = NULL;
+ module_ctor_t *dtors = NULL;
+ ctors_start = module_find_symbol("__ctors_start", module);
+ ctors_end = module_find_symbol("__ctors_end", module);
-static int extract_operations(struct elf_module *module) {
- Elf32_Sym *init_sym = module_find_symbol(MODULE_ELF_INIT_PTR, module);
- Elf32_Sym *exit_sym = module_find_symbol(MODULE_ELF_EXIT_PTR, module);
- Elf32_Sym *main_sym = module_find_symbol("main", module);
-
- if (init_sym) {
- module->init_func = (module_init_t*)module_get_absolute(
- init_sym->st_value, module);
- if (*(module->init_func) == NULL) {
- module->init_func = NULL;
+ if (ctors_start && ctors_end) {
+ module_ctor_t *start, *end;
+ int nr_ctors = 0;
+ int i, size;
+
+ start = module_get_absolute(ctors_start->st_value, module);
+ end = module_get_absolute(ctors_end->st_value, module);
+
+ nr_ctors = end - start;
+
+ size = nr_ctors * sizeof(module_ctor_t);
+ size += sizeof(module_ctor_t); /* NULL entry */
+
+ ctors = malloc(size);
+ if (!ctors) {
+ printf("Unable to alloc memory for ctors\n");
+ return -1;
}
+
+ memset(ctors, 0, size);
+ for (i = 0; i < nr_ctors; i++)
+ ctors[i] = start[i];
+
+ module->ctors = ctors;
}
- if (exit_sym) {
- module->exit_func = (module_exit_t*)module_get_absolute(
- exit_sym->st_value, module);
- if (*(module->exit_func) == NULL) {
- module->exit_func = NULL;
+ dtors_start = module_find_symbol("__dtors_start", module);
+ dtors_end = module_find_symbol("__dtors_end", module);
+
+ if (dtors_start && dtors_end) {
+ module_ctor_t *start, *end;
+ int nr_dtors = 0;
+ int i, size;
+
+ start = module_get_absolute(dtors_start->st_value, module);
+ end = module_get_absolute(dtors_end->st_value, module);
+
+ nr_dtors = end - start;
+
+ size = nr_dtors * sizeof(module_ctor_t);
+ size += sizeof(module_ctor_t); /* NULL entry */
+
+ dtors = malloc(size);
+ if (!dtors) {
+ printf("Unable to alloc memory for dtors\n");
+ free(ctors);
+ return -1;
}
- }
- if (main_sym)
- module->main_func =
- module_get_absolute(main_sym->st_value, module);
+ memset(dtors, 0, size);
+ for (i = 0; i < nr_dtors; i++)
+ dtors[i] = start[i];
+
+ module->dtors = dtors;
+ }
return 0;
}
@@ -436,12 +475,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;
+ module_ctor_t *ctor;
// Do not allow duplicate modules
if (module_find(module->name) != NULL) {
DBG_PRINT("Module %s is already loaded.\n", module->name);
- return -1;
+ return EEXIST;
}
// Get a mapping/copy of the ELF file in memory
@@ -467,42 +508,35 @@ int module_load(struct elf_module *module) {
CHECKED(res, load_segments(module, &elf_hdr), error);
//printf("bleah... 3\n");
// Obtain dynamic linking information
- nr_needed = 0;
CHECKED(res, prepare_dynlinking(module), error);
//printf("check... 4\n");
- //
- //dump_elf_module(module);
/* Find modules we need to load as dependencies */
if (module->str_table) {
- int i, n;
+ int i;
/*
- * nr_needed can be modified by recursive calls to
- * module_load() so keep a local copy on the stack.
+ * Note that we have to load the dependencies in
+ * reverse order.
*/
- n = nr_needed;
- for (i = 0; i < n; i++) {
- size_t len, j;
+ for (i = module->nr_needed - 1; i >= 0; i--) {
char *dep, *p;
+ char *argv[2] = { NULL, NULL };
- dep = module->str_table + needed[i];
+ dep = module->str_table + module->needed[i];
/* strip everything but the last component */
- j = len = strlen(dep);
- if (!len)
+ if (!strlen(dep))
continue;
- p = dep + len - 1;
- while (j > 0 && *p && *p != '/') {
- p--;
- j--;
- }
+ if (strchr(dep, '/')) {
+ p = strrchr(dep, '/');
+ p++;
+ } else
+ p = dep;
- if (*p++ == '/') {
- char argv[2] = { p, NULL };
- spawn_load(p, 1, argv);
- }
+ argv[0] = p;
+ spawn_load(p, 1, argv);
}
}
@@ -510,8 +544,11 @@ int module_load(struct elf_module *module) {
CHECKED(res, check_symbols(module), error);
//printf("check... 5\n");
- // Obtain constructors and destructors
- CHECKED(res, extract_operations(module), error);
+ main_sym = module_find_symbol("main", module);
+ if (main_sym)
+ module->main_func =
+ module_get_absolute(main_sym->st_value, module);
+
//printf("check... 6\n");
// Add the module at the beginning of the module list
@@ -520,6 +557,9 @@ int module_load(struct elf_module *module) {
// Perform the relocations
resolve_symbols(module);
+ // Obtain constructors and destructors
+ CHECKED(res, extract_operations(module), error);
+
//dprintf("module->symtable_size = %d\n", module->symtable_size);
//print_elf_symbols(module);
@@ -534,6 +574,10 @@ int module_load(struct elf_module *module) {
(module->init_func == NULL) ? NULL : *(module->init_func),
(module->exit_func == NULL) ? NULL : *(module->exit_func));
*/
+
+ for (ctor = module->ctors; *ctor; ctor++)
+ (*ctor) ();
+
return 0;
error:
diff --git a/com32/lib/sys/module/i386/elfutils.h b/com32/lib/sys/module/i386/elfutils.h
deleted file mode 100644
index b18968f3..00000000
--- a/com32/lib/sys/module/i386/elfutils.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef ELF_UTILS_H_
-#define ELF_UTILS_H_
-
-#include <elf.h>
-#include <stdlib.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;
-}
-
-/**
- * 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);
-
- return (Elf32_Phdr*)((Elf32_Off)elf_hdr + elf_hdr->e_phoff);
-}
-
-//
-/**
- * elf_get_ph - Returns the element with the given index in the PTH
- * @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);
-
- return (Elf32_Phdr*)((Elf32_Off)elf_pht + index * elf_hdr->e_phentsize);
-}
-
-/**
- * elf_hash - Returns the index in a SysV hash table for the symbol name.
- * @name: the name of the symbol to look for
- */
-extern unsigned long elf_hash(const unsigned char *name);
-
-/**
- * elf_gnu_hash - Returns the index in a GNU hash table for the symbol name.
- * @name: the name of the symbol to look for
- */
-extern unsigned long elf_gnu_hash(const unsigned char *name);
-
-/**
- * elf_malloc - Allocates memory to be used by ELF module contents.
- * @memptr: pointer to a variable to hold the address of the allocated block.
- * @alignment: alignment constraints of the block
- * @size: the required size of the block
- */
-extern int elf_malloc(void **memptr, size_t alignment, size_t size);
-
-/**
- * elf_free - Releases memory previously allocated by elf_malloc.
- * @memptr: the address of the allocated block
- */
-extern void elf_free(void *memptr);
-
-#endif /*ELF_UTILS_H_*/
diff --git a/com32/lib/sys/module/shallow_module.c b/com32/lib/sys/module/shallow_module.c
index fbcf781b..8a88e403 100644
--- a/com32/lib/sys/module/shallow_module.c
+++ b/com32/lib/sys/module/shallow_module.c
@@ -32,8 +32,8 @@ static int check_header_shallow(Elf32_Ehdr *elf_hdr) {
static int load_shallow_sections(struct elf_module *module, Elf32_Ehdr *elf_hdr) {
int i;
int res = 0;
- void *sht = NULL;
- void *buffer = NULL;
+ char *sht = NULL;
+ char *buffer = NULL;
Elf32_Shdr *crt_sht;
Elf32_Off buff_offset;
@@ -100,8 +100,8 @@ static int load_shallow_sections(struct elf_module *module, Elf32_Ehdr *elf_hdr)
// Setup module information
module->module_size = max_offset - min_offset;
- module->str_table = (char*)(module->module_addr + (str_offset - min_offset));
- module->sym_table = module->module_addr + (sym_offset - min_offset);
+ module->str_table = (char *)module->module_addr + (str_offset - min_offset);
+ module->sym_table = (char *)module->module_addr + (sym_offset - min_offset);
out:
// Release the SHT
diff --git a/com32/lib/sys/module/x86_64/common.c b/com32/lib/sys/module/x86_64/common.c
deleted file mode 100644
index ba4dbedc..00000000
--- a/com32/lib/sys/module/x86_64/common.c
+++ /dev/null
@@ -1,567 +0,0 @@
-/*
- * common.c
- *
- * Created on: Aug 11, 2008
- * Author: Stefan Bucur <stefanb@zytor.com>
- */
-
-#include <stdio.h>
-#include <elf.h>
-#include <string.h>
-#include <fs.h>
-
-#include <linux/list.h>
-#include <sys/module.h>
-
-#include "elfutils.h"
-#include "common.h"
-
-/**
- * The one and only list of loaded modules
- */
-LIST_HEAD(modules_head);
-
-// User-space debugging routines
-#ifdef ELF_DEBUG
-void print_elf_ehdr(Elf64_Ehdr *ehdr) {
- int i;
-
- fprintf(stderr, "Identification:\t");
- for (i=0; i < EI_NIDENT; i++) {
- printf("%d ", ehdr->e_ident[i]);
- }
- fprintf(stderr, "\n");
- fprintf(stderr, "Type:\t\t%u\n", ehdr->e_type);
- fprintf(stderr, "Machine:\t%u\n", ehdr->e_machine);
- fprintf(stderr, "Version:\t%u\n", ehdr->e_version);
- fprintf(stderr, "Entry:\t\t0x%08x\n", ehdr->e_entry);
- 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(Elf64_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;
- Elf64_Sym *crt_sym;
-
- for (i = 1; i < module->symtable_size; i++)
- {
- crt_sym = (Elf64_Sym*)(module->sym_table + i*module->syment_size);
-
- fprintf(stderr,"%s %d\n", module->str_table + crt_sym->st_name, crt_sym->st_value);
-
- }
-}
-#endif //ELF_DEBUG
-
-static FILE *findpath(char *name)
-{
- char path[FILENAME_MAX];
- FILE *f;
- char *p, *n;
- int i;
-
- p = PATH;
-again:
- memset(path, '\0', sizeof(path));
- i = 0;
- while (*p && *p != ':' && i < FILENAME_MAX) {
- path[i++] = *p++;
- }
-
- if (*p == ':')
- p++;
-
- if (!strcmp(path, ".")) {
- if (!core_getcwd(path, sizeof(path))) {
- DBG_PRINT("Could not get cwd\n");
- return NULL;
- }
- i = strlen(path);
- }
-
- n = name;
- while (*n && i < FILENAME_MAX)
- path[i++] = *n++;
- path[i] = '\0';
-
- f = fopen(path, "rb");
- if (f)
- return f;
-
- if (p >= PATH && p < PATH + strlen(PATH))
- goto again;
-
- return NULL;
-}
-
-/*
- * Image files manipulation routines
- */
-
-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);
- goto error;
- }
-
- module->u.l._cr_offset = 0;
-
- return 0;
-
-error:
- if (module->u.l._file != NULL) {
- fclose(module->u.l._file);
- module->u.l._file = NULL;
- }
-
- return -1;
-}
-
-
-int image_unload(struct elf_module *module) {
- if (module->u.l._file != NULL) {
- fclose(module->u.l._file);
- module->u.l._file = NULL;
-
- }
- module->u.l._cr_offset = 0;
-
- return 0;
-}
-
-int image_read(void *buff, size_t size, struct elf_module *module) {
- size_t result = fread(buff, size, 1, module->u.l._file);
-
- if (result < 1)
- return -1;
-
- module->u.l._cr_offset += size;
- return 0;
-}
-
-int image_skip(size_t size, struct elf_module *module) {
- void *skip_buff = NULL;
- size_t result;
-
- if (size == 0)
- return 0;
-
- skip_buff = malloc(size);
- result = fread(skip_buff, size, 1, module->u.l._file);
- free(skip_buff);
-
- if (result < 1)
- return -1;
-
- module->u.l._cr_offset += size;
- return 0;
-}
-
-int image_seek(Elf64_Off offset, struct elf_module *module) {
- if (offset < module->u.l._cr_offset) // Cannot seek backwards
- return -1;
-
- return image_skip(offset - module->u.l._cr_offset, module);
-}
-
-
-// Initialization of the module subsystem
-int modules_init(void) {
- return 0;
-}
-
-// Termination of the module subsystem
-void modules_term(void) {
-
-}
-
-// Allocates the structure for a new module
-struct elf_module *module_alloc(const char *name) {
- struct elf_module *result = malloc(sizeof(struct elf_module));
-
- memset(result, 0, sizeof(struct elf_module));
-
- INIT_LIST_HEAD(&result->list);
- INIT_LIST_HEAD(&result->required);
- INIT_LIST_HEAD(&result->dependants);
-
- strncpy(result->name, name, MODULE_NAME_SIZE);
-
- return result;
-}
-
-struct module_dep *module_dep_alloc(struct elf_module *module) {
- struct module_dep *result = malloc(sizeof(struct module_dep));
-
- INIT_LIST_HEAD (&result->list);
-
- result->module = module;
-
- return result;
-}
-
-struct elf_module *module_find(const char *name) {
- struct elf_module *cr_module;
-
- for_each_module(cr_module) {
- if (strcmp(cr_module->name, name) == 0)
- return cr_module;
- }
-
- return NULL;
-}
-
-
-// Performs verifications on ELF header to assure that the open file is a
-// valid SYSLINUX ELF module.
-int check_header_common(Elf64_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");
- return -1;
- }
-
- if (elf_hdr->e_ident[EI_CLASS] != MODULE_ELF_CLASS) {
- DBG_PRINT("Invalid ELF class code\n");
- return -1;
- }
-
- if (elf_hdr->e_ident[EI_DATA] != MODULE_ELF_DATA) {
- DBG_PRINT("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");
- return -1;
- }
-
- if (elf_hdr->e_machine != MODULE_ELF_MACHINE) {
- DBG_PRINT("Invalid ELF architecture\n");
- return -1;
- }
-
- return 0;
-}
-
-
-int enforce_dependency(struct elf_module *req, struct elf_module *dep) {
- struct module_dep *crt_dep;
- struct module_dep *new_dep;
-
- list_for_each_entry(crt_dep, &req->dependants, list) {
- if (crt_dep->module == dep) {
- // The dependency is already enforced
- return 0;
- }
- }
-
- new_dep = module_dep_alloc(req);
- list_add(&new_dep->list, &dep->required);
-
- new_dep = module_dep_alloc(dep);
- list_add(&new_dep->list, &req->dependants);
-
- return 0;
-}
-
-int clear_dependency(struct elf_module *req, struct elf_module *dep) {
- struct module_dep *crt_dep = NULL;
- int found = 0;
-
- list_for_each_entry(crt_dep, &req->dependants, list) {
- if (crt_dep->module == dep) {
- found = 1;
- break;
- }
- }
-
- if (found) {
- list_del(&crt_dep->list);
- free(crt_dep);
- }
-
- found = 0;
-
- list_for_each_entry(crt_dep, &dep->required, list) {
- if (crt_dep->module == req) {
- found = 1;
- break;
- }
- }
-
- if (found) {
- list_del(&crt_dep->list);
- free(crt_dep);
- }
-
- return 0;
-}
-
-int check_symbols(struct elf_module *module)
-{
- unsigned int i;
- Elf64_Sym *crt_sym = NULL, *ref_sym = NULL;
- char *crt_name;
- struct elf_module *crt_module;
-
- int strong_count;
- int weak_count;
-
- for(i = 1; i < module->symtable_size; i++)
- {
- crt_sym = (Elf64_Sym*)(module->sym_table + i * module->syment_size);
- crt_name = module->str_table + crt_sym->st_name;
-
- strong_count = 0;
- weak_count = 0;
-
- for_each_module(crt_module)
- {
- ref_sym = module_find_symbol(crt_name, crt_module);
-
- // If we found a definition for our symbol...
- if (ref_sym != NULL && ref_sym->st_shndx != SHN_UNDEF)
- {
- switch (ELF64_ST_BIND(ref_sym->st_info))
- {
- case STB_GLOBAL:
- strong_count++;
- break;
- case STB_WEAK:
- weak_count++;
- break;
- }
- }
- }
-
- if (crt_sym->st_shndx == SHN_UNDEF)
- {
- // We have an undefined symbol
- if (strong_count == 0 && weak_count == 0)
- {
- DBG_PRINT("Symbol %s is undefined\n", crt_name);
- //printf("Undef symbol FAIL: %s\n",crt_name);
- return -1;
- }
- }
- else
- {
- if (strong_count > 0 && ELF64_ST_BIND(ref_sym->st_info) == STB_GLOBAL)
- {
- // 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);
- }
- }
- //printf("symbol %s laoded from %d\n",crt_name,crt_sym->st_value);
- }
-
- return 0;
-}
-
-int module_unloadable(struct elf_module *module) {
- if (!list_empty(&module->dependants))
- return 0;
-
- return 1;
-}
-
-
-// Unloads the module from the system and releases all the associated memory
-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");
- return -1;
- }
-
- // Remove any dependency information
- list_for_each_entry_safe(crt_dep, tmp, &module->required, list) {
- clear_dependency(crt_dep->module, module);
- }
-
- // Remove the module from the module list
- list_del_init(&module->list);
-
- // Release the loaded segments or sections
- if (module->module_addr != NULL) {
- elf_free(module->module_addr);
-
- DBG_PRINT("%s MODULE %s UNLOADED\n", module->shallow ? "SHALLOW" : "",
- module->name);
- }
- // Release the module structure
- free(module);
-
- return 0;
-}
-
-
-static Elf64_Sym *module_find_symbol_sysv(const char *name, struct elf_module *module) {
- unsigned long h = elf_hash((const unsigned char*)name);
- Elf64_Word *cr_word = module->hash_table;
-
- Elf64_Word nbucket = *cr_word++;
- cr_word++; // Skip nchain
-
- Elf64_Word *bkt = cr_word;
- Elf64_Word *chn = cr_word + nbucket;
-
- Elf64_Word crt_index = bkt[h % module->hash_table[0]];
- Elf64_Sym *crt_sym;
-
-
- while (crt_index != STN_UNDEF) {
- crt_sym = (Elf64_Sym*)(module->sym_table + crt_index*module->syment_size);
-
- if (strcmp(name, module->str_table + crt_sym->st_name) == 0)
- return crt_sym;
-
- crt_index = chn[crt_index];
- }
-
- return NULL;
-}
-
-static Elf64_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)
- Elf64_Word *cr_word = module->ghash_table;
- Elf64_Word nbucket = *cr_word++;
- Elf64_Word symbias = *cr_word++;
- Elf64_Word bitmask_nwords = *cr_word++;
-
- if ((bitmask_nwords & (bitmask_nwords - 1)) != 0) {
- DBG_PRINT("Invalid GNU Hash structure\n");
- return NULL;
- }
-
- Elf64_Word gnu_shift = *cr_word++;
-
- Elf64_Addr *gnu_bitmask = cr_word;
- cr_word += MODULE_ELF_CLASS_SIZE / 32 * bitmask_nwords;
-
- Elf64_Word *gnu_buckets = cr_word;
- cr_word += nbucket;
-
- Elf64_Word *gnu_chain_zero = cr_word - symbias;
-
- // Computations
- /* bitask words are 64bit for ELFCLASS64 modules */
- Elf64_Xword bitmask_word = gnu_bitmask[(h / MODULE_ELF_CLASS_SIZE) &
- (bitmask_nwords - 1)];
-
- unsigned int hashbit1 = h & (MODULE_ELF_CLASS_SIZE - 1);
- unsigned int hashbit2 = (h >> gnu_shift) & (MODULE_ELF_CLASS_SIZE - 1);
-
- if ((bitmask_word >> hashbit1) & (bitmask_word >> hashbit2) & 1) {
- unsigned long rem;
- Elf64_Word bucket;
-
- rem = h % nbucket;
-
- bucket = gnu_buckets[rem];
-
- if (bucket != 0) {
- const Elf64_Word* hasharr = &gnu_chain_zero[bucket];
-
- do {
- if (((*hasharr ^ h ) >> 1) == 0) {
- Elf64_Sym *crt_sym = (Elf64_Sym*)(module->sym_table +
- (hasharr - gnu_chain_zero) * module->syment_size);
-
- if (strcmp(name, module->str_table + crt_sym->st_name) == 0) {
- return crt_sym;
- }
- }
- } while ((*hasharr++ & 1u) == 0);
- }
- }
-
- return NULL;
-}
-
-static Elf64_Sym *module_find_symbol_iterate(const char *name,struct elf_module *module)
-{
-
- unsigned int i;
- Elf64_Sym *crt_sym;
-
- for (i=1; i < module->symtable_size; i++)
- {
- crt_sym = (Elf64_Sym*)(module->sym_table + i*module->syment_size);
- if (strcmp(name, module->str_table + crt_sym->st_name) == 0)
- {
- return crt_sym;
- }
- }
-
- return NULL;
-}
-
-Elf64_Sym *module_find_symbol(const char *name, struct elf_module *module) {
- Elf64_Sym *result = NULL;
-
- if (module->ghash_table != NULL)
- result = module_find_symbol_gnu(name, module);
-
- if (result == NULL)
- {
- if (module->hash_table != NULL)
- {
- result = module_find_symbol_sysv(name, module);
- }
- else
- {
- result = module_find_symbol_iterate(name, module);
- }
- }
-
- return result;
-}
-
-Elf64_Sym *global_find_symbol(const char *name, struct elf_module **module) {
- struct elf_module *crt_module;
- Elf64_Sym *crt_sym = NULL;
- Elf64_Sym *result = NULL;
-
- for_each_module(crt_module) {
- crt_sym = module_find_symbol(name, crt_module);
-
- if (crt_sym != NULL && crt_sym->st_shndx != SHN_UNDEF) {
- switch (ELF64_ST_BIND(crt_sym->st_info)) {
- case STB_GLOBAL:
- if (module != NULL) {
- *module = crt_module;
- }
- return crt_sym;
- case STB_WEAK:
- // Consider only the first weak symbol
- if (result == NULL) {
- if (module != NULL) {
- *module = crt_module;
- }
- result = crt_sym;
- }
- break;
- }
- }
- }
-
- return result;
-}
diff --git a/com32/lib/sys/module/x86_64/elf_module.c b/com32/lib/sys/module/x86_64/elf_module.c
index 2ff2e20b..3c164996 100644
--- a/com32/lib/sys/module/x86_64/elf_module.c
+++ b/com32/lib/sys/module/x86_64/elf_module.c
@@ -5,20 +5,20 @@
* 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"
-
-#define MAX_NR_DEPS 64
+#include "../common.h"
static int check_header(Elf64_Ehdr *elf_hdr) {
int res;
@@ -50,7 +50,7 @@ static int check_header(Elf64_Ehdr *elf_hdr) {
static int load_segments(struct elf_module *module, Elf64_Ehdr *elf_hdr) {
int i;
int res = 0;
- void *pht = NULL;
+ char *pht = NULL;
Elf64_Phdr *cr_pht;
Elf64_Addr min_addr = 0x0000000000000000; // Min. ELF vaddr
@@ -136,8 +136,8 @@ static int load_segments(struct elf_module *module, Elf64_Ehdr *elf_hdr) {
// headers
Elf64_Off aux_off = module->u.l._cr_offset - cr_pht->p_offset;
- if (image_read(module_get_absolute(cr_pht->p_vaddr, module) + aux_off,
- cr_pht->p_filesz - aux_off, module) < 0) {
+ 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;
}
@@ -180,9 +180,6 @@ out:
return res;
}
-static int nr_needed;
-static Elf64_Word needed[MAX_NR_DEPS];;
-
static int prepare_dynlinking(struct elf_module *module) {
Elf64_Dyn *dyn_entry = module->dyn_table;
@@ -195,8 +192,8 @@ static int prepare_dynlinking(struct elf_module *module) {
* are then inform the user that we ran out of
* space.
*/
- if (nr_needed < MAX_NR_DEPS)
- needed[nr_needed++] = dyn_entry->d_un.d_ptr;
+ if (module->nr_needed < MAX_NR_DEPS)
+ module->needed[module->nr_needed++] = dyn_entry->d_un.d_ptr;
else {
printf("Too many dependencies!\n");
return -1;
@@ -242,6 +239,11 @@ static int prepare_dynlinking(struct elf_module *module) {
return 0;
}
+void undefined_symbol(void)
+{
+ printf("Error: An undefined symbol was referenced\n");
+ kaboom();
+}
static int perform_relocation(struct elf_module *module, Elf64_Rel *rel) {
Elf64_Xword *dest = module_get_absolute(rel->r_offset, module);
@@ -259,8 +261,7 @@ static int perform_relocation(struct elf_module *module, Elf64_Rel *rel) {
// Find out details about the symbol
// The symbol reference
- Elf64_Sym *sym_ref =
- (Elf64_Sym*)(module->sym_table + sym * module->syment_size);
+ Elf64_Sym *sym_ref = symbol_get_entry(module, sym);
// The symbol definition
sym_def =
@@ -268,11 +269,16 @@ static int perform_relocation(struct elf_module *module, Elf64_Rel *rel) {
&sym_module);
if (sym_def == NULL) {
- // This should never happen
DBG_PRINT("Cannot perform relocation for symbol %s\n",
module->str_table + sym_ref->st_name);
- return -1;
+ if (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
@@ -422,73 +428,93 @@ static int resolve_symbols(struct elf_module *module) {
res = perform_relocation(module, crt_rel);
- if (res < 0) {
+ if (res < 0)
return res;
- }
}
}
return 0;
}
+static int extract_operations(struct elf_module *module) {
+ Elf64_Sym *ctors_start, *ctors_end;
+ Elf64_Sym *dtors_start, *dtors_end;
+ module_ctor_t *ctors = NULL;
+ module_ctor_t *dtors = NULL;
+ ctors_start = module_find_symbol("__ctors_start", module);
+ ctors_end = module_find_symbol("__ctors_end", module);
-static int extract_operations(struct elf_module *module) {
- Elf64_Sym *init_sym = module_find_symbol(MODULE_ELF_INIT_PTR, module);
- Elf64_Sym *exit_sym = module_find_symbol(MODULE_ELF_EXIT_PTR, module);
- Elf64_Sym *main_sym = module_find_symbol("main", module);
-
- if (init_sym) {
- module->init_func = (module_init_t*)module_get_absolute(
- init_sym->st_value, module);
- if (*(module->init_func) == NULL) {
- module->init_func = NULL;
- }
- }
+ if (ctors_start && ctors_end) {
+ module_ctor_t *start, *end;
+ int nr_ctors = 0;
+ int i, size;
+
+ start = module_get_absolute(ctors_start->st_value, module);
+ end = module_get_absolute(ctors_end->st_value, module);
+
+ nr_ctors = end - start;
- if (exit_sym) {
- module->exit_func = (module_exit_t*)module_get_absolute(
- exit_sym->st_value, module);
- if (*(module->exit_func) == NULL) {
- module->exit_func = NULL;
+ size = nr_ctors * sizeof(module_ctor_t);
+ size += sizeof(module_ctor_t); /* NULL entry */
+
+ ctors = malloc(size);
+ if (!ctors) {
+ printf("Unable to alloc memory for ctors\n");
+ return -1;
}
+
+ memset(ctors, 0, size);
+ for (i = 0; i < nr_ctors; i++)
+ ctors[i] = start[i];
+
+ module->ctors = ctors;
}
- if (main_sym)
- module->main_func =
- module_get_absolute(main_sym->st_value, module);
+ dtors_start = module_find_symbol("__dtors_start", module);
+ dtors_end = module_find_symbol("__dtors_end", module);
- return 0;
-}
+ if (dtors_start && dtors_end) {
+ module_ctor_t *start, *end;
+ int nr_dtors = 0;
+ int i, size;
-void print_elf_ehdr(Elf64_Ehdr *ehdr) {
- int i;
+ start = module_get_absolute(dtors_start->st_value, module);
+ end = module_get_absolute(dtors_end->st_value, module);
+
+ nr_dtors = end - start;
+
+ size = nr_dtors * sizeof(module_ctor_t);
+ size += sizeof(module_ctor_t); /* NULL entry */
+
+ dtors = malloc(size);
+ if (!dtors) {
+ printf("Unable to alloc memory for dtors\n");
+ free(ctors);
+ return -1;
+ }
- printf("Identification:\t");
- for (i=0; i < EI_NIDENT; i++) {
- printf("%d ", ehdr->e_ident[i]);
+ memset(dtors, 0, size);
+ for (i = 0; i < nr_dtors; i++)
+ dtors[i] = start[i];
+
+ module->dtors = dtors;
}
- printf("\n");
- printf("Type:\t\t%u\n", ehdr->e_type);
- printf("Machine:\t%u\n", ehdr->e_machine);
- printf("Version:\t%u\n", ehdr->e_version);
- printf("Entry:\t\t0x%08x\n", ehdr->e_entry);
- printf("PHT Offset:\t0x%08x\n", ehdr->e_phoff);
- printf("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(Elf64_Ehdr));
- printf("phnum: %d shnum: %d\n", ehdr->e_phnum,
- ehdr->e_shnum);
+
+ return 0;
}
+
// Loads the module into the system
int module_load(struct elf_module *module) {
int res;
+ Elf64_Sym *main_sym;
Elf64_Ehdr elf_hdr;
+ module_ctor_t *ctor;
// Do not allow duplicate modules
if (module_find(module->name) != NULL) {
DBG_PRINT("Module %s is already loaded.\n", module->name);
- return -1;
+ return EEXIST;
}
// Get a mapping/copy of the ELF file in memory
@@ -512,45 +538,37 @@ int module_load(struct elf_module *module) {
// Load the segments in the memory
CHECKED(res, load_segments(module, &elf_hdr), error);
- //!!!!! Passed load_segments....
//printf("bleah... 3\n");
// Obtain dynamic linking information
- nr_needed = 0;
CHECKED(res, prepare_dynlinking(module), error);
//printf("check... 4\n");
- //
- //dump_elf_module(module);
/* Find modules we need to load as dependencies */
if (module->str_table) {
- int i, n;
+ int i;
/*
- * nr_needed can be modified by recursive calls to
- * module_load() so keep a local copy on the stack.
+ * Note that we have to load the dependencies in
+ * reverse order.
*/
- n = nr_needed;
- for (i = 0; i < n; i++) {
- size_t len, j;
+ for (i = module->nr_needed - 1; i >= 0; i--) {
char *dep, *p;
+ char *argv[2] = { NULL, NULL };
- dep = module->str_table + needed[i];
+ dep = module->str_table + module->needed[i];
/* strip everything but the last component */
- j = len = strlen(dep);
- if (!len)
+ if (!strlen(dep))
continue;
- p = dep + len - 1;
- while (j > 0 && *p && *p != '/') {
- p--;
- j--;
- }
+ if (strchr(dep, '/')) {
+ p = strrchr(dep, '/');
+ p++;
+ } else
+ p = dep;
- if (*p++ == '/') {
- char argv[2] = { p, NULL };
- spawn_load(p, 1, argv);
- }
+ argv[0] = p;
+ spawn_load(p, 1, argv);
}
}
@@ -558,8 +576,11 @@ int module_load(struct elf_module *module) {
CHECKED(res, check_symbols(module), error);
//printf("check... 5\n");
- // Obtain constructors and destructors
- CHECKED(res, extract_operations(module), error);
+ main_sym = module_find_symbol("main", module);
+ if (main_sym)
+ module->main_func =
+ module_get_absolute(main_sym->st_value, module);
+
//printf("check... 6\n");
// Add the module at the beginning of the module list
@@ -568,6 +589,9 @@ int module_load(struct elf_module *module) {
// Perform the relocations
resolve_symbols(module);
+ // Obtain constructors and destructors
+ CHECKED(res, extract_operations(module), error);
+
//dprintf("module->symtable_size = %d\n", module->symtable_size);
//print_elf_symbols(module);
@@ -582,6 +606,10 @@ int module_load(struct elf_module *module) {
(module->init_func == NULL) ? NULL : *(module->init_func),
(module->exit_func == NULL) ? NULL : *(module->exit_func));
*/
+
+ for (ctor = module->ctors; *ctor; ctor++)
+ (*ctor) ();
+
return 0;
error:
diff --git a/com32/lib/sys/open.c b/com32/lib/sys/open.c
index a0ef1597..3221bb60 100644
--- a/com32/lib/sys/open.c
+++ b/com32/lib/sys/open.c
@@ -30,6 +30,7 @@
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
+#include <fs.h>
#include "file.h"
/*
diff --git a/com32/lib/sys/rawcon_read.c b/com32/lib/sys/rawcon_read.c
index e6635909..7eae95f1 100644
--- a/com32/lib/sys/rawcon_read.c
+++ b/com32/lib/sys/rawcon_read.c
@@ -35,51 +35,38 @@
#include <errno.h>
#include <string.h>
#include <com32.h>
+#include <core.h>
#include <minmax.h>
#include "file.h"
/* Global, since it's used by stdcon_read */
-#ifndef SYSLINUX_EFI
ssize_t __rawcon_read(struct file_info *fp, void *buf, size_t count)
{
- com32sys_t ireg, oreg;
char *bufp = buf;
size_t n = 0;
+ char hi = 0;
-printf("__rawcon_read... enter\n");
(void)fp;
- memset(&ireg, 0, sizeof ireg);
-
while (n < count) {
+ if (hi) {
+ *bufp++ = hi;
+ n++;
+ hi = 0;
+ continue;
+ }
+
/* Poll */
- ireg.eax.b[1] = 0x0B;
- __intcall(0x21, &ireg, &oreg);
- if (!oreg.eax.b[0])
+ if (!pollchar())
break;
/* We have data, go get it */
- ireg.eax.b[1] = 0x08;
- __intcall(0x21, &ireg, &oreg);
- *bufp++ = oreg.eax.b[0];
+ *bufp++ = getchar(&hi);
n++;
}
return n;
}
-#else
-ssize_t __rawcon_read(struct file_info *fp, void *buf, size_t count)
-{
- extern char getchar();
- char *bufp = buf;
- size_t n = 0;
- while (n < count) {
- *bufp++ = getchar();
- n++;
- }
- return n;
-}
-#endif
const struct input_dev dev_rawcon_r = {
.dev_magic = __DEV_MAGIC,
diff --git a/com32/lib/sys/rawcon_write.c b/com32/lib/sys/rawcon_write.c
index 2d45a7b2..1f7920b2 100644
--- a/com32/lib/sys/rawcon_write.c
+++ b/com32/lib/sys/rawcon_write.c
@@ -34,24 +34,20 @@
#include <errno.h>
#include <string.h>
#include <com32.h>
+#include <core.h>
#include <minmax.h>
#include "file.h"
static ssize_t __rawcon_write(struct file_info *fp, const void *buf,
size_t count)
{
- com32sys_t ireg;
const char *bufp = buf;
size_t n = 0;
(void)fp;
- memset(&ireg, 0, sizeof ireg);
- ireg.eax.b[1] = 0x02;
-
while (count--) {
- ireg.edx.b[0] = *bufp++;
- __intcall(0x21, &ireg, NULL);
+ writechr(*bufp++);
n++;
}
diff --git a/com32/lib/sys/serial_write.c b/com32/lib/sys/serial_write.c
index fa0f4f4d..3f949fb7 100644
--- a/com32/lib/sys/serial_write.c
+++ b/com32/lib/sys/serial_write.c
@@ -34,13 +34,13 @@
#include <errno.h>
#include <string.h>
#include <com32.h>
+#include <core.h>
#include <minmax.h>
#include <syslinux/config.h>
#include "file.h"
ssize_t __serial_write(struct file_info *fp, const void *buf, size_t count)
{
- com32sys_t ireg;
const char *bufp = buf;
size_t n = 0;
@@ -49,12 +49,8 @@ ssize_t __serial_write(struct file_info *fp, const void *buf, size_t count)
if (!syslinux_serial_console_info()->iobase)
return count; /* Nothing to do */
- memset(&ireg, 0, sizeof ireg);
- ireg.eax.b[1] = 0x04;
-
while (count--) {
- ireg.edx.b[0] = *bufp++;
- __intcall(0x21, &ireg, NULL);
+ write_serial(*bufp++);
n++;
}
diff --git a/com32/lib/sys/stdcon_write.c b/com32/lib/sys/stdcon_write.c
index 9cb2f7db..9bd225f9 100644
--- a/com32/lib/sys/stdcon_write.c
+++ b/com32/lib/sys/stdcon_write.c
@@ -34,6 +34,7 @@
#include <errno.h>
#include <string.h>
#include <com32.h>
+#include <core.h>
#include <minmax.h>
#include "file.h"
@@ -57,22 +58,16 @@ static int __stdcon_open(struct file_info *fp)
static ssize_t __stdcon_write(struct file_info *fp, const void *buf,
size_t count)
{
- com32sys_t ireg;
const char *bufp = buf;
size_t n = 0;
(void)fp;
- memset(&ireg, 0, sizeof ireg);
- ireg.eax.b[1] = 0x02;
-
while (count--) {
- if (*bufp == '\n') {
- ireg.edx.b[0] = '\r';
- __intcall(0x21, &ireg, NULL);
- }
- ireg.edx.b[0] = *bufp++;
- __intcall(0x21, &ireg, NULL);
+ if (*bufp == '\n')
+ writechr('\r');
+
+ writechr(*bufp++);
n++;
}
diff --git a/com32/lib/sys/xserial_write.c b/com32/lib/sys/xserial_write.c
index e399f5fc..8a4fb9e0 100644
--- a/com32/lib/sys/xserial_write.c
+++ b/com32/lib/sys/xserial_write.c
@@ -35,6 +35,7 @@
#include <errno.h>
#include <string.h>
#include <com32.h>
+#include <core.h>
#include <minmax.h>
#include <colortbl.h>
#include <syslinux/config.h>
@@ -42,12 +43,7 @@
static void emit(char ch)
{
- static com32sys_t ireg; /* Zeroed with the BSS */
-
- ireg.eax.b[1] = 0x04;
- ireg.edx.b[0] = ch;
-
- __intcall(0x21, &ireg, NULL);
+ write_serial(ch);
}
ssize_t __xserial_write(struct file_info *fp, const void *buf, size_t count)
diff --git a/com32/lib/syslinux/cleanup.c b/com32/lib/syslinux/cleanup.c
index 12140e55..7d8581e4 100644
--- a/com32/lib/syslinux/cleanup.c
+++ b/com32/lib/syslinux/cleanup.c
@@ -26,15 +26,15 @@
* ----------------------------------------------------------------------- */
#include <syslinux/boot.h>
+#include <syslinux/config.h>
+#include <syslinux/pxe_api.h>
#include <stddef.h>
-#include <com32.h>
+#include <core.h>
void syslinux_final_cleanup(uint16_t flags)
{
- static com32sys_t ireg;
+ if (syslinux_filesystem() == SYSLINUX_FS_PXELINUX)
+ unload_pxe(flags);
- ireg.eax.w[0] = 0x000c;
- ireg.edx.w[0] = flags;
-
- __intcall(0x22, &ireg, NULL);
+ cleanup_hardware();
}
diff --git a/com32/lib/syslinux/disk.c b/com32/lib/syslinux/disk.c
new file mode 100644
index 00000000..093751ac
--- /dev/null
+++ b/com32/lib/syslinux/disk.c
@@ -0,0 +1,569 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ * Copyright (C) 2010 Shao Miller
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/**
+ * @file disk.c
+ *
+ * Deal with disks and partitions
+ */
+
+#include <dprintf.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslinux/disk.h>
+
+/**
+ * Call int 13h, but with retry on failure. Especially floppies need this.
+ *
+ * @v inreg CPU register settings upon INT call
+ * @v outreg CPU register settings returned by INT call
+ * @ret (int) 0 upon success, -1 upon failure
+ */
+int disk_int13_retry(const com32sys_t * inreg, com32sys_t * outreg)
+{
+ int retry = 6; /* Number of retries */
+ com32sys_t tmpregs;
+
+ if (!outreg)
+ outreg = &tmpregs;
+
+ while (retry--) {
+ __intcall(0x13, inreg, outreg);
+ if (!(outreg->eflags.l & EFLAGS_CF))
+ return 0; /* CF=0, OK */
+ }
+
+ return -1; /* Error */
+}
+
+/**
+ * Query disk parameters and EBIOS availability for a particular disk.
+ *
+ * @v disk The INT 0x13 disk drive number to process
+ * @v diskinfo The structure to save the queried params to
+ * @ret (int) 0 upon success, -1 upon failure
+ */
+int disk_get_params(int disk, struct disk_info *const diskinfo)
+{
+ static com32sys_t inreg, outreg;
+ struct disk_ebios_eparam *eparam;
+ int rv = 0;
+
+ memset(diskinfo, 0, sizeof *diskinfo);
+ diskinfo->disk = disk;
+ diskinfo->bps = SECTOR;
+
+ /* Get EBIOS support */
+ memset(&inreg, 0, sizeof inreg);
+ inreg.eax.b[1] = 0x41;
+ inreg.ebx.w[0] = 0x55aa;
+ inreg.edx.b[0] = disk;
+ inreg.eflags.b[0] = 0x3; /* CF set */
+
+ __intcall(0x13, &inreg, &outreg);
+
+ if (!(outreg.eflags.l & EFLAGS_CF) &&
+ outreg.ebx.w[0] == 0xaa55 && (outreg.ecx.b[0] & 1)) {
+ diskinfo->ebios = 1;
+ }
+
+ eparam = lmalloc(sizeof *eparam);
+ if (!eparam)
+ return -1;
+
+ /* Get extended disk parameters if ebios == 1 */
+ if (diskinfo->ebios) {
+ memset(&inreg, 0, sizeof inreg);
+ inreg.eax.b[1] = 0x48;
+ inreg.edx.b[0] = disk;
+ inreg.esi.w[0] = OFFS(eparam);
+ inreg.ds = SEG(eparam);
+
+ memset(eparam, 0, sizeof *eparam);
+ eparam->len = sizeof *eparam;
+
+ __intcall(0x13, &inreg, &outreg);
+
+ if (!(outreg.eflags.l & EFLAGS_CF)) {
+ diskinfo->lbacnt = eparam->lbacnt;
+ if (eparam->bps)
+ diskinfo->bps = eparam->bps;
+ /*
+ * don't think about using geometry data returned by
+ * 48h, as it can differ from 08h a lot ...
+ */
+ }
+ }
+ /*
+ * Get disk parameters the old way - really only useful for hard
+ * disks, but if we have a partitioned floppy it's actually our best
+ * chance...
+ */
+ memset(&inreg, 0, sizeof inreg);
+ inreg.eax.b[1] = 0x08;
+ inreg.edx.b[0] = disk;
+
+ __intcall(0x13, &inreg, &outreg);
+
+ if (outreg.eflags.l & EFLAGS_CF) {
+ rv = diskinfo->ebios ? 0 : -1;
+ goto out;
+ }
+
+ diskinfo->spt = 0x3f & outreg.ecx.b[0];
+ diskinfo->head = 1 + outreg.edx.b[1];
+ diskinfo->cyl = 1 + (outreg.ecx.b[1] | ((outreg.ecx.b[0] & 0xc0u) << 2));
+
+ if (diskinfo->spt)
+ diskinfo->cbios = 1; /* Valid geometry */
+ else {
+ diskinfo->head = 1;
+ diskinfo->spt = 1;
+ diskinfo->cyl = 1;
+ }
+
+ if (!diskinfo->lbacnt)
+ diskinfo->lbacnt = diskinfo->cyl * diskinfo->head * diskinfo->spt;
+
+out:
+ lfree(eparam);
+ return rv;
+}
+
+/**
+ * Get disk block(s) and return a malloc'd buffer.
+ *
+ * @v diskinfo The disk drive to read from
+ * @v lba The logical block address to begin reading at
+ * @v count The number of sectors to read
+ * @ret data An allocated buffer with the read data
+ *
+ * Uses the disk number and information from diskinfo. Read count sectors
+ * from drive, starting at lba. Return a new buffer, or NULL upon failure.
+ */
+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;
+ uint32_t size = 65536;
+
+ maxcnt = (size - diskinfo->bps) / diskinfo->bps;
+ if (!count || count > maxcnt || lba + count > diskinfo->lbacnt)
+ return NULL;
+
+ memset(&inreg, 0, sizeof inreg);
+
+ buf = lmalloc(count * diskinfo->bps);
+ 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;
+
+ data = malloc(count * diskinfo->bps);
+ if (data)
+ memcpy(data, buf, count * diskinfo->bps);
+out:
+ lfree(dapa);
+ lfree(buf);
+ return data;
+}
+
+/**
+ * Write disk block(s).
+ *
+ * @v diskinfo The disk drive to write to
+ * @v lba The logical block address to begin writing at
+ * @v data The data to write
+ * @v count The number of sectors to write
+ * @ret (int) 0 upon success, -1 upon failure
+ *
+ * Uses the disk number and information from diskinfo.
+ * Write sector(s) to a disk drive, starting at lba.
+ */
+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;
+ int rv = -1;
+
+ maxcnt = (size - diskinfo->bps) / diskinfo->bps;
+ if (!count || count > maxcnt || lba + count > diskinfo->lbacnt)
+ return -1;
+
+ buf = lmalloc(count * diskinfo->bps);
+ 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;
+}
+
+/**
+ * Write disk blocks and verify they were written.
+ *
+ * @v diskinfo The disk drive to write to
+ * @v lba The logical block address to begin writing at
+ * @v buf The data to write
+ * @v count The number of sectors to write
+ * @ret rv 0 upon success, -1 upon failure
+ *
+ * Uses the disk number and information from diskinfo.
+ * Writes sectors to a disk drive starting at lba, then reads them back
+ * to verify they were written correctly.
+ */
+int disk_write_verify_sectors(const struct disk_info *const diskinfo,
+ uint64_t lba, const void *buf, uint8_t count)
+{
+ char *rb;
+ int rv;
+
+ rv = disk_write_sectors(diskinfo, lba, buf, count);
+ if (rv)
+ return rv; /* Write failure */
+ rb = disk_read_sectors(diskinfo, lba, count);
+ if (!rb)
+ return -1; /* Readback failure */
+ rv = memcmp(buf, rb, count * diskinfo->bps);
+ free(rb);
+ return rv ? -1 : 0;
+}
+
+/**
+ * Dump info about a DOS partition entry
+ *
+ * @v part The 16-byte partition entry to examine
+ */
+void disk_dos_part_dump(const struct disk_dos_part_entry *const part)
+{
+ (void)part;
+ dprintf("Partition status _____ : 0x%.2x\n"
+ "Partition CHS start\n"
+ " Cylinder ___________ : 0x%.4x (%u)\n"
+ " Head _______________ : 0x%.2x (%u)\n"
+ " Sector _____________ : 0x%.2x (%u)\n"
+ "Partition type _______ : 0x%.2x\n"
+ "Partition CHS end\n"
+ " Cylinder ___________ : 0x%.4x (%u)\n"
+ " Head _______________ : 0x%.2x (%u)\n"
+ " Sector _____________ : 0x%.2x (%u)\n"
+ "Partition LBA start __ : 0x%.8x (%u)\n"
+ "Partition LBA count __ : 0x%.8x (%u)\n"
+ "-------------------------------\n",
+ part->active_flag,
+ chs_cylinder(part->start),
+ chs_cylinder(part->start),
+ chs_head(part->start),
+ chs_head(part->start),
+ chs_sector(part->start),
+ chs_sector(part->start),
+ part->ostype,
+ chs_cylinder(part->end),
+ chs_cylinder(part->end),
+ chs_head(part->end),
+ chs_head(part->end),
+ chs_sector(part->end),
+ chs_sector(part->end),
+ part->start_lba, part->start_lba, part->length, part->length);
+}
+
+/* Trivial error message output */
+static inline void error(const char *msg)
+{
+ fputs(msg, stderr);
+}
+
+/**
+ * This walk-map effectively reverses the little-endian
+ * portions of a GPT disk/partition GUID for a string representation.
+ * There might be a better header for this...
+ */
+static const char guid_le_walk_map[] = {
+ 3, -1, -1, -1, 0,
+ 5, -1, 0,
+ 3, -1, 0,
+ 2, 1, 0,
+ 1, 1, 1, 1, 1, 1
+};
+
+/**
+ * Fill a buffer with a textual GUID representation.
+ *
+ * @v buf Points to a minimum array of 37 chars
+ * @v id The GUID to represent as text
+ *
+ * The buffer must be >= char[37] and will be populated
+ * with an ASCII NUL C string terminator.
+ * Example: 11111111-2222-3333-4444-444444444444
+ * Endian: LLLLLLLL-LLLL-LLLL-BBBB-BBBBBBBBBBBB
+ */
+void guid_to_str(char *buf, const struct guid *const id)
+{
+ unsigned int i = 0;
+ const char *walker = (const char *)id;
+
+ while (i < sizeof(guid_le_walk_map)) {
+ walker += guid_le_walk_map[i];
+ if (!guid_le_walk_map[i])
+ *buf = '-';
+ else {
+ *buf = ((*walker & 0xF0) >> 4) + '0';
+ if (*buf > '9')
+ *buf += 'A' - '9' - 1;
+ buf++;
+ *buf = (*walker & 0x0F) + '0';
+ if (*buf > '9')
+ *buf += 'A' - '9' - 1;
+ }
+ buf++;
+ i++;
+ }
+ *buf = 0;
+}
+
+/**
+ * Create a GUID structure from a textual GUID representation.
+ *
+ * @v buf Points to a GUID string to parse
+ * @v id Points to a GUID to be populated
+ * @ret (int) Returns 0 upon success, -1 upon failure
+ *
+ * The input buffer must be >= 32 hexadecimal chars and be
+ * terminated with an ASCII NUL. Returns non-zero on failure.
+ * Example: 11111111-2222-3333-4444-444444444444
+ * Endian: LLLLLLLL-LLLL-LLLL-BBBB-BBBBBBBBBBBB
+ */
+int str_to_guid(const char *buf, struct guid *const id)
+{
+ char guid_seq[sizeof(struct guid) * 2];
+ unsigned int i = 0;
+ char *walker = (char *)id;
+
+ while (*buf && i < sizeof(guid_seq)) {
+ switch (*buf) {
+ /* Skip these three characters */
+ case '{':
+ case '}':
+ case '-':
+ break;
+ default:
+ /* Copy something useful to the temp. sequence */
+ if ((*buf >= '0') && (*buf <= '9'))
+ guid_seq[i] = *buf - '0';
+ else if ((*buf >= 'A') && (*buf <= 'F'))
+ guid_seq[i] = *buf - 'A' + 10;
+ else if ((*buf >= 'a') && (*buf <= 'f'))
+ guid_seq[i] = *buf - 'a' + 10;
+ else {
+ /* Or not */
+ error("Illegal character in GUID!\n");
+ return -1;
+ }
+ i++;
+ }
+ buf++;
+ }
+ /* Check for insufficient valid characters */
+ if (i < sizeof(guid_seq)) {
+ error("Too few GUID characters!\n");
+ return -1;
+ }
+ buf = guid_seq;
+ i = 0;
+ while (i < sizeof(guid_le_walk_map)) {
+ if (!guid_le_walk_map[i])
+ i++;
+ walker += guid_le_walk_map[i];
+ *walker = *buf << 4;
+ buf++;
+ *walker |= *buf;
+ buf++;
+ i++;
+ }
+ return 0;
+}
+
+/**
+ * Display GPT partition details.
+ *
+ * @v gpt_part The GPT partition entry to display
+ */
+void disk_gpt_part_dump(const struct disk_gpt_part_entry *const gpt_part)
+{
+ unsigned int i;
+ char guid_text[37];
+
+ dprintf("----------------------------------\n"
+ "GPT part. LBA first __ : 0x%.16llx\n"
+ "GPT part. LBA last ___ : 0x%.16llx\n"
+ "GPT part. attribs ____ : 0x%.16llx\n"
+ "GPT part. name _______ : '",
+ gpt_part->lba_first, gpt_part->lba_last, gpt_part->attribs);
+ for (i = 0; i < sizeof(gpt_part->name); i++) {
+ if (gpt_part->name[i])
+ dprintf("%c", gpt_part->name[i]);
+ }
+ dprintf("'");
+ guid_to_str(guid_text, &gpt_part->type);
+ dprintf("GPT part. type GUID __ : {%s}\n", guid_text);
+ guid_to_str(guid_text, &gpt_part->uid);
+ dprintf("GPT part. unique ID __ : {%s}\n", guid_text);
+}
+
+/**
+ * Display GPT header details.
+ *
+ * @v gpt The GPT header to display
+ */
+void disk_gpt_header_dump(const struct disk_gpt_header *const gpt)
+{
+ char guid_text[37];
+
+ printf("GPT sig ______________ : '%8.8s'\n"
+ "GPT major revision ___ : 0x%.4x\n"
+ "GPT minor revision ___ : 0x%.4x\n"
+ "GPT header size ______ : 0x%.8x\n"
+ "GPT header checksum __ : 0x%.8x\n"
+ "GPT reserved _________ : '%4.4s'\n"
+ "GPT LBA current ______ : 0x%.16llx\n"
+ "GPT LBA alternative __ : 0x%.16llx\n"
+ "GPT LBA first usable _ : 0x%.16llx\n"
+ "GPT LBA last usable __ : 0x%.16llx\n"
+ "GPT LBA part. table __ : 0x%.16llx\n"
+ "GPT partition count __ : 0x%.8x\n"
+ "GPT partition size ___ : 0x%.8x\n"
+ "GPT part. table chksum : 0x%.8x\n",
+ gpt->sig,
+ gpt->rev.fields.major,
+ gpt->rev.fields.minor,
+ gpt->hdr_size,
+ gpt->chksum,
+ gpt->reserved1,
+ gpt->lba_cur,
+ gpt->lba_alt,
+ gpt->lba_first_usable,
+ gpt->lba_last_usable,
+ gpt->lba_table, gpt->part_count, gpt->part_size, gpt->table_chksum);
+ guid_to_str(guid_text, &gpt->disk_guid);
+ printf("GPT disk GUID ________ : {%s}\n", guid_text);
+}
diff --git a/com32/lib/syslinux/dump_mmap.c b/com32/lib/syslinux/dump_mmap.c
index 3f1e340b..85638cd9 100644
--- a/com32/lib/syslinux/dump_mmap.c
+++ b/com32/lib/syslinux/dump_mmap.c
@@ -28,20 +28,22 @@
/*
* dump_mmap.c
*
- * Writes a syslinux_memmap out to a specified file. This is
- * intended for debugging.
+ * Writes a syslinux_memmap out to a dprintf.
*/
#include <stdio.h>
+#include <dprintf.h>
#include <syslinux/movebits.h>
-void syslinux_dump_memmap(FILE * file, struct syslinux_memmap *memmap)
+#ifdef DEBUG
+void syslinux_dump_memmap(struct syslinux_memmap *memmap)
{
- fprintf(file, "%10s %10s %10s\n"
+ dprintf("%10s %10s %10s\n"
"--------------------------------\n", "Start", "Length", "Type");
while (memmap->next) {
- fprintf(file, "0x%08x 0x%08x %10d\n", memmap->start,
+ dprintf("0x%08x 0x%08x %10d\n", memmap->start,
memmap->next->start - memmap->start, memmap->type);
memmap = memmap->next;
}
}
+#endif
diff --git a/com32/lib/syslinux/dump_movelist.c b/com32/lib/syslinux/dump_movelist.c
index 282d0068..4042ce96 100644
--- a/com32/lib/syslinux/dump_movelist.c
+++ b/com32/lib/syslinux/dump_movelist.c
@@ -33,14 +33,17 @@
*/
#include <stdio.h>
+#include <dprintf.h>
#include <syslinux/movebits.h>
-void syslinux_dump_movelist(FILE * file, struct syslinux_movelist *ml)
+#ifdef DEBUG
+void syslinux_dump_movelist(struct syslinux_movelist *ml)
{
- fprintf(file, "%10s %10s %10s\n"
+ dprintf("%10s %10s %10s\n"
"--------------------------------\n", "Dest", "Src", "Length");
while (ml) {
- fprintf(file, "0x%08x 0x%08x 0x%08x\n", ml->dst, ml->src, ml->len);
+ dprintf("0x%08x 0x%08x 0x%08x\n", ml->dst, ml->src, ml->len);
ml = ml->next;
}
}
+#endif
diff --git a/com32/lib/syslinux/idle.c b/com32/lib/syslinux/idle.c
index 6413d331..33e8035c 100644
--- a/com32/lib/syslinux/idle.c
+++ b/com32/lib/syslinux/idle.c
@@ -33,6 +33,7 @@
#include <stddef.h>
#include <com32.h>
+#include <core.h>
#include <syslinux/pmapi.h>
#include <syslinux/idle.h>
diff --git a/com32/elflink/ldlinux/ipappend.c b/com32/lib/syslinux/ipappend.c
index 45e2c3a7..3eda48cf 100644
--- a/com32/elflink/ldlinux/ipappend.c
+++ b/com32/lib/syslinux/ipappend.c
@@ -31,18 +31,20 @@
* Get ipappend strings
*/
-#include <syslinux/firmware.h>
#include <syslinux/config.h>
+#include <klibc/compiler.h>
+#include <core.h>
struct syslinux_ipappend_strings __syslinux_ipappend_strings;
+static const char *syslinux_ipappend_string_list[32];
-void __syslinux_get_ipappend_strings(void)
+void __constructor __syslinux_get_ipappend_strings(void)
{
- char *list;
- int count;
+ unsigned int i;
- if (firmware->ipappend_strings(&list, &count)) {
- __syslinux_ipappend_strings.count = count;
- __syslinux_ipappend_strings.ptr = list;
- }
+ __syslinux_ipappend_strings.count = (size_t)numIPAppends;
+ __syslinux_ipappend_strings.ptr = syslinux_ipappend_string_list;
+
+ for (i = 0; i < (size_t)numIPAppends; i++)
+ syslinux_ipappend_string_list[i] = (const char *)(size_t)IPAppends[i];
}
diff --git a/com32/lib/syslinux/keyboard.c b/com32/lib/syslinux/keyboard.c
index feafde0d..03bd216a 100644
--- a/com32/lib/syslinux/keyboard.c
+++ b/com32/lib/syslinux/keyboard.c
@@ -26,19 +26,13 @@
* ----------------------------------------------------------------------- */
#include <syslinux/keyboard.h>
-#include <com32.h>
+#include <core.h>
struct syslinux_keyboard_map __syslinux_keyboard_map;
void __constructor __syslinux_get_keyboard_map(void)
{
- static com32sys_t reg;
-
- reg.eax.w[0] = 0x001e;
- __intcall(0x22, &reg, &reg);
- if (!(reg.eflags.l & EFLAGS_CF)) {
- __syslinux_keyboard_map.version = reg.eax.w[0];
- __syslinux_keyboard_map.length = reg.ecx.w[0];
- __syslinux_keyboard_map.map = MK_PTR(reg.es, reg.ebx.w[0]);
- }
+ __syslinux_keyboard_map.version = 1;
+ __syslinux_keyboard_map.length = sizeof(KbdMap);
+ __syslinux_keyboard_map.map = (void *)KbdMap;
}
diff --git a/com32/lib/syslinux/load_linux.c b/com32/lib/syslinux/load_linux.c
index 86ea862a..4a8a1fd3 100644
--- a/com32/lib/syslinux/load_linux.c
+++ b/com32/lib/syslinux/load_linux.c
@@ -38,23 +38,17 @@
#include <inttypes.h>
#include <string.h>
#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>
#include <syslinux/firmware.h>
-#ifndef DEBUG
-# define DEBUG 0
-#endif
-#if DEBUG
-# include <stdio.h>
-# define dprintf printf
-#else
-# define dprintf(f, ...) ((void)0)
-#endif
-
#define BOOT_MAGIC 0xAA55
#define LINUX_MAGIC ('H' + ('d' << 8) + ('r' << 16) + ('S' << 24))
#define OLD_CMDLINE_MAGIC 0xA33F
@@ -131,13 +125,16 @@ static int map_initramfs(struct syslinux_movelist **fraglist,
}
int bios_boot_linux(void *kernel_buf, size_t kernel_size,
- struct initramfs *initramfs, char *cmdline)
+ 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;
addr_t irf_size;
size_t cmdline_size, cmdline_offset;
+ struct setup_data *sdp;
struct syslinux_rm_regs regs;
struct syslinux_movelist *fraglist = NULL;
struct syslinux_memmap *mmap = NULL;
@@ -260,10 +257,8 @@ int bios_boot_linux(void *kernel_buf, size_t kernel_size,
if (!mmap || !amap)
goto bail;
-#if DEBUG
dprintf("Initial memory map:\n");
- syslinux_dump_memmap(stdout, mmap);
-#endif
+ syslinux_dump_memmap(mmap);
/* If the user has specified a memory limit, mark that as unavailable.
Question: should we mark this off-limit in the mmap as well (meaning
@@ -402,6 +397,49 @@ int bios_boot_linux(void *kernel_buf, size_t kernel_size,
}
}
+ if (setup_data) {
+ uint64_t *prev_ptr = &whdr->setup_data;
+
+ for (sdp = setup_data->next; sdp != setup_data; sdp = sdp->next) {
+ struct syslinux_memmap *ml;
+ const addr_t align_mask = 15; /* Header is 16 bytes */
+ addr_t best_addr = 0;
+ size_t size = sdp->hdr.len + sizeof(sdp->hdr);
+
+ if (!sdp->data || !sdp->hdr.len)
+ continue;
+
+ if (hdr.version < 0x0209) {
+ /* Setup data not supported */
+ errno = ENXIO; /* Kind of arbitrary... */
+ goto bail;
+ }
+
+ for (ml = amap; ml->type != SMT_END; ml = ml->next) {
+ addr_t adj_start = (ml->start + align_mask) & ~align_mask;
+ addr_t adj_end = ml->next->start & ~align_mask;
+
+ if (ml->type == SMT_FREE && adj_end - adj_start >= size)
+ best_addr = (adj_end - size) & ~align_mask;
+ }
+
+ if (!best_addr)
+ goto bail;
+
+ *prev_ptr = best_addr;
+ prev_ptr = &sdp->hdr.next;
+
+ if (syslinux_add_memmap(&amap, best_addr, size, SMT_ALLOC))
+ goto bail;
+ if (syslinux_add_movelist(&fraglist, best_addr,
+ (addr_t)&sdp->hdr, sizeof sdp->hdr))
+ goto bail;
+ if (syslinux_add_movelist(&fraglist, best_addr + sizeof sdp->hdr,
+ (addr_t)sdp->data, sdp->hdr.len))
+ goto bail;
+ }
+ }
+
/* Set up the registers on entry */
memset(&regs, 0, sizeof regs);
regs.es = regs.ds = regs.ss = regs.fs = regs.gs = real_mode_base >> 4;
@@ -410,16 +448,25 @@ int bios_boot_linux(void *kernel_buf, size_t kernel_size,
/* Linux is OK with sp = 0 = 64K, but perhaps other things aren't... */
regs.esp.w[0] = min(cmdline_offset, (size_t) 0xfff0);
-#if DEBUG
dprintf("Final memory map:\n");
- syslinux_dump_memmap(stdout, mmap);
+ syslinux_dump_memmap(mmap);
dprintf("Final available map:\n");
- syslinux_dump_memmap(stdout, amap);
+ syslinux_dump_memmap(amap);
dprintf("Initial movelist:\n");
- syslinux_dump_movelist(stdout, fraglist);
-#endif
+ syslinux_dump_movelist(fraglist);
+
+ if (video_mode != 0x0f04) {
+ /*
+ * video_mode is not "current", so if we are in graphics mode we
+ * need to revert to text mode...
+ */
+ dprintf("*** Calling syslinux_force_text_mode()...\n");
+ syslinux_force_text_mode();
+ } else {
+ dprintf("*** vga=current, not calling syslinux_force_text_mode()...\n");
+ }
syslinux_shuffle_boot_rm(fraglist, mmap, 0, &regs);
@@ -431,7 +478,15 @@ bail:
}
int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
- struct initramfs *initramfs, char *cmdline)
+ struct initramfs *initramfs,
+ struct setup_data *setup_data,
+ char *cmdline)
{
- firmware->boot_linux(kernel_buf, kernel_size, initramfs, cmdline);
+ if (!firmware->boot_linux) {
+ printf("No linux boot function registered for firmware\n");
+ return -1;
+ }
+
+ firmware->boot_linux(kernel_buf, kernel_size, initramfs,
+ setup_data, cmdline);
}
diff --git a/com32/lib/syslinux/localboot.c b/com32/lib/syslinux/localboot.c
index 3b480c71..16016a9d 100644
--- a/com32/lib/syslinux/localboot.c
+++ b/com32/lib/syslinux/localboot.c
@@ -28,15 +28,11 @@
#include <syslinux/boot.h>
#include <stddef.h>
#include <com32.h>
+#include <localboot.h>
/* This returns only on failure */
-void syslinux_local_boot(uint16_t flags)
+void syslinux_local_boot(int16_t flags)
{
- static com32sys_t ireg;
-
- ireg.eax.w[0] = 0x0014;
- ireg.edx.w[0] = flags;
-
- __intcall(0x22, &ireg, NULL);
+ local_boot(flags);
}
diff --git a/com32/lib/syslinux/movebits.c b/com32/lib/syslinux/movebits.c
index bd5ce0e8..7a05f3c1 100644
--- a/com32/lib/syslinux/movebits.c
+++ b/com32/lib/syslinux/movebits.c
@@ -48,21 +48,7 @@
#include <stdbool.h>
#include <syslinux/movebits.h>
-
-#ifndef DEBUG
-# ifdef TEST
-# define DEBUG 1
-# else
-# define DEBUG 0
-# endif
-#endif
-
-#if DEBUG
-# include <stdio.h>
-# define dprintf printf
-#else
-# define dprintf(...) ((void)0)
-#endif
+#include <dprintf.h>
static jmp_buf new_movelist_bail;
@@ -242,10 +228,8 @@ static void shuffle_dealias(struct syslinux_movelist **fraglist,
addr_t ps, pe, xs, xe, delta;
bool advance;
-#if DEBUG
dprintf("Before alias resolution:\n");
- syslinux_dump_movelist(stdout, *fraglist);
-#endif
+ syslinux_dump_movelist(*fraglist);
*postcopy = NULL;
@@ -316,12 +300,10 @@ restart:
;
}
-#if DEBUG
dprintf("After alias resolution:\n");
- syslinux_dump_movelist(stdout, *fraglist);
+ syslinux_dump_movelist(*fraglist);
dprintf("Post-shuffle copies:\n");
- syslinux_dump_movelist(stdout, *postcopy);
-#endif
+ syslinux_dump_movelist(*postcopy);
}
/*
@@ -449,12 +431,10 @@ nomem:
/* As long as there are unprocessed fragments in the chain... */
while ((fp = &frags, f = *fp)) {
-#if DEBUG
dprintf("Current free list:\n");
- syslinux_dump_memmap(stdout, mmap);
+ syslinux_dump_memmap(mmap);
dprintf("Current frag list:\n");
- syslinux_dump_movelist(stdout, frags);
-#endif
+ syslinux_dump_movelist(frags);
/* Scan for fragments which can be discarded without action. */
if (f->src == f->dst) {
@@ -692,16 +672,16 @@ int main(int argc, char *argv[])
*fep = NULL;
- printf("Input move list:\n");
- syslinux_dump_movelist(stdout, frags);
- printf("Input free list:\n");
- syslinux_dump_memmap(stdout, memmap);
+ dprintf("Input move list:\n");
+ syslinux_dump_movelist(frags);
+ dprintf("Input free list:\n");
+ syslinux_dump_memmap(memmap);
if (syslinux_compute_movelist(&moves, frags, memmap)) {
printf("Failed to compute a move sequence\n");
return 1;
} else {
- printf("Final move list:\n");
+ dprintf("Final move list:\n");
syslinux_dump_movelist(stdout, moves);
return 0;
}
diff --git a/com32/lib/syslinux/pxe_dns.c b/com32/lib/syslinux/pxe_dns.c
index 6620396f..b813b543 100644
--- a/com32/lib/syslinux/pxe_dns.c
+++ b/com32/lib/syslinux/pxe_dns.c
@@ -43,12 +43,12 @@
or -1 on invocation failure */
uint32_t pxe_dns(const char *hostname)
{
- com32sys_t regs;
union {
unsigned char b[4];
uint32_t ip;
} q;
char *lm_hostname;
+ uint32_t status;
/* Is this a dot-quad? */
if (sscanf(hostname, "%hhu.%hhu.%hhu.%hhu",
@@ -59,17 +59,9 @@ uint32_t pxe_dns(const char *hostname)
if (!lm_hostname)
return 0;
- memset(&regs, 0, sizeof regs);
- regs.eax.w[0] = 0x0010;
- regs.es = SEG(lm_hostname);
- /* regs.ebx.w[0] = OFFS(lm_hostname); */
-
- __intcall(0x22, &regs, &regs);
+ status = dns_resolv(lm_hostname);
lfree(lm_hostname);
- if (regs.eflags.l & EFLAGS_CF)
- return 0;
-
- return regs.eax.l;
+ return status;
}
diff --git a/com32/lib/syslinux/pxe_get_cached.c b/com32/lib/syslinux/pxe_get_cached.c
index 47040378..a090a4c9 100644
--- a/com32/lib/syslinux/pxe_get_cached.c
+++ b/com32/lib/syslinux/pxe_get_cached.c
@@ -43,7 +43,6 @@
int pxe_get_cached_info(int level, void **buf, size_t * len)
{
const int max_dhcp_packet = 2048;
- com32sys_t regs;
t_PXENV_GET_CACHED_INFO *gci;
void *bbuf, *nbuf;
int err;
@@ -52,12 +51,6 @@ int pxe_get_cached_info(int level, void **buf, size_t * len)
if (!gci)
return -1;
- memset(&regs, 0, sizeof regs);
- regs.eax.w[0] = 0x0009;
- regs.ebx.w[0] = PXENV_GET_CACHED_INFO;
- regs.es = SEG(gci);
- /* regs.edi.w[0] = OFFS(gci); */
-
bbuf = &gci[1];
gci->Status = PXENV_STATUS_FAILURE;
@@ -66,9 +59,9 @@ int pxe_get_cached_info(int level, void **buf, size_t * len)
gci->Buffer.seg = SEG(bbuf);
gci->Buffer.offs = OFFS(bbuf);
- __intcall(0x22, &regs, &regs);
+ err = pxe_call(PXENV_GET_CACHED_INFO, gci);
- if (regs.eflags.l & EFLAGS_CF) {
+ if (err) {
err = -1;
goto exit;
}
diff --git a/com32/lib/syslinux/pxe_get_nic.c b/com32/lib/syslinux/pxe_get_nic.c
index b301a75a..6e256f92 100644
--- a/com32/lib/syslinux/pxe_get_nic.c
+++ b/com32/lib/syslinux/pxe_get_nic.c
@@ -42,25 +42,19 @@
or -1 on invocation failure */
int pxe_get_nic_type(t_PXENV_UNDI_GET_NIC_TYPE *gnt)
{
- com32sys_t regs;
t_PXENV_UNDI_GET_NIC_TYPE *lgnt;
+ int err;
lgnt = lzalloc(sizeof *lgnt);
if (!lgnt)
return -1;
- memset(&regs, 0, sizeof regs);
- regs.eax.w[0] = 0x0009;
- regs.ebx.w[0] = PXENV_UNDI_GET_NIC_TYPE;
- regs.es = SEG(lgnt);
- /* regs.edi.w[0] = OFFS(lgnt); */
-
- __intcall(0x22, &regs, &regs);
+ err = pxe_call(PXENV_UNDI_GET_NIC_TYPE, lgnt);
memcpy(gnt, lgnt, sizeof(t_PXENV_UNDI_GET_NIC_TYPE));
lfree(lgnt);
- if (regs.eflags.l & EFLAGS_CF)
+ if (err)
return -1;
return gnt->Status;
diff --git a/com32/lib/syslinux/run_command.c b/com32/lib/syslinux/run_command.c
index a0ac9a0d..0efb61f2 100644
--- a/com32/lib/syslinux/run_command.c
+++ b/com32/lib/syslinux/run_command.c
@@ -28,21 +28,16 @@
#include <syslinux/boot.h>
#include <stddef.h>
#include <string.h>
-#include <com32.h>
+#include <core.h>
int syslinux_run_command(const char *command)
{
- static com32sys_t ireg;
char *lm_command = lstrdup(command);
if (!lm_command)
return -1;
- ireg.eax.w[0] = 0x0003;
- ireg.es = SEG(lm_command);
- /* ireg.ebx.w[0] = OFFS(lm_command); */
-
- __intcall(0x22, &ireg, NULL);
+ create_args_and_load(lm_command);
/* Should not return even on failure, but in case... */
lfree(lm_command);
diff --git a/com32/lib/syslinux/run_default.c b/com32/lib/syslinux/run_default.c
index 8dc9fbe4..0cfa5470 100644
--- a/com32/lib/syslinux/run_default.c
+++ b/com32/lib/syslinux/run_default.c
@@ -26,16 +26,14 @@
* ----------------------------------------------------------------------- */
#include <syslinux/boot.h>
+#include <core.h>
#include <stddef.h>
-#include <com32.h>
+
+extern const char *default_cmd;
__noreturn syslinux_run_default(void)
{
- static com32sys_t ireg;
-
- ireg.eax.w[0] = 0x0004;
- __intcall(0x22, &ireg, NULL);
-
+ load_kernel(default_cmd);
/* Should not return even on failure */
for (;;) ;
}
diff --git a/com32/lib/syslinux/runimage.c b/com32/lib/syslinux/runimage.c
index d5cdbc62..4391114c 100644
--- a/com32/lib/syslinux/runimage.c
+++ b/com32/lib/syslinux/runimage.c
@@ -34,15 +34,18 @@
#include <stdlib.h>
#include <string.h>
#include <syslinux/boot.h>
-#include <com32.h>
+#include <syslinux/config.h>
+#include <core.h>
+
+extern unsigned int ipappend;
void syslinux_run_kernel_image(const char *filename, const char *cmdline,
uint32_t ipappend_flags, uint32_t type)
{
- static com32sys_t ireg;
char *bbfilename = NULL;
char *bbcmdline = NULL;
+
bbfilename = lstrdup(filename);
if (!bbfilename)
goto fail;
@@ -51,16 +54,10 @@ void syslinux_run_kernel_image(const char *filename, const char *cmdline,
if (!bbcmdline)
goto fail;
+ if (syslinux_filesystem() == SYSLINUX_FS_PXELINUX)
+ ipappend = ipappend_flags;
- ireg.eax.w[0] = 0x0016;
- ireg.ds = SEG(bbfilename);
- /* ireg.esi.w[0] = OFFS(bbfilename); */
- ireg.es = SEG(bbcmdline);
- /* ireg.ebx.w[0] = OFFS(bbcmdline); */
- ireg.ecx.l = ipappend_flags;
- ireg.edx.l = type;
-
- __intcall(0x22, &ireg, 0);
+ execute(bbfilename, type);
fail:
if (bbcmdline)
diff --git a/com32/lib/syslinux/serial.c b/com32/lib/syslinux/serial.c
index 4c6c1995..bc41acfc 100644
--- a/com32/lib/syslinux/serial.c
+++ b/com32/lib/syslinux/serial.c
@@ -35,31 +35,16 @@
#include <syslinux/firmware.h>
#include <syslinux/config.h>
#include <string.h>
-#include <com32.h>
struct syslinux_serial_console_info __syslinux_serial_console_info;
-void bios_get_serial_console_info(uint16_t *iobase, uint16_t *divisor,
- uint16_t *flowctl)
-{
- static com32sys_t reg;
-
- memset(&reg, 0, sizeof reg);
- reg.eax.w[0] = 0x000b;
- __intcall(0x22, &reg, &reg);
-
- *iobase = reg.edx.w[0];
- *divisor = reg.ecx.w[0];
- *flowctl = reg.ebx.w[0];
-}
-
void __constructor __syslinux_get_serial_console_info(void)
{
- uint16_t iobase, divisor, flowctl;
+ uint16_t iobase, divisor, flowctl;
- firmware->get_serial_console_info(&iobase, &divisor, &flowctl);
+ 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;
+ __syslinux_serial_console_info.iobase = iobase;
+ __syslinux_serial_console_info.divisor = divisor;
+ __syslinux_serial_console_info.flowctl = flowctl;
}
diff --git a/com32/lib/syslinux/setup_data.c b/com32/lib/syslinux/setup_data.c
new file mode 100644
index 00000000..a36c5b61
--- /dev/null
+++ b/com32/lib/syslinux/setup_data.c
@@ -0,0 +1,47 @@
+#include <stdlib.h>
+#include <syslinux/linux.h>
+#include <syslinux/loadfile.h>
+
+struct setup_data *setup_data_init(void)
+{
+ struct setup_data *setup_data;
+
+ setup_data = zalloc(sizeof(*setup_data));
+ if (!setup_data)
+ return NULL;
+
+ setup_data->prev = setup_data->next = setup_data;
+ return setup_data;
+}
+
+int setup_data_add(struct setup_data *head, uint32_t type,
+ const void *data, size_t data_len)
+{
+ struct setup_data *setup_data;
+
+ setup_data = zalloc(sizeof(*setup_data));
+ if (!setup_data)
+ return -1;
+
+ setup_data->data = data;
+ setup_data->hdr.len = data_len;
+ setup_data->hdr.type = type;
+ setup_data->prev = head->prev;
+ setup_data->next = head;
+ head->prev->next = setup_data;
+ head->prev = setup_data;
+
+ return 0;
+}
+
+int setup_data_load(struct setup_data *head, uint32_t type,
+ const char *filename)
+{
+ void *data;
+ size_t len;
+
+ if (loadfile(filename, &data, &len))
+ return -1;
+
+ return setup_data_add(head, type, data, len);
+}
diff --git a/com32/lib/syslinux/shuffle.c b/com32/lib/syslinux/shuffle.c
index 3f300a6c..d014340c 100644
--- a/com32/lib/syslinux/shuffle.c
+++ b/com32/lib/syslinux/shuffle.c
@@ -38,27 +38,12 @@
#include <string.h>
#include <inttypes.h>
#include <com32.h>
+#include <core.h>
#include <minmax.h>
+#include <dprintf.h>
#include <syslinux/movebits.h>
#include <klibc/compiler.h>
-#ifndef DEBUG
-# define DEBUG 0
-#endif
-
-#define dprintf(f, ...) ((void)0)
-#define dprintf2(f, ...) ((void)0)
-
-#if DEBUG
-# include <stdio.h>
-# undef dprintf
-# define dprintf printf
-# if DEBUG > 1
-# undef dprintf2
-# define dprintf2 printf
-# endif
-#endif
-
struct shuffle_descriptor {
uint32_t dst, src, len;
};
@@ -68,12 +53,8 @@ static int shuffler_size;
static void __syslinux_get_shuffer_size(void)
{
if (!shuffler_size) {
- static com32sys_t reg;
-
- reg.eax.w[0] = 0x0023;
- __intcall(0x22, &reg, &reg);
-
- shuffler_size = (reg.eflags.l & EFLAGS_CF) ? 2048 : reg.ecx.w[0];
+ /* +15 padding is to guarantee alignment */
+ shuffler_size = __bcopyxx_len + 15;
}
}
diff --git a/com32/lib/syslinux/version.c b/com32/lib/syslinux/version.c
index 15b617b0..1cd2efd3 100644
--- a/com32/lib/syslinux/version.c
+++ b/com32/lib/syslinux/version.c
@@ -27,20 +27,23 @@
#include <syslinux/config.h>
#include <klibc/compiler.h>
-#include <com32.h>
+#include <core.h>
+#include <../../../version.h>
struct syslinux_version __syslinux_version;
void __constructor __syslinux_get_version(void)
{
- static com32sys_t reg;
+ __syslinux_version.version = (VERSION_MAJOR << 8) + VERSION_MINOR;
- reg.eax.w[0] = 0x0001;
- __intcall(0x22, &reg, &reg);
+ /* We no longer support the COMBOOT API */
+ __syslinux_version.max_api = 0xffff;
- __syslinux_version.version = reg.ecx.w[0];
- __syslinux_version.max_api = reg.eax.w[0];
- __syslinux_version.filesystem = reg.edx.b[0];
- __syslinux_version.version_string = MK_PTR(reg.es, reg.esi.w[0]);
- __syslinux_version.copyright_string = MK_PTR(reg.es, reg.edi.w[0]);
+ __syslinux_version.filesystem = syslinux_filesystem();
+
+ /* Skip leading CR LF */
+ __syslinux_version.version_string = &syslinux_banner[2];
+
+ /* Skip leading space */
+ __syslinux_version.copyright_string = &copyright_str[1];
}
diff --git a/com32/lib/syslinux/video/fontquery.c b/com32/lib/syslinux/video/fontquery.c
index dd5d86e3..ac1fab3f 100644
--- a/com32/lib/syslinux/video/fontquery.c
+++ b/com32/lib/syslinux/video/fontquery.c
@@ -31,24 +31,18 @@
*/
#include <syslinux/video.h>
-#include <com32.h>
+#include <graphics.h>
/*
* Returns height of font or zero if no custom font loaded
*/
int syslinux_font_query(uint8_t **font)
{
- static com32sys_t ireg;
- com32sys_t oreg;
- int height;
+ if (!UserFont)
+ return 0;
- ireg.eax.w[0] = 0x0018;
- __intcall(0x22, &ireg, &oreg);
+ *font = (uint8_t *)fontbuf;
- height = !(oreg.eflags.l & EFLAGS_CF) ? oreg.eax.b[0] : 0;
- if (height)
- *font = MK_PTR(oreg.es, oreg.ebx.w[0]);
-
- return height;
+ return VGAFontSize;
}
diff --git a/com32/lib/syslinux/video/reportmode.c b/com32/lib/syslinux/video/reportmode.c
index 57fd6fdc..2a2c5770 100644
--- a/com32/lib/syslinux/video/reportmode.c
+++ b/com32/lib/syslinux/video/reportmode.c
@@ -31,15 +31,12 @@
*/
#include <syslinux/video.h>
-#include <com32.h>
+#include <graphics.h>
void syslinux_report_video_mode(uint16_t flags, uint16_t xsize, uint16_t ysize)
{
- static com32sys_t ireg;
+ if (flags > 0x0f)
+ return;
- ireg.eax.w[0] = 0x0017;
- ireg.ebx.w[0] = flags;
- ireg.ecx.w[0] = xsize;
- ireg.edx.w[0] = ysize;
- __intcall(0x22, &ireg, NULL);
+ using_vga(flags, xsize, ysize);
}
diff --git a/com32/lib/syslinux/zonelist.c b/com32/lib/syslinux/zonelist.c
index b548211f..7034c4be 100644
--- a/com32/lib/syslinux/zonelist.c
+++ b/com32/lib/syslinux/zonelist.c
@@ -39,21 +39,7 @@
#include <stdlib.h>
#include <syslinux/align.h>
#include <syslinux/movebits.h>
-
-#ifndef DEBUG
-# ifdef TEST
-# define DEBUG 1
-# else
-# define DEBUG 0
-# endif
-#endif
-
-#if DEBUG
-# include <stdio.h>
-# define dprintf printf
-#else
-# define dprintf(...) ((void)0)
-#endif
+#include <dprintf.h>
/*
* Create an empty syslinux_memmap list.
@@ -96,10 +82,8 @@ int syslinux_add_memmap(struct syslinux_memmap **list,
struct syslinux_memmap *range;
enum syslinux_memmap_types oldtype;
-#if DEBUG
dprintf("Input memmap:\n");
- syslinux_dump_memmap(stdout, *list);
-#endif
+ syslinux_dump_memmap(*list);
/* Remove this to make len == 0 mean all of memory */
if (len == 0)
@@ -164,10 +148,8 @@ int syslinux_add_memmap(struct syslinux_memmap **list,
}
}
-#if DEBUG
dprintf("After adding (%#x,%#x,%d):\n", start, len, type);
- syslinux_dump_memmap(stdout, *list);
-#endif
+ syslinux_dump_memmap(*list);
return 0;
}
diff --git a/com32/lib/vdprintf.c b/com32/lib/vdprintf.c
index 76da012d..bcf55bb7 100644
--- a/com32/lib/vdprintf.c
+++ b/com32/lib/vdprintf.c
@@ -10,9 +10,7 @@
#include <sys/io.h>
#include <sys/cpu.h>
-#undef DEBUG
-#define DEBUG 1
-#include <dprintf.h>
+#ifdef DEBUG_PORT
#define BUFFER_SIZE 4096
@@ -31,10 +29,6 @@ enum serial_port_regs {
SCR = 7,
};
-#ifndef DEBUG_PORT
-# define DEBUG_PORT 0x03f8 /* I/O base address */
-#endif
-
static const uint16_t debug_base = DEBUG_PORT;
static void debug_putc(char c)
@@ -49,14 +43,13 @@ static void debug_putc(char c)
void vdprintf(const char *format, va_list ap)
{
- int rv, _rv;
+ int rv;
char buffer[BUFFER_SIZE];
char *p;
static bool debug_init = false;
static bool debug_ok = false;
- _rv = rv = vsnprintf(buffer, BUFFER_SIZE, format, ap);
-
+ rv = vsnprintf(buffer, BUFFER_SIZE, format, ap);
if (rv < 0)
return;
@@ -113,6 +106,6 @@ void vdprintf(const char *format, va_list ap)
p = buffer;
while (rv--)
debug_putc(*p++);
-
- _fwrite(buffer, _rv, stdout);
}
+
+#endif /* DEBUG_PORT */
diff --git a/com32/libupload/cpio.c b/com32/libupload/cpio.c
index b3e1eb78..25b464d4 100644
--- a/com32/libupload/cpio.c
+++ b/com32/libupload/cpio.c
@@ -31,7 +31,7 @@ int cpio_hdr(struct upload_backend *be, uint32_t mode, size_t datalen,
cpio_pad(be);
- sprintf(hdr, "%06o%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x",
+ sprintf(hdr, "%06o%08x%08x%08x%08x%08x%08x%08zx%08x%08x%08x%08x%08x%08x",
070701, /* c_magic */
inode++, /* c_ino */
mode, /* c_mode */
diff --git a/com32/libupload/upload_tftp.c b/com32/libupload/upload_tftp.c
index 5e73c1c5..6a0dacb7 100644
--- a/com32/libupload/upload_tftp.c
+++ b/com32/libupload/upload_tftp.c
@@ -53,7 +53,6 @@ const char *tftp_string_error_message[]={
static int send_ack_packet(struct tftp_state *tftp,
const void *pkt, size_t len)
{
- com32sys_t ireg, oreg;
t_PXENV_UDP_WRITE *uw;
t_PXENV_UDP_READ *ur;
clock_t start;
@@ -67,9 +66,6 @@ static int send_ack_packet(struct tftp_state *tftp,
uw = lmalloc(sizeof *uw + len);
ur = lmalloc(sizeof *ur + RCV_BUF);
- memset(&ireg, 0, sizeof ireg);
- ireg.eax.w[0] = 0x0009;
-
for (timeout = timeouts ; *timeout ; timeout++) {
memset(uw, 0, sizeof *uw);
memcpy(uw+1, pkt, len);
@@ -80,11 +76,7 @@ static int send_ack_packet(struct tftp_state *tftp,
uw->buffer_size = len;
uw->buffer = FAR_PTR(uw+1);
- ireg.ebx.w[0] = PXENV_UDP_WRITE;
- ireg.es = SEG(uw);
- ireg.edi.w[0] = OFFS(uw);
-
- __intcall(0x22, &ireg, &oreg);
+ pxe_call(PXENV_UDP_WRITE, uw);
start = times(NULL);
@@ -97,13 +89,9 @@ static int send_ack_packet(struct tftp_state *tftp,
ur->buffer_size = RCV_BUF;
ur->buffer = FAR_PTR(ur+1);
- ireg.ebx.w[0] = PXENV_UDP_READ;
- ireg.es = SEG(ur);
- ireg.edi.w[0] = OFFS(ur);
- __intcall(0x22, &ireg, &oreg);
+ err = pxe_call(PXENV_UDP_READ, ur);
- if (!(oreg.eflags.l & EFLAGS_CF) &&
- ur->status == PXENV_STATUS_SUCCESS &&
+ if (!err && ur->status == PXENV_STATUS_SUCCESS &&
tftp->srv_ip == ur->src_ip &&
(tftp->srv_port == 0 ||
tftp->srv_port == ur->s_port)) {
diff --git a/com32/libutil/Makefile b/com32/libutil/Makefile
index 13fb4193..93c0c11c 100644
--- a/com32/libutil/Makefile
+++ b/com32/libutil/Makefile
@@ -61,6 +61,6 @@ spotless: clean
install: all
mkdir -m 755 -p $(INSTALLROOT)$(COM32DIR)
- install -m 644 libutil_com.a libutil_lnx.a $(INSTALLROOT)$(COM32DIR)
+ install -m 644 libutil_lnx.a $(INSTALLROOT)$(COM32DIR)
-include .*.d
diff --git a/com32/lua/src/Makefile b/com32/lua/src/Makefile
index f1ffb7e6..01d1f81c 100644
--- a/com32/lua/src/Makefile
+++ b/com32/lua/src/Makefile
@@ -44,6 +44,7 @@ LIBLUA_OBJS += dmi.o
LIBLUA_OBJS += cpu.o
LIBLUA_OBJS += pci.o
LIBLUA_OBJS += vesa.o
+LIBLUA_OBJS += dhcp.o
CFLAGS += -DLUA_ANSI
diff --git a/com32/lua/src/dhcp.c b/com32/lua/src/dhcp.c
new file mode 100644
index 00000000..af948131
--- /dev/null
+++ b/com32/lua/src/dhcp.c
@@ -0,0 +1,358 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2007 H. Peter Anvin - All Rights Reserved
+ * Copyright 2011 Timothy J Gleason <timmgleason_at_gmail.com> - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * dhcp.c
+ *
+ * Adds DHCPINFO functionality to the lua.c32 binary
+ *
+ * gettable() returns a table of the BOOTP message fields returned by
+ * the DHCP server for use in a Lua pxeboot script
+ * See http://tools.ietf.org/html/rfc1542
+ *
+ * lua key value RFC key
+ * -----------------------------------------------------------------------
+ * opcode op message opcode
+ * hardware.type htype Hardware address type
+ * hardware.length hlen Hardware address length
+ * hops hops Used by relay agents
+ * transaction.id xid transaction id
+ * elapsed.seconds secs Secs elapsed since client boot
+ * flags flags DHCP Flags field
+ * client.ip.addr ciaddr client IP addr
+ * your.ip.addr yiaddr 'Your' IP addr. (from server)
+ * server.ip.addr siaddr Boot server IP addr
+ * gateway.ip.addr giaddr Relay agent IP addr
+ * client.mac chaddr Client hardware addr
+ * server.hostname sname Optl. boot server hostname
+ * boot.file file boot file name (ascii path)
+ * magic.cookie cookie Magic cookie
+ *
+ * getoptions() returns a table of the DHCP Options field of the BOOTP
+ * message returned by the DHCP server for use in a Lua pxeboot script.
+ * Many of the options are reurned formatted in as strings in a standard,
+ * recognizable format, such as IP addresses.
+ *
+ * 1, 2, and 4 byte numerical options are returned as integers.
+ *
+ * Other Options with non-standard formats are returned as strings of the
+ * raw binary number that was returned by the DHCP server and must be decoded
+ * in a Lua script
+ *
+ * The Options table returns the Option code as the key except where there
+ * are multiple values returned. In those cases, an extra key increment number
+ * is added to allow individual access to each Option value.
+ *
+ * lua key value value Name
+ * -----------------------------------------------------------------------
+ * 1 Subnet Mask
+ * 6.1 DNS Server [element 1]
+ * 6.2 DNS Server [element 2]
+ * 6.3 DNS Server [element 3]
+ * 209 PXE Configuration File
+ * 21.1 Policy Filter [element 1]
+ * 21.2 Policy Filter [element 2]
+ *
+ * Options that can have a list of values, but contain only one (like Option 6)
+ * will not return with .sub key values.
+ *
+ * Usage:
+ t = dhcp.gettable()
+
+ for k,v in pairs(t) do
+ print(k.." : "..v)
+ end
+ */
+
+#include <stdio.h>
+#include "dhcp.h"
+#include "lua.h"
+#include "lauxlib.h"
+#include "lualib.h"
+#include <syslinux/pxe.h>
+
+#define STR_BUF_SIZE 129 /* Sized to accomdate File field in BOOTP message */
+
+void
+ip_address_list(lua_State *L, uint8_t* value, uint8_t len, uint8_t option )
+{
+ static char op_name[64];
+ static char op_value[255];
+ int loop;
+
+ loop = len/4;
+
+ if ( loop == 1) {
+ sprintf(op_name, "%u", option);
+ lua_pushstring(L, op_name);
+ sprintf(op_value, "%u.%u.%u.%u", value[0], value[1], value[2], value[3]);
+ lua_pushstring(L, op_value);
+ lua_settable(L,-3);
+ } else {
+ for (int done = 0; done < loop; done++){
+ sprintf(op_name, "%u.%d", option, done+1);
+ lua_pushstring(L, op_name);
+ sprintf(op_value, "%u.%u.%u.%u", value[0+(done*4)], value[1+(done*4)], value[2+(done*4)], value[3+(done*4)]);
+ lua_pushstring(L, op_value);
+ lua_settable(L,-3);
+ }
+ }
+
+}
+
+static int dhcp_getoptions(lua_State *L)
+{
+ void* dhcpdata = 0;
+ dhcp_t* dhcp = 0;
+ size_t dhcplen = 0;
+
+ /* Append the DHCP info */
+ if (pxe_get_cached_info(PXENV_PACKET_TYPE_DHCP_ACK,
+ &dhcpdata, &dhcplen))
+ {
+ return 0;
+ }
+
+ dhcp = (dhcp_t*)dhcpdata;
+
+ lua_newtable(L);
+
+ int done = 0;
+ uint8_t* ptr = (uint8_t*)&dhcp->options;
+ uint8_t len;
+ uint8_t option;
+ uint8_t* value;
+ static char op_name[64];
+
+ do {
+ option = *ptr++;
+ len = *ptr++;
+ value = ptr;
+ ptr += len;
+ switch (option) {
+// IP Address formatted lists, including singles
+ case 1:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 16:
+ case 21: /* Policy Filters - address/mask */
+ case 28:
+ case 32:
+ case 33: /* Static routes - destination/router */
+ case 41:
+ case 42:
+ case 44:
+ case 45:
+ case 47:
+ case 48:
+ case 49:
+ case 50:
+ case 51:
+ case 54:
+ case 65:
+ case 68:
+ case 69:
+ case 70:
+ case 71:
+ case 72:
+ case 73:
+ case 74:
+ case 75:
+ case 76:
+ ip_address_list(L, value, len, option);
+ break;
+// 4byte options - numerical
+ case 2:
+ case 24:
+ case 35:
+ case 38:
+ case 58:
+ case 59:
+ case 211:
+ sprintf(op_name, "%u", option);
+ lua_pushstring(L, op_name);
+ lua_pushinteger(L, ntohl(*(long*)value));
+ lua_settable(L,-3);
+ break;
+// 2byte options -numerical
+ case 13:
+ case 22:
+ case 26:
+ case 57:
+ sprintf(op_name, "%u", option);
+ lua_pushstring(L, op_name);
+ lua_pushinteger(L, ntohs(*(short*)value));
+ lua_settable(L,-3);
+ break;
+// 1byte options - numerical
+ case 19:
+ case 20:
+ case 23:
+ case 27:
+ case 29:
+ case 30:
+ case 31:
+ case 34:
+ case 36:
+ case 37:
+ case 39:
+ case 46:
+ case 52:
+ case 53:
+ sprintf(op_name, "%u", option);
+ lua_pushstring(L, op_name);
+ lua_pushinteger(L, *value);
+ lua_settable(L,-3);
+ break;
+ case 255:
+ done = 1;
+ break;
+ default:
+ sprintf(op_name, "%u", option);
+ lua_pushstring(L, op_name);
+ lua_pushlstring(L, (const char*)value, len);
+ lua_settable(L,-3);
+ break;
+ }
+
+ } while (!done);
+
+ return 1;
+}
+
+static int dhcp_gettable(lua_State *L)
+{
+ void* dhcpdata = 0;
+ dhcp_t* dhcp = 0;
+ size_t dhcplen = 0;
+ static char dhcp_arg[STR_BUF_SIZE];
+
+ /* Append the DHCP info */
+ if (pxe_get_cached_info(PXENV_PACKET_TYPE_DHCP_ACK,
+ &dhcpdata, &dhcplen))
+ {
+ return 0;
+ }
+
+ dhcp = (dhcp_t*)dhcpdata;
+
+
+ lua_newtable(L);
+
+ lua_pushstring(L, "opcode");
+ lua_pushinteger(L, dhcp->op);
+ lua_settable(L,-3);
+
+ lua_pushstring(L, "hardware.type");
+ lua_pushinteger(L, dhcp->htype);
+ lua_settable(L,-3);
+
+ lua_pushstring(L, "hardware.length");
+ lua_pushinteger(L, dhcp->hlen);
+ lua_settable(L,-3);
+
+ lua_pushstring(L, "hops");
+ lua_pushinteger(L, dhcp->hops);
+ lua_settable(L,-3);
+
+ lua_pushstring(L, "transaction.id");
+ lua_pushinteger(L, ntohl(dhcp->xid));
+ lua_settable(L,-3);
+
+ lua_pushstring(L, "elapsed.seconds");
+ lua_pushinteger(L, ntohs(dhcp->secs));
+ lua_settable(L,-3);
+
+ lua_pushstring(L, "flags");
+ lua_pushinteger(L, ntohs(dhcp->flags));
+ lua_settable(L,-3);
+
+ sprintf(dhcp_arg, "%u.%u.%u.%u", dhcp->ciaddr[0], dhcp->ciaddr[1], dhcp->ciaddr[2], dhcp->ciaddr[3]);
+ lua_pushstring(L, "client.ip.addr");
+ lua_pushstring(L, dhcp_arg);
+ lua_settable(L,-3);
+
+ sprintf(dhcp_arg, "%u.%u.%u.%u", dhcp->yiaddr[0], dhcp->yiaddr[1], dhcp->yiaddr[2], dhcp->yiaddr[3]);
+ lua_pushstring(L, "your.ip.addr");
+ lua_pushstring(L, dhcp_arg);
+ lua_settable(L,-3);
+
+ sprintf(dhcp_arg, "%u.%u.%u.%u", dhcp->siaddr[0], dhcp->siaddr[1], dhcp->siaddr[2], dhcp->siaddr[3]);
+ lua_pushstring(L, "server.ip.addr");
+ lua_pushstring(L, dhcp_arg);
+ lua_settable(L,-3);
+
+ sprintf(dhcp_arg, "%u.%u.%u.%u", dhcp->giaddr[0], dhcp->giaddr[1], dhcp->giaddr[2], dhcp->giaddr[3]);
+ lua_pushstring(L, "gateway.ip.addr");
+ lua_pushstring(L, dhcp_arg);
+ lua_settable(L,-3);
+
+ sprintf(dhcp_arg, "%02X:%02X:%02X:%02X:%02X:%02X",
+ dhcp->chaddr[0], dhcp->chaddr[1], dhcp->chaddr[2],
+ dhcp->chaddr[3], dhcp->chaddr[4], dhcp->chaddr[5]);
+ lua_pushstring(L, "client.mac");
+ lua_pushstring(L, dhcp_arg);
+ lua_settable(L,-3);
+
+ snprintf(dhcp_arg, STR_BUF_SIZE, "%s", dhcp->sname);
+ dhcp_arg[STR_BUF_SIZE-1] = 0; /* Guarantee for lua_pushstring that dhcp_arg is 0 terminated /*/
+ lua_pushstring(L, "server.hostname");
+ lua_pushstring(L, dhcp_arg);
+ lua_settable(L,-3);
+
+ snprintf(dhcp_arg, STR_BUF_SIZE, "%s", dhcp->file);
+ dhcp_arg[STR_BUF_SIZE-1] = 0; /* Guarantee for lua_pushstring that dhcp_arg is 0 terminated /*/
+ lua_pushstring(L, "boot.file");
+ lua_pushstring(L, dhcp_arg);
+ lua_settable(L,-3);
+
+ sprintf(dhcp_arg, "%u.%u.%u.%u", dhcp->cookie[0], dhcp->cookie[1], dhcp->cookie[2], dhcp->cookie[3]);
+ lua_pushstring(L, "magic.cookie");
+ lua_pushstring(L, dhcp_arg);
+ lua_settable(L,-3);
+
+ return 1;
+}
+
+static const luaL_reg dhcplib[] = {
+ {"gettable", dhcp_gettable},
+ {"getoptions", dhcp_getoptions},
+ {NULL, NULL}
+};
+
+LUALIB_API int luaopen_dhcp (lua_State *L) {
+ luaL_openlib(L, LUA_DHCPLIBNAME, dhcplib, 0);
+ return 1;
+}
diff --git a/com32/lib/syslinux/config.c b/com32/lua/src/dhcp.h
index b27aa827..a398cfc1 100644
--- a/com32/lib/syslinux/config.c
+++ b/com32/lua/src/dhcp.h
@@ -1,6 +1,7 @@
/* ----------------------------------------------------------------------- *
*
- * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2007 H. Peter Anvin - All Rights Reserved
+ * Copyright 2011 Timothy J Gleason <timmgleason_at_gmail.com> - All Rights Reserved
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -25,17 +26,24 @@
*
* ----------------------------------------------------------------------- */
-#include <syslinux/config.h>
-#include <klibc/compiler.h>
-#include <com32.h>
+#include <stdint.h>
-const char *__syslinux_config_file;
+typedef struct dhcp {
+ uint8_t op; /* message opcode */
+ uint8_t htype; /* Hardware address type */
+ uint8_t hlen; /* Hardware address length */
+ uint8_t hops; /* Used by relay agents */
+ uint32_t xid; /* transaction id */
+ uint16_t secs; /* Secs elapsed since client boot */
+ uint16_t flags; /* DHCP Flags field */
+ uint8_t ciaddr[4]; /* client IP addr */
+ uint8_t yiaddr[4]; /* 'Your' IP addr. (from server) */
+ uint8_t siaddr[4]; /* Boot server IP addr */
+ uint8_t giaddr[4]; /* Relay agent IP addr */
+ uint8_t chaddr[16]; /* Client hardware addr */
+ uint8_t sname[64]; /* Optl. boot server hostname */
+ uint8_t file[128]; /* boot file name (ascii path) */
+ uint8_t cookie[4]; /* Magic cookie */
+ uint8_t options[1020]; /* Options */
+} dhcp_t;
-void __constructor __syslinux_get_config_file_name(void)
-{
- static com32sys_t reg;
-
- reg.eax.w[0] = 0x000e;
- __intcall(0x22, &reg, &reg);
- __syslinux_config_file = MK_PTR(reg.es, reg.ebx.w[0]);
-}
diff --git a/com32/lua/src/linit.c b/com32/lua/src/linit.c
index 6c7f63e4..6e978736 100644
--- a/com32/lua/src/linit.c
+++ b/com32/lua/src/linit.c
@@ -33,6 +33,7 @@ static const luaL_Reg lualibs[] = {
{LUA_PCILIBNAME, luaopen_pci},
{LUA_SYSLINUXLIBNAME, luaopen_syslinux},
{LUA_VESALIBNAME, luaopen_vesa},
+ {LUA_DHCPLIBNAME, luaopen_dhcp},
#endif
{NULL, NULL}
};
diff --git a/com32/lua/src/lualib.h b/com32/lua/src/lualib.h
index 0ae6ba75..40d1bf29 100644
--- a/com32/lua/src/lualib.h
+++ b/com32/lua/src/lualib.h
@@ -54,6 +54,9 @@ LUALIB_API int (luaopen_vesa) (lua_State *L);
#define LUA_CPULIBNAME "cpu"
LUALIB_API int (luaopen_cpu) (lua_State *L);
+
+#define LUA_DHCPLIBNAME "dhcp"
+LUALIB_API int (luaopen_dhcp) (lua_State *L);
#endif
/* open all previous libraries */
diff --git a/com32/lua/src/syslinux.c b/com32/lua/src/syslinux.c
index 9b207db7..af5db834 100644
--- a/com32/lua/src/syslinux.c
+++ b/com32/lua/src/syslinux.c
@@ -278,7 +278,7 @@ static int sl_boot_linux(lua_State * L)
msleep(10000);
*/
- ret = syslinux_boot_linux(kernel_data, kernel_len, initramfs, newcmdline);
+ ret = syslinux_boot_linux(kernel_data, kernel_len, initramfs, NULL, newcmdline);
printf("syslinux_boot_linux returned %d\n", ret);
@@ -405,7 +405,7 @@ static int sl_boot_it(lua_State * L)
(void)mem_limit;
return syslinux_boot_linux(kernel->data, kernel->size,
- initramfs, (char *)cmdline);
+ initramfs, NULL, (char *)cmdline);
}
static int sl_derivative(lua_State * L)
diff --git a/com32/lua/src/vesa.c b/com32/lua/src/vesa.c
index 9f281348..06649e11 100644
--- a/com32/lua/src/vesa.c
+++ b/com32/lua/src/vesa.c
@@ -17,10 +17,15 @@ static int vesa_getmodes(lua_State *L)
struct vesa_general_info *gi;
struct vesa_mode_info *mi;
int nmode = 1;
+ int rv = -1;
- /* Allocate space in the bounce buffer for these structures */
- gi = &((struct vesa_info *)__com32.cs_bounce)->gi;
- mi = &((struct vesa_info *)__com32.cs_bounce)->mi;
+ gi = lmalloc(sizeof *gi);
+ if (!gi)
+ return -1;
+
+ mi = lmalloc(sizeof *mi);
+ if (!mi)
+ goto out;
memset(&rm, 0, sizeof rm);
memset(gi, 0, sizeof *gi);
@@ -32,11 +37,15 @@ static int vesa_getmodes(lua_State *L)
__intcall(0x10, &rm, &rm);
if ( rm.eax.w[0] != 0x004F )
- return -1; /* Function call failed */
- if ( gi->signature != VESA_MAGIC )
- return -2; /* No magic */
- if ( gi->version < 0x0102 )
- return -3; /* VESA 1.2+ required */
+ goto out; /* Function call failed */
+ if ( gi->signature != VESA_MAGIC ) {
+ rv = -2; /* No magic */
+ goto out;
+ }
+ if ( gi->version < 0x0102 ) {
+ rv = -3; /* VESA 1.2+ required */
+ goto out;
+ }
lua_newtable(L); /* list of modes */
@@ -86,7 +95,11 @@ static int vesa_getmodes(lua_State *L)
}
- return 1;
+ rv = 1;
+out:
+ lfree(mi);
+ lfree(gi);
+ return rv;
}
diff --git a/com32/mboot/initvesa.c b/com32/mboot/initvesa.c
index cf2707df..bd869e3d 100644
--- a/com32/mboot/initvesa.c
+++ b/com32/mboot/initvesa.c
@@ -38,6 +38,7 @@
#include <stdlib.h>
#include <string.h>
#include <limits.h>
+#include <graphics.h>
#include "vesa.h"
#include "mboot.h"
@@ -61,9 +62,13 @@ void set_graphics_mode(const struct multiboot_header *mbh,
if (!(mbh->flags & MULTIBOOT_VIDEO_MODE) || mbh->mode_type != 0)
return;
- /* Allocate space in the bounce buffer for these structures */
- gi = &((struct vesa_info *)__com32.cs_bounce)->gi;
- mi = &((struct vesa_info *)__com32.cs_bounce)->mi;
+ gi = lmalloc(sizeof *gi);
+ if (!gi)
+ return;
+
+ mi = lmalloc(sizeof *mi);
+ if (!mi)
+ goto out;
memset(&rm, 0, sizeof rm);
memset(gi, 0, sizeof *gi);
@@ -75,11 +80,11 @@ void set_graphics_mode(const struct multiboot_header *mbh,
__intcall(0x10, &rm, &rm);
if (rm.eax.w[0] != 0x004F)
- return; /* Function call failed */
+ goto out; /* Function call failed */
if (gi->signature != VESA_MAGIC)
- return; /* No magic */
+ goto out; /* No magic */
if (gi->version < 0x0102)
- return; /* VESA 1.2+ required */
+ goto out; /* VESA 1.2+ required */
memcpy(&vesa_info.gi, gi, sizeof *gi);
@@ -182,7 +187,7 @@ void set_graphics_mode(const struct multiboot_header *mbh,
}
if (!bestpxf)
- return; /* No mode found */
+ goto out; /* No mode found */
mi = &vesa_info.mi;
mode = bestmode;
@@ -193,7 +198,7 @@ void set_graphics_mode(const struct multiboot_header *mbh,
rm.ebx.w[0] = mode;
__intcall(0x10, &rm, &rm);
if (rm.eax.w[0] != 0x004F)
- return; /* Failed to set mode */
+ goto out; /* Failed to set mode */
mbi->flags |= MB_INFO_VIDEO_INFO;
mbi->vbe_mode = mode;
@@ -211,16 +216,16 @@ void set_graphics_mode(const struct multiboot_header *mbh,
mbi->vbe_interface_len = rm.ecx.w[0];
}
- /* Tell syslinux we changed video mode */
- rm.eax.w[0] = 0x0017; /* Report video mode change */
/* In theory this should be:
-
- rm.ebx.w[0] = (mi->mode_attr & 4) ? 0x0007 : 0x000f;
-
- However, that would assume all systems that claim to handle text
- output in VESA modes actually do that... */
- rm.ebx.w[0] = 0x000f;
- rm.ecx.w[0] = vesa_info.mi.h_res;
- rm.edx.w[0] = vesa_info.mi.v_res;
- __intcall(0x22, &rm, NULL);
+ *
+ * UsingVga = (mi->mode_attr & 4) ? 0x0007 : 0x000f;
+ *
+ * However, that would assume all systems that claim to handle text
+ * output in VESA modes actually do that...
+ */
+ graphics_using_vga(0x0F, vesa_info.mi.h_res, vesa_info.mi.v_res);
+
+out:
+ lfree(mi);
+ lfree(gi);
}
diff --git a/com32/mboot/map.c b/com32/mboot/map.c
index 0a71d4c9..99add306 100644
--- a/com32/mboot/map.c
+++ b/com32/mboot/map.c
@@ -91,10 +91,9 @@ int init_map(void)
error("Failed to allocate initial memory map!\n");
return -1;
}
-#if DEBUG
+
dprintf("Initial memory map:\n");
- syslinux_dump_memmap(stdout, mmap);
-#endif
+ syslinux_dump_memmap(mmap);
return 0;
}
diff --git a/com32/mboot/mem.c b/com32/mboot/mem.c
index 6a31fac0..6e3995bf 100644
--- a/com32/mboot/mem.c
+++ b/com32/mboot/mem.c
@@ -49,9 +49,10 @@ struct e820_entry {
static int mboot_scan_memory(struct AddrRangeDesc **ardp, uint32_t * dosmem)
{
com32sys_t ireg, oreg;
- struct e820_entry *e820buf = __com32.cs_bounce;
+ struct e820_entry *e820buf;
struct AddrRangeDesc *ard;
size_t ard_count, ard_space;
+ int rv = 0;
/* Use INT 12h to get DOS memory */
__intcall(0x12, &__com32_zero_regs, &oreg);
@@ -65,10 +66,14 @@ static int mboot_scan_memory(struct AddrRangeDesc **ardp, uint32_t * dosmem)
*dosmem = 640 * 1024; /* Hope for the best... */
}
+ e820buf = lmalloc(sizeof(*e820buf));
+ if (!e820buf)
+ return 0;
+
/* Allocate initial space */
*ardp = ard = malloc(RANGE_ALLOC_BLOCK * sizeof *ard);
if (!ard)
- return 0;
+ goto out;
ard_count = 0;
ard_space = RANGE_ALLOC_BLOCK;
@@ -93,8 +98,10 @@ static int mboot_scan_memory(struct AddrRangeDesc **ardp, uint32_t * dosmem)
if (ard_count >= ard_space) {
ard_space += RANGE_ALLOC_BLOCK;
*ardp = ard = realloc(ard, ard_space * sizeof *ard);
- if (!ard)
- return ard_count;
+ if (!ard) {
+ rv = ard_count;
+ goto out;
+ }
}
ard[ard_count].size = 20;
@@ -106,8 +113,10 @@ static int mboot_scan_memory(struct AddrRangeDesc **ardp, uint32_t * dosmem)
ireg.ebx.l = oreg.ebx.l;
} while (oreg.ebx.l);
- if (ard_count)
- return ard_count;
+ if (ard_count) {
+ rv = ard_count;
+ goto out;
+ };
ard[0].size = 20;
ard[0].BaseAddr = 0;
@@ -129,10 +138,12 @@ static int mboot_scan_memory(struct AddrRangeDesc **ardp, uint32_t * dosmem)
ard[2].BaseAddr = 16 << 20;
ard[2].Length = oreg.edx.w[0] << 16;
ard[2].Type = 1;
- return 3;
+ rv = 3;
} else {
- return 2;
+ rv = 2;
}
+
+ goto out;
}
/* Finally try INT 15h AH=88h */
@@ -142,10 +153,14 @@ static int mboot_scan_memory(struct AddrRangeDesc **ardp, uint32_t * dosmem)
ard[1].BaseAddr = 1 << 20;
ard[1].Length = oreg.ecx.w[0] << 10;
ard[1].Type = 1;
- return 2;
+ rv = 2;
+ goto out;
}
- return 1; /* ... problematic ... */
+ rv = 1; /* ... problematic ... */
+out:
+ lfree(e820buf);
+ return rv;
}
void mboot_make_memmap(void)
diff --git a/com32/menu/Makefile b/com32/menu/Makefile
index d1e85ad0..2096b4c4 100644
--- a/com32/menu/Makefile
+++ b/com32/menu/Makefile
@@ -24,14 +24,14 @@ MODULES = menu.c32 vesamenu.c32
TESTFILES =
COMMONOBJS = menumain.o readconfig.o passwd.o drain.o printmsg.o colors.o \
- background.o refstr.o execute.o
+ background.o refstr.o
all: $(MODULES) $(TESTFILES)
-menu.elf : menu.o $(COMMONOBJS) $(C_LIBS)
+menu.c32 : menu.o $(COMMONOBJS) $(C_LIBS)
$(LD) $(LDFLAGS) -o $@ $^
-vesamenu.elf : vesamenu.o $(COMMONOBJS) $(C_LIBS)
+vesamenu.c32 : vesamenu.o $(COMMONOBJS) $(C_LIBS)
$(LD) $(LDFLAGS) -o $@ $^
vesamenu.c32: vesamenu.o $(COMMONOBJS) $(C_LIBS)
diff --git a/com32/menu/execute.c b/com32/menu/execute.c
deleted file mode 100644
index c2de7353..00000000
--- a/com32/menu/execute.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/* ----------------------------------------------------------------------- *
- *
- * Copyright 2004-2008 H. Peter Anvin - All Rights Reserved
- *
- * 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 <stdlib.h>
-#include <string.h>
-#include <com32.h>
-#include "menu.h"
-
-void execute(const char *cmdline, enum kernel_type type)
-{
- com32sys_t ireg;
- const char *p, *const *pp;
- char *q = __com32.cs_bounce;
- const char *kernel, *args;
-
- memset(&ireg, 0, sizeof ireg);
-
- kernel = q;
- p = cmdline;
- while (*p && !my_isspace(*p)) {
- *q++ = *p++;
- }
- *q++ = '\0';
-
- args = q;
- while (*p && my_isspace(*p))
- p++;
-
- strcpy(q, p);
-
- if (kernel[0] == '.' && type == KT_NONE) {
- /* It might be a type specifier */
- enum kernel_type type = KT_NONE;
- for (pp = kernel_types; *pp; pp++, type++) {
- if (!strcmp(kernel + 1, *pp)) {
- execute(p, type); /* Strip the type specifier and retry */
- }
- }
- }
-
- if (type == KT_LOCALBOOT) {
- ireg.eax.w[0] = 0x0014; /* Local boot */
- ireg.edx.w[0] = strtoul(kernel, NULL, 0);
- } else {
- if (type < KT_KERNEL)
- type = KT_KERNEL;
-
- ireg.eax.w[0] = 0x0016; /* Run kernel image */
- ireg.esi.w[0] = OFFS(kernel);
- ireg.ds = SEG(kernel);
- ireg.ebx.w[0] = OFFS(args);
- ireg.es = SEG(args);
- ireg.edx.l = type - KT_KERNEL;
- /* ireg.ecx.l = 0; *//* We do ipappend "manually" */
- }
-
- __intcall(0x22, &ireg, NULL);
-
- /* If this returns, something went bad; return to menu */
-}
diff --git a/com32/menu/menumain.c b/com32/menu/menumain.c
index 5b3f6bd1..c9762b27 100644
--- a/com32/menu/menumain.c
+++ b/com32/menu/menumain.c
@@ -28,7 +28,9 @@
#include <setjmp.h>
#include <limits.h>
#include <com32.h>
+#include <core.h>
#include <syslinux/adv.h>
+#include <syslinux/boot.h>
#include "menu.h"
@@ -1108,7 +1110,7 @@ int main(int argc, char *argv[])
{
const char *cmdline;
struct menu *m;
- int rows, cols;
+ int rows, cols, cursorrow;
int i;
(void)argc;
@@ -1150,16 +1152,24 @@ int main(int argc, char *argv[])
local_cursor_enable(true);
cmdline = run_menu();
- if (clearmenu)
+ if (clearmenu) {
clear_screen();
+ cursorrow = 1;
+ } else {
+ cursorrow = END_ROW;
+ }
local_cursor_enable(false);
- printf("\033[?25h\033[%d;1H\033[0m", END_ROW);
+ printf("\033[?25h\033[%d;1H\033[0m", cursorrow);
if (cmdline) {
- execute(cmdline, KT_NONE);
- if (cm->onerror)
- execute(cm->onerror, KT_NONE);
+ uint32_t type = parse_image_type(cmdline);
+
+ execute(cmdline, type);
+ if (cm->onerror) {
+ type = parse_image_type(cm->onerror);
+ execute(cm->onerror, type);
+ }
} else {
return 0; /* Exit */
}
diff --git a/com32/menu/readconfig.c b/com32/menu/readconfig.c
index 0ac2564a..69f524c4 100644
--- a/com32/menu/readconfig.c
+++ b/com32/menu/readconfig.c
@@ -35,7 +35,7 @@ struct menu *root_menu, *start_menu, *hide_menu, *menu_list;
/* These are global parameters regardless of which menu we're displaying */
int shiftkey = 0; /* Only display menu if shift key pressed */
int hiddenmenu = 0;
-int clearmenu = 0;
+int clearmenu = 1;
long long totaltimeout = 0;
const char *hide_key[KEY_MAX];
@@ -62,7 +62,7 @@ static const struct messages messages[MSG_COUNT] = {
__p; })
/* Must match enum kernel_type */
-const char *const kernel_types[] = {
+static const char *const kernel_types[] = {
"none",
"localboot",
"kernel",
@@ -744,6 +744,8 @@ static void parse_config_file(FILE * f)
refstr_put(command);
} else if ((ep = looking_at(p, "clear"))) {
clearmenu = 1;
+ } else if ((ep = looking_at(p, "noclear"))) {
+ clearmenu = 0;
} else if ((ep = is_message_name(p, &msgnr))) {
refstr_put(m->messages[msgnr]);
m->messages[msgnr] = refstrdup(skipspace(ep));
diff --git a/com32/modules/Makefile b/com32/modules/Makefile
index 9d88d75b..8d94cfec 100644
--- a/com32/modules/Makefile
+++ b/com32/modules/Makefile
@@ -19,15 +19,30 @@ topdir = ../..
MAKEDIR = $(topdir)/mk
include $(MAKEDIR)/elf.mk
-MODULES = chain.c32 config.c32 ethersel.c32 dmitest.c32 cpuidtest.c32 \
+MODULES = config.c32 ethersel.c32 dmitest.c32 cpuidtest.c32 \
disk.c32 pcitest.c32 elf.c32 linux.c32 reboot.c32 pmload.c32 \
meminfo.c32 sdi.c32 sanboot.c32 ifcpu64.c32 vesainfo.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 \
- hello.c32
+ ifcpu.c32 cpuid.c32 cat.c32 pwd.c32 ifplop.c32 zzjson.c32 \
+ whichsys.c32 hello.c32 pxechn.c32
TESTFILES =
+LDFLAGS_cpuidtest.o = $(com32)/gpllib/libcom32gpl.c32
+LDFLAGS_disk.o = $(com32)/gpllib/libcom32gpl.c32
+LDFLAGS_ethersel.o = $(com32)/lib/libcom32.c32
+LDFLAGS_gpxecmd.o = $(com32)/lib/libcom32.c32
+LDFLAGS_host.o = $(com32)/lib/libcom32.c32
+LDFLAGS_ifcpu.o = $(com32)/libutil/libutil_com.c32 \
+ $(com32)/gpllib/libcom32gpl.c32
+LDFLAGS_kbdmap.o = $(com32)/lib/libcom32.c32
+LDFLAGS_linux.o = $(com32)/lib/libcom32.c32
+LDFLAGS_pxechn.o = $(com32)/lib/libcom32.c32 \
+ $(com32)/libutil/libutil_com.c32
+LDFLAGS_sanboot.o = $(com32)/lib/libcom32.c32
+LDFLAGS_vpdtest.o = $(com32)/gpllib/libcom32gpl.c32
+LDFLAGS_zzjson.o = $(com32)/gpllib/libcom32gpl.c32
+
all: $(MODULES) $(TESTFILES)
.PRECIOUS: %.o
diff --git a/com32/modules/chain.c b/com32/modules/chain.c
deleted file mode 100644
index 09cbeff8..00000000
--- a/com32/modules/chain.c
+++ /dev/null
@@ -1,1868 +0,0 @@
-/* ----------------------------------------------------------------------- *
- *
- * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
- * Copyright 2009-2011 Intel Corporation; author: H. Peter Anvin
- * Significant portions copyright (C) 2010 Shao Miller
- * [partition iteration, GPT, "fs"]
- *
- * 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.
- *
- * ----------------------------------------------------------------------- */
-
-/*
- * chain.c
- *
- * Chainload a hard disk (currently rather braindead.)
- *
- * Usage: chain [options]
- * chain hd<disk#> [<partition>] [options]
- * chain fd<disk#> [options]
- * chain mbr:<id> [<partition>] [options]
- * chain guid:<guid> [<partition>] [options]
- * chain label:<label> [<partition>] [options]
- * chain boot [<partition>] [options]
- *
- * For example, "chain msdos=io.sys" will load DOS from the current Syslinux
- * filesystem. "chain hd0 1" will boot the first partition on the first hard
- * disk.
- *
- * When none of the "hdX", "fdX", "mbr:", "guid:", "label:", "boot" or "fs"
- * options are specified, the default behaviour is equivalent to "boot".
- * "boot" means to use the current Syslinux drive, and you can also specify
- * a partition.
- *
- * The mbr: syntax means search all the hard disks until one with a
- * specific MBR serial number (bytes 440-443) is found.
- *
- * Partitions 1-4 are primary, 5+ logical, 0 = boot MBR (default.)
- *
- * "fs" will use the current Syslinux filesystem as the boot drive/partition.
- * When booting from PXELINUX, you will most likely wish to specify a disk.
- *
- * Options:
- *
- * file=<loader>
- * loads the file <loader> **from the Syslinux filesystem**
- * instead of loading the boot sector.
- *
- * seg=<segment>
- * loads at and jumps to <seg>:0000 instead of 0000:7C00.
- *
- * isolinux=<loader>
- * chainload another version/build of the ISOLINUX bootloader and patch
- * the loader with appropriate parameters in memory.
- * This avoids the need for the -eltorito-alt-boot parameter of mkisofs,
- * when you want more than one ISOLINUX per CD/DVD.
- *
- * ntldr=<loader>
- * equivalent to seg=0x2000 file=<loader> sethidden,
- * used with WinNT's loaders
- *
- * cmldr=<loader>
- * used with Recovery Console of Windows NT/2K/XP.
- * same as ntldr=<loader> & "cmdcons\0" written to
- * the system name field in the bootsector
- *
- * freedos=<loader>
- * equivalent to seg=0x60 file=<loader> sethidden,
- * used with FreeDOS' kernel.sys.
- *
- * msdos=<loader>
- * pcdos=<loader>
- * equivalent to seg=0x70 file=<loader> sethidden,
- * used with DOS' io.sys.
- *
- * drmk=<loader>
- * Similar to msdos=<loader> but prepares the special options
- * for the Dell Real Mode Kernel.
- *
- * grub=<loader>
- * same as seg=0x800 file=<loader> & jumping to seg 0x820,
- * used with GRUB Legacy stage2 files.
- *
- * grubcfg=<filename>
- * set an alternative config filename in stage2 of Grub Legacy,
- * only applicable in combination with "grub=<loader>".
- *
- * grldr=<loader>
- * pass the partition number to GRUB4DOS,
- * used with GRUB4DOS' grldr.
- *
- * swap
- * if the disk is not fd0/hd0, install a BIOS stub which swaps
- * the drive numbers.
- *
- * hide
- * change type of primary partitions with IDs 01, 04, 06, 07,
- * 0b, 0c, or 0e to 1x, except for the selected partition, which
- * is converted the other way.
- *
- * sethidden
- * update the "hidden sectors" (partition offset) field in a
- * FAT/NTFS boot sector.
- *
- * keeppxe
- * keep the PXE and UNDI stacks in memory (PXELINUX only).
- */
-
-#include <com32.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-#include <console.h>
-#include <minmax.h>
-#include <stdbool.h>
-#include <dprintf.h>
-#include <syslinux/loadfile.h>
-#include <syslinux/bootrm.h>
-#include <syslinux/config.h>
-#include <syslinux/video.h>
-
-#define SECTOR 512 /* bytes/sector */
-
-static struct options {
- const char *loadfile;
- uint16_t keeppxe;
- uint16_t seg;
- bool isolinux;
- bool cmldr;
- bool grub;
- bool grldr;
- const char *grubcfg;
- bool swap;
- bool hide;
- bool sethidden;
- bool drmk;
-} opt;
-
-struct data_area {
- void *data;
- addr_t base;
- addr_t size;
-};
-
-static inline void error(const char *msg)
-{
- fputs(msg, stderr);
-}
-
-/*
- * Call int 13h, but with retry on failure. Especially floppies need this.
- */
-static int int13_retry(const com32sys_t * inreg, com32sys_t * outreg)
-{
- int retry = 6; /* Number of retries */
- com32sys_t tmpregs;
-
- if (!outreg)
- outreg = &tmpregs;
-
- while (retry--) {
- __intcall(0x13, inreg, outreg);
- if (!(outreg->eflags.l & EFLAGS_CF))
- return 0; /* CF=0, OK */
- }
-
- return -1; /* Error */
-}
-
-/*
- * Query disk parameters and EBIOS availability for a particular disk.
- */
-struct diskinfo {
- int disk;
- int ebios; /* EBIOS supported on this disk */
- int cbios; /* CHS geometry is valid */
- int head;
- int sect;
-} disk_info;
-
-static int get_disk_params(int disk)
-{
- static com32sys_t getparm, parm, getebios, ebios;
-
- disk_info.disk = disk;
- disk_info.ebios = disk_info.cbios = 0;
-
- /* Get EBIOS support */
- getebios.eax.w[0] = 0x4100;
- getebios.ebx.w[0] = 0x55aa;
- getebios.edx.b[0] = disk;
- getebios.eflags.b[0] = 0x3; /* CF set */
-
- __intcall(0x13, &getebios, &ebios);
-
- if (!(ebios.eflags.l & EFLAGS_CF) &&
- ebios.ebx.w[0] == 0xaa55 && (ebios.ecx.b[0] & 1)) {
- disk_info.ebios = 1;
- }
-
- /* Get disk parameters -- really only useful for
- hard disks, but if we have a partitioned floppy
- it's actually our best chance... */
- getparm.eax.b[1] = 0x08;
- getparm.edx.b[0] = disk;
-
- __intcall(0x13, &getparm, &parm);
-
- if (parm.eflags.l & EFLAGS_CF)
- return disk_info.ebios ? 0 : -1;
-
- disk_info.head = parm.edx.b[1] + 1;
- disk_info.sect = parm.ecx.b[0] & 0x3f;
- if (disk_info.sect == 0) {
- disk_info.sect = 1;
- } else {
- disk_info.cbios = 1; /* Valid geometry */
- }
-
- return 0;
-}
-
-/*
- * Get a disk block and return a malloc'd buffer.
- * Uses the disk number and information from disk_info.
- */
-struct ebios_dapa {
- uint16_t len;
- uint16_t count;
- uint16_t off;
- uint16_t seg;
- uint64_t lba;
-};
-
-/* Read count sectors from drive, starting at lba. Return a new buffer */
-static void *read_sectors(uint64_t lba, uint8_t count)
-{
- com32sys_t inreg;
- struct ebios_dapa *dapa = __com32.cs_bounce;
- void *buf = (char *)__com32.cs_bounce + SECTOR;
- void *data;
-
- if (!count)
- /* Silly */
- return NULL;
-
- memset(&inreg, 0, sizeof inreg);
-
- if (disk_info.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] = disk_info.disk;
- inreg.eax.b[1] = 0x42; /* Extended read */
- } else {
- unsigned int c, h, s, t;
-
- if (!disk_info.cbios) {
- /* We failed to get the geometry */
-
- if (lba)
- return NULL; /* Can only read MBR */
-
- s = h = c = 0;
- } else {
- s = lba % disk_info.sect;
- t = lba / disk_info.sect; /* Track = head*cyl */
- h = t % disk_info.head;
- c = t / disk_info.head;
- }
-
- if (s >= 63 || h >= 256 || c >= 1024)
- return NULL;
-
- 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] = disk_info.disk;
- inreg.ebx.w[0] = OFFS(buf);
- inreg.es = SEG(buf);
- }
-
- if (int13_retry(&inreg, NULL))
- return NULL;
-
- data = malloc(count * SECTOR);
- if (data)
- memcpy(data, buf, count * SECTOR);
- return data;
-}
-
-static int write_sector(unsigned int lba, const void *data)
-{
- com32sys_t inreg;
- struct ebios_dapa *dapa = __com32.cs_bounce;
- void *buf = (char *)__com32.cs_bounce + SECTOR;
-
- memcpy(buf, data, SECTOR);
- memset(&inreg, 0, sizeof inreg);
-
- if (disk_info.ebios) {
- dapa->len = sizeof(*dapa);
- dapa->count = 1; /* 1 sector */
- 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] = disk_info.disk;
- inreg.eax.w[0] = 0x4300; /* Extended write */
- } else {
- unsigned int c, h, s, t;
-
- if (!disk_info.cbios) {
- /* We failed to get the geometry */
-
- if (lba)
- return -1; /* Can only write MBR */
-
- s = h = c = 0;
- } else {
- s = lba % disk_info.sect;
- t = lba / disk_info.sect; /* Track = head*cyl */
- h = t % disk_info.head;
- c = t / disk_info.head;
- }
-
- if (s >= 63 || h >= 256 || c >= 1024)
- return -1;
-
- inreg.eax.w[0] = 0x0301; /* Write one sector */
- inreg.ecx.b[1] = c;
- inreg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1);
- inreg.edx.b[1] = h;
- inreg.edx.b[0] = disk_info.disk;
- inreg.ebx.w[0] = OFFS(buf);
- inreg.es = SEG(buf);
- }
-
- if (int13_retry(&inreg, NULL))
- return -1;
-
- return 0; /* ok */
-}
-
-static int write_verify_sector(unsigned int lba, const void *buf)
-{
- char *rb;
- int rv;
-
- rv = write_sector(lba, buf);
- if (rv)
- return rv; /* Write failure */
- rb = read_sectors(lba, 1);
- if (!rb)
- return -1; /* Readback failure */
- rv = memcmp(buf, rb, SECTOR);
- free(rb);
- return rv ? -1 : 0;
-}
-
-/*
- * CHS (cylinder, head, sector) value extraction macros.
- * Taken from WinVBlock. Does not expand to an lvalue
-*/
-#define chs_head(chs) chs[0]
-#define chs_sector(chs) (chs[1] & 0x3F)
-#define chs_cyl_high(chs) (((uint16_t)(chs[1] & 0xC0)) << 2)
-#define chs_cyl_low(chs) ((uint16_t)chs[2])
-#define chs_cylinder(chs) (chs_cyl_high(chs) | chs_cyl_low(chs))
-typedef uint8_t chs[3];
-
-/* A DOS partition table entry */
-struct part_entry {
- uint8_t active_flag; /* 0x80 if "active" */
- chs start;
- uint8_t ostype;
- chs end;
- uint32_t start_lba;
- uint32_t length;
-} __attribute__ ((packed));
-
-static void mbr_part_dump(const struct part_entry *part)
-{
- (void)part;
- dprintf("Partition status _____ : 0x%.2x\n"
- "Partition CHS start\n"
- " Cylinder ___________ : 0x%.4x (%u)\n"
- " Head _______________ : 0x%.2x (%u)\n"
- " Sector _____________ : 0x%.2x (%u)\n"
- "Partition type _______ : 0x%.2x\n"
- "Partition CHS end\n"
- " Cylinder ___________ : 0x%.4x (%u)\n"
- " Head _______________ : 0x%.2x (%u)\n"
- " Sector _____________ : 0x%.2x (%u)\n"
- "Partition LBA start __ : 0x%.8x (%u)\n"
- "Partition LBA count __ : 0x%.8x (%u)\n"
- "-------------------------------\n",
- part->active_flag,
- chs_cylinder(part->start),
- chs_cylinder(part->start),
- chs_head(part->start),
- chs_head(part->start),
- chs_sector(part->start),
- chs_sector(part->start),
- part->ostype,
- chs_cylinder(part->end),
- chs_cylinder(part->end),
- chs_head(part->end),
- chs_head(part->end),
- chs_sector(part->end),
- chs_sector(part->end),
- part->start_lba,
- part->start_lba,
- part->length,
- part->length);
-}
-
-/* A DOS MBR */
-struct mbr {
- char code[440];
- uint32_t disk_sig;
- char pad[2];
- struct part_entry table[4];
- uint16_t sig;
-} __attribute__ ((packed));
-static const uint16_t mbr_sig_magic = 0xAA55;
-
-/* Search for a specific drive, based on the MBR signature; bytes 440-443 */
-static int find_disk(uint32_t mbr_sig)
-{
- int drive;
- bool is_me;
- struct mbr *mbr;
-
- for (drive = 0x80; drive <= 0xff; drive++) {
- if (get_disk_params(drive))
- continue; /* Drive doesn't exist */
- if (!(mbr = read_sectors(0, 1)))
- continue; /* Cannot read sector */
- is_me = (mbr->disk_sig == mbr_sig);
- free(mbr);
- if (is_me)
- return drive;
- }
- return -1;
-}
-
-/* Forward declaration */
-struct disk_part_iter;
-
-/* Partition-/scheme-specific routine returning the next partition */
-typedef struct disk_part_iter *(*disk_part_iter_func) (struct disk_part_iter *
- part);
-
-/* Contains details for a partition under examination */
-struct disk_part_iter {
- /* The block holding the table we are part of */
- char *block;
- /* The LBA for the beginning of data */
- uint64_t lba_data;
- /* The partition number, as determined by our heuristic */
- int index;
- /* The DOS partition record to pass, if applicable */
- const struct part_entry *record;
- /* Function returning the next available partition */
- disk_part_iter_func next;
- /* Partition-/scheme-specific details */
- union {
- /* MBR specifics */
- int mbr_index;
- /* EBR specifics */
- struct {
- /* The first extended partition's start LBA */
- uint64_t lba_extended;
- /* Any applicable parent, or NULL */
- struct disk_part_iter *parent;
- /* The parent extended partition index */
- int parent_index;
- } ebr;
- /* GPT specifics */
- struct {
- /* Real (not effective) index in the partition table */
- int index;
- /* Current partition GUID */
- const struct guid *part_guid;
- /* Current partition label */
- const char *part_label;
- /* Count of entries in GPT */
- int parts;
- /* Partition record size */
- uint32_t size;
- } gpt;
- } private;
-};
-
-static struct disk_part_iter *next_ebr_part(struct disk_part_iter *part)
-{
- const struct part_entry *ebr_table;
- const struct part_entry *parent_table =
- ((const struct mbr *)part->private.ebr.parent->block)->table;
- static const struct part_entry phony = {.start_lba = 0 };
- uint64_t ebr_lba;
-
- /* Don't look for a "next EBR" the first time around */
- if (part->private.ebr.parent_index >= 0)
- /* Look at the linked list */
- ebr_table = ((const struct mbr *)part->block)->table + 1;
- /* Do we need to look for an extended partition? */
- if (part->private.ebr.parent_index < 0 || !ebr_table->start_lba) {
- /* Start looking for an extended partition in the MBR */
- while (++part->private.ebr.parent_index < 4) {
- uint8_t type = parent_table[part->private.ebr.parent_index].ostype;
-
- if ((type == 0x05) || (type == 0x0F) || (type == 0x85))
- break;
- }
- if (part->private.ebr.parent_index == 4)
- /* No extended partitions found */
- goto out_finished;
- part->private.ebr.lba_extended =
- parent_table[part->private.ebr.parent_index].start_lba;
- ebr_table = &phony;
- }
- /* Load next EBR */
- ebr_lba = ebr_table->start_lba + part->private.ebr.lba_extended;
- free(part->block);
- part->block = read_sectors(ebr_lba, 1);
- if (!part->block) {
- error("Could not load EBR!\n");
- goto err_ebr;
- }
- ebr_table = ((const struct mbr *)part->block)->table;
- dprintf("next_ebr_part:\n");
- mbr_part_dump(ebr_table);
-
- /*
- * Sanity check entry: must not extend outside the
- * extended partition. This is necessary since some OSes
- * put crap in some entries.
- */
- {
- const struct mbr *mbr =
- (const struct mbr *)part->private.ebr.parent->block;
- const struct part_entry *extended =
- mbr->table + part->private.ebr.parent_index;
-
- if (ebr_table[0].start_lba >= extended->start_lba + extended->length) {
- dprintf("Insane logical partition!\n");
- goto err_insane;
- }
- }
- /* Success */
- part->lba_data = ebr_table[0].start_lba + ebr_lba;
- dprintf("Partition %d logical lba %u\n", part->index, part->lba_data);
- part->index++;
- part->record = ebr_table;
- return part;
-
-err_insane:
-
- free(part->block);
- part->block = NULL;
-err_ebr:
-
-out_finished:
- free(part->private.ebr.parent->block);
- free(part->private.ebr.parent);
- free(part->block);
- free(part);
- return NULL;
-}
-
-static struct disk_part_iter *next_mbr_part(struct disk_part_iter *part)
-{
- struct disk_part_iter *ebr_part;
- /* Look at the partition table */
- struct part_entry *table = ((struct mbr *)part->block)->table;
-
- /* Look for data partitions */
- while (++part->private.mbr_index < 4) {
- uint8_t type = table[part->private.mbr_index].ostype;
-
- if (type == 0x00 || type == 0x05 || type == 0x0F || type == 0x85)
- /* Skip empty or extended partitions */
- continue;
- if (!table[part->private.mbr_index].length)
- /* Empty */
- continue;
- break;
- }
- /* If we're currently the last partition, it's time for EBR processing */
- if (part->private.mbr_index == 4) {
- /* Allocate another iterator for extended partitions */
- ebr_part = malloc(sizeof(*ebr_part));
- if (!ebr_part) {
- error("Could not allocate extended partition iterator!\n");
- goto err_alloc;
- }
- /* Setup EBR iterator parameters */
- ebr_part->block = NULL;
- ebr_part->index = 4;
- ebr_part->record = NULL;
- ebr_part->next = next_ebr_part;
- ebr_part->private.ebr.parent = part;
- /* Trigger an initial EBR load */
- ebr_part->private.ebr.parent_index = -1;
- /* The EBR iterator is responsible for freeing us */
- return next_ebr_part(ebr_part);
- }
- dprintf("next_mbr_part:\n");
- mbr_part_dump(table + part->private.mbr_index);
-
- /* Update parameters to reflect this new partition. Re-use iterator */
- part->lba_data = table[part->private.mbr_index].start_lba;
- dprintf("Partition %d primary lba %u\n", part->private.mbr_index, part->lba_data);
- part->index = part->private.mbr_index + 1;
- part->record = table + part->private.mbr_index;
- return part;
-
- free(ebr_part);
-err_alloc:
-
- free(part->block);
- free(part);
- return NULL;
-}
-
-/*
- * GUID
- * Be careful with endianness, you must adjust it yourself
- * iff you are directly using the fourth data chunk
- */
-struct guid {
- uint32_t data1;
- uint16_t data2;
- uint16_t data3;
- uint64_t data4;
-} __attribute__ ((packed));
-
- /*
- * This walk-map effectively reverses the little-endian
- * portions of the GUID in the output text
- */
-static const char guid_le_walk_map[] = {
- 3, -1, -1, -1, 0,
- 5, -1, 0,
- 3, -1, 0,
- 2, 1, 0,
- 1, 1, 1, 1, 1, 1
-};
-
-#if DEBUG
-/*
- * Fill a buffer with a textual GUID representation.
- * The buffer must be >= char[37] and will be populated
- * with an ASCII NUL C string terminator.
- * Example: 11111111-2222-3333-4444-444444444444
- * Endian: LLLLLLLL-LLLL-LLLL-BBBB-BBBBBBBBBBBB
- */
-static void guid_to_str(char *buf, const struct guid *id)
-{
- unsigned int i = 0;
- const char *walker = (const char *)id;
-
- while (i < sizeof(guid_le_walk_map)) {
- walker += guid_le_walk_map[i];
- if (!guid_le_walk_map[i])
- *buf = '-';
- else {
- *buf = ((*walker & 0xF0) >> 4) + '0';
- if (*buf > '9')
- *buf += 'A' - '9' - 1;
- buf++;
- *buf = (*walker & 0x0F) + '0';
- if (*buf > '9')
- *buf += 'A' - '9' - 1;
- }
- buf++;
- i++;
- }
- *buf = 0;
-}
-#endif
-
-/*
- * Create a GUID structure from a textual GUID representation.
- * The input buffer must be >= 32 hexadecimal chars and be
- * terminated with an ASCII NUL. Returns non-zero on failure.
- * Example: 11111111-2222-3333-4444-444444444444
- * Endian: LLLLLLLL-LLLL-LLLL-BBBB-BBBBBBBBBBBB
- */
-static int str_to_guid(const char *buf, struct guid *id)
-{
- char guid_seq[sizeof(struct guid) * 2];
- unsigned int i = 0;
- char *walker = (char *)id;
-
- while (*buf && i < sizeof(guid_seq)) {
- switch (*buf) {
- /* Skip these three characters */
- case '{':
- case '}':
- case '-':
- break;
- default:
- /* Copy something useful to the temp. sequence */
- if ((*buf >= '0') && (*buf <= '9'))
- guid_seq[i] = *buf - '0';
- else if ((*buf >= 'A') && (*buf <= 'F'))
- guid_seq[i] = *buf - 'A' + 10;
- else if ((*buf >= 'a') && (*buf <= 'f'))
- guid_seq[i] = *buf - 'a' + 10;
- else {
- /* Or not */
- error("Illegal character in GUID!\n");
- return -1;
- }
- i++;
- }
- buf++;
- }
- /* Check for insufficient valid characters */
- if (i < sizeof(guid_seq)) {
- error("Too few GUID characters!\n");
- return -1;
- }
- buf = guid_seq;
- i = 0;
- while (i < sizeof(guid_le_walk_map)) {
- if (!guid_le_walk_map[i])
- i++;
- walker += guid_le_walk_map[i];
- *walker = *buf << 4;
- buf++;
- *walker |= *buf;
- buf++;
- i++;
- }
- return 0;
-}
-
-/* A GPT partition */
-struct gpt_part {
- struct guid type;
- struct guid uid;
- uint64_t lba_first;
- uint64_t lba_last;
- uint64_t attribs;
- char name[72];
-} __attribute__ ((packed));
-
-static void gpt_part_dump(const struct gpt_part *gpt_part)
-{
-#ifdef DEBUG
- unsigned int i;
- char guid_text[37];
-
- dprintf("----------------------------------\n"
- "GPT part. LBA first __ : 0x%.16llx\n"
- "GPT part. LBA last ___ : 0x%.16llx\n"
- "GPT part. attribs ____ : 0x%.16llx\n"
- "GPT part. name _______ : '",
- gpt_part->lba_first, gpt_part->lba_last, gpt_part->attribs);
- for (i = 0; i < sizeof(gpt_part->name); i++) {
- if (gpt_part->name[i])
- dprintf("%c", gpt_part->name[i]);
- }
- dprintf("'");
- guid_to_str(guid_text, &gpt_part->type);
- dprintf("GPT part. type GUID __ : {%s}\n", guid_text);
- guid_to_str(guid_text, &gpt_part->uid);
- dprintf("GPT part. unique ID __ : {%s}\n", guid_text);
-#endif
- (void)gpt_part;
-}
-
-/* A GPT header */
-struct gpt {
- char sig[8];
- union {
- struct {
- uint16_t minor;
- uint16_t major;
- } fields __attribute__ ((packed));
- uint32_t uint32;
- char raw[4];
- } rev __attribute__ ((packed));
- uint32_t hdr_size;
- uint32_t chksum;
- char reserved1[4];
- uint64_t lba_cur;
- uint64_t lba_alt;
- uint64_t lba_first_usable;
- uint64_t lba_last_usable;
- struct guid disk_guid;
- uint64_t lba_table;
- uint32_t part_count;
- uint32_t part_size;
- uint32_t table_chksum;
- char reserved2[1];
-} __attribute__ ((packed));
-static const char gpt_sig_magic[] = "EFI PART";
-
-#if DEBUG
-static void gpt_dump(const struct gpt *gpt)
-{
- char guid_text[37];
-
- printf("GPT sig ______________ : '%8.8s'\n"
- "GPT major revision ___ : 0x%.4x\n"
- "GPT minor revision ___ : 0x%.4x\n"
- "GPT header size ______ : 0x%.8x\n"
- "GPT header checksum __ : 0x%.8x\n"
- "GPT reserved _________ : '%4.4s'\n"
- "GPT LBA current ______ : 0x%.16llx\n"
- "GPT LBA alternative __ : 0x%.16llx\n"
- "GPT LBA first usable _ : 0x%.16llx\n"
- "GPT LBA last usable __ : 0x%.16llx\n"
- "GPT LBA part. table __ : 0x%.16llx\n"
- "GPT partition count __ : 0x%.8x\n"
- "GPT partition size ___ : 0x%.8x\n"
- "GPT part. table chksum : 0x%.8x\n",
- gpt->sig,
- gpt->rev.fields.major,
- gpt->rev.fields.minor,
- gpt->hdr_size,
- gpt->chksum,
- gpt->reserved1,
- gpt->lba_cur,
- gpt->lba_alt,
- gpt->lba_first_usable,
- gpt->lba_last_usable,
- gpt->lba_table, gpt->part_count, gpt->part_size, gpt->table_chksum);
- guid_to_str(guid_text, &gpt->disk_guid);
- printf("GPT disk GUID ________ : {%s}\n", guid_text);
-}
-#endif
-
-static struct disk_part_iter *next_gpt_part(struct disk_part_iter *part)
-{
- const struct gpt_part *gpt_part = NULL;
-
- while (++part->private.gpt.index < part->private.gpt.parts) {
- gpt_part =
- (const struct gpt_part *)(part->block +
- (part->private.gpt.index *
- part->private.gpt.size));
- if (!gpt_part->lba_first)
- continue;
- break;
- }
- /* Were we the last partition? */
- if (part->private.gpt.index == part->private.gpt.parts) {
- goto err_last;
- }
- part->lba_data = gpt_part->lba_first;
- part->private.gpt.part_guid = &gpt_part->uid;
- part->private.gpt.part_label = gpt_part->name;
- /* Update our index */
- part->index = part->private.gpt.index + 1;
- gpt_part_dump(gpt_part);
-
- /* In a GPT scheme, we re-use the iterator */
- return part;
-
-err_last:
- free(part->block);
- free(part);
-
- return NULL;
-}
-
-static struct disk_part_iter *get_first_partition(struct disk_part_iter *part)
-{
- const struct gpt *gpt_candidate;
-
- /*
- * Ignore any passed partition iterator. The caller should
- * have passed NULL. Allocate a new partition iterator
- */
- part = malloc(sizeof(*part));
- if (!part) {
- error("Count not allocate partition iterator!\n");
- goto err_alloc_iter;
- }
- /* Read MBR */
- part->block = read_sectors(0, 2);
- if (!part->block) {
- error("Could not read two sectors!\n");
- goto err_read_mbr;
- }
- /* Check for an MBR */
- if (((struct mbr *)part->block)->sig != mbr_sig_magic) {
- error("No MBR magic!\n");
- goto err_mbr;
- }
- /* Establish a pseudo-partition for the MBR (index 0) */
- part->index = 0;
- part->record = NULL;
- part->private.mbr_index = -1;
- part->next = next_mbr_part;
- /* Check for a GPT disk */
- gpt_candidate = (const struct gpt *)(part->block + SECTOR);
- if (!memcmp(gpt_candidate->sig, gpt_sig_magic, sizeof(gpt_sig_magic))) {
- /* LBA for partition table */
- uint64_t lba_table;
-
- /* It looks like one */
- /* TODO: Check checksum. Possibly try alternative GPT */
-#if DEBUG
- puts("Looks like a GPT disk.");
- gpt_dump(gpt_candidate);
-#endif
- /* TODO: Check table checksum (maybe) */
- /* Note relevant GPT details */
- part->next = next_gpt_part;
- part->private.gpt.index = -1;
- part->private.gpt.parts = gpt_candidate->part_count;
- part->private.gpt.size = gpt_candidate->part_size;
- lba_table = gpt_candidate->lba_table;
- gpt_candidate = NULL;
- /* Load the partition table */
- free(part->block);
- part->block =
- read_sectors(lba_table,
- ((part->private.gpt.size * part->private.gpt.parts) +
- SECTOR - 1) / SECTOR);
- if (!part->block) {
- error("Could not read GPT partition list!\n");
- goto err_gpt_table;
- }
- }
- /* Return the pseudo-partition's next partition, which is real */
- return part->next(part);
-
-err_gpt_table:
-
-err_mbr:
-
- free(part->block);
- part->block = NULL;
-err_read_mbr:
-
- free(part);
-err_alloc_iter:
-
- return NULL;
-}
-
-/*
- * Search for a specific drive/partition, based on the GPT GUID.
- * We return the disk drive number if found, as well as populating the
- * boot_part pointer with the matching partition, if applicable.
- * If no matching partition is found or the GUID is a disk GUID,
- * boot_part will be populated with NULL. If not matching disk is
- * found, we return -1.
- */
-static int find_by_guid(const struct guid *gpt_guid,
- struct disk_part_iter **boot_part)
-{
- int drive;
- bool is_me;
- struct gpt *header;
-
- for (drive = 0x80; drive <= 0xff; drive++) {
- if (get_disk_params(drive))
- continue; /* Drive doesn't exist */
- if (!(header = read_sectors(1, 1)))
- continue; /* Cannot read sector */
- if (memcmp(&header->sig, gpt_sig_magic, sizeof(gpt_sig_magic))) {
- /* Not a GPT disk */
- free(header);
- continue;
- }
-#if DEBUG
- gpt_dump(header);
-#endif
- is_me = !memcmp(&header->disk_guid, gpt_guid, sizeof(*gpt_guid));
- free(header);
- if (!is_me) {
- /* Check for a matching partition */
- boot_part[0] = get_first_partition(NULL);
- while (boot_part[0]) {
- is_me =
- !memcmp(boot_part[0]->private.gpt.part_guid, gpt_guid,
- sizeof(*gpt_guid));
- if (is_me)
- break;
- boot_part[0] = boot_part[0]->next(boot_part[0]);
- }
- } else
- boot_part[0] = NULL;
- if (is_me)
- return drive;
- }
- return -1;
-}
-
-/*
- * Search for a specific partition, based on the GPT label.
- * We return the disk drive number if found, as well as populating the
- * boot_part pointer with the matching partition, if applicable.
- * If no matching partition is found, boot_part will be populated with
- * NULL and we return -1.
- */
-static int find_by_label(const char *label, struct disk_part_iter **boot_part)
-{
- int drive;
- bool is_me;
-
- for (drive = 0x80; drive <= 0xff; drive++) {
- if (get_disk_params(drive))
- continue; /* Drive doesn't exist */
- /* Check for a GPT disk */
- boot_part[0] = get_first_partition(NULL);
- if (!(boot_part[0]->next == next_gpt_part)) {
- /* Not a GPT disk */
- while (boot_part[0]) {
- /* Run through until the end */
- boot_part[0] = boot_part[0]->next(boot_part[0]);
- }
- continue;
- }
- /* Check for a matching partition */
- while (boot_part[0]) {
- char gpt_label[sizeof(((struct gpt_part *) NULL)->name)];
- const char *gpt_label_scanner =
- boot_part[0]->private.gpt.part_label;
- int j = 0;
-
- /* Re-write the GPT partition label as ASCII */
- while (gpt_label_scanner <
- boot_part[0]->private.gpt.part_label + sizeof(gpt_label)) {
- if ((gpt_label[j] = *gpt_label_scanner))
- j++;
- gpt_label_scanner++;
- }
- if ((is_me = !strcmp(label, gpt_label)))
- break;
- boot_part[0] = boot_part[0]->next(boot_part[0]);
- }
- if (is_me)
- return drive;
- }
-
- return -1;
-}
-
-static void do_boot(struct data_area *data, int ndata,
- struct syslinux_rm_regs *regs)
-{
- uint16_t *const bios_fbm = (uint16_t *) 0x413;
- addr_t dosmem = *bios_fbm << 10; /* Technically a low bound */
- struct syslinux_memmap *mmap;
- struct syslinux_movelist *mlist = NULL;
- addr_t endimage;
- uint8_t driveno = regs->edx.b[0];
- uint8_t swapdrive = driveno & 0x80;
- int i;
-
- mmap = syslinux_memory_map();
-
- if (!mmap) {
- error("Cannot read system memory map\n");
- return;
- }
-
- endimage = 0;
- for (i = 0; i < ndata; i++) {
- if (data[i].base + data[i].size > endimage)
- endimage = data[i].base + data[i].size;
- }
- if (endimage > dosmem)
- goto too_big;
-
- for (i = 0; i < ndata; i++) {
- if (syslinux_add_movelist(&mlist, data[i].base,
- (addr_t) data[i].data, data[i].size))
- goto enomem;
- }
-
- if (opt.swap && driveno != swapdrive) {
- static const uint8_t swapstub_master[] = {
- /* The actual swap code */
- 0x53, /* 00: push bx */
- 0x0f, 0xb6, 0xda, /* 01: movzx bx,dl */
- 0x2e, 0x8a, 0x57, 0x60, /* 04: mov dl,[cs:bx+0x60] */
- 0x5b, /* 08: pop bx */
- 0xea, 0, 0, 0, 0, /* 09: jmp far 0:0 */
- 0x90, 0x90, /* 0E: nop; nop */
- /* Code to install this in the right location */
- /* Entry with DS = CS; ES = SI = 0; CX = 256 */
- 0x26, 0x66, 0x8b, 0x7c, 0x4c, /* 10: mov edi,[es:si+4*0x13] */
- 0x66, 0x89, 0x3e, 0x0a, 0x00, /* 15: mov [0x0A],edi */
- 0x26, 0x8b, 0x3e, 0x13, 0x04, /* 1A: mov di,[es:0x413] */
- 0x4f, /* 1F: dec di */
- 0x26, 0x89, 0x3e, 0x13, 0x04, /* 20: mov [es:0x413],di */
- 0x66, 0xc1, 0xe7, 0x16, /* 25: shl edi,16+6 */
- 0x26, 0x66, 0x89, 0x7c, 0x4c, /* 29: mov [es:si+4*0x13],edi */
- 0x66, 0xc1, 0xef, 0x10, /* 2E: shr edi,16 */
- 0x8e, 0xc7, /* 32: mov es,di */
- 0x31, 0xff, /* 34: xor di,di */
- 0xf3, 0x66, 0xa5, /* 36: rep movsd */
- 0xbe, 0, 0, /* 39: mov si,0 */
- 0xbf, 0, 0, /* 3C: mov di,0 */
- 0x8e, 0xde, /* 3F: mov ds,si */
- 0x8e, 0xc7, /* 41: mov es,di */
- 0x66, 0xb9, 0, 0, 0, 0, /* 43: mov ecx,0 */
- 0x66, 0xbe, 0, 0, 0, 0, /* 49: mov esi,0 */
- 0x66, 0xbf, 0, 0, 0, 0, /* 4F: mov edi,0 */
- 0xea, 0, 0, 0, 0, /* 55: jmp 0:0 */
- /* pad out to segment boundary */
- 0x90, 0x90, /* 5A: ... */
- 0x90, 0x90, 0x90, 0x90, /* 5C: ... */
- };
- static uint8_t swapstub[1024];
- uint8_t *p;
-
- /* Note: we can't rely on either INT 13h nor the dosmem
- vector to be correct at this stage, so we have to use an
- installer stub to put things in the right place.
- Round the installer location to a 1K boundary so the only
- possible overlap is the identity mapping. */
- endimage = (endimage + 1023) & ~1023;
-
- /* Create swap stub */
- memcpy(swapstub, swapstub_master, sizeof swapstub_master);
- *(uint16_t *) & swapstub[0x3a] = regs->ds;
- *(uint16_t *) & swapstub[0x3d] = regs->es;
- *(uint32_t *) & swapstub[0x45] = regs->ecx.l;
- *(uint32_t *) & swapstub[0x4b] = regs->esi.l;
- *(uint32_t *) & swapstub[0x51] = regs->edi.l;
- *(uint16_t *) & swapstub[0x56] = regs->ip;
- *(uint16_t *) & swapstub[0x58] = regs->cs;
- p = &swapstub[sizeof swapstub_master];
-
- /* Mapping table; start out with identity mapping everything */
- for (i = 0; i < 256; i++)
- p[i] = i;
-
- /* And the actual swap */
- p[driveno] = swapdrive;
- p[swapdrive] = driveno;
-
- /* Adjust registers */
- regs->ds = regs->cs = endimage >> 4;
- regs->es = regs->esi.l = 0;
- regs->ecx.l = sizeof swapstub >> 2;
- regs->ip = 0x10; /* Installer offset */
- regs->ebx.b[0] = regs->edx.b[0] = swapdrive;
-
- if (syslinux_add_movelist(&mlist, endimage, (addr_t) swapstub,
- sizeof swapstub))
- goto enomem;
-
- endimage += sizeof swapstub;
- }
-
- /* Tell the shuffler not to muck with this area... */
- syslinux_add_memmap(&mmap, endimage, 0xa0000 - endimage, SMT_RESERVED);
-
- /* Force text mode */
- syslinux_force_text_mode();
-
- fputs("Booting...\n", stdout);
- syslinux_shuffle_boot_rm(mlist, mmap, opt.keeppxe, regs);
- error("Chainboot failed!\n");
- return;
-
-too_big:
- error("Loader file too large\n");
- return;
-
-enomem:
- error("Out of memory\n");
- return;
-}
-
-static int hide_unhide(struct mbr *mbr, int part)
-{
- int i;
- struct part_entry *pt;
- const uint16_t mask =
- (1 << 0x01) | (1 << 0x04) | (1 << 0x06) | (1 << 0x07) | (1 << 0x0b) | (1
- <<
- 0x0c)
- | (1 << 0x0e);
- uint8_t t;
- bool write_back = false;
-
- for (i = 1; i <= 4; i++) {
- pt = mbr->table + i - 1;
- t = pt->ostype;
- if ((t <= 0x1f) && ((mask >> (t & ~0x10)) & 1)) {
- /* It's a hideable partition type */
- if (i == part)
- t &= ~0x10; /* unhide */
- else
- t |= 0x10; /* hide */
- }
- if (t != pt->ostype) {
- write_back = true;
- pt->ostype = t;
- }
- }
-
- if (write_back)
- return write_verify_sector(0, mbr);
-
- return 0; /* ok */
-}
-
-static uint32_t get_file_lba(const char *filename)
-{
- com32sys_t inregs;
- uint32_t lba;
-
- /* Start with clean registers */
- memset(&inregs, 0, sizeof(com32sys_t));
-
- /* Put the filename in the bounce buffer */
- strlcpy(__com32.cs_bounce, filename, __com32.cs_bounce_size);
-
- /* Call comapi_open() which returns a structure pointer in SI
- * to a structure whose first member happens to be the LBA.
- */
- inregs.eax.w[0] = 0x0006;
- inregs.esi.w[0] = OFFS(__com32.cs_bounce);
- inregs.es = SEG(__com32.cs_bounce);
- __com32.cs_intcall(0x22, &inregs, &inregs);
-
- if ((inregs.eflags.l & EFLAGS_CF) || inregs.esi.w[0] == 0) {
- return 0; /* Filename not found */
- }
-
- /* Since the first member is the LBA, we simply cast */
- lba = *((uint32_t *) MK_PTR(inregs.ds, inregs.esi.w[0]));
-
- /* Clean the registers for the next call */
- memset(&inregs, 0, sizeof(com32sys_t));
-
- /* Put the filename in the bounce buffer */
- strlcpy(__com32.cs_bounce, filename, __com32.cs_bounce_size);
-
- /* Call comapi_close() to free the structure */
- inregs.eax.w[0] = 0x0008;
- inregs.esi.w[0] = OFFS(__com32.cs_bounce);
- inregs.es = SEG(__com32.cs_bounce);
- __com32.cs_intcall(0x22, &inregs, &inregs);
-
- return lba;
-}
-
-static void usage(void)
-{
- static const char usage[] = "\
-Usage: chain.c32 [options]\n\
- chain.c32 hd<disk#> [<partition>] [options]\n\
- chain.c32 fd<disk#> [options]\n\
- chain.c32 mbr:<id> [<partition>] [options]\n\
- chain.c32 guid:<guid> [<partition>] [options]\n\
- chain.c32 label:<label> [<partition>] [options]\n\
- chain.c32 boot [<partition>] [options]\n\
- chain.c32 fs [options]\n\
-Options: file=<loader> Load and execute file, instead of boot sector\n\
- isolinux=<loader> Load another version of ISOLINUX\n\
- ntldr=<loader> Load Windows NTLDR, SETUPLDR.BIN or BOOTMGR\n\
- cmldr=<loader> Load Recovery Console of Windows NT/2K/XP/2003\n\
- freedos=<loader> Load FreeDOS KERNEL.SYS\n\
- msdos=<loader> Load MS-DOS IO.SYS\n\
- pcdos=<loader> Load PC-DOS IBMBIO.COM\n\
- drmk=<loader> Load DRMK DELLBIO.BIN\n\
- grub=<loader> Load GRUB Legacy stage2\n\
- grubcfg=<filename> Set alternative config filename for GRUB Legacy\n\
- grldr=<loader> Load GRUB4DOS grldr\n\
- seg=<segment> Jump to <seg>:0000, instead of 0000:7C00\n\
- swap Swap drive numbers, if bootdisk is not fd0/hd0\n\
- hide Hide primary partitions, except selected partition\n\
- sethidden Set the FAT/NTFS hidden sectors field\n\
- keeppxe Keep the PXE and UNDI stacks in memory (PXELINUX)\n\
-See syslinux/com32/modules/chain.c for more information\n";
- error(usage);
-}
-
-int main(int argc, char *argv[])
-{
- struct mbr *mbr = NULL;
- char *p;
- struct disk_part_iter *cur_part = NULL;
- struct syslinux_rm_regs regs;
- char *drivename, *partition;
- int hd, drive, whichpart = 0; /* MBR by default */
- int i;
- uint64_t fs_lba = 0; /* Syslinux partition */
- uint32_t file_lba = 0;
- struct guid gpt_guid;
- unsigned char *isolinux_bin;
- uint32_t *checksum, *chkhead, *chktail;
- struct data_area data[3];
- int ndata = 0;
- addr_t load_base;
- static const char cmldr_signature[8] = "cmdcons";
-
- drivename = "boot";
- partition = NULL;
-
- /* Prepare the register set */
- memset(&regs, 0, sizeof regs);
-
- for (i = 1; i < argc; i++) {
- if (!strncmp(argv[i], "file=", 5)) {
- opt.loadfile = argv[i] + 5;
- } else if (!strncmp(argv[i], "seg=", 4)) {
- uint32_t segval = strtoul(argv[i] + 4, NULL, 0);
- if (segval < 0x50 || segval > 0x9f000) {
- error("Invalid segment\n");
- goto bail;
- }
- opt.seg = segval;
- } else if (!strncmp(argv[i], "isolinux=", 9)) {
- opt.loadfile = argv[i] + 9;
- opt.isolinux = true;
- } else if (!strncmp(argv[i], "ntldr=", 6)) {
- opt.seg = 0x2000; /* NTLDR wants this address */
- opt.loadfile = argv[i] + 6;
- opt.sethidden = true;
- } else if (!strncmp(argv[i], "cmldr=", 6)) {
- opt.seg = 0x2000; /* CMLDR wants this address */
- opt.loadfile = argv[i] + 6;
- opt.cmldr = true;
- opt.sethidden = true;
- } else if (!strncmp(argv[i], "freedos=", 8)) {
- opt.seg = 0x60; /* FREEDOS wants this address */
- opt.loadfile = argv[i] + 8;
- opt.sethidden = true;
- } else if (!strncmp(argv[i], "msdos=", 6) ||
- !strncmp(argv[i], "pcdos=", 6)) {
- opt.seg = 0x70; /* MS-DOS 2.0+ wants this address */
- opt.loadfile = argv[i] + 6;
- opt.sethidden = true;
- } else if (!strncmp(argv[i], "drmk=", 5)) {
- opt.seg = 0x70; /* DRMK wants this address */
- opt.loadfile = argv[i] + 5;
- opt.sethidden = true;
- opt.drmk = true;
- } else if (!strncmp(argv[i], "grub=", 5)) {
- opt.seg = 0x800; /* stage2 wants this address */
- opt.loadfile = argv[i] + 5;
- opt.grub = true;
- } else if (!strncmp(argv[i], "grubcfg=", 8)) {
- opt.grubcfg = argv[i] + 8;
- } else if (!strncmp(argv[i], "grldr=", 6)) {
- opt.loadfile = argv[i] + 6;
- opt.grldr = true;
- } else if (!strcmp(argv[i], "swap")) {
- opt.swap = true;
- } else if (!strcmp(argv[i], "noswap")) {
- opt.swap = false;
- } else if (!strcmp(argv[i], "hide")) {
- opt.hide = true;
- } else if (!strcmp(argv[i], "nohide")) {
- opt.hide = false;
- } else if (!strcmp(argv[i], "keeppxe")) {
- opt.keeppxe = 3;
- } else if (!strcmp(argv[i], "sethidden")) {
- opt.sethidden = true;
- } else if (!strcmp(argv[i], "nosethidden")) {
- opt.sethidden = false;
- } else if (((argv[i][0] == 'h' || argv[i][0] == 'f')
- && argv[i][1] == 'd')
- || !strncmp(argv[i], "mbr:", 4)
- || !strncmp(argv[i], "mbr=", 4)
- || !strncmp(argv[i], "guid:", 5)
- || !strncmp(argv[i], "guid=", 5)
- || !strncmp(argv[i], "uuid:", 5)
- || !strncmp(argv[i], "uuid=", 5)
- || !strncmp(argv[i], "label:", 6)
- || !strncmp(argv[i], "label=", 6)
- || !strcmp(argv[i], "boot")
- || !strncmp(argv[i], "boot,", 5)
- || !strcmp(argv[i], "fs")) {
- drivename = argv[i];
- p = strchr(drivename, ',');
- if (p) {
- *p = '\0';
- partition = p + 1;
- } else if (argv[i + 1] && argv[i + 1][0] >= '0'
- && argv[i + 1][0] <= '9') {
- partition = argv[++i];
- }
- } else {
- usage();
- goto bail;
- }
- }
-
- if (opt.grubcfg && !opt.grub) {
- error("grubcfg=<filename> must be used together with grub=<loader>.\n");
- goto bail;
- }
-
- if (opt.seg) {
- regs.es = regs.cs = regs.ss = regs.ds = regs.fs = regs.gs = opt.seg;
- } else {
- regs.ip = regs.esp.l = 0x7c00;
- }
-
- hd = 0;
- if (!strncmp(drivename, "mbr", 3)) {
- drive = find_disk(strtoul(drivename + 4, NULL, 0));
- if (drive == -1) {
- error("Unable to find requested MBR signature\n");
- goto bail;
- }
- } else if (!strncmp(drivename, "guid", 4) ||
- !strncmp(drivename, "uuid", 4)) {
- if (str_to_guid(drivename + 5, &gpt_guid))
- goto bail;
- drive = find_by_guid(&gpt_guid, &cur_part);
- if (drive == -1) {
- error("Unable to find requested GPT disk/partition\n");
- goto bail;
- }
- } else if (!strncmp(drivename, "label", 5)) {
- if (!drivename[6]) {
- error("No label specified.\n");
- goto bail;
- }
- drive = find_by_label(drivename + 6, &cur_part);
- if (drive == -1) {
- error("Unable to find requested partition by label\n");
- goto bail;
- }
- } else if ((drivename[0] == 'h' || drivename[0] == 'f') &&
- drivename[1] == 'd') {
- hd = drivename[0] == 'h';
- drivename += 2;
- drive = (hd ? 0x80 : 0) | strtoul(drivename, NULL, 0);
- } else if (!strcmp(drivename, "boot") || !strcmp(drivename, "fs")) {
- const union syslinux_derivative_info *sdi;
-
- sdi = syslinux_derivative_info();
- if (sdi->c.filesystem == SYSLINUX_FS_PXELINUX)
- drive = 0x80; /* Boot drive not available */
- else
- drive = sdi->disk.drive_number;
- if (!strcmp(drivename, "fs")
- && (sdi->c.filesystem == SYSLINUX_FS_SYSLINUX
- || sdi->c.filesystem == SYSLINUX_FS_EXTLINUX
- || sdi->c.filesystem == SYSLINUX_FS_ISOLINUX))
- /* We should lookup the Syslinux partition number and use it */
- fs_lba = *sdi->disk.partoffset;
- } else {
- error("Unparsable drive specification\n");
- goto bail;
- }
-
- /* DOS kernels want the drive number in BL instead of DL. Indulge them. */
- regs.ebx.b[0] = regs.edx.b[0] = drive;
-
- /* Get the disk geometry and disk access setup */
- if (get_disk_params(drive)) {
- error("Cannot get disk parameters\n");
- goto bail;
- }
-
- /* Get MBR */
- if (!(mbr = read_sectors(0, 1))) {
- error("Cannot read Master Boot Record or sector 0\n");
- goto bail;
- }
-
- if (partition)
- whichpart = strtoul(partition, NULL, 0);
- /* "guid:" or "label:" might have specified a partition */
- if (cur_part)
- whichpart = cur_part->index;
-
- /* Boot the MBR by default */
- if (!cur_part && (whichpart || fs_lba)) {
- /* Boot a partition, possibly the Syslinux partition itself */
- cur_part = get_first_partition(NULL);
- while (cur_part) {
- if ((cur_part->index == whichpart)
- || (cur_part->lba_data == fs_lba))
- /* Found the partition to boot */
- break;
- cur_part = cur_part->next(cur_part);
- }
- if (!cur_part) {
- error("Requested partition not found!\n");
- goto bail;
- }
- whichpart = cur_part->index;
- }
-
- if (!(drive & 0x80) && whichpart) {
- error("Warning: Partitions of floppy devices may not work\n");
- }
-
- /*
- * GRLDR of GRUB4DOS wants the partition number in DH:
- * -1: whole drive (default)
- * 0-3: primary partitions
- * 4-*: logical partitions
- */
- if (opt.grldr)
- regs.edx.b[1] = whichpart - 1;
-
- if (opt.hide) {
- if (whichpart < 1 || whichpart > 4)
- error("WARNING: hide specified without a non-primary partition\n");
- if (hide_unhide(mbr, whichpart))
- error("WARNING: failed to write MBR for 'hide'\n");
- }
-
- /* Do the actual chainloading */
- load_base = opt.seg ? (opt.seg << 4) : 0x7c00;
-
- if (opt.loadfile) {
- fputs("Loading the boot file...\n", stdout);
- if (loadfile(opt.loadfile, &data[ndata].data, &data[ndata].size)) {
- error("Failed to load the boot file\n");
- goto bail;
- }
- data[ndata].base = load_base;
- load_base = 0x7c00; /* If we also load a boot sector */
-
- /* Create boot info table: needed when you want to chainload
- another version of ISOLINUX (or another bootlaoder that needs
- the -boot-info-table switch of mkisofs)
- (will only work when run from ISOLINUX) */
- if (opt.isolinux) {
- const union syslinux_derivative_info *sdi;
- sdi = syslinux_derivative_info();
-
- if (sdi->c.filesystem == SYSLINUX_FS_ISOLINUX) {
- /* Boot info table info (integers in little endian format)
-
- Offset Name Size Meaning
- 8 bi_pvd 4 bytes LBA of primary volume descriptor
- 12 bi_file 4 bytes LBA of boot file
- 16 bi_length 4 bytes Boot file length in bytes
- 20 bi_csum 4 bytes 32-bit checksum
- 24 bi_reserved 40 bytes Reserved
-
- The 32-bit checksum is the sum of all the 32-bit words in the
- boot file starting at byte offset 64. All linear block
- addresses (LBAs) are given in CD sectors (normally 2048 bytes).
-
- LBA of primary volume descriptor should already be set to 16.
- */
-
- isolinux_bin = (unsigned char *)data[ndata].data;
-
- /* Get LBA address of bootfile */
- file_lba = get_file_lba(opt.loadfile);
-
- if (file_lba == 0) {
- error("Failed to find LBA offset of the boot file\n");
- goto bail;
- }
- /* Set it */
- *((uint32_t *) & isolinux_bin[12]) = file_lba;
-
- /* Set boot file length */
- *((uint32_t *) & isolinux_bin[16]) = data[ndata].size;
-
- /* Calculate checksum */
- checksum = (uint32_t *) & isolinux_bin[20];
- chkhead = (uint32_t *) & isolinux_bin[64];
- chktail = (uint32_t *) & isolinux_bin[data[ndata].size & ~3];
- *checksum = 0;
- while (chkhead < chktail)
- *checksum += *chkhead++;
-
- /*
- * Deal with possible fractional dword at the end;
- * this *should* never happen...
- */
- if (data[ndata].size & 3) {
- uint32_t xword = 0;
- memcpy(&xword, chkhead, data[ndata].size & 3);
- *checksum += xword;
- }
- } else {
- error
- ("The isolinux= option is only valid when run from ISOLINUX\n");
- goto bail;
- }
- }
-
- if (opt.grub) {
- /* Layout of stage2 file (from byte 0x0 to 0x270) */
- struct grub_stage2_patch_area {
- /* 0x0 to 0x205 */
- char unknown[0x206];
- /* 0x206: compatibility version number major */
- uint8_t compat_version_major;
- /* 0x207: compatibility version number minor */
- uint8_t compat_version_minor;
-
- /* 0x208: install_partition variable */
- struct {
- /* 0x208: sub-partition in sub-partition part2 */
- uint8_t part3;
- /* 0x209: sub-partition in top-level partition */
- uint8_t part2;
- /* 0x20a: top-level partiton number */
- uint8_t part1;
- /* 0x20b: BIOS drive number (must be 0) */
- uint8_t drive;
- } __attribute__ ((packed)) install_partition;
-
- /* 0x20c: deprecated (historical reason only) */
- uint32_t saved_entryno;
- /* 0x210: stage2_ID: will always be STAGE2_ID_STAGE2 = 0 in stage2 */
- uint8_t stage2_id;
- /* 0x211: force LBA */
- uint8_t force_lba;
- /* 0x212: version string (will probably be 0.97) */
- char version_string[5];
- /* 0x217: config filename */
- char config_file[89];
- /* 0x270: start of code (after jump from 0x200) */
- char codestart[1];
- } __attribute__ ((packed)) *stage2;
-
- if (data[ndata].size < sizeof(struct grub_stage2_patch_area)) {
- error
- ("The file specified by grub=<loader> is to small to be stage2 of GRUB Legacy.\n");
- goto bail;
- }
-
- stage2 = data[ndata].data;
-
- /*
- * Check the compatibility version number to see if we loaded a real
- * stage2 file or a stage2 file that we support.
- */
- if (stage2->compat_version_major != 3
- || stage2->compat_version_minor != 2) {
- error
- ("The file specified by grub=<loader> is not a supported stage2 GRUB Legacy binary\n");
- goto bail;
- }
-
- /* jump 0x200 bytes into the loadfile */
- regs.ip = 0x200;
-
- /*
- * GRUB Legacy wants the partition number in the install_partition
- * variable, located at offset 0x208 of stage2.
- * When GRUB Legacy is loaded, it is located at memory address 0x8208.
- *
- * It looks very similar to the "boot information format" of the
- * Multiboot specification:
- * http://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Boot-information-format
- *
- * 0x208 = part3: sub-partition in sub-partition part2
- * 0x209 = part2: sub-partition in top-level partition
- * 0x20a = part1: top-level partition number
- * 0x20b = drive: BIOS drive number (must be 0)
- *
- * GRUB Legacy doesn't store the BIOS drive number at 0x20b, but at
- * another location.
- *
- * Partition numbers always start from zero.
- * Unused partition bytes must be set to 0xFF.
- *
- * We only care about top-level partition, so we only need to change
- * "part1" to the appropriate value:
- * -1: whole drive (default) (-1 = 0xFF)
- * 0-3: primary partitions
- * 4-*: logical partitions
- */
- stage2->install_partition.part1 = whichpart - 1;
-
- /*
- * Grub Legacy reserves 89 bytes (from 0x8217 to 0x826f) for the
- * config filename. The filename passed via grubcfg= will overwrite
- * the default config filename "/boot/grub/menu.lst".
- */
- if (opt.grubcfg) {
- if (strlen(opt.grubcfg) > sizeof(stage2->config_file) - 1) {
- error
- ("The config filename length can't exceed 88 characters.\n");
- goto bail;
- }
-
- strcpy((char *)stage2->config_file, opt.grubcfg);
- }
- }
-
- if (opt.drmk) {
- /* DRMK entry is different than MS-DOS/PC-DOS */
- /*
- * A new size, aligned to 16 bytes to ease use of ds:[bp+28].
- * We only really need 4 new, usable bytes at the end.
- */
- int tsize = (data[ndata].size + 19) & 0xfffffff0;
- const union syslinux_derivative_info *sdi;
-
- sdi = syslinux_derivative_info();
- /* We should lookup the Syslinux partition offset and use it */
- fs_lba = *sdi->disk.partoffset;
- /*
- * fs_lba should be verified against the disk as some DRMK
- * variants will check and fail if it does not match
- */
- dprintf(" fs_lba offset is %d\n", fs_lba);
- /* DRMK only uses a DWORD */
- if (fs_lba > 0xffffffff) {
- error("LBA very large; Only using lower 32 bits; DRMK will probably fail\n");
- }
- regs.ss = regs.fs = regs.gs = 0; /* Used before initialized */
- if (!realloc(data[ndata].data, tsize)) {
- error("Failed to realloc for DRMK\n");
- goto bail; /* We'll never make it */
- }
- data[ndata].size = tsize;
- /* ds:bp is assumed by DRMK to be the boot sector */
- /* offset 28 is the FAT HiddenSectors value */
- regs.ds = (tsize >> 4) + (opt.seg - 2);
- /* "Patch" into tail of the new space */
- *(int *)(data[ndata].data + tsize - 4) = (int)(fs_lba & 0xffffffff);
- }
-
- ndata++;
- }
-
- if (!opt.loadfile || data[0].base >= 0x7c00 + SECTOR) {
- /* Actually read the boot sector */
- if (!cur_part) {
- data[ndata].data = mbr;
- } else if (!(data[ndata].data = read_sectors(cur_part->lba_data, 1))) {
- error("Cannot read boot sector\n");
- goto bail;
- }
- data[ndata].size = SECTOR;
- data[ndata].base = load_base;
-
- if (!opt.loadfile) {
- const struct mbr *br =
- (const struct mbr *)((char *)data[ndata].data +
- data[ndata].size - sizeof(struct mbr));
- if (br->sig != mbr_sig_magic) {
- error
- ("Boot sector signature not found (unbootable disk/partition?)\n");
- goto bail;
- }
- }
- /*
- * To boot the Recovery Console of Windows NT/2K/XP we need to write
- * the string "cmdcons\0" to memory location 0000:7C03.
- * Memory location 0000:7C00 contains the bootsector of the partition.
- */
- if (cur_part && opt.cmldr) {
- memcpy((char *)data[ndata].data + 3, cmldr_signature,
- sizeof cmldr_signature);
- }
-
- /*
- * Modify the hidden sectors (partition offset) copy in memory;
- * this modifies the field used by FAT and NTFS filesystems, and
- * possibly other boot loaders which use the same format.
- */
- if (cur_part && opt.sethidden) {
- *(uint32_t *) ((char *)data[ndata].data + 28) = cur_part->lba_data;
- }
-
- ndata++;
- }
-
- if (cur_part) {
- if (cur_part->next == next_gpt_part) {
- /* Do GPT hand-over, if applicable (as per syslinux/doc/gpt.txt) */
- struct part_entry *record;
- /* Look at the GPT partition */
- const struct gpt_part *gp = (const struct gpt_part *)
- (cur_part->block +
- (cur_part->private.gpt.size * cur_part->private.gpt.index));
- /* Note the partition length */
- uint64_t lba_count = gp->lba_last - gp->lba_first + 1;
- /* The length of the hand-over */
- int synth_size =
- sizeof(struct part_entry) + sizeof(uint32_t) +
- cur_part->private.gpt.size;
- /* Will point to the partition record length in the hand-over */
- uint32_t *plen;
-
- /* Allocate the hand-over record */
- record = malloc(synth_size);
- if (!record) {
- error("Could not build GPT hand-over record!\n");
- goto bail;
- }
- /* Synthesize the record */
- memset(record, 0, synth_size);
- record->active_flag = 0x80;
- record->ostype = 0xED;
- /* All bits set by default */
- record->start_lba = ~(uint32_t) 0;
- record->length = ~(uint32_t) 0;
- /* If these fit the precision, pass them on */
- if (cur_part->lba_data < record->start_lba)
- record->start_lba = cur_part->lba_data;
- if (lba_count < record->length)
- record->length = lba_count;
- /* Next comes the GPT partition record length */
- plen = (uint32_t *) (record + 1);
- plen[0] = cur_part->private.gpt.size;
- /* Next comes the GPT partition record copy */
- memcpy(plen + 1, gp, plen[0]);
- cur_part->record = record;
-
- regs.eax.l = 0x54504721; /* '!GPT' */
- data[ndata].base = 0x7be;
- data[ndata].size = synth_size;
- data[ndata].data = (void *)record;
- ndata++;
- regs.esi.w[0] = 0x7be;
-
- dprintf("GPT handover:\n");
- mbr_part_dump(record);
- gpt_part_dump((struct gpt_part *)(plen + 1));
- } else if (cur_part->record) {
- /* MBR handover protocol */
- static struct part_entry handover_record;
-
- handover_record = *cur_part->record;
- handover_record.start_lba = cur_part->lba_data;
-
- data[ndata].base = 0x7be;
- data[ndata].size = sizeof handover_record;
- data[ndata].data = &handover_record;
- ndata++;
- regs.esi.w[0] = 0x7be;
-
- dprintf("MBR handover:\n");
- mbr_part_dump(&handover_record);
- }
- }
-
- do_boot(data, ndata, &regs);
-
-bail:
- if (cur_part) {
- free(cur_part->block);
- free((void *)cur_part->record);
- }
- free(cur_part);
- free(mbr);
- return 255;
-}
diff --git a/com32/modules/elf.c b/com32/modules/elf.c
index 84c80ac2..a946af1f 100644
--- a/com32/modules/elf.c
+++ b/com32/modules/elf.c
@@ -120,10 +120,8 @@ int boot_elf(void *ptr, size_t len, char **argv)
if (!mmap || !amap)
goto bail;
-#if DEBUG
dprintf("Initial memory map:\n");
- syslinux_dump_memmap(stdout, mmap);
-#endif
+ syslinux_dump_memmap(mmap);
ph = (Elf32_Phdr *) (cptr + eh->e_phoff);
@@ -185,10 +183,8 @@ int boot_elf(void *ptr, size_t len, char **argv)
if (!stack_frame)
goto bail;
-#if DEBUG
dprintf("Right before syslinux_memmap_largest()...\n");
- syslinux_dump_memmap(stdout, amap);
-#endif
+ syslinux_dump_memmap(amap);
if (syslinux_memmap_largest(amap, SMT_FREE, &lstart, &llen))
goto bail; /* NO free memory?! */
@@ -239,16 +235,14 @@ int boot_elf(void *ptr, size_t len, char **argv)
regs.eip = eh->e_entry;
regs.esp = stack_pointer;
-#if DEBUG
dprintf("Final memory map:\n");
- syslinux_dump_memmap(stdout, mmap);
+ syslinux_dump_memmap(mmap);
dprintf("Final available map:\n");
- syslinux_dump_memmap(stdout, amap);
+ syslinux_dump_memmap(amap);
dprintf("Movelist:\n");
- syslinux_dump_movelist(stdout, ml);
-#endif
+ syslinux_dump_movelist(ml);
/* This should not return... */
fputs("Booting...\n", stdout);
diff --git a/com32/modules/ethersel.c b/com32/modules/ethersel.c
index d6b4774f..039de276 100644
--- a/com32/modules/ethersel.c
+++ b/com32/modules/ethersel.c
@@ -38,12 +38,7 @@
#include <com32.h>
#include <syslinux/boot.h>
#include <syslinux/config.h>
-
-#ifdef DEBUG
-# define dprintf printf
-#else
-# define dprintf(...) ((void)0)
-#endif
+#include <dprintf.h>
#define MAX_LINE 512
diff --git a/com32/modules/gpxecmd.c b/com32/modules/gpxecmd.c
index 9ae1b601..d2d90a2f 100644
--- a/com32/modules/gpxecmd.c
+++ b/com32/modules/gpxecmd.c
@@ -22,7 +22,9 @@
#include <console.h>
#include <com32.h>
#include <string.h>
+
#include <sys/gpxe.h>
+#include <syslinux/pxe_api.h>
struct segoff16 {
uint16_t offs, seg;
@@ -37,11 +39,11 @@ static void gpxecmd(const char **args)
{
char *q;
struct s_PXENV_FILE_EXEC *fx;
- com32sys_t reg;
- memset(&reg, 0, sizeof reg);
+ fx = lmalloc(sizeof *fx);
+ if (!fx)
+ return;
- fx = __com32.cs_bounce;
q = (char *)(fx + 1);
fx->Status = 1;
@@ -55,13 +57,7 @@ static void gpxecmd(const char **args)
}
*--q = '\0';
- memset(&reg, 0, sizeof reg);
- reg.eax.w[0] = 0x0009;
- reg.ebx.w[0] = 0x00e5; /* PXENV_FILE_EXEC */
- reg.edi.w[0] = OFFS(fx);
- reg.es = SEG(fx);
-
- __intcall(0x22, &reg, &reg);
+ pxe_call(PXENV_FILE_EXEC, fx);
/* This should not return... */
}
diff --git a/com32/modules/hello.c b/com32/modules/hello.c
index f28d38d3..d3d4d299 100644
--- a/com32/modules/hello.c
+++ b/com32/modules/hello.c
@@ -13,7 +13,7 @@
#define NUM_COUNT 10
#define MAX_NUM 100
-int main(int argc, char **argv)
+int main(int argc __unused, char **argv __unused)
{
int *nums = NULL;
diff --git a/com32/modules/host.c b/com32/modules/host.c
index c9cea97c..d70efffd 100644
--- a/com32/modules/host.c
+++ b/com32/modules/host.c
@@ -1,39 +1,41 @@
#include <stdio.h>
-#include <console.h>
+#include <stdlib.h>
#include <string.h>
+#include <console.h>
#include <netinet/in.h>
#include <com32.h>
+#include <syslinux/pxe.h>
-static struct in_addr dnsresolve(const char *hostname)
+static inline uint32_t dns_resolve(const char *hostname)
{
- com32sys_t regs;
- struct in_addr addr;
-
- strcpy(__com32.cs_bounce, hostname);
-
- regs.eax.w[0] = 0x0010;
- regs.es = SEG(__com32.cs_bounce);
- regs.ebx.w[0] = OFFS(__com32.cs_bounce);
- __intcall(0x22, &regs, &regs);
+ return pxe_dns(hostname);
+}
- addr.s_addr = regs.eax.l;
- return addr;
+static inline void usage(const char *s)
+{
+ fprintf(stderr, "Usage: %s hostname [, hostname_1, hostname_2, ...]\n", s);
}
int main(int argc, char *argv[])
{
int i;
- struct in_addr addr;
+ uint32_t ip;
- for (i = 1; i < argc; i++) {
- addr = dnsresolve(argv[i]);
+ openconsole(&dev_null_r, &dev_stdcon_w);
+
+ if (argc < 2) {
+ usage(argv[0]);
+ return 1;
+ }
- printf("%-39s %08X %d.%d.%d.%d\n",
- argv[i], ntohl(addr.s_addr),
- ((uint8_t *)&addr.s_addr)[0],
- ((uint8_t *)&addr.s_addr)[1],
- ((uint8_t *)&addr.s_addr)[2],
- ((uint8_t *)&addr.s_addr)[3]);
+ for (i = 1; i < argc; i++) {
+ ip = dns_resolve(argv[i]);
+ if (!ip) {
+ printf("%s not found.\n", argv[i]);
+ } else {
+ printf("%-39s %08X %u.%u.%u.%u\n", argv[i], ntohl(ip), ip & 0xFF,
+ (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, (ip >> 24) & 0xFF);
+ }
}
return 0;
diff --git a/com32/modules/ifcpu.c b/com32/modules/ifcpu.c
index a28acc4e..0aa63327 100644
--- a/com32/modules/ifcpu.c
+++ b/com32/modules/ifcpu.c
@@ -49,11 +49,12 @@ static void usage(void)
" dry-run : just do the detection, don't boot \n"
"\n"
"cpu_features could be:\n"
- " 64 : Processor is x86_64 compatible (lm cpu flag)\n"
- " hvm : Processor features hardware virtualization (hvm or svm cpu flag)\n"
- " multicore : Processor must be multi-core \n"
- " smp : System must be multi-processor \n"
- " pae : Processor features Physical Address Extension (PAE)\n"
+ " 64 : Processor is x86_64 compatible (lm cpu flag)\n"
+ " hvm : Processor features hardware virtualization (hvm or svm cpu flag)\n"
+ " multicore : Processor must be multi-core \n"
+ " smp : System must be multi-processor \n"
+ " pae : Processor features Physical Address Extension (PAE)\n"
+ " hypervisor : Processor is running under an hypervisor\n"
"\n"
"if you want to match many cpu features, just separate them with a single space.\n");
}
@@ -114,30 +115,34 @@ int main(int argc, char *argv[])
args[n++] = &argv[i + 1];
} else if (!strcmp(argv[i], "64")) {
if (debug)
- printf(" 64bit : %s on this system\n",
+ printf(" 64bit : %s on this system\n"