summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile12
-rw-r--r--Makefile.private7
-rw-r--r--NEWS36
-rw-r--r--README7
-rw-r--r--com32/Makefile4
-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.c214
-rw-r--r--com32/chain/utility.h30
-rw-r--r--com32/cmenu/Makefile5
-rw-r--r--com32/gdbstub/Makefile3
-rw-r--r--com32/gfxboot/Makefile3
-rw-r--r--com32/gfxboot/gfxboot.c21
-rw-r--r--com32/gplinclude/acpi/acpi.h1
-rw-r--r--com32/gplinclude/cpuid.h236
-rw-r--r--com32/gplinclude/dmi/dmi_bios.h3
-rw-r--r--com32/gplinclude/zzjson/zzjson.h116
-rw-r--r--com32/gpllib/Makefile7
-rw-r--r--com32/gpllib/acpi/acpi.c19
-rw-r--r--com32/gpllib/cpuid.c175
-rw-r--r--com32/gpllib/disk/labels.c179
-rw-r--r--com32/gpllib/zzjson/zzjson_create.c240
-rw-r--r--com32/gpllib/zzjson/zzjson_free.c29
-rw-r--r--com32/gpllib/zzjson/zzjson_parse.c490
-rw-r--r--com32/gpllib/zzjson/zzjson_print.c110
-rw-r--r--com32/gpllib/zzjson/zzjson_query.c63
-rw-r--r--com32/hdt/.gitignore1
-rw-r--r--com32/hdt/Makefile37
-rw-r--r--com32/hdt/art/display.pngbin0 -> 19755 bytes
-rw-r--r--com32/hdt/art/red.pngbin0 -> 19674 bytes
-rw-r--r--com32/hdt/floppy/hdt.cfg28
-rw-r--r--com32/hdt/hdt-cli-acpi.c25
-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.c126
-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.c68
-rw-r--r--com32/hdt/hdt-cli.h5
-rw-r--r--com32/hdt/hdt-common.c69
-rw-r--r--com32/hdt/hdt-common.h34
-rw-r--r--com32/hdt/hdt-dump-acpi.c600
-rw-r--r--com32/hdt/hdt-dump-cpu.c53
-rw-r--r--com32/hdt/hdt-dump-disks.c145
-rw-r--r--com32/hdt/hdt-dump-dmi.c447
-rw-r--r--com32/hdt/hdt-dump-hdt.c50
-rw-r--r--com32/hdt/hdt-dump-kernel.c69
-rw-r--r--com32/hdt/hdt-dump-memory.c133
-rw-r--r--com32/hdt/hdt-dump-pci.c136
-rw-r--r--com32/hdt/hdt-dump-pxe.c80
-rw-r--r--com32/hdt/hdt-dump-syslinux.c43
-rw-r--r--com32/hdt/hdt-dump-vesa.c67
-rw-r--r--com32/hdt/hdt-dump-vpd.c47
-rw-r--r--com32/hdt/hdt-dump.c229
-rw-r--r--com32/hdt/hdt-dump.h85
-rw-r--r--com32/hdt/hdt-menu-acpi.c4
-rw-r--r--com32/hdt/hdt-menu-disk.c10
-rw-r--r--com32/hdt/hdt-menu-pxe.c6
-rw-r--r--com32/hdt/hdt-menu-summary.c3
-rw-r--r--com32/hdt/hdt-menu.c12
-rw-r--r--com32/hdt/hdt.c17
-rw-r--r--com32/hdt/hdt.h4
-rw-r--r--com32/include/bitsize/stddef.h6
-rw-r--r--com32/include/bitsize/stdint.h30
-rw-r--r--com32/include/bitsize/stdintconst.h2
-rw-r--r--com32/include/bitsize/stdintlimits.h2
-rw-r--r--com32/include/bufprintf.h10
-rw-r--r--com32/include/cpufeature.h2
-rw-r--r--com32/include/ctype.h1
-rw-r--r--com32/include/dhcp.h40
-rw-r--r--com32/include/dprintf.h20
-rw-r--r--com32/include/netinet/in.h3
-rw-r--r--com32/include/stdint.h184
-rw-r--r--com32/include/string.h1
-rw-r--r--com32/include/syslinux/disk.h180
-rw-r--r--com32/include/syslinux/linux.h29
-rw-r--r--com32/include/syslinux/movebits.h9
-rw-r--r--com32/lib/Makefile15
-rw-r--r--com32/lib/bufprintf.c41
-rw-r--r--com32/lib/chrreplace.c11
-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.c2
-rw-r--r--com32/lib/inet.c39
-rw-r--r--com32/lib/pci/scan.c24
-rw-r--r--com32/lib/strreplace.c58
-rw-r--r--com32/lib/syslinux/disk.c534
-rw-r--r--com32/lib/syslinux/dump_mmap.c12
-rw-r--r--com32/lib/syslinux/dump_movelist.c9
-rw-r--r--com32/lib/syslinux/load_linux.c72
-rw-r--r--com32/lib/syslinux/movebits.c42
-rw-r--r--com32/lib/syslinux/setup_data.c47
-rw-r--r--com32/lib/syslinux/shuffle.c18
-rw-r--r--com32/lib/syslinux/zonelist.c24
-rw-r--r--com32/lib/vdprintf.c4
-rw-r--r--com32/libupload/.gitignore2
-rw-r--r--com32/libupload/Makefile39
-rw-r--r--com32/libupload/cpio.c (renamed from com32/sysdump/cpio.c)14
-rw-r--r--com32/libupload/ctime.c (renamed from com32/sysdump/ctime.c)0
-rw-r--r--com32/libupload/ctime.h (renamed from com32/sysdump/ctime.h)0
-rw-r--r--com32/libupload/serial.c (renamed from com32/sysdump/serial.c)0
-rw-r--r--com32/libupload/serial.h (renamed from com32/sysdump/serial.h)0
-rw-r--r--com32/libupload/srecsend.h (renamed from com32/sysdump/srecsend.h)0
-rw-r--r--com32/libupload/tftp.h22
-rw-r--r--com32/libupload/upload_backend.h56
-rw-r--r--com32/libupload/upload_srec.c (renamed from com32/sysdump/be_srec.c)8
-rw-r--r--com32/libupload/upload_tftp.c (renamed from com32/sysdump/be_tftp.c)66
-rw-r--r--com32/libupload/upload_ymodem.c (renamed from com32/sysdump/be_ymodem.c)8
-rw-r--r--com32/libupload/ymodem.txt (renamed from com32/sysdump/ymodem.txt)0
-rw-r--r--com32/libupload/zout.c (renamed from com32/sysdump/zout.c)19
-rw-r--r--com32/libutil/Makefile3
-rw-r--r--com32/lua/src/Makefile7
-rw-r--r--com32/lua/src/cpu.c4
-rw-r--r--com32/lua/src/dhcp.c358
-rw-r--r--com32/lua/src/dhcp.h49
-rw-r--r--com32/lua/src/dmi.c624
-rw-r--r--com32/lua/src/linit.c1
-rw-r--r--com32/lua/src/liolib.c40
-rw-r--r--com32/lua/src/lualib.h3
-rw-r--r--com32/lua/src/syslinux.c37
-rw-r--r--com32/mboot/Makefile6
-rw-r--r--com32/mboot/map.c5
-rw-r--r--com32/mboot/mboot.c2
-rw-r--r--com32/menu/Makefile8
-rw-r--r--com32/menu/menumain.c2
-rw-r--r--com32/menu/readconfig.c4
-rw-r--r--com32/modules/Makefile8
-rw-r--r--com32/modules/chain.c1870
-rw-r--r--com32/modules/elf.c16
-rw-r--r--com32/modules/ethersel.c7
-rw-r--r--com32/modules/ifcpu.c25
-rw-r--r--com32/modules/ifmemdsk.c392
-rw-r--r--com32/modules/kontron_wdt.c414
-rw-r--r--com32/modules/kontron_wdt.h117
-rw-r--r--com32/modules/linux.c95
-rw-r--r--com32/modules/pcitest.c7
-rw-r--r--com32/modules/pmload.c16
-rw-r--r--com32/modules/prdhcp.c164
-rw-r--r--com32/modules/pxechn.c1161
-rw-r--r--com32/modules/zzjson.c101
-rw-r--r--com32/rosh/Makefile3
-rw-r--r--com32/samples/Makefile3
-rw-r--r--com32/sysdump/Makefile7
-rw-r--r--com32/sysdump/acpi.c9
-rw-r--r--com32/sysdump/backend.h55
-rw-r--r--com32/sysdump/cpuid.c3
-rw-r--r--com32/sysdump/data.h2
-rw-r--r--com32/sysdump/dmi.c7
-rw-r--r--com32/sysdump/main.c21
-rw-r--r--com32/sysdump/memmap.c5
-rw-r--r--com32/sysdump/memory.c5
-rw-r--r--com32/sysdump/pci.c5
-rw-r--r--com32/sysdump/sysdump.h16
-rw-r--r--com32/sysdump/vesa.c5
-rw-r--r--com32/tools/Makefile6
-rw-r--r--com32/tools/include/tools/le_byteshift.h70
-rw-r--r--com32/tools/relocs.c305
-rw-r--r--core/Makefile5
-rw-r--r--core/bootsect.inc16
-rw-r--r--core/comboot.inc15
-rw-r--r--core/diskboot.inc2
-rw-r--r--core/diskfs.inc4
-rw-r--r--core/diskstart.inc40
-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/ext2/ext2.c3
-rw-r--r--core/fs/fat/fat.c35
-rw-r--r--core/fs/fs.c13
-rw-r--r--core/fs/lib/searchconfig.c3
-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/head.inc4
-rw-r--r--core/include/fs.h1
-rw-r--r--core/init.inc24
-rw-r--r--core/isolinux.asm173
-rw-r--r--core/ldlinux.asm2
-rw-r--r--core/syslinux.ld9
-rw-r--r--core/ui.inc7
-rw-r--r--diag/geodsp/Makefile35
-rw-r--r--diag/geodsp/mk-lba-img.c55
-rwxr-xr-xdiag/geodsp/mk-lba-img.pl94
-rw-r--r--diag/mbr/Makefile3
-rw-r--r--diag/mbr/README4
-rw-r--r--diag/mbr/handoff.S4
-rw-r--r--doc/chain.txt327
-rw-r--r--doc/comboot.txt76
-rw-r--r--doc/gpt.txt2
-rw-r--r--doc/isolinux.txt31
-rw-r--r--doc/logo/LICENSE5
-rw-r--r--doc/logo/syslinux-100.pngbin0 -> 131308 bytes
-rw-r--r--doc/menu.txt2
-rw-r--r--doc/pxechn.txt138
-rw-r--r--doc/syslinux.txt2
-rw-r--r--dos/Makefile5
-rw-r--r--dos/syslinux.c5
-rw-r--r--dosutil/Makefile5
-rw-r--r--extlinux/Makefile11
-rw-r--r--extlinux/btrfs.h179
-rw-r--r--[-rwxr-xr-x]extlinux/main.c617
-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.h98
-rw-r--r--libinstaller/syslxmod.c25
-rw-r--r--libinstaller/syslxopt.c10
-rw-r--r--libinstaller/syslxopt.h1
-rw-r--r--linux/Makefile12
-rwxr-xr-xlinux/syslinux.c24
-rw-r--r--lzo/Makefile3
-rw-r--r--man/extlinux.111
-rw-r--r--mbr/Makefile3
-rw-r--r--mbr/altmbr.S2
-rw-r--r--mbr/isohdpfx.S31
-rw-r--r--memdisk/Makefile5
-rw-r--r--memdisk/mstructs.h4
-rw-r--r--memdump/Makefile3
-rw-r--r--mk/build.mk (renamed from MCONFIG.build)2
-rw-r--r--mk/com32.mk (renamed from com32/MCONFIG)2
-rw-r--r--mk/devel.mk (renamed from MCONFIG.devel)0
-rw-r--r--mk/embedded.mk (renamed from MCONFIG.embedded)2
-rw-r--r--mk/lib.mk (renamed from com32/lib/MCONFIG)2
-rw-r--r--mk/rosh.mk (renamed from com32/rosh/MCONFIG)2
-rw-r--r--mk/syslinux.mk (renamed from MCONFIG)6
-rw-r--r--modules/Makefile3
-rwxr-xr-xmtools/Makefile10
-rwxr-xr-xmtools/syslinux.c5
-rw-r--r--sample/Makefile3
-rw-r--r--utils/Makefile21
-rw-r--r--utils/isohybrid.c612
-rw-r--r--utils/isohybrid.h2
-rwxr-xr-xutils/ppmtolss162
-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
264 files changed, 19061 insertions, 3676 deletions
diff --git a/Makefile b/Makefile
index 60a59560..1b419aea 100644
--- a/Makefile
+++ b/Makefile
@@ -15,7 +15,8 @@
# Main Makefile for SYSLINUX
#
topdir = .
-include $(topdir)/MCONFIG
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/syslinux.mk
-include $(topdir)/version.mk
#
@@ -33,7 +34,7 @@ include $(topdir)/MCONFIG
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
# syslinux.exe is BTARGET so as to not require everyone to have the
# mingw suite installed
@@ -97,6 +98,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 c70c204d..92127e98 100644
--- a/Makefile.private
+++ b/Makefile.private
@@ -18,7 +18,7 @@
.PHONY: official release
# These files are removed when tarballs are generated.
-PRIVATE = Makefile.private MCONFIG.devel
+PRIVATE = Makefile.private mk/devel.mk
GIT_DIR ?= .git
ABS_GIT_DIR := $(shell cd '$(GIT_DIR)' 2>/dev/null && pwd)
@@ -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 94c47ab9..c8022c69 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,42 @@ 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.
+ * kontron_wdt.c32: Add a new module to enable the hardware
+ watchdog of some Kontron boards. It allows enabling the watchdog
+ and then booting a given image.
+ * HDT updated, and now can display images regarding some detection
+ steps. Add postexec command to run a particular entry after
+ HDT's execution, add silent option and various fixes.
+ * ifcpu.c32: Detect hypervisor presence.
+ * lua.c32: Add dhcp support and support for native Syslinux
+ functions syslinux_config(), syslinux_ipappend_strings() and
+ syslinux_reboot().
+ * isohybrid: Workaround for various EFI systems.
+ * pxechn.c32, a PXE NBP chainloader. More versatile alternative
+ to pxechain.com and resolves the PXELINUX -> WDS issue with
+ Microsoft Windows Server 2008R2 (Gene Cumm).
+ * btrfs: Fix booting off of a subvolume.
+ * com32: Add device tree support.
+ * SYSLINUX: Fix relative paths for VFAT. The CONFIG and APPEND
+ directives now support entirely relative paths.
+
+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.
* PXELINUX: Fix timer bug when PXELINUX might be unloaded
diff --git a/README b/README
index 08a82e42..bb1aeb65 100644
--- a/README
+++ b/README
@@ -20,6 +20,13 @@ SYSLINUX now builds in a Linux environment, using nasm. You need nasm
version 2.03 or later (2.07 or later recommended) to build SYSLINUX
from source. See http://www.nasm.us/ for information about nasm.
+"utils/isohybrid" needs the UUID library and following header file,
+
+ /usr/include/uuid/uuid.h
+
+You can get them from the "uuid-dev" package on Debian based systems
+or from the "libuuid-devel" package on RPM based distributions.
+
There is now a mailing list for SYSLINUX. See the end of syslinux.txt
for details.
diff --git a/com32/Makefile b/com32/Makefile
index b090c403..b59fd3f9 100644
--- a/com32/Makefile
+++ b/com32/Makefile
@@ -1,5 +1,5 @@
-SUBDIRS = tools lib gpllib libutil modules mboot menu samples rosh cmenu \
- hdt gfxboot sysdump lua/src
+SUBDIRS = libupload tools lib gpllib libutil modules mboot menu samples 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..9d398a85
--- /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)/com32.mk
+
+OBJS = chain.o partiter.o utility.o options.o mangle.o
+
+all: chain.c32
+
+chain.elf: $(OBJS) $(LIBS) $(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..fb59551b
--- /dev/null
+++ b/com32/chain/utility.c
@@ -0,0 +1,214 @@
+#include <com32.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <syslinux/disk.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)
+{
+ 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;
+}
+
+/* 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 794af741..446bbcdd 100644
--- a/com32/cmenu/Makefile
+++ b/com32/cmenu/Makefile
@@ -17,11 +17,12 @@
NOGPL := 1
-# This must be defined before MCONFIG is included
+# This must be defined before com32.mk is included
LIBS = libmenu/libmenu.a
topdir = ../..
-include ../MCONFIG
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/com32.mk
CFLAGS += -I./libmenu
diff --git a/com32/gdbstub/Makefile b/com32/gdbstub/Makefile
index 5513876b..38d003cc 100644
--- a/com32/gdbstub/Makefile
+++ b/com32/gdbstub/Makefile
@@ -15,7 +15,8 @@
##
topdir = ../..
-include ../MCONFIG
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/com32.mk
CFLAGS += -fPIE
diff --git a/com32/gfxboot/Makefile b/com32/gfxboot/Makefile
index 73133e1b..183115f4 100644
--- a/com32/gfxboot/Makefile
+++ b/com32/gfxboot/Makefile
@@ -12,7 +12,8 @@
## -----------------------------------------------------------------------
topdir = ../..
-include ../MCONFIG
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/com32.mk
MODULES = gfxboot.c32
diff --git a/com32/gfxboot/gfxboot.c b/com32/gfxboot/gfxboot.c
index 37499202..aa05caf8 100644
--- a/com32/gfxboot/gfxboot.c
+++ b/com32/gfxboot/gfxboot.c
@@ -102,6 +102,8 @@ typedef struct __attribute__ ((packed)) {
// 0: GFX_CB_MENU_INIT accepts 32 bit addresses
// 1: knows about xmem_start, xmem_end
uint16_t reserved_1; // 62:
+ uint32_t gfxboot_cwd; // 64: if set, points to current gfxboot working directory relative
+ // to syslinux working directory
} gfx_config_t;
@@ -181,6 +183,7 @@ int main(int argc, char **argv)
{
int menu_index;
const union syslinux_derivative_info *sdi;
+ char working_dir[256];
openconsole(&dev_stdcon_r, &dev_stdcon_w);
@@ -224,6 +227,10 @@ int main(int argc, char **argv)
return 0;
}
+ if(getcwd(working_dir, sizeof working_dir)) {
+ gfx_config.gfxboot_cwd = (uint32_t) working_dir;
+ }
+
if(gfx_init(argv[1])) {
printf("Error setting up gfxboot\n");
if(argc > 2) show_message(argv[2]);
@@ -806,6 +813,12 @@ void boot(int index)
int i, label_len;
unsigned ipapp;
const struct syslinux_ipappend_strings *ipappend;
+ char *gfxboot_cwd = (char *) gfx_config.gfxboot_cwd;
+
+ if(gfxboot_cwd) {
+ chdir(gfxboot_cwd);
+ gfx_config.gfxboot_cwd = 0;
+ }
for(menu_ptr = menu; menu_ptr; menu_ptr = menu_ptr->next, index--) {
if(!index) break;
@@ -922,11 +935,15 @@ void boot_entry(menu_t *menu_ptr, char *arg)
*skip_nonspaces(s) = 0;
initrd_arg = s;
}
+ else if(initrd_arg) {
+ free(s0);
+ initrd_arg = s0 = strdup(initrd_arg);
+ }
if(initrd_arg) {
initrd = initramfs_init();
- while((t = strsep(&s, ","))) {
+ while((t = strsep(&initrd_arg, ","))) {
initrd_buf = load_one(t, &initrd_size);
if(!initrd_buf) {
@@ -945,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/gplinclude/acpi/acpi.h b/com32/gplinclude/acpi/acpi.h
index 94589f35..bf3ffdb7 100644
--- a/com32/gplinclude/acpi/acpi.h
+++ b/com32/gplinclude/acpi/acpi.h
@@ -95,4 +95,5 @@ void parse_madt(s_acpi * acpi);
int search_rsdp(s_acpi *acpi);
void get_acpi_description_header(uint8_t *q, s_acpi_description_header * adh);
bool parse_header(uint64_t *address, s_acpi *acpi);
+char *flags_to_string(char *buffer, uint16_t flags);
#endif
diff --git a/com32/gplinclude/cpuid.h b/com32/gplinclude/cpuid.h
index 53a08085..6a33e9cb 100644
--- a/com32/gplinclude/cpuid.h
+++ b/com32/gplinclude/cpuid.h
@@ -18,9 +18,11 @@
#include <stdbool.h>
#include <stdint.h>
+#include <stdio.h>
#include <cpufeature.h>
#include <sys/bitops.h>
#include <sys/cpu.h>
+#include <sys/io.h>
#include <klibc/compiler.h>
#define PAGE_SIZE 4096
@@ -28,99 +30,112 @@
#define CPU_MODEL_SIZE 48
#define CPU_VENDOR_SIZE 48
+#define CPU_FLAGS(m_) \
+m_(bool, fpu, /* Onboard FPU */) \
+m_(bool, vme, /* Virtual Mode Extensions */) \
+m_(bool, de, /* Debugging Extensions */) \
+m_(bool, pse, /* Page Size Extensions */) \
+m_(bool, tsc, /* Time Stamp Counter */) \
+m_(bool, msr, /* Model-Specific Registers, RDMSR, WRMSR */) \
+m_(bool, pae, /* Physical Address Extensions */) \
+m_(bool, mce, /* Machine Check Architecture */) \
+m_(bool, cx8, /* CMPXCHG8 instruction */) \
+m_(bool, apic, /* Onboard APIC */) \
+m_(bool, sep, /* SYSENTER/SYSEXIT */) \
+m_(bool, mtrr, /* Memory Type Range Registers */) \
+m_(bool, pge, /* Page Global Enable */) \
+m_(bool, mca, /* Machine Check Architecture */) \
+m_(bool, cmov, /* CMOV instruction (FCMOVCC and FCOMI too if FPU present) */) \
+m_(bool, pat, /* Page Attribute Table */) \
+m_(bool, pse_36, /* 36-bit PSEs */) \
+m_(bool, psn, /* Processor serial number */) \
+m_(bool, clflsh, /* Supports the CLFLUSH instruction */) \
+m_(bool, dts, /* Debug Trace Store */) \
+m_(bool, acpi, /* ACPI via MSR */) \
+m_(bool, pbe, /* Pending Break Enable */) \
+m_(bool, mmx, /* Multimedia Extensions */) \
+m_(bool, fxsr, /* FXSAVE and FXRSTOR instructions (fast save and restore of FPU context), and CR4.OSFXSR available */) \
+m_(bool, sse, /* Streaming SIMD Extensions */) \
+m_(bool, sse2, /* Streaming SIMD Extensions 2 */) \
+m_(bool, ss, /* CPU self snoop */) \
+m_(bool, htt, /* Hyper-Threading */) \
+m_(bool, acc, /* Automatic clock control */) \
+m_(bool, syscall, /* SYSCALL/SYSRET */) \
+m_(bool, mp, /* MP Capable. */) \
+m_(bool, nx, /* Execute Disable */) \
+m_(bool, mmxext, /* AMD MMX extensions */) \
+m_(bool, fxsr_opt, /* FXSAVE/FXRSTOR optimizations */) \
+m_(bool, gbpages, /* "pdpe1gb" GB pages */) \
+m_(bool, rdtscp, /* RDTSCP */) \
+m_(bool, lm, /* Long Mode (x86-64) */) \
+m_(bool, nowext, /* AMD 3DNow! extensions */) \
+m_(bool, now, /* 3DNow! */) \
+m_(bool, smp, /* A smp configuration has been found */) \
+m_(bool, pni, /* Streaming SIMD Extensions-3 */) \
+m_(bool, pclmulqd, /* PCLMULQDQ instruction */) \
+m_(bool, dtes64, /* 64-bit Debug Store */) \
+m_(bool, vmx, /* Hardware virtualization */) \
+m_(bool, smx, /* Safer Mode */) \
+m_(bool, est, /* Enhanced SpeedStep */) \
+m_(bool, tm2, /* Thermal Monitor 2 */) \
+m_(bool, sse3, /* Supplemental SSE-3 */) \
+m_(bool, cid, /* Context ID */) \
+m_(bool, fma, /* Fused multiply-add */) \
+m_(bool, cx16, /* CMPXCHG16B */) \
+m_(bool, xtpr, /* Send Task Priority Messages */) \
+m_(bool, pdcm, /* Performance Capabilities */) \
+m_(bool, dca, /* Direct Cache Access */) \
+m_(bool, xmm4_1, /* "sse4_1" SSE-4.1 */) \
+m_(bool, xmm4_2, /* "sse4_2" SSE-4.2 */) \
+m_(bool, x2apic, /* x2APIC */) \
+m_(bool, movbe, /* MOVBE instruction */) \
+m_(bool, popcnt, /* POPCNT instruction */) \
+m_(bool, aes, /* AES Instruction */) \
+m_(bool, xsave, /* XSAVE/XRSTOR/XSETBV/XGETBV */) \
+m_(bool, osxsave, /* XSAVE enabled in the OS */) \
+m_(bool, avx, /* Advanced Vector Extensions */) \
+m_(bool, hypervisor, /* Running on a hypervisor */) \
+m_(bool, ace2, /* Advanced Cryptography Engine v2 */) \
+m_(bool, ace2_en, /* ACE v2 enabled */) \
+m_(bool, phe, /* PadLock Hash Engine */) \
+m_(bool, phe_en, /* PadLock Hash Engine Enabled */) \
+m_(bool, pmm, /* PadLock Montgomery Multiplier */) \
+m_(bool, pmm_en, /* PadLock Montgomery Multiplier enabled */) \
+m_(bool, svm, /* Secure virtual machine */) \
+m_(bool, extapic, /* Extended APIC space */) \
+m_(bool, cr8_legacy, /* CR8 in 32-bit mode */) \
+m_(bool, abm, /* Advanced bit manipulation */) \
+m_(bool, sse4a, /* SSE4-A */) \
+m_(bool, misalignsse, /* Misaligned SSE mode */) \
+m_(bool, nowprefetch, /* 3DNow prefetch instructions */) \
+m_(bool, osvw, /* OS Visible Workaround */) \
+m_(bool, ibs, /* Instruction Based Sampling */) \
+m_(bool, sse5, /* SSE5 */) \
+m_(bool, skinit, /* SKINIT/STGI instructions */) \
+m_(bool, wdt, /* Watchdog Timer */) \
+m_(bool, ida, /* Intel Dynamic Acceleration */) \
+m_(bool, arat, /* Always Running APIC Timer */) \
+m_(bool, tpr_shadow, /* Intel TPR Shadow */) \
+m_(bool, vnmi, /* Intel Virtual NMI */) \
+m_(bool, flexpriority, /* Intel FlexPriority */) \
+m_(bool, ept, /* Intel Extended Page Table */) \
+m_(bool, vpid, /* Intel Virtual Processor ID */)
+
+#define STRUCT_MEMBERS(type_, name_, comment_) type_ name_;
+
+#define STRUCT_MEMBER_NAMES(type_, name_, comment_) #name_ ,
+
+#define STRUCTURE_MEMBER_OFFSETS(type_, name_, comment_) \
+ offsetof(s_cpu_flags, name_),
+
typedef struct {
- bool fpu; /* Onboard FPU */
- bool vme; /* Virtual Mode Extensions */
- bool de; /* Debugging Extensions */
- bool pse; /* Page Size Extensions */
- bool tsc; /* Time Stamp Counter */
- bool msr; /* Model-Specific Registers, RDMSR, WRMSR */
- bool pae; /* Physical Address Extensions */
- bool mce; /* Machine Check Architecture */
- bool cx8; /* CMPXCHG8 instruction */
- bool apic; /* Onboard APIC */
- bool sep; /* SYSENTER/SYSEXIT */
- bool mtrr; /* Memory Type Range Registers */
- bool pge; /* Page Global Enable */
- bool mca; /* Machine Check Architecture */
- bool cmov; /* CMOV instruction (FCMOVCC and FCOMI too if FPU present) */
- bool pat; /* Page Attribute Table */
- bool pse_36; /* 36-bit PSEs */
- bool psn; /* Processor serial number */
- bool clflsh; /* Supports the CLFLUSH instruction */
- bool dts; /* Debug Trace Store */
- bool acpi; /* ACPI via MSR */
- bool pbe; /* Pending Break Enable */
- bool mmx; /* Multimedia Extensions */
- bool fxsr; /* FXSAVE and FXRSTOR instructions (fast save and restore */
- /* of FPU context), and CR4.OSFXSR available */
- bool sse; /* Streaming SIMD Extensions */
- bool sse2; /* Streaming SIMD Extensions 2 */
- bool ss; /* CPU self snoop */
- bool htt; /* Hyper-Threading */
- bool acc; /* Automatic clock control */
- bool syscall; /* SYSCALL/SYSRET */
- bool mp; /* MP Capable. */
- bool nx; /* Execute Disable */
- bool mmxext; /* AMD MMX extensions */
- bool fxsr_opt; /* FXSAVE/FXRSTOR optimizations */
- bool gbpages; /* "pdpe1gb" GB pages */
- bool rdtscp; /* RDTSCP */
- bool lm; /* Long Mode (x86-64) */
- bool nowext; /* AMD 3DNow! extensions */
- bool now; /* 3DNow! */
- bool smp; /* A smp configuration has been found */
- bool pni; /* Streaming SIMD Extensions-3 */
- bool pclmulqd; /* PCLMULQDQ instruction */
- bool dtes64; /* 64-bit Debug Store */
- bool vmx; /* Hardware virtualization */
- bool smx; /* Safer Mode */
- bool est; /* Enhanced SpeedStep */
- bool tm2; /* Thermal Monitor 2 */
- bool sse3; /* Supplemental SSE-3 */
- bool cid; /* Context ID */
- bool fma; /* Fused multiply-add */
- bool cx16; /* CMPXCHG16B */
- bool xtpr; /* Send Task Priority Messages */
- bool pdcm; /* Performance Capabilities */
- bool dca; /* Direct Cache Access */
- bool xmm4_1; /* "sse4_1" SSE-4.1 */
- bool xmm4_2; /* "sse4_2" SSE-4.2 */
- bool x2apic; /* x2APIC */
- bool movbe; /* MOVBE instruction */
- bool popcnt; /* POPCNT instruction */
- bool aes; /* AES Instruction */
- bool xsave; /* XSAVE/XRSTOR/XSETBV/XGETBV */
- bool osxsave; /* XSAVE enabled in the OS */
- bool avx; /* Advanced Vector Extensions */
- bool hypervisor; /* Running on a hypervisor */
- bool ace2; /* Advanced Cryptography Engine v2 */
- bool ace2_en; /* ACE v2 enabled */
- bool phe; /* PadLock Hash Engine */
- bool phe_en; /* PadLock Hash Engine Enabled */
- bool pmm; /* PadLock Montgomery Multiplier */
- bool pmm_en; /* PadLock Montgomery Multiplier enabled */
- bool svm; /* Secure virtual machine */
- bool extapic; /* Extended APIC space */
- bool cr8_legacy; /* CR8 in 32-bit mode */
- bool abm; /* Advanced bit manipulation */
- bool sse4a; /* SSE4-A */
- bool misalignsse; /* Misaligned SSE mode */
- bool nowprefetch; /* 3DNow prefetch instructions */
- bool osvw; /* OS Visible Workaround */
- bool ibs; /* Instruction Based Sampling */
- bool sse5; /* SSE5 */
- bool skinit; /* SKINIT/STGI instructions */
- bool wdt; /* Watchdog Timer */
- bool ida; /* Intel Dynamic Acceleration */
- bool arat; /* Always Running APIC Timer */
- bool tpr_shadow; /* Intel TPR Shadow */
- bool vnmi; /* Intel Virtual NMI */
- bool flexpriority; /* Intel FlexPriority */
- bool ept; /* Intel Extended Page Table */
- bool vpid; /* Intel Virtual Processor ID */
+ CPU_FLAGS(STRUCT_MEMBERS)
} s_cpu_flags;
+extern size_t cpu_flags_offset[];
+extern const char *cpu_flags_names[];
+extern size_t cpu_flags_count;
+
typedef struct {
char vendor[CPU_VENDOR_SIZE];
uint8_t vendor_id;
@@ -135,6 +150,7 @@ typedef struct {
s_cpu_flags flags;
} s_cpu;
+extern bool get_cpu_flag_value_from_name(s_cpu *cpu, const char * flag);
/**********************************************************************************/
/**********************************************************************************/
/* From this point this is some internal stuff mainly taken from the linux kernel */
@@ -171,11 +187,37 @@ typedef struct {
#define X86_VENDOR_RISE 6
#define X86_VENDOR_TRANSMETA 7
#define X86_VENDOR_NSC 8
-#define X86_VENDOR_NUM 9
-#define X86_VENDOR_UNKNOWN 0xff
+#define X86_VENDOR_UNKNOWN 9
+#define X86_VENDOR_NUM 10
#define cpu_has(c, bit) test_bit(bit, (c)->x86_capability)
+// Taken from asm/processor-flags.h
+// NSC/Cyrix CPU configuration register indexes
+#define CX86_CCR2 0xc2
+#define CX86_CCR3 0xc3
+#define CX86_DIR0 0xfe
+#define CX86_DIR1 0xff
+
+static const char Cx86_model[][9] = {
+ "Cx486", "Cx486", "5x86 ", "6x86", "MediaGX ", "6x86MX ",
+ "M II ", "Unknown"
+};
+
+static const char Cx486_name[][5] = {
+ "SLC", "DLC", "SLC2", "DLC2", "SRx", "DRx",
+ "SRx2", "DRx2"
+};
+
+static const char Cx486S_name[][4] = {
+ "S", "S2", "Se", "S2e"
+};
+
+static const char Cx486D_name[][4] = {
+ "DX", "DX2", "?", "?", "?", "DX4"
+};
+
+
/*
* CPU type and hardware bug flags. Kept separately for each CPU.
* Members of this structure are referenced in head.S, so think twice
@@ -260,6 +302,16 @@ struct intel_mp_floating {
uint8_t mpf_feature5; /* Unused (0) */
};
+static inline uint8_t getCx86(uint8_t reg) {
+ outb(reg, 0x22);
+ return inb(0x23);
+}
+
+static inline void setCx86(uint8_t reg, uint8_t data) {
+ outb(reg, 0x22);
+ outb(data, 0x23);
+}
+
extern void get_cpu_vendor(struct cpuinfo_x86 *c);
extern void detect_cpu(s_cpu * cpu);
#endif
diff --git a/com32/gplinclude/dmi/dmi_bios.h b/com32/gplinclude/dmi/dmi_bios.h
index 5d47e899..4af7e0bd 100644
--- a/com32/gplinclude/dmi/dmi_bios.h
+++ b/com32/gplinclude/dmi/dmi_bios.h
@@ -22,7 +22,7 @@
#define BIOS_BIOS_REVISION_SIZE 16
#define BIOS_FIRMWARE_REVISION_SIZE 16
-#define BIOS_CHAR_NB_ELEMENTS 28
+#define BIOS_CHAR_NB_ELEMENTS 29
#define BIOS_CHAR_X1_NB_ELEMENTS 8
#define BIOS_CHAR_X2_NB_ELEMENTS 3
@@ -46,6 +46,7 @@ typedef struct {
bool boot_from_cd;
bool selectable_boot;
bool bios_rom_socketed;
+ bool boot_from_pcmcia;
bool edd;
bool japanese_floppy_nec_9800_1_2MB;
bool japanese_floppy_toshiba_1_2MB;
diff --git a/com32/gplinclude/zzjson/zzjson.h b/com32/gplinclude/zzjson/zzjson.h
new file mode 100644
index 00000000..d4b32e12
--- /dev/null
+++ b/com32/gplinclude/zzjson/zzjson.h
@@ -0,0 +1,116 @@
+/* ZZJSON - Copyright (C) 2008 by Ivo van Poorten
+ * License: GNU Lesser General Public License version 2.1
+ */
+#ifndef ZZJSON_H
+#define ZZJSON_H
+
+#include <stdlib.h>
+
+/* Version: */
+
+#define ZZJSON_VERSION_MAJOR 1
+#define ZZJSON_VERSION_MINOR 1
+#define ZZJSON_VERSION_MICRO 0
+#define ZZJSON_VERSION_INT ( 1<<16 | 1<<8 | 0 )
+#define ZZJSON_IDENT "zzjson 1.1.0"
+
+/* Defines: */
+
+#define ZZJSON_ALLOW_EXTRA_COMMA 1
+#define ZZJSON_ALLOW_ILLEGAL_ESCAPE 2
+#define ZZJSON_ALLOW_CONTROL_CHARS 4
+#define ZZJSON_ALLOW_GARBAGE_AT_END 8
+#define ZZJSON_ALLOW_COMMENTS 16
+
+#define ZZJSON_VERY_LOOSE (-1)
+#define ZZJSON_VERY_STRICT 0
+
+/* Types: */
+
+/* needed by: pa = parser, pr = printer, f = free, q = query, c = create */
+typedef struct ZZJSON_CONFIG {
+ int strictness; // pa
+ void *ihandle; // pa
+ int (*getchar)(void *ihandle); // pa
+ int (*ungetchar)(int c, void *ihandle); // pa
+ void *(*malloc)(size_t size); // pa c
+ void *(*calloc)(size_t nmemb, size_t size); // pa c
+ void (*free)(void *ptr); // pa f c
+ void *(*realloc)(void *ptr, size_t size); // pa
+ void *ehandle; // pa pr c
+ void (*error)(void *ehandle, const char *format, ...); // pa pr c
+ void *ohandle; // pr
+ int (*print)(void *ohandle, const char *format, ...); // pr
+ int (*putchar)(int c, void *handle); // pr
+} ZZJSON_CONFIG;
+
+typedef enum ZZJSON_TYPE {
+ ZZJSON_NONE = 0,
+ ZZJSON_OBJECT,
+ ZZJSON_ARRAY,
+ ZZJSON_STRING,
+ ZZJSON_NUMBER_NEGINT,
+ ZZJSON_NUMBER_POSINT,
+ ZZJSON_NUMBER_DOUBLE,
+ ZZJSON_NULL,
+ ZZJSON_TRUE,
+ ZZJSON_FALSE
+} ZZJSON_TYPE;
+
+typedef struct ZZJSON {
+ ZZJSON_TYPE type;
+ union {
+ struct {
+ char *label;
+ struct ZZJSON *val;
+ } object;
+ struct {
+ struct ZZJSON *val;
+ } array;
+ struct {
+ char *string;
+ } string;
+ struct {
+ union {
+ unsigned long long ival;
+ double dval;
+ } val;
+ } number;
+ } value;
+ struct ZZJSON *next;
+} ZZJSON;
+
+/* Functions: */
+
+ZZJSON *zzjson_parse(ZZJSON_CONFIG *config);
+void zzjson_free(ZZJSON_CONFIG *config, ZZJSON *zzjson);
+int zzjson_print(ZZJSON_CONFIG *config, ZZJSON *zzjson);
+
+ZZJSON *zzjson_object_find_label(ZZJSON *zzjson, char *label);
+ZZJSON *zzjson_object_find_labels(ZZJSON *zzjson, ...); // end with , NULL
+unsigned int zzjson_object_count(ZZJSON *zzjson);
+unsigned int zzjson_array_count(ZZJSON *zzjson);
+
+ZZJSON *zzjson_create_true(ZZJSON_CONFIG *config);
+ZZJSON *zzjson_create_false(ZZJSON_CONFIG *config);
+ZZJSON *zzjson_create_null(ZZJSON_CONFIG *config);
+ZZJSON *zzjson_create_number_d(ZZJSON_CONFIG *config, double d);
+ZZJSON *zzjson_create_number_i(ZZJSON_CONFIG *config, long long i);
+ZZJSON *zzjson_create_string(ZZJSON_CONFIG *config, char *s);
+
+/* list of ZZJSON *'s and end with , NULL */
+ZZJSON *zzjson_create_array(ZZJSON_CONFIG *config, ...);
+
+/* list of char*,ZZJSON* pairs, end with , NULL */
+ZZJSON *zzjson_create_object(ZZJSON_CONFIG *config, ...);
+
+ZZJSON *zzjson_array_prepend(ZZJSON_CONFIG *config, ZZJSON *array,
+ ZZJSON *val);
+ZZJSON *zzjson_array_append (ZZJSON_CONFIG *config, ZZJSON *array,
+ ZZJSON *val);
+
+ZZJSON *zzjson_object_prepend(ZZJSON_CONFIG *config, ZZJSON *object,
+ char *label, ZZJSON *val);
+ZZJSON *zzjson_object_append (ZZJSON_CONFIG *config, ZZJSON *object,
+ char *label, ZZJSON *val);
+#endif
diff --git a/com32/gpllib/Makefile b/com32/gpllib/Makefile
index a1740610..4b7b8468 100644
--- a/com32/gpllib/Makefile
+++ b/com32/gpllib/Makefile
@@ -4,11 +4,12 @@
# Include configuration rules
topdir = ../..
-include ../lib/MCONFIG
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/lib.mk
-REQFLAGS += -I../gplinclude
+REQFLAGS += -I../gplinclude -I../gplinclude/zzjson
-GPLDIRS := . disk dmi vpd acpi
+GPLDIRS := . disk dmi vpd acpi zzjson
LIBOBJS := $(foreach dir,$(GPLDIRS),$(patsubst %.c,%.o,$(wildcard $(dir)/*.c)))
BINDIR = /usr/bin
diff --git a/com32/gpllib/acpi/acpi.c b/com32/gpllib/acpi/acpi.c
index 8e5ee29c..d2bf29e5 100644
--- a/com32/gpllib/acpi/acpi.c
+++ b/com32/gpllib/acpi/acpi.c
@@ -32,6 +32,25 @@
#include <memory.h>
#include "acpi/acpi.h"
+/* M1PS flags have to be interpreted as strings */
+char *flags_to_string(char *buffer, uint16_t flags)
+{
+ memset(buffer, 0, sizeof(buffer));
+ strcpy(buffer, "default");
+ if ((flags & POLARITY_ACTIVE_HIGH) == POLARITY_ACTIVE_HIGH)
+ strcpy(buffer, "high");
+ else if ((flags & POLARITY_ACTIVE_LOW) == POLARITY_ACTIVE_LOW)
+ strcpy(buffer, "low");
+ if ((flags & TRIGGER_EDGE) == TRIGGER_EDGE)
+ strncat(buffer, " edge", 5);
+ else if ((flags & TRIGGER_LEVEL) == TRIGGER_LEVEL)
+ strncat(buffer, " level", 6);
+ else
+ strncat(buffer, " default", 8);
+
+ return buffer;
+}
+
void dbg_printf(const char *fmt, ...)
{
va_list args;
diff --git a/com32/gpllib/cpuid.c b/com32/gpllib/cpuid.c
index 2d5b5ce9..2abd0bda 100644
--- a/com32/gpllib/cpuid.c
+++ b/com32/gpllib/cpuid.c
@@ -20,8 +20,31 @@
#include <string.h>
#include "cpuid.h"
+const char *cpu_flags_names[] = {
+ CPU_FLAGS(STRUCT_MEMBER_NAMES)
+};
+
+size_t cpu_flags_offset[] = {
+ CPU_FLAGS(STRUCTURE_MEMBER_OFFSETS)
+};
+
+size_t cpu_flags_count = sizeof cpu_flags_names / sizeof *cpu_flags_names;
+
struct cpu_dev *cpu_devs[X86_VENDOR_NUM] = { };
+bool get_cpu_flag_value_from_name(s_cpu *cpu, const char * flag_name) {
+ size_t i;
+ bool cpu_flag_present=false, *flag_value = &cpu_flag_present;
+
+ for (i = 0; i < cpu_flags_count; i++) {
+ if (strcmp(cpu_flags_names[i],flag_name) == 0) {
+ flag_value = (bool *)((char *)&cpu->flags + cpu_flags_offset[i]);
+ }
+ }
+ return *flag_value;
+}
+
+
/*
* CPUID functions returning a single datum
*/
@@ -73,6 +96,48 @@ static struct cpu_dev transmeta_cpu_dev = {
.c_ident = {"GenuineTMx86", "TransmetaCPU"}
};
+static struct cpu_dev nsc_cpu_dev = {
+ .c_vendor = "National Semiconductor",
+ .c_ident = {"Geode by NSC"}
+};
+
+static struct cpu_dev unknown_cpu_dev = {
+ .c_vendor = "Unknown Vendor",
+ .c_ident = {"Unknown CPU"}
+};
+
+/*
+ * Read NSC/Cyrix DEVID registers (DIR) to get more detailed info. about the CPU
+ */
+void do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
+{
+ unsigned char ccr2, ccr3;
+
+ /* we test for DEVID by checking whether CCR3 is writable */
+ ccr3 = getCx86(CX86_CCR3);
+ setCx86(CX86_CCR3, ccr3 ^ 0x80);
+ getCx86(0xc0); /* dummy to change bus */
+
+ if (getCx86(CX86_CCR3) == ccr3) { /* no DEVID regs. */
+ ccr2 = getCx86(CX86_CCR2);
+ setCx86(CX86_CCR2, ccr2 ^ 0x04);
+ getCx86(0xc0); /* dummy */
+
+ if (getCx86(CX86_CCR2) == ccr2) /* old Cx486SLC/DLC */
+ *dir0 = 0xfd;
+ else { /* Cx486S A step */
+ setCx86(CX86_CCR2, ccr2);
+ *dir0 = 0xfe;
+ }
+ } else {
+ setCx86(CX86_CCR3, ccr3); /* restore CCR3 */
+
+ /* read DIR0 and DIR1 CPU registers */
+ *dir0 = getCx86(CX86_DIR0);
+ *dir1 = getCx86(CX86_DIR1);
+ }
+}
+
void init_cpu_devs(void)
{
cpu_devs[X86_VENDOR_INTEL] = &intel_cpu_dev;
@@ -83,6 +148,8 @@ void init_cpu_devs(void)
cpu_devs[X86_VENDOR_CENTAUR] = &centaur_cpu_dev;
cpu_devs[X86_VENDOR_RISE] = &rise_cpu_dev;
cpu_devs[X86_VENDOR_TRANSMETA] = &transmeta_cpu_dev;
+ cpu_devs[X86_VENDOR_NSC] = &nsc_cpu_dev;
+ cpu_devs[X86_VENDOR_UNKNOWN] = &unknown_cpu_dev;
}
void get_cpu_vendor(struct cpuinfo_x86 *c)
@@ -90,7 +157,7 @@ void get_cpu_vendor(struct cpuinfo_x86 *c)
char *v = c->x86_vendor_id;
int i;
init_cpu_devs();
- for (i = 0; i < X86_VENDOR_NUM; i++) {
+ for (i = 0; i < X86_VENDOR_NUM-1; i++) {
if (cpu_devs[i]) {
if (!strcmp(v, cpu_devs[i]->c_ident[0]) ||
(cpu_devs[i]->c_ident[1] &&
@@ -177,6 +244,96 @@ void detect_cache(uint32_t xlvl, struct cpuinfo_x86 *c)
c->x86_l2_cache_size = l2size;
}
+void detect_cyrix(struct cpuinfo_x86 *c) {
+ unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0;
+ char *buf = c->x86_model_id;
+ char Cx86_cb[] = "?.5x Core/Bus Clock";
+ const char cyrix_model_mult1[] = "12??43";
+ const char cyrix_model_mult2[] = "12233445";
+ const char *p = NULL;
+
+ do_cyrix_devid(&dir0, &dir1);
+ dir0_msn = dir0 >> 4; /* identifies CPU "family" */
+ dir0_lsn = dir0 & 0xf; /* model or clock multiplier */
+ c->x86_model = (dir1 >> 4) + 1;
+ c->x86_mask = dir1 & 0xf;
+ switch (dir0_msn) {
+ unsigned char tmp;
+
+ case 0: /* Cx486SLC/DLC/SRx/DRx */
+ p = Cx486_name[dir0_lsn & 7];
+ break;
+
+ case 1: /* Cx486S/DX/DX2/DX4 */
+ p = (dir0_lsn & 8) ? Cx486D_name[dir0_lsn & 5] : Cx486S_name[dir0_lsn & 3];
+ break;
+
+ case 2: /* 5x86 */
+ Cx86_cb[2] = cyrix_model_mult1[dir0_lsn & 5];
+ p = Cx86_cb+2;
+ break;
+
+ case 3: /* 6x86/6x86L */
+ Cx86_cb[1] = ' ';
+ Cx86_cb[2] = cyrix_model_mult1[dir0_lsn & 5];
+ if (dir1 > 0x21) { /* 686L */
+ Cx86_cb[0] = 'L';
+ p = Cx86_cb;
+ (c->x86_model)++;
+ } else /* 686 */
+ p = Cx86_cb+1;
+
+ c->coma_bug = 1;
+ break;
+ case 4:
+ c->x86_l1_data_cache_size = 16; /* Yep 16K integrated cache thats it */
+ if (c->cpuid_level != 2) { /* Media GX */
+ Cx86_cb[2] = (dir0_lsn & 1) ? '3' : '4';
+ p = Cx86_cb+2;
+ }
+ break;
+
+ case 5: /* 6x86MX/M II */
+ if (dir1 > 7) {
+ dir0_msn++; /* M II */
+ } else {
+ c->coma_bug = 1; /* 6x86MX, it has the bug. */
+ }
+
+ tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0;
+ Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7];
+ p = Cx86_cb+tmp;
+ if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20))
+ (c->x86_model)++;
+ break;
+
+ case 0xf: /* Cyrix 486 without DEVID registers */
+ switch (dir0_lsn) {
+ case 0xd: /* either a 486SLC or DLC w/o DEVID */
+ dir0_msn = 0;
+ p = Cx486_name[(c->hard_math) ? 1 : 0];
+ break;
+
+ case 0xe: /* a 486S A step */
+ dir0_msn = 0;
+ p = Cx486S_name[0];
+ break;
+ }
+ break;
+
+ default:
+ dir0_msn = 7;
+ break;
+ }
+
+ /* If the processor is unknown, we keep the model name we got
+ * from the generic call */
+ if (dir0_msn < 7) {
+ strcpy(buf, Cx86_model[dir0_msn & 7]);
+ if (p) strcat(buf, p);
+ }
+}
+
void generic_identify(struct cpuinfo_x86 *c)
{
uint32_t tfms, xlvl;
@@ -222,6 +379,13 @@ void generic_identify(struct cpuinfo_x86 *c)
get_model_name(c); /* Default name */
}
+ /* Specific detection code */
+ switch (c->x86_vendor) {
+ case X86_VENDOR_CYRIX:
+ case X86_VENDOR_NSC: detect_cyrix(c); break;
+ default: break;
+ }
+
/* Detecting the number of cores */
switch (c->x86_vendor) {
case X86_VENDOR_AMD:
@@ -435,17 +599,12 @@ void set_generic_info(struct cpuinfo_x86 *c, s_cpu * cpu)
void detect_cpu(s_cpu * cpu)
{
struct cpuinfo_x86 c;
+ memset(&c,0,sizeof(c));
c.x86_clflush_size = 32;
- c.x86_l1_data_cache_size = 0;
- c.x86_l1_instruction_cache_size = 0;
- c.x86_l2_cache_size = 0;
c.x86_vendor = X86_VENDOR_UNKNOWN;
c.cpuid_level = -1; /* CPUID not detected */
- c.x86_model = c.x86_mask = 0; /* So far unknown... */
c.x86_num_cores = 1;
- memset(&c.x86_capability, 0, sizeof(c.x86_capability));
- memset(&c.x86_vendor_id, 0, sizeof(c.x86_vendor_id));
- memset(&c.x86_model_id, 0, sizeof(c.x86_model_id));
+ memset(&cpu->flags, 0, sizeof(s_cpu_flags));
if (!have_cpuid_p())
return;
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/zzjson/zzjson_create.c b/com32/gpllib/zzjson/zzjson_create.c
new file mode 100644
index 00000000..7e6bd5bd
--- /dev/null
+++ b/com32/gpllib/zzjson/zzjson_create.c
@@ -0,0 +1,240 @@
+/* JSON Create ZZJSON structures
+ * ZZJSON - Copyright (C) 2008 by Ivo van Poorten
+ * License: GNU Lesser General Public License version 2.1
+ */
+
+#include "zzjson.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#ifdef CONFIG_NO_ERROR_MESSAGES
+#define ERROR(x...)
+#else
+#define ERROR(x...) config->error(config->ehandle, ##x)
+#endif
+#define MEMERROR() ERROR("out of memory")
+
+static ZZJSON *zzjson_create_templ(ZZJSON_CONFIG *config, ZZJSON_TYPE type) {
+ ZZJSON *zzjson = config->calloc(1, sizeof(ZZJSON));
+ if (!zzjson) MEMERROR();
+ else zzjson->type = type;
+ return zzjson;
+}
+
+ZZJSON *zzjson_create_true(ZZJSON_CONFIG *config) {
+ return zzjson_create_templ(config, ZZJSON_TRUE);
+}
+
+ZZJSON *zzjson_create_false(ZZJSON_CONFIG *config) {
+ return zzjson_create_templ(config, ZZJSON_FALSE);
+}
+
+ZZJSON *zzjson_create_null(ZZJSON_CONFIG *config) {
+ return zzjson_create_templ(config, ZZJSON_NULL);
+}
+
+ZZJSON *zzjson_create_number_d(ZZJSON_CONFIG *config, double d) {
+ ZZJSON *zzjson = zzjson_create_templ(config, ZZJSON_NUMBER_DOUBLE);
+ if (zzjson)
+ zzjson->value.number.val.dval = d;
+ return zzjson;
+}
+
+ZZJSON *zzjson_create_number_i(ZZJSON_CONFIG *config, long long i) {
+ ZZJSON *zzjson = zzjson_create_templ(config, ZZJSON_NUMBER_NEGINT);
+ if (zzjson) {
+ zzjson->type = i<0LL ? ZZJSON_NUMBER_NEGINT : ZZJSON_NUMBER_POSINT;
+ zzjson->value.number.val.ival = llabs(i);
+ }
+ return zzjson;
+}
+
+/* sdup mimics strdup, but avoids having another function pointer in config */
+static char *sdup(ZZJSON_CONFIG *config, char *s) {
+ size_t slen = strlen(s)+1;
+ char *scopy = config->malloc(slen);
+
+ if (!scopy) MEMERROR();
+ else memcpy(scopy, s, slen);
+ return scopy;
+}
+
+ZZJSON *zzjson_create_string(ZZJSON_CONFIG *config, char *s) {
+ ZZJSON *zzjson = NULL;
+ char *scopy;
+
+ if (!(scopy = sdup(config,s))) return zzjson;
+
+ if ((zzjson = zzjson_create_templ(config, ZZJSON_STRING)))
+ zzjson->value.string.string = scopy;
+ else
+ config->free(scopy);
+
+ return zzjson;
+}
+
+ZZJSON *zzjson_create_array(ZZJSON_CONFIG *config, ...) {
+ ZZJSON *zzjson, *retval, *val;
+ va_list ap;
+
+ if (!(zzjson = zzjson_create_templ(config, ZZJSON_ARRAY))) return zzjson;
+ retval = zzjson;
+
+ va_start(ap, config);
+ val = va_arg(ap, ZZJSON *);
+ while (val) {
+ zzjson->value.array.val = val;
+ val = va_arg(ap, ZZJSON *);
+
+ if (val) {
+ ZZJSON *next = zzjson_create_templ(config, ZZJSON_ARRAY);
+ if (!next) {
+ while (retval) {
+ next = retval->next;
+ config->free(retval);
+ retval = next;
+ }
+ break;
+ }
+ zzjson->next = next;
+ zzjson = next;
+ }
+ }
+ va_end(ap);
+ return retval;
+}
+
+ZZJSON *zzjson_create_object(ZZJSON_CONFIG *config, ...) {
+ ZZJSON *zzjson, *retval, *val;
+ char *label, *labelcopy;
+ va_list ap;
+
+ if (!(zzjson = zzjson_create_templ(config, ZZJSON_OBJECT))) return zzjson;
+ retval = zzjson;
+
+ va_start(ap, config);
+ label = va_arg(ap, char *);
+ while (label) {
+ val = va_arg(ap, ZZJSON *);
+ labelcopy = sdup(config, label);
+
+ if (!labelcopy) {
+ zzjson_free(config, retval);
+ retval = NULL;
+ break;
+ }
+
+ zzjson->value.object.label = labelcopy;
+ zzjson->value.object.val = val;
+
+ label = va_arg(ap, char *);
+
+ if (label) {
+ ZZJSON *next = zzjson_create_templ(config, ZZJSON_OBJECT);
+ if (!next) {
+ while (retval) {
+ next = retval->next;
+ config->free(retval->value.object.label);
+ config->free(retval);
+ retval = next;
+ }
+ break;
+ }
+ zzjson->next = next;
+ zzjson = next;
+ }
+ }
+ va_end(ap);
+ return retval;
+}
+
+ZZJSON *zzjson_array_prepend(ZZJSON_CONFIG *config, ZZJSON *array,
+ ZZJSON *val) {
+ ZZJSON *zzjson;
+
+ if (!array->value.array.val) { /* empty array */
+ array->value.array.val = val;
+ return array;
+ }
+
+ zzjson = zzjson_create_templ(config, ZZJSON_ARRAY);
+ if (zzjson) {
+ zzjson->value.array.val = val;
+ zzjson->next = array;
+ }
+ return zzjson;
+}
+
+ZZJSON *zzjson_array_append(ZZJSON_CONFIG *config, ZZJSON *array,
+ ZZJSON *val) {
+ ZZJSON *retval = array, *zzjson;
+
+ if (!array->value.array.val) { /* empty array */
+ array->value.array.val = val;
+ return array;
+ }
+
+ zzjson = zzjson_create_templ(config, ZZJSON_ARRAY);
+ if (!zzjson) return NULL;
+
+ while (array->next) array = array->next;
+
+ zzjson->value.array.val = val;
+ array->next = zzjson;
+
+ return retval;
+}
+
+ZZJSON *zzjson_object_prepend(ZZJSON_CONFIG *config, ZZJSON *object,
+ char *label, ZZJSON *val) {
+ ZZJSON *zzjson = NULL;
+ char *labelcopy = sdup(config, label);
+
+ if (!labelcopy) return zzjson;
+
+ if (!object->value.object.label) { /* empty object */
+ object->value.object.label = labelcopy;
+ object->value.object.val = val;
+ return object;
+ }
+
+ zzjson = zzjson_create_templ(config, ZZJSON_OBJECT);
+ if (zzjson) {
+ zzjson->value.object.label = labelcopy;
+ zzjson->value.object.val = val;
+ zzjson->next = object;
+ } else {
+ config->free(labelcopy);
+ }
+ return zzjson;
+}
+
+ZZJSON *zzjson_object_append(ZZJSON_CONFIG *config, ZZJSON *object,
+ char *label, ZZJSON *val) {
+ ZZJSON *retval = object, *zzjson = NULL;
+ char *labelcopy = sdup(config, label);
+
+ if (!labelcopy) return zzjson;
+
+ if (!object->value.object.label) { /* empty object */
+ object->value.object.label = labelcopy;
+ object->value.object.val = val;
+ return object;
+ }
+
+ zzjson = zzjson_create_templ(config, ZZJSON_OBJECT);
+ if (!zzjson) {
+ config->free(labelcopy);
+ return NULL;
+ }
+
+ while (object->next) object = object->next;
+
+ zzjson->value.object.label = labelcopy;
+ zzjson->value.object.val = val;
+ object->next = zzjson;
+
+ return retval;
+}
+
diff --git a/com32/gpllib/zzjson/zzjson_free.c b/com32/gpllib/zzjson/zzjson_free.c
new file mode 100644
index 00000000..01dfd242
--- /dev/null
+++ b/com32/gpllib/zzjson/zzjson_free.c
@@ -0,0 +1,29 @@
+/* JSON free
+ * ZZJSON - Copyright (C) 2008 by Ivo van Poorten
+ * License: GNU Lesser General Public License version 2.1
+ */
+
+#include "zzjson.h"
+
+void zzjson_free(ZZJSON_CONFIG *config, ZZJSON *zzjson) {
+ while (zzjson) {
+ ZZJSON *next;
+ switch(zzjson->type) {
+ case ZZJSON_OBJECT:
+ config->free(zzjson->value.object.label);
+ zzjson_free(config, zzjson->value.object.val);
+ break;
+ case ZZJSON_ARRAY:
+ zzjson_free(config, zzjson->value.array.val);
+ break;
+ case ZZJSON_STRING:
+ config->free(zzjson->value.string.string);
+ break;
+ default:
+ break;
+ }
+ next = zzjson->next;
+ config->free(zzjson);
+ zzjson = next;
+ }
+}
diff --git a/com32/gpllib/zzjson/zzjson_parse.c b/com32/gpllib/zzjson/zzjson_parse.c
new file mode 100644
index 00000000..ecb6f61e
--- /dev/null
+++ b/com32/gpllib/zzjson/zzjson_parse.c
@@ -0,0 +1,490 @@
+/* JSON Parser
+ * ZZJSON - Copyright (C) 2008-2009 by Ivo van Poorten
+ * License: GNU Lesser General Public License version 2.1
+ */
+
+#include "zzjson.h"
+#include <ctype.h>
+#include <string.h>
+#include <math.h>
+#include <stdio.h>
+
+#define GETC() config->getchar(config->ihandle)
+#define UNGETC(c) config->ungetchar(c, config->ihandle)
+#define SKIPWS() skipws(config)
+#ifdef CONFIG_NO_ERROR_MESSAGES
+#define ERROR(x...)
+#else
+#define ERROR(x...) config->error(config->ehandle, ##x)
+#endif
+#define MEMERROR() ERROR("out of memory")
+
+#define ALLOW_EXTRA_COMMA (config->strictness & ZZJSON_ALLOW_EXTRA_COMMA)
+#define ALLOW_ILLEGAL_ESCAPE (config->strictness & ZZJSON_ALLOW_ILLEGAL_ESCAPE)
+#define ALLOW_CONTROL_CHARS (config->strictness & ZZJSON_ALLOW_CONTROL_CHARS)
+#define ALLOW_GARBAGE_AT_END (config->strictness & ZZJSON_ALLOW_GARBAGE_AT_END)
+#define ALLOW_COMMENTS (config->strictness & ZZJSON_ALLOW_COMMENTS)
+
+static ZZJSON *parse_array(ZZJSON_CONFIG *config);
+static ZZJSON *parse_object(ZZJSON_CONFIG *config);
+
+static void skipws(ZZJSON_CONFIG *config) {
+ int d, c = GETC();
+morews:
+ while (isspace(c)) c = GETC();
+ if (!ALLOW_COMMENTS) goto endws;
+ if (c != '/') goto endws;
+ d = GETC();
+ if (d != '*') goto endws; /* pushing back c will generate a parse error */
+ c = GETC();
+morecomments:
+ while (c != '*') {
+ if (c == EOF) goto endws;
+ c = GETC();
+ }
+ c = GETC();
+ if (c != '/') goto morecomments;
+ c = GETC();
+ if (isspace(c) || c == '/') goto morews;
+endws:
+ UNGETC(c);
+}
+
+static char *parse_string(ZZJSON_CONFIG *config) {
+ unsigned int len = 16, pos = 0;
+ int c;
+ char *str = NULL;
+
+ SKIPWS();
+ c = GETC();
+ if (c != '"') {
+ ERROR("string: expected \" at the start");
+ return NULL;
+ }
+
+ str = config->malloc(len);
+ if (!str) {
+ MEMERROR();
+ return NULL;
+ }
+ c = GETC();
+ while (c > 0 && c != '"') {
+ if (!ALLOW_CONTROL_CHARS && c >= 0 && c <= 31) {
+ ERROR("string: control characters not allowed");
+ goto errout;
+ }
+ if (c == '\\') {
+ c = GETC();
+ switch (c) {
+ case 'b': c = '\b'; break;
+ case 'f': c = '\f'; break;
+ case 'n': c = '\n'; break;
+ case 'r': c = '\r'; break;
+ case 't': c = '\t'; break;
+ case 'u': {
+ UNGETC(c); /* ignore \uHHHH, copy verbatim */
+ c = '\\';
+ break;
+ }
+ case '\\': case '/': case '"':
+ break;
+ default:
+ if (!ALLOW_ILLEGAL_ESCAPE) {
+ ERROR("string: illegal escape character");
+ goto errout;
+ }
+ }
+ }
+ str[pos++] = c;
+ if (pos == len-1) {
+ void *tmp = str;
+ len *= 2;
+ str = config->realloc(str, len);
+ if (!str) {
+ MEMERROR();
+ str = tmp;
+ goto errout;
+ }
+ }
+ c = GETC();
+ }
+ if (c != '"') {
+ ERROR("string: expected \" at the end");
+ goto errout;
+ }
+ str[pos] = 0;
+ return str;
+
+errout:
+ config->free(str);
+ return NULL;
+}
+
+static ZZJSON *parse_string2(ZZJSON_CONFIG *config) {
+ ZZJSON *zzjson = NULL;
+ char *str;
+
+ str = parse_string(config);
+ if (str) {
+ zzjson = config->calloc(1, sizeof(ZZJSON));
+ if (!zzjson) {
+ MEMERROR();
+ config->free(str);
+ return NULL;
+ }
+ zzjson->type = ZZJSON_STRING;
+ zzjson->value.string.string = str;
+ }
+ return zzjson;
+}
+
+static ZZJSON *parse_number(ZZJSON_CONFIG *config) {
+ ZZJSON *zzjson;
+ unsigned long long ival = 0, expo = 0;
+ double dval = 0.0, frac = 0.0, fracshft = 10.0;
+ int c, dbl = 0, sign = 1, signexpo = 1;
+
+ SKIPWS();
+ c = GETC();
+ if (c == '-') {
+ sign = -1;
+ c = GETC();
+ }
+ if (c == '0') {
+ c = GETC();
+ goto skip;
+ }
+
+ if (!isdigit(c)) {
+ ERROR("number: digit expected");
+ return NULL;
+ }
+
+ while (isdigit(c)) {
+ ival *= 10;
+ ival += c - '0';
+ c = GETC();
+ }
+
+skip:
+ if (c != '.') goto skipfrac;
+
+ dbl = 1;
+
+ c = GETC();
+ if (!isdigit(c)) {
+ ERROR("number: digit expected");
+ return NULL;
+ }
+
+ while (isdigit(c)) {
+ frac += (double)(c - '0') / fracshft;
+ fracshft *= 10.0;
+ c = GETC();
+ }
+
+skipfrac:
+ if (c != 'e' && c != 'E') goto skipexpo;
+
+ dbl = 1;
+
+ c = GETC();
+ if (c == '+')
+ c = GETC();
+ else if (c == '-') {
+ signexpo = -1;
+ c = GETC();
+ }
+
+ if (!isdigit(c)) {
+ ERROR("number: digit expected");
+ return NULL;
+ }
+
+ while (isdigit(c)) {
+ expo *= 10;
+ expo += c - '0';
+ c = GETC();
+ }
+
+skipexpo:
+ UNGETC(c);
+
+ if (dbl) {
+ dval = sign * (long long) ival;
+ dval += sign * frac;
+ dval *= pow(10.0, (double) signexpo * expo);
+ }
+
+ zzjson = config->calloc(1, sizeof(ZZJSON));
+ if (!zzjson) {
+ MEMERROR();
+ return NULL;
+ }
+ if (dbl) {
+ zzjson->type = ZZJSON_NUMBER_DOUBLE;
+ zzjson->value.number.val.dval = dval;
+ } else {
+ zzjson->type = sign < 0 ? ZZJSON_NUMBER_NEGINT : ZZJSON_NUMBER_POSINT;
+ zzjson->value.number.val.ival = ival;
+ }
+
+ return zzjson;
+}
+
+static ZZJSON *parse_literal(ZZJSON_CONFIG *config, char *s, ZZJSON_TYPE t) {
+ char b[strlen(s)+1];
+ unsigned int i;
+
+ for (i=0; i<strlen(s); i++) b[i] = GETC();
+ b[i] = 0;
+
+ if (!strcmp(b,s)) {
+ ZZJSON *zzjson;
+ zzjson = config->calloc(1, sizeof(ZZJSON));
+ if (!zzjson) {
+ MEMERROR();
+ return NULL;
+ }
+ zzjson->type = t;
+ return zzjson;
+ }
+ ERROR("literal: expected %s", s);
+ return NULL;
+}
+
+static ZZJSON *parse_true(ZZJSON_CONFIG *config) {
+ return parse_literal(config, (char *)"true", ZZJSON_TRUE);
+}
+
+static ZZJSON *parse_false(ZZJSON_CONFIG *config) {
+ return parse_literal(config, (char *)"false", ZZJSON_FALSE);
+}
+
+static ZZJSON *parse_null(ZZJSON_CONFIG *config) {
+ return parse_literal(config, (char *)"null", ZZJSON_NULL);
+}
+
+static ZZJSON *parse_value(ZZJSON_CONFIG *config) {
+ ZZJSON *retval = NULL;
+ int c;
+
+ SKIPWS();
+ c = GETC();
+ UNGETC(c);
+ switch (c) {
+ case '"': retval = parse_string2(config); break;
+ case '0': case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9': case '-':
+ retval = parse_number(config); break;
+ case '{': retval = parse_object(config); break;
+ case '[': retval = parse_array(config); break;
+ case 't': retval = parse_true(config); break;
+ case 'f': retval = parse_false(config); break;
+ case 'n': retval = parse_null(config); break;
+ }
+
+ if (!retval) {
+ ERROR("value: invalid value");
+ return retval;
+ }
+
+ return retval;
+}
+
+static ZZJSON *parse_array(ZZJSON_CONFIG *config) {
+ ZZJSON *retval = NULL, **next = &retval;
+ int c;
+
+ SKIPWS();
+ c = GETC();
+ if (c != '[') {
+ ERROR("array: expected '['");
+ return NULL;
+ }
+
+ SKIPWS();
+ c = GETC();
+ while (c > 0 && c != ']') {
+ ZZJSON *zzjson = NULL, *val = NULL;
+
+ UNGETC(c);
+
+ SKIPWS();
+ val = parse_value(config);
+ if (!val) {
+ ERROR("array: value expected");
+ goto errout;
+ }
+
+ SKIPWS();
+ c = GETC();
+ if (c != ',' && c != ']') {
+ ERROR("array: expected ',' or ']'");
+errout_with_val:
+ zzjson_free(config, val);
+ goto errout;
+ }
+ if (c == ',') {
+ SKIPWS();
+ c = GETC();
+ if (c == ']' && !ALLOW_EXTRA_COMMA) {
+ ERROR("array: expected value after ','");
+ goto errout_with_val;
+ }
+ }
+ UNGETC(c);
+
+ zzjson = config->calloc(1, sizeof(ZZJSON));
+ if (!zzjson) {
+ MEMERROR();
+ zzjson_free(config, val);
+ goto errout_with_val;
+ }
+ zzjson->type = ZZJSON_ARRAY;
+ zzjson->value.array.val = val;
+ *next = zzjson;
+ next = &zzjson->next;
+
+ c = GETC();
+ }
+
+ if (c != ']') {
+ ERROR("array: expected ']'");
+ goto errout;
+ }
+
+ if (!retval) { /* empty array, [ ] */
+ retval = config->calloc(1, sizeof(ZZJSON));
+ if (!retval) {
+ MEMERROR();
+ return NULL;
+ }
+ retval->type = ZZJSON_ARRAY;
+ }
+
+ return retval;
+
+errout:
+ zzjson_free(config, retval);
+ return NULL;
+}
+
+static ZZJSON *parse_object(ZZJSON_CONFIG *config) {
+ ZZJSON *retval = NULL;
+ int c;
+ ZZJSON **next = &retval;
+
+ SKIPWS();
+ c = GETC();
+ if (c != '{') {
+ ERROR("object: expected '{'");
+ return NULL;
+ }
+
+ SKIPWS();
+ c = GETC();
+ while (c > 0 && c != '}') {
+ ZZJSON *zzjson = NULL, *val = NULL;
+ char *str;
+
+ UNGETC(c);
+
+ str = parse_string(config);
+ if (!str) {
+ ERROR("object: expected string");
+errout_with_str:
+ config->free(str);
+ goto errout;
+ }
+
+ SKIPWS();
+ c = GETC();
+ if (c != ':') {
+ ERROR("object: expected ':'");
+ goto errout_with_str;
+ }
+
+ SKIPWS();
+ val = parse_value(config);
+ if (!val) {
+ ERROR("object: value expected");
+ goto errout_with_str;
+ }
+
+ SKIPWS();
+ c = GETC();
+ if (c != ',' && c != '}') {
+ ERROR("object: expected ',' or '}'");
+errout_with_str_and_val:
+ zzjson_free(config, val);
+ goto errout_with_str;
+ }
+ if (c == ',') {
+ SKIPWS();
+ c = GETC();
+ if (c == '}' && !ALLOW_EXTRA_COMMA) {
+ ERROR("object: expected pair after ','");
+ goto errout_with_str_and_val;
+ }
+ }
+ UNGETC(c);
+
+ zzjson = config->calloc(1, sizeof(ZZJSON));
+ if (!zzjson) {
+ MEMERROR();
+ goto errout_with_str_and_val;
+ }
+ zzjson->type = ZZJSON_OBJECT;
+ zzjson->value.object.label = str;
+ zzjson->value.object.val = val;
+ *next = zzjson;
+ next = &zzjson->next;
+
+ c = GETC();
+ }
+
+ if (c != '}') {
+ ERROR("object: expected '}'");
+ goto errout;
+ }
+
+ if (!retval) { /* empty object, { } */
+ retval = config->calloc(1, sizeof(ZZJSON));
+ if (!retval) {
+ MEMERROR();
+ return NULL;
+ }
+ retval->type = ZZJSON_OBJECT;
+ }
+
+ return retval;
+
+errout:
+ zzjson_free(config, retval);
+ return NULL;
+}
+
+ZZJSON *zzjson_parse(ZZJSON_CONFIG *config) {
+ ZZJSON *retval;
+ int c;
+
+ SKIPWS();
+ c = GETC();
+ UNGETC(c);
+ if (c == '[') retval = parse_array(config);
+ else if (c == '{') retval = parse_object(config);
+ else { ERROR("expected '[' or '{'"); return NULL; }
+
+ if (!retval) return NULL;
+
+ SKIPWS();
+ c = GETC();
+ if (c >= 0 && !ALLOW_GARBAGE_AT_END) {
+ ERROR("parse: garbage at end of file");
+ zzjson_free(config, retval);
+ return NULL;
+ }
+
+ return retval;
+}
diff --git a/com32/gpllib/zzjson/zzjson_print.c b/com32/gpllib/zzjson/zzjson_print.c
new file mode 100644
index 00000000..a59b3b09
--- /dev/null
+++ b/com32/gpllib/zzjson/zzjson_print.c
@@ -0,0 +1,110 @@
+/* JSON Printer
+ * ZZJSON - Copyright (C) 2008 by Ivo van Poorten
+ * License: GNU Lesser General Public License version 2.1
+ */
+
+#include "zzjson.h"
+
+#define PRINT(fmt...) if (config->print(config->ohandle, ##fmt) < 0) return -1;
+//#define PUTC(c) if (config->putchar(c, config->ohandle) < 0) return -1;
+#define PUTC(c) PRINT("%c",c)
+#define INC 4
+
+static int print_string(ZZJSON_CONFIG *config, char *s) {
+ int c, bs;
+ if (!s) return 0;
+ while ((c = *s++)) {
+ bs = 1;
+ switch (c) {
+// case '/': // useless escape of forward slash
+ case '\\':
+ if (*s == 'u') bs = 0; // copy \uHHHH verbatim
+ break;
+ case '"': break;
+ case '\b': c = 'b'; break;
+ case '\f': c = 'f'; break;
+ case '\n': c = 'n'; break;
+ case '\r': c = 'r'; break;
+ case '\t': c = 't'; break;
+ default: bs = 0; break;
+ }
+ if (bs) PUTC('\\');
+ PUTC(c);
+ }
+ return 0;
+}
+
+static int zzjson_print2(ZZJSON_CONFIG *config, ZZJSON *zzjson,
+ unsigned int indent, unsigned int objval) {
+ char c = 0, d = 0;
+ if (!zzjson) return -1;
+
+ switch(zzjson->type) {
+ case ZZJSON_OBJECT: c = '{'; d = '}'; break;
+ case ZZJSON_ARRAY: c = '['; d = ']'; break;
+ default: break;
+ }
+
+ if (c) PRINT("%s%*s%c", indent ? "\n" : "", indent, "", c);
+
+ while (zzjson) {
+ switch(zzjson->type) {
+ case ZZJSON_OBJECT:
+ if (zzjson->value.object.val) {
+ PRINT("\n%*s\"", indent+INC, "");
+ if (print_string(config, zzjson->value.object.label) < 0)
+ return -1;
+ PRINT("\" :");
+ if (zzjson_print2(config, zzjson->value.object.val,
+ indent+INC, 1) < 0) return -1;
+ }
+ break;
+ case ZZJSON_ARRAY:
+ if (zzjson->value.array.val)
+ if (zzjson_print2(config, zzjson->value.array.val,
+ indent+INC, 0) < 0) return -1;
+ break;
+ case ZZJSON_STRING:
+ PRINT(objval ? " \"" : "\n%*s\"", indent, "");
+ if (print_string(config, zzjson->value.string.string)<0) return -1;
+ PUTC('"');
+ break;
+ case ZZJSON_FALSE:
+ PRINT(objval ? " false" : "\n%*sfalse", indent, "");
+ break;
+ case ZZJSON_NULL:
+ PRINT(objval ? " null" : "\n%*snull", indent, "");
+ break;
+ case ZZJSON_TRUE:
+ PRINT(objval ? " true" : "\n%*strue", indent, "");
+ break;
+ case ZZJSON_NUMBER_NEGINT:
+ case ZZJSON_NUMBER_POSINT:
+ case ZZJSON_NUMBER_DOUBLE:
+ PRINT(objval ? " " : "\n%*s", indent, "");
+ if (zzjson->type == ZZJSON_NUMBER_DOUBLE) {
+ PRINT("%16.16e", zzjson->value.number.val.dval);
+ } else {
+ if (zzjson->type == ZZJSON_NUMBER_NEGINT) PUTC('-');
+ PRINT("%llu", zzjson->value.number.val.ival);
+ }
+ default:
+ break;
+ }
+ zzjson = zzjson->next;
+ if (zzjson) PUTC(',');
+ }
+
+ if (d) PRINT("\n%*s%c", indent, "", d);
+
+ return 0;
+}
+
+int zzjson_print(ZZJSON_CONFIG *config, ZZJSON *zzjson) {
+ int retval = zzjson_print2(config, zzjson, 0, 0);
+// if (retval >= 0) retval = config->putchar('\n', config->ohandle);
+#ifndef CONFIG_NO_ERROR_MESSAGES
+ if (retval < 0) config->error(config->ehandle, "print: unable to print");
+#endif
+ return retval;
+}
diff --git a/com32/gpllib/zzjson/zzjson_query.c b/com32/gpllib/zzjson/zzjson_query.c
new file mode 100644
index 00000000..35ba7b79
--- /dev/null
+++ b/com32/gpllib/zzjson/zzjson_query.c
@@ -0,0 +1,63 @@
+/* JSON query
+ * ZZJSON - Copyright (C) 2008 by Ivo van Poorten
+ * License: GNU Lesser General Public License version 2.1
+ */
+
+#include "zzjson.h"
+#include <string.h>
+#include <stdarg.h>
+
+ZZJSON *zzjson_object_find_label(ZZJSON *zzjson, char *label) {
+ if (zzjson->type != ZZJSON_OBJECT) return NULL;
+
+ while (zzjson) {
+ char *string = zzjson->value.object.label;
+
+ if (zzjson->type != ZZJSON_OBJECT) return NULL;
+ if (!string) return NULL;
+
+ if (!strcmp(string, label))
+ return zzjson->value.object.val;
+ zzjson = zzjson->next;
+ }
+ return NULL;
+}
+
+ZZJSON *zzjson_object_find_labels(ZZJSON *zzjson, ...) {
+ va_list ap;
+ char *lbl;
+
+ va_start(ap, zzjson);
+ lbl = va_arg(ap, char *);
+ while (lbl) {
+ zzjson = zzjson_object_find_label(zzjson, lbl);
+ if (!zzjson) break;
+ lbl = va_arg(ap, char *);
+ }
+ va_end(ap);
+
+ return zzjson;
+}
+
+unsigned int zzjson_object_count(ZZJSON *zzjson) {
+ unsigned int count = 1;
+
+ if (zzjson->type != ZZJSON_OBJECT) return 0;
+ if (!zzjson->value.object.label) return 0; /* empty { } */
+
+ while ((zzjson = zzjson->next)) count++;
+
+ return count;
+}
+
+unsigned int zzjson_array_count(ZZJSON *zzjson) {
+ unsigned int count = 1;
+
+ if (zzjson->type != ZZJSON_ARRAY) return 0;
+ if (!zzjson->value.array.val) return 0; /* empty [ ] */
+
+ while ((zzjson = zzjson->next)) count++;
+
+ return 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 40ea3ac4..add640a7 100644
--- a/com32/hdt/Makefile
+++ b/com32/hdt/Makefile
@@ -16,11 +16,11 @@
##
topdir = ../..
-include ../MCONFIG
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/com32.mk
-LIBS = ../cmenu/libmenu/libmenu.a ../libutil/libutil_com.a \
- ../lib/libcom32.a $(LIBGCC)
-CFLAGS += -I$(com32)/cmenu/libmenu
+LIBS = ../cmenu/libmenu/libmenu.a ../libupload/libcom32upload.a
+CFLAGS += -I$(com32)/cmenu/libmenu -I$(com32)
MODULES = hdt.c32
TESTFILES =
@@ -28,7 +28,8 @@ TESTFILES =
OBJS = $(patsubst %.c,%.o,$(wildcard *.c))
VERSION = $(shell $(SED) -n 's/\#define VERSION \"\(.*\)\"/\1/p' hdt.h)
CODENAME = $(shell $(SED) -n 's/\#define CODENAME \"\(.*\)\"/\1/p' hdt.h)
-VERSION_C32 = $(shell echo $(VERSION) | $(SED) -e 's/-/_/g' | $(SED) -e 's/\./_/g')
+NODASH_VERSION = $(shell echo $(VERSION) | $(SED) -e 's/-/_/g' | $(SED) -e 's/\./_/g')
+SUM_FILE = hdt-$(VERSION).checksums
MEMTEST_URL = http://memtest.org/download/4.20/memtest86+-4.20.bin
MEMTEST = memtest.bin
@@ -44,6 +45,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)/chain/chain.c32
ART_DIR ?= art/
QEMU ?= qemu-kvm
@@ -55,11 +57,11 @@ hdt.elf : $(OBJS) $(LIBS) $(C_LIBS)
memtest:
-[ ! -f $(FLOPPY_DIR)/$(MEMTEST) ] && $(WGET) $(MEMTEST_URL) -O $(FLOPPY_DIR)/$(MEMTEST)
-hdt.img: hdt.c32 $(FLOPPY_DIR)/hdt.cfg $(FLOPPY_DIR)/mtools.conf $(topdir)/mtools/syslinux $(MENU_COM32) memtest
+hdt.img: hdt.c32 $(FLOPPY_DIR)/hdt.cfg $(FLOPPY_DIR)/mtools.conf $(topdir)/mtools/syslinux $(MENU_COM32) memtest $(CHAIN_COM32)
rm -f hdt*.img
$(SED) -e 's/%VERSION%/$(VERSION)/g' $(FLOPPY_DIR)/hdt.cfg |\
$(SED) -e 's/%CODENAME%/$(CODENAME)/g' > $(FLOPPY_DIR)/syslinux.cfg
- MTOOLSRC=$(PWD)/$(FLOPPY_DIR)/mtools.conf $(MFORMAT) -v HDT_$(VERSION) -f 1440 -C a:
+ MTOOLSRC=$(PWD)/$(FLOPPY_DIR)/mtools.conf $(MFORMAT) -v HDT_$(NODASH_VERSION) -f 1440 -C a:
$(topdir)/mtools/syslinux hdt.img
-[ ! -f $(GZ_PCI_IDS_FILE) ] && cp /usr/share/hwdata/pci.ids $(PCI_IDS_FILE) && $(GZIPPROG) $(PCI_IDS_FILE)
-[ ! -f $(GZ_PCI_IDS_FILE) ] && cp /usr/share/pci.ids $(PCI_IDS_FILE) && $(GZIPPROG) $(PCI_IDS_FILE)
@@ -67,10 +69,13 @@ hdt.img: hdt.c32 $(FLOPPY_DIR)/hdt.cfg $(FLOPPY_DIR)/mtools.conf $(topdir)/mtool
-[ -f $(MODULES_PCIMAP_FILE) ] && cat $(MODULES_PCIMAP_FILE) | $(GZIPPROG) - -f | MTOOLSRC=$(PWD)/$(FLOPPY_DIR)/mtools.conf $(MCOPY) - a:modules.pcimap
MTOOLSRC=$(PWD)/$(FLOPPY_DIR)/mtools.conf $(MCOPY) hdt.c32 a:
MTOOLSRC=$(PWD)/$(FLOPPY_DIR)/mtools.conf $(MCOPY) $(MENU_COM32) a:
+ MTOOLSRC=$(PWD)/$(FLOPPY_DIR)/mtools.conf $(MCOPY) $(CHAIN_COM32) a:
@ [ -f $(GZ_PCI_IDS_FILE) ] && MTOOLSRC=$(PWD)/$(FLOPPY_DIR)/mtools.conf $(MCOPY) $(GZ_PCI_IDS_FILE) a:pci.ids || printf "\nThe $(GZ_PCI_IDS_FILE) file is missing and can be downloaded from http://pciids.sourceforge.net and gzipped in\nthe ./com32/hdt/$(FLOPPY_DIR) directory of the extracted Syslinux source.\n\n"
MTOOLSRC=$(PWD)/$(FLOPPY_DIR)/mtools.conf $(MCOPY) $(FLOPPY_DIR)/syslinux.cfg a:
MTOOLSRC=$(PWD)/$(FLOPPY_DIR)/mtools.conf $(MCOPY) $(FLOPPY_DIR)/$(MEMTEST) a:
MTOOLSRC=$(PWD)/$(FLOPPY_DIR)/mtools.conf $(MCOPY) $(ART_DIR)/backgnd.png a:
+ MTOOLSRC=$(PWD)/$(FLOPPY_DIR)/mtools.conf $(MCOPY) $(ART_DIR)/display.png a:
+ MTOOLSRC=$(PWD)/$(FLOPPY_DIR)/mtools.conf $(MCOPY) $(ART_DIR)/red.png a:
mv hdt.img hdt-$(VERSION).img
ln -sf hdt-$(VERSION).img hdt.img
@@ -89,7 +94,10 @@ hdt.iso: hdt.c32 $(topdir)/core/isolinux.bin $(FLOPPY_DIR)/hdt.cfg memtest
cp hdt.c32 $(ISO_DIR)/$(ISOLINUX_DIR)
cp $(FLOPPY_DIR)/$(MEMTEST) $(ISO_DIR)/$(ISOLINUX_DIR)
cp $(MENU_COM32) $(ISO_DIR)/$(ISOLINUX_DIR)
+ cp $(CHAIN_COM32) $(ISO_DIR)/$(ISOLINUX_DIR)
cp -av $(ART_DIR)/backgnd.png $(ISO_DIR)/$(ISOLINUX_DIR)
+ cp -av $(ART_DIR)/display.png $(ISO_DIR)/$(ISOLINUX_DIR)
+ cp -av $(ART_DIR)/red.png $(ISO_DIR)/$(ISOLINUX_DIR)
-[ ! -f $(GZ_PCI_IDS_FILE) ] && cp /usr/share/hwdata/pci.ids $(PCI_IDS_FILE) && $(GZIPPROG) $(PCI_IDS_FILE)
-[ ! -f $(GZ_PCI_IDS_FILE) ] && cp /usr/share/pci.ids $(PCI_IDS_FILE) && $(GZIPPROG) $(PCI_IDS_FILE)
-[ -f $(MODULES_ALIAS_FILE) ] && cp $(MODULES_ALIAS_FILE) $(ISO_DIR)/$(ISOLINUX_DIR)\
@@ -106,8 +114,18 @@ 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
- mv hdt.c32 hdt_$(VERSION_C32).c32
+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)
test: hdt.img
$(QEMU) -fda hdt.img
@@ -123,6 +141,7 @@ spotless: clean
rm -rf $(ISO_DIR)
rm -rf $(FLOPPY_DIR)/$(MEMTEST)
rm -rf $(FLOPPY_DIR)/pci.ids*
+ rm -rf hdt-*checksums
rm -f *~ \#*
install:
diff --git a/com32/hdt/art/display.png b/com32/hdt/art/display.png
new file mode 100644
index 00000000..31fabef6
--- /dev/null
+++ b/com32/hdt/art/display.png
Binary files differ
diff --git a/com32/hdt/art/red.png b/com32/hdt/art/red.png
new file mode 100644
index 00000000..c5616ac2
--- /dev/null
+++ b/com32/hdt/art/red.png
Binary files differ
diff --git a/com32/hdt/floppy/hdt.cfg b/com32/hdt/floppy/hdt.cfg
index f72a2134..524c4e06 100644
--- a/com32/hdt/floppy/hdt.cfg
+++ b/com32/hdt/floppy/hdt.cfg
@@ -77,6 +77,34 @@ ENDTEXT
COM32 hdt.c32
APPEND modules_pcimap=modules.pcimap modules_alias=modules.alias pciids=pci.ids verbose nomenu
+LABEL dump
+MENU LABEL Dump hardware config to TFTP server
+TEXT HELP
+ Starts HDT using the Command Line Interface (CLI) and run 'dump'
+ VESA mode is enabled
+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`;sleep 5;exit' postexec='memtest'
+
+LABEL display
+MENU LABEL Display feature (VESA mode)
+TEXT HELP
+ Starts HDT using the Command Line Interface (CLI)
+ VESA mode is enabled
+ A Picture is shown by using the display command
+ENDTEXT
+COM32 hdt.c32
+APPEND modules_pcimap=modules.pcimap modules_alias=modules.alias pciids=pci.ids silent nomenu vesa auto='display display.png; sleep 5000; display red.png'
+
MENU SEPARATOR
LABEL memtest
diff --git a/com32/hdt/hdt-cli-acpi.c b/com32/hdt/hdt-cli-acpi.c
index 1b608c26..55b0c3c7 100644
--- a/com32/hdt/hdt-cli-acpi.c
+++ b/com32/hdt/hdt-cli-acpi.c
@@ -37,7 +37,7 @@
/* Print ACPI's table header in a defined formating */
static void show_header(void *address, s_acpi_description_header * h)
{
- more_printf("%-4s v%03x %-6s %-7s 0x%08x %-4s 0x%08x @ 0x%p\n",
+ more_printf("%-4s v%03x %-6s %-8s 0x%08x %-7s 0x%08x @ 0x%p\n",
h->signature, h->revision, h->oem_id, h->oem_table_id,
h->oem_revision, h->creator_id, h->creator_revision, address)
}
@@ -158,25 +158,6 @@ static void show_local_apic(s_madt * madt)
}
}
-/* M1PS flags have to be interpreted as strings */
-static char *flags_to_string(char *buffer, uint16_t flags)
-{
- memset(buffer, 0, sizeof(buffer));
- strcpy(buffer, "default");
- if ((flags & POLARITY_ACTIVE_HIGH) == POLARITY_ACTIVE_HIGH)
- strcpy(buffer, "high");
- else if ((flags & POLARITY_ACTIVE_LOW) == POLARITY_ACTIVE_LOW)
- strcpy(buffer, "low");
- if ((flags & TRIGGER_EDGE) == TRIGGER_EDGE)
- strncat(buffer, " edge", 5);
- else if ((flags & TRIGGER_LEVEL) == TRIGGER_LEVEL)
- strncat(buffer, " level", 6);
- else
- strncat(buffer, " default", 8);
-
- return buffer;
-}
-
/* Display the local apic NMI configuration */
static void show_local_apic_nmi(s_madt * madt)
{
@@ -225,7 +206,7 @@ static void show_io_apic(s_madt * madt)
break;
}
- more_printf("IO_APIC[%d] : apic_id[0x%02x] adress[0x%08x] %s\n",
+ more_printf("IO_APIC[%d] : apic_id[0x%02x] address[0x%08x] %s\n",
i, sio->io_apic_id, sio->io_apic_address, buffer);
}
}
@@ -286,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 65068232..3c571d60 100644
--- a/com32/hdt/hdt-cli-hdt.c
+++ b/com32/hdt/hdt-cli-hdt.c
@@ -54,12 +54,12 @@ static void main_show_modes(int argc __unused, char **argv __unused,
int i = 0;
reset_more_printf();
- printf("Available modes:\n");
+ more_printf("Available modes:\n");
while (list_modes[i]) {
printf("%s ", list_modes[i]->name);
i++;
}
- printf("\n");
+ more_printf("\n");
}
/**
@@ -119,7 +119,7 @@ static void show_cli_help(int argc __unused, char **argv __unused,
find_cli_mode_descr(hdt_cli.mode, &current_mode);
- printf("Available commands are:\n");
+ more_printf("Available commands are:\n");
/* List first default modules of the mode */
if (current_mode->default_modules && current_mode->default_modules->modules) {
@@ -154,7 +154,7 @@ static void show_cli_help(int argc __unused, char **argv __unused,
/* List secondly the show modules of the mode */
if (current_mode->show_modules && current_mode->show_modules->modules) {
- printf("\nshow commands:\n");
+ more_printf("\nshow commands:\n");
j = 0;
while (current_mode->show_modules->modules[j].name) {
printf("%s ", current_mode->show_modules->modules[j].name);
@@ -165,7 +165,7 @@ static void show_cli_help(int argc __unused, char **argv __unused,
/* List thirdly the set modules of the mode */
if (current_mode->set_modules && current_mode->set_modules->modules) {
- printf("\nset commands:\n");
+ more_printf("\nset commands:\n");
j = 0;
while (current_mode->set_modules->modules[j].name) {
printf("%s ", current_mode->set_modules->modules[j].name);
@@ -250,97 +250,209 @@ static void do_reboot(int argc __unused, char **argv __unused,
syslinux_reboot(1);
}
+/**
+ * do_dump - dump info
+ **/
+static void do_dump(int argc __unused, char **argv __unused,
+ struct s_hardware *hardware)
+{
+ dump(hardware);
+}
+
+/**
+ * do_sleep - sleep a number of milliseconds
+ **/
+static void do_sleep(int argc , char **argv ,
+ struct s_hardware *hardware)
+{
+ (void) hardware;
+ if (argc != 1) return;
+ more_printf("Sleep %d milliseconds\n",atoi(argv[0]));
+ msleep(atoi(argv[0]));
+}
+
+/**
+ * do_display - display an image to user
+ **/
+static void do_display(int argc , char **argv ,
+ struct s_hardware *hardware)
+{
+ (void) hardware;
+ if ((argc != 1) || (vesamode == false)) return;
+ more_printf("Display %s file\n",argv[0]);
+ vesacon_load_background(argv[0]);
+}
+
+/**
+ * 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;
+#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);
+ }
+
+ more_printf("%s\n",text_to_say);
+ }
+}
+
/* 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 = CLI_DISPLAY,
+ .exec = do_display,
+ .nomodule = true,
+ },
+ {
+ .name = CLI_SLEEP,
+ .exec = do_sleep,
+ .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,
},
};
@@ -348,10 +460,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 8b5335eb..7542da83 100644
--- a/com32/hdt/hdt-cli.c
+++ b/com32/hdt/hdt-cli.c
@@ -132,7 +132,7 @@ void set_mode(cli_mode_t mode, struct s_hardware *hardware)
break;
case PXE_MODE:
if (hardware->sv->filesystem != SYSLINUX_FS_PXELINUX) {
- printf("You are not currently using PXELINUX\n");
+ more_printf("You are not currently using PXELINUX\n");
break;
}
hdt_cli.mode = mode;
@@ -160,7 +160,7 @@ void set_mode(cli_mode_t mode, struct s_hardware *hardware)
break;
case DMI_MODE:
if (!hardware->is_dmi_valid) {
- printf("No valid DMI table found, exiting.\n");
+ more_printf("No valid DMI table found, exiting.\n");
break;
}
hdt_cli.mode = mode;
@@ -172,7 +172,7 @@ void set_mode(cli_mode_t mode, struct s_hardware *hardware)
break;
case VPD_MODE:
if (!hardware->is_vpd_valid) {
- printf("No valid VPD table found, exiting.\n");
+ more_printf("No valid VPD table found, exiting.\n");
break;
}
hdt_cli.mode = mode;
@@ -188,9 +188,9 @@ void set_mode(cli_mode_t mode, struct s_hardware *hardware)
break;
default:
/* Invalid mode */
- printf("Unknown mode, please choose among:\n");
+ more_printf("Unknown mode, please choose among:\n");
while (list_modes[i]) {
- printf("\t%s\n", list_modes[i]->name);
+ more_printf("\t%s\n", list_modes[i]->name);
i++;
}
}
@@ -199,7 +199,7 @@ void set_mode(cli_mode_t mode, struct s_hardware *hardware)
/* There is not cli_mode_descr struct for the exit mode */
if (current_mode == NULL && hdt_cli.mode != EXIT_MODE) {
/* Shouldn't get here... */
- printf("!!! BUG: Mode '%d' unknown.\n", hdt_cli.mode);
+ more_printf("!!! BUG: Mode '%d' unknown.\n", hdt_cli.mode);
}
}
@@ -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) &&
@@ -657,7 +679,7 @@ static void exec_command(char *line, struct s_hardware *hardware)
if (current_module != NULL)
current_module->exec(argc, argv, hardware);
else
- printf("unknown command: '%s'\n", command);
+ more_printf("unknown command: '%s'\n", command);
}
} else {
/*
@@ -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);
@@ -738,8 +761,7 @@ void start_auto_mode(struct s_hardware *hardware)
int nb_commands = 0;
char *commands[MAX_NB_AUTO_COMMANDS];
- if (!quiet)
- more_printf("\nEntering Auto mode\n");
+ more_printf("\nEntering Auto mode\n");
/* Protecting the auto_label from the strtok modifications */
char *temp = strdup(hardware->auto_label);
@@ -811,7 +833,7 @@ void start_cli_mode(struct s_hardware *hardware)
find_cli_mode_descr(hdt_cli.mode, &current_mode);
if (current_mode == NULL) {
/* Shouldn't get here... */
- printf("!!! BUG: Mode '%d' unknown.\n", hdt_cli.mode);
+ more_printf("!!! BUG: Mode '%d' unknown.\n", hdt_cli.mode);
return;
}
@@ -820,7 +842,7 @@ void start_cli_mode(struct s_hardware *hardware)
start_auto_mode(hardware);
}
- printf("Entering CLI mode\n");
+ more_printf("Entering CLI mode\n");
reset_prompt();
diff --git a/com32/hdt/hdt-cli.h b/com32/hdt/hdt-cli.h
index 13291092..82a4fc99 100644
--- a/com32/hdt/hdt-cli.h
+++ b/com32/hdt/hdt-cli.h
@@ -65,6 +65,10 @@
#define CLI_ACPI "acpi"
#define CLI_ENABLE "enable"
#define CLI_DISABLE "disable"
+#define CLI_DUMP "dump"
+#define CLI_SAY "say"
+#define CLI_DISPLAY "display"
+#define CLI_SLEEP "sleep"
typedef enum {
INVALID_MODE,
@@ -119,6 +123,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 f1557b86..dcad28cd 100644
--- a/com32/hdt/hdt-common.c
+++ b/com32/hdt/hdt-common.c
@@ -63,6 +63,9 @@ void detect_parameters(const int argc, const char *argv[],
/* Quiet mode - make the output more quiet */
quiet = true;
+ /* Silent mode - make not output at all */
+ silent = false;
+
/* Vesa mode isn't set until we explictly call it */
vesamode = false;
@@ -75,6 +78,8 @@ void detect_parameters(const int argc, const char *argv[],
for (int i = 1; i < argc; i++) {
if (!strncmp(argv[i], "quiet", 5)) {
quiet = true;
+ } else if (!strncmp(argv[i], "silent", 6)) {
+ silent = true;
} else if (!strncmp(argv[i], "verbose", 7)) {
quiet = false;
} else if (!strncmp(argv[i], "modules_pcimap=", 15)) {
@@ -106,6 +111,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.
@@ -115,25 +150,19 @@ void detect_parameters(const int argc, const char *argv[],
*/
automode=true;
+ char *argument = (char*)argv[i]+6;
/* Extracting the first parameter */
- strcpy(hardware->auto_label, argv[i] + 6);
- strcat(hardware->auto_label, " ");
- char *pos;
- i++;
+ strcpy(hardware->auto_label, argument);
/* While we can't find the other AUTO_DELIMITER, let's process the argv[] */
- while (((pos = strstr(argv[i], AUTO_DELIMITER)) == NULL)
- && (i < argc)) {
- strcat(hardware->auto_label, argv[i]);
- strcat(hardware->auto_label, " ");
+ while ((strchr(argument, AUTO_DELIMITER) == NULL) && (i+1<argc)) {
i++;
- }
+ argument = (char *)argv[i];
+ strcat(hardware->auto_label, " ");
+ strcat(hardware->auto_label, argument);
+ }
- /* If we didn't reach the end of the line, let's grab the last item */
- if (i < argc) {
- strcat(hardware->auto_label, argv[i]);
- hardware->auto_label[strlen(hardware->auto_label) - 1] = 0;
- }
+ hardware->auto_label[strlen(hardware->auto_label) - 1] = 0;
}
}
}
@@ -203,7 +232,13 @@ void init_hardware(struct s_hardware *hardware)
sizeof hardware->modules_alias_path);
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");
@@ -652,7 +687,7 @@ char *del_multi_spaces(char *p)
* As we search for a double spacing
* we have to be sure then string is
* long enough to be processed */
- while (*p && *p + 1) {
+ while (*p && *(p + 1)) {
/* If we have two consecutive spaces */
if ((*p == ' ') && (*(p + 1) == ' ')) {
@@ -709,8 +744,8 @@ void detect_hardware(struct s_hardware *hardware)
if (!quiet)
more_printf("DMI: Detecting Table\n");
if (detect_dmi(hardware) == -ENODMITABLE) {
- printf("DMI: ERROR ! Table not found ! \n");
- printf("DMI: Many hardware components will not be detected ! \n");
+ more_printf("DMI: ERROR ! Table not found ! \n");
+ more_printf("DMI: Many hardware components will not be detected ! \n");
} else {
if (!quiet)
more_printf("DMI: Table found ! (version %u.%u)\n",
diff --git a/com32/hdt/hdt-common.h b/com32/hdt/hdt-common.h
index df7d2c98..c2299b48 100644
--- a/com32/hdt/hdt-common.h
+++ b/com32/hdt/hdt-common.h
@@ -48,16 +48,18 @@
#include "cpuid.h"
#include "dmi/dmi.h"
#include "hdt-ata.h"
-#include "../lib/sys/vesa/vesa.h"
+#include <lib/sys/vesa/vesa.h>
#include <vpd/vpd.h>
#include <libansi.h>
#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"
#define HDT_RETURN_TO_CLI 100
#define MAX_VESA_MODES 255
@@ -71,7 +73,7 @@
/* The char that separate two commands */
#define AUTO_SEPARATOR ";"
/* The char that surround the list of commands */
-#define AUTO_DELIMITER "'"
+#define AUTO_DELIMITER '\''
/* Graphic to load in background when using the vesa mode */
#define CLI_DEFAULT_BACKGROUND "backgnd.png"
@@ -80,9 +82,14 @@
#define MAX_CLI_LINES 20
#define MAX_VESA_CLI_LINES 24
+struct upload_backend *upload;
+
/* Defines if the cli is quiet*/
bool quiet;
+/* Defines if the cli is totally silent*/
+bool silent;
+
/* Defines if we must use the vesa mode */
bool vesamode;
@@ -110,16 +117,18 @@ extern bool disable_more_printf;
* one \n (and only one)
*/
#define more_printf(...) do {\
- if (__likely(!disable_more_printf)) {\
- if (display_line_nb == max_console_lines) {\
- display_line_nb=0;\
- printf("\n--More--");\
- get_key(stdin, 0);\
- printf("\033[2K\033[1G\033[1F");\
+ if (__likely(!silent)) {\
+ if (__likely(!disable_more_printf)) {\
+ if (display_line_nb == max_console_lines) {\
+ display_line_nb=0;\
+ printf("\n--More--");\
+ get_key(stdin, 0);\
+ printf("\033[2K\033[1G\033[1F");\
+ }\
+ display_line_nb++;\
}\
- display_line_nb++;\
+ printf(__VA_ARGS__);\
}\
- printf(__VA_ARGS__);\
} while (0);
/* Display CPU registers for debugging purposes */
@@ -209,9 +218,13 @@ struct s_hardware {
char modules_pcimap_path[255];
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);
@@ -236,4 +249,5 @@ int detect_vesa(struct s_hardware *hardware);
void detect_memory(struct s_hardware *hardware);
void init_console(struct s_hardware *hardware);
void detect_hardware(struct s_hardware *hardware);
+void dump(struct s_hardware *hardware);
#endif
diff --git a/com32/hdt/hdt-dump-acpi.c b/com32/hdt/hdt-dump-acpi.c
new file mode 100644
index 00000000..4cbaf66f
--- /dev/null
+++ b/com32/hdt/hdt-dump-acpi.c
@@ -0,0 +1,600 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * -----------------------------------------------------------------------
+ */
+
+#include "hdt-common.h"
+#include "hdt-dump.h"
+
+void show_header(char *name, void *address, s_acpi_description_header *h, ZZJSON_CONFIG *config, ZZJSON **item)
+{
+ char signature[10]={0};
+ char revision[10]={0};
+ char s_address[16]={0};
+ char oem_id[16]={0};
+ char oem_table_id[16]={0};
+ char oem_revision[16]={0};
+ char creator_revision[16]={0};
+ char creator_id[16]={0};
+ snprintf(signature,sizeof(signature),"%s",h->signature);
+ snprintf(revision,sizeof(revision),"0x%03x",h->revision);
+ snprintf(oem_id,sizeof(oem_id),"%s",h->oem_id);
+ snprintf(oem_table_id,sizeof(oem_table_id),"%s",h->oem_table_id);
+ snprintf(creator_id,sizeof(creator_id),"%s",h->creator_id);
+ snprintf(oem_revision,sizeof(oem_revision),"0x%08x",h->oem_revision);
+ snprintf(creator_revision,sizeof(creator_revision),"0x%08x",h->creator_revision);
+ snprintf(s_address,sizeof(s_address),"%p",address);
+
+ char address_name[32]={0};
+ char signature_name[32]={0};
+ char revision_name[32]={0};
+ char oem_id_name[32]={0};
+ char oem_table_id_name[32]={0};
+ char oem_revision_name[32]={0};
+ char creator_revision_name[32]={0};
+ char creator_id_name[32]={0};
+ snprintf(signature_name,sizeof(signature_name),"acpi.%s.signature",name);
+ snprintf(revision_name,sizeof(revision_name),"acpi.%s.revision",name);
+ snprintf(address_name,sizeof(address_name),"acpi.%s.address",name);
+ snprintf(oem_id_name,sizeof(oem_id_name),"acpi.%s.oem_id",name);
+ snprintf(oem_table_id_name,sizeof(oem_table_id_name),"acpi.%s.oem_table_id",name);
+ snprintf(oem_revision_name,sizeof(oem_revision_name),"acpi.%s.oem_revision",name);
+ snprintf(creator_revision_name,sizeof(creator_revision_name),"acpi.%s.creator_revision",name);
+ snprintf(creator_id_name,sizeof(creator_id_name),"acpi.%s.creator_id",name);
+
+ APPEND_ARRAY
+ add_as(signature_name,signature)
+ add_as(revision_name,revision)
+ add_as(oem_id_name,oem_id)
+ add_as(oem_table_id_name,oem_table_id)
+ add_as(oem_revision_name,oem_revision)
+ add_as(creator_id_name,creator_id)
+ add_as(creator_revision_name,creator_revision)
+ add_as(address_name,s_address)
+ END_OF_APPEND;
+
+ FLUSH_OBJECT;
+
+}
+
+void dump_rsdt(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item)
+{
+ char valid[8]={0};
+ snprintf(valid,sizeof(valid),"%s","false");
+ if (acpi->rsdt.valid) {
+ snprintf(valid,sizeof(valid),"%s","true");
+ }
+ CREATE_ARRAY
+ add_as("acpi.item","rsdt")
+ add_as("acpi.rsdt.is_valid",valid)
+ END_OF_ARRAY;
+
+ if (acpi->rsdt.valid==false) {
+ FLUSH_OBJECT;
+ return;
+ }
+
+ show_header("rsdt",acpi->rsdt.address, &acpi->rsdt.header, config, item);
+}
+
+void dump_xsdt(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item)
+{
+ char valid[8]={0};
+ snprintf(valid,sizeof(valid),"%s","false");
+ if (acpi->xsdt.valid) {
+ snprintf(valid,sizeof(valid),"%s","true");
+ }
+ CREATE_ARRAY
+ add_as("acpi.item","xsdt")
+ add_as("acpi.xsdt.is_valid",valid)
+ END_OF_ARRAY;
+
+ if (acpi->xsdt.valid==false) {
+ FLUSH_OBJECT;
+ return;
+ }
+
+ show_header("xsdt",acpi->xsdt.address, &acpi->xsdt.header, config, item);
+}
+
+void dump_fadt(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item)
+{
+ char valid[8]={0};
+ snprintf(valid,sizeof(valid),"%s","false");
+ if (acpi->rsdt.valid) {
+ snprintf(valid,sizeof(valid),"%s","true");
+ }
+ CREATE_ARRAY
+ add_as("acpi.item","fadt")
+ add_as("acpi.fadt.is_valid",valid)
+ END_OF_ARRAY;
+
+ if (acpi->fadt.valid==false) {
+ FLUSH_OBJECT;
+ return;
+ }
+
+ show_header("fadt",acpi->fadt.address, &acpi->fadt.header, config, item);
+}
+
+void dump_dsdt(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item)
+{
+ char valid[8]={0};
+ snprintf(valid,sizeof(valid),"%s","false");
+ if (acpi->dsdt.valid) {
+ snprintf(valid,sizeof(valid),"%s","true");
+ }
+ CREATE_ARRAY
+ add_as("acpi.item","dsdt")
+ add_as("acpi.dsdt.is_valid",valid)
+ END_OF_ARRAY;
+
+ if (acpi->dsdt.valid==false) {
+ FLUSH_OBJECT;
+ return;
+ }
+
+ show_header("dsdt",acpi->dsdt.address, &acpi->dsdt.header, config, item);
+}
+
+void dump_sbst(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item)
+{
+ char valid[8]={0};
+ snprintf(valid,sizeof(valid),"%s","false");
+ if (acpi->sbst.valid) {
+ snprintf(valid,sizeof(valid),"%s","true");
+ }
+ CREATE_ARRAY
+ add_as("acpi.item","sbst")
+ add_as("acpi.sbst.is_valid",valid)
+ END_OF_ARRAY;
+
+ if (acpi->sbst.valid==false) {
+ FLUSH_OBJECT;
+ return;
+ }
+
+ show_header("sbst",acpi->sbst.address, &acpi->sbst.header, config, item);
+}
+
+void dump_ecdt(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item)
+{
+ char valid[8]={0};
+ snprintf(valid,sizeof(valid),"%s","false");
+ if (acpi->ecdt.valid) {
+ snprintf(valid,sizeof(valid),"%s","true");
+ }
+ CREATE_ARRAY
+ add_as("acpi.item","ecdt")
+ add_as("acpi.ecdt.is_valid",valid)
+ END_OF_ARRAY;
+
+ if (acpi->ecdt.valid==false) {
+ FLUSH_OBJECT;
+ return;
+ }
+
+ show_header("ecdt",acpi->ecdt.address, &acpi->ecdt.header, config, item);
+}
+
+void dump_hpet(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item)
+{
+ char valid[8]={0};
+ snprintf(valid,sizeof(valid),"%s","false");
+ if (acpi->hpet.valid) {
+ snprintf(valid,sizeof(valid),"%s","true");
+ }
+ CREATE_ARRAY
+ add_as("acpi.item","hpet")
+ add_as("acpi.hpet.is_valid",valid)
+ END_OF_ARRAY;
+
+ if (acpi->hpet.valid==false) {
+ FLUSH_OBJECT;
+ return;
+ }
+
+ show_header("hpet",acpi->hpet.address, &acpi->hpet.header, config, item);
+}
+
+void dump_tcpa(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item)
+{
+ char valid[8]={0};
+ snprintf(valid,sizeof(valid),"%s","false");
+ if (acpi->tcpa.valid) {
+ snprintf(valid,sizeof(valid),"%s","true");
+ }
+ CREATE_ARRAY
+ add_as("acpi.item","tcpa")
+ add_as("acpi.tcpa.is_valid",valid)
+ END_OF_ARRAY;
+
+ if (acpi->tcpa.valid==false) {
+ FLUSH_OBJECT;
+ return;
+ }
+
+ show_header("tcpa",acpi->tcpa.address, &acpi->tcpa.header, config, item);
+}
+
+void dump_mcfg(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item)
+{
+ char valid[8]={0};
+ snprintf(valid,sizeof(valid),"%s","false");
+ if (acpi->mcfg.valid) {
+ snprintf(valid,sizeof(valid),"%s","true");
+ }
+ CREATE_ARRAY
+ add_as("acpi.item","mcfg")
+ add_as("acpi.mcfg.is_valid",valid)
+ END_OF_ARRAY;
+
+ if (acpi->mcfg.valid==false) {
+ FLUSH_OBJECT;
+ return;
+ }
+
+ show_header("mcfg",acpi->mcfg.address, &acpi->mcfg.header, config, item);
+}
+
+void dump_slic(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item)
+{
+ char valid[8]={0};
+ snprintf(valid,sizeof(valid),"%s","false");
+ if (acpi->slic.valid) {
+ snprintf(valid,sizeof(valid),"%s","true");
+ }
+ CREATE_ARRAY
+ add_as("acpi.item","slic")
+ add_as("acpi.slic.is_valid",valid)
+ END_OF_ARRAY;
+
+ if (acpi->slic.valid==false) {
+ FLUSH_OBJECT;
+ return;
+ }
+
+ show_header("slic",acpi->slic.address, &acpi->slic.header, config, item);
+}
+
+
+void dump_boot(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item)
+{
+ char valid[8]={0};
+ snprintf(valid,sizeof(valid),"%s","false");
+ if (acpi->boot.valid) {
+ snprintf(valid,sizeof(valid),"%s","true");
+ }
+ CREATE_ARRAY
+ add_as("acpi.item","boot")
+ add_as("acpi.boot.is_valid",valid)
+ END_OF_ARRAY;
+
+ if (acpi->boot.valid==false) {
+ FLUSH_OBJECT;
+ return;
+ }
+
+ show_header("boot",acpi->boot.address, &acpi->boot.header, config, item);
+}
+
+void dump_madt(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item)
+{
+ char valid[8]={0};
+ snprintf(valid,sizeof(valid),"%s","false");
+ if (acpi->madt.valid) {
+ snprintf(valid,sizeof(valid),"%s","true");
+ }
+ CREATE_ARRAY
+ add_as("acpi.item","madt")
+ add_as("acpi.madt.is_valid",valid)
+ END_OF_ARRAY;
+
+ if (acpi->madt.valid==false) {
+ FLUSH_OBJECT;
+ return;
+ }
+
+ show_header("madt",acpi->madt.address, &acpi->madt.header, config, item);
+}
+
+void dump_ssdt(s_ssdt *ssdt, ZZJSON_CONFIG * config, ZZJSON ** item)
+{
+ char valid[8]={0};
+ snprintf(valid,sizeof(valid),"%s","false");
+ if (ssdt->valid) {
+ snprintf(valid,sizeof(valid),"%s","true");
+ }
+ CREATE_ARRAY
+ add_as("acpi.item","ssdt")
+ add_as("acpi.ssdt.is_valid",valid)
+ END_OF_ARRAY;
+
+ if (ssdt->valid==false) {
+ FLUSH_OBJECT;
+ return;
+ }
+
+ show_header("ssdt",ssdt->address, &ssdt->header, config, item);
+}
+
+void dump_rsdp(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item)
+{
+ char valid[8]={0};
+ snprintf(valid,sizeof(valid),"%s","false");
+ if (acpi->rsdp.valid) {
+ snprintf(valid,sizeof(valid),"%s","true");
+ }
+ CREATE_ARRAY
+ add_as("acpi.item","rsdp")
+ add_as("acpi.rsdp.is_valid",valid)
+ END_OF_ARRAY;
+
+ if (acpi->rsdp.valid==false) {
+ FLUSH_OBJECT;
+ return;
+ }
+
+ s_rsdp *r = &acpi->rsdp;
+ char revision[10]={0};
+ char address[16]={0};
+ char oem_id[16]={0};
+ snprintf(revision,sizeof(revision),"0x%03x",r->revision);
+ snprintf(address,sizeof(address),"%p",r->address);
+ snprintf(oem_id,sizeof(oem_id),"%s",r->oem_id);
+ APPEND_ARRAY
+ add_as("acpi.rsdp.revision",revision)
+ add_as("acpi.rsdp.oem_id",oem_id)
+ add_as("acpi.rsdp.address",address)
+ END_OF_APPEND;
+
+ FLUSH_OBJECT;
+
+}
+
+void dump_facs(s_acpi * acpi, ZZJSON_CONFIG * config, ZZJSON ** item)
+{
+ char valid[8]={0};
+ snprintf(valid,sizeof(valid),"%s","false");
+ if (acpi->facs.valid) {
+ snprintf(valid,sizeof(valid),"%s","true");
+ }
+ CREATE_ARRAY
+ add_as("acpi.item","facs")
+ add_as("acpi.facs.is_valid",valid)
+ END_OF_ARRAY;
+
+ if (acpi->facs.valid==false) {
+ FLUSH_OBJECT;
+ return;
+ }
+
+ s_facs *fa = &acpi->facs;
+ char address[16]={0};
+ snprintf(address,sizeof(address),"%p",fa->address);
+ APPEND_ARRAY
+ add_as("acpi.facs.address",address)
+ END_OF_APPEND;
+
+ FLUSH_OBJECT;
+
+}
+
+void dump_interrupt_source_override(s_madt * madt, ZZJSON_CONFIG * config, ZZJSON ** item)
+{
+ CREATE_ARRAY
+ add_as("acpi.item","interrupt_source_override")
+ add_ai("acpi.interrupt_source_override.count", madt->interrupt_source_override_count)
+ END_OF_ARRAY;
+
+ if (madt->interrupt_source_override_count == 0) {
+ FLUSH_OBJECT;
+ return;
+ }
+
+ /* Let's process each interrupt source override */
+ for (int i = 0; i < madt->interrupt_source_override_count; i++) {
+ s_interrupt_source_override *siso = &madt->interrupt_source_override[i];
+ char buffer[20] = {0};
+ char bus_type[10]= {0};
+
+ /* Spec report bus type 0 as ISA */
+ if (siso->bus == 0)
+ strcpy(bus_type, "ISA");
+ else
+ strcpy(bus_type, "unknown");
+
+ APPEND_ARRAY
+ add_as("acpi.interrupt_source_override.bus_type",bus_type)
+ add_ai("acpi.interrupt_source_override.bus",siso->bus)
+ add_ai("acpi.interrupt_source_override.bus_irq",siso->source)
+ add_ai("acpi.interrupt_source_override.global_irq",siso->global_system_interrupt)
+ add_as("acpi.interrupt_source_override.flags",flags_to_string(buffer,siso->flags))
+ END_OF_APPEND;
+ }
+ FLUSH_OBJECT;
+}
+
+void dump_io_apic(s_madt * madt, ZZJSON_CONFIG * config, ZZJSON ** item)
+{
+ CREATE_ARRAY
+ add_as("acpi.item","io_apic")
+ add_ai("acpi.io_apic.count", madt->io_apic_count)
+ END_OF_ARRAY;
+
+ if (madt->io_apic_count == 0) {
+ FLUSH_OBJECT;
+ return;
+ }
+
+ /* For all IO APICS */
+ for (int i = 0; i < madt->io_apic_count; i++) {
+ s_io_apic *sio = &madt->io_apic[i];
+ char buffer[15]={0};
+ memset(buffer, 0, sizeof(buffer));
+ /* GSI base reports the GSI configuration
+ * Let's interpret it as string */
+ switch (sio->global_system_interrupt_base) {
+ case 0:
+ strcpy(buffer, "0-23");
+ break;
+ case 24:
+ strcpy(buffer,"24-39");
+ break;
+ case 40:
+ strcpy(buffer, "40-55");
+ break;
+ default:
+ strcpy(buffer,"Unknown");
+ break;
+ }
+
+ char apic_id[16] = { 0 };
+ char address[16] = { 0 };
+ snprintf(apic_id,sizeof(apic_id),"0x%02x",sio->io_apic_id);
+ snprintf(address,sizeof(address),"0x%08x",sio->io_apic_address);
+ APPEND_ARRAY
+ add_ai("acpi.io_apic.number",i)
+ add_as("acpi.io_apic.apic_id",apic_id)
+ add_as("acpi.io_apic.adress",address)
+ add_as("acpi.io_apic.gsi",buffer)
+ END_OF_APPEND;
+ }
+ FLUSH_OBJECT;
+}
+
+void dump_local_apic_nmi(s_madt * madt, ZZJSON_CONFIG * config, ZZJSON ** item)
+{
+ CREATE_ARRAY
+ add_as("acpi.item","local_apic_nmi")
+ add_ai("acpi.local_apic_nmi.count", madt->local_apic_nmi_count)
+ END_OF_ARRAY;
+
+ if (madt->local_apic_nmi_count == 0) {
+ FLUSH_OBJECT;
+ return;
+ }
+
+ for (int i = 0; i < madt->local_apic_nmi_count; i++) {
+ s_local_apic_nmi *slan = &madt->local_apic_nmi[i];
+ char buffer[20]={0};
+ char acpi_id[16] = { 0 };
+ char local_apic_lint[16] = { 0 };
+ snprintf(acpi_id, sizeof(acpi_id), "0x%02x", slan->acpi_processor_id);
+ snprintf(local_apic_lint, sizeof(local_apic_lint), "0x%02x", slan->local_apic_lint);
+ APPEND_ARRAY
+ add_as("acpi.processor_id", acpi_id)
+ add_as("acpi.local_apic_nmi.flags", flags_to_string(buffer,slan->flags))
+ add_as("acpi.local_apic_nmi.lint",local_apic_lint)
+ END_OF_APPEND;
+ }
+
+ FLUSH_OBJECT;
+}
+
+void dump_local_apic(s_madt * madt, ZZJSON_CONFIG * config, ZZJSON ** item)
+{
+ char buffer[16] = { 0 };
+ snprintf(buffer, sizeof(buffer), "0x%08x", madt->local_apic_address);
+
+ CREATE_ARRAY
+ add_as("acpi.item","local_apic")
+ add_as("acpi.local_apic.address", buffer)
+ add_ai("acpi.processor_local_apic.count", madt->processor_local_apic_count)
+ END_OF_ARRAY;
+
+ if (madt->processor_local_apic_count ==0) {
+ FLUSH_OBJECT;
+ return;
+ }
+
+ /* For all detected logical CPU */
+ for (int i = 0; i < madt->processor_local_apic_count; i++) {
+ s_processor_local_apic *sla = &madt->processor_local_apic[i];
+ char lapic_status[16] = { 0 };
+ char acpi_id[16] = { 0 };
+ char apic_id[16] = { 0 };
+
+ snprintf(lapic_status,sizeof(lapic_status),"%s","disabled");
+ /* Let's check if the flags reports the cpu as enabled */
+ if ((sla->flags & PROCESSOR_LOCAL_APIC_ENABLE) ==
+ PROCESSOR_LOCAL_APIC_ENABLE)
+ snprintf(lapic_status,sizeof(lapic_status),"%s","enabled");
+ snprintf(acpi_id, sizeof(acpi_id), "0x%02x", sla->acpi_id);
+ snprintf(apic_id, sizeof(apic_id), "0x%02x", sla->apic_id);
+ APPEND_ARRAY
+ add_ai("acpi.cpu.apic_id", sla->apic_id)
+ add_as("acpi.cpu.apic_id (hex)", apic_id)
+ add_as("acpi.cpu.acpi_id (hex)", acpi_id)
+ add_as("acpi.lapic.enabled", lapic_status)
+ END_OF_APPEND;
+ }
+ FLUSH_OBJECT;
+}
+
+void dump_acpi(struct s_hardware *hardware, ZZJSON_CONFIG * config,
+ ZZJSON ** item)
+{
+ CREATE_NEW_OBJECT;
+ add_hb(is_acpi_valid);
+ if (hardware->is_acpi_valid == false)
+ goto exit;
+
+ s_madt *madt = &hardware->acpi.madt;
+ add_b("acpi.apic.detected", madt->valid);
+ if (madt->valid == false) {
+ goto exit;
+ }
+
+ FLUSH_OBJECT;
+
+ dump_local_apic(madt, config, item);
+ dump_local_apic_nmi(madt, config, item);
+ dump_io_apic(madt, config, item);
+ dump_interrupt_source_override(madt, config, item);
+
+ dump_rsdp(&hardware->acpi,config,item);
+ dump_rsdt(&hardware->acpi,config,item);
+ dump_xsdt(&hardware->acpi,config,item);
+ dump_fadt(&hardware->acpi,config,item);
+ dump_dsdt(&hardware->acpi,config,item);
+ dump_sbst(&hardware->acpi,config,item);
+ dump_ecdt(&hardware->acpi,config,item);
+ dump_hpet(&hardware->acpi,config,item);
+ dump_tcpa(&hardware->acpi,config,item);
+ dump_mcfg(&hardware->acpi,config,item);
+ dump_slic(&hardware->acpi,config,item);
+ dump_boot(&hardware->acpi,config,item);
+ dump_madt(&hardware->acpi,config,item);
+ for (int i = 0; i < hardware->acpi.ssdt_count; i++) {
+ if ((hardware->acpi.ssdt[i] != NULL) && (hardware->acpi.ssdt[i]->valid))
+ dump_ssdt(hardware->acpi.ssdt[i], config, item);
+ }
+ dump_facs(&hardware->acpi,config,item);
+
+exit:
+ to_cpio("acpi");
+}
diff --git a/com32/hdt/hdt-dump-cpu.c b/com32/hdt/hdt-dump-cpu.c
new file mode 100644
index 00000000..33d561c8
--- /dev/null
+++ b/com32/hdt/hdt-dump-cpu.c
@@ -0,0 +1,53 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * -----------------------------------------------------------------------
+ */
+
+#include "hdt-common.h"
+#include "hdt-dump.h"
+
+void dump_cpu(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
+
+ CREATE_NEW_OBJECT;
+ add_hs(cpu.vendor);
+ add_hs(cpu.model);
+ add_hi(cpu.vendor_id);
+ add_hi(cpu.family);
+ add_hi(cpu.model_id);
+ add_hi(cpu.stepping);
+ add_hi(cpu.num_cores);
+ add_hi(cpu.l1_data_cache_size);
+ add_hi(cpu.l1_instruction_cache_size);
+ add_hi(cpu.l2_cache_size);
+ size_t i;
+ for (i = 0; i < cpu_flags_count; i++) {
+ char temp[128]={0};
+ snprintf(temp,sizeof(temp),"cpu.flags.%s",cpu_flags_names[i]);
+ add_b(temp,get_cpu_flag_value_from_name(&hardware->cpu,cpu_flags_names[i]));
+ }
+ FLUSH_OBJECT;
+ to_cpio("cpu");
+}
diff --git a/com32/hdt/hdt-dump-disks.c b/com32/hdt/hdt-dump-disks.c
new file mode 100644
index 00000000..ff744b30
--- /dev/null
+++ b/com32/hdt/hdt-dump-disks.c
@@ -0,0 +1,145 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * -----------------------------------------------------------------------
+ */
+
+#include "hdt-common.h"
+#include "hdt-dump.h"
+#include "hdt-util.h"
+
+ZZJSON_CONFIG *config;
+ZZJSON **item;
+
+static void show_partition_information(struct driveinfo *drive_info,
+ struct part_entry *ptab,
+ int partition_offset,
+ int nb_partitions_seen) {
+ char size[11] = {0};
+ char bootloader_name[9] = {0};
+ char ostype[64]={0};
+ char *parttype;
+ unsigned int start, end;
+ char bootable[6] = {0};
+
+ int i = nb_partitions_seen;
+ start = partition_offset;
+ end = start + ptab->length - 1;
+
+ if (ptab->length > 0)
+ sectors_to_size(ptab->length, size);
+
+ 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);
+
+ APPEND_ARRAY
+ add_ai("partition->number",i)
+ add_ai("partition->sector_start",start)
+ add_ai("partition->sector_end",end)
+ 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);
+}
+
+
+
+void show_disk(struct s_hardware *hardware, ZZJSON_CONFIG *conf, ZZJSON **it, int drive) {
+ config=conf;
+ item=it;
+ int i = drive - 0x80;
+ struct driveinfo *d = &hardware->disk_info[i];
+ char mbr_name[50]={0};
+ char disk_size[11]={0};
+
+ get_mbr_string(hardware->mbr_ids[i], &mbr_name,sizeof(mbr_name));
+ if ((int)d->edd_params.sectors > 0)
+ sectors_to_size((int)d->edd_params.sectors, disk_size);
+
+ char disk[5]={0};
+ char edd_version[5]={0};
+ snprintf(disk,sizeof(disk),"0x%X",d->disk);
+ snprintf(edd_version,sizeof(edd_version),"%X",d->edd_version);
+ zzjson_print(config, *item);
+ zzjson_free(config, *item);
+
+ CREATE_ARRAY
+ add_as("disk->number",disk)
+ add_ai("disk->cylinders",d->legacy_max_cylinder +1)
+ add_ai("disk->heads",d->legacy_max_head +1)
+ add_ai("disk->sectors_per_track",d->legacy_sectors_per_track)
+ add_as("disk->edd_version",edd_version)
+ add_as("disk->size",disk_size)
+ add_ai("disk->bytes_per_sector",(int)d->edd_params.bytes_per_sector)
+ add_ai("disk->sectors_per_track",(int)d->edd_params.sectors_per_track)
+ add_as("disk->host_bus",remove_spaces((char *)d->edd_params.host_bus_type))
+ add_as("disk->interface_type",remove_spaces((char *)d->edd_params.interface_type))
+ add_as("disk->mbr_name",mbr_name)
+ add_ai("disk->mbr_id",hardware->mbr_ids[i])
+ END_OF_ARRAY;
+
+ if (parse_partition_table(d, &show_partition_information)) {
+ if (errno_disk) {
+ APPEND_ARRAY
+ add_as("disk->error", "IO Error")
+ END_OF_APPEND;
+ } else {
+ APPEND_ARRAY
+ add_as("disk->error", "Unrecognized Partition Layout")
+ END_OF_APPEND;
+ }
+ }
+}
+
+void dump_disks(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
+ bool found=false;
+
+ 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;
+ add_b("disks->is_valid",true);
+ found=true;
+ }
+ show_disk(hardware, config, item, drive);
+ }
+ }
+
+ if (found==false) {
+ CREATE_NEW_OBJECT;
+ add_b("disks->is_valid",false);
+ }
+ FLUSH_OBJECT;
+ to_cpio("disks");
+}
diff --git a/com32/hdt/hdt-dump-dmi.c b/com32/hdt/hdt-dump-dmi.c
new file mode 100644
index 00000000..6e5c1ce8
--- /dev/null
+++ b/com32/hdt/hdt-dump-dmi.c
@@ -0,0 +1,447 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * -----------------------------------------------------------------------
+ */
+
+#include "hdt-common.h"
+#include "hdt-dump.h"
+
+void dump_hardware_security(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
+ if (!hardware->dmi.hardware_security.filled) {
+ CREATE_NEW_OBJECT;
+ add_s("dmi.warning","No hardware security structure found");
+ FLUSH_OBJECT;
+ return;
+ }
+
+ CREATE_NEW_OBJECT;
+ add_s("dmi.item","hardware_security");
+ add_hs(dmi.hardware_security.power_on_passwd_status);
+ add_hs(dmi.hardware_security.keyboard_passwd_status);
+ add_hs(dmi.hardware_security.administrator_passwd_status);
+ add_hs(dmi.hardware_security.front_panel_reset_status);
+ FLUSH_OBJECT;
+}
+
+void dump_oem_strings(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
+ if (strlen(hardware->dmi.oem_strings) == 0) {
+ CREATE_NEW_OBJECT;
+ add_s("dmi.warning","No OEM structure found");
+ FLUSH_OBJECT;
+ return;
+ }
+ CREATE_NEW_OBJECT;
+ add_s("dmi.item","OEM");
+ add_hs(dmi.oem_strings);
+ FLUSH_OBJECT;
+}
+
+void dump_memory_size(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
+ CREATE_NEW_OBJECT;
+ add_s("dmi.item","memory size");
+ add_i("dmi.memory_size (KB)",hardware->detected_memory_size);
+ add_i("dmi.memory_size (MB)",(hardware->detected_memory_size + (1 << 9)) >> 10);
+ FLUSH_OBJECT;
+}
+
+void dump_memory_modules(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
+
+ if (hardware->dmi.memory_module_count == 0) {
+ CREATE_NEW_OBJECT;
+ add_s("dmi.warning","No memory module structure found");
+ FLUSH_OBJECT;
+ return;
+ }
+
+ for (int module=0; module<hardware->dmi.memory_module_count;module++) {
+ if (hardware->dmi.memory_module[module].filled == false) {
+ char msg[64]={0};
+ snprintf(msg,sizeof(msg),"Module %d doesn't contain any information", module);
+
+ CREATE_NEW_OBJECT;
+ add_s("dmi.warning",msg);
+ FLUSH_OBJECT;
+ continue;
+ }
+
+ CREATE_NEW_OBJECT;
+ add_i("Memory module", module);
+ add_s("dmi.memory_module.socket_designation", hardware->dmi.memory_module[module].socket_designation);
+ add_s("dmi.memory_module.bank_connections", hardware->dmi.memory_module[module].bank_connections);
+ add_s("dmi.memory_module.speed", hardware->dmi.memory_module[module].speed);
+ add_s("dmi.memory_module.type", hardware->dmi.memory_module[module].type);
+ add_s("dmi.memory_module.installed_size", hardware->dmi.memory_module[module].installed_size);
+ add_s("dmi.memory_module.enabled_size", hardware->dmi.memory_module[module].enabled_size);
+ add_s("dmi.memory_module.error_status", hardware->dmi.memory_module[module].error_status);
+ FLUSH_OBJECT;
+ }
+}
+
+void dump_cache(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
+
+ if (hardware->dmi.cache_count == 0) {
+ CREATE_NEW_OBJECT;
+ add_s("dmi.warning","No cache structure found");
+ FLUSH_OBJECT;
+ return;
+ }
+
+ for (int cache=0; cache<hardware->dmi.cache_count;cache++) {
+ CREATE_NEW_OBJECT;
+ add_i("Cache", cache);
+ add_s("dmi.cache.socket_designation", hardware->dmi.cache[cache].socket_designation);
+ add_s("dmi.cache.configuration", hardware->dmi.cache[cache].configuration);
+ add_s("dmi.cache.mode", hardware->dmi.cache[cache].mode);
+ add_s("dmi.cache.location", hardware->dmi.cache[cache].location);
+ add_i("dmi.cache.installed_size (KB)", hardware->dmi.cache[cache].installed_size);
+ add_i("dmi.cache.max_size (KB)", hardware->dmi.cache[cache].max_size);
+ add_s("dmi.cache.supported_sram_types", hardware->dmi.cache[cache].supported_sram_types);
+ add_s("dmi.cache.installed_sram_types", hardware->dmi.cache[cache].installed_sram_types);
+ add_i("dmi.cache.speed (ns)", hardware->dmi.cache[cache].speed);
+ add_s("dmi.cache.error_correction_type", hardware->dmi.cache[cache].error_correction_type);
+ add_s("dmi.cache.system_type", hardware->dmi.cache[cache].system_type);
+ add_s("dmi.cache.associativity", hardware->dmi.cache[cache].associativity);
+ FLUSH_OBJECT;
+ }
+}
+void dump_memory_banks(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
+
+ if (hardware->dmi.memory_count == 0) {
+ CREATE_NEW_OBJECT;
+ add_s("dmi.warning","No memory bank structure found");
+ FLUSH_OBJECT;
+ return;
+ }
+
+ for (int bank=0; bank<hardware->dmi.memory_count;bank++) {
+
+ if (hardware->dmi.memory[bank].filled == false) {
+ char msg[64]={0};
+ snprintf(msg,sizeof(msg),"Bank %d doesn't contain any information", bank);
+
+ CREATE_NEW_OBJECT;
+ add_s("dmi.warning",msg);
+ FLUSH_OBJECT;
+ continue;
+ }
+
+ CREATE_NEW_OBJECT;
+ add_i("Memory Bank", bank);
+ add_s("dmi.memory.form_factor", hardware->dmi.memory[bank].form_factor);
+ add_s("dmi.memory.type", hardware->dmi.memory[bank].type);
+ add_s("dmi.memory.type_detail", hardware->dmi.memory[bank].type_detail);
+ add_s("dmi.memory.speed", hardware->dmi.memory[bank].speed);
+ add_s("dmi.memory.size", hardware->dmi.memory[bank].size);
+ add_s("dmi.memory.device_set", hardware->dmi.memory[bank].device_set);
+ add_s("dmi.memory.device_locator", hardware->dmi.memory[bank].device_locator);
+ add_s("dmi.memory.bank_locator", hardware->dmi.memory[bank].bank_locator);
+ add_s("dmi.memory.total_width", hardware->dmi.memory[bank].total_width);
+ add_s("dmi.memory.data_width", hardware->dmi.memory[bank].data_width);
+ add_s("dmi.memory.error", hardware->dmi.memory[bank].error);
+ add_s("dmi.memory.vendor", hardware->dmi.memory[bank].manufacturer);
+ add_s("dmi.memory.serial", hardware->dmi.memory[bank].serial);
+ add_s("dmi.memory.asset_tag", hardware->dmi.memory[bank].asset_tag);
+ add_s("dmi.memory.part_number", hardware->dmi.memory[bank].part_number);
+ FLUSH_OBJECT;
+ }
+}
+
+void dump_processor(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
+ if (hardware->dmi.processor.filled == false) {
+ CREATE_NEW_OBJECT;
+ add_s("dmi.warning","no processor structure found");
+ FLUSH_OBJECT;
+ return;
+ }
+
+ char voltage[16]={0};
+ snprintf(voltage,sizeof(voltage),"%d.%02d",
+ hardware->dmi.processor.voltage_mv / 1000,
+ hardware->dmi.processor.voltage_mv - ((hardware->dmi.processor.voltage_mv / 1000) * 1000));
+
+ CREATE_NEW_OBJECT;
+ add_s("dmi.item","processor");
+ add_hs(dmi.processor.socket_designation);
+ add_hs(dmi.processor.type);
+ add_hs(dmi.processor.family);
+ add_hs(dmi.processor.manufacturer);
+ add_hs(dmi.processor.version);
+ add_hi(dmi.processor.external_clock);
+ add_hi(dmi.processor.max_speed);
+ add_hi(dmi.processor.current_speed);
+ add_hi(dmi.processor.signature.type);
+ add_hi(dmi.processor.signature.family);
+ add_hi(dmi.processor.signature.model);
+ add_hi(dmi.processor.signature.stepping);
+ add_hi(dmi.processor.signature.minor_stepping);
+ add_s("dmi.processor.voltage",voltage);
+ add_hs(dmi.processor.status);
+ add_hs(dmi.processor.upgrade);
+ add_hs(dmi.processor.cache1);
+ add_hs(dmi.processor.cache2);
+ add_hs(dmi.processor.cache3);
+ add_hs(dmi.processor.serial);
+ add_hs(dmi.processor.part_number);
+ add_hi(dmi.processor.core_count);
+ add_hi(dmi.processor.core_enabled);
+ add_hi(dmi.processor.thread_count);
+ add_hs(dmi.processor.id);
+ for (int i = 0; i < PROCESSOR_FLAGS_ELEMENTS; i++) {
+ if (((bool *) (&hardware->dmi.processor.cpu_flags))[i] == true) {
+ add_s("dmi.processor.flag",(char *)cpu_flags_strings[i]);
+ }
+ }
+ FLUSH_OBJECT;
+}
+
+void dump_battery(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
+ if (hardware->dmi.battery.filled == false) {
+ CREATE_NEW_OBJECT;
+ add_s("dmi.warning","no battery structure found");
+ FLUSH_OBJECT;
+ return;
+ }
+
+ CREATE_NEW_OBJECT;
+ add_s("dmi.item","battery");
+ add_hs(dmi.battery.manufacturer);
+ add_hs(dmi.battery.manufacture_date);
+ add_hs(dmi.battery.serial);
+ add_hs(dmi.battery.name);
+ add_hs(dmi.battery.chemistry);
+ add_hs(dmi.battery.design_capacity);
+ add_hs(dmi.battery.design_voltage);
+ add_hs(dmi.battery.sbds);
+ add_hs(dmi.battery.sbds_manufacture_date);
+ add_hs(dmi.battery.sbds_chemistry);
+ add_hs(dmi.battery.maximum_error);
+ add_hs(dmi.battery.oem_info);
+ FLUSH_OBJECT;
+}
+
+void dump_ipmi(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
+ if (hardware->dmi.ipmi.filled == false) {
+ CREATE_NEW_OBJECT;
+ add_s("dmi.warning","no IPMI structure found");
+ FLUSH_OBJECT;
+ return;
+ }
+
+ char spec_ver[16]={0};
+ char i2c[16]={0};
+ char base[16]={0};
+ snprintf(spec_ver,sizeof(spec_ver),"%u.%u",
+ hardware->dmi.ipmi.major_specification_version,
+ hardware->dmi.ipmi.minor_specification_version);
+
+ snprintf(i2c,sizeof(i2c),"0x%02x", hardware->dmi.ipmi.I2C_slave_address);
+ snprintf(base,sizeof(base),"%08X%08X",
+ (uint32_t)(hardware->dmi.ipmi.base_address >> 32),
+ (uint32_t)((hardware->dmi.ipmi.base_address & 0xFFFF) & ~1));
+
+ CREATE_NEW_OBJECT;
+ add_s("dmi.item","ipmi");
+ add_hs(dmi.ipmi.interface_type);
+ add_s("dmi.ipmi.spec_version",spec_ver);
+ add_hi(dmi.ipmi.I2C_slave_address);
+ add_hi(dmi.ipmi.nv_address);
+ add_s("dmi.ipmi.base_address",base);
+ add_hi(dmi.ipmi.irq);
+ FLUSH_OBJECT;
+}
+
+void dump_chassis(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
+ if (hardware->dmi.chassis.filled == false) {
+ CREATE_NEW_OBJECT;
+ add_s("dmi.warning","no chassis structure found");
+ FLUSH_OBJECT;
+ return;
+ }
+
+ CREATE_NEW_OBJECT;
+ add_s("dmi.item","bios");
+ add_hs(dmi.chassis.manufacturer);
+ add_hs(dmi.chassis.type);
+ add_hs(dmi.chassis.lock);
+ add_hs(dmi.chassis.version);
+ add_hs(dmi.chassis.serial);
+ add_s("dmi.chassis.asset_tag",del_multi_spaces(hardware->dmi.chassis.asset_tag));
+ add_hs(dmi.chassis.boot_up_state);
+ add_hs(dmi.chassis.power_supply_state);
+ add_hs(dmi.chassis.thermal_state);
+ add_hs(dmi.chassis.security_status);
+ add_hs(dmi.chassis.oem_information);
+ add_hi(dmi.chassis.height);
+ add_hi(dmi.chassis.nb_power_cords);
+ FLUSH_OBJECT;
+}
+
+void dump_bios(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
+ if (hardware->dmi.bios.filled == false) {
+ CREATE_NEW_OBJECT;
+ add_s("dmi.warning","no bios structure found");
+ FLUSH_OBJECT;
+ return;
+ }
+ char address[16]={0};
+ char runtime[16]={0};
+ char rom[16]={0};
+ snprintf(address,sizeof(address),"0x%04X0",hardware->dmi.bios.address);
+ snprintf(runtime,sizeof(runtime),"%u %s",hardware->dmi.bios.runtime_size, hardware->dmi.bios.runtime_size_unit);
+ snprintf(rom,sizeof(rom),"%u %s",hardware->dmi.bios.rom_size, hardware->dmi.bios.rom_size_unit);
+
+ CREATE_NEW_OBJECT;
+ add_s("dmi.item","bios");
+ add_hs(dmi.bios.vendor);
+ add_hs(dmi.bios.version);
+ add_hs(dmi.bios.release_date);
+ add_hs(dmi.bios.bios_revision);
+ add_hs(dmi.bios.firmware_revision);
+ add_s("dmi.bios.address",address);
+ add_s("dmi.bios.runtime_size",runtime);
+ add_s("dmi.bios.rom_size",rom);
+ for (int i = 0; i < BIOS_CHAR_NB_ELEMENTS; i++) {
+ if (((bool *) (&hardware->dmi.bios.characteristics))[i] == true) {
+ add_s("dmi.bios.characteristics",(char *)bios_charac_strings[i]);
+ }
+ }
+
+ for (int i = 0; i < BIOS_CHAR_X1_NB_ELEMENTS; i++) {
+ if (((bool *) (&hardware->dmi.bios.characteristics_x1))[i] == true) {
+ add_s("dmi.bios.characteristics",(char *)bios_charac_x1_strings[i]);
+ }
+ }
+
+ for (int i = 0; i < BIOS_CHAR_X2_NB_ELEMENTS; i++) {
+ if (((bool *) (&hardware->dmi.bios.characteristics_x2))[i] == true) {
+ add_s("dmi.bios.characteristics",(char *)bios_charac_x2_strings[i]);
+ }
+ }
+ FLUSH_OBJECT;
+}
+
+void dump_system(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
+
+ if (hardware->dmi.system.filled == false) {
+ CREATE_NEW_OBJECT;
+ add_s("dmi.warning","no system structure found");
+ FLUSH_OBJECT;
+ return;
+ }
+ char system_reset_status[10]={0};
+ char watchdog_timer[15]={0};
+ snprintf(system_reset_status,sizeof(system_reset_status),"%s", (hardware->dmi.system.system_reset.status ? "Enabled" :"Disabled"));
+ snprintf(watchdog_timer,sizeof(watchdog_timer),"%s", (hardware->dmi.system.system_reset.watchdog ? "Present" :"Not Present"));
+
+ CREATE_NEW_OBJECT;
+ add_s("dmi.item","system");
+ add_hs(dmi.system.manufacturer);
+ add_hs(dmi.system.product_name);
+ add_hs(dmi.system.version);
+ add_hs(dmi.system.serial);
+ add_hs(dmi.system.uuid);
+ add_hs(dmi.system.wakeup_type);
+ add_hs(dmi.system.sku_number);
+ add_hs(dmi.system.family);
+ add_hs(dmi.system.configuration_options);
+ add_s("dmi.system.system_reset.status",system_reset_status);
+ add_s("dmi.system.system_reset.watchdog",watchdog_timer);
+ add_hs(dmi.system.system_reset.boot_option);
+ add_hs(dmi.system.system_reset.boot_option_on_limit);
+ add_hs(dmi.system.system_reset.reset_count);
+ add_hs(dmi.system.system_reset.reset_limit);
+ add_hs(dmi.system.system_reset.timer_interval);
+ add_hs(dmi.system.system_reset.timeout);
+ add_hs(dmi.system.system_boot_status);
+ FLUSH_OBJECT;
+}
+
+void dump_base_board(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
+
+ if (hardware->dmi.base_board.filled == false) {
+ CREATE_NEW_OBJECT;
+ add_s("dmi.warning","no base_board structure found");
+ FLUSH_OBJECT;
+ return;
+ }
+
+ CREATE_NEW_OBJECT;
+ add_s("dmi.item","base_board");
+ add_hs(dmi.base_board.manufacturer);
+ add_hs(dmi.base_board.product_name);
+ add_hs(dmi.base_board.version);
+ add_hs(dmi.base_board.serial);
+ add_hs(dmi.base_board.asset_tag);
+ add_hs(dmi.base_board.location);
+ add_hs(dmi.base_board.type);
+ for (int i = 0; i < BASE_BOARD_NB_ELEMENTS; i++) {
+ if (((bool *) (&hardware->dmi.base_board.features))[i] == true) {
+ add_s("dmi.base_board.features",(char *)base_board_features_strings[i]);
+ }
+ }
+
+ for (unsigned int i = 0; i < sizeof hardware->dmi.base_board.devices_information /
+ sizeof *hardware->dmi.base_board.devices_information; i++) {
+ if (strlen(hardware->dmi.base_board.devices_information[i].type)) {
+ add_s("dmi.base_board.devices_information.type", hardware->dmi.base_board.devices_information[i].type);
+ add_i("dmi.base_board.devices_information.status", hardware->dmi.base_board.devices_information[i].status);
+ add_s("dmi.base_board.devices_information.description", hardware->dmi.base_board.devices_information[i].description);
+ }
+ }
+ FLUSH_OBJECT;
+}
+
+void dump_dmi(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
+
+ CREATE_NEW_OBJECT;
+ add_hb(is_dmi_valid);
+
+ if (hardware->is_dmi_valid == false) {
+ FLUSH_OBJECT;
+ goto exit;
+ } else {
+ char buffer[8]={0};
+ snprintf(buffer,sizeof(buffer),"%d.%d",hardware->dmi.dmitable.major_version, hardware->dmi.dmitable.minor_version);
+ add_s("dmi.version",buffer);
+ FLUSH_OBJECT;
+ }
+
+ dump_base_board(hardware,config,item);
+ dump_system(hardware,config,item);
+ dump_bios(hardware,config,item);
+ dump_chassis(hardware,config,item);
+ dump_ipmi(hardware,config,item);
+ dump_battery(hardware,config,item);
+ dump_processor(hardware,config,item);
+ dump_cache(hardware,config,item);
+ dump_memory_banks(hardware,config,item);
+ dump_memory_modules(hardware,config,item);
+ dump_memory_size(hardware,config,item);
+ dump_oem_strings(hardware,config,item);
+ dump_hardware_security(hardware,config,item);
+exit:
+ to_cpio("dmi");
+}
diff --git a/com32/hdt/hdt-dump-hdt.c b/com32/hdt/hdt-dump-hdt.c
new file mode 100644
index 00000000..d081ebdb
--- /dev/null
+++ b/com32/hdt/hdt-dump-hdt.c
@@ -0,0 +1,50 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * -----------------------------------------------------------------------
+ */
+
+#include "hdt-common.h"
+#include "hdt-dump.h"
+#include <syslinux/config.h>
+
+void dump_hdt(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
+
+ (void) hardware;
+ CREATE_NEW_OBJECT;
+ add_s("hdt.product_name",PRODUCT_NAME);
+ add_s("hdt.version",VERSION);
+ add_s("hdt.code_name",CODENAME);
+ add_s("hdt.author", AUTHOR);
+ add_s("hdt.core_developer", CORE_DEVELOPER);
+ char *contributors[NB_CONTRIBUTORS] = CONTRIBUTORS;
+ for (int c = 0; c < NB_CONTRIBUTORS; c++) {
+ add_s("hdt.contributor", contributors[c]);
+ }
+ add_s("hdt.website",WEBSITE_URL);
+ add_s("hdt.irc_channel",IRC_CHANNEL);
+ FLUSH_OBJECT
+ to_cpio("hdt");
+}
diff --git a/com32/hdt/hdt-dump-kernel.c b/com32/hdt/hdt-dump-kernel.c
new file mode 100644
index 00000000..e0df8320
--- /dev/null
+++ b/com32/hdt/hdt-dump-kernel.c
@@ -0,0 +1,69 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * -----------------------------------------------------------------------
+ */
+
+#include "hdt-common.h"
+#include "hdt-dump.h"
+
+void dump_kernel(struct s_hardware *hardware, ZZJSON_CONFIG * config,
+ ZZJSON ** item)
+{
+ struct pci_device *pci_device = NULL;
+ CREATE_ARRAY
+ add_as("Linux Kernel modules", "")
+ END_OF_ARRAY;
+
+ if (hardware->pci_ids_return_code == -ENOPCIIDS) {
+ APPEND_ARRAY
+ add_as("Error", "No pci.ids file")
+ END_OF_APPEND FLUSH_OBJECT;
+ return;
+ }
+
+ if ((hardware->modules_pcimap_return_code == -ENOMODULESPCIMAP)
+ &&(hardware->modules_pcimap_return_code == -ENOMODULESALIAS)) {
+ APPEND_ARRAY
+ add_as("Error", "No modules.pcimap or modules.alias file")
+ END_OF_APPEND FLUSH_OBJECT;
+ return;
+
+ }
+
+ /* For every detected pci device, compute its submenu */
+ for_each_pci_func(pci_device, hardware->pci_domain) {
+ if (pci_device == NULL)
+ continue;
+ for (int kmod = 0;
+ kmod < pci_device->dev_info->linux_kernel_module_count; kmod++) {
+ APPEND_ARRAY
+ add_as(pci_device->dev_info->category_name, pci_device->dev_info->linux_kernel_module[kmod])
+ END_OF_APPEND;
+ }
+ }
+ FLUSH_OBJECT;
+ to_cpio("kernel");
+}
diff --git a/com32/hdt/hdt-dump-memory.c b/com32/hdt/hdt-dump-memory.c
new file mode 100644
index 00000000..5095d3c2
--- /dev/null
+++ b/com32/hdt/hdt-dump-memory.c
@@ -0,0 +1,133 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * -----------------------------------------------------------------------
+ */
+
+#include <memory.h>
+#include "hdt-common.h"
+#include "hdt-dump.h"
+
+void dump_88(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
+
+ (void) hardware;
+ int mem_size = 0;
+ CREATE_NEW_OBJECT;
+ if (detect_memory_88(&mem_size)) {
+ add_s("memory.error","8800h memory configuration is invalid");
+ FLUSH_OBJECT
+ return;
+ }
+
+ add_s("dmi.item","memory via 88");
+ add_i("memory.size (KiB)", mem_size);
+ add_i("memory.size (MiB)", mem_size >> 10);
+ FLUSH_OBJECT;
+}
+
+void dump_e801(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
+
+ (void) hardware;
+ int mem_low, mem_high = 0;
+ CREATE_NEW_OBJECT;
+ if (detect_memory_e801(&mem_low,&mem_high)) {
+ add_s("memory.error","e801 memory configuration is invalid");
+ FLUSH_OBJECT;
+ return;
+ }
+
+ add_s("dmi.item","memory via e801");
+ add_i("memory.total.size (KiB)", mem_low + (mem_high << 6));
+ add_i("memory.total.size (MiB)", (mem_low >> 10) + (mem_high >> 4));
+ add_i("memory.low.size (KiB)", mem_low );
+ add_i("memory.low.size (MiB)", mem_low >> 10);
+ add_i("memory.high.size (KiB)", mem_high << 6);
+ add_i("memory.high.size (MiB)", mem_high >> 4);
+ FLUSH_OBJECT;
+
+}
+void dump_e820(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
+
+ (void) hardware;
+ struct e820entry map[E820MAX];
+ struct e820entry nm[E820MAX];
+ unsigned long memsize = 0;
+ int count = 0;
+ char type[14] = {0};
+
+ detect_memory_e820(map, E820MAX, &count);
+ memsize = memsize_e820(map, count);
+
+ CREATE_NEW_OBJECT;
+ add_s("dmi.item","memory via e820");
+ add_i("memory.total.size (KiB)", memsize);
+ add_i("memory.total.size (MiB)", (memsize + (1 << 9)) >> 10);
+ FLUSH_OBJECT;
+
+ for (int i = 0; i < count; i++) {
+ get_type(map[i].type, type, sizeof(type));
+ char begin[24]={0};
+ char size[24]={0};
+ char end[24]={0};
+ snprintf(begin,sizeof(begin),"0x%016llx",map[i].addr);
+ snprintf(size,sizeof(size),"0x%016llx",map[i].size);
+ snprintf(end,sizeof(end),"0x%016llx",map[i].addr+map[i].size);
+ CREATE_NEW_OBJECT;
+ add_s("memory.segment.start",begin);
+ add_s("memory.segment.size ",size);
+ add_s("memory.segment.end ",end);
+ add_s("memory.segment.type ",remove_spaces(type));
+ FLUSH_OBJECT;
+ }
+
+ int nr = sanitize_e820_map(map, nm, count);
+ for (int i = 0; i < nr; i++) {
+ get_type(nm[i].type, type, sizeof(type));
+ char begin[24]={0};
+ char size[24]={0};
+ char end[24]={0};
+ snprintf(begin,sizeof(begin),"0x%016llx",nm[i].addr);
+ snprintf(size,sizeof(size),"0x%016llx",nm[i].size);
+ snprintf(end,sizeof(end),"0x%016llx",nm[i].addr+nm[i].size);
+ CREATE_NEW_OBJECT;
+ add_s("sanitized_memory.segment.start",begin);
+ add_s("sanitized_memory.segment.size ",size);
+ add_s("sanitized_memory.segment.end ",end);
+ add_s("sanitized_memory.segment.type ",remove_spaces(type));
+ FLUSH_OBJECT;
+ }
+}
+
+void dump_memory(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
+
+ CREATE_NEW_OBJECT;
+ add_s("Memory configuration","true");
+ FLUSH_OBJECT;
+
+ dump_88(hardware,config,item);
+ dump_e801(hardware,config,item);
+ dump_e820(hardware,config,item);
+ to_cpio("memory");
+}
diff --git a/com32/hdt/hdt-dump-pci.c b/com32/hdt/hdt-dump-pci.c
new file mode 100644
index 00000000..b1f18fdf
--- /dev/null
+++ b/com32/hdt/hdt-dump-pci.c
@@ -0,0 +1,136 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * -----------------------------------------------------------------------
+ */
+
+#include "hdt-common.h"
+#include "hdt-dump.h"
+
+void dump_pci(struct s_hardware *hardware, ZZJSON_CONFIG * config,
+ ZZJSON ** item)
+{
+ int i = 1;
+ struct pci_device *pci_device=NULL;
+ char kernel_modules[LINUX_KERNEL_MODULE_SIZE *
+ MAX_KERNEL_MODULES_PER_PCI_DEVICE];
+ bool nopciids = false;
+ bool nomodulespcimap = false;
+ bool nomodulesalias = false;
+ bool nomodulesfile = false;
+ int bus = 0, slot = 0, func = 0;
+
+ if (hardware->pci_ids_return_code == -ENOPCIIDS) {
+ nopciids = true;
+ }
+ if (hardware->modules_pcimap_return_code == -ENOMODULESPCIMAP) {
+ nomodulespcimap = true;
+ }
+ if (hardware->modules_pcimap_return_code == -ENOMODULESALIAS) {
+ nomodulesalias = true;
+ }
+
+ nomodulesfile = nomodulespcimap && nomodulesalias;
+
+ CREATE_NEW_OBJECT;
+
+ add_i("pci_device.count", hardware->nb_pci_devices);
+
+ FLUSH_OBJECT;
+ /* For every detected pci device, compute its submenu */
+ for_each_pci_func(pci_device, hardware->pci_domain) {
+ if (pci_device == NULL)
+ continue;
+ char v[10] = { 0 };
+ char sv[10] = { 0 };
+ char p[10] = { 0 };
+ char sp[10] = { 0 };
+ char c[10] = { 0 };
+ char r[10] = { 0 };
+
+ CREATE_NEW_OBJECT;
+ bus = __pci_bus;
+ slot = __pci_slot;
+ func = __pci_func;
+
+ memset(kernel_modules, 0, sizeof kernel_modules);
+ for (int kmod = 0;
+ kmod < pci_device->dev_info->linux_kernel_module_count; kmod++) {
+ if (kmod > 0) {
+ strncat(kernel_modules, " | ", 3);
+ }
+ strncat(kernel_modules,
+ pci_device->dev_info->linux_kernel_module[kmod],
+ LINUX_KERNEL_MODULE_SIZE - 1);
+ }
+ if (pci_device->dev_info->linux_kernel_module_count == 0)
+ strlcpy(kernel_modules, "unknown", 7);
+
+ add_i("pci_device.number", i);
+ if (nopciids == false) {
+ add_s("pci_device.vendor_name", pci_device->dev_info->vendor_name);
+ add_s("pci_device.product_name",
+ pci_device->dev_info->product_name);
+ }
+ if (nomodulesfile == false) {
+ add_s("pci_device.class_name", pci_device->dev_info->class_name);
+ add_s("pci_device.kernel_module", kernel_modules);
+ }
+
+ snprintf(v, sizeof(v), "%04x", pci_device->vendor);
+ snprintf(p, sizeof(p), "%04x", pci_device->product);
+ snprintf(sv, sizeof(sv), "%04x", pci_device->sub_vendor);
+ snprintf(sp, sizeof(sp), "%04x", pci_device->sub_product);
+ snprintf(c, sizeof(c), "%02x.%02x.%02x",
+ pci_device->class[2],
+ pci_device->class[1], pci_device->class[0]);
+ snprintf(r, sizeof(r), "%02x", pci_device->revision);
+ add_s("pci_device.vendor_id", v);
+ add_s("pci_device.product_id", p);
+ add_s("pci_device.sub_vendor_id", sv);
+ add_s("pci_device.sub_product_id", sp);
+ add_s("pci_device.class_id", c);
+ add_s("pci_device.revision", r);
+ if ((pci_device->dev_info->irq > 0)
+ && (pci_device->dev_info->irq < 255))
+ add_i("pci_device.irq", pci_device->dev_info->irq);
+
+ add_i("pci_device.latency", pci_device->dev_info->latency);
+ add_i("pci_device.bus", bus);
+ add_i("pci_device.slot", slot);
+ add_i("pci_device.func", func);
+
+ if (hardware->is_pxe_valid == true) {
+ if ((hardware->pxe.pci_device != NULL)
+ && (hardware->pxe.pci_device == pci_device)) {
+ add_hs(pxe.mac_addr);
+ add_s("pxe", "Current boot device");
+ }
+ }
+ i++;
+ FLUSH_OBJECT;
+ }
+ to_cpio("pci");
+}
diff --git a/com32/hdt/hdt-dump-pxe.c b/com32/hdt/hdt-dump-pxe.c
new file mode 100644
index 00000000..4e25c943
--- /dev/null
+++ b/com32/hdt/hdt-dump-pxe.c
@@ -0,0 +1,80 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * -----------------------------------------------------------------------
+ */
+
+#include "hdt-common.h"
+#include "hdt-dump.h"
+#include <sys/gpxe.h>
+#include <netinet/in.h>
+
+void dump_pxe(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
+ struct in_addr in;
+
+ CREATE_NEW_OBJECT;
+ add_hb(is_pxe_valid);
+ if (hardware->is_pxe_valid) {
+ char buffer[32] = {0};
+ snprintf(buffer,sizeof(buffer),"0x%x",hardware->pxe.vendor_id);
+ add_s("pxe.vendor_id",buffer);
+ snprintf(buffer,sizeof(buffer),"0x%x",hardware->pxe.product_id);
+ add_s("pxe.product_id",buffer);
+ snprintf(buffer,sizeof(buffer),"0x%x",hardware->pxe.subvendor_id);
+ add_s("pxe.subvendor_id",buffer);
+ snprintf(buffer,sizeof(buffer),"0x%x",hardware->pxe.subproduct_id);
+ add_s("pxe.subproduct_id",buffer);
+
+ if (hardware->pci_ids_return_code == -ENOPCIIDS || (hardware->pxe.pci_device == NULL)) {
+ add_s("Manufacturer_name","no_pci_ids_file or no device found");
+ add_s("Product_name","no_pci_ids_file or no device found");
+ } else {
+ add_s("Manufacturer_name", hardware->pxe.pci_device->dev_info->vendor_name);
+ add_s("Product_name", hardware->pxe.pci_device->dev_info->product_name);
+ }
+
+ add_hi(pxe.rev);
+ add_hi(pxe.pci_bus);
+ add_hi(pxe.pci_dev);
+ add_hi(pxe.pci_func);
+ add_hi(pxe.base_class);
+ add_hi(pxe.sub_class);
+ add_hi(pxe.prog_intf);
+ add_hi(pxe.nictype);
+ add_hs(pxe.mac_addr);
+
+ in.s_addr = hardware->pxe.dhcpdata.cip;
+ add_s("pxe.client_ip", inet_ntoa(in));
+ in.s_addr = hardware->pxe.dhcpdata.sip;
+ add_s("pxe.next_server_ip",inet_ntoa(in));
+ in.s_addr = hardware->pxe.dhcpdata.gip;
+ add_s("pxe.relay_agent_ip",inet_ntoa(in));
+ memcpy(&in, hardware->pxe.ip_addr, sizeof in);
+ add_s("pxe.ipaddr",inet_ntoa(in));
+ add_b("gpxe_detected",is_gpxe());
+ }
+ FLUSH_OBJECT;
+ to_cpio("pxe");
+}
diff --git a/com32/hdt/hdt-dump-syslinux.c b/com32/hdt/hdt-dump-syslinux.c
new file mode 100644
index 00000000..7cef925f
--- /dev/null
+++ b/com32/hdt/hdt-dump-syslinux.c
@@ -0,0 +1,43 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * -----------------------------------------------------------------------
+ */
+
+#include "hdt-common.h"
+#include "hdt-dump.h"
+#include <syslinux/config.h>
+
+void dump_syslinux(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
+
+ CREATE_NEW_OBJECT;
+ add_hs(syslinux_fs);
+ add_hs(sv->version_string);
+ add_hi(sv->version);
+ add_hi(sv->max_api);
+ add_hs(sv->copyright_string);
+ FLUSH_OBJECT
+ to_cpio("syslinux");
+}
diff --git a/com32/hdt/hdt-dump-vesa.c b/com32/hdt/hdt-dump-vesa.c
new file mode 100644
index 00000000..97d56c95
--- /dev/null
+++ b/com32/hdt/hdt-dump-vesa.c
@@ -0,0 +1,67 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * -----------------------------------------------------------------------
+ */
+
+#include "hdt-common.h"
+#include "hdt-dump.h"
+#include <syslinux/config.h>
+
+void dump_vesa(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
+
+ CREATE_NEW_OBJECT;
+ add_hb(is_vesa_valid);
+ if (hardware->is_vesa_valid) {
+ char buffer[64]={0};
+ snprintf(buffer,sizeof(buffer),"%d.%d", hardware->vesa.major_version, hardware->vesa.minor_version);
+ add_s("vesa.version",buffer);
+ add_hs(vesa.vendor);
+ add_hs(vesa.product);
+ add_hs(vesa.product_revision);
+ add_hi(vesa.software_rev);
+ memset(buffer,0,sizeof(buffer));
+ snprintf(buffer,sizeof(buffer),"%d KB",hardware->vesa.total_memory*64);
+ add_s("vesa.memory",buffer);
+ add_i("vesa.modes",hardware->vesa.vmi_count);
+ FLUSH_OBJECT;
+ for (int i = 0; i < hardware->vesa.vmi_count; i++) {
+ struct vesa_mode_info *mi = &hardware->vesa.vmi[i].mi;
+ if ((mi->h_res == 0) || (mi->v_res == 0))
+ continue;
+ CREATE_NEW_OBJECT;
+ memset(buffer,0,sizeof(buffer));
+ snprintf(buffer,sizeof(buffer),"0x%04x",hardware->vesa.vmi[i].mode + 0x200);
+ add_s("vesa.kernel_mode",buffer);
+ add_i("vesa.hres",mi->h_res);
+ add_i("vesa.vres",mi->v_res);
+ add_i("vesa.bpp",mi->bpp);
+ FLUSH_OBJECT;
+ }
+ } else {
+ FLUSH_OBJECT;
+ }
+ to_cpio("vesa");
+}
diff --git a/com32/hdt/hdt-dump-vpd.c b/com32/hdt/hdt-dump-vpd.c
new file mode 100644
index 00000000..36451c8a
--- /dev/null
+++ b/com32/hdt/hdt-dump-vpd.c
@@ -0,0 +1,47 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * -----------------------------------------------------------------------
+ */
+
+#include "hdt-common.h"
+#include "hdt-dump.h"
+
+void dump_vpd(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
+
+ CREATE_NEW_OBJECT;
+ add_hb(is_vpd_valid);
+ if (hardware->is_vpd_valid) {
+ add_hs(vpd.bios_build_id);
+ add_hs(vpd.bios_release_date);
+ add_hs(vpd.bios_version);
+ add_hs(vpd.default_flash_filename);
+ add_hs(vpd.box_serial_number);
+ add_hs(vpd.motherboard_serial_number);
+ add_hs(vpd.machine_type_model);
+ }
+ FLUSH_OBJECT;
+ to_cpio("vpd");
+}
diff --git a/com32/hdt/hdt-dump.c b/com32/hdt/hdt-dump.c
new file mode 100644
index 00000000..b1748c8e
--- /dev/null
+++ b/com32/hdt/hdt-dump.c
@@ -0,0 +1,229 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * -----------------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <getkey.h>
+#include <syslinux/config.h>
+#include "hdt-common.h"
+#include "hdt-dump.h"
+
+struct print_buf p_buf;
+
+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, ':', '-');
+
+ /* Avoid space to make filename easier to manipulate */
+ 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;
+}
+
+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;
+}
+
+/**
+ * dump - dump info
+ **/
+void dump(struct s_hardware *hardware)
+{
+ if (hardware->is_pxe_valid == false) {
+ more_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;
+ 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
+ };
+
+ memset(&p_buf, 0, sizeof(p_buf));
+
+ /* By now, we only support TFTP reporting */
+ upload = &upload_tftp;
+ upload->name = "tftp";
+
+ /* The following defines the behavior of the reporting */
+ char *arg[64];
+ 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;
+ } 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]);
+
+ }
+
+ /* We initiate the cpio to send */
+ cpio_init(upload, (const char **)arg);
+
+ dump_cpu(hardware, &config, &json);
+ dump_pxe(hardware, &config, &json);
+ dump_syslinux(hardware, &config, &json);
+ dump_vpd(hardware, &config, &json);
+ dump_vesa(hardware, &config, &json);
+ dump_disks(hardware, &config, &json);
+ dump_dmi(hardware, &config, &json);
+ dump_memory(hardware, &config, &json);
+ dump_pci(hardware, &config, &json);
+ dump_acpi(hardware, &config, &json);
+ dump_kernel(hardware, &config, &json);
+ dump_hdt(hardware, &config, &json);
+
+ /* We close & flush the file to send */
+ cpio_close(upload);
+
+ 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]);
+ } else {
+ more_printf("Dump file sent at %s:/%s\n", hardware->tftp_ip, filename);
+ }
+}
diff --git a/com32/hdt/hdt-dump.h b/com32/hdt/hdt-dump.h
new file mode 100644
index 00000000..f9669dac
--- /dev/null
+++ b/com32/hdt/hdt-dump.h
@@ -0,0 +1,85 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 20011 Erwan Velu - 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.
+ *
+ * -----------------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <bufprintf.h>
+#include <zzjson/zzjson.h>
+#include "hdt-common.h"
+
+// Macros to manipulate Arrays
+#define APPEND_ARRAY ZZJSON *temp_array; temp_array = zzjson_array_append(config, *item, zzjson_create_object(config,
+#define APPEND_OBJECT_ARRAY(value) ZZJSON *temp_ar; temp_ar = zzjson_array_append(config, *item, value); *item=temp_ar;
+#define CREATE_ARRAY *item = zzjson_create_array(config, zzjson_create_object(config,
+#define add_ai(name,value) name,zzjson_create_number_i(config,value),
+#define add_ahi(value) add_ai(#value,hardware->value)
+#define add_as(name,value) name,zzjson_create_string(config,value),
+#define add_ahs(value) add_as(#value,hardware->value)
+#define END_OF_ARRAY NULL),NULL)
+#define END_OF_APPEND NULL)); *item=temp_array;
+
+// Macros to manipulate objects
+#define CREATE_NEW_OBJECT *item = zzjson_create_object(config, NULL);
+#define FLUSH_OBJECT flush(config, item);
+
+// Macros to manipulate integers as objects
+#define add_i(name,value) *item = zzjson_object_append(config, *item, name, zzjson_create_number_i(config, value))
+#define add_hi(value) add_i(#value,hardware->value)
+
+// Macros to manipulate strings as objects
+#define add_s(name,value) *item = zzjson_object_append(config, *item, name, zzjson_create_string(config, value))
+#define add_hs(value) add_s(#value,(char *)hardware->value)
+
+// Macros to manipulate bool as objects
+#define add_bool_true(name) *item = zzjson_object_append(config, *item, (char *)name, zzjson_create_true(config))
+#define add_bool_false(name) *item = zzjson_object_append(config, *item, (char*)name, zzjson_create_false(config))
+#define add_b(name,value) if (value==true) {add_bool_true(name);} else {add_bool_false(name);}
+#define add_hb(value) add_b(#value,hardware->value)
+
+extern struct print_buf p_buf;
+
+void print_and_flush(ZZJSON_CONFIG *config, ZZJSON **item);
+int dumpprintf(FILE *p, const char *format, ...);
+void flush (ZZJSON_CONFIG *config, ZZJSON ** item);
+void to_cpio(char *filename);
+
+void dump_cpu(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item);
+void dump_pxe(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item);
+void dump_syslinux(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item);
+void dump_vpd(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item);
+void dump_vesa(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item);
+void dump_disks(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item);
+void dump_dmi(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item);
+void dump_memory(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item);
+void dump_pci(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item);
+void dump_acpi(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item);
+void dump_kernel(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item);
+void dump_hdt(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item);
+void dump(struct s_hardware *hardware);
diff --git a/com32/hdt/hdt-menu-acpi.c b/com32/hdt/hdt-menu-acpi.c
index 16bcf73a..8e0ba18f 100644
--- a/com32/hdt/hdt-menu-acpi.c
+++ b/com32/hdt/hdt-menu-acpi.c
@@ -32,7 +32,7 @@ void compute_table(struct s_my_menu *menu, void *address, s_acpi_description_hea
char buffer[SUBMENULEN + 1] = { 0 };
char statbuffer[STATLEN + 1] = { 0 };
- snprintf(buffer, sizeof buffer, "%-4s v%03x %-6s %-7s %-7s %08x",
+ snprintf(buffer, sizeof buffer, "%-4s v%03x %-6s %-8s %-7s %08x",
h->signature, h->revision, h->oem_id, h->oem_table_id, h->creator_id, h->creator_revision);
snprintf(statbuffer, sizeof statbuffer, "%-4s v%03x %-6s %-7s 0x%08x %-4s 0x%08x @ 0x%p",
h->signature, h->revision, h->oem_id, h->oem_table_id,
@@ -52,7 +52,7 @@ static void compute_acpi_tables(struct s_my_menu *menu,
char buffer[SUBMENULEN + 1] = { 0 };
- snprintf(buffer, sizeof buffer, "%-4s %-4s %-6s %-7s %-7s %-8s",
+ snprintf(buffer, sizeof buffer, "%-4s %-4s %-6s %-8s %-7s %-8s",
"ACPI", "rev", "oem", "table_id", "creator", "creator_rev");
add_item(buffer, "Description", OPT_INACTIVE, NULL, 0);
menu->items_count++;
diff --git a/com32/hdt/hdt-menu-disk.c b/com32/hdt/hdt-menu-disk.c
index b0b4a5ac..0716b435 100644
--- a/com32/hdt/hdt-menu-disk.c
+++ b/com32/hdt/hdt-menu-disk.c
@@ -120,9 +120,9 @@ static void compute_partition_information(struct driveinfo *drive_info,
add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0);
}
- snprintf(buffer, sizeof buffer, "Bootable : %s",
+ snprintf(buffer, sizeof buffer, "Boot Flag : %s",
(ptab->active_flag == 0x80) ? "Yes" : "No");
- snprintf(statbuffer, sizeof statbuffer, "Bootable: %s",
+ snprintf(statbuffer, sizeof statbuffer, "Boot Flag: %s",
(ptab->active_flag == 0x80) ? "Yes" : "No");
add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0);
@@ -243,12 +243,12 @@ void compute_disks(struct s_hdt_menu *menu, struct s_hardware *hardware)
if (hardware->disks_count == 0)
return;
- for (int i = 0; i < hardware->disks_count; i++) {
- if (!hardware->disk_info[i].cbios)
+ for (int drive = 0x80; drive < 0xff; drive++) {
+ if (!hardware->disk_info[drive - 0x80].cbios)
continue; /* Invalid geometry */
compute_disk_module
((struct s_my_menu *)&(menu->disk_sub_menu), nb_sub_disk_menu,
- hardware, i);
+ hardware, drive - 0x80);
nb_sub_disk_menu++;
}
diff --git a/com32/hdt/hdt-menu-pxe.c b/com32/hdt/hdt-menu-pxe.c
index 426bfe07..12d8b116 100644
--- a/com32/hdt/hdt-menu-pxe.c
+++ b/com32/hdt/hdt-menu-pxe.c
@@ -34,7 +34,7 @@ void compute_PXE(struct s_my_menu *menu, struct s_hardware *hardware)
{
char buffer[SUBMENULEN + 1];
char infobar[STATLEN + 1];
- char gpxe[4];
+ char gpxe[4]={0};
if (hardware->is_pxe_valid == false)
return;
@@ -113,8 +113,8 @@ void compute_PXE(struct s_my_menu *menu, struct s_hardware *hardware)
add_item(buffer, infobar, OPT_INACTIVE, NULL, 0);
menu->items_count++;
- if (is_gpxe()) strcat(gpxe,"Yes");
- else strcat (gpxe,"No");
+ if (is_gpxe()) snprintf(gpxe,sizeof(gpxe),"%s","Yes");
+ else snprintf (gpxe, sizeof(gpxe), "%s", "No");
snprintf(buffer, sizeof buffer, "gPXE Detected: %s", gpxe);
snprintf(infobar, sizeof infobar, "gPXE Detected: %s", gpxe);
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-menu.c b/com32/hdt/hdt-menu.c
index 0fdee039..50b3eaa8 100644
--- a/com32/hdt/hdt-menu.c
+++ b/com32/hdt/hdt-menu.c
@@ -62,6 +62,12 @@ int start_menu_mode(struct s_hardware *hardware, char *version_string)
(curr->data, HDT_SWITCH_TO_CLI, sizeof(HDT_SWITCH_TO_CLI))) {
return HDT_RETURN_TO_CLI;
}
+ /* Tweak, we want to start the dump mode */
+ if (!strncmp
+ (curr->data, HDT_DUMP, sizeof(HDT_DUMP))) {
+ dump(hardware);
+ return 0;
+ }
if (!strncmp
(curr->data, HDT_REBOOT, sizeof(HDT_REBOOT))) {
syslinux_reboot(1);
@@ -289,6 +295,12 @@ void compute_main_menu(struct s_hdt_menu *hdt_menu, struct s_hardware *hardware)
add_item("S<w>itch to CLI", "Switch to Command Line", OPT_RUN,
HDT_SWITCH_TO_CLI, 0);
+
+ if (hardware->is_pxe_valid == true) {
+ add_item("<D>ump to tftp", "Dump to tftp", OPT_RUN,
+ HDT_DUMP, 0);
+ }
+
add_item("<A>bout", "About Menu", OPT_SUBMENU, NULL,
hdt_menu->about_menu.menu);
add_item("<R>eboot", "Reboot", OPT_RUN, HDT_REBOOT, 0);
diff --git a/com32/hdt/hdt.c b/com32/hdt/hdt.c
index a1e3923c..653995d0 100644
--- a/com32/hdt/hdt.c
+++ b/com32/hdt/hdt.c
@@ -72,16 +72,23 @@ int main(const int argc, const char *argv[])
clear_screen();
printf("\033[1;1H");
- printf("%s\n", version_string);
+ more_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) {
+ more_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 dd489480..e385417a 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.4.1"
-#define CODENAME "chouffe"
+#define VERSION "0.5.2"
+#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 caa5e726..213e8ab7 100644
--- a/com32/include/bitsize/stddef.h
+++ b/com32/include/bitsize/stddef.h
@@ -6,13 +6,9 @@
#define _BITSIZE_STDDEF_H
#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;
#endif /* _BITSIZE_STDDEF_H */
diff --git a/com32/include/bitsize/stdint.h b/com32/include/bitsize/stdint.h
index 8cbfc5dd..8e444b6d 100644
--- a/com32/include/bitsize/stdint.h
+++ b/com32/include/bitsize/stdint.h
@@ -5,24 +5,24 @@
#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 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 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 int int_fast16_t;
+typedef int int_fast32_t;
-typedef unsigned int uint_fast16_t;
-typedef unsigned int uint_fast32_t;
+typedef unsigned int uint_fast16_t;
+typedef unsigned int uint_fast32_t;
-typedef int intptr_t;
-typedef unsigned int uintptr_t;
+typedef int intptr_t;
+typedef unsigned int uintptr_t;
#define __INT64_C(c) c ## LL
#define __UINT64_C(c) c ## ULL
@@ -31,4 +31,4 @@ typedef unsigned int uintptr_t;
#define __PRIFAST_RANK ""
#define __PRIPTR_RANK ""
-#endif /* _BITSIZE_STDINT_H */
+#endif /* _BITSIZE_STDINT_H */
diff --git a/com32/include/bitsize/stdintconst.h b/com32/include/bitsize/stdintconst.h
index 8157dd06..7db63bdf 100644
--- a/com32/include/bitsize/stdintconst.h
+++ b/com32/include/bitsize/stdintconst.h
@@ -15,4 +15,4 @@
#define UINTPTR_C(c) UINT32_C(c)
#define PTRDIFF_C(c) INT32_C(c)
-#endif /* _BITSIZE_STDINTCONST_H */
+#endif /* _BITSIZE_STDINTCONST_H */
diff --git a/com32/include/bitsize/stdintlimits.h b/com32/include/bitsize/stdintlimits.h
index b44fe011..d85094d9 100644
--- a/com32/include/bitsize/stdintlimits.h
+++ b/com32/include/bitsize/stdintlimits.h
@@ -19,4 +19,4 @@
#define PTRDIFF_MIN INT32_MIN
#define PTRDIFF_MAX INT32_MAX
-#endif /* _BITSIZE_STDINTLIMITS_H */
+#endif /* _BITSIZE_STDINTLIMITS_H */
diff --git a/com32/include/bufprintf.h b/com32/include/bufprintf.h
new file mode 100644
index 00000000..5cbeaa4b
--- /dev/null
+++ b/com32/include/bufprintf.h
@@ -0,0 +1,10 @@
+#define BUFPAD 4096
+
+struct print_buf {
+ char *buf;
+ size_t len;
+ size_t size;
+};
+
+int vbufprintf(struct print_buf *buf, const char *format, va_list ap);
+int bufprintf(struct print_buf *buf, const char *format, ...);
diff --git a/com32/include/cpufeature.h b/com32/include/cpufeature.h
index df9dd3d3..83263c2c 100644
--- a/com32/include/cpufeature.h
+++ b/com32/include/cpufeature.h
@@ -7,7 +7,7 @@
#ifndef __ASM_I386_CPUFEATURE_H
#define __ASM_I386_CPUFEATURE_H
-#define NCAPINTS 7 /* N 32-bit words worth of info */
+#define NCAPINTS 9 /* N 32-bit words worth of info */
/* Intel-defined CPU features, CPUID level 0x00000001 (edx), word 0 */
#define X86_FEATURE_FPU (0*32+ 0) /* Onboard FPU */
diff --git a/com32/include/ctype.h b/com32/include/ctype.h
index 83bbda1c..6e0645ee 100644
--- a/com32/include/ctype.h
+++ b/com32/include/ctype.h
@@ -117,5 +117,6 @@ __ctype_inline int tolower(int __c)
}
__extern char *skipspace(const char *p);
+__extern void chrreplace(char *source, char old, char new);
#endif /* _CTYPE_H */
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..b8a3b84c 100644
--- a/com32/include/dprintf.h
+++ b/com32/include/dprintf.h
@@ -7,16 +7,30 @@
#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/netinet/in.h b/com32/include/netinet/in.h
index ccf04750..d2af351f 100644
--- a/com32/include/netinet/in.h
+++ b/com32/include/netinet/in.h
@@ -5,6 +5,7 @@
#include <stdint.h>
#include <klibc/compiler.h>
+#include <klibc/extern.h>
#define __htons_macro(v) ((uint16_t) \
(((uint16_t)(v) << 8) | \
@@ -53,4 +54,6 @@ struct in_addr {
in_addr_t s_addr;
};
+__extern char *inet_ntoa(struct in_addr);
+
#endif /* _NETINET_IN_H */
diff --git a/com32/include/stdint.h b/com32/include/stdint.h
index a8391bf9..f64f0278 100644
--- a/com32/include/stdint.h
+++ b/com32/include/stdint.h
@@ -5,138 +5,112 @@
#ifndef _STDINT_H
#define _STDINT_H
-/* Exact types */
+#include <bitsize/stdint.h>
-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 */
-
-typedef signed char int_fast8_t;
-typedef signed short int_fast16_t;
-typedef signed int int_fast32_t;
-typedef signed long long int_fast64_t;
-
-typedef unsigned char uint_fast8_t;
-typedef unsigned short uint_fast16_t;
-typedef unsigned int uint_fast32_t;
-typedef unsigned long long uint_fast64_t;
-
-/* Pointer types */
-
-typedef int32_t intptr_t;
-typedef uint32_t uintptr_t;
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)
-/* Maximal types */
+#define INT8_MIN (-128)
+#define INT16_MIN (-32768)
+#define INT32_MIN (-2147483647-1)
+#define INT64_MIN (__INT64_C(-9223372036854775807)-1)
-typedef int64_t intmax_t;
-typedef uint64_t uintmax_t;
+#define INT8_MAX (127)
+#define INT16_MAX (32767)
+#define INT32_MAX (2147483647)
+#define INT64_MAX (__INT64_C(9223372036854775807))
-/*
- * To be strictly correct...
- */
-#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)
+#define UINT8_MAX (255U)
+#define UINT16_MAX (65535U)
+#define UINT32_MAX (4294967295U)
+#define UINT64_MAX (__UINT64_C(18446744073709551615))
-# define INT8_MIN (-128)
-# define INT16_MIN (-32767-1)
-# define INT32_MIN (-2147483647-1)
-# define INT64_MIN (-9223372036854775807LL-1)
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST64_MIN INT64_MIN
-# define INT8_MAX (127)
-# define INT16_MAX (32767)
-# define INT32_MAX (2147483647)
-# define INT64_MAX (9223372036854775807LL)
+#define INT_LEAST8_MAX INT8_MAX
+#define INT_LEAST16_MAX INT16_MAX
+#define INT_LEAST32_MAX INT32_MAX
+#define INT_LEAST64_MAX INT64_MAX
-# define UINT8_MAX (255U)
-# define UINT16_MAX (65535U)
-# define UINT32_MAX (4294967295U)
-# define UINT64_MAX (18446744073709551615ULL)
+#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 INT_LEAST8_MIN (-128)
-# define INT_LEAST16_MIN (-32767-1)
-# define INT_LEAST32_MIN (-2147483647-1)
-# define INT_LEAST64_MIN (-9223372036854775807LL-1)
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST64_MIN INT64_MIN
-# define INT_LEAST8_MAX (127)
-# define INT_LEAST16_MAX (32767)
-# define INT_LEAST32_MAX (2147483647)
-# define INT_LEAST64_MAX (9223372036854775807LL)
+#define INT_FAST8_MAX INT8_MAX
+#define INT_FAST64_MAX INT64_MAX
-# define UINT_LEAST8_MAX (255U)
-# define UINT_LEAST16_MAX (65535U)
-# define UINT_LEAST32_MAX (4294967295U)
-# define UINT_LEAST64_MAX (18446744073709551615ULL)
+#define UINT_FAST8_MAX UINT8_MAX
+#define UINT_FAST64_MAX UINT64_MAX
-# define INT_FAST8_MIN (-128)
-# define INT_FAST16_MIN (-32767-1)
-# define INT_FAST32_MIN (-2147483647-1)
-# define INT_FAST64_MIN (-9223372036854775807LL-1)
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
-# define INT_FAST8_MAX (127)
-# define INT_FAST16_MAX (32767)
-# define INT_FAST32_MAX (2147483647)
-# define INT_FAST64_MAX (9223372036854775807LL)
+#include <bitsize/stdintlimits.h>
-# define UINT_FAST8_MAX (255U)
-# define UINT_FAST16_MAX (65535U)
-# define UINT_FAST32_MAX (4294967295U)
-# define UINT_FAST64_MAX (18446744073709551615ULL)
+#endif
-# define INTPTR_MIN (-2147483647-1)
-# define INTPTR_MAX (2147483647)
-# define UINTPTR_MAX (4294967295U)
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS)
-# define INTMAX_MIN (-9223372036854775807LL-1)
-# define INTMAX_MAX (9223372036854775807LL)
-# define UINTMAX_MAX (18446744073709551615ULL)
+#define INT8_C(c) c
+#define INT16_C(c) c
+#define INT32_C(c) c
+#define INT64_C(c) __INT64_C(c)
-/* ptrdiff_t limit */
-# define PTRDIFF_MIN (-2147483647-1)
-# define PTRDIFF_MAX (2147483647)
+#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)
-/* sig_atomic_t limit */
-# define SIG_ATOMIC_MIN (-2147483647-1)
-# define SIG_ATOMIC_MAX (2147483647)
+#define INT_LEAST8_C(c) INT8_C(c)
+#define INT_LEAST16_C(c) INT16_C(c)
+#define INT_LEAST32_C(c) INT32_C(c)
+#define INT_LEAST64_C(c) INT64_C(c)
-/* size_t limit */
-# define SIZE_MAX (4294967295U)
+#define UINT_LEAST8_C(c) UINT8_C(c)
+#define UINT_LEAST16_C(c) UINT16_C(c)
+#define UINT_LEAST32_C(c) UINT32_C(c)
+#define UINT_LEAST64_C(c) UINT64_C(c)
-#endif /* STDC_LIMIT_MACROS */
+#define INT_FAST8_C(c) INT8_C(c)
+#define INT_FAST64_C(c) INT64_C(c)
-#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS)
+#define UINT_FAST8_C(c) UINT8_C(c)
+#define UINT_FAST64_C(c) UINT64_C(c)
-# define INT8_C(n) n
-# define INT16_C(n) n
-# define INT32_C(n) n
-# define INT64_C(n) n ## LL
+#define INTMAX_C(c) INT64_C(c)
+#define UINTMAX_C(c) UINT64_C(c)
-# define UINT8_C(n) n ## U
-# define UINT16_C(n) n ## U
-# define UINT32_C(n) n ## U
-# define UINT64_C(n) n ## ULL
+#include <bitsize/stdintconst.h>
-# define INTMAX_C(n) n ## LL
-# define UINTMAX_C(n) n ## ULL
+#endif
-#endif /* STDC_CONSTANT_MACROS */
+/* Keep the kernel from trying to define these types... */
+#define __BIT_TYPES_DEFINED__
-#endif /* _STDINT_H */
+#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/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/linux.h b/com32/include/syslinux/linux.h
index 754d1b64..f5f95fb0 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
@@ -51,8 +52,26 @@ 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
+
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 */
@@ -70,4 +89,12 @@ int initramfs_load_file(struct initramfs *ihead, const char *src_filename,
int initramfs_add_trailer(struct initramfs *ihead);
int initramfs_load_archive(struct initramfs *ihead, const char *filename);
+/* 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/lib/Makefile b/com32/lib/Makefile
index 48a166dd..5ab1fac4 100644
--- a/com32/lib/Makefile
+++ b/com32/lib/Makefile
@@ -4,8 +4,9 @@
# Include configuration rules
NOGPL := 1
-topdir = ../..
-include MCONFIG
+topdir = ../../
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/lib.mk
LIBOBJS = \
abort.o atexit.o atoi.o atol.o atoll.o calloc.o creat.o \
@@ -28,6 +29,10 @@ LIBOBJS = \
asprintf.o vasprintf.o strlcpy.o strlcat.o \
vsscanf.o zalloc.o \
skipspace.o \
+ chrreplace.o \
+ bufprintf.o \
+ inet.o dhcppack.o dhcpunpack.o \
+ strreplace.o \
\
lmalloc.o lstrdup.o \
\
@@ -122,7 +127,11 @@ LIBOBJS = \
syslinux/setadv.o \
\
syslinux/video/fontquery.o syslinux/video/forcetext.o \
- syslinux/video/reportmode.o
+ syslinux/video/reportmode.o \
+ \
+ syslinux/disk.o \
+ \
+ syslinux/setup_data.o
# These are the objects which are also imported into the core
LIBCOREOBJS = \
diff --git a/com32/lib/bufprintf.c b/com32/lib/bufprintf.c
new file mode 100644
index 00000000..939bcec3
--- /dev/null
+++ b/com32/lib/bufprintf.c
@@ -0,0 +1,41 @@
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <bufprintf.h>
+
+int vbufprintf(struct print_buf *buf, const char *format, va_list ap)
+{
+ va_list ap2;
+ int rv;
+
+ va_copy(ap2, ap);
+ rv = vsnprintf(NULL, 0, format, ap);
+
+ /* >= to make sure we have space for terminating null */
+ if (rv + buf->len >= buf->size) {
+ size_t newsize = rv + buf->len + BUFPAD;
+ char *newbuf;
+
+ newbuf = realloc(buf->buf, newsize);
+ if (!newbuf)
+ return -1;
+
+ buf->buf = newbuf;
+ buf->size = newsize;
+ }
+
+ rv = vsnprintf(buf->buf + buf->len, buf->size - buf->len, format, ap2);
+ buf->len += rv;
+ return rv;
+}
+
+int bufprintf(struct print_buf *buf, const char *format, ...)
+{
+ va_list ap;
+ int rv;
+
+ va_start(ap, format);
+ rv = vbufprintf(buf, format, ap);
+ va_end(ap);
+ return rv;
+}
diff --git a/com32/lib/chrreplace.c b/com32/lib/chrreplace.c
new file mode 100644
index 00000000..65786f94
--- /dev/null
+++ b/com32/lib/chrreplace.c
@@ -0,0 +1,11 @@
+#include <ctype.h>
+
+/* Replace char 'old' by char 'new' in source */
+void chrreplace(char *source, char old, char new)
+{
+ while (*source) {
+ source++;
+ if (source[0] == old) source[0]=new;
+ }
+}
+
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..aad11746 100644
--- a/com32/lib/dprintf.c
+++ b/com32/lib/dprintf.c
@@ -9,6 +9,7 @@
#define DEBUG 1
#include <dprintf.h>
+#ifndef dprintf
void dprintf(const char *format, ...)
{
va_list ap;
@@ -17,3 +18,4 @@ void dprintf(const char *format, ...)
vdprintf(format, ap);
va_end(ap);
}
+#endif
diff --git a/com32/lib/inet.c b/com32/lib/inet.c
new file mode 100644
index 00000000..133645ed
--- /dev/null
+++ b/com32/lib/inet.c
@@ -0,0 +1,39 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * -----------------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <netinet/in.h>
+
+char *inet_ntoa(struct in_addr addr)
+{
+ static char buf[16];
+ const uint8_t *bytes = (const uint8_t *)&addr.s_addr;
+
+ sprintf(buf, "%u.%u.%u.%u", bytes[0], bytes[1], bytes[2], bytes[3]);
+ return buf;
+}
diff --git a/com32/lib/pci/scan.c b/com32/lib/pci/scan.c
index c8334b11..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
@@ -66,15 +61,6 @@ static int hex_to_int(char *hexa)
return strtoul(hexa, NULL, 16);
}
-/* Replace char 'old' by char 'new' in source */
-void chr_replace(char *source, char old, char new)
-{
- while (*source) {
- source++;
- if (source[0] == old) source[0]=new;
- }
-}
-
/* Try to match any pci device to the appropriate kernel module */
/* it uses the modules.pcimap from the boot device */
int get_module_name_from_pcimap(struct pci_domain *domain,
@@ -135,7 +121,7 @@ int get_module_name_from_pcimap(struct pci_domain *domain,
* in the module name whereas modules.alias is only using '_'.
* To avoid kernel modules duplication, let's rename all '-' in '_'
* to match what modules.alias provides */
- case 0:chr_replace(result,'-','_');strcpy(module_name,result); break;
+ case 0:chrreplace(result,'-','_');strcpy(module_name,result); break;
case 1:strcpy(vendor_id,result); break;
case 2:strcpy(product_id,result); break;
case 3:strcpy(sub_vendor_id,result); break;
@@ -593,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/strreplace.c b/com32/lib/strreplace.c
new file mode 100644
index 00000000..d59efe0e
--- /dev/null
+++ b/com32/lib/strreplace.c
@@ -0,0 +1,58 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * -----------------------------------------------------------------------
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+char *strreplace(const char *string, const char *string_to_replace,
+ const char *string_to_insert)
+{
+ char *token = NULL;
+ char *out = NULL;
+
+ size_t slen, srlen, silen;
+
+ token = strstr(string, string_to_replace);
+ if (!token)
+ return strdup(string);
+
+ 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);
+
+ return out;
+}
diff --git a/com32/lib/syslinux/disk.c b/com32/lib/syslinux/disk.c
new file mode 100644
index 00000000..d6409af6
--- /dev/null
+++ b/com32/lib/syslinux/disk.c
@@ -0,0 +1,534 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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 = __com32.cs_bounce;
+
+ 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;
+ }
+
+ /* 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)
+ return diskinfo->ebios ? 0 : -1;
+
+ 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;
+
+ return 0;
+}
+
+/**
+ * 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 = __com32.cs_bounce;
+ void *buf = (char *)__com32.cs_bounce + diskinfo->bps;
+ void *data;
+ uint32_t maxcnt;
+
+ maxcnt = (__com32.cs_bounce_size - diskinfo->bps) / diskinfo->bps;
+ if (!count || count > maxcnt || lba + count > diskinfo->lbacnt)
+ return NULL;
+
+ memset(&inreg, 0, sizeof inreg);
+
+ 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))
+ return NULL;
+
+ data = malloc(count * diskinfo->bps);
+ if (data)
+ memcpy(data, buf, count * diskinfo->bps);
+ 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 = __com32.cs_bounce;
+ void *buf = (char *)__com32.cs_bounce + diskinfo->bps;
+ uint32_t maxcnt;
+
+ maxcnt = (__com32.cs_bounce_size - diskinfo->bps) / diskinfo->bps;
+ if (!count || count > maxcnt || lba + count > diskinfo->lbacnt)
+ return -1;
+
+ memcpy(buf, data, count * diskinfo->bps);
+ memset(&inreg, 0, sizeof inreg);
+
+ 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))
+ return -1;
+
+ return 0; /* ok */
+}
+
+/**
+ * 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/load_linux.c b/com32/lib/syslinux/load_linux.c
index c1ce875c..856141f8 100644
--- a/com32/lib/syslinux/load_linux.c
+++ b/com32/lib/syslinux/load_linux.c
@@ -38,21 +38,13 @@
#include <inttypes.h>
#include <string.h>
#include <minmax.h>
+#include <errno.h>
#include <suffix_number.h>
#include <syslinux/align.h>
#include <syslinux/linux.h>
#include <syslinux/bootrm.h>
#include <syslinux/movebits.h>
-
-#ifndef DEBUG
-# define DEBUG 0
-#endif
-#if DEBUG
-# include <stdio.h>
-# define dprintf printf
-#else
-# define dprintf(f, ...) ((void)0)
-#endif
+#include <dprintf.h>
struct linux_header {
uint8_t boot_sector_1[0x0020];
@@ -189,13 +181,16 @@ static int map_initramfs(struct syslinux_movelist **fraglist,
}
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)
{
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;
@@ -318,10 +313,8 @@ int syslinux_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
@@ -460,6 +453,49 @@ int syslinux_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;
@@ -468,16 +504,14 @@ int syslinux_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);
syslinux_shuffle_boot_rm(fraglist, mmap, 0, &regs);
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/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 54a7e651..e9ee6aad 100644
--- a/com32/lib/syslinux/shuffle.c
+++ b/com32/lib/syslinux/shuffle.c
@@ -39,26 +39,10 @@
#include <inttypes.h>
#include <com32.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;
};
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 d74f2782..c1f90a63 100644
--- a/com32/lib/vdprintf.c
+++ b/com32/lib/vdprintf.c
@@ -14,6 +14,8 @@
#define DEBUG 1
#include <dprintf.h>
+#ifndef vdprintf
+
#define BUFFER_SIZE 4096
enum serial_port_regs {
@@ -114,3 +116,5 @@ void vdprintf(const char *format, va_list ap)
while (rv--)
debug_putc(*p++);
}
+
+#endif /* vdprintf */
diff --git a/com32/libupload/.gitignore b/com32/libupload/.gitignore
new file mode 100644
index 00000000..e0292b19
--- /dev/null
+++ b/com32/libupload/.gitignore
@@ -0,0 +1,2 @@
+*.o
+*.a
diff --git a/com32/libupload/Makefile b/com32/libupload/Makefile
new file mode 100644
index 00000000..83053350
--- /dev/null
+++ b/com32/libupload/Makefile
@@ -0,0 +1,39 @@
+# Include configuration rules
+topdir = ../..
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/com32.mk
+
+REQFLAGS += -I./
+
+SUBDIRS := .
+LIBOBJS := $(foreach dir,$(SUBDIRS),$(patsubst %.c,%.o,$(wildcard $(dir)/*.c)))
+
+BINDIR = /usr/bin
+LIBDIR = /usr/lib
+DATADIR = /usr/share
+AUXDIR = $(DATADIR)/syslinux
+INCDIR = /usr/include
+COM32DIR = $(AUXDIR)/com32
+
+all: libcom32upload.a
+
+libcom32upload.a : $(LIBOBJS)
+ rm -f $@
+ $(AR) cq $@ $^
+ $(RANLIB) $@
+
+tidy dist clean:
+ find . \( -name \*.o -o -name \*.a -o -name .\*.d -o -name \*.tmp \) -print0 | \
+ xargs -0r rm -f
+
+spotless: clean
+ rm -f *.a
+ rm -f *~ \#* */*~ */\#*
+
+install: all
+ mkdir -m 755 -p $(INSTALLROOT)$(COM32DIR)
+ install -m 644 libcom32upload.a $(INSTALLROOT)$(COM32DIR)
+ mkdir -p $(INSTALLROOT)$(COM32DIR)/include/
+ cp -r *.h $(INSTALLROOT)$(COM32DIR)/include/
+
+-include .*.d */.*.d */*/.*.d
diff --git a/com32/sysdump/cpio.c b/com32/libupload/cpio.c
index 81d0d4be..25b464d4 100644
--- a/com32/sysdump/cpio.c
+++ b/com32/libupload/cpio.c
@@ -9,10 +9,10 @@
#include <inttypes.h>
#include <stdbool.h>
#include <zlib.h>
-#include "backend.h"
+#include "upload_backend.h"
#include "ctime.h"
-int cpio_pad(struct backend *be)
+int cpio_pad(struct upload_backend *be)
{
static char pad[4]; /* Up to 4 zero bytes */
if (be->dbytes & 3)
@@ -21,7 +21,7 @@ int cpio_pad(struct backend *be)
return 0;
}
-int cpio_hdr(struct backend *be, uint32_t mode, size_t datalen,
+int cpio_hdr(struct upload_backend *be, uint32_t mode, size_t datalen,
const char *filename)
{
static uint32_t inode = 2;
@@ -31,7 +31,7 @@ int cpio_hdr(struct 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 */
@@ -52,12 +52,12 @@ int cpio_hdr(struct backend *be, uint32_t mode, size_t datalen,
return rv;
}
-int cpio_mkdir(struct backend *be, const char *filename)
+int cpio_mkdir(struct upload_backend *be, const char *filename)
{
return cpio_hdr(be, MODE_DIR, 0, filename);
}
-int cpio_writefile(struct backend *be, const char *filename,
+int cpio_writefile(struct upload_backend *be, const char *filename,
const void *data, size_t len)
{
int rv;
@@ -69,7 +69,7 @@ int cpio_writefile(struct backend *be, const char *filename,
return rv;
}
-int cpio_close(struct backend *be)
+int cpio_close(struct upload_backend *be)
{
return cpio_hdr(be, 0, 0, "TRAILER!!!");
}
diff --git a/com32/sysdump/ctime.c b/com32/libupload/ctime.c
index 56c8efb6..56c8efb6 100644
--- a/com32/sysdump/ctime.c
+++ b/com32/libupload/ctime.c
diff --git a/com32/sysdump/ctime.h b/com32/libupload/ctime.h
index e6461253..e6461253 100644
--- a/com32/sysdump/ctime.h
+++ b/com32/libupload/ctime.h
diff --git a/com32/sysdump/serial.c b/com32/libupload/serial.c
index a3987531..a3987531 100644
--- a/com32/sysdump/serial.c
+++ b/com32/libupload/serial.c
diff --git a/com32/sysdump/serial.h b/com32/libupload/serial.h
index 356f2cef..356f2cef 100644
--- a/com32/sysdump/serial.h
+++ b/com32/libupload/serial.h
diff --git a/com32/sysdump/srecsend.h b/com32/libupload/srecsend.h
index 667be20d..667be20d 100644
--- a/com32/sysdump/srecsend.h
+++ b/com32/libupload/srecsend.h
diff --git a/com32/libupload/tftp.h b/com32/libupload/tftp.h
new file mode 100644
index 00000000..323dc16a
--- /dev/null
+++ b/com32/libupload/tftp.h
@@ -0,0 +1,22 @@
+#include <stdint.h>
+
+#ifndef UPLOAD_TFTP
+#define UPLOAD_TFTP
+/* TFTP Error codes */
+enum tftp_error_codes {
+TFTP_ERR_UNKNOWN_ERROR = 0, // We have to use the message from the server
+TFTP_ERR_FILE_NOT_FOUND = 1, /**< File not found */
+TFTP_ERR_ACCESS_DENIED = 2, /**< Access violation */
+TFTP_ERR_DISK_FULL = 3, /**< Disk full or allocation exceeded */
+TFTP_ERR_ILLEGAL_OP = 4, /**< Illegal TFTP operation */
+TFTP_ERR_UNKNOWN_TID = 5, /**< Unknown transfer ID */
+TFTP_ERR_FILE_EXISTS = 6, /**< File already exists */
+TFTP_ERR_UNKNOWN_USER = 7, /**< No such user */
+TFTP_ERR_BAD_OPTS = 8, /**< Option negotiation failed */
+TFTP_ERR_UNABLE_TO_RESOLVE = 9, // Not in RFC, internal usage
+TFTP_ERR_UNABLE_TO_CONNECT = 10, // Not in RFC, internal usage
+TFTP_OK = 11, /* Not in RFC */
+};
+
+extern const char *tftp_string_error_message[];
+#endif
diff --git a/com32/libupload/upload_backend.h b/com32/libupload/upload_backend.h
new file mode 100644
index 00000000..7ea03e46
--- /dev/null
+++ b/com32/libupload/upload_backend.h
@@ -0,0 +1,56 @@
+#ifndef BACKEND_H
+#define BACKEND_H
+
+#include <stddef.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <zlib.h>
+#include "serial.h"
+#include "tftp.h"
+
+/* Backend flags */
+#define BE_NEEDLEN 0x01
+
+struct upload_backend {
+ const char *name;
+ const char *helpmsg;
+ int minargs;
+
+ size_t dbytes;
+ size_t zbytes;
+ const char **argv;
+
+ uint32_t now;
+
+ int (*write)(struct upload_backend *);
+
+ z_stream zstream;
+ char *outbuf;
+ size_t alloc;
+};
+
+/* zout.c */
+int init_data(struct upload_backend *be, const char *argv[]);
+int write_data(struct upload_backend *be, const void *buf, size_t len);
+int flush_data(struct upload_backend *be);
+
+/* cpio.c */
+#define cpio_init init_data
+int cpio_hdr(struct upload_backend *be, uint32_t mode, size_t datalen,
+ const char *filename);
+int cpio_mkdir(struct upload_backend *be, const char *filename);
+int cpio_writefile(struct upload_backend *be, const char *filename,
+ const void *data, size_t len);
+int cpio_close(struct upload_backend *be);
+#define MODE_FILE 0100644
+#define MODE_DIR 0040755
+
+/* backends.c */
+struct upload_backend *get_upload_backend(const char *name);
+
+/* backends */
+extern struct upload_backend upload_tftp;
+extern struct upload_backend upload_ymodem;
+extern struct upload_backend upload_srec;
+
+#endif /* BACKEND_H */
diff --git a/com32/sysdump/be_srec.c b/com32/libupload/upload_srec.c
index fc69c886..c1907131 100644
--- a/com32/sysdump/be_srec.c
+++ b/com32/libupload/upload_srec.c
@@ -6,7 +6,7 @@
#include <stdio.h>
#include <inttypes.h>
#include <minmax.h>
-#include "backend.h"
+#include "upload_backend.h"
/* Write a single S-record */
static int write_srecord(unsigned int len, unsigned int alen,
@@ -43,7 +43,7 @@ static int write_srecord(unsigned int len, unsigned int alen,
return 0;
}
-static int be_srec_write(struct backend *be)
+static int upload_srec_write(struct upload_backend *be)
{
char name[33];
const char *buf;
@@ -77,9 +77,9 @@ static int be_srec_write(struct backend *be)
return 0;
}
-struct backend be_srec = {
+struct upload_backend upload_srec = {
.name = "srec",
.helpmsg = "[filename]",
.minargs = 0,
- .write = be_srec_write,
+ .write = upload_srec_write,
};
diff --git a/com32/sysdump/be_tftp.c b/com32/libupload/upload_tftp.c
index 36a91eb8..5e73c1c5 100644
--- a/com32/sysdump/be_tftp.c
+++ b/com32/libupload/upload_tftp.c
@@ -8,8 +8,7 @@
#include <syslinux/config.h>
#include <netinet/in.h>
#include <sys/times.h>
-
-#include "backend.h"
+#include "upload_backend.h"
enum tftp_opcode {
TFTP_RRQ = 1,
@@ -19,6 +18,12 @@ enum tftp_opcode {
TFTP_ERROR = 5,
};
+struct tftp_error {
+ uint16_t opcode;
+ uint16_t errcode;
+ char errmsg[0];
+} __attribute__ (( packed ));
+
struct tftp_state {
uint32_t my_ip;
uint32_t srv_ip;
@@ -28,6 +33,21 @@ struct tftp_state {
uint16_t seq;
};
+const char *tftp_string_error_message[]={
+"",
+"File not found",
+"Access Denied",
+"Disk Full",
+"Illegal Operation",
+"Unknown Transfert ID",
+"File already exists",
+"Unknown User",
+"Negociation failed",
+"Unable to resolve hostname", // not in RFC
+"Unable to connect", // not in RFC
+"No Error",
+};
+
#define RCV_BUF 2048
static int send_ack_packet(struct tftp_state *tftp,
@@ -51,7 +71,7 @@ static int send_ack_packet(struct tftp_state *tftp,
ireg.eax.w[0] = 0x0009;
for (timeout = timeouts ; *timeout ; timeout++) {
- memset(uw, 0, sizeof uw);
+ memset(uw, 0, sizeof *uw);
memcpy(uw+1, pkt, len);
uw->ip = tftp->srv_ip;
uw->gw = tftp->srv_gw;
@@ -69,7 +89,7 @@ static int send_ack_packet(struct tftp_state *tftp,
start = times(NULL);
do {
- memset(ur, 0, sizeof ur);
+ memset(ur, 0, sizeof *ur);
ur->src_ip = tftp->srv_ip;
ur->dest_ip = tftp->my_ip;
ur->s_port = tftp->srv_port;
@@ -91,9 +111,14 @@ static int send_ack_packet(struct tftp_state *tftp,
if (ntohs(xb[0]) == TFTP_ACK &&
ntohs(xb[1]) == tftp->seq) {
tftp->srv_port = ur->s_port;
- err = 0; /* All good! */
+ err = TFTP_OK; /* All good! */
goto done;
- } else if (ntohs(xb[1]) == TFTP_ERROR) {
+ } else if (ntohs(xb[0]) == TFTP_ERROR) {
+ struct tftp_error *te = (struct tftp_error *)(ur+1);
+ if (te->errcode == TFTP_ERR_UNKNOWN_ERROR) {
+ tftp_string_error_message[TFTP_ERR_UNKNOWN_ERROR]=strdup(te->errmsg);
+ }
+ err=-ntohs(te->errcode); // Return the associated error code
goto done;
}
}
@@ -107,12 +132,13 @@ done:
return err;
}
-static int be_tftp_write(struct backend *be)
+static int upload_tftp_write(struct upload_backend *be)
{
static uint16_t local_port = 0x4000;
struct tftp_state tftp;
char buffer[512+4+6];
int nlen;
+ int err=TFTP_OK;
const union syslinux_derivative_info *sdi =
syslinux_derivative_info();
const char *data = be->outbuf;
@@ -129,30 +155,30 @@ static int be_tftp_write(struct backend *be)
if (be->argv[1]) {
tftp.srv_ip = pxe_dns(be->argv[1]);
if (!tftp.srv_ip) {
- printf("\nUnable to resolve hostname: %s\n", be->argv[1]);
- return -1;
+// printf("\nUnable to resolve hostname: %s\n", be->argv[1]);
+ return -TFTP_ERR_UNABLE_TO_RESOLVE;
}
} else {
tftp.srv_ip = sdi->pxe.ipinfo->serverip;
if (!tftp.srv_ip) {
- printf("\nNo server IP address\n");
- return -1;
+// printf("\nNo server IP address\n");
+ return -TFTP_ERR_UNABLE_TO_CONNECT;
}
}
- printf("server %u.%u.%u.%u... ",
+/* printf("server %u.%u.%u.%u... ",
((uint8_t *)&tftp.srv_ip)[0],
((uint8_t *)&tftp.srv_ip)[1],
((uint8_t *)&tftp.srv_ip)[2],
- ((uint8_t *)&tftp.srv_ip)[3]);
+ ((uint8_t *)&tftp.srv_ip)[3]);*/
buffer[0] = 0;
buffer[1] = TFTP_WRQ;
nlen = strlcpy(buffer+2, be->argv[0], 512);
memcpy(buffer+3+nlen, "octet", 6);
- if (send_ack_packet(&tftp, buffer, 2+nlen+1+6))
- return -1;
+ if ((err=send_ack_packet(&tftp, buffer, 2+nlen+1+6))!=TFTP_OK)
+ return err;
do {
chunk = len >= 512 ? 512 : len;
@@ -163,16 +189,16 @@ static int be_tftp_write(struct backend *be)
data += chunk;
len -= chunk;
- if (send_ack_packet(&tftp, buffer, chunk+4))
- return -1;
+ if ((err=send_ack_packet(&tftp, buffer, chunk+4))!=TFTP_OK)
+ return err;
} while (chunk == 512);
- return 0;
+ return TFTP_OK;
}
-struct backend be_tftp = {
+struct upload_backend upload_tftp = {
.name = "tftp",
.helpmsg = "filename [tftp_server]",
.minargs = 1,
- .write = be_tftp_write,
+ .write = upload_tftp_write,
};
diff --git a/com32/sysdump/be_ymodem.c b/com32/libupload/upload_ymodem.c
index 316b3d4e..c42327d8 100644
--- a/com32/sysdump/be_ymodem.c
+++ b/com32/libupload/upload_ymodem.c
@@ -5,7 +5,7 @@
#include <string.h>
#include <stdio.h>
#include <inttypes.h>
-#include "backend.h"
+#include "upload_backend.h"
#include "serial.h"
enum {
@@ -98,7 +98,7 @@ static void send_ack(struct ymodem_state *ym, const uint8_t *blk, size_t bytes)
} while (ack_buf == NAK);
}
-static int be_ymodem_write(struct backend *be)
+static int upload_ymodem_write(struct upload_backend *be)
{
static const uint8_t eot_buf = EOT;
uint8_t ack_buf;
@@ -167,9 +167,9 @@ static int be_ymodem_write(struct backend *be)
return 0;
}
-struct backend be_ymodem = {
+struct upload_backend upload_ymodem = {
.name = "ymodem",
.helpmsg = "filename [port [speed]]",
.minargs = 1,
- .write = be_ymodem_write,
+ .write = upload_ymodem_write,
};
diff --git a/com32/sysdump/ymodem.txt b/com32/libupload/ymodem.txt
index 2264ff78..2264ff78 100644
--- a/com32/sysdump/ymodem.txt
+++ b/com32/libupload/ymodem.txt
diff --git a/com32/sysdump/zout.c b/com32/libupload/zout.c
index ece934cc..47c0d308 100644
--- a/com32/sysdump/zout.c
+++ b/com32/libupload/zout.c
@@ -8,12 +8,12 @@
#include <inttypes.h>
#include <stdbool.h>
#include <zlib.h>
-#include "backend.h"
+#include "upload_backend.h"
#include "ctime.h"
#define ALLOC_CHUNK 65536
-int init_data(struct backend *be, const char *argv[])
+int init_data(struct upload_backend *be, const char *argv[])
{
be->now = posix_time();
be->argv = argv;
@@ -33,7 +33,7 @@ int init_data(struct backend *be, const char *argv[])
return 0;
}
-static int do_deflate(struct backend *be, int flush)
+static int do_deflate(struct upload_backend *be, int flush)
{
int rv;
char *buf;
@@ -55,7 +55,7 @@ static int do_deflate(struct backend *be, int flush)
}
-int write_data(struct backend *be, const void *buf, size_t len)
+int write_data(struct upload_backend *be, const void *buf, size_t len)
{
int rv = Z_OK;
@@ -75,9 +75,10 @@ int write_data(struct backend *be, const void *buf, size_t len)
}
/* Output the data and shut down the stream */
-int flush_data(struct backend *be)
+int flush_data(struct upload_backend *be)
{
int rv = Z_OK;
+ int err=-1;
while (rv != Z_STREAM_END) {
rv = do_deflate(be, Z_FINISH);
@@ -85,15 +86,15 @@ int flush_data(struct backend *be)
return -1;
}
- printf("Uploading data, %u bytes... ", be->zbytes);
+// printf("Uploading data, %u bytes... ", be->zbytes);
- if (be->write(be))
- return -1;
+ if ((err=be->write(be)) != 0)
+ return err;
free(be->outbuf);
be->outbuf = NULL;
be->dbytes = be->zbytes = be->alloc = 0;
- printf("done.\n");
+// printf("done.\n");
return 0;
}
diff --git a/com32/libutil/Makefile b/com32/libutil/Makefile
index 7a6b5272..83e23a0a 100644
--- a/com32/libutil/Makefile
+++ b/com32/libutil/Makefile
@@ -30,7 +30,8 @@
##
topdir = ../..
-include ../MCONFIG
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/com32.mk
LIBOBJS = ansiline.o ansiraw.o get_key.o keyname.o \
sha1hash.o unbase64.o \
diff --git a/com32/lua/src/Makefile b/com32/lua/src/Makefile
index 4081bfe1..f03f7a7f 100644
--- a/com32/lua/src/Makefile
+++ b/com32/lua/src/Makefile
@@ -16,9 +16,9 @@
##
topdir = ../../..
-include ../../MCONFIG
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/com32.mk
-LIBS = ../../lib/libcom32.a $(LIBGCC)
LNXLIBS =
# Temporarily allow warnings not being treated as errors
@@ -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
@@ -54,7 +55,7 @@ $(LIBLUA) : $(LIBLUA_OBJS)
$(AR) cq $@ $^
$(RANLIB) $@
-lua.elf : $(OBJS) $(LIBLUA) $(LIBS) $(C_LIBS)
+lua.elf : $(OBJS) $(LIBLUA) $(C_LIBS)
$(LD) $(LDFLAGS) -o $@ $^
tidy dist:
diff --git a/com32/lua/src/cpu.c b/com32/lua/src/cpu.c
index 8a246e3d..6ef4e5a3 100644
--- a/com32/lua/src/cpu.c
+++ b/com32/lua/src/cpu.c
@@ -9,13 +9,13 @@
#include"lualib.h"
#include"cpuid.h"
-static void add_string_item(lua_State *L, const char *item, const char *value_str) {
+void add_string_item(lua_State *L, const char *item, const char *value_str) {
lua_pushstring(L,item);
lua_pushstring(L,value_str);
lua_settable(L,-3);
}
-static void add_int_item(lua_State *L, const char *item, int value_int) {
+void add_int_item(lua_State *L, const char *item, int value_int) {
lua_pushstring(L,item);
lua_pushnumber(L,value_int);
lua_settable(L,-3);
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/lua/src/dhcp.h b/com32/lua/src/dhcp.h
new file mode 100644
index 00000000..a398cfc1
--- /dev/null
+++ b/com32/lua/src/dhcp.h
@@ -0,0 +1,49 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <stdint.h>
+
+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;
+
diff --git a/com32/lua/src/dmi.c b/com32/lua/src/dmi.c
index c8329d33..984fb60c 100644
--- a/com32/lua/src/dmi.c
+++ b/com32/lua/src/dmi.c
@@ -9,275 +9,487 @@
#include "lualib.h"
#include "dmi/dmi.h"
-static int dmi_gettable(lua_State *L)
+extern void add_string_item(lua_State*, const char*, const char*);
+extern void add_int_item(lua_State*, const char*, int);
+typedef int (*table_fn)(lua_State*, s_dmi*);
+
+/* Add a Lua_String entry to the table on stack
+ xxx_P is the poiter version (i.e., pBase is a pointer)
+ xxx_S is the staic version (i.e., Base is the struct)
+*/
+#define LUA_ADD_STR_P(pLua_state, pBase, Field) \
+ add_string_item(pLua_state, #Field, pBase->Field);
+#define LUA_ADD_STR_S(pLua_state, Base, Field) \
+ add_string_item(pLua_state, #Field, Base.Field);
+
+/* Add a Lua_Number entry to the table on stack
+ xxx_P is the poiter version (i.e., pBase is a pointer)
+ xxx_S is the staic version (i.e., Base is the struct)
+*/
+#define LUA_ADD_NUM_P(pLua_state, pBase, Field) \
+ add_int_item(pLua_state, #Field, pBase->Field);
+#define LUA_ADD_NUM_S(pLua_state, Base, Field) \
+ add_int_item(pLua_state, #Field, Base.Field);
+
+/* Add a sub-DMI table to the table on stack
+ All (*table_fn)() have to be named as get_<tabel_name>_table() for this
+ macro to work. For example, for the bios subtable, the table_fn is
+ get_bios_table() and the subtable name is "bios".
+ All (*table_fn)() have to return 1 if a subtable is created on the stack
+ or 0 if the subtable is not created (no corresponding dim subtable found).
+*/
+#define LUA_ADD_TABLE(pLua_state, pDmi, tb_name) \
+ add_dmi_sub_table(pLua_state, pDmi, #tb_name, get_ ## tb_name ## _table);
+
+
+static void add_dmi_sub_table(lua_State *L, s_dmi *dmi_ptr, char *table_name,
+ table_fn get_table_fn)
{
- s_dmi dmi;
-
- lua_newtable(L);
-
- if ( ! dmi_iterate(&dmi) ) {
- printf("No DMI Structure found\n");
- return -1;
+ if (get_table_fn(L, dmi_ptr)) { /* only adding it when it is there */
+ lua_pushstring(L, table_name);
+ lua_insert(L, -2);
+ lua_settable(L,-3);
}
+}
- parse_dmitable(&dmi);
-
- /* bios */
- lua_pushstring(L, "bios.vendor");
- lua_pushstring(L, dmi.bios.vendor);
- lua_settable(L,-3);
-
- lua_pushstring(L, "bios.version");
- lua_pushstring(L, dmi.bios.version);
- lua_settable(L,-3);
-
- lua_pushstring(L, "bios.release_date");
- lua_pushstring(L, dmi.bios.release_date);
- lua_settable(L,-3);
- lua_pushstring(L, "bios.bios_revision");
- lua_pushstring(L, dmi.bios.bios_revision);
- lua_settable(L,-3);
+void get_bool_table(lua_State *L, const char *str_table[], int n_elem,
+ bool *bool_table)
+{
+ int i;
+ for (i = 0; i < n_elem; i++) {
+ if (!str_table[i] || !*str_table[i]) /* aviod NULL/empty string */
+ continue;
+
+ lua_pushstring(L, str_table[i]);
+ lua_pushboolean(L, bool_table[i]);
+ lua_settable(L,-3);
+ }
+}
- lua_pushstring(L, "bios.firmware_revision");
- lua_pushstring(L, dmi.bios.firmware_revision);
- lua_settable(L,-3);
- lua_pushstring(L, "bios.address");
- lua_pushnumber(L, dmi.bios.address);
- lua_settable(L,-3);
+/*
+** {======================================================
+** DMI subtables
+** =======================================================
+*/
+static int get_bios_table(lua_State *L, s_dmi *dmi_ptr)
+{
+ s_bios *bios = &dmi_ptr->bios;
- lua_pushstring(L, "bios.runtime_size");
- lua_pushnumber(L, dmi.bios.runtime_size);
+ if (!bios->filled)
+ return 0;
+ /* bios */
+ lua_newtable(L);
+ LUA_ADD_STR_P(L, bios, vendor)
+ LUA_ADD_STR_P(L, bios, version)
+ LUA_ADD_STR_P(L, bios, release_date)
+ LUA_ADD_STR_P(L, bios, bios_revision)
+ LUA_ADD_STR_P(L, bios, firmware_revision)
+ LUA_ADD_NUM_P(L, bios, address)
+ LUA_ADD_NUM_P(L, bios, runtime_size)
+ LUA_ADD_STR_P(L, bios, runtime_size_unit)
+ LUA_ADD_NUM_P(L, bios, rom_size)
+ LUA_ADD_STR_P(L, bios, rom_size_unit)
+
+ /* bios characteristics */
+ lua_pushstring(L, "chars");
+ lua_newtable(L);
+ get_bool_table(L, bios_charac_strings,
+ sizeof(s_characteristics)/sizeof(bool),
+ (bool *)(&bios->characteristics));
+ get_bool_table(L, bios_charac_x1_strings,
+ sizeof(s_characteristics_x1)/sizeof(bool),
+ (bool *)(&bios->characteristics_x1));
+ get_bool_table(L, bios_charac_x2_strings,
+ sizeof(s_characteristics_x2)/sizeof(bool),
+ (bool *)(&bios->characteristics_x2));
lua_settable(L,-3);
- lua_pushstring(L, "bios.runtime_size_unit");
- lua_pushstring(L, dmi.bios.runtime_size_unit);
- lua_settable(L,-3);
+ return 1;
+}
- lua_pushstring(L, "bios.rom_size");
- lua_pushnumber(L, dmi.bios.rom_size);
- lua_settable(L,-3);
- lua_pushstring(L, "bios.rom_size_unit");
- lua_pushstring(L, dmi.bios.rom_size_unit);
- lua_settable(L,-3);
+static int get_system_table(lua_State *L, s_dmi *dmi_ptr)
+{
+ s_system *system = &dmi_ptr->system;
+ if (!system->filled)
+ return 0;
/* system */
- lua_pushstring(L, "system.manufacturer");
- lua_pushstring(L, dmi.system.manufacturer);
- lua_settable(L,-3);
-
- lua_pushstring(L, "system.product_name");
- lua_pushstring(L, dmi.system.product_name);
- lua_settable(L,-3);
-
- lua_pushstring(L, "system.version");
- lua_pushstring(L, dmi.system.version);
- lua_settable(L,-3);
-
- lua_pushstring(L, "system.serial");
- lua_pushstring(L, dmi.system.serial);
- lua_settable(L,-3);
-
- lua_pushstring(L, "system.uuid");
- lua_pushstring(L, dmi.system.uuid);
- lua_settable(L,-3);
+ lua_newtable(L);
+ LUA_ADD_STR_P(L, system, manufacturer)
+ LUA_ADD_STR_P(L, system, product_name)
+ LUA_ADD_STR_P(L, system, version)
+ LUA_ADD_STR_P(L, system, serial)
+ LUA_ADD_STR_P(L, system, uuid)
+ LUA_ADD_STR_P(L, system, wakeup_type)
+ LUA_ADD_STR_P(L, system, sku_number)
+ LUA_ADD_STR_P(L, system, family)
+ LUA_ADD_STR_P(L, system, system_boot_status)
+ LUA_ADD_STR_P(L, system, configuration_options)
+
+ /* system reset */
+ if (system->system_reset.filled) {
+ lua_pushstring(L, "reset");
+ lua_newtable(L);
+ LUA_ADD_NUM_S(L, system->system_reset, status)
+ LUA_ADD_NUM_S(L, system->system_reset, watchdog)
+ LUA_ADD_STR_S(L, system->system_reset, boot_option)
+ LUA_ADD_STR_S(L, system->system_reset, boot_option_on_limit)
+ LUA_ADD_STR_S(L, system->system_reset, reset_count)
+ LUA_ADD_STR_S(L, system->system_reset, reset_limit)
+ LUA_ADD_STR_S(L, system->system_reset, timer_interval)
+ LUA_ADD_STR_S(L, system->system_reset, timeout)
+ lua_settable(L,-3);
+ }
- lua_pushstring(L, "system.wakeup_type");
- lua_pushstring(L, dmi.system.wakeup_type);
- lua_settable(L,-3);
+ return 1;
+}
- lua_pushstring(L, "system.sku_number");
- lua_pushstring(L, dmi.system.sku_number);
- lua_settable(L,-3);
- lua_pushstring(L, "system.family");
- lua_pushstring(L, dmi.system.family);
- lua_settable(L,-3);
+static int get_base_board_table(lua_State *L, s_dmi *dmi_ptr)
+{
+ s_base_board *base_board = &dmi_ptr->base_board;
+ int n_dev = sizeof(base_board->devices_information) /
+ sizeof(base_board->devices_information[0]);
+ int i, j, has_dev;
+ if (!base_board->filled)
+ return 0;
/* base_board */
- lua_pushstring(L, "base_board.manufacturer");
- lua_pushstring(L, dmi.base_board.manufacturer);
- lua_settable(L,-3);
-
- lua_pushstring(L, "base_board.product_name");
- lua_pushstring(L, dmi.base_board.product_name);
- lua_settable(L,-3);
+ lua_newtable(L);
+ LUA_ADD_STR_P(L, base_board, manufacturer)
+ LUA_ADD_STR_P(L, base_board, product_name)
+ LUA_ADD_STR_P(L, base_board, version)
+ LUA_ADD_STR_P(L, base_board, serial)
+ LUA_ADD_STR_P(L, base_board, asset_tag)
+ LUA_ADD_STR_P(L, base_board, location)
+ LUA_ADD_STR_P(L, base_board, type)
+
+ /* base board features */
+ lua_pushstring(L, "features");
+ lua_newtable(L);
+ get_bool_table(L, base_board_features_strings,
+ sizeof(s_base_board_features)/sizeof(bool),
+ (bool *)(&base_board->features));
+ lua_settable(L,-3);
+
+ /* on-board devices */
+ for (has_dev = 0, i = 0; i < n_dev; i++)
+ if (*base_board->devices_information[i].type)
+ has_dev++;
+
+ if (has_dev) {
+ lua_pushstring(L, "devices");
+ lua_newtable(L);
+ for (i = 0, j = 1; i < n_dev; i++) {
+ if (!*base_board->devices_information[i].type) /* empty device */
+ continue;
+
+ lua_pushinteger(L, j++);
+ lua_newtable(L);
+ LUA_ADD_STR_S(L, base_board->devices_information[i], type)
+ LUA_ADD_STR_S(L, base_board->devices_information[i], description)
+ LUA_ADD_NUM_S(L, base_board->devices_information[i], status)
+ lua_settable(L,-3);
+ }
+ lua_settable(L,-3);
+ }
- lua_pushstring(L, "base_board.version");
- lua_pushstring(L, dmi.base_board.version);
- lua_settable(L,-3);
+ return 1;
+}
- lua_pushstring(L, "base_board.serial");
- lua_pushstring(L, dmi.base_board.serial);
- lua_settable(L,-3);
- lua_pushstring(L, "base_board.asset_tag");
- lua_pushstring(L, dmi.base_board.asset_tag);
- lua_settable(L,-3);
+static int get_chassis_table(lua_State *L, s_dmi *dmi_ptr)
+{
+ s_chassis *chassis = &dmi_ptr->chassis;
- lua_pushstring(L, "base_board.location");
- lua_pushstring(L, dmi.base_board.location);
- lua_settable(L,-3);
+ if (!chassis->filled)
+ return 0;
+ /* chassis */
+ lua_newtable(L);
+ LUA_ADD_STR_P(L, chassis, manufacturer)
+ LUA_ADD_STR_P(L, chassis, type)
+ LUA_ADD_STR_P(L, chassis, lock)
+ LUA_ADD_STR_P(L, chassis, version)
+ LUA_ADD_STR_P(L, chassis, serial)
+ LUA_ADD_STR_P(L, chassis, asset_tag)
+ LUA_ADD_STR_P(L, chassis, boot_up_state)
+ LUA_ADD_STR_P(L, chassis, power_supply_state)
+ LUA_ADD_STR_P(L, chassis, thermal_state)
+ LUA_ADD_STR_P(L, chassis, security_status)
+ LUA_ADD_STR_P(L, chassis, oem_information)
+ LUA_ADD_NUM_P(L, chassis, height)
+ LUA_ADD_NUM_P(L, chassis, nb_power_cords)
- lua_pushstring(L, "base_board.type");
- lua_pushstring(L, dmi.base_board.type);
- lua_settable(L,-3);
+ return 1;
+}
- /* chassis */
- lua_pushstring(L, "chassis.manufacturer");
- lua_pushstring(L, dmi.chassis.manufacturer);
- lua_settable(L,-3);
- lua_pushstring(L, "chassis.type");
- lua_pushstring(L, dmi.chassis.type);
- lua_settable(L,-3);
+static int get_processor_table(lua_State *L, s_dmi *dmi_ptr)
+{
+ s_processor *processor = &dmi_ptr->processor;
+ s_signature *signature = &processor->signature;
- lua_pushstring(L, "chassis.lock");
- lua_pushstring(L, dmi.chassis.lock);
+ if (!processor->filled)
+ return 0;
+ /* processor */
+ lua_newtable(L);
+ LUA_ADD_STR_P(L, processor, socket_designation)
+ LUA_ADD_STR_P(L, processor, type)
+ LUA_ADD_STR_P(L, processor, family)
+ LUA_ADD_STR_P(L, processor, manufacturer)
+ LUA_ADD_STR_P(L, processor, version)
+ LUA_ADD_NUM_P(L, processor, external_clock)
+ LUA_ADD_NUM_P(L, processor, max_speed)
+ LUA_ADD_NUM_P(L, processor, current_speed)
+ LUA_ADD_NUM_P(L, processor, voltage_mv)
+ LUA_ADD_STR_P(L, processor, status)
+ LUA_ADD_STR_P(L, processor, upgrade)
+ LUA_ADD_STR_P(L, processor, cache1)
+ LUA_ADD_STR_P(L, processor, cache2)
+ LUA_ADD_STR_P(L, processor, cache3)
+ LUA_ADD_STR_P(L, processor, serial)
+ LUA_ADD_STR_P(L, processor, part_number)
+ LUA_ADD_STR_P(L, processor, id)
+ LUA_ADD_NUM_P(L, processor, core_count)
+ LUA_ADD_NUM_P(L, processor, core_enabled)
+ LUA_ADD_NUM_P(L, processor, thread_count)
+
+ /* processor signature */
+ lua_pushstring(L, "signature");
+ lua_newtable(L);
+ LUA_ADD_NUM_P(L, signature, type)
+ LUA_ADD_NUM_P(L, signature, family)
+ LUA_ADD_NUM_P(L, signature, model)
+ LUA_ADD_NUM_P(L, signature, stepping)
+ LUA_ADD_NUM_P(L, signature, minor_stepping)
lua_settable(L,-3);
- lua_pushstring(L, "chassis.version");
- lua_pushstring(L, dmi.chassis.version);
+ /* processor flags */
+ lua_pushstring(L, "flags");
+ lua_newtable(L);
+ get_bool_table(L, cpu_flags_strings,
+ sizeof(s_dmi_cpu_flags)/sizeof(bool),
+ (bool *)(&processor->cpu_flags));
lua_settable(L,-3);
- lua_pushstring(L, "chassis.serial");
- lua_pushstring(L, dmi.chassis.serial);
- lua_settable(L,-3);
+ return 1;
+}
- lua_pushstring(L, "chassis.asset_tag");
- lua_pushstring(L, dmi.chassis.asset_tag);
- lua_settable(L,-3);
- lua_pushstring(L, "chassis.boot_up_state");
- lua_pushstring(L, dmi.chassis.boot_up_state);
- lua_settable(L,-3);
+static int get_battery_table(lua_State *L, s_dmi *dmi_ptr)
+{
+ s_battery *battery = &dmi_ptr->battery;
- lua_pushstring(L, "chassis.power_supply_state");
- lua_pushstring(L, dmi.chassis.power_supply_state);
- lua_settable(L,-3);
+ if (!battery->filled)
+ return 0;
+ /* battery */
+ lua_newtable(L);
+ LUA_ADD_STR_P(L, battery, location)
+ LUA_ADD_STR_P(L, battery, manufacturer)
+ LUA_ADD_STR_P(L, battery, manufacture_date)
+ LUA_ADD_STR_P(L, battery, serial)
+ LUA_ADD_STR_P(L, battery, name)
+ LUA_ADD_STR_P(L, battery, chemistry)
+ LUA_ADD_STR_P(L, battery, design_capacity)
+ LUA_ADD_STR_P(L, battery, design_voltage)
+ LUA_ADD_STR_P(L, battery, sbds)
+ LUA_ADD_STR_P(L, battery, sbds_serial)
+ LUA_ADD_STR_P(L, battery, maximum_error)
+ LUA_ADD_STR_P(L, battery, sbds_manufacture_date)
+ LUA_ADD_STR_P(L, battery, sbds_chemistry)
+ LUA_ADD_STR_P(L, battery, oem_info)
- lua_pushstring(L, "chassis.thermal_state");
- lua_pushstring(L, dmi.chassis.thermal_state);
- lua_settable(L,-3);
+ return 1;
+}
- lua_pushstring(L, "chassis.security_status");
- lua_pushstring(L, dmi.chassis.security_status);
- lua_settable(L,-3);
- lua_pushstring(L, "chassis.oem_information");
- lua_pushstring(L, dmi.chassis.oem_information);
- lua_settable(L,-3);
+static int get_memory_table(lua_State *L, s_dmi *dmi_ptr)
+{
+ s_memory *memory = dmi_ptr->memory;
+ int i, j, n_mem = dmi_ptr->memory_count;
- lua_pushstring(L, "chassis.height");
- lua_pushnumber(L, dmi.chassis.height);
- lua_settable(L,-3);
+ if (n_mem <= 0) /* no memory info */
+ return 0;
- lua_pushstring(L, "chassis.nb_power_cords");
- lua_pushnumber(L, dmi.chassis.nb_power_cords);
- lua_settable(L,-3);
+ /* memory */
+ lua_newtable(L);
+ for (j = 1, i = 0; i < n_mem; i++) {
+ if (!memory[i].filled)
+ continue;
+
+ lua_pushinteger(L, j++);
+ lua_newtable(L);
+ LUA_ADD_STR_S(L, memory[i], manufacturer)
+ LUA_ADD_STR_S(L, memory[i], error)
+ LUA_ADD_STR_S(L, memory[i], total_width)
+ LUA_ADD_STR_S(L, memory[i], data_width)
+ LUA_ADD_STR_S(L, memory[i], size)
+ LUA_ADD_STR_S(L, memory[i], form_factor)
+ LUA_ADD_STR_S(L, memory[i], device_set)
+ LUA_ADD_STR_S(L, memory[i], device_locator)
+ LUA_ADD_STR_S(L, memory[i], bank_locator)
+ LUA_ADD_STR_S(L, memory[i], type)
+ LUA_ADD_STR_S(L, memory[i], type_detail)
+ LUA_ADD_STR_S(L, memory[i], speed)
+ LUA_ADD_STR_S(L, memory[i], serial)
+ LUA_ADD_STR_S(L, memory[i], asset_tag)
+ LUA_ADD_STR_S(L, memory[i], part_number)
+ lua_settable(L,-3);
+ }
+ return 1;
+}
- /* processor */
- lua_pushstring(L, "processor.socket_designation");
- lua_pushstring(L, dmi.processor.socket_designation);
- lua_settable(L,-3);
- lua_pushstring(L, "processor.type");
- lua_pushstring(L, dmi.processor.type);
- lua_settable(L,-3);
+static int get_memory_module_table(lua_State *L, s_dmi *dmi_ptr)
+{
+ s_memory_module *memory_module = dmi_ptr->memory_module;
+ int i, j, n_mem = dmi_ptr->memory_module_count;
- lua_pushstring(L, "processor.family");
- lua_pushstring(L, dmi.processor.family);
- lua_settable(L,-3);
+ if (n_mem <= 0) /* no memory module info */
+ return 0;
- lua_pushstring(L, "processor.manufacturer");
- lua_pushstring(L, dmi.processor.manufacturer);
- lua_settable(L,-3);
+ /* memory module */
+ lua_newtable(L);
+ for (j = 1, i = 0; i < n_mem; i++) {
+ if (!memory_module[i].filled)
+ continue;
+
+ lua_pushinteger(L, j++);
+ lua_newtable(L);
+ LUA_ADD_STR_S(L, memory_module[i], socket_designation)
+ LUA_ADD_STR_S(L, memory_module[i], bank_connections)
+ LUA_ADD_STR_S(L, memory_module[i], speed)
+ LUA_ADD_STR_S(L, memory_module[i], type)
+ LUA_ADD_STR_S(L, memory_module[i], installed_size)
+ LUA_ADD_STR_S(L, memory_module[i], enabled_size)
+ LUA_ADD_STR_S(L, memory_module[i], error_status)
+ lua_settable(L,-3);
+ }
+ return 1;
+}
- lua_pushstring(L, "processor.version");
- lua_pushstring(L, dmi.processor.version);
- lua_settable(L,-3);
- lua_pushstring(L, "processor.external_clock");
- lua_pushnumber(L, dmi.processor.external_clock);
- lua_settable(L,-3);
+static int get_cache_table(lua_State *L, s_dmi *dmi_ptr)
+{
+ s_cache *cache = dmi_ptr->cache;
+ int i, n_cache = dmi_ptr->cache_count;
- lua_pushstring(L, "processor.max_speed");
- lua_pushnumber(L, dmi.processor.max_speed);
- lua_settable(L,-3);
+ if (n_cache <= 0) /* no cache info */
+ return 0;
- lua_pushstring(L, "processor.current_speed");
- lua_pushnumber(L, dmi.processor.current_speed);
- lua_settable(L,-3);
+ /* memory */
+ lua_newtable(L);
+ for (i = 0; i < n_cache; i++) {
+ lua_pushinteger(L, i + 1);
+ lua_newtable(L);
+ LUA_ADD_STR_S(L, cache[i], socket_designation)
+ LUA_ADD_STR_S(L, cache[i], configuration)
+ LUA_ADD_STR_S(L, cache[i], mode)
+ LUA_ADD_STR_S(L, cache[i], location)
+ LUA_ADD_NUM_S(L, cache[i], installed_size)
+ LUA_ADD_NUM_S(L, cache[i], max_size)
+ LUA_ADD_STR_S(L, cache[i], supported_sram_types)
+ LUA_ADD_STR_S(L, cache[i], installed_sram_types)
+ LUA_ADD_NUM_S(L, cache[i], speed)
+ LUA_ADD_STR_S(L, cache[i], error_correction_type)
+ LUA_ADD_STR_S(L, cache[i], system_type)
+ LUA_ADD_STR_S(L, cache[i], associativity)
+ lua_settable(L,-3);
+ }
+ return 1;
+}
- lua_pushstring(L, "processor.signature.type");
- lua_pushnumber(L, dmi.processor.signature.type);
- lua_settable(L,-3);
- lua_pushstring(L, "processor.signature.family");
- lua_pushnumber(L, dmi.processor.signature.family);
- lua_settable(L,-3);
+static int get_hardware_security_table(lua_State *L, s_dmi *dmi_ptr)
+{
+ if (!dmi_ptr->hardware_security.filled)
+ return 0;
+ /* hardware_security */
+ lua_newtable(L);
+ LUA_ADD_STR_S(L, dmi_ptr->hardware_security, power_on_passwd_status)
+ LUA_ADD_STR_S(L, dmi_ptr->hardware_security, keyboard_passwd_status)
+ LUA_ADD_STR_S(L, dmi_ptr->hardware_security, administrator_passwd_status)
+ LUA_ADD_STR_S(L, dmi_ptr->hardware_security, front_panel_reset_status)
- lua_pushstring(L, "processor.signature.model");
- lua_pushnumber(L, dmi.processor.signature.model);
- lua_settable(L,-3);
+ return 1;
+}
- lua_pushstring(L, "processor.signature.stepping");
- lua_pushnumber(L, dmi.processor.signature.stepping);
- lua_settable(L,-3);
- lua_pushstring(L, "processor.signature.minor_stepping");
- lua_pushnumber(L, dmi.processor.signature.minor_stepping);
- lua_settable(L,-3);
+static int get_dmi_info_table(lua_State *L, s_dmi *dmi_ptr)
+{
+ dmi_table *dmitable = &dmi_ptr->dmitable;
- lua_pushstring(L, "processor.voltage_mv");
- lua_pushnumber(L, dmi.processor.voltage_mv);
- lua_settable(L,-3);
+ /* dmi info */
+ lua_newtable(L);
+ LUA_ADD_NUM_P(L, dmitable, num)
+ LUA_ADD_NUM_P(L, dmitable, len)
+ LUA_ADD_NUM_P(L, dmitable, ver)
+ LUA_ADD_NUM_P(L, dmitable, base)
+ LUA_ADD_NUM_P(L, dmitable, major_version)
+ LUA_ADD_NUM_P(L, dmitable, minor_version)
- lua_pushstring(L, "processor.status");
- lua_pushstring(L, dmi.processor.status);
- lua_settable(L,-3);
+ return 1;
+}
- lua_pushstring(L, "processor.upgrade");
- lua_pushstring(L, dmi.processor.upgrade);
- lua_settable(L,-3);
- lua_pushstring(L, "processor.cache1");
- lua_pushstring(L, dmi.processor.cache1);
- lua_settable(L,-3);
+static int get_ipmi_table(lua_State *L, s_dmi *dmi_ptr)
+{
+ s_ipmi *ipmi = &dmi_ptr->ipmi;
- lua_pushstring(L, "processor.cache2");
- lua_pushstring(L, dmi.processor.cache2);
- lua_settable(L,-3);
+ if (!ipmi->filled)
+ return 0;
+ /* ipmi */
+ lua_newtable(L);
+ LUA_ADD_STR_P(L, ipmi, interface_type)
+ LUA_ADD_NUM_P(L, ipmi, major_specification_version)
+ LUA_ADD_NUM_P(L, ipmi, minor_specification_version)
+ LUA_ADD_NUM_P(L, ipmi, I2C_slave_address)
+ LUA_ADD_NUM_P(L, ipmi, nv_address)
+ LUA_ADD_NUM_P(L, ipmi, base_address)
+ LUA_ADD_NUM_P(L, ipmi, irq)
- lua_pushstring(L, "processor.cache3");
- lua_pushstring(L, dmi.processor.cache3);
- lua_settable(L,-3);
+ return 1;
+}
+/*
+** {======================================================
+** End of DMI subtables
+** =======================================================
+*/
- lua_pushstring(L, "processor.serial");
- lua_pushstring(L, dmi.processor.serial);
- lua_settable(L,-3);
- lua_pushstring(L, "processor.part_number");
- lua_pushstring(L, dmi.processor.part_number);
- lua_settable(L,-3);
+static int dmi_gettable(lua_State *L)
+{
+ s_dmi dmi;
- lua_pushstring(L, "processor.id");
- lua_pushstring(L, dmi.processor.id);
- lua_settable(L,-3);
+ lua_newtable(L);
- lua_pushstring(L, "processor.core_count");
- lua_pushnumber(L, dmi.processor.core_count);
- lua_settable(L,-3);
+ if ( ! dmi_iterate(&dmi) ) {
+ printf("No DMI Structure found\n");
+ return -1;
+ }
- lua_pushstring(L, "processor.core_enabled");
- lua_pushnumber(L, dmi.processor.core_enabled);
- lua_settable(L,-3);
+ parse_dmitable(&dmi);
- lua_pushstring(L, "processor.thread_count");
- lua_pushnumber(L, dmi.processor.thread_count);
- lua_settable(L,-3);
+ LUA_ADD_NUM_S(L, dmi, memory_module_count)
+ LUA_ADD_NUM_S(L, dmi, memory_count)
+ LUA_ADD_NUM_S(L, dmi, cache_count)
+ LUA_ADD_STR_S(L, dmi, oem_strings)
+
+ LUA_ADD_TABLE(L, &dmi, bios)
+ LUA_ADD_TABLE(L, &dmi, system)
+ LUA_ADD_TABLE(L, &dmi, base_board)
+ LUA_ADD_TABLE(L, &dmi, chassis)
+ LUA_ADD_TABLE(L, &dmi, processor)
+ LUA_ADD_TABLE(L, &dmi, battery)
+ LUA_ADD_TABLE(L, &dmi, memory)
+ LUA_ADD_TABLE(L, &dmi, memory_module)
+ LUA_ADD_TABLE(L, &dmi, cache)
+ LUA_ADD_TABLE(L, &dmi, ipmi)
+ LUA_ADD_TABLE(L, &dmi, hardware_security)
+ LUA_ADD_TABLE(L, &dmi, dmi_info)
/* set global variable: lua_setglobal(L, "dmitable"); */
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/liolib.c b/com32/lua/src/liolib.c
index 3f27395d..cf9dca22 100644
--- a/com32/lua/src/liolib.c
+++ b/com32/lua/src/liolib.c
@@ -18,12 +18,18 @@
#include "lauxlib.h"
#include "lualib.h"
-
+#ifdef SYSLINUX
+ #define NO_TMP_FILE 1
+ #define NO_READ_NUMBER 1
+ #define NO_TEST_EOF 1
+ #define NO_CLEAR_ERR 1
+ #define NO_F_SEEK 1
+ #define NO_F_SETVBUF 1
+#endif
#define IO_INPUT 1
#define IO_OUTPUT 2
-
static const char *const fnames[] = {"input", "output"};
@@ -180,7 +186,7 @@ static int io_popen (lua_State *L) {
}
-#ifndef SYSLINUX
+#ifndef NO_TMP_FILE
static int io_tmpfile (lua_State *L) {
FILE **pf = newfile(L);
*pf = tmpfile();
@@ -271,7 +277,7 @@ static int io_lines (lua_State *L) {
** =======================================================
*/
-#ifndef SYSLINUX
+#ifndef NO_READ_NUMBER /* No fscanf() and thus no read_number() */
static int read_number (lua_State *L, FILE *f) {
lua_Number d;
if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) {
@@ -283,8 +289,9 @@ static int read_number (lua_State *L, FILE *f) {
return 0; /* read fails */
}
}
+#endif
-
+#ifndef NO_TEST_EOF /* no buffering -> no ungetc() -> no EOF test */
static int test_eof (lua_State *L, FILE *f) {
int c = getc(f);
ungetc(c, f);
@@ -315,7 +322,6 @@ static int read_line (lua_State *L, FILE *f) {
}
}
-#ifndef SYSLINUX /* Not used */
static int read_chars (lua_State *L, FILE *f, size_t n) {
size_t rlen; /* how much to read */
size_t nr; /* number of chars actually read */
@@ -337,7 +343,9 @@ static int g_read (lua_State *L, FILE *f, int first) {
int nargs = lua_gettop(L) - 1;
int success;
int n;
+#ifndef NO_CLEAR_ERR
clearerr(f);
+#endif
if (nargs == 0) { /* no arguments? */
success = read_line(L, f);
n = first+1; /* to return 1 result */
@@ -348,14 +356,22 @@ static int g_read (lua_State *L, FILE *f, int first) {
for (n = first; nargs-- && success; n++) {
if (lua_type(L, n) == LUA_TNUMBER) {
size_t l = (size_t)lua_tointeger(L, n);
+#ifndef NO_TEST_EOF
success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l);
+#else /* we don't have test_eof defined */
+ success = (l == 0) ? 1 : read_chars(L, f, l);
+#endif
}
else {
const char *p = lua_tostring(L, n);
luaL_argcheck(L, p && p[0] == '*', n, "invalid option");
switch (p[1]) {
case 'n': /* number */
+#ifndef NO_READ_NUMBER
success = read_number(L, f);
+#else
+ return luaL_argerror(L, n, "\"*number\" not supported");
+#endif
break;
case 'l': /* line */
success = read_line(L, f);
@@ -388,7 +404,6 @@ static int io_read (lua_State *L) {
static int f_read (lua_State *L) {
return g_read(L, tofile(L), 2);
}
-#endif
static int io_readline (lua_State *L) {
@@ -441,7 +456,7 @@ static int f_write (lua_State *L) {
return g_write(L, tofile(L), 2);
}
-#ifndef SYSLINUX
+#ifndef NO_F_SEEK
static int f_seek (lua_State *L) {
static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END};
static const char *const modenames[] = {"set", "cur", "end", NULL};
@@ -456,8 +471,9 @@ static int f_seek (lua_State *L) {
return 1;
}
}
+#endif
-
+#ifndef NO_F_SETVBUF
static int f_setvbuf (lua_State *L) {
static const int mode[] = {_IONBF, _IOFBF, _IOLBF};
static const char *const modenames[] = {"no", "full", "line", NULL};
@@ -488,8 +504,8 @@ static const luaL_Reg iolib[] = {
{"open", io_open},
{"output", io_output},
{"popen", io_popen},
-#ifndef SYSLINUX
{"read", io_read},
+#ifndef NO_TMP_FILE
{"tmpfile", io_tmpfile},
#endif
{"type", io_type},
@@ -502,9 +518,11 @@ static const luaL_Reg flib[] = {
{"close", io_close},
{"flush", f_flush},
{"lines", f_lines},
-#ifndef SYSLINUX
{"read", f_read},
+#ifndef NO_F_SEEK
{"seek", f_seek},
+#endif
+#ifndef NO_F_SETVBUF
{"setvbuf", f_setvbuf},
#endif
{"write", f_write},
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..afcdcaad 100644
--- a/com32/lua/src/syslinux.c
+++ b/com32/lua/src/syslinux.c
@@ -39,6 +39,7 @@
#include "syslinux/loadfile.h"
#include "syslinux/linux.h"
#include "syslinux/config.h"
+#include "syslinux/reboot.h"
int __parse_argv(char ***argv, const char *str);
@@ -278,7 +279,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 +406,36 @@ 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_config_file(lua_State * L)
+{
+ const char *config_file = syslinux_config_file();
+ lua_pushstring(L, config_file);
+ return 1;
+}
+
+static int sl_reboot(lua_State * L)
+{
+ int warm_boot = luaL_optint(L, 1, 0);
+ /* explicitly convert it to 1 or 0 */
+ warm_boot = warm_boot? 1 : 0;
+ syslinux_reboot(warm_boot);
+ return 0;
+}
+
+static int sl_ipappend_strs(lua_State * L)
+{
+ int i;
+ const struct syslinux_ipappend_strings *ip_strs = syslinux_ipappend_strings();
+ lua_newtable(L);
+ for (i = 0; i < ip_strs->count; i++) {
+ lua_pushinteger(L, i + 1);
+ lua_pushstring(L, ip_strs->ptr[i]);
+ lua_settable(L,-3);
+ }
+ return 1;
}
static int sl_derivative(lua_State * L)
@@ -459,6 +489,9 @@ static const luaL_reg syslinuxlib[] = {
{"initramfs_load_archive", sl_initramfs_load_archive},
{"initramfs_add_file", sl_initramfs_add_file},
{"boot_it", sl_boot_it},
+ {"config_file", sl_config_file},
+ {"ipappend_strs", sl_ipappend_strs},
+ {"reboot", sl_reboot},
{"derivative", sl_derivative},
{"version", sl_version},
{NULL, NULL}
diff --git a/com32/mboot/Makefile b/com32/mboot/Makefile
index 7e6c2e96..b7ee1154 100644
--- a/com32/mboot/Makefile
+++ b/com32/mboot/Makefile
@@ -16,9 +16,9 @@
##
topdir = ../..
-include ../MCONFIG
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/com32.mk
-LIBS = ../libutil/libutil_com.a ../lib/libcom32.a $(LIBGCC)
LNXLIBS = ../libutil/libutil_lnx.a
MODULES = mboot.c32
@@ -28,7 +28,7 @@ OBJS = mboot.o map.o mem.o initvesa.o apm.o solaris.o syslinux.o
all: $(MODULES) $(TESTFILES)
-mboot.elf : $(OBJS) $(LIBS) $(C_LIBS)
+mboot.elf : $(OBJS) $(C_LIBS)
$(LD) $(LDFLAGS) -o $@ $^
tidy dist:
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/mboot.c b/com32/mboot/mboot.c
index 35450e03..10e6701c 100644
--- a/com32/mboot/mboot.c
+++ b/com32/mboot/mboot.c
@@ -198,7 +198,7 @@ int main(int argc, char *argv[])
}
if (init_map())
- return 1; /* Failed to allocate intitial map */
+ return 1; /* Failed to allocate initial map */
/*
* Map the primary image. This should be done before mapping anything
diff --git a/com32/menu/Makefile b/com32/menu/Makefile
index 2a032728..b67b997d 100644
--- a/com32/menu/Makefile
+++ b/com32/menu/Makefile
@@ -15,9 +15,9 @@
##
topdir = ../..
-include ../MCONFIG
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/com32.mk
-LIBS = ../libutil/libutil_com.a ../lib/libcom32.a $(LIBGCC)
LNXLIBS = ../libutil/libutil_lnx.a
MODULES = menu.c32 vesamenu.c32
@@ -28,10 +28,10 @@ COMMONOBJS = menumain.o readconfig.o passwd.o drain.o printmsg.o colors.o \
all: $(MODULES) $(TESTFILES)
-menu.elf : menu.o $(COMMONOBJS) $(LIBS) $(C_LIBS)
+menu.elf : menu.o $(COMMONOBJS) $(C_LIBS)
$(LD) $(LDFLAGS) -o $@ $^
-vesamenu.elf : vesamenu.o $(COMMONOBJS) $(LIBS) $(C_LIBS)
+vesamenu.elf : vesamenu.o $(COMMONOBJS) $(C_LIBS)
$(LD) $(LDFLAGS) -o $@ $^
tidy dist:
diff --git a/com32/menu/menumain.c b/com32/menu/menumain.c
index 5b3f6bd1..8573901c 100644
--- a/com32/menu/menumain.c
+++ b/com32/menu/menumain.c
@@ -806,7 +806,7 @@ static const char *run_menu(void)
while (entry < cm->nentries && is_disabled(cm->menu_entries[entry]))
entry++;
}
- if (entry >= cm->nentries) {
+ if (entry >= cm->nentries - 1) {
entry = cm->nentries - 1;
while (entry > 0 && is_disabled(cm->menu_entries[entry]))
entry--;
diff --git a/com32/menu/readconfig.c b/com32/menu/readconfig.c
index 0ac2564a..431017f6 100644
--- a/com32/menu/readconfig.c
+++ b/com32/menu/readconfig.c
@@ -392,7 +392,9 @@ static void record(struct menu *m, struct labeldata *ld, const char *append)
break;
}
- if (ld->menudefault && me->action == MA_CMD)
+ if (ld->menudefault && (me->action == MA_CMD ||
+ me->action == MA_GOTO ||
+ me->action == MA_GOTO_UNRES))
m->defentry = m->nentries - 1;
}
diff --git a/com32/modules/Makefile b/com32/modules/Makefile
index 2d479132..f110e584 100644
--- a/com32/modules/Makefile
+++ b/com32/modules/Makefile
@@ -16,13 +16,15 @@
##
topdir = ../..
-include ../MCONFIG
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/com32.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 whichsys.c32
+ ifcpu.c32 cpuid.c32 cat.c32 pwd.c32 ifplop.c32 zzjson.c32 \
+ whichsys.c32 prdhcp.c32 pxechn.c32 kontron_wdt.c32 ifmemdsk.c32
TESTFILES =
diff --git a/com32/modules/chain.c b/com32/modules/chain.c
deleted file mode 100644
index 48f53ffd..00000000
--- a/com32/modules/chain.c
+++ /dev/null
@@ -1,1870 +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";
-
- openconsole(&dev_null_r, &dev_stdcon_w);
-
- 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 182afa60..0ac45174 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 5c3cf02a..28dc62ca 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/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",
show_bool(cpu.flags.lm));
hardware_matches = cpu.flags.lm && hardware_matches;
} else if (!strcmp(argv[i], "pae")) {
if (debug)
- printf(" pae : %s on this system\n",
+ printf(" pae : %s on this system\n",
show_bool(cpu.flags.pae));
hardware_matches = cpu.flags.pae && hardware_matches;
} else if (!strcmp(argv[i], "hvm")) {
if (debug)
- printf(" hvm : %s on this system\n",
+ printf(" hvm : %s on this system\n",
show_bool((cpu.flags.vmx || cpu.flags.svm)));
hardware_matches = (cpu.flags.vmx || cpu.flags.svm)
&& hardware_matches;
} else if (!strcmp(argv[i], "multicore")) {
if (debug)
- printf(" multicore : %d cores on this system\n", cpu.num_cores);
+ printf(" multicore : %d cores on this system\n", cpu.num_cores);
if (cpu.num_cores > 1)
multicore = true;
hardware_matches = multicore && hardware_matches;
} else if (!strcmp(argv[i], "smp")) {
if (debug)
- printf(" smp : %s on this system\n", show_bool(cpu.flags.smp));
+ printf(" smp : %s on this system\n", show_bool(cpu.flags.smp));
hardware_matches = cpu.flags.smp && hardware_matches;
+ } else if (!strcmp(argv[i], "hypervisor")) {
+ if (debug)
+ printf(" hypervisor : %s on this system\n", show_bool(cpu.flags.hypervisor));
+ hardware_matches = cpu.flags.hypervisor && hardware_matches;
} else if (!strcmp(argv[i], "dry-run")) {
dryrun = true;
} else if (!strcmp(argv[i], "debug")) {
diff --git a/com32/modules/ifmemdsk.c b/com32/modules/ifmemdsk.c
new file mode 100644
index 00000000..cfed87f9
--- /dev/null
+++ b/com32/modules/ifmemdsk.c
@@ -0,0 +1,392 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2011 Shao Miller - 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/****
+ * @file ifmemdsk.c
+ *
+ * This COM32 module detects if there are MEMDISKs established.
+ */
+
+static const char usage_text[] = "\
+Usage:\n\
+ ifmemdsk.c32 [<option> [...]] --info [<option> [...]]\n\
+ ifmemdsk.c32 [<option> [...]] [<detected_cmd>] -- [<not_detected_cmd>]\n\
+\n\
+Options:\n\
+ --info . . . . . Displays info about MEMDISK(s)\n\
+ --safe-hooks . . Will scan INT 13h \"safe hook\" chain\n\
+ --mbfts . . . . . Will scan memory for MEMDISK mBFTs\n\
+ --no-sequential Suppresses probing all drive numbers\n\
+\n\
+If a MEMDISK is found, or if a particular MEMDISK is sought by the options\n\
+and is found, then the 'detected_cmd' action will be taken, else the\n\
+'not_detected_cmd' action will be taken.\n\
+\n";
+
+#include <stdio.h>
+#include <string.h>
+#include <alloca.h>
+#include <com32.h>
+#include <console.h>
+#include <syslinux/boot.h>
+
+/* Pull in MEMDISK common structures */
+#include "../../memdisk/mstructs.h"
+
+/*** Macros */
+#define M_GET_DRIVE_PARAMS (0x08)
+#define M_SEGOFFTOPTR(seg, off) (((seg) << 4) + (off))
+#define M_INT13H M_SEGOFFTOPTR(0x0000, 0x0013 * 4)
+#define M_FREEBASEMEM M_SEGOFFTOPTR(0x0040, 0x0013)
+#define M_TOP M_SEGOFFTOPTR(0x9FFF, 0x0000)
+
+/*** Object types */
+typedef struct mdi s_mdi;
+typedef real_addr_t u_segoff;
+typedef struct safe_hook s_safe_hook;
+typedef struct mBFT s_mbft;
+
+/*** Function types */
+typedef int f_find(void);
+
+/*** Function declarations */
+static const s_mdi * installation_check(int);
+static f_find scan_drives;
+static f_find walk_safe_hooks;
+static const s_safe_hook * is_safe_hook(const void *);
+static const s_mdi * is_memdisk_hook(const s_safe_hook *);
+static f_find scan_mbfts;
+static const s_mbft * is_mbft(const void *);
+static f_find do_nothing;
+static void memdisk_info(const s_mdi *);
+static void boot_args(char **);
+static const char * bootloadername(uint8_t);
+
+/*** Structure/union definitions */
+
+/*** Objects */
+static int show_info = 0;
+
+/*** Function definitions */
+
+int main(int argc, char ** argv) {
+ static f_find * do_scan_drives = scan_drives;
+ static f_find * do_walk_safe_hooks = do_nothing;
+ static f_find * do_scan_mbfts = do_nothing;
+ char ** detected_cmd;
+ char ** not_detected_cmd;
+ char ** cmd;
+ char ** cur_arg;
+ int show_usage;
+ int found;
+
+ (void) argc;
+
+ openconsole(&dev_null_r, &dev_stdcon_w);
+
+ detected_cmd = NULL;
+ not_detected_cmd = NULL;
+ show_usage = 1;
+ for (cur_arg = argv + 1; *cur_arg; ++cur_arg) {
+ /* Check for command divider */
+ if (!strcmp(*cur_arg, "--")) {
+ show_usage = 0;
+ *cur_arg = NULL;
+ not_detected_cmd = cur_arg + 1;
+ break;
+ }
+
+ /* Check for '--info' */
+ if (!strcmp(*cur_arg, "--info")) {
+ show_usage = 0;
+ show_info = 1;
+ continue;
+ }
+
+ /* Other options */
+ if (!strcmp(*cur_arg, "--no-sequential")) {
+ do_scan_drives = do_nothing;
+ continue;
+ }
+
+ if (!strcmp(*cur_arg, "--safe-hooks")) {
+ do_walk_safe_hooks = walk_safe_hooks;
+ continue;
+ }
+
+ if (!strcmp(*cur_arg, "--mbfts")) {
+ do_scan_mbfts = scan_mbfts;
+ continue;
+ }
+
+ /* Check for invalid option */
+ if (!memcmp(*cur_arg, "--", sizeof "--" - 1)) {
+ puts("Invalid option!");
+ show_usage = 1;
+ break;
+ }
+
+ /* Set 'detected_cmd' if it's null */
+ if (!detected_cmd)
+ detected_cmd = cur_arg;
+
+ continue;
+ }
+
+ if (show_usage) {
+ fprintf(stderr, usage_text);
+ return 1;
+ }
+
+ found = 0;
+ found += do_walk_safe_hooks();
+ found += do_scan_mbfts();
+ found += do_scan_drives();
+
+ cmd = found ? detected_cmd : not_detected_cmd;
+ if (cmd && *cmd)
+ boot_args(cmd);
+
+ return 0;
+ }
+
+static const s_mdi * installation_check(int drive) {
+ com32sys_t params, results;
+ int found;
+
+ /* Set parameters for INT 0x13 call */
+ memset(&params, 0, sizeof params);
+ params.eax.w[0] = M_GET_DRIVE_PARAMS << 8;
+ params.edx.w[0] = drive;
+ /* 'ME' 'MD' 'IS' 'K?' */
+ params.eax.w[1] = 0x454D;
+ params.ecx.w[1] = 0x444D;
+ params.edx.w[1] = 0x5349;
+ params.ebx.w[1] = 0x3F4B;
+
+ /* Perform the call */
+ __intcall(0x13, &params, &results);
+
+ /* Check result */
+ found = (
+ /* '!M' 'EM' 'DI' 'SK' */
+ results.eax.w[1] == 0x4D21 &&
+ results.ecx.w[1] == 0x4D45 &&
+ results.edx.w[1] == 0x4944 &&
+ results.ebx.w[1] == 0x4B53
+ );
+
+ if (found)
+ return MK_PTR(results.es, results.edi.w[0]);
+
+ return NULL;
+ }
+
+static int scan_drives(void) {
+ int found, drive;
+ const s_mdi * mdi;
+
+ for (found = drive = 0; drive <= 0xFF; ++drive) {
+ mdi = installation_check(drive);
+ if (!mdi)
+ continue;
+
+ memdisk_info(mdi);
+ ++found;
+ continue;
+ }
+
+ return found;
+ }
+
+static int walk_safe_hooks(void) {
+ static const u_segoff * const int13 = (void *) M_INT13H;
+ const void * addr;
+ int found;
+ const s_safe_hook * hook;
+ const s_mdi * mdi;
+
+ /* INT 0x13 vector */
+ addr = MK_PTR(int13->seg_off.segment, int13->seg_off.offset);
+ found = 0;
+ while (addr) {
+ hook = is_safe_hook(addr);
+ if (!hook)
+ break;
+
+ mdi = is_memdisk_hook(hook);
+ if (mdi) {
+ memdisk_info(mdi);
+ ++found;
+ }
+
+ addr = MK_PTR(
+ hook->old_hook.seg_off.segment,
+ hook->old_hook.seg_off.offset
+ );
+ continue;
+ }
+ return found;
+ }
+
+static const s_safe_hook * is_safe_hook(const void * addr) {
+ static const char magic[] = "$INT13SF";
+ const s_safe_hook * const test = addr;
+
+ if (memcmp(test->signature, magic, sizeof magic - 1))
+ return NULL;
+
+ return test;
+ }
+
+static const s_mdi * is_memdisk_hook(const s_safe_hook * hook) {
+ static const char magic[] = "MEMDISK";
+ const s_mbft * mbft;
+
+ if (memcmp(hook->vendor, magic, sizeof magic - 1))
+ return NULL;
+
+ /* An mBFT is always aligned */
+ mbft = MK_PTR(hook->mbft >> 4, 0);
+ return &mbft->mdi;
+ }
+
+static int scan_mbfts(void) {
+ static const uint16_t * const free_base_mem = (void *) M_FREEBASEMEM;
+ static const void * const top = (void *) M_TOP;
+ const void * addr;
+ const s_mbft * mbft;
+ int found;
+
+ found = 0;
+ for (addr = MK_PTR(*free_base_mem << 4, 0); addr < top; addr += 1 << 4) {
+ if (!(mbft = is_mbft(addr)))
+ continue;
+
+ memdisk_info(&mbft->mdi);
+ ++found;
+ continue;
+ }
+
+ return found;
+ }
+
+static const s_mbft * is_mbft(const void * addr) {
+ static const char magic[] = "mBFT";
+ const s_mbft * const test = addr;
+ const uint8_t * ptr, * end;
+ uint8_t chksum;
+
+ if (memcmp(test->acpi.signature, magic, sizeof magic - 1))
+ return NULL;
+
+ if (test->acpi.length != sizeof *test)
+ return NULL;
+
+ end = (void *) (test + 1);
+ chksum = 0;
+ for (ptr = addr; ptr < end; ++ptr)
+ chksum += *ptr;
+ if (chksum)
+ return NULL;
+
+ /* Looks like it's an mBFT! */
+ return test;
+ }
+
+static int do_nothing(void) {
+ return 0;
+ }
+
+static void memdisk_info(const s_mdi * mdi) {
+ const char * cmdline;
+
+ if (!show_info)
+ return;
+
+ cmdline = MK_PTR(
+ mdi->cmdline.seg_off.segment,
+ mdi->cmdline.seg_off.offset
+ );
+ printf(
+ "Found MEMDISK version %u.%02u:\n"
+ " diskbuf == 0x%08X, disksize == %u sectors\n"
+ " bootloaderid == 0x%02X (%s),\n"
+ " cmdline: %s\n",
+ mdi->version_major,
+ mdi->version_minor,
+ mdi->diskbuf,
+ mdi->disksize,
+ mdi->bootloaderid,
+ bootloadername(mdi->bootloaderid),
+ cmdline
+ );
+ return;
+ }
+
+/* This function copyright H. Peter Anvin */
+static void boot_args(char **args)
+{
+ int len = 0, a = 0;
+ char **pp;
+ const char *p;
+ char c, *q, *str;
+
+ for (pp = args; *pp; pp++)
+ len += strlen(*pp) + 1;
+
+ q = str = alloca(len);
+ for (pp = args; *pp; pp++) {
+ p = *pp;
+ while ((c = *p++))
+ *q++ = c;
+ *q++ = ' ';
+ a = 1;
+ }
+ q -= a;
+ *q = '\0';
+
+ if (!str[0])
+ syslinux_run_default();
+ else
+ syslinux_run_command(str);
+}
+
+/* This function copyright H. Peter Anvin */
+static const char *bootloadername(uint8_t id)
+{
+ static const struct {
+ uint8_t id, mask;
+ const char *name;
+ } *lp, list[] = {
+ {0x00, 0xf0, "LILO"},
+ {0x10, 0xf0, "LOADLIN"},
+ {0x31, 0xff, "SYSLINUX"},
+ {0x32, 0xff, "PXELINUX"},
+ {0x33, 0xff, "ISOLINUX"},
+ {0x34, 0xff, "EXTLINUX"},
+ {0x30, 0xf0, "Syslinux family"},
+ {0x40, 0xf0, "Etherboot"},
+ {0x50, 0xf0, "ELILO"},
+ {0x70, 0xf0, "GrUB"},
+ {0x80, 0xf0, "U-Boot"},
+ {0xA0, 0xf0, "Gujin"},
+ {0xB0, 0xf0, "Qemu"},
+ {0x00, 0x00, "unknown"}
+ };
+
+ for (lp = list;; lp++) {
+ if (((id ^ lp->id) & lp->mask) == 0)
+ return lp->name;
+ }
+}
+
diff --git a/com32/modules/kontron_wdt.c b/com32/modules/kontron_wdt.c
new file mode 100644
index 00000000..4e1d2535
--- /dev/null
+++ b/com32/modules/kontron_wdt.c
@@ -0,0 +1,414 @@
+/*
+ * kempld_wdt.c - Kontron PLD watchdog driver
+ *
+ * Copyright (c) 2010 Kontron Embedded Modules GmbH
+ * Author: Michael Brunner <michael.brunner@kontron.com>
+ * Author: Erwan Velu <erwan.velu@zodiacaerospace.com>
+ *
+ * Note: From the PLD watchdog point of view timeout and pretimeout are
+ * defined differently than in the kernel.
+ * First the pretimeout stage runs out before the timeout stage gets
+ * active. This has to be kept in mind.
+ *
+ * Kernel/API: P-----| pretimeout
+ * |-----------------------T timeout
+ * Watchdog: |-----------------P pretimeout_stage
+ * |-----T timeout_stage
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <string.h>
+#include <sys/io.h>
+#include <unistd.h>
+#include <syslinux/boot.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <console.h>
+#include "kontron_wdt.h"
+
+struct kempld_device_data pld;
+struct kempld_watchdog_data wdt;
+uint8_t status;
+char default_label[255];
+
+/* Default Timeout is 60sec */
+#define TIMEOUT 60
+#define PRETIMEOUT 0
+
+#define do_div(n,base) ({ \
+ int __res; \
+ __res = ((unsigned long) n) % (unsigned) base; \
+ n = ((unsigned long) n) / (unsigned) base; \
+ __res; })
+
+
+/* Basic Wrappers to get code as less changed as possible */
+void iowrite8(uint8_t val, uint16_t addr) { outb(val,addr); }
+void iowrite16(uint16_t val, uint16_t addr) { outw(val,addr); }
+void iowrite32(uint32_t val, uint16_t addr) { outl(val,addr);}
+uint8_t ioread8(uint16_t addr) { return inb(addr);}
+uint16_t ioread16(uint16_t addr) { return inw(addr);}
+uint32_t ioread32(uint32_t addr) { return inl(addr);}
+
+
+/**
+ * kempld_set_index - change the current register index of the PLD
+ * @pld: kempld_device_data structure describing the PLD
+ * @index: register index on the chip
+ *
+ * This function changes the register index of the PLD.
+ */
+void kempld_set_index(struct kempld_device_data *pld, uint8_t index)
+{
+ if (pld->last_index != index) {
+ iowrite8(index, pld->io_index);
+ pld->last_index = index;
+ }
+}
+
+
+uint8_t kempld_read8(struct kempld_device_data *pld, uint8_t index) {
+ kempld_set_index(pld, index);
+ return ioread8(pld->io_data);
+}
+
+
+void kempld_write8(struct kempld_device_data *pld, uint8_t index, uint8_t data) {
+ kempld_set_index(pld, index);
+ iowrite8(data, pld->io_data);
+}
+
+
+uint16_t kempld_read16(struct kempld_device_data *pld, uint8_t index)
+{
+ return kempld_read8(pld, index) | kempld_read8(pld, index+1) << 8;
+}
+
+
+void kempld_write16(struct kempld_device_data *pld, uint8_t index, uint16_t data)
+{
+ kempld_write8(pld, index, (uint8_t)data);
+ kempld_write8(pld, index+1, (uint8_t)(data>>8));
+}
+
+uint32_t kempld_read32(struct kempld_device_data *pld, uint8_t index)
+{
+ return kempld_read16(pld, index) | kempld_read16(pld, index+2) << 16;
+}
+
+void kempld_write32(struct kempld_device_data *pld, uint8_t index, uint32_t data)
+{
+ kempld_write16(pld, index, (uint16_t)data);
+ kempld_write16(pld, index+2, (uint16_t)(data>>16));
+}
+
+static void kempld_release_mutex(struct kempld_device_data *pld)
+{
+ iowrite8(pld->last_index | KEMPLD_MUTEX_KEY, pld->io_index);
+}
+
+void init_structure(void) {
+ /* set default values for the case we start the watchdog or change
+ * the configuration */
+ memset(&wdt,0,sizeof(wdt));
+ memset(&pld,0,sizeof(pld));
+ memset(&default_label,0,sizeof(default_label));
+ wdt.timeout = TIMEOUT;
+ wdt.pretimeout = PRETIMEOUT;
+ wdt.pld = &pld;
+
+ pld.io_base=KEMPLD_IOPORT;
+ pld.io_index=KEMPLD_IOPORT;
+ pld.io_data=KEMPLD_IODATA;
+ pld.pld_clock=33333333;
+}
+
+static int kempld_probe(void) {
+ /* Check for empty IO space */
+ int ret=0;
+ uint8_t index_reg = ioread8(pld.io_index);
+ if ((index_reg == 0xff) && (ioread8(pld.io_data) == 0xff)) {
+ ret = 1;
+ goto err_empty_io;
+ }
+ printf("Kempld structure found at 0x%X (data @ 0x%X)\n",pld.io_base,pld.io_data);
+ return 0;
+
+err_empty_io:
+ printf("No IO Found !\n");
+ return ret;
+}
+
+static int kempld_wdt_probe_stages(struct kempld_watchdog_data *wdt)
+{
+ struct kempld_device_data *pld = wdt->pld;
+ int i, ret;
+ uint32_t timeout;
+ uint32_t timeout_mask;
+ struct kempld_watchdog_stage *stage;
+
+ wdt->stages = 0;
+ wdt->timeout_stage = NULL;
+ wdt->pretimeout_stage = NULL;
+
+ for (i = 0; i < KEMPLD_WDT_MAX_STAGES; i++) {
+
+ timeout = kempld_read32(pld, KEMPLD_WDT_STAGE_TIMEOUT(i));
+ kempld_write32(pld, KEMPLD_WDT_STAGE_TIMEOUT(i), 0x00000000);
+ timeout_mask = kempld_read32(pld, KEMPLD_WDT_STAGE_TIMEOUT(i));
+ kempld_write32(pld, KEMPLD_WDT_STAGE_TIMEOUT(i), timeout);
+
+ if (timeout_mask != 0xffffffff) {
+ stage = malloc(sizeof(struct kempld_watchdog_stage));
+ if (stage == NULL) {
+ ret = -1;
+ goto err_alloc_stages;
+ }
+ stage->num = i;
+ stage->timeout_mask = ~timeout_mask;
+ wdt->stage[i] = stage;
+ wdt->stages++;
+
+ /* assign available stages to timeout and pretimeout */
+ if (wdt->stages == 1)
+ wdt->timeout_stage = stage;
+ else if (wdt->stages == 2) {
+ wdt->pretimeout_stage = wdt->timeout_stage;
+ wdt->timeout_stage = stage;
+ }
+ } else {
+ wdt->stage[i] = NULL;
+ }
+ }
+
+ return 0;
+err_alloc_stages:
+ kempld_release_mutex(pld);
+ printf("Cannot allocate stages\n");
+ return ret;
+}
+
+static int kempld_wdt_keepalive(struct kempld_watchdog_data *wdt)
+{
+ struct kempld_device_data *pld = wdt->pld;
+
+ kempld_write8(pld, KEMPLD_WDT_KICK, 'K');
+
+ return 0;
+}
+
+static int kempld_wdt_setstageaction(struct kempld_watchdog_data *wdt,
+ struct kempld_watchdog_stage *stage,
+ int action)
+{
+ struct kempld_device_data *pld = wdt->pld;
+ uint8_t stage_cfg;
+
+ if (stage == NULL)
+ return -1;
+
+ stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->num));
+ stage_cfg &= ~KEMPLD_WDT_STAGE_CFG_ACTION_MASK;
+ stage_cfg |= (action & KEMPLD_WDT_STAGE_CFG_ACTION_MASK);
+ if (action == KEMPLD_WDT_ACTION_RESET)
+ stage_cfg |= KEMPLD_WDT_STAGE_CFG_ASSERT;
+ else
+ stage_cfg &= ~KEMPLD_WDT_STAGE_CFG_ASSERT;
+
+ kempld_write8(pld, KEMPLD_WDT_STAGE_CFG(stage->num), stage_cfg);
+ stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->num));
+
+ return 0;
+}
+
+static int kempld_wdt_setstagetimeout(struct kempld_watchdog_data *wdt,
+ struct kempld_watchdog_stage *stage,
+ int timeout)
+{
+ struct kempld_device_data *pld = wdt->pld;
+ uint8_t stage_cfg;
+ uint8_t prescaler;
+ uint64_t stage_timeout64;
+ uint32_t stage_timeout;
+
+ if (stage == NULL)
+ return -1;
+
+ prescaler = KEMPLD_WDT_PRESCALER_21BIT;
+
+ stage_timeout64 = ((uint64_t)timeout*pld->pld_clock);
+ do_div(stage_timeout64, KEMPLD_PRESCALER(prescaler));
+ stage_timeout = stage_timeout64 & stage->timeout_mask;
+
+ if (stage_timeout64 != (uint64_t)stage_timeout)
+ return -1;
+
+ stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->num));
+ stage_cfg &= ~KEMPLD_WDT_STAGE_CFG_PRESCALER_MASK;
+ stage_cfg |= KEMPLD_WDT_STAGE_CFG_SET_PRESCALER(prescaler);
+ kempld_write8(pld, KEMPLD_WDT_STAGE_CFG(stage->num), stage_cfg);
+ kempld_write32(pld, KEMPLD_WDT_STAGE_TIMEOUT(stage->num),
+ stage_timeout);
+
+ return 0;
+}
+
+
+static int kempld_wdt_settimeout(struct kempld_watchdog_data *wdt)
+{
+ int stage_timeout;
+ int stage_pretimeout;
+ int ret;
+ if ((wdt->timeout <= 0) ||
+ (wdt->pretimeout < 0) ||
+ (wdt->pretimeout > wdt->timeout)) {
+ ret = -1;
+ goto err_check_values;
+ }
+
+ if ((wdt->pretimeout == 0) || (wdt->pretimeout_stage == NULL)) {
+ if (wdt->pretimeout != 0)
+ printf("No pretimeout stage available, only enabling reset!\n");
+ stage_pretimeout = 0;
+ stage_timeout = wdt->timeout;
+ } else {
+ stage_pretimeout = wdt->timeout - wdt->pretimeout;
+ stage_timeout = wdt->pretimeout;
+ }
+
+ if (stage_pretimeout != 0) {
+ ret = kempld_wdt_setstageaction(wdt, wdt->pretimeout_stage,
+ KEMPLD_WDT_ACTION_NMI);
+ } else if ((stage_pretimeout == 0)
+ && (wdt->pretimeout_stage != NULL)) {
+ ret = kempld_wdt_setstageaction(wdt, wdt->pretimeout_stage,
+ KEMPLD_WDT_ACTION_NONE);
+ } else
+ ret = 0;
+ if (ret)
+ goto err_setstage;
+
+ if (stage_pretimeout != 0) {
+ ret = kempld_wdt_setstagetimeout(wdt, wdt->pretimeout_stage,
+ stage_pretimeout);
+ if (ret)
+ goto err_setstage;
+ }
+
+ ret = kempld_wdt_setstageaction(wdt, wdt->timeout_stage,
+ KEMPLD_WDT_ACTION_RESET);
+ if (ret)
+ goto err_setstage;
+
+ ret = kempld_wdt_setstagetimeout(wdt, wdt->timeout_stage,
+ stage_timeout);
+ if (ret)
+ goto err_setstage;
+
+ return 0;
+err_setstage:
+err_check_values:
+ return ret;
+}
+
+static int kempld_wdt_start(struct kempld_watchdog_data *wdt)
+{
+ struct kempld_device_data *pld = wdt->pld;
+ uint8_t status;
+
+ status = kempld_read8(pld, KEMPLD_WDT_CFG);
+ status |= KEMPLD_WDT_CFG_ENABLE;
+ kempld_write8(pld, KEMPLD_WDT_CFG, status);
+ status = kempld_read8(pld, KEMPLD_WDT_CFG);
+
+ /* check if the watchdog was enabled */
+ if (!(status & KEMPLD_WDT_CFG_ENABLE))
+ return -1;
+
+ return 0;
+}
+
+/* A regular configuration file looks like
+
+ LABEL WDT
+ COM32 wdt.c32
+ APPEND timeout=120 default_label=local
+*/
+void detect_parameters(const int argc, const char *argv[]) {
+ for (int i = 1; i < argc; i++) {
+ /* Override the timeout if specified on the cmdline */
+ if (!strncmp(argv[i], "timeout=", 8)) {
+ wdt.timeout=atoi(argv[i]+8);
+ } else
+ /* Define which boot entry shall be used */
+ if (!strncmp(argv[i], "default_label=", 14)) {
+ strlcpy(default_label, argv[i] + 14, sizeof(default_label));
+ }
+ }
+}
+
+int main(int argc, const char *argv[]) {
+ int ret=0;
+ openconsole(&dev_rawcon_r, &dev_stdcon_w);
+ init_structure();
+ detect_parameters(argc,argv);
+ kempld_probe();
+
+ /* probe how many usable stages we have */
+ if (kempld_wdt_probe_stages(&wdt)) {
+ printf("Cannot Probe Stages\n");
+ return -1;
+ }
+
+ /* Useless but who knows */
+ wdt.ident.firmware_version = KEMPLD_WDT_REV_GET(kempld_read8(&pld, KEMPLD_WDT_REV));
+
+ status = kempld_read8(&pld, KEMPLD_WDT_CFG);
+ /* kick the watchdog if it is already enabled, otherwise start it */
+ if (status & KEMPLD_WDT_CFG_ENABLE) {
+ /* Maybye the BIOS did setup a first timer
+ * in this case, let's enforce the timeout
+ * to be sure we do have the proper value */
+ kempld_wdt_settimeout(&wdt);
+ kempld_wdt_keepalive(&wdt);
+ } else {
+ ret = kempld_wdt_settimeout(&wdt);
+ if (ret) {
+ printf("Unable to setup timeout !\n");
+ goto booting;
+ }
+
+ ret = kempld_wdt_start(&wdt);
+ if (ret) {
+ printf("Unable to start watchdog !\n");
+ goto booting;
+ }
+
+ }
+
+ printf("Watchog armed ! Rebooting in %d seconds if no feed occurs !\n",wdt.timeout);
+
+booting:
+ /* Release Mutex to let Linux's Driver taking control */
+ kempld_release_mutex(&pld);
+
+ /* Let's boot the default entry if specified */
+ if (strlen(default_label)>0) {
+ printf("Executing default label = '%s'\n",default_label);
+ syslinux_run_command(default_label);
+ } else {
+ return ret;
+ }
+}
diff --git a/com32/modules/kontron_wdt.h b/com32/modules/kontron_wdt.h
new file mode 100644
index 00000000..e916de30
--- /dev/null
+++ b/com32/modules/kontron_wdt.h
@@ -0,0 +1,117 @@
+/*
+ * kempld_wdt.h - Kontron PLD watchdog driver definitions
+ *
+ * Copyright (c) 2010 Kontron Embedded Modules GmbH
+ * Author: Michael Brunner <michael.brunner@kontron.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _KEMPLD_WDT_H_
+#define _KEMPLD_WDT_H_
+#include <stdint.h>
+
+#define KEMPLD_IOPORT 0x0a80
+#define KEMPLD_IODATA (KEMPLD_IOPORT+1)
+
+#define KEMPLD_MUTEX_KEY 0x80
+
+/* watchdog register definitions */
+#define KEMPLD_WDT_KICK 0x16
+#define KEMPLD_WDT_REV 0x16
+#define KEMPLD_WDT_REV_GET(x) (x & 0xf)
+#define KEMPLD_WDT_CFG 0x17
+#define KEMPLD_WDT_CFG_STAGE_TIMEOUT_OCCURED(x) (1<<x)
+#define KEMPLD_WDT_CFG_ENABLE_LOCK 0x8
+#define KEMPLD_WDT_CFG_ENABLE 0x10
+#define KEMPLD_WDT_CFG_AUTO_RELOAD 0x40
+#define KEMPLD_WDT_CFG_GLOBAL_LOCK 0x80
+#define KEMPLD_WDT_STAGE_CFG(x) (0x18+x)
+#define KEMPLD_WDT_STAGE_CFG_ACTION_MASK 0x7
+#define KEMPLD_WDT_STAGE_CFG_GET_ACTION(x) (x & 0x7)
+#define KEMPLD_WDT_STAGE_CFG_ASSERT 0x8
+#define KEMPLD_WDT_STAGE_CFG_PRESCALER_MASK 0x30
+#define KEMPLD_WDT_STAGE_CFG_GET_PRESCALER(x) ((x & 0x30)>>4)
+#define KEMPLD_WDT_STAGE_CFG_SET_PRESCALER(x) ((x & 0x30)<<4)
+#define KEMPLD_WDT_STAGE_TIMEOUT(x) (0x1b+x*4)
+#define KEMPLD_WDT_MAX_STAGES 3
+
+#define KEMPLD_WDT_ACTION_NONE 0x0
+#define KEMPLD_WDT_ACTION_RESET 0x1
+#define KEMPLD_WDT_ACTION_NMI 0x2
+#define KEMPLD_WDT_ACTION_SMI 0x3
+#define KEMPLD_WDT_ACTION_SCI 0x4
+#define KEMPLD_WDT_ACTION_DELAY 0x5
+
+#define KEMPLD_WDT_PRESCALER_21BIT 0x0
+#define KEMPLD_WDT_PRESCALER_17BIT 0x1
+#define KEMPLD_WDT_PRESCALER_12BIT 0x2
+
+const int kempld_prescaler_bits[] = { 21, 17, 12 };
+
+struct kempld_watchdog_stage {
+ int num;
+ uint32_t timeout_mask;
+};
+
+/**
+ * struct kempld_device_data - Internal representation of the PLD device
+ * @io_base: Pointer to the IO memory
+ * @io_index: Pointer to the IO index register
+ * @io_data: Pointer to the IO data register
+ * @pld_clock: PLD clock frequency
+ * @lock: PLD spin-lock
+ * @lock_flags: PLD spin-lock flags
+ * @have_mutex: Bool value that indicates if mutex is aquired
+ * @last_index: Last written index value
+ * @rscr: Kernel resource structure
+ * @dev: Pointer to kernel device structure
+ * @info: KEMPLD info structure
+ */
+struct kempld_device_data {
+ uint16_t io_base;
+ uint16_t io_index;
+ uint16_t io_data;
+ uint32_t pld_clock;
+/* spinlock_t lock;
+ unsigned long lock_flags; */
+ int have_mutex;
+ uint8_t last_index;
+/* struct resource rscr;
+ struct device *dev;
+ struct kempld_info info;*/
+};
+
+struct watchdog_info {
+ uint32_t options; /* Options the card/driver supports */
+ uint32_t firmware_version; /* Firmware version of the card */
+ uint8_t identity[32]; /* Identity of the board */
+};
+
+struct kempld_watchdog_data {
+ unsigned int revision;
+ int timeout;
+ int pretimeout;
+ unsigned long is_open;
+ unsigned long expect_close;
+ int stages;
+ struct kempld_watchdog_stage *timeout_stage;
+ struct kempld_watchdog_stage *pretimeout_stage;
+ struct kempld_device_data *pld;
+ struct kempld_watchdog_stage *stage[KEMPLD_WDT_MAX_STAGES];
+ struct watchdog_info ident;
+};
+
+#endif /* _KEMPLD_WDT_H_ */
+#define KEMPLD_PRESCALER(x) (0xffffffff>>(32-kempld_prescaler_bits[x]))
diff --git a/com32/modules/linux.c b/com32/modules/linux.c
index b902ebc5..76443f91 100644
--- a/com32/modules/linux.c
+++ b/com32/modules/linux.c
@@ -1,7 +1,7 @@
/* ----------------------------------------------------------------------- *
*
* Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
- * Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ * Copyright 2009-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
@@ -38,6 +38,7 @@
* Usage: linux.c32 [-dhcpinfo] kernel arguments...
*/
+#include <errno.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
@@ -108,10 +109,31 @@ static char *make_cmdline(char **argv)
return cmdline;
}
+static int setup_data_file(struct setup_data *setup_data,
+ uint32_t type, const char *filename,
+ bool opt_quiet)
+{
+ if (!opt_quiet)
+ printf("Loading %s... ", filename);
+
+ if (setup_data_load(setup_data, type, filename)) {
+ if (opt_quiet)
+ printf("Loading %s ", filename);
+ printf("failed\n");
+ return -1;
+ }
+
+ if (!opt_quiet)
+ printf("ok\n");
+
+ return 0;
+}
+
int main(int argc, char *argv[])
{
const char *kernel_name;
struct initramfs *initramfs;
+ struct setup_data *setup_data;
char *cmdline;
char *boot_image;
void *kernel_data;
@@ -120,7 +142,7 @@ int main(int argc, char *argv[])
bool opt_quiet = false;
void *dhcpdata;
size_t dhcplen;
- char **argp, *arg, *p;
+ char **argp, **argl, *arg, *p;
openconsole(&dev_null_r, &dev_stdcon_w);
@@ -144,9 +166,12 @@ int main(int argc, char *argv[])
kernel_name = arg;
+ errno = 0;
boot_image = malloc(strlen(kernel_name) + 12);
- if (!boot_image)
+ if (!boot_image) {
+ fprintf(stderr, "Error allocating BOOT_IMAGE string: ");
goto bail;
+ }
strcpy(boot_image, "BOOT_IMAGE=");
strcpy(boot_image + 11, kernel_name);
/* argp now points to the kernel name, and the command line follows.
@@ -159,23 +184,30 @@ int main(int argc, char *argv[])
if (!opt_quiet)
printf("Loading %s... ", kernel_name);
+ errno = 0;
if (loadfile(kernel_name, &kernel_data, &kernel_len)) {
if (opt_quiet)
printf("Loading %s ", kernel_name);
- printf("failed!\n");
+ printf("failed: ");
goto bail;
}
if (!opt_quiet)
printf("ok\n");
+ errno = 0;
cmdline = make_cmdline(argp);
- if (!cmdline)
+ if (!cmdline) {
+ fprintf(stderr, "make_cmdline() failed: ");
goto bail;
+ }
/* Initialize the initramfs chain */
+ errno = 0;
initramfs = initramfs_init();
- if (!initramfs)
+ if (!initramfs) {
+ fprintf(stderr, "initramfs_init() failed: ");
goto bail;
+ }
if ((arg = find_argument(argp, "initrd="))) {
do {
@@ -185,10 +217,11 @@ int main(int argc, char *argv[])
if (!opt_quiet)
printf("Loading %s... ", arg);
+ errno = 0;
if (initramfs_load_archive(initramfs, arg)) {
if (opt_quiet)
printf("Loading %s ", kernel_name);
- printf("failed!\n");
+ printf("failed: ");
goto bail;
}
if (!opt_quiet)
@@ -202,15 +235,57 @@ int main(int argc, char *argv[])
/* Append the DHCP info */
if (opt_dhcpinfo &&
!pxe_get_cached_info(PXENV_PACKET_TYPE_DHCP_ACK, &dhcpdata, &dhcplen)) {
+ errno = 0;
if (initramfs_add_file(initramfs, dhcpdata, dhcplen, dhcplen,
- "/dhcpinfo.dat", 0, 0755))
+ "/dhcpinfo.dat", 0, 0755)) {
+ fprintf(stderr, "Unable to add DHCP info: ");
goto bail;
+ }
+ }
+
+ /* Handle dtb and eventually other setup data */
+ setup_data = setup_data_init();
+ if (!setup_data)
+ goto bail;
+
+ for (argl = argv; (arg = *argl); argl++) {
+ if (!memcmp(arg, "dtb=", 4)) {
+ if (setup_data_file(setup_data, SETUP_DTB, arg+4, opt_quiet))
+ goto bail;
+ } else if (!memcmp(arg, "blob.", 5)) {
+ uint32_t type;
+ char *ep;
+
+ type = strtoul(arg + 5, &ep, 10);
+ if (ep[0] != '=' || !ep[1])
+ continue;
+
+ if (!type)
+ continue;
+
+ if (setup_data_file(setup_data, type, ep+1, opt_quiet))
+ goto bail;
+ }
}
/* This should not return... */
- syslinux_boot_linux(kernel_data, kernel_len, initramfs, cmdline);
+ errno = 0;
+ syslinux_boot_linux(kernel_data, kernel_len, initramfs,
+ setup_data, cmdline);
+ fprintf(stderr, "syslinux_boot_linux() failed: ");
bail:
- fprintf(stderr, "Kernel load failure (insufficient memory?)\n");
+ switch(errno) {
+ case ENOENT:
+ fprintf(stderr, "File not found\n");
+ break;
+ case ENOMEM:
+ fprintf(stderr, "Out of memory\n");
+ break;
+ default:
+ fprintf(stderr, "Error %d\n", errno);
+ break;
+ }
+ fprintf(stderr, "%s: Boot aborted!\n", progname);
return 1;
}
diff --git a/com32/modules/pcitest.c b/com32/modules/pcitest.c
index 672023ad..9921ee6d 100644
--- a/com32/modules/pcitest.c
+++ b/com32/modules/pcitest.c
@@ -39,12 +39,7 @@
#include <com32.h>
#include <sys/pci.h>
#include <stdbool.h>
-
-#ifdef DEBUG
-# define dprintf printf
-#else
-# define dprintf(...) ((void)0)
-#endif
+#include <dprintf.h>
char display_line = 0;
#define moreprintf(...) \
diff --git a/com32/modules/pmload.c b/com32/modules/pmload.c
index 3064a94f..4c01db08 100644
--- a/com32/modules/pmload.c
+++ b/com32/modules/pmload.c
@@ -81,10 +81,8 @@ int boot_raw(void *ptr, size_t len, addr_t where, char **argv)
if (!mmap || !amap)
goto bail;
-#if DEBUG
dprintf("Initial memory map:\n");
- syslinux_dump_memmap(stdout, mmap);
-#endif
+ syslinux_dump_memmap(mmap);
dprintf("Segment at 0x%08x len 0x%08x\n", where, len);
@@ -119,10 +117,8 @@ int boot_raw(void *ptr, size_t len, addr_t where, 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?! */
@@ -173,16 +169,14 @@ int boot_raw(void *ptr, size_t len, addr_t where, char **argv)
regs.eip = where;
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/prdhcp.c b/com32/modules/prdhcp.c
new file mode 100644
index 00000000..e1785a03
--- /dev/null
+++ b/com32/modules/prdhcp.c
@@ -0,0 +1,164 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2010-2011 Gene Cumm - All Rights Reserved
+ *
+ * Portions from chain.c:
+ * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2010 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * prdhcp.c
+ *
+ * Print the contents of the 3 DHCP packets
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <consoles.h>
+#include <console.h>
+#include <errno.h>
+#include <string.h>
+#include <syslinux/config.h>
+#include <syslinux/loadfile.h>
+#include <syslinux/bootrm.h>
+#include <syslinux/video.h>
+#include <com32.h>
+#include <stdint.h>
+#include <syslinux/pxe.h>
+#include <sys/gpxe.h>
+#include <unistd.h>
+#include <getkey.h>
+
+#define DEBUG 0
+
+#define dprintf0(f, ...) ((void)0)
+
+#ifdef DEBUG
+# define dpressanykey pressanykey
+# define dprintf printf
+# define dprint_pxe_bootp_t print_pxe_bootp_t
+# define dprint_pxe_vendor_blk print_pxe_vendor_blk
+# define dprint_pxe_vendor_raw print_pxe_vendor_raw
+#else
+# define dpressanykey(void) ((void)0)
+# define dprintf(f, ...) ((void)0)
+# define dprint_pxe_bootp_t(p, l) ((void)0)
+# define dprint_pxe_vendor_blk(p, l) ((void)0)
+# define dprint_pxe_vendor_raw(p, l) ((void)0)
+#endif
+
+#define dprintf_opt_cp dprintf0
+#define dprintf_opt_inj dprintf
+
+
+const char app_name_str[] = "prdhcp.c32";
+
+
+int pressanykey(void) {
+ int inc;
+
+ printf("Press any key to continue. ");
+ inc = KEY_NONE;
+ while (inc == KEY_NONE)
+ inc = get_key(stdin, 6000);
+ puts("");
+ return inc;
+}
+
+void print_pxe_vendor_blk(pxe_bootp_t *p, size_t len)
+{
+ int i, vlen, oplen, j;
+ uint8_t *d;
+ uint32_t magic;
+ if (!p) {
+ printf(" packet pointer is null\n");
+ return;
+ }
+ vlen = len - ((void *)&(p->vendor) - (void *)p);
+ printf(" Vendor Data: Len=%d", vlen);
+ d = p->vendor.d;
+ /* Print only 256 characters of the vendor/option data */
+ /*
+ print_pxe_vendor_raw(p, (len - vlen) + 256);
+ vlen = 0;
+ */
+ magic = ntohl(*((uint32_t *)d));
+ printf(" Magic: %08X", ntohl(*((uint32_t *)d)));
+ if (magic != VM_RFC1048) /* Invalid DHCP packet */
+ vlen = 0;
+ for (i = 4; i < vlen; i++) {
+ if (d[i]) /* Skip the padding */
+ printf("\n @%03X-%3d", i, d[i]);
+ if (d[i] == 255) /* End of list */
+ break;
+ if (d[i]) {
+ oplen = d[++i];
+ printf(" l=%3d:", oplen);
+ for (j = (++i + oplen); i < vlen && i < j; i++) {
+ printf(" %02X", d[i]);
+ }
+ i--;
+ }
+ }
+ printf("\n");
+}
+
+void print_pxe_bootp_t(pxe_bootp_t *p, size_t len)
+{
+ if (!p) {
+ printf(" packet pointer is null\n");
+ return;
+ }
+ printf(" op:%02X hw:%02X hl:%02X gh:%02X id:%08X se:%04X f:%04X"
+ " cip:%08X\n", p->opcode, p->Hardware, p->Hardlen, p->Gatehops,
+ ntohl(p->ident), ntohs(p->seconds), ntohs(p->Flags), ntohl(p->cip));
+ printf(" yip:%08X sip:%08X gip:%08X",
+ ntohl(p->yip), ntohl(p->sip), ntohl(p->gip));
+ printf(" caddr-%02X:%02X:%02X:%02X:%02X:%02X\n", p->CAddr[0],
+ p->CAddr[1], p->CAddr[2], p->CAddr[3], p->CAddr[4], p->CAddr[5]);
+ printf(" sName: '%s'\n", p->Sname);
+ printf(" bootfile: '%s'\n", p->bootfile);
+ print_pxe_vendor_blk(p, len);
+}
+
+void print_dhcp_pkt_all(void)
+{
+ pxe_bootp_t *p;
+ size_t len;
+ int i;
+ int ptype[3] = {PXENV_PACKET_TYPE_DHCP_DISCOVER, PXENV_PACKET_TYPE_DHCP_ACK, PXENV_PACKET_TYPE_CACHED_REPLY};
+
+ for (i = 0; i < 3; i++) {
+ if (!pxe_get_cached_info(ptype[i],
+ (void **)&(p), &(len))) {
+ dprintf("Got packet #%d/%d\n", (i + 1), ptype[i]);
+ print_pxe_bootp_t(p, len);
+ pressanykey();
+ }
+ }
+}
+
+int main(void)
+{
+ int rv= -1;
+ const struct syslinux_version *sv;
+
+ console_ansi_raw();
+ sv = syslinux_version();
+ if (sv->filesystem != SYSLINUX_FS_PXELINUX) {
+ printf("%s: May only run in PXELINUX\n", app_name_str);
+ return -2;
+ }
+ print_dhcp_pkt_all();
+ return rv;
+}
diff --git a/com32/modules/pxechn.c b/com32/modules/pxechn.c
new file mode 100644
index 00000000..26376900
--- /dev/null
+++ b/com32/modules/pxechn.c
@@ -0,0 +1,1161 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2010-2012 Gene Cumm - All Rights Reserved
+ *
+ * Portions from chain.c:
+ * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2010 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * pxechn.c
+ *
+ * PXE Chain Loader; Chain load to another PXE network boot program
+ * that may be on another host.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <consoles.h>
+#include <console.h>
+#include <errno.h>
+#include <string.h>
+#include <syslinux/config.h>
+#include <syslinux/loadfile.h>
+#include <syslinux/bootrm.h>
+#include <syslinux/video.h>
+#include <com32.h>
+#include <stdint.h>
+#include <syslinux/pxe.h>
+#include <sys/gpxe.h>
+#include <unistd.h>
+#include <getkey.h>
+#include <dhcp.h>
+#include <limits.h>
+
+
+#ifdef DEBUG
+# define PXECHN_DEBUG 1
+#else
+# define PXECHN_DEBUG 0
+#endif
+
+typedef union {
+ uint64_t q;
+ uint32_t l[2];
+ uint16_t w[4];
+ uint8_t b[8];
+} reg64_t;
+
+#define dprintf0(f, ...) ((void)0)
+
+#ifndef dprintf
+# if (PXECHN_DEBUG > 0)
+# define dprintf printf
+# else
+# define dprintf(f, ...) ((void)0)
+# endif
+#endif
+
+#if (PXECHN_DEBUG > 0)
+# define dpressanykey pressanykey
+# define dprint_pxe_bootp_t print_pxe_bootp_t
+# define dprint_pxe_vendor_blk print_pxe_vendor_blk
+# define dprint_pxe_vendor_raw print_pxe_vendor_raw
+#else
+# define dpressanykey(tm) ((void)0)
+# define dprint_pxe_bootp_t(p, l) ((void)0)
+# define dprint_pxe_vendor_blk(p, l) ((void)0)
+# define dprint_pxe_vendor_raw(p, l) ((void)0)
+#endif
+
+#define dprintf_opt_cp dprintf0
+#define dprintf_opt_inj dprintf0
+#define dprintf_pc_pa dprintf
+#define dprintf_pc_so_s dprintf0
+
+#define t_PXENV_RESTART_TFTP t_PXENV_TFTP_READ_FILE
+
+#define STACK_SPLIT 11
+
+/* same as pxelinux.asm REBOOT_TIME */
+#define REBOOT_TIME 300
+
+#define NUM_DHCP_OPTS 256
+#define DHCP_OPT_LEN_MAX 256
+#define PXE_VENDOR_RAW_PRN_MAX 0x7F
+#define PXECHN_HOST_LEN 256 /* 63 bytes per label; 255 max total */
+
+#define PXECHN_NUM_PKT_TYPE 3
+#define PXECHN_NUM_PKT_AVAIL 2*PXECHN_NUM_PKT_TYPE
+#define PXECHN_PKT_TYPE_START PXENV_PACKET_TYPE_DHCP_DISCOVER
+
+#define PXECHN_FORCE_PKT1 0x80000000
+#define PXECHN_FORCE_PKT2 0x40000000
+#define PXECHN_FORCE_ALL (PXECHN_FORCE_PKT1 | PXECHN_FORCE_PKT2)
+#define PXECHN_FORCE_ALL_1 0
+#define STRASINT_str ('s' + (('t' + ('r' << 8)) << 8))
+
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+
+const char app_name_str[] = "pxechn.c32";
+
+struct pxelinux_opt {
+ char *fn; /* Filename as passed to us */
+ in_addr_t fip; /* fn's IP component */
+ char *fp; /* fn's path component */
+ in_addr_t gip; /* giaddr; Gateway/DHCP relay */
+ uint32_t force;
+ uint32_t wait; /* Additional decision to wait before boot */
+ int32_t wds; /* WDS option/level */
+ in_addr_t sip; /* siaddr: Next Server IP Address */
+ struct dhcp_option p[PXECHN_NUM_PKT_AVAIL];
+ /* original _DHCP_DISCOVER, _DHCP_ACK, _CACHED_REPLY then modified packets */
+ char host[PXECHN_HOST_LEN];
+ struct dhcp_option opts[PXECHN_NUM_PKT_TYPE][NUM_DHCP_OPTS];
+ char p_unpacked[PXECHN_NUM_PKT_TYPE];
+};
+
+
+/* from chain.c */
+struct data_area {
+ void *data;
+ addr_t base;
+ addr_t size;
+};
+
+/* From chain.c */
+static inline void error(const char *msg)
+{
+ fputs(msg, stderr);
+}
+
+/* From chain.c */
+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;
+ 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;
+ }
+
+
+ /* 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, 3, regs);
+ error("Chainboot failed!\n");
+ return;
+
+too_big:
+ error("Loader file too large\n");
+ return;
+
+enomem:
+ error("Out of memory\n");
+ return;
+}
+
+void usage(void)
+{
+ printf("USAGE:\n"
+ " %s [OPTIONS]... _new-nbp_\n"
+ " %s -r _new-nbp_ (calls PXE stack PXENV_RESTART_TFTP)\n"
+ "OPTIONS:\n"
+ " [-c config] [-g gateway] [-p prefix] [-t reboot] [-u] [-w] [-W]"
+ " [-o opt.ty=val]\n\n",
+ app_name_str, app_name_str);
+}
+
+void pxe_error(int ierr, const char *evt, const char *msg)
+{
+ if (msg)
+ printf("%s", msg);
+ else if (evt)
+ printf("Error while %s: ", evt);
+ printf("%d:%s\n", ierr, strerror(ierr));
+}
+
+int pressanykey(clock_t tm) {
+ int inc;
+
+ printf("Press any key to continue. ");
+ inc = get_key(stdin, tm);
+ puts("");
+ return inc;
+}
+
+int dhcp_find_opt(pxe_bootp_t *p, size_t len, uint8_t opt)
+{
+ int rv = -1;
+ int i, vlen, oplen;
+ uint8_t *d;
+ uint32_t magic;
+
+ if (!p) {
+ dprintf(" packet pointer is null\n");
+ return rv;
+ }
+ vlen = len - ((void *)&(p->vendor) - (void *)p);
+ d = p->vendor.d;
+ magic = ntohl(*((uint32_t *)d));
+ if (magic != VM_RFC1048) /* Invalid DHCP packet */
+ vlen = 0;
+ for (i = 4; i < vlen; i++) {
+ if (d[i] == opt) {
+ dprintf("\n @%03X-%2d\n", i, d[i]);
+ rv = i;
+ break;
+ }
+ if (d[i] == ((NUM_DHCP_OPTS) - 1)) /* End of list */
+ break;
+ if (d[i]) { /* Skip padding */
+ oplen = d[++i];
+ i += oplen;
+ }
+ }
+ return rv;
+}
+
+void print_pxe_vendor_raw(pxe_bootp_t *p, size_t len)
+{
+ int i, vlen;
+
+ if (!p) {
+ printf(" packet pointer is null\n");
+ return;
+ }
+ vlen = len - ((void *)&(p->vendor) - (void *)p);
+ if (vlen > PXE_VENDOR_RAW_PRN_MAX)
+ vlen = PXE_VENDOR_RAW_PRN_MAX;
+ dprintf(" rawLen = %d", vlen);
+ for (i = 0; i < vlen; i++) {
+ if ((i & 0xf) == 0)
+ printf("\n %04X:", i);
+ printf(" %02X", p->vendor.d[i]);
+ }
+ printf("\n");
+}
+
+void print_pxe_vendor_blk(pxe_bootp_t *p, size_t len)
+{
+ int i, vlen, oplen, j;
+ uint8_t *d;
+ uint32_t magic;
+ if (!p) {
+ printf(" packet pointer is null\n");
+ return;
+ }
+ vlen = len - ((void *)&(p->vendor) - (void *)p);
+ printf(" Vendor Data: Len=%d", vlen);
+ d = p->vendor.d;
+ magic = ntohl(*((uint32_t *)d));
+ printf(" Magic: %08X", ntohl(*((uint32_t *)d)));
+ if (magic != VM_RFC1048) /* Invalid DHCP packet */
+ vlen = 0;
+ for (i = 4; i < vlen; i++) {
+ if (d[i]) /* Skip the padding */
+ printf("\n @%03X-%3d", i, d[i]);
+ if (d[i] == ((NUM_DHCP_OPTS) - 1)) /* End of list */
+ break;
+ if (d[i]) {
+ oplen = d[++i];
+ printf(" l=%3d:", oplen);
+ for (j = (++i + oplen); i < vlen && i < j; i++) {
+ printf(" %02X", d[i]);
+ }
+ i--;
+ }
+ }
+ printf("\n");
+}
+
+void print_pxe_bootp_t(pxe_bootp_t *p, size_t len)
+{
+ if (!p || len <= 0) {
+ printf(" packet pointer is null\n");
+ return;
+ }
+ printf(" op:%02X hw:%02X hl:%02X gh:%02X id:%08X se:%04X f:%04X"
+ " cip:%08X\n", p->opcode, p->Hardware, p->Hardlen, p->Gatehops,
+ ntohl(p->ident), ntohs(p->seconds), ntohs(p->Flags), ntohl(p->cip));
+ printf(" yip:%08X sip:%08X gip:%08X",
+ ntohl(p->yip), ntohl(p->sip), ntohl(p->gip));
+ printf(" caddr-%02X:%02X:%02X:%02X:%02X:%02X\n", p->CAddr[0],
+ p->CAddr[1], p->CAddr[2], p->CAddr[3], p->CAddr[4], p->CAddr[5]);
+ printf(" sName: '%s'\n", p->Sname);
+ printf(" bootfile: '%s'\n", p->bootfile);
+ dprint_pxe_vendor_blk(p, len);
+}
+
+void pxe_set_regs(struct syslinux_rm_regs *regs)
+{
+ com32sys_t tregs;
+
+ regs->ip = 0x7C00;
+ /* Plan A uses SS:[SP + 4] */
+ /* sdi->pxe.stack is a usable pointer, not something that can be nicely
+ and reliably split to SS:SP without causing issues */
+ tregs.eax.l = 0x000A;
+ __intcall(0x22, &tregs, &tregs);
+ regs->ss = tregs.fs;
+ regs->esp.l = tregs.esi.w[0] + sizeof(tregs);
+ /* Plan B uses [ES:BX] */
+ regs->es = tregs.es;
+ regs->ebx = tregs.ebx;
+ dprintf("\nsp:%04x ss:%04x es:%04x bx:%04x\n", regs->esp.w[0],
+ regs->ss, regs->es, regs->ebx.w[0]);
+ /* Zero out everything else just to be sure */
+ regs->cs = regs->ds = regs->fs = regs->gs = 0;
+ regs->eax.l = regs->ecx.l = regs->edx.l = 0;
+}
+
+int hostlen_limit(int len)
+{
+ return min(len, ((PXECHN_HOST_LEN) - 1));
+}
+
+//FIXME: To a library
+/* Parse a filename into an IPv4 address and filename pointer
+ * returns Based on the interpretation of fn
+ * 0 regular file name
+ * 1 in format IP::FN
+ * 2 TFTP URL
+ * 3 HTTP URL
+ * 4 FTP URL
+ * 3 + 2^30 HTTPS URL
+ * -1 if fn is another URL type
+ */
+int pxechn_parse_fn(char fn[], in_addr_t *fip, char *host, char *fp[])
+{
+ in_addr_t tip = 0;
+ char *csep, *ssep, *hsep; /* Colon, Slash separator positions */
+ int hlen, plen; /* Hostname, protocol length */
+ int rv = 0;
+
+ csep = strchr(fn, ':');
+ if (csep) {
+ if (csep[1] == ':') { /* assume IP::FN */
+ *fp = &csep[2];
+ rv = 1;
+ if (fn[0] != ':') {
+ hlen = hostlen_limit(csep - fn);
+ memcpy(host, fn, hlen);
+ host[hlen] = 0;
+ }
+ } else if ((csep[1] == '/') && (csep[2] == '/')) {
+ /* URL: proto://host:port/path/file */
+ /* proto://[user[:passwd]@]host[:port]/path/file */
+ ssep = strchr(csep + 3, '/');
+ if (ssep) {
+ hlen = hostlen_limit(ssep - (csep + 3));
+ *fp = ssep + 1;
+ } else {
+ hlen = hostlen_limit(strlen(csep + 3));
+ }
+ memcpy(host, (csep + 3), hlen);
+ host[hlen] = 0;
+ plen = csep - fn;
+ if (strncmp(fn, "tftp", plen) == 0)
+ rv = 2;
+ else if (strncmp(fn, "http", plen) == 0)
+ rv = 3;
+ else if (strncmp(fn, "ftp", plen) == 0)
+ rv = 4;
+ else if (strncmp(fn, "https", plen) == 0)
+ rv = 3 + ( 1 << 30 );
+ else
+ rv = -1;
+ } else {
+ csep = NULL;
+ }
+ }
+ if (!csep) {
+ *fp = fn;
+ }
+ if (host[0]) {
+ hsep = strchr(host, '@');
+ if (!hsep)
+ hsep = host;
+ tip = pxe_dns(hsep);
+ }
+ if (tip != 0)
+ *fip = tip;
+ dprintf0(" host '%s'\n fp '%s'\n fip %08x\n", host, *fp, ntohl(*fip));
+ return rv;
+}
+
+void pxechn_opt_free(struct dhcp_option *opt)
+{
+ free(opt->data);
+ opt->len = -1;
+}
+
+void pxechn_fill_pkt(struct pxelinux_opt *pxe, int ptype)
+{
+ int rv = -1;
+ int p1, p2;
+ if ((ptype < 0) || (ptype > PXECHN_NUM_PKT_TYPE))
+ rv = -2;
+ p1 = ptype - PXECHN_PKT_TYPE_START;
+ p2 = p1 + PXECHN_NUM_PKT_TYPE;
+ if ((rv >= -1) && (!pxe_get_cached_info(ptype,
+ (void **)&(pxe->p[p1].data), (size_t *)&(pxe->p[p1].len)))) {
+ pxe->p[p2].data = malloc(2048);
+ if (pxe->p[p2].data) {
+ memcpy(pxe->p[p2].data, pxe->p[p1].data, pxe->p[p1].len);
+ pxe->p[p2].len = pxe->p[p1].len;
+ rv = 0;
+ dprint_pxe_bootp_t((pxe_bootp_t *)(pxe->p[p1].data), pxe->p[p1].len);
+ dpressanykey(INT_MAX);
+ } else {
+ printf("%s: ERROR: Unable to malloc() for second packet\n", app_name_str);
+ }
+ } else {
+ printf("%s: ERROR: Unable to retrieve first packet\n", app_name_str);
+ }
+ if (rv <= -1) {
+ pxechn_opt_free(&pxe->p[p1]);
+ }
+}
+
+void pxechn_init(struct pxelinux_opt *pxe)
+{
+ /* Init for paranoia */
+ pxe->fn = NULL;
+ pxe->fp = NULL;
+ pxe->force = 0;
+ pxe->wait = 0;
+ pxe->gip = 0;
+ pxe->wds = 0;
+ pxe->sip = 0;
+ pxe->host[0] = 0;
+ pxe->host[((NUM_DHCP_OPTS) - 1)] = 0;
+ for (int j = 0; j < PXECHN_NUM_PKT_TYPE; j++){
+ for (int i = 0; i < NUM_DHCP_OPTS; i++) {
+ pxe->opts[j][i].data = NULL;
+ pxe->opts[j][i].len = -1;
+ }
+ pxe->p_unpacked[j] = 0;
+ pxe->p[j].data = NULL;
+ pxe->p[j+PXECHN_NUM_PKT_TYPE].data = NULL;
+ pxe->p[j].len = 0;
+ pxe->p[j+PXECHN_NUM_PKT_TYPE].len = 0;
+ }
+ pxechn_fill_pkt(pxe, PXENV_PACKET_TYPE_CACHED_REPLY);
+}
+
+int pxechn_to_hex(char i)
+{
+ if (i >= '0' && i <= '9')
+ return (i - '0');
+ if (i >= 'A' && i <= 'F')
+ return (i - 'A' + 10);
+ if (i >= 'a' && i <= 'f')
+ return (i - 'a' + 10);
+ if (i == 0)
+ return -1;
+ return -2;
+}
+
+int pxechn_parse_2bhex(char ins[])
+{
+ int ret = -2;
+ int n0 = -3, n1 = -3;
+ /* NULL pointer */
+ if (!ins) {
+ ret = -1;
+ /* pxechn_to_hex can handle the NULL character by returning -1 and
+ breaking the execution of the statement chain */
+ } else if (((n0 = pxechn_to_hex(ins[0])) >= 0)
+ && ((n1 = pxechn_to_hex(ins[1])) >= 0)) {
+ ret = (n0 * 16) + n1;
+ } else if (n0 == -1) { /* Leading NULL char */
+ ret = -1;
+ }
+ return ret;
+}
+
+int pxechn_optnum_ok(int optnum)
+{
+ if ((optnum > 0) && (optnum < ((NUM_DHCP_OPTS) - 1)))
+ return 1;
+ return 0;
+}
+
+int pxechn_optnum_ok_notres(int optnum)
+{
+ if ((optnum <= 0) && (optnum >= ((NUM_DHCP_OPTS) - 1)))
+ return 0;
+ switch(optnum){
+ case 66: case 67:
+ return 0;
+ break;
+ default: return 1;
+ }
+}
+
+int pxechn_optlen_ok(int optlen)
+{
+ if ((optlen >= 0) && (optlen < ((DHCP_OPT_LEN_MAX) - 1)))
+ return 1;
+ return 0;
+}
+
+int pxechn_setopt(struct dhcp_option *opt, void *data, int len)
+{
+ void *p;
+ if (!opt || !data)
+ return -1;
+ if (len < 0) {
+ return -3;
+ }
+ p = realloc(opt->data, len);
+ if (!p && len) { /* Allow for len=0 */
+ pxechn_opt_free(opt);
+ return -2;
+ }
+ opt->data = p;
+ memcpy(opt->data, data, len);
+ opt->len = len;
+ return len;
+}
+
+int pxechn_setopt_str(struct dhcp_option *opt, void *data)
+{
+ return pxechn_setopt(opt, data, strnlen(data, DHCP_OPT_LEN_MAX));
+}
+
+int pxechn_parse_int(char *data, char istr[], int tlen)
+{
+ int terr = errno;
+
+ if ((tlen == 1) || (tlen == 2) || (tlen == 4)) {
+ errno = 0;
+ uint32_t optval = strtoul(istr, NULL, 0);
+ if (errno)
+ return -3;
+ errno = terr;
+ switch(tlen){
+ case 1:
+ if (optval & 0xFFFFFF00)
+ return -4;
+ break;
+ case 2:
+ if (optval & 0xFFFF0000)
+ return -4;
+ optval = htons(optval);
+ break;
+ case 4:
+ optval = htonl(optval);
+ break;
+ }
+ memcpy(data, &optval, tlen);
+ } else if (tlen == 8) {
+ errno = 0;
+ uint64_t optval = strtoull(istr, NULL, 0);
+ if (errno)
+ return -3;
+ errno = terr;
+ optval = htonq(optval);
+ memcpy(data, &optval, tlen);
+ } else {
+ return -2;
+ }
+ return tlen;
+}
+
+int pxechn_parse_hex_sep(char *data, char istr[], char sep)
+{
+ int len = 0;
+ int ipos = 0, ichar;
+
+ if (!data || !istr)
+ return -1;
+ while ((istr[ipos]) && (len < DHCP_OPT_LEN_MAX)) {
+ dprintf(" %02X%02X", *((int *)(istr + ipos)) & 0xFF, *((int *)(istr + ipos +1)) & 0xFF);
+ ichar = pxechn_parse_2bhex(istr + ipos);
+ if (ichar >=0) {
+ data[len++] = ichar;
+ } else {
+ return -EINVAL;
+ }
+ if (!istr[ipos+2]){
+ ipos += 2;
+ } else if (istr[ipos+2] != sep) {
+ return -(EINVAL + 1);
+ } else {
+ ipos += 3;
+ }
+ }
+ return len;
+}
+
+int pxechn_parse_opttype(char istr[], int optnum)
+{
+ char *pos;
+ int tlen, type, tmask;
+
+ if (!istr)
+ return -1;
+ pos = strchr(istr, '=');
+ if (!pos)
+ return -2;
+ if (istr[0] != '.') {
+ if (!pxechn_optnum_ok(optnum))
+ return -3;
+ return -3; /* do lookup here */
+ } else {
+ tlen = pos - istr - 1;
+ if ((tlen < 1) || (tlen > 4))
+ return -4;
+ tmask = 0xFFFFFFFF >> (8 * (4 - tlen));
+ type = (*(int*)(istr + 1)) & tmask;
+ }
+ return type;
+}
+
+int pxechn_parse_setopt(struct dhcp_option opts[], struct dhcp_option *iopt,
+ char istr[])
+{
+ int rv = 0, optnum, opttype;
+ char *cpos = NULL, *pos;
+
+ if (!opts || !iopt || !(iopt->data))
+ return -1;
+ if (!istr || !istr[0])
+ return -2;
+ // -EINVAL;
+ optnum = strtoul(istr, &cpos, 0);
+ if (!pxechn_optnum_ok(optnum))
+ return -3;
+ pos = strchr(cpos, '=');
+ if (!pos)
+ return -4;
+ opttype = pxechn_parse_opttype(cpos, optnum);
+ pos++;
+ switch(opttype) {
+ case 'b':
+ iopt->len = pxechn_parse_int(iopt->data, pos, 1);
+ break;
+ case 'l':
+ iopt->len = pxechn_parse_int(iopt->data, pos, 4);
+ break;
+ case 'q':
+ iopt->len = pxechn_parse_int(iopt->data, pos, 8);
+ break;
+ case 's':
+ case STRASINT_str:
+ iopt->len = strlen(pos);
+ if (iopt->len > DHCP_OPT_LEN_MAX)
+ iopt->len = DHCP_OPT_LEN_MAX;
+ memcpy(iopt->data, pos, iopt->len);
+ dprintf_pc_so_s("s.len=%d\trv=%d\n", iopt->len, rv);
+ break;
+ case 'w':
+ iopt->len = pxechn_parse_int(iopt->data, pos, 2);
+ break;
+ case 'x':
+ iopt->len = pxechn_parse_hex_sep(iopt->data, pos, ':');
+ break;
+ default:
+ return -6;
+ break;
+ }
+ if (pxechn_optlen_ok(iopt->len)) {
+ rv = pxechn_setopt(&(opts[optnum]), (void *)(iopt->data), iopt->len);
+ }
+ if((opttype == 's') || (opttype == STRASINT_str))
+ dprintf_pc_so_s("rv=%d\n", rv);
+ return rv;
+}
+
+int pxechn_parse_force(const char istr[])
+{
+ uint32_t rv = 0;
+ char *pos;
+ int terr = errno;
+
+ errno = 0;
+ rv = strtoul(istr, &pos, 0);
+ if ((istr == pos ) || ((rv == ULONG_MAX) && (errno)))
+ rv = 0;
+ errno = terr;
+ return rv;
+}
+
+int pxechn_uuid_set(struct pxelinux_opt *pxe)
+{
+ int ret = 0;
+
+ if (!pxe->p_unpacked[0])
+ ret = dhcp_unpack_packet((pxe_bootp_t *)(pxe->p[0].data),
+ pxe->p[0].len, pxe->opts[0]);
+ if (ret) {
+ error("Could not unpack packet\n");
+ return -ret; /* dhcp_unpack_packet always returns positive errors */
+ }
+
+ if (pxe->opts[0][97].len >= 0 )
+ pxechn_setopt(&(pxe->opts[2][97]), pxe->opts[0][97].data, pxe->opts[0][97].len);
+ return 1;
+ return 0;
+}
+
+int pxechn_parse_args(int argc, char *argv[], struct pxelinux_opt *pxe,
+ struct dhcp_option opts[])
+{
+ int arg, optnum, rv = 0;
+ char *p = NULL;
+ const char optstr[] = "c:f:g:o:p:St:uwW";
+ struct dhcp_option iopt;
+
+ if (pxe->p[5].data)
+ pxe->fip = ( (pxe_bootp_t *)(pxe->p[5].data) )->sip;
+ else
+ pxe->fip = 0;
+ /* Fill */
+ pxe->fn = argv[0];
+ pxechn_parse_fn(pxe->fn, &(pxe->fip), pxe->host, &(pxe->fp));
+ pxechn_setopt_str(&(opts[67]), pxe->fp);
+ pxechn_setopt_str(&(opts[66]), pxe->host);
+ iopt.data = malloc(DHCP_OPT_LEN_MAX);
+ iopt.len = 0;
+ while ((rv >= 0) && (arg = getopt(argc, argv, optstr)) >= 0) {
+ dprintf_pc_pa(" Got arg '%c'/'%c' addr %08X val %s\n", arg == '?' ? optopt : arg, arg, (unsigned int)optarg, optarg ? optarg : "");
+ switch(arg) {
+ case 'c': /* config */
+ pxechn_setopt_str(&(opts[209]), optarg);
+ break;
+ case 'f': /* force */
+ pxe->force = pxechn_parse_force(optarg);
+ break;
+ case 'g': /* gateway/DHCP relay */
+ pxe->gip = pxe_dns(optarg);
+ break;
+ case 'n': /* native */
+ break;
+ case 'o': /* option */
+ rv = pxechn_parse_setopt(opts, &iopt, optarg);
+ break;
+ case 'p': /* prefix */
+ pxechn_setopt_str(&(opts[210]), optarg);
+ break;
+ case 'S': /* sip from sName */
+ pxe->sip = 1;
+ break;
+ case 't': /* timeout */
+ optnum = strtoul(optarg, &p, 0);
+ if (p != optarg) {
+ optnum = htonl(optnum);
+ pxechn_setopt(&(opts[211]), (void *)(&optnum), 4);
+ } else {
+ rv = -3;
+ }
+ break;
+ case 'u': /* UUID: copy option 97 from packet 1 if present */
+ pxechn_uuid_set(pxe);
+ break;
+ case 'w': /* wait */
+ pxe->wait = 1;
+ break;
+ case 'W': /* WDS */
+ pxe->wds = 1;
+ break;
+ case '?':
+ rv = -'?';
+ default:
+ break;
+ }
+ if (rv >= 0) /* Clear it since getopt() doesn't guarentee it */
+ optarg = NULL;
+ }
+ if (iopt.data)
+ pxechn_opt_free(&iopt);
+/* FIXME: consider reordering the application of parsed command line options
+ such that the new nbp may be at the end */
+ if (rv >= 0) {
+ rv = 0;
+ } else if (arg != '?') {
+ printf("Invalid argument for -%c: %s\n", arg, optarg);
+ }
+ dprintf("pxechn_parse_args rv=%d\n", rv);
+ return rv;
+}
+
+int pxechn_args(int argc, char *argv[], struct pxelinux_opt *pxe)
+{
+ pxe_bootp_t *bootp0, *bootp1;
+ int ret = 0;
+ struct dhcp_option *opts;
+ char *str;
+
+ opts = pxe->opts[2];
+ /* Start filling packet #1 */
+ bootp0 = (pxe_bootp_t *)(pxe->p[2].data);
+ bootp1 = (pxe_bootp_t *)(pxe->p[5].data);
+
+ ret = dhcp_unpack_packet(bootp0, pxe->p[2].len, opts);
+ if (ret) {
+ error("Could not unpack packet\n");
+ return -ret;
+ }
+ pxe->p_unpacked[2] = 1;
+ pxe->gip = bootp1->gip;
+
+ ret = pxechn_parse_args(argc, argv, pxe, opts);
+ if (ret)
+ return ret;
+ if (pxe->sip > 0xFFFFFF) { /* a real IPv4 address */
+ bootp1->sip = pxe->sip;
+ } else if ((pxe->sip == 1)
+ && (opts[66].len > 0)){
+ /* unterminated? */
+ if (strnlen(opts[66].data, opts[66].len) == (size_t)opts[66].len) {
+ str = malloc(opts[66].len + 1);
+ if (str) {
+ memcpy(str, opts[66].data, opts[66].len);
+ str[opts[66].len] = 0;
+ }
+ } else {
+ str = opts[66].data;
+ }
+ if (str) {
+ bootp1->sip = pxe_dns(str);
+ if (str != opts[66].data)
+ free(str);
+ } else {
+ bootp1->sip = pxe->fip;
+ }
+ } else {
+ bootp1->sip = pxe->fip;
+ }
+ bootp1->gip = pxe->gip;
+
+ ret = dhcp_pack_packet(bootp1, (size_t *)&(pxe->p[5].len), opts);
+ if (ret) {
+ error("Could not pack packet\n");
+ return -ret; /* dhcp_pack_packet always returns positive errors */
+ }
+ return ret;
+}
+
+/* dhcp_pkt2pxe: Copy packet to PXE's BC data for a ptype packet
+ * Input:
+ * p Packet data to copy
+ * len length of data to copy
+ * ptype Packet type to overwrite
+ */
+int dhcp_pkt2pxe(pxe_bootp_t *p, size_t len, int ptype)
+{
+ com32sys_t reg;
+ t_PXENV_GET_CACHED_INFO *ci;
+ void *cp;
+ int rv = -1;
+
+ if (!(ci = lzalloc(sizeof(t_PXENV_GET_CACHED_INFO)))){
+ dprintf("Unable to lzalloc() for PXE call structure\n");
+ rv = 1;
+ goto ret;
+ }
+ ci->Status = PXENV_STATUS_FAILURE;
+ ci->PacketType = ptype;
+ memset(&reg, 0, sizeof(reg));
+ reg.eax.w[0] = 0x0009;
+ reg.ebx.w[0] = PXENV_GET_CACHED_INFO;
+ reg.edi.w[0] = OFFS(ci);
+ reg.es = SEG(ci);
+ __intcall(0x22, &reg, &reg);
+
+ if (ci->Status != PXENV_STATUS_SUCCESS) {
+ dprintf("PXE Get Cached Info failed: %d\n", ci->Status);
+ rv = 2;
+ goto ret;
+ }
+
+ cp = MK_PTR(ci->Buffer.seg, ci->Buffer.offs);
+ if (!(memcpy(cp, p, len))) {
+ dprintf("Failed to copy packet\n");
+ rv = 3;
+ goto ret;
+ }
+ret:
+ lfree(ci);
+ return rv;
+}
+
+int pxechn_mergeopt(struct pxelinux_opt *pxe, int d, int s)
+{
+ int ret = 0, i;
+
+ if ((d >= PXECHN_NUM_PKT_TYPE) || (s >= PXECHN_NUM_PKT_TYPE)
+ || (d < 0) || (s < 0)) {
+ return -2;
+ }
+ if (!pxe->p_unpacked[s])
+ ret = dhcp_unpack_packet(pxe->p[s].data, pxe->p[s].len, pxe->opts[s]);
+ if (ret) {
+ error("Could not unpack packet for merge\n");
+ printf("Error %d (%d)\n", ret, EINVAL);
+ if (ret == EINVAL) {
+ if (pxe->p[s].len < 240)
+ printf("Packet %d is too short: %d (240)\n", s, pxe->p[s].len);
+ else if (((const struct dhcp_packet *)(pxe->p[s].data))->magic != htonl(DHCP_VENDOR_MAGIC))
+ printf("Packet %d has no magic\n", s);
+ else
+ error("Unknown EINVAL error\n");
+ } else {
+ error("Unknown error\n");
+ }
+ return -ret;
+ }
+ for (i = 0; i < NUM_DHCP_OPTS; i++) {
+ if (pxe->opts[d][i].len <= -1) {
+ if (pxe->opts[s][i].len >= 0)
+ pxechn_setopt(&(pxe->opts[d][i]), pxe->opts[s][i].data, pxe->opts[s][i].len);
+ }
+ }
+ return 0;
+}
+
+/* pxechn: Chainload to new PXE file ourselves
+ * Input:
+ * argc Count of arguments passed
+ * argv Values of arguments passed
+ * Returns 0 on success (which should never happen)
+ * 1 on loadfile() error
+ * 2 if DHCP Option 52 (Option Overload) used file field
+ * -1 on usage error
+ */
+int pxechn(int argc, char *argv[])
+{
+ struct pxelinux_opt pxe;
+ pxe_bootp_t* p[(2 * PXECHN_NUM_PKT_TYPE)];
+ int rv = 0;
+ int i;
+ struct data_area file;
+ struct syslinux_rm_regs regs;
+
+ pxechn_init(&pxe);
+ for (i = 0; i < (2 * PXECHN_NUM_PKT_TYPE); i++) {
+ p[i] = (pxe_bootp_t *)(pxe.p[i].data);
+ }
+
+ /* Parse arguments and patch packet 1 */
+ rv = pxechn_args(argc, argv, &pxe);
+ dpressanykey(INT_MAX);
+ if (rv)
+ goto ret;
+ pxe_set_regs(&regs);
+ /* Load the file late; it's the most time-expensive operation */
+ printf("%s: Attempting to load '%s': ", app_name_str, pxe.fn);
+ if (loadfile(pxe.fn, &file.data, &file.size)) {
+ pxe_error(errno, NULL, NULL);
+ rv = -2;
+ goto ret;
+ }
+ puts("loaded.");
+ /* we'll be shuffling to the standard location of 7C00h */
+ file.base = 0x7C00;
+ if ((pxe.wds) ||
+ ((pxe.force) && ((pxe.force & (~PXECHN_FORCE_ALL)) == 0))) {
+ printf("Forcing behavior %08X\n", pxe.force);
+ // P2 is the same as P3 if no PXE server present.
+ if ((pxe.wds) ||
+ (pxe.force & PXECHN_FORCE_PKT2)) {
+ pxechn_fill_pkt(&pxe, PXENV_PACKET_TYPE_DHCP_ACK);
+ rv = pxechn_mergeopt(&pxe, 2, 1);
+ if (rv) {
+ dprintf("Merge Option returned %d\n", rv);
+ }
+ rv = dhcp_pack_packet(p[5], (size_t *)&(pxe.p[5].len), pxe.opts[2]);
+ rv = dhcp_pkt2pxe(p[5], pxe.p[5].len, PXENV_PACKET_TYPE_DHCP_ACK);
+ }
+ if (pxe.force & PXECHN_FORCE_PKT1) {
+ puts("Unimplemented force option utilized");
+ }
+ }
+ rv = dhcp_pkt2pxe(p[5], pxe.p[5].len, PXENV_PACKET_TYPE_CACHED_REPLY);
+ dprint_pxe_bootp_t(p[5], pxe.p[5].len);
+ if ((pxe.wds) ||
+ ((pxe.force) && ((pxe.force & (~PXECHN_FORCE_ALL)) == 0))) {
+ // printf("Forcing behavior %08X\n", pxe.force);
+ // P2 is the same as P3 if no PXE server present.
+ if ((pxe.wds) ||
+ (pxe.force & PXECHN_FORCE_PKT2)) {
+ rv = dhcp_pkt2pxe(p[5], pxe.p[5].len, PXENV_PACKET_TYPE_DHCP_ACK);
+ }
+ } else if (pxe.force) {
+ printf("FORCE: bad argument %08X\n", pxe.force);
+ }
+ printf("\n...Ready to boot:\n");
+ if (pxe.wait) {
+ pressanykey(INT_MAX);
+ } else {
+ dpressanykey(INT_MAX);
+ }
+ if (true) {
+ puts(" Attempting to boot...");
+ do_boot(&file, 1, &regs);
+ }
+ /* If failed, copy backup back in and abort */
+ dhcp_pkt2pxe(p[2], pxe.p[2].len, PXENV_PACKET_TYPE_CACHED_REPLY);
+ if (pxe.force && ((pxe.force & (~PXECHN_FORCE_ALL)) == 0)) {
+ if (pxe.force & PXECHN_FORCE_PKT2) {
+ rv = dhcp_pkt2pxe(p[1], pxe.p[1].len, PXENV_PACKET_TYPE_DHCP_ACK);
+ }
+ }
+ret:
+ return rv;
+}
+
+/* pxe_restart: Restart the PXE environment with a new PXE file
+ * Input:
+ * ifn Name of file to chainload to in a format PXELINUX understands
+ * This must strictly be TFTP or relative file
+ */
+int pxe_restart(char *ifn)
+{
+ int rv = 0;
+ struct pxelinux_opt pxe;
+ com32sys_t reg;
+ t_PXENV_RESTART_TFTP *pxep; /* PXENV callback Parameter */
+
+ pxe.fn = ifn;
+ pxechn_fill_pkt(&pxe, PXENV_PACKET_TYPE_CACHED_REPLY);
+ if (pxe.p[5].data)
+ pxe.fip = ( (pxe_bootp_t *)(pxe.p[5].data) )->sip;
+ else
+ pxe.fip = 0;
+ rv = pxechn_parse_fn(pxe.fn, &(pxe.fip), pxe.host, &(pxe.fp));
+ if ((rv > 2) || (rv < 0)) {
+ printf("%s: ERROR: Unparsable filename argument: '%s'\n\n", app_name_str, pxe.fn);
+ goto ret;
+ }
+ printf(" Attempting to boot '%s'...\n\n", pxe.fn);
+ memset(&reg, 0, sizeof reg);
+ if (sizeof(t_PXENV_TFTP_READ_FILE) <= __com32.cs_bounce_size) {
+ pxep = __com32.cs_bounce;
+ memset(pxep, 0, sizeof(t_PXENV_RESTART_TFTP));
+ } else if (!(pxep = lzalloc(sizeof(t_PXENV_RESTART_TFTP)))){
+ dprintf("Unable to lzalloc() for PXE call structure\n");
+ goto ret;
+ }
+ pxep->Status = PXENV_STATUS_SUCCESS; /* PXENV_STATUS_FAILURE */
+ strcpy((char *)pxep->FileName, ifn);
+ pxep->BufferSize = 0x8000;
+ pxep->Buffer = (void *)0x7c00;
+ pxep->ServerIPAddress = pxe.fip;
+ dprintf("FN='%s' %08X %08X %08X %08X\n\n", (char *)pxep->FileName,
+ pxep->ServerIPAddress, (unsigned int)pxep,
+ pxep->BufferSize, (unsigned int)pxep->Buffer);
+ dprintf("PXENV_RESTART_TFTP status %d\n", pxep->Status);
+ reg.eax.w[0] = 0x0009;
+ reg.ebx.w[0] = PXENV_RESTART_TFTP;
+ reg.edi.w[0] = OFFS(pxep);
+ reg.es = SEG(pxep);
+
+ __intcall(0x22, &reg, &reg);
+
+ printf("PXENV_RESTART_TFTP returned %d\n", pxep->Status);
+ if (pxep != __com32.cs_bounce)
+ lfree(pxep);
+
+ret:
+ return rv;
+}
+
+/* pxechn_gpxe: Use gPXE to chainload a new NBP
+ * Input:
+ * argc Count of arguments passed
+ * argv Values of arguments passed
+ * Returns 0 on success (which should never happen)
+ * 1 on loadfile() error
+ * -1 on usage error
+ */
+//FIXME:Implement
+int pxechn_gpxe(int argc, char *argv[])
+{
+ int rv = 0;
+ struct pxelinux_opt pxe;
+
+ if (argc) {
+ printf("%s\n", argv[0]);
+ pxechn_args(argc, argv, &pxe);
+ }
+ return rv;
+}
+
+int main(int argc, char *argv[])
+{
+ int rv= -1;
+ int err;
+ const struct syslinux_version *sv;
+
+ /* Initialization */
+ err = errno;
+ console_ansi_raw(); /* sets errno = 9 (EBADF) */
+ /* printf("%d %d\n", err, errno); */
+ errno = err;
+ sv = syslinux_version();
+ if (sv->filesystem != SYSLINUX_FS_PXELINUX) {
+ printf("%s: May only run in PXELINUX\n", app_name_str);
+ argc = 1; /* prevents further processing to boot */
+ }
+ if (argc == 2) {
+ if ((strcasecmp(argv[1], "-h") == 0) || ((strcmp(argv[1], "-?") == 0))
+ || (strcasecmp(argv[1], "--help") == 0)) {
+ argc = 1;
+ } else {
+ rv = pxechn(argc - 1, &argv[1]);
+ }
+ } else if (argc >= 3) {
+ if ((strcmp(argv[1], "-r") == 0)) {
+ if (argc == 3)
+ rv = pxe_restart(argv[2]);
+ } else {
+ rv = pxechn(argc - 1, &argv[1]);
+ }
+ }
+ if (rv <= -1 ) {
+ usage();
+ rv = 1;
+ }
+ return rv;
+}
diff --git a/com32/modules/zzjson.c b/com32/modules/zzjson.c
new file mode 100644
index 00000000..e2516fa1
--- /dev/null
+++ b/com32/modules/zzjson.c
@@ -0,0 +1,101 @@
+/*
+ * Display directory contents
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <console.h>
+#include <string.h>
+#include <com32.h>
+#include <zzjson/zzjson.h>
+#include <stdarg.h>
+
+static void myerror(void *ehandle, const char *format, ...) {
+ va_list ap;
+ fprintf(ehandle, "error: ");
+ va_start(ap, format);
+ vfprintf(ehandle, format, ap);
+ va_end(ap);
+ fputc('\n', ehandle);
+}
+
+
+int main(int argc, char *argv[])
+{
+ openconsole(&dev_rawcon_r, &dev_stdcon_w);
+ (void) argc;
+ (void) argv;
+ ZZJSON *tmp;
+ ZZJSON_CONFIG config = { ZZJSON_VERY_STRICT, NULL,
+ (int(*)(void*)) fgetc,
+ NULL,
+ malloc, calloc, free, realloc,
+ stderr, myerror, stdout,
+ (int(*)(void*,const char*,...)) fprintf,
+ (int(*)(int,void*)) fputc };
+
+ do {
+ ZZJSON *tmp2;
+
+ tmp = zzjson_create_array(&config,
+ zzjson_create_number_d(&config, 3.14),
+ zzjson_create_number_i(&config, 1234LL),
+ zzjson_create_number_i(&config, -4321LL),
+ zzjson_create_true(&config),
+ zzjson_create_false(&config),
+ zzjson_create_null(&config),
+ zzjson_create_string(&config, "hello, world"),
+ zzjson_create_object(&config,
+ "picard", zzjson_create_string(&config, "jean-luc"),
+ "riker", zzjson_create_string(&config, "william t."),
+ NULL),
+ zzjson_create_object(&config, NULL),
+ zzjson_create_array(&config, NULL),
+ NULL );
+
+ if (!tmp) {
+ fprintf(stderr, "error during creation of json tree\n");
+ break;
+ }
+
+ tmp2 = zzjson_array_prepend(&config, tmp,
+ zzjson_create_string(&config, "prepended string"));
+
+ if (!tmp2) {
+ fprintf(stderr, "error during prepend\n");
+ break;
+ }
+ tmp = tmp2;
+
+ tmp2 = zzjson_array_append(&config, tmp,
+ zzjson_create_string(&config, "appended string (slow)"));
+
+ if (!tmp2) {
+ fprintf(stderr, "error during append\n");
+ break;
+ }
+ tmp = tmp2;
+
+ zzjson_print(&config, tmp);
+ } while(0);
+ if (tmp) zzjson_free(&config, tmp);
+
+ {
+ tmp = zzjson_create_array(&config, NULL); /* empty array */
+ tmp = zzjson_array_prepend(&config, tmp, zzjson_create_true(&config));
+ zzjson_print(&config, tmp);
+ zzjson_free(&config, tmp);
+ }
+
+ {
+ tmp = zzjson_create_object(&config, NULL); /* empty object */
+ tmp = zzjson_object_prepend(&config, tmp, "hello",
+ zzjson_create_string(&config, "world"));
+ tmp = zzjson_object_append(&config, tmp, "goodbye",
+ zzjson_create_string(&config, "cruel world"));
+ zzjson_print(&config, tmp);
+ zzjson_free(&config, tmp);
+ }
+
+ return 0;
+}
+
diff --git a/com32/rosh/Makefile b/com32/rosh/Makefile
index f4b7d866..766f68d5 100644
--- a/com32/rosh/Makefile
+++ b/com32/rosh/Makefile
@@ -17,7 +17,8 @@
##
topdir = ../..
-include MCONFIG
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/rosh.mk
# from com32/sysdump/Makefile
# The DATE is set on the make command line when building binaries for
diff --git a/com32/samples/Makefile b/com32/samples/Makefile
index bee2b992..76986d59 100644
--- a/com32/samples/Makefile
+++ b/com32/samples/Makefile
@@ -15,7 +15,8 @@
##
topdir = ../..
-include ../MCONFIG
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/com32.mk
all: hello.c32 resolv.c32 serialinfo.c32 \
localboot.c32 \
diff --git a/com32/sysdump/Makefile b/com32/sysdump/Makefile
index bffee3a2..98e7f15a 100644
--- a/com32/sysdump/Makefile
+++ b/com32/sysdump/Makefile
@@ -16,12 +16,15 @@
##
topdir = ../..
-include ../MCONFIG
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/com32.mk
-include $(topdir)/version.mk
-LIBS = ../libutil/libutil_com.a ../lib/libcom32.a $(LIBGCC)
+LIBS = ../libupload/libcom32upload.a
LNXLIBS = ../libutil/libutil_lnx.a
+CFLAGS += -I$(com32) -I$(topdir)
+
MODULES = sysdump.c32
TESTFILES =
diff --git a/com32/sysdump/acpi.c b/com32/sysdump/acpi.c
index 8671fc8a..50222335 100644
--- a/com32/sysdump/acpi.c
+++ b/com32/sysdump/acpi.c
@@ -18,7 +18,6 @@
#include <string.h>
#include <stdlib.h>
#include "sysdump.h"
-#include "backend.h"
#include "rbtree.h"
struct acpi_rsdp {
@@ -151,7 +150,7 @@ static const struct acpi_rsdp *find_rsdp(void)
return scan_for_rsdp(0xe0000, 0x100000);
}
-static void dump_table(struct backend *be,
+static void dump_table(struct upload_backend *be,
const char name[], const void *ptr, uint32_t len)
{
char namebuf[64];
@@ -171,7 +170,7 @@ static void dump_table(struct backend *be,
write_data(be, ptr, len);
}
-static void dump_rsdt(struct backend *be, const struct acpi_rsdp *rsdp)
+static void dump_rsdt(struct upload_backend *be, const struct acpi_rsdp *rsdp)
{
const struct acpi_rsdt *rsdt;
uint32_t i, n;
@@ -196,7 +195,7 @@ static void dump_rsdt(struct backend *be, const struct acpi_rsdp *rsdp)
}
}
-static void dump_xsdt(struct backend *be, const struct acpi_rsdp *rsdp)
+static void dump_xsdt(struct upload_backend *be, const struct acpi_rsdp *rsdp)
{
const struct acpi_xsdt *xsdt;
uint32_t rsdp_len = rsdp->rev > 0 ? rsdp->len : 20;
@@ -231,7 +230,7 @@ static void dump_xsdt(struct backend *be, const struct acpi_rsdp *rsdp)
}
}
-void dump_acpi(struct backend *be)
+void dump_acpi(struct upload_backend *be)
{
const struct acpi_rsdp *rsdp;
uint32_t rsdp_len;
diff --git a/com32/sysdump/backend.h b/com32/sysdump/backend.h
deleted file mode 100644
index f2b3bc25..00000000
--- a/com32/sysdump/backend.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef BACKEND_H
-#define BACKEND_H
-
-#include <stddef.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <zlib.h>
-#include "serial.h"
-
-/* Backend flags */
-#define BE_NEEDLEN 0x01
-
-struct backend {
- const char *name;
- const char *helpmsg;
- int minargs;
-
- size_t dbytes;
- size_t zbytes;
- const char **argv;
-
- uint32_t now;
-
- int (*write)(struct backend *);
-
- z_stream zstream;
- char *outbuf;
- size_t alloc;
-};
-
-/* zout.c */
-int init_data(struct backend *be, const char *argv[]);
-int write_data(struct backend *be, const void *buf, size_t len);
-int flush_data(struct backend *be);
-
-/* cpio.c */
-#define cpio_init init_data
-int cpio_hdr(struct backend *be, uint32_t mode, size_t datalen,
- const char *filename);
-int cpio_mkdir(struct backend *be, const char *filename);
-int cpio_writefile(struct backend *be, const char *filename,
- const void *data, size_t len);
-int cpio_close(struct backend *be);
-#define MODE_FILE 0100644
-#define MODE_DIR 0040755
-
-/* backends.c */
-struct backend *get_backend(const char *name);
-
-/* backends */
-extern struct backend be_tftp;
-extern struct backend be_ymodem;
-extern struct backend be_srec;
-
-#endif /* BACKEND_H */
diff --git a/com32/sysdump/cpuid.c b/com32/sysdump/cpuid.c
index 372a70db..e7fc5767 100644
--- a/com32/sysdump/cpuid.c
+++ b/com32/sysdump/cpuid.c
@@ -8,7 +8,6 @@
#include <com32.h>
#include <sys/cpu.h>
#include "sysdump.h"
-#include "backend.h"
struct cpuid_data {
uint32_t eax, ebx, ecx, edx;
@@ -29,7 +28,7 @@ static void get_cpuid(uint32_t eax, uint32_t ecx, struct cpuid_data *data)
#define CPUID_CHUNK 128
-void dump_cpuid(struct backend *be)
+void dump_cpuid(struct upload_backend *be)
{
struct cpuid_info *buf = NULL;
int nentry, nalloc;
diff --git a/com32/sysdump/data.h b/com32/sysdump/data.h
deleted file mode 100644
index deacf721..00000000
--- a/com32/sysdump/data.h
+++ /dev/null
@@ -1,2 +0,0 @@
-#ifndef DATA_H
-#define DATA_H
diff --git a/com32/sysdump/dmi.c b/com32/sysdump/dmi.c
index be4cce46..ce25efa4 100644
--- a/com32/sysdump/dmi.c
+++ b/com32/sysdump/dmi.c
@@ -6,7 +6,6 @@
#include <string.h>
#include <stdlib.h>
#include "sysdump.h"
-#include "backend.h"
struct dmi_header {
char signature[5];
@@ -60,7 +59,7 @@ static bool is_smbios(size_t dptr)
is_old_dmi(dptr+16);
}
-static void dump_smbios(struct backend *be, size_t dptr)
+static void dump_smbios(struct upload_backend *be, size_t dptr)
{
const struct smbios_header *smb = (void *)dptr;
struct smbios_header smx = *smb;
@@ -82,7 +81,7 @@ static void dump_smbios(struct backend *be, size_t dptr)
write_data(be, (const void *)smb->dmi.tbladdr, smb->dmi.tbllen);
}
-static void dump_old_dmi(struct backend *be, size_t dptr)
+static void dump_old_dmi(struct upload_backend *be, size_t dptr)
{
const struct dmi_header *dmi = (void *)dptr;
struct fake {
@@ -108,7 +107,7 @@ static void dump_old_dmi(struct backend *be, size_t dptr)
write_data(be, (const void *)dmi->tbladdr, dmi->tbllen);
}
-void dump_dmi(struct backend *be)
+void dump_dmi(struct upload_backend *be)
{
size_t dptr;
diff --git a/com32/sysdump/main.c b/com32/sysdump/main.c
index d0d40a7b..f672585d 100644
--- a/com32/sysdump/main.c
+++ b/com32/sysdump/main.c
@@ -19,8 +19,7 @@
#include <dprintf.h>
#include <console.h>
#include <sys/cpu.h>
-#include "../../version.h"
-#include "backend.h"
+#include <version.h>
#include "sysdump.h"
const char program[] = "sysdump";
@@ -32,7 +31,7 @@ __noreturn die(const char *msg)
exit(1);
}
-static void dump_all(struct backend *be, const char *argv[])
+static void dump_all(struct upload_backend *be, const char *argv[])
{
cpio_init(be, argv);
@@ -50,20 +49,20 @@ static void dump_all(struct backend *be, const char *argv[])
flush_data(be);
}
-static struct backend *backends[] =
+static struct upload_backend *upload_backends[] =
{
- &be_tftp,
- &be_ymodem,
- &be_srec,
+ &upload_tftp,
+ &upload_ymodem,
+ &upload_srec,
NULL
};
__noreturn usage(void)
{
- struct backend **bep, *be;
+ struct upload_backend **bep, *be;
printf("Usage:\n");
- for (bep = backends ; (be = *bep) ; bep++)
+ for (bep = upload_backends ; (be = *bep) ; bep++)
printf(" %s %s %s\n", program, be->name, be->helpmsg);
exit(1);
@@ -71,7 +70,7 @@ __noreturn usage(void)
int main(int argc, char *argv[])
{
- struct backend **bep, *be;
+ struct upload_backend **bep, *be;
openconsole(&dev_null_r, &dev_stdcon_w);
fputs(version, stdout);
@@ -79,7 +78,7 @@ int main(int argc, char *argv[])
if (argc < 2)
usage();
- for (bep = backends ; (be = *bep) ; bep++) {
+ for (bep = upload_backends ; (be = *bep) ; bep++) {
if (!strcmp(be->name, argv[1]))
break;
}
diff --git a/com32/sysdump/memmap.c b/com32/sysdump/memmap.c
index 251107d5..929873fe 100644
--- a/com32/sysdump/memmap.c
+++ b/com32/sysdump/memmap.c
@@ -7,7 +7,6 @@
#include <stdlib.h>
#include <com32.h>
#include "sysdump.h"
-#include "backend.h"
#define E820_CHUNK 128
struct e820_info {
@@ -16,7 +15,7 @@ struct e820_info {
uint8_t data[24];
};
-static void dump_e820(struct backend *be)
+static void dump_e820(struct upload_backend *be)
{
com32sys_t ireg, oreg;
struct e820_info *curr;
@@ -63,7 +62,7 @@ static void dump_e820(struct backend *be)
lfree(curr);
}
-void dump_memory_map(struct backend *be)
+void dump_memory_map(struct upload_backend *be)
{
com32sys_t ireg, oreg;
diff --git a/com32/sysdump/memory.c b/com32/sysdump/memory.c
index 6552e7f3..377f9a99 100644
--- a/com32/sysdump/memory.c
+++ b/com32/sysdump/memory.c
@@ -7,7 +7,6 @@
#include <stdlib.h>
#include <sys/cpu.h>
#include "sysdump.h"
-#include "backend.h"
static char *lowmem;
static size_t lowmem_len;
@@ -29,7 +28,7 @@ void snapshot_lowmem(void)
}
}
-static void dump_memory_range(struct backend *be, const void *where,
+static void dump_memory_range(struct upload_backend *be, const void *where,
const void *addr, size_t len)
{
char filename[32];
@@ -38,7 +37,7 @@ static void dump_memory_range(struct backend *be, const void *where,
cpio_writefile(be, filename, where, len);
}
-void dump_memory(struct backend *be)
+void dump_memory(struct upload_backend *be)
{
printf("Dumping memory... ");
diff --git a/com32/sysdump/pci.c b/com32/sysdump/pci.c
index 1d687279..9c23a841 100644
--- a/com32/sysdump/pci.c
+++ b/com32/sysdump/pci.c
@@ -7,9 +7,8 @@
#include <stdlib.h>
#include <sys/pci.h>
#include "sysdump.h"
-#include "backend.h"
-static void dump_pci_device(struct backend *be, pciaddr_t a, uint8_t hdrtype)
+static void dump_pci_device(struct upload_backend *be, pciaddr_t a, uint8_t hdrtype)
{
unsigned int bus = pci_bus(a);
unsigned int dev = pci_dev(a);
@@ -31,7 +30,7 @@ static void dump_pci_device(struct backend *be, pciaddr_t a, uint8_t hdrtype)
cpio_writefile(be, filename, data, sizeof data);
}
-void dump_pci(struct backend *be)
+void dump_pci(struct upload_backend *be)
{
int cfgtype;
unsigned int nbus, ndev, nfunc, maxfunc;
diff --git a/com32/sysdump/sysdump.h b/com32/sysdump/sysdump.h
index a5b963f8..72e4875e 100644
--- a/com32/sysdump/sysdump.h
+++ b/com32/sysdump/sysdump.h
@@ -1,15 +1,15 @@
#ifndef SYSDUMP_H
#define SYSDUMP_H
-struct backend;
+#include <libupload/upload_backend.h>
-void dump_memory_map(struct backend *);
+void dump_memory_map(struct upload_backend *);
void snapshot_lowmem(void);
-void dump_memory(struct backend *);
-void dump_dmi(struct backend *);
-void dump_acpi(struct backend *);
-void dump_cpuid(struct backend *);
-void dump_pci(struct backend *);
-void dump_vesa_tables(struct backend *);
+void dump_memory(struct upload_backend *);
+void dump_dmi(struct upload_backend *);
+void dump_acpi(struct upload_backend *);
+void dump_cpuid(struct upload_backend *);
+void dump_pci(struct upload_backend *);
+void dump_vesa_tables(struct upload_backend *);
#endif /* SYSDUMP_H */
diff --git a/com32/sysdump/vesa.c b/com32/sysdump/vesa.c
index 017f9e4f..42adc3da 100644
--- a/com32/sysdump/vesa.c
+++ b/com32/sysdump/vesa.c
@@ -1,10 +1,9 @@
#include <string.h>
#include <stdio.h>
-#include "../lib/sys/vesa/vesa.h"
-#include "backend.h"
+#include <lib/sys/vesa/vesa.h>
#include "sysdump.h"
-void dump_vesa_tables(struct backend *be)
+void dump_vesa_tables(struct upload_backend *be)
{
com32sys_t rm;
struct vesa_info *vip;
diff --git a/com32/tools/Makefile b/com32/tools/Makefile
index e34296b4..0161baf1 100644
--- a/com32/tools/Makefile
+++ b/com32/tools/Makefile
@@ -10,11 +10,13 @@
##
## -----------------------------------------------------------------------
-topdir = ../..
-include $(topdir)/MCONFIG.build
+MAKEDIR = ../../mk
+include $(MAKEDIR)/build.mk
BINS = relocs
+INCLUDES += -I./include
+
all : $(BINS)
relocs : relocs.o
diff --git a/com32/tools/include/tools/le_byteshift.h b/com32/tools/include/tools/le_byteshift.h
new file mode 100644
index 00000000..c99d45a6
--- /dev/null
+++ b/com32/tools/include/tools/le_byteshift.h
@@ -0,0 +1,70 @@
+#ifndef _TOOLS_LE_BYTESHIFT_H
+#define _TOOLS_LE_BYTESHIFT_H
+
+#include <linux/types.h>
+
+static inline __u16 __get_unaligned_le16(const __u8 *p)
+{
+ return p[0] | p[1] << 8;
+}
+
+static inline __u32 __get_unaligned_le32(const __u8 *p)
+{
+ return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
+}
+
+static inline __u64 __get_unaligned_le64(const __u8 *p)
+{
+ return (__u64)__get_unaligned_le32(p + 4) << 32 |
+ __get_unaligned_le32(p);
+}
+
+static inline void __put_unaligned_le16(__u16 val, __u8 *p)
+{
+ *p++ = val;
+ *p++ = val >> 8;
+}
+
+static inline void __put_unaligned_le32(__u32 val, __u8 *p)
+{
+ __put_unaligned_le16(val >> 16, p + 2);
+ __put_unaligned_le16(val, p);
+}
+
+static inline void __put_unaligned_le64(__u64 val, __u8 *p)
+{
+ __put_unaligned_le32(val >> 32, p + 4);
+ __put_unaligned_le32(val, p);
+}
+
+static inline __u16 get_unaligned_le16(const void *p)
+{
+ return __get_unaligned_le16((const __u8 *)p);
+}
+
+static inline __u32 get_unaligned_le32(const void *p)
+{
+ return __get_unaligned_le32((const __u8 *)p);
+}
+
+static inline __u64 get_unaligned_le64(const void *p)
+{
+ return __get_unaligned_le64((const __u8 *)p);
+}
+
+static inline void put_unaligned_le16(__u16 val, void *p)
+{
+ __put_unaligned_le16(val, p);
+}
+
+static inline void put_unaligned_le32(__u32 val, void *p)
+{
+ __put_unaligned_le32(val, p);
+}
+
+static inline void put_unaligned_le64(__u64 val, void *p)
+{
+ __put_unaligned_le64(val, p);
+}
+
+#endif /* _TOOLS_LE_BYTESHIFT_H */
diff --git a/com32/tools/relocs.c b/com32/tools/relocs.c
index 24742060..86fc7c50 100644
--- a/com32/tools/relocs.c
+++ b/com32/tools/relocs.c
@@ -13,12 +13,16 @@
#define USE_BSD
#include <endian.h>
#include <regex.h>
-#include <sys/types.h>
+#include <tools/le_byteshift.h>
+
+static void die(char *fmt, ...);
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
static Elf32_Ehdr ehdr;
static unsigned long reloc_count, reloc_idx;
static unsigned long *relocs;
+static unsigned long reloc16_count, reloc16_idx;
+static unsigned long *relocs16;
struct section {
Elf32_Shdr shdr;
@@ -29,60 +33,87 @@ struct section {
};
static struct section *secs;
-static void die(char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
- exit(1);
-}
+enum symtype {
+ S_ABS,
+ S_REL,
+ S_SEG,
+ S_LIN,
+ S_NSYMTYPES
+};
+static const char * const sym_regex_kernel[S_NSYMTYPES] = {
/*
* Following symbols have been audited. Don't warn user about
* absolute relocations present w.r.t these symbols.
*/
+ [S_ABS] =
+ "^(__.*_len|__.*_dwords)$",
-/* True absolute relocations */
+/*
+ * These symbols are known to be relative, even if the linker marks them
+ * as absolute (typically defined outside any section in the linker script.)
+ */
+ [S_REL] =
+ "^(__.*_start|__.*_end|_end|_[se](text|data))$",
+};
-static const char safe_abs_regex[] =
-"^(__.*_len|__.*_dwords)$";
-static regex_t safe_abs_regex_c;
-static int is_safe_abs_reloc(const char *sym_name)
-{
- return !regexec(&safe_abs_regex_c, sym_name, 0, NULL, 0);
-}
+static const char * const sym_regex_realmode[S_NSYMTYPES] = {
+/*
+ * These are 16-bit segment symbols when compiling 16-bit code.
+ */
+ [S_SEG] =
+ "^real_mode_seg$",
-/* These are relative even though the linker marks them absolute */
+/*
+ * These are offsets belonging to segments, as opposed to linear addresses,
+ * when compiling 16-bit code.
+ */
+ [S_LIN] =
+ "^pa_",
+};
-static const char safe_rel_regex[] =
-"^(__.*_start|__.*_end|_end|_[se](text|data))$";
-static regex_t safe_rel_regex_c;
+static const char * const *sym_regex;
-static int is_safe_rel_reloc(const char *sym_name)
+static regex_t sym_regex_c[S_NSYMTYPES];
+static int is_reloc(enum symtype type, const char *sym_name)
{
- return !regexec(&safe_rel_regex_c, sym_name, 0, NULL, 0);
+ return sym_regex[type] &&
+ !regexec(&sym_regex_c[type], sym_name, 0, NULL, 0);
}
-static void regex_init(void)
+static void regex_init(int use_real_mode)
{
- char errbuf[128];
- int err;
+ char errbuf[128];
+ int err;
+ int i;
- err = regcomp(&safe_abs_regex_c, safe_abs_regex,
- REG_EXTENDED|REG_NOSUB);
- if (err) {
- regerror(err, &safe_abs_regex_c, errbuf, sizeof errbuf);
- die("%s", errbuf);
- }
+ if (use_real_mode)
+ sym_regex = sym_regex_realmode;
+ else
+ sym_regex = sym_regex_kernel;
- err = regcomp(&safe_rel_regex_c, safe_rel_regex,
- REG_EXTENDED|REG_NOSUB);
- if (err) {
- regerror(err, &safe_rel_regex_c, errbuf, sizeof errbuf);
- die("%s", errbuf);
- }
+ for (i = 0; i < S_NSYMTYPES; i++) {
+ if (!sym_regex[i])
+ continue;
+
+ err = regcomp(&sym_regex_c[i], sym_regex[i],
+ REG_EXTENDED|REG_NOSUB);
+
+ if (err) {
+ regerror(err, &sym_regex_c[i], errbuf, sizeof errbuf);
+ die("%s", errbuf);
+ }
+ }
+}
+
+static void die(char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ exit(1);
}
static const char *sym_type(unsigned type)
@@ -153,13 +184,16 @@ static const char *rel_type(unsigned type)
REL_TYPE(R_386_RELATIVE),
REL_TYPE(R_386_GOTOFF),
REL_TYPE(R_386_GOTPC),
+ REL_TYPE(R_386_8),
+ REL_TYPE(R_386_PC8),
+ REL_TYPE(R_386_16),
+ REL_TYPE(R_386_PC16),
#undef REL_TYPE
};
- const char *name = NULL;
- if (type < ARRAY_SIZE(type_name))
+ const char *name = "unknown type rel type name";
+ if (type < ARRAY_SIZE(type_name) && type_name[type]) {
name = type_name[type];
- if (!name)
- name = "unknown";
+ }
return name;
}
@@ -189,7 +223,7 @@ static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym)
name = sym_strtab + sym->st_name;
}
else {
- name = sec_name(secs[sym->st_shndx].shdr.sh_name);
+ name = sec_name(sym->st_shndx);
}
return name;
}
@@ -428,7 +462,7 @@ static void print_absolute_symbols(void)
printf("\n");
}
-static int print_absolute_relocs(FILE *f)
+static void print_absolute_relocs(void)
{
int i, printed = 0;
@@ -472,17 +506,18 @@ static int print_absolute_relocs(FILE *f)
* Before warning check if this absolute symbol
* relocation is harmless.
*/
- if (is_safe_abs_reloc(name) ||
- is_safe_rel_reloc(name))
+ if (is_reloc(S_ABS, name) || is_reloc(S_REL, name))
continue;
if (!printed) {
- fprintf(f, "Unknown absolute relocations present\n");
- fprintf(f, "Offset Info Type Sym.Value Sym.Name\n");
+ printf("WARNING: Absolute relocations"
+ " present\n");
+ printf("Offset Info Type Sym.Value "
+ "Sym.Name\n");
printed = 1;
}
- fprintf(f, "%08x %08x %10s %08x %s\n",
+ printf("%08x %08x %10s %08x %s\n",
rel->r_offset,
rel->r_info,
rel_type(ELF32_R_TYPE(rel->r_info)),
@@ -492,12 +527,11 @@ static int print_absolute_relocs(FILE *f)
}
if (printed)
- fputc('\n', f);
-
- return printed;
+ printf("\n");
}
-static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym))
+static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym),
+ int use_real_mode)
{
int i;
/* Walk through the relocations */
@@ -522,31 +556,71 @@ static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym))
Elf32_Rel *rel;
Elf32_Sym *sym;
unsigned r_type;
+ const char *symname;
+ int shn_abs;
+
rel = &sec->reltab[j];
sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
r_type = ELF32_R_TYPE(rel->r_info);
- /* Don't visit relocations to absolute symbols */
- if (sym->st_shndx == SHN_ABS &&
- !is_safe_rel_reloc(sym_name(sym_strtab, sym)))
- continue;
+
+ shn_abs = sym->st_shndx == SHN_ABS;
switch (r_type) {
case R_386_NONE:
case R_386_PC32:
+ case R_386_PC16:
+ case R_386_PC8:
case R_386_GOTPC:
case R_386_GOTOFF:
case R_386_GOT32:
case R_386_PLT32:
- /* Relative relocations don't need to
- be adjusted */
+ /*
+ * NONE can be ignored and and PC relative
+ * relocations don't need to be adjusted.
+ */
break;
+
+ case R_386_16:
+ symname = sym_name(sym_strtab, sym);
+ if (!use_real_mode)
+ goto bad;
+ if (shn_abs) {
+ if (is_reloc(S_ABS, symname))
+ break;
+ else if (!is_reloc(S_SEG, symname))
+ goto bad;
+ } else {
+ if (is_reloc(S_LIN, symname))
+ goto bad;
+ else
+ break;
+ }
+ visit(rel, sym);
+ break;
+
case R_386_32:
- /* Visit relocations that need adjustment */
+ symname = sym_name(sym_strtab, sym);
+ if (shn_abs) {
+ if (is_reloc(S_ABS, symname))
+ break;
+ else if (!is_reloc(S_REL, symname))
+ goto bad;
+ } else {
+ if (use_real_mode &&
+ !is_reloc(S_LIN, symname))
+ break;
+ }
visit(rel, sym);
break;
default:
die("Unsupported relocation type: %s (%d)\n",
rel_type(r_type), r_type);
+ break;
+ bad:
+ symname = sym_name(sym_strtab, sym);
+ die("Invalid %s %s relocation: %s\n",
+ shn_abs ? "absolute" : "relative",
+ rel_type(r_type), symname);
}
}
}
@@ -554,8 +628,12 @@ static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym))
static void count_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
{
- (void)rel; (void)sym;
- reloc_count += 1;
+ (void)sym;
+
+ if (ELF32_R_TYPE(rel->r_info) == R_386_16)
+ reloc16_count++;
+ else
+ reloc_count++;
}
static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
@@ -563,7 +641,10 @@ static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
(void)sym;
/* Remember the address that needs to be adjusted. */
- relocs[reloc_idx++] = rel->r_offset;
+ if (ELF32_R_TYPE(rel->r_info) == R_386_16)
+ relocs16[reloc16_idx++] = rel->r_offset;
+ else
+ relocs[reloc_idx++] = rel->r_offset;
}
static int cmp_relocs(const void *va, const void *vb)
@@ -573,23 +654,41 @@ static int cmp_relocs(const void *va, const void *vb)
return (*a == *b)? 0 : (*a > *b)? 1 : -1;
}
-static void emit_relocs(int as_text)
+static int write32(unsigned int v, FILE *f)
+{
+ unsigned char buf[4];
+
+ put_unaligned_le32(v, buf);
+ return fwrite(buf, 1, 4, f) == 4 ? 0 : -1;
+}
+
+static void emit_relocs(int as_text, int use_real_mode)
{
int i;
/* Count how many relocations I have and allocate space for them. */
reloc_count = 0;
- walk_relocs(count_reloc);
+ walk_relocs(count_reloc, use_real_mode);
relocs = malloc(reloc_count * sizeof(relocs[0]));
if (!relocs) {
die("malloc of %d entries for relocs failed\n",
reloc_count);
}
+
+ relocs16 = malloc(reloc16_count * sizeof(relocs[0]));
+ if (!relocs16) {
+ die("malloc of %d entries for relocs16 failed\n",
+ reloc16_count);
+ }
/* Collect up the relocations */
reloc_idx = 0;
- walk_relocs(collect_reloc);
+ walk_relocs(collect_reloc, use_real_mode);
+
+ if (reloc16_count && !use_real_mode)
+ die("Segment relocations found but --realmode not specified\n");
/* Order the relocations for more efficient processing */
qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs);
+ qsort(relocs16, reloc16_count, sizeof(relocs16[0]), cmp_relocs);
/* Print the relocations */
if (as_text) {
@@ -598,61 +697,83 @@ static void emit_relocs(int as_text)
*/
printf(".section \".data.reloc\",\"a\"\n");
printf(".balign 4\n");
- for (i = 0; i < reloc_count; i++) {
- printf("\t .long 0x%08lx\n", relocs[i]);
+ if (use_real_mode) {
+ printf("\t.long %lu\n", reloc16_count);
+ for (i = 0; i < reloc16_count; i++)
+ printf("\t.long 0x%08lx\n", relocs16[i]);
+ printf("\t.long %lu\n", reloc_count);
+ for (i = 0; i < reloc_count; i++) {
+ printf("\t.long 0x%08lx\n", relocs[i]);
+ }
+ } else {
+ for (i = 0; i < reloc_count; i++) {
+ printf("\t.long 0x%08lx\n", relocs[i]);
+ }
+ /* Print a stop */
+ printf("\t.long 0x%08lx\n", (unsigned long)0);
}
+
printf("\n");
}
else {
- unsigned char buf[4];
- /* Now print each relocation */
- for (i = 0; i < reloc_count; i++) {
- buf[0] = (relocs[i] >> 0) & 0xff;
- buf[1] = (relocs[i] >> 8) & 0xff;
- buf[2] = (relocs[i] >> 16) & 0xff;
- buf[3] = (relocs[i] >> 24) & 0xff;
- fwrite(buf, 4, 1, stdout);
+ if (use_real_mode) {
+ write32(reloc16_count, stdout);
+ for (i = 0; i < reloc16_count; i++)
+ write32(relocs16[i], stdout);
+ write32(reloc_count, stdout);
+
+ /* Now print each relocation */
+ for (i = 0; i < reloc_count; i++)
+ write32(relocs[i], stdout);
+ } else {
+ /* Now print each relocation */
+ for (i = 0; i < reloc_count; i++) {
+ write32(relocs[i], stdout);
+ }
+
+ /* Print a stop */
+ write32(0, stdout);
}
- /* Print a stop */
- memset(buf, 0, sizeof buf);
- fwrite(buf, 4, 1, stdout);
}
}
static void usage(void)
{
- die("relocs [--abs-syms |--abs-relocs | --text] vmlinux\n");
+ die("relocs [--abs-syms|--abs-relocs|--text|--realmode] vmlinux\n");
}
int main(int argc, char **argv)
{
int show_absolute_syms, show_absolute_relocs;
- int as_text;
+ int as_text, use_real_mode;
const char *fname;
FILE *fp;
int i;
- int err = 0;
show_absolute_syms = 0;
show_absolute_relocs = 0;
as_text = 0;
+ use_real_mode = 0;
fname = NULL;
for (i = 1; i < argc; i++) {
char *arg = argv[i];
if (*arg == '-') {
- if (strcmp(argv[1], "--abs-syms") == 0) {
+ if (strcmp(arg, "--abs-syms") == 0) {
show_absolute_syms = 1;
continue;
}
-
- if (strcmp(argv[1], "--abs-relocs") == 0) {
+ if (strcmp(arg, "--abs-relocs") == 0) {
show_absolute_relocs = 1;
continue;
}
- else if (strcmp(argv[1], "--text") == 0) {
+ if (strcmp(arg, "--text") == 0) {
as_text = 1;
continue;
}
+ if (strcmp(arg, "--realmode") == 0) {
+ use_real_mode = 1;
+ continue;
+ }
}
else if (!fname) {
fname = arg;
@@ -663,10 +784,7 @@ int main(int argc, char **argv)
if (!fname) {
usage();
}
-
-
- regex_init();
-
+ regex_init(use_real_mode);
fp = fopen(fname, "r");
if (!fp) {
die("Cannot open %s: %s\n",
@@ -682,10 +800,9 @@ int main(int argc, char **argv)
return 0;
}
if (show_absolute_relocs) {
- print_absolute_relocs(stdout);
+ print_absolute_relocs();
return 0;
}
- err = print_absolute_relocs(stderr);
- emit_relocs(as_text);
- return err;
+ emit_relocs(as_text, use_real_mode);
+ return 0;
}
diff --git a/core/Makefile b/core/Makefile
index 33ad7e95..112fe3a8 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -20,7 +20,8 @@ MAKEFLAGS += -r
MAKE += -r
topdir = ..
-include $(topdir)/MCONFIG.embedded
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/embedded.mk
-include $(topdir)/version.mk
OPTFLAGS =
@@ -109,7 +110,7 @@ ldlinux.bss: ldlinux.bin
dd if=$< of=$@ bs=512 count=1
ldlinux.sys: ldlinux.bin
- dd if=$< of=$@ bs=512 skip=1
+ dd if=$< of=$@ bs=512 skip=2
codepage.cp: ../codepage/$(CODEPAGE).cp
cp -f $< $@
diff --git a/core/bootsect.inc b/core/bootsect.inc
index 6c204096..9e47e1a5 100644
--- a/core/bootsect.inc
+++ b/core/bootsect.inc
@@ -1,7 +1,7 @@
;; -----------------------------------------------------------------------
;;
;; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
-;; Copyright 2009 Intel Corporation; author: H. Peter Anvin
+;; Copyright 2009-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
@@ -38,6 +38,7 @@ SuperSize equ $+1
load_bootsec:
mov edi,free_high_memory
mov [trackbuf+4],edi ; Copy from this address
+ mov eax,0xA0000 ; Maximum load
xor dx,dx ; No padding
mov bx,abort_check ; Don't print dots, but allow abort
call load_high
@@ -45,6 +46,9 @@ load_bootsec:
sub edi,free_high_memory
mov [trackbuf+8],edi ; Save length
+ cmp edi,0xA0000-7C00h
+ ja bs_too_big
+
mov eax,7C00h ; Entry point
mov [trackbuf],eax ; Copy to this address
@@ -237,3 +241,13 @@ replace_stub:
.csip equ $-4
section .text16
+bs_too_big:
+ call close
+ mov si,err_bs_too_big
+ jmp abort_load
+
+ section .data16
+err_bs_too_big db "Too large for a bootstrap (need LINUX instead of KERNEL?)"
+ db CR, LF, 0
+
+ section .text16
diff --git a/core/comboot.inc b/core/comboot.inc
index d6f670c9..61c8a3b7 100644
--- a/core/comboot.inc
+++ b/core/comboot.inc
@@ -651,21 +651,8 @@ comapi_cleanup:
ret
;
-; INT 22h AX=000Dh Clean up then replace bootstrap
+; INT 22h AX=000Dh Obsolete
;
-comapi_chainboot:
- call comapi_cleanup
- mov eax,P_EDI
- mov [trackbuf+4],eax ; Copy from
- mov eax,P_ECX
- mov [trackbuf+8],eax ; Total bytes
- mov eax,7C00h
- mov [trackbuf],eax ; Copy to
- push eax ; Entry point on stack
- mov esi,P_ESI
- mov edx,P_EBX
- mov bx,P_DS
- jmp replace_bootstrap_one
;
; INT 22h AX=000Eh Get configuration file name
diff --git a/core/diskboot.inc b/core/diskboot.inc
index 68672e4a..141986e8 100644
--- a/core/diskboot.inc
+++ b/core/diskboot.inc
@@ -278,7 +278,7 @@ Sect1Ptr1 equ $-4
cmp dword [ldlinux_magic+4],LDLINUX_MAGIC^HEXDATE
jne kaboom
- ; Go for it! This also normalizes CS:IP.
+ ; Go for it!
jmp ldlinux_ent
;
diff --git a/core/diskfs.inc b/core/diskfs.inc
index fc80a153..41391e7f 100644
--- a/core/diskfs.inc
+++ b/core/diskfs.inc
@@ -30,8 +30,8 @@ LDLINUX_MAGIC equ 0x3eb202fe ; A random number to identify ourselves with
; This indicates the general format of the last few bytes in the boot sector
BS_MAGIC_VER equ 0x1b << 9
-SECTOR_SHIFT equ 9
-SECTOR_SIZE equ (1 << SECTOR_SHIFT)
+MIN_SECTOR_SHIFT equ 9
+MIN_SECTOR_SIZE equ (1 << MIN_SECTOR_SHIFT)
;
; The following structure is used for "virtual kernels"; i.e. LILO-style
diff --git a/core/diskstart.inc b/core/diskstart.inc
index 02505a6b..b2ef2b63 100644
--- a/core/diskstart.inc
+++ b/core/diskstart.inc
@@ -23,6 +23,14 @@ Sect1Ptr1_VAL equ 0xfeedface
%include "diskboot.inc"
; ===========================================================================
+; Padding after the (minimum) 512-byte boot sector so that the rest of
+; the file has aligned sectors, even if they are larger than 512 bytes.
+; ===========================================================================
+
+ section .init
+align_pad zb 512
+
+; ===========================================================================
; Start of LDLINUX.SYS
; ===========================================================================
@@ -110,13 +118,15 @@ ldlinux_ent:
; Checksum data thus far
;
mov si,ldlinux_sys
- mov cx,SECTOR_SIZE >> 2
+ mov cx,[bsBytesPerSec]
+ shr cx,2
mov edx,-LDLINUX_MAGIC
.checksum:
lodsd
add edx,eax
loop .checksum
mov [CheckSum],edx ; Save intermediate result
+ movzx ebx,si ; Start of the next sector
;
; Tell the user if we're using EBIOS or CBIOS
@@ -132,6 +142,7 @@ print_bios:
call writestr_early
section .earlybss
+ alignb 2
%define HAVE_BIOSNAME 1
BIOSName resw 1
@@ -140,8 +151,9 @@ BIOSName resw 1
; Now we read the rest of LDLINUX.SYS.
;
load_rest:
+ push bx ; LSW of load address
+
lea esi,[SectorPtrs]
- mov ebx,TEXT_START+2*SECTOR_SIZE ; Where we start loading
mov cx,[DataSectors]
dec cx ; Minus this sector
@@ -157,7 +169,7 @@ load_rest:
xor bx,bx
call getlinsec
pop ebx
- shl ebp,SECTOR_SHIFT
+ imul bp,[bsBytesPerSec] ; Will be < 64K
add ebx,ebp
add si,10
jmp .get_chunk
@@ -170,9 +182,11 @@ load_rest:
; by the time we get to the end it should all cancel out.
;
verify_checksum:
- mov si,ldlinux_sys + SECTOR_SIZE
- mov ecx,[LDLDwords]
- sub ecx,SECTOR_SIZE >> 2
+ pop si ; LSW of load address
+ movzx eax,word [bsBytesPerSec]
+ shr ax,2
+ mov ecx,[LDLDwords] ; Total dwords
+ sub ecx,eax ; ... minus one sector
mov eax,[CheckSum]
.checksum:
add eax,[si]
@@ -260,7 +274,7 @@ getlinsec_ebios:
add eax,edi ; Advance sector pointer
adc edx,0
sub bp,di ; Sectors left
- shl di,SECTOR_SHIFT ; 512-byte sectors
+ imul di,[bsBytesPerSec]
add bx,di ; Advance buffer pointer
and bp,bp
jnz .loop
@@ -350,7 +364,7 @@ getlinsec_cbios:
jc .error
.resume:
movzx ecx,al ; ECX <- sectors transferred
- shl ax,SECTOR_SHIFT ; Convert sectors in AL to bytes in AX
+ imul ax,[bsBytesPerSec] ; Convert sectors in AL to bytes in AX
pop bx
add bx,ax
pop bp
@@ -418,10 +432,10 @@ safedumpregs:
rl_checkpt equ $ ; Must be <= 8000h
-rl_checkpt_off equ ($-$$)
+rl_checkpt_off equ $-ldlinux_sys
%ifndef DEPEND
- %if rl_checkpt_off > 3F6h ; Need one extent
- %assign rl_checkpt_overflow rl_checkpt_off - 3F6h
+ %if rl_checkpt_off > 512-10 ; Need minimum one extent
+ %assign rl_checkpt_overflow rl_checkpt_off - (512-10)
%error Sector 1 overflow by rl_checkpt_overflow bytes
%endif
%endif
@@ -434,8 +448,8 @@ rl_checkpt_off equ ($-$$)
;
alignz 2
MaxInitDataSize equ 96 << 10
-MaxLMA equ TEXT_START+SECTOR_SIZE+MaxInitDataSize
-SectorPtrs zb 10*(MaxInitDataSize >> SECTOR_SHIFT)
+MaxLMA equ LDLINUX_SYS+MaxInitDataSize
+SectorPtrs zb 10*(MaxInitDataSize >> MIN_SECTOR_SHIFT)
SectorPtrsEnd equ $
; ----------------------------------------------------------------------------
diff --git a/core/fs/btrfs/btrfs.c b/core/fs/btrfs/btrfs.c
index b6a14e3b..aeb7614a 100644
--- a/core/fs/btrfs/btrfs.c
+++ b/core/fs/btrfs/btrfs.c
@@ -602,12 +602,15 @@ static void btrfs_get_fs_tree(struct fs_info *fs)
do {
do {
struct btrfs_root_ref *ref;
+ int pathlen;
if (btrfs_comp_keys_type(&search_key,
&path.item.key))
break;
ref = (struct btrfs_root_ref *)path.data;
- if (!strcmp((char*)(ref + 1), SubvolName)) {
+ pathlen = path.item.size - sizeof(struct btrfs_root_ref);
+
+ if (!strncmp((char*)(ref + 1), SubvolName, pathlen)) {
subvol_ok = true;
break;
}
diff --git a/core/fs/cache.c b/core/fs/cache.c
index 0d7891be..3b21fc26 100644
--- a/core/fs/cache.c
+++ b/core/fs/cache.c
@@ -37,10 +37,10 @@ void cache_init(struct device *dev, int block_size_shift)
dev->cache_head = head = (struct cache *)
(data + (dev->cache_entries << block_size_shift));
- cache = dev->cache_head + 1; /* First cache descriptor */
+ cache = head + 1; /* First cache descriptor */
head->prev = &cache[dev->cache_entries-1];
- head->next->prev = dev->cache_head;
+ head->prev->next = head;
head->block = -1;
head->data = NULL;
diff --git a/core/fs/chdir.c b/core/fs/chdir.c
index 9e8dfd2e..903cabce 100644
--- a/core/fs/chdir.c
+++ b/core/fs/chdir.c
@@ -1,6 +1,7 @@
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
+#include <dprintf.h>
#include "fs.h"
#include "cache.h"
@@ -16,57 +17,70 @@ void pm_realpath(com32sys_t *regs)
realpath(dst, src, FILENAME_MAX);
}
-#define EMIT(x) \
-do { \
- if (++n < bufsize) \
- *q++ = (x); \
-} while (0)
-
-static size_t join_paths(char *dst, size_t bufsize,
- const char *s1, const char *s2)
+static size_t copy_string(char *buf, size_t ix, size_t bufsize, const char *src)
{
- const char *list[2];
- int i;
char c;
- const char *p;
- char *q = dst;
- size_t n = 0;
- bool slash = false;
-
- list[0] = s1;
- list[1] = s2;
-
- for (i = 0; i < 2; i++) {
- p = list[i];
-
- while ((c = *p++)) {
- if (c == '/') {
- if (!slash)
- EMIT(c);
- slash = true;
- } else {
- EMIT(c);
- slash = false;
- }
- }
+
+ while ((c = *src++)) {
+ if (ix+1 < bufsize)
+ buf[ix] = c;
+ ix++;
}
- if (bufsize)
- *q = '\0';
+ if (ix < bufsize)
+ buf[ix] = '\0';
- return n;
+ return ix;
+}
+
+static size_t generic_inode_to_path(struct inode *inode, char *dst, size_t bufsize)
+{
+ size_t s = 0;
+
+ dprintf("inode %p name %s\n", inode, inode->name);
+
+ if (inode->parent) {
+ if (!inode->name) /* Only the root should have no name */
+ return -1;
+
+ s = generic_inode_to_path(inode->parent, dst, bufsize);
+ if (s == (size_t)-1)
+ return s; /* Error! */
+
+ s = copy_string(dst, s, bufsize, "/");
+ s = copy_string(dst, s, bufsize, inode->name);
+ }
+
+ return s;
}
size_t realpath(char *dst, const char *src, size_t bufsize)
{
+ int rv;
+ struct file *file;
+ size_t s;
+
+ dprintf("realpath: input: %s\n", src);
+
if (this_fs->fs_ops->realpath) {
- return this_fs->fs_ops->realpath(this_fs, dst, src, bufsize);
+ s = this_fs->fs_ops->realpath(this_fs, dst, src, bufsize);
} else {
- /* Filesystems with "common" pathname resolution */
- return join_paths(dst, bufsize,
- src[0] == '/' ? "" : this_fs->cwd_name,
- src);
+ rv = searchdir(src);
+ if (rv < 0) {
+ dprintf("realpath: searchpath failure\n");
+ return -1;
+ }
+
+ file = handle_to_file(rv);
+ s = generic_inode_to_path(file->inode, dst, bufsize);
+ if (s == 0)
+ s = copy_string(dst, 0, bufsize, "/");
+
+ _close_file(file);
}
+
+ dprintf("realpath: output: %s\n", dst);
+ return s;
}
int chdir(const char *src)
@@ -74,6 +88,10 @@ int chdir(const char *src)
int rv;
struct file *file;
char cwd_buf[CURRENTDIR_MAX];
+ size_t s;
+
+ dprintf("chdir: from %s (inode %p) add %s\n",
+ this_fs->cwd_name, this_fs->cwd, src);
if (this_fs->fs_ops->chdir)
return this_fs->fs_ops->chdir(this_fs, src);
@@ -94,10 +112,20 @@ int chdir(const char *src)
_close_file(file);
/* Save the current working directory */
- realpath(cwd_buf, src, CURRENTDIR_MAX);
+ s = generic_inode_to_path(this_fs->cwd, cwd_buf, CURRENTDIR_MAX-1);
/* Make sure the cwd_name ends in a slash, it's supposed to be a prefix */
- join_paths(this_fs->cwd_name, CURRENTDIR_MAX, cwd_buf, "/");
+ if (s < 1 || cwd_buf[s-1] != '/')
+ cwd_buf[s++] = '/';
+
+ if (s >= CURRENTDIR_MAX)
+ s = CURRENTDIR_MAX - 1;
+
+ cwd_buf[s++] = '\0';
+ memcpy(this_fs->cwd_name, cwd_buf, s);
+
+ dprintf("chdir: final %s (inode %p)\n",
+ this_fs->cwd_name, this_fs->cwd);
return 0;
}
diff --git a/core/fs/ext2/ext2.c b/core/fs/ext2/ext2.c
index 716670c6..7988faaf 100644
--- a/core/fs/ext2/ext2.c
+++ b/core/fs/ext2/ext2.c
@@ -164,6 +164,9 @@ static struct inode *ext2_iget_by_inr(struct fs_info *fs, uint32_t inr)
struct inode *inode;
e_inode = ext2_get_inode(fs, inr);
+ if (!e_inode)
+ return NULL;
+
if (!(inode = alloc_inode(fs, inr, sizeof(struct ext2_pvt_inode))))
return NULL;
fill_inode(inode, e_inode);
diff --git a/core/fs/fat/fat.c b/core/fs/fat/fat.c
index d3079269..b08923cf 100644
--- a/core/fs/fat/fat.c
+++ b/core/fs/fat/fat.c
@@ -220,24 +220,30 @@ static sector_t next_sector(struct file *file)
return sector;
}
-/*
- * Mangle a filename pointed to by src into a buffer pointed to by dst;
- * ends on encountering any whitespace.
+/**
+ * mangle_name:
+ *
+ * Mangle a filename pointed to by src into a buffer pointed
+ * to by dst; ends on encountering any whitespace.
+ * dst is preserved.
+ *
+ * This verifies that a filename is < FILENAME_MAX characters,
+ * doesn't contain whitespace, zero-pads the output buffer,
+ * and removes redundant slashes.
+ *
+ * Unlike the generic version, this also converts backslashes to
+ * forward slashes.
*
*/
static void vfat_mangle_name(char *dst, const char *src)
{
char *p = dst;
+ int i = FILENAME_MAX-1;
char c;
- int i = FILENAME_MAX -1;
- /*
- * Copy the filename, converting backslash to slash and
- * collapsing duplicate separators.
- */
while (not_whitespace(c = *src)) {
- if (c == '\\')
- c = '/';
+ if (c == '\\')
+ c = '/';
if (c == '/') {
if (src[1] == '/' || src[1] == '\\') {
@@ -250,16 +256,13 @@ static void vfat_mangle_name(char *dst, const char *src)
*dst++ = *src++;
}
- /* Strip terminal slashes or whitespace */
while (1) {
if (dst == p)
break;
- if (*(dst-1) == '/' && dst-1 == p) /* it's the '/' case */
- break;
- if (dst-2 == p && *(dst-2) == '.' && *(dst-1) == '.' ) /* the '..' case */
- break;
- if ((*(dst-1) != '/') && (*(dst-1) != '.'))
+ if (dst[-1] != '/')
break;
+ if ((dst[-1] == '/') && ((dst - 1) == p))
+ break;
dst--;
i++;
diff --git a/core/fs/fs.c b/core/fs/fs.c
index ad2fb370..21f5dba0 100644
--- a/core/fs/fs.c
+++ b/core/fs/fs.c
@@ -37,6 +37,8 @@ void put_inode(struct inode *inode)
while (inode && --inode->refcnt == 0) {
struct inode *dead = inode;
inode = inode->parent;
+ if (dead->name)
+ free((char *)dead->name);
free(dead);
}
}
@@ -207,6 +209,9 @@ int searchdir(const char *name)
char *part, *p, echar;
int symlink_count = MAX_SYMLINK_CNT;
+ dprintf("searchdir: %s root: %p cwd: %p\n",
+ name, this_fs->root, this_fs->cwd);
+
if (!(file = alloc_file()))
goto err_no_close;
file->fs = this_fs;
@@ -305,6 +310,9 @@ int searchdir(const char *name)
goto got_link;
}
+ inode->name = strdup(part);
+ dprintf("path component: %s\n", inode->name);
+
inode->parent = parent;
parent = NULL;
@@ -349,6 +357,8 @@ int open_file(const char *name, struct com32_filedata *filedata)
struct file *file;
char mangled_name[FILENAME_MAX];
+ dprintf("open_file %s\n", name);
+
mangle_name(mangled_name, name);
rv = searchdir(mangled_name);
@@ -376,6 +386,8 @@ void pm_open_file(com32sys_t *regs)
const char *name = MK_PTR(regs->es, regs->esi.w[0]);
char mangled_name[FILENAME_MAX];
+ dprintf("pm_open_file %s\n", name);
+
mangle_name(mangled_name, name);
rv = searchdir(mangled_name);
if (rv < 0) {
@@ -470,6 +482,7 @@ void fs_init(com32sys_t *regs)
if (fs.fs_ops->iget_root) {
fs.root = fs.fs_ops->iget_root(&fs);
fs.cwd = get_inode(fs.root);
+ dprintf("init: root inode %p, cwd inode %p\n", fs.root, fs.cwd);
}
SectorShift = fs.sector_shift;
diff --git a/core/fs/lib/searchconfig.c b/core/fs/lib/searchconfig.c
index 24bfde31..f18836a8 100644
--- a/core/fs/lib/searchconfig.c
+++ b/core/fs/lib/searchconfig.c
@@ -25,7 +25,8 @@ int search_config(const char *search_directories[], const char *filenames[])
"%s%s%s",
sd, (*sd && sd[strlen(sd)-1] == '/') ? "" : "/",
sf);
- realpath(ConfigName, confignamebuf, FILENAME_MAX);
+ if (realpath(ConfigName, confignamebuf, FILENAME_MAX) == (size_t)-1)
+ continue;
regs.edi.w[0] = OFFS_WRT(ConfigName, 0);
dprintf("Config search: %s\n", ConfigName);
call16(core_open, &regs, &regs);
diff --git a/core/fs/ntfs/ntfs.c b/core/fs/ntfs/ntfs.c
new file mode 100644
index 00000000..500d0fd3
--- /dev/null
+++ b/core/fs/ntfs/ntfs.c
@@ -0,0 +1,1388 @@
+/*
+ * Copyright (C) 2011-2012 Paulo Alcantara <pcacjr@gmail.com>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/* Note: No support for compressed files */
+
+#include <dprintf.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/dirent.h>
+#include <cache.h>
+#include <core.h>
+#include <disk.h>
+#include <fs.h>
+#include <ilog2.h>
+#include <klibc/compiler.h>
+#include <ctype.h>
+
+#include "codepage.h"
+#include "ntfs.h"
+#include "runlist.h"
+
+static struct ntfs_readdir_state *readdir_state;
+
+/*** Function declarations */
+static f_mft_record_lookup ntfs_mft_record_lookup_3_0;
+static f_mft_record_lookup ntfs_mft_record_lookup_3_1;
+
+/*** Function definitions */
+
+/* Check if there are specific zero fields in an NTFS boot sector */
+static inline int ntfs_check_zero_fields(const struct ntfs_bpb *sb)
+{
+ return !sb->res_sectors && (!sb->zero_0[0] && !sb->zero_0[1] &&
+ !sb->zero_0[2]) && !sb->zero_1 && !sb->zero_2 &&
+ !sb->zero_3;
+}
+
+static inline int ntfs_check_sb_fields(const struct ntfs_bpb *sb)
+{
+ return ntfs_check_zero_fields(sb) &&
+ (!memcmp(sb->oem_name, "NTFS ", 8) ||
+ !memcmp(sb->oem_name, "MSWIN4.0", 8) ||
+ !memcmp(sb->oem_name, "MSWIN4.1", 8));
+}
+
+static inline struct inode *new_ntfs_inode(struct fs_info *fs)
+{
+ struct inode *inode;
+
+ inode = alloc_inode(fs, 0, sizeof(struct ntfs_inode));
+ if (!inode)
+ malloc_error("inode structure");
+
+ return inode;
+}
+
+static void ntfs_fixups_writeback(struct fs_info *fs, struct ntfs_record *nrec)
+{
+ uint16_t *usa;
+ uint16_t usa_no;
+ uint16_t usa_count;
+ uint16_t *blk;
+
+ dprintf("in %s()\n", __func__);
+
+ if (nrec->magic != NTFS_MAGIC_FILE && nrec->magic != NTFS_MAGIC_INDX)
+ return;
+
+ /* get the Update Sequence Array offset */
+ usa = (uint16_t *)((uint8_t *)nrec + nrec->usa_ofs);
+ /* get the Update Sequence Array Number and skip it */
+ usa_no = *usa++;
+ /* get the Update Sequene Array count */
+ usa_count = nrec->usa_count - 1; /* exclude the USA number */
+ /* make it to point to the last two bytes of the RECORD's first sector */
+ blk = (uint16_t *)((uint8_t *)nrec + SECTOR_SIZE(fs) - 2);
+
+ while (usa_count--) {
+ if (*blk != usa_no)
+ break;
+
+ *blk = *usa++;
+ blk = (uint16_t *)((uint8_t *)blk + SECTOR_SIZE(fs));
+ }
+}
+
+/* read content from cache */
+static int ntfs_read(struct fs_info *fs, void *buf, size_t len, uint64_t count,
+ block_t *blk, uint64_t *blk_offset,
+ uint64_t *blk_next_offset, uint64_t *lcn)
+{
+ uint8_t *data;
+ uint64_t offset = *blk_offset;
+ const uint32_t clust_byte_shift = NTFS_SB(fs)->clust_byte_shift;
+ const uint64_t blk_size = UINT64_C(1) << BLOCK_SHIFT(fs);
+ uint64_t bytes;
+ uint64_t lbytes;
+ uint64_t loffset;
+ uint64_t k;
+
+ dprintf("in %s()\n", __func__);
+
+ if (count > len)
+ goto out;
+
+ data = (uint8_t *)get_cache(fs->fs_dev, *blk);
+ if (!data)
+ goto out;
+
+ if (!offset)
+ offset = (*lcn << clust_byte_shift) % blk_size;
+
+ dprintf("LCN: 0x%X\n", *lcn);
+ dprintf("offset: 0x%X\n", offset);
+
+ bytes = count; /* bytes to copy */
+ lbytes = blk_size - offset; /* bytes left to copy */
+ if (lbytes >= bytes) {
+ /* so there's room enough, then copy the whole content */
+ memcpy(buf, data + offset, bytes);
+ loffset = offset;
+ offset += count;
+ } else {
+ dprintf("bytes: %u\n", bytes);
+ dprintf("bytes left: %u\n", lbytes);
+ /* otherwise, let's copy it partially... */
+ k = 0;
+ while (bytes) {
+ memcpy(buf + k, data + offset, lbytes);
+ bytes -= lbytes;
+ loffset = offset;
+ offset += lbytes;
+ k += lbytes;
+ if (offset >= blk_size) {
+ /* then fetch a new FS block */
+ data = (uint8_t *)get_cache(fs->fs_dev, ++*blk);
+ if (!data)
+ goto out;
+
+ lbytes = bytes;
+ loffset = offset;
+ offset = 0;
+ }
+ }
+ }
+
+ if (loffset >= blk_size)
+ loffset = 0; /* it must be aligned on a block boundary */
+
+ *blk_offset = loffset;
+
+ if (blk_next_offset)
+ *blk_next_offset = offset;
+
+ *lcn += blk_size / count; /* update LCN */
+
+ return 0;
+
+out:
+ return -1;
+}
+
+static struct ntfs_mft_record *ntfs_mft_record_lookup_3_0(struct fs_info *fs,
+ uint32_t file, block_t *blk)
+{
+ const uint64_t mft_record_size = NTFS_SB(fs)->mft_record_size;
+ uint8_t *buf;
+ const block_t mft_blk = NTFS_SB(fs)->mft_blk;
+ block_t cur_blk;
+ block_t right_blk;
+ uint64_t offset;
+ uint64_t next_offset;
+ const uint32_t mft_record_shift = ilog2(mft_record_size);
+ const uint32_t clust_byte_shift = NTFS_SB(fs)->clust_byte_shift;
+ uint64_t lcn;
+ int err;
+ struct ntfs_mft_record *mrec;
+
+ dprintf("in %s()\n", __func__);
+
+ buf = (uint8_t *)malloc(mft_record_size);
+ if (!buf)
+ malloc_error("uint8_t *");
+
+ /* determine MFT record's LCN and block number */
+ lcn = NTFS_SB(fs)->mft_lcn + (file << mft_record_shift >> clust_byte_shift);
+ cur_blk = (lcn << clust_byte_shift >> BLOCK_SHIFT(fs)) - mft_blk;
+ offset = (file << mft_record_shift) % BLOCK_SIZE(fs);
+ for (;;) {
+ right_blk = cur_blk + mft_blk;
+ err = ntfs_read(fs, buf, mft_record_size, mft_record_size, &right_blk,
+ &offset, &next_offset, &lcn);
+ if (err) {
+ printf("Error while reading from cache.\n");
+ break;
+ }
+
+ ntfs_fixups_writeback(fs, (struct ntfs_record *)buf);
+
+ mrec = (struct ntfs_mft_record *)buf;
+ /* check if it has a valid magic number */
+ if (mrec->magic == NTFS_MAGIC_FILE) {
+ if (blk)
+ *blk = cur_blk; /* update record starting block */
+
+ return mrec; /* found MFT record */
+ }
+
+ if (next_offset >= BLOCK_SIZE(fs)) {
+ /* try the next FS block */
+ offset = 0;
+ cur_blk = right_blk - mft_blk + 1;
+ } else {
+ /* there's still content to fetch in the current block */
+ cur_blk = right_blk - mft_blk;
+ offset = next_offset; /* update FS block offset */
+ }
+ }
+
+ free(buf);
+
+ return NULL;
+}
+
+static struct ntfs_mft_record *ntfs_mft_record_lookup_3_1(struct fs_info *fs,
+ uint32_t file, block_t *blk)
+{
+ const uint64_t mft_record_size = NTFS_SB(fs)->mft_record_size;
+ uint8_t *buf;
+ const block_t mft_blk = NTFS_SB(fs)->mft_blk;
+ block_t cur_blk;
+ block_t right_blk;
+ uint64_t offset;
+ uint64_t next_offset;
+ const uint32_t mft_record_shift = ilog2(mft_record_size);
+ const uint32_t clust_byte_shift = NTFS_SB(fs)->clust_byte_shift;
+ uint64_t lcn;
+ int err;
+ struct ntfs_mft_record *mrec;
+
+ dprintf("in %s()\n", __func__);
+
+ buf = (uint8_t *)malloc(mft_record_size);
+ if (!buf)
+ malloc_error("uint8_t *");
+
+ lcn = NTFS_SB(fs)->mft_lcn + (file << mft_record_shift >> clust_byte_shift);
+ cur_blk = (lcn << clust_byte_shift >> BLOCK_SHIFT(fs)) - mft_blk;
+ offset = (file << mft_record_shift) % BLOCK_SIZE(fs);
+ for (;;) {
+ right_blk = cur_blk + NTFS_SB(fs)->mft_blk;
+ err = ntfs_read(fs, buf, mft_record_size, mft_record_size, &right_blk,
+ &offset, &next_offset, &lcn);
+ if (err) {
+ printf("Error while reading from cache.\n");
+ break;
+ }
+
+ ntfs_fixups_writeback(fs, (struct ntfs_record *)buf);
+
+ mrec = (struct ntfs_mft_record *)buf;
+ /* Check if the NTFS 3.1 MFT record number matches */
+ if (mrec->magic == NTFS_MAGIC_FILE && mrec->mft_record_no == file) {
+ if (blk)
+ *blk = cur_blk; /* update record starting block */
+
+ return mrec; /* found MFT record */
+ }
+
+ if (next_offset >= BLOCK_SIZE(fs)) {
+ /* try the next FS block */
+ offset = 0;
+ cur_blk = right_blk - NTFS_SB(fs)->mft_blk + 1;
+ } else {
+ /* there's still content to fetch in the current block */
+ cur_blk = right_blk - NTFS_SB(fs)->mft_blk;
+ offset = next_offset; /* update FS block offset */
+ }
+ }
+
+ free(buf);
+
+ return NULL;
+}
+
+static bool ntfs_filename_cmp(const char *dname, struct ntfs_idx_entry *ie)
+{
+ const uint16_t *entry_fn;
+ uint8_t entry_fn_len;
+ unsigned i;
+
+ dprintf("in %s()\n", __func__);
+
+ entry_fn = ie->key.file_name.file_name;
+ entry_fn_len = ie->key.file_name.file_name_len;
+
+ if (strlen(dname) != entry_fn_len)
+ return false;
+
+ /* Do case-sensitive compares for Posix file names */
+ if (ie->key.file_name.file_name_type == FILE_NAME_POSIX) {
+ for (i = 0; i < entry_fn_len; i++)
+ if (entry_fn[i] != dname[i])
+ return false;
+ } else {
+ for (i = 0; i < entry_fn_len; i++)
+ if (tolower(entry_fn[i]) != tolower(dname[i]))
+ return false;
+ }
+
+ return true;
+}
+
+static inline uint8_t *mapping_chunk_init(struct ntfs_attr_record *attr,
+ struct mapping_chunk *chunk,
+ uint32_t *offset)
+{
+ memset(chunk, 0, sizeof *chunk);
+ *offset = 0U;
+
+ return (uint8_t *)attr + attr->data.non_resident.mapping_pairs_offset;
+}
+
+/* Parse data runs.
+ *
+ * return 0 on success or -1 on failure.
+ */
+static int parse_data_run(const void *stream, uint32_t *offset,
+ uint8_t *attr_len, struct mapping_chunk *chunk)
+{
+ uint8_t *buf; /* Pointer to the zero-terminated byte stream */
+ uint8_t count; /* The count byte */
+ uint8_t v, l; /* v is the number of changed low-order VCN bytes;
+ * l is the number of changed low-order LCN bytes
+ */
+ uint8_t *byte;
+ int byte_shift = 8;
+ int mask;
+ uint8_t val;
+ int64_t res;
+
+ (void)attr_len;
+
+ dprintf("in %s()\n", __func__);
+
+ chunk->flags &= ~MAP_MASK;
+
+ buf = (uint8_t *)stream + *offset;
+ if (buf > attr_len || !*buf) {
+ chunk->flags |= MAP_END; /* we're done */
+ return 0;
+ }
+
+ if (!*offset)
+ chunk->flags |= MAP_START; /* initial chunk */
+
+ count = *buf;
+ v = count & 0x0F;
+ l = count >> 4;
+
+ if (v > 8 || l > 8) /* more than 8 bytes ? */
+ goto out;
+
+ byte = (uint8_t *)buf + v;
+ count = v;
+
+ res = 0LL;
+ while (count--) {
+ val = *byte--;
+ mask = val >> (byte_shift - 1);
+ res = (res << byte_shift) | ((val + mask) ^ mask);
+ }
+
+ chunk->len = res; /* get length data */
+
+ byte = (uint8_t *)buf + v + l;
+ count = l;
+
+ mask = 0xFFFFFFFF;
+ res = 0LL;
+ if (*byte & 0x80)
+ res |= (int64_t)mask; /* sign-extend it */
+
+ while (count--)
+ res = (res << byte_shift) | *byte--;
+
+ chunk->lcn += res;
+ /* are VCNS from cur_vcn to next_vcn - 1 unallocated ? */
+ if (!chunk->lcn)
+ chunk->flags |= MAP_UNALLOCATED;
+ else
+ chunk->flags |= MAP_ALLOCATED;
+
+ *offset += v + l + 1;
+
+ return 0;
+
+out:
+ return -1;
+}
+
+static struct ntfs_mft_record *
+ntfs_attr_list_lookup(struct fs_info *fs, struct ntfs_attr_record *attr,
+ uint32_t type, struct ntfs_mft_record *mrec)
+{
+ uint8_t *attr_len;
+ struct mapping_chunk chunk;
+ uint32_t offset;
+ uint8_t *stream;
+ int err;
+ const uint64_t blk_size = UINT64_C(1) << BLOCK_SHIFT(fs);
+ uint8_t buf[blk_size];
+ uint64_t blk_offset;
+ int64_t vcn;
+ int64_t lcn;
+ int64_t last_lcn;
+ block_t blk;
+ struct ntfs_attr_list_entry *attr_entry;
+ uint32_t len = 0;
+ struct ntfs_mft_record *retval;
+ uint64_t start_blk = 0;
+
+ dprintf("in %s()\n", __func__);
+
+ if (attr->non_resident)
+ goto handle_non_resident_attr;
+
+ attr_entry = (struct ntfs_attr_list_entry *)
+ ((uint8_t *)attr + attr->data.resident.value_offset);
+ len = attr->data.resident.value_len;
+ for (; (uint8_t *)attr_entry < (uint8_t *)attr + len;
+ attr_entry = (struct ntfs_attr_list_entry *)((uint8_t *)attr_entry +
+ attr_entry->length)) {
+ dprintf("<$ATTRIBUTE_LIST> Attribute type: 0x%X\n",
+ attr_entry->type);
+ if (attr_entry->type == type)
+ goto found; /* We got the attribute! :-) */
+ }
+
+ printf("No attribute found.\n");
+ goto out;
+
+handle_non_resident_attr:
+ attr_len = (uint8_t *)attr + attr->len;
+ stream = mapping_chunk_init(attr, &chunk, &offset);
+ do {
+ err = parse_data_run(stream, &offset, attr_len, &chunk);
+ if (err) {
+ printf("parse_data_run()\n");
+ goto out;
+ }
+
+ if (chunk.flags & MAP_UNALLOCATED)
+ continue;
+ if (chunk.flags & MAP_END)
+ break;
+ if (chunk.flags & MAP_ALLOCATED) {
+ vcn = 0;
+ lcn = chunk.lcn;
+ while (vcn < chunk.len) {
+ blk = (lcn + vcn) << NTFS_SB(fs)->clust_byte_shift >>
+ BLOCK_SHIFT(fs);
+ blk_offset = 0;
+ last_lcn = lcn;
+ lcn += vcn;
+ err = ntfs_read(fs, buf, blk_size, blk_size, &blk,
+ &blk_offset, NULL, (uint64_t *)&lcn);
+ if (err) {
+ printf("Error while reading from cache.\n");
+ goto out;
+ }
+
+ attr_entry = (struct ntfs_attr_list_entry *)&buf;
+ len = attr->data.non_resident.data_size;
+ for (; (uint8_t *)attr_entry < (uint8_t *)&buf[0] + len;
+ attr_entry = (struct ntfs_attr_list_entry *)
+ ((uint8_t *)attr_entry + attr_entry->length)) {
+ dprintf("<$ATTRIBUTE_LIST> Attribute type: 0x%x\n",
+ attr_entry->type);
+ if (attr_entry->type == type)
+ goto found; /* We got the attribute! :-) */
+ }
+
+ lcn = last_lcn; /* restore original LCN */
+ /* go to the next VCN */
+ vcn += (blk_size / (1 << NTFS_SB(fs)->clust_byte_shift));
+ }
+ }
+ } while (!(chunk.flags & MAP_END));
+
+ printf("No attribute found.\n");
+
+out:
+ return NULL;
+
+found:
+ /* At this point we have the attribute we were looking for. Now we
+ * will look for the MFT record that stores information about this
+ * attribute.
+ */
+
+ /* Check if the attribute type we're looking for is in the same
+ * MFT record. If so, we do not need to look it up again - return it.
+ */
+ if (mrec->mft_record_no == attr_entry->mft_ref)
+ return mrec;
+
+ retval = NTFS_SB(fs)->mft_record_lookup(fs, attr_entry->mft_ref,
+ &start_blk);
+ if (!retval) {
+ printf("No MFT record found!\n");
+ goto out;
+ }
+
+ /* return the found MFT record */
+ return retval;
+}
+
+static struct ntfs_attr_record *
+__ntfs_attr_lookup(struct fs_info *fs, uint32_t type,
+ struct ntfs_mft_record **mrec)
+{
+ struct ntfs_mft_record *_mrec = *mrec;
+ struct ntfs_attr_record *attr;
+ struct ntfs_attr_record *attr_list_attr;
+
+ dprintf("in %s()\n", __func__);
+
+ if (!_mrec || type == NTFS_AT_END)
+ goto out;
+
+again:
+ attr_list_attr = NULL;
+
+ attr = (struct ntfs_attr_record *)((uint8_t *)_mrec + _mrec->attrs_offset);
+ /* walk through the file attribute records */
+ for (;; attr = (struct ntfs_attr_record *)((uint8_t *)attr + attr->len)) {
+ if (attr->type == NTFS_AT_END)
+ break;
+
+ if (attr->type == NTFS_AT_ATTR_LIST) {
+ dprintf("MFT record #%lu has an $ATTRIBUTE_LIST attribute.\n",
+ _mrec->mft_record_no);
+ attr_list_attr = attr;
+ continue;
+ }
+
+ if (attr->type == type)
+ break;
+ }
+
+ /* if the record has an $ATTRIBUTE_LIST attribute associated
+ * with it, then we need to look for the wanted attribute in
+ * it as well.
+ */
+ if (attr->type == NTFS_AT_END && attr_list_attr) {
+ struct ntfs_mft_record *retval;
+
+ retval = ntfs_attr_list_lookup(fs, attr_list_attr, type, _mrec);
+ if (!retval)
+ goto out;
+
+ _mrec = retval;
+ goto again;
+ } else if (attr->type == NTFS_AT_END && !attr_list_attr) {
+ attr = NULL;
+ }
+
+ return attr;
+
+out:
+ return NULL;
+}
+
+static inline struct ntfs_attr_record *
+ntfs_attr_lookup(struct fs_info *fs, uint32_t type,
+ struct ntfs_mft_record **mmrec,
+ struct ntfs_mft_record *mrec)
+{
+ struct ntfs_mft_record *_mrec = mrec;
+ struct ntfs_mft_record *other = *mmrec;
+ struct ntfs_attr_record *retval = NULL;
+
+ if (mrec == other)
+ return __ntfs_attr_lookup(fs, type, &other);
+
+ retval = __ntfs_attr_lookup(fs, type, &_mrec);
+ if (!retval) {
+ _mrec = other;
+ retval = __ntfs_attr_lookup(fs, type, &other);
+ if (!retval)
+ other = _mrec;
+ } else if (retval && (_mrec != mrec)) {
+ other = _mrec;
+ }
+
+ return retval;
+}
+
+static inline enum dirent_type get_inode_mode(struct ntfs_mft_record *mrec)
+{
+ return mrec->flags & MFT_RECORD_IS_DIRECTORY ? DT_DIR : DT_REG;
+}
+
+static int index_inode_setup(struct fs_info *fs, unsigned long mft_no,
+ struct inode *inode)
+{
+ uint64_t start_blk = 0;
+ struct ntfs_mft_record *mrec, *lmrec;
+ struct ntfs_attr_record *attr;
+ enum dirent_type d_type;
+ uint8_t *attr_len;
+ struct mapping_chunk chunk;
+ int err;
+ uint8_t *stream;
+ uint32_t offset;
+
+ dprintf("in %s()\n", __func__);
+
+ mrec = NTFS_SB(fs)->mft_record_lookup(fs, mft_no, &start_blk);
+ if (!mrec) {
+ printf("No MFT record found.\n");
+ goto out;
+ }
+
+ lmrec = mrec;
+
+ NTFS_PVT(inode)->mft_no = mft_no;
+ NTFS_PVT(inode)->seq_no = mrec->seq_no;
+
+ NTFS_PVT(inode)->start_cluster = start_blk >> NTFS_SB(fs)->clust_shift;
+ NTFS_PVT(inode)->here = start_blk;
+
+ d_type = get_inode_mode(mrec);
+ if (d_type == DT_DIR) { /* directory stuff */
+ dprintf("Got a directory.\n");
+ attr = ntfs_attr_lookup(fs, NTFS_AT_INDEX_ROOT, &mrec, lmrec);
+ if (!attr) {
+ printf("No attribute found.\n");
+ goto out;
+ }
+
+ /* check if we have a previous allocated state structure */
+ if (readdir_state) {
+ free(readdir_state);
+ readdir_state = NULL;
+ }
+
+ /* allocate our state structure */
+ readdir_state = malloc(sizeof *readdir_state);
+ if (!readdir_state)
+ malloc_error("ntfs_readdir_state structure");
+
+ readdir_state->mft_no = mft_no;
+ /* obviously, the ntfs_readdir() caller will start from INDEX root */
+ readdir_state->in_idx_root = true;
+ } else if (d_type == DT_REG) { /* file stuff */
+ dprintf("Got a file.\n");
+ attr = ntfs_attr_lookup(fs, NTFS_AT_DATA, &mrec, lmrec);
+ if (!attr) {
+ printf("No attribute found.\n");
+ goto out;
+ }
+
+ NTFS_PVT(inode)->non_resident = attr->non_resident;
+ NTFS_PVT(inode)->type = attr->type;
+
+ if (!attr->non_resident) {
+ NTFS_PVT(inode)->data.resident.offset =
+ (uint32_t)((uint8_t *)attr + attr->data.resident.value_offset);
+ inode->size = attr->data.resident.value_len;
+ } else {
+ attr_len = (uint8_t *)attr + attr->len;
+
+ stream = mapping_chunk_init(attr, &chunk, &offset);
+ NTFS_PVT(inode)->data.non_resident.rlist = NULL;
+ for (;;) {
+ err = parse_data_run(stream, &offset, attr_len, &chunk);
+ if (err) {
+ printf("parse_data_run()\n");
+ goto out;
+ }
+
+ if (chunk.flags & MAP_UNALLOCATED)
+ continue;
+ if (chunk.flags & MAP_END)
+ break;
+ if (chunk.flags & MAP_ALLOCATED) {
+ /* append new run to the runlist */
+ runlist_append(&NTFS_PVT(inode)->data.non_resident.rlist,
+ (struct runlist_element *)&chunk);
+ /* update for next VCN */
+ chunk.vcn += chunk.len;
+ }
+ }
+
+ if (runlist_is_empty(NTFS_PVT(inode)->data.non_resident.rlist)) {
+ printf("No mapping found\n");
+ goto out;
+ }
+
+ inode->size = attr->data.non_resident.initialized_size;
+ }
+ }
+
+ inode->mode = d_type;
+
+ free(mrec);
+
+ return 0;
+
+out:
+ free(mrec);
+
+ return -1;
+}
+
+static struct inode *ntfs_index_lookup(const char *dname, struct inode *dir)
+{
+ struct fs_info *fs = dir->fs;
+ struct ntfs_mft_record *mrec, *lmrec;
+ block_t blk;
+ uint64_t blk_offset;
+ struct ntfs_attr_record *attr;
+ struct ntfs_idx_root *ir;
+ struct ntfs_idx_entry *ie;
+ const uint64_t blk_size = UINT64_C(1) << BLOCK_SHIFT(fs);
+ uint8_t buf[blk_size];
+ struct ntfs_idx_allocation *iblk;
+ int err;
+ uint8_t *stream;
+ uint8_t *attr_len;
+ struct mapping_chunk chunk;
+ uint32_t offset;
+ int64_t vcn;
+ int64_t lcn;
+ int64_t last_lcn;
+ struct inode *inode;
+
+ dprintf("in %s()\n", __func__);
+
+ mrec = NTFS_SB(fs)->mft_record_lookup(fs, NTFS_PVT(dir)->mft_no, NULL);
+ if (!mrec) {
+ printf("No MFT record found.\n");
+ goto out;
+ }
+
+ lmrec = mrec;
+ attr = ntfs_attr_lookup(fs, NTFS_AT_INDEX_ROOT, &mrec, lmrec);
+ if (!attr) {
+ printf("No attribute found.\n");
+ goto out;
+ }
+
+ ir = (struct ntfs_idx_root *)((uint8_t *)attr +
+ attr->data.resident.value_offset);
+ ie = (struct ntfs_idx_entry *)((uint8_t *)&ir->index +
+ ir->index.entries_offset);
+ for (;; ie = (struct ntfs_idx_entry *)((uint8_t *)ie + ie->len)) {
+ /* bounds checks */
+ if ((uint8_t *)ie < (uint8_t *)mrec ||
+ (uint8_t *)ie + sizeof(struct ntfs_idx_entry_header) >
+ (uint8_t *)&ir->index + ir->index.index_len ||
+ (uint8_t *)ie + ie->len >
+ (uint8_t *)&ir->index + ir->index.index_len)
+ goto index_err;
+
+ /* last entry cannot contain a key. it can however contain
+ * a pointer to a child node in the B+ tree so we just break out
+ */
+ if (ie->flags & INDEX_ENTRY_END)
+ break;
+
+ if (ntfs_filename_cmp(dname, ie))
+ goto found;
+ }
+
+ /* check for the presence of a child node */
+ if (!(ie->flags & INDEX_ENTRY_NODE)) {
+ printf("No child node, aborting...\n");
+ goto out;
+ }
+
+ /* then descend into child node */
+
+ attr = ntfs_attr_lookup(fs, NTFS_AT_INDEX_ALLOCATION, &mrec, lmrec);
+ if (!attr) {
+ printf("No attribute found.\n");
+ goto out;
+ }
+
+ if (!attr->non_resident) {
+ printf("WTF ?! $INDEX_ALLOCATION isn't really resident.\n");
+ goto out;
+ }
+
+ attr_len = (uint8_t *)attr + attr->len;
+ stream = mapping_chunk_init(attr, &chunk, &offset);
+ do {
+ err = parse_data_run(stream, &offset, attr_len, &chunk);
+ if (err)
+ break;
+
+ if (chunk.flags & MAP_UNALLOCATED)
+ continue;
+
+ if (chunk.flags & MAP_ALLOCATED) {
+ dprintf("%d cluster(s) starting at 0x%08llX\n", chunk.len,
+ chunk.lcn);
+
+ vcn = 0;
+ lcn = chunk.lcn;
+ while (vcn < chunk.len) {
+ blk = (lcn + vcn) << NTFS_SB(fs)->clust_shift <<
+ SECTOR_SHIFT(fs) >> BLOCK_SHIFT(fs);
+
+ blk_offset = 0;
+ last_lcn = lcn;
+ lcn += vcn;
+ err = ntfs_read(fs, &buf, blk_size, blk_size, &blk,
+ &blk_offset, NULL, (uint64_t *)&lcn);
+ if (err) {
+ printf("Error while reading from cache.\n");
+ goto not_found;
+ }
+
+ ntfs_fixups_writeback(fs, (struct ntfs_record *)&buf);
+
+ iblk = (struct ntfs_idx_allocation *)&buf;
+ if (iblk->magic != NTFS_MAGIC_INDX) {
+ printf("Not a valid INDX record.\n");
+ goto not_found;
+ }
+
+ ie = (struct ntfs_idx_entry *)((uint8_t *)&iblk->index +
+ iblk->index.entries_offset);
+ for (;; ie = (struct ntfs_idx_entry *)((uint8_t *)ie +
+ ie->len)) {
+ /* bounds checks */
+ if ((uint8_t *)ie < (uint8_t *)iblk || (uint8_t *)ie +
+ sizeof(struct ntfs_idx_entry_header) >
+ (uint8_t *)&iblk->index + iblk->index.index_len ||
+ (uint8_t *)ie + ie->len >
+ (uint8_t *)&iblk->index + iblk->index.index_len)
+ goto index_err;
+
+ /* last entry cannot contain a key */
+ if (ie->flags & INDEX_ENTRY_END)
+ break;
+
+ if (ntfs_filename_cmp(dname, ie))
+ goto found;
+ }
+
+ lcn = last_lcn; /* restore the original LCN */
+ /* go to the next VCN */
+ vcn += (blk_size / (1 << NTFS_SB(fs)->clust_byte_shift));
+ }
+ }
+ } while (!(chunk.flags & MAP_END));
+
+not_found:
+ dprintf("Index not found\n");
+
+out:
+ free(mrec);
+
+ return NULL;
+
+found:
+ dprintf("Index found\n");
+ inode = new_ntfs_inode(fs);
+ err = index_inode_setup(fs, ie->data.dir.indexed_file, inode);
+ if (err) {
+ printf("Error in index_inode_setup()\n");
+ free(inode);
+ goto out;
+ }
+
+ free(mrec);
+
+ return inode;
+
+index_err:
+ printf("Corrupt index. Aborting lookup...\n");
+ goto out;
+}
+
+/* Convert an UTF-16LE LFN to OEM LFN */
+static uint8_t ntfs_cvt_filename(char *filename,
+ const struct ntfs_idx_entry *ie)
+{
+ const uint16_t *entry_fn;
+ uint8_t entry_fn_len;
+ unsigned i;
+
+ entry_fn = ie->key.file_name.file_name;
+ entry_fn_len = ie->key.file_name.file_name_len;
+
+ for (i = 0; i < entry_fn_len; i++)
+ filename[i] = (char)entry_fn[i];
+
+ filename[i] = '\0';
+
+ return entry_fn_len;
+}
+
+static int ntfs_next_extent(struct inode *inode, uint32_t lstart)
+{
+ struct fs_info *fs = inode->fs;
+ struct ntfs_sb_info *sbi = NTFS_SB(fs);
+ sector_t pstart = 0;
+ struct runlist *rlist;
+ struct runlist *ret;
+ const uint32_t sec_size = SECTOR_SIZE(fs);
+ const uint32_t sec_shift = SECTOR_SHIFT(fs);
+
+ dprintf("in %s()\n", __func__);
+
+ if (!NTFS_PVT(inode)->non_resident) {
+ pstart = (sbi->mft_blk + NTFS_PVT(inode)->here) << BLOCK_SHIFT(fs) >>
+ sec_shift;
+ inode->next_extent.len = (inode->size + sec_size - 1) >> sec_shift;
+ } else {
+ rlist = NTFS_PVT(inode)->data.non_resident.rlist;
+
+ if (!lstart || lstart >= NTFS_PVT(inode)->here) {
+ if (runlist_is_empty(rlist))
+ goto out; /* nothing to do ;-) */
+
+ ret = runlist_remove(&rlist);
+
+ NTFS_PVT(inode)->here =
+ ((ret->run.len << sbi->clust_byte_shift) >> sec_shift);
+
+ pstart = ret->run.lcn << sbi->clust_shift;
+ inode->next_extent.len =
+ ((ret->run.len << sbi->clust_byte_shift) + sec_size - 1) >>
+ sec_shift;
+
+ NTFS_PVT(inode)->data.non_resident.rlist = rlist;
+
+ free(ret);
+ ret = NULL;
+ }
+ }
+
+ inode->next_extent.pstart = pstart;
+
+ return 0;
+
+out:
+ return -1;
+}
+
+static uint32_t ntfs_getfssec(struct file *file, char *buf, int sectors,
+ bool *have_more)
+{
+ uint8_t non_resident;
+ uint32_t ret;
+ struct fs_info *fs = file->fs;
+ struct inode *inode = file->inode;
+ struct ntfs_mft_record *mrec, *lmrec;
+ struct ntfs_attr_record *attr;
+ char *p;
+
+ dprintf("in %s()\n", __func__);
+
+ non_resident = NTFS_PVT(inode)->non_resident;
+
+ ret = generic_getfssec(file, buf, sectors, have_more);
+ if (!ret)
+ return ret;
+
+ if (!non_resident) {
+ mrec = NTFS_SB(fs)->mft_record_lookup(fs, NTFS_PVT(inode)->mft_no,
+ NULL);
+ if (!mrec) {
+ printf("No MFT record found.\n");
+ goto out;
+ }
+
+ lmrec = mrec;
+ attr = ntfs_attr_lookup(fs, NTFS_AT_DATA, &mrec, lmrec);
+ if (!attr) {
+ printf("No attribute found.\n");
+ goto out;
+ }
+
+ p = (char *)((uint8_t *)attr + attr->data.resident.value_offset);
+
+ /* p now points to the data offset, so let's copy it into buf */
+ memcpy(buf, p, inode->size);
+
+ ret = inode->size;
+
+ free(mrec);
+ }
+
+ return ret;
+
+out:
+ free(mrec);
+
+ return 0;
+}
+
+static inline bool is_filename_printable(const char *s)
+{
+ return s && (*s != '.' && *s != '$');
+}
+
+static int ntfs_readdir(struct file *file, struct dirent *dirent)
+{
+ struct fs_info *fs = file->fs;
+ struct inode *inode = file->inode;
+ struct ntfs_mft_record *mrec, *lmrec;
+ block_t blk;
+ uint64_t blk_offset;
+ const uint64_t blk_size = UINT64_C(1) << BLOCK_SHIFT(fs);
+ struct ntfs_attr_record *attr;
+ struct ntfs_idx_root *ir;
+ uint32_t count;
+ int len;
+ struct ntfs_idx_entry *ie = NULL;
+ uint8_t buf[BLOCK_SIZE(fs)];
+ struct ntfs_idx_allocation *iblk;
+ int err;
+ uint8_t *stream;
+ uint8_t *attr_len;
+ struct mapping_chunk chunk;
+ uint32_t offset;
+ int64_t vcn;
+ int64_t lcn;
+ char filename[NTFS_MAX_FILE_NAME_LEN + 1];
+
+ dprintf("in %s()\n", __func__);
+
+ mrec = NTFS_SB(fs)->mft_record_lookup(fs, NTFS_PVT(inode)->mft_no, NULL);
+ if (!mrec) {
+ printf("No MFT record found.\n");
+ goto out;
+ }
+
+ lmrec = mrec;
+ attr = ntfs_attr_lookup(fs, NTFS_AT_INDEX_ROOT, &mrec, lmrec);
+ if (!attr) {
+ printf("No attribute found.\n");
+ goto out;
+ }
+
+ ir = (struct ntfs_idx_root *)((uint8_t *)attr +
+ attr->data.resident.value_offset);
+
+ if (!file->offset && readdir_state->in_idx_root) {
+ file->offset = (uint32_t)((uint8_t *)&ir->index +
+ ir->index.entries_offset);
+ }
+
+idx_root_next_entry:
+ if (readdir_state->in_idx_root) {
+ ie = (struct ntfs_idx_entry *)(uint8_t *)file->offset;
+ if (ie->flags & INDEX_ENTRY_END) {
+ file->offset = 0;
+ readdir_state->in_idx_root = false;
+ readdir_state->idx_blks_count = 1;
+ readdir_state->entries_count = 0;
+ readdir_state->last_vcn = 0;
+ goto descend_into_child_node;
+ }
+
+ file->offset = (uint32_t)((uint8_t *)ie + ie->len);
+ len = ntfs_cvt_filename(filename, ie);
+ if (!is_filename_printable(filename))
+ goto idx_root_next_entry;
+
+ goto done;
+ }
+
+descend_into_child_node:
+ if (!(ie->flags & INDEX_ENTRY_NODE))
+ goto out;
+
+ attr = ntfs_attr_lookup(fs, NTFS_AT_INDEX_ALLOCATION, &mrec, lmrec);
+ if (!attr)
+ goto out;
+
+ if (!attr->non_resident) {
+ printf("WTF ?! $INDEX_ALLOCATION isn't really resident.\n");
+ goto out;
+ }
+
+ attr_len = (uint8_t *)attr + attr->len;
+
+next_run:
+ stream = mapping_chunk_init(attr, &chunk, &offset);
+ count = readdir_state->idx_blks_count;
+ while (count--) {
+ err = parse_data_run(stream, &offset, attr_len, &chunk);
+ if (err) {
+ printf("Error while parsing data runs.\n");
+ goto out;
+ }
+
+ if (chunk.flags & MAP_UNALLOCATED)
+ break;
+ if (chunk.flags & MAP_END)
+ goto out;
+ }
+
+ if (chunk.flags & MAP_UNALLOCATED) {
+ readdir_state->idx_blks_count++;
+ goto next_run;
+ }
+
+next_vcn:
+ vcn = readdir_state->last_vcn;
+ if (vcn >= chunk.len) {
+ readdir_state->last_vcn = 0;
+ readdir_state->idx_blks_count++;
+ goto next_run;
+ }
+
+ lcn = chunk.lcn;
+ blk = (lcn + vcn) << NTFS_SB(fs)->clust_shift << SECTOR_SHIFT(fs) >>
+ BLOCK_SHIFT(fs);
+
+ blk_offset = 0;
+ err = ntfs_read(fs, &buf, blk_size, blk_size, &blk, &blk_offset, NULL,
+ (uint64_t *)&lcn);
+ if (err) {
+ printf("Error while reading from cache.\n");
+ goto not_found;
+ }
+
+ ntfs_fixups_writeback(fs, (struct ntfs_record *)&buf);
+
+ iblk = (struct ntfs_idx_allocation *)&buf;
+ if (iblk->magic != NTFS_MAGIC_INDX) {
+ printf("Not a valid INDX record.\n");
+ goto not_found;
+ }
+
+idx_block_next_entry:
+ ie = (struct ntfs_idx_entry *)((uint8_t *)&iblk->index +
+ iblk->index.entries_offset);
+ count = readdir_state->entries_count;
+ for ( ; count--; ie = (struct ntfs_idx_entry *)((uint8_t *)ie + ie->len)) {
+ /* bounds checks */
+ if ((uint8_t *)ie < (uint8_t *)iblk || (uint8_t *)ie +
+ sizeof(struct ntfs_idx_entry_header) >
+ (uint8_t *)&iblk->index + iblk->index.index_len ||
+ (uint8_t *)ie + ie->len >
+ (uint8_t *)&iblk->index + iblk->index.index_len)
+ goto index_err;
+
+ /* last entry cannot contain a key */
+ if (ie->flags & INDEX_ENTRY_END) {
+ /* go to the next VCN */
+ readdir_state->last_vcn += (blk_size / (1 <<
+ NTFS_SB(fs)->clust_byte_shift));
+ readdir_state->entries_count = 0;
+ goto next_vcn;
+ }
+ }
+
+ readdir_state->entries_count++;
+
+ /* Need to check if this entry has INDEX_ENTRY_END flag set. If
+ * so, then it won't contain a indexed_file file, so continue the
+ * lookup on the next VCN/LCN (if any).
+ */
+ if (ie->flags & INDEX_ENTRY_END)
+ goto next_vcn;
+
+ len = ntfs_cvt_filename(filename, ie);
+ if (!is_filename_printable(filename))
+ goto idx_block_next_entry;
+
+ goto done;
+
+out:
+ readdir_state->in_idx_root = true;
+
+ free(mrec);
+
+ return -1;
+
+done:
+ dirent->d_ino = ie->data.dir.indexed_file;
+ dirent->d_off = file->offset;
+ dirent->d_reclen = offsetof(struct dirent, d_name) + len + 1;
+
+ free(mrec);
+
+ mrec = NTFS_SB(fs)->mft_record_lookup(fs, ie->data.dir.indexed_file, NULL);
+ if (!mrec) {
+ printf("No MFT record found.\n");
+ goto out;
+ }
+
+ dirent->d_type = get_inode_mode(mrec);
+ memcpy(dirent->d_name, filename, len + 1);
+
+ free(mrec);
+
+ return 0;
+
+not_found:
+ printf("Index not found\n");
+ goto out;
+
+index_err:
+ printf("Corrupt index. Aborting lookup...\n");
+ goto out;
+}
+
+static inline struct inode *ntfs_iget(const char *dname, struct inode *parent)
+{
+ return ntfs_index_lookup(dname, parent);
+}
+
+static struct inode *ntfs_iget_root(struct fs_info *fs)
+{
+ uint64_t start_blk;
+ struct ntfs_mft_record *mrec, *lmrec;
+ struct ntfs_attr_record *attr;
+ struct ntfs_vol_info *vol_info;
+ struct inode *inode;
+ int err;
+
+ dprintf("in %s()\n", __func__);
+
+ /* Fetch the $Volume MFT record */
+ start_blk = 0;
+ mrec = NTFS_SB(fs)->mft_record_lookup(fs, FILE_Volume, &start_blk);
+ if (!mrec) {
+ printf("Could not fetch $Volume MFT record!\n");
+ goto err_mrec;
+ }
+
+ lmrec = mrec;
+
+ /* Fetch the volume information attribute */
+ attr = ntfs_attr_lookup(fs, NTFS_AT_VOL_INFO, &mrec, lmrec);
+ if (!attr) {
+ printf("Could not find volume info attribute!\n");
+ goto err_attr;
+ }
+
+ /* Note NTFS version and choose version-dependent functions */
+ vol_info = (void *)((char *)attr + attr->data.resident.value_offset);
+ NTFS_SB(fs)->major_ver = vol_info->major_ver;
+ NTFS_SB(fs)->minor_ver = vol_info->minor_ver;
+ if (vol_info->major_ver == 3 && vol_info->minor_ver == 0)
+ NTFS_SB(fs)->mft_record_lookup = ntfs_mft_record_lookup_3_0;
+ else if (vol_info->major_ver == 3 && vol_info->minor_ver == 1 &&
+ mrec->mft_record_no == FILE_Volume)
+ NTFS_SB(fs)->mft_record_lookup = ntfs_mft_record_lookup_3_1;
+
+ /* Free MFT record */
+ free(mrec);
+ mrec = NULL;
+
+ inode = new_ntfs_inode(fs);
+ inode->fs = fs;
+
+ err = index_inode_setup(fs, FILE_root, inode);
+ if (err)
+ goto err_setup;
+
+ NTFS_PVT(inode)->start = NTFS_PVT(inode)->here;
+
+ return inode;
+
+err_setup:
+
+ free(inode);
+err_attr:
+
+ free(mrec);
+err_mrec:
+
+ return NULL;
+}
+
+/* Initialize the filesystem metadata and return blk size in bits */
+static int ntfs_fs_init(struct fs_info *fs)
+{
+ int read_count;
+ struct ntfs_bpb ntfs;
+ struct ntfs_sb_info *sbi;
+ struct disk *disk = fs->fs_dev->disk;
+ uint8_t mft_record_shift;
+
+ dprintf("in %s()\n", __func__);
+
+ read_count = disk->rdwr_sectors(disk, &ntfs, 0, 1, 0);
+ if (!read_count)
+ return -1;
+
+ if (!ntfs_check_sb_fields(&ntfs))
+ return -1;
+
+ SECTOR_SHIFT(fs) = disk->sector_shift;
+
+ /* Note: ntfs.clust_per_mft_record can be a negative number.
+ * If negative, it represents a shift count, else it represents
+ * a multiplier for the cluster size.
+ */
+ mft_record_shift = ntfs.clust_per_mft_record < 0 ?
+ -ntfs.clust_per_mft_record :
+ ilog2(ntfs.sec_per_clust) + SECTOR_SHIFT(fs) +
+ ilog2(ntfs.clust_per_mft_record);
+
+ SECTOR_SIZE(fs) = 1 << SECTOR_SHIFT(fs);
+
+ sbi = malloc(sizeof *sbi);
+ if (!sbi)
+ malloc_error("ntfs_sb_info structure");
+
+ fs->fs_info = sbi;
+
+ sbi->clust_shift = ilog2(ntfs.sec_per_clust);
+ sbi->clust_byte_shift = sbi->clust_shift + SECTOR_SHIFT(fs);
+ sbi->clust_mask = ntfs.sec_per_clust - 1;
+ sbi->clust_size = ntfs.sec_per_clust << SECTOR_SHIFT(fs);
+ sbi->mft_record_size = 1 << mft_record_shift;
+ sbi->clust_per_idx_record = ntfs.clust_per_idx_record;
+
+ BLOCK_SHIFT(fs) = ilog2(ntfs.clust_per_idx_record) + sbi->clust_byte_shift;
+ BLOCK_SIZE(fs) = 1 << BLOCK_SHIFT(fs);
+
+ sbi->mft_lcn = ntfs.mft_lclust;
+ sbi->mft_blk = ntfs.mft_lclust << sbi->clust_shift << SECTOR_SHIFT(fs) >>
+ BLOCK_SHIFT(fs);
+ /* 16 MFT entries reserved for metadata files (approximately 16 KiB) */
+ sbi->mft_size = mft_record_shift << sbi->clust_shift << 4;
+
+ sbi->clusters = ntfs.total_sectors << SECTOR_SHIFT(fs) >> sbi->clust_shift;
+ if (sbi->clusters > 0xFFFFFFFFFFF4ULL)
+ sbi->clusters = 0xFFFFFFFFFFF4ULL;
+
+ /*
+ * Assume NTFS version 3.0 to begin with. If we find that the
+ * volume is a different version later on, we will adjust at
+ * that time.
+ */
+ sbi->major_ver = 3;
+ sbi->minor_ver = 0;
+ sbi->mft_record_lookup = ntfs_mft_record_lookup_3_0;
+
+ /* Initialize the cache */
+ cache_init(fs->fs_dev, BLOCK_SHIFT(fs));
+
+ return BLOCK_SHIFT(fs);
+}
+
+const struct fs_ops ntfs_fs_ops = {
+ .fs_name = "ntfs",
+ .fs_flags = FS_USEMEM | FS_THISIND,
+ .fs_init = ntfs_fs_init,
+ .searchdir = NULL,
+ .getfssec = ntfs_getfssec,
+ .close_file = generic_close_file,
+ .mangle_name = generic_mangle_name,
+ .load_config = generic_load_config,
+ .readdir = ntfs_readdir,
+ .iget_root = ntfs_iget_root,
+ .iget = ntfs_iget,
+ .next_extent = ntfs_next_extent,
+};
diff --git a/core/fs/ntfs/ntfs.h b/core/fs/ntfs/ntfs.h
new file mode 100644
index 00000000..721a78d7
--- /dev/null
+++ b/core/fs/ntfs/ntfs.h
@@ -0,0 +1,485 @@
+/*
+ * Copyright (C) 2011-2012 Paulo Alcantara <pcacjr@gmail.com>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "runlist.h"
+
+#ifndef _NTFS_H_
+#define _NTFS_H_
+
+struct ntfs_bpb {
+ uint8_t jmp_boot[3];
+ char oem_name[8];
+ uint16_t sector_size;
+ uint8_t sec_per_clust;
+ uint16_t res_sectors;
+ uint8_t zero_0[3];
+ uint16_t zero_1;
+ uint8_t media;
+ uint16_t zero_2;
+ uint16_t unused_0;
+ uint16_t unused_1;
+ uint32_t unused_2;
+ uint32_t zero_3;
+ uint32_t unused_3;
+ uint64_t total_sectors;
+ uint64_t mft_lclust;
+ uint64_t mft_mirr_lclust;
+ int8_t clust_per_mft_record;
+ uint8_t unused_4[3];
+ uint8_t clust_per_idx_record;
+ uint8_t unused_5[3];
+ uint64_t vol_serial;
+ uint32_t unused_6;
+
+ uint8_t pad[428]; /* padding to a sector boundary (512 bytes) */
+} __attribute__((__packed__));
+
+/* Function type for an NTFS-version-dependent MFT record lookup */
+struct ntfs_mft_record;
+typedef struct ntfs_mft_record *f_mft_record_lookup(struct fs_info *,
+ uint32_t, block_t *);
+
+struct ntfs_sb_info {
+ block_t mft_blk; /* The first MFT record block */
+ uint64_t mft_lcn; /* LCN of the first MFT record */
+ unsigned mft_size; /* The MFT size in sectors */
+ uint64_t mft_record_size; /* MFT record size in bytes */
+
+ uint8_t clust_per_idx_record; /* Clusters per Index Record */
+
+ unsigned long long clusters; /* Total number of clusters */
+
+ unsigned clust_shift; /* Based on sectors */
+ unsigned clust_byte_shift; /* Based on bytes */
+ unsigned clust_mask;
+ unsigned clust_size;
+
+ uint8_t major_ver; /* Major version from $Volume */
+ uint8_t minor_ver; /* Minor version from $Volume */
+
+ /* NTFS-version-dependent MFT record lookup function to use */
+ f_mft_record_lookup *mft_record_lookup;
+} __attribute__((__packed__));
+
+/* The NTFS in-memory inode structure */
+struct ntfs_inode {
+ int64_t initialized_size;
+ int64_t allocated_size;
+ unsigned long mft_no; /* Number of the mft record / inode */
+ uint16_t seq_no; /* Sequence number of the mft record */
+ uint32_t type; /* Attribute type of this inode */
+ uint8_t non_resident;
+ union { /* Non-resident $DATA attribute */
+ struct { /* Used only if non_resident flags isn't set */
+ uint32_t offset; /* Data offset */
+ } resident;
+ struct { /* Used only if non_resident is set */
+ struct runlist *rlist;
+ } non_resident;
+ } data;
+ uint32_t start_cluster; /* Starting cluster address */
+ sector_t start; /* Starting sector */
+ sector_t offset; /* Current sector offset */
+ sector_t here; /* Sector corresponding to offset */
+};
+
+/* This is structure is used to keep a state for ntfs_readdir() callers.
+ * As NTFS stores directory entries in a complex way, this is structure
+ * ends up saving a state required to find out where we must start from
+ * for the next ntfs_readdir() call.
+ */
+struct ntfs_readdir_state {
+ unsigned long mft_no; /* MFT record number */
+ bool in_idx_root; /* It's true if we're still in the INDEX root */
+ uint32_t idx_blks_count; /* Number of read INDX blocks */
+ uint32_t entries_count; /* Number of read INDEX entries */
+ int64_t last_vcn; /* Last VCN of the INDX block */
+};
+
+enum {
+ MAP_UNSPEC,
+ MAP_START = 1 << 0,
+ MAP_END = 1 << 1,
+ MAP_ALLOCATED = 1 << 2,
+ MAP_UNALLOCATED = 1 << 3,
+ MAP_MASK = 0x0000000F,
+};
+
+struct mapping_chunk {
+ uint64_t vcn;
+ int64_t lcn;
+ uint64_t len;
+ uint32_t flags;
+};
+
+/* System defined attributes (32-bit)
+ * Each attribute type has a corresponding attribute name (in Unicode)
+ */
+enum {
+ NTFS_AT_UNUSED = 0x00,
+ NTFS_AT_STANDARD_INFORMATION = 0x10,
+ NTFS_AT_ATTR_LIST = 0x20,
+ NTFS_AT_FILENAME = 0x30,
+ NTFS_AT_OBJ_ID = 0x40,
+ NTFS_AT_SECURITY_DESCP = 0x50,
+ NTFS_AT_VOL_NAME = 0x60,
+ NTFS_AT_VOL_INFO = 0x70,
+ NTFS_AT_DATA = 0x80,
+ NTFS_AT_INDEX_ROOT = 0x90,
+ NTFS_AT_INDEX_ALLOCATION = 0xA0,
+ NTFS_AT_BITMAP = 0xB0,
+ NTFS_AT_REPARSE_POINT = 0xC0,
+ NTFS_AT_EA_INFO = 0xD0,
+ NTFS_AT_EA = 0xE0,
+ NTFS_AT_PROPERTY_SET = 0xF0,
+ NTFS_AT_LOGGED_UTIL_STREAM = 0x100,
+ NTFS_AT_FIRST_USER_DEFINED_ATTR = 0x1000,
+ NTFS_AT_END = 0xFFFFFFFF,
+};
+
+/* NTFS File Permissions (also called attributes in DOS terminology) */
+enum {
+ NTFS_FILE_ATTR_READONLY = 0x00000001,
+ NTFS_FILE_ATTR_HIDDEN = 0x00000002,
+ NTFS_FILE_ATTR_SYSTEM = 0x00000004,
+ NTFS_FILE_ATTR_DIRECTORY = 0x00000010,
+ NTFS_FILE_ATTR_ARCHIVE = 0x00000020,
+ NTFS_FILE_ATTR_DEVICE = 0x00000040,
+ NTFS_FILE_ATTR_NORMAL = 0x00000080,
+ NTFS_FILE_ATTR_TEMPORARY = 0x00000100,
+ NTFS_FILE_ATTR_SPARSE_FILE = 0x00000200,
+ NTFS_FILE_ATTR_REPARSE_POINT = 0x00000400,
+ NTFS_FILE_ATTR_COMPRESSED = 0x00000800,
+ NTFS_FILE_ATTR_OFFLINE = 0x00001000,
+ NTFS_FILE_ATTR_NOT_CONTENT_INDEXED = 0x00002000,
+ NTFS_FILE_ATTR_ENCRYPTED = 0x00004000,
+ NTFS_FILE_ATTR_VALID_FLAGS = 0x00007FB7,
+ NTFS_FILE_ATTR_VALID_SET_FLAGS = 0x000031A7,
+ NTFS_FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT = 0x10000000,
+ NTFS_FILE_ATTR_DUP_VIEW_INDEX_PRESENT = 0x20000000,
+};
+
+/*
+ * Magic identifiers present at the beginning of all ntfs record containing
+ * records (like mft records for example).
+ */
+enum {
+ /* Found in $MFT/$DATA */
+ NTFS_MAGIC_FILE = 0x454C4946, /* MFT entry */
+ NTFS_MAGIC_INDX = 0x58444E49, /* Index buffer */
+ NTFS_MAGIC_HOLE = 0x454C4F48,
+
+ /* Found in $LogFile/$DATA */
+ NTFS_MAGIC_RSTR = 0x52545352,
+ NTFS_MAGIC_RCRD = 0x44524352,
+ /* Found in $LogFile/$DATA (May be found in $MFT/$DATA, also ?) */
+ NTFS_MAGIC_CHKDSK = 0x444B4843,
+ /* Found in all ntfs record containing records. */
+ NTFS_MAGIC_BAAD = 0x44414142,
+ NTFS_MAGIC_EMPTY = 0xFFFFFFFF, /* Record is empty */
+};
+
+struct ntfs_record {
+ uint32_t magic;
+ uint16_t usa_ofs;
+ uint16_t usa_count;
+} __attribute__((__packed__)) NTFS_RECORD;
+
+/* The $MFT metadata file types */
+enum ntfs_system_file {
+ FILE_MFT = 0,
+ FILE_MFTMirr = 1,
+ FILE_LogFile = 2,
+ FILE_Volume = 3,
+ FILE_AttrDef = 4,
+ FILE_root = 5,
+ FILE_Bitmap = 6,
+ FILE_Boot = 7,
+ FILE_BadClus = 8,
+ FILE_Secure = 9,
+ FILE_UpCase = 10,
+ FILE_Extend = 11,
+ FILE_reserved12 = 12,
+ FILE_reserved13 = 13,
+ FILE_reserved14 = 14,
+ FILE_reserved15 = 15,
+ FILE_reserved16 = 16,
+};
+
+enum {
+ MFT_RECORD_IN_USE = 0x0001,
+ MFT_RECORD_IS_DIRECTORY = 0x0002,
+} __attribute__((__packed__));
+
+struct ntfs_mft_record {
+ uint32_t magic;
+ uint16_t usa_ofs;
+ uint16_t usa_count;
+ uint64_t lsn;
+ uint16_t seq_no;
+ uint16_t link_count;
+ uint16_t attrs_offset;
+ uint16_t flags; /* MFT record flags */
+ uint32_t bytes_in_use;
+ uint32_t bytes_allocated;
+ uint64_t base_mft_record;
+ uint16_t next_attr_instance;
+ uint16_t reserved;
+ uint32_t mft_record_no;
+} __attribute__((__packed__)); /* 48 bytes */
+
+/* This is the version without the NTFS 3.1+ specific fields */
+struct ntfs_mft_record_old {
+ uint32_t magic;
+ uint16_t usa_ofs;
+ uint16_t usa_count;
+ uint64_t lsn;
+ uint16_t seq_no;
+ uint16_t link_count;
+ uint16_t attrs_offset;
+ uint16_t flags; /* MFT record flags */
+ uint32_t bytes_in_use;
+ uint32_t bytes_allocated;
+ uint64_t base_mft_record;
+ uint16_t next_attr_instance;
+} __attribute__((__packed__)); /* 42 bytes */
+
+enum {
+ ATTR_DEF_INDEXABLE = 0x02,
+ ATTR_DEF_MULTIPLE = 0x04,
+ ATTR_DEF_NOT_ZERO = 0x08,
+ ATTR_DEF_INDEXED_UNIQUE = 0x10,
+ ATTR_DEF_NAMED_UNIQUE = 0x20,
+ ATTR_DEF_RESIDENT = 0x40,
+ ATTR_DEF_ALWAYS_LOG = 0x80,
+};
+
+struct ntfs_attr_record {
+ uint32_t type; /* Attr. type code */
+ uint32_t len;
+ uint8_t non_resident;
+ uint8_t name_len;
+ uint16_t name_offset;
+ uint16_t flags; /* Attr. flags */
+ uint16_t instance;
+ union {
+ struct { /* Resident attribute */
+ uint32_t value_len;
+ uint16_t value_offset;
+ uint8_t flags; /* Flags of resident attributes */
+ int8_t reserved;
+ } __attribute__((__packed__)) resident;
+ struct { /* Non-resident attributes */
+ uint64_t lowest_vcn;
+ uint64_t highest_vcn;
+ uint16_t mapping_pairs_offset;
+ uint8_t compression_unit;
+ uint8_t reserved[5];
+ int64_t allocated_size;
+ int64_t data_size; /* Byte size of the attribute value.
+ * Note: it can be larger than
+ * allocated_size if attribute value is
+ * compressed or sparse.
+ */
+ int64_t initialized_size;
+ int64_t compressed_size;
+ } __attribute__((__packed__)) non_resident;
+ } __attribute__((__packed__)) data;
+} __attribute__((__packed__));
+
+/* Attribute: Attribute List (0x20)
+ * Note: it can be either resident or non-resident
+ */
+struct ntfs_attr_list_entry {
+ uint32_t type;
+ uint16_t length;
+ uint8_t name_length;
+ uint8_t name_offset;
+ uint64_t lowest_vcn;
+ uint64_t mft_ref;
+ uint16_t instance;
+ uint16_t name[0];
+} __attribute__((__packed__));
+
+#define NTFS_MAX_FILE_NAME_LEN 255
+
+/* Possible namespaces for filenames in ntfs (8-bit) */
+enum {
+ FILE_NAME_POSIX = 0x00,
+ FILE_NAME_WIN32 = 0x01,
+ FILE_NAME_DOS = 0x02,
+ FILE_NAME_WIN32_AND_DOS = 0x03,
+} __attribute__((__packed__));
+
+/* Attribute: Filename (0x30)
+ * Note: always resident
+ */
+struct ntfs_filename_attr {
+ uint64_t parent_directory;
+ int64_t ctime;
+ int64_t atime;
+ int64_t mtime;
+ int64_t rtime;
+ uint64_t allocated_size;
+ uint64_t data_size;
+ uint32_t file_attrs;
+ union {
+ struct {
+ uint16_t packed_ea_size;
+ uint16_t reserved; /* reserved for alignment */
+ } __attribute__((__packed__)) ea;
+ struct {
+ uint32_t reparse_point_tag;
+ } __attribute__((__packed__)) rp;
+ } __attribute__((__packed__)) type;
+ uint8_t file_name_len;
+ uint8_t file_name_type;
+ uint16_t file_name[0]; /* File name in Unicode */
+} __attribute__((__packed__));
+
+/* Attribute: Volume Name (0x60)
+ * Note: always resident
+ * Note: Present only in FILE_volume
+ */
+struct ntfs_vol_name {
+ uint16_t name[0]; /* The name of the volume in Unicode */
+} __attribute__((__packed__));
+
+/* Attribute: Volume Information (0x70)
+ * Note: always resident
+ * Note: present only in FILE_Volume
+ */
+struct ntfs_vol_info {
+ uint64_t reserved;
+ uint8_t major_ver;
+ uint8_t minor_ver;
+ uint16_t flags; /* Volume flags */
+} __attribute__((__packed__));
+
+/* Attribute: Data attribute (0x80)
+ * Note: can be either resident or non-resident
+ */
+struct ntfs_data_attr {
+ uint8_t data[0];
+} __attribute__((__packed__));
+
+/* Index header flags (8-bit) */
+enum {
+ SMALL_INDEX = 0,
+ LARGE_INDEX = 1,
+ LEAF_NODE = 0,
+ INDEX_NODE = 1,
+ NODE_MASK = 1,
+} __attribute__((__packed__));
+
+/* Header for the indexes, describing the INDEX_ENTRY records, which
+ * follow the struct ntfs_idx_header.
+ */
+struct ntfs_idx_header {
+ uint32_t entries_offset;
+ uint32_t index_len;
+ uint32_t allocated_size;
+ uint8_t flags; /* Index header flags */
+ uint8_t reserved[3]; /* Align to 8-byte boundary */
+} __attribute__((__packed__));
+
+/* Attribute: Index Root (0x90)
+ * Note: always resident
+ */
+struct ntfs_idx_root {
+ uint32_t type; /* It is $FILE_NAME for directories, zero for view indexes.
+ * No other values allowed.
+ */
+ uint32_t collation_rule;
+ uint32_t index_block_size;
+ uint8_t clust_per_index_block;
+ uint8_t reserved[3];
+ struct ntfs_idx_header index;
+} __attribute__((__packed__));
+
+/* Attribute: Index allocation (0xA0)
+ * Note: always non-resident, of course! :-)
+ */
+struct ntfs_idx_allocation {
+ uint32_t magic;
+ uint16_t usa_ofs; /* Update Sequence Array offsets */
+ uint16_t usa_count; /* Update Sequence Array number in bytes */
+ int64_t lsn;
+ int64_t index_block_vcn; /* Virtual cluster number of the index block */
+ struct ntfs_idx_header index;
+} __attribute__((__packed__));
+
+enum {
+ INDEX_ENTRY_NODE = 1,
+ INDEX_ENTRY_END = 2,
+ /* force enum bit width to 16-bit */
+ INDEX_ENTRY_SPACE_FILTER = 0xFFFF,
+} __attribute__((__packed__));
+
+struct ntfs_idx_entry_header {
+ union {
+ struct { /* Only valid when INDEX_ENTRY_END is not set */
+ uint64_t indexed_file;
+ } __attribute__((__packed__)) dir;
+ struct { /* Used for views/indexes to find the entry's data */
+ uint16_t data_offset;
+ uint16_t data_len;
+ uint32_t reservedV;
+ } __attribute__((__packed__)) vi;
+ } __attribute__((__packed__)) data;
+ uint16_t len;
+ uint16_t key_len;
+ uint16_t flags; /* Index entry flags */
+ uint16_t reserved; /* Align to 8-byte boundary */
+} __attribute__((__packed__));
+
+struct ntfs_idx_entry {
+ union {
+ struct { /* Only valid when INDEX_ENTRY_END is not set */
+ uint64_t indexed_file;
+ } __attribute__((__packed__)) dir;
+ struct { /* Used for views/indexes to find the entry's data */
+ uint16_t data_offset;
+ uint16_t data_len;
+ uint32_t reservedV;
+ } __attribute__((__packed__)) vi;
+ } __attribute__((__packed__)) data;
+ uint16_t len;
+ uint16_t key_len;
+ uint16_t flags; /* Index entry flags */
+ uint16_t reserved; /* Align to 8-byte boundary */
+ union {
+ struct ntfs_filename_attr file_name;
+ //SII_INDEX_KEY sii;
+ //SDH_INDEX_KEY sdh;
+ //GUID object_id;
+ //REPARSE_INDEX_KEY reparse;
+ //SID sid;
+ uint32_t owner_id;
+ } __attribute__((__packed__)) key;
+} __attribute__((__packed__));
+
+static inline struct ntfs_sb_info *NTFS_SB(struct fs_info *fs)
+{
+ return fs->fs_info;
+}
+
+#define NTFS_PVT(i) ((struct ntfs_inode *)((i)->pvt))
+
+#endif /* _NTFS_H_ */
diff --git a/core/fs/ntfs/runlist.h b/core/fs/ntfs/runlist.h
new file mode 100644
index 00000000..4938696b
--- /dev/null
+++ b/core/fs/ntfs/runlist.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2011 Paulo Alcantara <pcacjr@gmail.com>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef _RUNLIST_H_
+#define _RUNLIST_H_
+
+struct runlist_element {
+ uint64_t vcn;
+ int64_t lcn;
+ uint64_t len;
+};
+
+struct runlist {
+ struct runlist_element run;
+ struct runlist *next;
+};
+
+static struct runlist *tail;
+
+static inline bool runlist_is_empty(struct runlist *rlist)
+{
+ return !rlist;
+}
+
+static inline struct runlist *runlist_alloc(void)
+{
+ struct runlist *rlist;
+
+ rlist = malloc(sizeof *rlist);
+ if (!rlist)
+ malloc_error("runlist structure");
+
+ rlist->next = NULL;
+
+ return rlist;
+}
+
+static inline void runlist_append(struct runlist **rlist,
+ struct runlist_element *elem)
+{
+ struct runlist *n = runlist_alloc();
+
+ n->run = *elem;
+
+ if (runlist_is_empty(*rlist)) {
+ *rlist = n;
+ tail = n;
+ } else {
+ tail->next = n;
+ tail = n;
+ }
+}
+
+static inline struct runlist *runlist_remove(struct runlist **rlist)
+{
+ struct runlist *ret;
+
+ if (runlist_is_empty(*rlist))
+ return NULL;
+
+ ret = *rlist;
+ *rlist = ret->next;
+
+ return ret;
+}
+
+#endif /* _RUNLIST_H_ */
diff --git a/core/head.inc b/core/head.inc
index 18ce132c..71eb5744 100644
--- a/core/head.inc
+++ b/core/head.inc
@@ -20,8 +20,8 @@
%ifndef _HEAD_INC
%define _HEAD_INC
-%if __NASM_MAJOR__ < 2
- %error "NASM 2.00 or later required to compile correctly"
+%if __NASM_MAJOR__ < 2 || (__NASM_MAJOR__ == 2 && __NASM_MINOR__ < 3)
+ %error "NASM 2.03 or later required to compile correctly"
%endif
%include "macros.inc"
diff --git a/core/include/fs.h b/core/include/fs.h
index ecd148da..e1f5733c 100644
--- a/core/include/fs.h
+++ b/core/include/fs.h
@@ -95,6 +95,7 @@ struct extent {
struct inode {
struct fs_info *fs; /* The filesystem this inode is associated with */
struct inode *parent; /* Parent directory, if any */
+ const char *name; /* Name, valid for generic path search only */
int refcnt;
int mode; /* FILE , DIR or SYMLINK */
uint32_t size;
diff --git a/core/init.inc b/core/init.inc
index e06ca96f..8c6a178f 100644
--- a/core/init.inc
+++ b/core/init.inc
@@ -69,9 +69,15 @@ check_escapes:
shr edx,10
cmp ax,dx
jae enough_ram
- mov ax,dx
mov si,err_noram
mov cl,10
+ push dx
+ div cl
+ add [si+err_noram.need-err_noram+2],ah
+ cbw
+ div cl
+ add [si+err_noram.need-err_noram],ax
+ pop ax
div cl
add [si+err_noram.size-err_noram+2],ah
cbw
@@ -83,15 +89,15 @@ enough_ram:
skip_checks:
section .data16
-err_noram db 'It appears your computer has less than '
+err_noram db 'It appears your computer has only '
.size db '000'
- db 'K of low ("DOS")'
- db CR, LF
- db 'RAM. Syslinux needs at least this amount to boot. If you get'
- db CR, LF
- db 'this message in error, hold down the Ctrl key while'
- db CR, LF
- db 'booting, and I will take your word for it.', CR, LF, 0
+ db 'K of low ("DOS") RAM.', CR, LF
+ db 'This version of Syslinux needs '
+.need db '000'
+ db 'K to boot. If you get this', CR, LF
+ db 'message in error, hold down the Ctrl key while'
+ db 'booting, and I', CR, LF
+ db 'will take your word for it.', CR, LF, 0
section .text16
;
diff --git a/core/isolinux.asm b/core/isolinux.asm
index ca8ee3a3..7a871f0e 100644
--- a/core/isolinux.asm
+++ b/core/isolinux.asm
@@ -52,22 +52,6 @@ vk_append: resb max_cmd_len+1 ; Command line
vk_end: equ $ ; Should be <= vk_size
endstruc
-;
-; File structure. This holds the information for each currently open file.
-;
- struc open_file_t
-file_sector resd 1 ; Sector pointer (0 = structure free)
-file_bytesleft resd 1 ; Number of bytes left
-file_left resd 1 ; Number of sectors left
- resd 1 ; Unused
- endstruc
-
-%ifndef DEPEND
-%if (open_file_t_size & (open_file_t_size-1))
-%error "open_file_t is not a power of 2"
-%endif
-%endif
-
; ---------------------------------------------------------------------------
; BEGIN CODE
; ---------------------------------------------------------------------------
@@ -1195,138 +1179,6 @@ ROOT_FS_OPS:
;
%include "ui.inc"
-;
-; Enable disk emulation. The kind of disk we emulate is dependent on the
-; size of the file: 1200K, 1440K or 2880K floppy, otherwise harddisk.
-;
-is_disk_image:
- TRACER CR
- TRACER LF
- TRACER 'D'
- TRACER ':'
-
- mov edx,eax ; File size
- mov di,img_table
- mov cx,img_table_count
- mov eax,[si+file_sector] ; Starting LBA of file
- mov [dsp_lba],eax ; Location of file
- mov byte [dsp_drive], 0 ; 00h floppy, 80h hard disk
-.search_table:
- TRACER 't'
- mov eax,[di+4]
- cmp edx,[di]
- je .type_found
- add di,8
- loop .search_table
-
- ; Hard disk image. Need to examine the partition table
- ; in order to deduce the C/H/S geometry. Sigh.
-.hard_disk_image:
- TRACER 'h'
- cmp edx,512
- jb .bad_image
-
- mov bx,trackbuf
- mov cx,1 ; Load 1 sector
- pm_call getfssec
-
- cmp word [trackbuf+510],0aa55h ; Boot signature
- jne .bad_image ; Image not bootable
-
- mov cx,4 ; 4 partition entries
- mov di,trackbuf+446 ; Start of partition table
-
- xor ax,ax ; Highest sector(al) head(ah)
-
-.part_scan:
- cmp byte [di+4], 0
- jz .part_loop
- lea si,[di+1]
- call .hs_check
- add si,byte 4
- call .hs_check
-.part_loop:
- add di,byte 16
- loop .part_scan
-
- push eax ; H/S
- push edx ; File size
- mov bl,ah
- xor bh,bh
- inc bx ; # of heads in BX
- xor ah,ah ; # of sectors in AX
- cwde ; EAX[31:16] <- 0
- mul bx
- shl eax,9 ; Convert to bytes
- ; Now eax contains the number of bytes per cylinder
- pop ebx ; File size
- xor edx,edx
- div ebx
- and edx,edx
- jz .no_remainder
- inc eax ; Fractional cylinder...
- ; Now (e)ax contains the number of cylinders
-.no_remainder: cmp eax,1024
- jna .ok_cyl
- mov ax,1024 ; Max possible #
-.ok_cyl: dec ax ; Convert to max cylinder no
- pop ebx ; S(bl) H(bh)
- shl ah,6
- or bl,ah
- xchg ax,bx
- shl eax,16
- mov ah,bl
- mov al,4 ; Hard disk boot
- mov byte [dsp_drive], 80h ; Drive 80h = hard disk
-
-.type_found:
- TRACER 'T'
- mov bl,[sp_media]
- and bl,0F0h ; Copy controller info bits
- or al,bl
- mov [dsp_media],al ; Emulation type
- shr eax,8
- mov [dsp_chs],eax ; C/H/S geometry
- mov ax,[sp_devspec] ; Copy device spec
- mov [dsp_devspec],ax
- mov al,[sp_controller] ; Copy controller index
- mov [dsp_controller],al
-
- TRACER 'V'
- call vgaclearmode ; Reset video
-
- mov ax,4C00h ; Enable emulation and boot
- mov si,dspec_packet
- mov dl,[DriveNumber]
- lss sp,[InitStack]
- TRACER 'X'
-
- call int13
-
- ; If this returns, we have problems
-.bad_image:
- mov si,err_disk_image
- call writestr
- jmp enter_command
-
-;
-; Look for the highest seen H/S geometry
-; We compute cylinders separately
-;
-.hs_check:
- mov bl,[si] ; Head #
- cmp bl,ah
- jna .done_track
- mov ah,bl ; New highest head #
-.done_track: mov bl,[si+1]
- and bl,3Fh ; Sector #
- cmp bl,al
- jna .done_sector
- mov al,bl
-.done_sector: ret
-
-
-
; -----------------------------------------------------------------------------
; Common modules
; -----------------------------------------------------------------------------
@@ -1352,33 +1204,8 @@ err_disk_image db 'Cannot load disk image (invalid file)?', CR, LF, 0
;
alignz 4
exten_table: db '.cbt' ; COMBOOT (specific)
- db '.img' ; Disk image
db '.bin' ; CD boot sector
db '.com' ; COMBOOT (same as DOS)
db '.c32' ; COM32
exten_table_end:
dd 0, 0 ; Need 8 null bytes here
-
-;
-; Floppy image table
-;
- alignz 4
-img_table_count equ 3
-img_table:
- dd 1200*1024 ; 1200K floppy
- db 1 ; Emulation type
- db 80-1 ; Max cylinder
- db 15 ; Max sector
- db 2-1 ; Max head
-
- dd 1440*1024 ; 1440K floppy
- db 2 ; Emulation type
- db 80-1 ; Max cylinder
- db 18 ; Max sector
- db 2-1 ; Max head
-
- dd 2880*1024 ; 2880K floppy
- db 3 ; Emulation type
- db 80-1 ; Max cylinder
- db 36 ; Max sector
- db 2-1 ; Max head
diff --git a/core/ldlinux.asm b/core/ldlinux.asm
index f62f55b2..a2f859d0 100644
--- a/core/ldlinux.asm
+++ b/core/ldlinux.asm
@@ -37,6 +37,8 @@ ROOT_FS_OPS:
dd vfat_fs_ops
extern ext2_fs_ops
dd ext2_fs_ops
+ extern ntfs_fs_ops
+ dd ntfs_fs_ops
extern btrfs_fs_ops
dd btrfs_fs_ops
dd 0
diff --git a/core/syslinux.ld b/core/syslinux.ld
index 40a01394..11adbcb8 100644
--- a/core/syslinux.ld
+++ b/core/syslinux.ld
@@ -280,8 +280,9 @@ SECTIONS
__ctors_lma = __ctors_vma + __text_lma - __text_vma;
.ctors : AT(__ctors_lma) {
__ctors_start = .;
- KEEP (*(SORT(.ctors.*)))
- KEEP (*(.ctors))
+ KEEP (*(SORT(.preinit_array*)))
+ KEEP (*(SORT(.init_array*)))
+ KEEP (*(SORT(.ctors*)))
__ctors_end = .;
}
@@ -289,8 +290,8 @@ SECTIONS
__dtors_lma = __dtors_vma + __text_lma - __text_vma;
.dtors : AT(__dtors_lma) {
__dtors_start = .;
- KEEP (*(SORT(.dtors.*)))
- KEEP (*(.dtors))
+ KEEP (*(SORT(.fini_array*)))
+ KEEP (*(SORT(.dtors*)))
__dtors_end = .;
}
diff --git a/core/ui.inc b/core/ui.inc
index 0a4bb569..631860f8 100644
--- a/core/ui.inc
+++ b/core/ui.inc
@@ -681,11 +681,8 @@ is_bad_image:
%else
is_bss_sector equ is_bad_image
%endif
-%if IS_ISOLINUX
- ; ok
-%else
-is_disk_image equ is_bad_image
-%endif
+
+is_disk_image equ is_bad_image ; No longer supported
section .data16
boot_prompt db 'boot: ', 0
diff --git a/diag/geodsp/Makefile b/diag/geodsp/Makefile
index 6af0d2db..55160859 100644
--- a/diag/geodsp/Makefile
+++ b/diag/geodsp/Makefile
@@ -19,46 +19,41 @@
#
topdir = ../..
-# include $(topdir)/MCONFIG.embedded
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/embedded.mk
coredir = $(topdir)/core
-BTARGET = geodsp1s.bin geodspms.bin mk-lba-img \
+BTARGET = geodsp1s.bin geodspms.bin \
geodsp1s.img.xz geodspms.img.xz
-# lba-1s.img.xz lba-ms.img.xz
- # lba-1s.img lba-ms.img
NASMOPT = -i $(coredir)/ -Ox -f bin
NASMOPT += -w+orphan-labels
+CFLAGS = -g -O
all: $(BTARGET)
-.PRECIOUS: %.img
-# .PRECIOUS: lba-%.img
-
# Higher compression levels result in larger files
-%.img.xz: %.img
- xz -k0f $<
+%.img.xz: %.bin mk-lba-img.pl
+ $(PERL) mk-lba-img $< | $(XZ) -0 > $@ || ( rm -f $@ ; false )
-%.img.gz: %.img
- gzip -9c $< > $@
+%.img.gz: %.bin mk-lba-img.pl
+ $(PERL) mk-lba-img $< | $(GZIPPROG) -9 > $@ || ( rm -f $@ ; false )
-%.img: %.bin lba.img
- (cp -a lba.img $@ && dd conv=notrunc if=$< of=$@) || rm -f $@
+# in case someone really wants these without needing a decompressor
+%.img: %.bin mk-lba-img.pl
+ $(PERL) mk-lba-img $< > $@ || ( rm -f $@ ; false )
%.bin: %.asm $(coredir)/writehex.inc $(coredir)/macros.inc $(coredir)/diskboot.inc
- nasm $(NASMOPT) -o $@ -l $(@:.bin=.lst) $<
+ $(NASM) $(NASMOPT) -o $@ -l $(@:.bin=.lst) $<
mk-lba-img: mk-lba-img.c
- gcc -o $@ $<
-
-lba.img: mk-lba-img
- ./$< $@
+ $(CC) $(CFLAGS) -o $@ $<
tidy dist:
- rm -Rf *.img
+ rm -Rf *.lst *.img
+ rm -f mk-lba-img
clean: tidy
- rm -f *.lst *.bin *_bin.c
spotless: clean
rm -f $(BTARGET)
diff --git a/diag/geodsp/mk-lba-img.c b/diag/geodsp/mk-lba-img.c
index 795de1a7..eb1c3393 100644
--- a/diag/geodsp/mk-lba-img.c
+++ b/diag/geodsp/mk-lba-img.c
@@ -24,16 +24,18 @@
#define NUM_SECT (256*63+1)
#define BPS (512)
-#define SECT_INT (512 / sizeof(int))
+#define SECT_INT (BPS / sizeof(unsigned int))
typedef unsigned char uint8_t;
typedef unsigned int uint32_t;
-const char DEF_FN[] = "lba.img";
+const char DEF_FN[] = "-";
int main(int argc, char *argv[])
{
- int i, j, b[SECT_INT], rv = 0, one = 0;
+ int i, rv = 0, one = 0;
+ unsigned int lba, b[SECT_INT];
+ int len;
FILE *f;
uint8_t tt = 0;
const char *fn;
@@ -53,23 +55,40 @@ int main(int argc, char *argv[])
fn = DEF_FN;
}
- f = fopen(fn, "w");
+ if (!strcmp(fn, "-"))
+ f = stdout;
+ else
+ f = fopen(fn, "w");
- if (f) {
- for (i = 0; i < NUM_SECT; i++) {
- if (one) {
- b[0] = i;
- } else {
- for (j = 0; j < (512 / sizeof(int)); j++) {
- b[j] = i;
- }
- }
- fwrite(b, 512, 1, f);
+ if (!f) {
+ fprintf(stderr, "%s: %s: unable to open for writing: %s\n",
+ argv[0], fn, strerror(errno));
+ return 1;
+ }
+
+ lba = 0;
+ while ((len = fread(b, 1, BPS, stdin))) {
+ if (len < BPS)
+ memset((char *)b + len, 0, BPS - len);
+ fwrite(b, 1, BPS, f);
+ lba++;
+ }
+
+ memset(b, 0, sizeof b);
+
+ while (lba < NUM_SECT) {
+ if (one) {
+ b[0] = lba;
+ } else {
+ for (i = 0; i < SECT_INT; i++)
+ b[i] = lba;
}
- fclose(f);
- } else {
- puts("Unable to open for writing");
- rv = 1;
+ fwrite(b, 1, BPS, f);
+ lba++;
}
+
+ if (f != stdout)
+ fclose(f);
+
return rv;
}
diff --git a/diag/geodsp/mk-lba-img.pl b/diag/geodsp/mk-lba-img.pl
new file mode 100755
index 00000000..59ef4f0f
--- /dev/null
+++ b/diag/geodsp/mk-lba-img.pl
@@ -0,0 +1,94 @@
+## -----------------------------------------------------------------------
+##
+## Copyright 2011 Gene Cumm
+##
+## 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.
+##
+## -----------------------------------------------------------------------
+
+##
+## mk-lba-img.pl
+##
+## Make an image where each sector contains the LBA of the sector with
+## a head of an input file.
+##
+
+# use bytes;
+
+use constant SECTOR_SIZE => 512;
+use constant LBA_SIZE => 8;
+use constant LONG_SIZE => 4;
+use constant NUM_SECTORS => (256*63+1);
+# use constant NUM_SECTORS => 5;
+use constant DEBUG => 1;
+
+# sub dprint
+# {
+# if (DEBUG) {
+# print($_);
+# }
+# }
+
+($ifilen, $ofilen) = @ARGV;
+
+if ((!defined($ifilen)) || ($ifilen eq "-")) { #
+ print(STDERR "Using stdin\n");
+ $IFILE = STDIN;
+} else {
+ open($IFILE, '<', $ifilen) or die "open:$!";
+ print(STDERR "Using $ifilen\n");
+}
+
+binmode($ifile);
+
+if (!defined($ofilen)) {
+ $OFILE = STDOUT;
+} else {
+ open($OFILE, '>', $ofilen) or die "open:$!";
+ print(STDERR "Using $ofilen\n");
+}
+
+binmode($OFILE);
+
+# $pk0 = pack('L', 0);
+$n_long = (SECTOR_SIZE/LONG_SIZE);
+$n_lba = (SECTOR_SIZE/LBA_SIZE);
+
+$len=0;
+while ( read($IFILE, $ch, 1) ) {
+ print($OFILE $ch);
+ $len++;
+}
+$tail = (SECTOR_SIZE - ($len % SECTOR_SIZE)) % SECTOR_SIZE;
+$ch = pack("C", 0);
+print("Len: $len\ttail: $tail\n");
+for ($i=0; $i<$tail; $i++) {
+ print($OFILE $ch);
+}
+
+$st = ($len + $tail) / SECTOR_SIZE;
+
+for ($i=$st; $i<(NUM_SECTORS); $i++) {
+ @ia = ();
+ for ($j=0; $j< $n_lba; $j++) {
+ push(@ia, $i, 0);
+ }
+ @ipk = pack("L[$n_long]", @ia);
+ # There is a 64-bit INT conversion but it normally isn't usable
+ # on a 32-bit platform
+ print($OFILE @ipk); # Gently simulate a 64-bit LBA
+}
+
+if (defined($ifilen) && (!($ifilen eq "-"))) {
+ close($IFILE);
+}
+
+if (defined($ofilen)) {
+ close($OFILE);
+}
+
+exit 0;
diff --git a/diag/mbr/Makefile b/diag/mbr/Makefile
index a94253af..79ff9f01 100644
--- a/diag/mbr/Makefile
+++ b/diag/mbr/Makefile
@@ -17,7 +17,8 @@
topdir = ../..
mbrdir = $(topdir)/mbr
-include $(topdir)/MCONFIG.embedded
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/embedded.mk
all: handoff.bin
diff --git a/diag/mbr/README b/diag/mbr/README
index fb7a7dd8..96b67c6c 100644
--- a/diag/mbr/README
+++ b/diag/mbr/README
@@ -5,11 +5,13 @@ handoff.bin Show the data that the BIOS/MBR hands off to an MBR/VBR.
+++ USAGE +++
+NOTE: in the examples, mbr.bin, /dev/hda and /dev/hda1 are used as generic representations.
+
Writing out an MBR is straight forward (it is assumed below that /dev/hda is the target raw device and /dev/hda1 is the target partition):
dd conv=notrunc bs=440 count=1 if=mbr.bin of=/dev/hda
-Writing a VBR to match Syslinux requires more work as it must have a jump and be offset into the partition:
+Writing a VBR to match Syslinux requires more work as it must have a jump and be offset into the partition (and as a result the code must be compaible with this offset):
echo -en "\0353\0130\0220" |dd conv=notrunc bs=1 count=3 of=/dev/hda1
dd conv=notrunc bs=2 count=210 seek=45 if=mbr.bin of=/dev/hda1
diff --git a/diag/mbr/handoff.S b/diag/mbr/handoff.S
index 7af3fdeb..ab8582b7 100644
--- a/diag/mbr/handoff.S
+++ b/diag/mbr/handoff.S
@@ -43,11 +43,11 @@
* Install instructions (assuming your target is /dev/dev; file or block device):
*
* MBR:
- * dd conv=notrunc bs=440 count=1 if=mbr_ho.bin of=/dev/dev
+ * dd conv=notrunc bs=440 count=1 if=handoff.bin of=/dev/dev
*
* VBR/PBR (should work for FAT12/16/32, ext[234]fs, btrfs):
* echo -en "\0353\0130\0220" |dd conv=notrunc bs=1 count=3 of=/dev/dev
- * dd conv=notrunc bs=2 count=210 seek=45 if=mbr_ho.bin of=/dev/dev
+ * dd conv=notrunc bs=2 count=210 seek=45 if=handoff.bin of=/dev/dev
*/
// #define DEBUG_MARKER1 /* Insert markers in binary */
diff --git a/doc/chain.txt b/doc/chain.txt
new file mode 100644
index 00000000..6dd0632d
--- /dev/null
+++ b/doc/chain.txt
@@ -0,0 +1,327 @@
+ chain.c32 documentation
+
+Although syslinux is capable of (very simple) native chainloading (through .bss
+and .bs options - see doc/syslinux.txt), it also features a very roboust and
+rich com32 module designed for such purpose.
+
+Chain module can perform few basic tasks:
+
+- load and jump to a sector
+- load and jump to a file (also loading a sector for other purposes)
+- prepare handover data to use by a file / boot sector
+- fix different options in a file / sector / partition entries
+- perform a "service-only" run
+
+It can chainload data from both GPT and DOS partitions, as well as boot the
+first sector from a raw disk.
+
+In more details, the rough overview of code is as follows:
+
+1. Parse arguments.
+2. Find drive and/or partition to boot from.
+3. Perform partition-level patching - for example hiding, unhiding, fixing chs values, etc.
+4. Load a file to boot from.
+5. Load a sector to boot from, if it doesn't conflict with #5.
+6. Prepare handover area, if it doesn't conflict with #5 & #6.
+7. Prepare registers.
+8. Patch loaded file if necessary.
+9. Patch loaded sector if necessary.
+10. Chainload.
+
+In most basic form, syslinux loads specified boot sector (or mbr, if not
+specified) at 0:0x7c00, prepares handover area as a standard mbr would do, and
+jumps to 0:0x7c00.
+
+A "service-only" run is possible when either:
+
+- 'break' is in effect
+
+or
+
+- 'nofile' and 'nomaps' (or 'nosect') are in effect
+
+This is useful for invocations such as:
+
+chain.c32 hdN M setbpb save break
+chain.c32 hdN fixchs break
+chain.c32 hdN unhideall break
+
+Please see respective options for more details.
+
+
+Module invocation:
+
+chain [drive/partition] [options]
+
+ DRIVE / PARTITION SPECIFICATION
+
+Drive can be specified as 'hd#', 'fd#', 'boot', 'mbr', or 'guid'.
+
+- 'mbr' will select a drive by a signature.
+- 'guid' will select a drive by a guid
+- 'boot' is the drive syslinux was booted from. This is the default value, if
+ nothing else is specified.
+- 'hd#' and 'fd#' are standard ways to specify drive number as seen by bios,
+ starting from 0.
+
+Option 'guid' is shared with partition selection (see below). If you happened
+to have non-unique guids, they are searched in disk0, partitions of disk0,
+disk1 ... order.
+
+The priority of those options are the same as in the above list.
+
+If you specify the same value more than once, the last value will be used.
+
+'mbr' and 'guid' take extra parameter - you should use ':' or '=' as a
+delimiter.
+
+
+Partition can be specified as '#', 'guid', 'label' or 'fs'.
+
+- 'guid' option will select a partition by a guid (not a type guid !)
+- 'label' will select a partition by a label (searching is done in
+ disk order)
+- 'fs' will select a partition from which syslinux was executed
+- '#' is the standard method. Partitions 1-4 are primary, 5+ logical, 0 = boot
+ MBR (default).
+
+The priority of those options are the same as in the above list.
+
+If you use a number to select a partition it should be specified after a drive
+using space or comma as delimiters (after 'hd#', 'fd#', 'mbr', 'guid' or 'boot').
+
+ OPTIONS
+ file=<file>
+ *nofile
+
+It's often convenient to load a file directly and transfer control to it,
+instead of the sector from the disk. Note, that the <file> must reside on
+syslinux partition.
+
+If you choose this option without specifying any addresses explicitly (see
+options 'sect=' and 'seg='), the file will cause sector to not be loaded at all
+(as their memory placement would overlap).
+
+ seg=<segment>:<offset>:<ip>
+ *seg=0:0x7c00:0x7c00
+
+This triplet lets you alter the addresses a file will use. It's loaded at
+<segment:offset>, the entry point is at <segment:ip>. When you chainload some
+other bootloader or kernel, it's almost always mandatory.
+
+The defaults, if option is not specified, are 0:0x7c00:0x7c00
+If any of the fields are ommited (e.g. 0x2000::), they default to 0.
+
+ sect=<segment>:<offset>:<ip>
+ nosect
+ *sect=0:0x7c00:0x7c00
+ nosect sets: nomaps
+
+This triplet lets you alter the addresses a sector will use. It's loaded at
+<segment:offset>, the entry point is at <segment:ip>. This option is mostly
+used in tandem with 'file=' and 'seg=' options, as some loaders/kernels will
+expect relocated sector at some particular address (e.g. DRKM).
+
+'nosect' will cause sector to not be loaded at all. In plenty cases, when a file
+is being chainloaded, sector is not necessary.
+
+The defaults if option is not specified, are 0:0x7c00:0x7c00.
+If some of the fields are ommited (e.g. 0x2000::), they default to 0.
+
+ *maps
+ nomaps
+
+In some cases, it's useful to fix BPB values in NTFS/FATxx bootsectors and
+evntually write them back, but otherwise boot sector itself is not necessary to
+continue booting. 'nomaps' allows that - a sector will be loaded, but won't be
+mmapped into real memory. Any overlap tests (vs. handover or file areas) are
+not performed, being meaningless in such case.
+
+ setbpb
+ *nosetbpb
+
+Microsoft side of the world is paritculary sensitive to certain BPB values.
+Depending on the system and chainloading method (sector or file), some or all
+of those fields must match reality - and after e.g. drive clonning or
+when using usb stick in different computers - that is often not the case.
+
+The "reality" means:
+
+"hidden sectors" - valid offset of the partition from the beginning of the disk
+"geometry" - valid disk geometry as reported by BIOS
+"drive" - valid drive number
+
+This option will automatically determine the type of BPB and fix what is possible
+to fix, relatively to detected BPB. If it's impossible to detect BPB, function
+will do nothing.
+
+ filebpb
+ *nofilebpb
+
+Chainloaded file can simply be an image of a sector. In such case, it could be
+useful to also fix its BPB values.
+
+ save
+ *nosave
+
+Fixing BPB values only in memory might not be enough. This option allows
+writing of the corrected sector. You will probably want to use this option
+together with 'setbpb'.
+
+- this option never applies to a loaded file
+- chain module will not save anything to disk by default (besides options such
+ as hide or fixchs - so options related directly to partition entries)
+- writing is only performed, if the values actually changed
+
+ *hand
+ nohand
+
+By default, a handover area is always prepared if possible - meaning it doesn't
+overlap with other areas. It's often not necessary though - usually, a
+chainloaded file or kernel don't care about it anymore, so a user can disable
+it explicitly with this option.
+
+ hptr
+ *nohptr
+
+In case when both file and sector are loaded, ds:si and ds:bp will point to
+sector address before the chainloading. This option lets user force those
+registers to point to handover area. This is useful when both the file and the
+sector are actually a sector's image and the sector is mmapped.
+
+ swap
+ *noswap
+
+This option will install a tiny stub code used to swap drive numbers, if the
+drive we use during chainloading is not fd0 or hd0.
+
+ hide[all]
+ unhide[all]
+ *nohide
+
+In certain situations it's useful to hide partitions - for example to make sure
+DOS gets C:. 'hide' will hide hidable primary partitions, except the one we're
+booting from. Similary, 'hideall' will hide all hidable partitions, except the
+one we're booting from. Hiding is performed only on the selected drive. Options
+starting with 'un' will simply unhide every partition (primary ones or all).
+Writing is only performed, if the os type values actually changed.
+
+ fixchs
+ *nofixchs
+
+If you want to make a drive you're booting from totally compatible with current
+BIOS, you can use this to fix all partitions' CHS numbers. Good to silence e.g.
+FreeDOS complainig about 'logical CHS differs from physical' of sfdisk about
+'found (...) expected (...). Functionally seems to be mostly cosmetic, as
+Microsoft world - in cases it cares about geometry - generally sticks to values
+written in bootsectors. And the rest of the world generally doesn't care about
+them at all. Writing is only performed, if the values actually got changed.
+
+ keepexe
+ *nokeepexe
+
+If you're booting over a network using pxelinux - this lets you keep UNDI
+stacks in memory (pxelinux only).
+
+ warn
+ *nowarn
+
+This option will wait for a keypress right before continuing the chainloading.
+Useful to see warnings emited by the chain module.
+
+ *nobreak
+ break
+ break sets: nofile nomaps nohand
+
+It is possible to trigger a "service-only" run - The chain module will do
+everything requested as usual, but it will not perform the actual chainloading.
+'break' option disables handover, file loading and sector mapping, as these
+are pointless in such scenario (although file might be reenabled in some future
+version, if writing to actual files becomes possible). Mainly useful for
+options 'fixchs', '[un]hide[all]' and setbpb.
+
+ isolinux=<file>
+ sets: file=<file> nohand nosect isolinux
+
+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=<file>
+ sets: file=<file> seg=0x2000 setbpb nohand
+
+Prepares to load ntldr directly. You might want to add 'save' option to store
+corrected BPB values.
+
+ cmldr=<file>
+ sets: file=<file> seg=0x2000 setbpb nohand cmldr
+
+Prepares to load recovery console directly. In-memory copy of bootsector is
+patched with "cmdcons\0". Remarks the same as in 'ntldr='.
+
+ reactos=<file>
+ sets: file=<file> seg=0:0x8000:0x8100 setbpb nohand
+
+Prepares to load ReactOS's freeldr directly. You might want to add 'save'
+option to store corrected BPB values.
+
+ freedos=<file>
+ sets: file=<file> seg=0x60 sect=0x1FE0 setbpb nohand
+
+Prepares to load freedos kernel directly. You will likely want to add 'save'
+option, as those kernels seem to require proper geometry written back to disk.
+Sector address is chosen based on where freedos' bootsectors relocate themselves,
+although it seems the kernel doesn't rely on it.
+
+You might also want to employ 'hide' option, if you have problems with properly
+assigned C: drive.
+
+ pcdos=<file>
+ msdos=<file>
+ sets: file=<file> seg=0x70 sect=0x8000 setbpb nohand
+
+Similary to 'freedos=', This prepares to load MSDOS 2.00 - 6.xx or derivatives.
+Sector address is chosen arbitrarily. Otherwise comments as above.
+
+ msdos7=<file>
+ sets: file=<file> seg=0x70::0x200 sect=0x8000 setbpb nohand
+
+Only for MSDOS 7+ versions (98se ~ 7.xx, Me ~ 8.xx). Comments as above.
+TODO/TEST
+
+ drmk=<file>
+ sets: file=<file> seg=0x70 sect=0x2000:0:0 setbpb nohand
+
+This is used for loading of *only* Dell's DOS derivatives. It does require boot
+sector at 0x2000 and overall valid BPB values. As in other DOS-ish cases,
+likely candidates for use are 'save' and 'hide'.
+
+ grub=<file> [grubcfg=<config>]
+ sets: file=<file> seg=0x800::0x200 nohand nosect grub
+
+Chainloads grub legacy's stage2, performing additional corrections on the file
+in memory. Additionally, alternate config file can be specified through
+'grubcfg=' option
+
+ grldr=<file>
+ sets: file=<file> nohand nosect grldr
+
+Chainloads GRUB4DOS grldr, performing additional corrections on the file
+in memory.
+
+ bss=<file>
+ sets: file=<file> nomaps setbpb bss
+
+This emulates syslinux's native BSS option. This loads both the file and the
+sector, adjusts BPB values in the loaded sector, then copies all possible BPB
+fields to the loaded file. Everything is made with reference to the selected
+disk/partition.
+
+ bs=<file>
+ sets: file=<file> nosect filebpb
+
+This emulates syslinux's native BS option. This loads the file and if possible
+- adjusts its BPB values. Everything is made with reference to the selected
+disk/partition.
+
diff --git a/doc/comboot.txt b/doc/comboot.txt
index 04d5deb8..6e9d7ab5 100644
--- a/doc/comboot.txt
+++ b/doc/comboot.txt
@@ -560,29 +560,7 @@ AX=000Ch [2.00] Perform final cleanup
meanings in future versions of Syslinux.
-AX=000Dh [2.08] Cleanup and replace bootstrap code
- Input: AX 000Dh
- DX derivative-specific flags (see previous function)
- EDI bootstrap code (linear address, can be in high memory)
- ECX bootstrap code length in bytes (must fit in low mem)
- EBX(!) initial value of EDX after bootstrap
- ESI initial value of ESI after bootstrap
- DS initial value of DS after bootstrap
- Output: Does not return
-
- This routine performs final cleanup, then takes a piece of
- code, copies it over the primary bootstrap at address 7C00h,
- and jumps to it. This can be used to chainload boot sectors,
- MBRs, bootstraps, etc.
-
- Normal boot sectors expect DL to contain the drive number,
- and, for hard drives (DL >= 80h) DS:SI to contain a pointer to
- the 16-byte partition table entry. The memory between
- 600h-7FFh is available to put the partition table entry in.
-
- For PXELINUX, if the PXE stack is not unloaded, all registers
- (except DS, ESI and EDX) and the stack will be set up as they
- were set up by the PXE ROM.
+AX=000Dh [2.08] Obsoleted in 3.80
AX=000Eh [2.11] Get configuration file name
@@ -627,57 +605,7 @@ AX=0010h [3.00] Resolve hostname [PXELINUX]
AX=0011h [3.05] Obsoleted in 3.80
-AX=0012h [3.50] Cleanup, shuffle and boot
- Input: AX 0012h
- DX derivative-specific flags (see function 000Ch)
- ES:DI shuffle descriptor list (must be in low memory)
- CX number of shuffle descriptors
- EBX(!) initial value of EDX after bootstrap
- ESI initial value of ESI after bootstrap
- DS initial value of DS after bootstrap
- EBP CS:IP of routine to jump to
- Output: Does not return
- (if CX is too large the routine returns with CF=1)
-
- This routine performs final cleanup, then performs a sequence
- of copies, and jumps to a specified real mode entry point.
- This is a more general version of function 000Dh, which can
- also be used to load other types of programs.
-
- The copies must not touch memory below address 7C00h.
-
- ES:DI points to a list of CX descriptors each of the form:
-
- Offset Size Meaning
- 0 dword destination address
- 4 dword source address
- 8 dword length in bytes
-
- The copies are overlap-safe, like memmove().
-
- Starting in version 3.50, if the source address is -1
- (FFFFFFFFh) then the block specified by the destination
- address and the length is set to all zero.
-
- Starting in version 3.50, if the destination address is -1
- (FFFFFFFFh) then the data block is loaded as a new set of
- descriptors, and processing is continued (and unprocessed
- descriptors are lost, this is thus typically only used as the
- last descriptor in a block.) The block must still fit in the
- internal descriptor buffer (see function 0011h), but can, of
- course, itself chain another block.
-
-
- Normal boot sectors expect DL to contain the drive number,
- and, for hard drives (DL >= 80h) DS:SI to contain a pointer to
- the 16-byte partition table entry. The memory between
- 600h-7FFh is available to put the partition table entry in.
-
- For PXELINUX, if the PXE stack is not unloaded, all registers
- (except DS, ESI and EDX) and the stack will be set up as they
- were set up by the PXE ROM.
-
- This interface was probably broken before version 3.50.
+AX=0012h [3.50] Obsoleted in 3.80
AX=0013h [3.08] Idle loop call
diff --git a/doc/gpt.txt b/doc/gpt.txt
index 09099320..2ef387a9 100644
--- a/doc/gpt.txt
+++ b/doc/gpt.txt
@@ -51,7 +51,7 @@ form:
4 1 0xED (partition type: synthetic)
5 3 CHS of partition end
8 4 Partition start LBA
- 12 4 Partition end LBA
+ 12 4 Partition length in sectors
16 4 Length of the GPT entry
20 varies GPT partition entry
diff --git a/doc/isolinux.txt b/doc/isolinux.txt
index eca2a974..807c6311 100644
--- a/doc/isolinux.txt
+++ b/doc/isolinux.txt
@@ -100,34 +100,3 @@ The ISO 9660 filesystem is encapsulated in a partition (which starts
at offset zero, which may confuse some systems.) This makes it
possible for the operating system, once booted, to use the remainder
of the device for persistent storage by creating a second partition.
-
-
- ++++ BOOTING DOS (OR OTHER SIMILAR OPERATING SYSTEMS) ++++
-
-WARNING: This feature depends on BIOS functionality which is
-apparently broken in a very large number of BIOSes. Therefore, this
-may not work on any particular system. No workaround is possible; if
-you find that it doesn't work please complain to your vendor and
-indicate that "BIOS INT 13h AX=4C00h fails."
-
-To boot DOS, or other real-mode operating systems (protected-mode
-operating systems may or may not work correctly), using ISOLINUX, you
-need to prepare a disk image (usually a floppy image, but a hard disk
-image can be used on *most* systems) with the relevant operating
-system. This file should be included on the CD-ROM in the /isolinux
-directory, and have a .img extension. The ".img" extension does not
-have to be specified on the command line, but has to be explicitly
-specified if used in a "kernel" statement in isolinux.cfg.
-
-For a floppy image, the size of the image should be exactly one of the
-following:
-
- 1,228,800 bytes - For a 1200K floppy image
- 1,474,560 bytes - For a 1440K floppy image
- 2,949,120 bytes - For a 2880K floppy image
-
-Any other size is assumed to be a hard disk image. In order to work
-on as many systems as possible, a hard disk image should have exactly
-one partition, marked active, that covers the entire size of the disk
-image file. Even so, hard disk images are not supported on all
-BIOSes.
diff --git a/doc/logo/LICENSE b/doc/logo/LICENSE
new file mode 100644
index 00000000..e753087f
--- /dev/null
+++ b/doc/logo/LICENSE
@@ -0,0 +1,5 @@
+The Syslinux logo is licensed under the Creative Commons
+Attribution-ShareAlike 3.0 Unported License. To view a copy of this
+license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send
+a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain
+View, California, 94041, USA.
diff --git a/doc/logo/syslinux-100.png b/doc/logo/syslinux-100.png
new file mode 100644
index 00000000..647635a2
--- /dev/null
+++ b/doc/logo/syslinux-100.png
Binary files differ
diff --git a/doc/menu.txt b/doc/menu.txt
index 620527e6..8a999cd4 100644
--- a/doc/menu.txt
+++ b/doc/menu.txt
@@ -18,7 +18,7 @@ See menu/README for more information.
+++ THE SIMPLE MENU SYSTEM +++
The simple menu system is a single module located at
-com32/modules/vesamenu.c32 (graphical) or com32/modules/menu.c32 (text
+com32/menu/vesamenu.c32 (graphical) or com32/menu/menu.c32 (text
mode only). It uses the same configuration file as the regular
Syslinux command line, and displays all the LABEL statements.
diff --git a/doc/pxechn.txt b/doc/pxechn.txt
new file mode 100644
index 00000000..7853d9ab
--- /dev/null
+++ b/doc/pxechn.txt
@@ -0,0 +1,138 @@
+= pxechn.c32(1) =
+:doctype: manpage
+:author: Gene Cumm
+:email: gene.cumm@gmail.com
+:revdate: 2012-09-16
+
+
+== NAME ==
+pxechn.c32 - Chainboot to new Network Boot Program (NBP)
+
+
+== SYNOPSIS ==
+[verse]
+*pxechn.c32* [-h | --help | -?]
+*pxechn.c32* -r 'FILE'
+*pxechn.c32* 'FILE' ['OPTIONS']
+
+
+== DESCRIPTION ==
+Chainboot to a new Network Boot Program (NBP) 'FILE' with options to
+adjust PXE packet #3 (PXENV_PACKET_TYPE_CACHED_REPLY) to alter end
+behavior. 'FILE' may be a filename, an IP::FN (
+192.168.1.1::path/to/file.0 ), or URL. 'FILE' is parsed to adjust the
+DHCP 'sname' field/option 66 and 'file' field/option 67.
+// but these may be override-able in the future.
+
+
+== OPTIONS ==
+*-c* 'CONFIG'::
+ 'config' file for PXELINUX (DHCP Option 209).
+
+// *-f* 'MOD'::
+// 'Force' behavior specified by modifier 'MOD'
+//
+// *-g* 'HOST'::
+// Set 'gateway'/relay DHCP field to 'HOST'. Parsed by pxe_dns().
+//
+*-h*, *--help*, *-?*::
+ Print 'help'/usage information; invalid options will also cause
+ this.
+
+// *-n*::
+// Use 'native' methods, ignoring underlying gPXE/iPXE.
+//
+// *-N*::
+// Use 'non-native' methods to utilize gPXE/iPXE (if available).
+//
+*-o* 'OPT.TYPE=VALUE'::
+ Set 'option'. 'OPT' is in 'DECIMAL INPUT' format (below). 'TYPE'
+ specifies the output type and input syntax (listed here in quotes
+ and at present, 1 character). ''b'yte', ''w'ord'(2B), ''l'ong'(4B),
+ ''q'uad'(8B), character ''s'tring' and colon-separated 'he'x''
+ string (case insensitive; bytes must have 2 digits and each byte
+ must be separated). byte, word, long and quad input values must
+ meet criteria for 'DECIMAL INPUT'
+
+*-p* 'PATH'::
+ 'path' option for PXELINUX (DHCP Option 210).
+
+*-r*::
+ 'restart'. Call the PXE stack with PXENV_RESTART_TFTP. _Must_ be
+ the only option and before 'FILE'.
+
+*-S*::
+ Set 'sip' based on sname field/option 66 (by direct IP if a
+ period-delimited address or otherwise DNS).
+
+*-t* 'SECONDS'::
+ 'timeout' option for PXELINUX (DHCP Option 211).
+
+// *-u*::
+// Copy 'UUID' (Option 97) if found in packet #1
+
+*-w*::
+ 'wait'. After loading, wait for user input before booting.
+
+*-W*::
+ Enable 'WDS' (Windows Deployment Services) - specific options.
+ 'FILE' (or its overrides for DHCP fields siaddr and file) must point
+ at the WDS server.
+ *NOTE:* As of 2012-05-31, there is a known issue with gPXE/iPXE, at
+ least with undionly.kkpxe.
+// PXELINUX asks gPXE/iPXE to unload, reverting to an underlying stack
+
+
+== DECIMAL INPUT ==
+All parameters that are defaulted to decimal format are processed by
+*strtoul*(3) with a base of 0 which allows alternate formats and finds a
+suitable non-space separating character.
+
+
+== EXAMPLES ==
+`pxechn.c32 http://myhost.dom.loc/path/nbp.0 -c myconfig`::
+ Load nbp.0 and set PXELINUX config (option 209).
+
+`pxechn.c32 gpxelinux.0 -p http://10.1.1.4/tftp/ -w -c myconfig -o 15.s=domain.loc -o 6.x=0A:01:01:02:ac:17:4D:Ec -`::
+ Load gpxelinux.0 from the current directory, set prefix, wait to
+ execute, set first config, set the domain name and 2 domain name
+ servers (case mixed to show insensitivity; 10.1.1.2 and
+ 172.23.77.236).
+
+`pxechn.c32 gpxelinux.0 -p http://10.1.1.4/tftp/ -w -o 0xA0.x=12:34:56:78 -x 197.x=00:d0:de:00`::
+ Load gpxelinux.0 (relative to the current directory and not
+ altering sname/option 66), set the PXELINUX path prefix, wait after
+ loading, set option 160 to 0x12 0x34 0x56 0x78, and option 197 to
+ 0x00 0xD0 0xDE 0x00.
+
+`pxechn.c32 10.1.1.8:boot\x86\wdsnbp.com -W`::
+ Load wdsnbp.com from 10.1.1.8 and copy DHCP Option 66 to DHCP
+ field sname if there's room.
+
+`pxechn.c32 10.1.1.4:boot\x86\wdsnbp.com -W -o 66.x=0a:01:01:08 -S`::
+ Load wdsnbp.com from 10.1.1.4, point packets to 10.1.1.8 for use
+ with WDS, copy DHCP Option 66 to DHCP field sname if there's room
+ and decode this to an IPv4 address.
+
+
+== NOTES ==
+Please note that some NBPs may ignore packet #3 by either not examining
+it at all or by issuing its own DHCP DISCOVER/REQUEST, negating all DHCP
+field/option modifications by pxechn.c32, including Microsoft Windows
+Server 2008R2 WDS's wdsnbp.com. See also option '-W'.
+
+URL specifications in 'FILE' that include user/password before the host
+will currently cause the siaddr field to not be set properly.
+
+The non-space constraint is due to how Syslinux variants parse the
+command line as of 2012-09-16.
+
+
+== AUTHOR ==
+{author} <{email}>
+
+
+== COPYRIGHT ==
+Copyright \(C) 2012 {author}. Free use of this software is granted under
+the terms of the GNU General Public License (GPL), version 2 (GPLv2)
+(or, at your option, any later version).
diff --git a/doc/syslinux.txt b/doc/syslinux.txt
index 07d5df9a..033a1ec0 100644
--- a/doc/syslinux.txt
+++ b/doc/syslinux.txt
@@ -100,7 +100,7 @@ directory on the disk.
There are two versions of the Linux installer; one in the "mtools"
directory which requires no special privilege (other than write
permission to the device where you are installing) but requires the
-mtools program suite to be available, and one in the "unix" directory
+mtools program suite to be available, and one in the "linux" directory
which requires root privilege.
diff --git a/dos/Makefile b/dos/Makefile
index 2667de8c..f9420084 100644
--- a/dos/Makefile
+++ b/dos/Makefile
@@ -15,7 +15,8 @@
##
topdir = ..
-include $(topdir)/MCONFIG.embedded
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/embedded.mk
CFLAGS += -D__MSDOS__
# CFLAGS += -DDEBUG
@@ -26,7 +27,7 @@ INCLUDES = -include code16.h -nostdinc -iwithprefix include \
-I. -I.. -I../libfat -I ../libinstaller -I ../libinstaller/getopt
SRCS = syslinux.c \
- ../libinstaller/fat.c \
+ ../libinstaller/fs.c \
../libinstaller/syslxmod.c \
../libinstaller/syslxopt.c \
../libinstaller/setadv.c \
diff --git a/dos/syslinux.c b/dos/syslinux.c
index b5fdfc52..fa4bf387 100644
--- a/dos/syslinux.c
+++ b/dos/syslinux.c
@@ -31,6 +31,7 @@
#include "sysexits.h"
#include "syslxopt.h"
#include "syslxint.h"
+#include "syslxfs.h"
char *program = "syslinux.com"; /* Name of program */
uint16_t dos_version;
@@ -638,7 +639,7 @@ int main(int argc, char *argv[])
/*
* Check to see that what we got was indeed an MS-DOS boot sector/superblock
*/
- if ((errmsg = syslinux_check_bootsect(sectbuf))) {
+ if ((errmsg = syslinux_check_bootsect(sectbuf, NULL))) {
unlock_device(0);
puts(errmsg);
putchar('\n');
@@ -749,7 +750,7 @@ int main(int argc, char *argv[])
read_device(dev_fd, sectbuf, 1, 0);
/* Copy the syslinux code into the boot sector */
- syslinux_make_bootsect(sectbuf);
+ syslinux_make_bootsect(sectbuf, VFAT);
/* Write new boot sector */
if (opt.bootsecfile) {
diff --git a/dosutil/Makefile b/dosutil/Makefile
index fc10ff90..6bce6248 100644
--- a/dosutil/Makefile
+++ b/dosutil/Makefile
@@ -2,7 +2,8 @@
# OpenWatcom compile and link utility
#
topdir = ..
-include $(topdir)/MCONFIG
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/syslinux.mk
WCL = wcl
WCLOPT = -6 -osx -mt -bt=DOS -l=COM
@@ -10,7 +11,7 @@ WCLOPT = -6 -osx -mt -bt=DOS -l=COM
UPX = upx
NASM = nasm
-NASMOPT = -O9999
+NASMOPT = -Ox
WCTARGETS = mdiskchk.com
NSTARGETS = eltorito.sys copybs.com
diff --git a/extlinux/Makefile b/extlinux/Makefile
index 83cf1a54..6cde574e 100644
--- a/extlinux/Makefile
+++ b/extlinux/Makefile
@@ -11,19 +11,21 @@
## -----------------------------------------------------------------------
##
-## Linux vfat, ext2/ext3/ext4 and btrfs installer
+## Linux vfat, ntfs, ext2/ext3/ext4 and btrfs installer
##
topdir = ..
-include $(topdir)/MCONFIG
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/syslinux.mk
OPTFLAGS = -g -Os
INCLUDES = -I. -I.. -I../libinstaller
CFLAGS = $(GCCWARN) -Wno-sign-compare -D_FILE_OFFSET_BITS=64 \
$(OPTFLAGS) $(INCLUDES)
-LDFLAGS = # -s
+LDFLAGS =
SRCS = main.c \
+ mountinfo.c \
../libinstaller/syslxmod.c \
../libinstaller/syslxopt.c \
../libinstaller/syslxcom.c \
@@ -53,6 +55,9 @@ installer: extlinux
extlinux: $(OBJS)
$(CC) $(LDFLAGS) -o $@ $^
+strip:
+ $(STRIP) extlinux
+
%.o: %.c
$(CC) $(UMAKEDEPS) $(CFLAGS) -c -o $@ $<
%.i: %.c
diff --git a/extlinux/btrfs.h b/extlinux/btrfs.h
index 39a861a5..4e2cb317 100644
--- a/extlinux/btrfs.h
+++ b/extlinux/btrfs.h
@@ -1,22 +1,185 @@
#ifndef _BTRFS_H_
#define _BTRFS_H_
+#include <asm/types.h>
+#include <linux/ioctl.h>
+
#define BTRFS_SUPER_MAGIC 0x9123683E
#define BTRFS_SUPER_INFO_OFFSET (64 * 1024)
#define BTRFS_SUPER_INFO_SIZE 4096
#define BTRFS_MAGIC "_BHRfS_M"
+#define BTRFS_MAGIC_L 8
#define BTRFS_CSUM_SIZE 32
#define BTRFS_FSID_SIZE 16
+#define BTRFS_UUID_SIZE 16
+
+typedef __u64 u64;
+typedef __u32 u32;
+typedef __u16 u16;
+typedef __u8 u8;
+typedef u64 __le64;
+typedef u16 __le16;
+
+#define BTRFS_ROOT_BACKREF_KEY 144
+#define BTRFS_ROOT_TREE_DIR_OBJECTID 6ULL
+#define BTRFS_DIR_ITEM_KEY 84
+
+/*
+ * * this is used for both forward and backward root refs
+ * */
+struct btrfs_root_ref {
+ __le64 dirid;
+ __le64 sequence;
+ __le16 name_len;
+} __attribute__ ((__packed__));
+
+struct btrfs_disk_key {
+ __le64 objectid;
+ u8 type;
+ __le64 offset;
+} __attribute__ ((__packed__));
+
+struct btrfs_dir_item {
+ struct btrfs_disk_key location;
+ __le64 transid;
+ __le16 data_len;
+ __le16 name_len;
+ u8 type;
+} __attribute__ ((__packed__));
struct btrfs_super_block {
- unsigned char csum[BTRFS_CSUM_SIZE];
- /* the first 3 fields must match struct btrfs_header */
- unsigned char fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */
- u64 bytenr; /* this block number */
- u64 flags;
-
- /* allowed to be different from the btrfs_header from here own down */
- u64 magic;
+ uint8_t csum[32];
+ uint8_t fsid[16];
+ uint64_t bytenr;
+ uint64_t flags;
+ uint8_t magic[8];
+ uint64_t generation;
+ uint64_t root;
+ uint64_t chunk_root;
+ uint64_t log_root;
+ uint64_t log_root_transid;
+ uint64_t total_bytes;
+ uint64_t bytes_used;
+ uint64_t root_dir_objectid;
+ uint64_t num_devices;
+ uint32_t sectorsize;
+ uint32_t nodesize;
+ uint32_t leafsize;
+ uint32_t stripesize;
+ uint32_t sys_chunk_array_size;
+ uint64_t chunk_root_generation;
+ uint64_t compat_flags;
+ uint64_t compat_ro_flags;
+ uint64_t incompat_flags;
+ uint16_t csum_type;
+ uint8_t root_level;
+ uint8_t chunk_root_level;
+ uint8_t log_root_level;
+ struct btrfs_dev_item {
+ uint64_t devid;
+ uint64_t total_bytes;
+ uint64_t bytes_used;
+ uint32_t io_align;
+ uint32_t io_width;
+ uint32_t sector_size;
+ uint64_t type;
+ uint64_t generation;
+ uint64_t start_offset;
+ uint32_t dev_group;
+ uint8_t seek_speed;
+ uint8_t bandwidth;
+ uint8_t uuid[16];
+ uint8_t fsid[16];
+ } __attribute__ ((__packed__)) dev_item;
+ uint8_t label[256];
} __attribute__ ((__packed__));
+#define BTRFS_IOCTL_MAGIC 0x94
+#define BTRFS_VOL_NAME_MAX 255
+#define BTRFS_PATH_NAME_MAX 4087
+
+struct btrfs_ioctl_vol_args {
+ __s64 fd;
+ char name[BTRFS_PATH_NAME_MAX + 1];
+};
+
+struct btrfs_ioctl_search_key {
+ /* which root are we searching. 0 is the tree of tree roots */
+ __u64 tree_id;
+
+ /* keys returned will be >= min and <= max */
+ __u64 min_objectid;
+ __u64 max_objectid;
+
+ /* keys returned will be >= min and <= max */
+ __u64 min_offset;
+ __u64 max_offset;
+
+ /* max and min transids to search for */
+ __u64 min_transid;
+ __u64 max_transid;
+
+ /* keys returned will be >= min and <= max */
+ __u32 min_type;
+ __u32 max_type;
+
+ /*
+ * how many items did userland ask for, and how many are we
+ * returning
+ */
+ __u32 nr_items;
+
+ /* align to 64 bits */
+ __u32 unused;
+
+ /* some extra for later */
+ __u64 unused1;
+ __u64 unused2;
+ __u64 unused3;
+ __u64 unused4;
+};
+
+struct btrfs_ioctl_search_header {
+ __u64 transid;
+ __u64 objectid;
+ __u64 offset;
+ __u32 type;
+ __u32 len;
+} __attribute__((may_alias));
+
+#define BTRFS_DEVICE_PATH_NAME_MAX 1024
+struct btrfs_ioctl_dev_info_args {
+ __u64 devid; /* in/out */
+ __u8 uuid[BTRFS_UUID_SIZE]; /* in/out */
+ __u64 bytes_used; /* out */
+ __u64 total_bytes; /* out */
+ __u64 unused[379]; /* pad to 4k */
+ __u8 path[BTRFS_DEVICE_PATH_NAME_MAX]; /* out */
+};
+
+struct btrfs_ioctl_fs_info_args {
+ __u64 max_id; /* out */
+ __u64 num_devices; /* out */
+ __u8 fsid[BTRFS_FSID_SIZE]; /* out */
+ __u64 reserved[124]; /* pad to 1k */
+};
+
+#define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key))
+/*
+ * the buf is an array of search headers where
+ * each header is followed by the actual item
+ * the type field is expanded to 32 bits for alignment
+ */
+struct btrfs_ioctl_search_args {
+ struct btrfs_ioctl_search_key key;
+ char buf[BTRFS_SEARCH_ARGS_BUFSIZE];
+};
+
+#define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \
+ struct btrfs_ioctl_search_args)
+#define BTRFS_IOC_DEV_INFO _IOWR(BTRFS_IOCTL_MAGIC, 30, \
+ struct btrfs_ioctl_dev_info_args)
+#define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \
+ struct btrfs_ioctl_fs_info_args)
+
#endif
diff --git a/extlinux/main.c b/extlinux/main.c
index e5212a95..f0d8e11b 100755..100644
--- a/extlinux/main.c
+++ b/extlinux/main.c
@@ -1,7 +1,7 @@
/* ----------------------------------------------------------------------- *
*
* Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
- * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ * Copyright 2009-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
@@ -14,18 +14,18 @@
/*
* extlinux.c
*
- * Install the syslinux boot block on an fat, ext2/3/4 and btrfs filesystem
+ * Install the syslinux boot block on an fat, ntfs, ext2/3/4 and btrfs filesystem
*/
#define _GNU_SOURCE /* Enable everything */
#include <inttypes.h>
/* This is needed to deal with the kernel headers imported into glibc 3.3.3. */
-typedef uint64_t u64;
#include <alloca.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
+#include <dirent.h>
#ifndef __KLIBC__
#include <mntent.h>
#endif
@@ -45,11 +45,14 @@ typedef uint64_t u64;
#include "btrfs.h"
#include "fat.h"
+#include "ntfs.h"
#include "../version.h"
#include "syslxint.h"
#include "syslxcom.h" /* common functions shared with extlinux and syslinux */
+#include "syslxfs.h"
#include "setadv.h"
#include "syslxopt.h" /* unified options */
+#include "mountinfo.h"
#ifdef DEBUG
# define dprintf printf
@@ -65,7 +68,6 @@ typedef uint64_t u64;
boot image, the boot sector is from 0~512, the boot image starts after */
#define BTRFS_BOOTSECT_AREA 65536
#define BTRFS_EXTLINUX_OFFSET SECTOR_SIZE
-#define BTRFS_SUBVOL_OPT "subvol="
#define BTRFS_SUBVOL_MAX 256 /* By btrfs specification */
static char subvol[BTRFS_SUBVOL_MAX];
@@ -74,7 +76,7 @@ static char subvol[BTRFS_SUBVOL_MAX];
/*
* Get the size of a block device
*/
-uint64_t get_size(int devfd)
+static uint64_t get_size(int devfd)
{
uint64_t bytes;
uint32_t sects;
@@ -112,7 +114,7 @@ static int sysfs_get_offset(int devfd, unsigned long *start)
if ((size_t)snprintf(sysfs_name, sizeof sysfs_name,
"/sys/dev/block/%u:%u/start",
- major(st.st_dev), minor(st.st_dev))
+ major(st.st_rdev), minor(st.st_rdev))
>= sizeof sysfs_name)
return -1;
@@ -153,7 +155,7 @@ int get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo)
memset(geo, 0, sizeof *geo);
- if (!ioctl(devfd, HDIO_GETGEO, &geo)) {
+ if (!ioctl(devfd, HDIO_GETGEO, geo)) {
goto ok;
} else if (!ioctl(devfd, FDGETPRM, &fd_str)) {
geo->heads = fd_str.head;
@@ -208,14 +210,14 @@ ok:
*
* Returns the number of modified bytes in the boot file.
*/
-int patch_file_and_bootblock(int fd, const char *dir, int devfd)
+static int patch_file_and_bootblock(int fd, const char *dir, int devfd)
{
struct stat dirst, xdst;
struct hd_geometry geo;
sector_t *sectp;
uint64_t totalbytes, totalsectors;
int nsect;
- struct boot_sector *sbs;
+ struct fat_boot_sector *sbs;
char *dirpath, *subpath, *xdirpath;
int rv;
@@ -272,7 +274,7 @@ int patch_file_and_bootblock(int fd, const char *dir, int devfd)
early bootstrap share code with the FAT version. */
dprintf("heads = %u, sect = %u\n", geo.heads, geo.sectors);
- sbs = (struct boot_sector *)syslinux_bootsect;
+ sbs = (struct fat_boot_sector *)syslinux_bootsect;
totalsectors = totalbytes >> SECTOR_SHIFT;
if (totalsectors >= 65536) {
@@ -293,7 +295,7 @@ int patch_file_and_bootblock(int fd, const char *dir, int devfd)
nsect = (boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
nsect += 2; /* Two sectors for the ADV */
sectp = alloca(sizeof(sector_t) * nsect);
- if (fs_type == EXT2 || fs_type == VFAT) {
+ if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS) {
if (sectmap(fd, sectp, nsect)) {
perror("bmap");
exit(1);
@@ -324,7 +326,8 @@ int install_bootblock(int fd, const char *device)
{
struct ext2_super_block sb;
struct btrfs_super_block sb2;
- struct boot_sector sb3;
+ struct fat_boot_sector sb3;
+ struct ntfs_boot_sector sb4;
bool ok = false;
if (fs_type == EXT2) {
@@ -340,31 +343,48 @@ int install_bootblock(int fd, const char *device)
perror("reading superblock");
return 1;
}
- if (sb2.magic == *(u64 *)BTRFS_MAGIC)
+ if (!memcmp(sb2.magic, BTRFS_MAGIC, BTRFS_MAGIC_L))
ok = true;
} else if (fs_type == VFAT) {
if (xpread(fd, &sb3, sizeof sb3, 0) != sizeof sb3) {
perror("reading fat superblock");
return 1;
}
- if (sb3.bsResSectors && sb3.bsFATs &&
- (strstr(sb3.bs16.FileSysType, "FAT") ||
- strstr(sb3.bs32.FileSysType, "FAT")))
+ if (fat_check_sb_fields(&sb3))
ok = true;
+ } else if (fs_type == NTFS) {
+ if (xpread(fd, &sb4, sizeof(sb4), 0) != sizeof(sb4)) {
+ perror("reading ntfs superblock");
+ return 1;
+ }
+
+ if (ntfs_check_sb_fields(&sb4))
+ ok = true;
}
if (!ok) {
- fprintf(stderr, "no fat, ext2/3/4 or btrfs superblock found on %s\n",
+ fprintf(stderr, "no fat, ntfs, ext2/3/4 or btrfs superblock found on %s\n",
device);
return 1;
}
if (fs_type == VFAT) {
- struct boot_sector *sbs = (struct boot_sector *)syslinux_bootsect;
- if (xpwrite(fd, &sbs->bsHead, bsHeadLen, 0) != bsHeadLen ||
- xpwrite(fd, &sbs->bsCode, bsCodeLen,
- offsetof(struct boot_sector, bsCode)) != bsCodeLen) {
+ struct fat_boot_sector *sbs = (struct fat_boot_sector *)syslinux_bootsect;
+ if (xpwrite(fd, &sbs->FAT_bsHead, FAT_bsHeadLen, 0) != FAT_bsHeadLen ||
+ xpwrite(fd, &sbs->FAT_bsCode, FAT_bsCodeLen,
+ offsetof(struct fat_boot_sector, FAT_bsCode)) != FAT_bsCodeLen) {
perror("writing fat bootblock");
return 1;
}
+ } else if (fs_type == NTFS) {
+ struct ntfs_boot_sector *sbs =
+ (struct ntfs_boot_sector *)syslinux_bootsect;
+ if (xpwrite(fd, &sbs->NTFS_bsHead,
+ NTFS_bsHeadLen, 0) != NTFS_bsHeadLen ||
+ xpwrite(fd, &sbs->NTFS_bsCode, NTFS_bsCodeLen,
+ offsetof(struct ntfs_boot_sector,
+ NTFS_bsCode)) != NTFS_bsCodeLen) {
+ perror("writing ntfs bootblock");
+ return 1;
+ }
} else {
if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len, 0)
!= syslinux_bootsect_len) {
@@ -494,9 +514,241 @@ int btrfs_install_file(const char *path, int devfd, struct stat *rst)
return 0;
}
-int install_file(const char *path, int devfd, struct stat *rst)
+/*
+ * * test if path is a subvolume:
+ * * this function return
+ * * 0-> path exists but it is not a subvolume
+ * * 1-> path exists and it is a subvolume
+ * * -1 -> path is unaccessible
+ * */
+static int test_issubvolume(char *path)
+{
+
+ struct stat st;
+ int res;
+
+ res = stat(path, &st);
+ if(res < 0 )
+ return -1;
+
+ return (st.st_ino == 256) && S_ISDIR(st.st_mode);
+
+}
+
+/*
+ * Get the default subvolume of a btrfs filesystem
+ * rootdir: btrfs root dir
+ * subvol: this function will save the default subvolume name here
+ */
+static char * get_default_subvol(char * rootdir, char * subvol)
+{
+ struct btrfs_ioctl_search_args args;
+ struct btrfs_ioctl_search_key *sk = &args.key;
+ struct btrfs_ioctl_search_header *sh;
+ int ret, i;
+ int fd;
+ struct btrfs_root_ref *ref;
+ struct btrfs_dir_item *dir_item;
+ unsigned long off = 0;
+ int name_len;
+ char *name;
+ char dirname[4096];
+ u64 defaultsubvolid = 0;
+
+ ret = test_issubvolume(rootdir);
+ if (ret == 1) {
+ fd = open(rootdir, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "ERROR: failed to open %s\n", rootdir);
+ }
+ ret = fd;
+ }
+ if (ret <= 0) {
+ subvol[0] = '\0';
+ return NULL;
+ }
+
+ memset(&args, 0, sizeof(args));
+
+ /* search in the tree of tree roots */
+ sk->tree_id = 1;
+
+ /*
+ * set the min and max to backref keys. The search will
+ * only send back this type of key now.
+ */
+ sk->max_type = BTRFS_DIR_ITEM_KEY;
+ sk->min_type = BTRFS_DIR_ITEM_KEY;
+
+ /*
+ * set all the other params to the max, we'll take any objectid
+ * and any trans
+ */
+ sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
+ sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
+
+ sk->max_offset = (u64)-1;
+ sk->min_offset = 0;
+ sk->max_transid = (u64)-1;
+
+ /* just a big number, doesn't matter much */
+ sk->nr_items = 4096;
+
+ while(1) {
+ ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: can't perform the search\n");
+ subvol[0] = '\0';
+ return NULL;
+ }
+ /* the ioctl returns the number of item it found in nr_items */
+ if (sk->nr_items == 0) {
+ break;
+ }
+
+ off = 0;
+
+ /*
+ * for each item, pull the key out of the header and then
+ * read the root_ref item it contains
+ */
+ for (i = 0; i < sk->nr_items; i++) {
+ sh = (struct btrfs_ioctl_search_header *)(args.buf + off);
+ off += sizeof(*sh);
+ if (sh->type == BTRFS_DIR_ITEM_KEY) {
+ dir_item = (struct btrfs_dir_item *)(args.buf + off);
+ name_len = dir_item->name_len;
+ name = (char *)(dir_item + 1);
+
+
+ /*add_root(&root_lookup, sh->objectid, sh->offset,
+ dir_id, name, name_len);*/
+ strncpy(dirname, name, name_len);
+ dirname[name_len] = '\0';
+ if (strcmp(dirname, "default") == 0) {
+ defaultsubvolid = dir_item->location.objectid;
+ break;
+ }
+ }
+ off += sh->len;
+
+ /*
+ * record the mins in sk so we can make sure the
+ * next search doesn't repeat this root
+ */
+ sk->min_objectid = sh->objectid;
+ sk->min_type = sh->type;
+ sk->max_type = sh->type;
+ sk->min_offset = sh->offset;
+ }
+ if (defaultsubvolid != 0)
+ break;
+ sk->nr_items = 4096;
+ /* this iteration is done, step forward one root for the next
+ * ioctl
+ */
+ if (sk->min_objectid < (u64)-1) {
+ sk->min_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
+ sk->max_objectid = BTRFS_ROOT_TREE_DIR_OBJECTID;
+ sk->max_type = BTRFS_ROOT_BACKREF_KEY;
+ sk->min_type = BTRFS_ROOT_BACKREF_KEY;
+ sk->min_offset = 0;
+ } else
+ break;
+ }
+
+ if (defaultsubvolid == 0) {
+ subvol[0] = '\0';
+ return NULL;
+ }
+
+ memset(&args, 0, sizeof(args));
+
+ /* search in the tree of tree roots */
+ sk->tree_id = 1;
+
+ /*
+ * set the min and max to backref keys. The search will
+ * only send back this type of key now.
+ */
+ sk->max_type = BTRFS_ROOT_BACKREF_KEY;
+ sk->min_type = BTRFS_ROOT_BACKREF_KEY;
+
+ /*
+ * set all the other params to the max, we'll take any objectid
+ * and any trans
+ */
+ sk->max_objectid = (u64)-1;
+ sk->max_offset = (u64)-1;
+ sk->max_transid = (u64)-1;
+
+ /* just a big number, doesn't matter much */
+ sk->nr_items = 4096;
+
+ while(1) {
+ ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
+ if (ret < 0) {
+ fprintf(stderr, "ERROR: can't perform the search\n");
+ subvol[0] = '\0';
+ return NULL;
+ }
+ /* the ioctl returns the number of item it found in nr_items */
+ if (sk->nr_items == 0)
+ break;
+
+ off = 0;
+
+ /*
+ * for each item, pull the key out of the header and then
+ * read the root_ref item it contains
+ */
+ for (i = 0; i < sk->nr_items; i++) {
+ sh = (struct btrfs_ioctl_search_header *)(args.buf + off);
+ off += sizeof(*sh);
+ if (sh->type == BTRFS_ROOT_BACKREF_KEY) {
+ ref = (struct btrfs_root_ref *)(args.buf + off);
+ name_len = ref->name_len;
+ name = (char *)(ref + 1);
+
+ if (sh->objectid == defaultsubvolid) {
+ strncpy(subvol, name, name_len);
+ subvol[name_len] = '\0';
+ dprintf("The default subvolume: %s, ID: %llu\n",
+ subvol, sh->objectid);
+ break;
+ }
+
+ }
+
+ off += sh->len;
+
+ /*
+ * record the mins in sk so we can make sure the
+ * next search doesn't repeat this root
+ */
+ sk->min_objectid = sh->objectid;
+ sk->min_type = sh->type;
+ sk->min_offset = sh->offset;
+ }
+ if (subvol[0] != '\0')
+ break;
+ sk->nr_items = 4096;
+ /* this iteration is done, step forward one root for the next
+ * ioctl
+ */
+ if (sk->min_objectid < (u64)-1) {
+ sk->min_objectid++;
+ sk->min_type = BTRFS_ROOT_BACKREF_KEY;
+ sk->min_offset = 0;
+ } else
+ break;
+ }
+ return subvol;
+}
+
+static int install_file(const char *path, int devfd, struct stat *rst)
{
- if (fs_type == EXT2 || fs_type == VFAT)
+ if (fs_type == EXT2 || fs_type == VFAT || fs_type == NTFS)
return ext2_fat_install_file(path, devfd, rst);
else if (fs_type == BTRFS)
return btrfs_install_file(path, devfd, rst);
@@ -514,17 +766,33 @@ static void device_cleanup(void)
/* Verify that a device fd and a pathname agree.
Return 0 on valid, -1 on error. */
+static int validate_device_btrfs(int pathfd, int devfd);
static int validate_device(const char *path, int devfd)
{
struct stat pst, dst;
struct statfs sfs;
+ int pfd;
+ int rv = -1;
+
+ pfd = open(path, O_RDONLY|O_DIRECTORY);
+ if (pfd < 0)
+ goto err;
+
+ if (fstat(pfd, &pst) || fstat(devfd, &dst) || statfs(path, &sfs))
+ goto err;
- if (stat(path, &pst) || fstat(devfd, &dst) || statfs(path, &sfs))
- return -1;
/* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
- if (fs_type == BTRFS && sfs.f_type == BTRFS_SUPER_MAGIC)
- return 0;
- return (pst.st_dev == dst.st_rdev) ? 0 : -1;
+ if (fs_type == BTRFS) {
+ if (sfs.f_type == BTRFS_SUPER_MAGIC)
+ rv = validate_device_btrfs(pfd, devfd);
+ } else {
+ rv = (pst.st_dev == dst.st_rdev) ? 0 : -1;
+ }
+
+err:
+ if (pfd >= 0)
+ close(pfd);
+ return rv;
}
#ifndef __KLIBC__
@@ -545,47 +813,46 @@ static const char *find_device(const char *mtab_file, dev_t dev)
/* btrfs st_dev is not matched with mnt st_rdev, it is a known issue */
switch (fs_type) {
case BTRFS:
- if (!strcmp(mnt->mnt_type, "btrfs") &&
- !stat(mnt->mnt_dir, &dst) &&
- dst.st_dev == dev) {
- char *opt = strstr(mnt->mnt_opts, BTRFS_SUBVOL_OPT);
-
- if (opt) {
- if (!subvol[0]) {
- char *tmp;
-
- strcpy(subvol, opt + sizeof(BTRFS_SUBVOL_OPT) - 1);
- tmp = strchr(subvol, 32);
- if (tmp)
- *tmp = '\0';
- }
- break; /* should break and let upper layer try again */
- } else
- done = true;
- }
- break;
+ if (!strcmp(mnt->mnt_type, "btrfs") &&
+ !stat(mnt->mnt_dir, &dst) &&
+ dst.st_dev == dev) {
+ if (!subvol[0])
+ get_default_subvol(mnt->mnt_dir, subvol);
+ done = true;
+ }
+ break;
case EXT2:
- if ((!strcmp(mnt->mnt_type, "ext2") ||
- !strcmp(mnt->mnt_type, "ext3") ||
- !strcmp(mnt->mnt_type, "ext4")) &&
- !stat(mnt->mnt_fsname, &dst) &&
- dst.st_rdev == dev) {
- done = true;
- break;
- }
+ if ((!strcmp(mnt->mnt_type, "ext2") ||
+ !strcmp(mnt->mnt_type, "ext3") ||
+ !strcmp(mnt->mnt_type, "ext4")) &&
+ !stat(mnt->mnt_fsname, &dst) &&
+ dst.st_rdev == dev) {
+ done = true;
+ break;
+ }
case VFAT:
- if ((!strcmp(mnt->mnt_type, "vfat")) &&
- !stat(mnt->mnt_fsname, &dst) &&
- dst.st_rdev == dev) {
- done = true;
- break;
- }
+ if ((!strcmp(mnt->mnt_type, "vfat")) &&
+ !stat(mnt->mnt_fsname, &dst) &&
+ dst.st_rdev == dev) {
+ done = true;
+ break;
+ }
+ case NTFS:
+ if ((!strcmp(mnt->mnt_type, "fuseblk") /* ntfs-3g */ ||
+ !strcmp(mnt->mnt_type, "ntfs")) &&
+ !stat(mnt->mnt_fsname, &dst) &&
+ dst.st_rdev == dev) {
+ done = true;
+ break;
+ }
+
+ break;
case NONE:
break;
}
if (done) {
- devname = strdup(mnt->mnt_fsname);
- break;
+ devname = strdup(mnt->mnt_fsname);
+ break;
}
}
endmntent(mtab);
@@ -594,6 +861,158 @@ static const char *find_device(const char *mtab_file, dev_t dev)
}
#endif
+/*
+ * On newer Linux kernels we can use sysfs to get a backwards mapping
+ * from device names to standard filenames
+ */
+static const char *find_device_sysfs(dev_t dev)
+{
+ char sysname[64];
+ char linkname[PATH_MAX];
+ ssize_t llen;
+ char *p, *q;
+ char *buf = NULL;
+ struct stat st;
+
+ snprintf(sysname, sizeof sysname, "/sys/dev/block/%u:%u",
+ major(dev), minor(dev));
+
+ llen = readlink(sysname, linkname, sizeof linkname);
+ if (llen < 0 || llen >= sizeof linkname)
+ goto err;
+
+ linkname[llen] = '\0';
+
+ p = strrchr(linkname, '/');
+ p = p ? p+1 : linkname; /* Leave basename */
+
+ buf = q = malloc(strlen(p) + 6);
+ if (!buf)
+ goto err;
+
+ memcpy(q, "/dev/", 5);
+ q += 5;
+
+ while (*p) {
+ *q++ = (*p == '!') ? '/' : *p;
+ p++;
+ }
+
+ *q = '\0';
+
+ if (!stat(buf, &st) && st.st_dev == dev)
+ return buf; /* Found it! */
+
+err:
+ if (buf)
+ free(buf);
+ return NULL;
+}
+
+static const char *find_device_mountinfo(const char *path, dev_t dev)
+{
+ const struct mountinfo *m;
+ struct stat st;
+
+ m = find_mount(path, NULL);
+
+ if (m->devpath[0] == '/' && m->dev == dev &&
+ !stat(m->devpath, &st) && S_ISBLK(st.st_mode) && st.st_rdev == dev)
+ return m->devpath;
+ else
+ return NULL;
+}
+
+static int validate_device_btrfs(int pfd, int dfd)
+{
+ struct btrfs_ioctl_fs_info_args fsinfo;
+ static struct btrfs_ioctl_dev_info_args devinfo;
+ struct btrfs_super_block sb2;
+
+ if (ioctl(pfd, BTRFS_IOC_FS_INFO, &fsinfo))
+ return -1;
+
+ /* We do not support multi-device btrfs yet */
+ if (fsinfo.num_devices != 1)
+ return -1;
+
+ /* The one device will have the max devid */
+ memset(&devinfo, 0, sizeof devinfo);
+ devinfo.devid = fsinfo.max_id;
+ if (ioctl(pfd, BTRFS_IOC_DEV_INFO, &devinfo))
+ return -1;
+
+ if (devinfo.path[0] != '/')
+ return -1;
+
+ if (xpread(dfd, &sb2, sizeof sb2, BTRFS_SUPER_INFO_OFFSET) != sizeof sb2)
+ return -1;
+
+ if (memcmp(sb2.magic, BTRFS_MAGIC, BTRFS_MAGIC_L))
+ return -1;
+
+ if (memcmp(sb2.fsid, fsinfo.fsid, sizeof fsinfo.fsid))
+ return -1;
+
+ if (sb2.num_devices != 1)
+ return -1;
+
+ if (sb2.dev_item.devid != devinfo.devid)
+ return -1;
+
+ if (memcmp(sb2.dev_item.uuid, devinfo.uuid, sizeof devinfo.uuid))
+ return -1;
+
+ if (memcmp(sb2.dev_item.fsid, fsinfo.fsid, sizeof fsinfo.fsid))
+ return -1;
+
+ return 0; /* It's good! */
+}
+
+static const char *find_device_btrfs(const char *path)
+{
+ int pfd, dfd;
+ struct btrfs_ioctl_fs_info_args fsinfo;
+ static struct btrfs_ioctl_dev_info_args devinfo;
+ const char *rv = NULL;
+
+ pfd = dfd = -1;
+
+ pfd = open(path, O_RDONLY);
+ if (pfd < 0)
+ goto err;
+
+ if (ioctl(pfd, BTRFS_IOC_FS_INFO, &fsinfo))
+ goto err;
+
+ /* We do not support multi-device btrfs yet */
+ if (fsinfo.num_devices != 1)
+ goto err;
+
+ /* The one device will have the max devid */
+ memset(&devinfo, 0, sizeof devinfo);
+ devinfo.devid = fsinfo.max_id;
+ if (ioctl(pfd, BTRFS_IOC_DEV_INFO, &devinfo))
+ goto err;
+
+ if (devinfo.path[0] != '/')
+ goto err;
+
+ dfd = open((const char *)devinfo.path, O_RDONLY);
+ if (dfd < 0)
+ goto err;
+
+ if (!validate_device_btrfs(pfd, dfd))
+ rv = (const char *)devinfo.path; /* It's good! */
+
+err:
+ if (pfd >= 0)
+ close(pfd);
+ if (dfd >= 0)
+ close(dfd);
+ return rv;
+}
+
static const char *get_devname(const char *path)
{
const char *devname = NULL;
@@ -608,48 +1027,57 @@ static const char *get_devname(const char *path)
fprintf(stderr, "%s: statfs %s: %s\n", program, path, strerror(errno));
return devname;
}
-#ifdef __KLIBC__
- /* klibc doesn't have getmntent and friends; instead, just create
- a new device with the appropriate device type */
- snprintf(devname_buf, sizeof devname_buf, "/tmp/dev-%u:%u",
- major(st.st_dev), minor(st.st_dev));
+ if (opt.device)
+ devname = opt.device;
- if (mknod(devname_buf, S_IFBLK | 0600, st.st_dev)) {
- fprintf(stderr, "%s: cannot create device %s\n", program, devname);
- return devname;
+ if (!devname){
+ if (fs_type == BTRFS) {
+ /* For btrfs try to get the device name from btrfs itself */
+ devname = find_device_btrfs(path);
+ }
}
- atexit(device_cleanup); /* unlink the device node on exit */
- devname = devname_buf;
-
-#else
+ if (!devname) {
+ devname = find_device_mountinfo(path, st.st_dev);
+ }
- /* check /etc/mtab first, since btrfs subvol info is only in here */
- devname = find_device("/etc/mtab", st.st_dev);
- if (subvol[0] && !devname) { /* we just find it is a btrfs subvol */
- char parent[256];
- char *tmp;
-
- strcpy(parent, path);
- tmp = strrchr(parent, '/');
- if (tmp) {
- *tmp = '\0';
- fprintf(stderr, "%s is subvol, try its parent dir %s\n", path, parent);
- devname = get_devname(parent);
- } else
- devname = NULL;
+#ifdef __KLIBC__
+ if (!devname) {
+ devname = find_device_sysfs(st.st_dev);
+ }
+ if (!devname) {
+ /* klibc doesn't have getmntent and friends; instead, just create
+ a new device with the appropriate device type */
+ snprintf(devname_buf, sizeof devname_buf, "/tmp/dev-%u:%u",
+ major(st.st_dev), minor(st.st_dev));
+
+ if (mknod(devname_buf, S_IFBLK | 0600, st.st_dev)) {
+ fprintf(stderr, "%s: cannot create device %s\n", program, devname);
+ return devname;
+ }
+
+ atexit(device_cleanup); /* unlink the device node on exit */
+ devname = devname_buf;
}
+
+#else
if (!devname) {
- /* Didn't find it in /etc/mtab, try /proc/mounts */
devname = find_device("/proc/mounts", st.st_dev);
}
if (!devname) {
+ /* Didn't find it in /proc/mounts, try /etc/mtab */
+ devname = find_device("/etc/mtab", st.st_dev);
+ }
+ if (!devname) {
+ devname = find_device_sysfs(st.st_dev);
+
fprintf(stderr, "%s: cannot find device for path %s\n", program, path);
return devname;
}
fprintf(stderr, "%s is device %s\n", path, devname);
+
#endif
return devname;
}
@@ -676,9 +1104,12 @@ static int open_device(const char *path, struct stat *st, const char **_devname)
fs_type = BTRFS;
else if (sfs.f_type == MSDOS_SUPER_MAGIC)
fs_type = VFAT;
+ else if (sfs.f_type == NTFS_SB_MAGIC ||
+ sfs.f_type == FUSE_SUPER_MAGIC /* ntfs-3g */)
+ fs_type = NTFS;
if (!fs_type) {
- fprintf(stderr, "%s: not a fat, ext2/3/4 or btrfs filesystem: %s\n",
+ fprintf(stderr, "%s: not a fat, ntfs, ext2/3/4 or btrfs filesystem: %s\n",
program, path);
return -1;
}
@@ -725,7 +1156,7 @@ static int ext_read_adv(const char *path, int devfd, const char **namep)
if (err == 2) /* ldlinux.sys does not exist */
err = read_adv(path, name = "extlinux.sys");
if (namep)
- *namep = name;
+ *namep = name;
return err;
}
}
@@ -743,7 +1174,7 @@ static int ext_write_adv(const char *path, const char *cfg, int devfd)
return write_adv(path, cfg);
}
-int install_loader(const char *path, int update_only)
+static int install_loader(const char *path, int update_only)
{
struct stat st, fst;
int devfd, rv;
diff --git a/extlinux/mountinfo.c b/extlinux/mountinfo.c
new file mode 100644
index 00000000..2be87580
--- /dev/null
+++ b/extlinux/mountinfo.c
@@ -0,0 +1,277 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2012 Intel Corporation; 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 <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include "mountinfo.h"
+
+/*
+ * Parse /proc/self/mountinfo
+ */
+static int get_string(FILE *f, char *string_buf, size_t string_len, char *ec)
+{
+ int ch;
+ char *p = string_buf;
+
+ for (;;) {
+ if (!string_len)
+ return -2; /* String too long */
+
+ ch = getc(f);
+ if (ch == EOF) {
+ return -1; /* Got EOF */
+ } else if (ch == ' ' || ch == '\t' || ch == '\n') {
+ *ec = ch;
+ *p = '\0';
+ return p - string_buf;
+ } else if (ch == '\\') {
+ /* Should always be followed by 3 octal digits in 000..377 */
+ int oc = 0;
+ int i;
+ for (i = 0; i < 3; i++) {
+ ch = getc(f);
+ if (ch < '0' || ch > '7' || (i == 0 && ch > '3'))
+ return -1; /* Bad escape sequence */
+ oc = (oc << 3) + (ch - '0');
+ }
+ if (!oc)
+ return -1; /* We can't handle \000 */
+ *p++ = oc;
+ string_len--;
+ } else {
+ *p++ = ch;
+ string_len--;
+ }
+ }
+}
+
+static void free_mountinfo(struct mountinfo *m)
+{
+ struct mountinfo *nx;
+
+ while (m) {
+ free((char *)m->root);
+ free((char *)m->path);
+ free((char *)m->fstype);
+ free((char *)m->devpath);
+ free((char *)m->mountopt);
+ nx = m->next;
+ free(m);
+ m = nx;
+ }
+}
+
+static struct mountinfo *head = NULL, **tail = &head;
+
+static void parse_mountinfo(void)
+{
+ FILE *f;
+ struct mountinfo *m, *mm;
+ char string_buf[PATH_MAX*8];
+ int n;
+ char ec, *ep;
+ unsigned int ma, mi;
+
+ f = fopen("/proc/self/mountinfo", "r");
+ if (!f)
+ return;
+
+ for (;;) {
+ m = malloc(sizeof(struct mountinfo));
+ if (!m)
+ break;
+ memset(m, 0, sizeof *m);
+
+ n = get_string(f, string_buf, sizeof string_buf, &ec);
+ if (n < 0 || ec == '\n')
+ break;
+
+ m->mountid = strtoul(string_buf, &ep, 10);
+ if (*ep)
+ break;
+
+ n = get_string(f, string_buf, sizeof string_buf, &ec);
+ if (n < 0 || ec == '\n')
+ break;
+
+ m->parentid = strtoul(string_buf, &ep, 10);
+ if (*ep)
+ break;
+
+ n = get_string(f, string_buf, sizeof string_buf, &ec);
+ if (n < 0 || ec == '\n')
+ break;
+
+ if (sscanf(string_buf, "%u:%u", &ma, &mi) != 2)
+ break;
+
+ m->dev = makedev(ma, mi);
+
+ n = get_string(f, string_buf, sizeof string_buf, &ec);
+ if (n < 1 || ec == '\n' || string_buf[0] != '/')
+ break;
+
+ m->root = strdup(string_buf);
+ if (!m->root)
+ break;
+
+ n = get_string(f, string_buf, sizeof string_buf, &ec);
+ if (n < 1 || ec == '\n' || string_buf[0] != '/')
+ break;
+
+ m->path = strdup(string_buf);
+ m->pathlen = (n == 1) ? 0 : n; /* Treat / as empty */
+
+ /* Skip tagged attributes */
+ do {
+ n = get_string(f, string_buf, sizeof string_buf, &ec);
+ if (n < 0 || ec == '\n')
+ goto quit;
+ } while (n != 1 || string_buf[0] != '-');
+
+ n = get_string(f, string_buf, sizeof string_buf, &ec);
+ if (n < 0 || ec == '\n')
+ break;
+
+ m->fstype = strdup(string_buf);
+ if (!m->fstype)
+ break;
+
+ n = get_string(f, string_buf, sizeof string_buf, &ec);
+ if (n < 0 || ec == '\n')
+ break;
+
+ m->devpath = strdup(string_buf);
+ if (!m->devpath)
+ break;
+
+ n = get_string(f, string_buf, sizeof string_buf, &ec);
+ if (n < 0)
+ break;
+
+ m->mountopt = strdup(string_buf);
+ if (!m->mountopt)
+ break;
+
+ /* Skip any previously unknown fields */
+ while (ec != '\n' && ec != EOF)
+ ec = getc(f);
+
+ *tail = m;
+ tail = &m->next;
+ }
+quit:
+ fclose(f);
+ free_mountinfo(m);
+
+ /* Create parent links */
+ for (m = head; m; m = m->next) {
+ for (mm = head; mm; mm = mm->next) {
+ if (m->parentid == mm->mountid) {
+ m->parent = mm;
+ if (!strcmp(m->path, mm->path))
+ mm->hidden = 1; /* Hidden under another mount */
+ break;
+ }
+ }
+ }
+}
+
+const struct mountinfo *find_mount(const char *path, char **subpath)
+{
+ static int done_init;
+ char *real_path;
+ const struct mountinfo *m, *best;
+ struct stat st;
+ int len, matchlen;
+
+ if (!done_init) {
+ parse_mountinfo();
+ done_init = 1;
+ }
+
+ if (stat(path, &st))
+ return NULL;
+
+ real_path = realpath(path, NULL);
+ if (!real_path)
+ return NULL;
+
+ /*
+ * Tricky business: we need the longest matching subpath
+ * which isn't a parent of the same subpath.
+ */
+ len = strlen(real_path);
+ matchlen = 0;
+ best = NULL;
+ for (m = head; m; m = m->next) {
+ if (m->hidden)
+ continue; /* Hidden underneath another mount */
+
+ if (m->pathlen > len)
+ continue; /* Cannot possibly match */
+
+ if (m->pathlen < matchlen)
+ continue; /* No point in testing this one */
+
+ if (st.st_dev == m->dev &&
+ !memcmp(m->path, real_path, m->pathlen) &&
+ (real_path[m->pathlen] == '/' || real_path[m->pathlen] == '\0')) {
+ matchlen = m->pathlen;
+ best = m;
+ }
+ }
+
+ if (best && subpath) {
+ if (real_path[best->pathlen] == '\0')
+ *subpath = strdup("/");
+ else
+ *subpath = strdup(real_path + best->pathlen);
+ }
+
+ return best;
+}
+
+#ifdef TEST
+
+int main(int argc, char *argv[])
+{
+ int i;
+ const struct mountinfo *m;
+ char *subpath;
+
+ parse_mountinfo();
+
+ for (i = 1; i < argc; i++) {
+ m = find_mount(argv[i], &subpath);
+ if (!m) {
+ printf("%s: %s\n", argv[i], strerror(errno));
+ continue;
+ }
+
+ printf("%s -> %s @ %s(%u,%u):%s %s %s\n",
+ argv[i], subpath, m->devpath, major(m->dev), minor(m->dev),
+ m->root, m->fstype, m->mountopt);
+ printf("Usable device: %s\n", find_device(m->dev, m->devpath));
+ free(subpath);
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/extlinux/mountinfo.h b/extlinux/mountinfo.h
new file mode 100644
index 00000000..9cbcac12
--- /dev/null
+++ b/extlinux/mountinfo.h
@@ -0,0 +1,35 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2012 Intel Corporation; 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef SYSLINUX_MOUNTINFO_H
+#define SYSLINUX_MOUNTINFO_H
+
+#include <sys/types.h>
+
+struct mountinfo {
+ struct mountinfo *next;
+ struct mountinfo *parent;
+ const char *root;
+ const char *path;
+ const char *fstype;
+ const char *devpath;
+ const char *mountopt;
+ int mountid;
+ int parentid;
+ int pathlen;
+ int hidden;
+ dev_t dev;
+};
+
+const struct mountinfo *find_mount(const char *path, char **subpath);
+
+#endif /* SYSLINUX_MOUNTINFO_H */
diff --git a/extlinux/ntfs.h b/extlinux/ntfs.h
new file mode 100644
index 00000000..d907d452
--- /dev/null
+++ b/extlinux/ntfs.h
@@ -0,0 +1,19 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2011 Paulo Alcantara <pcacjr@gmail.com>
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef _NTFS_H_
+#define _NTFS_H_
+
+#define NTFS_SB_MAGIC 0x5346544E
+#define FUSE_SUPER_MAGIC 0x65735546
+
+#endif /* _NTFS_H_ */
diff --git a/libinstaller/Makefile b/libinstaller/Makefile
index 2beb9315..e67a4686 100644
--- a/libinstaller/Makefile
+++ b/libinstaller/Makefile
@@ -26,3 +26,5 @@ clean: tidy
dist: tidy
spotless: clean
+
+strip:
diff --git a/libinstaller/ext2fs/ext2_fs.h b/libinstaller/ext2fs/ext2_fs.h
new file mode 100644
index 00000000..e52c9e1f
--- /dev/null
+++ b/libinstaller/ext2fs/ext2_fs.h
@@ -0,0 +1,856 @@
+/*
+ * linux/include/linux/ext2_fs.h
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * from
+ *
+ * linux/include/linux/minix_fs.h
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#ifndef _EXT2FS_EXT2_FS_H
+#define _EXT2FS_EXT2_FS_H
+
+#include <linux/types.h>
+
+/*
+ * The second extended filesystem constants/structures
+ */
+
+/*
+ * Define EXT2FS_DEBUG to produce debug messages
+ */
+#undef EXT2FS_DEBUG
+
+/*
+ * Define EXT2_PREALLOCATE to preallocate data blocks for expanding files
+ */
+#define EXT2_PREALLOCATE
+#define EXT2_DEFAULT_PREALLOC_BLOCKS 8
+
+/*
+ * The second extended file system version
+ */
+#define EXT2FS_DATE "95/08/09"
+#define EXT2FS_VERSION "0.5b"
+
+/*
+ * Special inode numbers
+ */
+#define EXT2_BAD_INO 1 /* Bad blocks inode */
+#define EXT2_ROOT_INO 2 /* Root inode */
+#define EXT4_USR_QUOTA_INO 3 /* User quota inode */
+#define EXT4_GRP_QUOTA_INO 4 /* Group quota inode */
+#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */
+#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */
+#define EXT2_RESIZE_INO 7 /* Reserved group descriptors inode */
+#define EXT2_JOURNAL_INO 8 /* Journal inode */
+#define EXT2_EXCLUDE_INO 9 /* The "exclude" inode, for snapshots */
+#define EXT4_REPLICA_INO 10 /* Used by non-upstream feature */
+
+/* First non-reserved inode for old ext2 filesystems */
+#define EXT2_GOOD_OLD_FIRST_INO 11
+
+/*
+ * The second extended file system magic number
+ */
+#define EXT2_SUPER_MAGIC 0xEF53
+
+#ifdef __KERNEL__
+#define EXT2_SB(sb) (&((sb)->u.ext2_sb))
+#else
+/* Assume that user mode programs are passing in an ext2fs superblock, not
+ * a kernel struct super_block. This will allow us to call the feature-test
+ * macros from user land. */
+#define EXT2_SB(sb) (sb)
+#endif
+
+/*
+ * Maximal count of links to a file
+ */
+#define EXT2_LINK_MAX 65000
+
+/*
+ * Macro-instructions used to manage several block sizes
+ */
+#define EXT2_MIN_BLOCK_LOG_SIZE 10 /* 1024 */
+#define EXT2_MAX_BLOCK_LOG_SIZE 16 /* 65536 */
+#define EXT2_MIN_BLOCK_SIZE (1 << EXT2_MIN_BLOCK_LOG_SIZE)
+#define EXT2_MAX_BLOCK_SIZE (1 << EXT2_MAX_BLOCK_LOG_SIZE)
+#ifdef __KERNEL__
+#define EXT2_BLOCK_SIZE(s) ((s)->s_blocksize)
+#define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits)
+#define EXT2_ADDR_PER_BLOCK_BITS(s) (EXT2_SB(s)->addr_per_block_bits)
+#define EXT2_INODE_SIZE(s) (EXT2_SB(s)->s_inode_size)
+#define EXT2_FIRST_INO(s) (EXT2_SB(s)->s_first_ino)
+#else
+#define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
+#define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
+#define EXT2_INODE_SIZE(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
+ EXT2_GOOD_OLD_INODE_SIZE : (s)->s_inode_size)
+#define EXT2_FIRST_INO(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
+ EXT2_GOOD_OLD_FIRST_INO : (s)->s_first_ino)
+#endif
+#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof(__u32))
+
+/*
+ * Macro-instructions used to manage allocation clusters
+ */
+#define EXT2_MIN_CLUSTER_LOG_SIZE EXT2_MIN_BLOCK_LOG_SIZE
+#define EXT2_MAX_CLUSTER_LOG_SIZE 29 /* 512MB */
+#define EXT2_MIN_CLUSTER_SIZE EXT2_MIN_BLOCK_SIZE
+#define EXT2_MAX_CLUSTER_SIZE (1 << EXT2_MAX_CLUSTER_LOG_SIZE)
+#define EXT2_CLUSTER_SIZE(s) (EXT2_MIN_BLOCK_SIZE << \
+ (s)->s_log_cluster_size)
+#define EXT2_CLUSTER_SIZE_BITS(s) ((s)->s_log_cluster_size + 10)
+
+/*
+ * Macro-instructions used to manage fragments
+ *
+ * Note: for backwards compatibility only, for the dump program.
+ * Ext2/3/4 will never support fragments....
+ */
+#define EXT2_MIN_FRAG_SIZE EXT2_MIN_BLOCK_SIZE
+#define EXT2_MAX_FRAG_SIZE EXT2_MAX_BLOCK_SIZE
+#define EXT2_MIN_FRAG_LOG_SIZE EXT2_MIN_BLOCK_LOG_SIZE
+#define EXT2_FRAG_SIZE(s) EXT2_BLOCK_SIZE(s)
+#define EXT2_FRAGS_PER_BLOCK(s) 1
+
+/*
+ * ACL structures
+ */
+struct ext2_acl_header /* Header of Access Control Lists */
+{
+ __u32 aclh_size;
+ __u32 aclh_file_count;
+ __u32 aclh_acle_count;
+ __u32 aclh_first_acle;
+};
+
+struct ext2_acl_entry /* Access Control List Entry */
+{
+ __u32 acle_size;
+ __u16 acle_perms; /* Access permissions */
+ __u16 acle_type; /* Type of entry */
+ __u16 acle_tag; /* User or group identity */
+ __u16 acle_pad1;
+ __u32 acle_next; /* Pointer on next entry for the */
+ /* same inode or on next free entry */
+};
+
+/*
+ * Structure of a blocks group descriptor
+ */
+struct ext2_group_desc
+{
+ __u32 bg_block_bitmap; /* Blocks bitmap block */
+ __u32 bg_inode_bitmap; /* Inodes bitmap block */
+ __u32 bg_inode_table; /* Inodes table block */
+ __u16 bg_free_blocks_count; /* Free blocks count */
+ __u16 bg_free_inodes_count; /* Free inodes count */
+ __u16 bg_used_dirs_count; /* Directories count */
+ __u16 bg_flags;
+ __u32 bg_exclude_bitmap_lo; /* Exclude bitmap for snapshots */
+ __u16 bg_block_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bitmap) LSB */
+ __u16 bg_inode_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bitmap) LSB */
+ __u16 bg_itable_unused; /* Unused inodes count */
+ __u16 bg_checksum; /* crc16(s_uuid+grouo_num+group_desc)*/
+};
+
+/*
+ * Structure of a blocks group descriptor
+ */
+struct ext4_group_desc
+{
+ __u32 bg_block_bitmap; /* Blocks bitmap block */
+ __u32 bg_inode_bitmap; /* Inodes bitmap block */
+ __u32 bg_inode_table; /* Inodes table block */
+ __u16 bg_free_blocks_count; /* Free blocks count */
+ __u16 bg_free_inodes_count; /* Free inodes count */
+ __u16 bg_used_dirs_count; /* Directories count */
+ __u16 bg_flags; /* EXT4_BG_flags (INODE_UNINIT, etc) */
+ __u32 bg_exclude_bitmap_lo; /* Exclude bitmap for snapshots */
+ __u16 bg_block_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bitmap) LSB */
+ __u16 bg_inode_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bitmap) LSB */
+ __u16 bg_itable_unused; /* Unused inodes count */
+ __u16 bg_checksum; /* crc16(sb_uuid+group+desc) */
+ __u32 bg_block_bitmap_hi; /* Blocks bitmap block MSB */
+ __u32 bg_inode_bitmap_hi; /* Inodes bitmap block MSB */
+ __u32 bg_inode_table_hi; /* Inodes table block MSB */
+ __u16 bg_free_blocks_count_hi;/* Free blocks count MSB */
+ __u16 bg_free_inodes_count_hi;/* Free inodes count MSB */
+ __u16 bg_used_dirs_count_hi; /* Directories count MSB */
+ __u16 bg_itable_unused_hi; /* Unused inodes count MSB */
+ __u32 bg_exclude_bitmap_hi; /* Exclude bitmap block MSB */
+ __u16 bg_block_bitmap_csum_hi;/* crc32c(s_uuid+grp_num+bitmap) MSB */
+ __u16 bg_inode_bitmap_csum_hi;/* crc32c(s_uuid+grp_num+bitmap) MSB */
+ __u32 bg_reserved;
+};
+
+#define EXT2_BG_INODE_UNINIT 0x0001 /* Inode table/bitmap not initialized */
+#define EXT2_BG_BLOCK_UNINIT 0x0002 /* Block bitmap not initialized */
+#define EXT2_BG_INODE_ZEROED 0x0004 /* On-disk itable initialized to zero */
+
+/*
+ * Data structures used by the directory indexing feature
+ *
+ * Note: all of the multibyte integer fields are little endian.
+ */
+
+/*
+ * Note: dx_root_info is laid out so that if it should somehow get
+ * overlaid by a dirent the two low bits of the hash version will be
+ * zero. Therefore, the hash version mod 4 should never be 0.
+ * Sincerely, the paranoia department.
+ */
+struct ext2_dx_root_info {
+ __u32 reserved_zero;
+ __u8 hash_version; /* 0 now, 1 at release */
+ __u8 info_length; /* 8 */
+ __u8 indirect_levels;
+ __u8 unused_flags;
+};
+
+#define EXT2_HASH_LEGACY 0
+#define EXT2_HASH_HALF_MD4 1
+#define EXT2_HASH_TEA 2
+#define EXT2_HASH_LEGACY_UNSIGNED 3 /* reserved for userspace lib */
+#define EXT2_HASH_HALF_MD4_UNSIGNED 4 /* reserved for userspace lib */
+#define EXT2_HASH_TEA_UNSIGNED 5 /* reserved for userspace lib */
+
+#define EXT2_HASH_FLAG_INCOMPAT 0x1
+
+struct ext2_dx_entry {
+ __u32 hash;
+ __u32 block;
+};
+
+struct ext2_dx_countlimit {
+ __u16 limit;
+ __u16 count;
+};
+
+
+/*
+ * Macro-instructions used to manage group descriptors
+ */
+#define EXT2_MIN_DESC_SIZE 32
+#define EXT2_MIN_DESC_SIZE_64BIT 64
+#define EXT2_MAX_DESC_SIZE EXT2_MIN_BLOCK_SIZE
+#define EXT2_DESC_SIZE(s) \
+ ((EXT2_SB(s)->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT) ? \
+ (s)->s_desc_size : EXT2_MIN_DESC_SIZE)
+
+#define EXT2_BLOCKS_PER_GROUP(s) (EXT2_SB(s)->s_blocks_per_group)
+#define EXT2_INODES_PER_GROUP(s) (EXT2_SB(s)->s_inodes_per_group)
+#define EXT2_CLUSTERS_PER_GROUP(s) (EXT2_SB(s)->s_clusters_per_group)
+#define EXT2_INODES_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s)/EXT2_INODE_SIZE(s))
+/* limits imposed by 16-bit value gd_free_{blocks,inode}_count */
+#define EXT2_MAX_BLOCKS_PER_GROUP(s) ((((unsigned) 1 << 16) - 8) * \
+ (EXT2_CLUSTER_SIZE(s) / \
+ EXT2_BLOCK_SIZE(s)))
+#define EXT2_MAX_CLUSTERS_PER_GROUP(s) (((unsigned) 1 << 16) - 8)
+#define EXT2_MAX_INODES_PER_GROUP(s) (((unsigned) 1 << 16) - \
+ EXT2_INODES_PER_BLOCK(s))
+#ifdef __KERNEL__
+#define EXT2_DESC_PER_BLOCK(s) (EXT2_SB(s)->s_desc_per_block)
+#define EXT2_DESC_PER_BLOCK_BITS(s) (EXT2_SB(s)->s_desc_per_block_bits)
+#else
+#define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_DESC_SIZE(s))
+#endif
+
+/*
+ * Constants relative to the data blocks
+ */
+#define EXT2_NDIR_BLOCKS 12
+#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
+#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
+#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
+#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
+
+/*
+ * Inode flags
+ */
+#define EXT2_SECRM_FL 0x00000001 /* Secure deletion */
+#define EXT2_UNRM_FL 0x00000002 /* Undelete */
+#define EXT2_COMPR_FL 0x00000004 /* Compress file */
+#define EXT2_SYNC_FL 0x00000008 /* Synchronous updates */
+#define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */
+#define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */
+#define EXT2_NODUMP_FL 0x00000040 /* do not dump file */
+#define EXT2_NOATIME_FL 0x00000080 /* do not update atime */
+/* Reserved for compression usage... */
+#define EXT2_DIRTY_FL 0x00000100
+#define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */
+#define EXT2_NOCOMPR_FL 0x00000400 /* Access raw compressed data */
+#define EXT2_ECOMPR_FL 0x00000800 /* Compression error */
+/* End compression flags --- maybe not all used */
+#define EXT2_BTREE_FL 0x00001000 /* btree format dir */
+#define EXT2_INDEX_FL 0x00001000 /* hash-indexed directory */
+#define EXT2_IMAGIC_FL 0x00002000
+#define EXT3_JOURNAL_DATA_FL 0x00004000 /* file data should be journaled */
+#define EXT2_NOTAIL_FL 0x00008000 /* file tail should not be merged */
+#define EXT2_DIRSYNC_FL 0x00010000 /* Synchronous directory modifications */
+#define EXT2_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/
+#define EXT4_HUGE_FILE_FL 0x00040000 /* Set to each huge file */
+#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */
+#define EXT4_EA_INODE_FL 0x00200000 /* Inode used for large EA */
+/* EXT4_EOFBLOCKS_FL 0x00400000 was here */
+#define EXT4_SNAPFILE_FL 0x01000000 /* Inode is a snapshot */
+#define EXT4_SNAPFILE_DELETED_FL 0x04000000 /* Snapshot is being deleted */
+#define EXT4_SNAPFILE_SHRUNK_FL 0x08000000 /* Snapshot shrink has completed */
+#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */
+
+#define EXT2_FL_USER_VISIBLE 0x004BDFFF /* User visible flags */
+#define EXT2_FL_USER_MODIFIABLE 0x004B80FF /* User modifiable flags */
+
+/*
+ * ioctl commands
+ */
+
+/* Used for online resize */
+struct ext2_new_group_input {
+ __u32 group; /* Group number for this data */
+ __u32 block_bitmap; /* Absolute block number of block bitmap */
+ __u32 inode_bitmap; /* Absolute block number of inode bitmap */
+ __u32 inode_table; /* Absolute block number of inode table start */
+ __u32 blocks_count; /* Total number of blocks in this group */
+ __u16 reserved_blocks; /* Number of reserved blocks in this group */
+ __u16 unused; /* Number of reserved GDT blocks in group */
+};
+
+struct ext4_new_group_input {
+ __u32 group; /* Group number for this data */
+ __u64 block_bitmap; /* Absolute block number of block bitmap */
+ __u64 inode_bitmap; /* Absolute block number of inode bitmap */
+ __u64 inode_table; /* Absolute block number of inode table start */
+ __u32 blocks_count; /* Total number of blocks in this group */
+ __u16 reserved_blocks; /* Number of reserved blocks in this group */
+ __u16 unused;
+};
+
+#ifdef __GNU__ /* Needed for the Hurd */
+#define _IOT_ext2_new_group_input _IOT (_IOTS(__u32), 5, _IOTS(__u16), 2, 0, 0)
+#endif
+
+#define EXT2_IOC_GETFLAGS _IOR('f', 1, long)
+#define EXT2_IOC_SETFLAGS _IOW('f', 2, long)
+#define EXT2_IOC_GETVERSION _IOR('v', 1, long)
+#define EXT2_IOC_SETVERSION _IOW('v', 2, long)
+#define EXT2_IOC_GETVERSION_NEW _IOR('f', 3, long)
+#define EXT2_IOC_SETVERSION_NEW _IOW('f', 4, long)
+#define EXT2_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long)
+#define EXT2_IOC_GROUP_ADD _IOW('f', 8,struct ext2_new_group_input)
+#define EXT4_IOC_GROUP_ADD _IOW('f', 8,struct ext4_new_group_input)
+#define EXT4_IOC_RESIZE_FS _IOW('f', 16, __u64)
+
+/*
+ * Structure of an inode on the disk
+ */
+struct ext2_inode {
+ __u16 i_mode; /* File mode */
+ __u16 i_uid; /* Low 16 bits of Owner Uid */
+ __u32 i_size; /* Size in bytes */
+ __u32 i_atime; /* Access time */
+ __u32 i_ctime; /* Inode change time */
+ __u32 i_mtime; /* Modification time */
+ __u32 i_dtime; /* Deletion Time */
+ __u16 i_gid; /* Low 16 bits of Group Id */
+ __u16 i_links_count; /* Links count */
+ __u32 i_blocks; /* Blocks count */
+ __u32 i_flags; /* File flags */
+ union {
+ struct {
+ __u32 l_i_version; /* was l_i_reserved1 */
+ } linux1;
+ struct {
+ __u32 h_i_translator;
+ } hurd1;
+ } osd1; /* OS dependent 1 */
+ __u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
+ __u32 i_generation; /* File version (for NFS) */
+ __u32 i_file_acl; /* File ACL */
+ __u32 i_size_high; /* Formerly i_dir_acl, directory ACL */
+ __u32 i_faddr; /* Fragment address */
+ union {
+ struct {
+ __u16 l_i_blocks_hi;
+ __u16 l_i_file_acl_high;
+ __u16 l_i_uid_high; /* these 2 fields */
+ __u16 l_i_gid_high; /* were reserved2[0] */
+ __u16 l_i_checksum_lo; /* crc32c(uuid+inum+inode) */
+ __u16 l_i_reserved;
+ } linux2;
+ struct {
+ __u8 h_i_frag; /* Fragment number */
+ __u8 h_i_fsize; /* Fragment size */
+ __u16 h_i_mode_high;
+ __u16 h_i_uid_high;
+ __u16 h_i_gid_high;
+ __u32 h_i_author;
+ } hurd2;
+ } osd2; /* OS dependent 2 */
+};
+
+/*
+ * Permanent part of an large inode on the disk
+ */
+struct ext2_inode_large {
+ __u16 i_mode; /* File mode */
+ __u16 i_uid; /* Low 16 bits of Owner Uid */
+ __u32 i_size; /* Size in bytes */
+ __u32 i_atime; /* Access time */
+ __u32 i_ctime; /* Inode Change time */
+ __u32 i_mtime; /* Modification time */
+ __u32 i_dtime; /* Deletion Time */
+ __u16 i_gid; /* Low 16 bits of Group Id */
+ __u16 i_links_count; /* Links count */
+ __u32 i_blocks; /* Blocks count */
+ __u32 i_flags; /* File flags */
+ union {
+ struct {
+ __u32 l_i_version; /* was l_i_reserved1 */
+ } linux1;
+ struct {
+ __u32 h_i_translator;
+ } hurd1;
+ } osd1; /* OS dependent 1 */
+ __u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
+ __u32 i_generation; /* File version (for NFS) */
+ __u32 i_file_acl; /* File ACL */
+ __u32 i_size_high; /* Formerly i_dir_acl, directory ACL */
+ __u32 i_faddr; /* Fragment address */
+ union {
+ struct {
+ __u16 l_i_blocks_hi;
+ __u16 l_i_file_acl_high;
+ __u16 l_i_uid_high; /* these 2 fields */
+ __u16 l_i_gid_high; /* were reserved2[0] */
+ __u16 l_i_checksum_lo; /* crc32c(uuid+inum+inode) */
+ __u16 l_i_reserved;
+ } linux2;
+ struct {
+ __u8 h_i_frag; /* Fragment number */
+ __u8 h_i_fsize; /* Fragment size */
+ __u16 h_i_mode_high;
+ __u16 h_i_uid_high;
+ __u16 h_i_gid_high;
+ __u32 h_i_author;
+ } hurd2;
+ } osd2; /* OS dependent 2 */
+ __u16 i_extra_isize;
+ __u16 i_checksum_hi; /* crc32c(uuid+inum+inode) */
+ __u32 i_ctime_extra; /* extra Change time (nsec << 2 | epoch) */
+ __u32 i_mtime_extra; /* extra Modification time (nsec << 2 | epoch) */
+ __u32 i_atime_extra; /* extra Access time (nsec << 2 | epoch) */
+ __u32 i_crtime; /* File creation time */
+ __u32 i_crtime_extra; /* extra File creation time (nsec << 2 | epoch)*/
+ __u32 i_version_hi; /* high 32 bits for 64-bit version */
+};
+
+#define i_dir_acl i_size_high
+
+#if defined(__KERNEL__) || defined(__linux__)
+#define i_reserved1 osd1.linux1.l_i_reserved1
+#define i_frag osd2.linux2.l_i_frag
+#define i_fsize osd2.linux2.l_i_fsize
+#define i_uid_low i_uid
+#define i_gid_low i_gid
+#define i_uid_high osd2.linux2.l_i_uid_high
+#define i_gid_high osd2.linux2.l_i_gid_high
+#else
+#if defined(__GNU__)
+
+#define i_translator osd1.hurd1.h_i_translator
+#define i_frag osd2.hurd2.h_i_frag;
+#define i_fsize osd2.hurd2.h_i_fsize;
+#define i_uid_high osd2.hurd2.h_i_uid_high
+#define i_gid_high osd2.hurd2.h_i_gid_high
+#define i_author osd2.hurd2.h_i_author
+
+#endif /* __GNU__ */
+#endif /* defined(__KERNEL__) || defined(__linux__) */
+
+#define inode_uid(inode) ((inode).i_uid | (inode).osd2.linux2.l_i_uid_high << 16)
+#define inode_gid(inode) ((inode).i_gid | (inode).osd2.linux2.l_i_gid_high << 16)
+#define ext2fs_set_i_uid_high(inode,x) ((inode).osd2.linux2.l_i_uid_high = (x))
+#define ext2fs_set_i_gid_high(inode,x) ((inode).osd2.linux2.l_i_gid_high = (x))
+
+/*
+ * File system states
+ */
+#define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */
+#define EXT2_ERROR_FS 0x0002 /* Errors detected */
+#define EXT3_ORPHAN_FS 0x0004 /* Orphans being recovered */
+
+/*
+ * Misc. filesystem flags
+ */
+#define EXT2_FLAGS_SIGNED_HASH 0x0001 /* Signed dirhash in use */
+#define EXT2_FLAGS_UNSIGNED_HASH 0x0002 /* Unsigned dirhash in use */
+#define EXT2_FLAGS_TEST_FILESYS 0x0004 /* OK for use on development code */
+#define EXT2_FLAGS_IS_SNAPSHOT 0x0010 /* This is a snapshot image */
+#define EXT2_FLAGS_FIX_SNAPSHOT 0x0020 /* Snapshot inodes corrupted */
+#define EXT2_FLAGS_FIX_EXCLUDE 0x0040 /* Exclude bitmaps corrupted */
+
+/*
+ * Mount flags
+ */
+#define EXT2_MOUNT_CHECK 0x0001 /* Do mount-time checks */
+#define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */
+#define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */
+#define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */
+#define EXT2_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */
+#define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */
+#define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */
+#define EXT2_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */
+
+#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt
+#define set_opt(o, opt) o |= EXT2_MOUNT_##opt
+#define test_opt(sb, opt) (EXT2_SB(sb)->s_mount_opt & \
+ EXT2_MOUNT_##opt)
+/*
+ * Maximal mount counts between two filesystem checks
+ */
+#define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */
+#define EXT2_DFL_CHECKINTERVAL 0 /* Don't use interval check */
+
+/*
+ * Behaviour when detecting errors
+ */
+#define EXT2_ERRORS_CONTINUE 1 /* Continue execution */
+#define EXT2_ERRORS_RO 2 /* Remount fs read-only */
+#define EXT2_ERRORS_PANIC 3 /* Panic */
+#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE
+
+#if (__GNUC__ >= 4)
+#define ext4_offsetof(TYPE,MEMBER) __builtin_offsetof(TYPE,MEMBER)
+#else
+#define ext4_offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+/*
+ * Structure of the super block
+ */
+struct ext2_super_block {
+ __u32 s_inodes_count; /* Inodes count */
+ __u32 s_blocks_count; /* Blocks count */
+ __u32 s_r_blocks_count; /* Reserved blocks count */
+ __u32 s_free_blocks_count; /* Free blocks count */
+ __u32 s_free_inodes_count; /* Free inodes count */
+ __u32 s_first_data_block; /* First Data Block */
+ __u32 s_log_block_size; /* Block size */
+ __u32 s_log_cluster_size; /* Allocation cluster size */
+ __u32 s_blocks_per_group; /* # Blocks per group */
+ __u32 s_clusters_per_group; /* # Fragments per group */
+ __u32 s_inodes_per_group; /* # Inodes per group */
+ __u32 s_mtime; /* Mount time */
+ __u32 s_wtime; /* Write time */
+ __u16 s_mnt_count; /* Mount count */
+ __s16 s_max_mnt_count; /* Maximal mount count */
+ __u16 s_magic; /* Magic signature */
+ __u16 s_state; /* File system state */
+ __u16 s_errors; /* Behaviour when detecting errors */
+ __u16 s_minor_rev_level; /* minor revision level */
+ __u32 s_lastcheck; /* time of last check */
+ __u32 s_checkinterval; /* max. time between checks */
+ __u32 s_creator_os; /* OS */
+ __u32 s_rev_level; /* Revision level */
+ __u16 s_def_resuid; /* Default uid for reserved blocks */
+ __u16 s_def_resgid; /* Default gid for reserved blocks */
+ /*
+ * These fields are for EXT2_DYNAMIC_REV superblocks only.
+ *
+ * Note: the difference between the compatible feature set and
+ * the incompatible feature set is that if there is a bit set
+ * in the incompatible feature set that the kernel doesn't
+ * know about, it should refuse to mount the filesystem.
+ *
+ * e2fsck's requirements are more strict; if it doesn't know
+ * about a feature in either the compatible or incompatible
+ * feature set, it must abort and not try to meddle with
+ * things it doesn't understand...
+ */
+ __u32 s_first_ino; /* First non-reserved inode */
+ __u16 s_inode_size; /* size of inode structure */
+ __u16 s_block_group_nr; /* block group # of this superblock */
+ __u32 s_feature_compat; /* compatible feature set */
+ __u32 s_feature_incompat; /* incompatible feature set */
+ __u32 s_feature_ro_compat; /* readonly-compatible feature set */
+ __u8 s_uuid[16]; /* 128-bit uuid for volume */
+ char s_volume_name[16]; /* volume name */
+ char s_last_mounted[64]; /* directory where last mounted */
+ __u32 s_algorithm_usage_bitmap; /* For compression */
+ /*
+ * Performance hints. Directory preallocation should only
+ * happen if the EXT2_FEATURE_COMPAT_DIR_PREALLOC flag is on.
+ */
+ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
+ __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
+ __u16 s_reserved_gdt_blocks; /* Per group table for online growth */
+ /*
+ * Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set.
+ */
+ __u8 s_journal_uuid[16]; /* uuid of journal superblock */
+ __u32 s_journal_inum; /* inode number of journal file */
+ __u32 s_journal_dev; /* device number of journal file */
+ __u32 s_last_orphan; /* start of list of inodes to delete */
+ __u32 s_hash_seed[4]; /* HTREE hash seed */
+ __u8 s_def_hash_version; /* Default hash version to use */
+ __u8 s_jnl_backup_type; /* Default type of journal backup */
+ __u16 s_desc_size; /* Group desc. size: INCOMPAT_64BIT */
+ __u32 s_default_mount_opts;
+ __u32 s_first_meta_bg; /* First metablock group */
+ __u32 s_mkfs_time; /* When the filesystem was created */
+ __u32 s_jnl_blocks[17]; /* Backup of the journal inode */
+ __u32 s_blocks_count_hi; /* Blocks count high 32bits */
+ __u32 s_r_blocks_count_hi; /* Reserved blocks count high 32 bits*/
+ __u32 s_free_blocks_hi; /* Free blocks count */
+ __u16 s_min_extra_isize; /* All inodes have at least # bytes */
+ __u16 s_want_extra_isize; /* New inodes should reserve # bytes */
+ __u32 s_flags; /* Miscellaneous flags */
+ __u16 s_raid_stride; /* RAID stride */
+ __u16 s_mmp_update_interval; /* # seconds to wait in MMP checking */
+ __u64 s_mmp_block; /* Block for multi-mount protection */
+ __u32 s_raid_stripe_width; /* blocks on all data disks (N*stride)*/
+ __u8 s_log_groups_per_flex; /* FLEX_BG group size */
+ __u8 s_reserved_char_pad;
+ __u16 s_reserved_pad; /* Padding to next 32bits */
+ __u64 s_kbytes_written; /* nr of lifetime kilobytes written */
+ __u32 s_snapshot_inum; /* Inode number of active snapshot */
+ __u32 s_snapshot_id; /* sequential ID of active snapshot */
+ __u64 s_snapshot_r_blocks_count; /* reserved blocks for active
+ snapshot's future use */
+ __u32 s_snapshot_list; /* inode number of the head of the on-disk snapshot list */
+#define EXT4_S_ERR_START ext4_offsetof(struct ext2_super_block, s_error_count)
+ __u32 s_error_count; /* number of fs errors */
+ __u32 s_first_error_time; /* first time an error happened */
+ __u32 s_first_error_ino; /* inode involved in first error */
+ __u64 s_first_error_block; /* block involved of first error */
+ __u8 s_first_error_func[32]; /* function where the error happened */
+ __u32 s_first_error_line; /* line number where error happened */
+ __u32 s_last_error_time; /* most recent time of an error */
+ __u32 s_last_error_ino; /* inode involved in last error */
+ __u32 s_last_error_line; /* line number where error happened */
+ __u64 s_last_error_block; /* block involved of last error */
+ __u8 s_last_error_func[32]; /* function where the error happened */
+#define EXT4_S_ERR_END ext4_offsetof(struct ext2_super_block, s_mount_opts)
+ __u8 s_mount_opts[64];
+ __u32 s_usr_quota_inum; /* inode number of user quota file */
+ __u32 s_grp_quota_inum; /* inode number of group quota file */
+ __u32 s_overhead_blocks; /* overhead blocks/clusters in fs */
+ __u32 s_reserved[108]; /* Padding to the end of the block */
+ __u32 s_checksum; /* crc32c(superblock) */
+};
+
+#define EXT4_S_ERR_LEN (EXT4_S_ERR_END - EXT4_S_ERR_START)
+
+/*
+ * Codes for operating systems
+ */
+#define EXT2_OS_LINUX 0
+#define EXT2_OS_HURD 1
+#define EXT2_OBSO_OS_MASIX 2
+#define EXT2_OS_FREEBSD 3
+#define EXT2_OS_LITES 4
+
+/*
+ * Revision levels
+ */
+#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */
+#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */
+
+#define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV
+#define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV
+
+#define EXT2_GOOD_OLD_INODE_SIZE 128
+
+/*
+ * Journal inode backup types
+ */
+#define EXT3_JNL_BACKUP_BLOCKS 1
+
+/*
+ * Feature set definitions
+ */
+
+#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_feature_compat & (mask) )
+#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_feature_ro_compat & (mask) )
+#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \
+ ( EXT2_SB(sb)->s_feature_incompat & (mask) )
+
+#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001
+#define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002
+#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
+#define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008
+#define EXT2_FEATURE_COMPAT_RESIZE_INODE 0x0010
+#define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020
+#define EXT2_FEATURE_COMPAT_LAZY_BG 0x0040
+/* #define EXT2_FEATURE_COMPAT_EXCLUDE_INODE 0x0080 not used, legacy */
+#define EXT2_FEATURE_COMPAT_EXCLUDE_BITMAP 0x0100
+
+
+#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
+#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
+/* #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 not used */
+#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008
+#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010
+#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
+#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040
+#define EXT4_FEATURE_RO_COMPAT_HAS_SNAPSHOT 0x0080
+#define EXT4_FEATURE_RO_COMPAT_QUOTA 0x0100
+#define EXT4_FEATURE_RO_COMPAT_BIGALLOC 0x0200
+#define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM 0x0400
+#define EXT4_FEATURE_RO_COMPAT_REPLICA 0x0800
+
+#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
+#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
+#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */
+#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */
+#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
+#define EXT3_FEATURE_INCOMPAT_EXTENTS 0x0040
+#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
+#define EXT4_FEATURE_INCOMPAT_MMP 0x0100
+#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200
+#define EXT4_FEATURE_INCOMPAT_EA_INODE 0x0400
+#define EXT4_FEATURE_INCOMPAT_DIRDATA 0x1000
+
+#define EXT2_FEATURE_COMPAT_SUPP 0
+#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \
+ EXT4_FEATURE_INCOMPAT_MMP)
+#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+ EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
+ EXT4_FEATURE_RO_COMPAT_DIR_NLINK| \
+ EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
+
+/*
+ * Default values for user and/or group using reserved blocks
+ */
+#define EXT2_DEF_RESUID 0
+#define EXT2_DEF_RESGID 0
+
+/*
+ * Default mount options
+ */
+#define EXT2_DEFM_DEBUG 0x0001
+#define EXT2_DEFM_BSDGROUPS 0x0002
+#define EXT2_DEFM_XATTR_USER 0x0004
+#define EXT2_DEFM_ACL 0x0008
+#define EXT2_DEFM_UID16 0x0010
+#define EXT3_DEFM_JMODE 0x0060
+#define EXT3_DEFM_JMODE_DATA 0x0020
+#define EXT3_DEFM_JMODE_ORDERED 0x0040
+#define EXT3_DEFM_JMODE_WBACK 0x0060
+#define EXT4_DEFM_NOBARRIER 0x0100
+#define EXT4_DEFM_BLOCK_VALIDITY 0x0200
+#define EXT4_DEFM_DISCARD 0x0400
+#define EXT4_DEFM_NODELALLOC 0x0800
+
+/*
+ * Structure of a directory entry
+ */
+#define EXT2_NAME_LEN 255
+
+struct ext2_dir_entry {
+ __u32 inode; /* Inode number */
+ __u16 rec_len; /* Directory entry length */
+ __u16 name_len; /* Name length */
+ char name[EXT2_NAME_LEN]; /* File name */
+};
+
+/*
+ * The new version of the directory entry. Since EXT2 structures are
+ * stored in intel byte order, and the name_len field could never be
+ * bigger than 255 chars, it's safe to reclaim the extra byte for the
+ * file_type field.
+ */
+struct ext2_dir_entry_2 {
+ __u32 inode; /* Inode number */
+ __u16 rec_len; /* Directory entry length */
+ __u8 name_len; /* Name length */
+ __u8 file_type;
+ char name[EXT2_NAME_LEN]; /* File name */
+};
+
+/*
+ * Ext2 directory file types. Only the low 3 bits are used. The
+ * other bits are reserved for now.
+ */
+#define EXT2_FT_UNKNOWN 0
+#define EXT2_FT_REG_FILE 1
+#define EXT2_FT_DIR 2
+#define EXT2_FT_CHRDEV 3
+#define EXT2_FT_BLKDEV 4
+#define EXT2_FT_FIFO 5
+#define EXT2_FT_SOCK 6
+#define EXT2_FT_SYMLINK 7
+
+#define EXT2_FT_MAX 8
+
+/*
+ * EXT2_DIR_PAD defines the directory entries boundaries
+ *
+ * NOTE: It must be a multiple of 4
+ */
+#define EXT2_DIR_PAD 4
+#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
+#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
+ ~EXT2_DIR_ROUND)
+
+/*
+ * This structure is used for multiple mount protection. It is written
+ * into the block number saved in the s_mmp_block field in the superblock.
+ * Programs that check MMP should assume that if SEQ_FSCK (or any unknown
+ * code above SEQ_MAX) is present then it is NOT safe to use the filesystem,
+ * regardless of how old the timestamp is.
+ *
+ * The timestamp in the MMP structure will be updated by e2fsck at some
+ * arbitary intervals (start of passes, after every few groups of inodes
+ * in pass1 and pass1b). There is no guarantee that e2fsck is updating
+ * the MMP block in a timely manner, and the updates it does are purely
+ * for the convenience of the sysadmin and not for automatic validation.
+ *
+ * Note: Only the mmp_seq value is used to determine whether the MMP block
+ * is being updated. The mmp_time, mmp_nodename, and mmp_bdevname
+ * fields are only for informational purposes for the administrator,
+ * due to clock skew between nodes and hostname HA service takeover.
+ */
+#define EXT4_MMP_MAGIC 0x004D4D50U /* ASCII for MMP */
+#define EXT4_MMP_SEQ_CLEAN 0xFF4D4D50U /* mmp_seq value for clean unmount */
+#define EXT4_MMP_SEQ_FSCK 0xE24D4D50U /* mmp_seq value when being fscked */
+#define EXT4_MMP_SEQ_MAX 0xE24D4D4FU /* maximum valid mmp_seq value */
+
+struct mmp_struct {
+ __u32 mmp_magic; /* Magic number for MMP */
+ __u32 mmp_seq; /* Sequence no. updated periodically */
+ __u64 mmp_time; /* Time last updated */
+ char mmp_nodename[64]; /* Node which last updated MMP block */
+ char mmp_bdevname[32]; /* Bdev which last updated MMP block */
+ __u16 mmp_check_interval; /* Changed mmp_check_interval */
+ __u16 mmp_pad1;
+ __u32 mmp_pad2[227];
+};
+
+/*
+ * Default interval for MMP update in seconds.
+ */
+#define EXT4_MMP_UPDATE_INTERVAL 5
+
+/*
+ * Maximum interval for MMP update in seconds.
+ */
+#define EXT4_MMP_MAX_UPDATE_INTERVAL 300
+
+/*
+ * Minimum interval for MMP checking in seconds.
+ */
+#define EXT4_MMP_MIN_CHECK_INTERVAL 5
+
+#endif /* _EXT2FS_EXT2_FS_H */
diff --git a/libinstaller/fat.c b/libinstaller/fs.c
index 9cde00c2..179629e9 100644
--- a/libinstaller/fat.c
+++ b/libinstaller/fs.c
@@ -1,7 +1,8 @@
/* ----------------------------------------------------------------------- *
*
- * Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
- * Copyright 2009-2010 Intel Corporation; author H. Peter Anvin
+ * Copyright 1998-2011 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2011 Intel Corporation; author H. Peter Anvin
+ * Copyright 2011 Paulo Alcantara <pcacjr@gmail.com>
*
* 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
@@ -12,7 +13,7 @@
* ----------------------------------------------------------------------- */
/*
- * fat.c - Initial sanity check for FAT-based installers
+ * fs.c - Generic sanity check for FAT/NTFS-based installers
*/
#define _XOPEN_SOURCE 500 /* Required on glibc 2.x */
@@ -25,45 +26,41 @@
#include "syslinux.h"
#include "syslxint.h"
+#include "syslxcom.h"
+#include "syslxfs.h"
-void syslinux_make_bootsect(void *bs)
+void syslinux_make_bootsect(void *bs, int fs_type)
{
- struct boot_sector *bootsect = bs;
- const struct boot_sector *sbs =
- (const struct boot_sector *)boot_sector;
-
- memcpy(&bootsect->bsHead, &sbs->bsHead, bsHeadLen);
- memcpy(&bootsect->bsCode, &sbs->bsCode, bsCodeLen);
+ if (fs_type == VFAT) {
+ struct fat_boot_sector *bootsect = bs;
+ const struct fat_boot_sector *sbs =
+ (const struct fat_boot_sector *)boot_sector;
+
+ memcpy(&bootsect->FAT_bsHead, &sbs->FAT_bsHead, FAT_bsHeadLen);
+ memcpy(&bootsect->FAT_bsCode, &sbs->FAT_bsCode, FAT_bsCodeLen);
+ } else if (fs_type == NTFS) {
+ struct ntfs_boot_sector *bootsect = bs;
+ const struct ntfs_boot_sector *sbs =
+ (const struct ntfs_boot_sector *)boot_sector;
+
+ memcpy(&bootsect->NTFS_bsHead, &sbs->NTFS_bsHead, NTFS_bsHeadLen);
+ memcpy(&bootsect->NTFS_bsCode, &sbs->NTFS_bsCode, NTFS_bsCodeLen);
+ }
}
-/*
- * Check to see that what we got was indeed an MS-DOS boot sector/superblock;
- * Return NULL if OK and otherwise an error message;
- */
-const char *syslinux_check_bootsect(const void *bs)
+static const char *check_fat_bootsect(const void *bs, int *fs_type)
{
int sectorsize;
+ const struct fat_boot_sector *sectbuf = bs;
long long sectors, fatsectors, dsectors;
long long clusters;
int rootdirents, clustersize;
- const struct boot_sector *sectbuf = bs;
-
- /* Must be 0xF0 or 0xF8..0xFF */
- if (get_8(&sectbuf->bsMedia) != 0xF0 && get_8(&sectbuf->bsMedia) < 0xF8)
- return "invalid media signature (not a FAT filesystem?)";
sectorsize = get_16(&sectbuf->bsBytesPerSec);
- if (sectorsize == SECTOR_SIZE)
- ; /* ok */
- else if (sectorsize >= 512 && sectorsize <= 4096 &&
- (sectorsize & (sectorsize - 1)) == 0)
- return "unsupported sectors size";
- else
- return "impossible sector size";
clustersize = get_8(&sectbuf->bsSecPerClust);
if (clustersize == 0 || (clustersize & (clustersize - 1)))
- return "impossible cluster size";
+ return "impossible cluster size on an FAT volume";
sectors = get_16(&sectbuf->bsSectors);
sectors = sectors ? sectors : get_32(&sectbuf->bsHugeSectors);
@@ -79,16 +76,19 @@ const char *syslinux_check_bootsect(const void *bs)
dsectors -= (rootdirents + sectorsize / 32 - 1) / sectorsize;
if (dsectors < 0)
- return "negative number of data sectors";
-
- if (fatsectors == 0)
- return "zero FAT sectors";
+ return "negative number of data sectors on an FAT volume";
clusters = dsectors / clustersize;
+ fatsectors = get_16(&sectbuf->bsFATsecs);
+ fatsectors = fatsectors ? fatsectors : get_32(&sectbuf->bs32.FATSz32);
+ fatsectors *= get_8(&sectbuf->bsFATs);
+
+ if (!fatsectors)
+ return "zero FAT sectors";
+
if (clusters < 0xFFF5) {
/* FAT12 or FAT16 */
-
if (!get_16(&sectbuf->bsFATsecs))
return "zero FAT sectors (FAT12/16)";
@@ -100,10 +100,10 @@ const char *syslinux_check_bootsect(const void *bs)
if (clusters < 0xFF5)
return "less than 4084 clusters but claims FAT16";
} else if (!memcmp(&sectbuf->bs16.FileSysType, "FAT32 ", 8)) {
- return "less than 65525 clusters but claims FAT32";
+ return "less than 65525 clusters but claims FAT32";
} else if (memcmp(&sectbuf->bs16.FileSysType, "FAT ", 8)) {
- static char fserr[] =
- "filesystem type \"????????\" not supported";
+ static char fserr[] = "filesystem type \"????????\" not "
+ "supported";
memcpy(fserr + 17, &sectbuf->bs16.FileSysType, 8);
return fserr;
}
@@ -119,8 +119,54 @@ const char *syslinux_check_bootsect(const void *bs)
memcmp(&sectbuf->bs32.FileSysType, "FAT32 ", 8))
return "missing FAT32 signature";
} else {
- return "impossibly large number of clusters";
+ return "impossibly large number of clusters on an FAT volume";
}
+ if (fs_type)
+ *fs_type = VFAT;
+
+ return NULL;
+}
+
+static const char *check_ntfs_bootsect(const void *bs, int *fs_type)
+{
+ const struct ntfs_boot_sector *sectbuf = bs;
+
+ if (memcmp(&sectbuf->bsOemName, "NTFS ", 8) &&
+ memcmp(&sectbuf->bsOemName, "MSWIN4.0", 8) &&
+ memcmp(&sectbuf->bsOemName, "MSWIN4.1", 8))
+ return "unknown OEM name but claims NTFS";
+
+ if (fs_type)
+ *fs_type = NTFS;
+
return NULL;
}
+
+const char *syslinux_check_bootsect(const void *bs, int *fs_type)
+{
+ uint8_t media_sig;
+ int sectorsize;
+ const struct fat_boot_sector *sectbuf = bs;
+ const char *retval;
+
+ media_sig = get_8(&sectbuf->bsMedia);
+ /* Must be 0xF0 or 0xF8-0xFF for FAT/NTFS volumes */
+ if (media_sig != 0xF0 && media_sig < 0xF8)
+ return "invalid media signature (not an FAT/NTFS volume?)";
+
+ sectorsize = get_16(&sectbuf->bsBytesPerSec);
+ if (sectorsize == SECTOR_SIZE) ; /* ok */
+ else if (sectorsize >= 512 && sectorsize <= 4096 &&
+ (sectorsize & (sectorsize - 1)) == 0)
+ return "unsupported sectors size";
+ else
+ return "impossible sector size";
+
+ if (ntfs_check_zero_fields((struct ntfs_boot_sector *)bs))
+ retval = check_ntfs_bootsect(bs, fs_type);
+ else
+ retval = check_fat_bootsect(bs, fs_type);
+
+ return retval;
+}
diff --git a/libinstaller/linuxioctl.h b/libinstaller/linuxioctl.h
index 7ef919a3..e2731c7c 100644
--- a/libinstaller/linuxioctl.h
+++ b/libinstaller/linuxioctl.h
@@ -9,22 +9,36 @@
#include <sys/ioctl.h>
+#ifdef __linux__
+
#define statfs _kernel_statfs /* HACK to deal with broken 2.4 distros */
#include <linux/fd.h> /* Floppy geometry */
#include <linux/hdreg.h> /* Hard disk geometry */
-#include <linux/fs.h> /* FIGETBSZ, FIBMAP, FS_IOC_FIEMAP */
-#include <linux/msdos_fs.h> /* FAT_IOCTL_SET_ATTRIBUTES */
+#include <linux/fs.h> /* FIGETBSZ, FIBMAP, FS_IOC_* */
#undef SECTOR_SIZE /* Defined in msdos_fs.h for no good reason */
#undef SECTOR_BITS
-#include <linux/ext2_fs.h> /* EXT2_IOC_* */
+
+#ifndef FS_IOC_GETFLAGS
+/* Old kernel headers, these were once ext2-specific... */
+# include <linux/ext2_fs.h> /* EXT2_IOC_* */
+
+# define FS_IOC_GETFLAGS EXT2_IOC_GETFLAGS
+# define FS_IOC_SETFLAGS EXT2_IOC_SETFLAGS
+
+# define FS_IMMUTABLE_FL EXT2_IMMUTABLE_FL
+
+#else
+
+# include <ext2fs/ext2_fs.h>
+
+#endif
#ifndef FAT_IOCTL_GET_ATTRIBUTES
# define FAT_IOCTL_GET_ATTRIBUTES _IOR('r', 0x10, __u32)
#endif
-
#ifndef FAT_IOCTL_SET_ATTRIBUTES
# define FAT_IOCTL_SET_ATTRIBUTES _IOW('r', 0x11, __u32)
#endif
@@ -37,11 +51,13 @@
#undef statfs
-#if defined(__linux__) && !defined(BLKGETSIZE64)
+#ifndef BLKGETSIZE64
/* This takes a u64, but the size field says size_t. Someone screwed big. */
# define BLKGETSIZE64 _IOR(0x12,114,size_t)
#endif
#include <linux/loop.h>
+#endif /* __linux__ */
+
#endif /* LIBINSTALLER_LINUXIOCTL_H */
diff --git a/libinstaller/setadv.c b/libinstaller/setadv.c
index 9cf6f188..214f7fc1 100644
--- a/libinstaller/setadv.c
+++ b/libinstaller/setadv.c
@@ -30,6 +30,7 @@
#include <errno.h>
#include "syslxint.h"
#include "syslxcom.h"
+#include "syslxfs.h"
unsigned char syslinux_adv[2 * ADV_SIZE];
diff --git a/libinstaller/syslinux.h b/libinstaller/syslinux.h
index 710d30e5..8b86f881 100644
--- a/libinstaller/syslinux.h
+++ b/libinstaller/syslinux.h
@@ -40,10 +40,10 @@ extern const int syslinux_mbr_mtime;
#define SECTOR_SIZE (1 << SECTOR_SHIFT)
/* This takes a boot sector and merges in the syslinux fields */
-void syslinux_make_bootsect(void *);
+void syslinux_make_bootsect(void *bs, int fs_type);
/* Check to see that what we got was indeed an MS-DOS boot sector/superblock */
-const char *syslinux_check_bootsect(const void *bs);
+const char *syslinux_check_bootsect(const void *bs, int *fs_type);
/* This patches the boot sector and ldlinux.sys based on a sector map */
typedef uint64_t sector_t;
diff --git a/libinstaller/syslxcom.c b/libinstaller/syslxcom.c
index 1de85aa5..57f13cda 100644
--- a/libinstaller/syslxcom.c
+++ b/libinstaller/syslxcom.c
@@ -30,8 +30,10 @@
#include <sys/types.h>
#include <sys/mount.h>
#include <sys/vfs.h>
+
#include "linuxioctl.h"
#include "syslxcom.h"
+#include "syslxfs.h"
const char *program;
@@ -121,9 +123,9 @@ void clear_attributes(int fd)
{
int flags;
- if (!ioctl(fd, EXT2_IOC_GETFLAGS, &flags)) {
- flags &= ~EXT2_IMMUTABLE_FL;
- ioctl(fd, EXT2_IOC_SETFLAGS, &flags);
+ if (!ioctl(fd, FS_IOC_GETFLAGS, &flags)) {
+ flags &= ~FS_IMMUTABLE_FL;
+ ioctl(fd, FS_IOC_SETFLAGS, &flags);
}
break;
}
@@ -133,6 +135,8 @@ void clear_attributes(int fd)
ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &attr);
break;
}
+ case NTFS:
+ break;
default:
break;
}
@@ -151,9 +155,9 @@ void set_attributes(int fd)
{
int flags;
- if (st.st_uid == 0 && !ioctl(fd, EXT2_IOC_GETFLAGS, &flags)) {
- flags |= EXT2_IMMUTABLE_FL;
- ioctl(fd, EXT2_IOC_SETFLAGS, &flags);
+ if (st.st_uid == 0 && !ioctl(fd, FS_IOC_GETFLAGS, &flags)) {
+ flags |= FS_IMMUTABLE_FL;
+ ioctl(fd, FS_IOC_SETFLAGS, &flags);
}
break;
}
@@ -163,6 +167,8 @@ void set_attributes(int fd)
ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &attr);
break;
}
+ case NTFS:
+ break;
default:
break;
}
diff --git a/libinstaller/syslxcom.h b/libinstaller/syslxcom.h
index bf186ca6..8b3b4614 100644
--- a/libinstaller/syslxcom.h
+++ b/libinstaller/syslxcom.h
@@ -3,15 +3,6 @@
#include "syslinux.h"
-/* Global fs_type for handling fat, ext2/3/4 and btrfs */
-enum filesystem {
- NONE,
- EXT2,
- BTRFS,
- VFAT,
-};
-
-extern int fs_type;
extern const char *program;
ssize_t xpread(int fd, void *buf, size_t count, off_t offset);
ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset);
diff --git a/libinstaller/syslxfs.h b/libinstaller/syslxfs.h
new file mode 100644
index 00000000..7a231461
--- /dev/null
+++ b/libinstaller/syslxfs.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2011 Paulo Alcantara <pcacjr@gmail.com>
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef _SYSLXFS_H_
+#define _SYSLXFS_H_
+
+/* Global fs_type for handling fat, ntfs, ext2/3/4 and btrfs */
+enum filesystem {
+ NONE,
+ EXT2,
+ BTRFS,
+ VFAT,
+ NTFS,
+};
+
+extern int fs_type;
+
+#endif /* _SYSLXFS_H_ */
diff --git a/libinstaller/syslxint.h b/libinstaller/syslxint.h
index 80c40f76..e5428b79 100644
--- a/libinstaller/syslxint.h
+++ b/libinstaller/syslxint.h
@@ -2,6 +2,7 @@
*
* Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
* Copyright 2009-2011 Intel Corporation; author: H. Peter Anvin
+ * Copyright 2011 Paulo Alcantara <pcacjr@gmail.com>
*
* 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
@@ -22,6 +23,17 @@
# define X86_MEM 0
#endif
+#ifdef __GNUC__
+# ifdef __MINGW32__
+ /* gcc 4.7 miscompiles packed structures in MS-bitfield mode */
+# define PACKED __attribute__((packed,gcc_struct))
+# else
+# define PACKED __attribute__((packed))
+# endif
+#else
+# error "Need to define PACKED for this compiler"
+#endif
+
/*
* Access functions for littleendian numbers, possibly misaligned.
*/
@@ -189,10 +201,10 @@ struct ext_patch_area {
struct syslinux_extent {
uint64_t lba;
uint16_t len;
-} __attribute__((packed));
+} PACKED;
/* FAT bootsector format, also used by other disk-based derivatives */
-struct boot_sector {
+struct fat_boot_sector {
uint8_t bsJump[3];
char bsOemName[8];
uint16_t bsBytesPerSec;
@@ -217,7 +229,7 @@ struct boot_sector {
char VolumeLabel[11];
char FileSysType[8];
uint8_t Code[442];
- } __attribute__ ((packed)) bs16;
+ } PACKED bs16;
struct {
uint32_t FATSz32;
uint16_t ExtFlags;
@@ -233,18 +245,82 @@ struct boot_sector {
char VolumeLabel[11];
char FileSysType[8];
uint8_t Code[414];
- } __attribute__ ((packed)) bs32;
- } __attribute__ ((packed));
+ } PACKED bs32;
+ } PACKED;
uint32_t bsMagic;
uint16_t bsForwardPtr;
uint16_t bsSignature;
-} __attribute__ ((packed));
+} PACKED;
-#define bsHead bsJump
-#define bsHeadLen offsetof(struct boot_sector, bsBytesPerSec)
-#define bsCode bs32.Code /* The common safe choice */
-#define bsCodeLen (offsetof(struct boot_sector, bsSignature) - \
- offsetof(struct boot_sector, bsCode))
+/* NTFS bootsector format */
+struct ntfs_boot_sector {
+ uint8_t bsJump[3];
+ char bsOemName[8];
+ uint16_t bsBytesPerSec;
+ uint8_t bsSecPerClust;
+ uint16_t bsResSectors;
+ uint8_t bsZeroed_0[3];
+ uint16_t bsZeroed_1;
+ uint8_t bsMedia;
+ uint16_t bsZeroed_2;
+ uint16_t bsUnused_0;
+ uint16_t bsUnused_1;
+ uint32_t bsUnused_2;
+ uint32_t bsZeroed_3;
+ uint32_t bsUnused_3;
+ uint64_t bsTotalSectors;
+ uint64_t bsMFTLogicalClustNr;
+ uint64_t bsMFTMirrLogicalClustNr;
+ uint8_t bsClustPerMFTrecord;
+ uint8_t bsUnused_4[3];
+ uint8_t bsClustPerIdxBuf;
+ uint8_t bsUnused_5[3];
+ uint64_t bsVolSerialNr;
+ uint32_t bsUnused_6;
+
+ uint8_t Code[420];
+
+ uint32_t bsMagic;
+ uint16_t bsForwardPtr;
+ uint16_t bsSignature;
+} PACKED;
+
+#define FAT_bsHead bsJump
+#define FAT_bsHeadLen offsetof(struct fat_boot_sector, bsBytesPerSec)
+#define FAT_bsCode bs32.Code /* The common safe choice */
+#define FAT_bsCodeLen (offsetof(struct fat_boot_sector, bsSignature) - \
+ offsetof(struct fat_boot_sector, FAT_bsCode))
+
+#define NTFS_bsHead bsJump
+#define NTFS_bsHeadLen offsetof(struct ntfs_boot_sector, bsOemName)
+#define NTFS_bsCode Code
+#define NTFS_bsCodeLen (offsetof(struct ntfs_boot_sector, bsSignature) - \
+ offsetof(struct ntfs_boot_sector, NTFS_bsCode))
+
+/* Check if there are specific zero fields in an NTFS boot sector */
+static inline int ntfs_check_zero_fields(const struct ntfs_boot_sector *sb)
+{
+ return !sb->bsResSectors && (!sb->bsZeroed_0[0] && !sb->bsZeroed_0[1] &&
+ !sb->bsZeroed_0[2]) && !sb->bsZeroed_1 && !sb->bsZeroed_2 &&
+ !sb->bsZeroed_3;
+}
+
+static inline int ntfs_check_sb_fields(const struct ntfs_boot_sector *sb)
+{
+ return ntfs_check_zero_fields(sb) &&
+ (!memcmp(sb->bsOemName, "NTFS ", 8) ||
+ !memcmp(sb->bsOemName, "MSWIN4.0", 8) ||
+ !memcmp(sb->bsOemName, "MSWIN4.1", 8));
+}
+
+static inline int fat_check_sb_fields(const struct fat_boot_sector *sb)
+{
+ return sb->bsResSectors && sb->bsFATs &&
+ (!memcmp(sb->bs16.FileSysType, "FAT12 ", 8) ||
+ !memcmp(sb->bs16.FileSysType, "FAT16 ", 8) ||
+ !memcmp(sb->bs16.FileSysType, "FAT ", 8) ||
+ !memcmp(sb->bs32.FileSysType, "FAT32 ", 8));
+}
#endif /* SYSLXINT_H */
diff --git a/libinstaller/syslxmod.c b/libinstaller/syslxmod.c
index a68f19fb..c706f2c2 100644
--- a/libinstaller/syslxmod.c
+++ b/libinstaller/syslxmod.c
@@ -33,26 +33,29 @@
static void generate_extents(struct syslinux_extent *ex, int nptrs,
const sector_t *sectp, int nsect)
{
- uint32_t addr = 0x7c00 + 2*SECTOR_SIZE;
+ uint32_t addr = 0x8000; /* ldlinux.sys starts loading here */
uint32_t base;
sector_t sect, lba;
unsigned int len;
- len = lba = base = 0;
+ base = addr;
+ len = lba = 0;
memset(ex, 0, nptrs * sizeof *ex);
while (nsect) {
sect = *sectp++;
- if (len && sect == lba + len &&
- ((addr ^ (base + len * SECTOR_SIZE)) & 0xffff0000) == 0) {
- /* We can add to the current extent */
- len++;
- goto next;
- }
-
if (len) {
+ uint32_t xbytes = (len + 1) * SECTOR_SIZE;
+
+ if (sect == lba + len && xbytes < 65536 &&
+ ((addr ^ (base + xbytes - 1)) & 0xffff0000) == 0) {
+ /* We can add to the current extent */
+ len++;
+ goto next;
+ }
+
set_64_sl(&ex->lba, lba);
set_16_sl(&ex->len, len);
ex++;
@@ -93,8 +96,6 @@ static inline void *ptr(void *img, uint16_t *offset_p)
* Returns the number of modified bytes in ldlinux.sys if successful,
* otherwise -1.
*/
-#define NADV 2
-
int syslinux_patch(const sector_t *sectp, int nsectors,
int stupid, int raid_mode,
const char *subdir, const char *subvol)
@@ -106,7 +107,7 @@ int syslinux_patch(const sector_t *sectp, int nsectors,
int nsect = ((boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT) + 2;
uint32_t csum;
int i, dw, nptrs;
- struct boot_sector *sbs = (struct boot_sector *)boot_sector;
+ struct fat_boot_sector *sbs = (struct fat_boot_sector *)boot_sector;
uint64_t *advptrs;
if (nsectors < nsect)
diff --git a/libinstaller/syslxopt.c b/libinstaller/syslxopt.c
index 7ceb3ba2..b739752f 100644
--- a/libinstaller/syslxopt.c
+++ b/libinstaller/syslxopt.c
@@ -25,6 +25,7 @@
#include <sysexits.h>
#include "../version.h"
#include "syslxcom.h"
+#include "syslxfs.h"
#include "syslxopt.h"
/* These are the options we can set their values */
@@ -65,6 +66,7 @@ const struct option long_options[] = {
{"menu-save", 1, NULL, 'M'},
{"mbr", 0, NULL, 'm'}, /* DOS/Win32 only */
{"active", 0, NULL, 'a'}, /* DOS/Win32 only */
+ {"device", 1, NULL, OPT_DEVICE},
{0, 0, 0, 0}
};
@@ -86,7 +88,8 @@ void __attribute__ ((noreturn)) usage(int rv, enum syslinux_mode mode)
/* Mounted fs installation (extlinux) */
/* Actually extlinux can also use -d to provide a directory too... */
fprintf(stderr,
- "Usage: %s [options] directory\n",
+ "Usage: %s [options] directory\n"
+ " --device Force use of a specific block device (experts only)\n",
program);
break;
@@ -209,6 +212,11 @@ void parse_options(int argc, char *argv[], enum syslinux_mode mode)
case 'a':
opt.activate_partition = 1;
break;
+ case OPT_DEVICE:
+ if (mode != MODE_EXTLINUX)
+ usage(EX_USAGE, mode);
+ opt.device = optarg;
+ break;
case 'v':
fprintf(stderr,
"%s " VERSION_STR " Copyright 1994-" YEAR_STR
diff --git a/libinstaller/syslxopt.h b/libinstaller/syslxopt.h
index bcbe0352..042301f6 100644
--- a/libinstaller/syslxopt.h
+++ b/libinstaller/syslxopt.h
@@ -24,6 +24,7 @@ enum long_only_opt {
OPT_NONE,
OPT_RESET_ADV,
OPT_ONCE,
+ OPT_DEVICE,
};
enum syslinux_mode {
diff --git a/linux/Makefile b/linux/Makefile
index ffe22728..08a3ed49 100644
--- a/linux/Makefile
+++ b/linux/Makefile
@@ -11,13 +11,14 @@
## -----------------------------------------------------------------------
##
-## Linux FAT installer
+## Linux FAT/NTFS installer
##
topdir = ..
-include $(topdir)/MCONFIG
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/syslinux.mk
-OPTFLAGS = -g -O0 -Dalloca=malloc
+OPTFLAGS = -g -Os
INCLUDES = -I. -I.. -I../libinstaller
CFLAGS = $(GCCWARN) -D_FILE_OFFSET_BITS=64 $(OPTFLAGS) $(INCLUDES)
LDFLAGS =
@@ -27,7 +28,7 @@ SRCS = syslinux.c \
../libinstaller/syslxcom.c \
../libinstaller/setadv.c \
../libinstaller/advio.c \
- ../libinstaller/fat.c \
+ ../libinstaller/fs.c \
../libinstaller/syslxmod.c \
../libinstaller/bootsect_bin.c \
../libinstaller/ldlinux_bin.c
@@ -56,6 +57,9 @@ syslinux: $(OBJS)
syslinux-nomtools: syslinux
ln -f $< $@
+strip:
+ $(STRIP) syslinux syslinux-nomtools
+
%.o: %.c
$(CC) $(UMAKEDEPS) $(CFLAGS) -c -o $@ $<
%.i: %.c
diff --git a/linux/syslinux.c b/linux/syslinux.c
index c7a9ecc4..4b13b7fe 100755
--- a/linux/syslinux.c
+++ b/linux/syslinux.c
@@ -69,6 +69,7 @@
#include <getopt.h>
#include <sysexits.h>
#include "syslxcom.h"
+#include "syslxfs.h"
#include "setadv.h"
#include "syslxopt.h" /* unified options */
@@ -294,14 +295,14 @@ int main(int argc, char *argv[])
die("can't combine an offset with a block device");
}
- fs_type = VFAT;
xpread(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);
fsync(dev_fd);
/*
- * Check to see that what we got was indeed an MS-DOS boot sector/superblock
+ * Check to see that what we got was indeed an FAT/NTFS
+ * boot sector/superblock
*/
- if ((errmsg = syslinux_check_bootsect(sectbuf))) {
+ if ((errmsg = syslinux_check_bootsect(sectbuf, &fs_type))) {
fprintf(stderr, "%s: %s\n", opt.device, errmsg);
exit(1);
}
@@ -357,10 +358,17 @@ int main(int argc, char *argv[])
mntpath = mntname;
}
- if (do_mount(dev_fd, &mnt_cookie, mntpath, "vfat") &&
- do_mount(dev_fd, &mnt_cookie, mntpath, "msdos")) {
- rmdir(mntpath);
- die("mount failed");
+ if (fs_type == VFAT) {
+ if (do_mount(dev_fd, &mnt_cookie, mntpath, "vfat") &&
+ do_mount(dev_fd, &mnt_cookie, mntpath, "msdos")) {
+ rmdir(mntpath);
+ die("failed on mounting fat volume");
+ }
+ } else if (fs_type == NTFS) {
+ if (do_mount(dev_fd, &mnt_cookie, mntpath, "ntfs-3g")) {
+ rmdir(mntpath);
+ die("failed on mounting ntfs volume");
+ }
}
ldlinux_path = alloca(strlen(mntpath) + strlen(subdir) + 1);
@@ -474,7 +482,7 @@ umount:
xpread(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);
/* Copy the syslinux code into the boot sector */
- syslinux_make_bootsect(sectbuf);
+ syslinux_make_bootsect(sectbuf, fs_type);
/* Write new boot sector */
xpwrite(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);
diff --git a/lzo/Makefile b/lzo/Makefile
index d88279dd..cf8f985a 100644
--- a/lzo/Makefile
+++ b/lzo/Makefile
@@ -11,7 +11,8 @@
## -----------------------------------------------------------------------
topdir = ..
-include $(topdir)/MCONFIG.build
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/build.mk
INCLUDES += -I./include
diff --git a/man/extlinux.1 b/man/extlinux.1
index 3192122a..5daa4e52 100644
--- a/man/extlinux.1
+++ b/man/extlinux.1
@@ -45,8 +45,17 @@ Updates a previous \fBEXTLINUX\fP installation.
.TP
\fB\-z\fR, \fB\-\-zip\fR
Force zipdrive geometry (-H 64 -S 32).
+.TP
+\fB\-\-device\fR=\fIdevicename\fR
+Override the automatic detection of device names. This option is
+intended for special environments only and should not be used by
+normal users. Misuse of this option can cause disk corruption and
+lost data.
.SH FILES
-The extlinux configuration file needs to be named extlinux.conf and needs to be stored in the extlinux installation directory. For more information about the contents of extlinux.conf, see syslinux(1) manpage, section files.
+The extlinux configuration file needs to be named syslinux.cfg or
+extlinux.conf and needs to be stored in the extlinux installation
+directory. For more information about the contents of extlinux.conf,
+see syslinux(1) manpage, section files.
.SH BUGS
I would appreciate hearing of any problems you have with \s-1SYSLINUX\s+1. I
would also like to hear from you if you have successfully used \s-1SYSLINUX\s+1,
diff --git a/mbr/Makefile b/mbr/Makefile
index c3eb97a7..993bb100 100644
--- a/mbr/Makefile
+++ b/mbr/Makefile
@@ -16,7 +16,8 @@
#
topdir = ..
-include $(topdir)/MCONFIG.embedded
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/embedded.mk
all: mbr.bin altmbr.bin gptmbr.bin isohdpfx.bin isohdppx.bin \
mbr_c.bin altmbr_c.bin gptmbr_c.bin isohdpfx_c.bin isohdppx_c.bin \
diff --git a/mbr/altmbr.S b/mbr/altmbr.S
index 1b609051..c66b4ddc 100644
--- a/mbr/altmbr.S
+++ b/mbr/altmbr.S
@@ -204,7 +204,7 @@ scan_partition_table:
5:
decb (partition)
jz boot
- addw $16, %bx
+ addw $16, %si
loopw 5b
popw %cx /* %cx <- 4 */
diff --git a/mbr/isohdpfx.S b/mbr/isohdpfx.S
index 2784fb80..17e1efe1 100644
--- a/mbr/isohdpfx.S
+++ b/mbr/isohdpfx.S
@@ -66,6 +66,37 @@ bootsec:
.globl _start
_start:
.byte 0x33, 0xed /* xorw %bp, %bp */
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ .byte 0x33, 0xed /* xorw %bp, %bp */
cli
movw %bp, %ss
movw $stack, %sp
diff --git a/memdisk/Makefile b/memdisk/Makefile
index 92f565a4..b5cd52ce 100644
--- a/memdisk/Makefile
+++ b/memdisk/Makefile
@@ -12,14 +12,15 @@
## -----------------------------------------------------------------------
topdir = ..
-include $(topdir)/MCONFIG.embedded
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/embedded.mk
-include $(topdir)/version.mk
INCLUDES = -I$(topdir)/com32/include
CFLAGS += -D__MEMDISK__ -DDATE='"$(DATE)"'
LDFLAGS = $(GCCOPT) -g
NASM = nasm
-NASMOPT = -O9999
+NASMOPT = -Ox
NFLAGS = -dDATE='"$(DATE)"'
NINCLUDE =
diff --git a/memdisk/mstructs.h b/memdisk/mstructs.h
index fecbff40..0b0dc07d 100644
--- a/memdisk/mstructs.h
+++ b/memdisk/mstructs.h
@@ -121,9 +121,9 @@ typedef union {
uint8_t specify1; /* "First specify byte" */
uint8_t specify2; /* "Second specify byte" */
uint8_t delay; /* Delay until motor turn off */
- uint8_t sectors; /* Sectors/track */
-
uint8_t bps; /* Bytes/sector (02h = 512) */
+
+ uint8_t sectors; /* Sectors/track */
uint8_t isgap; /* Length of intersector gap */
uint8_t dlen; /* Data length (0FFh) */
uint8_t fgap; /* Formatting gap */
diff --git a/memdump/Makefile b/memdump/Makefile
index e56c7bd4..6a30431a 100644
--- a/memdump/Makefile
+++ b/memdump/Makefile
@@ -15,7 +15,8 @@
##
topdir = ..
-include $(topdir)/MCONFIG.embedded
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/embedded.mk
OPTFLAGS =
INCLUDES = -include code16.h -I.
diff --git a/MCONFIG.build b/mk/build.mk
index d1abff2a..0ca82bea 100644
--- a/MCONFIG.build
+++ b/mk/build.mk
@@ -14,7 +14,7 @@
## Right now we don't distinguish between "build" system and the "host"
## system, although we really should...
##
-include $(topdir)/MCONFIG
+include $(MAKEDIR)/syslinux.mk
OPTFLAGS = -g -Os
INCLUDES =
diff --git a/com32/MCONFIG b/mk/com32.mk
index a74ed326..4a6caae9 100644
--- a/com32/MCONFIG
+++ b/mk/com32.mk
@@ -15,7 +15,7 @@
## COM32 common configurables
##
-include $(topdir)/MCONFIG
+include $(MAKEDIR)/syslinux.mk
GCCOPT := $(call gcc_ok,-std=gnu99,)
GCCOPT += $(call gcc_ok,-m32,)
diff --git a/MCONFIG.devel b/mk/devel.mk
index 104207f5..104207f5 100644
--- a/MCONFIG.devel
+++ b/mk/devel.mk
diff --git a/MCONFIG.embedded b/mk/embedded.mk
index 9f5846d7..e8f3ae30 100644
--- a/MCONFIG.embedded
+++ b/mk/embedded.mk
@@ -14,7 +14,7 @@
## Make configuration for embedded directories
##
-include $(topdir)/MCONFIG
+include $(MAKEDIR)/syslinux.mk
GCCOPT := $(call gcc_ok,-m32,)
GCCOPT += $(call gcc_ok,-ffreestanding,)
diff --git a/com32/lib/MCONFIG b/mk/lib.mk
index 44278bd1..48b2a13d 100644
--- a/com32/lib/MCONFIG
+++ b/mk/lib.mk
@@ -1,6 +1,6 @@
# -*- makefile -*-
-include $(topdir)/MCONFIG
+include $(MAKEDIR)/syslinux.mk
GCCOPT := $(call gcc_ok,-std=gnu99,)
GCCOPT += $(call gcc_ok,-m32,)
diff --git a/com32/rosh/MCONFIG b/mk/rosh.mk
index 25c41396..7fdba0f1 100644
--- a/com32/rosh/MCONFIG
+++ b/mk/rosh.mk
@@ -15,7 +15,7 @@
##
## Include the COM32 common configurables
-include ../MCONFIG
+include $(MAKEDIR)/com32.mk
# CFLAGS = $(GCCOPT) $(GCCWARN) -march=i386 \
# -fomit-frame-pointer -D__COM32__ \
diff --git a/MCONFIG b/mk/syslinux.mk
index a71fd139..6d87187f 100644
--- a/MCONFIG
+++ b/mk/syslinux.mk
@@ -53,7 +53,9 @@ OBJCOPY = objcopy
AR = ar
NM = nm
RANLIB = ranlib
+STRIP = strip
GZIPPROG = gzip
+XZ = xz
PNGTOPNM = pngtopnm
MCOPY = mcopy
MFORMAT = mformat
@@ -77,7 +79,7 @@ UMAKEDEPS = -Wp,-MT,$@,-MMD,$(dir $@).$(notdir $@).d
# Items that are only appropriate during development; this file is
# removed when tarballs are generated.
--include $(topdir)/MCONFIG.devel
+-include $(MAKEDIR)/devel.mk
# Local additions, like -DDEBUG can go here
--include $(topdir)/MCONFIG.local
+-include $(MAKEDIR)/local.mk
diff --git a/modules/Makefile b/modules/Makefile
index 9b50bb23..f878c70d 100644
--- a/modules/Makefile
+++ b/modules/Makefile
@@ -15,7 +15,8 @@
##
topdir = ..
-include $(topdir)/MCONFIG.embedded
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/embedded.mk
INCLUDES = -I$(com32)/include
diff --git a/mtools/Makefile b/mtools/Makefile
index 6164d24c..78cea1e2 100755
--- a/mtools/Makefile
+++ b/mtools/Makefile
@@ -1,13 +1,14 @@
topdir = ..
-include $(topdir)/MCONFIG
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/syslinux.mk
OPTFLAGS = -g -Os
INCLUDES = -I. -I.. -I../libfat -I../libinstaller
CFLAGS = $(GCCWARN) -D_FILE_OFFSET_BITS=64 $(OPTFLAGS) $(INCLUDES)
-LDFLAGS = -s
+LDFLAGS =
SRCS = syslinux.c \
- ../libinstaller/fat.c \
+ ../libinstaller/fs.c \
../libinstaller/syslxmod.c \
../libinstaller/syslxopt.c \
../libinstaller/setadv.c \
@@ -36,6 +37,9 @@ installer: syslinux
syslinux: $(OBJS)
$(CC) $(LDFLAGS) -o $@ $^
+strip:
+ $(STRIP) syslinux
+
%.o: %.c
$(CC) $(UMAKEDEPS) $(CFLAGS) -c -o $@ $<
%.i: %.c
diff --git a/mtools/syslinux.c b/mtools/syslinux.c
index ac189c61..c65021bb 100755
--- a/mtools/syslinux.c
+++ b/mtools/syslinux.c
@@ -41,6 +41,7 @@
#include "libfat.h"
#include "setadv.h"
#include "syslxopt.h"
+#include "syslxfs.h"
char *program; /* Name of program */
pid_t mypid;
@@ -197,7 +198,7 @@ int main(int argc, char *argv[])
/*
* Check to see that what we got was indeed an MS-DOS boot sector/superblock
*/
- if ((errmsg = syslinux_check_bootsect(sectbuf))) {
+ if ((errmsg = syslinux_check_bootsect(sectbuf, NULL))) {
die(errmsg);
}
@@ -356,7 +357,7 @@ int main(int argc, char *argv[])
xpread(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);
/* Copy the syslinux code into the boot sector */
- syslinux_make_bootsect(sectbuf);
+ syslinux_make_bootsect(sectbuf, VFAT);
/* Write new boot sector */
xpwrite(dev_fd, sectbuf, SECTOR_SIZE, opt.offset);
diff --git a/sample/Makefile b/sample/Makefile
index d7f439ca..9e504d96 100644
--- a/sample/Makefile
+++ b/sample/Makefile
@@ -15,7 +15,8 @@
##
topdir = ..
-include $(topdir)/MCONFIG.embedded
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/embedded.mk
PPMTOLSS16 = $(topdir)/utils/ppmtolss16
diff --git a/utils/Makefile b/utils/Makefile
index 455eb828..be739935 100644
--- a/utils/Makefile
+++ b/utils/Makefile
@@ -15,15 +15,19 @@
#
topdir = ..
-include $(topdir)/MCONFIG
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/syslinux.mk
CFLAGS = $(GCCWARN) -Os -fomit-frame-pointer -D_FILE_OFFSET_BITS=64
-LDFLAGS = -O2 -s
+LDFLAGS = -O2
-TARGETS = mkdiskimage isohybrid gethostip memdiskfind
-TARGETS += isohybrid.pl # about to be obsoleted
-ASIS = keytab-lilo lss16toppm md5pass ppmtolss16 sha1pass syslinux2ansi \
- pxelinux-options
+C_TARGETS = isohybrid gethostip memdiskfind
+SCRIPT_TARGETS = mkdiskimage
+SCRIPT_TARGETS += isohybrid.pl # about to be obsoleted
+ASIS = keytab-lilo lss16toppm md5pass ppmtolss16 sha1pass \
+ syslinux2ansi pxelinux-options
+
+TARGETS = $(C_TARGETS) $(SCRIPT_TARGETS)
ISOHDPFX = ../mbr/isohdpfx.bin ../mbr/isohdpfx_f.bin ../mbr/isohdpfx_c.bin \
../mbr/isohdppx.bin ../mbr/isohdppx_f.bin ../mbr/isohdppx_c.bin
@@ -47,7 +51,7 @@ isohdpfx.c: $(ISOHDPFX) isohdpfxarray.pl
$(PERL) isohdpfxarray.pl $(ISOHDPFX) > $@
isohybrid: isohybrid.o isohdpfx.o
- $(CC) $(LDFLAGS) -o $@ $^
+ $(CC) $(LDFLAGS) -o $@ $^ -luuid
gethostip: gethostip.o
$(CC) $(LDFLAGS) -o $@ $^
@@ -69,4 +73,7 @@ install: installer
mkdir -m 755 -p $(INSTALLROOT)$(BINDIR)
install -m 755 $(TARGETS) $(ASIS) $(INSTALLROOT)$(BINDIR)
+strip:
+ $(STRIP) $(C_TARGETS)
+
-include .*.d
diff --git a/utils/isohybrid.c b/utils/isohybrid.c
index 7ee9a7f0..97d43b86 100644
--- a/utils/isohybrid.c
+++ b/utils/isohybrid.c
@@ -36,20 +36,25 @@
#include <unistd.h>
#include <sys/stat.h>
#include <inttypes.h>
+#include <uuid/uuid.h>
#include "isohybrid.h"
char *prog = NULL;
extern int opterr, optind;
+struct stat isostat;
+unsigned int padding = 0;
+
+uuid_t disk_uuid, part_uuid, iso_uuid;
uint8_t mode = 0;
-enum { VERBOSE = 1 };
+enum { VERBOSE = 1 , EFI = 2 , MAC = 4};
/* user options */
uint16_t head = 64; /* 1 <= head <= 256 */
uint8_t sector = 32; /* 1 <= sector <= 63 */
-uint8_t entry = 1; /* partition number: 1 <= entry <= 4 */
+uint8_t entry = 0; /* partition number: 1 <= entry <= 4 */
uint8_t offset = 0; /* partition offset: 0 <= offset <= 64 */
uint16_t type = 0x17; /* partition type: 0 <= type <= 255 */
uint32_t id = 0; /* MBR: 0 <= id <= 0xFFFFFFFF(4294967296) */
@@ -61,10 +66,150 @@ uint16_t ve[16];
uint32_t catoffset = 0;
uint32_t c = 0, cc = 0, cs = 0;
+uint32_t psize = 0, isosize = 0;
+
/* boot catalogue parameters */
uint32_t de_lba = 0;
uint16_t de_seg = 0, de_count = 0, de_mbz2 = 0;
uint8_t de_boot = 0, de_media = 0, de_sys = 0, de_mbz1 = 0;
+uint32_t efi_lba = 0, mac_lba = 0;
+uint16_t efi_count = 0, mac_count = 0;
+uint8_t efi_boot = 0, efi_media = 0, efi_sys = 0;
+
+int apm_parts = 3;
+
+uint8_t afp_header[] = { 0x45, 0x52, 0x08, 0x00, 0x00, 0x00, 0x90, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+uuid_t efi_system_partition = {0xC1, 0x2A, 0x73, 0x28, 0xF8, 0x1F, 0x11, 0xD2, 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B};
+uuid_t basic_partition = {0xEB,0xD0,0xA0,0xA2,0xB9,0xE5,0x44,0x33,0x87,0xC0,0x68,0xB6,0xB7,0x26,0x99,0xC7};
+uuid_t hfs_partition = {0x48, 0x46, 0x53, 0x00, 0x00, 0x00, 0x11, 0xAA, 0xAA, 0x11, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC};
+
+uint32_t crc_tab[256] =
+{
+ 0, 0x77073096, 0xEE0E612C, 0x990951BA,
+ 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+ 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
+ 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
+ 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
+ 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
+ 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
+ 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
+ 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
+ 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
+ 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
+ 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
+ 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
+ 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
+ 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
+ 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
+ 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
+ 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
+ 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
+ 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
+ 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
+ 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
+ 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
+ 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
+ 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
+ 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
+ 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
+ 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
+ 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
+ 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
+ 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
+ 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
+ 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
+ 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+};
+
+struct iso_primary_descriptor {
+ uint8_t ignore [80];
+ uint32_t size;
+ uint8_t ignore2 [44];
+ uint16_t block_size;
+};
+
+struct gpt_header {
+ uint64_t signature;
+ uint32_t revision;
+ uint32_t headerSize;
+ uint32_t headerCRC;
+ uint32_t reserved;
+ uint64_t currentLBA;
+ uint64_t backupLBA;
+ uint64_t firstUsableLBA;
+ uint64_t lastUsableLBA;
+ uuid_t diskGUID;
+ uint64_t partitionEntriesLBA;
+ uint32_t numParts;
+ uint32_t sizeOfPartitionEntries;
+ uint32_t partitionEntriesCRC;
+ uint8_t reserved2[420];
+};
+
+struct gpt_part_header {
+ uuid_t partTypeGUID;
+ uuid_t partGUID;
+ uint64_t firstLBA;
+ uint64_t lastLBA;
+ uint64_t attributes;
+ uint16_t name[36];
+};
+
+#define APM_OFFSET 2048
+
+struct apple_part_header {
+ uint16_t signature; /* expected to be MAC_PARTITION_MAGIC */
+ uint16_t res1;
+ uint32_t map_count; /* # blocks in partition map */
+ uint32_t start_block; /* absolute starting block # of partition */
+ uint32_t block_count; /* number of blocks in partition */
+ char name[32]; /* partition name */
+ char type[32]; /* string type description */
+ uint32_t data_start; /* rel block # of first data block */
+ uint32_t data_count; /* number of data blocks */
+ uint32_t status; /* partition status bits */
+ uint32_t boot_start;
+ uint32_t boot_count;
+ uint32_t boot_load;
+ uint32_t boot_load2;
+ uint32_t boot_entry;
+ uint32_t boot_entry2;
+ uint32_t boot_cksum;
+ char processor[16]; /* Contains 680x0, x=0,2,3,4; or empty */
+ uint32_t driver_sig;
+ char _padding[372];
+};
void
@@ -89,6 +234,8 @@ printh(void)
printf(FMT, " -o --offset", "Specify partition offset (default 0)");
printf(FMT, " -t --type", "Specify partition type (default 0x17)");
printf(FMT, " -i --id", "Specify MBR ID (default random)");
+ printf(FMT, " -u --uefi", "Build EFI bootable image");
+ printf(FMT, " -m --mac", "Add AFP table support");
printf("\n");
printf(FMT, " --forcehd0", "Assume we are loaded as disk ID 0");
@@ -108,6 +255,7 @@ printh(void)
int
check_option(int argc, char *argv[])
{
+ char *err = NULL;
int n = 0, ind = 0;
const char optstr[] = ":h:s:e:o:t:i:fcp?vV";
@@ -121,6 +269,8 @@ check_option(int argc, char *argv[])
{ "forcehd0", no_argument, NULL, 'f' },
{ "ctrlhd0", no_argument, NULL, 'c' },
{ "partok", no_argument, NULL, 'p'},
+ { "uefi", no_argument, NULL, 'u'},
+ { "mac", no_argument, NULL, 'm'},
{ "help", no_argument, NULL, '?' },
{ "verbose", no_argument, NULL, 'v' },
@@ -135,32 +285,40 @@ check_option(int argc, char *argv[])
switch (n)
{
case 'h':
- if (!sscanf(optarg, "%hu", &head) || head < 1 || head > 256)
+ head = strtoul(optarg, &err, 0);
+ if (head < 1 || head > 256)
errx(1, "invalid head: `%s', 1 <= head <= 256", optarg);
break;
case 's':
- if (!sscanf(optarg, "%hhu", &sector) || sector < 1 || sector > 63)
+ sector = strtoul(optarg, &err, 0);
+ if (sector < 1 || sector > 63)
errx(1, "invalid sector: `%s', 1 <= sector <= 63", optarg);
break;
case 'e':
- if (!sscanf(optarg, "%hhu", &entry) || entry < 1 || entry > 4)
+ entry = strtoul(optarg, &err, 0);
+ if (entry < 1 || entry > 4)
errx(1, "invalid entry: `%s', 1 <= entry <= 4", optarg);
+ if (mode & MAC || mode & EFI)
+ errx(1, "setting an entry is unsupported with EFI or Mac");
break;
case 'o':
- if (!sscanf(optarg, "%hhu", &offset) || offset > 64)
+ offset = strtoul(optarg, &err, 0);
+ if (*err || offset > 64)
errx(1, "invalid offset: `%s', 0 <= offset <= 64", optarg);
break;
case 't':
- if (!sscanf(optarg, "%hu", &type) || type > 255)
+ type = strtoul(optarg, &err, 0);
+ if (*err || type > 255)
errx(1, "invalid type: `%s', 0 <= type <= 255", optarg);
break;
case 'i':
- if (!sscanf(optarg, "%u", &id))
+ id = strtoul(optarg, &err, 0);
+ if (*err)
errx(1, "invalid id: `%s'", optarg);
break;
@@ -176,6 +334,18 @@ check_option(int argc, char *argv[])
partok = 1;
break;
+ case 'u':
+ mode |= EFI;
+ if (entry)
+ errx(1, "setting an entry is unsupported with EFI or Mac");
+ break;
+
+ case 'm':
+ mode |= MAC;
+ if (entry)
+ errx(1, "setting an entry is unsupported with EFI or Mac");
+ break;
+
case 'v':
mode |= VERBOSE;
break;
@@ -200,6 +370,33 @@ check_option(int argc, char *argv[])
return optind;
}
+uint16_t
+bendian_short(const uint16_t s)
+{
+ uint16_t r = 1;
+
+ if (!*(uint8_t *)&r)
+ return s;
+
+ r = (s & 0x00FF) << 8 | (s & 0xFF00) >> 8;
+
+ return r;
+}
+
+
+uint32_t
+bendian_int(const uint32_t s)
+{
+ uint32_t r = 1;
+
+ if (!*(uint8_t *)&r)
+ return s;
+
+ r = (s & 0x000000FF) << 24 | (s & 0xFF000000) >> 24
+ | (s & 0x0000FF00) << 8 | (s & 0x00FF0000) >> 8;
+
+ return r;
+}
uint16_t
lendian_short(const uint16_t s)
@@ -229,6 +426,22 @@ lendian_int(const uint32_t s)
return r;
}
+uint64_t
+lendian_64(const uint64_t s)
+{
+ uint64_t r = 1;
+
+ if (*(uint8_t *)&r)
+ return s;
+
+ r = (s & 0x00000000000000FFull) << 56 | (s & 0xFF00000000000000ull) >> 56
+ | (s & 0x000000000000FF00ull) << 40 | (s & 0x00FF000000000000ull) >> 40
+ | (s & 0x0000000000FF0000ull) << 24 | (s & 0x0000FF0000000000ull) >> 24
+ | (s & 0x00000000FF000000ull) << 8 | (s & 0x000000FF00000000ull) >> 8;
+
+ return r;
+}
+
int
check_banner(const uint8_t *buf)
@@ -307,6 +520,43 @@ read_catalogue(const uint8_t *buf)
}
+int
+read_efi_section(const uint8_t *buf)
+{
+ unsigned char header_indicator;
+ unsigned char platform_id;
+ short count;
+
+ memcpy(&header_indicator, buf++, 1);
+ memcpy(&platform_id, buf++, 1);
+
+ memcpy(&count, buf, 2);
+ count = lendian_short(count);
+ buf += 2;
+
+ if (platform_id == 0xef)
+ return 0;
+
+ return 1;
+}
+
+int
+read_efi_catalogue(const uint8_t *buf, uint16_t *count, uint32_t *lba)
+{
+ buf += 6;
+
+ memcpy(count, buf, 2);
+ *count = lendian_short(*count);
+ buf += 2;
+
+ memcpy(lba, buf, 4);
+ *lba = lendian_int(*lba);
+ buf += 6;
+
+ return 0;
+}
+
+
void
display_catalogue(void)
{
@@ -320,12 +570,11 @@ display_catalogue(void)
printf("de_mbz2: %hu\n", de_mbz2);
}
-
int
initialise_mbr(uint8_t *mbr)
{
int i = 0;
- uint32_t psize = 0, tmp = 0;
+ uint32_t tmp = 0;
uint8_t ptype = 0, *rbm = mbr;
uint8_t bhead = 0, bsect = 0, bcyle = 0;
uint8_t ehead = 0, esect = 0, ecyle = 0;
@@ -333,6 +582,17 @@ initialise_mbr(uint8_t *mbr)
extern unsigned char isohdpfx[][MBRSIZE];
memcpy(mbr, &isohdpfx[hd0 + 3 * partok], MBRSIZE);
+
+ if (mode & MAC) {
+ memcpy(mbr, afp_header, sizeof(afp_header));
+ }
+
+ if (!entry)
+ entry = 1;
+
+ if (mode & EFI)
+ type = 0;
+
mbr += MBRSIZE; /* offset 432 */
tmp = lendian_int(de_lba * 4);
@@ -385,6 +645,40 @@ initialise_mbr(uint8_t *mbr)
tmp = lendian_int(psize);
memcpy(&mbr[12], &tmp, sizeof(tmp));
}
+ if (i == 2 && (mode & EFI))
+ {
+ mbr[0] = 0x0;
+ mbr[1] = 0xfe;
+ mbr[2] = 0xff;
+ mbr[3] = 0xff;
+ mbr[4] = 0xef;
+ mbr[5] = 0xfe;
+ mbr[6] = 0xff;
+ mbr[7] = 0xff;
+
+ tmp = lendian_int(efi_lba * 4);
+ memcpy(&mbr[8], &tmp, sizeof(tmp));
+
+ tmp = lendian_int(efi_count);
+ memcpy(&mbr[12], &tmp, sizeof(tmp));
+ }
+ if (i == 3 && (mode & MAC))
+ {
+ mbr[0] = 0x0;
+ mbr[1] = 0xfe;
+ mbr[2] = 0xff;
+ mbr[3] = 0xff;
+ mbr[4] = 0x0;
+ mbr[5] = 0xfe;
+ mbr[6] = 0xff;
+ mbr[7] = 0xff;
+
+ tmp = lendian_int(mac_lba * 4);
+ memcpy(&mbr[8], &tmp, sizeof(tmp));
+
+ tmp = lendian_int(mac_count);
+ memcpy(&mbr[12], &tmp, sizeof(tmp));
+ }
mbr += 16;
}
mbr[0] = 0x55;
@@ -394,7 +688,6 @@ initialise_mbr(uint8_t *mbr)
return mbr - rbm;
}
-
void
display_mbr(const uint8_t *mbr, size_t len)
{
@@ -424,14 +717,179 @@ display_mbr(const uint8_t *mbr, size_t len)
}
+uint32_t chksum_crc32 (unsigned char *block, unsigned int length)
+{
+ register unsigned long crc;
+ unsigned long i;
+
+ crc = 0xFFFFFFFF;
+ for (i = 0; i < length; i++)
+ {
+ crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_tab[(crc ^ *block++) & 0xFF];
+ }
+ return (crc ^ 0xFFFFFFFF);
+}
+
+void
+reverse_uuid(uuid_t uuid)
+{
+ uint8_t t, *p = (uint8_t *)uuid;
+
+ t = p[0]; p[0] = p[3]; p[3] = t;
+ t = p[1]; p[1] = p[2]; p[2] = t;
+ t = p[4]; p[4] = p[5]; p[5] = t;
+ t = p[6]; p[6] = p[7]; p[7] = t;
+}
+
+void
+initialise_gpt(uint8_t *gpt, uint32_t current, uint32_t alternate, int primary)
+{
+ struct gpt_header *header = (struct gpt_header *)gpt;
+ struct gpt_part_header *part;
+ int hole = 0;
+ int gptsize = 128 / 4 + 2;
+
+ if (mac_lba) {
+ /* 2048 bytes per partition, plus round to 2048 boundary */
+ hole = (apm_parts * 4) + 2;
+ }
+
+ if (primary) {
+ uuid_generate(disk_uuid);
+ reverse_uuid(disk_uuid);
+ }
+
+ header->signature = lendian_64(0x5452415020494645ull);
+ header->revision = lendian_int(0x010000);
+ header->headerSize = lendian_int(0x5c);
+ header->currentLBA = lendian_64(current);
+ header->backupLBA = lendian_64(alternate);
+ header->firstUsableLBA = lendian_64(gptsize + hole);
+ header->lastUsableLBA = lendian_64((isostat.st_size + padding)/512 -
+ gptsize);
+ if (primary)
+ header->partitionEntriesLBA = lendian_64(0x02 + hole);
+ else
+ header->partitionEntriesLBA = lendian_64(current - (128 / 4));
+ header->numParts = lendian_int(0x80);
+ header->sizeOfPartitionEntries = lendian_int(0x80);
+ memcpy(header->diskGUID, disk_uuid, sizeof(uuid_t));
+
+ if (primary)
+ gpt += sizeof(struct gpt_header) + hole * 512;
+ else
+ gpt -= header->sizeOfPartitionEntries * header->numParts;
+
+ part = (struct gpt_part_header *)gpt;
+ if (primary) {
+ uuid_generate(part_uuid);
+ uuid_generate(iso_uuid);
+ reverse_uuid(part_uuid);
+ reverse_uuid(iso_uuid);
+ }
+
+ memcpy(part->partGUID, iso_uuid, sizeof(uuid_t));
+ memcpy(part->partTypeGUID, basic_partition, sizeof(uuid_t));
+ part->firstLBA = lendian_64(0);
+ part->lastLBA = lendian_64(psize);
+ memcpy(part->name, "ISOHybrid ISO", 28);
+
+ gpt += sizeof(struct gpt_part_header);
+ part++;
+
+ memcpy(part->partGUID, part_uuid, sizeof(uuid_t));
+ memcpy(part->partTypeGUID, basic_partition, sizeof(uuid_t));
+ part->firstLBA = lendian_64(efi_lba * 4);
+ part->lastLBA = lendian_64(part->firstLBA + efi_count - 1);
+ memcpy(part->name, "ISOHybrid", 20);
+
+ gpt += sizeof(struct gpt_part_header);
+
+ if (mac_lba) {
+ gpt += sizeof(struct gpt_part_header);
+
+ part++;
+
+ memcpy(part->partGUID, part_uuid, sizeof(uuid_t));
+ memcpy(part->partTypeGUID, hfs_partition, sizeof(uuid_t));
+ part->firstLBA = lendian_64(mac_lba * 4);
+ part->lastLBA = lendian_64(part->firstLBA + mac_count - 1);
+ memcpy(part->name, "ISOHybrid", 20);
+
+ part--;
+ }
+
+ part--;
+
+ header->partitionEntriesCRC = lendian_int (chksum_crc32((uint8_t *)part,
+ header->numParts * header->sizeOfPartitionEntries));
+
+ header->headerCRC = lendian_int(chksum_crc32((uint8_t *)header,
+ header->headerSize));
+}
+
+void
+initialise_apm(uint8_t *gpt, uint32_t start)
+{
+ struct apple_part_header *part = (struct apple_part_header *)gpt;
+
+ part->signature = bendian_short(0x504d);
+ part->map_count = bendian_int(apm_parts);
+ part->start_block = bendian_int(1);
+ part->block_count = bendian_int(0x10);
+ strcpy(part->name, "Apple");
+ strcpy(part->type, "Apple_partition_map");
+ part->data_start = bendian_int(0);
+ part->data_count = bendian_int(10);
+ part->status = bendian_int(0x03);
+
+ part = (struct apple_part_header *)(gpt + 2048);
+
+ part->signature = bendian_short(0x504d);
+ part->map_count = bendian_int(3);
+ part->start_block = bendian_int(efi_lba);
+ part->block_count = bendian_int(efi_count);
+ strcpy(part->name, "EFI");
+ strcpy(part->type, "Apple_HFS");
+ part->data_start = bendian_int(0);
+ part->data_count = bendian_int(efi_count);
+ part->status = bendian_int(0x33);
+
+ part = (struct apple_part_header *)(gpt + 4096);
+
+ if (mac_lba)
+ {
+ part->signature = bendian_short(0x504d);
+ part->map_count = bendian_int(3);
+ part->start_block = bendian_int(mac_lba);
+ part->block_count = bendian_int(mac_count);
+ strcpy(part->name, "EFI");
+ strcpy(part->type, "Apple_HFS");
+ part->data_start = bendian_int(0);
+ part->data_count = bendian_int(mac_count);
+ part->status = bendian_int(0x33);
+ } else {
+ part->signature = bendian_short(0x504d);
+ part->map_count = bendian_int(3);
+ part->start_block = bendian_int((start/2048) + 10);
+ part->block_count = bendian_int(efi_lba - start/2048 - 10);
+ strcpy(part->name, "ISO");
+ strcpy(part->type, "Apple_Free");
+ part->data_start = bendian_int(0);
+ part->data_count = bendian_int(efi_lba - start/2048 - 10);
+ part->status = bendian_int(0x01);
+ }
+}
+
int
main(int argc, char *argv[])
{
int i = 0;
FILE *fp = NULL;
- struct stat isostat;
uint8_t *buf = NULL, *bufz = NULL;
- int cylsize = 0, frac = 0, padding = 0;
+ int cylsize = 0, frac = 0;
+ size_t orig_gpt_size, free_space, gpt_size;
+ struct iso_primary_descriptor descriptor;
prog = strcpy(alloca(strlen(argv[0]) + 1), argv[0]);
i = check_option(argc, argv);
@@ -443,10 +901,21 @@ main(int argc, char *argv[])
usage();
return 1;
}
+
+ if ((mode & EFI) && offset)
+ errx(1, "%s: --offset is invalid with UEFI images\n", argv[0]);
+
srand(time(NULL) << (getppid() << getpid()));
if (!(fp = fopen(argv[0], "r+")))
err(1, "could not open file `%s'", argv[0]);
+
+ if (fseek(fp, (16 << 11), SEEK_SET))
+ err(1, "%s: seek error - 0", argv[0]);
+
+ if (fread(&descriptor, sizeof(char), sizeof(descriptor), fp) != sizeof(descriptor))
+ err(1, "%s: read error - 0", argv[0]);
+
if (fseek(fp, 17 * 2048, SEEK_SET))
err(1, "%s: seek error - 1", argv[0]);
@@ -478,6 +947,38 @@ main(int argc, char *argv[])
if (mode & VERBOSE)
display_catalogue();
+ buf += 32;
+
+ if (mode & EFI)
+ {
+ if (!read_efi_section(buf)) {
+ buf += 32;
+ if (!read_efi_catalogue(buf, &efi_count, &efi_lba) && efi_lba) {
+ offset = 0;
+ } else {
+ errx(1, "%s: invalid efi catalogue", argv[0]);
+ }
+ } else {
+ errx(1, "%s: unable to find efi image", argv[0]);
+ }
+ }
+
+ buf += 32;
+
+ if (mode & MAC)
+ {
+ if (!read_efi_section(buf)) {
+ buf += 32;
+ if (!read_efi_catalogue(buf, &mac_count, &mac_lba) && mac_lba) {
+ offset = 0;
+ } else {
+ errx(1, "%s: invalid efi catalogue", argv[0]);
+ }
+ } else {
+ errx(1, "%s: unable to find mac efi image", argv[0]);
+ }
+ }
+
if (fseek(fp, (de_lba * 2048 + 0x40), SEEK_SET))
err(1, "%s: seek error - 3", argv[0]);
@@ -494,6 +995,9 @@ main(int argc, char *argv[])
if (stat(argv[0], &isostat))
err(1, "%s", argv[0]);
+ isosize = lendian_int(descriptor.size) * lendian_short(descriptor.block_size);
+ free_space = isostat.st_size - isosize;
+
cylsize = head * sector * 512;
frac = isostat.st_size % cylsize;
padding = (frac > 0) ? cylsize - frac : 0;
@@ -501,7 +1005,7 @@ main(int argc, char *argv[])
if (mode & VERBOSE)
printf("imgsize: %zu, padding: %d\n", (size_t)isostat.st_size, padding);
- cc = c = (isostat.st_size + padding) / cylsize;
+ cc = c = ( isostat.st_size + padding) / cylsize;
if (c > 1024)
{
warnx("Warning: more than 1024 cylinders: %d", c);
@@ -541,6 +1045,62 @@ main(int argc, char *argv[])
if (fwrite(buf, sizeof(char), i, fp) != (size_t)i)
err(1, "%s: write error - 1", argv[0]);
+ if (efi_lba) {
+ reverse_uuid(basic_partition);
+ reverse_uuid(hfs_partition);
+
+ /* 512 byte header, 128 entries of 128 bytes */
+ orig_gpt_size = gpt_size = 512 + (128 * 128);
+
+ /* Leave space for the APM if necessary */
+ if (mac_lba)
+ gpt_size += (4 * 2048);
+
+ buf = calloc(gpt_size, sizeof(char));
+ memset(buf, 0, gpt_size);
+
+ /*
+ * We need to ensure that we have enough space for the secondary GPT.
+ * Unlike the primary, this doesn't need a hole for the APM. We still
+ * want to be 1MB aligned so just bump the padding by a megabyte.
+ */
+ if (free_space < orig_gpt_size && padding < orig_gpt_size) {
+ padding += 1024 * 1024;
+ }
+
+ /*
+ * Determine the size of the ISO filesystem. This will define the size
+ * of the partition that covers it.
+ */
+ psize = isosize / 512;
+
+ /*
+ * Primary GPT starts at sector 1, secondary GPT starts at 1 sector
+ * before the end of the image
+ */
+ initialise_gpt(buf, 1, (isostat.st_size + padding - 1024) / 512, 1);
+
+ if (fseek(fp, 512, SEEK_SET))
+ err(1, "%s: seek error - 6", argv[0]);
+
+ if (fwrite(buf, sizeof(char), gpt_size, fp) != (size_t)gpt_size)
+ err(1, "%s: write error - 2", argv[0]);
+ }
+
+ if (mac_lba)
+ {
+ /* Apple partition entries filling 2048 bytes each */
+ int apm_size = apm_parts * 2048;
+
+ buf = realloc(buf, apm_size);
+ memset(buf, 0, apm_size);
+
+ initialise_apm(buf, APM_OFFSET);
+
+ fseek(fp, APM_OFFSET, SEEK_SET);
+ fwrite(buf, sizeof(char), apm_size, fp);
+ }
+
if (padding)
{
if (fsync(fileno(fp)))
@@ -550,6 +1110,30 @@ main(int argc, char *argv[])
err(1, "%s: could not add padding bytes", argv[0]);
}
+ if (efi_lba) {
+ buf = realloc(buf, orig_gpt_size);
+ memset(buf, 0, orig_gpt_size);
+
+ buf += orig_gpt_size - sizeof(struct gpt_header);
+
+ initialise_gpt(buf, (isostat.st_size + padding - 1024) / 512, 1, 0);
+
+ /* Shift back far enough to write the 128 GPT entries */
+ buf -= 128 * sizeof(struct gpt_part_header);
+
+ /*
+ * Seek far enough back that the gpt header is 512 bytes before the
+ * end of the image
+ */
+
+ if (fseek(fp, (isostat.st_size + padding) - orig_gpt_size - 512,
+ SEEK_SET))
+ err(1, "%s: seek error - 8", argv[0]);
+
+ if (fwrite(buf, sizeof(char), orig_gpt_size, fp) != orig_gpt_size)
+ err(1, "%s: write error - 4", argv[0]);
+ }
+
free(buf);
fclose(fp);
diff --git a/utils/isohybrid.h b/utils/isohybrid.h
index 826e90c5..eecf1caa 100644
--- a/utils/isohybrid.h
+++ b/utils/isohybrid.h
@@ -20,7 +20,7 @@
*
*/
-#define VERSION "0.11"
+#define VERSION "0.12"
#define BUFSIZE 2048
#define MBRSIZE 432
diff --git a/utils/ppmtolss16 b/utils/ppmtolss16
index 5af90831..ae2d546d 100755
--- a/utils/ppmtolss16
+++ b/utils/ppmtolss16
@@ -229,7 +229,7 @@ for ( $y = 0 ; $y < $ysize ; $y++ ) {
start_new_row();
for ( $x = 0 ; $x < $xsize ; $x++ ) {
die "$0: Premature EOF at ($x,$y) of ($xsize,$ysize)\n"
- if ( !defined(@pnmrgb = getrgb($form)) );
+ if ( !scalar(@pnmrgb = getrgb($form)) );
# Convert to 6-bit representation
$rgb = rgbconvert($pnmrgb[0], $pnmrgb[1], $pnmrgb[2], $maxmult);
$color_count{$rgb}++;
diff --git a/version b/version
index 427de92d..4408eab2 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-4.04 2011
+4.06 2012
diff --git a/win/ntfssect.c b/win/ntfssect.c
new file mode 100644
index 00000000..8c2bccaa
--- /dev/null
+++ b/win/ntfssect.c
@@ -0,0 +1,355 @@
+/* -------------------------------------------------------------------------- *
+ *
+ * Copyright 2011 Shao Miller - 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., 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.
+ *
+ * ------------------------------------------------------------------------- */
+
+/****
+ * ntfssect.c
+ *
+ * Fetch NTFS file cluster & sector information via Windows
+ *
+ * With special thanks to Mark Roddy for his article:
+ * http://www.wd-3.com/archive/luserland.htm
+ */
+
+#include <windows.h>
+#include <winioctl.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "ntfssect.h"
+
+/*** Macros */
+#define M_ERR(msg) (NtfsSectLastErrorMessage = (msg))
+
+/*** Function declarations */
+static DWORD NtfsSectGetVolumeHandle(
+ CHAR * VolumeName,
+ S_NTFSSECT_VOLINFO * VolumeInfo
+ );
+static DWORD NtfsSectGetVolumePartitionLba(S_NTFSSECT_VOLINFO * VolumeInfo);
+
+/*** Objects */
+CHAR * NtfsSectLastErrorMessage;
+
+/*** Function definitions */
+DWORD M_NTFSSECT_API NtfsSectGetFileVcnExtent(
+ HANDLE File,
+ LARGE_INTEGER * Vcn,
+ S_NTFSSECT_EXTENT * Extent
+ ) {
+ BOOL bad, ok;
+ DWORD output_size, rc;
+ STARTING_VCN_INPUT_BUFFER input;
+ RETRIEVAL_POINTERS_BUFFER output;
+
+ bad = (
+ File == INVALID_HANDLE_VALUE ||
+ !Vcn ||
+ Vcn->QuadPart < 0 ||
+ !Extent
+ );
+ if (bad)
+ return ERROR_INVALID_PARAMETER;
+
+ input.StartingVcn = *Vcn;
+ ok = DeviceIoControl(
+ File,
+ FSCTL_GET_RETRIEVAL_POINTERS,
+ &input,
+ sizeof input,
+ &output,
+ sizeof output,
+ &output_size,
+ NULL
+ );
+ rc = GetLastError();
+ switch (rc) {
+ case NO_ERROR:
+ case ERROR_MORE_DATA:
+ Extent->FirstVcn = output.StartingVcn;
+ Extent->NextVcn = output.Extents[0].NextVcn;
+ Extent->FirstLcn = output.Extents[0].Lcn;
+ return ERROR_SUCCESS;
+
+ case ERROR_HANDLE_EOF:
+ break;
+
+ default:
+ M_ERR("NtfsSectGetFileVcnExtent(): Unknown status!");
+ }
+
+ return rc;
+ }
+
+/* Internal use only */
+static DWORD NtfsSectGetVolumeHandle(
+ CHAR * VolumeName,
+ S_NTFSSECT_VOLINFO * VolumeInfo
+ ) {
+ #define M_VOL_PREFIX "\\\\.\\"
+ CHAR volname[sizeof M_VOL_PREFIX - 1 + MAX_PATH + 1] = M_VOL_PREFIX;
+ CHAR * const volname_short = volname + sizeof M_VOL_PREFIX - 1;
+ CHAR * c;
+ DWORD rc;
+
+ /* Prefix "\\.\" onto the passed volume name */
+ strcpy(volname + sizeof M_VOL_PREFIX - 1, VolumeName);
+
+ /* Find the last non-null character */
+ for (c = volname_short; *c; ++c)
+ ;
+
+ /* Remove trailing back-slash */
+ if (c[-1] == '\\')
+ c[-1] = 0;
+
+ /* Open the volume */
+ VolumeInfo->Handle = CreateFile(
+ volname,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL
+ );
+ rc = GetLastError();
+ if (VolumeInfo->Handle == INVALID_HANDLE_VALUE) {
+ M_ERR("Unable to open volume handle!");
+ goto err_handle;
+ }
+
+ return ERROR_SUCCESS;
+
+ CloseHandle(VolumeInfo->Handle);
+ err_handle:
+
+ return rc;
+ }
+
+DWORD M_NTFSSECT_API NtfsSectGetVolumeInfo(
+ CHAR * VolumeName,
+ S_NTFSSECT_VOLINFO * VolumeInfo
+ ) {
+ S_NTFSSECT_XPFUNCS xp_funcs;
+ DWORD rc, free_clusts, total_clusts;
+ BOOL ok;
+
+ if (!VolumeName || !VolumeInfo)
+ return ERROR_INVALID_PARAMETER;
+
+ rc = NtfsSectGetVolumeHandle(VolumeName, VolumeInfo);
+ if (rc != ERROR_SUCCESS)
+ goto err_handle;
+
+ rc = NtfsSectLoadXpFuncs(&xp_funcs);
+ if (rc != ERROR_SUCCESS)
+ goto err_xp_funcs;
+
+ ok = xp_funcs.GetDiskFreeSpace(
+ VolumeName,
+ &VolumeInfo->SectorsPerCluster,
+ &VolumeInfo->BytesPerSector,
+ &free_clusts,
+ &total_clusts
+ );
+ rc = GetLastError();
+ if (!ok) {
+ M_ERR("GetDiskFreeSpace() failed!");
+ goto err_freespace;
+ }
+
+ rc = NtfsSectGetVolumePartitionLba(VolumeInfo);
+ if (rc != ERROR_SUCCESS)
+ goto err_lba;
+
+ VolumeInfo->Size = sizeof *VolumeInfo;
+ rc = ERROR_SUCCESS;
+
+ err_lba:
+
+ err_freespace:
+
+ NtfsSectUnloadXpFuncs(&xp_funcs);
+ err_xp_funcs:
+
+ if (rc != ERROR_SUCCESS) {
+ CloseHandle(VolumeInfo->Handle);
+ VolumeInfo->Handle = INVALID_HANDLE_VALUE;
+ }
+ err_handle:
+
+ return rc;
+ }
+
+DWORD M_NTFSSECT_API NtfsSectGetVolumeInfoFromFileName(
+ CHAR * FileName,
+ S_NTFSSECT_VOLINFO * VolumeInfo
+ ) {
+ S_NTFSSECT_XPFUNCS xp_funcs;
+ DWORD rc;
+ CHAR volname[MAX_PATH + 1];
+ BOOL ok;
+
+ if (!FileName || !VolumeInfo)
+ return ERROR_INVALID_PARAMETER;
+
+ rc = NtfsSectLoadXpFuncs(&xp_funcs);
+ if (rc != ERROR_SUCCESS) {
+ goto err_xp_funcs;
+ }
+
+ ok = xp_funcs.GetVolumePathName(
+ FileName,
+ volname,
+ sizeof volname
+ );
+ rc = GetLastError();
+ if (!ok) {
+ M_ERR("GetVolumePathName() failed!");
+ goto err_volname;
+ }
+
+ rc = NtfsSectGetVolumeInfo(volname, VolumeInfo);
+
+ err_volname:
+
+ NtfsSectUnloadXpFuncs(&xp_funcs);
+ err_xp_funcs:
+
+ return rc;
+ }
+
+/* Internal use only */
+static DWORD NtfsSectGetVolumePartitionLba(S_NTFSSECT_VOLINFO * VolumeInfo) {
+ BOOL ok;
+ VOLUME_DISK_EXTENTS vol_disk_extents;
+ DWORD output_size, rc;
+
+ ok = DeviceIoControl(
+ VolumeInfo->Handle,
+ IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
+ NULL,
+ 0,
+ &vol_disk_extents,
+ sizeof vol_disk_extents,
+ &output_size,
+ NULL
+ );
+ rc = GetLastError();
+ if (!ok) {
+ M_ERR("Couldn't fetch volume disk extent(s)!");
+ goto err_vol_disk_extents;
+ }
+
+ if (vol_disk_extents.NumberOfDiskExtents != 1) {
+ M_ERR("Unsupported number of volume disk extents!");
+ goto err_num_of_extents;
+ }
+
+ VolumeInfo->PartitionLba.QuadPart = (
+ vol_disk_extents.Extents[0].StartingOffset.QuadPart /
+ VolumeInfo->BytesPerSector
+ );
+
+ return ERROR_SUCCESS;
+
+ err_num_of_extents:
+
+ err_vol_disk_extents:
+
+ return rc;
+ }
+
+DWORD M_NTFSSECT_API NtfsSectLcnToLba(
+ const S_NTFSSECT_VOLINFO * VolumeInfo,
+ const LARGE_INTEGER * Lcn,
+ LARGE_INTEGER * Lba
+ ) {
+ BOOL bad;
+ bad = (
+ !VolumeInfo ||
+ !VolumeInfo->BytesPerSector ||
+ !VolumeInfo->SectorsPerCluster ||
+ !Lcn ||
+ Lcn->QuadPart < 0 ||
+ !Lba
+ );
+ if (bad)
+ return ERROR_INVALID_PARAMETER;
+
+ Lba->QuadPart = (
+ VolumeInfo->PartitionLba.QuadPart +
+ Lcn->QuadPart *
+ VolumeInfo->SectorsPerCluster
+ );
+ return ERROR_SUCCESS;
+ }
+
+DWORD M_NTFSSECT_API NtfsSectLoadXpFuncs(S_NTFSSECT_XPFUNCS * XpFuncs) {
+ DWORD rc;
+
+ if (!XpFuncs)
+ return ERROR_INVALID_PARAMETER;
+
+ XpFuncs->Size = sizeof *XpFuncs;
+
+ XpFuncs->Kernel32 = LoadLibrary("kernel32.dll");
+ rc = GetLastError();
+ if (!XpFuncs->Kernel32) {
+ M_ERR("KERNEL32.DLL not found!");
+ goto err;
+ }
+
+ XpFuncs->GetVolumePathName = (F_KERNEL32_GETVOLUMEPATHNAME *) (
+ GetProcAddress(
+ XpFuncs->Kernel32,
+ "GetVolumePathNameA"
+ )
+ );
+ rc = GetLastError();
+ if (!XpFuncs->GetVolumePathName) {
+ M_ERR("GetVolumePathName() not found in KERNEL32.DLL!");
+ goto err;
+ }
+
+ XpFuncs->GetDiskFreeSpace = (F_KERNEL32_GETDISKFREESPACE *) (
+ GetProcAddress(
+ XpFuncs->Kernel32,
+ "GetDiskFreeSpaceA"
+ )
+ );
+ rc = GetLastError();
+ if (!XpFuncs->GetDiskFreeSpace) {
+ M_ERR("GetDiskFreeSpace() not found in KERNEL32.DLL!");
+ goto err;
+ }
+
+ return ERROR_SUCCESS;
+
+ err:
+ NtfsSectUnloadXpFuncs(XpFuncs);
+ return rc;
+ }
+
+VOID M_NTFSSECT_API NtfsSectUnloadXpFuncs(S_NTFSSECT_XPFUNCS * XpFuncs) {
+ if (!XpFuncs)
+ return;
+
+ XpFuncs->GetDiskFreeSpace = NULL;
+ XpFuncs->GetVolumePathName = NULL;
+ if (XpFuncs->Kernel32)
+ FreeLibrary(XpFuncs->Kernel32);
+ XpFuncs->Kernel32 = NULL;
+ XpFuncs->Size = 0;
+ return;
+ }
+
diff --git a/win/ntfssect.h b/win/ntfssect.h
new file mode 100644
index 00000000..246c26da
--- /dev/null
+++ b/win/ntfssect.h
@@ -0,0 +1,152 @@
+/* -------------------------------------------------------------------------- *
+ *
+ * Copyright 2011 Shao Miller - 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., 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.
+ *
+ * ------------------------------------------------------------------------- */
+#ifndef M_NTFSSECT_H_
+
+/****
+ * ntfssect.h
+ *
+ * Fetch NTFS file cluster & sector information via Windows
+ *
+ * With special thanks to Mark Roddy for his article:
+ * http://www.wd-3.com/archive/luserland.htm
+ */
+
+/*** Macros */
+#define M_NTFSSECT_H_
+#define M_NTFSSECT_API
+
+/*** Object types */
+
+/* An "extent;" a contiguous range of file data */
+typedef struct S_NTFSSECT_EXTENT_ S_NTFSSECT_EXTENT;
+
+/* Volume info relevant to file cluster & sector info */
+typedef struct S_NTFSSECT_VOLINFO_ S_NTFSSECT_VOLINFO;
+
+/* Stores function pointers to some Windows functions */
+typedef struct S_NTFSSECT_XPFUNCS_ S_NTFSSECT_XPFUNCS;
+
+/*** Function types */
+
+/* The function type for Kernel32.dll's GetDiskFreeSpace() */
+typedef BOOL WINAPI F_KERNEL32_GETDISKFREESPACE(
+ LPCTSTR,
+ LPDWORD,
+ LPDWORD,
+ LPDWORD,
+ LPDWORD
+ );
+
+/* The function type for Kernel32.dll's GetVolumePathName() */
+typedef BOOL WINAPI F_KERNEL32_GETVOLUMEPATHNAME(LPCTSTR, LPCTSTR, DWORD);
+
+/*** Function declarations */
+
+/**
+ * Fetch the extent containing a particular VCN
+ *
+ * @v File
+ * @v Vcn
+ * @v Extent
+ * @ret DWORD
+ */
+DWORD M_NTFSSECT_API NtfsSectGetFileVcnExtent(
+ HANDLE File,
+ LARGE_INTEGER * Vcn,
+ S_NTFSSECT_EXTENT * Extent
+ );
+
+/**
+ * Populate a volume info object
+ *
+ * @v VolumeName
+ * @v VolumeInfo
+ * @ret DWORD
+ */
+DWORD M_NTFSSECT_API NtfsSectGetVolumeInfo(
+ CHAR * VolumeName,
+ S_NTFSSECT_VOLINFO * VolumeInfo
+ );
+
+/**
+ * Populate a volume info object
+ *
+ * @v FileName
+ * @v VolumeInfo
+ * @ret DWORD
+ */
+DWORD M_NTFSSECT_API NtfsSectGetVolumeInfoFromFileName(
+ CHAR * FileName,
+ S_NTFSSECT_VOLINFO * VolumeInfo
+ );
+
+/**
+ * Convert a volume LCN to an absolute disk LBA
+ *
+ * @v VolumeInfo
+ * @v Lcn
+ * @v Lba
+ * @ret DWORD
+ */
+DWORD M_NTFSSECT_API NtfsSectLcnToLba(
+ const S_NTFSSECT_VOLINFO * VolumeInfo,
+ const LARGE_INTEGER * Lcn,
+ LARGE_INTEGER * Lba
+ );
+
+/**
+ * Load some helper XP functions
+ *
+ * @v XpFuncs
+ * @ret DWORD
+ */
+DWORD M_NTFSSECT_API NtfsSectLoadXpFuncs(S_NTFSSECT_XPFUNCS * XpFuncs);
+
+/**
+ * Unload some helper XP functions
+ *
+ * @v XpFuncs
+ * @ret DWORD
+ */
+VOID M_NTFSSECT_API NtfsSectUnloadXpFuncs(S_NTFSSECT_XPFUNCS * XpFuncs);
+
+/*** Object declarations */
+
+/**
+ * The last error message set by one of our functions.
+ * Obviously not per-thread
+ */
+extern CHAR * NtfsSectLastErrorMessage;
+
+/*** Struct/union definitions */
+struct S_NTFSSECT_EXTENT_ {
+ LARGE_INTEGER FirstVcn;
+ LARGE_INTEGER NextVcn;
+ LARGE_INTEGER FirstLcn;
+ };
+
+struct S_NTFSSECT_VOLINFO_ {
+ DWORD Size;
+ HANDLE Handle;
+ DWORD BytesPerSector;
+ DWORD SectorsPerCluster;
+ LARGE_INTEGER PartitionLba;
+ };
+
+struct S_NTFSSECT_XPFUNCS_ {
+ DWORD Size;
+ HMODULE Kernel32;
+ F_KERNEL32_GETVOLUMEPATHNAME * GetVolumePathName;
+ F_KERNEL32_GETDISKFREESPACE * GetDiskFreeSpace;
+ };
+
+#endif /* M_NTFSSECT_H_ */
diff --git a/win/ntfstest.c b/win/ntfstest.c
new file mode 100644
index 00000000..1fc27182
--- /dev/null
+++ b/win/ntfstest.c
@@ -0,0 +1,163 @@
+/* -------------------------------------------------------------------------- *
+ *
+ * Copyright 2011 Shao Miller - 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., 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.
+ *
+ * ------------------------------------------------------------------------- */
+
+/****
+ * ntfstest.c
+ *
+ * (C) Shao Miller, 2011
+ *
+ * Tests ntfssect.c functions
+ *
+ * With special thanks to Mark Roddy for his article:
+ * http://www.wd-3.com/archive/luserland.htm
+ */
+#include <windows.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ntfssect.h"
+
+/*** Object types */
+
+/*** Function declarations */
+static void show_usage(void);
+static void show_last_err(void);
+static void show_err(DWORD);
+
+/*** Struct/union definitions */
+
+/*** Function definitions */
+
+/** Program entry-point */
+int main(int argc, char ** argv) {
+ int rc;
+ DWORD err;
+ S_NTFSSECT_VOLINFO vol_info;
+ HANDLE file;
+ LARGE_INTEGER vcn, lba;
+ S_NTFSSECT_EXTENT extent;
+ LONGLONG len;
+ BOOL ok;
+
+ if (argc != 2) {
+ rc = EXIT_FAILURE;
+ show_usage();
+ goto err_args;
+ }
+
+ /* Get volume info */
+ err = NtfsSectGetVolumeInfoFromFileName(argv[1], &vol_info);
+ if (err != ERROR_SUCCESS) {
+ show_err(err);
+ goto err_vol_info;
+ }
+ printf(
+ "Volume has %d bytes per sector, %d sectors per cluster\n",
+ vol_info.BytesPerSector,
+ vol_info.SectorsPerCluster
+ );
+
+ /* Open the file for reading */
+ file = CreateFile(
+ argv[1],
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL
+ );
+ if (file == INVALID_HANDLE_VALUE) {
+ rc = EXIT_FAILURE;
+ show_last_err();
+ goto err_file;
+ }
+
+ /* For each extent */
+ for (
+ vcn.QuadPart = 0;
+ NtfsSectGetFileVcnExtent(file, &vcn, &extent) == ERROR_SUCCESS;
+ vcn = extent.NextVcn
+ ) {
+ len = extent.NextVcn.QuadPart - extent.FirstVcn.QuadPart;
+ printf("Extent @ VCN #%lld,", extent.FirstVcn.QuadPart);
+ printf(" %lld clusters long:\n", len);
+ printf(" VCN #%lld -", extent.FirstVcn.QuadPart);
+ printf(" #%lld\n", extent.FirstVcn.QuadPart + len - 1);
+ printf(" LCN #%lld -", extent.FirstLcn.QuadPart);
+ printf(" #%lld\n", extent.FirstLcn.QuadPart + len - 1);
+ err = NtfsSectLcnToLba(
+ &vol_info,
+ &extent.FirstLcn,
+ &lba
+ );
+ if (err == ERROR_SUCCESS) {
+ printf(" LBA #%lld -", lba.QuadPart);
+ printf(
+ " #%lld\n",
+ lba.QuadPart + len * vol_info.SectorsPerCluster
+ );
+ }
+ continue;
+ }
+
+ rc = EXIT_SUCCESS;
+
+ CloseHandle(file);
+ err_file:
+
+ CloseHandle(vol_info.Handle);
+ err_vol_info:
+
+ err_args:
+
+ return rc;
+ }
+
+/** Display usage */
+static void show_usage(void) {
+ static const char usage_text[] = "\
+ File sector info . . . . . . . . . . . . . . . . . . . . Shao Miller, 2011\n\
+\n\
+ Usage: NTFSTEST.EXE <filename>\n\
+\n\
+ Attempts to dump cluster and sector info for <filename>.\n";
+
+ printf(usage_text);
+ return;
+ }
+
+static void show_last_err(void) {
+ show_err(GetLastError());
+ return;
+ }
+
+/** Display an error */
+static void show_err(DWORD err_code) {
+ void * buf;
+
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ err_code,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &buf,
+ 0,
+ NULL
+ );
+ fprintf(stderr, "Error: %s\n", buf);
+ LocalFree(buf);
+ return;
+ }
+
diff --git a/win/ntfstest.rc b/win/ntfstest.rc
new file mode 100644
index 00000000..462d21f1
--- /dev/null
+++ b/win/ntfstest.rc
@@ -0,0 +1,26 @@
+
+1 VERSIONINFO
+FILEVERSION 0,0,0,1
+PRODUCTVERSION 0,0,0,1
+FILEOS 0x40004
+FILETYPE 0x1
+ {
+ BLOCK "StringFileInfo"
+ {
+ BLOCK "040904B0"
+ {
+ VALUE "CompanyName", "Shao Miller"
+ VALUE "FileDescription", "NTFS File Sector Info"
+ VALUE "FileVersion", "0.0.0.1 (Aug-12-2011)"
+ VALUE "InternalName", "NTFSTest"
+ VALUE "LegalCopyright", "© 2011 Shao Miller. All rights reserved."
+ VALUE "OriginalFilename", "NTFSTEST.EXE"
+ VALUE "ProductName", "Utilities"
+ VALUE "ProductVersion", "0.0.0.1"
+ }
+ }
+ }
+
+#if 0
+1 ICON "ntfstest.ico"
+#endif
diff --git a/win/syslinux.c b/win/syslinux.c
index 0e833d8d..669450eb 100644
--- a/win/syslinux.c
+++ b/win/syslinux.c
@@ -27,6 +27,8 @@
#include "setadv.h"
#include "sysexits.h"
#include "syslxopt.h"
+#include "syslxfs.h"
+#include "ntfssect.h"
#ifdef __GNUC__
# define noreturn void __attribute__((noreturn))
@@ -48,16 +50,16 @@ void error(char *msg);
// The following struct should be in the ntddstor.h file, but I didn't have it.
// mingw32 has <ddk/ntddstor.h>, but including that file causes all kinds
// of other failures. mingw64 has it in <winioctl.h>.
-#ifndef __x86_64__
-typedef struct _STORAGE_DEVICE_NUMBER {
+// Thus, instead of STORAGE_DEVICE_NUMBER, use a lower-case private
+// definition...
+struct storage_device_number {
DEVICE_TYPE DeviceType;
ULONG DeviceNumber;
ULONG PartitionNumber;
-} STORAGE_DEVICE_NUMBER, *PSTORAGE_DEVICE_NUMBER;
-#endif
+};
BOOL GetStorageDeviceNumberByHandle(HANDLE handle,
- const STORAGE_DEVICE_NUMBER * sdn)
+ const struct storage_device_number *sdn)
{
BOOL result = FALSE;
DWORD count;
@@ -254,6 +256,7 @@ int main(int argc, char *argv[])
int ldlinux_sectors;
uint32_t ldlinux_cluster;
int nsectors;
+ int fs_type;
if (!checkver()) {
fprintf(stderr,
@@ -326,8 +329,10 @@ int main(int argc, char *argv[])
exit(1);
}
- /* Check to see that what we got was indeed an MS-DOS boot sector/superblock */
- if ((errmsg = syslinux_check_bootsect(sectbuf))) {
+ /* Check to see that what we got was indeed an FAT/NTFS
+ * boot sector/superblock
+ */
+ if ((errmsg = syslinux_check_bootsect(sectbuf, &fs_type))) {
fprintf(stderr, "%s\n", errmsg);
exit(1);
}
@@ -379,6 +384,38 @@ int main(int argc, char *argv[])
ldlinux_sectors = (syslinux_ldlinux_len + 2 * ADV_SIZE + SECTOR_SIZE - 1)
>> SECTOR_SHIFT;
sectors = calloc(ldlinux_sectors, sizeof *sectors);
+ if (fs_type == NTFS) {
+ DWORD err;
+ S_NTFSSECT_VOLINFO vol_info;
+ LARGE_INTEGER vcn, lba, len;
+ S_NTFSSECT_EXTENT extent;
+
+ err = NtfsSectGetVolumeInfo(drive_name + 4, &vol_info);
+ if (err != ERROR_SUCCESS) {
+ error("Could not fetch NTFS volume info");
+ exit(1);
+ }
+ secp = sectors;
+ nsectors = 0;
+ for (vcn.QuadPart = 0;
+ NtfsSectGetFileVcnExtent(f_handle, &vcn, &extent) == ERROR_SUCCESS;
+ vcn = extent.NextVcn) {
+ err = NtfsSectLcnToLba(&vol_info, &extent.FirstLcn, &lba);
+ if (err != ERROR_SUCCESS) {
+ error("Could not translate LDLINUX.SYS LCN to disk LBA");
+ exit(1);
+ }
+ lba.QuadPart -= vol_info.PartitionLba.QuadPart;
+ len.QuadPart = ((extent.NextVcn.QuadPart -
+ extent.FirstVcn.QuadPart) *
+ vol_info.SectorsPerCluster);
+ while (len.QuadPart-- && nsectors < ldlinux_sectors) {
+ *secp++ = lba.QuadPart++;
+ nsectors++;
+ }
+ }
+ goto map_done;
+ }
fs = libfat_open(libfat_readfile, (intptr_t) d_handle);
ldlinux_cluster = libfat_searchdir(fs, 0, "LDLINUX SYS", NULL);
secp = sectors;
@@ -390,6 +427,7 @@ int main(int argc, char *argv[])
s = libfat_nextsector(fs, s);
}
libfat_close(fs);
+map_done:
/*
* Patch ldlinux.sys and the boot sector
@@ -409,7 +447,7 @@ int main(int argc, char *argv[])
/* If desired, fix the MBR */
if (opt.install_mbr || opt.activate_partition) {
- STORAGE_DEVICE_NUMBER sdn;
+ struct storage_device_number sdn;
if (GetStorageDeviceNumberByHandle(d_handle, &sdn)) {
if (!FixMBR(sdn.DeviceNumber, sdn.PartitionNumber, opt.install_mbr, opt.activate_partition)) {
fprintf(stderr,
@@ -472,7 +510,7 @@ int main(int argc, char *argv[])
}
/* Make the syslinux boot sector */
- syslinux_make_bootsect(sectbuf);
+ syslinux_make_bootsect(sectbuf, fs_type);
/* Write the syslinux boot sector into the boot sector */
if (opt.bootsecfile) {
diff --git a/win32/Makefile b/win32/Makefile
index d4133ff8..f960998a 100644
--- a/win32/Makefile
+++ b/win32/Makefile
@@ -47,9 +47,9 @@ WINCC_IS_GOOD := $(shell $(WINCC) $(WINCFLAGS) $(WINLDFLAGS) \
.SUFFIXES: .c .obj .lib .exe .i .s .S
-SRCS = ../win/syslinux.c
+SRCS = ../win/syslinux.c ../win/ntfssect.c
OBJS = $(patsubst %.c,%.obj,$(notdir $(SRCS)))
-LIBSRC = ../libinstaller/fat.c \
+LIBSRC = ../libinstaller/fs.c \
../libinstaller/syslxmod.c \
../libinstaller/syslxopt.c \
../libinstaller/setadv.c \
diff --git a/win32/find-mingw32.sh b/win32/find-mingw32.sh
index f79949c7..51dcdd7e 100755
--- a/win32/find-mingw32.sh
+++ b/win32/find-mingw32.sh
@@ -20,7 +20,8 @@ for prefix in \
i386-mingw32msvc- \
i486-mingw32msvc- \
i586-mingw32msvc- \
- i686-mingw32msvc-; do
+ i686-mingw32msvc- \
+ i686-w64-mingw32-; do
if "${prefix}${cc}" -v > /dev/null 2>&1; then
echo "$prefix"
exit 0
diff --git a/win32/ntfstest/Makefile b/win32/ntfstest/Makefile
new file mode 100644
index 00000000..00e89cf9
--- /dev/null
+++ b/win32/ntfstest/Makefile
@@ -0,0 +1,87 @@
+## -----------------------------------------------------------------------
+##
+## Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
+## Copyright 2010 Intel Corporation; author: H. Peter Anvin
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, Inc., 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.
+##
+## -----------------------------------------------------------------------
+
+#
+# Makefile for Win32 NTFS file cluster test
+#
+# This is separated out mostly so we can have a different set of Makefile
+# variables.
+#
+
+OSTYPE = $(shell uname -msr)
+ifeq ($(findstring CYGWIN,$(OSTYPE)),CYGWIN)
+## Compiling on Cygwin
+WINPREFIX :=
+WINCFLAGS := -mno-cygwin $(GCCWARN) -Os -fomit-frame-pointer -D_FILE_OFFSET_BITS=64
+WINLDFLAGS := -mno-cygwin -Os -s
+else
+## Compiling on some variant of MinGW
+ifeq ($(findstring MINGW32,$(OSTYPE)),MINGW32)
+WINPREFIX :=
+else
+WINPREFIX := $(shell ../find-mingw32.sh gcc)
+endif
+WINCFLAGS := $(GCCWARN) -Wno-sign-compare -Os -fomit-frame-pointer \
+ -D_FILE_OFFSET_BITS=64
+WINLDFLAGS := -Os -s
+endif
+WINCFLAGS += -I. -I../../win
+
+WINCC := $(WINPREFIX)gcc
+WINAR := $(WINPREFIX)ar
+WINRANLIB := $(WINPREFIX)ranlib
+WINDRES := $(WINPREFIX)windres
+
+WINCC_IS_GOOD := $(shell $(WINCC) $(WINCFLAGS) $(WINLDFLAGS) \
+ -o hello.exe ../../win/hello.c >/dev/null 2>&1 ; echo $$?)
+
+.SUFFIXES: .c .obj .lib .exe .i .s .S .rc .res
+
+SRCS = ../../win/ntfstest.c ../../win/ntfssect.c
+RCS = ../../win/ntfstest.rc
+OBJS = $(patsubst %.c,%.obj,$(notdir $(SRCS)))
+RESS = $(patsubst %.rc,%.res,$(notdir $(RCS)))
+
+VPATH = .:../../win
+
+TARGETS = ntfstest.exe
+
+ifeq ($(WINCC_IS_GOOD),0)
+all: $(TARGETS)
+else
+all:
+ rm -f $(TARGETS)
+endif
+
+tidy dist:
+ -rm -f *.o *.obj *.lib *.i *.s *.a .*.d *.tmp *_bin.c hello.exe
+
+clean: tidy
+
+spotless: clean
+ -rm -f *~ $(TARGETS)
+
+ntfstest.exe: $(OBJS) $(RESS)
+ $(WINCC) $(WINLDFLAGS) -o $@ $^
+
+
+%.obj: %.c
+ $(WINCC) $(UMAKEDEPS) $(WINCFLAGS) -c -o $@ $<
+%.i: %.c
+ $(WINCC) $(UMAKEDEPS) $(WINCFLAGS) -E -o $@ $<
+%.s: %.c
+ $(WINCC) $(UMAKEDEPS) $(WINCFLAGS) -S -o $@ $<
+%.res: %.rc
+ $(WINDRES) -O COFF $< $@
+
+-include .*.d *.tmp
diff --git a/win64/Makefile b/win64/Makefile
index 0bc746d5..fe60793c 100644
--- a/win64/Makefile
+++ b/win64/Makefile
@@ -37,9 +37,9 @@ WINCC_IS_GOOD := $(shell $(WINCC) $(WINCFLAGS) $(WINLDFLAGS) \
.SUFFIXES: .c .obj .lib .exe .i .s .S
-SRCS = ../win/syslinux.c
+SRCS = ../win/syslinux.c ../win/ntfssect.c
OBJS = $(patsubst %.c,%.obj,$(notdir $(SRCS)))
-LIBSRC = ../libinstaller/fat.c \
+LIBSRC = ../libinstaller/fs.c \
../libinstaller/syslxmod.c \
../libinstaller/syslxopt.c \
../libinstaller/setadv.c \
diff --git a/win64/find-mingw64.sh b/win64/find-mingw64.sh
index c45db562..c2e42cd7 100755
--- a/win64/find-mingw64.sh
+++ b/win64/find-mingw64.sh
@@ -12,6 +12,8 @@ for prefix in \
x86_64-mingw64msvc- \
x86_64-mingw32- \
x86_64-mingw32msvc- \
+ x86_64-w64-mingw32- \
+ x86_64-w64-mingw32msvc- \
amd64-pc-mingw64- \
amd64-pc-mingw64msvc- \
amd64-pc-mingw32- \
@@ -20,6 +22,8 @@ for prefix in \
amd64-mingw64msvc- \
amd64-mingw32- \
amd64-mingw32msvc- \
+ amd64-w64-mingw32- \
+ amd64-w64-mingw32msvc- \
; do
if "${prefix}${cc}" -v > /dev/null 2>&1; then
echo "$prefix"
diff --git a/win64/ntfstest/Makefile b/win64/ntfstest/Makefile
new file mode 100644
index 00000000..5b975be5
--- /dev/null
+++ b/win64/ntfstest/Makefile
@@ -0,0 +1,76 @@
+## -----------------------------------------------------------------------
+##
+## Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
+## Copyright 2010 Intel Corporation; author: H. Peter Anvin
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, Inc., 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.
+##
+## -----------------------------------------------------------------------
+
+#
+# Makefile for Win64 NTFS file cluster test
+#
+# This is separated out mostly so we can have a different set of Makefile
+# variables.
+#
+
+OSTYPE = $(shell uname -msr)
+# Don't know how to do a native compile here...
+WINPREFIX := $(shell ../find-mingw64.sh gcc)
+WINCFLAGS := $(GCCWARN) -Wno-sign-compare -Os -fomit-frame-pointer \
+ -D_FILE_OFFSET_BITS=64
+WINLDFLAGS := -Os -s
+WINCFLAGS += -I. -I../../win
+
+WINCC := $(WINPREFIX)gcc
+WINAR := $(WINPREFIX)ar
+WINRANLIB := $(WINPREFIX)ranlib
+WINDRES := $(WINPREFIX)windres
+
+WINCC_IS_GOOD := $(shell $(WINCC) $(WINCFLAGS) $(WINLDFLAGS) \
+ -o hello.exe ../../win/hello.c >/dev/null 2>&1 ; echo $$?)
+
+.SUFFIXES: .c .obj .lib .exe .i .s .S .rc .res
+
+SRCS = ../../win/ntfstest.c ../../win/ntfssect.c
+RCS = ../../win/ntfstest.rc
+OBJS = $(patsubst %.c,%.obj,$(notdir $(SRCS)))
+RESS = $(patsubst %.rc,%.res,$(notdir $(RCS)))
+
+VPATH = .:../../win
+
+TARGETS = ntfstest64.exe
+
+ifeq ($(WINCC_IS_GOOD),0)
+all: $(TARGETS)
+else
+all:
+ rm -f $(TARGETS)
+endif
+
+tidy dist:
+ -rm -f *.o *.obj *.lib *.i *.s *.a .*.d *.tmp *_bin.c hello.exe
+
+clean: tidy
+
+spotless: clean
+ -rm -f *~ $(TARGETS)
+
+ntfstest64.exe: $(OBJS) $(RESS)
+ $(WINCC) $(WINLDFLAGS) -o $@ $^
+
+
+%.obj: %.c
+ $(WINCC) $(UMAKEDEPS) $(WINCFLAGS) -c -o $@ $<
+%.i: %.c
+ $(WINCC) $(UMAKEDEPS) $(WINCFLAGS) -E -o $@ $<
+%.s: %.c
+ $(WINCC) $(UMAKEDEPS) $(WINCFLAGS) -S -o $@ $<
+%.res: %.rc
+ $(WINDRES) -O COFF $< $@
+
+-include .*.d *.tmp