summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile15
-rw-r--r--Makefile.private5
-rw-r--r--NEWS11
-rw-r--r--com32/Makefile5
-rw-r--r--com32/chain/Makefile42
-rw-r--r--com32/chain/chain.c658
-rw-r--r--com32/chain/chain.h14
-rw-r--r--com32/chain/common.h9
-rw-r--r--com32/chain/mangle.c618
-rw-r--r--com32/chain/mangle.h32
-rw-r--r--com32/chain/options.c376
-rw-r--r--com32/chain/options.h47
-rw-r--r--com32/chain/partiter.c805
-rw-r--r--com32/chain/partiter.h107
-rw-r--r--com32/chain/utility.c204
-rw-r--r--com32/chain/utility.h30
-rw-r--r--com32/cmenu/Makefile14
-rw-r--r--com32/cmenu/libmenu/syslnx.c43
-rw-r--r--com32/elflink/Makefile8
-rw-r--r--com32/elflink/ldlinux/Makefile7
-rw-r--r--com32/elflink/ldlinux/adv.c6
-rw-r--r--com32/elflink/ldlinux/chainboot.c157
-rw-r--r--com32/elflink/ldlinux/cli.c103
-rw-r--r--com32/elflink/ldlinux/config.h7
-rw-r--r--com32/elflink/ldlinux/eprintf.c1
-rw-r--r--com32/elflink/ldlinux/execute.c102
-rw-r--r--com32/elflink/ldlinux/get_key.c10
-rw-r--r--com32/elflink/ldlinux/kernel.c54
-rw-r--r--com32/elflink/ldlinux/ldlinux.c235
-rw-r--r--com32/elflink/ldlinux/loadhigh.c (renamed from core/fs/loadhigh.c)2
-rw-r--r--com32/elflink/ldlinux/readconfig.c47
-rw-r--r--com32/gfxboot/gfxboot.c2
-rw-r--r--com32/gpllib/disk/geom.c11
-rw-r--r--com32/gpllib/disk/labels.c179
-rw-r--r--com32/gpllib/disk/read.c25
-rw-r--r--com32/gpllib/disk/write.c26
-rw-r--r--com32/gpllib/memory.c15
-rw-r--r--com32/hdt/.gitignore1
-rw-r--r--com32/hdt/Makefile13
-rw-r--r--com32/hdt/floppy/hdt.cfg9
-rw-r--r--com32/hdt/hdt-cli-acpi.c2
-rw-r--r--com32/hdt/hdt-cli-disk.c3
-rw-r--r--com32/hdt/hdt-cli-dmi.c15
-rw-r--r--com32/hdt/hdt-cli-hdt.c87
-rw-r--r--com32/hdt/hdt-cli-memory.c5
-rw-r--r--com32/hdt/hdt-cli-pci.c3
-rw-r--r--com32/hdt/hdt-cli-vesa.c5
-rw-r--r--com32/hdt/hdt-cli.c47
-rw-r--r--com32/hdt/hdt-cli.h2
-rw-r--r--com32/hdt/hdt-common.c47
-rw-r--r--com32/hdt/hdt-common.h5
-rw-r--r--com32/hdt/hdt-dump-disks.c12
-rw-r--r--com32/hdt/hdt-dump.c192
-rw-r--r--com32/hdt/hdt-menu-summary.c3
-rw-r--r--com32/hdt/hdt.c15
-rw-r--r--com32/hdt/hdt.h4
-rw-r--r--com32/include/bitsize/stddef.h14
-rw-r--r--com32/include/bitsize/stdint.h71
-rw-r--r--com32/include/bitsize/stdintconst.h2
-rw-r--r--com32/include/bitsize/stdintlimits.h2
-rw-r--r--com32/include/bitsize32/limits.h4
-rw-r--r--com32/include/bitsize32/stddef.h6
-rw-r--r--com32/include/bitsize32/stdint.h17
-rw-r--r--com32/include/bitsize64/limits.h4
-rw-r--r--com32/include/bitsize64/stddef.h2
-rw-r--r--com32/include/bitsize64/stdint.h17
-rw-r--r--com32/include/com32.h14
-rw-r--r--com32/include/dhcp.h40
-rw-r--r--com32/include/dprintf.h24
-rw-r--r--com32/include/hw/vga.h104
-rw-r--r--com32/include/klibc/compiler.h7
-rw-r--r--com32/include/linux/list.h13
-rw-r--r--com32/include/menu.h9
-rw-r--r--com32/include/stdint.h192
-rw-r--r--com32/include/string.h1
-rw-r--r--com32/include/sys/exec.h23
-rw-r--r--com32/include/sys/i386/module.h360
-rw-r--r--com32/include/sys/module.h345
-rw-r--r--com32/include/sys/x86_64/module.h360
-rw-r--r--com32/include/syslinux/boot.h12
-rw-r--r--com32/include/syslinux/config.h9
-rw-r--r--com32/include/syslinux/disk.h180
-rw-r--r--com32/include/syslinux/features.h10
-rw-r--r--com32/include/syslinux/firmware.h12
-rw-r--r--com32/include/syslinux/linux.h29
-rw-r--r--com32/include/syslinux/movebits.h9
-rw-r--r--com32/include/syslinux/pxe_api.h4
-rw-r--r--com32/lib/Makefile23
-rw-r--r--com32/lib/com32.ld33
-rw-r--r--com32/lib/dhcppack.c166
-rw-r--r--com32/lib/dhcpunpack.c116
-rw-r--r--com32/lib/dprintf.c8
-rw-r--r--com32/lib/elf32.ld10
-rw-r--r--com32/lib/getcwd.c1
-rw-r--r--com32/lib/lmalloc.c9
-rw-r--r--com32/lib/lstrdup.c2
-rw-r--r--com32/lib/pci/scan.c13
-rw-r--r--com32/lib/strreplace.c (renamed from com32/lib/syslinux/features.c)45
-rw-r--r--com32/lib/sys/ansicon_write.c115
-rw-r--r--com32/lib/sys/fileclose.c1
-rw-r--r--com32/lib/sys/fileread.c1
-rw-r--r--com32/lib/sys/gpxe.c19
-rw-r--r--com32/lib/sys/module/common.c115
-rw-r--r--com32/lib/sys/module/common.h14
-rw-r--r--com32/lib/sys/module/elf_module.c169
-rw-r--r--com32/lib/sys/module/elfutils.c4
-rw-r--r--com32/lib/sys/module/elfutils.h72
-rw-r--r--com32/lib/sys/module/exec.c87
-rw-r--r--com32/lib/sys/module/i386/common.c571
-rw-r--r--com32/lib/sys/module/i386/elf_module.c176
-rw-r--r--com32/lib/sys/module/i386/elfutils.h64
-rw-r--r--com32/lib/sys/module/shallow_module.c8
-rw-r--r--com32/lib/sys/module/x86_64/common.c567
-rw-r--r--com32/lib/sys/module/x86_64/elf_module.c190
-rw-r--r--com32/lib/sys/open.c1
-rw-r--r--com32/lib/sys/rawcon_read.c35
-rw-r--r--com32/lib/sys/rawcon_write.c8
-rw-r--r--com32/lib/sys/serial_write.c8
-rw-r--r--com32/lib/sys/stdcon_write.c15
-rw-r--r--com32/lib/sys/xserial_write.c8
-rw-r--r--com32/lib/syslinux/cleanup.c12
-rw-r--r--com32/lib/syslinux/disk.c569
-rw-r--r--com32/lib/syslinux/dump_mmap.c12
-rw-r--r--com32/lib/syslinux/dump_movelist.c9
-rw-r--r--com32/lib/syslinux/idle.c1
-rw-r--r--com32/lib/syslinux/ipappend.c (renamed from com32/elflink/ldlinux/ipappend.c)18
-rw-r--r--com32/lib/syslinux/keyboard.c14
-rw-r--r--com32/lib/syslinux/load_linux.c97
-rw-r--r--com32/lib/syslinux/localboot.c10
-rw-r--r--com32/lib/syslinux/movebits.c42
-rw-r--r--com32/lib/syslinux/pxe_dns.c14
-rw-r--r--com32/lib/syslinux/pxe_get_cached.c11
-rw-r--r--com32/lib/syslinux/pxe_get_nic.c12
-rw-r--r--com32/lib/syslinux/run_command.c9
-rw-r--r--com32/lib/syslinux/run_default.c10
-rw-r--r--com32/lib/syslinux/runimage.c19
-rw-r--r--com32/lib/syslinux/serial.c25
-rw-r--r--com32/lib/syslinux/setup_data.c47
-rw-r--r--com32/lib/syslinux/shuffle.c27
-rw-r--r--com32/lib/syslinux/version.c21
-rw-r--r--com32/lib/syslinux/video/fontquery.c16
-rw-r--r--com32/lib/syslinux/video/reportmode.c11
-rw-r--r--com32/lib/syslinux/zonelist.c24
-rw-r--r--com32/lib/vdprintf.c17
-rw-r--r--com32/libupload/cpio.c2
-rw-r--r--com32/libupload/upload_tftp.c18
-rw-r--r--com32/libutil/Makefile2
-rw-r--r--com32/lua/src/Makefile1
-rw-r--r--com32/lua/src/dhcp.c358
-rw-r--r--com32/lua/src/dhcp.h (renamed from com32/lib/syslinux/config.c)34
-rw-r--r--com32/lua/src/linit.c1
-rw-r--r--com32/lua/src/lualib.h3
-rw-r--r--com32/lua/src/syslinux.c4
-rw-r--r--com32/lua/src/vesa.c31
-rw-r--r--com32/mboot/initvesa.c43
-rw-r--r--com32/mboot/map.c5
-rw-r--r--com32/mboot/mem.c35
-rw-r--r--com32/menu/Makefile6
-rw-r--r--com32/menu/execute.c69
-rw-r--r--com32/menu/menumain.c22
-rw-r--r--com32/menu/readconfig.c6
-rw-r--r--com32/modules/Makefile21
-rw-r--r--com32/modules/chain.c1868
-rw-r--r--com32/modules/elf.c16
-rw-r--r--com32/modules/ethersel.c7
-rw-r--r--com32/modules/gpxecmd.c16
-rw-r--r--com32/modules/hello.c2
-rw-r--r--com32/modules/host.c46
-rw-r--r--com32/modules/ifcpu.c25
-rw-r--r--com32/modules/ifmemdsk.c392
-rw-r--r--com32/modules/linux.c95
-rw-r--r--com32/modules/meminfo.c10
-rw-r--r--com32/modules/pcitest.c7
-rw-r--r--com32/modules/pmload.c16
-rw-r--r--com32/modules/pxechn.c1106
-rw-r--r--com32/modules/sanboot.c16
-rw-r--r--com32/modules/vesainfo.c4
-rw-r--r--com32/rosh/Makefile2
-rw-r--r--com32/samples/Makefile3
-rw-r--r--com32/samples/resolv.c17
-rw-r--r--com32/tools/Makefile2
-rw-r--r--com32/tools/include/tools/le_byteshift.h70
-rw-r--r--com32/tools/relocs.c305
-rw-r--r--core/Makefile6
-rw-r--r--core/bios.c217
-rw-r--r--core/comboot.inc15
-rw-r--r--core/conio.c28
-rw-r--r--core/console.c7
-rw-r--r--core/diskboot.inc1
-rw-r--r--core/diskfs.inc57
-rw-r--r--core/elflink/load_env32.c86
-rw-r--r--core/extern.inc4
-rw-r--r--core/font.c90
-rw-r--r--core/fs/btrfs/btrfs.c5
-rw-r--r--core/fs/cache.c4
-rw-r--r--core/fs/chdir.c110
-rw-r--r--core/fs/fat/fat.c64
-rw-r--r--core/fs/fs.c16
-rw-r--r--core/fs/iso9660/iso9660.c2
-rw-r--r--core/fs/lib/chdir.c1
-rw-r--r--core/fs/lib/loadconfig.c2
-rw-r--r--core/fs/lib/searchconfig.c20
-rw-r--r--core/fs/ntfs/ntfs.c1388
-rw-r--r--core/fs/ntfs/ntfs.h485
-rw-r--r--core/fs/ntfs/runlist.h83
-rw-r--r--core/fs/pxe/dhcp_option.c6
-rw-r--r--core/fs/pxe/dnsresolv.c6
-rw-r--r--core/fs/pxe/pxe.c40
-rw-r--r--core/fs/pxe/pxe.h4
-rw-r--r--core/graphics.c92
-rw-r--r--core/hello.c8
-rw-r--r--core/include/bios.h28
-rw-r--r--core/include/core.h34
-rw-r--r--core/include/fs.h10
-rw-r--r--core/include/graphics.h (renamed from core/elflink/config.c)46
-rw-r--r--core/include/localboot.h (renamed from com32/lib/syslinux/video/forcetext.c)19
-rw-r--r--core/init.c81
-rw-r--r--core/init.inc7
-rw-r--r--core/isolinux.asm60
-rw-r--r--core/kaboom.c12
-rw-r--r--core/layout.inc17
-rw-r--r--core/ldlinux.asm2
-rw-r--r--core/localboot.c10
-rw-r--r--core/mem/init.c2
-rw-r--r--core/mem/malloc.c7
-rw-r--r--core/plaincon.c12
-rw-r--r--core/pxelinux.asm174
-rw-r--r--core/rawcon.c4
-rw-r--r--core/serirq.c10
-rw-r--r--core/syslinux.ld39
-rw-r--r--core/ui.inc763
-rw-r--r--core/writestr.c1
-rw-r--r--diag/geodsp/Makefile29
-rwxr-xr-xdiag/geodsp/mk-lba-img.pl94
-rw-r--r--diag/mbr/README4
-rw-r--r--diag/mbr/handoff.S4
-rw-r--r--doc/chain.txt327
-rw-r--r--doc/gpt.txt2
-rw-r--r--doc/logo/LICENSE5
-rw-r--r--doc/logo/syslinux-100.pngbin0 -> 131308 bytes
-rw-r--r--doc/pxechn.txt94
-rw-r--r--dos/Makefile2
-rw-r--r--dos/syslinux.c5
-rw-r--r--dosutil/Makefile2
-rw-r--r--efi/Makefile2
-rw-r--r--efi/diskio.c2
-rw-r--r--efi/main.c30
-rw-r--r--extlinux/Makefile8
-rw-r--r--extlinux/btrfs.h179
-rw-r--r--[-rwxr-xr-x]extlinux/main.c609
-rw-r--r--extlinux/mountinfo.c277
-rw-r--r--extlinux/mountinfo.h35
-rw-r--r--extlinux/ntfs.h19
-rw-r--r--libinstaller/Makefile2
-rw-r--r--libinstaller/ext2fs/ext2_fs.h856
-rw-r--r--libinstaller/fs.c (renamed from libinstaller/fat.c)120
-rw-r--r--libinstaller/linuxioctl.h26
-rw-r--r--libinstaller/setadv.c1
-rw-r--r--libinstaller/syslinux.h4
-rw-r--r--libinstaller/syslxcom.c18
-rw-r--r--libinstaller/syslxcom.h9
-rw-r--r--libinstaller/syslxfs.h26
-rw-r--r--libinstaller/syslxint.h77
-rw-r--r--libinstaller/syslxmod.c2
-rw-r--r--libinstaller/syslxopt.c10
-rw-r--r--libinstaller/syslxopt.h1
-rw-r--r--linux/Makefile9
-rwxr-xr-xlinux/syslinux.c24
-rw-r--r--man/extlinux.111
-rw-r--r--mbr/altmbr.S2
-rw-r--r--mbr/isohdpfx.S31
-rw-r--r--memdisk/Makefile2
-rw-r--r--mk/com32.mk3
-rw-r--r--mk/devel.mk1
-rw-r--r--mk/elf.mk11
-rw-r--r--mk/lib.mk79
-rw-r--r--mk/syslinux.mk6
-rwxr-xr-xmtools/Makefile7
-rwxr-xr-xmtools/syslinux.c5
-rw-r--r--utils/Makefile18
-rw-r--r--utils/isohybrid.c612
-rw-r--r--utils/isohybrid.h2
-rw-r--r--version2
-rw-r--r--win/ntfssect.c355
-rw-r--r--win/ntfssect.h152
-rw-r--r--win/ntfstest.c163
-rw-r--r--win/ntfstest.rc26
-rw-r--r--win/syslinux.c56
-rw-r--r--win32/Makefile4
-rwxr-xr-xwin32/find-mingw32.sh3
-rw-r--r--win32/ntfstest/Makefile87
-rw-r--r--win64/Makefile4
-rwxr-xr-xwin64/find-mingw64.sh4
-rw-r--r--win64/ntfstest/Makefile76
294 files changed, 16305 insertions, 7321 deletions
diff --git a/Makefile b/Makefile
index 45d0b193..e0294280 100644
--- a/Makefile
+++ b/Makefile
@@ -35,14 +35,18 @@ ifndef EFI_BUILD
MODULES = memdisk/memdisk memdump/memdump.com modules/*.com \
com32/menu/*.c32 com32/modules/*.c32 com32/mboot/*.c32 \
com32/hdt/*.c32 com32/rosh/*.c32 com32/gfxboot/*.c32 \
- com32/sysdump/*.c32 com32/lua/src/*.c32
+ com32/sysdump/*.c32 com32/lua/src/*.c32 com32/chain/*.c32 \
+ com32/lib/*.c32 com32/libutil/*.c32 com32/gpllib/*.c32 \
+ com32/elflink/ldlinux/*.c32
else
# memdump is BIOS specific code exclude it for EFI
# FIXME: Prune other BIOS-centric modules
MODULES = memdisk/memdisk modules/*.com \
com32/menu/*.c32 com32/modules/*.c32 com32/mboot/*.c32 \
com32/hdt/*.c32 com32/rosh/*.c32 com32/gfxboot/*.c32 \
- com32/sysdump/*.c32 com32/lua/src/*.c32
+ com32/sysdump/*.c32 com32/lua/src/*.c32 com32/chain/*.c32 \
+ com32/lib/*.c32 com32/libutil/*.c32 com32/gpllib/*.c32 \
+ com32/elflink/ldlinux/*.c32
endif
# syslinux.exe is BTARGET so as to not require everyone to have the
@@ -114,6 +118,13 @@ installer:
installer-local: $(ITARGET) $(BINFILES)
+strip:
+ $(MAKE) strip-local
+ set -e ; for i in $(ISUBDIRS); do $(MAKE) -C $$i strip ; done
+ -ls -l $(BOBJECTS) $(IOBJECTS)
+
+strip-local:
+
version.gen: version version.pl
$(PERL) version.pl $< $@ '%define < @'
version.h: version version.pl
diff --git a/Makefile.private b/Makefile.private
index 6ca0598f..92127e98 100644
--- a/Makefile.private
+++ b/Makefile.private
@@ -38,6 +38,7 @@ burn: isolinux.iso
official:
$(MAKE) spotless CC='$(CC) -m32'
$(MAKE) all CC='$(CC) -m32'
+ $(MAKE) strip CC='$(CC) -m32'
$(MAKE) dist CC='$(CC) -m32'
release:
@@ -99,7 +100,3 @@ LATEST_PREREL := syslinux-$(VERSION)-pre$(LATEST_PRERELNO)
unprerel:
echo $(LATEST_PRERELNO) > $(PRERELDIR)/.prerel
@echo Next release will be $(LATEST_PREREL)
-
-preupload:
- scp $(PRERELDIR)/$(LATEST_PREREL).* $(UPLOAD)/Testing
- git push --tags
diff --git a/NEWS b/NEWS
index 443e1a51..863b8676 100644
--- a/NEWS
+++ b/NEWS
@@ -2,12 +2,23 @@ Starting with 1.47, changes marked with SYSLINUX, PXELINUX, ISOLINUX
or EXTLINUX apply to that specific program only; other changes apply
to all derivatives.
+Changes in 4.06:
+ * Support for NTFS, by Paulo Alcantara.
+ * EXTLINUX: more robust device detection, allow user to override.
+
Changes in 4.05:
* HDT updated, and now supports uploading data to a TFTP
server.
* ISOLINUX: remove the .img file support; it has been broken
on virtually all systems since the beginning, and has been
totally broken since 4.00 at least. Use MEMDISK instead.
+ * chain.c32: Support chaining ReactOS' FreeLdr (Shao Miller)
+ * isohybrid: -m option to add support for Mac EFI booting.
+ * ifmemdsk.c32: Choose boot option based on presence of
+ MEMDISK.
+ * Remove bogus distributed mk-lba-img binary.
+ * The Syslinux project has a new, cool logo by Abi
+ "ixxvil" Rasheed (doc/logo/*).
Changes in 4.04:
* PXELINUX: Fix handling of unqualified DNS names.
diff --git a/com32/Makefile b/com32/Makefile
index debfe473..c4699cfd 100644
--- a/com32/Makefile
+++ b/com32/Makefile
@@ -1,4 +1,5 @@
-SUBDIRS = elflink/ldlinux libupload tools lib gpllib libutil modules mboot menu samples \
- elflink rosh cmenu hdt gfxboot sysdump lua/src
+SUBDIRS = libupload tools lib elflink/ldlinux gpllib libutil modules mboot \
+ menu samples elflink rosh cmenu hdt gfxboot sysdump lua/src chain
+
all tidy dist clean spotless install:
set -e; for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done
diff --git a/com32/chain/Makefile b/com32/chain/Makefile
new file mode 100644
index 00000000..9a298fae
--- /dev/null
+++ b/com32/chain/Makefile
@@ -0,0 +1,42 @@
+## -----------------------------------------------------------------------
+##
+## Copyright 2001-2010 H. Peter Anvin - All Rights Reserved
+## Copyright 2010 Michal Soltys
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+## Boston MA 02111-1307, USA; either version 2 of the License, or
+## (at your option) any later version; incorporated herein by reference.
+##
+## -----------------------------------------------------------------------
+
+
+topdir = ../..
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/elf.mk
+
+OBJS = chain.o partiter.o utility.o options.o mangle.o
+
+all: chain.c32
+
+chain.c32: $(OBJS) $(C_LIBS)
+ $(LD) $(LDFLAGS) -o $@ $^
+
+%.o: %.c
+ $(CC) $(MAKEDEPS) $(CFLAGS) $(CHAINEXTOPT) -c -o $@ $<
+
+tidy dist:
+ rm -f *.o *.lo *.a *.lst *.elf .*.d *.tmp
+
+clean: tidy
+ rm -f *.lnx
+
+spotless: clean
+ rm -f *.lss *.c32 *.com
+ rm -f *~ \#*
+
+install:
+
+
+-include .*.d
diff --git a/com32/chain/chain.c b/com32/chain/chain.c
new file mode 100644
index 00000000..30153c4d
--- /dev/null
+++ b/com32/chain/chain.c
@@ -0,0 +1,658 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ * Copyright 2010 Shao Miller
+ * Copyright 2010 Michal Soltys
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Please see doc/chain.txt for the detailed documentation.
+ */
+
+#include <com32.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <console.h>
+#include <consoles.h>
+#include <minmax.h>
+#include <stdbool.h>
+#include <dprintf.h>
+#include <errno.h>
+#include <unistd.h>
+#include <syslinux/loadfile.h>
+#include <syslinux/bootrm.h>
+#include <syslinux/config.h>
+#include <syslinux/disk.h>
+#include <syslinux/video.h>
+#include "common.h"
+#include "chain.h"
+#include "utility.h"
+#include "options.h"
+#include "partiter.h"
+#include "mangle.h"
+
+static int fixed_cnt = 128; /* see comments in main() */
+
+static int overlap(const struct data_area *a, const struct data_area *b)
+{
+ return
+ a->base + a->size > b->base &&
+ b->base + b->size > a->base;
+}
+
+static int is_phys(uint8_t sdifs)
+{
+ return
+ sdifs == SYSLINUX_FS_SYSLINUX ||
+ sdifs == SYSLINUX_FS_EXTLINUX ||
+ sdifs == SYSLINUX_FS_ISOLINUX;
+}
+
+/*
+ * Search for a specific drive, based on the MBR signature.
+ * Return drive and iterator at 0th position.
+ */
+static int find_by_sig(uint32_t mbr_sig,
+ struct part_iter **_boot_part)
+{
+ struct part_iter *boot_part = NULL;
+ struct disk_info diskinfo;
+ int drive;
+
+ for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) {
+ if (disk_get_params(drive, &diskinfo))
+ continue; /* Drive doesn't exist */
+ if (!(boot_part = pi_begin(&diskinfo, 0)))
+ continue;
+ /* Check for a MBR disk */
+ if (boot_part->type != typedos) {
+ pi_del(&boot_part);
+ continue;
+ }
+ if (boot_part->sub.dos.disk_sig == mbr_sig) {
+ goto ok;
+ }
+ }
+ drive = -1;
+ok:
+ *_boot_part = boot_part;
+ return drive;
+}
+
+/*
+ * Search for a specific drive/partition, based on the GPT GUID.
+ * Return drive and iterator at proper position.
+ */
+static int find_by_guid(const struct guid *gpt_guid,
+ struct part_iter **_boot_part)
+{
+ struct part_iter *boot_part = NULL;
+ struct disk_info diskinfo;
+ int drive;
+
+ for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) {
+ if (disk_get_params(drive, &diskinfo))
+ continue; /* Drive doesn't exist */
+ if (!(boot_part = pi_begin(&diskinfo, 0)))
+ continue;
+ /* Check for a GPT disk */
+ if (boot_part->type != typegpt) {
+ pi_del(&boot_part);
+ continue;
+ }
+ /* Check for a matching GPT disk guid */
+ if (!memcmp(&boot_part->sub.gpt.disk_guid, gpt_guid, sizeof(*gpt_guid))) {
+ goto ok;
+ }
+ /* disk guid doesn't match, maybe partition guid will */
+ while (!pi_next(&boot_part)) {
+ if (!memcmp(&boot_part->sub.gpt.part_guid, gpt_guid, sizeof(*gpt_guid)))
+ goto ok;
+ }
+ }
+ drive = -1;
+ok:
+ *_boot_part = boot_part;
+ return drive;
+}
+
+/*
+ * Search for a specific drive/partition, based on the GPT label.
+ * Return drive and iterator at proper position.
+ */
+static int find_by_label(const char *label, struct part_iter **_boot_part)
+{
+ struct part_iter *boot_part = NULL;
+ struct disk_info diskinfo;
+ int drive;
+
+ for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) {
+ if (disk_get_params(drive, &diskinfo))
+ continue; /* Drive doesn't exist */
+ if (!(boot_part = pi_begin(&diskinfo, 0)))
+ continue;
+ /* Check for a GPT disk */
+ if (!(boot_part->type == typegpt)) {
+ pi_del(&boot_part);
+ continue;
+ }
+ /* Check for a matching partition */
+ while (!pi_next(&boot_part)) {
+ if (!strcmp(label, boot_part->sub.gpt.part_label))
+ goto ok;
+ }
+ }
+ drive = -1;
+ok:
+ *_boot_part = boot_part;
+ return drive;
+}
+
+static void do_boot(struct data_area *data, int ndata)
+{
+ uint16_t *const bios_fbm = (uint16_t *) 0x413;
+ addr_t dosmem = (addr_t)(*bios_fbm << 10); /* Technically a low bound */
+ struct syslinux_memmap *mmap;
+ struct syslinux_movelist *mlist = NULL;
+ addr_t endimage;
+ uint8_t driveno = opt.regs.edx.b[0];
+ uint8_t swapdrive = driveno & 0x80;
+ int i;
+
+ mmap = syslinux_memory_map();
+
+ if (!mmap) {
+ error("Cannot read system memory map\n");
+ return;
+ }
+
+ endimage = 0;
+ for (i = 0; i < ndata; i++) {
+ if (data[i].base + data[i].size > endimage)
+ endimage = data[i].base + data[i].size;
+ }
+ if (endimage > dosmem)
+ goto too_big;
+
+ for (i = 0; i < ndata; i++) {
+ if (syslinux_add_movelist(&mlist, data[i].base,
+ (addr_t) data[i].data, data[i].size))
+ goto enomem;
+ }
+
+ if (opt.swap && driveno != swapdrive) {
+ static const uint8_t swapstub_master[] = {
+ /* The actual swap code */
+ 0x53, /* 00: push bx */
+ 0x0f, 0xb6, 0xda, /* 01: movzx bx,dl */
+ 0x2e, 0x8a, 0x57, 0x60, /* 04: mov dl,[cs:bx+0x60] */
+ 0x5b, /* 08: pop bx */
+ 0xea, 0, 0, 0, 0, /* 09: jmp far 0:0 */
+ 0x90, 0x90, /* 0E: nop; nop */
+ /* Code to install this in the right location */
+ /* Entry with DS = CS; ES = SI = 0; CX = 256 */
+ 0x26, 0x66, 0x8b, 0x7c, 0x4c, /* 10: mov edi,[es:si+4*0x13] */
+ 0x66, 0x89, 0x3e, 0x0a, 0x00, /* 15: mov [0x0A],edi */
+ 0x26, 0x8b, 0x3e, 0x13, 0x04, /* 1A: mov di,[es:0x413] */
+ 0x4f, /* 1F: dec di */
+ 0x26, 0x89, 0x3e, 0x13, 0x04, /* 20: mov [es:0x413],di */
+ 0x66, 0xc1, 0xe7, 0x16, /* 25: shl edi,16+6 */
+ 0x26, 0x66, 0x89, 0x7c, 0x4c, /* 29: mov [es:si+4*0x13],edi */
+ 0x66, 0xc1, 0xef, 0x10, /* 2E: shr edi,16 */
+ 0x8e, 0xc7, /* 32: mov es,di */
+ 0x31, 0xff, /* 34: xor di,di */
+ 0xf3, 0x66, 0xa5, /* 36: rep movsd */
+ 0xbe, 0, 0, /* 39: mov si,0 */
+ 0xbf, 0, 0, /* 3C: mov di,0 */
+ 0x8e, 0xde, /* 3F: mov ds,si */
+ 0x8e, 0xc7, /* 41: mov es,di */
+ 0x66, 0xb9, 0, 0, 0, 0, /* 43: mov ecx,0 */
+ 0x66, 0xbe, 0, 0, 0, 0, /* 49: mov esi,0 */
+ 0x66, 0xbf, 0, 0, 0, 0, /* 4F: mov edi,0 */
+ 0xea, 0, 0, 0, 0, /* 55: jmp 0:0 */
+ /* pad out to segment boundary */
+ 0x90, 0x90, /* 5A: ... */
+ 0x90, 0x90, 0x90, 0x90, /* 5C: ... */
+ };
+ static uint8_t swapstub[1024];
+ uint8_t *p;
+
+ /* Note: we can't rely on either INT 13h nor the dosmem
+ vector to be correct at this stage, so we have to use an
+ installer stub to put things in the right place.
+ Round the installer location to a 1K boundary so the only
+ possible overlap is the identity mapping. */
+ endimage = (endimage + 1023u) & ~1023u;
+
+ /* Create swap stub */
+ memcpy(swapstub, swapstub_master, sizeof swapstub_master);
+ *(uint16_t *) & swapstub[0x3a] = opt.regs.ds;
+ *(uint16_t *) & swapstub[0x3d] = opt.regs.es;
+ *(uint32_t *) & swapstub[0x45] = opt.regs.ecx.l;
+ *(uint32_t *) & swapstub[0x4b] = opt.regs.esi.l;
+ *(uint32_t *) & swapstub[0x51] = opt.regs.edi.l;
+ *(uint16_t *) & swapstub[0x56] = opt.regs.ip;
+ *(uint16_t *) & swapstub[0x58] = opt.regs.cs;
+ p = &swapstub[sizeof swapstub_master];
+
+ /* Mapping table; start out with identity mapping everything */
+ for (i = 0; i < 256; i++)
+ p[i] = (uint8_t)i;
+
+ /* And the actual swap */
+ p[driveno] = swapdrive;
+ p[swapdrive] = driveno;
+
+ /* Adjust registers */
+ opt.regs.ds = opt.regs.cs = (uint16_t)(endimage >> 4);
+ opt.regs.esi.l = opt.regs.es = 0;
+ opt.regs.ecx.l = sizeof swapstub >> 2;
+ opt.regs.ip = 0x10; /* Installer offset */
+ opt.regs.ebx.b[0] = opt.regs.edx.b[0] = swapdrive;
+
+ if (syslinux_add_movelist(&mlist, endimage, (addr_t) swapstub,
+ sizeof swapstub))
+ goto enomem;
+
+ endimage += sizeof swapstub;
+ }
+
+ /* Tell the shuffler not to muck with this area... */
+ syslinux_add_memmap(&mmap, endimage, 0xa0000 - endimage, SMT_RESERVED);
+
+ /* Force text mode */
+ syslinux_force_text_mode();
+
+ fputs("Booting...\n", stdout);
+ syslinux_shuffle_boot_rm(mlist, mmap, opt.keeppxe, &opt.regs);
+ error("Chainboot failed!\n");
+ return;
+
+too_big:
+ error("Loader file too large\n");
+ return;
+
+enomem:
+ error("Out of memory\n");
+ return;
+}
+
+int find_dp(struct part_iter **_iter)
+{
+ struct part_iter *iter = NULL;
+ struct disk_info diskinfo;
+ struct guid gpt_guid;
+ uint64_t fs_lba;
+ int drive, hd, partition;
+ const union syslinux_derivative_info *sdi;
+
+ sdi = syslinux_derivative_info();
+
+ if (!strncmp(opt.drivename, "mbr", 3)) {
+ if (find_by_sig(strtoul(opt.drivename + 4, NULL, 0), &iter) < 0) {
+ error("Unable to find requested MBR signature.\n");
+ goto bail;
+ }
+ } else if (!strncmp(opt.drivename, "guid", 4)) {
+ if (str_to_guid(opt.drivename + 5, &gpt_guid))
+ goto bail;
+ if (find_by_guid(&gpt_guid, &iter) < 0) {
+ error("Unable to find requested GPT disk or partition by guid.\n");
+ goto bail;
+ }
+ } else if (!strncmp(opt.drivename, "label", 5)) {
+ if (!opt.drivename[6]) {
+ error("No label specified.\n");
+ goto bail;
+ }
+ if (find_by_label(opt.drivename + 6, &iter) < 0) {
+ error("Unable to find requested GPT partition by label.\n");
+ goto bail;
+ }
+ } else if ((opt.drivename[0] == 'h' || opt.drivename[0] == 'f') &&
+ opt.drivename[1] == 'd') {
+ hd = opt.drivename[0] == 'h' ? 0x80 : 0;
+ opt.drivename += 2;
+ drive = hd | strtol(opt.drivename, NULL, 0);
+
+ if (disk_get_params(drive, &diskinfo))
+ goto bail;
+ /* this will start iteration over FDD, possibly raw */
+ if (!(iter = pi_begin(&diskinfo, 0)))
+ goto bail;
+
+ } else if (!strcmp(opt.drivename, "boot") || !strcmp(opt.drivename, "fs")) {
+ if (!is_phys(sdi->c.filesystem)) {
+ error("When syslinux is not booted from physical disk (or its emulation),\n"
+ "'boot' and 'fs' are meaningless.\n");
+ goto bail;
+ }
+ /* offsets match, but in case it changes in the future */
+ if (sdi->c.filesystem == SYSLINUX_FS_ISOLINUX) {
+ drive = sdi->iso.drive_number;
+ fs_lba = *sdi->iso.partoffset;
+ } else {
+ drive = sdi->disk.drive_number;
+ fs_lba = *sdi->disk.partoffset;
+ }
+ if (disk_get_params(drive, &diskinfo))
+ goto bail;
+ /* this will start iteration over disk emulation, possibly raw */
+ if (!(iter = pi_begin(&diskinfo, 0)))
+ goto bail;
+
+ /* 'fs' => we should lookup the syslinux partition number and use it */
+ if (!strcmp(opt.drivename, "fs")) {
+ while (!pi_next(&iter)) {
+ if (iter->start_lba == fs_lba)
+ break;
+ }
+ /* broken part structure or other problems */
+ if (iter->status) {
+ error("Can't find myself on the drive I booted from.\n");
+ goto bail;
+ }
+ }
+ } else {
+ error("Unparsable drive specification.\n");
+ goto bail;
+ }
+ /* main options done - only thing left is explicit partition specification,
+ * if we're still at the disk stage with the iterator AND user supplied
+ * partition number (including disk pseudo-partition).
+ */
+ if (!iter->index && opt.partition) {
+ partition = strtol(opt.partition, NULL, 0);
+ /* search for matching part#, including disk */
+ do {
+ if (iter->index == partition)
+ break;
+ } while (!pi_next(&iter));
+ if (iter->status) {
+ error("Requested disk / partition combination not found.\n");
+ goto bail;
+ }
+ }
+
+ if (!(iter->di.disk & 0x80) && iter->index) {
+ error("WARNING: Partitions on floppy devices may not work.\n");
+ }
+
+ *_iter = iter;
+
+ return 0;
+
+bail:
+ pi_del(&iter);
+ return -1;
+}
+
+static int setup_handover(const struct part_iter *iter,
+ struct data_area *data)
+{
+ struct disk_dos_part_entry *ha;
+ uint32_t synth_size;
+ uint32_t *plen;
+
+ if (!iter->index) { /* implies typeraw or non-iterated */
+ uint32_t len;
+ /* RAW handover protocol */
+ synth_size = sizeof(struct disk_dos_part_entry);
+ ha = malloc(synth_size);
+ if (!ha) {
+ error("Could not build RAW hand-over record!\n");
+ goto bail;
+ }
+ len = ~0u;
+ if (iter->length < len)
+ len = (uint32_t)iter->length;
+ lba2chs(&ha->start, &iter->di, 0, l2c_cadd);
+ lba2chs(&ha->end, &iter->di, len - 1, l2c_cadd);
+ ha->active_flag = 0x80;
+ ha->ostype = 0xDA; /* "Non-FS Data", anything is good here though ... */
+ ha->start_lba = 0;
+ ha->length = len;
+ } else if (iter->type == typegpt) {
+ /* GPT handover protocol */
+ synth_size = sizeof(struct disk_dos_part_entry) +
+ sizeof(uint32_t) + (uint32_t)iter->sub.gpt.pe_size;
+ ha = malloc(synth_size);
+ if (!ha) {
+ error("Could not build GPT hand-over record!\n");
+ goto bail;
+ }
+ lba2chs(&ha->start, &iter->di, iter->start_lba, l2c_cadd);
+ lba2chs(&ha->end, &iter->di, iter->start_lba + iter->length - 1, l2c_cadd);
+ ha->active_flag = 0x80;
+ ha->ostype = 0xED;
+ /* All bits set by default */
+ ha->start_lba = ~0u;
+ ha->length = ~0u;
+ /* If these fit the precision, pass them on */
+ if (iter->start_lba < ha->start_lba)
+ ha->start_lba = (uint32_t)iter->start_lba;
+ if (iter->length < ha->length)
+ ha->length = (uint32_t)iter->length;
+ /* Next comes the GPT partition record length */
+ plen = (uint32_t *) (ha + 1);
+ plen[0] = (uint32_t)iter->sub.gpt.pe_size;
+ /* Next comes the GPT partition record copy */
+ memcpy(plen + 1, iter->record, plen[0]);
+#ifdef DEBUG
+ dprintf("GPT handover:\n");
+ disk_dos_part_dump(ha);
+ disk_gpt_part_dump((struct disk_gpt_part_entry *)(plen + 1));
+#endif
+ } else if (iter->type == typedos) {
+ /* MBR handover protocol */
+ synth_size = sizeof(struct disk_dos_part_entry);
+ ha = malloc(synth_size);
+ if (!ha) {
+ error("Could not build MBR hand-over record!\n");
+ goto bail;
+ }
+ memcpy(ha, iter->record, synth_size);
+ /* make sure these match bios imaginations and are ebr agnostic */
+ lba2chs(&ha->start, &iter->di, iter->start_lba, l2c_cadd);
+ lba2chs(&ha->end, &iter->di, iter->start_lba + iter->length - 1, l2c_cadd);
+ ha->start_lba = (uint32_t)iter->start_lba;
+ ha->length = (uint32_t)iter->length;
+
+#ifdef DEBUG
+ dprintf("MBR handover:\n");
+ disk_dos_part_dump(ha);
+#endif
+ } else {
+ /* shouldn't ever happen */
+ goto bail;
+ }
+
+ data->base = 0x7be;
+ data->size = synth_size;
+ data->data = (void *)ha;
+
+ return 0;
+bail:
+ return -1;
+}
+
+int main(int argc, char *argv[])
+{
+ struct part_iter *iter = NULL;
+ void *sbck = NULL;
+ struct data_area fdat, hdat, sdat, data[3];
+ int ndata = 0;
+
+ console_ansi_raw();
+
+ memset(&fdat, 0, sizeof(fdat));
+ memset(&hdat, 0, sizeof(hdat));
+ memset(&sdat, 0, sizeof(sdat));
+
+ opt_set_defs();
+ if (opt_parse_args(argc, argv))
+ goto bail;
+
+#if 0
+ /* Get max fixed disk number */
+ fixed_cnt = *(uint8_t *)(0x475);
+
+ /*
+ * hmm, looks like we can't do that -
+ * some bioses/vms just set it to 1
+ * and go on living happily
+ * any better options than hardcoded 0x80 - 0xFF ?
+ */
+#endif
+
+ /* Get disk/part iterator matching user supplied options */
+ if (find_dp(&iter))
+ goto bail;
+
+ /* Perform initial partition entry mangling */
+ if (manglepe_fixchs(iter))
+ goto bail;
+ if (manglepe_hide(iter))
+ goto bail;
+
+ /* Load the boot file */
+ if (opt.file) {
+ fdat.base = (opt.fseg << 4) + opt.foff;
+
+ if (loadfile(opt.file, &fdat.data, &fdat.size)) {
+ error("Couldn't read the boot file.\n");
+ goto bail;
+ }
+ if (fdat.base + fdat.size - 1 > ADDRMAX) {
+ error("The boot file is too big to load at this address.\n");
+ goto bail;
+ }
+ }
+
+ /* Load the sector */
+ if (opt.sect) {
+ sdat.base = (opt.sseg << 4) + opt.soff;
+ sdat.size = iter->di.bps;
+
+ if (sdat.base + sdat.size - 1 > ADDRMAX) {
+ error("The sector cannot be loaded at such high address.\n");
+ goto bail;
+ }
+ if (!(sdat.data = disk_read_sectors(&iter->di, iter->start_lba, 1))) {
+ error("Couldn't read the sector.\n");
+ goto bail;
+ }
+ if (opt.save) {
+ if (!(sbck = malloc(sdat.size))) {
+ error("Couldn't allocate cmp-buf for option 'save'.\n");
+ goto bail;
+ }
+ memcpy(sbck, sdat.data, sdat.size);
+ }
+ if (opt.file && opt.maps && overlap(&fdat, &sdat)) {
+ error("WARNING: The sector won't be mmapped, as it would conflict with the boot file.\n");
+ opt.maps = false;
+ }
+ }
+
+ /* Prep the handover */
+ if (opt.hand) {
+ if (setup_handover(iter, &hdat))
+ goto bail;
+ /* Verify possible conflicts */
+ if ( ( opt.file && overlap(&fdat, &hdat)) ||
+ ( opt.maps && overlap(&sdat, &hdat)) ) {
+ error("WARNING: Handover area won't be prepared,\n"
+ "as it would conflict with the boot file and/or the sector.\n");
+ opt.hand = false;
+ }
+ }
+
+ /* Adjust registers */
+
+ mangler_init(iter);
+ mangler_handover(iter, &hdat);
+ mangler_grldr(iter);
+
+ /* Patching functions */
+
+ if (manglef_isolinux(&fdat))
+ goto bail;
+
+ if (manglef_grub(iter, &fdat))
+ goto bail;
+#if 0
+ if (manglef_drmk(&fdat))
+ goto bail;
+#endif
+ if (manglef_bpb(iter, &fdat))
+ goto bail;
+
+ if (mangles_bpb(iter, &sdat))
+ goto bail;
+
+ if (mangles_save(iter, &sdat, sbck))
+ goto bail;
+
+ if (manglesf_bss(&sdat, &fdat))
+ goto bail;
+
+ /* This *must* be after BPB saving or copying */
+ if (mangles_cmldr(&sdat))
+ goto bail;
+
+ /*
+ * Prepare boot-time mmap data. We should to it here, as manglers could
+ * potentially alter some of the data.
+ */
+
+ if (opt.file)
+ memcpy(data + ndata++, &fdat, sizeof(fdat));
+ if (opt.maps)
+ memcpy(data + ndata++, &sdat, sizeof(sdat));
+ if (opt.hand)
+ memcpy(data + ndata++, &hdat, sizeof(hdat));
+
+#ifdef DEBUG
+ printf("iter->di dsk, bps: %X, %u\niter->di lbacnt, C*H*S: %"PRIu64", %u\n"
+ "iter->di C, H, S: %u, %u, %u\n",
+ iter->di.disk, iter->di.bps,
+ iter->di.lbacnt, iter->di.cyl * iter->di.head * iter->di.spt,
+ iter->di.cyl, iter->di.head, iter->di.spt);
+ printf("iter idx: %d\n", iter->index);
+ printf("iter lba: %"PRIu64"\n", iter->start_lba);
+ if (opt.hand)
+ printf("hand lba: %u\n",
+ ((struct disk_dos_part_entry *)hdat.data)->start_lba);
+#endif
+
+ if (opt.warn) {
+ puts("Press any key to continue booting...");
+ wait_key();
+ }
+
+ if (ndata && !opt.brkchain) /* boot only if we actually chainload */
+ do_boot(data, ndata);
+ else
+ error("Service-only run completed, exiting.\n");
+bail:
+ pi_del(&iter);
+ /* Free allocated areas */
+ free(fdat.data);
+ free(sdat.data);
+ free(hdat.data);
+ free(sbck);
+ return 255;
+}
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/chain.h b/com32/chain/chain.h
new file mode 100644
index 00000000..fc481bc6
--- /dev/null
+++ b/com32/chain/chain.h
@@ -0,0 +1,14 @@
+#ifndef _COM32_CHAIN_CHAIN_H
+#define _COM32_CHAIN_CHAIN_H
+
+#include <syslinux/movebits.h>
+
+struct data_area {
+ void *data;
+ addr_t base;
+ addr_t size;
+};
+
+#endif
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/common.h b/com32/chain/common.h
new file mode 100644
index 00000000..b170a732
--- /dev/null
+++ b/com32/chain/common.h
@@ -0,0 +1,9 @@
+#ifndef _COM32_CHAIN_COMMON_H
+#define _COM32_CHAIN_COMMON_H
+
+#define ADDRMAX 0x9EFFFu
+#define ADDRMIN 0x500u
+
+#endif
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/mangle.c b/com32/chain/mangle.c
new file mode 100644
index 00000000..8358106e
--- /dev/null
+++ b/com32/chain/mangle.c
@@ -0,0 +1,618 @@
+#include <com32.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <dprintf.h>
+#include <syslinux/config.h>
+#include "common.h"
+#include "chain.h"
+#include "options.h"
+#include "utility.h"
+#include "partiter.h"
+#include "mangle.h"
+
+static const char cmldr_signature[8] = "cmdcons";
+
+/* Create boot info table: needed when you want to chainload
+ * another version of ISOLINUX (or another bootlaoder that needs
+ * the -boot-info-table switch of mkisofs)
+ * (will only work when run from ISOLINUX)
+ */
+int manglef_isolinux(struct data_area *data)
+{
+ const union syslinux_derivative_info *sdi;
+ unsigned char *isolinux_bin;
+ uint32_t *checksum, *chkhead, *chktail;
+ uint32_t file_lba = 0;
+
+ if (!(opt.file && opt.isolinux))
+ return 0;
+
+ sdi = syslinux_derivative_info();
+
+ if (sdi->c.filesystem != SYSLINUX_FS_ISOLINUX) {
+ error ("The isolinux= option is only valid when run from ISOLINUX.\n");
+ goto bail;
+ }
+
+ /* Boot info table info (integers in little endian format)
+
+ Offset Name Size Meaning
+ 8 bi_pvd 4 bytes LBA of primary volume descriptor
+ 12 bi_file 4 bytes LBA of boot file
+ 16 bi_length 4 bytes Boot file length in bytes
+ 20 bi_csum 4 bytes 32-bit checksum
+ 24 bi_reserved 40 bytes Reserved
+
+ The 32-bit checksum is the sum of all the 32-bit words in the
+ boot file starting at byte offset 64. All linear block
+ addresses (LBAs) are given in CD sectors (normally 2048 bytes).
+
+ LBA of primary volume descriptor should already be set to 16.
+ */
+
+ isolinux_bin = (unsigned char *)data->data;
+
+ /* Get LBA address of bootfile */
+ file_lba = get_file_lba(opt.file);
+
+ if (file_lba == 0) {
+ error("Failed to find LBA offset of the boot file\n");
+ goto bail;
+ }
+ /* Set it */
+ *((uint32_t *) & isolinux_bin[12]) = file_lba;
+
+ /* Set boot file length */
+ *((uint32_t *) & isolinux_bin[16]) = data->size;
+
+ /* Calculate checksum */
+ checksum = (uint32_t *) & isolinux_bin[20];
+ chkhead = (uint32_t *) & isolinux_bin[64];
+ chktail = (uint32_t *) & isolinux_bin[data->size & ~3u];
+ *checksum = 0;
+ while (chkhead < chktail)
+ *checksum += *chkhead++;
+
+ /*
+ * Deal with possible fractional dword at the end;
+ * this *should* never happen...
+ */
+ if (data->size & 3) {
+ uint32_t xword = 0;
+ memcpy(&xword, chkhead, data->size & 3);
+ *checksum += xword;
+ }
+ return 0;
+bail:
+ return -1;
+}
+
+/*
+ * Legacy grub's stage2 chainloading
+ */
+int manglef_grub(const struct part_iter *iter, struct data_area *data)
+{
+ /* Layout of stage2 file (from byte 0x0 to 0x270) */
+ struct grub_stage2_patch_area {
+ /* 0x0 to 0x205 */
+ char unknown[0x206];
+ /* 0x206: compatibility version number major */
+ uint8_t compat_version_major;
+ /* 0x207: compatibility version number minor */
+ uint8_t compat_version_minor;
+
+ /* 0x208: install_partition variable */
+ struct {
+ /* 0x208: sub-partition in sub-partition part2 */
+ uint8_t part3;
+ /* 0x209: sub-partition in top-level partition */
+ uint8_t part2;
+ /* 0x20a: top-level partiton number */
+ uint8_t part1;
+ /* 0x20b: BIOS drive number (must be 0) */
+ uint8_t drive;
+ } __attribute__ ((packed)) install_partition;
+
+ /* 0x20c: deprecated (historical reason only) */
+ uint32_t saved_entryno;
+ /* 0x210: stage2_ID: will always be STAGE2_ID_STAGE2 = 0 in stage2 */
+ uint8_t stage2_id;
+ /* 0x211: force LBA */
+ uint8_t force_lba;
+ /* 0x212: version string (will probably be 0.97) */
+ char version_string[5];
+ /* 0x217: config filename */
+ char config_file[89];
+ /* 0x270: start of code (after jump from 0x200) */
+ char codestart[1];
+ } __attribute__ ((packed)) *stage2;
+
+ if (!(opt.file && opt.grub))
+ return 0;
+
+ if (data->size < sizeof(struct grub_stage2_patch_area)) {
+ error("The file specified by grub=<loader> is too small to be stage2 of GRUB Legacy.\n");
+ goto bail;
+ }
+ stage2 = data->data;
+
+ /*
+ * Check the compatibility version number to see if we loaded a real
+ * stage2 file or a stage2 file that we support.
+ */
+ if (stage2->compat_version_major != 3
+ || stage2->compat_version_minor != 2) {
+ error("The file specified by grub=<loader> is not a supported stage2 GRUB Legacy binary.\n");
+ goto bail;
+ }
+
+ /*
+ * GRUB Legacy wants the partition number in the install_partition
+ * variable, located at offset 0x208 of stage2.
+ * When GRUB Legacy is loaded, it is located at memory address 0x8208.
+ *
+ * It looks very similar to the "boot information format" of the
+ * Multiboot specification:
+ * http://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Boot-information-format
+ *
+ * 0x208 = part3: sub-partition in sub-partition part2
+ * 0x209 = part2: sub-partition in top-level partition
+ * 0x20a = part1: top-level partition number
+ * 0x20b = drive: BIOS drive number (must be 0)
+ *
+ * GRUB Legacy doesn't store the BIOS drive number at 0x20b, but at
+ * another location.
+ *
+ * Partition numbers always start from zero.
+ * Unused partition bytes must be set to 0xFF.
+ *
+ * We only care about top-level partition, so we only need to change
+ * "part1" to the appropriate value:
+ * -1: whole drive (default) (-1 = 0xFF)
+ * 0-3: primary partitions
+ * 4-*: logical partitions
+ */
+ stage2->install_partition.part1 = (uint8_t)(iter->index - 1);
+
+ /*
+ * Grub Legacy reserves 89 bytes (from 0x8217 to 0x826f) for the
+ * config filename. The filename passed via grubcfg= will overwrite
+ * the default config filename "/boot/grub/menu.lst".
+ */
+ if (opt.grubcfg) {
+ if (strlen(opt.grubcfg) > sizeof(stage2->config_file) - 1) {
+ error ("The config filename length can't exceed 88 characters.\n");
+ goto bail;
+ }
+
+ strcpy((char *)stage2->config_file, opt.grubcfg);
+ }
+
+ return 0;
+bail:
+ return -1;
+}
+#if 0
+/*
+ * Dell's DRMK chainloading.
+ */
+int manglef_drmk(struct data_area *data)
+{
+ /*
+ * DRMK entry is different than MS-DOS/PC-DOS
+ * A new size, aligned to 16 bytes to ease use of ds:[bp+28].
+ * We only really need 4 new, usable bytes at the end.
+ */
+
+ if (!(opt.file && opt.drmk))
+ return 0;
+
+ uint32_t tsize = (data->size + 19) & 0xfffffff0;
+ const union syslinux_derivative_info *sdi;
+ uint64_t fs_lba;
+
+ sdi = syslinux_derivative_info();
+ /* We should lookup the Syslinux partition offset and use it */
+ fs_lba = *sdi->disk.partoffset;
+
+ /*
+ * fs_lba should be verified against the disk as some DRMK
+ * variants will check and fail if it does not match
+ */
+ dprintf(" fs_lba offset is %d\n", fs_lba);
+ /* DRMK only uses a DWORD */
+ if (fs_lba > 0xffffffff) {
+ error("LBA very large; Only using lower 32 bits; DRMK will probably fail\n");
+ }
+ opt.regs.ss = opt.regs.fs = opt.regs.gs = 0; /* Used before initialized */
+ if (!realloc(data->data, tsize)) {
+ error("Failed to realloc for DRMK.\n");
+ goto bail;
+ }
+ data->size = tsize;
+ /* ds:bp is assumed by DRMK to be the boot sector */
+ /* offset 28 is the FAT HiddenSectors value */
+ opt.regs.ds = (uint16_t)((tsize >> 4) + (opt.fseg - 2));
+ /* "Patch" into tail of the new space */
+ *(uint32_t *)((char*)data->data + tsize - 4) = (uint32_t)fs_lba;
+
+ return 0;
+bail:
+ return -1;
+}
+#endif
+/* Adjust BPB common function */
+static int mangle_bpb(const struct part_iter *iter, struct data_area *data, const char *tag)
+{
+ unsigned int off;
+ int type = bpb_detect(data->data, tag);
+
+ /* BPB: hidden sectors 32bit*/
+ if (type >= bpbV34) {
+ if (iter->start_lba < ~0u)
+ *(uint32_t *) ((char *)data->data + 0x1c) = (uint32_t)iter->start_lba;
+ else
+ /* won't really help much, but ... */
+ *(uint32_t *) ((char *)data->data + 0x1c) = ~0u;
+ }
+ /* BPB: hidden sectors 16bit*/
+ if (bpbV30 <= type && type <= bpbV32) {
+ if (iter->start_lba < 0xFFFF)
+ *(uint16_t *) ((char *)data->data + 0x1c) = (uint16_t)iter->start_lba;
+ else
+ /* won't really help much, but ... */
+ *(uint16_t *) ((char *)data->data + 0x1c) = (uint16_t)~0u;
+ }
+ /* BPB: legacy geometry */
+ if (type >= bpbV30) {
+ if (iter->di.cbios)
+ *(uint32_t *)((char *)data->data + 0x18) = (uint32_t)((iter->di.head << 16) | iter->di.spt);
+ else {
+ if (iter->di.disk & 0x80)
+ *(uint32_t *)((char *)data->data + 0x18) = 0x00FF003F;
+ else
+ *(uint32_t *)((char *)data->data + 0x18) = 0x00020012;
+ }
+ }
+ /* BPB: drive */
+ if (drvoff_detect(type, &off)) {
+ *(uint8_t *)((char *)data->data + off) = (uint8_t)
+ (opt.swap ? iter->di.disk & 0x80 : iter->di.disk);
+ }
+
+ return 0;
+}
+
+/*
+ * Adjust BPB of a BPB-compatible file
+ */
+int manglef_bpb(const struct part_iter *iter, struct data_area *data)
+{
+ if (!(opt.file && opt.filebpb))
+ return 0;
+
+ return mangle_bpb(iter, data, "file");
+}
+
+/*
+ * Adjust BPB of a sector
+ */
+int mangles_bpb(const struct part_iter *iter, struct data_area *data)
+{
+ if (!(opt.sect && opt.setbpb))
+ return 0;
+
+ return mangle_bpb(iter, data, "sect");
+}
+
+/*
+ * This function performs full BPB patching, analogously to syslinux's
+ * native BSS.
+ */
+int manglesf_bss(struct data_area *sec, struct data_area *fil)
+{
+ int type1, type2;
+ unsigned int cnt = 0;
+
+ if (!(opt.sect && opt.file && opt.bss))
+ return 0;
+
+ type1 = bpb_detect(fil->data, "bss/file");
+ type2 = bpb_detect(sec->data, "bss/sect");
+
+ if (!type1 || !type2) {
+ error("Couldn't determine the BPB type for option 'bss'.\n");
+ goto bail;
+ }
+ if (type1 != type2) {
+ error("Option 'bss' can't be used,\n"
+ "when a sector and a file have incompatible BPBs.\n");
+ goto bail;
+ }
+
+ /* Copy common 2.0 data */
+ memcpy((char *)fil->data + 0x0B, (char *)sec->data + 0x0B, 0x0D);
+
+ /* Copy 3.0+ data */
+ if (type1 <= bpbV30) {
+ cnt = 0x06;
+ } else if (type1 <= bpbV32) {
+ cnt = 0x08;
+ } else if (type1 <= bpbV34) {
+ cnt = 0x0C;
+ } else if (type1 <= bpbV40) {
+ cnt = 0x2E;
+ } else if (type1 <= bpbVNT) {
+ cnt = 0x3C;
+ } else if (type1 <= bpbV70) {
+ cnt = 0x42;
+ }
+ memcpy((char *)fil->data + 0x18, (char *)sec->data + 0x18, cnt);
+
+ return 0;
+bail:
+ return -1;
+}
+
+/*
+ * Save sector.
+ */
+int mangles_save(const struct part_iter *iter, const struct data_area *data, void *org)
+{
+ if (!(opt.sect && opt.save))
+ return 0;
+
+ if (memcmp(org, data->data, data->size)) {
+ if (disk_write_sectors(&iter->di, iter->start_lba, data->data, 1)) {
+ error("Cannot write the updated sector.\n");
+ goto bail;
+ }
+ /* function can be called again */
+ memcpy(org, data->data, data->size);
+ }
+
+ return 0;
+bail:
+ return -1;
+}
+
+/*
+ * To boot the Recovery Console of Windows NT/2K/XP we need to write
+ * the string "cmdcons\0" to memory location 0000:7C03.
+ * Memory location 0000:7C00 contains the bootsector of the partition.
+ */
+int mangles_cmldr(struct data_area *data)
+{
+ if (!(opt.sect && opt.cmldr))
+ return 0;
+
+ memcpy((char *)data->data + 3, cmldr_signature, sizeof(cmldr_signature));
+ return 0;
+}
+
+/* Set common registers */
+int mangler_init(const struct part_iter *iter)
+{
+ /* Set initial registry values */
+ if (opt.file) {
+ opt.regs.cs = opt.regs.ds = opt.regs.ss = (uint16_t)opt.fseg;
+ opt.regs.ip = (uint16_t)opt.fip;
+ } else {
+ opt.regs.cs = opt.regs.ds = opt.regs.ss = (uint16_t)opt.sseg;
+ opt.regs.ip = (uint16_t)opt.sip;
+ }
+
+ if (opt.regs.ip == 0x7C00 && !opt.regs.cs)
+ opt.regs.esp.l = 0x7C00;
+
+ /* DOS kernels want the drive number in BL instead of DL. Indulge them. */
+ opt.regs.ebx.b[0] = opt.regs.edx.b[0] = (uint8_t)iter->di.disk;
+
+ return 0;
+}
+
+/* ds:si & ds:bp */
+int mangler_handover(const struct part_iter *iter, const struct data_area *data)
+{
+ if (opt.file && opt.maps && !opt.hptr) {
+ opt.regs.esi.l = opt.regs.ebp.l = opt.soff;
+ opt.regs.ds = (uint16_t)opt.sseg;
+ opt.regs.eax.l = 0;
+ } else if (opt.hand) {
+ /* base is really 0x7be */
+ opt.regs.esi.l = opt.regs.ebp.l = data->base;
+ opt.regs.ds = 0;
+ if (iter->index && iter->type == typegpt) /* must be iterated and GPT */
+ opt.regs.eax.l = 0x54504721; /* '!GPT' */
+ else
+ opt.regs.eax.l = 0;
+ }
+
+ return 0;
+}
+
+/*
+ * GRLDR of GRUB4DOS wants the partition number in DH:
+ * -1: whole drive (default)
+ * 0-3: primary partitions
+ * 4-*: logical partitions
+ */
+int mangler_grldr(const struct part_iter *iter)
+{
+ if (opt.grldr)
+ opt.regs.edx.b[1] = (uint8_t)(iter->index - 1);
+
+ return 0;
+}
+
+/*
+ * try to copy values from temporary iterator, if positions match
+ */
+static void push_embr(struct part_iter *diter, struct part_iter *siter)
+{
+ if (diter->sub.dos.cebr_lba == siter->sub.dos.cebr_lba &&
+ diter->di.disk == siter->di.disk) {
+ memcpy(diter->data, siter->data, sizeof(struct disk_dos_mbr));
+ }
+}
+
+static int mpe_sethide(struct part_iter *iter, struct part_iter *miter)
+{
+ struct disk_dos_part_entry *dp;
+ static const uint16_t mask =
+ (1 << 0x01) | (1 << 0x04) | (1 << 0x06) |
+ (1 << 0x07) | (1 << 0x0b) | (1 << 0x0c) | (1 << 0x0e);
+ uint8_t t;
+
+ dp = (struct disk_dos_part_entry *)iter->record;
+ t = dp->ostype;
+
+ if ((t <= 0x1f) && ((mask >> (t & ~0x10u)) & 1)) {
+ /* It's a hideable partition type */
+ if (miter->index == iter->index || opt.hide & 4)
+ t &= (uint8_t)(~0x10u); /* unhide */
+ else
+ t |= 0x10u; /* hide */
+ }
+ if (dp->ostype != t) {
+ dp->ostype = t;
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * miter - iterator we match against
+ * hide bits meaning:
+ * ..| - enable (1) / disable (0)
+ * .|. - all (1) / pri (0)
+ * |.. - unhide (1) / hide (0)
+ */
+int manglepe_hide(struct part_iter *miter)
+{
+ int wb = 0, werr = 0;
+ struct part_iter *iter = NULL;
+ struct disk_dos_part_entry *dp;
+ int ridx;
+
+ if (!opt.hide)
+ return 0;
+
+ if (miter->type != typedos) {
+ error("Options '*hide*' is meaningful only for legacy partition scheme.\n");
+ return -1;
+ }
+
+ if (miter->index < 1)
+ error("WARNING: It's impossible to unhide a disk.\n");
+
+ if (miter->index > 4 && !(opt.hide & 2))
+ error("WARNING: your partition is beyond mbr, so it can't be unhidden without '*hideall'.\n");
+
+ if (!(iter = pi_begin(&miter->di, 1))) /* turn stepall on */
+ return -1;
+
+ while (!pi_next(&iter) && !werr) {
+ ridx = iter->rawindex;
+ if (!(opt.hide & 2) && ridx > 4)
+ break; /* skip when we're constrained to pri only */
+
+ dp = (struct disk_dos_part_entry *)iter->record;
+ if (dp->ostype)
+ wb |= mpe_sethide(iter, miter);
+
+ if (ridx >= 4 && wb && !werr) {
+ push_embr(miter, iter);
+ werr |= disk_write_sectors(&iter->di, iter->sub.dos.cebr_lba, iter->data, 1);
+ wb = 0;
+ }
+ }
+
+ if (iter->status > PI_DONE)
+ goto bail;
+
+ /* last write */
+ if (wb && !werr) {
+ push_embr(miter, iter);
+ werr |= disk_write_sectors(&iter->di, iter->sub.dos.cebr_lba, iter->data, 1);
+ }
+ if (werr)
+ error("WARNING: failed to write E/MBR during '*hide*'\n");
+
+bail:
+ pi_del(&iter);
+ return 0;
+}
+
+static int mpe_setchs(const struct disk_info *di,
+ struct disk_dos_part_entry *dp,
+ uint32_t lba1)
+{
+ uint32_t ochs1, ochs2;
+
+ ochs1 = *(uint32_t *)dp->start;
+ ochs2 = *(uint32_t *)dp->end;
+
+ lba2chs(&dp->start, di, lba1, l2c_cadd);
+ lba2chs(&dp->end, di, lba1 + dp->length - 1, l2c_cadd);
+
+ return
+ *(uint32_t *)dp->start != ochs1 ||
+ *(uint32_t *)dp->end != ochs2;
+}
+
+/*
+ * miter - iterator we match against
+ */
+int manglepe_fixchs(struct part_iter *miter)
+{
+ int wb = 0, werr = 0;
+ struct part_iter *iter = NULL;
+ struct disk_dos_part_entry *dp;
+ int ridx;
+
+ if (!opt.fixchs)
+ return 0;
+
+ if (miter->type != typedos) {
+ error("Options 'fixchs' is meaningful only for legacy partition scheme.\n");
+ return -1;
+ }
+
+ if (!(iter = pi_begin(&miter->di, 1))) /* turn stepall on */
+ return -1;
+
+ while (!pi_next(&iter) && !werr) {
+ ridx = iter->rawindex;
+ dp = (struct disk_dos_part_entry *)iter->record;
+
+ wb |= mpe_setchs(&iter->di, dp, (uint32_t)iter->start_lba);
+ if (ridx > 4)
+ wb |= mpe_setchs(&iter->di, dp + 1, iter->sub.dos.nebr_lba);
+
+ if (ridx >= 4 && wb && !werr) {
+ push_embr(miter, iter);
+ werr |= disk_write_sectors(&iter->di, iter->sub.dos.cebr_lba, iter->data, 1);
+ wb = 0;
+ }
+ }
+
+ if (iter->status > PI_DONE)
+ goto bail;
+
+ /* last write */
+ if (wb && !werr) {
+ push_embr(miter, iter);
+ werr |= disk_write_sectors(&iter->di, iter->sub.dos.cebr_lba, iter->data, 1);
+ }
+ if (werr)
+ error("WARNING: failed to write E/MBR during 'fixchs'\n");
+
+bail:
+ pi_del(&iter);
+ return 0;
+}
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/mangle.h b/com32/chain/mangle.h
new file mode 100644
index 00000000..bcefea3b
--- /dev/null
+++ b/com32/chain/mangle.h
@@ -0,0 +1,32 @@
+#ifndef _COM32_CHAIN_MANGLE_H
+#define _COM32_CHAIN_MANGLE_H
+
+#include "chain.h"
+#include "partiter.h"
+
+/* file's manglers */
+int manglef_isolinux(struct data_area *data);
+int manglef_grub(const struct part_iter *iter, struct data_area *data);
+int manglef_bpb(const struct part_iter *iter, struct data_area *data);
+/* int manglef_drmk(struct data_area *data);*/
+
+/* sector's manglers */
+int mangles_bpb(const struct part_iter *iter, struct data_area *data);
+int mangles_save(const struct part_iter *iter, const struct data_area *data, void *org);
+int mangles_cmldr(struct data_area *data);
+
+/* sector + file's manglers */
+int manglesf_bss(struct data_area *sec, struct data_area *fil);
+
+/* registers' manglers */
+int mangler_init(const struct part_iter *iter);
+int mangler_handover(const struct part_iter *iter, const struct data_area *data);
+int mangler_grldr(const struct part_iter *iter);
+
+/* partition layout's manglers */
+int manglepe_fixchs(struct part_iter *miter);
+int manglepe_hide(struct part_iter *miter);
+
+#endif
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/options.c b/com32/chain/options.c
new file mode 100644
index 00000000..658a45ca
--- /dev/null
+++ b/com32/chain/options.c
@@ -0,0 +1,376 @@
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include "common.h"
+#include "chain.h"
+#include "utility.h"
+#include "options.h"
+
+struct options opt;
+
+static int soi_s2n(char *ptr, unsigned int *seg,
+ unsigned int *off,
+ unsigned int *ip,
+ unsigned int def)
+{
+ unsigned int segval = 0, offval, ipval, val;
+ char *p;
+
+ offval = def;
+ ipval = def;
+
+ segval = strtoul(ptr, &p, 0);
+ if (p[0] == ':' && p[1] && p[1] != ':')
+ offval = strtoul(p+1, &p, 0);
+ if (p[0] == ':' && p[1] && p[1] != ':')
+ ipval = strtoul(p+1, NULL, 0);
+
+ val = (segval << 4) + offval;
+
+ if (val < ADDRMIN || val > ADDRMAX) {
+ error("Invalid seg:off:* address specified..\n");
+ goto bail;
+ }
+
+ val = (segval << 4) + ipval;
+
+ if (ipval > 0xFFFE || val < ADDRMIN || val > ADDRMAX) {
+ error("Invalid seg:*:ip address specified.\n");
+ goto bail;
+ }
+
+ if (seg)
+ *seg = segval;
+ if (off)
+ *off = offval;
+ if (ip)
+ *ip = ipval;
+
+ return 0;
+bail:
+ return -1;
+}
+
+static void usage(void)
+{
+ unsigned int i;
+ static const char key[] = "Press any key...\n";
+ static const char *const usage[] = {
+"\
+Usage:\n\
+ chain.c32 [options]\n\
+ chain.c32 {fd|hd}<disk#>{,| }[<part#>] [options]\n\
+ chain.c32 mbr{:|=}<id>{,| }[<part#>] [options]\n\
+ chain.c32 guid{:|=}<guid>{,| }[<part#>] [options]\n\
+ chain.c32 label{:|=}<label> [<part#>] [options]\n\
+ chain.c32 boot{,| }[<part#>] [options]\n\
+ chain.c32 fs [options]\n\
+", "\
+\nOptions ('no' prefix specifies default value):\n\
+ sect[=<s[:o[:i]]>] Load sector at <s:o>, jump to <s:i>\n\
+ - defaults to 0:0x7C00:0x7C00\n\
+ - ommited o/i values default to 0\n\
+ maps Map loaded sector into real memory\n\
+ nosetbpb Fix BPB fields in loaded sector\n\
+ nofilebpb Apply 'setbpb' to loaded file\n\
+ nosave Write adjusted sector back to disk\n\
+ hand Prepare handover area\n\
+ nohptr Force ds:si and ds:bp to point to handover area\n\
+ noswap Swap drive numbers, if bootdisk is not fd0/hd0\n\
+ nohide Disable all hide variations (also the default)\n\
+ hide Hide primary partitions, unhide selected partition\n\
+ hideall Hide *all* partitions, unhide selected partition\n\
+ unhide Unhide primary partitions\n\
+ unhideall Unhide *all* partitions\n\
+ nofixchs Walk *all* partitions and fix E/MBRs' chs values\n\
+ nokeeppxe Keep the PXE and UNDI stacks in memory (PXELINUX)\n\
+ nowarn Wait for a keypress to continue chainloading\n\
+ - useful to see emited warnings\n\
+ nobreak Actually perform the chainloading\n\
+", "\
+\nOptions continued ...\n\
+ file=<file> Load and execute <file>\n\
+ seg=<s[:o[:i]]> Load file at <s:o>, jump to <s:i>\n\
+ - defaults to 0:0x7C00:0x7C00\n\
+ - ommited o/i values default to 0\n\
+ isolinux=<loader> Load another version of ISOLINUX\n\
+ ntldr=<loader> Load Windows NTLDR, SETUPLDR.BIN or BOOTMGR\n\
+ reactos=<loader> Load ReactOS's loader\n\
+ cmldr=<loader> Load Recovery Console of Windows NT/2K/XP/2003\n\
+ freedos=<loader> Load FreeDOS KERNEL.SYS\n\
+ msdos=<loader> Load MS-DOS 2.xx - 6.xx IO.SYS\n\
+ msdos7=<loader> Load MS-DOS 7+ IO.SYS\n\
+ pcdos=<loader> Load PC-DOS IBMBIO.COM\n\
+ drmk=<loader> Load DRMK DELLBIO.BIN\n\
+ grub=<loader> Load GRUB Legacy stage2\n\
+ grubcfg=<filename> Set alternative config filename for GRUB Legacy\n\
+ grldr=<loader> Load GRUB4DOS grldr\n\
+ bss=<filename> Emulate syslinux's BSS\n\
+ bs=<filename> Emulate syslinux's BS\n\
+\nPlease see doc/chain.txt for the detailed documentation.\n\
+"
+ };
+ for (i = 0; i < sizeof(usage)/sizeof(usage[0]); i++) {
+ if (i) {
+ error(key);
+ wait_key();
+ }
+ error(usage[i]);
+ }
+}
+
+void opt_set_defs(void)
+{
+ memset(&opt, 0, sizeof(opt));
+ opt.sect = true; /* by def. load sector */
+ opt.maps = true; /* by def. map sector */
+ opt.hand = true; /* by def. prepare handover */
+ opt.brkchain = false; /* by def. do chainload */
+ opt.foff = opt.soff = opt.fip = opt.sip = 0x7C00;
+ opt.drivename = "boot";
+#ifdef DEBUG
+ opt.warn = true;
+#endif
+}
+
+int opt_parse_args(int argc, char *argv[])
+{
+ int i;
+ unsigned int v;
+ char *p;
+
+ for (i = 1; i < argc; i++) {
+ if (!strncmp(argv[i], "file=", 5)) {
+ opt.file = argv[i] + 5;
+ } else if (!strcmp(argv[i], "nofile")) {
+ opt.file = NULL;
+ } else if (!strncmp(argv[i], "seg=", 4)) {
+ if (soi_s2n(argv[i] + 4, &opt.fseg, &opt.foff, &opt.fip, 0))
+ goto bail;
+ } else if (!strncmp(argv[i], "bss=", 4)) {
+ opt.file = argv[i] + 4;
+ opt.bss = true;
+ opt.maps = false;
+ opt.setbpb = true;
+ /* opt.save = true; */
+ } else if (!strncmp(argv[i], "bs=", 3)) {
+ opt.file = argv[i] + 3;
+ opt.sect = false;
+ opt.filebpb = true;
+ } else if (!strncmp(argv[i], "isolinux=", 9)) {
+ opt.file = argv[i] + 9;
+ opt.isolinux = true;
+ opt.hand = false;
+ opt.sect = false;
+ } else if (!strncmp(argv[i], "ntldr=", 6)) {
+ opt.fseg = 0x2000; /* NTLDR wants this address */
+ opt.foff = 0;
+ opt.fip = 0;
+ opt.file = argv[i] + 6;
+ opt.setbpb = true;
+ /* opt.save = true; */
+ opt.hand = false;
+ } else if (!strncmp(argv[i], "reactos=", 8)) {
+ /*
+ * settings based on commit
+ * ad4cf1470977f648ee1dd45e97939589ccb0393c
+ * note, conflicts with:
+ * http://reactos.freedoors.org/Reactos%200.3.13/ReactOS-0.3.13-REL-src/boot/freeldr/notes.txt
+ */
+ opt.fseg = 0;
+ opt.foff = 0x8000;
+ opt.fip = 0x8100;
+ opt.file = argv[i] + 8;
+ opt.setbpb = true;
+ /* opt.save = true; */
+ opt.hand = false;
+ } else if (!strncmp(argv[i], "cmldr=", 6)) {
+ opt.fseg = 0x2000; /* CMLDR wants this address */
+ opt.foff = 0;
+ opt.fip = 0;
+ opt.file = argv[i] + 6;
+ opt.cmldr = true;
+ opt.setbpb = true;
+ /* opt.save = true; */
+ opt.hand = false;
+ } else if (!strncmp(argv[i], "freedos=", 8)) {
+ opt.fseg = 0x60; /* FREEDOS wants this address */
+ opt.foff = 0;
+ opt.fip = 0;
+ opt.sseg = 0x1FE0;
+ opt.file = argv[i] + 8;
+ opt.setbpb = true;
+ /* opt.save = true; */
+ opt.hand = false;
+ } else if ( (v = 6, !strncmp(argv[i], "msdos=", v) ||
+ !strncmp(argv[i], "pcdos=", v)) ||
+ (v = 7, !strncmp(argv[i], "msdos7=", v)) ) {
+ opt.fseg = 0x70; /* MS-DOS 2.00 .. 6.xx wants this address */
+ opt.foff = 0;
+ opt.fip = v == 7 ? 0x200 : 0; /* MS-DOS 7.0+ wants this ip */
+ opt.sseg = 0x8000;
+ opt.file = argv[i] + v;
+ opt.setbpb = true;
+ /* opt.save = true; */
+ opt.hand = false;
+ } else if (!strncmp(argv[i], "drmk=", 5)) {
+ opt.fseg = 0x70; /* DRMK wants this address */
+ opt.foff = 0;
+ opt.fip = 0;
+ opt.sseg = 0x2000;
+ opt.soff = 0;
+ opt.sip = 0;
+ opt.file = argv[i] + 5;
+ /* opt.drmk = true; */
+ opt.setbpb = true;
+ /* opt.save = true; */
+ opt.hand = false;
+ } else if (!strncmp(argv[i], "grub=", 5)) {
+ opt.fseg = 0x800; /* stage2 wants this address */
+ opt.foff = 0;
+ opt.fip = 0x200;
+ opt.file = argv[i] + 5;
+ opt.grub = true;
+ opt.hand = false;
+ opt.sect = false;
+ } else if (!strncmp(argv[i], "grubcfg=", 8)) {
+ opt.grubcfg = argv[i] + 8;
+ } else if (!strncmp(argv[i], "grldr=", 6)) {
+ opt.file = argv[i] + 6;
+ opt.grldr = true;
+ opt.hand = false;
+ opt.sect = false;
+ } else if (!strcmp(argv[i], "keeppxe")) {
+ opt.keeppxe = 3;
+ } else if (!strcmp(argv[i], "nokeeppxe")) {
+ opt.keeppxe = 0;
+ } else if (!strcmp(argv[i], "maps")) {
+ opt.maps = true;
+ } else if (!strcmp(argv[i], "nomaps")) {
+ opt.maps = false;
+ } else if (!strcmp(argv[i], "hand")) {
+ opt.hand = true;
+ } else if (!strcmp(argv[i], "nohand")) {
+ opt.hand = false;
+ } else if (!strcmp(argv[i], "hptr")) {
+ opt.hptr = true;
+ } else if (!strcmp(argv[i], "nohptr")) {
+ opt.hptr = false;
+ } else if (!strcmp(argv[i], "swap")) {
+ opt.swap = true;
+ } else if (!strcmp(argv[i], "noswap")) {
+ opt.swap = false;
+ } else if (!strcmp(argv[i], "nohide")) {
+ opt.hide = 0;
+ } else if (!strcmp(argv[i], "hide")) {
+ opt.hide = 1; /* 001b */
+ } else if (!strcmp(argv[i], "hideall")) {
+ opt.hide = 2; /* 010b */
+ } else if (!strcmp(argv[i], "unhide")) {
+ opt.hide = 5; /* 101b */
+ } else if (!strcmp(argv[i], "unhideall")) {
+ opt.hide = 6; /* 110b */
+ } else if (!strcmp(argv[i], "setbpb")) {
+ opt.setbpb = true;
+ } else if (!strcmp(argv[i], "nosetbpb")) {
+ opt.setbpb = false;
+ } else if (!strcmp(argv[i], "filebpb")) {
+ opt.filebpb = true;
+ } else if (!strcmp(argv[i], "nofilebpb")) {
+ opt.filebpb = false;
+ } else if (!strncmp(argv[i], "sect=", 5) ||
+ !strcmp(argv[i], "sect")) {
+ if (argv[i][4]) {
+ if (soi_s2n(argv[i] + 5, &opt.sseg, &opt.soff, &opt.sip, 0))
+ goto bail;
+ }
+ opt.sect = true;
+ } else if (!strcmp(argv[i], "nosect")) {
+ opt.sect = false;
+ opt.maps = false;
+ } else if (!strcmp(argv[i], "save")) {
+ opt.save = true;
+ } else if (!strcmp(argv[i], "nosave")) {
+ opt.save = false;
+ } else if (!strcmp(argv[i], "fixchs")) {
+ opt.fixchs = true;
+ } else if (!strcmp(argv[i], "nofixchs")) {
+ opt.fixchs = false;
+ } else if (!strcmp(argv[i], "warn")) {
+ opt.warn = true;
+ } else if (!strcmp(argv[i], "nowarn")) {
+ opt.warn = false;
+ } else if (!strcmp(argv[i], "nobreak")) {
+ opt.brkchain = false;
+ } else if (!strcmp(argv[i], "break")) {
+ opt.brkchain = true;
+ opt.file = NULL;
+ opt.maps = false;
+ opt.hand = false;
+ } else if (((argv[i][0] == 'h' || argv[i][0] == 'f')
+ && argv[i][1] == 'd')
+ || !strncmp(argv[i], "mbr:", 4)
+ || !strncmp(argv[i], "mbr=", 4)
+ || !strncmp(argv[i], "guid:", 5)
+ || !strncmp(argv[i], "guid=", 5)
+ || !strncmp(argv[i], "label:", 6)
+ || !strncmp(argv[i], "label=", 6)
+ || !strcmp(argv[i], "boot")
+ || !strncmp(argv[i], "boot,", 5)
+ || !strcmp(argv[i], "fs")) {
+ opt.drivename = argv[i];
+ if (strncmp(argv[i], "label", 5))
+ p = strchr(opt.drivename, ',');
+ else
+ p = NULL;
+ if (p) {
+ *p = '\0';
+ opt.partition = p + 1;
+ } else if (argv[i + 1] && argv[i + 1][0] >= '0'
+ && argv[i + 1][0] <= '9') {
+ opt.partition = argv[++i];
+ }
+ } else {
+ usage();
+ goto bail;
+ }
+ }
+
+ if (opt.grubcfg && !opt.grub) {
+ error("grubcfg=<filename> must be used together with grub=<loader>.\n");
+ goto bail;
+ }
+
+#if 0
+ if ((!opt.maps || !opt.sect) && !opt.file) {
+ error("You have to load something.\n");
+ goto bail;
+ }
+#endif
+
+ if (opt.filebpb && !opt.file) {
+ error("Option 'filebpb' requires a file.\n");
+ goto bail;
+ }
+
+ if (opt.save && !opt.sect) {
+ error("Option 'save' requires a sector.\n");
+ goto bail;
+ }
+
+ if (opt.setbpb && !opt.sect) {
+ error("Option 'setbpb' requires a sector.\n");
+ goto bail;
+ }
+
+ if (opt.maps && !opt.sect) {
+ error("Option 'maps' requires a sector.\n");
+ goto bail;
+ }
+
+ return 0;
+bail:
+ return -1;
+}
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/options.h b/com32/chain/options.h
new file mode 100644
index 00000000..4493ef1f
--- /dev/null
+++ b/com32/chain/options.h
@@ -0,0 +1,47 @@
+#ifndef _COM32_CHAIN_OPTIONS_H
+#define _COM32_CHAIN_OPTIONS_H
+
+#include <stdint.h>
+#include <syslinux/bootrm.h>
+
+struct options {
+ unsigned int fseg;
+ unsigned int foff;
+ unsigned int fip;
+ unsigned int sseg;
+ unsigned int soff;
+ unsigned int sip;
+ const char *drivename;
+ const char *partition;
+ const char *file;
+ const char *grubcfg;
+ bool isolinux;
+ bool cmldr;
+ bool drmk;
+ bool grub;
+ bool grldr;
+ bool maps;
+ bool hand;
+ bool hptr;
+ bool swap;
+ int hide;
+ bool sect;
+ bool save;
+ bool bss;
+ bool setbpb;
+ bool filebpb;
+ bool fixchs;
+ bool warn;
+ bool brkchain;
+ uint16_t keeppxe;
+ struct syslinux_rm_regs regs;
+};
+
+extern struct options opt;
+
+void opt_set_defs(void);
+int opt_parse_args(int argc, char *argv[]);
+
+#endif
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/partiter.c b/com32/chain/partiter.c
new file mode 100644
index 00000000..1acd1958
--- /dev/null
+++ b/com32/chain/partiter.c
@@ -0,0 +1,805 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2003-2010 H. Peter Anvin - All Rights Reserved
+ * Copyright 2010 Shao Miller
+ * Copyright 2010 Michal Soltys
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * partiter.c
+ *
+ * Provides disk / partition iteration.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <zlib.h>
+#include <syslinux/disk.h>
+#include "common.h"
+#include "partiter.h"
+#include "utility.h"
+
+#define ost_is_ext(type) ((type) == 0x05 || (type) == 0x0F || (type) == 0x85)
+#define ost_is_nondata(type) (ost_is_ext(type) || (type) == 0x00)
+#define sane(s,l) ((s)+(l) > (s))
+
+/* forwards */
+
+static int iter_ctor(struct part_iter *, va_list *);
+static int iter_dos_ctor(struct part_iter *, va_list *);
+static int iter_gpt_ctor(struct part_iter *, va_list *);
+static void iter_dtor(struct part_iter *);
+static struct part_iter *pi_dos_next(struct part_iter *);
+static struct part_iter *pi_gpt_next(struct part_iter *);
+static struct part_iter *pi_raw_next(struct part_iter *);
+
+static struct itertype types[] = {
+ [0] = {
+ .ctor = &iter_dos_ctor,
+ .dtor = &iter_dtor,
+ .next = &pi_dos_next,
+}, [1] = {
+ .ctor = &iter_gpt_ctor,
+ .dtor = &iter_dtor,
+ .next = &pi_gpt_next,
+}, [2] = {
+ .ctor = &iter_ctor,
+ .dtor = &iter_dtor,
+ .next = &pi_raw_next,
+}};
+
+const struct itertype * const typedos = types;
+const struct itertype * const typegpt = types+1;
+const struct itertype * const typeraw = types+2;
+
+#ifdef DEBUG
+static int inv_type(const void *type)
+{
+ int i, cnt = sizeof(types)/sizeof(types[0]);
+ for (i = 0; i < cnt; i++) {
+ if (type == types + i)
+ return 0;
+ }
+ return -1;
+}
+#endif
+
+/**
+ * iter_ctor() - common iterator initialization
+ * @iter: iterator pointer
+ * @args(0): disk_info structure used for disk functions
+ * @args(1): stepall modifier
+ *
+ * Second and further arguments are passed as a pointer to va_list
+ **/
+static int iter_ctor(struct part_iter *iter, va_list *args)
+{
+ const struct disk_info *di = va_arg(*args, const struct disk_info *);
+ int stepall = va_arg(*args, int);
+
+#ifdef DEBUG
+ if (!di)
+ return -1;
+#endif
+
+ memcpy(&iter->di, di, sizeof(struct disk_info));
+ iter->stepall = stepall;
+ iter->index0 = -1;
+ iter->length = di->lbacnt;
+
+ return 0;
+}
+
+/**
+ * iter_dtor() - common iterator cleanup
+ * @iter: iterator pointer
+ *
+ **/
+static void iter_dtor(struct part_iter *iter)
+{
+ free(iter->data);
+}
+
+/**
+ * iter_dos_ctor() - MBR/EBR iterator specific initialization
+ * @iter: iterator pointer
+ * @args(0): disk_info structure used for disk functions
+ * @args(1): pointer to buffer with loaded valid MBR
+ *
+ * Second and further arguments are passed as a pointer to va_list.
+ * This function only makes rudimentary checks. If user uses
+ * pi_new(), he/she is responsible for doing proper sanity checks.
+ **/
+static int iter_dos_ctor(struct part_iter *iter, va_list *args)
+{
+ const struct disk_dos_mbr *mbr;
+
+ /* uses args(0) */
+ if (iter_ctor(iter, args))
+ return -1;
+
+ mbr = va_arg(*args, const struct disk_dos_mbr *);
+
+#ifdef DEBUG
+ if (!mbr)
+ goto bail;
+#endif
+
+ if (!(iter->data = malloc(sizeof(struct disk_dos_mbr))))
+ goto bail;
+
+ memcpy(iter->data, mbr, sizeof(struct disk_dos_mbr));
+
+ iter->sub.dos.bebr_index0 = -1;
+ iter->sub.dos.disk_sig = mbr->disk_sig;
+
+ return 0;
+bail:
+ iter->type->dtor(iter);
+ return -1;
+}
+
+/**
+ * iter_gpt_ctor() - GPT iterator specific initialization
+ * @iter: iterator pointer
+ * @args(0): ptr to disk_info structure
+ * @args(1): ptr to buffer with GPT header
+ * @args(2): ptr to buffer with GPT partition list
+ *
+ * Second and further arguments are passed as a pointer to va_list.
+ * This function only makes rudimentary checks. If user uses
+ * pi_new(), he/she is responsible for doing proper sanity checks.
+ **/
+static int iter_gpt_ctor(struct part_iter *iter, va_list *args)
+{
+ uint64_t siz;
+ const struct disk_gpt_header *gpth;
+ const struct disk_gpt_part_entry *gptl;
+
+ /* uses args(0) */
+ if (iter_ctor(iter, args))
+ return -1;
+
+ gpth = va_arg(*args, const struct disk_gpt_header *);
+ gptl = va_arg(*args, const struct disk_gpt_part_entry *);
+
+#ifdef DEBUG
+ if (!gpth || !gptl)
+ goto bail;
+#endif
+
+ siz = (uint64_t)gpth->part_count * gpth->part_size;
+
+#ifdef DEBUG
+ if (!siz || (siz + iter->di.bps - 1) / iter->di.bps > 255u ||
+ gpth->part_size < sizeof(struct disk_gpt_part_entry)) {
+ goto bail;
+ }
+#endif
+
+ if (!(iter->data = malloc((size_t)siz)))
+ goto bail;
+
+ memcpy(iter->data, gptl, (size_t)siz);
+
+ iter->sub.gpt.pe_count = (int)gpth->part_count;
+ iter->sub.gpt.pe_size = (int)gpth->part_size;
+ iter->sub.gpt.ufirst = gpth->lba_first_usable;
+ iter->sub.gpt.ulast = gpth->lba_last_usable;
+
+ memcpy(&iter->sub.gpt.disk_guid, &gpth->disk_guid, sizeof(struct guid));
+
+ return 0;
+bail:
+ iter->type->dtor(iter);
+ return -1;
+}
+
+/* Logical partition must be sane, meaning:
+ * - must be data or empty
+ * - must have non-0 start and length
+ * - values must not wrap around 32bit
+ * - must be inside current EBR frame
+ */
+
+static int notsane_logical(const struct part_iter *iter)
+{
+ const struct disk_dos_part_entry *dp;
+ uint32_t end_log;
+
+ dp = ((struct disk_dos_mbr *)iter->data)->table;
+
+ if (!dp[0].ostype)
+ return 0;
+
+ if (ost_is_ext(dp[0].ostype)) {
+ error("1st EBR entry must be data or empty.\n");
+ return -1;
+ }
+
+ end_log = dp[0].start_lba + dp[0].length;
+
+ if (!dp[0].start_lba ||
+ !dp[0].length ||
+ !sane(dp[0].start_lba, dp[0].length) ||
+ end_log > iter->sub.dos.ebr_size) {
+
+ error("Insane logical partition.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Extended partition must be sane, meaning:
+ * - must be extended or empty
+ * - must have non-0 start and length
+ * - values must not wrap around 32bit
+ * - must be inside base EBR frame
+ */
+
+static int notsane_extended(const struct part_iter *iter)
+{
+ const struct disk_dos_part_entry *dp;
+ uint32_t end_ebr;
+
+ dp = ((struct disk_dos_mbr *)iter->data)->table;
+
+ if (!dp[1].ostype)
+ return 0;
+
+ if (!ost_is_nondata(dp[1].ostype)) {
+ error("2nd EBR entry must be extended or empty.\n");
+ return -1;
+ }
+
+ end_ebr = dp[1].start_lba + dp[1].length;
+
+ if (!dp[1].start_lba ||
+ !dp[1].length ||
+ !sane(dp[1].start_lba, dp[1].length) ||
+ end_ebr > iter->sub.dos.bebr_size) {
+
+ error("Insane extended partition.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Primary partition must be sane, meaning:
+ * - must have non-0 start and length
+ * - values must not wrap around 32bit
+ */
+
+static int notsane_primary(const struct part_iter *iter)
+{
+ const struct disk_dos_part_entry *dp;
+ dp = ((struct disk_dos_mbr *)iter->data)->table + iter->index0;
+
+ if (!dp->ostype)
+ return 0;
+
+ if (!dp->start_lba ||
+ !dp->length ||
+ !sane(dp->start_lba, dp->length) ||
+ dp->start_lba + dp->length > iter->di.lbacnt) {
+ error("Insane primary (MBR) partition.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int notsane_gpt(const struct part_iter *iter)
+{
+ const struct disk_gpt_part_entry *gp;
+ gp = (const struct disk_gpt_part_entry *)
+ (iter->data + iter->index0 * iter->sub.gpt.pe_size);
+
+ if (guid_is0(&gp->type))
+ return 0;
+
+ if (gp->lba_first < iter->sub.gpt.ufirst ||
+ gp->lba_last > iter->sub.gpt.ulast) {
+ error("Insane GPT partition.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int pi_dos_next_mbr(struct part_iter *iter, uint32_t *lba,
+ struct disk_dos_part_entry **_dp)
+{
+ struct disk_dos_part_entry *dp;
+
+ while (++iter->index0 < 4) {
+ dp = ((struct disk_dos_mbr *)iter->data)->table + iter->index0;
+
+ if (notsane_primary(iter)) {
+ iter->status = PI_INSANE;
+ goto bail;
+ }
+
+ if (ost_is_ext(dp->ostype)) {
+ if (iter->sub.dos.bebr_index0 >= 0) {
+ error("You have more than 1 extended partition.\n");
+ iter->status = PI_INSANE;
+ goto bail;
+ }
+ /* record base EBR index */
+ iter->sub.dos.bebr_index0 = iter->index0;
+ }
+ if (!ost_is_nondata(dp->ostype) || iter->stepall) {
+ *lba = dp->start_lba;
+ *_dp = dp;
+ break;
+ }
+ }
+
+ return 0;
+bail:
+ return -1;
+}
+
+static int prep_base_ebr(struct part_iter *iter)
+{
+ struct disk_dos_part_entry *dp;
+
+ if (iter->sub.dos.bebr_index0 < 0) /* if we don't have base extended partition at all */
+ return -1;
+ else if (!iter->sub.dos.bebr_start) { /* if not initialized yet */
+ dp = ((struct disk_dos_mbr *)iter->data)->table + iter->sub.dos.bebr_index0;
+
+ iter->sub.dos.bebr_start = dp->start_lba;
+ iter->sub.dos.bebr_size = dp->length;
+
+ iter->sub.dos.ebr_start = 0;
+ iter->sub.dos.ebr_size = iter->sub.dos.bebr_size;
+
+ iter->sub.dos.cebr_lba = 0;
+ iter->sub.dos.nebr_lba = iter->sub.dos.bebr_start;
+
+ iter->index0--;
+ }
+ return 0;
+}
+
+static int pi_dos_next_ebr(struct part_iter *iter, uint32_t *lba,
+ struct disk_dos_part_entry **_dp)
+{
+ struct disk_dos_part_entry *dp;
+
+ if (prep_base_ebr(iter)) {
+ iter->status = PI_DONE;
+ return -1;
+ }
+
+ while (++iter->index0 < 1024 && iter->sub.dos.nebr_lba) {
+ free(iter->data);
+ if (!(iter->data =
+ disk_read_sectors(&iter->di, iter->sub.dos.nebr_lba, 1))) {
+ error("Couldn't load EBR.\n");
+ iter->status = PI_ERRLOAD;
+ return -1;
+ }
+
+ if (notsane_logical(iter) || notsane_extended(iter)) {
+ iter->status = PI_INSANE;
+ return -1;
+ }
+
+ dp = ((struct disk_dos_mbr *)iter->data)->table;
+
+ iter->sub.dos.cebr_lba = iter->sub.dos.nebr_lba;
+
+ /* setup next frame values */
+ if (dp[1].ostype) {
+ iter->sub.dos.ebr_start = dp[1].start_lba;
+ iter->sub.dos.ebr_size = dp[1].length;
+ iter->sub.dos.nebr_lba = iter->sub.dos.bebr_start + dp[1].start_lba;
+ } else {
+ iter->sub.dos.ebr_start = 0;
+ iter->sub.dos.ebr_size = 0;
+ iter->sub.dos.nebr_lba = 0;
+ }
+
+ if (!dp[0].ostype)
+ iter->sub.dos.skipcnt++;
+
+ if (dp[0].ostype || iter->stepall) {
+ *lba = iter->sub.dos.cebr_lba + dp[0].start_lba;
+ *_dp = dp;
+ return 0;
+ }
+ /*
+ * This way it's possible to continue, if some crazy soft left a "hole"
+ * - EBR with a valid extended partition without a logical one. In
+ * such case, linux will not reserve a number for such hole - so we
+ * don't increase index0. If stepall flag is set, we will never reach
+ * this place.
+ */
+ }
+ iter->status = PI_DONE;
+ return -1;
+}
+
+static struct part_iter *pi_dos_next(struct part_iter *iter)
+{
+ uint32_t start_lba = 0;
+ struct disk_dos_part_entry *dos_part = NULL;
+
+ if (iter->status)
+ goto bail;
+
+ /* look for primary partitions */
+ if (iter->index0 < 4 &&
+ pi_dos_next_mbr(iter, &start_lba, &dos_part))
+ goto bail;
+
+ /* look for logical partitions */
+ if (iter->index0 >= 4 &&
+ pi_dos_next_ebr(iter, &start_lba, &dos_part))
+ goto bail;
+
+ /*
+ * note special index handling, if we have stepall set -
+ * this is made to keep index consistent with non-stepall
+ * iterators
+ */
+
+ if (iter->index0 >= 4 && !dos_part->ostype)
+ iter->index = -1;
+ else
+ iter->index = iter->index0 - iter->sub.dos.skipcnt + 1;
+ iter->rawindex = iter->index0 + 1;
+ iter->start_lba = start_lba;
+ iter->length = dos_part->length;
+ iter->record = (char *)dos_part;
+
+#ifdef DEBUG
+ disk_dos_part_dump(dos_part);
+#endif
+
+ return iter;
+bail:
+ return NULL;
+}
+
+static void gpt_conv_label(struct part_iter *iter)
+{
+ const struct disk_gpt_part_entry *gp;
+ const int16_t *orig_lab;
+
+ gp = (const struct disk_gpt_part_entry *)
+ (iter->data + iter->index0 * iter->sub.gpt.pe_size);
+ orig_lab = (const int16_t *)gp->name;
+
+ /* caveat: this is very crude conversion */
+ for (int i = 0; i < PI_GPTLABSIZE/2; i++) {
+ iter->sub.gpt.part_label[i] = (char)orig_lab[i];
+ }
+ iter->sub.gpt.part_label[PI_GPTLABSIZE/2] = 0;
+}
+
+static struct part_iter *pi_gpt_next(struct part_iter *iter)
+{
+ const struct disk_gpt_part_entry *gpt_part = NULL;
+
+ if (iter->status)
+ goto bail;
+
+ while (++iter->index0 < iter->sub.gpt.pe_count) {
+ gpt_part = (const struct disk_gpt_part_entry *)
+ (iter->data + iter->index0 * iter->sub.gpt.pe_size);
+
+ if (notsane_gpt(iter)) {
+ iter->status = PI_INSANE;
+ goto bail;
+ }
+
+ if (!guid_is0(&gpt_part->type) || iter->stepall)
+ break;
+ }
+ /* no more partitions ? */
+ if (iter->index0 == iter->sub.gpt.pe_count) {
+ iter->status = PI_DONE;
+ goto bail;
+ }
+ /* gpt_part is guaranteed to be valid here */
+ iter->index = iter->index0 + 1;
+ iter->rawindex = iter->index0 + 1;
+ iter->start_lba = gpt_part->lba_first;
+ iter->length = gpt_part->lba_last - gpt_part->lba_first + 1;
+ iter->record = (char *)gpt_part;
+ memcpy(&iter->sub.gpt.part_guid, &gpt_part->uid, sizeof(struct guid));
+ gpt_conv_label(iter);
+
+#ifdef DEBUG
+ disk_gpt_part_dump(gpt_part);
+#endif
+
+ return iter;
+bail:
+ return NULL;
+}
+
+static struct part_iter *pi_raw_next(struct part_iter *iter)
+{
+ iter->status = PI_DONE;
+ return NULL;
+}
+
+static int check_crc(uint32_t crc_match, const uint8_t *buf, unsigned int siz)
+{
+ uint32_t crc;
+
+ crc = crc32(0, NULL, 0);
+ crc = crc32(crc, buf, siz);
+
+ return crc_match != crc;
+}
+
+static int gpt_check_hdr_crc(const struct disk_info * const diskinfo, struct disk_gpt_header **_gh)
+{
+ struct disk_gpt_header *gh = *_gh;
+ uint64_t lba_alt;
+ uint32_t hold_crc32;
+
+ hold_crc32 = gh->chksum;
+ gh->chksum = 0;
+ if (check_crc(hold_crc32, (const uint8_t *)gh, gh->hdr_size)) {
+ error("WARNING: Primary GPT header checksum invalid.\n");
+ /* retry with backup */
+ lba_alt = gh->lba_alt;
+ free(gh);
+ if (!(gh = *_gh = disk_read_sectors(diskinfo, lba_alt, 1))) {
+ error("Couldn't read backup GPT header.\n");
+ return -1;
+ }
+ hold_crc32 = gh->chksum;
+ gh->chksum = 0;
+ if (check_crc(hold_crc32, (const uint8_t *)gh, gh->hdr_size)) {
+ error("Secondary GPT header checksum invalid.\n");
+ return -1;
+ }
+ }
+ /* restore old checksum */
+ gh->chksum = hold_crc32;
+
+ return 0;
+}
+
+/*
+ * ----------------------------------------------------------------------------
+ * Following functions are for users to call.
+ * ----------------------------------------------------------------------------
+ */
+
+
+int pi_next(struct part_iter **_iter)
+{
+ struct part_iter *iter;
+
+ if(!_iter || !*_iter)
+ return 0;
+ iter = *_iter;
+#ifdef DEBUG
+ if (inv_type(iter->type)) {
+ error("This is not a valid iterator.\n");
+ return 0;
+ }
+#endif
+ if ((iter = iter->type->next(iter))) {
+ *_iter = iter;
+ }
+ return (*_iter)->status;
+}
+
+/**
+ * pi_new() - get new iterator
+ * @itertype: iterator type
+ * @...: variable arguments passed to ctors
+ *
+ * Variable arguments depend on the type. Please see functions:
+ * iter_gpt_ctor() and iter_dos_ctor() for details.
+ **/
+struct part_iter *pi_new(const struct itertype *type, ...)
+{
+ int badctor = 0;
+ struct part_iter *iter = NULL;
+ va_list ap;
+
+ va_start(ap, type);
+
+#ifdef DEBUG
+ if (inv_type(type)) {
+ error("Unknown iterator requested.\n");
+ goto bail;
+ }
+#endif
+
+ if (!(iter = malloc(sizeof(struct part_iter)))) {
+ error("Couldn't allocate memory for the iterator.\n");
+ goto bail;
+ }
+
+ memset(iter, 0, sizeof(struct part_iter));
+ iter->type = type;
+
+ if (type->ctor(iter, &ap)) {
+ badctor = -1;
+ error("Cannot initialize the iterator.\n");
+ goto bail;
+ }
+
+bail:
+ va_end(ap);
+ if (badctor) {
+ free(iter);
+ iter = NULL;
+ }
+ return iter;
+}
+
+/**
+ * pi_del() - delete iterator
+ * @iter: iterator double pointer
+ *
+ **/
+
+void pi_del(struct part_iter **_iter)
+{
+ struct part_iter *iter;
+
+ if(!_iter || !*_iter)
+ return;
+ iter = *_iter;
+
+#ifdef DEBUG
+ if (inv_type(iter->type)) {
+ error("This is not a valid iterator.\n");
+ return;
+ }
+#endif
+
+ iter->type->dtor(iter);
+ free(iter);
+ *_iter = NULL;
+}
+
+/**
+ * pi_begin() - check disk, validate, and get proper iterator
+ * @di: diskinfo struct pointer
+ *
+ * This function checks the disk for GPT or legacy partition table and allocates
+ * an appropriate iterator.
+ **/
+struct part_iter *pi_begin(const struct disk_info *di, int stepall)
+{
+ int setraw = 0;
+ struct part_iter *iter = NULL;
+ struct disk_dos_mbr *mbr = NULL;
+ struct disk_gpt_header *gpth = NULL;
+ struct disk_gpt_part_entry *gptl = NULL;
+
+ /* Read MBR */
+ if (!(mbr = disk_read_sectors(di, 0, 1))) {
+ error("Couldn't read first disk sector.\n");
+ goto bail;
+ }
+
+ setraw = -1;
+
+ /* Check for MBR magic*/
+ if (mbr->sig != disk_mbr_sig_magic) {
+ error("No MBR magic.\n");
+ goto bail;
+ }
+
+ /* Check for GPT protective MBR */
+ if (mbr->table[0].ostype == 0xEE) {
+ if (!(gpth = disk_read_sectors(di, 1, 1))) {
+ error("Couldn't read potential GPT header.\n");
+ goto bail;
+ }
+ }
+
+ if (gpth && gpth->rev.uint32 == 0x00010000 &&
+ !memcmp(gpth->sig, disk_gpt_sig_magic, sizeof(disk_gpt_sig_magic))) {
+ /* looks like GPT v1.0 */
+ uint64_t gpt_loff; /* offset to GPT partition list in sectors */
+ uint64_t gpt_lsiz; /* size of GPT partition list in bytes */
+ uint64_t gpt_lcnt; /* size of GPT partition in sectors */
+#ifdef DEBUG
+ puts("Looks like a GPT v1.0 disk.");
+ disk_gpt_header_dump(gpth);
+#endif
+ /* Verify checksum, fallback to backup, then bail if invalid */
+ if (gpt_check_hdr_crc(di, &gpth))
+ goto bail;
+
+ gpt_loff = gpth->lba_table;
+ gpt_lsiz = (uint64_t)gpth->part_size * gpth->part_count;
+ gpt_lcnt = (gpt_lsiz + di->bps - 1) / di->bps;
+
+ /*
+ * disk_read_sectors allows reading of max 255 sectors, so we use
+ * it as a sanity check base. EFI doesn't specify max (AFAIK).
+ * Apart from that, some extensive sanity checks.
+ */
+ if (!gpt_loff || !gpt_lsiz || gpt_lcnt > 255u ||
+ gpth->lba_first_usable > gpth->lba_last_usable ||
+ !sane(gpt_loff, gpt_lcnt) ||
+ gpt_loff + gpt_lcnt > gpth->lba_first_usable ||
+ !sane(gpth->lba_last_usable, gpt_lcnt) ||
+ gpth->lba_last_usable + gpt_lcnt >= gpth->lba_alt ||
+ gpth->lba_alt >= di->lbacnt ||
+ gpth->part_size < sizeof(struct disk_gpt_part_entry)) {
+ error("Invalid GPT header's values.\n");
+ goto bail;
+ }
+ if (!(gptl = disk_read_sectors(di, gpt_loff, (uint8_t)gpt_lcnt))) {
+ error("Couldn't read GPT partition list.\n");
+ goto bail;
+ }
+ /* Check array checksum(s). */
+ if (check_crc(gpth->table_chksum, (const uint8_t *)gptl, (unsigned int)gpt_lsiz)) {
+ error("WARNING: GPT partition list checksum invalid, trying backup.\n");
+ free(gptl);
+ /* secondary array directly precedes secondary header */
+ if (!(gptl = disk_read_sectors(di, gpth->lba_alt - gpt_lcnt, (uint8_t)gpt_lcnt))) {
+ error("Couldn't read backup GPT partition list.\n");
+ goto bail;
+ }
+ if (check_crc(gpth->table_chksum, (const uint8_t *)gptl, (unsigned int)gpt_lsiz)) {
+ error("Backup GPT partition list checksum invalid.\n");
+ goto bail;
+ }
+ }
+ /* allocate iterator and exit */
+ iter = pi_new(typegpt, di, stepall, gpth, gptl);
+ } else {
+ /* looks like MBR */
+ iter = pi_new(typedos, di, stepall, mbr);
+ }
+
+ setraw = 0;
+bail:
+ if (setraw) {
+ error("WARNING: treating disk as raw.\n");
+ iter = pi_new(typeraw, di, stepall);
+ }
+ free(mbr);
+ free(gpth);
+ free(gptl);
+
+ return iter;
+}
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/partiter.h b/com32/chain/partiter.h
new file mode 100644
index 00000000..7deeb534
--- /dev/null
+++ b/com32/chain/partiter.h
@@ -0,0 +1,107 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2003-2010 H. Peter Anvin - All Rights Reserved
+ * Copyright 2010 Michal Soltys
+ * Copyright 2010 Shao Miller
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * partiter.h
+ *
+ * Provides disk / partition iteration.
+ */
+
+#ifndef _COM32_CHAIN_PARTITER_H
+#define _COM32_CHAIN_PARTITER_H
+
+#include <stdint.h>
+#include <syslinux/disk.h>
+
+#define PI_ERRLOAD 3
+#define PI_INSANE 2
+#define PI_DONE 1
+#define PI_OK 0
+
+struct itertype;
+struct part_iter;
+
+struct itertype {
+ int (*ctor)(struct part_iter *, va_list *);
+ void (*dtor)(struct part_iter *);
+ struct part_iter *(*next) (struct part_iter *);
+};
+
+#define PI_GPTLABSIZE ((int)sizeof(((struct disk_gpt_part_entry *)0)->name))
+
+struct part_iter {
+ const struct itertype *type;
+ char *data;
+ char *record;
+ uint64_t start_lba;
+ uint64_t length;
+ int index;
+ int rawindex;
+ struct disk_info di;
+ int stepall;
+ int status;
+ /* internal */
+ int index0;
+ union _sub {
+ struct _dos {
+ uint32_t disk_sig;
+ uint32_t nebr_lba;
+ uint32_t cebr_lba;
+ /* internal */
+ uint32_t ebr_start;
+ uint32_t ebr_size;
+ uint32_t bebr_start;
+ uint32_t bebr_size;
+ int bebr_index0;
+ int skipcnt;
+ } dos;
+ struct _gpt {
+ struct guid disk_guid;
+ struct guid part_guid;
+ char part_label[PI_GPTLABSIZE/2+1];
+ int pe_count;
+ int pe_size;
+ uint64_t ufirst;
+ uint64_t ulast;
+ } gpt;
+ } sub;
+};
+
+extern const struct itertype * const typedos;
+extern const struct itertype * const typegpt;
+extern const struct itertype * const typeraw;
+
+struct part_iter *pi_begin(const struct disk_info *, int stepall);
+struct part_iter *pi_new(const struct itertype *, ...);
+void pi_del(struct part_iter **);
+int pi_next(struct part_iter **);
+
+#endif
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/utility.c b/com32/chain/utility.c
new file mode 100644
index 00000000..cb882722
--- /dev/null
+++ b/com32/chain/utility.c
@@ -0,0 +1,204 @@
+#include <com32.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <fs.h>
+#include <syslinux/disk.h>
+#include <syslinux/pmapi.h>
+#include "utility.h"
+
+static const char *bpbtypes[] = {
+ [0] = "unknown",
+ [1] = "2.0",
+ [2] = "3.0",
+ [3] = "3.2",
+ [4] = "3.4",
+ [5] = "4.0",
+ [6] = "8.0 (NT+)",
+ [7] = "7.0",
+};
+
+void error(const char *msg)
+{
+ fputs(msg, stderr);
+}
+
+int guid_is0(const struct guid *guid)
+{
+ return !*(const uint64_t *)guid && !*((const uint64_t *)guid + 1);
+}
+
+void wait_key(void)
+{
+ int cnt;
+ char junk;
+
+ /* drain */
+ do {
+ errno = 0;
+ cnt = read(0, &junk, 1);
+ } while (cnt > 0 || (cnt < 0 && errno == EAGAIN));
+
+ /* wait */
+ do {
+ errno = 0;
+ cnt = read(0, &junk, 1);
+ } while (!cnt || (cnt < 0 && errno == EAGAIN));
+}
+
+void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, uint32_t mode)
+{
+ uint32_t c, h, s, t;
+ uint32_t cs, hs, ss;
+
+ /*
+ * Not much reason here, but if we have no valid CHS geometry, we assume
+ * "typical" ones to have something to return.
+ */
+ if (di->cbios) {
+ cs = di->cyl;
+ hs = di->head;
+ ss = di->spt;
+ if (mode == l2c_cadd && cs < 1024 && di->lbacnt > cs*hs*ss)
+ cs++;
+ else if (mode == l2c_cmax)
+ cs = 1024;
+ } else {
+ if (di->disk & 0x80) {
+ cs = 1024;
+ hs = 255;
+ ss = 63;
+ } else {
+ cs = 80;
+ hs = 2;
+ ss = 18;
+ }
+ }
+
+ if (lba >= cs*hs*ss) {
+ s = ss;
+ h = hs - 1;
+ c = cs - 1;
+ } else {
+ s = ((uint32_t)lba % ss) + 1;
+ t = (uint32_t)lba / ss;
+ h = t % hs;
+ c = t / hs;
+ }
+
+ (*dst)[0] = h;
+ (*dst)[1] = s | ((c & 0x300) >> 2);
+ (*dst)[2] = c;
+}
+
+uint32_t get_file_lba(const char *filename)
+{
+ struct com32_filedata fd;
+ uint32_t lba = 0;
+ int size = 65536;
+ char *buf;
+
+ buf = lmalloc(size);
+ if (!buf)
+ return 0;
+
+ /* Put the filename in the bounce buffer */
+ strlcpy(buf, filename, size);
+
+ if (open_file(buf, &fd) <= 0) {
+ goto fail; /* Filename not found */
+ }
+
+ /* Since the first member is the LBA, we simply cast */
+ lba = *((uint32_t *) MK_PTR(0, fd.handle));
+
+ /* Call comapi_close() to free the structure */
+ close_file(fd.handle);
+
+fail:
+ lfree(buf);
+ return lba;
+}
+
+/* drive offset detection */
+int drvoff_detect(int type, unsigned int *off)
+{
+ if (bpbV40 <= type && type <= bpbVNT) {
+ *off = 0x24;
+ } else if (type == bpbV70) {
+ *off = 0x40;
+ } else
+ return 0;
+
+ return -1;
+}
+
+/*
+ * heuristics could certainly be improved
+ */
+int bpb_detect(const uint8_t *sec, const char *tag)
+{
+ int a, b, c, jmp = -1, rev = 0;
+
+ /* media descriptor check */
+ if ((sec[0x15] & 0xF0) != 0xF0)
+ goto out;
+
+ if (sec[0] == 0xEB) /* jump short */
+ jmp = 2 + *(int8_t *)(sec + 1);
+ else if (sec[0] == 0xE9) /* jump near */
+ jmp = 3 + *(int16_t *)(sec + 1);
+
+ if (jmp < 0) /* no boot code at all ? */
+ goto nocode;
+
+ /* sanity */
+ if (jmp < 0x18 || jmp > 0x1F0)
+ goto out;
+
+ /* detect by jump */
+ if (jmp >= 0x18 && jmp < 0x1E)
+ rev = bpbV20;
+ else if (jmp >= 0x1E && jmp < 0x20)
+ rev = bpbV30;
+ else if (jmp >= 0x20 && jmp < 0x24)
+ rev = bpbV32;
+ else if (jmp >= 0x24 && jmp < 0x46)
+ rev = bpbV34;
+
+ /* TODO: some better V2 - V3.4 checks ? */
+
+ if (rev)
+ goto out;
+ /*
+ * BPB info:
+ * 2.0 == 0x0B - 0x17
+ * 3.0 == 2.0 + 0x18 - 0x1D
+ * 3.2 == 3.0 + 0x1E - 0x1F
+ * 3.4 ==!2.0 + 0x18 - 0x23
+ * 4.0 == 3.4 + 0x24 - 0x45
+ * NT ==~3.4 + 0x24 - 0x53
+ * 7.0 == 3.4 + 0x24 - 0x59
+ */
+
+nocode:
+ a = memcmp(sec + 0x03, "NTFS", 4);
+ b = memcmp(sec + 0x36, "FAT", 3);
+ c = memcmp(sec + 0x52, "FAT", 3); /* ext. DOS 7+ bs */
+
+ if ((sec[0x26] & 0xFE) == 0x28 && !b) {
+ rev = bpbV40;
+ } else if (sec[0x26] == 0x80 && !a) {
+ rev = bpbVNT;
+ } else if ((sec[0x42] & 0xFE) == 0x28 && !c) {
+ rev = bpbV70;
+ }
+
+out:
+ printf("BPB detection (%s): %s\n", tag, bpbtypes[rev]);
+ return rev;
+}
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/chain/utility.h b/com32/chain/utility.h
new file mode 100644
index 00000000..8a08be71
--- /dev/null
+++ b/com32/chain/utility.h
@@ -0,0 +1,30 @@
+#ifndef _COM32_CHAIN_UTILITY_H
+#define _COM32_CHAIN_UTILITY_H
+
+#include <stdint.h>
+#include <syslinux/disk.h>
+
+#define bpbUNK 0
+#define bpbV20 1
+#define bpbV30 2
+#define bpbV32 3
+#define bpbV34 4
+#define bpbV40 5
+#define bpbVNT 6
+#define bpbV70 7
+
+#define l2c_cnul 0
+#define l2c_cadd 1
+#define l2c_cmax 2
+
+void error(const char *msg);
+int guid_is0(const struct guid *guid);
+void wait_key(void);
+void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, uint32_t mode);
+uint32_t get_file_lba(const char *filename);
+int drvoff_detect(int type, unsigned int *off);
+int bpb_detect(const uint8_t *bpb, const char *tag);
+
+#endif
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
diff --git a/com32/cmenu/Makefile b/com32/cmenu/Makefile
index 00825b46..c6e0cae3 100644
--- a/com32/cmenu/Makefile
+++ b/com32/cmenu/Makefile
@@ -17,22 +17,24 @@
NOGPL := 1
-# This must be defined before com32.mk is included
-LIBS = libmenu/libmenu.c32
-
topdir = ../..
MAKEDIR = $(topdir)/mk
include $(MAKEDIR)/elf.mk
CFLAGS += -I./libmenu
+LIBS = libmenu/libmenu.c32 \
+ $(com32)/libutil/libutil_com.c32 \
+ $(com32)/lib/libcom32.c32
+
LIBMENU = libmenu/syslnx.o libmenu/com32io.o libmenu/tui.o \
- libmenu/menu.o libmenu/passwords.o libmenu/des.o libmenu/help.o
+ libmenu/menu.o libmenu/passwords.o libmenu/des.o libmenu/help.o \
+ $(com32)/libutil/libutil_com.c32 $(com32)/lib/libcom32.c32
CMENUS = $(patsubst %.c,%.c32,$(wildcard *.c))
IMENUS = $(patsubst %.menu,%.c32,$(wildcard *.menu))
-MENUS = $(CMENUS) $(IMENUS) $(LIBS)
+MENUS = $(LIBS) $(CMENUS) $(IMENUS)
.SUFFIXES: .S .c .o .elf .c32 .menu
@@ -40,7 +42,7 @@ MENUS = $(CMENUS) $(IMENUS) $(LIBS)
%.c: %.menu adv_menu.tpl
python menugen.py --input=$< --output=$@ --template=adv_menu.tpl
-all: menus
+all: menus
libmenu/libmenu.c32: $(LIBMENU)
$(LD) -shared $(LDFLAGS) -o $@ $^
diff --git a/com32/cmenu/libmenu/syslnx.c b/com32/cmenu/libmenu/syslnx.c
index 53e2401b..c681f585 100644
--- a/com32/cmenu/libmenu/syslnx.c
+++ b/com32/cmenu/libmenu/syslnx.c
@@ -12,7 +12,10 @@
#include <string.h>
#include <com32.h>
+#include <core.h>
+#include <graphics.h>
#include "syslnx.h"
+#include <syslinux/config.h>
com32sys_t inreg, outreg; // Global registers for this module
@@ -28,40 +31,40 @@ char issyslinux(void)
void runsyslinuxcmd(const char *cmd)
{
- strcpy(__com32.cs_bounce, cmd);
- REG_AX(inreg) = 0x0003; // Run command
- REG_BX(inreg) = OFFS(__com32.cs_bounce);
- REG_ES(inreg) = SEG(__com32.cs_bounce);
- __intcall(0x22, &inreg, &outreg);
+ char *bounce;
+
+ bounce = lmalloc(strlen(cmd) + 1);
+ if (!bounce)
+ return;
+
+ strcpy(bounce, cmd);
+ load_kernel(bounce);
}
void gototxtmode(void)
{
- REG_AX(inreg) = 0x0005;
- __intcall(0x22, &inreg, &outreg);
+ syslinux_force_text_mode();
}
void syslinux_idle(void)
{
- REG_AX(inreg) = 0x0013;
- __intcall(0x22, &inreg, &outreg);
+ __idle();
}
unsigned int getversion(char *deriv, unsigned int *numfun)
{
- REG_AX(inreg) = 0x0001;
- __intcall(0x22, &inreg, &outreg);
if (deriv)
- *deriv = REG_DL(outreg);
+ *deriv = __syslinux_version.filesystem;
if (numfun)
- *numfun = REG_AX(outreg);
- return REG_CX(outreg);
+ *numfun = __syslinux_version.max_api;
+ return __syslinux_version.version;
}
void runsyslinuximage(const char *cmd, long ipappend)
{
unsigned int numfun = 0;
char *ptr, *cmdline;
+ char *bounce;
(void)ipappend; // XXX: Unused?!
@@ -71,8 +74,12 @@ void runsyslinuximage(const char *cmd, long ipappend)
runsyslinuxcmd(cmd);
// Try the Run Kernel Image function
// Split command line into
- strcpy(__com32.cs_bounce, cmd);
- ptr = __com32.cs_bounce;
+ bounce = lmalloc(strlen(cmd) + 1);
+ if (!bounce)
+ return;
+
+ strcpy(bounce, cmd);
+ ptr = bounce;
// serach for first space or end of string
while ((*ptr) && (*ptr != ' '))
ptr++;
@@ -87,8 +94,8 @@ void runsyslinuximage(const char *cmd, long ipappend)
// Now call the interrupt
REG_BX(inreg) = OFFS(cmdline);
REG_ES(inreg) = SEG(cmdline);
- REG_SI(inreg) = OFFS(__com32.cs_bounce);
- REG_DS(inreg) = SEG(__com32.cs_bounce);
+ REG_SI(inreg) = OFFS(bounce);
+ REG_DS(inreg) = SEG(bounce);
REG_EDX(inreg) = 0;
__intcall(0x22, &inreg, &outreg); // If successful does not return
diff --git a/com32/elflink/Makefile b/com32/elflink/Makefile
index aca37438..fce1be8c 100644
--- a/com32/elflink/Makefile
+++ b/com32/elflink/Makefile
@@ -19,8 +19,8 @@ test_memalign.elf : test_memalign.o $(LIBS) $(C_LIBS)
$(LD) $(LDFLAGS) -o $@ $^
test_com32.elf: CFLAGS += -DELF_DEBUG
-test_com32.elf: test_com32.o ../libutil/libutil_com.a ../lib/libcom32min.a $(LIBGCC)
- $(LD) -n $(LDFLAGS) -o $@ test_com32.o ../libutil/libutil_com.a $(LIBGCC) --whole-archive ../lib/libcom32min.a -Map test_com32.map
+test_com32.elf: test_com32.o ../lib/libcom32min.a $(LIBGCC)
+ $(LD) -n $(LDFLAGS) -o $@ test_com32.o $(LIBGCC) --whole-archive ../lib/libcom32min.a -Map test_com32.map
tidy dist:
rm -f *.o *.lo *.a *.lst *.elf .*.d *.map
@@ -31,8 +31,6 @@ clean: tidy
spotless: clean
rm -f *~ \#*
-install: all
- mkdir -m 755 -p $(INSTALLROOT)$(AUXDIR)
- install -m 644 $(MODULES) $(INSTALLROOT)$(AUXDIR)
+install:
-include .*.d
diff --git a/com32/elflink/ldlinux/Makefile b/com32/elflink/ldlinux/Makefile
index 5927e500..dc48ca97 100644
--- a/com32/elflink/ldlinux/Makefile
+++ b/com32/elflink/ldlinux/Makefile
@@ -15,13 +15,14 @@ MAKEDIR = $(topdir)/mk
include $(MAKEDIR)/elf.mk
CFLAGS += -I$(topdir)/core/elflink -I$(topdir)/core/include
+LIBS = --whole-archive $(com32)/lib/libcom32min.a
all: ldlinux.c32 ldlinux_lnx.a
ldlinux.c32 : ldlinux.o cli.o readconfig.o refstr.o colors.o getadv.o \
- adv.o ipappend.o execute.o kernel.o get_key.o \
- advwrite.o setadv.o eprintf.o
- $(LD) $(LDFLAGS) -o $@ $^
+ adv.o execute.o chainboot.o kernel.o get_key.o \
+ advwrite.o setadv.o eprintf.o loadhigh.o
+ $(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
LNXLIBOBJS = get_key.lo
ldlinux_lnx.a: $(LNXLIBOBJS)
diff --git a/com32/elflink/ldlinux/adv.c b/com32/elflink/ldlinux/adv.c
index cf02d129..ae473908 100644
--- a/com32/elflink/ldlinux/adv.c
+++ b/com32/elflink/ldlinux/adv.c
@@ -33,8 +33,12 @@
#include <syslinux/adv.h>
#include <syslinux/firmware.h>
+#include <klibc/compiler.h>
-void __syslinux_init(void)
+void *__syslinux_adv_ptr;
+size_t __syslinux_adv_size;
+
+void __constructor __syslinux_init(void)
{
firmware->adv_ops->init();
}
diff --git a/com32/elflink/ldlinux/chainboot.c b/com32/elflink/ldlinux/chainboot.c
new file mode 100644
index 00000000..4a4a2e1a
--- /dev/null
+++ b/com32/elflink/ldlinux/chainboot.c
@@ -0,0 +1,157 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2012 Intel Corporation, author: H. Peter Anvin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * chainbooting - replace the current bootloader completely. This
+ * is BIOS-specific.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <dprintf.h>
+
+#include <com32.h>
+#include <sys/exec.h>
+#include <sys/io.h>
+#include "core.h"
+#include "menu.h"
+#include "fs.h"
+#include "config.h"
+#include "localboot.h"
+#include "bios.h"
+
+#include <syslinux/boot.h>
+#include <syslinux/bootrm.h>
+#include <syslinux/movebits.h>
+#include <syslinux/config.h>
+
+void chainboot_file(const char *file, uint32_t type)
+{
+ uint8_t keeppxe = 0;
+ const union syslinux_derivative_info *sdi;
+ struct syslinux_rm_regs regs;
+ struct syslinux_movelist *fraglist = NULL;
+ struct syslinux_memmap *mmap = NULL;
+ struct com32_filedata fd;
+ com32sys_t reg;
+ char *stack;
+ void *buf;
+ int rv, max, size;
+
+ max = 0xA0000; /* Maximum load */
+ buf = malloc(max);
+ if (!buf)
+ goto bail;
+
+ rv = open_file(file, &fd);
+ if (rv == -1) {
+ free(buf);
+ goto bail;
+ }
+
+ reg.eax.l = max;
+ reg.ebx.l = 0;
+ reg.edx.w[0] = 0;
+ reg.edi.l = (uint32_t)buf;
+ reg.ebp.l = -1; /* XXX: limit? */
+ reg.esi.w[0] = rv;
+
+ pm_load_high(&reg);
+
+ size = reg.edi.l - (unsigned long)buf;
+ if (size > 0xA0000 - 0x7C00) {
+ printf("Too large for a boostrap (need LINUX instead of KERNEL?)\n");
+ goto bail;
+ }
+
+ mmap = syslinux_memory_map();
+ if (!mmap)
+ goto bail;
+
+ sdi = syslinux_derivative_info();
+
+ memset(&regs, 0, sizeof(regs));
+ regs.ip = 0x7c00;
+
+ if (sdi->c.filesystem == SYSLINUX_FS_SYSLINUX ||
+ sdi->c.filesystem == SYSLINUX_FS_EXTLINUX) {
+ if (syslinux_add_movelist(&fraglist, 0x800 - 18,
+ (addr_t)sdi->r.esbx, 16))
+ goto bail;
+
+ /* DS:SI points to partition info */
+ regs.esi.l = 0x800 - 18;
+ }
+
+ /*
+ * For a BSS boot sector we have to transfer the
+ * superblock.
+ */
+ if (sdi->c.filesystem == SYSLINUX_FS_SYSLINUX &&
+ type == IMAGE_TYPE_BSS && this_fs->fs_ops->copy_super(buf))
+ goto bail;
+
+ if (sdi->c.filesystem == SYSLINUX_FS_PXELINUX) {
+ keeppxe = 0x03; /* Chainloading + keep PXE */
+ stack = (char *)sdi->r.fssi;
+
+ /*
+ * Set up the registers with their initial values
+ */
+
+ regs.eax.l = *(uint32_t *)&stack[36];
+ regs.ecx.l = *(uint32_t *)&stack[32];
+ regs.edx.l = *(uint32_t *)&stack[28];
+ regs.ebx.l = *(uint32_t *)&stack[24];
+ regs.esp.l = sdi->rr.r.esi.w[0] + 44;
+ regs.ebp.l = *(uint32_t *)&stack[16];
+ regs.esi.l = *(uint32_t *)&stack[12];
+ regs.edi.l = *(uint32_t *)&stack[8];
+ regs.es = *(uint16_t *)&stack[4];
+ regs.ss = sdi->rr.r.fs;
+ regs.ds = *(uint16_t *)&stack[6];
+ regs.fs = *(uint16_t *)&stack[2];
+ regs.gs = *(uint16_t *)&stack[0];
+ } else {
+ const uint16_t *esdi = (const uint16_t *)sdi->disk.esdi_ptr;
+
+ regs.esp.l = (uint16_t)(unsigned long)StackBuf + 44;
+
+ /*
+ * DON'T DO THIS FOR PXELINUX...
+ * For PXE, ES:BX -> PXENV+, and this would
+ * corrupt that use.
+ *
+ * Restore ES:DI -> $PnP (if we were ourselves
+ * called that way...)
+ */
+ regs.edi.w[0] = esdi[0]; /* New DI */
+ regs.es = esdi[2]; /* New ES */
+
+ regs.edx.l = sdi->rr.r.edx.b[0]; /* Drive number -> DL */
+ }
+
+ if (syslinux_add_movelist(&fraglist, 0x7c00, (addr_t)buf, size))
+ goto bail;
+
+ syslinux_shuffle_boot_rm(fraglist, mmap, keeppxe, &regs);
+
+bail:
+ if (fraglist)
+ syslinux_free_movelist(fraglist);
+ if (mmap)
+ syslinux_free_memmap(mmap);
+ if (buf)
+ free(buf);
+ return;
+}
diff --git a/com32/elflink/ldlinux/cli.c b/com32/elflink/ldlinux/cli.c
index 7b2da880..a1cf50cc 100644
--- a/com32/elflink/ldlinux/cli.c
+++ b/com32/elflink/ldlinux/cli.c
@@ -19,8 +19,6 @@
#include "cli.h"
#include "config.h"
-static jmp_buf timeout_jump;
-
static struct list_head cli_history_head;
void clear_screen(void)
@@ -29,71 +27,37 @@ void clear_screen(void)
fputs("\033e\033%@\033)0\033(B\1#0\033[?25l\033[2J", stdout);
}
-static int __get_key(void)
-{
- unsigned char buffer[KEY_MAXLEN];
- int another;
- int nc, rv;
- int code;
-
- nc = 0;
- do {
- buffer[nc++] = getchar();
-
- another = 0;
- rv = get_key_decode(buffer, nc, &code);
- if (!rv)
- return code;
- else if (rv == 1)
- another = 1;
-
- } while (another);
-
- /* We got an unrecognized sequence; return the first character */
- /* We really should remember this and return subsequent characters later */
- return buffer[0];
-}
-
-int mygetkey(clock_t timeout)
+static int mygetkey_timeout(clock_t *kbd_to, clock_t *tto)
{
- clock_t t0, t;
- clock_t tto, to;
+ clock_t t0, t1;
int key;
- //dprintf("enter");
- if (!totaltimeout)
- return __get_key();
-
- for (;;) {
- tto = min(totaltimeout, INT_MAX);
- to = timeout ? min(tto, timeout) : tto;
+ t0 = times(NULL);
+ key = get_key(stdin, *kbd_to ? *kbd_to : *tto);
- t0 = 0;
- key = __get_key();
- t = 0 - t0;
+ /* kbdtimeout only applies to the first character */
+ if (*kbd_to)
+ *kbd_to = 0;
- if (totaltimeout <= t)
- longjmp(timeout_jump, 1);
+ t1 = times(NULL) - t0;
+ if (*tto) {
+ /* Timed out. */
+ if (*tto <= (long long)t1)
+ key = KEY_NONE;
+ else {
+ /* Did it wrap? */
+ if (*tto > totaltimeout)
+ key = KEY_NONE;
- totaltimeout -= t;
-
- if (key != KEY_NONE) {
- //dprintf("get key 0x%x", key);
- return key;
- }
-
- if (timeout) {
- if (timeout <= t) {
- //dprintf("timeout");
- return KEY_NONE;
- }
-
- timeout -= t;
+ *tto -= t1;
}
}
+
+ return key;
}
-static const char * cmd_reverse_search(int *cursor)
+static const char * cmd_reverse_search(int *cursor, clock_t *kbd_to,
+ clock_t *tto)
{
int key;
int i = 0;
@@ -108,7 +72,7 @@ static const char * cmd_reverse_search(int *cursor)
eprintf("\033[1G\033[1;36m(reverse-i-search)`': \033[0m");
while (1) {
- key = mygetkey(0);
+ key = mygetkey_timeout(kbd_to, tto);
if (key == KEY_CTRL('C')) {
return NULL;
@@ -124,7 +88,7 @@ static const char * cmd_reverse_search(int *cursor)
break;
}
- while (last_found != &cli_history_head) {
+ while (!list_is_last(&last_found->list, &cli_history_head)) {
p = strstr(last_found->command, buf);
if (p)
break;
@@ -164,7 +128,9 @@ const char *edit_cmdline(const char *input, int top /*, int width */ ,
bool done = false;
const char *ret;
int width = 0;
- struct cli_command *comm_counter;
+ struct cli_command *comm_counter = NULL;
+ clock_t kbd_to = kbdtimeout;
+ clock_t tto = totaltimeout;
if (!width) {
int height;
@@ -199,7 +165,7 @@ const char *edit_cmdline(const char *input, int top /*, int width */ ,
eprintf("\033[?7l\033[?25l");
if (y)
eprintf("\033[%dA", y);
- eprintf("\033[1G\033[1;36m%s \033[0m", input);
+ eprintf("\033[1G%s ", input);
x = strlen(input);
y = 0;
@@ -230,9 +196,13 @@ const char *edit_cmdline(const char *input, int top /*, int width */ ,
redraw = 0;
}
- key = mygetkey(0);
+ key = mygetkey_timeout(&kbd_to, &tto);
switch (key) {
+ case KEY_NONE:
+ /* We timed out. */
+ return NULL;
+
case KEY_CTRL('L'):
redraw = 2;
break;
@@ -406,7 +376,7 @@ const char *edit_cmdline(const char *input, int top /*, int width */ ,
* Handle this case in another function, since it's
* a kind of special.
*/
- const char *p = cmd_reverse_search(&cursor);
+ const char *p = cmd_reverse_search(&cursor, &kbd_to, &tto);
if (p) {
strcpy(cmdline, p);
len = strlen(cmdline);
@@ -479,17 +449,14 @@ const char *edit_cmdline(const char *input, int top /*, int width */ ,
return len ? ret : NULL;
}
-static int cli_init(void)
+static int __constructor cli_init(void)
{
INIT_LIST_HEAD(&cli_history_head);
return 0;
}
-static void cli_exit(void)
+static void __destructor cli_exit(void)
{
/* Nothing to do */
}
-
-MODULE_INIT(cli_init);
-MODULE_EXIT(cli_exit);
diff --git a/com32/elflink/ldlinux/config.h b/com32/elflink/ldlinux/config.h
index c34b2cc6..45832022 100644
--- a/com32/elflink/ldlinux/config.h
+++ b/com32/elflink/ldlinux/config.h
@@ -35,9 +35,16 @@ extern short nohalt; //idle.inc
extern const char *default_cmd; //"default" command line
extern const char *onerror; //"onerror" command line
+extern const char *ontimeout; //"ontimeout" command line
extern void cat_help_file(int key);
+extern struct menu_entry *find_label(const char *str);
+extern void print_labels(const char *prefix, size_t len);
extern void eprintf(const char *filename, ...);
+extern int new_linux_kernel(char *okernel, char *ocmdline);
+
+extern void pm_load_high(com32sys_t *regs);
+
#endif /* __CONFIG_H__ */
diff --git a/com32/elflink/ldlinux/eprintf.c b/com32/elflink/ldlinux/eprintf.c
index d8858ff9..f15edc6e 100644
--- a/com32/elflink/ldlinux/eprintf.c
+++ b/com32/elflink/ldlinux/eprintf.c
@@ -1,6 +1,7 @@
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
+#include <core.h>
#define BUFFER_SIZE 4096
diff --git a/com32/elflink/ldlinux/execute.c b/com32/elflink/ldlinux/execute.c
index 2b265a11..77d268c8 100644
--- a/com32/elflink/ldlinux/execute.c
+++ b/com32/elflink/ldlinux/execute.c
@@ -17,31 +17,39 @@
#include <com32.h>
#include <sys/exec.h>
+#include <sys/io.h>
#include "core.h"
#include "menu.h"
-
-/* Must match enum kernel_type */
-const char *const kernel_types[] = {
- "none",
- "localboot",
- "kernel",
- "linux",
- "boot",
- "bss",
- "pxe",
- "fdimage",
- "comboot",
- "com32",
- "config",
- NULL
+#include "fs.h"
+#include "config.h"
+#include "localboot.h"
+#include "bios.h"
+
+#include <syslinux/bootrm.h>
+#include <syslinux/movebits.h>
+#include <syslinux/config.h>
+#include <syslinux/boot.h>
+
+const struct image_types image_boot_types[] = {
+ { "localboot", IMAGE_TYPE_LOCALBOOT },
+ { "kernel", IMAGE_TYPE_KERNEL },
+ { "linux", IMAGE_TYPE_LINUX },
+ { "boot", IMAGE_TYPE_BOOT },
+ { "bss", IMAGE_TYPE_BSS },
+ { "pxe", IMAGE_TYPE_PXE },
+ { "fdimage", IMAGE_TYPE_FDIMAGE },
+ { "comboot", IMAGE_TYPE_COMBOOT },
+ { "com32", IMAGE_TYPE_COM32 },
+ { "config", IMAGE_TYPE_CONFIG },
+ { NULL, 0 },
};
extern int create_args_and_load(char *);
-void execute(const char *cmdline, enum kernel_type type)
+void execute(const char *cmdline, uint32_t type)
{
- const char *p, *const *pp;
const char *kernel, *args;
+ const char *p;
com32sys_t ireg;
char *q;
@@ -70,46 +78,44 @@ void execute(const char *cmdline, enum kernel_type type)
dprintf("kernel is %s, args = %s type = %d \n", kernel, args, type);
- if (kernel[0] == '.' && type == KT_NONE) {
+ if (kernel[0] == '.') {
/* It might be a type specifier */
- enum kernel_type type = KT_NONE;
- for (pp = kernel_types; *pp; pp++, type++) {
- if (!strcmp(kernel + 1, *pp))
- execute(p, type); /* Strip the type specifier and retry */
+ const struct image_types *t;
+ for (t = image_boot_types; t->name; t++) {
+ if (!strcmp(kernel + 1, t->name)) {
+ /* Strip the type specifier and retry */
+ execute(p, t->type);
+ return;
+ }
}
}
- if (type == KT_COM32) {
+ if (type == IMAGE_TYPE_COM32) {
/* new entry for elf format c32 */
- lfree(kernel);
- create_args_and_load(cmdline);
- } else if (type == KT_KERNEL) {
- /* Need add one item for kernel load, as we don't use
- * the assembly runkernel.inc any more */
- new_linux_kernel(kernel, cmdline);
- } else if (type == KT_CONFIG) {
+ create_args_and_load((char *)cmdline);
+ } else if (type == IMAGE_TYPE_CONFIG) {
+ char *argv[] = { "ldlinux.c32", NULL };
+
/* kernel contains the config file name */
- char *spawn_load_param[2] = { args, NULL };
- spawn_load(kernel, 1, spawn_load_param);
+ realpath(ConfigName, kernel, FILENAME_MAX);
+
+ /* If we got anything on the command line, do a chdir */
+ if (*args)
+ mangle_name(config_cwd, args);
+
+ start_ldlinux(argv);
+ } else if (type == IMAGE_TYPE_LOCALBOOT) {
+ local_boot(strtoul(kernel, NULL, 0));
+ } else if (type == IMAGE_TYPE_PXE || type == IMAGE_TYPE_BSS ||
+ type == IMAGE_TYPE_BOOT) {
+ chainboot_file(kernel, type);
} else {
- /* process the image need int 22 support */
- if (type == KT_LOCALBOOT) {
- ireg.eax.w[0] = 0x0014; /* Local boot */
- ireg.edx.w[0] = strtoul(kernel, NULL, 0);
- } else {
- ireg.eax.w[0] = 0x0016; /* Run kernel image */
- ireg.esi.w[0] = OFFS(kernel);
- ireg.ds = SEG(kernel);
- ireg.ebx.w[0] = OFFS(args);
- ireg.es = SEG(args);
- ireg.edx.l = type - KT_KERNEL;
- /* ireg.ecx.l = 0; *//* We do ipappend "manually" */
- }
-
- __intcall(0x22, &ireg, NULL);
+ /* Need add one item for kernel load, as we don't use
+ * the assembly runkernel.inc any more */
+ new_linux_kernel((char *)kernel, (char *)cmdline);
}
- lfree(kernel);
+ lfree((void *)kernel);
/* If this returns, something went bad; return to menu */
}
diff --git a/com32/elflink/ldlinux/get_key.c b/com32/elflink/ldlinux/get_key.c
index 42ff5c12..0be06b98 100644
--- a/com32/elflink/ldlinux/get_key.c
+++ b/com32/elflink/ldlinux/get_key.c
@@ -148,10 +148,10 @@ int get_key_decode(char *buffer, int nc, int *code)
int get_key(FILE * f, clock_t timeout)
{
- unsigned char buffer[KEY_MAXLEN];
- int nc, i, rv;
+ char buffer[KEY_MAXLEN];
+ int nc, rv;
int another;
- unsigned char ch;
+ char ch;
clock_t start;
int code;
@@ -167,7 +167,7 @@ int get_key(FILE * f, clock_t timeout)
clock_t lateness = times(NULL) - start;
if (nc && lateness > 1 + KEY_TIMEOUT) {
if (nc == 1)
- return buffer[0]; /* timeout in sequence */
+ return (unsigned char)buffer[0]; /* timeout */
else if (timeout && lateness > timeout)
return KEY_NONE;
} else if (!nc && timeout && lateness > timeout)
@@ -194,5 +194,5 @@ int get_key(FILE * f, clock_t timeout)
/* We got an unrecognized sequence; return the first character */
/* We really should remember this and return subsequent characters later */
- return buffer[0];
+ return (unsigned char)buffer[0];
}
diff --git a/com32/elflink/ldlinux/kernel.c b/com32/elflink/ldlinux/kernel.c
index bdcd3cb1..b8f9cb8d 100644
--- a/com32/elflink/ldlinux/kernel.c
+++ b/com32/elflink/ldlinux/kernel.c
@@ -15,15 +15,14 @@ const char *append = NULL;
/* Will be called from readconfig.c */
int new_linux_kernel(char *okernel, char *ocmdline)
{
- const char *kernel_name;
- struct initramfs *initramfs;
+ const char *kernel_name = NULL;
+ struct initramfs *initramfs = NULL;
char *temp;
void *kernel_data;
size_t kernel_len;
bool opt_quiet = false;
char initrd_name[256];
char cmdline_buf[256], *cmdline;
- int i;
dprintf("okernel = %s, ocmdline = %s", okernel, ocmdline);
@@ -98,36 +97,41 @@ int new_linux_kernel(char *okernel, char *ocmdline)
if (!opt_quiet)
printf("ok\n");
- /* Initialize the initramfs chain */
- initramfs = initramfs_init();
- if (!initramfs)
- goto bail;
-
/* Find and load initramfs */
temp = strstr(cmdline, "initrd=");
if (temp) {
- char *p;
+ /* Initialize the initramfs chain */
+ initramfs = initramfs_init();
+ if (!initramfs)
+ goto bail;
- temp += strlen("initrd=");
+ temp += 6; /* strlen("initrd") */
do {
- p = strchr(temp, ',');
- if (p)
- *p = '\0';
-
- if (initramfs_load_archive(initramfs, temp)) {
- printf("failed!\n");
- goto bail;
- }
-
- if (p)
- *p++ = ',';
- } while ((temp = p));
- }
+ char *p = initrd_name;
+
+ temp++; /* Skip = or , */
- //dprintf("loading initrd done");
+ while (*temp != ' ' && *temp != ',' && *temp)
+ *p++ = *temp++;
+ *p = '\0';
+
+ if (!opt_quiet)
+ printf("Loading %s...", initrd_name);
+
+ if (initramfs_load_archive(initramfs, initrd_name)) {
+ if (opt_quiet)
+ printf("Loading %s ", initrd_name);
+ printf("failed!\n");
+ goto bail;
+ }
+
+ if (!opt_quiet)
+ printf("ok\n");
+ } while (*temp == ',');
+ }
/* This should not return... */
- syslinux_boot_linux(kernel_data, kernel_len, initramfs, cmdline);
+ syslinux_boot_linux(kernel_data, kernel_len, initramfs, NULL, cmdline);
bail:
printf("Kernel load failure (insufficient memory?)\n");
diff --git a/com32/elflink/ldlinux/ldlinux.c b/com32/elflink/ldlinux/ldlinux.c
index 53604179..073f1116 100644
--- a/com32/elflink/ldlinux/ldlinux.c
+++ b/com32/elflink/ldlinux/ldlinux.c
@@ -1,16 +1,135 @@
#include <linux/list.h>
#include <sys/times.h>
+#include <fcntl.h>
#include <stdbool.h>
+#include <string.h>
#include <core.h>
+#include <fs.h>
#include "cli.h"
#include "console.h"
#include "com32.h"
#include "menu.h"
#include "config.h"
#include "syslinux/adv.h"
+#include "syslinux/boot.h"
#include <sys/module.h>
+struct file_ext {
+ const char *name;
+ enum kernel_type type;
+};
+
+static const struct file_ext file_extensions[] = {
+ { ".com", IMAGE_TYPE_COMBOOT },
+ { ".cbt", IMAGE_TYPE_COMBOOT },
+ { ".c32", IMAGE_TYPE_COM32 },
+ { ".img", IMAGE_TYPE_FDIMAGE },
+ { ".bss", IMAGE_TYPE_BSS },
+ { ".bin", IMAGE_TYPE_BOOT },
+ { ".bs", IMAGE_TYPE_BOOT },
+ { ".0", IMAGE_TYPE_PXE },
+ { NULL, 0 },
+};
+
+/*
+ * Return a pointer to one byte after the last character of the
+ * command.
+ */
+static inline const char *find_command(const char *str)
+{
+ const char *p;
+
+ p = str;
+ while (*p && !my_isspace(*p))
+ p++;
+ return p;
+}
+
+uint32_t parse_image_type(const char *kernel)
+{
+ const struct file_ext *ext;
+ const char *p;
+ int len;
+
+ /* Find the end of the command */
+ p = find_command(kernel);
+ len = p - kernel;
+
+ for (ext = file_extensions; ext->name; ext++) {
+ int elen = strlen(ext->name);
+
+ if (!strncmp(kernel + len - elen, ext->name, elen))
+ return ext->type;
+ }
+
+ /* use IMAGE_TYPE_KERNEL as default */
+ return IMAGE_TYPE_KERNEL;
+}
+
+/*
+ * Returns the kernel name with file extension if one wasn't present.
+ */
+static const char *get_extension(const char *kernel)
+{
+ const struct file_ext *ext;
+ const char *p;
+ int len;
+
+ /* Find the end of the command */
+ p = find_command(kernel);
+ len = p - kernel;
+
+ for (ext = file_extensions; ext->name; ext++) {
+ char *str;
+ int elen = strlen(ext->name);
+ int fd;
+
+ str = malloc(len + elen + 1);
+
+ strncpy(str, kernel, len);
+ strncpy(str + len, ext->name, elen);
+ str[len + elen] = '\0';
+
+ fd = searchdir(str);
+ free(str);
+
+ if (fd >= 0)
+ return ext->name;
+ }
+
+ return NULL;
+}
+
+static const char *apply_extension(const char *kernel, const char *ext)
+{
+ const char *p;
+ char *k;
+ int len = strlen(kernel);
+ int elen = strlen(ext);
+
+ k = malloc(len + elen + 1);
+ if (!k)
+ return NULL;
+
+ p = find_command(kernel);
+
+ len = p - kernel;
+
+ /* Copy just the kernel name */
+ memcpy(k, kernel, len);
+
+ /* Append the extension */
+ memcpy(k + len, ext, elen);
+
+ /* Copy the rest of the command line */
+ strcpy(k + len + elen, p);
+
+ k[len + elen + strlen(p)] = '\0';
+
+ return k;
+}
+
/*
* Attempt to load a kernel after deciding what type of image it is.
*
@@ -18,21 +137,21 @@
* the the kernel. If we return the caller should call enter_cmdline()
* so that the user can help us out.
*/
-static void load_kernel(const char *kernel)
+void load_kernel(const char *command_line)
{
struct menu_entry *me;
- enum kernel_type type;
- const char *cmdline, *p;
- int len;
+ const char *cmdline;
+ const char *kernel;
+ uint32_t type;
+
+ kernel = strdup(command_line);
+ if (!kernel)
+ goto bad_kernel;
/* Virtual kernel? */
me = find_label(kernel);
if (me) {
- enum kernel_type type = KT_KERNEL;
-
- /* cmdline contains type specifier */
- if (me->cmdline[0] == '.')
- type = KT_NONE;
+ type = parse_image_type(me->cmdline);
execute(me->cmdline, type);
/* We shouldn't return */
@@ -42,33 +161,37 @@ static void load_kernel(const char *kernel)
if (!allowimplicit)
goto bad_implicit;
- p = kernel;
- /* Find the end of the command */
- while (*p && !my_isspace(*p))
- p++;
+ /* Insert a null character to ignore any user-specified options */
+ if (!allowoptions) {
+ char *p = (char *)find_command(kernel);
+ *p = '\0';
+ }
- len = p - kernel;
- if (!strncmp(kernel + len - 4, ".c32", 4)) {
- type = KT_COM32;
- } else if (!strncmp(kernel + len - 2, ".0", 2)) {
- type = KT_PXE;
- } else if (!strncmp(kernel + len - 3, ".bs", 3)) {
- type = KT_BOOT;
- } else if (!strncmp(kernel + len - 4, ".img", 4)) {
- type = KT_FDIMAGE;
- } else if (!strncmp(kernel + len - 4, ".bin", 4)) {
- type = KT_BOOT;
- } else if (!strncmp(kernel + len - 4, ".bss", 4)) {
- type = KT_BSS;
- } else if (!strncmp(kernel + len - 4, ".com", 4) ||
- !strncmp(kernel + len - 4, ".cbt", 4)) {
- type = KT_COMBOOT;
+ type = parse_image_type(kernel);
+ if (type == IMAGE_TYPE_KERNEL) {
+ const char *ext;
+
+ /*
+ * Automatically lookup the extension if one wasn't
+ * supplied by the user.
+ */
+ ext = get_extension(kernel);
+ if (ext) {
+ const char *k;
+
+ k = apply_extension(kernel, ext);
+ if (!k)
+ goto bad_kernel;
+
+ free((void *)kernel);
+ kernel = k;
+
+ type = parse_image_type(kernel);
+ }
}
- /* use KT_KERNEL as default */
- else
- type = KT_KERNEL;
execute(kernel, type);
+ free((void *)kernel);
bad_implicit:
bad_kernel:
@@ -78,7 +201,7 @@ bad_kernel:
*/
if (onerrorlen) {
rsprintf(&cmdline, "%s %s", onerror, default_cmd);
- execute(cmdline, KT_COM32);
+ execute(cmdline, IMAGE_TYPE_COM32);
}
}
@@ -88,43 +211,41 @@ static void enter_cmdline(void)
/* Enter endless command line prompt, should support "exit" */
while (1) {
- cmdline = edit_cmdline("syslinux$", 1, NULL, cat_help_file);
- if (!cmdline)
- continue;
-
- /* return if user only press enter */
- if (cmdline[0] == '\0') {
- printf("\n");
- continue;
- }
+ cmdline = edit_cmdline("boot:", 1, NULL, cat_help_file);
printf("\n");
+ /* return if user only press enter or we timed out */
+ if (!cmdline || cmdline[0] == '\0')
+ return;
+
load_kernel(cmdline);
}
}
-int main(int argc, char **argv)
+int main(int argc __unused, char **argv __unused)
{
- com32sys_t ireg, oreg;
- uint8_t *adv;
- int count = 0;
+ const void *adv;
+ const char *cmdline;
+ size_t count = 0;
+ char *config_argv[2] = { NULL, NULL };
openconsole(&dev_rawcon_r, &dev_ansiserial_w);
- __syslinux_get_ipappend_strings();
- parse_configs(NULL);
+ if (ConfigName[0])
+ config_argv[0] = ConfigName;
+
+ parse_configs(config_argv);
- __syslinux_init();
adv = syslinux_getadv(ADV_BOOTONCE, &count);
if (adv && count) {
/*
* We apparently have a boot-once set; clear it and
* then execute the boot-once.
*/
- uint8_t *src, *dst, *cmdline;
- int i;
+ char *src, *dst;
+ size_t i;
- src = adv;
+ src = (char *)adv;
cmdline = dst = malloc(count + 1);
if (!dst) {
printf("Failed to allocate memory for ADV\n");
@@ -148,12 +269,14 @@ int main(int argc, char **argv)
if (forceprompt)
goto cmdline;
+ cmdline = default_cmd;
+auto_boot:
/*
* Auto boot
*/
if (defaultlevel || noescape) {
if (defaultlevel) {
- load_kernel(default_cmd); /* Shouldn't return */
+ load_kernel(cmdline); /* Shouldn't return */
} else {
printf("No DEFAULT or UI configuration directive found!\n");
@@ -163,8 +286,12 @@ int main(int argc, char **argv)
}
cmdline:
- /* Should never return */
+ /* Only returns if the user pressed enter or input timed out */
enter_cmdline();
+ cmdline = ontimeoutlen ? ontimeout : default_cmd;
+
+ goto auto_boot;
+
return 0;
}
diff --git a/core/fs/loadhigh.c b/com32/elflink/ldlinux/loadhigh.c
index bd9d3535..0f2f8428 100644
--- a/core/fs/loadhigh.c
+++ b/com32/elflink/ldlinux/loadhigh.c
@@ -37,7 +37,7 @@
#include "core.h"
#include "fs.h"
-#define MAX_CHUNK (1 << 20) /* 1 MB */
+#define MAX_CHUNK (1UL << 20) /* 1 MB */
void pm_load_high(com32sys_t *regs)
{
diff --git a/com32/elflink/ldlinux/readconfig.c b/com32/elflink/ldlinux/readconfig.c
index 564cbeff..1db397a1 100644
--- a/com32/elflink/ldlinux/readconfig.c
+++ b/com32/elflink/ldlinux/readconfig.c
@@ -52,6 +52,22 @@ const struct menu_parameter mparm[NPARAMS] = {
[P_HIDDEN_ROW] = {"hiddenrow", -2},
};
+/* Must match enum kernel_type */
+static const char *const kernel_types[] = {
+ "none",
+ "localboot",
+ "kernel",
+ "linux",
+ "boot",
+ "bss",
+ "pxe",
+ "fdimage",
+ "comboot",
+ "com32",
+ "config",
+ NULL
+};
+
short uappendlen = 0; //bytes in append= command
short ontimeoutlen = 0; //bytes in ontimeout command
short onerrorlen = 0; //bytes in onerror command
@@ -68,6 +84,7 @@ short nohalt = 1; //idle.inc
const char *default_cmd = NULL; //"default" command line
const char *onerror = NULL; //"onerror" command line
+const char *ontimeout = NULL; //"ontimeout" command line
/* Empty refstring */
const char *empty_string;
@@ -79,6 +96,7 @@ struct menu *root_menu, *start_menu, *hide_menu, *menu_list, *default_menu;
int shiftkey = 0; /* Only display menu if shift key pressed */
int hiddenmenu = 0;
long long totaltimeout = 0;
+unsigned int kbdtimeout = 0;
/* Keep track of global default */
static int has_ui = 0; /* DEFAULT only counts if UI is found */
@@ -1081,13 +1099,14 @@ do_include:
//dprintf("got a kernel: %s, type = %d", ld.kernel, ld.type);
}
} else if (looking_at(p, "timeout")) {
- m->timeout = (atoi(skipspace(p + 7)) * CLK_TCK + 9) / 10;
+ kbdtimeout = (atoi(skipspace(p + 7)) * CLK_TCK + 9) / 10;
} else if (looking_at(p, "totaltimeout")) {
totaltimeout = (atoll(skipspace(p + 13)) * CLK_TCK + 9) / 10;
} else if (looking_at(p, "ontimeout")) {
- m->ontimeout = refstrdup(skipspace(p + 9));
+ ontimeout = refstrdup(skipspace(p + 9));
+ ontimeoutlen = strlen(ontimeout);
} else if (looking_at(p, "allowoptions")) {
- m->allowedit = !!atoi(skipspace(p + 12));
+ allowoptions = !!atoi(skipspace(p + 12));
} else if (looking_at(p, "ipappend")) {
if (ld.label)
ld.ipappend = atoi(skipspace(p + 8));
@@ -1121,7 +1140,8 @@ do_include:
* display/font/kbdmap are rather similar, open a file then do sth
*/
else if (looking_at(p, "display")) {
- char *filename, *dst = KernelName;
+ const char *filename;
+ char *dst = KernelName;
size_t len = FILENAME_MAX - 1;
filename = refstrdup(skipspace(p + 7));
@@ -1133,7 +1153,8 @@ do_include:
get_msg_file(KernelName);
refstr_put(filename);
} else if (looking_at(p, "font")) {
- char *filename, *dst = KernelName;
+ const char *filename;
+ char *dst = KernelName;
size_t len = FILENAME_MAX - 1;
filename = refstrdup(skipspace(p + 4));
@@ -1145,8 +1166,8 @@ do_include:
loadfont(KernelName);
refstr_put(filename);
} else if (looking_at(p, "kbdmap")) {
- com32sys_t reg;
- char *filename, *dst = KernelName;
+ const char *filename;
+ char *dst = KernelName;
size_t len = FILENAME_MAX - 1;
filename = refstrdup(skipspace(p + 4));
@@ -1189,7 +1210,6 @@ do_include:
/* serial setting, bps, flow control */
else if (looking_at(p, "serial")) {
- com32sys_t ireg;
uint16_t port, flow;
uint32_t baud;
@@ -1309,18 +1329,20 @@ do_include:
eprintf("%s\n", p+4);
} else if (looking_at(p, "path")) {
/* PATH-based lookup */
- char *new_path, *_p;
+ const char *new_path;
+ char *_p;
size_t len, new_len;
new_path = refstrdup(skipspace(p + 4));
len = strlen(PATH);
new_len = strlen(new_path);
- _p = realloc(PATH, len + new_len + 2);
+ _p = malloc(len + new_len + 2);
if (_p) {
strncpy(_p, PATH, len);
_p[len++] = ':';
strncpy(_p + len, new_path, new_len);
_p[len + new_len] = '\0';
+ free(PATH);
PATH = _p;
} else
eprintf("Failed to realloc PATH\n");
@@ -1345,6 +1367,11 @@ static int parse_one_config(const char *filename)
f = fdopen(fd, mode);
parse_config_file(f);
+ if (config_cwd[0]) {
+ chdir(config_cwd);
+ config_cwd[0] = '\0';
+ }
+
return 0;
}
diff --git a/com32/gfxboot/gfxboot.c b/com32/gfxboot/gfxboot.c
index 35d180a6..aa05caf8 100644
--- a/com32/gfxboot/gfxboot.c
+++ b/com32/gfxboot/gfxboot.c
@@ -962,7 +962,7 @@ void boot_entry(menu_t *menu_ptr, char *arg)
gfx_done();
- syslinux_boot_linux(kernel, kernel_size, initrd, arg);
+ syslinux_boot_linux(kernel, kernel_size, initrd, NULL, arg);
}
diff --git a/com32/gpllib/disk/geom.c b/com32/gpllib/disk/geom.c
index 9e673ed4..e1095200 100644
--- a/com32/gpllib/disk/geom.c
+++ b/com32/gpllib/disk/geom.c
@@ -120,7 +120,7 @@ static int detect_extensions(struct driveinfo *drive_info)
static int get_drive_parameters_with_extensions(struct driveinfo *drive_info)
{
com32sys_t inreg, outreg;
- struct edd_device_parameters *dp = __com32.cs_bounce;
+ struct edd_device_parameters *dp;
memset(&inreg, 0, sizeof inreg);
@@ -134,6 +134,10 @@ static int get_drive_parameters_with_extensions(struct driveinfo *drive_info)
* If the buffer length is less than 26 on entry an error shall be
* returned.
*/
+ dp = lmalloc(sizeof *dp);
+ if (!dp)
+ return -1;
+
dp->len = sizeof(struct edd_device_parameters);
inreg.esi.w[0] = OFFS(dp);
@@ -144,10 +148,13 @@ static int get_drive_parameters_with_extensions(struct driveinfo *drive_info)
__intcall(0x13, &inreg, &outreg);
/* CF set on error */
- if (outreg.eflags.l & EFLAGS_CF)
+ if (outreg.eflags.l & EFLAGS_CF) {
+ lfree(dp);
return outreg.eax.b[1];
+ }
memcpy(&drive_info->edd_params, dp, sizeof drive_info->edd_params);
+ lfree(dp);
return 0;
}
diff --git a/com32/gpllib/disk/labels.c b/com32/gpllib/disk/labels.c
index ad3d33b3..f27ff655 100644
--- a/com32/gpllib/disk/labels.c
+++ b/com32/gpllib/disk/labels.c
@@ -36,29 +36,29 @@ void get_label(int label, char **buffer_label)
strlcpy(buffer, "DOS 3.31+ 16-bit FAT (over 32M)", buffer_size);
break;
case 0x07:
- strlcpy(buffer, "OS/2 IFS (e.g., HPFS)", buffer_size);
- break;
+ strlcpy(buffer, "NTFS/exFAT/HPFS", buffer_size);
//case 0x07: strlcpy(buffer, "Advanced Unix", buffer_size); break;
//case 0x07: strlcpy(buffer, "Windows NT NTFS", buffer_size); break;
//case 0x07: strlcpy(buffer, "QNX2.x (pre-1988)", buffer_size); break;
- case 0x08:
- strlcpy(buffer, "OS/2 (v1.0-1.3 only)", buffer_size);
break;
+ case 0x08:
+ strlcpy(buffer, "AIX", buffer_size);
//case 0x08: strlcpy(buffer, "AIX boot partition", buffer_size); break;
//case 0x08: strlcpy(buffer, "SplitDrive", buffer_size); break;
//case 0x08: strlcpy(buffer, "DELL partition spanning multiple drives", buffer_size); break;
//case 0x08: strlcpy(buffer, "Commodore DOS", buffer_size); break;
//case 0x08: strlcpy(buffer, "QNX 1.x and 2.x ("qny")", buffer_size); break;
- case 0x09:
- strlcpy(buffer, "AIX data partition", buffer_size);
break;
+ case 0x09:
+ strlcpy(buffer, "AIX bootable partition", buffer_size);
//case 0x09: strlcpy(buffer, "Coherent filesystem", buffer_size); break;
//case 0x09: strlcpy(buffer, "QNX 1.x and 2.x ("qnz")", buffer_size); break;
+ break;
case 0x0a:
strlcpy(buffer, "OS/2 Boot Manager", buffer_size);
- break;
//case 0x0a: strlcpy(buffer, "Coherent swap partition", buffer_size); break;
//case 0x0a: strlcpy(buffer, "OPUS", buffer_size); break;
+ break;
case 0x0b:
strlcpy(buffer, "WIN95 OSR2 32-bit FAT", buffer_size);
break;
@@ -72,13 +72,13 @@ void get_label(int label, char **buffer_label)
strlcpy(buffer, "WIN95: Extended partition, LBA-mapped", buffer_size);
break;
case 0x10:
- strlcpy(buffer, "OPUS (?)", buffer_size);
+ strlcpy(buffer, "OPUS", buffer_size);
break;
case 0x11:
strlcpy(buffer, "Hidden DOS 12-bit FAT", buffer_size);
break;
case 0x12:
- strlcpy(buffer, "Compaq config partition", buffer_size);
+ strlcpy(buffer, "Compaq diagnostic partition", buffer_size);
break;
case 0x14:
strlcpy(buffer, "Hidden DOS 16-bit FAT <32M", buffer_size);
@@ -87,7 +87,7 @@ void get_label(int label, char **buffer_label)
strlcpy(buffer, "Hidden DOS 16-bit FAT >=32M", buffer_size);
break;
case 0x17:
- strlcpy(buffer, "Hidden IFS (e.g., HPFS)", buffer_size);
+ strlcpy(buffer, "Hidden HPFS/exFAT/NTFS", buffer_size);
break;
case 0x18:
strlcpy(buffer, "AST SmartSleep Partition", buffer_size);
@@ -111,8 +111,8 @@ void get_label(int label, char **buffer_label)
break;
case 0x21:
strlcpy(buffer, "Reserved", buffer_size);
- break;
//case 0x21: strlcpy(buffer, "Unused", buffer_size); break;
+ break;
case 0x22:
strlcpy(buffer, "Unused", buffer_size);
break;
@@ -125,6 +125,18 @@ void get_label(int label, char **buffer_label)
case 0x26:
strlcpy(buffer, "Reserved", buffer_size);
break;
+ case 0x27:
+ strlcpy(buffer, "PQService (Acer laptop hidden rescue partition)", buffer_size);
+ //Windows RE hidden partition
+ //MirOS BSD partition
+ //RouterBOOT kernel partition
+ break;
+ case 0x2a:
+ strlcpy(buffer, "AtheOS File System (AFS)", buffer_size);
+ break;
+ case 0x2b:
+ strlcpy(buffer, "SyllableSecure (SylStor)", buffer_size);
+ break;
case 0x31:
strlcpy(buffer, "Reserved", buffer_size);
break;
@@ -148,8 +160,8 @@ void get_label(int label, char **buffer_label)
break;
case 0x39:
strlcpy(buffer, "Plan 9 partition", buffer_size);
- break;
//case 0x39: strlcpy(buffer, "THEOS ver 4 spanned partition", buffer_size); break;
+ break;
case 0x3a:
strlcpy(buffer, "THEOS ver 4 4gb partition", buffer_size);
break;
@@ -166,15 +178,15 @@ void get_label(int label, char **buffer_label)
strlcpy(buffer, "Venix 80286", buffer_size);
break;
case 0x41:
- strlcpy(buffer, "Linux/MINIX (sharing disk with DRDOS)", buffer_size);
- break;
+ strlcpy(buffer, "PPC PReP Boot", buffer_size); break;
//case 0x41: strlcpy(buffer, "Personal RISC Boot", buffer_size); break;
- //case 0x41: strlcpy(buffer, "PPC PReP (Power PC Reference Platform) Boot", buffer_size); break;
- case 0x42:
- strlcpy(buffer, "Linux swap (sharing disk with DRDOS)", buffer_size);
+ // strlcpy(buffer, "Linux/MINIX (sharing disk with DRDOS)", buffer_size);
break;
- //case 0x42: strlcpy(buffer, "SFS (Secure Filesystem)", buffer_size); break;
+ case 0x42:
+ strlcpy(buffer, "SFS (Secure Filesystem)", buffer_size); break;
+ // strlcpy(buffer, "Linux swap (sharing disk with DRDOS)", buffer_size);
//case 0x42: strlcpy(buffer, "Windows 2000 marker", buffer_size); break;
+ break;
case 0x43:
strlcpy(buffer, "Linux native (sharing disk with DRDOS)", buffer_size);
break;
@@ -183,9 +195,9 @@ void get_label(int label, char **buffer_label)
break;
case 0x45:
strlcpy(buffer, "Boot-US boot manager", buffer_size);
- break;
//case 0x45: strlcpy(buffer, "Priam", buffer_size); break;
//case 0x45: strlcpy(buffer, "EUMEL/Elan", buffer_size); break;
+ break;
case 0x46:
strlcpy(buffer, "EUMEL/Elan", buffer_size);
break;
@@ -197,8 +209,8 @@ void get_label(int label, char **buffer_label)
break;
case 0x4a:
strlcpy(buffer, "AdaOS Aquila (Default)", buffer_size);
- break;
//case 0x4a: strlcpy(buffer, "ALFS/THIN lightweight filesystem for DOS", buffer_size); break;
+ break;
case 0x4c:
strlcpy(buffer, "Oberon partition", buffer_size);
break;
@@ -210,22 +222,22 @@ void get_label(int label, char **buffer_label)
break;
case 0x4f:
strlcpy(buffer, "QNX4.x 3rd part", buffer_size);
- break;
//case 0x4f: strlcpy(buffer, "Oberon partition", buffer_size); break;
+ break;
case 0x50:
strlcpy(buffer, "OnTrack Disk Manager (older versions) RO",
buffer_size);
- break;
//case 0x50: strlcpy(buffer, "Lynx RTOS", buffer_size); break;
//case 0x50: strlcpy(buffer, "Native Oberon (alt)", buffer_size); break;
+ break;
case 0x51:
strlcpy(buffer, "OnTrack Disk Manager RW (DM6 Aux1)", buffer_size);
- break;
//case 0x51: strlcpy(buffer, "Novell", buffer_size); break;
+ break;
case 0x52:
strlcpy(buffer, "CP/M", buffer_size);
- break;
//case 0x52: strlcpy(buffer, "Microport SysV/AT", buffer_size); break;
+ break;
case 0x53:
strlcpy(buffer, "Disk Manager 6.0 Aux3", buffer_size);
break;
@@ -237,12 +249,12 @@ void get_label(int label, char **buffer_label)
break;
case 0x56:
strlcpy(buffer, "Golden Bow VFeature Partitioned Volume.", buffer_size);
- break;
//case 0x56: strlcpy(buffer, "DM converted to EZ-BIOS", buffer_size); break;
+ break;
case 0x57:
strlcpy(buffer, "DrivePro", buffer_size);
- break;
//case 0x57: strlcpy(buffer, "VNDI Partition", buffer_size); break;
+ break;
case 0x5c:
strlcpy(buffer, "Priam EDisk", buffer_size);
break;
@@ -255,9 +267,9 @@ void get_label(int label, char **buffer_label)
buffer_size);
break;
case 0x64:
- strlcpy(buffer, "PC-ARMOUR protected partition", buffer_size);
+ strlcpy(buffer, "Novell Netware 286, 2.xx", buffer_size); break;
+ //strlcpy(buffer, "PC-ARMOUR protected partition", buffer_size);
break;
- //case 0x64: strlcpy(buffer, "Novell Netware 286, 2.xx", buffer_size); break;
case 0x65:
strlcpy(buffer, "Novell Netware 386, 3.xx or 4.xx", buffer_size);
break;
@@ -280,13 +292,15 @@ void get_label(int label, char **buffer_label)
case 0x71:
strlcpy(buffer, "Reserved", buffer_size);
break;
+ case 0x72:
+ strlcpy(buffer, "V7/x86", buffer_size);
+ break;
case 0x73:
strlcpy(buffer, "Reserved", buffer_size);
break;
case 0x74:
- strlcpy(buffer, "Reserved", buffer_size);
- break;
- //case 0x74: strlcpy(buffer, "Scramdisk partition", buffer_size); break;
+ //strlcpy(buffer, "Reserved", buffer_size);
+ strlcpy(buffer, "Scramdisk partition", buffer_size); break;
case 0x75:
strlcpy(buffer, "IBM PC/IX", buffer_size);
break;
@@ -301,37 +315,40 @@ void get_label(int label, char **buffer_label)
strlcpy(buffer, "XOSL FS", buffer_size);
break;
case 0x7E:
- strlcpy(buffer, " ", buffer_size);
+ strlcpy(buffer, "Unused", buffer_size);
break;
case 0x80:
strlcpy(buffer, "MINIX until 1.4a", buffer_size);
break;
case 0x81:
strlcpy(buffer, "MINIX since 1.4b, early Linux", buffer_size);
- break;
//case 0x81: strlcpy(buffer, "Mitac disk manager", buffer_size); break;
- //case 0x82: strlcpy(buffer, "Prime", buffer_size); break;
- //case 0x82: strlcpy(buffer, "Solaris x86", buffer_size); break;
+ break;
case 0x82:
strlcpy(buffer, "Linux swap", buffer_size);
+ //case 0x82: strlcpy(buffer, "Prime", buffer_size); break;
+ //case 0x82: strlcpy(buffer, "Solaris x86", buffer_size); break;
break;
case 0x83:
strlcpy(buffer, "Linux native (usually ext2fs)", buffer_size);
break;
case 0x84:
strlcpy(buffer, "OS/2 hidden C: drive", buffer_size);
- break;
//case 0x84: strlcpy(buffer, "Hibernation partition", buffer_size); break;
+ break;
case 0x85:
strlcpy(buffer, "Linux extended partition", buffer_size);
break;
- //case 0x86: strlcpy(buffer, "Old Linux RAID partition superblock", buffer_size); break;
case 0x86:
strlcpy(buffer, "NTFS volume set", buffer_size);
+ //case 0x86: strlcpy(buffer, "Old Linux RAID partition superblock", buffer_size); break;
break;
case 0x87:
strlcpy(buffer, "NTFS volume set", buffer_size);
break;
+ case 0x88:
+ strlcpy(buffer, "Linux Plaintext", buffer_size);
+ break;
case 0x8a:
strlcpy(buffer, "Linux Kernel Partition (used by AiR-BOOT)",
buffer_size);
@@ -349,7 +366,7 @@ void get_label(int label, char **buffer_label)
buffer_size);
break;
case 0x8e:
- strlcpy(buffer, "Linux Logical Volume Manager partition", buffer_size);
+ strlcpy(buffer, "Linux LVM partition", buffer_size);
break;
case 0x90:
strlcpy(buffer, "Free FDISK hidden Primary DOS FAT16 partitition",
@@ -365,14 +382,17 @@ void get_label(int label, char **buffer_label)
break;
case 0x93:
strlcpy(buffer, "Hidden Linux native partition", buffer_size);
- break;
//case 0x93: strlcpy(buffer, "Amoeba", buffer_size); break;
+ break;
case 0x94:
strlcpy(buffer, "Amoeba bad block table", buffer_size);
break;
case 0x95:
strlcpy(buffer, "MIT EXOPC native partitions", buffer_size);
break;
+ case 0x96:
+ strlcpy(buffer, "CHRP ISO-9660 filesystem", buffer_size);
+ break;
case 0x97:
strlcpy(buffer, "Free FDISK hidden Primary DOS FAT32 partitition",
buffer_size);
@@ -392,6 +412,9 @@ void get_label(int label, char **buffer_label)
strlcpy(buffer, "Free FDISK hidden DOS extended partitition (LBA)",
buffer_size);
break;
+ case 0x9e:
+ strlcpy(buffer, "ForthOS partition", buffer_size);
+ break;
case 0x9f:
strlcpy(buffer, "BSD/OS", buffer_size);
break;
@@ -400,13 +423,13 @@ void get_label(int label, char **buffer_label)
break;
case 0xa1:
strlcpy(buffer, "Laptop hibernation partition", buffer_size);
- break;
//case 0xa1: strlcpy(buffer, "HP Volume Expansion (SpeedStor variant)", buffer_size); break;
+ break;
case 0xa3:
- strlcpy(buffer, "Reserved", buffer_size);
+ strlcpy(buffer, "HP Volume Expansion (SpeedStor variant)", buffer_size);
break;
case 0xa4:
- strlcpy(buffer, "Reserved", buffer_size);
+ strlcpy(buffer, "HP Volume Expansion (SpeedStor variant)", buffer_size);
break;
case 0xa5:
strlcpy(buffer, "BSD/386, 386BSD, NetBSD, FreeBSD", buffer_size);
@@ -415,7 +438,7 @@ void get_label(int label, char **buffer_label)
strlcpy(buffer, "OpenBSD", buffer_size);
break;
case 0xa7:
- strlcpy(buffer, "NEXTSTEP", buffer_size);
+ strlcpy(buffer, "NeXTSTEP", buffer_size);
break;
case 0xa8:
strlcpy(buffer, "Mac OS-X", buffer_size);
@@ -429,8 +452,8 @@ void get_label(int label, char **buffer_label)
break;
case 0xab:
strlcpy(buffer, "Mac OS-X Boot partition", buffer_size);
- break;
//case 0xab: strlcpy(buffer, "GO! partition", buffer_size); break;
+ break;
case 0xae:
strlcpy(buffer, "ShagOS filesystem", buffer_size);
break;
@@ -441,16 +464,19 @@ void get_label(int label, char **buffer_label)
strlcpy(buffer, "BootStar Dummy", buffer_size);
break;
case 0xb1:
- strlcpy(buffer, "Reserved", buffer_size);
+ strlcpy(buffer, "HP Volume Expansion (SpeedStor variant)", buffer_size);
+ break;
+ case 0xb2:
+ strlcpy(buffer, "QNX Neutrino Power-Safe filesystem", buffer_size);
break;
case 0xb3:
- strlcpy(buffer, "Reserved", buffer_size);
+ strlcpy(buffer, "HP Volume Expansion (SpeedStor variant)", buffer_size);
break;
case 0xb4:
- strlcpy(buffer, "Reserved", buffer_size);
+ strlcpy(buffer, "HP Volume Expansion (SpeedStor variant)", buffer_size);
break;
case 0xb6:
- strlcpy(buffer, "Reserved", buffer_size);
+ strlcpy(buffer, "HP Volume Expansion (SpeedStor variant)", buffer_size);
break;
case 0xb7:
strlcpy(buffer, "BSDI BSD/386 filesystem", buffer_size);
@@ -461,21 +487,27 @@ void get_label(int label, char **buffer_label)
case 0xbb:
strlcpy(buffer, "Boot Wizard hidden", buffer_size);
break;
+ case 0xbc:
+ strlcpy(buffer, "Acronis backup partition", buffer_size);
+ break;
case 0xbe:
strlcpy(buffer, "Solaris 8 boot partition", buffer_size);
break;
+ case 0xbf:
+ strlcpy(buffer, "Solaris partition", buffer_size);
+ break;
case 0xc0:
strlcpy(buffer, "CTOS", buffer_size);
- break;
//case 0xc0: strlcpy(buffer, "REAL/32 secure small partition", buffer_size); break;
//case 0xc0: strlcpy(buffer, "NTFT Partition", buffer_size); break;
+ break;
case 0xc1:
strlcpy(buffer, "DRDOS/secured (FAT-12)", buffer_size);
break;
case 0xc2:
- strlcpy(buffer, "Reserved for DR-DOS 7+", buffer_size);
+ strlcpy(buffer, "Hidden Linux", buffer_size); break;
+ //strlcpy(buffer, "Reserved for DR-DOS 7+", buffer_size);
break;
- //case 0xc2: strlcpy(buffer, "Hidden Linux", buffer_size); break;
case 0xc3:
strlcpy(buffer, "Hidden Linux swap", buffer_size);
break;
@@ -487,21 +519,21 @@ void get_label(int label, char **buffer_label)
break;
case 0xc6:
strlcpy(buffer, "DRDOS/secured (FAT-16, >= 32M)", buffer_size);
- break;
//case 0xc6: strlcpy(buffer, "Windows NT corrupted FAT16 volume/stripe set", buffer_size); break;
+ break;
case 0xc7:
strlcpy(buffer, "Windows NT corrupted NTFS volume/stripe set",
buffer_size);
- break;
//case 0xc7: strlcpy(buffer, "Syrinx boot", buffer_size); break;
+ break;
case 0xc8:
- strlcpy(buffer, "(See also ID c2.)", buffer_size);
+ strlcpy(buffer, "Reserved for DR-DOS 8.0+", buffer_size);
break;
case 0xc9:
- strlcpy(buffer, "(See also ID c2.)", buffer_size);
+ strlcpy(buffer, "Reserved for DR-DOS 8.0+", buffer_size);
break;
case 0xca:
- strlcpy(buffer, "(See also ID c2.)", buffer_size);
+ strlcpy(buffer, "Reserved for DR-DOS 8.0+", buffer_size);
break;
case 0xcb:
strlcpy(buffer, "reserved for DRDOS/secured (FAT32)", buffer_size);
@@ -515,6 +547,9 @@ void get_label(int label, char **buffer_label)
case 0xce:
strlcpy(buffer, "reserved for DRDOS/secured (FAT16, LBA)", buffer_size);
break;
+ case 0xcf:
+ strlcpy(buffer, "DR-DOS 7.04+ secured EXT DOS (LBA)", buffer_size);
+ break;
case 0xd0:
strlcpy(buffer, "REAL/32 secure big partition", buffer_size);
break;
@@ -541,9 +576,9 @@ void get_label(int label, char **buffer_label)
strlcpy(buffer,
"Digital Research CP/M, Concurrent CP/M, Concurrent DOS",
buffer_size);
- break;
//case 0xdb: strlcpy(buffer, "CTOS (Convergent Technologies OS -Unisys)", buffer_size); break;
//case 0xdb: strlcpy(buffer, "KDG Telemetry SCPU boot", buffer_size); break;
+ break;
case 0xdd:
strlcpy(buffer, "Hidden CTOS Memdump?", buffer_size);
break;
@@ -575,24 +610,30 @@ void get_label(int label, char **buffer_label)
strlcpy(buffer,
"Tandy DOS with logical sectored FAT (According to Powerquest.)",
buffer_size);
- break;
//case 0xe5: strlcpy(buffer, "Reserved", buffer_size); break;
+ break;
case 0xe6:
- strlcpy(buffer, "Reserved", buffer_size);
+ strlcpy(buffer, "Storage Dimensions SpeedStor", buffer_size);
+ break;
+ case 0xe8:
+ strlcpy(buffer, "LUKS", buffer_size);
break;
case 0xeb:
- strlcpy(buffer, "BFS (aka BeFS)", buffer_size);
+ strlcpy(buffer, "BeOS", buffer_size);
+ break;
+ case 0xec:
+ strlcpy(buffer, "SkyOS SkyFS", buffer_size);
break;
case 0xed:
strlcpy(buffer, "Reserved for Matthias Paul's Sprytix", buffer_size);
break;
case 0xee:
strlcpy(buffer,
- "Indication that this legacy MBR is followed by an EFI header",
+ "GPT",
buffer_size);
break;
case 0xef:
- strlcpy(buffer, "Partition that contains an EFI file system",
+ strlcpy(buffer, "EFI file system",
buffer_size);
break;
case 0xf0:
@@ -613,8 +654,8 @@ void get_label(int label, char **buffer_label)
break;
case 0xf4:
strlcpy(buffer, "SpeedStor large partition", buffer_size);
- break;
//case 0xf4: strlcpy(buffer, "Prologue single-volume partition", buffer_size); break;
+ break;
case 0xf5:
strlcpy(buffer, "Prologue multi-volume partition", buffer_size);
break;
@@ -623,6 +664,12 @@ void get_label(int label, char **buffer_label)
"Reserved (Powerquest writes: Storage Dimensions SpeedStor. )",
buffer_size);
break;
+ case 0xf7:
+ strlcpy(buffer, "DDRdrive Solid State File System", buffer_size);
+ break;
+ case 0xf9:
+ strlcpy(buffer, "pCache", buffer_size);
+ break;
case 0xfa:
strlcpy(buffer, "Bochs", buffer_size);
break;
@@ -638,12 +685,12 @@ void get_label(int label, char **buffer_label)
buffer_size);
break;
case 0xfe:
- strlcpy(buffer, "SpeedStor > 1024 cyl.", buffer_size);
- break;
- //case 0xfe: strlcpy(buffer, "LANstep", buffer_size); break;
+ strlcpy(buffer, "LANstep", buffer_size); break;
+ //strlcpy(buffer, "SpeedStor > 1024 cyl.", buffer_size);
//case 0xfe: strlcpy(buffer, "IBM PS/2 IML (Initial Microcode Load) partition, located at the end of the disk.", buffer_size); break;
//case 0xfe: strlcpy(buffer, "Windows NT Disk Administrator hidden partition", buffer_size); break;
//case 0xfe: strlcpy(buffer, "Linux Logical Volume Manager partition (old)", buffer_size); break;
+ break;
case 0xff:
strlcpy(buffer, "Xenix Bad Block Table ", buffer_size);
break;
diff --git a/com32/gpllib/disk/read.c b/com32/gpllib/disk/read.c
index 7a6cc430..541957f9 100644
--- a/com32/gpllib/disk/read.c
+++ b/com32/gpllib/disk/read.c
@@ -76,13 +76,22 @@ int read_sectors(struct driveinfo *drive_info, void *data,
const unsigned int lba, const int sectors)
{
com32sys_t inreg, outreg;
- struct ebios_dapa *dapa = __com32.cs_bounce;
- void *buf = (char *)__com32.cs_bounce + sectors * SECTOR;
+ struct ebios_dapa *dapa;
+ void *buf;
char *bufp = data;
+ int rv = -1;
if (get_drive_parameters(drive_info) == -1)
return -1;
+ buf = lmalloc(sectors * SECTOR);
+ if (!buf)
+ return -1;
+
+ dapa = lmalloc(sizeof(*dapa));
+ if (!dapa)
+ goto fail;
+
memset(&inreg, 0, sizeof inreg);
if (drive_info->ebios) {
@@ -102,7 +111,7 @@ int read_sectors(struct driveinfo *drive_info, void *data,
if (!drive_info->cbios) { // XXX errno
/* We failed to get the geometry */
if (lba)
- return -1; /* Can only read MBR */
+ goto fail; /* Can only read MBR */
s = 1;
h = 0;
@@ -112,7 +121,7 @@ int read_sectors(struct driveinfo *drive_info, void *data,
// XXX errno
if (s > 63 || h > 256 || c > 1023)
- return -1;
+ goto fail;
inreg.eax.w[0] = 0x0201; /* Read one sector */
inreg.ecx.b[1] = c & 0xff;
@@ -126,10 +135,14 @@ int read_sectors(struct driveinfo *drive_info, void *data,
/* Perform the read */
if (int13_retry(&inreg, &outreg)) {
errno_disk = outreg.eax.b[1];
- return -1; /* Give up */
+ goto fail; /* Give up */
}
memcpy(bufp, buf, sectors * SECTOR);
+ rv = sectors;
- return sectors;
+fail:
+ lfree(dapa);
+ lfree(buf);
+ return rv;
}
diff --git a/com32/gpllib/disk/write.c b/com32/gpllib/disk/write.c
index 89e530d9..d183adef 100644
--- a/com32/gpllib/disk/write.c
+++ b/com32/gpllib/disk/write.c
@@ -36,8 +36,17 @@ int write_sectors(const struct driveinfo *drive_info, const unsigned int lba,
const void *data, const int size)
{
com32sys_t inreg, outreg;
- struct ebios_dapa *dapa = __com32.cs_bounce;
- void *buf = (char *)__com32.cs_bounce + size;
+ struct ebios_dapa *dapa;
+ void *buf;
+ int rv = -1;
+
+ buf = lmalloc(size);
+ if (!buf)
+ return -1;
+
+ dapa = lmalloc(sizeof(*dapa));
+ if (!dapa)
+ goto out;
memcpy(buf, data, size);
memset(&inreg, 0, sizeof inreg);
@@ -59,7 +68,7 @@ int write_sectors(const struct driveinfo *drive_info, const unsigned int lba,
if (!drive_info->cbios) { // XXX errno
/* We failed to get the geometry */
if (lba)
- return -1; /* Can only write MBR */
+ goto out; /* Can only write MBR */
s = 1;
h = 0;
@@ -69,7 +78,7 @@ int write_sectors(const struct driveinfo *drive_info, const unsigned int lba,
// XXX errno
if (s > 63 || h > 256 || c > 1023)
- return -1;
+ goto out;
inreg.eax.w[0] = 0x0301; /* Write one sector */
inreg.ecx.b[1] = c & 0xff;
@@ -82,10 +91,13 @@ int write_sectors(const struct driveinfo *drive_info, const unsigned int lba,
/* Perform the write */
if (int13_retry(&inreg, &outreg)) {
- errno_disk = outreg.eax.b[1];
- return -1; /* Give up */
+ errno_disk = outreg.eax.b[1]; /* Give up */
} else
- return size;
+ rv = size;
+out:
+ lfree(dapa);
+ lfree(buf);
+ return rv;
}
/**
diff --git a/com32/gpllib/memory.c b/com32/gpllib/memory.c
index 28a95ff4..06c746da 100644
--- a/com32/gpllib/memory.c
+++ b/com32/gpllib/memory.c
@@ -87,15 +87,20 @@ void detect_memory_e820(struct e820entry *desc, int size_map, int *size_found)
{
int count = 0;
static struct e820_ext_entry buf; /* static so it is zeroed */
+ void *bounce;
com32sys_t ireg, oreg;
memset(&ireg, 0, sizeof ireg);
+ bounce = lmalloc(sizeof buf);
+ if (!bounce)
+ goto out;
+
ireg.eax.w[0] = 0xe820;
ireg.edx.l = SMAP;
ireg.ecx.l = sizeof(struct e820_ext_entry);
- ireg.edi.w[0] = OFFS(__com32.cs_bounce);
- ireg.es = SEG(__com32.cs_bounce);
+ ireg.edi.w[0] = OFFS(bounce);
+ ireg.es = SEG(bounce);
/*
* Set this here so that if the BIOS doesn't change this field
@@ -105,7 +110,7 @@ void detect_memory_e820(struct e820entry *desc, int size_map, int *size_found)
buf.ext_flags = 1;
do {
- memcpy(__com32.cs_bounce, &buf, sizeof buf);
+ memcpy(bounce, &buf, sizeof buf);
/* Important: %edx and %esi are clobbered by some BIOSes,
so they must be either used for the error output
@@ -126,7 +131,7 @@ void detect_memory_e820(struct e820entry *desc, int size_map, int *size_found)
if (oreg.eflags.l & EFLAGS_CF || oreg.ecx.l < 20)
break;
- memcpy(&buf, __com32.cs_bounce, sizeof buf);
+ memcpy(&buf, bounce, sizeof buf);
/*
* ACPI 3.0 added the extended flags support. If bit 0
@@ -143,6 +148,8 @@ void detect_memory_e820(struct e820entry *desc, int size_map, int *size_found)
ireg.ebx.l = oreg.ebx.l;
} while (ireg.ebx.l && count < size_map);
+out:
+ lfree(bounce);
*size_found = count;
}
diff --git a/com32/hdt/.gitignore b/com32/hdt/.gitignore
index 98927943..82d5b472 100644
--- a/com32/hdt/.gitignore
+++ b/com32/hdt/.gitignore
@@ -5,3 +5,4 @@ floppy/syslinux.cfg
*.iso
iso/
*gz
+hdt*checksums
diff --git a/com32/hdt/Makefile b/com32/hdt/Makefile
index 934ad25f..ff0fa2e2 100644
--- a/com32/hdt/Makefile
+++ b/com32/hdt/Makefile
@@ -20,6 +20,9 @@ MAKEDIR = $(topdir)/mk
include $(MAKEDIR)/elf.mk
LIBS = ../libupload/libcom32upload.a
+C_LIBS += $(com32)/cmenu/libmenu/libmenu.c32 \
+ $(com32)/libutil/libutil_com.c32 \
+ $(com32)/lib/libcom32.c32 $(com32)/gpllib/libcom32gpl.c32
CFLAGS += -I$(com32)/cmenu/libmenu -I$(com32)
MODULES = hdt.c32
@@ -45,7 +48,7 @@ FLOPPY_DIR ?= floppy
PCI_IDS_FILE ?= $(PWD)/$(FLOPPY_DIR)/pci.ids
GZ_PCI_IDS_FILE ?= $(PCI_IDS_FILE).gz
MENU_COM32 ?= $(com32)/menu/menu.c32
-CHAIN_COM32 ?= $(com32)/modules/chain.c32
+CHAIN_COM32 ?= $(com32)/chain/chain.c32
ART_DIR ?= art/
QEMU ?= qemu-kvm
@@ -110,10 +113,16 @@ hdt.iso: hdt.c32 $(topdir)/core/isolinux.bin $(FLOPPY_DIR)/hdt.cfg memtest
mv hdt.iso hdt-$(VERSION).iso
ln -sf hdt-$(VERSION).iso hdt.iso
-release: spotless hdt.c32 hdt.img hdt.img.gz hdt.iso
+hdt-hybrid.iso: hdt.iso ../../utils/isohybrid
+ cp hdt-$(VERSION).iso hdt-hybrid-$(VERSION).iso
+ ../../utils/isohybrid --partok hdt-hybrid-$(VERSION).iso
+ ln -sf hdt-hybrid-$(VERSION).iso hdt-hybrid.iso
+
+release: spotless hdt.c32 hdt.img hdt.img.gz hdt.iso hdt-hybrid.iso
mv hdt.c32 hdt_$(NODASH_VERSION).c32
md5sum hdt_$(NODASH_VERSION).c32 >$(SUM_FILE)
md5sum hdt-$(VERSION).iso >>$(SUM_FILE)
+ md5sum hdt-hybrid-$(VERSION).iso >>$(SUM_FILE)
md5sum hdt-$(VERSION).img >>$(SUM_FILE)
md5sum hdt-$(VERSION).img.gz >>$(SUM_FILE)
diff --git a/com32/hdt/floppy/hdt.cfg b/com32/hdt/floppy/hdt.cfg
index c876d239..e5f3b0a0 100644
--- a/com32/hdt/floppy/hdt.cfg
+++ b/com32/hdt/floppy/hdt.cfg
@@ -86,6 +86,15 @@ ENDTEXT
COM32 hdt.c32
APPEND modules_pcimap=modules.pcimap modules_alias=modules.alias pciids=pci.ids quiet vesa nomenu auto='dump'
+LABEL postexec
+MENU LABEL Dump memory info, sleep 5 and start memtest entry
+TEXT HELP
+ Starts HDT using the Command Line Interface (CLI), show an item, say a message reboot and start memtest
+ VESA mode is enabled
+ENDTEXT
+COM32 hdt.c32
+APPEND modules_pcimap=modules.pcimap modules_alias=modules.alias pciids=pci.ids quiet vesa nomenu auto='show memory;say `########`;say `Starting memtest in 5 sec`%5;exit' postexec='memtest'
+
MENU SEPARATOR
LABEL memtest
diff --git a/com32/hdt/hdt-cli-acpi.c b/com32/hdt/hdt-cli-acpi.c
index a978bb36..55b0c3c7 100644
--- a/com32/hdt/hdt-cli-acpi.c
+++ b/com32/hdt/hdt-cli-acpi.c
@@ -267,10 +267,12 @@ struct cli_callback_descr list_acpi_show_modules[] = {
{
.name = "apic",
.exec = show_acpi_apic,
+ .nomodule = false,
},
{
.name = NULL,
.exec = NULL,
+ .nomodule = false,
},
};
diff --git a/com32/hdt/hdt-cli-disk.c b/com32/hdt/hdt-cli-disk.c
index 24fce676..10c95d7d 100644
--- a/com32/hdt/hdt-cli-disk.c
+++ b/com32/hdt/hdt-cli-disk.c
@@ -225,14 +225,17 @@ struct cli_callback_descr list_disk_show_modules[] = {
{
.name = "disks",
.exec = main_show_disks,
+ .nomodule = false,
},
{
.name = "disk",
.exec = main_show_disk,
+ .nomodule = false,
},
{
.name = NULL,
.exec = NULL,
+ .nomodule = false,
},
};
diff --git a/com32/hdt/hdt-cli-dmi.c b/com32/hdt/hdt-cli-dmi.c
index 45cbb240..02bea0f7 100644
--- a/com32/hdt/hdt-cli-dmi.c
+++ b/com32/hdt/hdt-cli-dmi.c
@@ -617,62 +617,77 @@ struct cli_callback_descr list_dmi_show_modules[] = {
{
.name = CLI_DMI_BASE_BOARD,
.exec = show_dmi_base_board,
+ .nomodule = false,
},
{
.name = CLI_DMI_BIOS,
.exec = show_dmi_bios,
+ .nomodule = false,
},
{
.name = CLI_DMI_BATTERY,
.exec = show_dmi_battery,
+ .nomodule = false,
},
{
.name = CLI_DMI_CHASSIS,
.exec = show_dmi_chassis,
+ .nomodule = false,
},
{
.name = CLI_DMI_MEMORY,
.exec = show_dmi_memory_modules,
+ .nomodule = false,
},
{
.name = CLI_DMI_MEMORY_BANK,
.exec = show_dmi_memory_bank,
+ .nomodule = false,
},
{
.name = "module",
.exec = show_dmi_memory_module,
+ .nomodule = false,
},
{
.name = CLI_DMI_PROCESSOR,
.exec = show_dmi_cpu,
+ .nomodule = false,
},
{
.name = CLI_DMI_SYSTEM,
.exec = show_dmi_system,
+ .nomodule = false,
},
{
.name = CLI_DMI_OEM,
.exec = show_dmi_oem_strings,
+ .nomodule = false,
},
{
.name = CLI_DMI_SECURITY,
.exec = show_dmi_hardware_security,
+ .nomodule = false,
},
{
.name = CLI_DMI_IPMI,
.exec = show_dmi_ipmi,
+ .nomodule = false,
},
{
.name = CLI_DMI_CACHE,
.exec = show_dmi_cache,
+ .nomodule = false,
},
{
.name = CLI_DMI_LIST,
.exec = show_dmi_modules,
+ .nomodule = false,
},
{
.name = NULL,
.exec = NULL,
+ .nomodule = false,
},
};
diff --git a/com32/hdt/hdt-cli-hdt.c b/com32/hdt/hdt-cli-hdt.c
index e9752612..f7f7e949 100644
--- a/com32/hdt/hdt-cli-hdt.c
+++ b/com32/hdt/hdt-cli-hdt.c
@@ -259,101 +259,184 @@ static void do_dump(int argc __unused, char **argv __unused,
dump(hardware);
}
+/**
+ * do_say - say message to user
+ **/
+static void do_say(int argc , char **argv ,
+ struct s_hardware *hardware)
+{
+ (void) hardware;
+ if (argc == 0) return;
+
+ char text_to_say[255]={0};
+ int arg=0;
+ int sleep_time=0;
+#if DEBUG
+ for (int i=0; i<argc;i++) dprintf("SAY: arg[%d]={%s}\n",i,argv[i]);
+#endif
+ char *argument = strchr(argv[arg],'`');
+ if ( argument != NULL) {
+ argument++;
+ strcat(text_to_say, argument);
+
+ while ((strchr(argument, '`') == NULL) && (arg+1<argc)) {
+ arg++;
+ argument = (char *)argv[arg];
+ strcat(text_to_say, " ");
+ strcat(text_to_say, argument);
+ }
+
+ /* Removing last ` if any */
+ char *last_quote = strrchr(text_to_say,'`');
+ if ( last_quote != NULL ) {
+ *last_quote='\0';
+ dprintf("SAY CMD = [%s]\n",text_to_say);
+ }
+
+ /* The % char can be in the same argument, let's consider it again */
+ arg--;
+
+ /* Searching for a % argument to determine the time to show the message */
+ char *time_to_display = NULL;
+ /* Search for a requested time to display */
+ while ( ((time_to_display=strchr(argument, '%')) == NULL) && (arg+1<argc)) {
+ arg++;
+ argument = (char *)argv[arg];
+ }
+
+ if (time_to_display != NULL) {
+ sleep_time=atoi(time_to_display+1);
+ dprintf("SAY CMD :Time to display = %d\n",sleep_time);
+ }
+
+ printf("%s\n",text_to_say);
+ sleep(sleep_time);
+ }
+}
+
/* Default hdt mode */
struct cli_callback_descr list_hdt_default_modules[] = {
{
.name = CLI_CLEAR,
.exec = cli_clear_screen,
+ .nomodule = false,
},
{
.name = CLI_EXIT,
.exec = do_exit,
+ .nomodule = false,
},
{
.name = CLI_HELP,
.exec = show_cli_help,
+ .nomodule = false,
},
{
.name = CLI_MENU,
.exec = goto_menu,
+ .nomodule = false,
},
{
.name = CLI_REBOOT,
.exec = do_reboot,
+ .nomodule = false,
},
{
.name = CLI_HISTORY,
.exec = print_history,
+ .nomodule = false,
},
{
.name = CLI_DUMP,
.exec = do_dump,
+ .nomodule = false,
+ },
+ {
+ .name = CLI_SAY,
+ .exec = do_say,
+ .nomodule = true,
},
{
.name = NULL,
- .exec = NULL},
+ .exec = NULL,
+ .nomodule = false},
};
struct cli_callback_descr list_hdt_show_modules[] = {
{
.name = CLI_SUMMARY,
.exec = main_show_summary,
+ .nomodule = false,
},
{
.name = CLI_PCI,
.exec = main_show_pci,
+ .nomodule = false,
},
{
.name = CLI_DMI,
.exec = main_show_dmi,
+ .nomodule = false,
},
{
.name = CLI_CPU,
.exec = main_show_cpu,
+ .nomodule = false,
},
{
.name = CLI_DISK,
.exec = disks_summary,
+ .nomodule = false,
},
{
.name = CLI_PXE,
.exec = main_show_pxe,
+ .nomodule = false,
},
{
.name = CLI_SYSLINUX,
.exec = main_show_syslinux,
+ .nomodule = false,
},
{
.name = CLI_KERNEL,
.exec = main_show_kernel,
+ .nomodule = false,
},
{
.name = CLI_VESA,
.exec = main_show_vesa,
+ .nomodule = false,
},
{
.name = CLI_HDT,
.exec = main_show_hdt,
+ .nomodule = false,
},
{
.name = CLI_VPD,
.exec = main_show_vpd,
+ .nomodule = false,
},
{
.name = CLI_MEMORY,
.exec = show_dmi_memory_modules,
+ .nomodule = false,
},
{
.name = CLI_ACPI,
.exec = main_show_acpi,
+ .nomodule = false,
},
{
.name = "modes",
.exec = main_show_modes,
+ .nomodule = false,
},
{
.name = NULL,
.exec = NULL,
+ .nomodule = false,
},
};
@@ -361,10 +444,12 @@ struct cli_callback_descr list_hdt_set_modules[] = {
{
.name = CLI_MODE,
.exec = cli_set_mode,
+ .nomodule = false,
},
{
.name = NULL,
.exec = NULL,
+ .nomodule = false,
},
};
diff --git a/com32/hdt/hdt-cli-memory.c b/com32/hdt/hdt-cli-memory.c
index 51d087e8..c05b7cd6 100644
--- a/com32/hdt/hdt-cli-memory.c
+++ b/com32/hdt/hdt-cli-memory.c
@@ -101,22 +101,27 @@ struct cli_callback_descr list_memory_show_modules[] = {
{
.name = "e820",
.exec = show_memory_e820,
+ .nomodule=false,
},
{
.name = "e801",
.exec = show_memory_e801,
+ .nomodule=false,
},
{
.name = "88",
.exec = show_memory_88,
+ .nomodule=false,
},
{
.name = CLI_DMI_MEMORY_BANK,
.exec = show_dmi_memory_bank,
+ .nomodule=false,
},
{
.name = NULL,
.exec = NULL,
+ .nomodule=false,
},
};
diff --git a/com32/hdt/hdt-cli-pci.c b/com32/hdt/hdt-cli-pci.c
index 07c079d5..75fc0011 100644
--- a/com32/hdt/hdt-cli-pci.c
+++ b/com32/hdt/hdt-cli-pci.c
@@ -266,14 +266,17 @@ struct cli_callback_descr list_pci_show_modules[] = {
{
.name = CLI_IRQ,
.exec = show_pci_irq,
+ .nomodule=false,
},
{
.name = CLI_PCI_DEVICE,
.exec = show_pci_device,
+ .nomodule=false,
},
{
.name = NULL,
.exec = NULL,
+ .nomodule=false,
},
};
diff --git a/com32/hdt/hdt-cli-vesa.c b/com32/hdt/hdt-cli-vesa.c
index 702f8bd6..ca44987a 100644
--- a/com32/hdt/hdt-cli-vesa.c
+++ b/com32/hdt/hdt-cli-vesa.c
@@ -98,10 +98,12 @@ struct cli_callback_descr list_vesa_show_modules[] = {
{
.name = CLI_MODES,
.exec = show_vesa_modes,
+ .nomodule=false,
},
{
.name = NULL,
.exec = NULL,
+ .nomodule=false,
},
};
@@ -109,15 +111,18 @@ struct cli_callback_descr list_vesa_commands[] = {
{
.name = CLI_ENABLE,
.exec = enable_vesa,
+ .nomodule=false,
},
{
.name = CLI_DISABLE,
.exec = disable_vesa,
+ .nomodule=false,
},
{
.name = NULL,
.exec = NULL,
+ .nomodule=false,
},
};
diff --git a/com32/hdt/hdt-cli.c b/com32/hdt/hdt-cli.c
index 330f93c4..11984e5a 100644
--- a/com32/hdt/hdt-cli.c
+++ b/com32/hdt/hdt-cli.c
@@ -365,14 +365,14 @@ static void parse_command_line(char *line, char **command, char **module,
*command = malloc((token_len + 1) * sizeof(char));
strlcpy(*command, pch, token_len);
(*command)[token_len] = '\0';
- dprintf("CLI DEBUG: command = %s\n", *command);
+ dprintf("CLI DEBUG parse: command = %s\n", *command);
args_pos += args_len;
} else if (token_found == 1) {
/* Module */
*module = malloc((token_len + 1) * sizeof(char));
strlcpy(*module, pch, token_len);
(*module)[token_len] = '\0';
- dprintf("CLI DEBUG: module = %s\n", *module);
+ dprintf("CLI DEBUG parse: module = %s\n", *module);
args_pos += args_len;
} else
(*argc)++;
@@ -380,7 +380,7 @@ static void parse_command_line(char *line, char **command, char **module,
token_found++;
pch = pch_next;
}
- dprintf("CLI DEBUG: argc = %d\n", *argc);
+ dprintf("CLI DEBUG parse: argc = %d\n", *argc);
/* Skip arguments handling if none is supplied */
if (!*argc)
@@ -390,9 +390,9 @@ static void parse_command_line(char *line, char **command, char **module,
*argv = malloc(*argc * sizeof(char *));
pch = strtok(line + args_pos, CLI_SPACE);
while (pch != NULL) {
- dprintf("CLI DEBUG: argv[%d] = %s\n", argc_iter, pch);
- argv[argc_iter] = malloc(sizeof(pch) * sizeof(char));
- strlcpy(argv[argc_iter], pch, sizeof(pch));
+ dprintf("CLI DEBUG parse: argv[%d] = %s\n", argc_iter, pch);
+ argv[argc_iter] = malloc(strlen(pch) * sizeof(char));
+ strlcpy(argv[argc_iter], pch, strlen(pch));
argc_iter++;
pch = strtok(NULL, CLI_SPACE);
/*
@@ -585,6 +585,7 @@ static void autocomplete(char *line)
parse_command_line(line, &command, &module, &argc, argv);
+ dprintf("CLI DEBUG autocomplete: before checking args\n");
/* If the user specified arguments, there is nothing we can complete */
if (argc != 0)
goto out;
@@ -625,22 +626,43 @@ static void exec_command(char *line, struct s_hardware *hardware)
/* This will allocate memory for command and module */
parse_command_line(line, &command, &module, &argc, argv);
+ dprintf("CLI DEBUG exec: Checking for aliases\n");
/*
* Expand shortcuts, if needed
* This will allocate memory for argc/argv
*/
expand_aliases(line, &command, &module, &argc, argv);
+
+ find_cli_callback_descr(command, current_mode->default_modules,
+ &current_module);
- if (module == NULL) {
- dprintf("CLI DEBUG: single command detected\n");
+ if ((module == NULL) || (current_module->nomodule == true)) {
+ dprintf("CLI DEBUG exec : single command detected\n");
/*
* A single word was specified: look at the list of default
* commands in the current mode to see if there is a match.
* If not, it may be a generic function (exit, help, ...). These
* are stored in the list of default commands of the hdt mode.
*/
- find_cli_callback_descr(command, current_mode->default_modules,
- &current_module);
+
+ /* First of all it the command doesn't need module, let's rework the arguments */
+ if ((current_module->nomodule == true) && ( module != NULL)) {
+ dprintf("CLI_DEBUG exec: Reworking arguments with argc=%d\n",argc);
+ char **new_argv=NULL;
+ new_argv=malloc((argc + 2)*sizeof(char));
+ for (int argc_iter=0; argc_iter<argc; argc_iter++) {
+ dprintf("CLI_DEBUG exec rework : copy %d to %d (%s)\n",argc_iter,argc_iter+1,argv[argc_iter]);
+ new_argv[argc_iter+1] = malloc(strlen(argv[argc_iter]));
+ strlcpy(new_argv[argc_iter+1], argv[argc_iter], strlen(argv[argc_iter]));
+ free(argv[argc_iter]);
+ }
+ new_argv[0] = malloc(strlen(module)*sizeof(char));
+ strlcpy(new_argv[0], module, strlen(module));
+ argc++;
+ free(argv);
+ argv=new_argv;
+ }
+
if (current_module != NULL)
current_module->exec(argc, argv, hardware);
else if (!strncmp(command, CLI_SHOW, sizeof(CLI_SHOW) - 1) &&
@@ -673,7 +695,7 @@ static void exec_command(char *line, struct s_hardware *hardware)
* hdt> set mode dmi
*/
if (!strncmp(command, CLI_SHOW, sizeof(CLI_SHOW) - 1)) {
- dprintf("CLI DEBUG: %s command detected\n", CLI_SHOW);
+ dprintf("CLI DEBUG exec: %s command detected\n", CLI_SHOW);
/* Look first for a 'show' callback in the current mode */
find_cli_callback_descr(module, current_mode->show_modules,
&current_module);
@@ -681,6 +703,7 @@ static void exec_command(char *line, struct s_hardware *hardware)
if (current_module != NULL)
current_module->exec(argc, argv, hardware);
else {
+ dprintf("CLI DEBUG exec: Looking for callback\n");
/* Look now for a 'show' callback in the hdt mode */
find_cli_callback_descr(module, hdt_mode.show_modules,
&current_module);
@@ -691,7 +714,7 @@ static void exec_command(char *line, struct s_hardware *hardware)
printf("unknown module: '%s'\n", module);
}
} else if (!strncmp(command, CLI_SET, sizeof(CLI_SET) - 1)) {
- dprintf("CLI DEBUG: %s command detected\n", CLI_SET);
+ dprintf("CLI DEBUG exec : %s command detected\n", CLI_SET);
/* Look now for a 'set' callback in the hdt mode */
find_cli_callback_descr(module, current_mode->set_modules,
&current_module);
diff --git a/com32/hdt/hdt-cli.h b/com32/hdt/hdt-cli.h
index 68b33158..30fe5187 100644
--- a/com32/hdt/hdt-cli.h
+++ b/com32/hdt/hdt-cli.h
@@ -66,6 +66,7 @@
#define CLI_ENABLE "enable"
#define CLI_DISABLE "disable"
#define CLI_DUMP "dump"
+#define CLI_SAY "say"
typedef enum {
INVALID_MODE,
@@ -120,6 +121,7 @@ struct cli_module_descr {
struct cli_callback_descr {
const char *name;
void (*exec) (int argc, char **argv, struct s_hardware * hardware);
+ bool nomodule;
};
/* Manage aliases */
diff --git a/com32/hdt/hdt-common.c b/com32/hdt/hdt-common.c
index aac50eb9..f729a107 100644
--- a/com32/hdt/hdt-common.c
+++ b/com32/hdt/hdt-common.c
@@ -106,12 +106,36 @@ void detect_parameters(const int argc, const char *argv[],
max_console_lines = MAX_CLI_LINES;
} else if (!strncmp(argv[i], "nomenu", 6)) {
menumode = false;
+ } else if (!strncmp(argv[i], "dump_filename=", 14)) {
+ strlcpy(hardware->dump_filename, argv[i] + 14,
+ sizeof(hardware->dump_filename));
} else if (!strncmp(argv[i], "dump_path=", 10)) {
strlcpy(hardware->dump_path, argv[i] + 10,
sizeof(hardware->dump_path));
} else if (!strncmp(argv[i], "tftp_ip=", 8)) {
strlcpy(hardware->tftp_ip, argv[i] + 8,
sizeof(hardware->tftp_ip));
+ } else if (!strncmp(argv[i], "postexec=", 9)) {
+ /* The postexec= parameter is separated in several argv[]
+ * as it can contains spaces.
+ * We use the AUTO_DELIMITER char to define the limits
+ * of this parameter.
+ * i.e postexec='linux memtest.bin'
+ */
+
+ char *argument = (char*)argv[i]+10;
+ /* Extracting the first parameter */
+ strcpy(hardware->postexec, argument);
+
+ /* While we can't find the other AUTO_DELIMITER, let's process the argv[] */
+ while ((strchr(argument, AUTO_DELIMITER) == NULL) && (i+1<argc)) {
+ i++;
+ argument = (char *)argv[i];
+ strcat(hardware->postexec, " ");
+ strcat(hardware->postexec, argument);
+ }
+
+ hardware->postexec[strlen(hardware->postexec) - 1] = 0;
} else if (!strncmp(argv[i], "auto=", 5)) {
/* The auto= parameter is separated in several argv[]
* as it can contains spaces.
@@ -204,9 +228,12 @@ void init_hardware(struct s_hardware *hardware)
memset(hardware->memtest_label, 0, sizeof hardware->memtest_label);
memset(hardware->auto_label, 0, sizeof hardware->auto_label);
memset(hardware->dump_path, 0, sizeof hardware->dump_path);
+ memset(hardware->dump_filename, 0, sizeof hardware->dump_filename);
memset(hardware->vesa_background, 0, sizeof hardware->vesa_background);
memset(hardware->tftp_ip, 0, sizeof hardware->tftp_ip);
+ memset(hardware->postexec, 0, sizeof hardware->postexec);
strcat(hardware->dump_path, "hdt");
+ strcat(hardware->dump_filename, "%{m}+%{p}+%{v}");
strcat(hardware->pciids_path, "pci.ids");
strcat(hardware->modules_pcimap_path, "modules.pcimap");
strcat(hardware->modules_alias_path, "modules.alias");
@@ -285,6 +312,7 @@ int detect_vesa(struct s_hardware *hardware)
struct vesa_mode_info *mi;
uint16_t mode, *mode_ptr;
char *oem_ptr;
+ int rv = -1;
if (hardware->vesa_detection == true)
return -1;
@@ -292,9 +320,13 @@ int detect_vesa(struct s_hardware *hardware)
hardware->vesa_detection = true;
hardware->is_vesa_valid = false;
- /* Allocate space in the bounce buffer for these structures */
- gi = &((struct vesa_info *)__com32.cs_bounce)->gi;
- mi = &((struct vesa_info *)__com32.cs_bounce)->mi;
+ gi = lmalloc(sizeof(*gi));
+ if (!gi)
+ return -1;
+
+ mi = lmalloc(sizeof(*mi));
+ if (!mi)
+ goto out;
gi->signature = VBE2_MAGIC; /* Get VBE2 extended data */
rm.eax.w[0] = 0x4F00; /* Get SVGA general information */
@@ -303,7 +335,7 @@ int detect_vesa(struct s_hardware *hardware)
__intcall(0x10, &rm, &rm);
if (rm.eax.w[0] != 0x004F) {
- return -1;
+ goto out;
};
mode_ptr = GET_PTR(gi->video_mode_ptr);
@@ -342,7 +374,12 @@ int detect_vesa(struct s_hardware *hardware)
hardware->vesa.vmi_count++;
}
hardware->is_vesa_valid = true;
- return 0;
+
+ rv = 0;
+out:
+ lfree(mi);
+ lfree(gi);
+ return rv;
}
/* Try to detect disks from port 0x80 to 0xff */
diff --git a/com32/hdt/hdt-common.h b/com32/hdt/hdt-common.h
index d37fcc8a..4a288b44 100644
--- a/com32/hdt/hdt-common.h
+++ b/com32/hdt/hdt-common.h
@@ -54,9 +54,6 @@
#include <acpi/acpi.h>
#include <libupload/upload_backend.h>
-/* Declare a variable or data structure as unused. */
-#define __unused __attribute__ (( unused ))
-
/* This two values are used for switching for the menu to the CLI mode */
#define HDT_SWITCH_TO_CLI "hdt_switch_to_cli"
#define HDT_DUMP "hdt_dump"
@@ -214,10 +211,12 @@ struct s_hardware {
char modules_alias_path[255];
char pciids_path[255];
char dump_path[255]; /* Dump path on the tftp server */
+ char dump_filename[255]; /* Dump filename on the tftp server */
char tftp_ip[255]; /* IP address of tftp server (dump mode) */
char memtest_label[255];
char auto_label[AUTO_COMMAND_SIZE];
char vesa_background[255];
+ char postexec[255];
};
void reset_more_printf(void);
diff --git a/com32/hdt/hdt-dump-disks.c b/com32/hdt/hdt-dump-disks.c
index dcbcaa9e..ff744b30 100644
--- a/com32/hdt/hdt-dump-disks.c
+++ b/com32/hdt/hdt-dump-disks.c
@@ -42,6 +42,7 @@ static void show_partition_information(struct driveinfo *drive_info,
char ostype[64]={0};
char *parttype;
unsigned int start, end;
+ char bootable[6] = {0};
int i = nb_partitions_seen;
start = partition_offset;
@@ -52,6 +53,10 @@ static void show_partition_information(struct driveinfo *drive_info,
get_label(ptab->ostype, &parttype);
get_bootloader_string(drive_info, ptab, bootloader_name, 9);
+ if (ptab->active_flag == 0x80)
+ snprintf(bootable,sizeof(bootable),"%s","true");
+ else
+ snprintf(bootable,sizeof(bootable),"%s","false");
snprintf(ostype,sizeof(ostype),"%02X",ptab->ostype);
@@ -62,6 +67,7 @@ static void show_partition_information(struct driveinfo *drive_info,
add_as("partition->size",size)
add_as("partition->type",parttype)
add_as("partition->os_type",ostype)
+ add_as("partition->boot_flag",bootable)
END_OF_APPEND;
free(parttype);
}
@@ -117,7 +123,9 @@ void show_disk(struct s_hardware *hardware, ZZJSON_CONFIG *conf, ZZJSON **it, in
void dump_disks(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **item) {
bool found=false;
- for (int drive = 0x80; drive < 0xff; drive++) {
+
+ if (hardware->disks_count > 0)
+ for (int drive = 0x80; drive < 0xff; drive++) {
if (hardware->disk_info[drive - 0x80].cbios) {
if (found==false) {
CREATE_NEW_OBJECT;
@@ -131,7 +139,7 @@ void dump_disks(struct s_hardware *hardware, ZZJSON_CONFIG *config, ZZJSON **ite
if (found==false) {
CREATE_NEW_OBJECT;
add_b("disks->is_valid",false);
- FLUSH_OBJECT;
}
+ FLUSH_OBJECT;
to_cpio("disks");
}
diff --git a/com32/hdt/hdt-dump.c b/com32/hdt/hdt-dump.c
index 8c221405..b963e19b 100644
--- a/com32/hdt/hdt-dump.c
+++ b/com32/hdt/hdt-dump.c
@@ -37,56 +37,117 @@
struct print_buf p_buf;
-void compute_filename(struct s_hardware *hardware, char *filename, int size) {
-
- snprintf(filename,size,"%s/",hardware->dump_path);
-
- if (hardware->is_pxe_valid) {
- strncat(filename, hardware->pxe.mac_addr, sizeof(hardware->pxe.mac_addr));
- strncat(filename, "+", 1);
- }
-
- if (hardware->is_dmi_valid) {
- strncat(filename, remove_spaces(hardware->dmi.system.product_name), sizeof(hardware->dmi.system.manufacturer));
- strncat(filename, "+", 1);
- strncat(filename, remove_spaces(hardware->dmi.system.manufacturer), sizeof(hardware->dmi.system.product_name));
+struct dump_option {
+ char *flag;
+ char *item;
+};
+
+char *get_value_from_option(struct s_hardware *hardware, char *option)
+{
+ struct dump_option dump_options[10];
+ dump_options[0].flag = "%{m}";
+ dump_options[0].item = hardware->pxe.mac_addr;
+
+ dump_options[1].flag = "%{v}";
+ dump_options[1].item = hardware->dmi.system.manufacturer;
+
+ dump_options[2].flag = "%{p}";
+ dump_options[2].item = hardware->dmi.system.product_name;
+
+ dump_options[3].flag = "%{ba}";
+ dump_options[3].item = hardware->dmi.base_board.asset_tag;
+
+ dump_options[4].flag = "%{bs}";
+ dump_options[4].item = hardware->dmi.base_board.serial;
+
+ dump_options[5].flag = "%{ca}";
+ dump_options[5].item = hardware->dmi.chassis.asset_tag;
+
+ dump_options[6].flag = "%{cs}";
+ dump_options[6].item = hardware->dmi.chassis.serial;
+
+ dump_options[7].flag = "%{sk}";
+ dump_options[7].item = hardware->dmi.system.sku_number;
+
+ dump_options[8].flag = "%{ss}";
+ dump_options[8].item = hardware->dmi.system.serial;
+
+ dump_options[9].flag = NULL;
+ dump_options[9].item = NULL;
+
+ for (int i = 0; i < 9; i++) {
+ if (strcmp(option, dump_options[i].flag) == 0) {
+ return remove_spaces(dump_options[i].item);
+ }
+ }
+
+ return NULL;
+}
+
+char *compute_filename(struct s_hardware *hardware)
+{
+
+ char *filename = malloc(512);
+ snprintf(filename, 512, "%s/%s", hardware->dump_path,
+ hardware->dump_filename);
+
+ /* Until we found some dump parameters */
+ char *buffer;
+ while ((buffer = strstr(filename, "%{"))) {
+ // Find the end of the parameter
+ char *buffer_end = strstr(buffer, "}");
+
+ // Extracting the parameter between %{ and }
+ char option[8] = { 0 };
+ strncpy(option, buffer, buffer_end - buffer + 1);
+
+ /* Replace this option by its value in the filename
+ * Filename is longer than the previous filename we had
+ * so let's restart from the beginning */
+ filename =
+ strreplace(filename, option,
+ get_value_from_option(hardware, option));
}
/* We replace the ":" in the filename by some "-"
* This will avoid Microsoft FS turning crazy */
- chrreplace(filename,':','-');
+ chrreplace(filename, ':', '-');
/* Avoid space to make filename easier to manipulate */
- chrreplace(filename,' ','_');
+ chrreplace(filename, ' ', '_');
+ return filename;
}
-int dumpprintf(FILE *p, const char *format, ...) {
- va_list ap;
- int rv;
-
- (void) p;
- va_start(ap, format);
- rv = vbufprintf(&p_buf,format, ap);
- va_end(ap);
- return rv;
+int dumpprintf(FILE * p, const char *format, ...)
+{
+ va_list ap;
+ int rv;
+
+ (void)p;
+ va_start(ap, format);
+ rv = vbufprintf(&p_buf, format, ap);
+ va_end(ap);
+ return rv;
}
-void to_cpio(char *filename) {
- cpio_writefile(upload,filename,p_buf.buf,p_buf.len);
- if ((p_buf.buf) && (p_buf.len > 0)){
- memset(p_buf.buf,0,p_buf.len);
- free(p_buf.buf);
- p_buf.buf=NULL;
- p_buf.size=0;
- p_buf.len=0;
- }
+void to_cpio(char *filename)
+{
+ cpio_writefile(upload, filename, p_buf.buf, p_buf.len);
+ if ((p_buf.buf) && (p_buf.len > 0)) {
+ memset(p_buf.buf, 0, p_buf.len);
+ free(p_buf.buf);
+ p_buf.buf = NULL;
+ p_buf.size = 0;
+ p_buf.len = 0;
+ }
}
-void flush (ZZJSON_CONFIG *config, ZZJSON ** item) {
- zzjson_print(config, *item);
- zzjson_free(config, *item);
- *item=NULL;
+void flush(ZZJSON_CONFIG * config, ZZJSON ** item)
+{
+ zzjson_print(config, *item);
+ zzjson_free(config, *item);
+ *item = NULL;
}
/**
@@ -94,53 +155,52 @@ void flush (ZZJSON_CONFIG *config, ZZJSON ** item) {
**/
void dump(struct s_hardware *hardware)
{
- if (hardware->is_pxe_valid==false) {
- printf("PXE stack was not detected, Dump feature is not available\n");
- return;
+ if (hardware->is_pxe_valid == false) {
+ printf("PXE stack was not detected, Dump feature is not available\n");
+ return;
}
const union syslinux_derivative_info *sdi = syslinux_derivative_info();
- int err=0;
+ int err = 0;
ZZJSON *json = NULL;
ZZJSON_CONFIG config = { ZZJSON_VERY_STRICT, NULL,
- (int(*)(void*)) fgetc,
- NULL,
- malloc, calloc, free, realloc,
- stderr, NULL, stdout,
- (int(*)(void *,const char*,...)) dumpprintf,
- (int(*)(int,void*)) fputc
+ (int (*)(void *))fgetc,
+ NULL,
+ malloc, calloc, free, realloc,
+ stderr, NULL, stdout,
+ (int (*)(void *, const char *,...))dumpprintf,
+ (int (*)(int, void *))fputc
};
- memset(&p_buf,0,sizeof(p_buf));
+ memset(&p_buf, 0, sizeof(p_buf));
/* By now, we only support TFTP reporting */
- upload=&upload_tftp;
- upload->name="tftp";
+ upload = &upload_tftp;
+ upload->name = "tftp";
/* The following defines the behavior of the reporting */
char *arg[64];
- char filename[512]={0};
- compute_filename(hardware, filename, sizeof(filename));
+ char *filename = compute_filename(hardware);
/* The filename */
arg[0] = filename;
/* The server to upload the file */
if (strlen(hardware->tftp_ip) != 0) {
- arg[1] = hardware->tftp_ip;
- arg[2] = NULL;
+ arg[1] = hardware->tftp_ip;
+ arg[2] = NULL;
} else {
- arg[1] = NULL;
- snprintf(hardware->tftp_ip, sizeof(hardware->tftp_ip),
- "%u.%u.%u.%u",
- ((uint8_t *)&sdi->pxe.ipinfo->serverip)[0],
- ((uint8_t *)&sdi->pxe.ipinfo->serverip)[1],
- ((uint8_t *)&sdi->pxe.ipinfo->serverip)[2],
- ((uint8_t *)&sdi->pxe.ipinfo->serverip)[3]);
+ arg[1] = NULL;
+ snprintf(hardware->tftp_ip, sizeof(hardware->tftp_ip),
+ "%u.%u.%u.%u",
+ ((uint8_t *) & sdi->pxe.ipinfo->serverip)[0],
+ ((uint8_t *) & sdi->pxe.ipinfo->serverip)[1],
+ ((uint8_t *) & sdi->pxe.ipinfo->serverip)[2],
+ ((uint8_t *) & sdi->pxe.ipinfo->serverip)[3]);
}
/* We initiate the cpio to send */
- cpio_init(upload,(const char **)arg);
+ cpio_init(upload, (const char **)arg);
dump_cpu(hardware, &config, &json);
dump_pxe(hardware, &config, &json);
@@ -158,12 +218,12 @@ void dump(struct s_hardware *hardware)
/* We close & flush the file to send */
cpio_close(upload);
- if ((err=flush_data(upload)) != TFTP_OK) {
+ if ((err = flush_data(upload)) != TFTP_OK) {
/* As we manage a tftp connection, let's display the associated error message */
more_printf("Dump failed !\n");
- more_printf("TFTP ERROR on : %s:/%s \n",hardware->tftp_ip, filename);
- more_printf("TFTP ERROR msg : %s \n",tftp_string_error_message[-err]);
+ more_printf("TFTP ERROR on : %s:/%s \n", hardware->tftp_ip, filename);
+ more_printf("TFTP ERROR msg : %s \n", tftp_string_error_message[-err]);
} else {
- more_printf("Dump file sent at %s:/%s\n",hardware->tftp_ip, filename);
+ more_printf("Dump file sent at %s:/%s\n", hardware->tftp_ip, filename);
}
}
diff --git a/com32/hdt/hdt-menu-summary.c b/com32/hdt/hdt-menu-summary.c
index ad87c299..cef7e69e 100644
--- a/com32/hdt/hdt-menu-summary.c
+++ b/com32/hdt/hdt-menu-summary.c
@@ -52,8 +52,7 @@ void compute_summarymenu(struct s_my_menu *menu, struct s_hardware *hardware)
add_item(buffer, statbuffer, OPT_INACTIVE, NULL, 0);
menu->items_count++;
- char features[SUBMENULEN + 1];
- memset(features, 0, sizeof(features));
+ char features[255]={0};
if (hardware->dmi.processor.thread_count != 0)
sprintf(buffer, ", %d thread", hardware->dmi.processor.thread_count);
else
diff --git a/com32/hdt/hdt.c b/com32/hdt/hdt.c
index a1e3923c..851b0462 100644
--- a/com32/hdt/hdt.c
+++ b/com32/hdt/hdt.c
@@ -74,14 +74,21 @@ int main(const int argc, const char *argv[])
printf("%s\n", version_string);
+ int return_code = 0;
+
if (!menumode || automode)
start_cli_mode(&hardware);
else {
- int return_code = start_menu_mode(&hardware, version_string);
+ return_code = start_menu_mode(&hardware, version_string);
if (return_code == HDT_RETURN_TO_CLI)
start_cli_mode(&hardware);
- else
- return return_code;
}
- return 0;
+
+ /* Do we got request to do something at exit time ? */
+ if (strlen(hardware.postexec)>0) {
+ printf("Executing postexec instructions : %s\n",hardware.postexec);
+ runsyslinuxcmd(hardware.postexec);
+ }
+
+ return return_code;
}
diff --git a/com32/hdt/hdt.h b/com32/hdt/hdt.h
index 7b35236e..041d726d 100644
--- a/com32/hdt/hdt.h
+++ b/com32/hdt/hdt.h
@@ -33,8 +33,8 @@
#define AUTHOR "Erwan Velu"
#define CORE_DEVELOPER "Pierre-Alexandre Meyer"
#define CONTACT "hdt@zytor.com"
-#define VERSION "0.5.0"
-#define CODENAME "Van De Keizer"
+#define VERSION "0.5.2-pre2"
+#define CODENAME "Manon"
#define NB_CONTRIBUTORS 3
#define CONTRIBUTORS {"Sebastien Gonzalve (Patches)", "Gert Hulselmans (Tests)", "Alexander Andino (Design)"}
#define WEBSITE_URL "http://hdt-project.org"
diff --git a/com32/include/bitsize/stddef.h b/com32/include/bitsize/stddef.h
index 3d5c3e7a..04418a04 100644
--- a/com32/include/bitsize/stddef.h
+++ b/com32/include/bitsize/stddef.h
@@ -5,7 +5,6 @@
#ifndef _BITSIZE_STDDEF_H
#define _BITSIZE_STDDEF_H
-#define _SIZE_T
#if __SIZEOF_POINTER__ == 4
#include <bitsize32/stddef.h>
#elif __SIZEOF_POINTER__ == 8
@@ -13,18 +12,5 @@
#else
#error "Unable to build for to-be-defined architecture type"
#endif
-/* Original definitions below */
-/*
-#if defined(__s390__) || defined(__hppa__) || defined(__cris__)
-typedef unsigned long size_t;
-#else
-typedef unsigned int size_t;
-#endif
-#define _PTRDIFF_T
-typedef signed int ptrdiff_t;
-*/
-
-#else
-#error "BITSIZE_STDDEF already defined"
#endif /* _BITSIZE_STDDEF_H */
diff --git a/com32/include/bitsize/stdint.h b/com32/include/bitsize/stdint.h
index 854c5430..7e7b2355 100644
--- a/com32/include/bitsize/stdint.h
+++ b/com32/include/bitsize/stdint.h
@@ -5,71 +5,14 @@
#ifndef _BITSIZE_STDINT_H
#define _BITSIZE_STDINT_H
-/*
-typedef signed char int8_t;
-typedef short int int16_t;
-typedef int int32_t;
-typedef long long int int64_t;
-
-typedef unsigned char uint8_t;
-typedef unsigned short int uint16_t;
-typedef unsigned int uint32_t;
-typedef unsigned long long int uint64_t;
-
-typedef int int_fast16_t;
-typedef int int_fast32_t;
-
-typedef unsigned int uint_fast16_t;
-typedef unsigned int uint_fast32_t;
-
-typedef int intptr_t;
-typedef unsigned int uintptr_t;
-
-#define __INT64_C(c) c ## LL
-#define __UINT64_C(c) c ## ULL
-
-#define __PRI64_RANK "ll"
-#define __PRIFAST_RANK ""
-#define __PRIPTR_RANK ""
-*/
-
-/* Exact types */
-
-typedef signed char int8_t;
-typedef signed short int16_t;
-typedef signed int int32_t;
-typedef signed long long int64_t;
-
-typedef unsigned char uint8_t;
-typedef unsigned short uint16_t;
-typedef unsigned int uint32_t;
-typedef unsigned long long uint64_t;
-
-/* Small types */
-
-typedef signed char int_least8_t;
-typedef signed short int_least16_t;
-typedef signed int int_least32_t;
-typedef signed long long int_least64_t;
-
-typedef unsigned char uint_least8_t;
-typedef unsigned short uint_least16_t;
-typedef unsigned int uint_least32_t;
-typedef unsigned long long uint_least64_t;
-
-/* Fast types */
-
-typedef signed char int_fast8_t;
-typedef signed long long int_fast64_t;
-
-typedef unsigned char uint_fast8_t;
-typedef unsigned int uint_fast32_t;
-typedef unsigned long long uint_fast64_t;
+typedef signed char int8_t;
+typedef short int int16_t;
+typedef int int32_t;
-/* Maximal types */
+typedef unsigned char uint8_t;
+typedef unsigned short int uint16_t;
+typedef unsigned int uint32_t;
-typedef int64_t intmax_t;
-typedef uint64_t uintmax_t;
#if __SIZEOF_POINTER__ == 4
#include <bitsize32/stdint.h>
#elif __SIZEOF_POINTER__ == 8
@@ -77,4 +20,4 @@ typedef uint64_t uintmax_t;
#else
#error "Unable to build for to-be-defined architecture type"
#endif
-#endif /* _BITSIZE_STDINT_H */
+#endif /* _BITSIZE_STDINT_H */
diff --git a/com32/include/bitsize/stdintconst.h b/com32/include/bitsize/stdintconst.h
index ae4e9fc0..b2f3141a 100644
--- a/com32/include/bitsize/stdintconst.h
+++ b/com32/include/bitsize/stdintconst.h
@@ -13,4 +13,4 @@
#error "Unable to build for to-be-defined architecture type"
#endif
-#endif /* _BITSIZE_STDINTCONST_H */
+#endif /* _BITSIZE_STDINTCONST_H */
diff --git a/com32/include/bitsize/stdintlimits.h b/com32/include/bitsize/stdintlimits.h
index 9f3657d2..c342c448 100644
--- a/com32/include/bitsize/stdintlimits.h
+++ b/com32/include/bitsize/stdintlimits.h
@@ -13,4 +13,4 @@
#error "Unable to build for to-be-defined architecture type"
#endif
-#endif /* _BITSIZE_STDINTLIMITS_H */
+#endif /* _BITSIZE_STDINTLIMITS_H */
diff --git a/com32/include/bitsize32/limits.h b/com32/include/bitsize32/limits.h
index 8eb97d6d..f19205fe 100644
--- a/com32/include/bitsize32/limits.h
+++ b/com32/include/bitsize32/limits.h
@@ -2,8 +2,8 @@
* bits32/limits.h
*/
-#ifndef _BITSIZE_LIMITS_H
-#define _BITSIZE_LIMITS_H
+#ifndef _BITSIZE32_LIMITS_H
+#define _BITSIZE32_LIMITS_H
#define LONG_BIT 32
diff --git a/com32/include/bitsize32/stddef.h b/com32/include/bitsize32/stddef.h
index e5d49376..c34c675c 100644
--- a/com32/include/bitsize32/stddef.h
+++ b/com32/include/bitsize32/stddef.h
@@ -3,11 +3,7 @@
*/
#define _SIZE_T
-#if defined(__s390__) || defined(__hppa__) || defined(__cris__)
-typedef unsigned long size_t;
-#else
typedef unsigned int size_t;
-#endif
#define _PTRDIFF_T
-typedef signed int ptrdiff_t;
+typedef signed long ptrdiff_t;
diff --git a/com32/include/bitsize32/stdint.h b/com32/include/bitsize32/stdint.h
index c886a4c2..bdc69705 100644
--- a/com32/include/bitsize32/stdint.h
+++ b/com32/include/bitsize32/stdint.h
@@ -3,15 +3,8 @@
*/
-/*
-typedef signed char int8_t;
-typedef short int int16_t;
-typedef int int32_t;
typedef long long int int64_t;
-typedef unsigned char uint8_t;
-typedef unsigned short int uint16_t;
-typedef unsigned int uint32_t;
typedef unsigned long long int uint64_t;
typedef int int_fast16_t;
@@ -29,13 +22,3 @@ typedef unsigned int uintptr_t;
#define __PRI64_RANK "ll"
#define __PRIFAST_RANK ""
#define __PRIPTR_RANK ""
-*/
-
-/* changes made according compiler output */
-typedef signed int int_fast16_t; /* was short */
-typedef signed int int_fast32_t;
-typedef unsigned int uint_fast16_t; /* was ushort */
-/* Pointer types */
-
-typedef int32_t intptr_t;
-typedef uint32_t uintptr_t;
diff --git a/com32/include/bitsize64/limits.h b/com32/include/bitsize64/limits.h
index f5bbf830..1acb1bc8 100644
--- a/com32/include/bitsize64/limits.h
+++ b/com32/include/bitsize64/limits.h
@@ -2,8 +2,8 @@
* bits64/limits.h
*/
-#ifndef _BITSIZE_LIMITS_H
-#define _BITSIZE_LIMITS_H
+#ifndef _BITSIZE64_LIMITS_H
+#define _BITSIZE64_LIMITS_H
#define LONG_BIT 64
diff --git a/com32/include/bitsize64/stddef.h b/com32/include/bitsize64/stddef.h
index 057a721f..c61bf8ce 100644
--- a/com32/include/bitsize64/stddef.h
+++ b/com32/include/bitsize64/stddef.h
@@ -2,9 +2,9 @@
* bits64/stddef.h
*/
-
#define _SIZE_T
typedef unsigned long size_t;
+
#define _PTRDIFF_T
typedef signed long ptrdiff_t;
diff --git a/com32/include/bitsize64/stdint.h b/com32/include/bitsize64/stdint.h
index 32de44c5..91930003 100644
--- a/com32/include/bitsize64/stdint.h
+++ b/com32/include/bitsize64/stdint.h
@@ -3,15 +3,8 @@
*/
-/*
-typedef signed char int8_t;
-typedef short int int16_t;
-typedef int int32_t;
typedef long int int64_t;
-typedef unsigned char uint8_t;
-typedef unsigned short int uint16_t;
-typedef unsigned int uint32_t;
typedef unsigned long int uint64_t;
typedef long int int_fast16_t;
@@ -29,13 +22,3 @@ typedef unsigned long int uintptr_t;
#define __PRI64_RANK "l"
#define __PRIFAST_RANK "l"
#define __PRIPTR_RANK "l"
-*/
-
-/* based on compiler output */
-typedef signed long int_fast16_t;
-typedef signed long int int_fast32_t;
-typedef unsigned long int uint_fast16_t;
-/* Pointer types */
-
-typedef long int intptr_t;
-typedef long unsigned int uintptr_t;
diff --git a/com32/include/com32.h b/com32/include/com32.h
index f49f9eab..148d08eb 100644
--- a/com32/include/com32.h
+++ b/com32/include/com32.h
@@ -120,7 +120,7 @@ extern const com32sys_t __com32_zero_regs;
/*
* Lowmem allocation functions
*/
-void *clmalloc(size_t);
+void *lmalloc(size_t);
void *lzalloc(size_t);
void lfree(void *);
char *lstrdup(const char *);
@@ -135,10 +135,22 @@ char *lstrdup(const char *);
* specific segment. OFFS_VALID() will return whether or not the
* pointer is actually reachable from the target segment.
*/
+#if defined(DEBUG) && (defined(__COM32__) || defined(__SYSLINUX_CORE__))
+__noreturn __bad_SEG(const volatile void *);
+
+static inline uint16_t SEG(const volatile void *__p)
+{
+ if (__unlikely((uintptr_t)__p > 0xfffff))
+ __bad_SEG(__p);
+
+ return (uint16_t) (((uintptr_t) __p) >> 4);
+}
+#else
static inline uint16_t SEG(const volatile void *__p)
{
return (uint16_t) (((uintptr_t) __p) >> 4);
}
+#endif
static inline uint16_t OFFS(const volatile void *__p)
{
diff --git a/com32/include/dhcp.h b/com32/include/dhcp.h
new file mode 100644
index 00000000..afef9242
--- /dev/null
+++ b/com32/include/dhcp.h
@@ -0,0 +1,40 @@
+#ifndef DHCP_H
+#define DHCP_H
+
+#include <inttypes.h>
+
+struct dhcp_option {
+ void *data;
+ int len;
+};
+
+struct dhcp_packet {
+ uint8_t op; /* 0 */
+ uint8_t htype; /* 1 */
+ uint8_t hlen; /* 2 */
+ uint8_t hops; /* 3 */
+ uint32_t xid; /* 4 */
+ uint16_t secs; /* 8 */
+ uint16_t flags; /* 10 */
+ uint32_t ciaddr; /* 12 */
+ uint32_t yiaddr; /* 16 */
+ uint32_t siaddr; /* 20 */
+ uint32_t giaddr; /* 24 */
+ uint8_t chaddr[16]; /* 28 */
+ uint8_t sname[64]; /* 44 */
+ uint8_t file[128]; /* 108 */
+ uint32_t magic; /* 236 */
+ uint8_t options[4]; /* 240 */
+};
+
+#define DHCP_VENDOR_MAGIC 0x63825363
+
+int dhcp_pack_packet(void *packet, size_t *len,
+ const struct dhcp_option opt[256]);
+
+int dhcp_unpack_packet(const void *packet, size_t len,
+ struct dhcp_option opt[256]);
+
+#endif /* DHCP_H */
+
+
diff --git a/com32/include/dprintf.h b/com32/include/dprintf.h
index 30a21ada..26ca734b 100644
--- a/com32/include/dprintf.h
+++ b/com32/include/dprintf.h
@@ -5,18 +5,36 @@
#ifndef _DPRINTF_H
#define _DPRINTF_H
+#if !defined(DEBUG_PORT) && !defined(DEBUG_STDIO)
+# undef DEBUG
+#endif
+
#ifdef DEBUG
-#include <stdio.h>
+# include <stdio.h>
+# ifdef DEBUG_STDIO
+# define dprintf printf
+# define vdprintf vprintf
+# else
void dprintf(const char *, ...);
void vdprintf(const char *, va_list);
+# endif
#else
-#define dprintf(fmt, ...) ((void)(0))
-#define vdprintf(fmt, ap) ((void)(0))
+# define dprintf(fmt, ...) ((void)(0))
+# define vdprintf(fmt, ap) ((void)(0))
#endif /* DEBUG */
+# if DEBUG >= 2
+/* Really verbose debugging... */
+# define dprintf2 dprintf
+# define vdprintf2 vdprintf
+# else
+# define dprintf2(fmt, ...) ((void)(0))
+# define vdprintf2(fmt, ap) ((void)(0))
+# endif
+
#endif /* _DPRINTF_H */
diff --git a/com32/include/hw/vga.h b/com32/include/hw/vga.h
new file mode 100644
index 00000000..0ebd2e25
--- /dev/null
+++ b/com32/include/hw/vga.h
@@ -0,0 +1,104 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2012 Intel Corporation; author: H. Peter Anvin
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef _HW_VGA_H
+#define _HW_VGA_H 1
+
+#include <sys/io.h>
+
+/* These are relative to the CRTC base address */
+#define VGA_CRTC_ADDR 0x4
+#define VGA_CRTC_DATA 0x5
+#define VGA_CRTC_IX_HORIZ_TOTAL 0x00
+#define VGA_CRTC_IX_END_HORIZ_DISPLAY 0x01
+#define VGA_CRTC_IX_START_HORIZ_BLANK 0x02
+#define VGA_CRTC_IX_END_HORIZ_BLANK 0x03
+#define VGA_CRTC_IX_START_HORIZ_RETR 0x04
+#define VGA_CRTC_IX_END_HORIZ_RETR 0x05
+#define VGA_CRTC_IX_VERT_TOTAL 0x06
+#define VGA_CRTC_IX_OVERFLOW 0x07
+#define VGA_CRTC_IX_PRESET_ROW_SCAN 0x08
+#define VGA_CRTC_IX_MAX_SCAN_LINE 0x09
+#define VGA_CRTC_IX_CURSOR_START 0x0a
+#define VGA_CRTC_IX_CURSOR_END 0x0b
+#define VGA_CRTC_IX_START_ADDR_HIGH 0x0c
+#define VGA_CRTC_IX_START_ADDR_LOW 0x0d
+#define VGA_CRTC_IX_CURSOR_POS_HIGH 0x0e
+#define VGA_CRTC_IX_CURSOR_POS_LOW 0x0f
+#define VGA_CRTC_IX_START_VERT_RETR 0x10
+#define VGA_CRTC_IX_END_VERT_RETR 0x11
+#define VGA_CRTC_IX_END_VERT_DISPLAY 0x12
+#define VGA_CRTC_IX_OFFSET 0x13
+#define VGA_CRTC_IX_UNDERLINE 0x14
+#define VGA_CRTC_IX_START_VERT_BLANK 0x15
+#define VGA_CRTC_IX_END_VERT_BLANK 0x16
+#define VGA_CRTC_IX_MODE_CONTROL 0x17
+#define VGA_CRTC_IX_LINE_COMPARE 0x18
+#define VGA_CRTC_INPUT_STATUS_1 0xa
+#define VGA_CRTC_FEATURE_CONTROL_WRITE 0xa
+
+#define VGA_ATTR_ADDR_DATA 0x3c0
+#define VGA_ATTR_DATA_READ 0x3c1
+/* 0x00-0x0f are 16->64 palette registers */
+#define VGA_ATTR_IX_MODE_CONTROL 0x10
+#define VGA_ATTR_IX_OVERSCAN 0x11
+#define VGA_ATTR_IX_COLOR_PLANE_ENABLE 0x12
+#define VGA_ATTR_IX_HORIZ_PIXEL_PAN 0x13
+#define VGA_ADDR_IX_COLOR_SELECT 0x14
+#define VGA_INPUT_STATUS_0 0x3c2
+#define VGA_MISC_OUTPUT_WRITE 0x3c2
+#define VGA_SEQ_ADDR 0x3c4
+#define VGA_SEQ_DATA 0x3c5
+#define VGA_SEQ_IX_RESET 0
+#define VGA_SEQ_IX_CLOCKMODE 1
+#define VGA_SEQ_IX_MAP_MASK 2
+#define VGA_SEQ_IX_CHAR_MAP 3
+#define VGA_SEQ_IX_SEQ_MEM_MODE 4
+#define VGA_DAC_STATE 0x3c7
+#define VGA_DAC_ADDR_READ_MODE 0x3c7
+#define VGA_DAC_ADDR_WRITE_MODE 0x3c8
+#define VGA_DAC_DATA 0x3c9
+#define VGA_FEATURE_CONTROL_READ 0x3ca
+#define VGA_MISC_OUTPUT_READ 0x3cc
+#define VGA_GC_ADDR 0x3ce
+#define VGA_GC_DATA 0x3cf
+#define VGA_GC_IX_SET_RESET 0
+#define VGA_GC_IX_ENABLE_SET_RESET 1
+#define VGA_GC_IX_COLOR_COMPARE 2
+#define VGA_GC_IX_DATA_ROTATE 3
+#define VGA_GC_IX_READ_MAP_SELECT 4
+#define VGA_GC_IX_GRAPHICS_MODE 5
+#define VGA_GC_IX_MISC_GRAPHICS 6
+#define VGA_GC_IX_COLOR_DONT_CARE 7
+#define VGA_GC_IX_BIT_MASK 8
+
+static inline uint16_t vga_crtc_base(void)
+{
+ return 0x3b0 + ((inb(VGA_MISC_OUTPUT_READ) & 1) << 5);
+}
+
+#endif /* _HW_VGA_H */
diff --git a/com32/include/klibc/compiler.h b/com32/include/klibc/compiler.h
index b5919d67..210971f1 100644
--- a/com32/include/klibc/compiler.h
+++ b/com32/include/klibc/compiler.h
@@ -108,6 +108,13 @@
# define __unusedfunc
#endif
+/* Declare a variable or data structure as unused. */
+#ifdef __GNUC__
+# define __unused __attribute__((unused))
+#else
+# define __unused
+#endif
+
/* Used symbol */
#define __used __attribute__((used))
diff --git a/com32/include/linux/list.h b/com32/include/linux/list.h
index 3b92e254..afe89808 100644
--- a/com32/include/linux/list.h
+++ b/com32/include/linux/list.h
@@ -338,6 +338,19 @@ static inline void list_splice_init(struct list_head *list,
pos = list_entry(pos->member.next, typeof(*pos), member))
/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+* @pos: the type * to use as a loop cursor.
+* @n: another type * to use as temporary storage
+* @head: the head for your list.
+* @member: the name of the list_struct within the struct.
+*/
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
* list_for_each_entry_reverse - iterate backwards over list of given type.
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
diff --git a/com32/include/menu.h b/com32/include/menu.h
index 1db4d7c9..5a4c901e 100644
--- a/com32/include/menu.h
+++ b/com32/include/menu.h
@@ -92,8 +92,6 @@ enum kernel_type {
KT_CONFIG, /* Configuration file */
};
-extern const char *const kernel_types[];
-
/* Configurable integer parameters */
enum parameter_number {
P_WIDTH,
@@ -187,6 +185,7 @@ extern int shiftkey;
extern int hiddenmenu;
extern int clearmenu;
extern long long totaltimeout;
+extern clock_t kbdtimeout;
extern const char *hide_key[KEY_MAX];
void parse_configs(char **argv);
@@ -227,10 +226,10 @@ extern const int message_base_color;
extern const char *current_background;
void set_background(const char *new_background);
-/* execute.c */
-void execute(const char *cmdline, enum kernel_type type);
-
/* drain.c */
void drain_keyboard(void);
+/* chainboot.c */
+void chainboot_file(const char *file, enum kernel_type type);
+
#endif /* MENU_H */
diff --git a/com32/include/stdint.h b/com32/include/stdint.h
index 0d0e8f69..f64f0278 100644
--- a/com32/include/stdint.h
+++ b/com32/include/stdint.h
@@ -5,151 +5,87 @@
#ifndef _STDINT_H
#define _STDINT_H
-/* FIXME: Move common typedefs to bitsize/stdint.h
- * and architecture specificis to bitsize32/64
- */
#include <bitsize/stdint.h>
-#if 0
-/* Exact types */
-typedef signed char int8_t;
-typedef signed short int16_t;
-typedef signed int int32_t;
-typedef signed long long int64_t;
+typedef int8_t int_least8_t;
+typedef int16_t int_least16_t;
+typedef int32_t int_least32_t;
+typedef int64_t int_least64_t;
-typedef unsigned char uint8_t;
-typedef unsigned short uint16_t;
-typedef unsigned int uint32_t;
-typedef unsigned long long uint64_t;
+typedef uint8_t uint_least8_t;
+typedef uint16_t uint_least16_t;
+typedef uint32_t uint_least32_t;
+typedef uint64_t uint_least64_t;
-/* Small types */
+typedef int8_t int_fast8_t;
+typedef int64_t int_fast64_t;
-typedef signed char int_least8_t;
-typedef signed short int_least16_t;
-typedef signed int int_least32_t;
-typedef signed long long int_least64_t;
+typedef uint8_t uint_fast8_t;
+typedef uint64_t uint_fast64_t;
-typedef unsigned char uint_least8_t;
-typedef unsigned short uint_least16_t;
-typedef unsigned int uint_least32_t;
-typedef unsigned long long uint_least64_t;
+typedef int64_t intmax_t;
+typedef uint64_t uintmax_t;
-/* Fast types */
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)
-typedef signed char int_fast8_t;
-typedef signed short int_fast16_t; /* ?? 32: int 64: long */
-typedef signed int int_fast32_t; /* ?? 64: long int */
-typedef signed long long int_fast64_t; /* 64: long int */
+#define INT8_MIN (-128)
+#define INT16_MIN (-32768)
+#define INT32_MIN (-2147483647-1)
+#define INT64_MIN (__INT64_C(-9223372036854775807)-1)
-typedef unsigned char uint_fast8_t;
-typedef unsigned short uint_fast16_t; /* 32: unsigned int 64: short unsigned int */
-typedef unsigned int uint_fast32_t;
-typedef unsigned long long uint_fast64_t;/* 64: long unsigned int */
+#define INT8_MAX (127)
+#define INT16_MAX (32767)
+#define INT32_MAX (2147483647)
+#define INT64_MAX (__INT64_C(9223372036854775807))
-/* Pointer types */
+#define UINT8_MAX (255U)
+#define UINT16_MAX (65535U)
+#define UINT32_MAX (4294967295U)
+#define UINT64_MAX (__UINT64_C(18446744073709551615))
-typedef int32_t intptr_t; /* 64: long int */
-typedef uint32_t uintptr_t; /* 64: long unsigned int */
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST64_MIN INT64_MIN
-/* Maximal types */
+#define INT_LEAST8_MAX INT8_MAX
+#define INT_LEAST16_MAX INT16_MAX
+#define INT_LEAST32_MAX INT32_MAX
+#define INT_LEAST64_MAX INT64_MAX
-typedef int64_t intmax_t;
-typedef uint64_t uintmax_t;
-#endif
-/* FIXME: move common definitions to bitsize/stdint.h and
- * architecture specifics to bitsize32/64/stdintlimits.h as appropriate
- */
-/*
- * To be strictly correct...
- */
-#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)
+#define UINT_LEAST8_MAX UINT8_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
-# define INT8_MIN (-128)
-# define INT16_MIN (-32767-1)
-# define INT32_MIN (-2147483647-1)
-# define INT64_MIN (-9223372036854775807LL-1)
-
-# define INT8_MAX (127)
-# define INT16_MAX (32767)
-# define INT32_MAX (2147483647)
-# define INT64_MAX (9223372036854775807LL)
-
-# define UINT8_MAX (255U)
-# define UINT16_MAX (65535U)
-# define UINT32_MAX (4294967295U)
-# define UINT64_MAX (18446744073709551615ULL)
-
-# define INT_LEAST8_MIN INT8_MIN //(-128)
-# define INT_LEAST16_MIN INT16_MIN //(-32767-1)
-# define INT_LEAST32_MIN INT32_MIN //(-2147483647-1)
-# define INT_LEAST64_MIN INT64_MIN //(-9223372036854775807LL-1)
-
-# define INT_LEAST8_MAX INT8_MAX //(127)
-# define INT_LEAST16_MAX INT16_MAX //(32767)
-# define INT_LEAST32_MAX INT32_MAX //(2147483647)
-# define INT_LEAST64_MAX INT64_MAX //(9223372036854775807LL)
-
-# define UINT_LEAST8_MAX UINT8_MAX //(255U)
-# define UINT_LEAST16_MAX UINT16_MAX //(65535U)
-# define UINT_LEAST32_MAX UINT32_MAX //(4294967295U)
-# define UINT_LEAST64_MAX UINT64_MAX //(18446744073709551615ULL)
-
-# define INT_FAST8_MIN INT8_MIN //(-128)
-//# define INT_FAST16_MIN (-32767-1)
-//# define INT_FAST32_MIN (-2147483647-1)
-# define INT_FAST64_MIN INT64_MIN //(-9223372036854775807LL-1)
-
-# define INT_FAST8_MAX INT8_MAX //(127)
-//# define INT_FAST16_MAX (32767)
-//# define INT_FAST32_MAX (2147483647)
-# define INT_FAST64_MAX INT64_MAX //(9223372036854775807LL)
-
-# define UINT_FAST8_MAX UINT8_MAX //(255U)
-//# define UINT_FAST16_MAX (65535U)
-//# define UINT_FAST32_MAX (4294967295U)
-# define UINT_FAST64_MAX UINT64_MAX //(18446744073709551615ULL)
-
-//FIXME: Move *INTPTR to architecture specific as they vary
-//# define INTPTR_MIN (-2147483647-1)
-//# define INTPTR_MAX (2147483647)
-//# define UINTPTR_MAX (4294967295U)
-
-# define INTMAX_MIN (-9223372036854775807LL-1)
-# define INTMAX_MAX (9223372036854775807LL)
-# define UINTMAX_MAX (18446744073709551615ULL)
-
-/* FIXME: include the architecture specific limits from bitsizexx/stdintlimits.h */
-/* ptrdiff_t limit */
-//# define PTRDIFF_MIN (-2147483647-1)
-//# define PTRDIFF_MAX (2147483647)
-
-/* sig_atomic_t limit */
-//# define SIG_ATOMIC_MIN (-2147483647-1)
-//# define SIG_ATOMIC_MAX (2147483647)
-
-/* size_t limit */
-//# define SIZE_MAX (4294967295U)
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST64_MIN INT64_MIN
-#include <bitsize/stdintlimits.h>
+#define INT_FAST8_MAX INT8_MAX
+#define INT_FAST64_MAX INT64_MAX
-#endif /* STDC_LIMIT_MACROS */
+#define UINT_FAST8_MAX UINT8_MAX
+#define UINT_FAST64_MAX UINT64_MAX
-#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS)
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+
+#include <bitsize/stdintlimits.h>
-# define INT8_C(n) n
-# define INT16_C(n) n
-# define INT32_C(n) n
-# define INT64_C(n) n ## LL
+#endif
-# define UINT8_C(n) n ## U
-# define UINT16_C(n) n ## U
-# define UINT32_C(n) n ## U
-# define UINT64_C(n) n ## ULL
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS)
-//# define INTMAX_C(n) n ## LL
-//# define UINTMAX_C(n) n ## ULL
+#define INT8_C(c) c
+#define INT16_C(c) c
+#define INT32_C(c) c
+#define INT64_C(c) __INT64_C(c)
-/* included from klibc/usr/include/stdint.h */
+#define UINT8_C(c) c ## U
+#define UINT16_C(c) c ## U
+#define UINT32_C(c) c ## U
+#define UINT64_C(c) __UINT64_C(c)
#define INT_LEAST8_C(c) INT8_C(c)
#define INT_LEAST16_C(c) INT16_C(c)
@@ -171,6 +107,10 @@ typedef uint64_t uintmax_t;
#define UINTMAX_C(c) UINT64_C(c)
#include <bitsize/stdintconst.h>
-#endif /* STDC_CONSTANT_MACROS */
-#endif /* _STDINT_H */
+#endif
+
+/* Keep the kernel from trying to define these types... */
+#define __BIT_TYPES_DEFINED__
+
+#endif /* _STDINT_H */
diff --git a/com32/include/string.h b/com32/include/string.h
index af9792b6..d847440d 100644
--- a/com32/include/string.h
+++ b/com32/include/string.h
@@ -42,5 +42,6 @@ __extern char *strsep(char **, const char *);
__extern size_t strspn(const char *, const char *);
__extern char *strstr(const char *, const char *);
__extern char *strtok(char *, const char *);
+__extern char *strreplace(const char *, const char *, const char *);
#endif /* _STRING_H */
diff --git a/com32/include/sys/exec.h b/com32/include/sys/exec.h
index 9c00e4a5..ac05c276 100644
--- a/com32/include/sys/exec.h
+++ b/com32/include/sys/exec.h
@@ -55,29 +55,6 @@ extern int exec_init(void);
/**
- * load_library - Loads a dynamic library into the environment.
- * @name: the name of the library to load, including the extension
- * (e.g. 'sort.c32')
- *
- * A dynamic library is an ELF module that may contain initialization and
- * termination routines, but not a main routine. At the same time, any memory
- * allocations using malloc() and its derivatives are made on behalf of the
- * currently executing program or the COM32 root module. If the library
- * is unloaded, no memory cleanup is performed.
- */
-extern int load_library(const char *name);
-
-/**
- * unload_library - unloads a library from the environment.
- * @name: the name of the library to unload, including the extension
- * (e.g. 'sort.c32')
- *
- * Note that no memory allocated by the library code is cleaned up, as the
- * allocations belong to the innermost calling program in the call stack.
- */
-extern int unload_library(const char *name);
-
-/**
* spawnv - Executes a program in the current environment.
* @name: the name of the program to spawn, including the extension
* (e.g. 'hello.c32')
diff --git a/com32/include/sys/i386/module.h b/com32/include/sys/i386/module.h
index 5890d771..21988ead 100644
--- a/com32/include/sys/i386/module.h
+++ b/com32/include/sys/i386/module.h
@@ -4,179 +4,10 @@
* Dynamic ELF modules definitions and services.
*/
+#ifndef I386_MODULE_H_
+#define I386_MODULE_H_
-#include <stdio.h>
#include <elf.h>
-#include <stdint.h>
-#include <setjmp.h>
-#include <stdbool.h>
-#include <linux/list.h>
-
-/*
- * The maximum length of the module file name (including path), stored
- * in the struct module descriptor.
- */
-#define MODULE_NAME_SIZE 256
-
-/*
- * Some common information about what kind of modules we're dealing with
- */
-#define UNKNOWN_MODULE -1
-#define EXEC_MODULE 0
-#define LIB_MODULE 1
-
-/*
- * Initialization and finalization function signatures
- */
-
-
-/**
- * module_init_t - pointer to a initialization routine
- *
- * The initialization routine is called after all module constructors were invoked.
- * It takes no parameters and returns 0 if the module was initialized successfully,
- * or a non-zero value if errors have occurred.
- */
-typedef int (*module_init_t)(void);
-
-/**
- * module_exit_t - pointer to a finalization routine
- *
- * The finalization routine is called before the module destructors are to be invoked.
- * It simply executes some cleanup code, without error reporting.
- */
-typedef void (*module_exit_t)(void);
-
-/**
- * module_main_t - pointer to an entry routine
- *
- * The entry routine is present only in executable modules, and represents
- * the entry point for the program.
- */
-typedef int (*module_main_t)(int, char**);
-
-
-/**
- * struct elf_module - structure encapsulating a module loaded in memory.
- *
- * Each SYSLINUX ELF module must have an associated struct elf_module descriptor
- * that keeps track of memory allocations, symbol information, and various other
- * resources needed by the module itself or by other modules that depend on it.
- *
- * There are two types of modules:
- * - regular modules, which are actual memory images of a loaded & linked shared
- * object (ELF file). Memory is reserved for the struct elf_module structure itself
- * and for the object loadable sections read from the file.
- * - shallow modules, which are not associated with an ELF shared object, but contain
- * metainformation about a memory region already present and containing the
- * actual code and data. One particular usage of shallow modules is to access
- * symbol information from the root COM32 module loaded by the SYSLINUX core.
- * As their name suggests, memory is reserved only for the elf_module structure
- * itself and optionally for a usually small memory region containing metainformation
- * (symbol information).
- *
- * Module descriptors are related to each other through dependency information. A module
- * can depend on symbols from other modules, and in turn it can provide symbols used
- * by other dependant modules. This relationship can be described as a directed
- * acyclic graph (DAG). The graph is stored using double linked lists of
- * predecessors and successors. There is also a global linked list containing all
- * the modules currently loaded.
- */
-struct atexit;
-struct elf_module {
- char name[MODULE_NAME_SIZE]; // The module name
-
- bool shallow; // Whether the module contains any code
-
- struct list_head required; // Head of the required modules list
- struct list_head dependants; // Head of module dependants list
- struct list_head list; // The list entry in the module list
-
- module_init_t *init_func; // The initialization entry point
- module_exit_t *exit_func; // The module finalization code
- module_main_t main_func; // The main function (for executable modules)
-
-
- void *module_addr; // The module location in the memory
- Elf32_Addr base_addr; // The base address of the module
- Elf32_Word module_size; // The module size in memory
-
- Elf32_Word *hash_table; // The symbol hash table
- Elf32_Word *ghash_table; // The GNU style hash table
- char *str_table; // The string table
- void *sym_table; // The symbol table
- void *got; // The Global Offset Table
- Elf32_Dyn *dyn_table; // Dynamic loading information table
-
- Elf32_Word strtable_size; // The size of the string table
- Elf32_Word syment_size; // The size of a symbol entry
- Elf32_Word symtable_size; // The size of the symbol table
-
-
- union {
- // Transient - Data available while the module is loading
- struct {
- FILE *_file; // The file object of the open file
- Elf32_Off _cr_offset; // The current offset in the open file
- } l;
-
- // Process execution data
- struct {
- jmp_buf process_exit; // Exit state
- struct atexit *atexit_list; // atexit() chain
- } x;
- } u;
-
-};
-
-static inline void dump_elf_module(struct elf_module *module)
-{
- /*
- dprintf("module name = %s", module->name);
- printf("base_addr = 0x%p, module_size = %d\n", module->base_addr, module->module_size);
- printf("hash tlb = 0x%p, ghash tbl = 0x%p\n", module->hash_table, module->ghash_table);
- printf("str tbl = 0x%p, size = %d\n", module->str_table, module->strtable_size);
- printf("sym tbl = 0x%p, entry = %d, size = %d\n", module->sym_table, module->syment_size, module->symtable_size);
- printf("init: %p", module->init_func);
- printf("main: %p", module->main_func);
- printf("exit: %p", module->exit_func);
- printf("", module->base_addr);
- printf("", module->base_addr);
- printf("", module->base_addr);
- */
-}
-
-/**
- * struct module_dep - structure encapsulating a module dependency need
- *
- * This structure represents an item in a double linked list of predecessors or
- * successors. The item contents is a pointer to the corresponding module descriptor.
- */
-struct module_dep {
- struct list_head list; // The list entry in the dependency list
-
- struct elf_module *module; // The target module descriptor
-};
-
-
-
-#ifdef DYNAMIC_MODULE
-
-/*
- * This portion is included by dynamic (ELF) module source files.
- */
-
-#define MODULE_INIT(fn) static module_init_t __module_init \
- __used __attribute__((section(".ctors_modinit"))) = fn
-
-#define MODULE_EXIT(fn) static module_exit_t __module_exit \
- __used __attribute__((section(".dtors_modexit"))) = fn
-
-#else
-
-/*
- * This portion is included by the core COM32 module.
- */
/*
* Accepted values for various ELF header parameters found in an ELF dynamic
@@ -189,181 +20,16 @@ struct module_dep {
#define MODULE_ELF_TYPE ET_DYN // Executable type (shared object - .so)
#define MODULE_ELF_MACHINE EM_386 // Target architecture
-/**
- * Names of symbols with special meaning (treated as special cases at linking)
- */
-#define MODULE_ELF_INIT_PTR "__module_init_ptr" // Initialization pointer symbol name
-#define MODULE_ELF_EXIT_PTR "__module_exit_ptr" // Finalization pointer symbol name
-#define MODULE_ELF_MAIN_PTR "__module_main_ptr" // Entry pointer symbol name
-
-/**
- * modules_head - A global linked list containing all the loaded modules.
- */
-extern struct list_head modules_head;
-
-
-/**
- * for_each_module - iterator loop through the list of loaded modules.
- */
-#define for_each_module(m) list_for_each_entry(m, &modules_head, list)
-
-/**
- * modules_init - initialize the module subsystem.
- *
- * This function must be called before any module operation is to be performed.
- */
-extern int modules_init(void);
-
-
-/**
- * modules_term - releases all resources pertaining to the module subsystem.
- *
- * This function should be called after all module operations.
- */
-extern void modules_term(void);
-
-
-/**
- * module_alloc - reserves space for a new module descriptor.
- * @name: the file name of the module to be loaded.
- *
- * The function simply allocates a new module descriptor and initializes its fields
- * in order to be used by subsequent loading operations.
- */
-extern struct elf_module *module_alloc(const char *name);
-
-
-/**
- * module_load - loads a regular ELF module into memory.
- * @module: the module descriptor returned by module_alloc.
- *
- * The function reads the module file, checks whether the file has a
- * valid structure, then loads into memory the code and the data and performs
- * any symbol relocations. A module dependency is created automatically when the
- * relocated symbol is defined in a different module.
- *
- * The function returns 0 if the operation is completed successfully, and
- * a non-zero value if an error occurs. Possible errors include invalid module
- * structure, missing symbol definitions (unsatisfied dependencies) and memory
- * allocation issues.
- */
-extern int module_load(struct elf_module *module);
-
-
-/**
- * module_load_shallow - loads a shallow ELF module into memory.
- * @module: the module descriptor returned by module_alloc.
- *
- * The function reads the module file, checks whether the file has a valid
- * structure, then loads into memory the module metadata. The metadata currently
- * contains a symbol table that describes code & data allocated by other means.
- * Its current use is to describe the root COM32 module to the rest of the
- * module subsystem.
- */
-extern int module_load_shallow(struct elf_module *module, Elf32_Addr base_addr);
-
-/**
- * module_unload - unloads the module from the system.
- * @module: the module descriptor structure.
- *
- * The function checks to see whether the module can be safely removed, then
- * it releases all the associated memory. This function can be applied both
- * for standard modules and for shallow modules.
- *
- * A module can be safely removed from the system when no other modules reference
- * symbols from it.
- */
-extern int module_unload(struct elf_module *module);
-
-/**
- * module_unload - unloads the module from the system.
- * @module: the module descriptor structure.
- *
- * This function returns the type of module we're dealing with
- * either a library module ( LIB_MODULE ), executable module ( EXEC_MODULE ),
- * or an error ( UNKNOWN_MODULE ). The way it checks teh type is by checking to see
- * if the module has its main_func set ( in which case it's an executable ). In case
- * it doesn't it then checks to see if init_func is set ( in which case it's a
- * library module. If this isn't the case either we don't know what it is so bail out
- */
-extern int get_module_type(struct elf_module *module);
-
-/**
- * module_unloadable - checks whether the given module can be unloaded.
- * @module: the module descriptor structure
- *
- * A module can be unloaded from the system when no other modules depend on it,
- * that is, no symbols are referenced from it.
- */
-extern int module_unloadable(struct elf_module *module);
-
-/**
- * module_find - searches for a module by its name.
- * @name: the name of the module, as it was specified in module_alloc.
- *
- * The function returns a pointer to the module descriptor, if found, or
- * NULL otherwise.
- */
-extern struct elf_module *module_find(const char *name);
-
-/**
- * module_find_symbol - searches for a symbol definition in a given module.
- * @name: the name of the symbol to be found.
- * @module: the module descriptor structure.
- *
- * The function searches the module symbol table for a symbol matching exactly
- * the name provided. The operation uses the following search algorithms, in this
- * order:
- * - If a GNU hash table is present in the module, it is used to find the symbol.
- * - If the symbol cannot be found with the first method (either the hash table
- * is not present or the symbol is not found) and if a regular (SysV) hash table
- * is present, a search is performed on the SysV hash table. If the symbol is not
- * found, NULL is returned.
- * - If the second method cannot be applied, a linear search is performed by
- * inspecting every symbol in the symbol table.
- *
- * If the symbol is found, a pointer to its descriptor structure is returned, and
- * NULL otherwise.
- */
-extern Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module);
-
-/**
- * global_find_symbol - searches for a symbol definition in the entire module namespace.
- * @name: the name of the symbol to be found.
- * @module: an optional (may be NULL) pointer to a module descriptor variable that
- * will hold the module where the symbol was found.
- *
- * The function search for the given symbol name in all the modules currently
- * loaded in the system, in the reverse module loading order. That is, the most
- * recently loaded module is searched first, followed by the previous one, until
- * the first loaded module is reached.
- *
- * If no module contains the symbol, NULL is returned, otherwise the return value is
- * a pointer to the symbol descriptor structure. If the module parameter is not NULL,
- * it is filled with the address of the module descriptor where the symbol is defined.
- */
-extern Elf32_Sym *global_find_symbol(const char *name, struct elf_module **module);
-
-/**
- * module_get_absolute - converts an memory address relative to a module base address
- * to its absolute value in RAM.
- * @addr: the relative address to convert.
- * @module: the module whose base address is used for the conversion.
- *
- * The function returns a pointer to the absolute memory address.
- */
-static inline void *module_get_absolute(Elf32_Addr addr, struct elf_module *module) {
- return (void*)(module->base_addr + addr);
-}
-
-/**
- * syslinux_current - get the current module process
- */
-extern struct elf_module *__syslinux_current;
-static inline const struct elf_module *syslinux_current(void)
-{
- return __syslinux_current;
-}
+#define ELF_MOD_SYS "32 bit"
+typedef Elf32_Addr Elf_Addr;
+typedef Elf32_Dyn Elf_Dyn;
+typedef Elf32_Word Elf_Word;
+typedef Elf32_Off Elf_Off;
+typedef Elf32_Sym Elf_Sym;
+typedef Elf32_Ehdr Elf_Ehdr;
+typedef Elf32_Phdr Elf_Phdr;
+typedef Elf32_Rel Elf_Rel;
+typedef Elf32_Word Elf_Bword;
-#endif // DYNAMIC_MODULE
+#endif // I386_MODULE_H_
diff --git a/com32/include/sys/module.h b/com32/include/sys/module.h
index 7fcd00a5..88c8f8ec 100644
--- a/com32/include/sys/module.h
+++ b/com32/include/sys/module.h
@@ -7,6 +7,13 @@
#ifndef MODULE_H_
#define MODULE_H_
+#include <stdio.h>
+#include <elf.h>
+#include <stdint.h>
+#include <setjmp.h>
+#include <stdbool.h>
+#include <linux/list.h>
+
#if __SIZEOF_POINTER__ == 4
#include <i386/module.h>
#elif __SIZEOF_POINTER__ == 8
@@ -15,4 +22,340 @@
#error "unsupported architecture"
#endif
-#endif
+/*
+ * The maximum length of the module file name (including path), stored
+ * in the struct module descriptor.
+ */
+#define MODULE_NAME_SIZE 256
+
+/*
+ * Some common information about what kind of modules we're dealing with
+ */
+#define EXEC_MODULE 0
+#define LIB_MODULE 1
+
+#define MAX_NR_DEPS 64
+
+/*
+ * Initialization and finalization function signatures
+ */
+
+/**
+ * module_main_t - pointer to an entry routine
+ *
+ * The entry routine is present only in executable modules, and represents
+ * the entry point for the program.
+ */
+typedef int (*module_main_t)(int, char**);
+
+/**
+ * module_ctor_t - pointer to a constructor or destructor routine
+ *
+ * A module may have multiple routines that need to be executed before
+ * or after the main routine. These are the constructors and
+ * destructors, respectively.
+ */
+typedef void (*module_ctor_t) (void);
+
+/**
+ * struct elf_module - structure encapsulating a module loaded in memory.
+ *
+ * Each SYSLINUX ELF module must have an associated struct elf_module descriptor
+ * that keeps track of memory allocations, symbol information, and various other
+ * resources needed by the module itself or by other modules that depend on it.
+ *
+ * There are two types of modules:
+ * - regular modules, which are actual memory images of a loaded & linked shared
+ * object (ELF file). Memory is reserved for the struct elf_module structure itself
+ * and for the object loadable sections read from the file.
+ * - shallow modules, which are not associated with an ELF shared object, but contain
+ * metainformation about a memory region already present and containing the
+ * actual code and data. One particular usage of shallow modules is to access
+ * symbol information from the root COM32 module loaded by the SYSLINUX core.
+ * As their name suggests, memory is reserved only for the elf_module structure
+ * itself and optionally for a usually small memory region containing metainformation
+ * (symbol information).
+ *
+ * Module descriptors are related to each other through dependency information. A module
+ * can depend on symbols from other modules, and in turn it can provide symbols used
+ * by other dependant modules. This relationship can be described as a directed
+ * acyclic graph (DAG). The graph is stored using double linked lists of
+ * predecessors and successors. There is also a global linked list containing all
+ * the modules currently loaded.
+ */
+struct atexit;
+struct elf_module {
+ char name[MODULE_NAME_SIZE]; // The module name
+
+ bool shallow; // Whether the module contains any code
+
+ struct list_head required; // Head of the required modules list
+ struct list_head dependants; // Head of module dependants list
+ struct list_head list; // The list entry in the module list
+
+ module_ctor_t *ctors; // module constructors
+ module_ctor_t *dtors; // module destructors
+ module_main_t main_func; // The main function (for executable modules)
+
+ void *module_addr; // The module location in the memory
+ Elf_Addr base_addr; // The base address of the module
+ Elf_Word module_size; // The module size in memory
+
+ Elf_Word *hash_table; // The symbol hash table
+ Elf_Word *ghash_table; // The GNU style hash table
+ char *str_table; // The string table
+ void *sym_table; // The symbol table
+ void *got; // The Global Offset Table
+ Elf_Dyn *dyn_table; // Dynamic loading information table
+
+ Elf_Word strtable_size; // The size of the string table
+ Elf_Word syment_size; // The size of a symbol entry
+ Elf_Word symtable_size; // The size of the symbol table
+
+
+ union {
+ // Transient - Data available while the module is loading
+ struct {
+ FILE *_file; // The file object of the open file
+ Elf_Off _cr_offset; // The current offset in the open file
+ } l;
+
+ // Process execution data
+ struct {
+ jmp_buf process_exit; // Exit state
+ struct atexit *atexit_list; // atexit() chain
+ } x;
+ } u;
+
+ // ELF DT_NEEDED entries for this module
+ int nr_needed;
+ Elf_Word needed[MAX_NR_DEPS];
+};
+
+/**
+ * struct module_dep - structure encapsulating a module dependency need
+ *
+ * This structure represents an item in a double linked list of predecessors or
+ * successors. The item contents is a pointer to the corresponding module descriptor.
+ */
+struct module_dep {
+ struct list_head list; // The list entry in the dependency list
+
+ struct elf_module *module; // The target module descriptor
+};
+
+
+
+#ifdef DYNAMIC_MODULE
+
+/*
+ * This portion is included by dynamic (ELF) module source files.
+ */
+
+#define MODULE_INIT(fn) static module_init_t __module_init \
+ __used __attribute__((section(".ctors_modinit"))) = fn
+
+#define MODULE_EXIT(fn) static module_exit_t __module_exit \
+ __used __attribute__((section(".dtors_modexit"))) = fn
+
+#else
+
+/*
+ * This portion is included by the core COM32 module.
+ */
+
+/**
+ * Names of symbols with special meaning (treated as special cases at linking)
+ */
+#define MODULE_ELF_INIT_PTR "__module_init_ptr" // Initialization pointer symbol name
+#define MODULE_ELF_EXIT_PTR "__module_exit_ptr" // Finalization pointer symbol name
+#define MODULE_ELF_MAIN_PTR "__module_main_ptr" // Entry pointer symbol name
+
+/**
+ * modules_head - A global linked list containing all the loaded modules.
+ */
+extern struct list_head modules_head;
+
+
+/**
+ * for_each_module - iterator loop through the list of loaded modules.
+ */
+#define for_each_module(m) list_for_each_entry(m, &modules_head, list)
+
+/**
+ * for_each_module - iterator loop through the list of loaded modules safe against removal.
+ */
+#define for_each_module_safe(m, n) \
+ list_for_each_entry_safe(m, n, &modules_head, list)
+
+/**
+ * modules_init - initialize the module subsystem.
+ *
+ * This function must be called before any module operation is to be performed.
+ */
+extern int modules_init(void);
+
+
+/**
+ * modules_term - releases all resources pertaining to the module subsystem.
+ *
+ * This function should be called after all module operations.
+ */
+extern void modules_term(void);
+
+
+/**
+ * module_alloc - reserves space for a new module descriptor.
+ * @name: the file name of the module to be loaded.
+ *
+ * The function simply allocates a new module descriptor and initializes its fields
+ * in order to be used by subsequent loading operations.
+ */
+extern struct elf_module *module_alloc(const char *name);
+
+
+/**
+ * module_load - loads a regular ELF module into memory.
+ * @module: the module descriptor returned by module_alloc.
+ *
+ * The function reads the module file, checks whether the file has a
+ * valid structure, then loads into memory the code and the data and performs
+ * any symbol relocations. A module dependency is created automatically when the
+ * relocated symbol is defined in a different module.
+ *
+ * The function returns 0 if the operation is completed successfully, and
+ * a non-zero value if an error occurs. Possible errors include invalid module
+ * structure, missing symbol definitions (unsatisfied dependencies) and memory
+ * allocation issues.
+ */
+extern int module_load(struct elf_module *module);
+
+
+/**
+ * module_load_shallow - loads a shallow ELF module into memory.
+ * @module: the module descriptor returned by module_alloc.
+ *
+ * The function reads the module file, checks whether the file has a valid
+ * structure, then loads into memory the module metadata. The metadata currently
+ * contains a symbol table that describes code & data allocated by other means.
+ * Its current use is to describe the root COM32 module to the rest of the
+ * module subsystem.
+ */
+extern int module_load_shallow(struct elf_module *module, Elf_Addr base_addr);
+
+/**
+ * module_unload - unloads the module from the system.
+ * @module: the module descriptor structure.
+ *
+ * The function checks to see whether the module can be safely
+ * removed, then it executes any destructors and releases all the
+ * associated memory. This function can be applied both for standard
+ * modules and for shallow modules.
+ *
+ * A module can be safely removed from the system when no other modules reference
+ * symbols from it.
+ */
+extern int module_unload(struct elf_module *module);
+
+/**
+ * _module_unload - unloads the module without running destructors
+ *
+ * This function is the same as module_unload(), except that the
+ * module's destructors are not executed.
+ */
+extern int _module_unload(struct elf_module *module);
+
+/**
+ * module_unload - unloads the module from the system.
+ * @module: the module descriptor structure.
+ *
+ * This function returns the type of module we're dealing with
+ * either a library module ( LIB_MODULE ), executable module ( EXEC_MODULE ),
+ * or an error ( UNKNOWN_MODULE ). The way it checks teh type is by checking to see
+ * if the module has its main_func set ( in which case it's an executable ). In case
+ * it doesn't it then checks to see if init_func is set ( in which case it's a
+ * library module. If this isn't the case either we don't know what it is so bail out
+ */
+extern int get_module_type(struct elf_module *module);
+
+/**
+ * module_unloadable - checks whether the given module can be unloaded.
+ * @module: the module descriptor structure
+ *
+ * A module can be unloaded from the system when no other modules depend on it,
+ * that is, no symbols are referenced from it.
+ */
+extern int module_unloadable(struct elf_module *module);
+
+/**
+ * module_find - searches for a module by its name.
+ * @name: the name of the module, as it was specified in module_alloc.
+ *
+ * The function returns a pointer to the module descriptor, if found, or
+ * NULL otherwise.
+ */
+extern struct elf_module *module_find(const char *name);
+
+/**
+ * module_find_symbol - searches for a symbol definition in a given module.
+ * @name: the name of the symbol to be found.
+ * @module: the module descriptor structure.
+ *
+ * The function searches the module symbol table for a symbol matching exactly
+ * the name provided. The operation uses the following search algorithms, in this
+ * order:
+ * - If a GNU hash table is present in the module, it is used to find the symbol.
+ * - If the symbol cannot be found with the first method (either the hash table
+ * is not present or the symbol is not found) and if a regular (SysV) hash table
+ * is present, a search is performed on the SysV hash table. If the symbol is not
+ * found, NULL is returned.
+ * - If the second method cannot be applied, a linear search is performed by
+ * inspecting every symbol in the symbol table.
+ *
+ * If the symbol is found, a pointer to its descriptor structure is returned, and
+ * NULL otherwise.
+ */
+extern Elf_Sym *module_find_symbol(const char *name, struct elf_module *module);
+
+/**
+ * global_find_symbol - searches for a symbol definition in the entire module namespace.
+ * @name: the name of the symbol to be found.
+ * @module: an optional (may be NULL) pointer to a module descriptor variable that
+ * will hold the module where the symbol was found.
+ *
+ * The function search for the given symbol name in all the modules currently
+ * loaded in the system, in the reverse module loading order. That is, the most
+ * recently loaded module is searched first, followed by the previous one, until
+ * the first loaded module is reached.
+ *
+ * If no module contains the symbol, NULL is returned, otherwise the return value is
+ * a pointer to the symbol descriptor structure. If the module parameter is not NULL,
+ * it is filled with the address of the module descriptor where the symbol is defined.
+ */
+extern Elf_Sym *global_find_symbol(const char *name, struct elf_module **module);
+
+/**
+ * module_get_absolute - converts an memory address relative to a module base address
+ * to its absolute value in RAM.
+ * @addr: the relative address to convert.
+ * @module: the module whose base address is used for the conversion.
+ *
+ * The function returns a pointer to the absolute memory address.
+ */
+static inline void *module_get_absolute(Elf_Addr addr, struct elf_module *module) {
+ return (void*)(module->base_addr + addr);
+}
+
+/**
+ * syslinux_current - get the current module process
+ */
+extern struct elf_module *__syslinux_current;
+static inline const struct elf_module *syslinux_current(void)
+{
+ return __syslinux_current;
+}
+
+
+#endif // DYNAMIC_MODULE
+
+#endif // MODULE_H_
diff --git a/com32/include/sys/x86_64/module.h b/com32/include/sys/x86_64/module.h
index 032fd549..203a6cd0 100644
--- a/com32/include/sys/x86_64/module.h
+++ b/com32/include/sys/x86_64/module.h
@@ -4,179 +4,10 @@
* Dynamic ELF64 modules definitions and services.
*/
+#ifndef _X86_64_MODULE_H_
+#define _X86_64_MODULE_H_
-#include <stdio.h>
#include <elf.h>
-#include <stdint.h>
-#include <setjmp.h>
-#include <stdbool.h>
-#include <linux/list.h>
-
-/*
- * The maximum length of the module file name (including path), stored
- * in the struct module descriptor.
- */
-#define MODULE_NAME_SIZE 256
-
-/*
- * Some common information about what kind of modules we're dealing with
- */
-#define UNKNOWN_MODULE -1
-#define EXEC_MODULE 0
-#define LIB_MODULE 1
-
-/*
- * Initialization and finalization function signatures
- */
-
-
-/**
- * module_init_t - pointer to a initialization routine
- *
- * The initialization routine is called after all module constructors were invoked.
- * It takes no parameters and returns 0 if the module was initialized successfully,
- * or a non-zero value if errors have occurred.
- */
-typedef int64_t (*module_init_t)(void);
-
-/**
- * module_exit_t - pointer to a finalization routine
- *
- * The finalization routine is called before the module destructors are to be invoked.
- * It simply executes some cleanup code, without error reporting.
- */
-typedef void (*module_exit_t)(void);
-
-/**
- * module_main_t - pointer to an entry routine
- *
- * The entry routine is present only in executable modules, and represents
- * the entry point for the program.
- */
-typedef int64_t (*module_main_t)(int, char**);
-
-
-/**
- * struct elf_module - structure encapsulating a module loaded in memory.
- *
- * Each SYSLINUX ELF module must have an associated struct elf_module descriptor
- * that keeps track of memory allocations, symbol information, and various other
- * resources needed by the module itself or by other modules that depend on it.
- *
- * There are two types of modules:
- * - regular modules, which are actual memory images of a loaded & linked shared
- * object (ELF file). Memory is reserved for the struct elf_module structure itself
- * and for the object loadable sections read from the file.
- * - shallow modules, which are not associated with an ELF shared object, but contain
- * metainformation about a memory region already present and containing the
- * actual code and data. One particular usage of shallow modules is to access
- * symbol information from the root COM32 module loaded by the SYSLINUX core.
- * As their name suggests, memory is reserved only for the elf_module structure
- * itself and optionally for a usually small memory region containing metainformation
- * (symbol information).
- *
- * Module descriptors are related to each other through dependency information. A module
- * can depend on symbols from other modules, and in turn it can provide symbols used
- * by other dependant modules. This relationship can be described as a directed
- * acyclic graph (DAG). The graph is stored using double linked lists of
- * predecessors and successors. There is also a global linked list containing all
- * the modules currently loaded.
- */
-struct atexit;
-struct elf_module {
- char name[MODULE_NAME_SIZE]; // The module name
-
- bool shallow; // Whether the module contains any code
-
- struct list_head required; // Head of the required modules list
- struct list_head dependants; // Head of module dependants list
- struct list_head list; // The list entry in the module list
-
- module_init_t *init_func; // The initialization entry point
- module_exit_t *exit_func; // The module finalization code
- module_main_t main_func; // The main function (for executable modules)
-
-
- void *module_addr; // The module location in the memory
- Elf64_Addr base_addr; // The base address of the module
- Elf64_Word module_size; // The module size in memory
-
- Elf64_Word *hash_table; // The symbol hash table
- Elf64_Word *ghash_table; // The GNU style hash table
- char *str_table; // The string table
- void *sym_table; // The symbol table
- void *got; // The Global Offset Table
- Elf64_Dyn *dyn_table; // Dynamic loading information table
-
- Elf64_Word strtable_size; // The size of the string table
- Elf64_Word syment_size; // The size of a symbol entry
- Elf64_Word symtable_size; // The size of the symbol table
-
-
- union {
- // Transient - Data available while the module is loading
- struct {
- FILE *_file; // The file object of the open file
- Elf64_Off _cr_offset; // The current offset in the open file
- } l;
-
- // Process execution data
- struct {
- jmp_buf process_exit; // Exit state
- struct atexit *atexit_list; // atexit() chain
- } x;
- } u;
-
-};
-
-static inline void dump_elf_module(struct elf_module *module)
-{
- /*
- dprintf("module name = %s", module->name);
- printf("base_addr = 0x%p, module_size = %d\n", module->base_addr, module->module_size);
- printf("hash tlb = 0x%p, ghash tbl = 0x%p\n", module->hash_table, module->ghash_table);
- printf("str tbl = 0x%p, size = %d\n", module->str_table, module->strtable_size);
- printf("sym tbl = 0x%p, entry = %d, size = %d\n", module->sym_table, module->syment_size, module->symtable_size);
- printf("init: %p", module->init_func);
- printf("main: %p", module->main_func);
- printf("exit: %p", module->exit_func);
- printf("", module->base_addr);
- printf("", module->base_addr);
- printf("", module->base_addr);
- */
-}
-
-/**
- * struct module_dep - structure encapsulating a module dependency need
- *
- * This structure represents an item in a double linked list of predecessors or
- * successors. The item contents is a pointer to the corresponding module descriptor.
- */
-struct module_dep {
- struct list_head list; // The list entry in the dependency list
-
- struct elf_module *module; // The target module descriptor
-};
-
-
-
-#ifdef DYNAMIC_MODULE
-
-/*
- * This portion is included by dynamic (ELF) module source files.
- */
-
-#define MODULE_INIT(fn) static module_init_t __module_init \
- __used __attribute__((section(".ctors_modinit"))) = fn
-
-#define MODULE_EXIT(fn) static module_exit_t __module_exit \
- __used __attribute__((section(".dtors_modexit"))) = fn
-
-#else
-
-/*
- * This portion is included by the core COM32 module.
- */
/*
* Accepted values for various ELF header parameters found in an ELF dynamic
@@ -189,181 +20,16 @@ struct module_dep {
#define MODULE_ELF_TYPE ET_DYN // Executable type (shared object - .so)
#define MODULE_ELF_MACHINE EM_X86_64 // Target architecture
-/**
- * Names of symbols with special meaning (treated as special cases at linking)
- */
-#define MODULE_ELF_INIT_PTR "__module_init_ptr" // Initialization pointer symbol name
-#define MODULE_ELF_EXIT_PTR "__module_exit_ptr" // Finalization pointer symbol name
-#define MODULE_ELF_MAIN_PTR "__module_main_ptr" // Entry pointer symbol name
-
-/**
- * modules_head - A global linked list containing all the loaded modules.
- */
-extern struct list_head modules_head;
-
-
-/**
- * for_each_module - iterator loop through the list of loaded modules.
- */
-#define for_each_module(m) list_for_each_entry(m, &modules_head, list)
-
-/**
- * modules_init - initialize the module subsystem.
- *
- * This function must be called before any module operation is to be performed.
- */
-extern int modules_init(void);
-
-
-/**
- * modules_term - releases all resources pertaining to the module subsystem.
- *
- * This function should be called after all module operations.
- */
-extern void modules_term(void);
-
-
-/**
- * module_alloc - reserves space for a new module descriptor.
- * @name: the file name of the module to be loaded.
- *
- * The function simply allocates a new module descriptor and initializes its fields
- * in order to be used by subsequent loading operations.
- */
-extern struct elf_module *module_alloc(const char *name);
-
-
-/**
- * module_load - loads a regular ELF module into memory.
- * @module: the module descriptor returned by module_alloc.
- *
- * The function reads the module file, checks whether the file has a
- * valid structure, then loads into memory the code and the data and performs
- * any symbol relocations. A module dependency is created automatically when the
- * relocated symbol is defined in a different module.
- *
- * The function returns 0 if the operation is completed successfully, and
- * a non-zero value if an error occurs. Possible errors include invalid module
- * structure, missing symbol definitions (unsatisfied dependencies) and memory
- * allocation issues.
- */
-extern int module_load(struct elf_module *module);
-
-
-/**
- * module_load_shallow - loads a shallow ELF module into memory.
- * @module: the module descriptor returned by module_alloc.
- *
- * The function reads the module file, checks whether the file has a valid
- * structure, then loads into memory the module metadata. The metadata currently
- * contains a symbol table that describes code & data allocated by other means.
- * Its current use is to describe the root COM32 module to the rest of the
- * module subsystem.
- */
-extern int module_load_shallow(struct elf_module *module, Elf64_Addr base_addr);
-
-/**
- * module_unload - unloads the module from the system.
- * @module: the module descriptor structure.
- *
- * The function checks to see whether the module can be safely removed, then
- * it releases all the associated memory. This function can be applied both
- * for standard modules and for shallow modules.
- *
- * A module can be safely removed from the system when no other modules reference
- * symbols from it.
- */
-extern int module_unload(struct elf_module *module);
-
-/**
- * module_unload - unloads the module from the system.
- * @module: the module descriptor structure.
- *
- * This function returns the type of module we're dealing with
- * either a library module ( LIB_MODULE ), executable module ( EXEC_MODULE ),
- * or an error ( UNKNOWN_MODULE ). The way it checks teh type is by checking to see
- * if the module has its main_func set ( in which case it's an executable ). In case
- * it doesn't it then checks to see if init_func is set ( in which case it's a
- * library module. If this isn't the case either we don't know what it is so bail out
- */
-extern int get_module_type(struct elf_module *module);
-
-/**
- * module_unloadable - checks whether the given module can be unloaded.
- * @module: the module descriptor structure
- *
- * A module can be unloaded from the system when no other modules depend on it,
- * that is, no symbols are referenced from it.
- */
-extern int module_unloadable(struct elf_module *module);
-
-/**
- * module_find - searches for a module by its name.
- * @name: the name of the module, as it was specified in module_alloc.
- *
- * The function returns a pointer to the module descriptor, if found, or
- * NULL otherwise.
- */
-extern struct elf_module *module_find(const char *name);
-
-/**
- * module_find_symbol - searches for a symbol definition in a given module.
- * @name: the name of the symbol to be found.
- * @module: the module descriptor structure.
- *
- * The function searches the module symbol table for a symbol matching exactly
- * the name provided. The operation uses the following search algorithms, in this
- * order:
- * - If a GNU hash table is present in the module, it is used to find the symbol.
- * - If the symbol cannot be found with the first method (either the hash table
- * is not present or the symbol is not found) and if a regular (SysV) hash table
- * is present, a search is performed on the SysV hash table. If the symbol is not
- * found, NULL is returned.
- * - If the second method cannot be applied, a linear search is performed by
- * inspecting every symbol in the symbol table.
- *
- * If the symbol is found, a pointer to its descriptor structure is returned, and
- * NULL otherwise.
- */
-extern Elf64_Sym *module_find_symbol(const char *name, struct elf_module *module);
-
-/**
- * global_find_symbol - searches for a symbol definition in the entire module namespace.
- * @name: the name of the symbol to be found.
- * @module: an optional (may be NULL) pointer to a module descriptor variable that
- * will hold the module where the symbol was found.
- *
- * The function search for the given symbol name in all the modules currently
- * loaded in the system, in the reverse module loading order. That is, the most
- * recently loaded module is searched first, followed by the previous one, until
- * the first loaded module is reached.
- *
- * If no module contains the symbol, NULL is returned, otherwise the return value is
- * a pointer to the symbol descriptor structure. If the module parameter is not NULL,
- * it is filled with the address of the module descriptor where the symbol is defined.
- */
-extern Elf64_Sym *global_find_symbol(const char *name, struct elf_module **module);
-
-/**
- * module_get_absolute - converts an memory address relative to a module base address
- * to its absolute value in RAM.
- * @addr: the relative address to convert.
- * @module: the module whose base address is used for the conversion.
- *
- * The function returns a pointer to the absolute memory address.
- */
-static inline void *module_get_absolute(Elf64_Addr addr, struct elf_module *module) {
- return (void*)(module->base_addr + addr);
-}
-
-/**
- * syslinux_current - get the current module process
- */
-extern struct elf_module *__syslinux_current;
-static inline const struct elf_module *syslinux_current(void)
-{
- return __syslinux_current;
-}
+#define ELF_MOD_SYS "64 bit"
+typedef Elf64_Addr Elf_Addr;
+typedef Elf64_Dyn Elf_Dyn;
+typedef Elf64_Word Elf_Word;
+typedef Elf64_Off Elf_Off;
+typedef Elf64_Sym Elf_Sym;
+typedef Elf64_Ehdr Elf_Ehdr;
+typedef Elf64_Phdr Elf_Phdr;
+typedef Elf64_Rel Elf_Rel;
+typedef Elf64_Xword Elf_Bword;
-#endif // DYNAMIC_MODULE
+#endif // _X86_64_MODULE_H_
diff --git a/com32/include/syslinux/boot.h b/com32/include/syslinux/boot.h
index 21bea01a..aea32d9c 100644
--- a/com32/include/syslinux/boot.h
+++ b/com32/include/syslinux/boot.h
@@ -40,7 +40,7 @@
int syslinux_run_command(const char *);
__noreturn syslinux_run_default(void);
-void syslinux_local_boot(uint16_t flags);
+void syslinux_local_boot(int16_t flags);
void syslinux_final_cleanup(uint16_t flags);
@@ -48,6 +48,13 @@ void syslinux_chain_bootstrap(uint16_t flags, const void *bootstrap,
uint32_t bootstrap_len, uint32_t edx,
uint32_t esi, uint16_t ds);
+struct image_types {
+ const char *name;
+ uint32_t type;
+};
+
+extern const struct image_types image_boot_types[];
+
#define IMAGE_TYPE_KERNEL 0
#define IMAGE_TYPE_LINUX 1
#define IMAGE_TYPE_BOOT 2
@@ -57,6 +64,9 @@ void syslinux_chain_bootstrap(uint16_t flags, const void *bootstrap,
#define IMAGE_TYPE_COMBOOT 6
#define IMAGE_TYPE_COM32 7
#define IMAGE_TYPE_CONFIG 8
+#define IMAGE_TYPE_LOCALBOOT 9
+
+uint32_t parse_image_type(const char *cmdline);
void syslinux_run_kernel_image(const char *filename, const char *cmdline,
uint32_t ipappend_flags, uint32_t type);
diff --git a/com32/include/syslinux/config.h b/com32/include/syslinux/config.h
index 79a4750e..7bdcdd6b 100644
--- a/com32/include/syslinux/config.h
+++ b/com32/include/syslinux/config.h
@@ -164,10 +164,10 @@ static inline const struct syslinux_serial_console_info
return &__syslinux_serial_console_info;
}
-extern __nocommon const char *__syslinux_config_file;
+extern char ConfigName[];
static inline const char *syslinux_config_file(void)
{
- return __syslinux_config_file;
+ return ConfigName;
}
struct syslinux_ipappend_strings {
@@ -181,4 +181,9 @@ static inline const struct syslinux_ipappend_strings
return &__syslinux_ipappend_strings;
}
+static inline enum syslinux_filesystem syslinux_filesystem(void)
+{
+ return syslinux_derivative_info()->c.filesystem;
+}
+
#endif /* _SYSLINUX_CONFIG_H */
diff --git a/com32/include/syslinux/disk.h b/com32/include/syslinux/disk.h
new file mode 100644
index 00000000..f96ca686
--- /dev/null
+++ b/com32/include/syslinux/disk.h
@@ -0,0 +1,180 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ * Copyright (C) 2010 Shao Miller
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/**
+ * @file syslinux/disk.h
+ *
+ * Deal with disks and partitions
+ */
+
+#ifndef _SYSLINUX_DISK_H
+#define _SYSLINUX_DISK_H
+
+#include <com32.h>
+#include <stdint.h>
+
+#define SECTOR 512u /* bytes/sector */
+
+struct disk_info {
+ int disk;
+ int ebios; /* EBIOS supported on this disk */
+ int cbios; /* CHS geometry is valid */
+ uint32_t bps; /* bytes per sector */
+ uint64_t lbacnt; /* total amount of sectors */
+ uint32_t cyl;
+ uint32_t head;
+ uint32_t spt;
+};
+
+struct disk_ebios_dapa {
+ uint16_t len;
+ uint16_t count;
+ uint16_t off;
+ uint16_t seg;
+ uint64_t lba;
+} __attribute__ ((packed));
+
+struct disk_ebios_eparam {
+ uint16_t len;
+ uint16_t info;
+ uint32_t cyl;
+ uint32_t head;
+ uint32_t spt;
+ uint64_t lbacnt;
+ uint16_t bps; /* bytes per sector */
+ uint32_t edd;
+ uint16_t dpi_sig;
+ uint8_t dpi_len;
+ char reserved1[3];
+ char hostbus[4];
+ char if_type[8];
+ char if_path[8];
+ char dev_path[8];
+ char reserved2;
+ uint8_t checksum;
+} __attribute__ ((packed));
+
+/**
+ * CHS (cylinder, head, sector) value extraction macros.
+ * Taken from WinVBlock. None expand to an lvalue.
+*/
+#define chs_head(chs) chs[0]
+#define chs_sector(chs) (chs[1] & 0x3F)
+#define chs_cyl_high(chs) (((uint16_t)(chs[1] & 0xC0)) << 2)
+#define chs_cyl_low(chs) ((uint16_t)chs[2])
+#define chs_cylinder(chs) (chs_cyl_high(chs) | chs_cyl_low(chs))
+typedef uint8_t disk_chs[3];
+
+/* A DOS partition table entry */
+struct disk_dos_part_entry {
+ uint8_t active_flag; /* 0x80 if "active" */
+ disk_chs start;
+ uint8_t ostype;
+ disk_chs end;
+ uint32_t start_lba;
+ uint32_t length;
+} __attribute__ ((packed));
+
+/* A DOS MBR */
+struct disk_dos_mbr {
+ char code[440];
+ uint32_t disk_sig;
+ char pad[2];
+ struct disk_dos_part_entry table[4];
+ uint16_t sig;
+} __attribute__ ((packed));
+#define disk_mbr_sig_magic 0xAA55
+
+/**
+ * A GPT disk/partition GUID
+ *
+ * Be careful with endianness, you must adjust it yourself
+ * iff you are directly using the fourth data chunk.
+ * There might be a better header for this...
+ */
+struct guid {
+ uint32_t data1;
+ uint16_t data2;
+ uint16_t data3;
+ uint64_t data4;
+} __attribute__ ((packed));
+
+/* A GPT partition */
+struct disk_gpt_part_entry {
+ struct guid type;
+ struct guid uid;
+ uint64_t lba_first;
+ uint64_t lba_last;
+ uint64_t attribs;
+ char name[72];
+} __attribute__ ((packed));
+
+/* A GPT header */
+struct disk_gpt_header {
+ char sig[8];
+ union {
+ struct {
+ uint16_t minor;
+ uint16_t major;
+ } fields __attribute__ ((packed));
+ uint32_t uint32;
+ char raw[4];
+ } rev __attribute__ ((packed));
+ uint32_t hdr_size;
+ uint32_t chksum;
+ char reserved1[4];
+ uint64_t lba_cur;
+ uint64_t lba_alt;
+ uint64_t lba_first_usable;
+ uint64_t lba_last_usable;
+ struct guid disk_guid;
+ uint64_t lba_table;
+ uint32_t part_count;
+ uint32_t part_size;
+ uint32_t table_chksum;
+ char reserved2[1];
+} __attribute__ ((packed));
+static const char disk_gpt_sig_magic[] = "EFI PART";
+
+extern int disk_int13_retry(const com32sys_t * inreg, com32sys_t * outreg);
+extern int disk_get_params(int disk, struct disk_info *const diskinfo);
+extern void *disk_read_sectors(const struct disk_info *const diskinfo,
+ uint64_t lba, uint8_t count);
+extern int disk_write_sectors(const struct disk_info *const diskinfo,
+ uint64_t lba, const void *data, uint8_t count);
+extern int disk_write_verify_sectors(const struct disk_info *const diskinfo,
+ uint64_t lba, const void *buf, uint8_t count);
+extern void disk_dos_part_dump(const struct disk_dos_part_entry *const part);
+extern void guid_to_str(char *buf, const struct guid *const id);
+extern int str_to_guid(const char *buf, struct guid *const id);
+extern void disk_gpt_part_dump(const struct disk_gpt_part_entry *const
+ gpt_part);
+extern void disk_gpt_header_dump(const struct disk_gpt_header *const gpt);
+
+#endif /* _SYSLINUX_DISK_H */
diff --git a/com32/include/syslinux/features.h b/com32/include/syslinux/features.h
index 4bebda49..d25d08d5 100644
--- a/com32/include/syslinux/features.h
+++ b/com32/include/syslinux/features.h
@@ -31,18 +31,16 @@
#define SYSLINUX_FEATURE_LOCAL_BOOT (0*8+0)
#define SYSLINUX_FEATURE_NOOP_IDLE (0*8+1)
-extern struct __syslinux_feature_flags {
- unsigned int len;
- const unsigned char *ptr;
-} __syslinux_feature_flags;
+extern uint8_t feature_flags;
+extern uint8_t feature_flags_len;
static inline int syslinux_has_feature(unsigned int __flag)
{
unsigned int __byte = __flag >> 3;
unsigned int __bit = __flag & 7;
- if (__byte <= __syslinux_feature_flags.len)
- return (__syslinux_feature_flags.ptr[__byte] >> __bit) & 1;
+ if (__byte <= feature_flags_len)
+ return (feature_flags[__byte] >> __bit) & 1;
else
return 0;
}
diff --git a/com32/include/syslinux/firmware.h b/com32/include/syslinux/firmware.h
index 456ba662..05f97630 100644
--- a/com32/include/syslinux/firmware.h
+++ b/com32/include/syslinux/firmware.h
@@ -3,10 +3,12 @@
#include <syslinux/memscan.h>
+struct term_state;
+
struct output_ops {
void (*erase) (int, int, int, int, uint8_t);
void (*write_char) (uint8_t, uint8_t);
- void (*showcursor) (uint16_t);
+ void (*showcursor) (const struct term_state *);
void (*scroll_up) (uint8_t, uint8_t, uint8_t);
void (*set_cursor) (int, int, bool);
void (*beep) (void);
@@ -16,7 +18,8 @@ struct output_ops {
};
struct input_ops {
- char (*getchar)(void);
+ char (*getchar)(char *);
+ int (*pollchar)(void);
};
struct adv_ops {
@@ -26,6 +29,7 @@ struct adv_ops {
struct disk_private;
struct initramfs;
+struct setup_data;
struct firmware {
void (*init)(void);
@@ -35,11 +39,11 @@ struct firmware {
struct disk *(*disk_init)(void *);
struct output_ops *o_ops;
struct input_ops *i_ops;
- char *(*get_config_file_name)(void);
void (*get_serial_console_info)(uint16_t *, uint16_t *, uint16_t *);
bool (*ipappend_strings)(char **, int *);
struct adv_ops *adv_ops;
- int (*boot_linux)(void *, size_t, struct initramfs *, char *);
+ int (*boot_linux)(void *, size_t, struct initramfs *,
+ struct setup_data *, char *);
};
extern struct firmware *firmware;
diff --git a/com32/include/syslinux/linux.h b/com32/include/syslinux/linux.h
index abc71dc1..a8c6f2f5 100644
--- a/com32/include/syslinux/linux.h
+++ b/com32/include/syslinux/linux.h
@@ -1,6 +1,7 @@
/* ----------------------------------------------------------------------- *
*
* Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2012 Intel Corporation; author: H. Peter Anvin
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -52,6 +53,22 @@ struct initramfs {
};
#define INITRAMFS_MAX_ALIGN 4096
+struct setup_data_header {
+ uint64_t next;
+ uint32_t type;
+ uint32_t len;
+} __packed;
+
+struct setup_data {
+ struct setup_data *prev, *next;
+ const void *data;
+ struct setup_data_header hdr;
+};
+
+#define SETUP_NONE 0
+#define SETUP_E820_EXT 1
+#define SETUP_DTB 2
+
struct linux_header {
uint8_t boot_sector_1[0x0020];
uint16_t old_cmd_line_magic;
@@ -134,7 +151,9 @@ struct screen_info {
} __packed;
int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
- struct initramfs *initramfs, char *cmdline);
+ struct initramfs *initramfs,
+ struct setup_data *setup_data,
+ char *cmdline);
/* Initramfs manipulation functions */
@@ -169,4 +188,12 @@ static inline uint32_t initramfs_size(struct initramfs *initramfs)
return size;
}
+/* Setup data manipulation functions */
+
+struct setup_data *setup_data_init(void);
+int setup_data_add(struct setup_data *head, uint32_t type,
+ const void *data, size_t data_len);
+int setup_data_load(struct setup_data *head, uint32_t type,
+ const char *filename);
+
#endif /* _SYSLINUX_LINUX_H */
diff --git a/com32/include/syslinux/movebits.h b/com32/include/syslinux/movebits.h
index 54ee7ff9..8bcdf3ed 100644
--- a/com32/include/syslinux/movebits.h
+++ b/com32/include/syslinux/movebits.h
@@ -83,7 +83,12 @@ int syslinux_memmap_find(struct syslinux_memmap *list,
addr_t * start, addr_t * len, addr_t align);
/* Debugging functions */
-void syslinux_dump_movelist(FILE * file, struct syslinux_movelist *ml);
-void syslinux_dump_memmap(FILE * file, struct syslinux_memmap *memmap);
+#ifdef DEBUG
+void syslinux_dump_movelist(struct syslinux_movelist *ml);
+void syslinux_dump_memmap(struct syslinux_memmap *memmap);
+#else
+#define syslinux_dump_movelist(x) ((void)0)
+#define syslinux_dump_memmap(x) ((void)0)
+#endif
#endif /* _SYSLINUX_MOVEBITS_H */
diff --git a/com32/include/syslinux/pxe_api.h b/com32/include/syslinux/pxe_api.h
index 27166b0b..203ab38f 100644
--- a/com32/include/syslinux/pxe_api.h
+++ b/com32/include/syslinux/pxe_api.h
@@ -568,4 +568,8 @@ typedef struct s_PXENV_UNLOAD_STACK {
#define PXENV_STATUS_LOADER_UNDI_START 0xca
#define PXENV_STATUS_LOADER_BC_START 0xcb
+int __weak pxe_call(int, void *);
+void __weak unload_pxe(uint16_t flags);
+uint32_t __weak dns_resolv(const char *);
+
#endif /* _SYSLINUX_PXE_API_H */
diff --git a/com32/lib/Makefile b/com32/lib/Makefile
index 616a5506..705feb3f 100644
--- a/com32/lib/Makefile
+++ b/com32/lib/Makefile
@@ -47,16 +47,24 @@ LIBPCI_OBJS = \
LIBSYSLINUX_OBJS = \
syslinux/reboot.o syslinux/keyboard.o \
- syslinux/features.o syslinux/config.o \
- syslinux/dsinfo.o syslinux/version.o \
+ syslinux/version.o \
syslinux/pxe_get_cached.o syslinux/pxe_get_nic.o \
syslinux/pxe_dns.o \
- syslinux/video/fontquery.o syslinux/video/forcetext.o \
- syslinux/video/reportmode.o
+ syslinux/video/fontquery.o syslinux/video/reportmode.o
DYNENTRY_OBJS = \
atexit.o onexit.o abort.o
+MINLIBOBJS = \
+ syslinux/ipappend.o \
+ syslinux/dsinfo.o \
+ $(LIBOTHER_OBJS) \
+ $(LIBGCC_OBJS) \
+ $(LIBCONSOLE_OBJS) \
+ $(LIBLOAD_OBJS) \
+ $(LIBZLIB_OBJS)
+# $(LIBVESA_OBJS)
+
DYNLIBOBJS = \
$(LIBZLIB_OBJS) \
$(LIBPNG_OBJS) \
@@ -79,7 +87,7 @@ AUXDIR = $(DATADIR)/syslinux
INCDIR = /usr/include
COM32DIR = $(AUXDIR)/com32
-all: libcom32.c32 libcom32min.a
+all: libcom32.c32 libcom32min.a libcom32core.a
libcom32.c32 : $(LIBOBJS)
rm -f $@
@@ -90,6 +98,11 @@ libcom32min.a : $(MINLIBOBJS)
$(AR) cq $@ $^
$(RANLIB) $@
+libcom32core.a : $(CORELIBOBJS)
+ rm -f $@
+ $(AR) cq $@ $^
+ $(RANLIB) $@
+
tidy dist clean:
rm -f sys/vesa/alphatbl.c
find . \( -name \*.o -o -name \*.a -o -name .\*.d -o -name \*.tmp \) -print0 | \
diff --git a/com32/lib/com32.ld b/com32/lib/com32.ld
index 37ee46cf..008e4ceb 100644
--- a/com32/lib/com32.ld
+++ b/com32/lib/com32.ld
@@ -36,36 +36,23 @@ SECTIONS
.rodata1 : { *(.rodata1) }
__rodata_end = .;
- /* Ensure the __preinit_array_start label is properly aligned. We
- could instead move the label definition inside the section, but
- the linker would then create the section even if it turns out to
- be empty, which isn't pretty. */
+ /*
+ * The difference betwee .ctors/.dtors and .init_array/.fini_array
+ * is the ordering, but we don't use prioritization for libcom32, so
+ * just lump them all together and hope that's okay.
+ */
. = ALIGN(4);
- .preinit_array : {
- PROVIDE (__preinit_array_start = .);
- *(.preinit_array)
- PROVIDE (__preinit_array_end = .);
- }
- .init_array : {
- PROVIDE (__init_array_start = .);
- *(.init_array)
- PROVIDE (__init_array_end = .);
- }
- .fini_array : {
- PROVIDE (__fini_array_start = .);
- *(.fini_array)
- PROVIDE (__fini_array_end = .);
- }
.ctors : {
PROVIDE (__ctors_start = .);
- KEEP (*(SORT(.ctors.*)))
- KEEP (*(.ctors))
+ KEEP (*(SORT(.preinit_array*)))
+ KEEP (*(SORT(.init_array*)))
+ KEEP (*(SORT(.ctors*)))
PROVIDE (__ctors_end = .);
}
.dtors : {
PROVIDE (__dtors_start = .);
- KEEP (*(SORT(.dtors.*)))
- KEEP (*(.dtors))
+ KEEP (*(SORT(.fini_array*)))
+ KEEP (*(SORT(.dtors*)))
PROVIDE (__dtors_end = .);
}
diff --git a/com32/lib/dhcppack.c b/com32/lib/dhcppack.c
new file mode 100644
index 00000000..a08583c4
--- /dev/null
+++ b/com32/lib/dhcppack.c
@@ -0,0 +1,166 @@
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+// #include <arpa/inet.h>
+#include <netinet/in.h>
+
+// #include "dhcp.h"
+#include <dhcp.h>
+
+/*
+ * Pack DHCP options into an option field, without overload support.
+ * On return, len contains the number of active bytes, and the full
+ * field is zero-padded.
+ *
+ * Options which are successfully placed have their length zeroed out.
+ */
+static int dhcp_pack_field_zero(void *field, size_t *len,
+ struct dhcp_option opt[256])
+{
+ int i;
+ size_t xlen, plen;
+ const uint8_t *p;
+ uint8_t *q = field;
+ size_t spc = *len;
+ int err = 0;
+
+ if (!*len)
+ return ENOSPC;
+
+ for (i = 1; i < 255; i++) {
+ if (opt[i].len < 0)
+ continue;
+
+ /* We need to handle the 0 case as well as > 255 */
+ if (opt[i].len <= 255)
+ xlen = opt[i].len + 2;
+ else
+ xlen = opt[i].len + 2*((opt[i].len+254)/255);
+
+ p = opt[i].data;
+
+ if (xlen >= spc) {
+ /* This option doesn't fit... */
+ err++;
+ continue;
+ }
+
+ xlen = opt[i].len;
+ do {
+ *q++ = i;
+ *q++ = plen = xlen > 255 ? 255 : xlen;
+ if (plen)
+ memcpy(q, p, plen);
+ q += plen;
+ p += plen;
+ spc -= plen+2;
+ xlen -= plen;
+ } while (xlen);
+
+ opt[i].len = -1;
+ }
+
+ *q++ = 255; /* End marker */
+ memset(q, 0, spc); /* Zero-pad the rest of the field */
+
+ *len = xlen = q - (uint8_t *)field;
+ return err;
+}
+
+/*
+ * Pack DHCP options into an option field, without overload support.
+ * On return, len contains the number of active bytes, and the full
+ * field is zero-padded.
+ *
+ * Use this to encode encapsulated option fields.
+ */
+int dhcp_pack_field(void *field, size_t *len,
+ struct dhcp_option opt[256])
+{
+ struct dhcp_option ox[256];
+
+ memcpy(ox, opt, sizeof ox);
+ return dhcp_pack_field_zero(field, len, ox);
+}
+
+/*
+ * Pack DHCP options into a packet.
+ * Apply overloading if (and only if) the "file" or "sname" option
+ * doesn't fit in the respective dedicated fields.
+ */
+int dhcp_pack_packet(void *packet, size_t *len,
+ const struct dhcp_option opt[256])
+{
+ struct dhcp_packet *pkt = packet;
+ size_t spc = *len;
+ uint8_t overload;
+ struct dhcp_option ox[256];
+ uint8_t *q;
+ int err;
+
+ if (spc < sizeof(struct dhcp_packet))
+ return ENOSPC; /* Buffer impossibly small */
+
+ pkt->magic = htonl(DHCP_VENDOR_MAGIC);
+
+ memcpy(ox, opt, sizeof ox);
+
+ /* Figure out if we should do overloading or not */
+ overload = 0;
+
+ if (opt[67].len > 128)
+ overload |= 1;
+ else
+ ox[67].len = -1;
+
+ if (opt[66].len > 64)
+ overload |= 2;
+ else
+ ox[66].len = -1;
+
+ /* Kill any passed-in overload option */
+ ox[52].len = -1;
+
+ q = pkt->options;
+ spc -= 240;
+
+ /* Force option 53 (DHCP packet type) first */
+ if (ox[53].len == 1) {
+ *q++ = 53;
+ *q++ = 1;
+ *q++ = *(uint8_t *)ox[53].data;
+ spc -= 3;
+ ox[53].len = -1;
+ }
+
+ /* Follow with the overload option, if applicable */
+ if (overload) {
+ *q++ = 52;
+ *q++ = 1;
+ *q++ = overload;
+ spc -= 3;
+ }
+
+ err = dhcp_pack_field_zero(q, &spc, ox);
+ *len = spc + (q-(uint8_t *)packet);
+
+ if (overload & 1) {
+ spc = 128;
+ err = dhcp_pack_field_zero(pkt->file, &spc, ox);
+ } else {
+ memset(pkt->file, 0, 128);
+ if (opt[67].len > 0)
+ memcpy(pkt->file, opt[67].data, opt[67].len);
+ }
+
+ if (overload & 2) {
+ spc = 64;
+ err = dhcp_pack_field_zero(pkt->sname, &spc, ox);
+ } else {
+ memset(pkt->sname, 0, 64);
+ if (opt[66].len > 0)
+ memcpy(pkt->sname, opt[66].data, opt[66].len);
+ }
+
+ return err;
+}
diff --git a/com32/lib/dhcpunpack.c b/com32/lib/dhcpunpack.c
new file mode 100644
index 00000000..248173a8
--- /dev/null
+++ b/com32/lib/dhcpunpack.c
@@ -0,0 +1,116 @@
+#define _GNU_SOURCE /* For strnlen() */
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+// #include <arpa/inet.h>
+#include <netinet/in.h>
+
+// #include "dhcp.h"
+#include <dhcp.h>
+
+/*
+ * Unpack DHCP options from a field. Assumes opt is pre-initalized
+ * (to all zero in the common case.)
+ */
+int dhcp_unpack_field(const void *field, size_t len,
+ struct dhcp_option opt[256])
+{
+ const uint8_t *p = field;
+ int err = 0;
+
+ while (len > 1) {
+ uint8_t op;
+ size_t xlen;
+
+ op = *p++; len--;
+ if (op == 0)
+ continue;
+ else if (op == 255)
+ break;
+
+ xlen = *p++; len--;
+ if (xlen > len)
+ break;
+ if (opt[op].len < 0)
+ opt[op].len = 0;
+ if (xlen) {
+ opt[op].data = realloc(opt[op].data,
+ opt[op].len + xlen + 1);
+ if (!opt[op].data) {
+ err = ENOMEM;
+ continue;
+ }
+ memcpy((char *)opt[op].data + opt[op].len, p, xlen);
+ opt[op].len += xlen;
+ /* Null-terminate as a courtesy to users */
+ *((char *)opt[op].data + opt[op].len) = 0;
+ p += xlen;
+ len -= xlen;
+ }
+ }
+
+ return err;
+}
+
+/*
+ * Unpack a DHCP packet, with overload support. Do not use this
+ * to unpack an encapsulated option set.
+ */
+int dhcp_unpack_packet(const void *packet, size_t len,
+ struct dhcp_option opt[256])
+{
+ const struct dhcp_packet *pkt = packet;
+ int err;
+ uint8_t overload;
+ int i;
+
+ if (len < 240 || pkt->magic != htonl(DHCP_VENDOR_MAGIC))
+ return EINVAL; /* Bogus packet */
+
+ for (i = 0; i < 256; i++) {
+ opt[i].len = -1; /* Option not present */
+ opt[i].data = NULL;
+ }
+
+ err = dhcp_unpack_field(pkt->options, len-240, opt);
+
+ overload = 0;
+ if (opt[52].len == 1) {
+ overload = *(uint8_t *)opt[52].data;
+ free(opt[52].data);
+ opt[52].len = -1;
+ opt[52].data = NULL;
+ }
+
+ if (overload & 1) {
+ err |= dhcp_unpack_field(pkt->file, 128, opt);
+ } else {
+ opt[67].len = strnlen((const char *)pkt->file, 128);
+ if (opt[67].len) {
+ opt[67].data = malloc(opt[67].len + 1);
+ if (opt[67].data) {
+ memcpy(opt[67].data, pkt->file, opt[67].len);
+ *((char *)opt[67].data + opt[67].len) = 0;
+ } else {
+ err |= ENOMEM;
+ }
+ }
+ }
+
+ if (overload & 2) {
+ err |= dhcp_unpack_field(pkt->sname, 64, opt);
+ } else {
+ opt[66].len = strnlen((const char *)pkt->sname, 64);
+ if (opt[66].len) {
+ opt[66].data = malloc(opt[66].len + 1);
+ if (opt[66].data) {
+ memcpy(opt[66].data, pkt->file, opt[66].len);
+ *((char *)opt[66].data + opt[66].len) = 0;
+ } else {
+ err |= ENOMEM;
+ }
+ }
+ }
+
+ return err;
+}
diff --git a/com32/lib/dprintf.c b/com32/lib/dprintf.c
index 900c0a47..dea77b39 100644
--- a/com32/lib/dprintf.c
+++ b/com32/lib/dprintf.c
@@ -5,9 +5,9 @@
#include <stdio.h>
#include <stdarg.h>
-#undef DEBUG
-#define DEBUG 1
-#include <dprintf.h>
+#ifdef DEBUG_PORT
+
+void vdprintf(const char *, va_list);
void dprintf(const char *format, ...)
{
@@ -17,3 +17,5 @@ void dprintf(const char *format, ...)
vdprintf(format, ap);
va_end(ap);
}
+
+#endif /* DEBUG_PORT */
diff --git a/com32/lib/elf32.ld b/com32/lib/elf32.ld
index 158badbb..ddf6e048 100644
--- a/com32/lib/elf32.ld
+++ b/com32/lib/elf32.ld
@@ -91,13 +91,9 @@ SECTIONS
__ctors_start = .;
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
- LONG(0x00000000)
- __module_init_ptr = .;
KEEP (*(.ctors_modinit))
- LONG(0x00000000)
- __module_main_ptr = .;
KEEP (*(.ctors_modmain))
- LONG(0x00000000)
+ __ctors_end = .;
}
.dtors :
@@ -105,10 +101,8 @@ SECTIONS
__dtors_start = .;
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
- LONG(0x00000000)
- __module_exit_ptr = .;
KEEP (*(.dtors_modexit))
- LONG(0x00000000)
+ __dtors_end = .;
}
.jcr : { KEEP (*(.jcr)) }
diff --git a/com32/lib/getcwd.c b/com32/lib/getcwd.c
index 2939c07c..d5fa9d7d 100644
--- a/com32/lib/getcwd.c
+++ b/com32/lib/getcwd.c
@@ -4,6 +4,7 @@
#include <com32.h>
#include <syslinux/pmapi.h>
+#include <fs.h>
char *getcwd(char *buf, size_t size)
{
diff --git a/com32/lib/lmalloc.c b/com32/lib/lmalloc.c
index 9d532c80..3e69ac1d 100644
--- a/com32/lib/lmalloc.c
+++ b/com32/lib/lmalloc.c
@@ -31,15 +31,6 @@
#include <string.h>
#include <syslinux/pmapi.h>
-void *clmalloc(size_t size)
-{
- void *p;
- p = lmalloc(size);
- if (!p)
- errno = ENOMEM;
- return p;
-}
-
void *lzalloc(size_t size)
{
void *p;
diff --git a/com32/lib/lstrdup.c b/com32/lib/lstrdup.c
index 6747ef3a..d11efe7e 100644
--- a/com32/lib/lstrdup.c
+++ b/com32/lib/lstrdup.c
@@ -9,7 +9,7 @@
char *lstrdup(const char *s)
{
int l = strlen(s) + 1;
- char *d = clmalloc(l);
+ char *d = lmalloc(l);
if (d)
memcpy(d, s, l);
diff --git a/com32/lib/pci/scan.c b/com32/lib/pci/scan.c
index 4e5635f6..fe00fc25 100644
--- a/com32/lib/pci/scan.c
+++ b/com32/lib/pci/scan.c
@@ -41,12 +41,7 @@
#include <stdbool.h>
#include <ctype.h>
#include <syslinux/zio.h>
-
-#ifdef DEBUG
-# define dprintf printf
-#else
-# define dprintf(...) ((void)0)
-#endif
+#include <dprintf.h>
#define MAX_LINE 512
@@ -584,14 +579,14 @@ void free_pci_domain(struct pci_domain *domain)
free(func->dev_info);
free(func);
}
- free(slot);
}
+ free(slot);
}
- free(bus);
}
+ free(bus);
}
- free(domain);
}
+ free(domain);
}
}
diff --git a/com32/lib/syslinux/features.c b/com32/lib/strreplace.c
index c88aef30..d59efe0e 100644
--- a/com32/lib/syslinux/features.c
+++ b/com32/lib/strreplace.c
@@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- *
*
- * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2011 Erwan Velu - All Rights Reserved
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -23,29 +23,36 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
- * ----------------------------------------------------------------------- */
-
-/*
- * syslinux/features.c
- *
- * SYSLINUX feature flag query
+ * -----------------------------------------------------------------------
*/
-#include <klibc/compiler.h>
-#include <syslinux/features.h>
#include <string.h>
-#include <com32.h>
-
-struct __syslinux_feature_flags __syslinux_feature_flags;
+#include <stdlib.h>
-void __constructor __syslinux_detect_features(void)
+char *strreplace(const char *string, const char *string_to_replace,
+ const char *string_to_insert)
{
- static com32sys_t reg;
+ char *token = NULL;
+ char *out = NULL;
+
+ size_t slen, srlen, silen;
+
+ token = strstr(string, string_to_replace);
+ if (!token)
+ return strdup(string);
- memset(&reg, 0, sizeof reg);
- reg.eax.w[0] = 0x0015;
- __intcall(0x22, &reg, &reg);
+ slen = strlen(string);
+ srlen = strlen(string_to_replace);
+ silen = strlen(string_to_insert);
+
+ out = malloc(slen - srlen + silen + 1);
+ if (!out)
+ return NULL;
+
+ memcpy(out, string, token - string);
+ memcpy(out + (token - string), string_to_insert, silen);
+ memcpy(out + (token - string) + silen, token + srlen,
+ slen - srlen - (token - string) + 1);
- __syslinux_feature_flags.len = reg.ecx.w[0];
- __syslinux_feature_flags.ptr = MK_PTR(reg.es, reg.ebx.w[0]);
+ return out;
}
diff --git a/com32/lib/sys/ansicon_write.c b/com32/lib/sys/ansicon_write.c
index a963923d..74add717 100644
--- a/com32/lib/sys/ansicon_write.c
+++ b/com32/lib/sys/ansicon_write.c
@@ -35,7 +35,6 @@
#include <errno.h>
#include <string.h>
-#include <com32.h>
#include <minmax.h>
#include <colortbl.h>
#include <klibc/compiler.h>
@@ -43,6 +42,7 @@
#include "file.h"
#include "ansi.h"
#include <syslinux/firmware.h>
+#include "graphics.h"
static void ansicon_erase(const struct term_state *, int, int, int, int);
static void ansicon_write_char(int, int, uint8_t, const struct term_state *);
@@ -66,53 +66,15 @@ static struct term_info ti = {
.op = &__ansicon_ops
};
-#define BIOS_CURXY ((struct curxy *)0x450) /* Array for each page */
-#define BIOS_ROWS (*(uint8_t *)0x484) /* Minus one; if zero use 24 (= 25 lines) */
-#define BIOS_COLS (*(uint16_t *)0x44A)
-#define BIOS_PAGE (*(uint8_t *)0x462)
-
#define TEXT_MODE 0x0005
/* Reference counter to the screen, to keep track of if we need
reinitialization. */
static int ansicon_counter = 0;
-static uint16_t cursor_type; /* Saved cursor pattern */
-
-void bios_set_mode(uint16_t mode)
-{
- com32sys_t ireg;
-
- ireg.eax.w[0] = mode;
- __intcall(0x22, &ireg, NULL);
-}
-
-void bios_get_mode(int *cols, int *rows)
-{
- *rows = BIOS_ROWS ? BIOS_ROWS + 1 : 25;
- *cols = BIOS_COLS;
-}
-
-void bios_get_cursor(int *x, int *y)
-{
- com32sys_t ireg, oreg;
-
- memset(&ireg, 0, sizeof(ireg));
-
- ireg.eax.b[1] = 0x03;
- ireg.ebx.b[1] = BIOS_PAGE;
- __intcall(0x10, &ireg, &oreg);
- cursor_type = oreg.ecx.w[0];
- *x = oreg.edx.b[0];
- *y = oreg.edx.b[1];
-}
-
/* Common setup */
int __ansicon_open(struct file_info *fp)
{
- static com32sys_t ireg; /* Auto-initalized to all zero */
- com32sys_t oreg;
-
if (!ansicon_counter) {
/* Are we disabled? */
if (syslinux_serial_console_info()->flowctl & 0x8000) {
@@ -175,19 +137,6 @@ static uint8_t ansicon_attribute(const struct term_state *st)
return (bg << 4) | fg;
}
-void bios_erase(int x0, int y0, int x1, int y1, uint8_t attribute)
-{
- static com32sys_t ireg;
-
- ireg.eax.w[0] = 0x0600; /* Clear window */
- ireg.ebx.b[1] = attribute;
- ireg.ecx.b[0] = x0;
- ireg.ecx.b[1] = y0;
- ireg.edx.b[0] = x1;
- ireg.edx.b[1] = y1;
- __intcall(0x10, &ireg, NULL);
-}
-
/* Erase a region of the screen */
static void ansicon_erase(const struct term_state *st,
int x0, int y0, int x1, int y1)
@@ -198,37 +147,10 @@ static void ansicon_erase(const struct term_state *st,
firmware->o_ops->erase(x0, y0, x1, y1, attribute);
}
-void bios_showcursor(uint16_t cursor)
-{
- static com32sys_t ireg;
-
- ireg.eax.b[1] = 0x01;
- ireg.ecx.w[0] = cursor;
- __intcall(0x10, &ireg, NULL);
-}
-
/* Show or hide the cursor */
static void ansicon_showcursor(const struct term_state *st)
{
- uint16_t cursor = st->cursor ? cursor_type : 0x2020;
- firmware->o_ops->showcursor(cursor);
-}
-
-void bios_set_cursor(int x, int y, bool visible)
-{
- const int page = BIOS_PAGE;
- struct curxy xy = BIOS_CURXY[page];
- static com32sys_t ireg;
-
- (void)visible;
-
- if (xy.x != x || xy.y != y) {
- ireg.eax.b[1] = 0x02;
- ireg.ebx.b[1] = page;
- ireg.edx.b[1] = y;
- ireg.edx.b[0] = x;
- __intcall(0x10, &ireg, NULL);
- }
+ firmware->o_ops->showcursor(st);
}
static void ansicon_set_cursor(int x, int y, bool visible)
@@ -236,18 +158,6 @@ static void ansicon_set_cursor(int x, int y, bool visible)
firmware->o_ops->set_cursor(x, y, visible);
}
-void bios_write_char(uint8_t ch, uint8_t attribute)
-{
- static com32sys_t ireg;
-
- ireg.eax.b[1] = 0x09;
- ireg.eax.b[0] = ch;
- ireg.ebx.b[1] = BIOS_PAGE;
- ireg.ebx.b[0] = attribute;
- ireg.ecx.w[0] = 1;
- __intcall(0x10, &ireg, NULL);
-}
-
static void ansicon_write_char(int x, int y, uint8_t ch,
const struct term_state *st)
{
@@ -257,18 +167,6 @@ static void ansicon_write_char(int x, int y, uint8_t ch,
firmware->o_ops->write_char(ch, attribute);
}
-void bios_scroll_up(uint8_t cols, uint8_t rows, uint8_t attribute)
-{
- static com32sys_t ireg;
-
- ireg.eax.w[0] = 0x0601;
- ireg.ebx.b[1] = attribute;
- ireg.ecx.w[0] = 0;
- ireg.edx.b[1] = rows;
- ireg.edx.b[0] = cols;
- __intcall(0x10, &ireg, NULL); /* Scroll */
-}
-
static void ansicon_scroll_up(const struct term_state *st)
{
uint8_t rows, cols, attribute;
@@ -302,15 +200,6 @@ ssize_t __ansicon_write(struct file_info *fp, const void *buf, size_t count)
return n;
}
-void bios_beep(void)
-{
- static com32sys_t ireg;
-
- ireg.eax.w[0] = 0x0e07;
- ireg.ebx.b[1] = BIOS_PAGE;
- __intcall(0x10, &ireg, NULL);
-}
-
void __ansicon_beep(void)
{
if (firmware->o_ops->beep)
diff --git a/com32/lib/sys/fileclose.c b/com32/lib/sys/fileclose.c
index 26e15082..699dbe32 100644
--- a/com32/lib/sys/fileclose.c
+++ b/com32/lib/sys/fileclose.c
@@ -34,6 +34,7 @@
#include <errno.h>
#include <com32.h>
#include <string.h>
+#include <fs.h>
#include "file.h"
int __file_close(struct file_info *fp)
diff --git a/com32/lib/sys/fileread.c b/com32/lib/sys/fileread.c
index 7d9e1b91..26b0ceb6 100644
--- a/com32/lib/sys/fileread.c
+++ b/com32/lib/sys/fileread.c
@@ -34,6 +34,7 @@
#include <errno.h>
#include <string.h>
#include <com32.h>
+#include <pmapi.h>
#include <syslinux/pmapi.h>
#include <minmax.h>
#include "file.h"
diff --git a/com32/lib/sys/gpxe.c b/com32/lib/sys/gpxe.c
index d86da42a..3cc2b845 100644
--- a/com32/lib/sys/gpxe.c
+++ b/com32/lib/sys/gpxe.c
@@ -1,13 +1,15 @@
+#include <string.h>
+
#include <sys/gpxe.h>
#include <syslinux/config.h>
-#include <string.h>
+#include <syslinux/pxe_api.h>
bool is_gpxe(void)
{
const struct syslinux_version *sv;
- com32sys_t reg;
struct s_PXENV_FILE_CHECK_API *fca;
bool gpxe;
+ int err;
sv = syslinux_version();
if (sv->filesystem != SYSLINUX_FS_PXELINUX)
@@ -16,23 +18,18 @@ bool is_gpxe(void)
fca = lzalloc(sizeof *fca);
if (!fca)
return false;
+
fca->Size = sizeof *fca;
fca->Magic = 0x91d447b2;
- memset(&reg, 0, sizeof reg);
- reg.eax.w[0] = 0x0009;
- reg.ebx.w[0] = 0x00e6; /* PXENV_FILE_API_CHECK */
- /* reg.edi.w[0] = OFFS(fca); */
- reg.es = SEG(fca);
-
- __intcall(0x22, &reg, &reg);
+ err = pxe_call(PXENV_FILE_API_CHECK, fca);
gpxe = true;
- if (reg.eflags.l & EFLAGS_CF)
+ if (err)
gpxe = false; /* Cannot invoke PXE stack */
- if (reg.eax.w[0] || fca->Status)
+ if (fca->Status)
gpxe = false; /* PXE failure */
if (fca->Magic != 0xe9c17b20)
diff --git a/com32/lib/sys/module/common.c b/com32/lib/sys/module/common.c
index 1e33db8e..bc058a66 100644
--- a/com32/lib/sys/module/common.c
+++ b/com32/lib/sys/module/common.c
@@ -23,7 +23,7 @@ LIST_HEAD(modules_head);
// User-space debugging routines
#ifdef ELF_DEBUG
-void print_elf_ehdr(Elf32_Ehdr *ehdr) {
+void print_elf_ehdr(Elf_Ehdr *ehdr) {
int i;
fprintf(stderr, "Identification:\t");
@@ -38,18 +38,18 @@ void print_elf_ehdr(Elf32_Ehdr *ehdr) {
fprintf(stderr, "PHT Offset:\t0x%08x\n", ehdr->e_phoff);
fprintf(stderr, "SHT Offset:\t0x%08x\n", ehdr->e_shoff);
//fprintf(stderr, "Flags:\t\t%u\n", ehdr->e_flags);
- //fprintf(stderr, "Header size:\t%u (Structure size: %u)\n", ehdr->e_ehsize,sizeof(Elf32_Ehdr));
+ //fprintf(stderr, "Header size:\t%u (Structure size: %u)\n", ehdr->e_ehsize,sizeof(Elf_Ehdr));
fprintf(stderr, "phnum: %d shnum: %d\n", ehdr->e_phnum,
ehdr->e_shnum);
}
void print_elf_symbols(struct elf_module *module) {
unsigned int i;
- Elf32_Sym *crt_sym;
+ Elf_Sym *crt_sym;
for (i = 1; i < module->symtable_size; i++)
{
- crt_sym = (Elf32_Sym*)(module->sym_table + i*module->syment_size);
+ crt_sym = (Elf_Sym*)(module->sym_table + i*module->syment_size);
fprintf(stderr,"%s %d\n", module->str_table + crt_sym->st_name, crt_sym->st_value);
@@ -64,6 +64,10 @@ static FILE *findpath(char *name)
char *p, *n;
int i;
+ f = fopen(name, "rb"); /* for full path */
+ if (f)
+ return f;
+
p = PATH;
again:
i = 0;
@@ -74,15 +78,6 @@ again:
if (*p == ':')
p++;
- if (!strcmp(path, ".")) {
- if (!core_getcwd(path, sizeof(path))) {
- DBG_PRINT("Could not get cwd\n");
- return NULL;
- }
-
- i = strlen(path);
- }
-
n = name;
while (*n && i < FILENAME_MAX)
path[i++] = *n++;
@@ -164,7 +159,7 @@ int image_skip(size_t size, struct elf_module *module) {
return 0;
}
-int image_seek(Elf32_Off offset, struct elf_module *module) {
+int image_seek(Elf_Off offset, struct elf_module *module) {
if (offset < module->u.l._cr_offset) // Cannot seek backwards
return -1;
@@ -226,7 +221,7 @@ struct elf_module *module_find(const char *name) {
//
// Performs verifications on ELF header to assure that the open file is a
// valid SYSLINUX ELF module.
-int check_header_common(Elf32_Ehdr *elf_hdr) {
+int check_header_common(Elf_Ehdr *elf_hdr) {
// Check the header magic
if (elf_hdr->e_ident[EI_MAG0] != ELFMAG0 ||
elf_hdr->e_ident[EI_MAG1] != ELFMAG1 ||
@@ -237,7 +232,7 @@ int check_header_common(Elf32_Ehdr *elf_hdr) {
return -1;
}
- if (elf_hdr->e_ident[EI_CLASS] != ELFCLASS32 ||
+ if (elf_hdr->e_ident[EI_CLASS] != ELFCLASS32 &&
elf_hdr->e_ident[EI_CLASS] != ELFCLASS64) {
DBG_PRINT("Invalid ELF class code\n");
return -1;
@@ -254,15 +249,17 @@ int check_header_common(Elf32_Ehdr *elf_hdr) {
return -1;
}
- if (elf_hdr->e_machine != EM_386 ||
+ if (elf_hdr->e_machine != EM_386 &&
elf_hdr->e_machine != EM_X86_64) {
DBG_PRINT("Invalid ELF architecture\n");
return -1;
+ }
return 0;
}
+
int enforce_dependency(struct elf_module *req, struct elf_module *dep) {
struct module_dep *crt_dep;
struct module_dep *new_dep;
@@ -319,7 +316,7 @@ int clear_dependency(struct elf_module *req, struct elf_module *dep) {
int check_symbols(struct elf_module *module)
{
unsigned int i;
- Elf32_Sym *crt_sym = NULL, *ref_sym = NULL;
+ Elf_Sym *crt_sym = NULL, *ref_sym = NULL;
char *crt_name;
struct elf_module *crt_module;
@@ -328,11 +325,11 @@ int check_symbols(struct elf_module *module)
for(i = 1; i < module->symtable_size; i++)
{
- crt_sym = (Elf32_Sym*)(module->sym_table + i * module->syment_size);
+ crt_sym = symbol_get_entry(module, i);
crt_name = module->str_table + crt_sym->st_name;
strong_count = 0;
- weak_count = 0;
+ weak_count = (ELF32_ST_BIND(crt_sym->st_info) == STB_WEAK);
for_each_module(crt_module)
{
@@ -356,10 +353,17 @@ int check_symbols(struct elf_module *module)
if (crt_sym->st_shndx == SHN_UNDEF)
{
// We have an undefined symbol
+ //
+ // We use the weak_count to differentiate
+ // between Syslinux-derivative-specific
+ // functions. For example, unload_pxe() is
+ // only provided by PXELINUX, so we mark it as
+ // __weak and replace it with a reference to
+ // undefined_symbol() on SYSLINUX, EXTLINUX,
+ // and ISOLINUX. See perform_relocations().
if (strong_count == 0 && weak_count == 0)
{
DBG_PRINT("Symbol %s is undefined\n", crt_name);
- printf("Undef symbol FAIL: %s\n",crt_name);
return -1;
}
}
@@ -387,7 +391,7 @@ int module_unloadable(struct elf_module *module) {
// Unloads the module from the system and releases all the associated memory
-int module_unload(struct elf_module *module) {
+int _module_unload(struct elf_module *module) {
struct module_dep *crt_dep, *tmp;
// Make sure nobody needs us
if (!module_unloadable(module)) {
@@ -416,23 +420,31 @@ int module_unload(struct elf_module *module) {
return 0;
}
+int module_unload(struct elf_module *module) {
+ module_ctor_t *dtor;
+
+ for (dtor = module->dtors; *dtor; dtor++)
+ (*dtor) ();
+
+ return _module_unload(module);
+}
-static Elf32_Sym *module_find_symbol_sysv(const char *name, struct elf_module *module) {
+static Elf_Sym *module_find_symbol_sysv(const char *name, struct elf_module *module) {
unsigned long h = elf_hash((const unsigned char*)name);
- Elf32_Word *cr_word = module->hash_table;
+ Elf_Word *cr_word = module->hash_table;
- Elf32_Word nbucket = *cr_word++;
+ Elf_Word nbucket = *cr_word++;
cr_word++; // Skip nchain
- Elf32_Word *bkt = cr_word;
- Elf32_Word *chn = cr_word + nbucket;
+ Elf_Word *bkt = cr_word;
+ Elf_Word *chn = cr_word + nbucket;
- Elf32_Word crt_index = bkt[h % module->hash_table[0]];
- Elf32_Sym *crt_sym;
+ Elf_Word crt_index = bkt[h % module->hash_table[0]];
+ Elf_Sym *crt_sym;
while (crt_index != STN_UNDEF) {
- crt_sym = (Elf32_Sym*)(module->sym_table + crt_index*module->syment_size);
+ crt_sym = symbol_get_entry(module, crt_index);
if (strcmp(name, module->str_table + crt_sym->st_name) == 0)
return crt_sym;
@@ -443,32 +455,32 @@ static Elf32_Sym *module_find_symbol_sysv(const char *name, struct elf_module *m
return NULL;
}
-static Elf32_Sym *module_find_symbol_gnu(const char *name, struct elf_module *module) {
+static Elf_Sym *module_find_symbol_gnu(const char *name, struct elf_module *module) {
unsigned long h = elf_gnu_hash((const unsigned char*)name);
// Setup code (TODO: Optimize this by computing only once)
- Elf32_Word *cr_word = module->ghash_table;
- Elf32_Word nbucket = *cr_word++;
- Elf32_Word symbias = *cr_word++;
- Elf32_Word bitmask_nwords = *cr_word++;
+ Elf_Word *cr_word = module->ghash_table;
+ Elf_Word nbucket = *cr_word++;
+ Elf_Word symbias = *cr_word++;
+ Elf_Word bitmask_nwords = *cr_word++;
if ((bitmask_nwords & (bitmask_nwords - 1)) != 0) {
DBG_PRINT("Invalid GNU Hash structure\n");
return NULL;
}
- Elf32_Word gnu_shift = *cr_word++;
+ Elf_Word gnu_shift = *cr_word++;
- Elf32_Addr *gnu_bitmask = (Elf32_Addr*)cr_word;
+ Elf_Addr *gnu_bitmask = (Elf_Addr*)cr_word;
cr_word += MODULE_ELF_CLASS_SIZE / 32 * bitmask_nwords;
- Elf32_Word *gnu_buckets = cr_word;
+ Elf_Word *gnu_buckets = cr_word;
cr_word += nbucket;
- Elf32_Word *gnu_chain_zero = cr_word - symbias;
+ Elf_Word *gnu_chain_zero = cr_word - symbias;
// Computations
- Elf32_Word bitmask_word = gnu_bitmask[(h / MODULE_ELF_CLASS_SIZE) &
+ Elf_Bword bitmask_word = gnu_bitmask[(h / MODULE_ELF_CLASS_SIZE) &
(bitmask_nwords - 1)];
unsigned int hashbit1 = h & (MODULE_ELF_CLASS_SIZE - 1);
@@ -476,19 +488,18 @@ static Elf32_Sym *module_find_symbol_gnu(const char *name, struct elf_module *mo
if ((bitmask_word >> hashbit1) & (bitmask_word >> hashbit2) & 1) {
unsigned long rem;
- Elf32_Word bucket;
+ Elf_Word bucket;
rem = h % nbucket;
bucket = gnu_buckets[rem];
if (bucket != 0) {
- const Elf32_Word* hasharr = &gnu_chain_zero[bucket];
+ const Elf_Word* hasharr = &gnu_chain_zero[bucket];
do {
if (((*hasharr ^ h ) >> 1) == 0) {
- Elf32_Sym *crt_sym = (Elf32_Sym*)(module->sym_table +
- (hasharr - gnu_chain_zero) * module->syment_size);
+ Elf_Sym *crt_sym = symbol_get_entry(module, (hasharr - gnu_chain_zero));
if (strcmp(name, module->str_table + crt_sym->st_name) == 0) {
return crt_sym;
@@ -501,15 +512,15 @@ static Elf32_Sym *module_find_symbol_gnu(const char *name, struct elf_module *mo
return NULL;
}
-static Elf32_Sym *module_find_symbol_iterate(const char *name,struct elf_module *module)
+static Elf_Sym *module_find_symbol_iterate(const char *name,struct elf_module *module)
{
unsigned int i;
- Elf32_Sym *crt_sym;
+ Elf_Sym *crt_sym;
for (i=1; i < module->symtable_size; i++)
{
- crt_sym = (Elf32_Sym*)(module->sym_table + i*module->syment_size);
+ crt_sym = symbol_get_entry(module, i);
if (strcmp(name, module->str_table + crt_sym->st_name) == 0)
{
return crt_sym;
@@ -519,8 +530,8 @@ static Elf32_Sym *module_find_symbol_iterate(const char *name,struct elf_module
return NULL;
}
-Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module) {
- Elf32_Sym *result = NULL;
+Elf_Sym *module_find_symbol(const char *name, struct elf_module *module) {
+ Elf_Sym *result = NULL;
if (module->ghash_table != NULL)
result = module_find_symbol_gnu(name, module);
@@ -542,10 +553,10 @@ Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module) {
return result;
}
-Elf32_Sym *global_find_symbol(const char *name, struct elf_module **module) {
+Elf_Sym *global_find_symbol(const char *name, struct elf_module **module) {
struct elf_module *crt_module;
- Elf32_Sym *crt_sym = NULL;
- Elf32_Sym *result = NULL;
+ Elf_Sym *crt_sym = NULL;
+ Elf_Sym *result = NULL;
for_each_module(crt_module) {
crt_sym = module_find_symbol(name, crt_module);
diff --git a/com32/lib/sys/module/common.h b/com32/lib/sys/module/common.h
index 928fe139..652c9735 100644
--- a/com32/lib/sys/module/common.h
+++ b/com32/lib/sys/module/common.h
@@ -26,6 +26,14 @@
#define MIN(x,y) (((x) < (y)) ? (x) : (y))
#define MAX(x,y) (((x) > (y)) ? (x) : (y))
+static inline Elf_Sym *symbol_get_entry(struct elf_module *module, int entry)
+{
+ char *sym_table = (char *)module->sym_table;
+ int index = entry * module->syment_size;
+
+ return (Elf_Sym *)(sym_table + index);
+}
+
//#define ELF_DEBUG
#ifdef ELF_DEBUG
@@ -36,7 +44,7 @@
// User-space debugging routines
#ifdef ELF_DEBUG
-extern void print_elf_ehdr(Elf32_Ehdr *ehdr);
+extern void print_elf_ehdr(Elf_Ehdr *ehdr);
extern void print_elf_symbols(struct elf_module *module);
#endif //ELF_DEBUG
@@ -49,11 +57,11 @@ extern int image_load(struct elf_module *module);
extern int image_unload(struct elf_module *module);
extern int image_read(void *buff, size_t size, struct elf_module *module);
extern int image_skip(size_t size, struct elf_module *module);
-extern int image_seek(Elf32_Off offset, struct elf_module *module);
+extern int image_seek(Elf_Off offset, struct elf_module *module);
extern struct module_dep *module_dep_alloc(struct elf_module *module);
-extern int check_header_common(Elf32_Ehdr *elf_hdr);
+extern int check_header_common(Elf_Ehdr *elf_hdr);
extern int enforce_dependency(struct elf_module *req, struct elf_module *dep);
extern int clear_dependency(struct elf_module *req, struct elf_module *dep);
diff --git a/com32/lib/sys/module/elf_module.c b/com32/lib/sys/module/elf_module.c
index 7d8dad42..b220e1ad 100644
--- a/com32/lib/sys/module/elf_module.c
+++ b/com32/lib/sys/module/elf_module.c
@@ -5,21 +5,21 @@
* Author: Stefan Bucur <stefanb@zytor.com>
*/
-
+#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <elf.h>
#include <dprintf.h>
+#include <core.h>
#include <linux/list.h>
#include <sys/module.h>
+#include <sys/exec.h>
#include "elfutils.h"
#include "common.h"
-#define MAX_NR_DEPS 64
-
static int check_header(Elf32_Ehdr *elf_hdr) {
int res;
@@ -50,7 +50,7 @@ static int check_header(Elf32_Ehdr *elf_hdr) {
static int load_segments(struct elf_module *module, Elf32_Ehdr *elf_hdr) {
int i;
int res = 0;
- void *pht = NULL;
+ char *pht = NULL;
Elf32_Phdr *cr_pht;
Elf32_Addr min_addr = 0x00000000; // Min. ELF vaddr
@@ -136,8 +136,8 @@ static int load_segments(struct elf_module *module, Elf32_Ehdr *elf_hdr) {
// headers
Elf32_Off aux_off = module->u.l._cr_offset - cr_pht->p_offset;
- if (image_read(module_get_absolute(cr_pht->p_vaddr, module) + aux_off,
- cr_pht->p_filesz - aux_off, module) < 0) {
+ if (image_read((char *)module_get_absolute(cr_pht->p_vaddr, module) + aux_off,
+ cr_pht->p_filesz - aux_off, module) < 0) {
res = -1;
goto out;
}
@@ -180,9 +180,6 @@ out:
return res;
}
-static int nr_needed;
-static Elf32_Word needed[MAX_NR_DEPS];;
-
static int prepare_dynlinking(struct elf_module *module) {
Elf32_Dyn *dyn_entry = module->dyn_table;
@@ -195,8 +192,8 @@ static int prepare_dynlinking(struct elf_module *module) {
* are then inform the user that we ran out of
* space.
*/
- if (nr_needed < MAX_NR_DEPS)
- needed[nr_needed++] = dyn_entry->d_un.d_ptr;
+ if (module->nr_needed < MAX_NR_DEPS)
+ module->needed[module->nr_needed++] = dyn_entry->d_un.d_ptr;
else {
printf("Too many dependencies!\n");
return -1;
@@ -242,6 +239,11 @@ static int prepare_dynlinking(struct elf_module *module) {
return 0;
}
+void undefined_symbol(void)
+{
+ printf("Error: An undefined symbol was referenced\n");
+ kaboom();
+}
static int perform_relocation(struct elf_module *module, Elf32_Rel *rel) {
Elf32_Word *dest = module_get_absolute(rel->r_offset, module);
@@ -259,8 +261,7 @@ static int perform_relocation(struct elf_module *module, Elf32_Rel *rel) {
// Find out details about the symbol
// The symbol reference
- Elf32_Sym *sym_ref =
- (Elf32_Sym*)(module->sym_table + sym * module->syment_size);
+ Elf32_Sym *sym_ref = symbol_get_entry(module, sym);
// The symbol definition
sym_def =
@@ -268,11 +269,16 @@ static int perform_relocation(struct elf_module *module, Elf32_Rel *rel) {
&sym_module);
if (sym_def == NULL) {
- // This should never happen
DBG_PRINT("Cannot perform relocation for symbol %s\n",
module->str_table + sym_ref->st_name);
- return -1;
+ if (ELF32_ST_BIND(sym_ref->st_info) != STB_WEAK)
+ return -1;
+
+ // This must be a derivative-specific
+ // function. We're OK as long as we never
+ // execute the function.
+ sym_def = global_find_symbol("undefined_symbol", &sym_module);
}
// Compute the absolute symbol virtual address
@@ -321,9 +327,9 @@ static int resolve_symbols(struct elf_module *module) {
int res;
Elf32_Word plt_rel_size = 0;
- void *plt_rel = NULL;
+ char *plt_rel = NULL;
- void *rel = NULL;
+ char *rel = NULL;
Elf32_Word rel_size = 0;
Elf32_Word rel_entry = 0;
@@ -398,32 +404,70 @@ static int resolve_symbols(struct elf_module *module) {
return 0;
}
+static int extract_operations(struct elf_module *module) {
+ Elf32_Sym *ctors_start, *ctors_end;
+ Elf32_Sym *dtors_start, *dtors_end;
+ module_ctor_t *ctors = NULL;
+ module_ctor_t *dtors = NULL;
+ ctors_start = module_find_symbol("__ctors_start", module);
+ ctors_end = module_find_symbol("__ctors_end", module);
-static int extract_operations(struct elf_module *module) {
- Elf32_Sym *init_sym = module_find_symbol(MODULE_ELF_INIT_PTR, module);
- Elf32_Sym *exit_sym = module_find_symbol(MODULE_ELF_EXIT_PTR, module);
- Elf32_Sym *main_sym = module_find_symbol("main", module);
-
- if (init_sym) {
- module->init_func = (module_init_t*)module_get_absolute(
- init_sym->st_value, module);
- if (*(module->init_func) == NULL) {
- module->init_func = NULL;
+ if (ctors_start && ctors_end) {
+ module_ctor_t *start, *end;
+ int nr_ctors = 0;
+ int i, size;
+
+ start = module_get_absolute(ctors_start->st_value, module);
+ end = module_get_absolute(ctors_end->st_value, module);
+
+ nr_ctors = end - start;
+
+ size = nr_ctors * sizeof(module_ctor_t);
+ size += sizeof(module_ctor_t); /* NULL entry */
+
+ ctors = malloc(size);
+ if (!ctors) {
+ printf("Unable to alloc memory for ctors\n");
+ return -1;
}
+
+ memset(ctors, 0, size);
+ for (i = 0; i < nr_ctors; i++)
+ ctors[i] = start[i];
+
+ module->ctors = ctors;
}
- if (exit_sym) {
- module->exit_func = (module_exit_t*)module_get_absolute(
- exit_sym->st_value, module);
- if (*(module->exit_func) == NULL) {
- module->exit_func = NULL;
+ dtors_start = module_find_symbol("__dtors_start", module);
+ dtors_end = module_find_symbol("__dtors_end", module);
+
+ if (dtors_start && dtors_end) {
+ module_ctor_t *start, *end;
+ int nr_dtors = 0;
+ int i, size;
+
+ start = module_get_absolute(dtors_start->st_value, module);
+ end = module_get_absolute(dtors_end->st_value, module);
+
+ nr_dtors = end - start;
+
+ size = nr_dtors * sizeof(module_ctor_t);
+ size += sizeof(module_ctor_t); /* NULL entry */
+
+ dtors = malloc(size);
+ if (!dtors) {
+ printf("Unable to alloc memory for dtors\n");
+ free(ctors);
+ return -1;
}
- }
- if (main_sym)
- module->main_func =
- module_get_absolute(main_sym->st_value, module);
+ memset(dtors, 0, size);
+ for (i = 0; i < nr_dtors; i++)
+ dtors[i] = start[i];
+
+ module->dtors = dtors;
+ }
return 0;
}
@@ -431,12 +475,14 @@ static int extract_operations(struct elf_module *module) {
// Loads the module into the system
int module_load(struct elf_module *module) {
int res;
+ Elf32_Sym *main_sym;
Elf32_Ehdr elf_hdr;
+ module_ctor_t *ctor;
// Do not allow duplicate modules
if (module_find(module->name) != NULL) {
DBG_PRINT("Module %s is already loaded.\n", module->name);
- return -1;
+ return EEXIST;
}
// Get a mapping/copy of the ELF file in memory
@@ -462,42 +508,35 @@ int module_load(struct elf_module *module) {
CHECKED(res, load_segments(module, &elf_hdr), error);
//printf("bleah... 3\n");
// Obtain dynamic linking information
- nr_needed = 0;
CHECKED(res, prepare_dynlinking(module), error);
//printf("check... 4\n");
- //
- //dump_elf_module(module);
/* Find modules we need to load as dependencies */
if (module->str_table) {
- int i, n;
+ int i;
/*
- * nr_needed can be modified by recursive calls to
- * module_load() so keep a local copy on the stack.
+ * Note that we have to load the dependencies in
+ * reverse order.
*/
- n = nr_needed;
- for (i = 0; i < n; i++) {
- size_t len, j;
+ for (i = module->nr_needed - 1; i >= 0; i--) {
char *dep, *p;
+ char *argv[2] = { NULL, NULL };
- dep = module->str_table + needed[i];
+ dep = module->str_table + module->needed[i];
/* strip everything but the last component */
- j = len = strlen(dep);
- if (!len)
+ if (!strlen(dep))
continue;
- p = dep + len - 1;
- while (j > 0 && *p && *p != '/') {
- p--;
- j--;
- }
+ if (strchr(dep, '/')) {
+ p = strrchr(dep, '/');
+ p++;
+ } else
+ p = dep;
- if (*p++ == '/') {
- char argv[2] = { p, NULL };
- spawn_load(p, 1, argv);
- }
+ argv[0] = p;
+ spawn_load(p, 1, argv);
}
}
@@ -505,8 +544,11 @@ int module_load(struct elf_module *module) {
CHECKED(res, check_symbols(module), error);
//printf("check... 5\n");
- // Obtain constructors and destructors
- CHECKED(res, extract_operations(module), error);
+ main_sym = module_find_symbol("main", module);
+ if (main_sym)
+ module->main_func =
+ module_get_absolute(main_sym->st_value, module);
+
//printf("check... 6\n");
// Add the module at the beginning of the module list
@@ -515,6 +557,9 @@ int module_load(struct elf_module *module) {
// Perform the relocations
resolve_symbols(module);
+ // Obtain constructors and destructors
+ CHECKED(res, extract_operations(module), error);
+
//dprintf("module->symtable_size = %d\n", module->symtable_size);
//print_elf_symbols(module);
@@ -529,6 +574,10 @@ int module_load(struct elf_module *module) {
(module->init_func == NULL) ? NULL : *(module->init_func),
(module->exit_func == NULL) ? NULL : *(module->exit_func));
*/
+
+ for (ctor = module->ctors; *ctor; ctor++)
+ (*ctor) ();
+
return 0;
error:
diff --git a/com32/lib/sys/module/elfutils.c b/com32/lib/sys/module/elfutils.c
index 64be0770..b7d760b4 100644
--- a/com32/lib/sys/module/elfutils.c
+++ b/com32/lib/sys/module/elfutils.c
@@ -37,7 +37,7 @@ struct memalign_info {
};
int elf_malloc(void **memptr, size_t alignment, size_t size) {
- void *start_addr = NULL;
+ char *start_addr = NULL;
struct memalign_info *info;
if ((alignment & (alignment - 1)) != 0)
@@ -63,7 +63,7 @@ int elf_malloc(void **memptr, size_t alignment, size_t size) {
return 0;
}
-void elf_free(void *memptr) {
+void elf_free(char *memptr) {
struct memalign_info *info = (struct memalign_info*)(memptr -
sizeof(struct memalign_info));
diff --git a/com32/lib/sys/module/elfutils.h b/com32/lib/sys/module/elfutils.h
index b6750ae7..91bdcb3f 100644
--- a/com32/lib/sys/module/elfutils.h
+++ b/com32/lib/sys/module/elfutils.h
@@ -1,7 +1,65 @@
-#if __SIZEOF_POINTER__ == 4
-#include <i386/elfutils.h>
-#elif __SIZEOF_POINTER__ == 8
-#include <x86_64/elfutils.h>
-#else
-#error "unsupported architecture"
-#endif
+#ifndef ELF_UTILS_H_
+#define ELF_UTILS_H_
+
+#include <elf.h>
+#include <stdlib.h>
+#include <sys/module.h>
+
+/**
+ * elf_get_header - Returns a pointer to the ELF header structure.
+ * @elf_image: pointer to the ELF file image in memory
+ */
+static inline Elf_Ehdr *elf_get_header(void *elf_image) {
+ return (Elf_Ehdr*)elf_image;
+}
+
+/**
+ * elf_get_pht - Returns a pointer to the first entry in the PHT.
+ * @elf_image: pointer to the ELF file image in memory
+ */
+static inline Elf_Phdr *elf_get_pht(void *elf_image) {
+ Elf_Ehdr *elf_hdr = elf_get_header(elf_image);
+
+ return (Elf_Phdr*)((Elf_Off)elf_hdr + elf_hdr->e_phoff);
+}
+
+//
+/**
+ * elf_get_ph - Returns the element with the given index in the PTH
+ * @elf_image: pointer to the ELF file image in memory
+ * @index: the index of the PHT entry to look for
+ */
+static inline Elf_Phdr *elf_get_ph(void *elf_image, int index) {
+ Elf_Phdr *elf_pht = elf_get_pht(elf_image);
+ Elf_Ehdr *elf_hdr = elf_get_header(elf_image);
+
+ return (Elf_Phdr*)((Elf_Off)elf_pht + index * elf_hdr->e_phentsize);
+}
+
+/**
+ * elf_hash - Returns the index in a SysV hash table for the symbol name.
+ * @name: the name of the symbol to look for
+ */
+extern unsigned long elf_hash(const unsigned char *name);
+
+/**
+ * elf_gnu_hash - Returns the index in a GNU hash table for the symbol name.
+ * @name: the name of the symbol to look for
+ */
+extern unsigned long elf_gnu_hash(const unsigned char *name);
+
+/**
+ * elf_malloc - Allocates memory to be used by ELF module contents.
+ * @memptr: pointer to a variable to hold the address of the allocated block.
+ * @alignment: alignment constraints of the block
+ * @size: the required size of the block
+ */
+extern int elf_malloc(void **memptr, size_t alignment, size_t size);
+
+/**
+ * elf_free - Releases memory previously allocated by elf_malloc.
+ * @memptr: the address of the allocated block
+ */
+extern void elf_free(char *memptr);
+
+#endif /*ELF_UTILS_H_*/
diff --git a/com32/lib/sys/module/exec.c b/com32/lib/sys/module/exec.c
index 71d31929..29d0a2fd 100644
--- a/com32/lib/sys/module/exec.c
+++ b/com32/lib/sys/module/exec.c
@@ -47,64 +47,7 @@ int exec_init(void)
int get_module_type(struct elf_module *module)
{
if(module->main_func) return EXEC_MODULE;
- else if(module->init_func) return LIB_MODULE;
- return UNKNOWN_MODULE;
-}
-
-int load_library(const char *name)
-{
- int res;
- struct elf_module *module = module_alloc(name);
-
- if (module == NULL)
- return -1;
-
- res = module_load(module);
- if (res != 0) {
- module_unload(module);
- return res;
- }
-
- if (module->main_func != NULL) {
- DBG_PRINT("Cannot load executable module as library.\n");
- module_unload(module);
- return -1;
- }
-
- if (module->init_func != NULL) {
- res = (*(module->init_func))();
- if (res)
- DBG_PRINT("Initialization error! function returned: %d\n", res);
- } else {
- DBG_PRINT("No initialization function present.\n");
- }
-
- if (res != 0) {
- module_unload(module);
- return res;
- }
-
- return 0;
-}
-
-int unload_library(const char *name)
-{
- int res;
- struct elf_module *module = module_find(name);
-
- if (module == NULL)
- return -1;
-
- if (!module_unloadable(module)) {
- return -1;
- }
-
- if (module->exit_func != NULL) {
- (*(module->exit_func))();
- }
-
- res = module_unload(module);
- return res;
+ return LIB_MODULE;
}
jmp_buf __process_exit_jmp;
@@ -243,7 +186,6 @@ int spawn_load(const char *name, int argc, char **argv)
//malloc_tag_t prev_mem_tag;
struct elf_module *module = module_alloc(name);
struct elf_module *prev_module;
-
int type;
dprintf("enter: name = %s", name);
@@ -277,7 +219,7 @@ int spawn_load(const char *name, int argc, char **argv)
res = module_load(module);
if (res != 0) {
- module_unload(module);
+ _module_unload(module);
return res;
}
@@ -288,23 +230,7 @@ int spawn_load(const char *name, int argc, char **argv)
dprintf("type = %d, prev = %s, cur = %s",
type, prev_module->name, cur_module->name);
- if(type==LIB_MODULE)
- {
- if (module->init_func != NULL) {
- res = (*(module->init_func))();
- DBG_PRINT("Initialization function returned: %d\n", res);
- } else {
- DBG_PRINT("No initialization function present.\n");
- }
-
- if (res != 0) {
- cur_module = prev_module;
- module_unload(module);
- return res;
- }
- return 0;
- }
- else if(type==EXEC_MODULE)
+ if(type==EXEC_MODULE)
{
previous = __syslinux_current;
//prev_mem_tag = __mem_get_tag_global();
@@ -323,7 +249,6 @@ int spawn_load(const char *name, int argc, char **argv)
else
exit((module->main_func)(argc, argv)); /* Actually run! */
-
// Clean up the allocation context
//__free_tagged(module);
// Restore the allocation context
@@ -340,10 +265,8 @@ int spawn_load(const char *name, int argc, char **argv)
return ((unsigned int)ret_val & 0xFF);
}
- /*
- module_unload(module);
- return -1;
- */
+
+ return 0;
}
void exec_term(void)
diff --git a/com32/lib/sys/module/i386/common.c b/com32/lib/sys/module/i386/common.c
deleted file mode 100644
index 41e71e83..00000000
--- a/com32/lib/sys/module/i386/common.c
+++ /dev/null
@@ -1,571 +0,0 @@
-/*
- * common.c
- *
- * Created on: Aug 11, 2008
- * Author: Stefan Bucur <stefanb@zytor.com>
- */
-
-#include <stdio.h>
-#include <elf.h>
-#include <string.h>
-#include <fs.h>
-
-#include <linux/list.h>
-#include <sys/module.h>
-
-#include "elfutils.h"
-#include "common.h"
-
-/**
- * The one and only list of loaded modules
- */
-LIST_HEAD(modules_head);
-
-// User-space debugging routines
-#ifdef ELF_DEBUG
-void print_elf_ehdr(Elf32_Ehdr *ehdr) {
- int i;
-
- fprintf(stderr, "Identification:\t");
- for (i=0; i < EI_NIDENT; i++) {
- printf("%d ", ehdr->e_ident[i]);
- }
- fprintf(stderr, "\n");
- fprintf(stderr, "Type:\t\t%u\n", ehdr->e_type);
- fprintf(stderr, "Machine:\t%u\n", ehdr->e_machine);
- fprintf(stderr, "Version:\t%u\n", ehdr->e_version);
- fprintf(stderr, "Entry:\t\t0x%08x\n", ehdr->e_entry);
- fprintf(stderr, "PHT Offset:\t0x%08x\n", ehdr->e_phoff);
- fprintf(stderr, "SHT Offset:\t0x%08x\n", ehdr->e_shoff);
- //fprintf(stderr, "Flags:\t\t%u\n", ehdr->e_flags);
- //fprintf(stderr, "Header size:\t%u (Structure size: %u)\n", ehdr->e_ehsize,sizeof(Elf32_Ehdr));
- fprintf(stderr, "phnum: %d shnum: %d\n", ehdr->e_phnum,
- ehdr->e_shnum);
-}
-
-void print_elf_symbols(struct elf_module *module) {
- unsigned int i;
- Elf32_Sym *crt_sym;
-
- for (i = 1; i < module->symtable_size; i++)
- {
- crt_sym = (Elf32_Sym*)(module->sym_table + i*module->syment_size);
-
- fprintf(stderr,"%s %d\n", module->str_table + crt_sym->st_name, crt_sym->st_value);
-
- }
-}
-#endif //ELF_DEBUG
-
-static FILE *findpath(char *name)
-{
- char path[FILENAME_MAX];
- FILE *f;
- char *p, *n;
- int i;
-
- p = PATH;
-again:
- memset(path, '\0', sizeof(path));
- i = 0;
- while (*p && *p != ':' && i < FILENAME_MAX) {
- path[i++] = *p++;
- }
- //path[i] = '\0'; // without null the strcmp will fail
-
- if (*p == ':')
- p++;
-
- if (!strcmp(path, ".")) {
- if (!core_getcwd(path, sizeof(path))) {
- DBG_PRINT("Could not get cwd\n");
- return NULL;
- }
- i = strlen(path);
- }
-
- n = name;
- while (*n && i < FILENAME_MAX)
- path[i++] = *n++;
- path[i] = '\0';
-
- f = fopen(path, "rb");
- if (f)
- return f;
-
- if (p >= PATH && p < PATH + strlen(PATH))
- goto again;
-
- return NULL;
-}
-
-/*
- * Image files manipulation routines
- */
-
-int image_load(struct elf_module *module)
-{
- module->u.l._file = findpath(module->name);
-
- if (module->u.l._file == NULL) {
- DBG_PRINT("Could not open object file '%s'\n", module->name);
- goto error;
- }
-
- module->u.l._cr_offset = 0;
-
- return 0;
-
-error:
- if (module->u.l._file != NULL) {
- fclose(module->u.l._file);
- module->u.l._file = NULL;
- }
-
- return -1;
-}
-
-
-int image_unload(struct elf_module *module) {
- if (module->u.l._file != NULL) {
- fclose(module->u.l._file);
- module->u.l._file = NULL;
-
- }
- module->u.l._cr_offset = 0;
-
- return 0;
-}
-
-int image_read(void *buff, size_t size, struct elf_module *module) {
- size_t result = fread(buff, size, 1, module->u.l._file);
-
- if (result < 1)
- return -1;
-
- module->u.l._cr_offset += size;
- return 0;
-}
-
-int image_skip(size_t size, struct elf_module *module) {
- void *skip_buff = NULL;
- size_t result;
-
- if (size == 0)
- return 0;
-
- skip_buff = malloc(size);
- result = fread(skip_buff, size, 1, module->u.l._file);
- free(skip_buff);
-
- if (result < 1)
- return -1;
-
- module->u.l._cr_offset += size;
- return 0;
-}
-
-int image_seek(Elf32_Off offset, struct elf_module *module) {
- if (offset < module->u.l._cr_offset) // Cannot seek backwards
- return -1;
-
- return image_skip(offset - module->u.l._cr_offset, module);
-}
-
-
-// Initialization of the module subsystem
-int modules_init(void) {
- return 0;
-}
-
-// Termination of the module subsystem
-void modules_term(void) {
-
-}
-
-// Allocates the structure for a new module
-struct elf_module *module_alloc(const char *name) {
- struct elf_module *result = malloc(sizeof(struct elf_module));
-
- memset(result, 0, sizeof(struct elf_module));
-
- INIT_LIST_HEAD(&result->list);
- INIT_LIST_HEAD(&result->required);
- INIT_LIST_HEAD(&result->dependants);
-
- strncpy(result->name, name, MODULE_NAME_SIZE);
-
- return result;
-}
-
-struct module_dep *module_dep_alloc(struct elf_module *module) {
- struct module_dep *result = malloc(sizeof(struct module_dep));
-
- INIT_LIST_HEAD (&result->list);
-
- result->module = module;
-
- return result;
-}
-
-struct elf_module *module_find(const char *name) {
- struct elf_module *cr_module;
-
- for_each_module(cr_module) {
- if (strcmp(cr_module->name, name) == 0)
- return cr_module;
- }
-
- return NULL;
-}
-
-
-// Performs verifications on ELF header to assure that the open file is a
-// valid SYSLINUX ELF module.
-int check_header_common(Elf32_Ehdr *elf_hdr) {
- // Check the header magic
- if (elf_hdr->e_ident[EI_MAG0] != ELFMAG0 ||
- elf_hdr->e_ident[EI_MAG1] != ELFMAG1 ||
- elf_hdr->e_ident[EI_MAG2] != ELFMAG2 ||
- elf_hdr->e_ident[EI_MAG3] != ELFMAG3) {
-
- DBG_PRINT("The file is not an ELF object\n");
- return -1;
- }
-
- if (elf_hdr->e_ident[EI_CLASS] != MODULE_ELF_CLASS) {
- DBG_PRINT("Invalid ELF class code\n");
- return -1;
- }
-
- if (elf_hdr->e_ident[EI_DATA] != MODULE_ELF_DATA) {
- DBG_PRINT("Invalid ELF data encoding\n");
- return -1;
- }
-
- if (elf_hdr->e_ident[EI_VERSION] != MODULE_ELF_VERSION ||
- elf_hdr->e_version != MODULE_ELF_VERSION) {
- DBG_PRINT("Invalid ELF file version\n");
- return -1;
- }
-
- if (elf_hdr->e_machine != MODULE_ELF_MACHINE) {
- DBG_PRINT("Invalid ELF architecture\n");
- return -1;
- }
-
- return 0;
-}
-
-
-int enforce_dependency(struct elf_module *req, struct elf_module *dep) {
- struct module_dep *crt_dep;
- struct module_dep *new_dep;
-
- list_for_each_entry(crt_dep, &req->dependants, list) {
- if (crt_dep->module == dep) {
- // The dependency is already enforced
- return 0;
- }
- }
-
- new_dep = module_dep_alloc(req);
- list_add(&new_dep->list, &dep->required);
-
- new_dep = module_dep_alloc(dep);
- list_add(&new_dep->list, &req->dependants);
-
- return 0;
-}
-
-int clear_dependency(struct elf_module *req, struct elf_module *dep) {
- struct module_dep *crt_dep = NULL;
- int found = 0;
-
- list_for_each_entry(crt_dep, &req->dependants, list) {
- if (crt_dep->module == dep) {
- found = 1;
- break;
- }
- }
-
- if (found) {
- list_del(&crt_dep->list);
- free(crt_dep);
- }
-
- found = 0;
-
- list_for_each_entry(crt_dep, &dep->required, list) {
- if (crt_dep->module == req) {
- found = 1;
- break;
- }
- }
-
- if (found) {
- list_del(&crt_dep->list);
- free(crt_dep);
- }
-
- return 0;
-}
-
-int check_symbols(struct elf_module *module)
-{
- unsigned int i;
- Elf32_Sym *crt_sym = NULL, *ref_sym = NULL;
- char *crt_name;
- struct elf_module *crt_module;
-
- int strong_count;
- int weak_count;
-
- for(i = 1; i < module->symtable_size; i++)
- {
- crt_sym = (Elf32_Sym*)(module->sym_table + i * module->syment_size);
- crt_name = module->str_table + crt_sym->st_name;
-
- strong_count = 0;
- weak_count = 0;
-
- for_each_module(crt_module)
- {
- ref_sym = module_find_symbol(crt_name, crt_module);
-
- // If we found a definition for our symbol...
- if (ref_sym != NULL && ref_sym->st_shndx != SHN_UNDEF)
- {
- switch (ELF32_ST_BIND(ref_sym->st_info))
- {
- case STB_GLOBAL:
- strong_count++;
- break;
- case STB_WEAK:
- weak_count++;
- break;
- }
- }
- }
-
- if (crt_sym->st_shndx == SHN_UNDEF)
- {
- // We have an undefined symbol
- if (strong_count == 0 && weak_count == 0)
- {
- DBG_PRINT("Symbol %s is undefined\n", crt_name);
- //printf("Undef symbol FAIL: %s\n",crt_name);
- return -1;
- }
- }
- else
- {
- if (strong_count > 0 && ELF32_ST_BIND(ref_sym->st_info) == STB_GLOBAL)
- {
- // It's not an error - at relocation, the most recent symbol
- // will be considered
- DBG_PRINT("Info: Symbol %s is defined more than once\n", crt_name);
- }
- }
- //printf("symbol %s laoded from %d\n",crt_name,crt_sym->st_value);
- }
-
- return 0;
-}
-
-int module_unloadable(struct elf_module *module) {
- if (!list_empty(&module->dependants))
- return 0;
-
- return 1;
-}
-
-
-// Unloads the module from the system and releases all the associated memory
-int module_unload(struct elf_module *module) {
- struct module_dep *crt_dep, *tmp;
- // Make sure nobody needs us
- if (!module_unloadable(module)) {
- DBG_PRINT("Module is required by other modules.\n");
- return -1;
- }
-
- // Remove any dependency information
- list_for_each_entry_safe(crt_dep, tmp, &module->required, list) {
- clear_dependency(crt_dep->module, module);
- }
-
- // Remove the module from the module list
- list_del_init(&module->list);
-
- // Release the loaded segments or sections
- if (module->module_addr != NULL) {
- elf_free(module->module_addr);
-
- DBG_PRINT("%s MODULE %s UNLOADED\n", module->shallow ? "SHALLOW" : "",
- module->name);
- }
- // Release the module structure
- free(module);
-
- return 0;
-}
-
-
-static Elf32_Sym *module_find_symbol_sysv(const char *name, struct elf_module *module) {
- unsigned long h = elf_hash((const unsigned char*)name);
- Elf32_Word *cr_word = module->hash_table;
-
- Elf32_Word nbucket = *cr_word++;
- cr_word++; // Skip nchain
-
- Elf32_Word *bkt = cr_word;
- Elf32_Word *chn = cr_word + nbucket;
-
- Elf32_Word crt_index = bkt[h % module->hash_table[0]];
- Elf32_Sym *crt_sym;
-
-
- while (crt_index != STN_UNDEF) {
- crt_sym = (Elf32_Sym*)(module->sym_table + crt_index*module->syment_size);
-
- if (strcmp(name, module->str_table + crt_sym->st_name) == 0)
- return crt_sym;
-
- crt_index = chn[crt_index];
- }
-
- return NULL;
-}
-
-static Elf32_Sym *module_find_symbol_gnu(const char *name, struct elf_module *module) {
- unsigned long h = elf_gnu_hash((const unsigned char*)name);
-
- // Setup code (TODO: Optimize this by computing only once)
- Elf32_Word *cr_word = module->ghash_table;
- Elf32_Word nbucket = *cr_word++;
- Elf32_Word symbias = *cr_word++;
- Elf32_Word bitmask_nwords = *cr_word++;
-
-
- if ((bitmask_nwords & (bitmask_nwords - 1)) != 0) {
- DBG_PRINT("Invalid GNU Hash structure\n");
- return NULL;
- }
-
- Elf32_Word gnu_shift = *cr_word++;
-
- Elf32_Addr *gnu_bitmask = (Elf32_Addr*)cr_word;
- cr_word += MODULE_ELF_CLASS_SIZE / 32 * bitmask_nwords;
-
- Elf32_Word *gnu_buckets = cr_word;
- cr_word += nbucket;
-
- Elf32_Word *gnu_chain_zero = cr_word - symbias;
-
- // Computations
- Elf32_Word bitmask_word = gnu_bitmask[(h / MODULE_ELF_CLASS_SIZE) &
- (bitmask_nwords - 1)];
-
- unsigned int hashbit1 = h & (MODULE_ELF_CLASS_SIZE - 1);
- unsigned int hashbit2 = (h >> gnu_shift) & (MODULE_ELF_CLASS_SIZE - 1);
-
- if ((bitmask_word >> hashbit1) & (bitmask_word >> hashbit2) & 1) {
- unsigned long rem;
- Elf32_Word bucket;
-
- rem = h % nbucket;
-
- bucket = gnu_buckets[rem];
-
- if (bucket != 0) {
- const Elf32_Word* hasharr = &gnu_chain_zero[bucket];
-
- do {
- if (((*hasharr ^ h ) >> 1) == 0) {
- Elf32_Sym *crt_sym = (Elf32_Sym*)(module->sym_table +
- (hasharr - gnu_chain_zero) * module->syment_size);
-
- if (strcmp(name, module->str_table + crt_sym->st_name) == 0) {
- return crt_sym;
- }
- }
- } while ((*hasharr++ & 1u) == 0);
- }
- }
-
- return NULL;
-}
-
-static Elf32_Sym *module_find_symbol_iterate(const char *name,struct elf_module *module)
-{
-
- unsigned int i;
- Elf32_Sym *crt_sym;
-
- for (i=1; i < module->symtable_size; i++)
- {
- crt_sym = (Elf32_Sym*)(module->sym_table + i*module->syment_size);
- if (strcmp(name, module->str_table + crt_sym->st_name) == 0)
- {
- return crt_sym;
- }
- }
-
- return NULL;
-}
-
-Elf32_Sym *module_find_symbol(const char *name, struct elf_module *module) {
- Elf32_Sym *result = NULL;
-
-
- if (module->ghash_table != NULL)
- result = module_find_symbol_gnu(name, module);
-
- if (result == NULL)
- {
- if (module->hash_table != NULL)
- {
- //printf("Attempting SYSV Symbol search\n");
- result = module_find_symbol_sysv(name, module);
- }
- else
- {
- //printf("Attempting Iterative Symbol search\n");
- result = module_find_symbol_iterate(name, module);
- }
- }
-
- return result;
-}
-
-Elf32_Sym *global_find_symbol(const char *name, struct elf_module **module) {
- struct elf_module *crt_module;
- Elf32_Sym *crt_sym = NULL;
- Elf32_Sym *result = NULL;
-
- for_each_module(crt_module) {
- crt_sym = module_find_symbol(name, crt_module);
-
- if (crt_sym != NULL && crt_sym->st_shndx != SHN_UNDEF) {
- switch (ELF32_ST_BIND(crt_sym->st_info)) {
- case STB_GLOBAL:
- if (module != NULL) {
- *module = crt_module;
- }
- return crt_sym;
- case STB_WEAK:
- // Consider only the first weak symbol
- if (result == NULL) {
- if (module != NULL) {
- *module = crt_module;
- }
- result = crt_sym;
- }
- break;
- }
- }
- }
-
- return result;
-}
diff --git a/com32/lib/sys/module/i386/elf_module.c b/com32/lib/sys/module/i386/elf_module.c
index 864344a7..f4a8618a 100644
--- a/com32/lib/sys/module/i386/elf_module.c
+++ b/com32/lib/sys/module/i386/elf_module.c
@@ -5,20 +5,20 @@
* Author: Stefan Bucur <stefanb@zytor.com>
*/
-
+#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <elf.h>
#include <dprintf.h>
+#include <core.h>
#include <linux/list.h>
#include <sys/module.h>
+#include <sys/exec.h>
#include "elfutils.h"
-#include "common.h"
-
-#define MAX_NR_DEPS 64
+#include "../common.h"
static int check_header(Elf32_Ehdr *elf_hdr) {
int res;
@@ -50,7 +50,7 @@ static int check_header(Elf32_Ehdr *elf_hdr) {
static int load_segments(struct elf_module *module, Elf32_Ehdr *elf_hdr) {
int i;
int res = 0;
- void *pht = NULL;
+ char *pht = NULL;
Elf32_Phdr *cr_pht;
Elf32_Addr min_addr = 0x00000000; // Min. ELF vaddr
@@ -136,8 +136,8 @@ static int load_segments(struct elf_module *module, Elf32_Ehdr *elf_hdr) {
// headers
Elf32_Off aux_off = module->u.l._cr_offset - cr_pht->p_offset;
- if (image_read(module_get_absolute(cr_pht->p_vaddr, module) + aux_off,
- cr_pht->p_filesz - aux_off, module) < 0) {
+ if (image_read((char *)module_get_absolute(cr_pht->p_vaddr, module) + aux_off,
+ cr_pht->p_filesz - aux_off, module) < 0) {
res = -1;
goto out;
}
@@ -180,9 +180,6 @@ out:
return res;
}
-static int nr_needed;
-static Elf32_Word needed[MAX_NR_DEPS];;
-
static int prepare_dynlinking(struct elf_module *module) {
Elf32_Dyn *dyn_entry = module->dyn_table;
@@ -195,8 +192,8 @@ static int prepare_dynlinking(struct elf_module *module) {
* are then inform the user that we ran out of
* space.
*/
- if (nr_needed < MAX_NR_DEPS)
- needed[nr_needed++] = dyn_entry->d_un.d_ptr;
+ if (module->nr_needed < MAX_NR_DEPS)
+ module->needed[module->nr_needed++] = dyn_entry->d_un.d_ptr;
else {
printf("Too many dependencies!\n");
return -1;
@@ -242,6 +239,11 @@ static int prepare_dynlinking(struct elf_module *module) {
return 0;
}
+void undefined_symbol(void)
+{
+ printf("Error: An undefined symbol was referenced\n");
+ kaboom();
+}
static int perform_relocation(struct elf_module *module, Elf32_Rel *rel) {
Elf32_Word *dest = module_get_absolute(rel->r_offset, module);
@@ -259,8 +261,7 @@ static int perform_relocation(struct elf_module *module, Elf32_Rel *rel) {
// Find out details about the symbol
// The symbol reference
- Elf32_Sym *sym_ref =
- (Elf32_Sym*)(module->sym_table + sym * module->syment_size);
+ Elf32_Sym *sym_ref = symbol_get_entry(module, sym);
// The symbol definition
sym_def =
@@ -268,15 +269,16 @@ static int perform_relocation(struct elf_module *module, Elf32_Rel *rel) {
&sym_module);
if (sym_def == NULL) {
- // This should never happen
DBG_PRINT("Cannot perform relocation for symbol %s\n",
module->str_table + sym_ref->st_name);
- /*
- printf("Cannot perform relocation for symbol %s\n",
- module->str_table + sym_ref->st_name);
- */
- return -1;
+ if (ELF32_ST_BIND(sym_ref->st_info) != STB_WEAK)
+ return -1;
+
+ // This must be a derivative-specific
+ // function. We're OK as long as we never
+ // execute the function.
+ sym_def = global_find_symbol("undefined_symbol", &sym_module);
}
// Compute the absolute symbol virtual address
@@ -325,9 +327,9 @@ static int resolve_symbols(struct elf_module *module) {
int res;
Elf32_Word plt_rel_size = 0;
- void *plt_rel = NULL;
+ char *plt_rel = NULL;
- void *rel = NULL;
+ char *rel = NULL;
Elf32_Word rel_size = 0;
Elf32_Word rel_entry = 0;
@@ -346,7 +348,6 @@ static int resolve_symbols(struct elf_module *module) {
DBG_PRINT("Unsupported PLT relocation\n");
return -1;
}
- //break; // mouli: wasn't there before
case DT_JMPREL:
plt_rel = module_get_absolute(dyn_entry->d_un.d_ptr, module);
break;
@@ -403,32 +404,70 @@ static int resolve_symbols(struct elf_module *module) {
return 0;
}
+static int extract_operations(struct elf_module *module) {
+ Elf32_Sym *ctors_start, *ctors_end;
+ Elf32_Sym *dtors_start, *dtors_end;
+ module_ctor_t *ctors = NULL;
+ module_ctor_t *dtors = NULL;
+ ctors_start = module_find_symbol("__ctors_start", module);
+ ctors_end = module_find_symbol("__ctors_end", module);
-static int extract_operations(struct elf_module *module) {
- Elf32_Sym *init_sym = module_find_symbol(MODULE_ELF_INIT_PTR, module);
- Elf32_Sym *exit_sym = module_find_symbol(MODULE_ELF_EXIT_PTR, module);
- Elf32_Sym *main_sym = module_find_symbol("main", module);
-
- if (init_sym) {
- module->init_func = (module_init_t*)module_get_absolute(
- init_sym->st_value, module);
- if (*(module->init_func) == NULL) {
- module->init_func = NULL;
+ if (ctors_start && ctors_end) {
+ module_ctor_t *start, *end;
+ int nr_ctors = 0;
+ int i, size;
+
+ start = module_get_absolute(ctors_start->st_value, module);
+ end = module_get_absolute(ctors_end->st_value, module);
+
+ nr_ctors = end - start;
+
+ size = nr_ctors * sizeof(module_ctor_t);
+ size += sizeof(module_ctor_t); /* NULL entry */
+
+ ctors = malloc(size);
+ if (!ctors) {
+ printf("Unable to alloc memory for ctors\n");
+ return -1;
}
+
+ memset(ctors, 0, size);
+ for (i = 0; i < nr_ctors; i++)
+ ctors[i] = start[i];
+
+ module->ctors = ctors;
}
- if (exit_sym) {
- module->exit_func = (module_exit_t*)module_get_absolute(
- exit_sym->st_value, module);
- if (*(module->exit_func) == NULL) {
- module->exit_func = NULL;
+ dtors_start = module_find_symbol("__dtors_start", module);
+ dtors_end = module_find_symbol("__dtors_end", module);
+
+ if (dtors_start && dtors_end) {
+ module_ctor_t *start, *end;
+ int nr_dtors = 0;
+ int i, size;
+
+ start = module_get_absolute(dtors_start->st_value, module);
+ end = module_get_absolute(dtors_end->st_value, module);
+
+ nr_dtors = end - start;
+
+ size = nr_dtors * sizeof(module_ctor_t);
+ size += sizeof(module_ctor_t); /* NULL entry */
+
+ dtors = malloc(size);
+ if (!dtors) {
+ printf("Unable to alloc memory for dtors\n");
+ free(ctors);
+ return -1;
}
- }
- if (main_sym)
- module->main_func =
- module_get_absolute(main_sym->st_value, module);
+ memset(dtors, 0, size);
+ for (i = 0; i < nr_dtors; i++)
+ dtors[i] = start[i];
+
+ module->dtors = dtors;
+ }
return 0;
}
@@ -436,12 +475,14 @@ static int extract_operations(struct elf_module *module) {
// Loads the module into the system
int module_load(struct elf_module *module) {
int res;
+ Elf32_Sym *main_sym;
Elf32_Ehdr elf_hdr;
+ module_ctor_t *ctor;
// Do not allow duplicate modules
if (module_find(module->name) != NULL) {
DBG_PRINT("Module %s is already loaded.\n", module->name);
- return -1;
+ return EEXIST;
}
// Get a mapping/copy of the ELF file in memory
@@ -467,42 +508,35 @@ int module_load(struct elf_module *module) {
CHECKED(res, load_segments(module, &elf_hdr), error);
//printf("bleah... 3\n");
// Obtain dynamic linking information
- nr_needed = 0;
CHECKED(res, prepare_dynlinking(module), error);
//printf("check... 4\n");
- //
- //dump_elf_module(module);
/* Find modules we need to load as dependencies */
if (module->str_table) {
- int i, n;
+ int i;
/*
- * nr_needed can be modified by recursive calls to
- * module_load() so keep a local copy on the stack.
+ * Note that we have to load the dependencies in
+ * reverse order.
*/
- n = nr_needed;
- for (i = 0; i < n; i++) {
- size_t len, j;
+ for (i = module->nr_needed - 1; i >= 0; i--) {
char *dep, *p;
+ char *argv[2] = { NULL, NULL };
- dep = module->str_table + needed[i];
+ dep = module->str_table + module->needed[i];
/* strip everything but the last component */
- j = len = strlen(dep);
- if (!len)
+ if (!strlen(dep))
continue;
- p = dep + len - 1;
- while (j > 0 && *p && *p != '/') {
- p--;
- j--;
- }
+ if (strchr(dep, '/')) {
+ p = strrchr(dep, '/');
+ p++;
+ } else
+ p = dep;
- if (*p++ == '/') {
- char argv[2] = { p, NULL };
- spawn_load(p, 1, argv);
- }
+ argv[0] = p;
+ spawn_load(p, 1, argv);
}
}
@@ -510,8 +544,11 @@ int module_load(struct elf_module *module) {
CHECKED(res, check_symbols(module), error);
//printf("check... 5\n");
- // Obtain constructors and destructors
- CHECKED(res, extract_operations(module), error);
+ main_sym = module_find_symbol("main", module);
+ if (main_sym)
+ module->main_func =
+ module_get_absolute(main_sym->st_value, module);
+
//printf("check... 6\n");
// Add the module at the beginning of the module list
@@ -520,6 +557,9 @@ int module_load(struct elf_module *module) {
// Perform the relocations
resolve_symbols(module);
+ // Obtain constructors and destructors
+ CHECKED(res, extract_operations(module), error);
+
//dprintf("module->symtable_size = %d\n", module->symtable_size);
//print_elf_symbols(module);
@@ -534,6 +574,10 @@ int module_load(struct elf_module *module) {
(module->init_func == NULL) ? NULL : *(module->init_func),
(module->exit_func == NULL) ? NULL : *(module->exit_func));
*/
+
+ for (ctor = module->ctors; *ctor; ctor++)
+ (*ctor) ();
+
return 0;
error:
diff --git a/com32/lib/sys/module/i386/elfutils.h b/com32/lib/sys/module/i386/elfutils.h
deleted file mode 100644
index b18968f3..00000000
--- a/com32/lib/sys/module/i386/elfutils.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef ELF_UTILS_H_
-#define ELF_UTILS_H_
-
-#include <elf.h>
-#include <stdlib.h>
-
-/**
- * elf_get_header - Returns a pointer to the ELF header structure.
- * @elf_image: pointer to the ELF file image in memory
- */
-static inline Elf32_Ehdr *elf_get_header(void *elf_image) {
- return (Elf32_Ehdr*)elf_image;
-}
-
-/**
- * elf_get_pht - Returns a pointer to the first entry in the PHT.
- * @elf_image: pointer to the ELF file image in memory
- */
-static inline Elf32_Phdr *elf_get_pht(void *elf_image) {
- Elf32_Ehdr *elf_hdr = elf_get_header(elf_image);
-
- return (Elf32_Phdr*)((Elf32_Off)elf_hdr + elf_hdr->e_phoff);
-}
-
-//
-/**
- * elf_get_ph - Returns the element with the given index in the PTH
- * @elf_image: pointer to the ELF file image in memory
- * @index: the index of the PHT entry to look for
- */
-static inline Elf32_Phdr *elf_get_ph(void *elf_image, int index) {
- Elf32_Phdr *elf_pht = elf_get_pht(elf_image);
- Elf32_Ehdr *elf_hdr = elf_get_header(elf_image);
-
- return (Elf32_Phdr*)((Elf32_Off)elf_pht + index * elf_hdr->e_phentsize);
-}
-
-/**
- * elf_hash - Returns the index in a SysV hash table for the symbol name.
- * @name: the name of the symbol to look for
- */
-extern unsigned long elf_hash(const unsigned char *name);
-
-/**
- * elf_gnu_hash - Returns the index in a GNU hash table for the symbol name.
- * @name: the name of the symbol to look for
- */
-extern unsigned long elf_gnu_hash(const unsigned char *name);
-
-/**
- * elf_malloc - Allocates memory to be used by ELF module contents.
- * @memptr: pointer to a variable to hold the address of the allocated block.
- * @alignment: alignment constraints of the block
- * @size: the required size of the block
- */
-extern int elf_malloc(void **memptr, size_t alignment, size_t size);
-
-/**
- * elf_free - Releases memory previously allocated by elf_malloc.
- * @memptr: the address of the allocated block
- */
-extern void elf_free(void *memptr);
-
-#endif /*ELF_UTILS_H_*/
diff --git a/com32/lib/sys/module/shallow_module.c b/com32/lib/sys/module/shallow_module.c
index fbcf781b..8a88e403 100644
--- a/com32/lib/sys/module/shallow_module.c
+++ b/com32/lib/sys/module/shallow_module.c
@@ -32,8 +32,8 @@ static int check_header_shallow(Elf32_Ehdr *elf_hdr) {
static int load_shallow_sections(struct elf_module *module, Elf32_Ehdr *elf_hdr) {
int i;
int res = 0;
- void *sht = NULL;
- void *buffer = NULL;
+ char *sht = NULL;
+ char *buffer = NULL;
Elf32_Shdr *crt_sht;
Elf32_Off buff_offset;
@@ -100,8 +100,8 @@ static int load_shallow_sections(struct elf_module *module, Elf32_Ehdr *elf_hdr)
// Setup module information
module->module_size = max_offset - min_offset;
- module->str_table = (char*)(module->module_addr + (str_offset - min_offset));
- module->sym_table = module->module_addr + (sym_offset - min_offset);
+ module->str_table = (char *)module->module_addr + (str_offset - min_offset);
+ module->sym_table = (char *)module->module_addr + (sym_offset - min_offset);
out:
// Release the SHT
diff --git a/com32/lib/sys/module/x86_64/common.c b/com32/lib/sys/module/x86_64/common.c
deleted file mode 100644
index ba4dbedc..00000000
--- a/com32/lib/sys/module/x86_64/common.c
+++ /dev/null
@@ -1,567 +0,0 @@
-/*
- * common.c
- *
- * Created on: Aug 11, 2008
- * Author: Stefan Bucur <stefanb@zytor.com>
- */
-
-#include <stdio.h>
-#include <elf.h>
-#include <string.h>
-#include <fs.h>
-
-#include <linux/list.h>
-#include <sys/module.h>
-
-#include "elfutils.h"
-#include "common.h"
-
-/**
- * The one and only list of loaded modules
- */
-LIST_HEAD(modules_head);
-
-// User-space debugging routines
-#ifdef ELF_DEBUG
-void print_elf_ehdr(Elf64_Ehdr *ehdr) {
- int i;
-
- fprintf(stderr, "Identification:\t");
- for (i=0; i < EI_NIDENT; i++) {
- printf("%d ", ehdr->e_ident[i]);
- }
- fprintf(stderr, "\n");
- fprintf(stderr, "Type:\t\t%u\n", ehdr->e_type);
- fprintf(stderr, "Machine:\t%u\n", ehdr->e_machine);
- fprintf(stderr, "Version:\t%u\n", ehdr->e_version);
- fprintf(stderr, "Entry:\t\t0x%08x\n", ehdr->e_entry);
- fprintf(stderr, "PHT Offset:\t0x%08x\n", ehdr->e_phoff);
- fprintf(stderr, "SHT Offset:\t0x%08x\n", ehdr->e_shoff);
- //fprintf(stderr, "Flags:\t\t%u\n", ehdr->e_flags);
- //fprintf(stderr, "Header size:\t%u (Structure size: %u)\n", ehdr->e_ehsize,sizeof(Elf64_Ehdr));
- fprintf(stderr, "phnum: %d shnum: %d\n", ehdr->e_phnum,
- ehdr->e_shnum);
-}
-
-void print_elf_symbols(struct elf_module *module) {
- unsigned int i;
- Elf64_Sym *crt_sym;
-
- for (i = 1; i < module->symtable_size; i++)
- {
- crt_sym = (Elf64_Sym*)(module->sym_table + i*module->syment_size);
-
- fprintf(stderr,"%s %d\n", module->str_table + crt_sym->st_name, crt_sym->st_value);
-
- }
-}
-#endif //ELF_DEBUG
-
-static FILE *findpath(char *name)
-{
- char path[FILENAME_MAX];
- FILE *f;
- char *p, *n;
- int i;
-
- p = PATH;
-again:
- memset(path, '\0', sizeof(path));
- i = 0;
- while (*p && *p != ':' && i < FILENAME_MAX) {
- path[i++] = *p++;
- }
-
- if (*p == ':')
- p++;
-
- if (!strcmp(path, ".")) {
- if (!core_getcwd(path, sizeof(path))) {
- DBG_PRINT("Could not get cwd\n");
- return NULL;
- }
- i = strlen(path);
- }
-
- n = name;
- while (*n && i < FILENAME_MAX)
- path[i++] = *n++;
- path[i] = '\0';
-
- f = fopen(path, "rb");
- if (f)
- return f;
-
- if (p >= PATH && p < PATH + strlen(PATH))
- goto again;
-
- return NULL;
-}
-
-/*
- * Image files manipulation routines
- */
-
-int image_load(struct elf_module *module)
-{
- module->u.l._file = findpath(module->name);
-
- if (module->u.l._file == NULL) {
- DBG_PRINT("Could not open object file '%s'\n", module->name);
- goto error;
- }
-
- module->u.l._cr_offset = 0;
-
- return 0;
-
-error:
- if (module->u.l._file != NULL) {
- fclose(module->u.l._file);
- module->u.l._file = NULL;
- }
-
- return -1;
-}
-
-
-int image_unload(struct elf_module *module) {
- if (module->u.l._file != NULL) {
- fclose(module->u.l._file);
- module->u.l._file = NULL;
-
- }
- module->u.l._cr_offset = 0;
-
- return 0;
-}
-
-int image_read(void *buff, size_t size, struct elf_module *module) {
- size_t result = fread(buff, size, 1, module->u.l._file);
-
- if (result < 1)
- return -1;
-
- module->u.l._cr_offset += size;
- return 0;
-}
-
-int image_skip(size_t size, struct elf_module *module) {
- void *skip_buff = NULL;
- size_t result;
-
- if (size == 0)
- return 0;
-
- skip_buff = malloc(size);
- result = fread(skip_buff, size, 1, module->u.l._file);
- free(skip_buff);
-
- if (result < 1)
- return -1;
-
- module->u.l._cr_offset += size;
- return 0;
-}
-
-int image_seek(Elf64_Off offset, struct elf_module *module) {
- if (offset < module->u.l._cr_offset) // Cannot seek backwards
- return -1;
-
- return image_skip(offset - module->u.l._cr_offset, module);
-}
-
-
-// Initialization of the module subsystem
-int modules_init(void) {
- return 0;
-}
-
-// Termination of the module subsystem
-void modules_term(void) {
-
-}
-
-// Allocates the structure for a new module
-struct elf_module *module_alloc(const char *name) {
- struct elf_module *result = malloc(sizeof(struct elf_module));
-
- memset(result, 0, sizeof(struct elf_module));
-
- INIT_LIST_HEAD(&result->list);
- INIT_LIST_HEAD(&result->required);
- INIT_LIST_HEAD(&result->dependants);
-
- strncpy(result->name, name, MODULE_NAME_SIZE);
-
- return result;
-}
-
-struct module_dep *module_dep_alloc(struct elf_module *module) {
- struct module_dep *result = malloc(sizeof(struct module_dep));
-
- INIT_LIST_HEAD (&result->list);
-
- result->module = module;
-
- return result;
-}
-
-struct elf_module *module_find(const char *name) {
- struct elf_module *cr_module;
-
- for_each_module(cr_module) {
- if (strcmp(cr_module->name, name) == 0)
- return cr_module;
- }
-
- return NULL;
-}
-
-
-// Performs verifications on ELF header to assure that the open file is a
-// valid SYSLINUX ELF module.
-int check_header_common(Elf64_Ehdr *elf_hdr) {
- // Check the header magic
- if (elf_hdr->e_ident[EI_MAG0] != ELFMAG0 ||
- elf_hdr->e_ident[EI_MAG1] != ELFMAG1 ||
- elf_hdr->e_ident[EI_MAG2] != ELFMAG2 ||
- elf_hdr->e_ident[EI_MAG3] != ELFMAG3) {
-
- DBG_PRINT("The file is not an ELF object\n");
- return -1;
- }
-
- if (elf_hdr->e_ident[EI_CLASS] != MODULE_ELF_CLASS) {
- DBG_PRINT("Invalid ELF class code\n");
- return -1;
- }
-
- if (elf_hdr->e_ident[EI_DATA] != MODULE_ELF_DATA) {
- DBG_PRINT("Invalid ELF data encoding\n");
- return -1;
- }
-
- if (elf_hdr->e_ident[EI_VERSION] != MODULE_ELF_VERSION ||
- elf_hdr->e_version != MODULE_ELF_VERSION) {
- DBG_PRINT("Invalid ELF file version\n");
- return -1;
- }
-
- if (elf_hdr->e_machine != MODULE_ELF_MACHINE) {
- DBG_PRINT("Invalid ELF architecture\n");
- return -1;
- }
-
- return 0;
-}
-
-
-int enforce_dependency(struct elf_module *req, struct elf_module *dep) {
- struct module_dep *crt_dep;
- struct module_dep *new_dep;
-
- list_for_each_entry(crt_dep, &req->dependants, list) {
- if (crt_dep->module == dep) {
- // The dependency is already enforced
- return 0;
- }
- }
-
- new_dep = module_dep_alloc(req);
- list_add(&new_dep->list, &dep->required);
-
- new_dep = module_dep_alloc(dep);
- list_add(&new_dep->list, &req->dependants);
-
- return 0;
-}
-
-int clear_dependency(struct elf_module *req, struct elf_module *dep) {
- struct module_dep *crt_dep = NULL;
- int found = 0;
-
- list_for_each_entry(crt_dep, &req->dependants, list) {
- if (crt_dep->module == dep) {
- found = 1;
- break;
- }
- }
-
- if (found) {
- list_del(&crt_dep->list);
- free(crt_dep);
- }
-
- found = 0;
-
- list_for_each_entry(crt_dep, &dep->required, list) {
- if (crt_dep->module == req) {
- found = 1;
- break;
- }
- }
-
- if (found) {
- list_del(&crt_dep->list);
- free(crt_dep);
- }
-
- return 0;
-}
-
-int check_symbols(struct elf_module *module)
-{
- unsigned int i;
- Elf64_Sym *crt_sym = NULL, *ref_sym = NULL;
- char *crt_name;
- struct elf_module *crt_module;
-
- int strong_count;
- int weak_count;
-
- for(i = 1; i < module->symtable_size; i++)
- {
- crt_sym = (Elf64_Sym*)(module->sym_table + i * module->syment_size);
- crt_name = module->str_table + crt_sym->st_name;
-
- strong_count = 0;
- weak_count = 0;
-
- for_each_module(crt_module)
- {
- ref_sym = module_find_symbol(crt_name, crt_module);
-
- // If we found a definition for our symbol...
- if (ref_sym != NULL && ref_sym->st_shndx != SHN_UNDEF)
- {
- switch (ELF64_ST_BIND(ref_sym->st_info))
- {
- case STB_GLOBAL:
- strong_count++;
- break;
- case STB_WEAK:
- weak_count++;
- break;
- }
- }
- }
-
- if (crt_sym->st_shndx == SHN_UNDEF)
- {
- // We have an undefined symbol
- if (strong_count == 0 && weak_count == 0)
- {
- DBG_PRINT("Symbol %s is undefined\n", crt_name);
- //printf("Undef symbol FAIL: %s\n",crt_name);
- return -1;
- }
- }
- else
- {
- if (strong_count > 0 && ELF64_ST_BIND(ref_sym->st_info) == STB_GLOBAL)
- {
- // It's not an error - at relocation, the most recent symbol
- // will be considered
- DBG_PRINT("Info: Symbol %s is defined more than once\n", crt_name);
- }
- }
- //printf("symbol %s laoded from %d\n",crt_name,crt_sym->st_value);
- }
-
- return 0;
-}
-
-int module_unloadable(struct elf_module *module) {
- if (!list_empty(&module->dependants))
- return 0;
-
- return 1;
-}
-
-
-// Unloads the module from the system and releases all the associated memory
-int module_unload(struct elf_module *module) {
- struct module_dep *crt_dep, *tmp;
- // Make sure nobody needs us
- if (!module_unloadable(module)) {
- DBG_PRINT("Module is required by other modules.\n");
- return -1;
- }
-
- // Remove any dependency information
- list_for_each_entry_safe(crt_dep, tmp, &module->required, list) {
- clear_dependency(crt_dep->module, module);
- }
-
- // Remove the module from the module list
- list_del_init(&module->list);
-
- // Release the loaded segments or sections
- if (module->module_addr != NULL) {
- elf_free(module->module_addr);
-
- DBG_PRINT("%s MODULE %s UNLOADED\n", module->shallow ? "SHALLOW" : "",
- module->name);
- }
- // Release the module structure
- free(module);
-
- return 0;
-}
-
-
-static Elf64_Sym *module_find_symbol_sysv(const char *name, struct elf_module *module) {
- unsigned long h = elf_hash((const unsigned char*)name);
- Elf64_Word *cr_word = module->hash_table;
-
- Elf64_Word nbucket = *cr_word++;
- cr_word++; // Skip nchain
-
- Elf64_Word *bkt = cr_word;
- Elf64_Word *chn = cr_word + nbucket;
-
- Elf64_Word crt_index = bkt[h % module->hash_table[0]];
- Elf64_Sym *crt_sym;
-
-
- while (crt_index != STN_UNDEF) {
- crt_sym = (Elf64_Sym*)(module->sym_table + crt_index*module->syment_size);
-
- if (strcmp(name, module->str_table + crt_sym->st_name) == 0)
- return crt_sym;
-
- crt_index = chn[crt_index];
- }
-
- return NULL;
-}
-
-static Elf64_Sym *module_find_symbol_gnu(const char *name, struct elf_module *module) {
- unsigned long h = elf_gnu_hash((const unsigned char*)name);
-
- // Setup code (TODO: Optimize this by computing only once)
- Elf64_Word *cr_word = module->ghash_table;
- Elf64_Word nbucket = *cr_word++;
- Elf64_Word symbias = *cr_word++;
- Elf64_Word bitmask_nwords = *cr_word++;
-
- if ((bitmask_nwords & (bitmask_nwords - 1)) != 0) {
- DBG_PRINT("Invalid GNU Hash structure\n");
- return NULL;
- }
-
- Elf64_Word gnu_shift = *cr_word++;
-
- Elf64_Addr *gnu_bitmask = cr_word;
- cr_word += MODULE_ELF_CLASS_SIZE / 32 * bitmask_nwords;
-
- Elf64_Word *gnu_buckets = cr_word;
- cr_word += nbucket;
-
- Elf64_Word *gnu_chain_zero = cr_word - symbias;
-
- // Computations
- /* bitask words are 64bit for ELFCLASS64 modules */
- Elf64_Xword bitmask_word = gnu_bitmask[(h / MODULE_ELF_CLASS_SIZE) &
- (bitmask_nwords - 1)];
-
- unsigned int hashbit1 = h & (MODULE_ELF_CLASS_SIZE - 1);
- unsigned int hashbit2 = (h >> gnu_shift) & (MODULE_ELF_CLASS_SIZE - 1);
-
- if ((bitmask_word >> hashbit1) & (bitmask_word >> hashbit2) & 1) {
- unsigned long rem;
- Elf64_Word bucket;
-
- rem = h % nbucket;
-
- bucket = gnu_buckets[rem];
-
- if (bucket != 0) {
- const Elf64_Word* hasharr = &gnu_chain_zero[bucket];
-
- do {
- if (((*hasharr ^ h ) >> 1) == 0) {
- Elf64_Sym *crt_sym = (Elf64_Sym*)(module->sym_table +
- (hasharr - gnu_chain_zero) * module->syment_size);
-
- if (strcmp(name, module->str_table + crt_sym->st_name) == 0) {
- return crt_sym;
- }
- }
- } while ((*hasharr++ & 1u) == 0);
- }
- }
-
- return NULL;
-}
-
-static Elf64_Sym *module_find_symbol_iterate(const char *name,struct elf_module *module)
-{
-
- unsigned int i;
- Elf64_Sym *crt_sym;
-
- for (i=1; i < module->symtable_size; i++)
- {
- crt_sym = (Elf64_Sym*)(module->sym_table + i*module->syment_size);
- if (strcmp(name, module->str_table + crt_sym->st_name) == 0)
- {
- return crt_sym;
- }
- }
-
- return NULL;
-}
-
-Elf64_Sym *module_find_symbol(const char *name, struct elf_module *module) {
- Elf64_Sym *result = NULL;
-
- if (module->ghash_table != NULL)
- result = module_find_symbol_gnu(name, module);
-
- if (result == NULL)
- {
- if (module->hash_table != NULL)
- {
- result = module_find_symbol_sysv(name, module);
- }
- else
- {
- result = module_find_symbol_iterate(name, module);
- }
- }
-
- return result;
-}
-
-Elf64_Sym *global_find_symbol(const char *name, struct elf_module **module) {
- struct elf_module *crt_module;
- Elf64_Sym *crt_sym = NULL;
- Elf64_Sym *result = NULL;
-
- for_each_module(crt_module) {
- crt_sym = module_find_symbol(name, crt_module);
-
- if (crt_sym != NULL && crt_sym->st_shndx != SHN_UNDEF) {
- switch (ELF64_ST_BIND(crt_sym->st_info)) {
- case STB_GLOBAL:
- if (module != NULL) {
- *module = crt_module;
- }
- return crt_sym;
- case STB_WEAK:
- // Consider only the first weak symbol
- if (result == NULL) {
- if (module != NULL) {
- *module = crt_module;
- }
- result = crt_sym;
- }
- break;
- }
- }
- }
-
- return result;
-}
diff --git a/com32/lib/sys/module/x86_64/elf_module.c b/com32/lib/sys/module/x86_64/elf_module.c
index 2ff2e20b..3c164996 100644
--- a/com32/lib/sys/module/x86_64/elf_module.c
+++ b/com32/lib/sys/module/x86_64/elf_module.c
@@ -5,20 +5,20 @@
* Author: Stefan Bucur <stefanb@zytor.com>
*/
-
+#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <elf.h>
#include <dprintf.h>
+#include <core.h>
#include <linux/list.h>
#include <sys/module.h>
+#include <sys/exec.h>
#include "elfutils.h"
-#include "common.h"
-
-#define MAX_NR_DEPS 64
+#include "../common.h"
static int check_header(Elf64_Ehdr *elf_hdr) {
int res;
@@ -50,7 +50,7 @@ static int check_header(Elf64_Ehdr *elf_hdr) {
static int load_segments(struct elf_module *module, Elf64_Ehdr *elf_hdr) {
int i;
int res = 0;
- void *pht = NULL;
+ char *pht = NULL;
Elf64_Phdr *cr_pht;
Elf64_Addr min_addr = 0x0000000000000000; // Min. ELF vaddr
@@ -136,8 +136,8 @@ static int load_segments(struct elf_module *module, Elf64_Ehdr *elf_hdr) {
// headers
Elf64_Off aux_off = module->u.l._cr_offset - cr_pht->p_offset;
- if (image_read(module_get_absolute(cr_pht->p_vaddr, module) + aux_off,
- cr_pht->p_filesz - aux_off, module) < 0) {
+ if (image_read((char *)module_get_absolute(cr_pht->p_vaddr, module) + aux_off,
+ cr_pht->p_filesz - aux_off, module) < 0) {
res = -1;
goto out;
}
@@ -180,9 +180,6 @@ out:
return res;
}
-static int nr_needed;
-static Elf64_Word needed[MAX_NR_DEPS];;
-
static int prepare_dynlinking(struct elf_module *module) {
Elf64_Dyn *dyn_entry = module->dyn_table;
@@ -195,8 +192,8 @@ static int prepare_dynlinking(struct elf_module *module) {
* are then inform the user that we ran out of
* space.
*/
- if (nr_needed < MAX_NR_DEPS)
- needed[nr_needed++] = dyn_entry->d_un.d_ptr;
+ if (module->nr_needed < MAX_NR_DEPS)
+ module->needed[module->nr_needed++] = dyn_entry->d_un.d_ptr;
else {
printf("Too many dependencies!\n");
return -1;
@@ -242,6 +239,11 @@ static int prepare_dynlinking(struct elf_module *module) {
return 0;
}
+void undefined_symbol(void)
+{
+ printf("Error: An undefined symbol was referenced\n");
+ kaboom();
+}
static int perform_relocation(struct elf_module *module, Elf64_Rel *rel) {
Elf64_Xword *dest = module_get_absolute(rel->r_offset, module);
@@ -259,8 +261,7 @@ static int perform_relocation(struct elf_module *module, Elf64_Rel *rel) {
// Find out details about the symbol
// The symbol reference
- Elf64_Sym *sym_ref =
- (Elf64_Sym*)(module->sym_table + sym * module->syment_size);
+ Elf64_Sym *sym_ref = symbol_get_entry(module, sym);
// The symbol definition
sym_def =
@@ -268,11 +269,16 @@ static int perform_relocation(struct elf_module *module, Elf64_Rel *rel) {
&sym_module);
if (sym_def == NULL) {
- // This should never happen
DBG_PRINT("Cannot perform relocation for symbol %s\n",
module->str_table + sym_ref->st_name);
- return -1;
+ if (ELF64_ST_BIND(sym_ref->st_info) != STB_WEAK)
+ return -1;
+
+ // This must be a derivative-specific
+ // function. We're OK as long as we never
+ // execute the function.
+ sym_def = global_find_symbol("undefined_symbol", &sym_module);
}
// Compute the absolute symbol virtual address
@@ -422,73 +428,93 @@ static int resolve_symbols(struct elf_module *module) {
res = perform_relocation(module, crt_rel);
- if (res < 0) {
+ if (res < 0)
return res;
- }
}
}
return 0;
}
+static int extract_operations(struct elf_module *module) {
+ Elf64_Sym *ctors_start, *ctors_end;
+ Elf64_Sym *dtors_start, *dtors_end;
+ module_ctor_t *ctors = NULL;
+ module_ctor_t *dtors = NULL;
+ ctors_start = module_find_symbol("__ctors_start", module);
+ ctors_end = module_find_symbol("__ctors_end", module);
-static int extract_operations(struct elf_module *module) {
- Elf64_Sym *init_sym = module_find_symbol(MODULE_ELF_INIT_PTR, module);
- Elf64_Sym *exit_sym = module_find_symbol(MODULE_ELF_EXIT_PTR, module);
- Elf64_Sym *main_sym = module_find_symbol("main", module);
-
- if (init_sym) {
- module->init_func = (module_init_t*)module_get_absolute(
- init_sym->st_value, module);
- if (*(module->init_func) == NULL) {
- module->init_func = NULL;
- }
- }
+ if (ctors_start && ctors_end) {
+ module_ctor_t *start, *end;
+ int nr_ctors = 0;
+ int i, size;
+
+ start = module_get_absolute(ctors_start->st_value, module);
+ end = module_get_absolute(ctors_end->st_value, module);
+
+ nr_ctors = end - start;
- if (exit_sym) {
- module->exit_func = (module_exit_t*)module_get_absolute(
- exit_sym->st_value, module);
- if (*(module->exit_func) == NULL) {
- module->exit_func = NULL;
+ size = nr_ctors * sizeof(module_ctor_t);
+ size += sizeof(module_ctor_t); /* NULL entry */
+
+ ctors = malloc(size);
+ if (!ctors) {
+ printf("Unable to alloc memory for ctors\n");
+ return -1;
}
+
+ memset(ctors, 0, size);
+ for (i = 0; i < nr_ctors; i++)
+ ctors[i] = start[i];
+
+ module->ctors = ctors;
}
- if (main_sym)
- module->main_func =
- module_get_absolute(main_sym->st_value, module);
+ dtors_start = module_find_symbol("__dtors_start", module);
+ dtors_end = module_find_symbol("__dtors_end", module);
- return 0;
-}
+ if (dtors_start && dtors_end) {
+ module_ctor_t *start, *end;
+ int nr_dtors = 0;
+ int i, size;
-void print_elf_ehdr(Elf64_Ehdr *ehdr) {
- int i;
+ start = module_get_absolute(dtors_start->st_value, module);
+ end = module_get_absolute(dtors_end->st_value, module);
+
+ nr_dtors = end - start;
+
+ size = nr_dtors * sizeof(module_ctor_t);
+ size += sizeof(module_ctor_t); /* NULL entry */
+
+ dtors = malloc(size);
+ if (!dtors) {
+ printf("Unable to alloc memory for dtors\n");
+ free(ctors);
+ return -1;
+ }
- printf("Identification:\t");
- for (i=0; i < EI_NIDENT; i++) {
- printf("%d ", ehdr->e_ident[i]);
+ memset(dtors, 0, size);
+ for (i = 0; i < nr_dtors; i++)
+ dtors[i] = start[i];
+
+ module->dtors = dtors;
}
- printf("\n");
- printf("Type:\t\t%u\n", ehdr->e_type);
- printf("Machine:\t%u\n", ehdr->e_machine);
- printf("Version:\t%u\n", ehdr->e_version);
- printf("Entry:\t\t0x%08x\n", ehdr->e_entry);
- printf("PHT Offset:\t0x%08x\n", ehdr->e_phoff);
- printf("SHT Offset:\t0x%08x\n", ehdr->e_shoff);
- //fprintf(stderr, "Flags:\t\t%u\n", ehdr->e_flags);
- //fprintf(stderr, "Header size:\t%u (Structure size: %u)\n", ehdr->e_ehsize,sizeof(Elf64_Ehdr));
- printf("phnum: %d shnum: %d\n", ehdr->e_phnum,
- ehdr->e_shnum);
+
+ return 0;
}
+
// Loads the module into the system
int module_load(struct elf_module *module) {
int res;
+ Elf64_Sym *main_sym;
Elf64_Ehdr elf_hdr;
+ module_ctor_t *ctor;
// Do not allow duplicate modules
if (module_find(module->name) != NULL) {
DBG_PRINT("Module %s is already loaded.\n", module->name);
- return -1;
+ return EEXIST;
}
// Get a mapping/copy of the ELF file in memory
@@ -512,45 +538,37 @@ int module_load(struct elf_module *module) {
// Load the segments in the memory
CHECKED(res, load_segments(module, &elf_hdr), error);
- //!!!!! Passed load_segments....
//printf("bleah... 3\n");
// Obtain dynamic linking information
- nr_needed = 0;
CHECKED(res, prepare_dynlinking(module), error);
//printf("check... 4\n");
- //
- //dump_elf_module(module);
/* Find modules we need to load as dependencies */
if (module->str_table) {
- int i, n;
+ int i;
/*
- * nr_needed can be modified by recursive calls to
- * module_load() so keep a local copy on the stack.
+ * Note that we have to load the dependencies in
+ * reverse order.
*/
- n = nr_needed;
- for (i = 0; i < n; i++) {
- size_t len, j;
+ for (i = module->nr_needed - 1; i >= 0; i--) {
char *dep, *p;
+ char *argv[2] = { NULL, NULL };
- dep = module->str_table + needed[i];
+ dep = module->str_table + module->needed[i];
/* strip everything but the last component */
- j = len = strlen(dep);
- if (!len)
+ if (!strlen(dep))
continue;
- p = dep + len - 1;
- while (j > 0 && *p && *p != '/') {
- p--;
- j--;
- }
+ if (strchr(dep, '/')) {
+ p = strrchr(dep, '/');
+ p++;
+ } else
+ p = dep;
- if (*p++ == '/') {
- char argv[2] = { p, NULL };
- spawn_load(p, 1, argv);
- }
+ argv[0] = p;
+ spawn_load(p, 1, argv);
}
}
@@ -558,8 +576,11 @@ int module_load(struct elf_module *module) {
CHECKED(res, check_symbols(module), error);
//printf("check... 5\n");
- // Obtain constructors and destructors
- CHECKED(res, extract_operations(module), error);
+ main_sym = module_find_symbol("main", module);
+ if (main_sym)
+ module->main_func =
+ module_get_absolute(main_sym->st_value, module);
+
//printf("check... 6\n");
// Add the module at the beginning of the module list
@@ -568,6 +589,9 @@ int module_load(struct elf_module *module) {
// Perform the relocations
resolve_symbols(module);
+ // Obtain constructors and destructors
+ CHECKED(res, extract_operations(module), error);
+
//dprintf("module->symtable_size = %d\n", module->symtable_size);
//print_elf_symbols(module);
@@ -582,6 +606,10 @@ int module_load(struct elf_module *module) {
(module->init_func == NULL) ? NULL : *(module->init_func),
(module->exit_func == NULL) ? NULL : *(module->exit_func));
*/
+
+ for (ctor = module->ctors; *ctor; ctor++)
+ (*ctor) ();
+
return 0;
error:
diff --git a/com32/lib/sys/open.c b/com32/lib/sys/open.c
index a0ef1597..3221bb60 100644
--- a/com32/lib/sys/open.c
+++ b/com32/lib/sys/open.c
@@ -30,6 +30,7 @@
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
+#include <fs.h>
#include "file.h"
/*
diff --git a/com32/lib/sys/rawcon_read.c b/com32/lib/sys/rawcon_read.c
index e6635909..7eae95f1 100644
--- a/com32/lib/sys/rawcon_read.c
+++ b/com32/lib/sys/rawcon_read.c
@@ -35,51 +35,38 @@
#include <errno.h>
#include <string.h>
#include <com32.h>
+#include <core.h>
#include <minmax.h>
#include "file.h"
/* Global, since it's used by stdcon_read */
-#ifndef SYSLINUX_EFI
ssize_t __rawcon_read(struct file_info *fp, void *buf, size_t count)
{
- com32sys_t ireg, oreg;
char *bufp = buf;
size_t n = 0;
+ char hi = 0;
-printf("__rawcon_read... enter\n");
(void)fp;
- memset(&ireg, 0, sizeof ireg);
-
while (n < count) {
+ if (hi) {
+ *bufp++ = hi;
+ n++;
+ hi = 0;
+ continue;
+ }
+
/* Poll */
- ireg.eax.b[1] = 0x0B;
- __intcall(0x21, &ireg, &oreg);
- if (!oreg.eax.b[0])
+ if (!pollchar())
break;
/* We have data, go get it */
- ireg.eax.b[1] = 0x08;
- __intcall(0x21, &ireg, &oreg);
- *bufp++ = oreg.eax.b[0];
+ *bufp++ = getchar(&hi);
n++;
}
return n;
}
-#else
-ssize_t __rawcon_read(struct file_info *fp, void *buf, size_t count)
-{
- extern char getchar();
- char *bufp = buf;
- size_t n = 0;
- while (n < count) {
- *bufp++ = getchar();
- n++;
- }
- return n;
-}
-#endif
const struct input_dev dev_rawcon_r = {
.dev_magic = __DEV_MAGIC,
diff --git a/com32/lib/sys/rawcon_write.c b/com32/lib/sys/rawcon_write.c
index 2d45a7b2..1f7920b2 100644
--- a/com32/lib/sys/rawcon_write.c
+++ b/com32/lib/sys/rawcon_write.c
@@ -34,24 +34,20 @@
#include <errno.h>
#include <string.h>
#include <com32.h>
+#include <core.h>
#include <minmax.h>
#include "file.h"
static ssize_t __rawcon_write(struct file_info *fp, const void *buf,
size_t count)
{
- com32sys_t ireg;
const char *bufp = buf;
size_t n = 0;
(void)fp;
- memset(&ireg, 0, sizeof ireg);
- ireg.eax.b[1] = 0x02;
-
while (count--) {
- ireg.edx.b[0] = *bufp++;
- __intcall(0x21, &ireg, NULL);
+ writechr(*bufp++);
n++;
}
diff --git a/com32/lib/sys/serial_write.c b/com32/lib/sys/serial_write.c
index fa0f4f4d..3f949fb7 100644
--- a/com32/lib/sys/serial_write.c
+++ b/com32/lib/sys/serial_write.c
@@ -34,13 +34,13 @@
#include <errno.h>
#include <string.h>
#include <com32.h>
+#include <core.h>
#include <minmax.h>
#include <syslinux/config.h>
#include "file.h"
ssize_t __serial_write(struct file_info *fp, const void *buf, size_t count)
{
- com32sys_t ireg;
const char *bufp = buf;
size_t n = 0;
@@ -49,12 +49,8 @@ ssize_t __serial_write(struct file_info *fp, const void *buf, size_t count)
if (!syslinux_serial_console_info()->iobase)
return count; /* Nothing to do */
- memset(&ireg, 0, sizeof ireg);
- ireg.eax.b[1] = 0x04;
-
while (count--) {
- ireg.edx.b[0] = *bufp++;
- __intcall(0x21, &ireg, NULL);
+ write_serial(*bufp++);
n++;
}
diff --git a/com32/lib/sys/stdcon_write.c b/com32/lib/sys/stdcon_write.c
index 9cb2f7db..9bd225f9 100644
--- a/com32/lib/sys/stdcon_write.c
+++ b/com32/lib/sys/stdcon_write.c
@@ -34,6 +34,7 @@
#include <errno.h>
#include <string.h>
#include <com32.h>
+#include <core.h>
#include <minmax.h>
#include "file.h"
@@ -57,22 +58,16 @@ static int __stdcon_open(struct file_info *fp)
static ssize_t __stdcon_write(struct file_info *fp, const void *buf,
size_t count)
{
- com32sys_t ireg;
const char *bufp = buf;
size_t n = 0;
(void)fp;
- memset(&ireg, 0, sizeof ireg);
- ireg.eax.b[1] = 0x02;
-
while (count--) {
- if (*bufp == '\n') {
- ireg.edx.b[0] = '\r';
- __intcall(0x21, &ireg, NULL);
- }
- ireg.edx.b[0] = *bufp++;
- __intcall(0x21, &ireg, NULL);
+ if (*bufp == '\n')
+ writechr('\r');
+
+ writechr(*bufp++);
n++;
}
diff --git a/com32/lib/sys/xserial_write.c b/com32/lib/sys/xserial_write.c
index e399f5fc..8a4fb9e0 100644
--- a/com32/lib/sys/xserial_write.c
+++ b/com32/lib/sys/xserial_write.c
@@ -35,6 +35,7 @@
#include <errno.h>
#include <string.h>
#include <com32.h>
+#include <core.h>
#include <minmax.h>
#include <colortbl.h>
#include <syslinux/config.h>
@@ -42,12 +43,7 @@
static void emit(char ch)
{
- static com32sys_t ireg; /* Zeroed with the BSS */
-
- ireg.eax.b[1] = 0x04;
- ireg.edx.b[0] = ch;
-
- __intcall(0x21, &ireg, NULL);
+ write_serial(ch);
}
ssize_t __xserial_write(struct file_info *fp, const void *buf, size_t count)
diff --git a/com32/lib/syslinux/cleanup.c b/com32/lib/syslinux/cleanup.c
index 12140e55..7d8581e4 100644
--- a/com32/lib/syslinux/cleanup.c
+++ b/com32/lib/syslinux/cleanup.c
@@ -26,15 +26,15 @@
* ----------------------------------------------------------------------- */
#include <syslinux/boot.h>
+#include <syslinux/config.h>
+#include <syslinux/pxe_api.h>
#include <stddef.h>
-#include <com32.h>
+#include <core.h>
void syslinux_final_cleanup(uint16_t flags)
{
- static com32sys_t ireg;
+ if (syslinux_filesystem() == SYSLINUX_FS_PXELINUX)
+ unload_pxe(flags);
- ireg.eax.w[0] = 0x000c;
- ireg.edx.w[0] = flags;
-
- __intcall(0x22, &ireg, NULL);
+ cleanup_hardware();
}
diff --git a/com32/lib/syslinux/disk.c b/com32/lib/syslinux/disk.c
new file mode 100644
index 00000000..093751ac
--- /dev/null
+++ b/com32/lib/syslinux/disk.c
@@ -0,0 +1,569 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ * Copyright (C) 2010 Shao Miller
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/**
+ * @file disk.c
+ *
+ * Deal with disks and partitions
+ */
+
+#include <dprintf.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslinux/disk.h>
+
+/**
+ * Call int 13h, but with retry on failure. Especially floppies need this.
+ *
+ * @v inreg CPU register settings upon INT call
+ * @v outreg CPU register settings returned by INT call
+ * @ret (int) 0 upon success, -1 upon failure
+ */
+int disk_int13_retry(const com32sys_t * inreg, com32sys_t * outreg)
+{
+ int retry = 6; /* Number of retries */
+ com32sys_t tmpregs;
+
+ if (!outreg)
+ outreg = &tmpregs;
+
+ while (retry--) {
+ __intcall(0x13, inreg, outreg);
+ if (!(outreg->eflags.l & EFLAGS_CF))
+ return 0; /* CF=0, OK */
+ }
+
+ return -1; /* Error */
+}
+
+/**
+ * Query disk parameters and EBIOS availability for a particular disk.
+ *
+ * @v disk The INT 0x13 disk drive number to process
+ * @v diskinfo The structure to save the queried params to
+ * @ret (int) 0 upon success, -1 upon failure
+ */
+int disk_get_params(int disk, struct disk_info *const diskinfo)
+{
+ static com32sys_t inreg, outreg;
+ struct disk_ebios_eparam *eparam;
+ int rv = 0;
+
+ memset(diskinfo, 0, sizeof *diskinfo);
+ diskinfo->disk = disk;
+ diskinfo->bps = SECTOR;
+
+ /* Get EBIOS support */
+ memset(&inreg, 0, sizeof inreg);
+ inreg.eax.b[1] = 0x41;
+ inreg.ebx.w[0] = 0x55aa;
+ inreg.edx.b[0] = disk;
+ inreg.eflags.b[0] = 0x3; /* CF set */
+
+ __intcall(0x13, &inreg, &outreg);
+
+ if (!(outreg.eflags.l & EFLAGS_CF) &&
+ outreg.ebx.w[0] == 0xaa55 && (outreg.ecx.b[0] & 1)) {
+ diskinfo->ebios = 1;
+ }
+
+ eparam = lmalloc(sizeof *eparam);
+ if (!eparam)
+ return -1;
+
+ /* Get extended disk parameters if ebios == 1 */
+ if (diskinfo->ebios) {
+ memset(&inreg, 0, sizeof inreg);
+ inreg.eax.b[1] = 0x48;
+ inreg.edx.b[0] = disk;
+ inreg.esi.w[0] = OFFS(eparam);
+ inreg.ds = SEG(eparam);
+
+ memset(eparam, 0, sizeof *eparam);
+ eparam->len = sizeof *eparam;
+
+ __intcall(0x13, &inreg, &outreg);
+
+ if (!(outreg.eflags.l & EFLAGS_CF)) {
+ diskinfo->lbacnt = eparam->lbacnt;
+ if (eparam->bps)
+ diskinfo->bps = eparam->bps;
+ /*
+ * don't think about using geometry data returned by
+ * 48h, as it can differ from 08h a lot ...
+ */
+ }
+ }
+ /*
+ * Get disk parameters the old way - really only useful for hard
+ * disks, but if we have a partitioned floppy it's actually our best
+ * chance...
+ */
+ memset(&inreg, 0, sizeof inreg);
+ inreg.eax.b[1] = 0x08;
+ inreg.edx.b[0] = disk;
+
+ __intcall(0x13, &inreg, &outreg);
+
+ if (outreg.eflags.l & EFLAGS_CF) {
+ rv = diskinfo->ebios ? 0 : -1;
+ goto out;
+ }
+
+ diskinfo->spt = 0x3f & outreg.ecx.b[0];
+ diskinfo->head = 1 + outreg.edx.b[1];
+ diskinfo->cyl = 1 + (outreg.ecx.b[1] | ((outreg.ecx.b[0] & 0xc0u) << 2));
+
+ if (diskinfo->spt)
+ diskinfo->cbios = 1; /* Valid geometry */
+ else {
+ diskinfo->head = 1;
+ diskinfo->spt = 1;
+ diskinfo->cyl = 1;
+ }
+
+ if (!diskinfo->lbacnt)
+ diskinfo->lbacnt = diskinfo->cyl * diskinfo->head * diskinfo->spt;
+
+out:
+ lfree(eparam);
+ return rv;
+}
+
+/**
+ * Get disk block(s) and return a malloc'd buffer.
+ *
+ * @v diskinfo The disk drive to read from
+ * @v lba The logical block address to begin reading at
+ * @v count The number of sectors to read
+ * @ret data An allocated buffer with the read data
+ *
+ * Uses the disk number and information from diskinfo. Read count sectors
+ * from drive, starting at lba. Return a new buffer, or NULL upon failure.
+ */
+void *disk_read_sectors(const struct disk_info *const diskinfo, uint64_t lba,
+ uint8_t count)
+{
+ com32sys_t inreg;
+ struct disk_ebios_dapa *dapa;
+ void *buf;
+ void *data = NULL;
+ uint32_t maxcnt;
+ uint32_t size = 65536;
+
+ maxcnt = (size - diskinfo->bps) / diskinfo->bps;
+ if (!count || count > maxcnt || lba + count > diskinfo->lbacnt)
+ return NULL;
+
+ memset(&inreg, 0, sizeof inreg);
+
+ buf = lmalloc(count * diskinfo->bps);
+ if (!buf)
+ return NULL;
+
+ dapa = lmalloc(sizeof(*dapa));
+ if (!dapa)
+ goto out;
+
+ if (diskinfo->ebios) {
+ dapa->len = sizeof(*dapa);
+ dapa->count = count;
+ dapa->off = OFFS(buf);
+ dapa->seg = SEG(buf);
+ dapa->lba = lba;
+
+ inreg.esi.w[0] = OFFS(dapa);
+ inreg.ds = SEG(dapa);
+ inreg.edx.b[0] = diskinfo->disk;
+ inreg.eax.b[1] = 0x42; /* Extended read */
+ } else {
+ unsigned int c, h, s, t;
+ /*
+ * if we passed lba + count check and we get here, that means that
+ * lbacnt was calculated from chs geometry (or faked from 1/1/1), thus
+ * 32bits are perfectly enough and lbacnt corresponds to cylinder
+ * boundary
+ */
+ s = lba % diskinfo->spt;
+ t = lba / diskinfo->spt;
+ h = t % diskinfo->head;
+ c = t / diskinfo->head;
+
+ inreg.eax.b[0] = count;
+ inreg.eax.b[1] = 0x02; /* Read */
+ inreg.ecx.b[1] = c;
+ inreg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1);
+ inreg.edx.b[1] = h;
+ inreg.edx.b[0] = diskinfo->disk;
+ inreg.ebx.w[0] = OFFS(buf);
+ inreg.es = SEG(buf);
+ }
+
+ if (disk_int13_retry(&inreg, NULL))
+ goto out;
+
+ data = malloc(count * diskinfo->bps);
+ if (data)
+ memcpy(data, buf, count * diskinfo->bps);
+out:
+ lfree(dapa);
+ lfree(buf);
+ return data;
+}
+
+/**
+ * Write disk block(s).
+ *
+ * @v diskinfo The disk drive to write to
+ * @v lba The logical block address to begin writing at
+ * @v data The data to write
+ * @v count The number of sectors to write
+ * @ret (int) 0 upon success, -1 upon failure
+ *
+ * Uses the disk number and information from diskinfo.
+ * Write sector(s) to a disk drive, starting at lba.
+ */
+int disk_write_sectors(const struct disk_info *const diskinfo, uint64_t lba,
+ const void *data, uint8_t count)
+{
+ com32sys_t inreg;
+ struct disk_ebios_dapa *dapa;
+ void *buf;
+ uint32_t maxcnt;
+ uint32_t size = 65536;
+ int rv = -1;
+
+ maxcnt = (size - diskinfo->bps) / diskinfo->bps;
+ if (!count || count > maxcnt || lba + count > diskinfo->lbacnt)
+ return -1;
+
+ buf = lmalloc(count * diskinfo->bps);
+ if (!buf)
+ return -1;
+
+ memcpy(buf, data, count * diskinfo->bps);
+ memset(&inreg, 0, sizeof inreg);
+
+ dapa = lmalloc(sizeof(*dapa));
+ if (!dapa)
+ goto out;
+
+ if (diskinfo->ebios) {
+ dapa->len = sizeof(*dapa);
+ dapa->count = count;
+ dapa->off = OFFS(buf);
+ dapa->seg = SEG(buf);
+ dapa->lba = lba;
+
+ inreg.esi.w[0] = OFFS(dapa);
+ inreg.ds = SEG(dapa);
+ inreg.edx.b[0] = diskinfo->disk;
+ inreg.eax.b[1] = 0x43; /* Extended write */
+ } else {
+ unsigned int c, h, s, t;
+ /*
+ * if we passed lba + count check and we get here, that means that
+ * lbacnt was calculated from chs geometry (or faked from 1/1/1), thus
+ * 32bits are perfectly enough and lbacnt corresponds to cylinder
+ * boundary
+ */
+ s = lba % diskinfo->spt;
+ t = lba / diskinfo->spt;
+ h = t % diskinfo->head;
+ c = t / diskinfo->head;
+
+ inreg.eax.b[0] = count;
+ inreg.eax.b[1] = 0x03; /* Write */
+ inreg.ecx.b[1] = c;
+ inreg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1);
+ inreg.edx.b[1] = h;
+ inreg.edx.b[0] = diskinfo->disk;
+ inreg.ebx.w[0] = OFFS(buf);
+ inreg.es = SEG(buf);
+ }
+
+ if (disk_int13_retry(&inreg, NULL))
+ goto out;
+
+ rv = 0; /* ok */
+out:
+ lfree(dapa);
+ lfree(buf);
+ return rv;
+}
+
+/**
+ * Write disk blocks and verify they were written.
+ *
+ * @v diskinfo The disk drive to write to
+ * @v lba The logical block address to begin writing at
+ * @v buf The data to write
+ * @v count The number of sectors to write
+ * @ret rv 0 upon success, -1 upon failure
+ *
+ * Uses the disk number and information from diskinfo.
+ * Writes sectors to a disk drive starting at lba, then reads them back
+ * to verify they were written correctly.
+ */
+int disk_write_verify_sectors(const struct disk_info *const diskinfo,
+ uint64_t lba, const void *buf, uint8_t count)
+{
+ char *rb;
+ int rv;
+
+ rv = disk_write_sectors(diskinfo, lba, buf, count);
+ if (rv)
+ return rv; /* Write failure */
+ rb = disk_read_sectors(diskinfo, lba, count);
+ if (!rb)
+ return -1; /* Readback failure */
+ rv = memcmp(buf, rb, count * diskinfo->bps);
+ free(rb);
+ return rv ? -1 : 0;
+}
+
+/**
+ * Dump info about a DOS partition entry
+ *
+ * @v part The 16-byte partition entry to examine
+ */
+void disk_dos_part_dump(const struct disk_dos_part_entry *const part)
+{
+ (void)part;
+ dprintf("Partition status _____ : 0x%.2x\n"
+ "Partition CHS start\n"
+ " Cylinder ___________ : 0x%.4x (%u)\n"
+ " Head _______________ : 0x%.2x (%u)\n"
+ " Sector _____________ : 0x%.2x (%u)\n"
+ "Partition type _______ : 0x%.2x\n"
+ "Partition CHS end\n"
+ " Cylinder ___________ : 0x%.4x (%u)\n"
+ " Head _______________ : 0x%.2x (%u)\n"
+ " Sector _____________ : 0x%.2x (%u)\n"
+ "Partition LBA start __ : 0x%.8x (%u)\n"
+ "Partition LBA count __ : 0x%.8x (%u)\n"
+ "-------------------------------\n",
+ part->active_flag,
+ chs_cylinder(part->start),
+ chs_cylinder(part->start),
+ chs_head(part->start),
+ chs_head(part->start),
+ chs_sector(part->start),
+ chs_sector(part->start),
+ part->ostype,
+ chs_cylinder(part->end),
+ chs_cylinder(part->end),
+ chs_head(part->end),
+ chs_head(part->end),
+ chs_sector(part->end),
+ chs_sector(part->end),
+ part->start_lba, part->start_lba, part->length, part->length);
+}
+
+/* Trivial error message output */
+static inline void error(const char *msg)
+{
+ fputs(msg, stderr);
+}
+
+/**
+ * This walk-map effectively reverses the little-endian
+ * portions of a GPT disk/partition GUID for a string representation.
+ * There might be a better header for this...
+ */
+static const char guid_le_walk_map[] = {
+ 3, -1, -1, -1, 0,
+ 5, -1, 0,
+ 3, -1, 0,
+ 2, 1, 0,
+ 1, 1, 1, 1, 1, 1
+};
+
+/**
+ * Fill a buffer with a textual GUID representation.
+ *
+ * @v buf Points to a minimum array of 37 chars
+ * @v id The GUID to represent as text
+ *
+ * The buffer must be >= char[37] and will be populated
+ * with an ASCII NUL C string terminator.
+ * Example: 11111111-2222-3333-4444-444444444444
+ * Endian: LLLLLLLL-LLLL-LLLL-BBBB-BBBBBBBBBBBB
+ */
+void guid_to_str(char *buf, const struct guid *const id)
+{
+ unsigned int i = 0;
+ const char *walker = (const char *)id;
+
+ while (i < sizeof(guid_le_walk_map)) {
+ walker += guid_le_walk_map[i];
+ if (!guid_le_walk_map[i])
+ *buf = '-';
+ else {
+ *buf = ((*walker & 0xF0) >> 4) + '0';
+ if (*buf > '9')
+ *buf += 'A' - '9' - 1;
+ buf++;
+ *buf = (*walker & 0x0F) + '0';
+ if (*buf > '9')
+ *buf += 'A' - '9' - 1;
+ }
+ buf++;
+ i++;
+ }
+ *buf = 0;
+}
+
+/**
+ * Create a GUID structure from a textual GUID representation.
+ *
+ * @v buf Points to a GUID string to parse
+ * @v id Points to a GUID to be populated
+ * @ret (int) Returns 0 upon success, -1 upon failure
+ *
+ * The input buffer must be >= 32 hexadecimal chars and be
+ * terminated with an ASCII NUL. Returns non-zero on failure.
+ * Example: 11111111-2222-3333-4444-444444444444
+ * Endian: LLLLLLLL-LLLL-LLLL-BBBB-BBBBBBBBBBBB
+ */
+int str_to_guid(const char *buf, struct guid *const id)
+{
+ char guid_seq[sizeof(struct guid) * 2];
+ unsigned int i = 0;
+ char *walker = (char *)id;
+
+ while (*buf && i < sizeof(guid_seq)) {
+ switch (*buf) {
+ /* Skip these three characters */
+ case '{':
+ case '}':
+ case '-':
+ break;
+ default:
+ /* Copy something useful to the temp. sequence */
+ if ((*buf >= '0') && (*buf <= '9'))
+ guid_seq[i] = *buf - '0';
+ else if ((*buf >= 'A') && (*buf <= 'F'))
+ guid_seq[i] = *buf - 'A' + 10;
+ else if ((*buf >= 'a') && (*buf <= 'f'))
+ guid_seq[i] = *buf - 'a' + 10;
+ else {
+ /* Or not */
+ error("Illegal character in GUID!\n");
+ return -1;
+ }
+ i++;
+ }
+ buf++;
+ }
+ /* Check for insufficient valid characters */
+ if (i < sizeof(guid_seq)) {
+ error("Too few GUID characters!\n");
+ return -1;
+ }
+ buf = guid_seq;
+ i = 0;
+ while (i < sizeof(guid_le_walk_map)) {
+ if (!guid_le_walk_map[i])
+ i++;
+ walker += guid_le_walk_map[i];
+ *walker = *buf << 4;
+ buf++;
+ *walker |= *buf;
+ buf++;
+ i++;
+ }
+ return 0;
+}
+
+/**
+ * Display GPT partition details.
+ *
+ * @v gpt_part The GPT partition entry to display
+ */
+void disk_gpt_part_dump(const struct disk_gpt_part_entry *const gpt_part)
+{
+ unsigned int i;
+ char guid_text[37];
+
+ dprintf("----------------------------------\n"
+ "GPT part. LBA first __ : 0x%.16llx\n"
+ "GPT part. LBA last ___ : 0x%.16llx\n"
+ "GPT part. attribs ____ : 0x%.16llx\n"
+ "GPT part. name _______ : '",
+ gpt_part->lba_first, gpt_part->lba_last, gpt_part->attribs);
+ for (i = 0; i < sizeof(gpt_part->name); i++) {
+ if (gpt_part->name[i])
+ dprintf("%c", gpt_part->name[i]);
+ }
+ dprintf("'");
+ guid_to_str(guid_text, &gpt_part->type);
+ dprintf("GPT part. type GUID __ : {%s}\n", guid_text);
+ guid_to_str(guid_text, &gpt_part->uid);
+ dprintf("GPT part. unique ID __ : {%s}\n", guid_text);
+}
+
+/**
+ * Display GPT header details.
+ *
+ * @v gpt The GPT header to display
+ */
+void disk_gpt_header_dump(const struct disk_gpt_header *const gpt)
+{
+ char guid_text[37];
+
+ printf("GPT sig ______________ : '%8.8s'\n"
+ "GPT major revision ___ : 0x%.4x\n"
+ "GPT minor revision ___ : 0x%.4x\n"
+ "GPT header size ______ : 0x%.8x\n"
+ "GPT header checksum __ : 0x%.8x\n"
+ "GPT reserved _________ : '%4.4s'\n"
+ "GPT LBA current ______ : 0x%.16llx\n"
+ "GPT LBA alternative __ : 0x%.16llx\n"
+ "GPT LBA first usable _ : 0x%.16llx\n"
+ "GPT LBA last usable __ : 0x%.16llx\n"
+ "GPT LBA part. table __ : 0x%.16llx\n"
+ "GPT partition count __ : 0x%.8x\n"
+ "GPT partition size ___ : 0x%.8x\n"
+ "GPT part. table chksum : 0x%.8x\n",
+ gpt->sig,
+ gpt->rev.fields.major,
+ gpt->rev.fields.minor,
+ gpt->hdr_size,
+ gpt->chksum,
+ gpt->reserved1,
+ gpt->lba_cur,
+ gpt->lba_alt,
+ gpt->lba_first_usable,
+ gpt->lba_last_usable,
+ gpt->lba_table, gpt->part_count, gpt->part_size, gpt->table_chksum);
+ guid_to_str(guid_text, &gpt->disk_guid);
+ printf("GPT disk GUID ________ : {%s}\n", guid_text);
+}
diff --git a/com32/lib/syslinux/dump_mmap.c b/com32/lib/syslinux/dump_mmap.c
index 3f1e340b..85638cd9 100644
--- a/com32/lib/syslinux/dump_mmap.c
+++ b/com32/lib/syslinux/dump_mmap.c
@@ -28,20 +28,22 @@
/*
* dump_mmap.c
*
- * Writes a syslinux_memmap out to a specified file. This is
- * intended for debugging.
+ * Writes a syslinux_memmap out to a dprintf.
*/
#include <stdio.h>
+#include <dprintf.h>
#include <syslinux/movebits.h>
-void syslinux_dump_memmap(FILE * file, struct syslinux_memmap *memmap)
+#ifdef DEBUG
+void syslinux_dump_memmap(struct syslinux_memmap *memmap)
{
- fprintf(file, "%10s %10s %10s\n"
+ dprintf("%10s %10s %10s\n"
"--------------------------------\n", "Start", "Length", "Type");
while (memmap->next) {
- fprintf(file, "0x%08x 0x%08x %10d\n", memmap->start,
+ dprintf("0x%08x 0x%08x %10d\n", memmap->start,
memmap->next->start - memmap->start, memmap->type);
memmap = memmap->next;
}
}
+#endif
diff --git a/com32/lib/syslinux/dump_movelist.c b/com32/lib/syslinux/dump_movelist.c
index 282d0068..4042ce96 100644
--- a/com32/lib/syslinux/dump_movelist.c
+++ b/com32/lib/syslinux/dump_movelist.c
@@ -33,14 +33,17 @@
*/
#include <stdio.h>
+#include <dprintf.h>
#include <syslinux/movebits.h>
-void syslinux_dump_movelist(FILE * file, struct syslinux_movelist *ml)
+#ifdef DEBUG
+void syslinux_dump_movelist(struct syslinux_movelist *ml)
{
- fprintf(file, "%10s %10s %10s\n"
+ dprintf("%10s %10s %10s\n"
"--------------------------------\n", "Dest", "Src", "Length");
while (ml) {
- fprintf(file, "0x%08x 0x%08x 0x%08x\n", ml->dst, ml->src, ml->len);
+ dprintf("0x%08x 0x%08x 0x%08x\n", ml->dst, ml->src, ml->len);
ml = ml->next;
}
}
+#endif
diff --git a/com32/lib/syslinux/idle.c b/com32/lib/syslinux/idle.c
index 6413d331..33e8035c 100644
--- a/com32/lib/syslinux/idle.c
+++ b/com32/lib/syslinux/idle.c
@@ -33,6 +33,7 @@
#include <stddef.h>
#include <com32.h>
+#include <core.h>
#include <syslinux/pmapi.h>
#include <syslinux/idle.h>
diff --git a/com32/elflink/ldlinux/ipappend.c b/com32/lib/syslinux/ipappend.c
index 45e2c3a7..3eda48cf 100644
--- a/com32/elflink/ldlinux/ipappend.c
+++ b/com32/lib/syslinux/ipappend.c
@@ -31,18 +31,20 @@
* Get ipappend strings
*/
-#include <syslinux/firmware.h>
#include <syslinux/config.h>
+#include <klibc/compiler.h>
+#include <core.h>
struct syslinux_ipappend_strings __syslinux_ipappend_strings;
+static const char *syslinux_ipappend_string_list[32];
-void __syslinux_get_ipappend_strings(void)
+void __constructor __syslinux_get_ipappend_strings(void)
{
- char *list;
- int count;
+ unsigned int i;
- if (firmware->ipappend_strings(&list, &count)) {
- __syslinux_ipappend_strings.count = count;
- __syslinux_ipappend_strings.ptr = list;
- }
+ __syslinux_ipappend_strings.count = (size_t)numIPAppends;
+ __syslinux_ipappend_strings.ptr = syslinux_ipappend_string_list;
+
+ for (i = 0; i < (size_t)numIPAppends; i++)
+ syslinux_ipappend_string_list[i] = (const char *)(size_t)IPAppends[i];
}
diff --git a/com32/lib/syslinux/keyboard.c b/com32/lib/syslinux/keyboard.c
index feafde0d..03bd216a 100644
--- a/com32/lib/syslinux/keyboard.c
+++ b/com32/lib/syslinux/keyboard.c
@@ -26,19 +26,13 @@
* ----------------------------------------------------------------------- */
#include <syslinux/keyboard.h>
-#include <com32.h>
+#include <core.h>
struct syslinux_keyboard_map __syslinux_keyboard_map;
void __constructor __syslinux_get_keyboard_map(void)
{
- static com32sys_t reg;
-
- reg.eax.w[0] = 0x001e;
- __intcall(0x22, &reg, &reg);
- if (!(reg.eflags.l & EFLAGS_CF)) {
- __syslinux_keyboard_map.version = reg.eax.w[0];
- __syslinux_keyboard_map.length = reg.ecx.w[0];
- __syslinux_keyboard_map.map = MK_PTR(reg.es, reg.ebx.w[0]);
- }
+ __syslinux_keyboard_map.version = 1;
+ __syslinux_keyboard_map.length = sizeof(KbdMap);
+ __syslinux_keyboard_map.map = (void *)KbdMap;
}
diff --git a/com32/lib/syslinux/load_linux.c b/com32/lib/syslinux/load_linux.c
index 86ea862a..4a8a1fd3 100644
--- a/com32/lib/syslinux/load_linux.c
+++ b/com32/lib/syslinux/load_linux.c
@@ -38,23 +38,17 @@
#include <inttypes.h>
#include <string.h>
#include <minmax.h>
+#include <errno.h>
#include <suffix_number.h>
+#include <graphics.h>
+#include <dprintf.h>
+
#include <syslinux/align.h>
#include <syslinux/linux.h>
#include <syslinux/bootrm.h>
#include <syslinux/movebits.h>
#include <syslinux/firmware.h>
-#ifndef DEBUG
-# define DEBUG 0
-#endif
-#if DEBUG
-# include <stdio.h>
-# define dprintf printf
-#else
-# define dprintf(f, ...) ((void)0)
-#endif
-
#define BOOT_MAGIC 0xAA55
#define LINUX_MAGIC ('H' + ('d' << 8) + ('r' << 16) + ('S' << 24))
#define OLD_CMDLINE_MAGIC 0xA33F
@@ -131,13 +125,16 @@ static int map_initramfs(struct syslinux_movelist **fraglist,
}
int bios_boot_linux(void *kernel_buf, size_t kernel_size,
- struct initramfs *initramfs, char *cmdline)
+ struct initramfs *initramfs,
+ struct setup_data *setup_data,
+ char *cmdline)
{
struct linux_header hdr, *whdr;
size_t real_mode_size, prot_mode_size;
addr_t real_mode_base, prot_mode_base;
addr_t irf_size;
size_t cmdline_size, cmdline_offset;
+ struct setup_data *sdp;
struct syslinux_rm_regs regs;
struct syslinux_movelist *fraglist = NULL;
struct syslinux_memmap *mmap = NULL;
@@ -260,10 +257,8 @@ int bios_boot_linux(void *kernel_buf, size_t kernel_size,
if (!mmap || !amap)
goto bail;
-#if DEBUG
dprintf("Initial memory map:\n");
- syslinux_dump_memmap(stdout, mmap);
-#endif
+ syslinux_dump_memmap(mmap);
/* If the user has specified a memory limit, mark that as unavailable.
Question: should we mark this off-limit in the mmap as well (meaning
@@ -402,6 +397,49 @@ int bios_boot_linux(void *kernel_buf, size_t kernel_size,
}
}
+ if (setup_data) {
+ uint64_t *prev_ptr = &whdr->setup_data;
+
+ for (sdp = setup_data->next; sdp != setup_data; sdp = sdp->next) {
+ struct syslinux_memmap *ml;
+ const addr_t align_mask = 15; /* Header is 16 bytes */
+ addr_t best_addr = 0;
+ size_t size = sdp->hdr.len + sizeof(sdp->hdr);
+
+ if (!sdp->data || !sdp->hdr.len)
+ continue;
+
+ if (hdr.version < 0x0209) {
+ /* Setup data not supported */
+ errno = ENXIO; /* Kind of arbitrary... */
+ goto bail;
+ }
+
+ for (ml = amap; ml->type != SMT_END; ml = ml->next) {
+ addr_t adj_start = (ml->start + align_mask) & ~align_mask;
+ addr_t adj_end = ml->next->start & ~align_mask;
+
+ if (ml->type == SMT_FREE && adj_end - adj_start >= size)
+ best_addr = (adj_end - size) & ~align_mask;
+ }
+
+ if (!best_addr)
+ goto bail;
+
+ *prev_ptr = best_addr;
+ prev_ptr = &sdp->hdr.next;
+
+ if (syslinux_add_memmap(&amap, best_addr, size, SMT_ALLOC))
+ goto bail;
+ if (syslinux_add_movelist(&fraglist, best_addr,
+ (addr_t)&sdp->hdr, sizeof sdp->hdr))
+ goto bail;
+ if (syslinux_add_movelist(&fraglist, best_addr + sizeof sdp->hdr,
+ (addr_t)sdp->data, sdp->hdr.len))
+ goto bail;
+ }
+ }
+
/* Set up the registers on entry */
memset(&regs, 0, sizeof regs);
regs.es = regs.ds = regs.ss = regs.fs = regs.gs = real_mode_base >> 4;
@@ -410,16 +448,25 @@ int bios_boot_linux(void *kernel_buf, size_t kernel_size,
/* Linux is OK with sp = 0 = 64K, but perhaps other things aren't... */
regs.esp.w[0] = min(cmdline_offset, (size_t) 0xfff0);
-#if DEBUG
dprintf("Final memory map:\n");
- syslinux_dump_memmap(stdout, mmap);
+ syslinux_dump_memmap(mmap);
dprintf("Final available map:\n");
- syslinux_dump_memmap(stdout, amap);
+ syslinux_dump_memmap(amap);
dprintf("Initial movelist:\n");
- syslinux_dump_movelist(stdout, fraglist);
-#endif
+ syslinux_dump_movelist(fraglist);
+
+ if (video_mode != 0x0f04) {
+ /*
+ * video_mode is not "current", so if we are in graphics mode we
+ * need to revert to text mode...
+ */
+ dprintf("*** Calling syslinux_force_text_mode()...\n");
+ syslinux_force_text_mode();
+ } else {
+ dprintf("*** vga=current, not calling syslinux_force_text_mode()...\n");
+ }
syslinux_shuffle_boot_rm(fraglist, mmap, 0, &regs);
@@ -431,7 +478,15 @@ bail:
}
int syslinux_boot_linux(void *kernel_buf, size_t kernel_size,
- struct initramfs *initramfs, char *cmdline)
+ struct initramfs *initramfs,
+ struct setup_data *setup_data,
+ char *cmdline)
{
- firmware->boot_linux(kernel_buf, kernel_size, initramfs, cmdline);
+ if (!firmware->boot_linux) {
+ printf("No linux boot function registered for firmware\n");
+ return -1;
+ }
+
+ firmware->boot_linux(kernel_buf, kernel_size, initramfs,
+ setup_data, cmdline);
}
diff --git a/com32/lib/syslinux/localboot.c b/com32/lib/syslinux/localboot.c
index 3b480c71..16016a9d 100644
--- a/com32/lib/syslinux/localboot.c
+++ b/com32/lib/syslinux/localboot.c
@@ -28,15 +28,11 @@
#include <syslinux/boot.h>
#include <stddef.h>
#include <com32.h>
+#include <localboot.h>
/* This returns only on failure */
-void syslinux_local_boot(uint16_t flags)
+void syslinux_local_boot(int16_t flags)
{
- static com32sys_t ireg;
-
- ireg.eax.w[0] = 0x0014;
- ireg.edx.w[0] = flags;
-
- __intcall(0x22, &ireg, NULL);
+ local_boot(flags);
}
diff --git a/com32/lib/syslinux/movebits.c b/com32/lib/syslinux/movebits.c
index bd5ce0e8..7a05f3c1 100644
--- a/com32/lib/syslinux/movebits.c
+++ b/com32/lib/syslinux/movebits.c
@@ -48,21 +48,7 @@
#include <stdbool.h>
#include <syslinux/movebits.h>
-
-#ifndef DEBUG
-# ifdef TEST
-# define DEBUG 1
-# else
-# define DEBUG 0
-# endif
-#endif
-
-#if DEBUG
-# include <stdio.h>
-# define dprintf printf
-#else
-# define dprintf(...) ((void)0)
-#endif
+#include <dprintf.h>
static jmp_buf new_movelist_bail;
@@ -242,10 +228,8 @@ static void shuffle_dealias(struct syslinux_movelist **fraglist,
addr_t ps, pe, xs, xe, delta;
bool advance;
-#if DEBUG
dprintf("Before alias resolution:\n");
- syslinux_dump_movelist(stdout, *fraglist);
-#endif
+ syslinux_dump_movelist(*fraglist);
*postcopy = NULL;
@@ -316,12 +300,10 @@ restart:
;
}
-#if DEBUG
dprintf("After alias resolution:\n");
- syslinux_dump_movelist(stdout, *fraglist);
+ syslinux_dump_movelist(*fraglist);
dprintf("Post-shuffle copies:\n");
- syslinux_dump_movelist(stdout, *postcopy);
-#endif
+ syslinux_dump_movelist(*postcopy);
}
/*
@@ -449,12 +431,10 @@ nomem:
/* As long as there are unprocessed fragments in the chain... */
while ((fp = &frags, f = *fp)) {
-#if DEBUG
dprintf("Current free list:\n");
- syslinux_dump_memmap(stdout, mmap);
+ syslinux_dump_memmap(mmap);
dprintf("Current frag list:\n");
- syslinux_dump_movelist(stdout, frags);
-#endif
+ syslinux_dump_movelist(frags);
/* Scan for fragments which can be discarded without action. */
if (f->src == f->dst) {
@@ -692,16 +672,16 @@ int main(int argc, char *argv[])
*fep = NULL;
- printf("Input move list:\n");
- syslinux_dump_movelist(stdout, frags);
- printf("Input free list:\n");
- syslinux_dump_memmap(stdout, memmap);
+ dprintf("Input move list:\n");
+ syslinux_dump_movelist(frags);
+ dprintf("Input free list:\n");
+ syslinux_dump_memmap(memmap);
if (syslinux_compute_movelist(&moves, frags, memmap)) {
printf("Failed to compute a move sequence\n");
return 1;
} else {
- printf("Final move list:\n");
+ dprintf("Final move list:\n");
syslinux_dump_movelist(stdout, moves);
return 0;
}
diff --git a/com32/lib/syslinux/pxe_dns.c b/com32/lib/syslinux/pxe_dns.c
index 6620396f..b813b543 100644
--- a/com32/lib/syslinux/pxe_dns.c
+++ b/com32/lib/syslinux/pxe_dns.c
@@ -43,12 +43,12 @@
or -1 on invocation failure */
uint32_t pxe_dns(const char *hostname)
{
- com32sys_t regs;
union {
unsigned char b[4];
uint32_t ip;
} q;
char *lm_hostname;
+ uint32_t status;
/* Is this a dot-quad? */
if (sscanf(hostname, "%hhu.%hhu.%hhu.%hhu",
@@ -59,17 +59,9 @@ uint32_t pxe_dns(const char *hostname)
if (!lm_hostname)
return 0;
- memset(&regs, 0, sizeof regs);
- regs.eax.w[0] = 0x0010;
- regs.es = SEG(lm_hostname);
- /* regs.ebx.w[0] = OFFS(lm_hostname); */
-
- __intcall(0x22, &regs, &regs);
+ status = dns_resolv(lm_hostname);
lfree(lm_hostname);
- if (regs.eflags.l & EFLAGS_CF)
- return 0;
-
- return regs.eax.l;
+ return status;
}
diff --git a/com32/lib/syslinux/pxe_get_cached.c b/com32/lib/syslinux/pxe_get_cached.c
index 47040378..a090a4c9 100644
--- a/com32/lib/syslinux/pxe_get_cached.c
+++ b/com32/lib/syslinux/pxe_get_cached.c
@@ -43,7 +43,6 @@
int pxe_get_cached_info(int level, void **buf, size_t * len)
{
const int max_dhcp_packet = 2048;
- com32sys_t regs;
t_PXENV_GET_CACHED_INFO *gci;
void *bbuf, *nbuf;
int err;
@@ -52,12 +51,6 @@ int pxe_get_cached_info(int level, void **buf, size_t * len)
if (!gci)
return -1;
- memset(&regs, 0, sizeof regs);
- regs.eax.w[0] = 0x0009;
- regs.ebx.w[0] = PXENV_GET_CACHED_INFO;
- regs.es = SEG(gci);
- /* regs.edi.w[0] = OFFS(gci); */
-
bbuf = &gci[1];
gci->Status = PXENV_STATUS_FAILURE;
@@ -66,9 +59,9 @@ int pxe_get_cached_info(int level, void **buf, size_t * len)
gci->Buffer.seg = SEG(bbuf);
gci->Buffer.offs = OFFS(bbuf);
- __intcall(0x22, &regs, &regs);
+ err = pxe_call(PXENV_GET_CACHED_INFO, gci);
- if (regs.eflags.l & EFLAGS_CF) {
+ if (err) {
err = -1;
goto exit;
}
diff --git a/com32/lib/syslinux/pxe_get_nic.c b/com32/lib/syslinux/pxe_get_nic.c
index b301a75a..6e256f92 100644
--- a/com32/lib/syslinux/pxe_get_nic.c
+++ b/com32/lib/syslinux/pxe_get_nic.c
@@ -42,25 +42,19 @@
or -1 on invocation failure */
int pxe_get_nic_type(t_PXENV_UNDI_GET_NIC_TYPE *gnt)
{
- com32sys_t regs;
t_PXENV_UNDI_GET_NIC_TYPE *lgnt;
+ int err;
lgnt = lzalloc(sizeof *lgnt);
if (!lgnt)
return -1;
- memset(&regs, 0, sizeof regs);
- regs.eax.w[0] = 0x0009;
- regs.ebx.w[0] = PXENV_UNDI_GET_NIC_TYPE;
- regs.es = SEG(lgnt);
- /* regs.edi.w[0] = OFFS(lgnt); */
-
- __intcall(0x22, &regs, &regs);
+ err = pxe_call(PXENV_UNDI_GET_NIC_TYPE, lgnt);
memcpy(gnt, lgnt, sizeof(t_PXENV_UNDI_GET_NIC_TYPE));
lfree(lgnt);
- if (regs.eflags.l & EFLAGS_CF)
+ if (err)
return -1;
return gnt->Status;
diff --git a/com32/lib/syslinux/run_command.c b/com32/lib/syslinux/run_command.c
index a0ac9a0d..0efb61f2 100644
--- a/com32/lib/syslinux/run_command.c
+++ b/com32/lib/syslinux/run_command.c
@@ -28,21 +28,16 @@
#include <syslinux/boot.h>
#include <stddef.h>
#include <string.h>
-#include <com32.h>
+#include <core.h>
int syslinux_run_command(const char *command)
{
- static com32sys_t ireg;
char *lm_command = lstrdup(command);
if (!lm_command)
return -1;
- ireg.eax.w[0] = 0x0003;
- ireg.es = SEG(lm_command);
- /* ireg.ebx.w[0] = OFFS(lm_command); */
-
- __intcall(0x22, &ireg, NULL);
+ create_args_and_load(lm_command);
/* Should not return even on failure, but in case... */
lfree(lm_command);
diff --git a/com32/lib/syslinux/run_default.c b/com32/lib/syslinux/run_default.c
index 8dc9fbe4..0cfa5470 100644
--- a/com32/lib/syslinux/run_default.c
+++ b/com32/lib/syslinux/run_default.c
@@ -26,16 +26,14 @@
* ----------------------------------------------------------------------- */
#include <syslinux/boot.h>
+#include <core.h>
#include <stddef.h>
-#include <com32.h>
+
+extern const char *default_cmd;
__noreturn syslinux_run_default(void)
{
- static com32sys_t ireg;
-
- ireg.eax.w[0] = 0x0004;
- __intcall(0x22, &ireg, NULL);
-
+ load_kernel(default_cmd);
/* Should not return even on failure */
for (;;) ;
}
diff --git a/com32/lib/syslinux/runimage.c b/com32/lib/syslinux/runimage.c
index d5cdbc62..4391114c 100644
--- a/com32/lib/syslinux/runimage.c
+++ b/com32/lib/syslinux/runimage.c
@@ -34,15 +34,18 @@
#include <stdlib.h>
#include <string.h>
#include <syslinux/boot.h>
-#include <com32.h>
+#include <syslinux/config.h>
+#include <core.h>
+
+extern unsigned int ipappend;
void syslinux_run_kernel_image(const char *filename, const char *cmdline,
uint32_t ipappend_flags, uint32_t type)
{
- static com32sys_t ireg;
char *bbfilename = NULL;
char *bbcmdline = NULL;
+
bbfilename = lstrdup(filename);
if (!bbfilename)
goto fail;
@@ -51,16 +54,10 @@ void syslinux_run_kernel_image(const char *filename, const char *cmdline,
if (!bbcmdline)
goto fail;
+ if (syslinux_filesystem() == SYSLINUX_FS_PXELINUX)
+ ipappend = ipappend_flags;
- ireg.eax.w[0] = 0x0016;
- ireg.ds = SEG(bbfilename);
- /* ireg.esi.w[0] = OFFS(bbfilename); */
- ireg.es = SEG(bbcmdline);
- /* ireg.ebx.w[0] = OFFS(bbcmdline); */
- ireg.ecx.l = ipappend_flags;
- ireg.edx.l = type;
-
- __intcall(0x22, &ireg, 0);
+ execute(bbfilename, type);
fail:
if (bbcmdline)
diff --git a/com32/lib/syslinux/serial.c b/com32/lib/syslinux/serial.c
index 4c6c1995..bc41acfc 100644
--- a/com32/lib/syslinux/serial.c
+++ b/com32/lib/syslinux/serial.c
@@ -35,31 +35,16 @@
#include <syslinux/firmware.h>
#include <syslinux/config.h>
#include <string.h>
-#include <com32.h>
struct syslinux_serial_console_info __syslinux_serial_console_info;
-void bios_get_serial_console_info(uint16_t *iobase, uint16_t *divisor,
- uint16_t *flowctl)
-{
- static com32sys_t reg;
-
- memset(&reg, 0, sizeof reg);
- reg.eax.w[0] = 0x000b;
- __intcall(0x22, &reg, &reg);
-
- *iobase = reg.edx.w[0];
- *divisor = reg.ecx.w[0];
- *flowctl = reg.ebx.w[0];
-}
-
void __constructor __syslinux_get_serial_console_info(void)
{
- uint16_t iobase, divisor, flowctl;
+ uint16_t iobase, divisor, flowctl;
- firmware->get_serial_console_info(&iobase, &divisor, &flowctl);
+ firmware->get_serial_console_info(&iobase, &divisor, &flowctl);
- __syslinux_serial_console_info.iobase = iobase;
- __syslinux_serial_console_info.divisor = divisor;
- __syslinux_serial_console_info.flowctl = flowctl;
+ __syslinux_serial_console_info.iobase = iobase;
+ __syslinux_serial_console_info.divisor = divisor;
+ __syslinux_serial_console_info.flowctl = flowctl;
}
diff --git a/com32/lib/syslinux/setup_data.c b/com32/lib/syslinux/setup_data.c
new file mode 100644
index 00000000..a36c5b61
--- /dev/null
+++ b/com32/lib/syslinux/setup_data.c
@@ -0,0 +1,47 @@
+#include <stdlib.h>
+#include <syslinux/linux.h>
+#include <syslinux/loadfile.h>
+
+struct setup_data *setup_data_init(void)
+{
+ struct setup_data *setup_data;
+
+ setup_data = zalloc(sizeof(*setup_data));
+ if (!setup_data)
+ return NULL;
+
+ setup_data->prev = setup_data->next = setup_data;
+ return setup_data;
+}
+
+int setup_data_add(struct setup_data *head, uint32_t type,
+ const void *data, size_t data_len)
+{
+ struct setup_data *setup_data;
+
+ setup_data = zalloc(sizeof(*setup_data));
+ if (!setup_data)
+ return -1;
+
+ setup_data->data = data;
+ setup_data->hdr.len = data_len;
+ setup_data->hdr.type = type;
+ setup_data->prev = head->prev;
+ setup_data->next = head;
+ head->prev->next = setup_data;
+ head->prev = setup_data;
+
+ return 0;
+}
+
+int setup_data_load(struct setup_data *head, uint32_t type,
+ const char *filename)
+{
+ void *data;
+ size_t len;
+
+ if (loadfile(filename, &data, &len))
+ return -1;
+
+ return setup_data_add(head, type, data, len);
+}
diff --git a/com32/lib/syslinux/shuffle.c b/com32/lib/syslinux/shuffle.c
index 3f300a6c..d014340c 100644
--- a/com32/lib/syslinux/shuffle.c
+++ b/com32/lib/syslinux/shuffle.c
@@ -38,27 +38,12 @@
#include <string.h>
#include <inttypes.h>
#include <com32.h>
+#include <core.h>
#include <minmax.h>
+#include <dprintf.h>
#include <syslinux/movebits.h>
#include <klibc/compiler.h>
-#ifndef DEBUG
-# define DEBUG 0
-#endif
-
-#define dprintf(f, ...) ((void)0)
-#define dprintf2(f, ...) ((void)0)
-
-#if DEBUG
-# include <stdio.h>
-# undef dprintf
-# define dprintf printf
-# if DEBUG > 1
-# undef dprintf2
-# define dprintf2 printf
-# endif
-#endif
-
struct shuffle_descriptor {
uint32_t dst, src, len;
};
@@ -68,12 +53,8 @@ static int shuffler_size;
static void __syslinux_get_shuffer_size(void)
{
if (!shuffler_size) {
- static com32sys_t reg;
-
- reg.eax.w[0] = 0x0023;
- __intcall(0x22, &reg, &reg);
-
- shuffler_size = (reg.eflags.l & EFLAGS_CF) ? 2048 : reg.ecx.w[0];
+ /* +15 padding is to guarantee alignment */
+ shuffler_size = __bcopyxx_len + 15;
}
}
diff --git a/com32/lib/syslinux/version.c b/com32/lib/syslinux/version.c
index 15b617b0..1cd2efd3 100644
--- a/com32/lib/syslinux/version.c
+++ b/com32/lib/syslinux/version.c
@@ -27,20 +27,23 @@
#include <syslinux/config.h>
#include <klibc/compiler.h>
-#include <com32.h>
+#include <core.h>
+#include <../../../version.h>
struct syslinux_version __syslinux_version;
void __constructor __syslinux_get_version(void)
{
- static com32sys_t reg;
+ __syslinux_version.version = (VERSION_MAJOR << 8) + VERSION_MINOR;
- reg.eax.w[0] = 0x0001;
- __intcall(0x22, &reg, &reg);
+ /* We no longer support the COMBOOT API */
+ __syslinux_version.max_api = 0xffff;
- __syslinux_version.version = reg.ecx.w[0];
- __syslinux_version.max_api = reg.eax.w[0];
- __syslinux_version.filesystem = reg.edx.b[0];
- __syslinux_version.version_string = MK_PTR(reg.es, reg.esi.w[0]);
- __syslinux_version.copyright_string = MK_PTR(reg.es, reg.edi.w[0]);
+ __syslinux_version.filesystem = syslinux_filesystem();
+
+ /* Skip leading CR LF */
+ __syslinux_version.version_string = &syslinux_banner[2];
+
+ /* Skip leading space */
+ __syslinux_version.copyright_string = &copyright_str[1];
}
diff --git a/com32/lib/syslinux/video/fontquery.c b/com32/lib/syslinux/video/fontquery.c
index dd5d86e3..ac1fab3f 100644
--- a/com32/lib/syslinux/video/fontquery.c
+++ b/com32/lib/syslinux/video/fontquery.c
@@ -31,24 +31,18 @@
*/
#include <syslinux/video.h>
-#include <com32.h>
+#include <graphics.h>
/*
* Returns height of font or zero if no custom font loaded
*/
int syslinux_font_query(uint8_t **font)
{
- static com32sys_t ireg;
- com32sys_t oreg;
- int height;
+ if (!UserFont)
+ return 0;
- ireg.eax.w[0] = 0x0018;
- __intcall(0x22, &ireg, &oreg);
+ *font = (uint8_t *)fontbuf;
- height = !(oreg.eflags.l & EFLAGS_CF) ? oreg.eax.b[0] : 0;
- if (height)
- *font = MK_PTR(oreg.es, oreg.ebx.w[0]);
-
- return height;
+ return VGAFontSize;
}
diff --git a/com32/lib/syslinux/video/reportmode.c b/com32/lib/syslinux/video/reportmode.c
index 57fd6fdc..2a2c5770 100644
--- a/com32/lib/syslinux/video/reportmode.c
+++ b/com32/lib/syslinux/video/reportmode.c
@@ -31,15 +31,12 @@
*/
#include <syslinux/video.h>
-#include <com32.h>
+#include <graphics.h>
void syslinux_report_video_mode(uint16_t flags, uint16_t xsize, uint16_t ysize)
{
- static com32sys_t ireg;
+ if (flags > 0x0f)
+ return;
- ireg.eax.w[0] = 0x0017;
- ireg.ebx.w[0] = flags;
- ireg.ecx.w[0] = xsize;
- ireg.edx.w[0] = ysize;
- __intcall(0x22, &ireg, NULL);
+ using_vga(flags, xsize, ysize);
}
diff --git a/com32/lib/syslinux/zonelist.c b/com32/lib/syslinux/zonelist.c
index b548211f..7034c4be 100644
--- a/com32/lib/syslinux/zonelist.c
+++ b/com32/lib/syslinux/zonelist.c
@@ -39,21 +39,7 @@
#include <stdlib.h>
#include <syslinux/align.h>
#include <syslinux/movebits.h>
-
-#ifndef DEBUG
-# ifdef TEST
-# define DEBUG 1
-# else
-# define DEBUG 0
-# endif
-#endif
-
-#if DEBUG
-# include <stdio.h>
-# define dprintf printf
-#else
-# define dprintf(...) ((void)0)
-#endif
+#include <dprintf.h>
/*
* Create an empty syslinux_memmap list.
@@ -96,10 +82,8 @@ int syslinux_add_memmap(struct syslinux_memmap **list,
struct syslinux_memmap *range;
enum syslinux_memmap_types oldtype;
-#if DEBUG
dprintf("Input memmap:\n");
- syslinux_dump_memmap(stdout, *list);
-#endif
+ syslinux_dump_memmap(*list);
/* Remove this to make len == 0 mean all of memory */
if (len == 0)
@@ -164,10 +148,8 @@ int syslinux_add_memmap(struct syslinux_memmap **list,
}
}
-#if DEBUG
dprintf("After adding (%#x,%#x,%d):\n", start, len, type);
- syslinux_dump_memmap(stdout, *list);
-#endif
+ syslinux_dump_memmap(*list);
return 0;
}
diff --git a/com32/lib/vdprintf.c b/com32/lib/vdprintf.c
index 76da012d..bcf55bb7 100644
--- a/com32/lib/vdprintf.c
+++ b/com32/lib/vdprintf.c
@@ -10,9 +10,7 @@
#include <sys/io.h>
#include <sys/cpu.h>
-#undef DEBUG
-#define DEBUG 1
-#include <dprintf.h>
+#ifdef DEBUG_PORT
#define BUFFER_SIZE 4096
@@ -31,10 +29,6 @@ enum serial_port_regs {
SCR = 7,
};
-#ifndef DEBUG_PORT
-# define DEBUG_PORT 0x03f8 /* I/O base address */
-#endif
-
static const uint16_t debug_base = DEBUG_PORT;
static void debug_putc(char c)
@@ -49,14 +43,13 @@ static void debug_putc(char c)
void vdprintf(const char *format, va_list ap)
{
- int rv, _rv;
+ int rv;
char buffer[BUFFER_SIZE];
char *p;
static bool debug_init = false;
static bool debug_ok = false;
- _rv = rv = vsnprintf(buffer, BUFFER_SIZE, format, ap);
-
+ rv = vsnprintf(buffer, BUFFER_SIZE, format, ap);
if (rv < 0)
return;
@@ -113,6 +106,6 @@ void vdprintf(const char *format, va_list ap)
p = buffer;
while (rv--)
debug_putc(*p++);
-
- _fwrite(buffer, _rv, stdout);
}
+
+#endif /* DEBUG_PORT */
diff --git a/com32/libupload/cpio.c b/com32/libupload/cpio.c
index b3e1eb78..25b464d4 100644
--- a/com32/libupload/cpio.c
+++ b/com32/libupload/cpio.c
@@ -31,7 +31,7 @@ int cpio_hdr(struct upload_backend *be, uint32_t mode, size_t datalen,
cpio_pad(be);
- sprintf(hdr, "%06o%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x",
+ sprintf(hdr, "%06o%08x%08x%08x%08x%08x%08x%08zx%08x%08x%08x%08x%08x%08x",
070701, /* c_magic */
inode++, /* c_ino */
mode, /* c_mode */
diff --git a/com32/libupload/upload_tftp.c b/com32/libupload/upload_tftp.c
index 5e73c1c5..6a0dacb7 100644
--- a/com32/libupload/upload_tftp.c
+++ b/com32/libupload/upload_tftp.c
@@ -53,7 +53,6 @@ const char *tftp_string_error_message[]={
static int send_ack_packet(struct tftp_state *tftp,
const void *pkt, size_t len)
{
- com32sys_t ireg, oreg;
t_PXENV_UDP_WRITE *uw;
t_PXENV_UDP_READ *ur;
clock_t start;
@@ -67,9 +66,6 @@ static int send_ack_packet(struct tftp_state *tftp,
uw = lmalloc(sizeof *uw + len);
ur = lmalloc(sizeof *ur + RCV_BUF);
- memset(&ireg, 0, sizeof ireg);
- ireg.eax.w[0] = 0x0009;
-
for (timeout = timeouts ; *timeout ; timeout++) {
memset(uw, 0, sizeof *uw);
memcpy(uw+1, pkt, len);
@@ -80,11 +76,7 @@ static int send_ack_packet(struct tftp_state *tftp,
uw->buffer_size = len;
uw->buffer = FAR_PTR(uw+1);
- ireg.ebx.w[0] = PXENV_UDP_WRITE;
- ireg.es = SEG(uw);
- ireg.edi.w[0] = OFFS(uw);
-
- __intcall(0x22, &ireg, &oreg);
+ pxe_call(PXENV_UDP_WRITE, uw);
start = times(NULL);
@@ -97,13 +89,9 @@ static int send_ack_packet(struct tftp_state *tftp,
ur->buffer_size = RCV_BUF;
ur->buffer = FAR_PTR(ur+1);
- ireg.ebx.w[0] = PXENV_UDP_READ;
- ireg.es = SEG(ur);
- ireg.edi.w[0] = OFFS(ur);
- __intcall(0x22, &ireg, &oreg);
+ err = pxe_call(PXENV_UDP_READ, ur);
- if (!(oreg.eflags.l & EFLAGS_CF) &&
- ur->status == PXENV_STATUS_SUCCESS &&
+ if (!err && ur->status == PXENV_STATUS_SUCCESS &&
tftp->srv_ip == ur->src_ip &&
(tftp->srv_port == 0 ||
tftp->srv_port == ur->s_port)) {
diff --git a/com32/libutil/Makefile b/com32/libutil/Makefile
index 13fb4193..93c0c11c 100644
--- a/com32/libutil/Makefile
+++ b/com32/libutil/Makefile
@@ -61,6 +61,6 @@ spotless: clean
install: all
mkdir -m 755 -p $(INSTALLROOT)$(COM32DIR)
- install -m 644 libutil_com.a libutil_lnx.a $(INSTALLROOT)$(COM32DIR)
+ install -m 644 libutil_lnx.a $(INSTALLROOT)$(COM32DIR)
-include .*.d
diff --git a/com32/lua/src/Makefile b/com32/lua/src/Makefile
index f1ffb7e6..01d1f81c 100644
--- a/com32/lua/src/Makefile
+++ b/com32/lua/src/Makefile
@@ -44,6 +44,7 @@ LIBLUA_OBJS += dmi.o
LIBLUA_OBJS += cpu.o
LIBLUA_OBJS += pci.o
LIBLUA_OBJS += vesa.o
+LIBLUA_OBJS += dhcp.o
CFLAGS += -DLUA_ANSI
diff --git a/com32/lua/src/dhcp.c b/com32/lua/src/dhcp.c
new file mode 100644
index 00000000..af948131
--- /dev/null
+++ b/com32/lua/src/dhcp.c
@@ -0,0 +1,358 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2007 H. Peter Anvin - All Rights Reserved
+ * Copyright 2011 Timothy J Gleason <timmgleason_at_gmail.com> - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * dhcp.c
+ *
+ * Adds DHCPINFO functionality to the lua.c32 binary
+ *
+ * gettable() returns a table of the BOOTP message fields returned by
+ * the DHCP server for use in a Lua pxeboot script
+ * See http://tools.ietf.org/html/rfc1542
+ *
+ * lua key value RFC key
+ * -----------------------------------------------------------------------
+ * opcode op message opcode
+ * hardware.type htype Hardware address type
+ * hardware.length hlen Hardware address length
+ * hops hops Used by relay agents
+ * transaction.id xid transaction id
+ * elapsed.seconds secs Secs elapsed since client boot
+ * flags flags DHCP Flags field
+ * client.ip.addr ciaddr client IP addr
+ * your.ip.addr yiaddr 'Your' IP addr. (from server)
+ * server.ip.addr siaddr Boot server IP addr
+ * gateway.ip.addr giaddr Relay agent IP addr
+ * client.mac chaddr Client hardware addr
+ * server.hostname sname Optl. boot server hostname
+ * boot.file file boot file name (ascii path)
+ * magic.cookie cookie Magic cookie
+ *
+ * getoptions() returns a table of the DHCP Options field of the BOOTP
+ * message returned by the DHCP server for use in a Lua pxeboot script.
+ * Many of the options are reurned formatted in as strings in a standard,
+ * recognizable format, such as IP addresses.
+ *
+ * 1, 2, and 4 byte numerical options are returned as integers.
+ *
+ * Other Options with non-standard formats are returned as strings of the
+ * raw binary number that was returned by the DHCP server and must be decoded
+ * in a Lua script
+ *
+ * The Options table returns the Option code as the key except where there
+ * are multiple values returned. In those cases, an extra key increment number
+ * is added to allow individual access to each Option value.
+ *
+ * lua key value value Name
+ * -----------------------------------------------------------------------
+ * 1 Subnet Mask
+ * 6.1 DNS Server [element 1]
+ * 6.2 DNS Server [element 2]
+ * 6.3 DNS Server [element 3]
+ * 209 PXE Configuration File
+ * 21.1 Policy Filter [element 1]
+ * 21.2 Policy Filter [element 2]
+ *
+ * Options that can have a list of values, but contain only one (like Option 6)
+ * will not return with .sub key values.
+ *
+ * Usage:
+ t = dhcp.gettable()
+
+ for k,v in pairs(t) do
+ print(k.." : "..v)
+ end
+ */
+
+#include <stdio.h>
+#include "dhcp.h"
+#include "lua.h"
+#include "lauxlib.h"
+#include "lualib.h"
+#include <syslinux/pxe.h>
+
+#define STR_BUF_SIZE 129 /* Sized to accomdate File field in BOOTP message */
+
+void
+ip_address_list(lua_State *L, uint8_t* value, uint8_t len, uint8_t option )
+{
+ static char op_name[64];
+ static char op_value[255];
+ int loop;
+
+ loop = len/4;
+
+ if ( loop == 1) {
+ sprintf(op_name, "%u", option);
+ lua_pushstring(L, op_name);
+ sprintf(op_value, "%u.%u.%u.%u", value[0], value[1], value[2], value[3]);
+ lua_pushstring(L, op_value);
+ lua_settable(L,-3);
+ } else {
+ for (int done = 0; done < loop; done++){
+ sprintf(op_name, "%u.%d", option, done+1);
+ lua_pushstring(L, op_name);
+ sprintf(op_value, "%u.%u.%u.%u", value[0+(done*4)], value[1+(done*4)], value[2+(done*4)], value[3+(done*4)]);
+ lua_pushstring(L, op_value);
+ lua_settable(L,-3);
+ }
+ }
+
+}
+
+static int dhcp_getoptions(lua_State *L)
+{
+ void* dhcpdata = 0;
+ dhcp_t* dhcp = 0;
+ size_t dhcplen = 0;
+
+ /* Append the DHCP info */
+ if (pxe_get_cached_info(PXENV_PACKET_TYPE_DHCP_ACK,
+ &dhcpdata, &dhcplen))
+ {
+ return 0;
+ }
+
+ dhcp = (dhcp_t*)dhcpdata;
+
+ lua_newtable(L);
+
+ int done = 0;
+ uint8_t* ptr = (uint8_t*)&dhcp->options;
+ uint8_t len;
+ uint8_t option;
+ uint8_t* value;
+ static char op_name[64];
+
+ do {
+ option = *ptr++;
+ len = *ptr++;
+ value = ptr;
+ ptr += len;
+ switch (option) {
+// IP Address formatted lists, including singles
+ case 1:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 16:
+ case 21: /* Policy Filters - address/mask */
+ case 28:
+ case 32:
+ case 33: /* Static routes - destination/router */
+ case 41:
+ case 42:
+ case 44:
+ case 45:
+ case 47:
+ case 48:
+ case 49:
+ case 50:
+ case 51:
+ case 54:
+ case 65:
+ case 68:
+ case 69:
+ case 70:
+ case 71:
+ case 72:
+ case 73:
+ case 74:
+ case 75:
+ case 76:
+ ip_address_list(L, value, len, option);
+ break;
+// 4byte options - numerical
+ case 2:
+ case 24:
+ case 35:
+ case 38:
+ case 58:
+ case 59:
+ case 211:
+ sprintf(op_name, "%u", option);
+ lua_pushstring(L, op_name);
+ lua_pushinteger(L, ntohl(*(long*)value));
+ lua_settable(L,-3);
+ break;
+// 2byte options -numerical
+ case 13:
+ case 22:
+ case 26:
+ case 57:
+ sprintf(op_name, "%u", option);
+ lua_pushstring(L, op_name);
+ lua_pushinteger(L, ntohs(*(short*)value));
+ lua_settable(L,-3);
+ break;
+// 1byte options - numerical
+ case 19:
+ case 20:
+ case 23:
+ case 27:
+ case 29:
+ case 30:
+ case 31:
+ case 34:
+ case 36:
+ case 37:
+ case 39:
+ case 46:
+ case 52:
+ case 53:
+ sprintf(op_name, "%u", option);
+ lua_pushstring(L, op_name);
+ lua_pushinteger(L, *value);
+ lua_settable(L,-3);
+ break;
+ case 255:
+ done = 1;
+ break;
+ default:
+ sprintf(op_name, "%u", option);
+ lua_pushstring(L, op_name);
+ lua_pushlstring(L, (const char*)value, len);
+ lua_settable(L,-3);
+ break;
+ }
+
+ } while (!done);
+
+ return 1;
+}
+
+static int dhcp_gettable(lua_State *L)
+{
+ void* dhcpdata = 0;
+ dhcp_t* dhcp = 0;
+ size_t dhcplen = 0;
+ static char dhcp_arg[STR_BUF_SIZE];
+
+ /* Append the DHCP info */
+ if (pxe_get_cached_info(PXENV_PACKET_TYPE_DHCP_ACK,
+ &dhcpdata, &dhcplen))
+ {
+ return 0;
+ }
+
+ dhcp = (dhcp_t*)dhcpdata;
+
+
+ lua_newtable(L);
+
+ lua_pushstring(L, "opcode");
+ lua_pushinteger(L, dhcp->op);
+ lua_settable(L,-3);
+
+ lua_pushstring(L, "hardware.type");
+ lua_pushinteger(L, dhcp->htype);
+ lua_settable(L,-3);
+
+ lua_pushstring(L, "hardware.length");
+ lua_pushinteger(L, dhcp->hlen);
+ lua_settable(L,-3);
+
+ lua_pushstring(L, "hops");
+ lua_pushinteger(L, dhcp->hops);
+ lua_settable(L,-3);
+
+ lua_pushstring(L, "transaction.id");
+ lua_pushinteger(L, ntohl(dhcp->xid));
+ lua_settable(L,-3);
+
+ lua_pushstring(L, "elapsed.seconds");
+ lua_pushinteger(L, ntohs(dhcp->secs));
+ lua_settable(L,-3);
+
+ lua_pushstring(L, "flags");
+ lua_pushinteger(L, ntohs(dhcp->flags));
+ lua_settable(L,-3);
+
+ sprintf(dhcp_arg, "%u.%u.%u.%u", dhcp->ciaddr[0], dhcp->ciaddr[1], dhcp->ciaddr[2], dhcp->ciaddr[3]);
+ lua_pushstring(L, "client.ip.addr");
+ lua_pushstring(L, dhcp_arg);
+ lua_settable(L,-3);
+
+ sprintf(dhcp_arg, "%u.%u.%u.%u", dhcp->yiaddr[0], dhcp->yiaddr[1], dhcp->yiaddr[2], dhcp->yiaddr[3]);
+ lua_pushstring(L, "your.ip.addr");
+ lua_pushstring(L, dhcp_arg);
+ lua_settable(L,-3);
+
+ sprintf(dhcp_arg, "%u.%u.%u.%u", dhcp->siaddr[0], dhcp->siaddr[1], dhcp->siaddr[2], dhcp->siaddr[3]);
+ lua_pushstring(L, "server.ip.addr");
+ lua_pushstring(L, dhcp_arg);
+ lua_settable(L,-3);
+
+ sprintf(dhcp_arg, "%u.%u.%u.%u", dhcp->giaddr[0], dhcp->giaddr[1], dhcp->giaddr[2], dhcp->giaddr[3]);
+ lua_pushstring(L, "gateway.ip.addr");
+ lua_pushstring(L, dhcp_arg);
+ lua_settable(L,-3);
+
+ sprintf(dhcp_arg, "%02X:%02X:%02X:%02X:%02X:%02X",
+ dhcp->chaddr[0], dhcp->chaddr[1], dhcp->chaddr[2],
+ dhcp->chaddr[3], dhcp->chaddr[4], dhcp->chaddr[5]);
+ lua_pushstring(L, "client.mac");
+ lua_pushstring(L, dhcp_arg);
+ lua_settable(L,-3);
+
+ snprintf(dhcp_arg, STR_BUF_SIZE, "%s", dhcp->sname);
+ dhcp_arg[STR_BUF_SIZE-1] = 0; /* Guarantee for lua_pushstring that dhcp_arg is 0 terminated /*/
+ lua_pushstring(L, "server.hostname");
+ lua_pushstring(L, dhcp_arg);
+ lua_settable(L,-3);
+
+ snprintf(dhcp_arg, STR_BUF_SIZE, "%s", dhcp->file);
+ dhcp_arg[STR_BUF_SIZE-1] = 0; /* Guarantee for lua_pushstring that dhcp_arg is 0 terminated /*/
+ lua_pushstring(L, "boot.file");
+ lua_pushstring(L, dhcp_arg);
+ lua_settable(L,-3);
+
+ sprintf(dhcp_arg, "%u.%u.%u.%u", dhcp->cookie[0], dhcp->cookie[1], dhcp->cookie[2], dhcp->cookie[3]);
+ lua_pushstring(L, "magic.cookie");
+ lua_pushstring(L, dhcp_arg);
+ lua_settable(L,-3);
+
+ return 1;
+}
+
+static const luaL_reg dhcplib[] = {
+ {"gettable", dhcp_gettable},
+ {"getoptions", dhcp_getoptions},
+ {NULL, NULL}
+};
+
+LUALIB_API int luaopen_dhcp (lua_State *L) {
+ luaL_openlib(L, LUA_DHCPLIBNAME, dhcplib, 0);
+ return 1;
+}
diff --git a/com32/lib/syslinux/config.c b/com32/lua/src/dhcp.h
index b27aa827..a398cfc1 100644
--- a/com32/lib/syslinux/config.c
+++ b/com32/lua/src/dhcp.h
@@ -1,6 +1,7 @@
/* ----------------------------------------------------------------------- *
*
- * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2007 H. Peter Anvin - All Rights Reserved
+ * Copyright 2011 Timothy J Gleason <timmgleason_at_gmail.com> - All Rights Reserved
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -25,17 +26,24 @@
*
* ----------------------------------------------------------------------- */
-#include <syslinux/config.h>
-#include <klibc/compiler.h>
-#include <com32.h>
+#include <stdint.h>
-const char *__syslinux_config_file;
+typedef struct dhcp {
+ uint8_t op; /* message opcode */
+ uint8_t htype; /* Hardware address type */
+ uint8_t hlen; /* Hardware address length */
+ uint8_t hops; /* Used by relay agents */
+ uint32_t xid; /* transaction id */
+ uint16_t secs; /* Secs elapsed since client boot */
+ uint16_t flags; /* DHCP Flags field */
+ uint8_t ciaddr[4]; /* client IP addr */
+ uint8_t yiaddr[4]; /* 'Your' IP addr. (from server) */
+ uint8_t siaddr[4]; /* Boot server IP addr */
+ uint8_t giaddr[4]; /* Relay agent IP addr */
+ uint8_t chaddr[16]; /* Client hardware addr */
+ uint8_t sname[64]; /* Optl. boot server hostname */
+ uint8_t file[128]; /* boot file name (ascii path) */
+ uint8_t cookie[4]; /* Magic cookie */
+ uint8_t options[1020]; /* Options */
+} dhcp_t;
-void __constructor __syslinux_get_config_file_name(void)
-{
- static com32sys_t reg;
-
- reg.eax.w[0] = 0x000e;
- __intcall(0x22, &reg, &reg);
- __syslinux_config_file = MK_PTR(reg.es, reg.ebx.w[0]);
-}
diff --git a/com32/lua/src/linit.c b/com32/lua/src/linit.c
index 6c7f63e4..6e978736 100644
--- a/com32/lua/src/linit.c
+++ b/com32/lua/src/linit.c
@@ -33,6 +33,7 @@ static const luaL_Reg lualibs[] = {
{LUA_PCILIBNAME, luaopen_pci},
{LUA_SYSLINUXLIBNAME, luaopen_syslinux},
{LUA_VESALIBNAME, luaopen_vesa},
+ {LUA_DHCPLIBNAME, luaopen_dhcp},
#endif
{NULL, NULL}
};
diff --git a/com32/lua/src/lualib.h b/com32/lua/src/lualib.h
index 0ae6ba75..40d1bf29 100644
--- a/com32/lua/src/lualib.h
+++ b/com32/lua/src/lualib.h
@@ -54,6 +54,9 @@ LUALIB_API int (luaopen_vesa) (lua_State *L);
#define LUA_CPULIBNAME "cpu"
LUALIB_API int (luaopen_cpu) (lua_State *L);
+
+#define LUA_DHCPLIBNAME "dhcp"
+LUALIB_API int (luaopen_dhcp) (lua_State *L);
#endif
/* open all previous libraries */
diff --git a/com32/lua/src/syslinux.c b/com32/lua/src/syslinux.c
index 9b207db7..af5db834 100644
--- a/com32/lua/src/syslinux.c
+++ b/com32/lua/src/syslinux.c
@@ -278,7 +278,7 @@ static int sl_boot_linux(lua_State * L)
msleep(10000);
*/
- ret = syslinux_boot_linux(kernel_data, kernel_len, initramfs, newcmdline);
+ ret = syslinux_boot_linux(kernel_data, kernel_len, initramfs, NULL, newcmdline);
printf("syslinux_boot_linux returned %d\n", ret);
@@ -405,7 +405,7 @@ static int sl_boot_it(lua_State * L)
(void)mem_limit;
return syslinux_boot_linux(kernel->data, kernel->size,
- initramfs, (char *)cmdline);
+ initramfs, NULL, (char *)cmdline);
}
static int sl_derivative(lua_State * L)
diff --git a/com32/lua/src/vesa.c b/com32/lua/src/vesa.c
index 9f281348..06649e11 100644
--- a/com32/lua/src/vesa.c
+++ b/com32/lua/src/vesa.c
@@ -17,10 +17,15 @@ static int vesa_getmodes(lua_State *L)
struct vesa_general_info *gi;
struct vesa_mode_info *mi;
int nmode = 1;
+ int rv = -1;
- /* Allocate space in the bounce buffer for these structures */
- gi = &((struct vesa_info *)__com32.cs_bounce)->gi;
- mi = &((struct vesa_info *)__com32.cs_bounce)->mi;
+ gi = lmalloc(sizeof *gi);
+ if (!gi)
+ return -1;
+
+ mi = lmalloc(sizeof *mi);
+ if (!mi)
+ goto out;
memset(&rm, 0, sizeof rm);
memset(gi, 0, sizeof *gi);
@@ -32,11 +37,15 @@ static int vesa_getmodes(lua_State *L)
__intcall(0x10, &rm, &rm);
if ( rm.eax.w[0] != 0x004F )
- return -1; /* Function call failed */
- if ( gi->signature != VESA_MAGIC )
- return -2; /* No magic */
- if ( gi->version < 0x0102 )
- return -3; /* VESA 1.2+ required */
+ goto out; /* Function call failed */
+ if ( gi->signature != VESA_MAGIC ) {
+ rv = -2; /* No magic */
+ goto out;
+ }
+ if ( gi->version < 0x0102 ) {
+ rv = -3; /* VESA 1.2+ required */
+ goto out;
+ }
lua_newtable(L); /* list of modes */
@@ -86,7 +95,11 @@ static int vesa_getmodes(lua_State *L)
}
- return 1;
+ rv = 1;
+out:
+ lfree(mi);
+ lfree(gi);
+ return rv;
}
diff --git a/com32/mboot/initvesa.c b/com32/mboot/initvesa.c
index cf2707df..bd869e3d 100644
--- a/com32/mboot/initvesa.c
+++ b/com32/mboot/initvesa.c
@@ -38,6 +38,7 @@
#include <stdlib.h>
#include <string.h>
#include <limits.h>
+#include <graphics.h>
#include "vesa.h"
#include "mboot.h"
@@ -61,9 +62,13 @@ void set_graphics_mode(const struct multiboot_header *mbh,
if (!(mbh->flags & MULTIBOOT_VIDEO_MODE) || mbh->mode_type != 0)
return;
- /* Allocate space in the bounce buffer for these structures */
- gi = &((struct vesa_info *)__com32.cs_bounce)->gi;
- mi = &((struct vesa_info *)__com32.cs_bounce)->mi;
+ gi = lmalloc(sizeof *gi);
+ if (!gi)
+ return;
+
+ mi = lmalloc(sizeof *mi);
+ if (!mi)
+ goto out;
memset(&rm, 0, sizeof rm);
memset(gi, 0, sizeof *gi);
@@ -75,11 +80,11 @@ void set_graphics_mode(const struct multiboot_header *mbh,
__intcall(0x10, &rm, &rm);
if (rm.eax.w[0] != 0x004F)
- return; /* Function call failed */
+ goto out; /* Function call failed */
if (gi->signature != VESA_MAGIC)
- return; /* No magic */
+ goto out; /* No magic */
if (gi->version < 0x0102)
- return; /* VESA 1.2+ required */
+ goto out; /* VESA 1.2+ required */
memcpy(&vesa_info.gi, gi, sizeof *gi);
@@ -182,7 +187,7 @@ void set_graphics_mode(const struct multiboot_header *mbh,
}
if (!bestpxf)
- return; /* No mode found */
+ goto out; /* No mode found */
mi = &vesa_info.mi;
mode = bestmode;
@@ -193,7 +198,7 @@ void set_graphics_mode(const struct multiboot_header *mbh,
rm.ebx.w[0] = mode;
__intcall(0x10, &rm, &rm);
if (rm.eax.w[0] != 0x004F)
- return; /* Failed to set mode */
+ goto out; /* Failed to set mode */
mbi->flags |= MB_INFO_VIDEO_INFO;
mbi->vbe_mode = mode;
@@ -211,16 +216,16 @@ void set_graphics_mode(const struct multiboot_header *mbh,
mbi->vbe_interface_len = rm.ecx.w[0];
}
- /* Tell syslinux we changed video mode */
- rm.eax.w[0] = 0x0017; /* Report video mode change */
/* In theory this should be:
-
- rm.ebx.w[0] = (mi->mode_attr & 4) ? 0x0007 : 0x000f;
-
- However, that would assume all systems that claim to handle text
- output in VESA modes actually do that... */
- rm.ebx.w[0] = 0x000f;
- rm.ecx.w[0] = vesa_info.mi.h_res;
- rm.edx.w[0] = vesa_info.mi.v_res;
- __intcall(0x22, &rm, NULL);
+ *
+ * UsingVga = (mi->mode_attr & 4) ? 0x0007 : 0x000f;
+ *
+ * However, that would assume all systems that claim to handle text
+ * output in VESA modes actually do that...
+ */
+ graphics_using_vga(0x0F, vesa_info.mi.h_res, vesa_info.mi.v_res);
+
+out:
+ lfree(mi);
+ lfree(gi);
}
diff --git a/com32/mboot/map.c b/com32/mboot/map.c
index 0a71d4c9..99add306 100644
--- a/com32/mboot/map.c
+++ b/com32/mboot/map.c
@@ -91,10 +91,9 @@ int init_map(void)
error("Failed to allocate initial memory map!\n");
return -1;
}
-#if DEBUG
+
dprintf("Initial memory map:\n");
- syslinux_dump_memmap(stdout, mmap);
-#endif
+ syslinux_dump_memmap(mmap);
return 0;
}
diff --git a/com32/mboot/mem.c b/com32/mboot/mem.c
index 6a31fac0..6e3995bf 100644
--- a/com32/mboot/mem.c
+++ b/com32/mboot/mem.c
@@ -49,9 +49,10 @@ struct e820_entry {
static int mboot_scan_memory(struct AddrRangeDesc **ardp, uint32_t * dosmem)
{
com32sys_t ireg, oreg;
- struct e820_entry *e820buf = __com32.cs_bounce;
+ struct e820_entry *e820buf;
struct AddrRangeDesc *ard;
size_t ard_count, ard_space;
+ int rv = 0;
/* Use INT 12h to get DOS memory */
__intcall(0x12, &__com32_zero_regs, &oreg);
@@ -65,10 +66,14 @@ static int mboot_scan_memory(struct AddrRangeDesc **ardp, uint32_t * dosmem)
*dosmem = 640 * 1024; /* Hope for the best... */
}
+ e820buf = lmalloc(sizeof(*e820buf));
+ if (!e820buf)
+ return 0;
+
/* Allocate initial space */
*ardp = ard = malloc(RANGE_ALLOC_BLOCK * sizeof *ard);
if (!ard)
- return 0;
+ goto out;
ard_count = 0;
ard_space = RANGE_ALLOC_BLOCK;
@@ -93,8 +98,10 @@ static int mboot_scan_memory(struct AddrRangeDesc **ardp, uint32_t * dosmem)
if (ard_count >= ard_space) {
ard_space += RANGE_ALLOC_BLOCK;
*ardp = ard = realloc(ard, ard_space * sizeof *ard);
- if (!ard)
- return ard_count;
+ if (!ard) {
+ rv = ard_count;
+ goto out;
+ }
}
ard[ard_count].size = 20;
@@ -106,8 +113,10 @@ static int mboot_scan_memory(struct AddrRangeDesc **ardp, uint32_t * dosmem)
ireg.ebx.l = oreg.ebx.l;
} while (oreg.ebx.l);
- if (ard_count)
- return ard_count;
+ if (ard_count) {
+ rv = ard_count;
+ goto out;
+ };
ard[0].size = 20;
ard[0].BaseAddr = 0;
@@ -129,10 +138,12 @@ static int mboot_scan_memory(struct AddrRangeDesc **ardp, uint32_t * dosmem)
ard[2].BaseAddr = 16 << 20;
ard[2].Length = oreg.edx.w[0] << 16;
ard[2].Type = 1;
- return 3;
+ rv = 3;
} else {
- return 2;
+ rv = 2;
}
+
+ goto out;
}
/* Finally try INT 15h AH=88h */
@@ -142,10 +153,14 @@ static int mboot_scan_memory(struct AddrRangeDesc **ardp, uint32_t * dosmem)
ard[1].BaseAddr = 1 << 20;
ard[1].Length = oreg.ecx.w[0] << 10;
ard[1].Type = 1;
- return 2;
+ rv = 2;
+ goto out;
}
- return 1; /* ... problematic ... */
+ rv = 1; /* ... problematic ... */
+out:
+ lfree(e820buf);
+ return rv;
}
void mboot_make_memmap(void)
diff --git a/com32/menu/Makefile b/com32/menu/Makefile
index d1e85ad0..2096b4c4 100644
--- a/com32/menu/Makefile
+++ b/com32/menu/Makefile
@@ -24,14 +24,14 @@ MODULES = menu.c32 vesamenu.c32
TESTFILES =
COMMONOBJS = menumain.o readconfig.o passwd.o drain.o printmsg.o colors.o \
- background.o refstr.o execute.o
+ background.o refstr.o
all: $(MODULES) $(TESTFILES)
-menu.elf : menu.o $(COMMONOBJS) $(C_LIBS)
+menu.c32 : menu.o $(COMMONOBJS) $(C_LIBS)
$(LD) $(LDFLAGS) -o $@ $^
-vesamenu.elf : vesamenu.o $(COMMONOBJS) $(C_LIBS)
+vesamenu.c32 : vesamenu.o $(COMMONOBJS) $(C_LIBS)
$(LD) $(LDFLAGS) -o $@ $^
vesamenu.c32: vesamenu.o $(COMMONOBJS) $(C_LIBS)
diff --git a/com32/menu/execute.c b/com32/menu/execute.c
deleted file mode 100644
index c2de7353..00000000
--- a/com32/menu/execute.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/* ----------------------------------------------------------------------- *
- *
- * Copyright 2004-2008 H. Peter Anvin - All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
- * Boston MA 02110-1301, USA; either version 2 of the License, or
- * (at your option) any later version; incorporated herein by reference.
- *
- * ----------------------------------------------------------------------- */
-
-#include <stdlib.h>
-#include <string.h>
-#include <com32.h>
-#include "menu.h"
-
-void execute(const char *cmdline, enum kernel_type type)
-{
- com32sys_t ireg;
- const char *p, *const *pp;
- char *q = __com32.cs_bounce;
- const char *kernel, *args;
-
- memset(&ireg, 0, sizeof ireg);
-
- kernel = q;
- p = cmdline;
- while (*p && !my_isspace(*p)) {
- *q++ = *p++;
- }
- *q++ = '\0';
-
- args = q;
- while (*p && my_isspace(*p))
- p++;
-
- strcpy(q, p);
-
- if (kernel[0] == '.' && type == KT_NONE) {
- /* It might be a type specifier */
- enum kernel_type type = KT_NONE;
- for (pp = kernel_types; *pp; pp++, type++) {
- if (!strcmp(kernel + 1, *pp)) {
- execute(p, type); /* Strip the type specifier and retry */
- }
- }
- }
-
- if (type == KT_LOCALBOOT) {
- ireg.eax.w[0] = 0x0014; /* Local boot */
- ireg.edx.w[0] = strtoul(kernel, NULL, 0);
- } else {
- if (type < KT_KERNEL)
- type = KT_KERNEL;
-
- ireg.eax.w[0] = 0x0016; /* Run kernel image */
- ireg.esi.w[0] = OFFS(kernel);
- ireg.ds = SEG(kernel);
- ireg.ebx.w[0] = OFFS(args);
- ireg.es = SEG(args);
- ireg.edx.l = type - KT_KERNEL;
- /* ireg.ecx.l = 0; *//* We do ipappend "manually" */
- }
-
- __intcall(0x22, &ireg, NULL);
-
- /* If this returns, something went bad; return to menu */
-}
diff --git a/com32/menu/menumain.c b/com32/menu/menumain.c
index 5b3f6bd1..c9762b27 100644
--- a/com32/menu/menumain.c
+++ b/com32/menu/menumain.c
@@ -28,7 +28,9 @@
#include <setjmp.h>
#include <limits.h>
#include <com32.h>
+#include <core.h>
#include <syslinux/adv.h>
+#include <syslinux/boot.h>
#include "menu.h"
@@ -1108,7 +1110,7 @@ int main(int argc, char *argv[])
{
const char *cmdline;
struct menu *m;
- int rows, cols;
+ int rows, cols, cursorrow;
int i;
(void)argc;
@@ -1150,16 +1152,24 @@ int main(int argc, char *argv[])
local_cursor_enable(true);
cmdline = run_menu();
- if (clearmenu)
+ if (clearmenu) {
clear_screen();
+ cursorrow = 1;
+ } else {
+ cursorrow = END_ROW;
+ }
local_cursor_enable(false);
- printf("\033[?25h\033[%d;1H\033[0m", END_ROW);
+ printf("\033[?25h\033[%d;1H\033[0m", cursorrow);
if (cmdline) {
- execute(cmdline, KT_NONE);
- if (cm->onerror)
- execute(cm->onerror, KT_NONE);
+ uint32_t type = parse_image_type(cmdline);
+
+ execute(cmdline, type);
+ if (cm->onerror) {
+ type = parse_image_type(cm->onerror);
+ execute(cm->onerror, type);
+ }
} else {
return 0; /* Exit */
}
diff --git a/com32/menu/readconfig.c b/com32/menu/readconfig.c
index 0ac2564a..69f524c4 100644
--- a/com32/menu/readconfig.c
+++ b/com32/menu/readconfig.c
@@ -35,7 +35,7 @@ struct menu *root_menu, *start_menu, *hide_menu, *menu_list;
/* These are global parameters regardless of which menu we're displaying */
int shiftkey = 0; /* Only display menu if shift key pressed */
int hiddenmenu = 0;
-int clearmenu = 0;
+int clearmenu = 1;
long long totaltimeout = 0;
const char *hide_key[KEY_MAX];
@@ -62,7 +62,7 @@ static const struct messages messages[MSG_COUNT] = {
__p; })
/* Must match enum kernel_type */
-const char *const kernel_types[] = {
+static const char *const kernel_types[] = {
"none",
"localboot",
"kernel",
@@ -744,6 +744,8 @@ static void parse_config_file(FILE * f)
refstr_put(command);
} else if ((ep = looking_at(p, "clear"))) {
clearmenu = 1;
+ } else if ((ep = looking_at(p, "noclear"))) {
+ clearmenu = 0;
} else if ((ep = is_message_name(p, &msgnr))) {
refstr_put(m->messages[msgnr]);
m->messages[msgnr] = refstrdup(skipspace(ep));
diff --git a/com32/modules/Makefile b/com32/modules/Makefile
index 9d88d75b..8d94cfec 100644
--- a/com32/modules/Makefile
+++ b/com32/modules/Makefile
@@ -19,15 +19,30 @@ topdir = ../..
MAKEDIR = $(topdir)/mk
include $(MAKEDIR)/elf.mk
-MODULES = chain.c32 config.c32 ethersel.c32 dmitest.c32 cpuidtest.c32 \
+MODULES = config.c32 ethersel.c32 dmitest.c32 cpuidtest.c32 \
disk.c32 pcitest.c32 elf.c32 linux.c32 reboot.c32 pmload.c32 \
meminfo.c32 sdi.c32 sanboot.c32 ifcpu64.c32 vesainfo.c32 \
kbdmap.c32 cmd.c32 vpdtest.c32 host.c32 ls.c32 gpxecmd.c32 \
- ifcpu.c32 cpuid.c32 cat.c32 pwd.c32 ifplop.c32 zzjson.c32 whichsys.c32 \
- hello.c32
+ ifcpu.c32 cpuid.c32 cat.c32 pwd.c32 ifplop.c32 zzjson.c32 \
+ whichsys.c32 hello.c32 pxechn.c32
TESTFILES =
+LDFLAGS_cpuidtest.o = $(com32)/gpllib/libcom32gpl.c32
+LDFLAGS_disk.o = $(com32)/gpllib/libcom32gpl.c32
+LDFLAGS_ethersel.o = $(com32)/lib/libcom32.c32
+LDFLAGS_gpxecmd.o = $(com32)/lib/libcom32.c32
+LDFLAGS_host.o = $(com32)/lib/libcom32.c32
+LDFLAGS_ifcpu.o = $(com32)/libutil/libutil_com.c32 \
+ $(com32)/gpllib/libcom32gpl.c32
+LDFLAGS_kbdmap.o = $(com32)/lib/libcom32.c32
+LDFLAGS_linux.o = $(com32)/lib/libcom32.c32
+LDFLAGS_pxechn.o = $(com32)/lib/libcom32.c32 \
+ $(com32)/libutil/libutil_com.c32
+LDFLAGS_sanboot.o = $(com32)/lib/libcom32.c32
+LDFLAGS_vpdtest.o = $(com32)/gpllib/libcom32gpl.c32
+LDFLAGS_zzjson.o = $(com32)/gpllib/libcom32gpl.c32
+
all: $(MODULES) $(TESTFILES)
.PRECIOUS: %.o
diff --git a/com32/modules/chain.c b/com32/modules/chain.c
deleted file mode 100644
index 09cbeff8..00000000
--- a/com32/modules/chain.c
+++ /dev/null
@@ -1,1868 +0,0 @@
-/* ----------------------------------------------------------------------- *
- *
- * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
- * Copyright 2009-2011 Intel Corporation; author: H. Peter Anvin
- * Significant portions copyright (C) 2010 Shao Miller
- * [partition iteration, GPT, "fs"]
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
- * Boston MA 02111-1307, USA; either version 2 of the License, or
- * (at your option) any later version; incorporated herein by reference.
- *
- * ----------------------------------------------------------------------- */
-
-/*
- * chain.c
- *
- * Chainload a hard disk (currently rather braindead.)
- *
- * Usage: chain [options]
- * chain hd<disk#> [<partition>] [options]
- * chain fd<disk#> [options]
- * chain mbr:<id> [<partition>] [options]
- * chain guid:<guid> [<partition>] [options]
- * chain label:<label> [<partition>] [options]
- * chain boot [<partition>] [options]
- *
- * For example, "chain msdos=io.sys" will load DOS from the current Syslinux
- * filesystem. "chain hd0 1" will boot the first partition on the first hard
- * disk.
- *
- * When none of the "hdX", "fdX", "mbr:", "guid:", "label:", "boot" or "fs"
- * options are specified, the default behaviour is equivalent to "boot".
- * "boot" means to use the current Syslinux drive, and you can also specify
- * a partition.
- *
- * The mbr: syntax means search all the hard disks until one with a
- * specific MBR serial number (bytes 440-443) is found.
- *
- * Partitions 1-4 are primary, 5+ logical, 0 = boot MBR (default.)
- *
- * "fs" will use the current Syslinux filesystem as the boot drive/partition.
- * When booting from PXELINUX, you will most likely wish to specify a disk.
- *
- * Options:
- *
- * file=<loader>
- * loads the file <loader> **from the Syslinux filesystem**
- * instead of loading the boot sector.
- *
- * seg=<segment>
- * loads at and jumps to <seg>:0000 instead of 0000:7C00.
- *
- * isolinux=<loader>
- * chainload another version/build of the ISOLINUX bootloader and patch
- * the loader with appropriate parameters in memory.
- * This avoids the need for the -eltorito-alt-boot parameter of mkisofs,
- * when you want more than one ISOLINUX per CD/DVD.
- *
- * ntldr=<loader>
- * equivalent to seg=0x2000 file=<loader> sethidden,
- * used with WinNT's loaders
- *
- * cmldr=<loader>
- * used with Recovery Console of Windows NT/2K/XP.
- * same as ntldr=<loader> & "cmdcons\0" written to
- * the system name field in the bootsector
- *
- * freedos=<loader>
- * equivalent to seg=0x60 file=<loader> sethidden,
- * used with FreeDOS' kernel.sys.
- *
- * msdos=<loader>
- * pcdos=<loader>
- * equivalent to seg=0x70 file=<loader> sethidden,
- * used with DOS' io.sys.
- *
- * drmk=<loader>
- * Similar to msdos=<loader> but prepares the special options
- * for the Dell Real Mode Kernel.
- *
- * grub=<loader>
- * same as seg=0x800 file=<loader> & jumping to seg 0x820,
- * used with GRUB Legacy stage2 files.
- *
- * grubcfg=<filename>
- * set an alternative config filename in stage2 of Grub Legacy,
- * only applicable in combination with "grub=<loader>".
- *
- * grldr=<loader>
- * pass the partition number to GRUB4DOS,
- * used with GRUB4DOS' grldr.
- *
- * swap
- * if the disk is not fd0/hd0, install a BIOS stub which swaps
- * the drive numbers.
- *
- * hide
- * change type of primary partitions with IDs 01, 04, 06, 07,
- * 0b, 0c, or 0e to 1x, except for the selected partition, which
- * is converted the other way.
- *
- * sethidden
- * update the "hidden sectors" (partition offset) field in a
- * FAT/NTFS boot sector.
- *
- * keeppxe
- * keep the PXE and UNDI stacks in memory (PXELINUX only).
- */
-
-#include <com32.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-#include <console.h>
-#include <minmax.h>
-#include <stdbool.h>
-#include <dprintf.h>
-#include <syslinux/loadfile.h>
-#include <syslinux/bootrm.h>
-#include <syslinux/config.h>
-#include <syslinux/video.h>
-
-#define SECTOR 512 /* bytes/sector */
-
-static struct options {
- const char *loadfile;
- uint16_t keeppxe;
- uint16_t seg;
- bool isolinux;
- bool cmldr;
- bool grub;
- bool grldr;
- const char *grubcfg;
- bool swap;
- bool hide;
- bool sethidden;
- bool drmk;
-} opt;
-
-struct data_area {
- void *data;
- addr_t base;
- addr_t size;
-};
-
-static inline void error(const char *msg)
-{
- fputs(msg, stderr);
-}
-
-/*
- * Call int 13h, but with retry on failure. Especially floppies need this.
- */
-static int int13_retry(const com32sys_t * inreg, com32sys_t * outreg)
-{
- int retry = 6; /* Number of retries */
- com32sys_t tmpregs;
-
- if (!outreg)
- outreg = &tmpregs;
-
- while (retry--) {
- __intcall(0x13, inreg, outreg);
- if (!(outreg->eflags.l & EFLAGS_CF))
- return 0; /* CF=0, OK */
- }
-
- return -1; /* Error */
-}
-
-/*
- * Query disk parameters and EBIOS availability for a particular disk.
- */
-struct diskinfo {
- int disk;
- int ebios; /* EBIOS supported on this disk */
- int cbios; /* CHS geometry is valid */
- int head;
- int sect;
-} disk_info;
-
-static int get_disk_params(int disk)
-{
- static com32sys_t getparm, parm, getebios, ebios;
-
- disk_info.disk = disk;
- disk_info.ebios = disk_info.cbios = 0;
-
- /* Get EBIOS support */
- getebios.eax.w[0] = 0x4100;
- getebios.ebx.w[0] = 0x55aa;
- getebios.edx.b[0] = disk;
- getebios.eflags.b[0] = 0x3; /* CF set */
-
- __intcall(0x13, &getebios, &ebios);
-
- if (!(ebios.eflags.l & EFLAGS_CF) &&
- ebios.ebx.w[0] == 0xaa55 && (ebios.ecx.b[0] & 1)) {
- disk_info.ebios = 1;
- }
-
- /* Get disk parameters -- really only useful for
- hard disks, but if we have a partitioned floppy
- it's actually our best chance... */
- getparm.eax.b[1] = 0x08;
- getparm.edx.b[0] = disk;
-
- __intcall(0x13, &getparm, &parm);
-
- if (parm.eflags.l & EFLAGS_CF)
- return disk_info.ebios ? 0 : -1;
-
- disk_info.head = parm.edx.b[1] + 1;
- disk_info.sect = parm.ecx.b[0] & 0x3f;
- if (disk_info.sect == 0) {
- disk_info.sect = 1;
- } else {
- disk_info.cbios = 1; /* Valid geometry */
- }
-
- return 0;
-}
-
-/*
- * Get a disk block and return a malloc'd buffer.
- * Uses the disk number and information from disk_info.
- */
-struct ebios_dapa {
- uint16_t len;
- uint16_t count;
- uint16_t off;
- uint16_t seg;
- uint64_t lba;
-};
-
-/* Read count sectors from drive, starting at lba. Return a new buffer */
-static void *read_sectors(uint64_t lba, uint8_t count)
-{
- com32sys_t inreg;
- struct ebios_dapa *dapa = __com32.cs_bounce;
- void *buf = (char *)__com32.cs_bounce + SECTOR;
- void *data;
-
- if (!count)
- /* Silly */
- return NULL;
-
- memset(&inreg, 0, sizeof inreg);
-
- if (disk_info.ebios) {
- dapa->len = sizeof(*dapa);
- dapa->count = count;
- dapa->off = OFFS(buf);
- dapa->seg = SEG(buf);
- dapa->lba = lba;
-
- inreg.esi.w[0] = OFFS(dapa);
- inreg.ds = SEG(dapa);
- inreg.edx.b[0] = disk_info.disk;
- inreg.eax.b[1] = 0x42; /* Extended read */
- } else {
- unsigned int c, h, s, t;
-
- if (!disk_info.cbios) {
- /* We failed to get the geometry */
-
- if (lba)
- return NULL; /* Can only read MBR */
-
- s = h = c = 0;
- } else {
- s = lba % disk_info.sect;
- t = lba / disk_info.sect; /* Track = head*cyl */
- h = t % disk_info.head;
- c = t / disk_info.head;
- }
-
- if (s >= 63 || h >= 256 || c >= 1024)
- return NULL;
-
- inreg.eax.b[0] = count;
- inreg.eax.b[1] = 0x02; /* Read */
- inreg.ecx.b[1] = c;
- inreg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1);
- inreg.edx.b[1] = h;
- inreg.edx.b[0] = disk_info.disk;
- inreg.ebx.w[0] = OFFS(buf);
- inreg.es = SEG(buf);
- }
-
- if (int13_retry(&inreg, NULL))
- return NULL;
-
- data = malloc(count * SECTOR);
- if (data)
- memcpy(data, buf, count * SECTOR);
- return data;
-}
-
-static int write_sector(unsigned int lba, const void *data)
-{
- com32sys_t inreg;
- struct ebios_dapa *dapa = __com32.cs_bounce;
- void *buf = (char *)__com32.cs_bounce + SECTOR;
-
- memcpy(buf, data, SECTOR);
- memset(&inreg, 0, sizeof inreg);
-
- if (disk_info.ebios) {
- dapa->len = sizeof(*dapa);
- dapa->count = 1; /* 1 sector */
- dapa->off = OFFS(buf);
- dapa->seg = SEG(buf);
- dapa->lba = lba;
-
- inreg.esi.w[0] = OFFS(dapa);
- inreg.ds = SEG(dapa);
- inreg.edx.b[0] = disk_info.disk;
- inreg.eax.w[0] = 0x4300; /* Extended write */
- } else {
- unsigned int c, h, s, t;
-
- if (!disk_info.cbios) {
- /* We failed to get the geometry */
-
- if (lba)
- return -1; /* Can only write MBR */
-
- s = h = c = 0;
- } else {
- s = lba % disk_info.sect;
- t = lba / disk_info.sect; /* Track = head*cyl */
- h = t % disk_info.head;
- c = t / disk_info.head;
- }
-
- if (s >= 63 || h >= 256 || c >= 1024)
- return -1;
-
- inreg.eax.w[0] = 0x0301; /* Write one sector */
- inreg.ecx.b[1] = c;
- inreg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1);
- inreg.edx.b[1] = h;
- inreg.edx.b[0] = disk_info.disk;
- inreg.ebx.w[0] = OFFS(buf);
- inreg.es = SEG(buf);
- }
-
- if (int13_retry(&inreg, NULL))
- return -1;
-
- return 0; /* ok */
-}
-
-static int write_verify_sector(unsigned int lba, const void *buf)
-{
- char *rb;
- int rv;
-
- rv = write_sector(lba, buf);
- if (rv)
- return rv; /* Write failure */
- rb = read_sectors(lba, 1);
- if (!rb)
- return -1; /* Readback failure */
- rv = memcmp(buf, rb, SECTOR);
- free(rb);
- return rv ? -1 : 0;
-}
-
-/*
- * CHS (cylinder, head, sector) value extraction macros.
- * Taken from WinVBlock. Does not expand to an lvalue
-*/
-#define chs_head(chs) chs[0]
-#define chs_sector(chs) (chs[1] & 0x3F)
-#define chs_cyl_high(chs) (((uint16_t)(chs[1] & 0xC0)) << 2)
-#define chs_cyl_low(chs) ((uint16_t)chs[2])
-#define chs_cylinder(chs) (chs_cyl_high(chs) | chs_cyl_low(chs))
-typedef uint8_t chs[3];
-
-/* A DOS partition table entry */
-struct part_entry {
- uint8_t active_flag; /* 0x80 if "active" */
- chs start;
- uint8_t ostype;
- chs end;
- uint32_t start_lba;
- uint32_t length;
-} __attribute__ ((packed));
-
-static void mbr_part_dump(const struct part_entry *part)
-{
- (void)part;
- dprintf("Partition status _____ : 0x%.2x\n"
- "Partition CHS start\n"
- " Cylinder ___________ : 0x%.4x (%u)\n"
- " Head _______________ : 0x%.2x (%u)\n"
- " Sector _____________ : 0x%.2x (%u)\n"
- "Partition type _______ : 0x%.2x\n"
- "Partition CHS end\n"
- " Cylinder ___________ : 0x%.4x (%u)\n"
- " Head _______________ : 0x%.2x (%u)\n"
- " Sector _____________ : 0x%.2x (%u)\n"
- "Partition LBA start __ : 0x%.8x (%u)\n"
- "Partition LBA count __ : 0x%.8x (%u)\n"
- "-------------------------------\n",
- part->active_flag,
- chs_cylinder(part->start),
- chs_cylinder(part->start),
- chs_head(part->start),
- chs_head(part->start),
- chs_sector(part->start),
- chs_sector(part->start),
- part->ostype,
- chs_cylinder(part->end),
- chs_cylinder(part->end),
- chs_head(part->end),
- chs_head(part->end),
- chs_sector(part->end),
- chs_sector(part->end),
- part->start_lba,
- part->start_lba,
- part->length,
- part->length);
-}
-
-/* A DOS MBR */
-struct mbr {
- char code[440];
- uint32_t disk_sig;
- char pad[2];
- struct part_entry table[4];
- uint16_t sig;
-} __attribute__ ((packed));
-static const uint16_t mbr_sig_magic = 0xAA55;
-
-/* Search for a specific drive, based on the MBR signature; bytes 440-443 */
-static int find_disk(uint32_t mbr_sig)
-{
- int drive;
- bool is_me;
- struct mbr *mbr;
-
- for (drive = 0x80; drive <= 0xff; drive++) {
- if (get_disk_params(drive))
- continue; /* Drive doesn't exist */
- if (!(mbr = read_sectors(0, 1)))
- continue; /* Cannot read sector */
- is_me = (mbr->disk_sig == mbr_sig);
- free(mbr);
- if (is_me)
- return drive;
- }
- return -1;
-}
-
-/* Forward declaration */
-struct disk_part_iter;
-
-/* Partition-/scheme-specific routine returning the next partition */
-typedef struct disk_part_iter *(*disk_part_iter_func) (struct disk_part_iter *
- part);
-
-/* Contains details for a partition under examination */
-struct disk_part_iter {
- /* The block holding the table we are part of */
- char *block;
- /* The LBA for the beginning of data */
- uint64_t lba_data;
- /* The partition number, as determined by our heuristic */
- int index;
- /* The DOS partition record to pass, if applicable */
- const struct part_entry *record;
- /* Function returning the next available partition */
- disk_part_iter_func next;
- /* Partition-/scheme-specific details */
- union {
- /* MBR specifics */
- int mbr_index;
- /* EBR specifics */
- struct {
- /* The first extended partition's start LBA */
- uint64_t lba_extended;
- /* Any applicable parent, or NULL */
- struct disk_part_iter *parent;
- /* The parent extended partition index */
- int parent_index;
- } ebr;
- /* GPT specifics */
- struct {
- /* Real (not effective) index in the partition table */
- int index;
- /* Current partition GUID */
- const struct guid *part_guid;
- /* Current partition label */
- const char *part_label;
- /* Count of entries in GPT */
- int parts;
- /* Partition record size */
- uint32_t size;
- } gpt;
- } private;
-};
-
-static struct disk_part_iter *next_ebr_part(struct disk_part_iter *part)
-{
- const struct part_entry *ebr_table;
- const struct part_entry *parent_table =
- ((const struct mbr *)part->private.ebr.parent->block)->table;
- static const struct part_entry phony = {.start_lba = 0 };
- uint64_t ebr_lba;
-
- /* Don't look for a "next EBR" the first time around */
- if (part->private.ebr.parent_index >= 0)
- /* Look at the linked list */
- ebr_table = ((const struct mbr *)part->block)->table + 1;
- /* Do we need to look for an extended partition? */
- if (part->private.ebr.parent_index < 0 || !ebr_table->start_lba) {
- /* Start looking for an extended partition in the MBR */
- while (++part->private.ebr.parent_index < 4) {
- uint8_t type = parent_table[part->private.ebr.parent_index].ostype;
-
- if ((type == 0x05) || (type == 0x0F) || (type == 0x85))
- break;
- }
- if (part->private.ebr.parent_index == 4)
- /* No extended partitions found */
- goto out_finished;
- part->private.ebr.lba_extended =
- parent_table[part->private.ebr.parent_index].start_lba;
- ebr_table = &phony;
- }
- /* Load next EBR */
- ebr_lba = ebr_table->start_lba + part->private.ebr.lba_extended;
- free(part->block);
- part->block = read_sectors(ebr_lba, 1);
- if (!part->block) {
- error("Could not load EBR!\n");
- goto err_ebr;
- }
- ebr_table = ((const struct mbr *)part->block)->table;
- dprintf("next_ebr_part:\n");
- mbr_part_dump(ebr_table);
-
- /*
- * Sanity check entry: must not extend outside the
- * extended partition. This is necessary since some OSes
- * put crap in some entries.
- */
- {
- const struct mbr *mbr =
- (const struct mbr *)part->private.ebr.parent->block;
- const struct part_entry *extended =
- mbr->table + part->private.ebr.parent_index;
-
- if (ebr_table[0].start_lba >= extended->start_lba + extended->length) {
- dprintf("Insane logical partition!\n");
- goto err_insane;
- }
- }
- /* Success */
- part->lba_data = ebr_table[0].start_lba + ebr_lba;
- dprintf("Partition %d logical lba %u\n", part->index, part->lba_data);
- part->index++;
- part->record = ebr_table;
- return part;
-
-err_insane:
-
- free(part->block);
- part->block = NULL;
-err_ebr:
-
-out_finished:
- free(part->private.ebr.parent->block);
- free(part->private.ebr.parent);
- free(part->block);
- free(part);
- return NULL;
-}
-
-static struct disk_part_iter *next_mbr_part(struct disk_part_iter *part)
-{
- struct disk_part_iter *ebr_part;
- /* Look at the partition table */
- struct part_entry *table = ((struct mbr *)part->block)->table;
-
- /* Look for data partitions */
- while (++part->private.mbr_index < 4) {
- uint8_t type = table[part->private.mbr_index].ostype;
-
- if (type == 0x00 || type == 0x05 || type == 0x0F || type == 0x85)
- /* Skip empty or extended partitions */
- continue;
- if (!table[part->private.mbr_index].length)
- /* Empty */
- continue;
- break;
- }
- /* If we're currently the last partition, it's time for EBR processing */
- if (part->private.mbr_index == 4) {
- /* Allocate another iterator for extended partitions */
- ebr_part = malloc(sizeof(*ebr_part));
- if (!ebr_part) {
- error("Could not allocate extended partition iterator!\n");
- goto err_alloc;
- }
- /* Setup EBR iterator parameters */
- ebr_part->block = NULL;
- ebr_part->index = 4;
- ebr_part->record = NULL;
- ebr_part->next = next_ebr_part;
- ebr_part->private.ebr.parent = part;
- /* Trigger an initial EBR load */
- ebr_part->private.ebr.parent_index = -1;
- /* The EBR iterator is responsible for freeing us */
- return next_ebr_part(ebr_part);
- }
- dprintf("next_mbr_part:\n");
- mbr_part_dump(table + part->private.mbr_index);
-
- /* Update parameters to reflect this new partition. Re-use iterator */
- part->lba_data = table[part->private.mbr_index].start_lba;
- dprintf("Partition %d primary lba %u\n", part->private.mbr_index, part->lba_data);
- part->index = part->private.mbr_index + 1;
- part->record = table + part->private.mbr_index;
- return part;
-
- free(ebr_part);
-err_alloc:
-
- free(part->block);
- free(part);
- return NULL;
-}
-
-/*
- * GUID
- * Be careful with endianness, you must adjust it yourself
- * iff you are directly using the fourth data chunk
- */
-struct guid {
- uint32_t data1;
- uint16_t data2;
- uint16_t data3;
- uint64_t data4;
-} __attribute__ ((packed));
-
- /*
- * This walk-map effectively reverses the little-endian
- * portions of the GUID in the output text
- */
-static const char guid_le_walk_map[] = {
- 3, -1, -1, -1, 0,
- 5, -1, 0,
- 3, -1, 0,
- 2, 1, 0,
- 1, 1, 1, 1, 1, 1
-};
-
-#if DEBUG
-/*
- * Fill a buffer with a textual GUID representation.
- * The buffer must be >= char[37] and will be populated
- * with an ASCII NUL C string terminator.
- * Example: 11111111-2222-3333-4444-444444444444
- * Endian: LLLLLLLL-LLLL-LLLL-BBBB-BBBBBBBBBBBB
- */
-static void guid_to_str(char *buf, const struct guid *id)
-{
- unsigned int i = 0;
- const char *walker = (const char *)id;
-
- while (i < sizeof(guid_le_walk_map)) {
- walker += guid_le_walk_map[i];
- if (!guid_le_walk_map[i])
- *buf = '-';
- else {
- *buf = ((*walker & 0xF0) >> 4) + '0';
- if (*buf > '9')
- *buf += 'A' - '9' - 1;
- buf++;
- *buf = (*walker & 0x0F) + '0';
- if (*buf > '9')
- *buf += 'A' - '9' - 1;
- }
- buf++;
- i++;
- }
- *buf = 0;
-}
-#endif
-
-/*
- * Create a GUID structure from a textual GUID representation.
- * The input buffer must be >= 32 hexadecimal chars and be
- * terminated with an ASCII NUL. Returns non-zero on failure.
- * Example: 11111111-2222-3333-4444-444444444444
- * Endian: LLLLLLLL-LLLL-LLLL-BBBB-BBBBBBBBBBBB
- */
-static int str_to_guid(const char *buf, struct guid *id)
-{
- char guid_seq[sizeof(struct guid) * 2];
- unsigned int i = 0;
- char *walker = (char *)id;
-
- while (*buf && i < sizeof(guid_seq)) {
- switch (*buf) {
- /* Skip these three characters */
- case '{':
- case '}':
- case '-':
- break;
- default:
- /* Copy something useful to the temp. sequence */
- if ((*buf >= '0') && (*buf <= '9'))
- guid_seq[i] = *buf - '0';
- else if ((*buf >= 'A') && (*buf <= 'F'))
- guid_seq[i] = *buf - 'A' + 10;
- else if ((*buf >= 'a') && (*buf <= 'f'))
- guid_seq[i] = *buf - 'a' + 10;
- else {
- /* Or not */
- error("Illegal character in GUID!\n");
- return -1;
- }
- i++;
- }
- buf++;
- }
- /* Check for insufficient valid characters */
- if (i < sizeof(guid_seq)) {
- error("Too few GUID characters!\n");
- return -1;
- }
- buf = guid_seq;
- i = 0;
- while (i < sizeof(guid_le_walk_map)) {
- if (!guid_le_walk_map[i])
- i++;
- walker += guid_le_walk_map[i];
- *walker = *buf << 4;
- buf++;
- *walker |= *buf;
- buf++;
- i++;
- }
- return 0;
-}
-
-/* A GPT partition */
-struct gpt_part {
- struct guid type;
- struct guid uid;
- uint64_t lba_first;
- uint64_t lba_last;
- uint64_t attribs;
- char name[72];
-} __attribute__ ((packed));
-
-static void gpt_part_dump(const struct gpt_part *gpt_part)
-{
-#ifdef DEBUG
- unsigned int i;
- char guid_text[37];
-
- dprintf("----------------------------------\n"
- "GPT part. LBA first __ : 0x%.16llx\n"
- "GPT part. LBA last ___ : 0x%.16llx\n"
- "GPT part. attribs ____ : 0x%.16llx\n"
- "GPT part. name _______ : '",
- gpt_part->lba_first, gpt_part->lba_last, gpt_part->attribs);
- for (i = 0; i < sizeof(gpt_part->name); i++) {
- if (gpt_part->name[i])
- dprintf("%c", gpt_part->name[i]);
- }
- dprintf("'");
- guid_to_str(guid_text, &gpt_part->type);
- dprintf("GPT part. type GUID __ : {%s}\n", guid_text);
- guid_to_str(guid_text, &gpt_part->uid);
- dprintf("GPT part. unique ID __ : {%s}\n", guid_text);
-#endif
- (void)gpt_part;
-}
-
-/* A GPT header */
-struct gpt {
- char sig[8];
- union {
- struct {
- uint16_t minor;
- uint16_t major;
- } fields __attribute__ ((packed));
- uint32_t uint32;
- char raw[4];
- } rev __attribute__ ((packed));
- uint32_t hdr_size;
- uint32_t chksum;
- char reserved1[4];
- uint64_t lba_cur;
- uint64_t lba_alt;
- uint64_t lba_first_usable;
- uint64_t lba_last_usable;
- struct guid disk_guid;
- uint64_t lba_table;
- uint32_t part_count;
- uint32_t part_size;
- uint32_t table_chksum;
- char reserved2[1];
-} __attribute__ ((packed));
-static const char gpt_sig_magic[] = "EFI PART";
-
-#if DEBUG
-static void gpt_dump(const struct gpt *gpt)
-{
- char guid_text[37];
-
- printf("GPT sig ______________ : '%8.8s'\n"
- "GPT major revision ___ : 0x%.4x\n"
- "GPT minor revision ___ : 0x%.4x\n"
- "GPT header size ______ : 0x%.8x\n"
- "GPT header checksum __ : 0x%.8x\n"
- "GPT reserved _________ : '%4.4s'\n"
- "GPT LBA current ______ : 0x%.16llx\n"
- "GPT LBA alternative __ : 0x%.16llx\n"
- "GPT LBA first usable _ : 0x%.16llx\n"
- "GPT LBA last usable __ : 0x%.16llx\n"
- "GPT LBA part. table __ : 0x%.16llx\n"
- "GPT partition count __ : 0x%.8x\n"
- "GPT partition size ___ : 0x%.8x\n"
- "GPT part. table chksum : 0x%.8x\n",
- gpt->sig,
- gpt->rev.fields.major,
- gpt->rev.fields.minor,
- gpt->hdr_size,
- gpt->chksum,
- gpt->reserved1,
- gpt->lba_cur,
- gpt->lba_alt,
- gpt->lba_first_usable,
- gpt->lba_last_usable,
- gpt->lba_table, gpt->part_count, gpt->part_size, gpt->table_chksum);
- guid_to_str(guid_text, &gpt->disk_guid);
- printf("GPT disk GUID ________ : {%s}\n", guid_text);
-}
-#endif
-
-static struct disk_part_iter *next_gpt_part(struct disk_part_iter *part)
-{
- const struct gpt_part *gpt_part = NULL;
-
- while (++part->private.gpt.index < part->private.gpt.parts) {
- gpt_part =
- (const struct gpt_part *)(part->block +
- (part->private.gpt.index *
- part->private.gpt.size));
- if (!gpt_part->lba_first)
- continue;
- break;
- }
- /* Were we the last partition? */
- if (part->private.gpt.index == part->private.gpt.parts) {
- goto err_last;
- }
- part->lba_data = gpt_part->lba_first;
- part->private.gpt.part_guid = &gpt_part->uid;
- part->private.gpt.part_label = gpt_part->name;
- /* Update our index */
- part->index = part->private.gpt.index + 1;
- gpt_part_dump(gpt_part);
-
- /* In a GPT scheme, we re-use the iterator */
- return part;
-
-err_last:
- free(part->block);
- free(part);
-
- return NULL;
-}
-
-static struct disk_part_iter *get_first_partition(struct disk_part_iter *part)
-{
- const struct gpt *gpt_candidate;
-
- /*
- * Ignore any passed partition iterator. The caller should
- * have passed NULL. Allocate a new partition iterator
- */
- part = malloc(sizeof(*part));
- if (!part) {
- error("Count not allocate partition iterator!\n");
- goto err_alloc_iter;
- }
- /* Read MBR */
- part->block = read_sectors(0, 2);
- if (!part->block) {
- error("Could not read two sectors!\n");
- goto err_read_mbr;
- }
- /* Check for an MBR */
- if (((struct mbr *)part->block)->sig != mbr_sig_magic) {
- error("No MBR magic!\n");
- goto err_mbr;
- }
- /* Establish a pseudo-partition for the MBR (index 0) */
- part->index = 0;
- part->record = NULL;
- part->private.mbr_index = -1;
- part->next = next_mbr_part;
- /* Check for a GPT disk */
- gpt_candidate = (const struct gpt *)(part->block + SECTOR);
- if (!memcmp(gpt_candidate->sig, gpt_sig_magic, sizeof(gpt_sig_magic))) {
- /* LBA for partition table */
- uint64_t lba_table;
-
- /* It looks like one */
- /* TODO: Check checksum. Possibly try alternative GPT */
-#if DEBUG
- puts("Looks like a GPT disk.");
- gpt_dump(gpt_candidate);
-#endif
- /* TODO: Check table checksum (maybe) */
- /* Note relevant GPT details */
- part->next = next_gpt_part;
- part->private.gpt.index = -1;
- part->private.gpt.parts = gpt_candidate->part_count;
- part->private.gpt.size = gpt_candidate->part_size;
- lba_table = gpt_candidate->lba_table;
- gpt_candidate = NULL;
- /* Load the partition table */
- free(part->block);
- part->block =
- read_sectors(lba_table,
- ((part->private.gpt.size * part->private.gpt.parts) +
- SECTOR - 1) / SECTOR);
- if (!part->block) {
- error("Could not read GPT partition list!\n");
- goto err_gpt_table;
- }
- }
- /* Return the pseudo-partition's next partition, which is real */
- return part->next(part);
-
-err_gpt_table:
-
-err_mbr:
-
- free(part->block);
- part->block = NULL;
-err_read_mbr:
-
- free(part);
-err_alloc_iter:
-
- return NULL;
-}
-
-/*
- * Search for a specific drive/partition, based on the GPT GUID.
- * We return the disk drive number if found, as well as populating the
- * boot_part pointer with the matching partition, if applicable.
- * If no matching partition is found or the GUID is a disk GUID,
- * boot_part will be populated with NULL. If not matching disk is
- * found, we return -1.
- */
-static int find_by_guid(const struct guid *gpt_guid,
- struct disk_part_iter **boot_part)
-{
- int drive;
- bool is_me;
- struct gpt *header;
-
- for (drive = 0x80; drive <= 0xff; drive++) {
- if (get_disk_params(drive))
- continue; /* Drive doesn't exist */
- if (!(header = read_sectors(1, 1)))
- continue; /* Cannot read sector */
- if (memcmp(&header->sig, gpt_sig_magic, sizeof(gpt_sig_magic))) {
- /* Not a GPT disk */
- free(header);
- continue;
- }
-#if DEBUG
- gpt_dump(header);
-#endif
- is_me = !memcmp(&header->disk_guid, gpt_guid, sizeof(*gpt_guid));
- free(header);
- if (!is_me) {
- /* Check for a matching partition */
- boot_part[0] = get_first_partition(NULL);
- while (boot_part[0]) {
- is_me =
- !memcmp(boot_part[0]->private.gpt.part_guid, gpt_guid,
- sizeof(*gpt_guid));
- if (is_me)
- break;
- boot_part[0] = boot_part[0]->next(boot_part[0]);
- }
- } else
- boot_part[0] = NULL;
- if (is_me)
- return drive;
- }
- return -1;
-}
-
-/*
- * Search for a specific partition, based on the GPT label.
- * We return the disk drive number if found, as well as populating the
- * boot_part pointer with the matching partition, if applicable.
- * If no matching partition is found, boot_part will be populated with
- * NULL and we return -1.
- */
-static int find_by_label(const char *label, struct disk_part_iter **boot_part)
-{
- int drive;
- bool is_me;
-
- for (drive = 0x80; drive <= 0xff; drive++) {
- if (get_disk_params(drive))
- continue; /* Drive doesn't exist */
- /* Check for a GPT disk */
- boot_part[0] = get_first_partition(NULL);
- if (!(boot_part[0]->next == next_gpt_part)) {
- /* Not a GPT disk */
- while (boot_part[0]) {
- /* Run through until the end */
- boot_part[0] = boot_part[0]->next(boot_part[0]);
- }
- continue;
- }
- /* Check for a matching partition */
- while (boot_part[0]) {
- char gpt_label[sizeof(((struct gpt_part *) NULL)->name)];
- const char *gpt_label_scanner =
- boot_part[0]->private.gpt.part_label;
- int j = 0;
-
- /* Re-write the GPT partition label as ASCII */
- while (gpt_label_scanner <
- boot_part[0]->private.gpt.part_label + sizeof(gpt_label)) {
- if ((gpt_label[j] = *gpt_label_scanner))
- j++;
- gpt_label_scanner++;
- }
- if ((is_me = !strcmp(label, gpt_label)))
- break;
- boot_part[0] = boot_part[0]->next(boot_part[0]);
- }
- if (is_me)
- return drive;
- }
-
- return -1;
-}
-
-static void do_boot(struct data_area *data, int ndata,
- struct syslinux_rm_regs *regs)
-{
- uint16_t *const bios_fbm = (uint16_t *) 0x413;
- addr_t dosmem = *bios_fbm << 10; /* Technically a low bound */
- struct syslinux_memmap *mmap;
- struct syslinux_movelist *mlist = NULL;
- addr_t endimage;
- uint8_t driveno = regs->edx.b[0];
- uint8_t swapdrive = driveno & 0x80;
- int i;
-
- mmap = syslinux_memory_map();
-
- if (!mmap) {
- error("Cannot read system memory map\n");
- return;
- }
-
- endimage = 0;
- for (i = 0; i < ndata; i++) {
- if (data[i].base + data[i].size > endimage)
- endimage = data[i].base + data[i].size;
- }
- if (endimage > dosmem)
- goto too_big;
-
- for (i = 0; i < ndata; i++) {
- if (syslinux_add_movelist(&mlist, data[i].base,
- (addr_t) data[i].data, data[i].size))
- goto enomem;
- }
-
- if (opt.swap && driveno != swapdrive) {
- static const uint8_t swapstub_master[] = {
- /* The actual swap code */
- 0x53, /* 00: push bx */
- 0x0f, 0xb6, 0xda, /* 01: movzx bx,dl */
- 0x2e, 0x8a, 0x57, 0x60, /* 04: mov dl,[cs:bx+0x60] */
- 0x5b, /* 08: pop bx */
- 0xea, 0, 0, 0, 0, /* 09: jmp far 0:0 */
- 0x90, 0x90, /* 0E: nop; nop */
- /* Code to install this in the right location */
- /* Entry with DS = CS; ES = SI = 0; CX = 256 */
- 0x26, 0x66, 0x8b, 0x7c, 0x4c, /* 10: mov edi,[es:si+4*0x13] */
- 0x66, 0x89, 0x3e, 0x0a, 0x00, /* 15: mov [0x0A],edi */
- 0x26, 0x8b, 0x3e, 0x13, 0x04, /* 1A: mov di,[es:0x413] */
- 0x4f, /* 1F: dec di */
- 0x26, 0x89, 0x3e, 0x13, 0x04, /* 20: mov [es:0x413],di */
- 0x66, 0xc1, 0xe7, 0x16, /* 25: shl edi,16+6 */
- 0x26, 0x66, 0x89, 0x7c, 0x4c, /* 29: mov [es:si+4*0x13],edi */
- 0x66, 0xc1, 0xef, 0x10, /* 2E: shr edi,16 */
- 0x8e, 0xc7, /* 32: mov es,di */
- 0x31, 0xff, /* 34: xor di,di */
- 0xf3, 0x66, 0xa5, /* 36: rep movsd */
- 0xbe, 0, 0, /* 39: mov si,0 */
- 0xbf, 0, 0, /* 3C: mov di,0 */
- 0x8e, 0xde, /* 3F: mov ds,si */
- 0x8e, 0xc7, /* 41: mov es,di */
- 0x66, 0xb9, 0, 0, 0, 0, /* 43: mov ecx,0 */
- 0x66, 0xbe, 0, 0, 0, 0, /* 49: mov esi,0 */
- 0x66, 0xbf, 0, 0, 0, 0, /* 4F: mov edi,0 */
- 0xea, 0, 0, 0, 0, /* 55: jmp 0:0 */
- /* pad out to segment boundary */
- 0x90, 0x90, /* 5A: ... */
- 0x90, 0x90, 0x90, 0x90, /* 5C: ... */
- };
- static uint8_t swapstub[1024];
- uint8_t *p;
-
- /* Note: we can't rely on either INT 13h nor the dosmem
- vector to be correct at this stage, so we have to use an
- installer stub to put things in the right place.
- Round the installer location to a 1K boundary so the only
- possible overlap is the identity mapping. */
- endimage = (endimage + 1023) & ~1023;
-
- /* Create swap stub */
- memcpy(swapstub, swapstub_master, sizeof swapstub_master);
- *(uint16_t *) & swapstub[0x3a] = regs->ds;
- *(uint16_t *) & swapstub[0x3d] = regs->es;
- *(uint32_t *) & swapstub[0x45] = regs->ecx.l;
- *(uint32_t *) & swapstub[0x4b] = regs->esi.l;
- *(uint32_t *) & swapstub[0x51] = regs->edi.l;
- *(uint16_t *) & swapstub[0x56] = regs->ip;
- *(uint16_t *) & swapstub[0x58] = regs->cs;
- p = &swapstub[sizeof swapstub_master];
-
- /* Mapping table; start out with identity mapping everything */
- for (i = 0; i < 256; i++)
- p[i] = i;
-
- /* And the actual swap */
- p[driveno] = swapdrive;
- p[swapdrive] = driveno;
-
- /* Adjust registers */
- regs->ds = regs->cs = endimage >> 4;
- regs->es = regs->esi.l = 0;
- regs->ecx.l = sizeof swapstub >> 2;
- regs->ip = 0x10; /* Installer offset */
- regs->ebx.b[0] = regs->edx.b[0] = swapdrive;
-
- if (syslinux_add_movelist(&mlist, endimage, (addr_t) swapstub,
- sizeof swapstub))
- goto enomem;
-
- endimage += sizeof swapstub;
- }
-
- /* Tell the shuffler not to muck with this area... */
- syslinux_add_memmap(&mmap, endimage, 0xa0000 - endimage, SMT_RESERVED);
-
- /* Force text mode */
- syslinux_force_text_mode();
-
- fputs("Booting...\n", stdout);
- syslinux_shuffle_boot_rm(mlist, mmap, opt.keeppxe, regs);
- error("Chainboot failed!\n");
- return;
-
-too_big:
- error("Loader file too large\n");
- return;
-
-enomem:
- error("Out of memory\n");
- return;
-}
-
-static int hide_unhide(struct mbr *mbr, int part)
-{
- int i;
- struct part_entry *pt;
- const uint16_t mask =
- (1 << 0x01) | (1 << 0x04) | (1 << 0x06) | (1 << 0x07) | (1 << 0x0b) | (1
- <<
- 0x0c)
- | (1 << 0x0e);
- uint8_t t;
- bool write_back = false;
-
- for (i = 1; i <= 4; i++) {
- pt = mbr->table + i - 1;
- t = pt->ostype;
- if ((t <= 0x1f) && ((mask >> (t & ~0x10)) & 1)) {
- /* It's a hideable partition type */
- if (i == part)
- t &= ~0x10; /* unhide */
- else
- t |= 0x10; /* hide */
- }
- if (t != pt->ostype) {
- write_back = true;
- pt->ostype = t;
- }
- }
-
- if (write_back)
- return write_verify_sector(0, mbr);
-
- return 0; /* ok */
-}
-
-static uint32_t get_file_lba(const char *filename)
-{
- com32sys_t inregs;
- uint32_t lba;
-
- /* Start with clean registers */
- memset(&inregs, 0, sizeof(com32sys_t));
-
- /* Put the filename in the bounce buffer */
- strlcpy(__com32.cs_bounce, filename, __com32.cs_bounce_size);
-
- /* Call comapi_open() which returns a structure pointer in SI
- * to a structure whose first member happens to be the LBA.
- */
- inregs.eax.w[0] = 0x0006;
- inregs.esi.w[0] = OFFS(__com32.cs_bounce);
- inregs.es = SEG(__com32.cs_bounce);
- __com32.cs_intcall(0x22, &inregs, &inregs);
-
- if ((inregs.eflags.l & EFLAGS_CF) || inregs.esi.w[0] == 0) {
- return 0; /* Filename not found */
- }
-
- /* Since the first member is the LBA, we simply cast */
- lba = *((uint32_t *) MK_PTR(inregs.ds, inregs.esi.w[0]));
-
- /* Clean the registers for the next call */
- memset(&inregs, 0, sizeof(com32sys_t));
-
- /* Put the filename in the bounce buffer */
- strlcpy(__com32.cs_bounce, filename, __com32.cs_bounce_size);
-
- /* Call comapi_close() to free the structure */
- inregs.eax.w[0] = 0x0008;
- inregs.esi.w[0] = OFFS(__com32.cs_bounce);
- inregs.es = SEG(__com32.cs_bounce);
- __com32.cs_intcall(0x22, &inregs, &inregs);
-
- return lba;
-}
-
-static void usage(void)
-{
- static const char usage[] = "\
-Usage: chain.c32 [options]\n\
- chain.c32 hd<disk#> [<partition>] [options]\n\
- chain.c32 fd<disk#> [options]\n\
- chain.c32 mbr:<id> [<partition>] [options]\n\
- chain.c32 guid:<guid> [<partition>] [options]\n\
- chain.c32 label:<label> [<partition>] [options]\n\
- chain.c32 boot [<partition>] [options]\n\
- chain.c32 fs [options]\n\
-Options: file=<loader> Load and execute file, instead of boot sector\n\
- isolinux=<loader> Load another version of ISOLINUX\n\
- ntldr=<loader> Load Windows NTLDR, SETUPLDR.BIN or BOOTMGR\n\
- cmldr=<loader> Load Recovery Console of Windows NT/2K/XP/2003\n\
- freedos=<loader> Load FreeDOS KERNEL.SYS\n\
- msdos=<loader> Load MS-DOS IO.SYS\n\
- pcdos=<loader> Load PC-DOS IBMBIO.COM\n\
- drmk=<loader> Load DRMK DELLBIO.BIN\n\
- grub=<loader> Load GRUB Legacy stage2\n\
- grubcfg=<filename> Set alternative config filename for GRUB Legacy\n\
- grldr=<loader> Load GRUB4DOS grldr\n\
- seg=<segment> Jump to <seg>:0000, instead of 0000:7C00\n\
- swap Swap drive numbers, if bootdisk is not fd0/hd0\n\
- hide Hide primary partitions, except selected partition\n\
- sethidden Set the FAT/NTFS hidden sectors field\n\
- keeppxe Keep the PXE and UNDI stacks in memory (PXELINUX)\n\
-See syslinux/com32/modules/chain.c for more information\n";
- error(usage);
-}
-
-int main(int argc, char *argv[])
-{
- struct mbr *mbr = NULL;
- char *p;
- struct disk_part_iter *cur_part = NULL;
- struct syslinux_rm_regs regs;
- char *drivename, *partition;
- int hd, drive, whichpart = 0; /* MBR by default */
- int i;
- uint64_t fs_lba = 0; /* Syslinux partition */
- uint32_t file_lba = 0;
- struct guid gpt_guid;
- unsigned char *isolinux_bin;
- uint32_t *checksum, *chkhead, *chktail;
- struct data_area data[3];
- int ndata = 0;
- addr_t load_base;
- static const char cmldr_signature[8] = "cmdcons";
-
- drivename = "boot";
- partition = NULL;
-
- /* Prepare the register set */
- memset(&regs, 0, sizeof regs);
-
- for (i = 1; i < argc; i++) {
- if (!strncmp(argv[i], "file=", 5)) {
- opt.loadfile = argv[i] + 5;
- } else if (!strncmp(argv[i], "seg=", 4)) {
- uint32_t segval = strtoul(argv[i] + 4, NULL, 0);
- if (segval < 0x50 || segval > 0x9f000) {
- error("Invalid segment\n");
- goto bail;
- }
- opt.seg = segval;
- } else if (!strncmp(argv[i], "isolinux=", 9)) {
- opt.loadfile = argv[i] + 9;
- opt.isolinux = true;
- } else if (!strncmp(argv[i], "ntldr=", 6)) {
- opt.seg = 0x2000; /* NTLDR wants this address */
- opt.loadfile = argv[i] + 6;
- opt.sethidden = true;
- } else if (!strncmp(argv[i], "cmldr=", 6)) {
- opt.seg = 0x2000; /* CMLDR wants this address */
- opt.loadfile = argv[i] + 6;
- opt.cmldr = true;
- opt.sethidden = true;
- } else if (!strncmp(argv[i], "freedos=", 8)) {
- opt.seg = 0x60; /* FREEDOS wants this address */
- opt.loadfile = argv[i] + 8;
- opt.sethidden = true;
- } else if (!strncmp(argv[i], "msdos=", 6) ||
- !strncmp(argv[i], "pcdos=", 6)) {
- opt.seg = 0x70; /* MS-DOS 2.0+ wants this address */
- opt.loadfile = argv[i] + 6;
- opt.sethidden = true;
- } else if (!strncmp(argv[i], "drmk=", 5)) {
- opt.seg = 0x70; /* DRMK wants this address */
- opt.loadfile = argv[i] + 5;
- opt.sethidden = true;
- opt.drmk = true;
- } else if (!strncmp(argv[i], "grub=", 5)) {
- opt.seg = 0x800; /* stage2 wants this address */
- opt.loadfile = argv[i] + 5;
- opt.grub = true;
- } else if (!strncmp(argv[i], "grubcfg=", 8)) {
- opt.grubcfg = argv[i] + 8;
- } else if (!strncmp(argv[i], "grldr=", 6)) {
- opt.loadfile = argv[i] + 6;
- opt.grldr = true;
- } else if (!strcmp(argv[i], "swap")) {
- opt.swap = true;
- } else if (!strcmp(argv[i], "noswap")) {
- opt.swap = false;
- } else if (!strcmp(argv[i], "hide")) {
- opt.hide = true;
- } else if (!strcmp(argv[i], "nohide")) {
- opt.hide = false;
- } else if (!strcmp(argv[i], "keeppxe")) {
- opt.keeppxe = 3;
- } else if (!strcmp(argv[i], "sethidden")) {
- opt.sethidden = true;
- } else if (!strcmp(argv[i], "nosethidden")) {
- opt.sethidden = false;
- } else if (((argv[i][0] == 'h' || argv[i][0] == 'f')
- && argv[i][1] == 'd')
- || !strncmp(argv[i], "mbr:", 4)
- || !strncmp(argv[i], "mbr=", 4)
- || !strncmp(argv[i], "guid:", 5)
- || !strncmp(argv[i], "guid=", 5)
- || !strncmp(argv[i], "uuid:", 5)
- || !strncmp(argv[i], "uuid=", 5)
- || !strncmp(argv[i], "label:", 6)
- || !strncmp(argv[i], "label=", 6)
- || !strcmp(argv[i], "boot")
- || !strncmp(argv[i], "boot,", 5)
- || !strcmp(argv[i], "fs")) {
- drivename = argv[i];
- p = strchr(drivename, ',');
- if (p) {
- *p = '\0';
- partition = p + 1;
- } else if (argv[i + 1] && argv[i + 1][0] >= '0'
- && argv[i + 1][0] <= '9') {
- partition = argv[++i];
- }
- } else {
- usage();
- goto bail;
- }
- }
-
- if (opt.grubcfg && !opt.grub) {
- error("grubcfg=<filename> must be used together with grub=<loader>.\n");
- goto bail;
- }
-
- if (opt.seg) {
- regs.es = regs.cs = regs.ss = regs.ds = regs.fs = regs.gs = opt.seg;
- } else {
- regs.ip = regs.esp.l = 0x7c00;
- }
-
- hd = 0;
- if (!strncmp(drivename, "mbr", 3)) {
- drive = find_disk(strtoul(drivename + 4, NULL, 0));
- if (drive == -1) {
- error("Unable to find requested MBR signature\n");
- goto bail;
- }
- } else if (!strncmp(drivename, "guid", 4) ||
- !strncmp(drivename, "uuid", 4)) {
- if (str_to_guid(drivename + 5, &gpt_guid))
- goto bail;
- drive = find_by_guid(&gpt_guid, &cur_part);
- if (drive == -1) {
- error("Unable to find requested GPT disk/partition\n");
- goto bail;
- }
- } else if (!strncmp(drivename, "label", 5)) {
- if (!drivename[6]) {
- error("No label specified.\n");
- goto bail;
- }
- drive = find_by_label(drivename + 6, &cur_part);
- if (drive == -1) {
- error("Unable to find requested partition by label\n");
- goto bail;
- }
- } else if ((drivename[0] == 'h' || drivename[0] == 'f') &&
- drivename[1] == 'd') {
- hd = drivename[0] == 'h';
- drivename += 2;
- drive = (hd ? 0x80 : 0) | strtoul(drivename, NULL, 0);
- } else if (!strcmp(drivename, "boot") || !strcmp(drivename, "fs")) {
- const union syslinux_derivative_info *sdi;
-
- sdi = syslinux_derivative_info();
- if (sdi->c.filesystem == SYSLINUX_FS_PXELINUX)
- drive = 0x80; /* Boot drive not available */
- else
- drive = sdi->disk.drive_number;
- if (!strcmp(drivename, "fs")
- && (sdi->c.filesystem == SYSLINUX_FS_SYSLINUX
- || sdi->c.filesystem == SYSLINUX_FS_EXTLINUX
- || sdi->c.filesystem == SYSLINUX_FS_ISOLINUX))
- /* We should lookup the Syslinux partition number and use it */
- fs_lba = *sdi->disk.partoffset;
- } else {
- error("Unparsable drive specification\n");
- goto bail;
- }
-
- /* DOS kernels want the drive number in BL instead of DL. Indulge them. */
- regs.ebx.b[0] = regs.edx.b[0] = drive;
-
- /* Get the disk geometry and disk access setup */
- if (get_disk_params(drive)) {
- error("Cannot get disk parameters\n");
- goto bail;
- }
-
- /* Get MBR */
- if (!(mbr = read_sectors(0, 1))) {
- error("Cannot read Master Boot Record or sector 0\n");
- goto bail;
- }
-
- if (partition)
- whichpart = strtoul(partition, NULL, 0);
- /* "guid:" or "label:" might have specified a partition */
- if (cur_part)
- whichpart = cur_part->index;
-
- /* Boot the MBR by default */
- if (!cur_part && (whichpart || fs_lba)) {
- /* Boot a partition, possibly the Syslinux partition itself */
- cur_part = get_first_partition(NULL);
- while (cur_part) {
- if ((cur_part->index == whichpart)
- || (cur_part->lba_data == fs_lba))
- /* Found the partition to boot */
- break;
- cur_part = cur_part->next(cur_part);
- }
- if (!cur_part) {
- error("Requested partition not found!\n");
- goto bail;
- }
- whichpart = cur_part->index;
- }
-
- if (!(drive & 0x80) && whichpart) {
- error("Warning: Partitions of floppy devices may not work\n");
- }
-
- /*
- * GRLDR of GRUB4DOS wants the partition number in DH:
- * -1: whole drive (default)
- * 0-3: primary partitions
- * 4-*: logical partitions
- */
- if (opt.grldr)
- regs.edx.b[1] = whichpart - 1;
-
- if (opt.hide) {
- if (whichpart < 1 || whichpart > 4)
- error("WARNING: hide specified without a non-primary partition\n");
- if (hide_unhide(mbr, whichpart))
- error("WARNING: failed to write MBR for 'hide'\n");
- }
-
- /* Do the actual chainloading */
- load_base = opt.seg ? (opt.seg << 4) : 0x7c00;
-
- if (opt.loadfile) {
- fputs("Loading the boot file...\n", stdout);
- if (loadfile(opt.loadfile, &data[ndata].data, &data[ndata].size)) {
- error("Failed to load the boot file\n");
- goto bail;
- }
- data[ndata].base = load_base;
- load_base = 0x7c00; /* If we also load a boot sector */
-
- /* Create boot info table: needed when you want to chainload
- another version of ISOLINUX (or another bootlaoder that needs
- the -boot-info-table switch of mkisofs)
- (will only work when run from ISOLINUX) */
- if (opt.isolinux) {
- const union syslinux_derivative_info *sdi;
- sdi = syslinux_derivative_info();
-
- if (sdi->c.filesystem == SYSLINUX_FS_ISOLINUX) {
- /* Boot info table info (integers in little endian format)
-
- Offset Name Size Meaning
- 8 bi_pvd 4 bytes LBA of primary volume descriptor
- 12 bi_file 4 bytes LBA of boot file
- 16 bi_length 4 bytes Boot file length in bytes
- 20 bi_csum 4 bytes 32-bit checksum
- 24 bi_reserved 40 bytes Reserved
-
- The 32-bit checksum is the sum of all the 32-bit words in the
- boot file starting at byte offset 64. All linear block
- addresses (LBAs) are given in CD sectors (normally 2048 bytes).
-
- LBA of primary volume descriptor should already be set to 16.
- */
-
- isolinux_bin = (unsigned char *)data[ndata].data;
-
- /* Get LBA address of bootfile */
- file_lba = get_file_lba(opt.loadfile);
-
- if (file_lba == 0) {
- error("Failed to find LBA offset of the boot file\n");
- goto bail;
- }
- /* Set it */
- *((uint32_t *) & isolinux_bin[12]) = file_lba;
-
- /* Set boot file length */
- *((uint32_t *) & isolinux_bin[16]) = data[ndata].size;
-
- /* Calculate checksum */
- checksum = (uint32_t *) & isolinux_bin[20];
- chkhead = (uint32_t *) & isolinux_bin[64];
- chktail = (uint32_t *) & isolinux_bin[data[ndata].size & ~3];
- *checksum = 0;
- while (chkhead < chktail)
- *checksum += *chkhead++;
-
- /*
- * Deal with possible fractional dword at the end;
- * this *should* never happen...
- */
- if (data[ndata].size & 3) {
- uint32_t xword = 0;
- memcpy(&xword, chkhead, data[ndata].size & 3);
- *checksum += xword;
- }
- } else {
- error
- ("The isolinux= option is only valid when run from ISOLINUX\n");
- goto bail;
- }
- }
-
- if (opt.grub) {
- /* Layout of stage2 file (from byte 0x0 to 0x270) */
- struct grub_stage2_patch_area {
- /* 0x0 to 0x205 */
- char unknown[0x206];
- /* 0x206: compatibility version number major */
- uint8_t compat_version_major;
- /* 0x207: compatibility version number minor */
- uint8_t compat_version_minor;
-
- /* 0x208: install_partition variable */
- struct {
- /* 0x208: sub-partition in sub-partition part2 */
- uint8_t part3;
- /* 0x209: sub-partition in top-level partition */
- uint8_t part2;
- /* 0x20a: top-level partiton number */
- uint8_t part1;
- /* 0x20b: BIOS drive number (must be 0) */
- uint8_t drive;
- } __attribute__ ((packed)) install_partition;
-
- /* 0x20c: deprecated (historical reason only) */
- uint32_t saved_entryno;
- /* 0x210: stage2_ID: will always be STAGE2_ID_STAGE2 = 0 in stage2 */
- uint8_t stage2_id;
- /* 0x211: force LBA */
- uint8_t force_lba;
- /* 0x212: version string (will probably be 0.97) */
- char version_string[5];
- /* 0x217: config filename */
- char config_file[89];
- /* 0x270: start of code (after jump from 0x200) */
- char codestart[1];
- } __attribute__ ((packed)) *stage2;
-
- if (data[ndata].size < sizeof(struct grub_stage2_patch_area)) {
- error
- ("The file specified by grub=<loader> is to small to be stage2 of GRUB Legacy.\n");
- goto bail;
- }
-
- stage2 = data[ndata].data;
-
- /*
- * Check the compatibility version number to see if we loaded a real
- * stage2 file or a stage2 file that we support.
- */
- if (stage2->compat_version_major != 3
- || stage2->compat_version_minor != 2) {
- error
- ("The file specified by grub=<loader> is not a supported stage2 GRUB Legacy binary\n");
- goto bail;
- }
-
- /* jump 0x200 bytes into the loadfile */
- regs.ip = 0x200;
-
- /*
- * GRUB Legacy wants the partition number in the install_partition
- * variable, located at offset 0x208 of stage2.
- * When GRUB Legacy is loaded, it is located at memory address 0x8208.
- *
- * It looks very similar to the "boot information format" of the
- * Multiboot specification:
- * http://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Boot-information-format
- *
- * 0x208 = part3: sub-partition in sub-partition part2
- * 0x209 = part2: sub-partition in top-level partition
- * 0x20a = part1: top-level partition number
- * 0x20b = drive: BIOS drive number (must be 0)
- *
- * GRUB Legacy doesn't store the BIOS drive number at 0x20b, but at
- * another location.
- *
- * Partition numbers always start from zero.
- * Unused partition bytes must be set to 0xFF.
- *
- * We only care about top-level partition, so we only need to change
- * "part1" to the appropriate value:
- * -1: whole drive (default) (-1 = 0xFF)
- * 0-3: primary partitions
- * 4-*: logical partitions
- */
- stage2->install_partition.part1 = whichpart - 1;
-
- /*
- * Grub Legacy reserves 89 bytes (from 0x8217 to 0x826f) for the
- * config filename. The filename passed via grubcfg= will overwrite
- * the default config filename "/boot/grub/menu.lst".
- */
- if (opt.grubcfg) {
- if (strlen(opt.grubcfg) > sizeof(stage2->config_file) - 1) {
- error
- ("The config filename length can't exceed 88 characters.\n");
- goto bail;
- }
-
- strcpy((char *)stage2->config_file, opt.grubcfg);
- }
- }
-
- if (opt.drmk) {
- /* DRMK entry is different than MS-DOS/PC-DOS */
- /*
- * A new size, aligned to 16 bytes to ease use of ds:[bp+28].
- * We only really need 4 new, usable bytes at the end.
- */
- int tsize = (data[ndata].size + 19) & 0xfffffff0;
- const union syslinux_derivative_info *sdi;
-
- sdi = syslinux_derivative_info();
- /* We should lookup the Syslinux partition offset and use it */
- fs_lba = *sdi->disk.partoffset;
- /*
- * fs_lba should be verified against the disk as some DRMK
- * variants will check and fail if it does not match
- */
- dprintf(" fs_lba offset is %d\n", fs_lba);
- /* DRMK only uses a DWORD */
- if (fs_lba > 0xffffffff) {
- error("LBA very large; Only using lower 32 bits; DRMK will probably fail\n");
- }
- regs.ss = regs.fs = regs.gs = 0; /* Used before initialized */
- if (!realloc(data[ndata].data, tsize)) {
- error("Failed to realloc for DRMK\n");
- goto bail; /* We'll never make it */
- }
- data[ndata].size = tsize;
- /* ds:bp is assumed by DRMK to be the boot sector */
- /* offset 28 is the FAT HiddenSectors value */
- regs.ds = (tsize >> 4) + (opt.seg - 2);
- /* "Patch" into tail of the new space */
- *(int *)(data[ndata].data + tsize - 4) = (int)(fs_lba & 0xffffffff);
- }
-
- ndata++;
- }
-
- if (!opt.loadfile || data[0].base >= 0x7c00 + SECTOR) {
- /* Actually read the boot sector */
- if (!cur_part) {
- data[ndata].data = mbr;
- } else if (!(data[ndata].data = read_sectors(cur_part->lba_data, 1))) {
- error("Cannot read boot sector\n");
- goto bail;
- }
- data[ndata].size = SECTOR;
- data[ndata].base = load_base;
-
- if (!opt.loadfile) {
- const struct mbr *br =
- (const struct mbr *)((char *)data[ndata].data +
- data[ndata].size - sizeof(struct mbr));
- if (br->sig != mbr_sig_magic) {
- error
- ("Boot sector signature not found (unbootable disk/partition?)\n");
- goto bail;
- }
- }
- /*
- * To boot the Recovery Console of Windows NT/2K/XP we need to write
- * the string "cmdcons\0" to memory location 0000:7C03.
- * Memory location 0000:7C00 contains the bootsector of the partition.
- */
- if (cur_part && opt.cmldr) {
- memcpy((char *)data[ndata].data + 3, cmldr_signature,
- sizeof cmldr_signature);
- }
-
- /*
- * Modify the hidden sectors (partition offset) copy in memory;
- * this modifies the field used by FAT and NTFS filesystems, and
- * possibly other boot loaders which use the same format.
- */
- if (cur_part && opt.sethidden) {
- *(uint32_t *) ((char *)data[ndata].data + 28) = cur_part->lba_data;
- }
-
- ndata++;
- }
-
- if (cur_part) {
- if (cur_part->next == next_gpt_part) {
- /* Do GPT hand-over, if applicable (as per syslinux/doc/gpt.txt) */
- struct part_entry *record;
- /* Look at the GPT partition */
- const struct gpt_part *gp = (const struct gpt_part *)
- (cur_part->block +
- (cur_part->private.gpt.size * cur_part->private.gpt.index));
- /* Note the partition length */
- uint64_t lba_count = gp->lba_last - gp->lba_first + 1;
- /* The length of the hand-over */
- int synth_size =
- sizeof(struct part_entry) + sizeof(uint32_t) +
- cur_part->private.gpt.size;
- /* Will point to the partition record length in the hand-over */
- uint32_t *plen;
-
- /* Allocate the hand-over record */
- record = malloc(synth_size);
- if (!record) {
- error("Could not build GPT hand-over record!\n");
- goto bail;
- }
- /* Synthesize the record */
- memset(record, 0, synth_size);
- record->active_flag = 0x80;
- record->ostype = 0xED;
- /* All bits set by default */
- record->start_lba = ~(uint32_t) 0;
- record->length = ~(uint32_t) 0;
- /* If these fit the precision, pass them on */
- if (cur_part->lba_data < record->start_lba)
- record->start_lba = cur_part->lba_data;
- if (lba_count < record->length)
- record->length = lba_count;
- /* Next comes the GPT partition record length */
- plen = (uint32_t *) (record + 1);
- plen[0] = cur_part->private.gpt.size;
- /* Next comes the GPT partition record copy */
- memcpy(plen + 1, gp, plen[0]);
- cur_part->record = record;
-
- regs.eax.l = 0x54504721; /* '!GPT' */
- data[ndata].base = 0x7be;
- data[ndata].size = synth_size;
- data[ndata].data = (void *)record;
- ndata++;
- regs.esi.w[0] = 0x7be;
-
- dprintf("GPT handover:\n");
- mbr_part_dump(record);
- gpt_part_dump((struct gpt_part *)(plen + 1));
- } else if (cur_part->record) {
- /* MBR handover protocol */
- static struct part_entry handover_record;
-
- handover_record = *cur_part->record;
- handover_record.start_lba = cur_part->lba_data;
-
- data[ndata].base = 0x7be;
- data[ndata].size = sizeof handover_record;
- data[ndata].data = &handover_record;
- ndata++;
- regs.esi.w[0] = 0x7be;
-
- dprintf("MBR handover:\n");
- mbr_part_dump(&handover_record);
- }
- }
-
- do_boot(data, ndata, &regs);
-
-bail:
- if (cur_part) {
- free(cur_part->block);
- free((void *)cur_part->record);
- }
- free(cur_part);
- free(mbr);
- return 255;
-}
diff --git a/com32/modules/elf.c b/com32/modules/elf.c
index 84c80ac2..a946af1f 100644
--- a/com32/modules/elf.c
+++ b/com32/modules/elf.c
@@ -120,10 +120,8 @@ int boot_elf(void *ptr, size_t len, char **argv)
if (!mmap || !amap)
goto bail;
-#if DEBUG
dprintf("Initial memory map:\n");
- syslinux_dump_memmap(stdout, mmap);
-#endif
+ syslinux_dump_memmap(mmap);
ph = (Elf32_Phdr *) (cptr + eh->e_phoff);
@@ -185,10 +183,8 @@ int boot_elf(void *ptr, size_t len, char **argv)
if (!stack_frame)
goto bail;
-#if DEBUG
dprintf("Right before syslinux_memmap_largest()...\n");
- syslinux_dump_memmap(stdout, amap);
-#endif
+ syslinux_dump_memmap(amap);
if (syslinux_memmap_largest(amap, SMT_FREE, &lstart, &llen))
goto bail; /* NO free memory?! */
@@ -239,16 +235,14 @@ int boot_elf(void *ptr, size_t len, char **argv)
regs.eip = eh->e_entry;
regs.esp = stack_pointer;
-#if DEBUG
dprintf("Final memory map:\n");
- syslinux_dump_memmap(stdout, mmap);
+ syslinux_dump_memmap(mmap);
dprintf("Final available map:\n");
- syslinux_dump_memmap(stdout, amap);
+ syslinux_dump_memmap(amap);
dprintf("Movelist:\n");
- syslinux_dump_movelist(stdout, ml);
-#endif
+ syslinux_dump_movelist(ml);
/* This should not return... */
fputs("Booting...\n", stdout);
diff --git a/com32/modules/ethersel.c b/com32/modules/ethersel.c
index d6b4774f..039de276 100644
--- a/com32/modules/ethersel.c
+++ b/com32/modules/ethersel.c
@@ -38,12 +38,7 @@
#include <com32.h>
#include <syslinux/boot.h>
#include <syslinux/config.h>
-
-#ifdef DEBUG
-# define dprintf printf
-#else
-# define dprintf(...) ((void)0)
-#endif
+#include <dprintf.h>
#define MAX_LINE 512
diff --git a/com32/modules/gpxecmd.c b/com32/modules/gpxecmd.c
index 9ae1b601..d2d90a2f 100644
--- a/com32/modules/gpxecmd.c
+++ b/com32/modules/gpxecmd.c
@@ -22,7 +22,9 @@
#include <console.h>
#include <com32.h>
#include <string.h>
+
#include <sys/gpxe.h>
+#include <syslinux/pxe_api.h>
struct segoff16 {
uint16_t offs, seg;
@@ -37,11 +39,11 @@ static void gpxecmd(const char **args)
{
char *q;
struct s_PXENV_FILE_EXEC *fx;
- com32sys_t reg;
- memset(&reg, 0, sizeof reg);
+ fx = lmalloc(sizeof *fx);
+ if (!fx)
+ return;
- fx = __com32.cs_bounce;
q = (char *)(fx + 1);
fx->Status = 1;
@@ -55,13 +57,7 @@ static void gpxecmd(const char **args)
}
*--q = '\0';
- memset(&reg, 0, sizeof reg);
- reg.eax.w[0] = 0x0009;
- reg.ebx.w[0] = 0x00e5; /* PXENV_FILE_EXEC */
- reg.edi.w[0] = OFFS(fx);
- reg.es = SEG(fx);
-
- __intcall(0x22, &reg, &reg);
+ pxe_call(PXENV_FILE_EXEC, fx);
/* This should not return... */
}
diff --git a/com32/modules/hello.c b/com32/modules/hello.c
index f28d38d3..d3d4d299 100644
--- a/com32/modules/hello.c
+++ b/com32/modules/hello.c
@@ -13,7 +13,7 @@
#define NUM_COUNT 10
#define MAX_NUM 100
-int main(int argc, char **argv)
+int main(int argc __unused, char **argv __unused)
{
int *nums = NULL;
diff --git a/com32/modules/host.c b/com32/modules/host.c
index c9cea97c..d70efffd 100644
--- a/com32/modules/host.c
+++ b/com32/modules/host.c
@@ -1,39 +1,41 @@
#include <stdio.h>
-#include <console.h>
+#include <stdlib.h>
#include <string.h>
+#include <console.h>
#include <netinet/in.h>
#include <com32.h>
+#include <syslinux/pxe.h>
-static struct in_addr dnsresolve(const char *hostname)
+static inline uint32_t dns_resolve(const char *hostname)
{
- com32sys_t regs;
- struct in_addr addr;
-
- strcpy(__com32.cs_bounce, hostname);
-
- regs.eax.w[0] = 0x0010;
- regs.es = SEG(__com32.cs_bounce);
- regs.ebx.w[0] = OFFS(__com32.cs_bounce);
- __intcall(0x22, &regs, &regs);
+ return pxe_dns(hostname);
+}
- addr.s_addr = regs.eax.l;
- return addr;
+static inline void usage(const char *s)
+{
+ fprintf(stderr, "Usage: %s hostname [, hostname_1, hostname_2, ...]\n", s);
}
int main(int argc, char *argv[])
{
int i;
- struct in_addr addr;
+ uint32_t ip;
- for (i = 1; i < argc; i++) {
- addr = dnsresolve(argv[i]);
+ openconsole(&dev_null_r, &dev_stdcon_w);
+
+ if (argc < 2) {
+ usage(argv[0]);
+ return 1;
+ }
- printf("%-39s %08X %d.%d.%d.%d\n",
- argv[i], ntohl(addr.s_addr),
- ((uint8_t *)&addr.s_addr)[0],
- ((uint8_t *)&addr.s_addr)[1],
- ((uint8_t *)&addr.s_addr)[2],
- ((uint8_t *)&addr.s_addr)[3]);
+ for (i = 1; i < argc; i++) {
+ ip = dns_resolve(argv[i]);
+ if (!ip) {
+ printf("%s not found.\n", argv[i]);
+ } else {
+ printf("%-39s %08X %u.%u.%u.%u\n", argv[i], ntohl(ip), ip & 0xFF,
+ (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, (ip >> 24) & 0xFF);
+ }
}
return 0;
diff --git a/com32/modules/ifcpu.c b/com32/modules/ifcpu.c
index a28acc4e..0aa63327 100644
--- a/com32/modules/ifcpu.c
+++ b/com32/modules/ifcpu.c
@@ -49,11 +49,12 @@ static void usage(void)
" dry-run : just do the detection, don't boot \n"
"\n"
"cpu_features could be:\n"
- " 64 : Processor is x86_64 compatible (lm cpu flag)\n"
- " hvm : Processor features hardware virtualization (hvm or svm cpu flag)\n"
- " multicore : Processor must be multi-core \n"
- " smp : System must be multi-processor \n"
- " pae : Processor features Physical Address Extension (PAE)\n"
+ " 64 : Processor is x86_64 compatible (lm cpu flag)\n"
+ " hvm : Processor features hardware virtualization (hvm or svm cpu flag)\n"
+ " multicore : Processor must be multi-core \n"
+ " smp : System must be multi-processor \n"
+ " pae : Processor features Physical Address Extension (PAE)\n"
+ " hypervisor : Processor is running under an hypervisor\n"
"\n"
"if you want to match many cpu features, just separate them with a single space.\n");
}
@@ -114,30 +115,34 @@ int main(int argc, char *argv[])
args[n++] = &argv[i + 1];
} else if (!strcmp(argv[i], "64")) {
if (debug)
- printf(" 64bit : %s on this system\n",
+ printf(" 64bit : %s on this system\n",
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/linux.c b/com32/modules/linux.c
index a5ce01f2..e4c067ff 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;
(void)argc;
argp = argv + 1;
@@ -142,9 +164,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.
@@ -157,23 +182,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 {
@@ -183,10 +215,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)
@@ -200,15 +233,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/meminfo.c b/com32/modules/meminfo.c
index 00d0e14d..34b3e91d 100644
--- a/com32/modules/meminfo.c
+++ b/com32/modules/meminfo.c
@@ -44,9 +44,9 @@ static void dump_e820(void)
uint32_t type;
void *low_ed;
- low_ed = lmalloc(sizeof ed);
- if (!low_ed)
- return;
+ low_ed = lmalloc(sizeof ed);
+ if (!low_ed)
+ return;
memset(&ireg, 0, sizeof ireg);
@@ -90,7 +90,7 @@ static void dump_e820(void)
ireg.ebx.l = oreg.ebx.l;
} while (ireg.ebx.l);
- free(low_ed);
+ lfree(low_ed);
}
static void dump_legacy(void)
@@ -122,7 +122,7 @@ static void dump_legacy(void)
oreg.ecx.w[0], oreg.ecx.w[0], oreg.edx.w[0], oreg.edx.w[0] << 6);
}
-int main(int argc, char **argv)
+int main(int argc __unused, char **argv __unused)
{
dump_legacy();
dump_e820();
diff --git a/com32/modules/pcitest.c b/com32/modules/pcitest.c
index c4317eff..fb6bbbf1 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 88065fb2..6808d38a 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/pxechn.c b/com32/modules/pxechn.c
new file mode 100644
index 00000000..39ac72ea
--- /dev/null
+++ b/com32/modules/pxechn.c
@@ -0,0 +1,1106 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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>
+
+
+#define PXECHN_DEBUG 1
+
+typedef union {
+ uint64_t q;
+ uint32_t l[2];
+ uint16_t w[4];
+ uint8_t b[8];
+} reg64_t;
+
+#define dprintf0(f, ...) ((void)0)
+
+#if (PXECHN_DEBUG > 0)
+# 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(tm) ((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 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 */
+ 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->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:t: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 '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;
+
+ 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;
+ 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)
+{
+ 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;
+ pxe_call(PXENV_GET_CACHED_INFO, ci);
+
+ 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;
+ 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);
+ 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);
+
+ pxe_call(PXENV_RESTART_TFTP, pxep);
+
+ printf("PXENV_RESTART_TFTP returned %d\n", pxep->Status);
+ 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/sanboot.c b/com32/modules/sanboot.c
index 01265dea..ff55f68e 100644
--- a/com32/modules/sanboot.c
+++ b/com32/modules/sanboot.c
@@ -22,7 +22,9 @@
#include <console.h>
#include <com32.h>
#include <string.h>
+
#include <sys/gpxe.h>
+#include <syslinux/pxe_api.h>
struct segoff16 {
uint16_t offs, seg;
@@ -37,11 +39,11 @@ static void sanboot(const char **args)
{
char *q;
struct s_PXENV_FILE_EXEC *fx;
- com32sys_t reg;
- memset(&reg, 0, sizeof reg);
+ fx = lmalloc(sizeof *fx);
+ if (!fx)
+ return;
- fx = __com32.cs_bounce;
q = (char *)(fx + 1);
fx->Status = 1;
@@ -56,13 +58,7 @@ static void sanboot(const char **args)
args++;
}
- memset(&reg, 0, sizeof reg);
- reg.eax.w[0] = 0x0009;
- reg.ebx.w[0] = 0x00e5; /* PXENV_FILE_EXEC */
- reg.edi.w[0] = OFFS(fx);
- reg.es = SEG(fx);
-
- __intcall(0x22, &reg, &reg);
+ pxe_call(PXENV_FILE_EXEC, fx);
/* This should not return... */
}
diff --git a/com32/modules/vesainfo.c b/com32/modules/vesainfo.c
index 86a43657..66b121d7 100644
--- a/com32/modules/vesainfo.c
+++ b/com32/modules/vesainfo.c
@@ -79,11 +79,11 @@ static void print_modes(void)
}
exit:
- free(vesa);
+ lfree(vesa);
return;
}
-int main(int argc, char **argv)
+int main(int argc __unused, char **argv __unused)
{
print_modes();
return 0;
diff --git a/com32/rosh/Makefile b/com32/rosh/Makefile
index 766f68d5..f3283952 100644
--- a/com32/rosh/Makefile
+++ b/com32/rosh/Makefile
@@ -34,6 +34,8 @@ endif
CFLAGS += -DDATE='"$(DATE)"'
LNXCFLAGS += -DDATE='"$(DATE)"'
+LDFLAGS_rosh.o = $(com32)/libutil/libutil_com.c32 $(com32)/lib/libcom32.c32
+
rosh.o: rosh.h
rosh.lo: rosh.h
diff --git a/com32/samples/Makefile b/com32/samples/Makefile
index 167c638c..bca197ed 100644
--- a/com32/samples/Makefile
+++ b/com32/samples/Makefile
@@ -18,6 +18,9 @@ topdir = ../..
MAKEDIR = $(topdir)/mk
include $(MAKEDIR)/elf.mk
+LDFLAGS_fancyhello.o = $(com32)/libutil/libutil_com.c32
+LDFLAGS_keytest.o = $(com32)/libutil/libutil_com.c32
+
all: hello.c32 resolv.c32 serialinfo.c32 \
localboot.c32 \
fancyhello.c32 fancyhello.lnx \
diff --git a/com32/samples/resolv.c b/com32/samples/resolv.c
index fae6649b..8f062d19 100644
--- a/com32/samples/resolv.c
+++ b/com32/samples/resolv.c
@@ -16,6 +16,7 @@
* Resolve an IP address
*/
+#include <syslinux/pxe_api.h>
#include <string.h>
#include <stdio.h>
#include <console.h>
@@ -24,21 +25,7 @@
uint32_t resolv(const char *name)
{
- com32sys_t reg;
-
- strcpy((char *)__com32.cs_bounce, name);
-
- memset(&reg, 0, sizeof reg);
- reg.eax.w[0] = 0x0010;
- reg.ebx.w[0] = OFFS(__com32.cs_bounce);
- reg.es = SEG(__com32.cs_bounce);
-
- __intcall(0x22, &reg, &reg);
-
- if (reg.eflags.l & EFLAGS_CF)
- return 0;
- else
- return reg.eax.l;
+ return dns_resolv(name);
}
int main(int argc, char *argv[])
diff --git a/com32/tools/Makefile b/com32/tools/Makefile
index 7badabd2..0161baf1 100644
--- a/com32/tools/Makefile
+++ b/com32/tools/Makefile
@@ -15,6 +15,8 @@ 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 fd8edd14..3a1e875a 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -53,16 +53,16 @@ SOBJ := $(patsubst %.S,%.o,$(SSRC))
COBJS = $(filter-out rawcon.o plaincon.o,$(COBJ))
LIB = libcom32.a
-LIBS = $(LIB) --whole-archive $(com32)/lib/libcom32min.a
+LIBS = $(LIB) --whole-archive $(com32)/lib/libcom32core.a
LIBDEP = $(filter-out -% %start%,$(LIBS))
-LIBOBJS = $(COBJS) $(SOBJ)
+LIBOBJS = $(COBJS) $(SOBJ)
NASMDEBUG = -g -F dwarf
NASMOPT += $(NASMDEBUG)
PREPCORE = ../lzo/prepcore
-# CFLAGS += -DDEBUG=1
+CFLAGS += -D__SYSLINUX_CORE__
# The DATE is set on the make command line when building binaries for
# official release. Otherwise, substitute a hex string that is pretty much
diff --git a/core/bios.c b/core/bios.c
index 9e341467..ce6a31c0 100644
--- a/core/bios.c
+++ b/core/bios.c
@@ -1,6 +1,9 @@
+#include <sys/ansi.h>
#include <sys/io.h>
#include <fs.h>
#include <bios.h>
+#include <com32.h>
+#include <graphics.h>
#include <syslinux/memscan.h>
#include <syslinux/firmware.h>
@@ -8,15 +11,110 @@ struct firmware *firmware = NULL;
extern struct ansi_ops bios_ansi_ops;
-extern void bios_erase(int, int, int, int, uint8_t);
-extern void bios_write_char(uint8_t, uint8_t);
-extern void bios_showcursor(uint16_t);
-extern void bios_scroll_up(uint8_t, uint8_t, uint8_t);
-extern void bios_set_cursor(int, int, bool);
-extern void bios_beep(void);
-extern void bios_set_mode(uint16_t mode);
-extern void bios_get_mode(int *rows, int *cols);
-extern void bios_get_cursor(int *x, int *y);
+#define BIOS_CURXY ((struct curxy *)0x450) /* Array for each page */
+#define BIOS_ROWS (*(uint8_t *)0x484) /* Minus one; if zero use 24 (= 25 lines) */
+#define BIOS_COLS (*(uint16_t *)0x44A)
+#define BIOS_PAGE (*(uint8_t *)0x462)
+
+static void bios_set_mode(uint16_t mode)
+{
+ syslinux_force_text_mode();
+}
+
+static void bios_get_mode(int *cols, int *rows)
+{
+ *rows = BIOS_ROWS ? BIOS_ROWS + 1 : 25;
+ *cols = BIOS_COLS;
+}
+
+static uint16_t cursor_type; /* Saved cursor pattern */
+
+static void bios_get_cursor(int *x, int *y)
+{
+ com32sys_t ireg, oreg;
+
+ memset(&ireg, 0, sizeof(ireg));
+
+ ireg.eax.b[1] = 0x03;
+ ireg.ebx.b[1] = BIOS_PAGE;
+ __intcall(0x10, &ireg, &oreg);
+ cursor_type = oreg.ecx.w[0];
+ *x = oreg.edx.b[0];
+ *y = oreg.edx.b[1];
+}
+
+static void bios_erase(int x0, int y0, int x1, int y1, uint8_t attribute)
+{
+ static com32sys_t ireg;
+
+ ireg.eax.w[0] = 0x0600; /* Clear window */
+ ireg.ebx.b[1] = attribute;
+ ireg.ecx.b[0] = x0;
+ ireg.ecx.b[1] = y0;
+ ireg.edx.b[0] = x1;
+ ireg.edx.b[1] = y1;
+ __intcall(0x10, &ireg, NULL);
+}
+
+static void bios_showcursor(const struct term_state *st)
+{
+ static com32sys_t ireg;
+ uint16_t cursor = st->cursor ? cursor_type : 0x2020;
+
+ ireg.eax.b[1] = 0x01;
+ ireg.ecx.w[0] = cursor;
+ __intcall(0x10, &ireg, NULL);
+}
+
+static void bios_set_cursor(int x, int y, bool visible)
+{
+ const int page = BIOS_PAGE;
+ struct curxy xy = BIOS_CURXY[page];
+ static com32sys_t ireg;
+
+ (void)visible;
+
+ if (xy.x != x || xy.y != y) {
+ ireg.eax.b[1] = 0x02;
+ ireg.ebx.b[1] = page;
+ ireg.edx.b[1] = y;
+ ireg.edx.b[0] = x;
+ __intcall(0x10, &ireg, NULL);
+ }
+}
+
+static void bios_write_char(uint8_t ch, uint8_t attribute)
+{
+ static com32sys_t ireg;
+
+ ireg.eax.b[1] = 0x09;
+ ireg.eax.b[0] = ch;
+ ireg.ebx.b[1] = BIOS_PAGE;
+ ireg.ebx.b[0] = attribute;
+ ireg.ecx.w[0] = 1;
+ __intcall(0x10, &ireg, NULL);
+}
+
+static void bios_scroll_up(uint8_t cols, uint8_t rows, uint8_t attribute)
+{
+ static com32sys_t ireg;
+
+ ireg.eax.w[0] = 0x0601;
+ ireg.ebx.b[1] = attribute;
+ ireg.ecx.w[0] = 0;
+ ireg.edx.b[1] = rows;
+ ireg.edx.b[0] = cols;
+ __intcall(0x10, &ireg, NULL); /* Scroll */
+}
+
+static void bios_beep(void)
+{
+ static com32sys_t ireg;
+
+ ireg.eax.w[0] = 0x0e07;
+ ireg.ebx.b[1] = BIOS_PAGE;
+ __intcall(0x10, &ireg, NULL);
+}
struct output_ops bios_output_ops = {
.erase = bios_erase,
@@ -30,10 +128,12 @@ struct output_ops bios_output_ops = {
.get_cursor = bios_get_cursor,
};
-extern char bios_getchar(void);
+extern char bios_getchar(char *);
+extern int bios_pollchar(void);
struct input_ops bios_input_ops = {
.getchar = bios_getchar,
+ .pollchar = bios_pollchar,
};
static const char *syslinux_ipappend_string_list[32];
@@ -60,8 +160,17 @@ bool bios_ipappend_strings(char **list, int *count)
return true;
}
-extern char *bios_get_config_file_name(void);
-extern void bios_get_serial_console_info(uint16_t *, uint16_t *, uint16_t *);
+static void bios_get_serial_console_info(uint16_t *iobase, uint16_t *divisor,
+ uint16_t *flowctl)
+{
+ *iobase = SerialPort;
+ *divisor = BaudDivisor;
+
+ *flowctl = FlowOutput | FlowInput | (FlowIgnore << 4);
+
+ if (!DisplayCon)
+ *flowctl |= (0x80 << 8);
+}
void *__syslinux_adv_ptr;
size_t __syslinux_adv_size;
@@ -93,7 +202,87 @@ struct adv_ops bios_adv_ops = {
.write = bios_adv_write,
};
-extern int bios_boot_linux(void *, size_t, struct initramfs *, char *);
+static uint32_t min_lowmem_heap = 65536;
+extern char __lowmem_heap[];
+uint8_t KbdFlags; /* Check for keyboard escapes */
+
+static inline void check_escapes(void)
+{
+ com32sys_t ireg, oreg;
+
+ ireg.eax.b[1] = 0x02; /* Check keyboard flags */
+ __intcall(0x16, &ireg, &oreg);
+
+ KbdFlags = oreg.eax.b[0];
+
+ /* Ctrl->skip 386 check */
+ if (oreg.eax.b[0] & 0x04) {
+ /*
+ * Now check that there is sufficient low (DOS) memory
+ *
+ * NOTE: Linux doesn't use all of real_mode_seg, but we use
+ * the same segment for COMBOOT images, which can use all 64K.
+ */
+ uint16_t mem;
+
+ __intcall(0x12, &ireg, &oreg);
+
+ mem = ((uint32_t)__lowmem_heap) + min_lowmem_heap + 1023;
+ mem = mem >> 10;
+
+ if (mem < oreg.eax.w[0]) {
+ char buf[256];
+
+ snprintf(buf, sizeof(buf),
+ "It appears your computer has only "
+ "%dK of low (\"DOS\") RAM.\n"
+ "This version of Syslinux needs "
+ "%dK to boot. "
+ "If you get this\nmessage in error, "
+ "hold down the Ctrl key while booting, "
+ "and I\nwill take your word for it.\n",
+ oreg.eax.w[0], mem);
+ writestr(buf);
+ kaboom();
+ }
+ }
+}
+
+extern uint32_t BIOS_timer_next;
+extern uint32_t timer_irq;
+static inline void bios_timer_init(void)
+{
+ unsigned long next;
+ uint32_t *hook = (uint32_t *)BIOS_timer_hook;
+
+ next = *hook;
+ BIOS_timer_next = next;
+ *hook = (uint32_t)&timer_irq;
+}
+
+extern uint8_t bios_free_mem;
+extern void printf_init(void);
+
+void bios_init(void)
+{
+ int i;
+
+ /* Initialize timer */
+ bios_timer_init();
+
+ for (i = 0; i < 256; i++)
+ KbdMap[i] = i;
+
+ bios_adjust_screen();
+ printf_init();
+
+ /* Init the memory subsystem */
+ bios_free_mem = (uint16_t *)0x413;
+ mem_init();
+
+ /* CPU-dependent initialization and related checks. */
+ check_escapes();
+}
struct firmware bios_fw = {
.init = bios_init,
@@ -104,10 +293,8 @@ struct firmware bios_fw = {
.o_ops = &bios_output_ops,
.i_ops = &bios_input_ops,
.ipappend_strings = bios_ipappend_strings,
- .get_config_file_name = bios_get_config_file_name,
.get_serial_console_info = bios_get_serial_console_info,
.adv_ops = &bios_adv_ops,
- .boot_linux = bios_boot_linux,
};
void syslinux_register_bios(void)
diff --git a/core/comboot.inc b/core/comboot.inc
index e0ad0681..175c50c9 100644
--- a/core/comboot.inc
+++ b/core/comboot.inc
@@ -429,7 +429,7 @@ comapi_run_default:
; Puts the video in standard text mode
;
comapi_textmode:
- pm_call vgaclearmode
+ pm_call syslinux_force_text_mode
clc
ret
@@ -591,11 +591,11 @@ comapi_ipappend:
; INT 22h AX=0010h Resolve hostname
;
%if IS_PXELINUX
- extern pxe_dns_resolv
+ extern pm_pxe_dns_resolv
comapi_dnsresolv:
mov ds,P_ES
mov si,P_BX
- pm_call pxe_dns_resolv
+ pm_call pm_pxe_dns_resolv
mov P_EAX,eax
clc
ret
@@ -654,7 +654,7 @@ comapi_usingvga:
ja .error
mov cx,P_CX
mov dx,P_DX
- pm_call pm_usingvga
+ pm_call pm_using_vga
clc
ret
.error:
@@ -669,10 +669,12 @@ comapi_userfont:
and al,al
jz .done
mov al,[VGAFontSize]
- mov P_ES,aux_seg
- mov P_BX,aux.fontbuf
+ pm_call pm_userfont
+ mov P_ES,es
+ mov P_BX,bx
.done: ; CF=0 here
+ mov P_AL,al
ret
;
@@ -840,6 +842,7 @@ zero_string db 0 ; Empty, null-terminated string
; Note: PXELINUX clears the idle is noop flag if appropriate
; in pxe_detect_nic_type
;
+ global feature_flags, feature_flags_len
feature_flags:
db 1 ; Have local boot, idle is not noop
feature_flags_len equ ($-feature_flags)
diff --git a/core/conio.c b/core/conio.c
index e18f0c77..d34c9cf2 100644
--- a/core/conio.c
+++ b/core/conio.c
@@ -24,13 +24,14 @@
#include <stddef.h>
#include <stdio.h>
#include <string.h>
-
#include <fs.h>
-#include "bios.h"
#include <com32.h>
#include <sys/cpu.h>
#include <syslinux/firmware.h>
+#include "bios.h"
+#include "graphics.h"
+
union screen _cursor;
union screen _screensize;
@@ -209,7 +210,7 @@ static void write_serial_str_displaymask(char *data)
*
* Returns 1 if character pending.
*/
-int pollchar(void)
+int bios_pollchar(void)
{
com32sys_t ireg, oreg;
uint8_t data = 0;
@@ -249,7 +250,12 @@ int pollchar(void)
return data;
}
-int pm_pollchar(com32sys_t *regs)
+int pollchar(void)
+{
+ return firmware->i_ops->pollchar();
+}
+
+void pm_pollchar(com32sys_t *regs)
{
if (pollchar())
regs->eflags.l &= ~EFLAGS_ZF;
@@ -259,7 +265,7 @@ int pm_pollchar(com32sys_t *regs)
extern void do_idle(void);
-char bios_getchar(void)
+char bios_getchar(char *hi)
{
com32sys_t ireg, oreg;
unsigned char data;
@@ -282,7 +288,7 @@ char bios_getchar(void)
sti(); /* We already know we'll consume data */
data = *SerialTail++;
- SerialTail = (unsigned char *)((unsigned long)SerialTail & (serial_buf_size - 1));
+ SerialTail = (char *)((unsigned long)SerialTail & (serial_buf_size - 1));
} else {
/* LSR */
data = inb(SerialPort + 5) & 1;
@@ -307,6 +313,8 @@ char bios_getchar(void)
__intcall(0x16, &ireg, &oreg);
data = oreg.eax.b[0];
+ *hi = oreg.eax.b[1];
+
if (data == 0xE0)
data = 0;
@@ -326,14 +334,14 @@ char bios_getchar(void)
/*
* getchar: Read a character from keyboard or serial port
*/
-char getchar(void)
+char getchar(char *hi)
{
- return firmware->i_ops->getchar();
+ return firmware->i_ops->getchar(hi);
}
void pm_getchar(com32sys_t *regs)
{
- regs->eax.b[0] = getchar();
+ regs->eax.b[0] = getchar((char *)&regs->eax.b[1]);
}
static void msg_setbg(char data)
@@ -410,7 +418,7 @@ static void msg_formfeed(void)
static void msg_novga(void)
{
- vgaclearmode();
+ syslinux_force_text_mode();
msg_initvars();
}
diff --git a/core/console.c b/core/console.c
index 282c57f5..3b545bbd 100644
--- a/core/console.c
+++ b/core/console.c
@@ -1,18 +1,15 @@
#include <stddef.h>
#include <com32.h>
+#include <core.h>
#include <stdio.h>
#include <string.h>
void myputchar(int c)
{
- static com32sys_t ireg;
-
if (c == '\n')
myputchar('\r');
- ireg.eax.b[1] = 0x02;
- ireg.edx.b[0] = c;
- __intcall(0x21, &ireg, NULL);
+ writechr(c);
}
void myputs(const char *str)
diff --git a/core/diskboot.inc b/core/diskboot.inc
index 141986e8..3e42044a 100644
--- a/core/diskboot.inc
+++ b/core/diskboot.inc
@@ -28,6 +28,7 @@
; reduce the code size...
;
+ global StackBuf
StackBuf equ STACK_TOP-44-92 ; Start the stack here (grow down - 4K)
PartInfo equ StackBuf
.mbr equ PartInfo
diff --git a/core/diskfs.inc b/core/diskfs.inc
index fff0d32b..dcbc924a 100644
--- a/core/diskfs.inc
+++ b/core/diskfs.inc
@@ -70,7 +70,6 @@ trackbuf resb trackbufsize ; Track buffer goes here
;
%include "diskstart.inc"
-
;
; Now, everything is "up and running"... patch kaboom for more
; verbosity and using the full screen system
@@ -87,11 +86,61 @@ trackbuf resb trackbufsize ; Track buffer goes here
; If we get to this point ldlinux.c32 failed to run. There's nothing
; left to do but inform that user that something went wrong.
;
+enter_command:
+auto_boot:
jmp kaboom
-%include "ui.inc"
+ section .bss16
+ global CmdOptPtr, KbdMap
+ alignb 4
+ThisKbdTo resd 1 ; Temporary holder for KbdTimeout
+ThisTotalTo resd 1 ; Temporary holder for TotalTimeout
+KernelExtPtr resw 1 ; During search, final null pointer
+CmdOptPtr resw 1 ; Pointer to first option on cmd line
+KbdFlags resb 1 ; Check for keyboard escapes
+FuncFlag resb 1 ; Escape sequences received from keyboard
+KernelType resb 1 ; Kernel type, from vkernel, if known
+KbdMap resb 256 ; Keyboard map
+ global KernelName
+KernelName resb FILENAME_MAX ; Mangled name for kernel
+ section .config
+ global PXERetry
+PXERetry dw 0 ; Extra PXE retries
+ section .data16
+ global SerialNotice
+SerialNotice db 1 ; Only print this once
+ global IPAppends, numIPAppends
+%if IS_PXELINUX
+ extern IPOption
+ alignz 2
+IPAppends dw IPOption
+numIPAppends equ ($-IPAppends)/2
+%else
+IPAppends equ 0
+numIPAppends equ 0
+%endif
+
+ section .text16
+;
+; COMBOOT-loading code
+;
+%include "comboot.inc"
+%include "com32.inc"
+
+;
+; Boot sector loading code
+;
+
+;
+; Abort loading code
+;
;
+; Hardware cleanup common code
+;
+
+%include "localboot.inc"
+
;
; kaboom2: once everything is loaded, replace the part of kaboom
; starting with "kaboom.patch" with this part
@@ -102,11 +151,11 @@ kaboom2:
cmp byte [kaboom.again+1],18h ; INT 18h version?
je .int18
pm_call pm_getchar
- pm_call vgaclearmode
+ pm_call syslinux_force_text_mode
int 19h ; And try once more to boot...
.norge: jmp short .norge ; If int 19h returned; this is the end
.int18:
- pm_call vgaclearmode
+ pm_call syslinux_force_text_mode
int 18h
.noreg: jmp short .noreg ; Nynorsk
diff --git a/core/elflink/load_env32.c b/core/elflink/load_env32.c
index d1c21b95..e671891b 100644
--- a/core/elflink/load_env32.c
+++ b/core/elflink/load_env32.c
@@ -24,24 +24,6 @@
#define LDLINUX "ldlinux.c32"
-#if __SIZEOF_POINTER__ == 4
-typedef Elf32_Dyn Elf_Dyn;
-typedef Elf32_Word Elf_Word;
-typedef Elf32_Addr Elf_Addr;
-#define ELF_SYMENT_SIZE sizeof(Elf32_Sym)
-#define ELF_MOD_SYS "32 bit"
-#elif __SIZEOF_POINTER__ == 8
-typedef Elf64_Dyn Elf_Dyn;
-typedef Elf64_Word Elf_Word;
-typedef Elf64_Addr Elf_Addr;
-#define ELF_SYMENT_SIZE sizeof(Elf64_Sym)
-#define ELF_MOD_SYS "64 bit"
-#else
-#error "unsupported architecture"
-#endif
-typedef void (*constructor_t) (void);
-constructor_t __ctors_start[], __ctors_end[];
-
extern char __dynstr_start[];
extern char __dynstr_end[], __dynsym_end[];
extern char __dynsym_start[];
@@ -62,7 +44,7 @@ struct elf_module core_module = {
.sym_table = __dynsym_start,
.got = __got_start,
.dyn_table = __dynamic_start,
- .syment_size = ELF_SYMENT_SIZE,
+ .syment_size = sizeof(Elf_Sym),
};
/*
@@ -75,21 +57,57 @@ void init_module_subsystem(struct elf_module *module)
list_add(&module->list, &modules_head);
}
-/* call_constr: initializes sme things related */
-static void call_constr(void)
+int start_ldlinux(char **argv)
{
- constructor_t *p;
+ int rv;
+
+again:
+ rv = spawn_load(LDLINUX, 1, argv);
+ if (rv == EEXIST) {
+ struct elf_module *m, *mod, *begin = NULL;
+
+ /*
+ * If a COM32 module calls execute() we may need to
+ * unload all the modules loaded since ldlinux.c32,
+ * and restart initialisation. This is especially
+ * important for config files.
+ */
+ for_each_module(mod) {
+ if (!strcmp(mod->name, LDLINUX)) {
+ begin = mod;
+ break;
+ }
+ }
+
+ for_each_module_safe(mod, m) {
+ if (mod == begin)
+ break;
+
+ if (mod != begin)
+ module_unload(mod);
+ }
- for (p = __ctors_start; p < __ctors_end; p++)
- (*p) ();
+ /*
+ * Finally unload LDLINUX.
+ *
+ * We'll reload it when we jump to 'again' which will
+ * cause all the initialsation steps to be executed
+ * again.
+ */
+ module_unload(begin);
+ goto again;
+ }
+
+ return rv;
}
/* note to self: do _*NOT*_ use static key word on this function */
-void load_env32(com32sys_t * regs)
+void load_env32(com32sys_t * regs __unused)
{
struct file_info *fp;
int fd;
char *argv[] = { LDLINUX, NULL };
+ char realname[FILENAME_MAX];
size_t size;
static const char *search_directories[] = {
@@ -107,7 +125,15 @@ void load_env32(com32sys_t * regs)
};
dprintf("Starting %s elf module subsystem...\n", ELF_MOD_SYS);
- call_constr();
+
+ PATH = malloc(strlen(PATH_DEFAULT) + 1);
+ if (!PATH) {
+ printf("Couldn't allocate memory for PATH\n");
+ return;
+ }
+
+ strcpy(PATH, PATH_DEFAULT);
+ PATH[strlen(PATH_DEFAULT)] = '\0';
size = (size_t)__dynstr_end - (size_t)__dynstr_start;
core_module.strtable_size = size;
@@ -117,12 +143,12 @@ void load_env32(com32sys_t * regs)
init_module_subsystem(&core_module);
- spawn_load(LDLINUX, 1, argv);
+ start_ldlinux(argv);
/*
* If we failed to load LDLINUX it could be because our
* current working directory isn't the install directory. Try
- * a bit harder to find LDLINUX. If search_config() succeeds
+ * a bit harder to find LDLINUX. If search_dirs() succeeds
* in finding LDLINUX it will set the cwd.
*/
fd = opendev(&__file_dev, NULL, O_RDONLY);
@@ -131,8 +157,8 @@ void load_env32(com32sys_t * regs)
fp = &__file_info[fd];
- if (!search_config(&fp->i.fd, search_directories, filenames))
- spawn_load(LDLINUX, 1, argv);
+ if (!search_dirs(&fp->i.fd, search_directories, filenames, realname))
+ start_ldlinux(argv);
}
int create_args_and_load(char *cmdline)
diff --git a/core/extern.inc b/core/extern.inc
index 72afe7ae..078985ee 100644
--- a/core/extern.inc
+++ b/core/extern.inc
@@ -64,13 +64,13 @@
extern pm_writehex2, pm_writehex4, pm_writehex8
; graphics.c
- extern vgaclearmode, vgashowcursor, vgahidecursor
+ extern syslinux_force_text_mode, vgashowcursor, vgahidecursor, pm_using_vga
; conio.c
extern pm_pollchar, pm_write_serial, pm_serialcfg
; font.c
- extern pm_getchar, pm_adjust_screen, pm_usingvga, pm_userfont
+ extern pm_getchar, pm_adjust_screen, pm_userfont
; localboot.c
extern pm_local_boot
diff --git a/core/font.c b/core/font.c
index ff98635c..a0f73332 100644
--- a/core/font.c
+++ b/core/font.c
@@ -21,18 +21,12 @@
#include <sys/io.h>
#include <stdio.h>
#include <fs.h>
+
#include "bios.h"
+#include "graphics.h"
#include "core.h"
-struct aux {
- char fontbuf[8192];
- char serial[serial_buf_size];
-};
-
-#define fontbuf offsetof(struct aux, fontbuf)
-
-extern uint16_t VGAFontSize;
-extern uint8_t UserFont;
+__lowmem char fontbuf[8192];
uint16_t GXPixCols = 1; /* Graphics mode pixel columns */
uint16_t GXPixRows = 1; /* Graphics mode pixel rows */
@@ -40,13 +34,14 @@ uint16_t GXPixRows = 1; /* Graphics mode pixel rows */
/*
* loadfont: Load a .psf font file and install it onto the VGA console
* (if we're not on a VGA screen then ignore.)
- *
- * The .psf font file must alredy be open and getc_file must be set.
*/
-void loadfont(char *filename)
+void loadfont(const char *filename)
{
- uint16_t height, magic;
- uint32_t *di, *si;
+ struct psfheader {
+ uint16_t magic;
+ uint8_t mode;
+ uint8_t height;
+ } hdr;
FILE *f;
char *p;
int i;
@@ -55,49 +50,39 @@ void loadfont(char *filename)
if (!f)
return;
- p = trackbuf;
/* Read header */
- for (i = 0; i < 4; i++) {
- char ch = getc(f);
- if (ch == EOF)
- return;
- *p++ = ch;
- }
+ if (_fread(&hdr, sizeof hdr, f) != sizeof hdr)
+ goto fail;
/* Magic number */
- magic = *(uint16_t *)trackbuf;
- if (magic != 0x0436)
- return;
+ if (hdr.magic != 0x0436)
+ goto fail;
/* File mode: font modes 0-5 supported */
- if (*(trackbuf) > 5)
- return;
-
- height = *(trackbuf + 3); /* Height of font */
+ if (hdr.mode > 5)
+ goto fail;
/* VGA minimum/maximum */
- if (height < 2 || height > 32)
- return;
+ if (hdr.height < 2 || hdr.height > 32)
+ goto fail;
- /* Load the actual font. Bytes = font height * 256 */
- p = trackbuf;
- for (i = 0; i < (height << 8); i++) {
- char ch = getc(f);
+ /* Load the actual font into the font buffer. */
+ memset(fontbuf, 0, 256*32);
- if (ch == EOF)
- return;
- *p++ = ch;
+ p = fontbuf;
+ for (i = 0; i < 256; i++) {
+ if (_fread(p, hdr.height, f) != hdr.height)
+ goto fail;
+ p += 32;
}
- /* Copy to font buffer */
- VGAFontSize = height;
- di = (uint32_t *)MK_PTR(aux_seg, fontbuf);
- si = (uint32_t *)trackbuf;
- for (i = 0; i < (height << 6); i++)
- *di++ = *si++;
-
+ /* Loaded OK */
+ VGAFontSize = hdr.height;
UserFont = 1; /* Set font flag */
use_font();
+
+fail:
+ fclose(f);
}
/*
@@ -111,15 +96,14 @@ void use_font(void)
com32sys_t ireg, oreg;
uint8_t bytes = VGAFontSize;
-
/* Nonstandard mode? */
if (UsingVGA & ~0x3)
- vgaclearmode();
+ syslinux_force_text_mode();
memset(&ireg, 0, sizeof(ireg));
- ireg.es = aux_seg;
- ireg.ebp.w[0] = fontbuf; /* ES:BP -> font */
+ ireg.es = SEG(fontbuf);
+ ireg.ebp.w[0] = OFFS(fontbuf); /* ES:BP -> font */
/* Are we using a user-specified font? */
if (UserFont & 0x1) {
@@ -169,7 +153,7 @@ void use_font(void)
void bios_adjust_screen(void)
{
com32sys_t ireg, oreg;
- volatile uint8_t *vidrows = BIOS_vidrows;
+ volatile uint8_t *vidrows = (volatile uint8_t *)BIOS_vidrows;
uint8_t rows, cols;
rows = *vidrows;
@@ -190,7 +174,13 @@ void bios_adjust_screen(void)
VidCols = --cols; /* Store count-1 (same as rows) */
}
-void pm_adjust_screen(com32sys_t *regs)
+void pm_adjust_screen(com32sys_t *regs __unused)
{
bios_adjust_screen();
}
+
+void pm_userfont(com32sys_t *regs)
+{
+ regs->es = SEG(fontbuf);
+ regs->ebx.w[0] = OFFS(fontbuf);
+}
diff --git a/core/fs/btrfs/btrfs.c b/core/fs/btrfs/btrfs.c
index 8dedf8ac..16386cc0 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/fat/fat.c b/core/fs/fat/fat.c
index fbc4386b..b2c20ee0 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++;
@@ -779,6 +782,34 @@ static int vfat_fs_init(struct fs_info *fs)
return fs->block_shift;
}
+static int vfat_copy_superblock(void *buf)
+{
+ struct fat_bpb fat;
+ struct disk *disk;
+ size_t sb_off;
+ void *dst;
+ int sb_len;
+
+ disk = this_fs->fs_dev->disk;
+ disk->rdwr_sectors(disk, &fat, 0, 1, 0);
+
+ /* XXX: Find better sanity checks... */
+ if (!fat.bxResSectors || !fat.bxFATs)
+ return -1;
+
+ sb_off = offsetof(struct fat_bpb, sector_size);
+ sb_len = offsetof(struct fat_bpb, fat12_16) - sb_off \
+ + sizeof(fat.fat12_16);
+
+ /*
+ * Only copy fields of the superblock we actually care about.
+ */
+ dst = buf + sb_off;
+ memcpy(dst, (void *)&fat + sb_off, sb_len);
+
+ return 0;
+}
+
const struct fs_ops vfat_fs_ops = {
.fs_name = "vfat",
.fs_flags = FS_USEMEM | FS_THISIND,
@@ -793,4 +824,5 @@ const struct fs_ops vfat_fs_ops = {
.iget_root = vfat_iget_root,
.iget = vfat_iget,
.next_extent = fat_next_extent,
+ .copy_super = vfat_copy_superblock,
};
diff --git a/core/fs/fs.c b/core/fs/fs.c
index e6f35370..d8abaa69 100644
--- a/core/fs/fs.c
+++ b/core/fs/fs.c
@@ -2,13 +2,14 @@
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
+#include <unistd.h>
#include <dprintf.h>
#include "core.h"
#include "dev.h"
#include "fs.h"
#include "cache.h"
-char *PATH = ".:/bin/";
+char *PATH;
/* The currently mounted filesystem */
struct fs_info *this_fs = NULL; /* Root filesystem */
@@ -42,6 +43,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);
}
}
@@ -223,6 +226,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;
@@ -321,6 +327,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;
@@ -365,6 +374,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);
@@ -392,6 +403,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) {
@@ -479,6 +492,7 @@ void fs_init(const struct fs_ops **ops, struct disk_private *priv)
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);
}
if (fs.fs_ops->chdir_start) {
diff --git a/core/fs/iso9660/iso9660.c b/core/fs/iso9660/iso9660.c
index 792cd99f..fe58a5b3 100644
--- a/core/fs/iso9660/iso9660.c
+++ b/core/fs/iso9660/iso9660.c
@@ -243,7 +243,7 @@ static int iso_open_config(struct com32_filedata *filedata)
NULL
};
- return search_config(filedata, search_directories, filenames);
+ return search_dirs(filedata, search_directories, filenames, ConfigName);
}
static int iso_fs_init(struct fs_info *fs)
diff --git a/core/fs/lib/chdir.c b/core/fs/lib/chdir.c
index 5c7b130f..715284bb 100644
--- a/core/fs/lib/chdir.c
+++ b/core/fs/lib/chdir.c
@@ -1,3 +1,4 @@
+#include <unistd.h>
#include <core.h>
int generic_chdir_start(void)
diff --git a/core/fs/lib/loadconfig.c b/core/fs/lib/loadconfig.c
index 100500c5..95e6f3f8 100644
--- a/core/fs/lib/loadconfig.c
+++ b/core/fs/lib/loadconfig.c
@@ -30,5 +30,5 @@ int generic_open_config(struct com32_filedata *filedata)
dprintf("CurrentDirName: \"%s\"\n", CurrentDirName);
- return search_config(filedata, search_directories, filenames);
+ return search_dirs(filedata, search_directories, filenames, ConfigName);
}
diff --git a/core/fs/lib/searchconfig.c b/core/fs/lib/searchconfig.c
index 7fdad183..f2d740b3 100644
--- a/core/fs/lib/searchconfig.c
+++ b/core/fs/lib/searchconfig.c
@@ -5,30 +5,32 @@
#include <fs.h>
char ConfigName[FILENAME_MAX];
+char config_cwd[FILENAME_MAX];
/*
- * Common implementation of load_config
- *
* This searches for a specified set of filenames in a specified set
* of directories. If found, set the current working directory to
* match.
*/
-int search_config(struct com32_filedata *filedata,
- const char *search_directories[], const char *filenames[])
+int search_dirs(struct com32_filedata *filedata,
+ const char *search_directories[],
+ const char *filenames[],
+ char *realname)
{
- char confignamebuf[FILENAME_MAX];
+ char namebuf[FILENAME_MAX];
const char *sd, **sdp;
const char *sf, **sfp;
for (sdp = search_directories; (sd = *sdp); sdp++) {
for (sfp = filenames; (sf = *sfp); sfp++) {
- snprintf(confignamebuf, sizeof confignamebuf,
+ snprintf(namebuf, sizeof namebuf,
"%s%s%s",
sd, (*sd && sd[strlen(sd)-1] == '/') ? "" : "/",
sf);
- realpath(ConfigName, confignamebuf, FILENAME_MAX);
- dprintf("Config search: %s\n", ConfigName);
- if (open_file(ConfigName, filedata) >= 0) {
+ if (realpath(realname, namebuf, FILENAME_MAX) == (size_t)-1)
+ continue;
+ dprintf("Config search: %s\n", realname);
+ if (open_file(realname, filedata) >= 0) {
chdir(sd);
return 0; /* Got it */
}
diff --git a/core/fs/ntfs/ntfs.c b/core/fs/ntfs/ntfs.c
new file mode 100644
index 00000000..f54df7e5
--- /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,
+ .open_config = generic_open_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/fs/pxe/dhcp_option.c b/core/fs/pxe/dhcp_option.c
index 50f2de04..f63d4a91 100644
--- a/core/fs/pxe/dhcp_option.c
+++ b/core/fs/pxe/dhcp_option.c
@@ -227,12 +227,10 @@ static void parse_dhcp_options(const void *option, int size, uint8_t opt_filter)
* LocalDomain - Local domain name
* MAC_len, MAC - Client identifier, if MAC_len == 0
*
- * This assumes the DHCP packet is in "trackbuf".
- *
*/
-void parse_dhcp(int pkt_len)
+void parse_dhcp(const void *pkt, size_t pkt_len)
{
- struct bootp_t *dhcp = (struct bootp_t *)trackbuf;
+ const struct bootp_t *dhcp = (const struct bootp_t *)pkt;
int opt_len;
IPInfo.ipv4 = 4; /* This is IPv4 only for now... */
diff --git a/core/fs/pxe/dnsresolv.c b/core/fs/pxe/dnsresolv.c
index 641ea389..fda0f815 100644
--- a/core/fs/pxe/dnsresolv.c
+++ b/core/fs/pxe/dnsresolv.c
@@ -337,11 +337,7 @@ done:
return result;
}
-
-/*
- * the one should be called from ASM file
- */
-void pxe_dns_resolv(com32sys_t *regs)
+void pm_pxe_dns_resolv(com32sys_t *regs)
{
const char *name = MK_PTR(regs->ds, regs->esi.w[0]);
diff --git a/core/fs/pxe/pxe.c b/core/fs/pxe/pxe.c
index 7b63d17b..6f490ce8 100644
--- a/core/fs/pxe/pxe.c
+++ b/core/fs/pxe/pxe.c
@@ -340,13 +340,13 @@ static void ack_packet(struct inode *inode, uint16_t ack_num)
/**
- * Get a DHCP packet from the PXE stack into the trackbuf
+ * Get a DHCP packet from the PXE stack into a lowmem buffer
*
* @param: type, packet type
* @return: buffer size
*
*/
-static int pxe_get_cached_info(int type)
+static int pxe_get_cached_info(int type, void *buf, size_t bufsiz)
{
int err;
static __lowmem struct s_PXENV_GET_CACHED_INFO get_cached_info;
@@ -354,8 +354,8 @@ static int pxe_get_cached_info(int type)
get_cached_info.Status = 0;
get_cached_info.PacketType = type;
- get_cached_info.BufferSize = 8192;
- get_cached_info.Buffer = FAR_PTR(trackbuf);
+ get_cached_info.BufferSize = bufsiz;
+ get_cached_info.Buffer = FAR_PTR(buf);
err = pxe_call(PXENV_GET_CACHED_INFO, &get_cached_info);
if (err) {
printf("PXE API call failed, error %04x\n", err);
@@ -1151,7 +1151,7 @@ static void make_sysuuid_string(void)
/*
* Generate an ip=<client-ip>:<boot-server-ip>:<gw-ip>:<netmask>
- * option into IPOption based on a DHCP packet in trackbuf.
+ * option into IPOption based on DHCP information in IPInfo.
*
*/
char __bss16 IPOption[3+4*16];
@@ -1187,9 +1187,6 @@ static void ip_init(void)
/*
* Print the IPAPPEND strings, in order
*/
-extern const uint16_t IPAppends[];
-extern const char numIPAppends[];
-
static void print_ipappend(void)
{
size_t i;
@@ -1448,8 +1445,15 @@ static void udp_init(void)
*/
static void network_init(void)
{
- struct bootp_t *bp = (struct bootp_t *)trackbuf;
int pkt_len;
+ struct bootp_t *bp;
+ const size_t dhcp_max_packet = 4096;
+
+ bp = lmalloc(dhcp_max_packet);
+ if (!bp) {
+ printf("Out of low memory\n");
+ kaboom();
+ }
*LocalDomain = 0; /* No LocalDomain received */
@@ -1457,8 +1461,8 @@ static void network_init(void)
* Get the DHCP client identifiers (query info 1)
*/
printf("Getting cached packet ");
- pkt_len = pxe_get_cached_info(1);
- parse_dhcp(pkt_len);
+ pkt_len = pxe_get_cached_info(1, bp, dhcp_max_packet);
+ parse_dhcp(bp, pkt_len);
/*
* We don't use flags from the request packet, so
* this is a good time to initialize DHCPMagic...
@@ -1474,8 +1478,8 @@ static void network_init(void)
* Get the BOOTP/DHCP packet that brought us file (and an IP
* address). This lives in the DHCPACK packet (query info 2)
*/
- pkt_len = pxe_get_cached_info(2);
- parse_dhcp(pkt_len);
+ pkt_len = pxe_get_cached_info(2, bp, dhcp_max_packet);
+ parse_dhcp(bp, pkt_len);
/*
* Save away MAC address (assume this is in query info 2. If this
* turns out to be problematic it might be better getting it from
@@ -1489,10 +1493,12 @@ static void network_init(void)
* Get the boot file and other info. This lives in the CACHED_REPLY
* packet (query info 3)
*/
- pkt_len = pxe_get_cached_info(3);
- parse_dhcp(pkt_len);
+ pkt_len = pxe_get_cached_info(3, bp, dhcp_max_packet);
+ parse_dhcp(bp, pkt_len);
printf("\n");
+ lfree(bp);
+
make_bootif_string();
make_sysuuid_string();
ip_init();
@@ -1647,7 +1653,7 @@ int reset_pxe(void)
* This function unloads the PXE and UNDI stacks and
* unclaims the memory.
*/
-void unload_pxe(void)
+void unload_pxe(uint16_t flags)
{
/* PXE unload sequences */
static const uint8_t new_api_unload[] = {
@@ -1676,7 +1682,7 @@ void unload_pxe(void)
dprintf("FBM after reset_pxe = %d, err = %d\n", BIOS_fbm, err);
/* If we want to keep PXE around, we still need to reset it */
- if (KeepPXE || err)
+ if (flags || err)
return;
dprintf("APIVer = %04x\n", APIVer);
diff --git a/core/fs/pxe/pxe.h b/core/fs/pxe/pxe.h
index 1e6fa76a..c754106d 100644
--- a/core/fs/pxe/pxe.h
+++ b/core/fs/pxe/pxe.h
@@ -232,14 +232,12 @@ static inline uint32_t gateway(uint32_t ip)
/* pxe.c */
bool ip_ok(uint32_t);
-int pxe_call(int, void *);
/* dhcp_options.c */
-void parse_dhcp(int);
+void parse_dhcp(const void *, size_t);
/* dnsresolv.c */
int dns_mangle(char **, const char *);
-uint32_t dns_resolv(const char *);
/* idle.c */
void pxe_idle_init(void);
diff --git a/core/graphics.c b/core/graphics.c
index ff3a1899..e9fea617 100644
--- a/core/graphics.c
+++ b/core/graphics.c
@@ -19,8 +19,11 @@
#include <stddef.h>
#include "core.h"
#include <sys/io.h>
+#include <hw/vga.h>
#include "fs.h"
+
#include "bios.h"
+#include "graphics.h"
uint8_t UsingVGA = 0;
uint16_t VGAPos; /* Pointer into VGA memory */
@@ -92,14 +95,15 @@ static int vgasetmode(void)
ireg.eax.w[0] = 0x0012; /* Set mode = 640x480 VGA 16 colors */
__intcall(0x10, &ireg, &oreg);
- ireg.edx.w[0] = (uint16_t)linear_color;
+ ireg.edx.w[0] = (uint32_t)linear_color;
ireg.eax.w[0] = 0x1002; /* Write color registers */
__intcall(0x10, &ireg, &oreg);
UsingVGA = 1;
/* Set GXPixCols and GXPixRows */
- GXPixCols = 640+(480 << 16);
+ GXPixCols = 640;
+ GXPixRows = 480;
use_font();
ScrollAttribute = 0;
@@ -176,29 +180,26 @@ again:
* packedpixel2vga:
* Convert packed-pixel to VGA bitplanes
*
- * 'in': packed pixel string
- * 'out': output (four planes)
+ * 'in': packed pixel string (640 pixels)
+ * 'out': output (four planes @ 640/8 = 80 bytes)
* 'count': pixel count (multiple of 8)
*/
-static void packedpixel2vga(uint8_t *in, uint8_t *out, size_t count)
+static void packedpixel2vga(const uint8_t *in, uint8_t *out)
{
- uint8_t bx, al, dl;
- int plane, pixel;
-
- for (plane = 0; plane < 4; plane++) {
- for (bx = 0; bx < count; bx += 8) {
- for (pixel = 0; pixel < 8; pixel++) {
- al = *in++;
- al >>= plane;
-
- /*
- * VGA is bigendian. Sigh.
- * Left rotate through carry
- */
- dl = dl << 1 | (dl >> (8 - 1));
+ int i, j, k;
+
+ for (i = 0; i < 4; i++) {
+ const uint8_t *ip = in;
+
+ for (j = 0; j < 640/8; j++) {
+ uint8_t ob = 0;
+
+ for (k = 0; k < 8; k++) {
+ uint8_t px = *ip++;
+ ob = (ob << 1) | ((px >> i) & 1);
}
- *out++ = dl;
+ *out++ = ob;
}
}
}
@@ -210,24 +211,18 @@ static void packedpixel2vga(uint8_t *in, uint8_t *out, size_t count)
* 'in': four planes @ 640/8=80 bytes
* 'out': pointer into VGA memory
*/
-static void outputvga(uint32_t *in, uint32_t *out)
+static void outputvga(const void *in, void *out)
{
- uint8_t val, *addr;
- int i, j;
-
- addr = (uint8_t *)0x3C4; /* VGA Sequencer Register select port */
- val = 2; /* Sequencer mask */
+ int i;
/* Select the sequencer mask */
- outb(val, (uint16_t)addr);
+ outb(VGA_SEQ_IX_MAP_MASK, VGA_SEQ_ADDR);
- addr += 1; /* VGA Sequencer Register data port */
- for (i = 1; i <= 8; i *= 2) {
+ for (i = 1; i <= 8; i <<= 1) {
/* Select the bit plane to write */
- outb(i, (uint16_t)addr);
-
- for (j = 0; j < (640 / 32); j++)
- *(out + j) = *(in + j);
+ outb(i, VGA_SEQ_DATA);
+ memcpy(out, in, 640/8);
+ in = (const char *)in + 640/8;
}
}
@@ -245,7 +240,7 @@ void vgadisplayfile(FILE *_fd)
* This is a cheap and easy way to make sure the screen is
* cleared in case we were in graphics mode aready.
*/
- vgaclearmode();
+ syslinux_force_text_mode();
vgasetmode();
size = 4+2*2+16*3;
@@ -299,8 +294,8 @@ void vgadisplayfile(FILE *_fd)
/* Decode one row */
rledecode(VGARowBuffer, GraphXSize);
- packedpixel2vga(VGARowBuffer, VGAPlaneBuffer, 640);
- outputvga(VGAPlaneBuffer, MK_PTR(0x0A000, VGAPos));
+ packedpixel2vga(VGARowBuffer, VGAPlaneBuffer);
+ outputvga(VGAPlaneBuffer, MK_PTR(0xA000, VGAPos));
VGAPos += 640/8;
}
}
@@ -309,7 +304,7 @@ void vgadisplayfile(FILE *_fd)
/*
* Disable VGA graphics.
*/
-void vgaclearmode(void)
+void syslinux_force_text_mode(void)
{
com32sys_t ireg, oreg;
@@ -361,16 +356,17 @@ void vgashowcursor(void)
vgacursorcommon('_');
}
-void pm_usingvga(com32sys_t *regs)
+void using_vga(uint8_t vga, uint16_t pix_cols, uint16_t pix_rows)
{
- UsingVGA = regs->eax.b[0];
- GXPixCols = regs->ecx.w[0];
- GXPixRows = regs->edx.w[0];
-
- if (UsingVGA & 0x08)
- regs->eflags.l &= ~EFLAGS_CF;
- else {
- bios_adjust_screen();
- set_flags(regs, EFLAGS_CF);
- }
+ UsingVGA = vga;
+ GXPixCols = pix_cols;
+ GXPixRows = pix_rows;
+
+ if (!(UsingVGA & 0x08))
+ bios_adjust_screen();
+}
+
+void pm_using_vga(com32sys_t *regs)
+{
+ using_vga(regs->eax.b[0], regs->ecx.w[0], regs->edx.w[0]);
}
diff --git a/core/hello.c b/core/hello.c
index 45bdf57c..d30fc3b9 100644
--- a/core/hello.c
+++ b/core/hello.c
@@ -7,18 +7,12 @@
#include <console.h>
-static int console_init = 0;
-
void myputchar(int c)
{
- static com32sys_t ireg;
-
if (c == '\n')
myputchar('\r');
- ireg.eax.b[1] = 0x02;
- ireg.edx.b[0] = c;
- __intcall(0x21, &ireg, NULL);
+ writechr(c);
}
void myputs(const char *str)
diff --git a/core/include/bios.h b/core/include/bios.h
index 3c49cf22..49a75f5a 100644
--- a/core/include/bios.h
+++ b/core/include/bios.h
@@ -44,12 +44,6 @@ static inline void io_delay(void)
outb(0x0, IO_DELAY_PORT);
}
-/* conio.c */
-extern unsigned short SerialPort;
-extern unsigned char FlowIgnore;
-extern uint8_t ScrollAttribute;
-extern uint16_t DisplayCon;
-
/*
* Sometimes we need to access screen coordinates as separate 8-bit
* entities and sometimes we need to use them as 16-bit entities. Using
@@ -73,31 +67,13 @@ extern union screen _screensize;
#define VidCols _screensize.b.col
#define VidRows _screensize.b.row
-extern void write_serial(char data);
-
/* font.c */
-extern uint16_t VGAFontSize;
extern void use_font(void);
extern void bios_adjust_screen(void);
-/* graphics.c */
-#ifdef IS_SYSLINUX
-#define VGA_FILE_BUF_SIZE (FILENAME_MAX + 2)
-#else
-#define VGA_FILE_BUF_SIZE FILENAME_MAX
-#endif
-
-extern uint8_t UsingVGA;
-extern uint16_t VGAPos;
-extern uint16_t *VGAFilePtr;
-extern char VGAFileBuf[VGA_FILE_BUF_SIZE];
-extern char VGAFileMBuf[];
-extern void vgaclearmode(void);
-extern void vgadisplayfile(FILE *fd);
-
/* serirq.c */
-extern unsigned char *SerialHead;
-extern unsigned char *SerialTail;
+extern char *SerialHead;
+extern char *SerialTail;
extern void bios_init(void);
extern void bios_cleanup_hardware(void);
diff --git a/core/include/core.h b/core/include/core.h
index b66e0089..c665d790 100644
--- a/core/include/core.h
+++ b/core/include/core.h
@@ -14,6 +14,7 @@
#ifdef SYSLINUX_EFI
#include <efi.h>
#include <efilib.h>
+#undef DEBUG
#include <efistdarg.h>
#endif
@@ -23,15 +24,29 @@ extern char trackbuf[];
extern char CurrentDirName[];
extern char SubvolName[];
extern char ConfigName[];
+extern char config_cwd[];
extern char KernelName[];
extern char cmd_line[];
extern char ConfigFile[];
extern char syslinux_banner[];
extern char copyright_str[];
+extern char StackBuf[];
+extern unsigned int __bcopyxx_len;
-extern char aux_seg[];
extern uint8_t KbdMap[256];
+extern const uint16_t IPAppends[];
+extern const char numIPAppends[];
+
+extern uint16_t SerialPort;
+extern uint16_t BaudDivisor;
+extern uint8_t FlowOutput;
+extern uint8_t FlowInput;
+extern uint8_t FlowIgnore;
+
+extern uint8_t ScrollAttribute;
+extern uint16_t DisplayCon;
+
/* diskstart.inc isolinux.asm*/
extern void getlinsec(void);
@@ -104,4 +119,21 @@ static inline void set_flags(com32sys_t *regs, uint32_t flags)
regs->eflags.l = eflags;
}
+extern int start_ldlinux(char **argv);
+extern int create_args_and_load(char *);
+
+extern void write_serial(char data);
+extern void writestr(char *str);
+extern void writechr(char data);
+extern void crlf(void);
+extern int pollchar(void);
+extern char getchar(char *hi);
+
+extern void cleanup_hardware(void);
+extern void sirq_cleanup(void);
+extern void adjust_screen(void);
+
+extern void execute(const char *cmdline, uint32_t type);
+extern void load_kernel(const char *cmdline);
+
#endif /* CORE_H */
diff --git a/core/include/fs.h b/core/include/fs.h
index a9bf9a6d..673be38e 100644
--- a/core/include/fs.h
+++ b/core/include/fs.h
@@ -72,6 +72,8 @@ struct fs_ops {
int (*readdir)(struct file *, struct dirent *);
int (*next_extent)(struct inode *, uint32_t);
+
+ int (*copy_super)(void *buf);
};
/*
@@ -96,6 +98,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;
@@ -179,6 +182,7 @@ static inline struct file *handle_to_file(uint16_t handle)
return handle ? &files[handle-1] : NULL;
}
+#define PATH_DEFAULT "/boot/syslinux/:/boot/"
extern char *PATH;
/* fs.c */
@@ -193,6 +197,7 @@ int open_file(const char *name, struct com32_filedata *filedata);
void pm_open_file(com32sys_t *);
void close_file(uint16_t handle);
void pm_close_file(com32sys_t *);
+int open_config(void);
/* chdir.c */
void pm_realpath(com32sys_t *regs);
@@ -218,8 +223,9 @@ int generic_chdir_start(void);
void generic_mangle_name(char *, const char *);
/* loadconfig.c */
-int search_config(struct com32_filedata *filedata,
- const char *search_directores[], const char *filenames[]);
+int search_dirs(struct com32_filedata *filedata,
+ const char *search_directores[], const char *filenames[],
+ char *realname);
int generic_open_config(struct com32_filedata *filedata);
/* close.c */
diff --git a/core/elflink/config.c b/core/include/graphics.h
index 1c092fdd..814ffe7d 100644
--- a/core/elflink/config.c
+++ b/core/include/graphics.h
@@ -1,6 +1,6 @@
/* ----------------------------------------------------------------------- *
*
- * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2012 Paulo Alcantara <pcacjr@zytor.com>
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -25,23 +25,39 @@
*
* ----------------------------------------------------------------------- */
-#include <syslinux/firmware.h>
-#include <syslinux/config.h>
-#include <klibc/compiler.h>
-#include <com32.h>
+#ifndef GRAPHICS_H_
+#define GRAPHICS_H_
-const char *__syslinux_config_file;
+#include <stddef.h>
-char *bios_get_config_file_name(void)
-{
- static com32sys_t reg;
+#include "core.h"
+#include "fs.h"
- reg.eax.w[0] = 0x000e;
- __intcall(0x22, &reg, &reg);
- return MK_PTR(reg.es, reg.ebx.w[0]);
-}
+#ifdef IS_SYSLINUX
+#define VGA_FILE_BUF_SIZE (FILENAME_MAX + 2)
+#else
+#define VGA_FILE_BUF_SIZE FILENAME_MAX
+#endif
+
+extern uint8_t UsingVGA;
+extern uint16_t VGAPos;
+extern uint16_t *VGAFilePtr;
+extern char VGAFileBuf[VGA_FILE_BUF_SIZE];
+extern char VGAFileMBuf[];
+extern uint16_t VGAFontSize;
+
+extern uint8_t UserFont;
-void __constructor __syslinux_get_config_file_name(void)
+extern __lowmem char fontbuf[8192];
+
+extern void syslinux_force_text_mode(void);
+extern void vgadisplayfile(FILE *_fd);
+extern void using_vga(uint8_t vga, uint16_t pix_cols, uint16_t pix_rows);
+
+static inline void graphics_using_vga(uint8_t vga, uint16_t pix_cols,
+ uint16_t pix_rows)
{
- __syslinux_config_file = firmware->get_config_file_name();
+ using_vga(vga, pix_cols, pix_rows);
}
+
+#endif /* GRAPHICS_H_ */
diff --git a/com32/lib/syslinux/video/forcetext.c b/core/include/localboot.h
index 136cb279..4bb79a6a 100644
--- a/com32/lib/syslinux/video/forcetext.c
+++ b/core/include/localboot.h
@@ -1,7 +1,6 @@
/* ----------------------------------------------------------------------- *
*
- * Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
- * Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ * Copyright 2012 Paulo Alcantara <pcacjr@zytor.com>
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
@@ -26,17 +25,9 @@
*
* ----------------------------------------------------------------------- */
-/*
- * syslinux/video/forcetext.c
- */
+#ifndef LOCALBOOT_H_
+#define LOCALBOOT_H_
-#include <syslinux/video.h>
-#include <com32.h>
+extern void local_boot(int16_t ax);
-void syslinux_force_text_mode(void)
-{
- static com32sys_t ireg;
-
- ireg.eax.w[0] = 0x0005;
- __intcall(0x22, &ireg, NULL);
-}
+#endif /* LOCALBOOT_H_ */
diff --git a/core/init.c b/core/init.c
index f10ba723..45a05093 100644
--- a/core/init.c
+++ b/core/init.c
@@ -3,90 +3,9 @@
#include <sys/io.h>
#include <fs.h>
#include <bios.h>
-
#include <syslinux/memscan.h>
#include <syslinux/firmware.h>
-static uint16_t min_lowmem_heap = 65536;
-extern char __lowmem_heap[];
-uint8_t KbdFlags; /* Check for keyboard escapes */
-
-static inline void check_escapes(void)
-{
- com32sys_t ireg, oreg;
-
- ireg.eax.b[1] = 0x02; /* Check keyboard flags */
- __intcall(0x16, &ireg, &oreg);
-
- KbdFlags = oreg.eax.b[0];
-
- /* Ctrl->skip 386 check */
- if (oreg.eax.b[0] & 0x04) {
- /*
- * Now check that there is sufficient low (DOS) memory
- *
- * NOTE: Linux doesn't use all of real_mode_seg, but we use
- * the same segment for COMBOOT images, which can use all 64K.
- */
- uint16_t mem;
-
- __intcall(0x12, &ireg, &oreg);
-
- mem = ((uint16_t)__lowmem_heap) + min_lowmem_heap + 1023;
- mem = mem >> 10;
-
- if (mem < oreg.eax.w[0]) {
- char buf[256];
-
- snprintf(buf, sizeof(buf),
- "It appears you computer has less than "
- "%dK of low (DOS)\nRAM. Syslinux "
- "needs at least this amount to boot. "
- "If you get\nthis message in error, "
- "hold down the Ctrl key while\nbooting, "
- "and I will take your word for it.\n",
- mem);
- writestr(buf);
- kaboom();
- }
- }
-}
-
-extern uint32_t BIOS_timer_next;
-extern uint32_t timer_irq;
-static inline void bios_timer_init(void)
-{
- unsigned long next;
- uint32_t *hook = BIOS_timer_hook;
-
- next = *hook;
- BIOS_timer_next = next;
- *hook = &timer_irq;
-}
-
-extern uint8_t KbdMap[];
-extern uint8_t bios_free_mem;
-void bios_init(void)
-{
- int i;
-
- /* Initialize timer */
- bios_timer_init();
-
- for (i = 0; i < 256; i++)
- KbdMap[i] = i;
-
- bios_adjust_screen();
- printf_init();
-
- /* Init the memory subsystem */
- bios_free_mem = (uint16_t *)0x413;
- mem_init();
-
- /* CPU-dependent initialization and related checks. */
- check_escapes();
-}
-
void init(void)
{
firmware->init();
diff --git a/core/init.inc b/core/init.inc
index 4ee68b27..995f9825 100644
--- a/core/init.inc
+++ b/core/init.inc
@@ -23,6 +23,11 @@ common_init:
; Initialize PM invocation framework
call pm_init
+%if IS_PXELINUX
+ ; Save derivative-specific data
+ pm_call pm_save_data
+%endif
+
; Decompress PM code to its target location
pm_call pm_decompress
cmp eax,__pm_code_len
@@ -65,7 +70,7 @@ pm_decompress:
mov edi,__bss16_start
mov ecx,__bss16_dwords
rep stosd
- mov edi,__high_clear_start ; .uibss, .auxseg, .lowmem
+ mov edi,__high_clear_start ; .uibss, .lowmem
mov ecx,__high_clear_dwords
rep stosd
diff --git a/core/isolinux.asm b/core/isolinux.asm
index cb64d8ab..06291f8b 100644
--- a/core/isolinux.asm
+++ b/core/isolinux.asm
@@ -167,6 +167,7 @@ _spec_len equ _spec_end - _spec_start
;; CD-ROM sector (2K) of the file, so the number one priority is actually
;; loading the rest.
;;
+ global StackBuf
StackBuf equ STACK_TOP-44 ; 44 bytes needed for
; the bootsector chainloading
; code!
@@ -521,7 +522,7 @@ award_string db 0b8h,1,2,0bbh,0,7ch,0b9h,6,0,0bah,80h,1,09ch,09ah ;;
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
award_hack: mov si,spec_err_msg ; Moved to this place from
- call writemsg ; spec_query_faild
+ call writemsg ; spec_query_failed
;
%ifdef DEBUG_MESSAGES ;
;
@@ -1035,7 +1036,7 @@ xint13: mov byte [RetryCount],retry_count
disk_error:
kaboom:
RESET_STACK_AND_SEGS AX
- mov si,err_bootfailed
+ mov si,bailmsg
pm_call pm_writestr
pm_call pm_getchar
cli
@@ -1168,6 +1169,10 @@ init_fs:
mov di,[bsSecPerTrack]
pm_call pm_fs_init
pm_call load_env32
+enter_command:
+auto_boot:
+ jmp kaboom ; load_env32() should never return. If
+ ; it does, then kaboom!
popad
section .rodata
@@ -1195,11 +1200,56 @@ debug_tracer: pushad
ret
%endif ; DEBUG_TRACERS
+ section .bss16
+ global CmdOptPtr, KbdMap
+ alignb 4
+ThisKbdTo resd 1 ; Temporary holder for KbdTimeout
+ThisTotalTo resd 1 ; Temporary holder for TotalTimeout
+KernelExtPtr resw 1 ; During search, final null pointer
+CmdOptPtr resw 1 ; Pointer to first option on cmd line
+KbdFlags resb 1 ; Check for keyboard escapes
+FuncFlag resb 1 ; Escape sequences received from keyboard
+KernelType resb 1 ; Kernel type, from vkernel, if known
+KbdMap resb 256 ; Keyboard map
+ global KernelName
+KernelName resb FILENAME_MAX ; Mangled name for kernel
+ section .config
+ global PXERetry
+PXERetry dw 0 ; Extra PXE retries
+ section .data16
+ global SerialNotice
+SerialNotice db 1 ; Only print this once
+ global IPAppends, numIPAppends
+%if IS_PXELINUX
+ extern IPOption
+ alignz 2
+IPAppends dw IPOption
+numIPAppends equ ($-IPAppends)/2
+%else
+IPAppends equ 0
+numIPAppends equ 0
+%endif
+
+ section .text16
+;
+; COMBOOT-loading code
+;
+%include "comboot.inc"
+%include "com32.inc"
+
+;
+; Boot sector loading code
+;
+
;
-; Now we have the config file open. Parse the config file and
-; run the user interface.
+; Abort loading code
;
-%include "ui.inc"
+
+;
+; Hardware cleanup common code
+;
+
+%include "localboot.inc"
; -----------------------------------------------------------------------------
; Common modules
diff --git a/core/kaboom.c b/core/kaboom.c
index d639915a..9bb30736 100644
--- a/core/kaboom.c
+++ b/core/kaboom.c
@@ -4,6 +4,18 @@
#include "core.h"
+#ifdef DEBUG
+
+#include <dprintf.h>
+
+__noreturn __bad_SEG(const volatile void *p)
+{
+ dprintf("SEG() passed an invalid pointer: %p\n", p);
+ kaboom();
+}
+
+#endif
+
#undef kaboom
__noreturn _kaboom(void)
diff --git a/core/layout.inc b/core/layout.inc
index dab27dde..24843923 100644
--- a/core/layout.inc
+++ b/core/layout.inc
@@ -97,6 +97,8 @@ RBFG_brainfuck: resb 2048 ; Bigger than an Ethernet packet...
; the spillover from the last fractional sector load.
section .uibss write nobits align=16
+ section .savedata write nobits align=16
+
; Symbols from linker script
%macro SECINFO 1
extern __%1_start, __%1_lma, __%1_end
@@ -128,21 +130,6 @@ RBFG_brainfuck: resb 2048 ; Bigger than an Ethernet packet...
serial_buf_size equ 4096 ; Should be a power of 2
;
-; Contents of aux_seg
-;
- extern aux_seg ; Actual segment assigned by linker
-
- struc aux
-.fontbuf resb 8192
-.serial resb serial_buf_size
-
- alignb 4096 ; Align the next segment to 4K
- endstruc
-
- section .auxseg write nobits align=16
-auxseg resb aux_size
-
-;
; Transfer buffer segment: guaranteed to be aligned 64K, used for disk I/O
; One symbol for the segment number, one for the absolute address
;
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/localboot.c b/core/localboot.c
index c6993fc0..03ac866d 100644
--- a/core/localboot.c
+++ b/core/localboot.c
@@ -11,7 +11,12 @@
* -----------------------------------------------------------------------
*/
#include <sys/cpu.h>
+#include <sys/io.h>
+#include <string.h>
#include <core.h>
+#include <fs.h>
+#include <bios.h>
+#include <graphics.h>
/*
* localboot.c
@@ -32,10 +37,9 @@ extern void local_boot16(void);
void local_boot(int16_t ax)
{
com32sys_t ireg, oreg;
- unsigned long data;
int i;
- vgaclearmode();
+ syslinux_force_text_mode();
writestr(LOCALBOOT_MSG);
crlf();
@@ -73,7 +77,7 @@ void local_boot(int16_t ax)
kaboom();
cli(); /* Abandon hope, ye who enter here */
- memcpy(0x07C00, trackbuf, 512);
+ memcpy((void *)0x07C00, trackbuf, 512);
ireg.esi.w[0] = OFFS(trackbuf);
ireg.edi.w[0] = 0x07C00;
diff --git a/core/mem/init.c b/core/mem/init.c
index 39a34e3e..0526dfbf 100644
--- a/core/mem/init.c
+++ b/core/mem/init.c
@@ -15,7 +15,6 @@ extern char free_high_memory[];
int scan_highmem_area(void *data, addr_t start, addr_t len, bool is_ram)
{
struct free_arena_header *fp;
- addr_t end;
(void)data;
@@ -31,7 +30,6 @@ int scan_highmem_area(void *data, addr_t start, addr_t len, bool is_ram)
}
if (len > E820_MEM_MAX - start)
len = E820_MEM_MAX - start;
- end = start + len;
if (len >= 2 * sizeof(struct arena_header)) {
fp = (struct free_arena_header *)start;
diff --git a/core/mem/malloc.c b/core/mem/malloc.c
index 732ad677..865de1e7 100644
--- a/core/mem/malloc.c
+++ b/core/mem/malloc.c
@@ -97,7 +97,12 @@ void *malloc(size_t size)
void *lmalloc(size_t size)
{
- return _malloc(size, HEAP_LOWMEM, MALLOC_CORE);
+ void *p;
+
+ p = _malloc(size, HEAP_LOWMEM, MALLOC_CORE);
+ if (!p)
+ errno = ENOMEM;
+ return p;
}
void *pmapi_lmalloc(size_t size)
diff --git a/core/plaincon.c b/core/plaincon.c
index a12d551a..dfeb9784 100644
--- a/core/plaincon.c
+++ b/core/plaincon.c
@@ -1,12 +1,14 @@
-/*
- * writechr: Write a single character in AL to the console without
- * mangling any registers; handle video pages correctly.
- */
#include <sys/io.h>
#include <fs.h>
#include <com32.h>
+
#include "bios.h"
+#include "graphics.h"
+/*
+ * Write a single character in AL to the console without
+ * mangling any registers; handle video pages correctly.
+ */
void writechr(char data)
{
com32sys_t ireg, oreg;
@@ -14,7 +16,7 @@ void writechr(char data)
write_serial(data); /* write to serial port if needed */
if (UsingVGA & 0x8)
- vgaclearmode();
+ syslinux_force_text_mode();
if (!(DisplayCon & 0x1))
return;
diff --git a/core/pxelinux.asm b/core/pxelinux.asm
index d990553f..aa11702d 100644
--- a/core/pxelinux.asm
+++ b/core/pxelinux.asm
@@ -89,6 +89,7 @@ LocalBootType resw 1 ; Local boot return code
DHCPMagic resb 1 ; PXELINUX magic flags
section .text16
+ global StackBuf
StackBuf equ STACK_TOP-44 ; Base of stack if we use our own
StackHome equ StackBuf
@@ -154,54 +155,6 @@ _start1:
lss esp,[BaseStack]
sti ; Stack set up and ready
-;
-; Move the hardwired DHCP options (if present) to a safe place...
-;
-bdhcp_copy:
- mov cx,[bdhcp_len]
- mov ax,trackbufsize/2
- jcxz .none
- cmp cx,ax
- jbe .oksize
- mov cx,ax
- mov [bdhcp_len],ax
-.oksize:
- mov eax,[bdhcp_offset]
- add eax,_start
- mov si,ax
- and si,000Fh
- shr eax,4
- push ds
- mov ds,ax
- mov di,trackbuf
- add cx,3
- shr cx,2
- rep movsd
- pop ds
-.none:
-
-adhcp_copy:
- mov cx,[adhcp_len]
- mov ax,trackbufsize/2
- jcxz .none
- cmp cx,ax
- jbe .oksize
- mov cx,ax
- mov [adhcp_len],ax
-.oksize:
- mov eax,[adhcp_offset]
- add eax,_start
- mov si,ax
- and si,000Fh
- shr eax,4
- push ds
- mov ds,ax
- mov di,trackbuf+trackbufsize/2
- add cx,3
- shr cx,2
- rep movsd
- pop ds
-.none:
;
; Initialize screen (if we're using one)
@@ -223,7 +176,6 @@ adhcp_copy:
mov eax,ROOT_FS_OPS
xor ebp,ebp
pm_call pm_fs_init
- pm_call load_env32
section .rodata
alignz 4
@@ -265,15 +217,124 @@ ROOT_FS_OPS:
%endmacro
;
+; Open configuration file. ldlinux.c32 needs ConfigName to be set - so we need
+; to call open_config() before loading it.
+;
+; Note: We don't need to check return value of open_config() function. It will
+; call kaboom() on failure.
+;
+ extern open_config
+ pm_call open_config
+
+;
; Jump to 32-bit ELF space
;
pm_call load_env32
+ jmp kaboom ; load_env32() shouldn't return. If it does, then kaboom!
+
+print_hello:
+enter_command:
+auto_boot:
+ pm_call hello
+
+;
+; Save hardwired DHCP options. This is done before the C environment
+; is initialized, so it has to be done in assembly.
+;
+%define MAX_DHCP_OPTS 4096
+ bits 32
+
+ section .savedata
+ global bdhcp_data, adhcp_data
+bdhcp_data: resb MAX_DHCP_OPTS
+adhcp_data: resb MAX_DHCP_OPTS
+
+ section .textnr
+pm_save_data:
+ mov eax,MAX_DHCP_OPTS
+ movzx ecx,word [bdhcp_len]
+ cmp ecx,eax
+ jna .oksize
+ mov ecx,eax
+ mov [bdhcp_len],ax
+.oksize:
+ mov esi,[bdhcp_offset]
+ add esi,_start
+ mov edi,bdhcp_data
+ add ecx,3
+ shr ecx,2
+ rep movsd
+
+adhcp_copy:
+ movzx ecx,word [adhcp_len]
+ cmp ecx,eax
+ jna .oksize
+ mov ecx,eax
+ mov [adhcp_len],ax
+.oksize:
+ mov esi,[adhcp_offset]
+ add esi,_start
+ mov edi,adhcp_data
+ add ecx,3
+ shr ecx,2
+ rep movsd
+ ret
+
+ bits 16
+
+; As core/ui.inc used to be included here in core/pxelinux.asm, and it's no
+; longer used, its global variables that were previously used by
+; core/pxelinux.asm are now declared here.
+ section .bss16
+ alignb 4
+Kernel_EAX resd 1
+Kernel_SI resw 1
+
+ section .bss16
+ global CmdOptPtr, KbdMap
+ alignb 4
+ThisKbdTo resd 1 ; Temporary holder for KbdTimeout
+ThisTotalTo resd 1 ; Temporary holder for TotalTimeout
+KernelExtPtr resw 1 ; During search, final null pointer
+CmdOptPtrj resw 1 ; Pointer to first option on cmd line
+KbdFlags resb 1 ; Check for keyboard escapes
+FuncFlag resb 1 ; Escape sequences received from keyboard
+KernelType resb 1 ; Kernel type, from vkernel, if known
+KbdMap resb 256 ; Keyboard map
+ global KernelName
+KernelName resb FILENAME_MAX ; Mangled name for kernel
+ section .config
+ global PXERetry
+PXERetry dw 0 ; Extra PXE retries
+ section .data16
+ global SerialNotice
+SerialNotice db 1 ; Only print this once
+ extern IPOption
+ global IPAppends, numIPAppends
+ alignz 2
+IPAppends dw IPOption
+numIPAppends equ ($-IPAppends)/2
+
+ section .text16
+;
+; COMBOOT-loading code
+;
+%include "comboot.inc"
+%include "com32.inc"
+
+;
+; Boot sector loading code
+;
;
-; Now we have the config file open. Parse the config file and
-; run the user interface.
+; Abort loading code
;
-%include "ui.inc"
+
+;
+; Hardware cleanup common code
+;
+
+%include "localboot.inc"
;
; kaboom: write a message and bail out. Wait for quite a while,
@@ -317,7 +378,6 @@ kaboom:
mov word [BIOS_magic],0 ; Cold reboot
jmp 0F000h:0FFF0h ; Reset vector address
-
;
; pxenv
;
@@ -335,9 +395,9 @@ pxenv:
pushad
; We may be removing ourselves from memory
- cmp bx,0073h ; PXENV_RESTART_TFTP
+ cmp bx,PXENV_RESTART_TFTP
jz .disable_timer
- cmp bx,00E5h ; gPXE PXENV_FILE_EXEC
+ cmp bx,PXENV_FILE_EXEC
jnz .store_stack
.disable_timer:
@@ -372,9 +432,9 @@ pxenv:
popad
; If the call failed, it could return.
- cmp bx,0073h
+ cmp bx,PXENV_RESTART_TFTP
jz .enable_timer
- cmp bx,00E5h
+ cmp bx,PXENV_FILE_EXEC
jnz .pop_flags
.enable_timer:
diff --git a/core/rawcon.c b/core/rawcon.c
index d28113b8..1a52c954 100644
--- a/core/rawcon.c
+++ b/core/rawcon.c
@@ -6,12 +6,14 @@
#include <sys/io.h>
#include <fs.h>
#include <com32.h>
+
#include "bios.h"
+#include "graphics.h"
void writechr(char data)
{
if (UsingVGA & 0x08)
- vgaclearmode();
+ syslinux_force_text_mode();
write_serial(data); /* write to serial port if needed */
diff --git a/core/serirq.c b/core/serirq.c
index 767099e1..e0675c9a 100644
--- a/core/serirq.c
+++ b/core/serirq.c
@@ -26,8 +26,8 @@
static char serial_buf[serial_buf_size];
static unsigned short SerialIRQPort; /* Serial port w IRQ service */
-unsigned char *SerialHead = serial_buf; /* Head of serial port rx buffer */
-unsigned char *SerialTail = serial_buf; /* Tail of serial port rx buffer */
+char *SerialHead = serial_buf; /* Head of serial port rx buffer */
+char *SerialTail = serial_buf; /* Tail of serial port rx buffer */
static unsigned char IRQMask[2]; /* PIC IRQ mask status */
@@ -39,11 +39,11 @@ void sirq_cleanup(void);
static void irq_common(unsigned short old_irq)
{
- unsigned char *dst;
+ char *dst;
irqhandler_t next;
char val;
- dst = (unsigned char *)SerialHead;
+ dst = SerialHead;
next = (irqhandler_t)oldirq[old_irq];
/* LSR */
@@ -57,7 +57,7 @@ static void irq_common(unsigned short old_irq)
val = inb(SerialPort + 5);
if ((val & FlowIgnore) == FlowIgnore) {
/* Wrap around if necessary */
- dst = (unsigned char *)((unsigned long)dst & (serial_buf_size - 1));
+ dst = (char *)((unsigned long)dst & (serial_buf_size - 1));
/* Would this cause overflow? */
if (dst != SerialTail)
diff --git a/core/syslinux.ld b/core/syslinux.ld
index 7b4e012c..edd89e86 100644
--- a/core/syslinux.ld
+++ b/core/syslinux.ld
@@ -213,21 +213,6 @@ SECTIONS
xfer_buf_seg = core_xfer_buf >> 4;
/*
- * The auxilliary data segment is used by the 16-bit code
- * for items that don't need to live in the bottom 64K.
- */
-
- . = ALIGN(16);
- .auxseg (NOLOAD) : {
- __auxseg_start = .;
- *(.auxseg)
- __auxseg_end = .;
- }
- __auxseg_len = ABSOLUTE(__auxseg_end) - ABSOLUTE(__auxseg_start);
- __auxseg_dwords = (__auxseg_len + 3) >> 2;
- aux_seg = __auxseg_start >> 4;
-
- /*
* Used to allocate lowmem buffers from 32-bit code
*/
.lowmem (NOLOAD) : {
@@ -283,8 +268,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 = .;
}
@@ -292,8 +278,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 = .;
}
@@ -392,6 +378,8 @@ SECTIONS
/* Very large objects which don't need to be zeroed */
+ . = ALIGN(128);
+
__hugebss_vma = .;
__hugebss_lma = .; /* Dummy */
.hugebss (NOLOAD) : AT (__hugebss_lma) {
@@ -403,6 +391,19 @@ SECTIONS
__hugebss_len = ABSOLUTE(__hugebss_end) - ABSOLUTE(__hugebss_start);
__hugebss_dwords = (__hugebss_len + 3) >> 2;
+ /* Data saved away before bss initialization */
+ . = ALIGN(128);
+
+ __savedata_vma = .;
+ __savedata_lma = .; /* Dummy */
+ .savedata (NOLOAD) : AT (__savedata_lma) {
+ __savedata_start = .;
+ *(.savedata)
+ *(.savedata.*)
+ __savedata_end = .;
+ }
+ __savedata_len = ABSOLUTE(__savedata_end) - ABSOLUTE(__savedata_start);
+ __savedata_dwords = (__savedata_len + 3) >> 2;
/* XXX: This stack should be unified with the COM32 stack */
__stack_vma = .;
diff --git a/core/ui.inc b/core/ui.inc
deleted file mode 100644
index e50c7f55..00000000
--- a/core/ui.inc
+++ /dev/null
@@ -1,763 +0,0 @@
-;; -----------------------------------------------------------------------
-;;
-;; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
-;; Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
-;;
-;; This program is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, Inc., 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.
-;;
-;; -----------------------------------------------------------------------
-
-;
-; This file should be entered with the config file open (for getc)
-;
-%if 1
-on_error:
-no_config_file:
-enter_command:
-auto_boot:
-load_kernel:
-kernel_good_saved:
-kernel_corrupt:
- pm_call hello
-
-%else ; comment off the original ui.inc
-load_config_file:
- call parse_config ; Parse configuration file
-no_config_file:
-
- call adv_init
-;
-; Check for an ADV boot-once entry
-;
- mov dl,ADV_BOOTONCE
- call adv_get
- jcxz .no_bootonce
-
-.have_bootone:
- ; We apparently have a boot-once set; clear it and
- ; then execute the boot-once...
-
- ; Save the boot-once data; SI = data, CX = length
- mov di,command_line
- rep movsb
- xor ax,ax
- stosb
-
- ; Clear the boot-once data from the ADV
- xor cx,cx ; Set to zero = delete
- call adv_set
- jc .err
- call adv_write
-.err: jmp load_kernel
-
-.no_bootonce:
-
-;
-; Check whether or not we are supposed to display the boot prompt.
-;
-check_for_key:
- test byte [KbdFlags],5Bh ; Shift Alt Caps Scroll
- jnz enter_command
- cmp word [ForcePrompt],0 ; Force prompt?
- jz auto_boot
- cmp word [DefaultLevel],1 ; Active UI statement?
- ja auto_boot
-
-enter_command:
- cmp word [NoEscape],0 ; If NOESCAPE, no prompt,
- jne auto_boot ; always run default cmd
-
- mov si,boot_prompt
- call writestr
-
- mov byte [FuncFlag],0 ; <Ctrl-F> not pressed
- mov di,command_line
-
-;
-; get the very first character -- we can either time
-; out, or receive a character press at this time. Some dorky BIOSes stuff
-; a return in the buffer on bootup, so wipe the keyboard buffer first.
-;
-clear_buffer: mov ah,11h ; Check for pending char
- int 16h
- jz get_char_time
- mov ah,10h ; Get char
- int 16h
- jmp short clear_buffer
-
- ; For the first character, both KbdTimeout and
- ; TotalTimeout apply; after that, only TotalTimeout.
-
-get_char_time:
- mov eax,[TotalTimeout]
- mov [ThisTotalTo],eax
- mov eax,[KbdTimeout]
- mov [ThisKbdTo],eax
-
-get_char:
- call getchar_timeout
- and dword [ThisKbdTo],0 ; For the next time...
-
- and al,al
- jz func_key
-
-got_ascii: cmp al,7Fh ; <DEL> == <BS>
- je backspace
- cmp al,' ' ; ASCII?
- jb not_ascii
- ja enter_char
- cmp di,command_line ; Space must not be first
- je short get_char
-enter_char: test byte [FuncFlag],1
- jnz ctrl_f ; Keystroke after <Ctrl-F>
- cmp di,max_cmd_len+command_line ; Check there's space
- jnb short get_char
- stosb ; Save it
- call writechr ; Echo to screen
- jmp short get_char
-not_ascii:
- cmp al,0Dh ; Enter
- je command_done
- cmp al,09h ; Tab
- je display_labels
- cmp al,'F' & 1Fh ; <Ctrl-F>
- je set_func_flag
-%if IS_PXELINUX
- cmp al,'N' & 1Fh ; <Ctrl-N>
- je show_network_info
-%endif
- cmp al,'U' & 1Fh ; <Ctrl-U>
- je kill_command ; Kill input line
- cmp al,'V' & 1Fh ; <Ctrl-V>
- je print_version
- cmp al,'X' & 1Fh ; <Ctrl-X>
- je force_text_mode
- cmp al,08h ; Backspace
- jne get_char
-backspace: cmp di,command_line ; Make sure there is anything
- je get_char ; to erase
- dec di ; Unstore one character
- mov si,wipe_char ; and erase it from the screen
- call writestr
-get_char_2:
- jmp short get_char
-
-kill_command:
- call crlf
- jmp enter_command
-
-force_text_mode:
- call vgaclearmode
- jmp enter_command
-
-set_func_flag:
- mov byte [FuncFlag],1
- jmp short get_char_2
-
-display_labels:
- cmp word [NoComplete],0 ; Label completion enabled?
- jne get_char_2
- push di ; Save pointer
- mov cx,di
- sub cx,command_line
- call crlf
- mov esi,[HighMemSize] ; Start from top of memory
-.scan:
- cmp esi,[VKernelEnd]
- jbe .not_vk
-
- push cx ; save command line size
-
- mov edi,VKernelBuf
- pm_call rllunpack
- ; ESI updated on return
-
- sub di,cx ; Return to beginning of buf
- pop cx ; restore command line size
- push si ; save SI
- cmp cx,0
- jz .print
- push di
- push cx
- mov si,command_line
- es repe cmpsb
- pop cx
- pop di
- jne .next
-.print:
- mov al,' '
- call writechr
-
- mov si,di
- call writestr
-.next:
- pop si ; restore SI
- jmp .scan
-.not_vk:
- call crlf
- jmp fk_wrcmd
-
-ctrl_f:
- xor ah,ah
- mov [FuncFlag],ah
- cmp al,'0'
- jb get_char_2
- je .zero ; <Ctrl-F>0 = F10
- or al,20h ; Lower case
- cmp al,'9'
- jna .digit
- cmp al,'a' ; F10-F12 = <Ctrl-F>A, B, C
- jb get_char_2
- cmp al,'c'
- ja get_char_2
- sub al,'a'-10
- jmp show_help
-.zero:
- mov al,10
- jmp show_help
-.digit:
- sub al,'1'
- jmp show_help
-
-func_key:
- ; AL = 0 if we get here
- xchg al,ah
- cmp al,44h ; F10
- ja .f11_f12
- sub al,3Bh ; F1
- jb get_char_2
- jmp show_help
-.f11_f12:
- cmp al,85h ; F11
- jb get_char_2
- cmp al,86h ; F12
- ja get_char_2
- sub al,85h-10
-
-show_help: ; AX = func key # (0 = F1, 9 = F10, 11 = F12)
- push di ; Save end-of-cmdline pointer
- shl ax,FILENAME_MAX_LG2 ; Convert to pointer
- add ax,FKeyName
- xchg di,ax
- cmp byte [di+NULLOFFSET],NULLFILE
- je short fk_nofile ; Undefined F-key
- call core_open
- jz short fk_nofile ; File not found
- call crlf
- call get_msg_file
- jmp short fk_wrcmd
-
-print_version:
- push di ; Command line write pointer
- mov si,syslinux_banner
- call writestr
-%ifdef HAVE_BIOSNAME
- mov si,[BIOSName]
- call writestr
-%endif
- mov si,copyright_str
- call writestr
-
- ; ... fall through ...
-
- ; Write the boot prompt and command line again and
- ; wait for input. Note that this expects the cursor
- ; to already have been CRLF'd, and that the old value
- ; of DI (the command line write pointer) is on the stack.
-fk_wrcmd:
- mov si,boot_prompt
- call writestr
- pop di ; Command line write pointer
- push di
- mov byte [di],0 ; Null-terminate command line
- mov si,command_line
- call writestr ; Write command line so far
-fk_nofile: pop di
- jmp get_char
-
-;
-; Show network info (in the form of the ipappend strings)
-;
-%if IS_PXELINUX
-show_network_info:
- push di ; Command line write pointer
- call crlf
- mov si,IPAppends ; See comboot.doc
- mov cx,numIPAppends
-.loop:
- lodsw
- push si
- mov si,ax
- call writestr
- call crlf
- pop si
- loop .loop
- jmp fk_wrcmd
-%endif
-
-;
-; Jump here to run the default command line
-;
-auto_boot:
- cmp word [DefaultLevel],0 ; No UI or DEFAULT?
- jne .have_default
- mov si,no_default_msg
- call writestr
- cmp word [NoEscape],0 ; NOESCAPE but no DEFAULT?
- jne kaboom ; If so, we're stuck!
- jmp enter_command
-
-.have_default:
- mov si,default_cmd
- mov di,command_line
- mov cx,(max_cmd_len+4) >> 2
- rep movsd
- jmp short load_kernel
-
- section .data16
-no_default_msg db 'No DEFAULT or UI configuration directive found!'
- db CR, LF, 0
-
- section .text16
-
-;
-; Jump here when the command line is completed
-;
-command_done:
- call crlf
- cmp di,command_line ; Did we just hit return?
- je auto_boot
- xor al,al ; Store a final null
- stosb
-
-load_kernel: ; Load the kernel now
-;
-; First we need to mangle the kernel name the way DOS would...
-;
- mov si,command_line
- mov di,KernelName
- push si
- pm_call pm_mangle_name
- pop si
-;
-; Fast-forward to first option (we start over from the beginning, since
-; pm_mangle_name doesn't necessarily return a consistent ending state.)
-;
-clin_non_wsp: lodsb
- cmp al,' '
- ja clin_non_wsp
-clin_is_wsp: and al,al
- jz clin_opt_ptr
- lodsb
- cmp al,' '
- jbe clin_is_wsp
-clin_opt_ptr: dec si ; Point to first nonblank
- mov [CmdOptPtr],si ; Save ptr to first option
-;
-; If "allowoptions 0", put a null character here in order to ignore any
-; user-specified options.
-;
- mov ax,[AllowOptions]
- and ax,ax
- jnz clin_opt_ok
- mov [si],al
-clin_opt_ok:
-
-;
-; Now check if it is a "virtual kernel"
-;
-vk_check:
- mov esi,[HighMemSize] ; Start from top of memory
-.scan:
- cmp esi,[VKernelEnd]
- jbe .not_vk
-
- mov edi,VKernelBuf
- pm_call rllunpack
- ; ESI updated on return
-
- sub di,cx ; Return to beginning of buf
- push si
- mov si,command_line
-.loop:
- lodsb
- cmp al,' '
- jbe .done
- scasb
- je .loop
-.nomatch:
- pop si
- jmp .scan
-.done:
- cmp byte [di],0 ; Must match end of string
- jne .nomatch
- pop si
-
-;
-; We *are* using a "virtual kernel"
-;
-.found:
- push es
- push word real_mode_seg
- pop es
- mov di,cmd_line_here
- mov si,VKernelBuf+vk_append
- mov cx,[VKernelBuf+vk_appendlen]
- rep movsb
- mov byte [es:di],cl ; Null-terminate
- mov [CmdLinePtr],di ; Where to add rest of cmd
- pop es
- mov di,KernelName
- push di
- mov si,VKernelBuf+vk_rname
- mov cx,FILENAME_MAX ; We need ECX == CX later
- rep movsb
- pop di
-%if IS_PXELINUX
- mov al,[VKernelBuf+vk_ipappend]
- mov [IPAppend],al
-%endif
- xor bx,bx ; Try only one version
-
- mov al,[VKernelBuf+vk_type]
- mov [KernelType],al
-
- ; Is this a "localboot" pseudo-kernel?
- cmp al,VK_LOCALBOOT ; al == KernelType
- mov ax,[VKernelBuf+vk_rname] ; Possible localboot type
- je local_boot
- jmp get_kernel
-
-.not_vk:
-;
-; Not a "virtual kernel" - check that's OK and construct the command line
-;
- cmp word [AllowImplicit],byte 0
- je bad_implicit
- push es
- push si
- push di
- mov di,real_mode_seg
- mov es,di
- mov si,AppendBuf
- mov di,cmd_line_here
- mov cx,[AppendLen]
- rep movsb
- mov byte [es:di],cl ; Null-terminate
- mov [CmdLinePtr],di
- pop di
- pop si
- pop es
-
- mov [KernelType], cl ; CL == 0 here
-
-;
-; Find the kernel on disk
-;
-get_kernel: mov byte [KernelName+FILENAME_MAX],0 ; Zero-terminate filename/extension
- mov di,KernelName
- cmp byte [di],' '
- jbe bad_kernel ; Missing kernel name
- xor al,al
- mov cx,FILENAME_MAX-5 ; Need 4 chars + null
- repne scasb ; Scan for final null
- jne .no_skip
- dec di ; Point to final null
-.no_skip: mov [KernelExtPtr],di
- mov bx,exten_table
-.search_loop: push bx
- mov di,KernelName ; Search on disk
- pm_call pm_searchdir
- pop bx
- jnz kernel_good
- mov eax,[bx] ; Try a different extension
- mov si,[KernelExtPtr]
- mov [si],eax
- mov byte [si+4],0
- add bx,byte 4
- cmp bx,exten_table_end
- jna .search_loop ; allow == case (final case)
- ; Fall into bad_kernel
-;
-; bad_kernel: Kernel image not found
-; bad_implicit: The user entered a nonvirtual kernel name, with "implicit 0"
-;
-bad_implicit:
-bad_kernel:
- mov cx,[OnerrorLen]
- and cx,cx
- jnz on_error
-.really:
- mov si,err_notfound ; Complain about missing kernel
- call writestr
- mov si,KernelName
- call writestr
- mov si,crlf_msg
- jmp abort_load ; Ask user for clue
-
-;
-; on_error: bad kernel, but we have onerror set; CX = OnerrorLen
-;
-on_error:
- mov si,Onerror
- mov di,command_line
- push si ; <A>
- push di ; <B>
- push cx ; <C>
- push cx ; <D>
- push di ; <E>
- repe cmpsb
- pop di ; <E> di == command_line
- pop bx ; <D> bx == [OnerrorLen]
- je bad_kernel.really ; Onerror matches command_line already
- neg bx ; bx == -[OnerrorLen]
- lea cx,[max_cmd_len+bx]
- ; CX == max_cmd_len-[OnerrorLen]
- mov di,command_line+max_cmd_len-1
- mov byte [di+1],0 ; Enforce null-termination
- lea si,[di+bx]
- std
- rep movsb ; Make space in command_line
- cld
- pop cx ; <C> cx == [OnerrorLen]
- pop di ; <B> di == command_line
- pop si ; <A> si == Onerror
- rep movsb
- jmp load_kernel
-
-;
-; kernel_corrupt: Called if the kernel file does not seem healthy
-;
-kernel_corrupt: mov si,err_notkernel
- jmp abort_load
-
-;
-; Get a key, observing ThisKbdTO and ThisTotalTO -- those are timeouts
-; which can be adjusted by the caller based on the corresponding
-; master variables; on return they're updated.
-;
-; This cheats. If we say "no timeout" we actually get a timeout of
-; 7.5 years.
-;
-getchar_timeout:
- call vgashowcursor
- call reset_idle
-
-.loop:
- push word [__jiffies]
- call pollchar
- jnz .got_char
- call do_idle
- pop ax
- cmp ax,[__jiffies] ; Has the timer advanced?
- je .loop
-
- dec dword [ThisKbdTo]
- jz .timeout
- dec dword [ThisTotalTo]
- jnz .loop
-
-.timeout:
- ; Timeout!!!!
- pop cx ; Discard return address
- call vgahidecursor
- mov si,Ontimeout ; Copy ontimeout command
- mov di,command_line
- mov cx,[OntimeoutLen] ; if we have one...
- rep movsb
- jmp command_done
-
-.got_char:
- pop cx ; Discard
- call getchar
- call vgahidecursor
- ret
-
-;
-; This is it! We have a name (and location on the disk)... let's load
-; that sucker!! First we have to decide what kind of file this is; base
-; that decision on the file extension. The following extensions are
-; recognized; case insensitive:
-;
-; .com - COMBOOT image
-; .cbt - COMBOOT image
-; .c32 - COM32 image
-; .bs - Boot sector
-; .0 - PXE bootstrap program (PXELINUX only)
-; .bin - Boot sector
-; .bss - Boot sector, but transfer over DOS superblock (SYSLINUX only)
-; .img - Floppy image (ISOLINUX only)
-;
-; Anything else is assumed to be a Linux kernel.
-;
-
- section .text16
-kernel_good_saved:
- ; Alternate entry point for which the return from
- ; searchdir is stored in memory. This is used for
- ; COMBOOT function INT 22h, AX=0016h.
- mov si,[Kernel_SI]
- mov eax,[Kernel_EAX]
-
-kernel_good:
- pushad
- ;
- ; Common initialization for all kernel types
- ;
- xor ax,ax
- mov [InitRDPtr],ax
- mov [QuietBoot],al
-%if IS_PXELINUX
- mov [KeepPXE],al
-%endif
-
- ; Default memory limit, can be overridden by image loaders
- mov eax,[HighMemRsvd]
- mov [MyHighMemSize],eax
-
- popad
-
- push di
- push ax
- mov di,KernelName
- xor al,al
- mov cx,FILENAME_MAX
- repne scasb
- jne .one_step
- dec di
-.one_step: mov ecx,[di-4] ; 4 bytes before end
- pop ax
- pop di
-
-;
-; At this point, EAX contains the size of the kernel, SI contains
-; the file handle/cluster pointer, and ECX contains the extension (if any.)
-;
- movzx di,byte [KernelType]
- add di,di
- jmp [kerneltype_table+di]
-
-is_unknown_filetype:
- or ecx,20202000h ; Force lower case (except dot)
-
- cmp ecx,'.com'
- je is_comboot_image
- cmp ecx,'.cbt'
- je is_comboot_image
- cmp ecx,'.c32'
- je is_com32_image
-%if IS_ISOLINUX
- cmp ecx,'.img'
- je is_disk_image
-%endif
- cmp ecx,'.bss'
- je is_bss_sector
- cmp ecx,'.bin'
- je is_bootsector
- shr ecx,8
- cmp ecx,'.bs'
- je is_bootsector
- shr ecx,8
- cmp cx,'.0'
- je is_bootsector
-
- ; Otherwise Linux kernel
- jmp is_linux_kernel
-
-; This is an image type we can't deal with
-is_bad_image:
- mov si,err_badimage
- call writestr
- jmp enter_command
-
-%if IS_SYSLINUX
- ; ok
-%else
-is_bss_sector equ is_bad_image
-%endif
-
-is_disk_image equ is_bad_image ; No longer supported
-
-%endif ; start of replacing ui.inc
-
- section .bss16
- alignb 4
-Kernel_EAX resd 1
-Kernel_SI resw 1
-
-
- section .data16
-boot_prompt db 'boot: ', 0
-wipe_char db BS, ' ', BS, 0
-err_badimage db 'Invalid image type for this media type!', CR, LF, 0
-err_notfound db 'Could not find kernel image: ',0
-err_notkernel db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0
-
-
-%if 0
- alignz 2
-kerneltype_table:
- dw is_unknown_filetype ; VK_KERNEL
- dw is_linux_kernel ; VK_LINUX
- dw is_bootsector ; VK_BOOT
- dw is_bss_sector ; VK_BSS
- dw is_bootsector ; VK_PXE
- dw is_disk_image ; VK_FDIMAGE
- dw is_comboot_image ; VK_COMBOOT
- dw is_com32_image ; VK_COM32
-%endif
-
- section .bss16
- global CmdOptPtr, KbdMap
- alignb 4
-ThisKbdTo resd 1 ; Temporary holder for KbdTimeout
-ThisTotalTo resd 1 ; Temporary holder for TotalTimeout
-KernelExtPtr resw 1 ; During search, final null pointer
-CmdOptPtr resw 1 ; Pointer to first option on cmd line
-KbdFlags resb 1 ; Check for keyboard escapes
-FuncFlag resb 1 ; Escape sequences received from keyboard
-KernelType resb 1 ; Kernel type, from vkernel, if known
-KbdMap resb 256 ; Keyboard map
- global KernelName
-KernelName resb FILENAME_MAX ; Mangled name for kernel
- section .config
- global PXERetry
-PXERetry dw 0 ; Extra PXE retries
- section .data16
- global SerialNotice
-SerialNotice db 1 ; Only print this once
-%if IS_PXELINUX
- extern IPOption
- global IPAppends, numIPAppends
- alignz 2
-IPAppends dw IPOption
-numIPAppends equ ($-IPAppends)/2
-%else
-IPAppends equ 0
-numIPAppends equ 0
-%endif
-
- section .text16
-;
-; COMBOOT-loading code
-;
-%include "comboot.inc"
-%include "com32.inc"
-
-;
-; Boot sector loading code
-;
-
-;
-; Abort loading code
-;
-
-;
-; Hardware cleanup common code
-;
-
-%include "localboot.inc"
diff --git a/core/writestr.c b/core/writestr.c
index 66d126af..fb9de348 100644
--- a/core/writestr.c
+++ b/core/writestr.c
@@ -17,6 +17,7 @@
* Code to write a simple string.
*/
#include <com32.h>
+#include <core.h>
/*
* crlf: Print a newline
diff --git a/diag/geodsp/Makefile b/diag/geodsp/Makefile
index b76eb77d..55160859 100644
--- a/diag/geodsp/Makefile
+++ b/diag/geodsp/Makefile
@@ -19,40 +19,41 @@
#
topdir = ../..
-# include $(topdir)/mk/embedded.mk
+MAKEDIR = $(topdir)/mk
+include $(MAKEDIR)/embedded.mk
coredir = $(topdir)/core
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: %.bin mk-lba-img
- ./mk-lba-img < $< | xz -0f > $@ || ( rm -f $@ ; false )
+%.img.xz: %.bin mk-lba-img.pl
+ $(PERL) mk-lba-img $< | $(XZ) -0 > $@ || ( rm -f $@ ; false )
+
+%.img.gz: %.bin mk-lba-img.pl
+ $(PERL) mk-lba-img $< | $(GZIPPROG) -9 > $@ || ( rm -f $@ ; false )
-%.img.gz: %.img
- ./mk-lba-img < $< | gzip -9 > $@ || ( rm -f $@ ; false )
+# 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 -g -O -o $@ $<
+ $(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 mk-lba-img
spotless: clean
rm -f $(BTARGET)
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/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/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/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/pxechn.txt b/doc/pxechn.txt
new file mode 100644
index 00000000..a09bbe2b
--- /dev/null
+++ b/doc/pxechn.txt
@@ -0,0 +1,94 @@
+= pxechn.c32 =
+:doctype: manpage
+:author: Gene Cumm
+:email: gene.cumm@gmail.com
+:revdate: 2012-05-27
+
+
+== NAME ==
+pxechn.c32 - Chainboot to new NBP
+
+
+== SYNOPSIS ==
+*pxechn.c32* [-h | --help | -?]
+*pxechn.c32* -r 'FILE'
+*pxechn.c32* 'FILE' ['OPTIONS']
+
+
+== DESCRIPTION ==
+Chainboot to a new NBP (Network Boot Program) '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'::
+ PXELINUX config file (DHCP Option 209).
+
+// *-f* 'MOD'::
+// Force behavior specified by 'MOD'
+//
+// *-g* 'HOST'::
+// Set DHCP gateway/relay. Parsed by pxe_dns().
+//
+*-h*, *--help*, *-?*::
+ Print 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'::
+ Specify a generic option. 'OPT' is in 'DECIMAL INPUT' format (below). 'TYPE' specifies the output type and input syntax. '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'::
+ PXELINUX path (DHCP Option 210).
+
+*-r*::
+ Call the PXE stack with PXENV_RESTART_TFTP. _Must_ be the only option and before 'FILE'.
+
+*-t* 'SECONDS'::
+ PXELINUX timeout (DHCP Option 211).
+
+// *-u*::
+// Copy UUID (Option 97) if found in packet #1
+
+*-w*::
+ wait after loading before booting for user input.
+
+*-W*::
+ Enable WDS (Windows Deployment Services) - specific options.
+
+
+== 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://172.16.23.1/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://172.16.23.1/tftp/ -w -X A012345678 -x 197:00d0de00
+pxechn.c32 gpxelinux.0 -p http://172.16.23.1/tftp/ -w -X A012:3456:78 -x 197:00-d0-de-00
+ Both of these are equivalent. 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.
+
+
+== 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.
+
+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-01-12.
+
+
+== 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).
diff --git a/dos/Makefile b/dos/Makefile
index 5e5fc63f..f9420084 100644
--- a/dos/Makefile
+++ b/dos/Makefile
@@ -27,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 5746e86b..6bce6248 100644
--- a/dosutil/Makefile
+++ b/dosutil/Makefile
@@ -11,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/efi/Makefile b/efi/Makefile
index 338f4512..3304d763 100644
--- a/efi/Makefile
+++ b/efi/Makefile
@@ -22,7 +22,7 @@ CORE_COBJ := $(patsubst %.c,%.o,$(CORE_CSRC))
CORE_OBJS = $(filter-out $(core)/hello.o $(core)/rawcon.o \
$(core)/plaincon.o $(core)/strcasecmp.o $(core)/bios.o \
$(core)/fs/diskio_bios.o,$(CORE_COBJ))
-LIB_OBJS = $(addprefix $(com32)/lib/,$(MINLIBOBJS))
+LIB_OBJS = $(addprefix $(com32)/lib/,$(CORELIBOBJS))
CSRC = $(wildcard *.c)
OBJ = $(patsubst %.c,%.o,$(CSRC))
diff --git a/efi/diskio.c b/efi/diskio.c
index e30f8da8..a4d558a4 100644
--- a/efi/diskio.c
+++ b/efi/diskio.c
@@ -33,7 +33,7 @@ static int efi_rdwr_sectors(struct disk *disk, void *buf,
if (status != EFI_SUCCESS)
Print(L"Failed to %s blocks: 0x%x\n",
- is_write ? "write" : "read",
+ is_write ? L"write" : L"read",
status);
return count << disk->sector_shift;
diff --git a/efi/main.c b/efi/main.c
index 251f5aa5..f98d95c3 100644
--- a/efi/main.c
+++ b/efi/main.c
@@ -81,12 +81,14 @@ void pxenv(void)
{
}
-uint16_t numIPAppends = 0;
-char *IPAppends = NULL;
+const char numIPAppends[4];
+const uint16_t IPAppends[32];
uint16_t BIOS_fbm = 1;
far_ptr_t InitStack;
+char StackBuf[4096];
uint16_t APIVer;
far_ptr_t PXEEntry;
+unsigned int __bcopyxx_len = 0;
void gpxe_unload(void)
{
@@ -126,7 +128,7 @@ static void efi_write_char(uint8_t ch, uint8_t attribute)
uefi_call_wrapper(out->OutputString, 2, out, c);
}
-static void efi_showcursor(uint16_t cursor)
+static void efi_showcursor(const struct term_state *st)
{
SIMPLE_TEXT_OUTPUT_INTERFACE *out = ST->ConOut;
uefi_call_wrapper(out->SetCursorPosition, 3, out, cursor_x, cursor_y);
@@ -236,7 +238,7 @@ void efi_init(void)
mem_init();
}
-char efi_getchar(void)
+char efi_getchar(char *hi)
{
SIMPLE_INPUT_INTERFACE *in = ST->ConIn;
EFI_INPUT_KEY key;
@@ -252,15 +254,20 @@ char efi_getchar(void)
return c;
}
+int efi_pollchar(void)
+{
+ SIMPLE_INPUT_INTERFACE *in = ST->ConIn;
+ EFI_STATUS status;
+
+ status = WaitForSingleEvent(in->WaitForKey, 1);
+ return status != EFI_TIMEOUT;
+}
+
struct input_ops efi_iops = {
.getchar = efi_getchar,
+ .pollchar = efi_pollchar,
};
-char *efi_get_config_file_name(void)
-{
- return ConfigName;
-}
-
bool efi_ipappend_strings(char **list, int *count)
{
*count = numIPAppends;
@@ -436,7 +443,9 @@ static void free_addr(EFI_PHYSICAL_ADDRESS addr, size_t size)
}
int efi_boot_linux(void *kernel_buf, size_t kernel_size,
- struct initramfs *initramfs, char *cmdline)
+ struct initramfs *initramfs,
+ struct setup_data *setup_data,
+ char *cmdline)
{
EFI_MEMORY_DESCRIPTOR *map;
struct linux_header *hdr;
@@ -719,7 +728,6 @@ struct firmware efi_fw = {
.disk_init = efi_disk_init,
.o_ops = &efi_ops,
.i_ops = &efi_iops,
- .get_config_file_name = efi_get_config_file_name,
.get_serial_console_info = serialcfg,
.ipappend_strings = efi_ipappend_strings,
.adv_ops = &efi_adv_ops,
diff --git a/extlinux/Makefile b/extlinux/Makefile
index 5da19e4a..6cde574e 100644
--- a/extlinux/Makefile
+++ b/extlinux/Makefile
@@ -11,7 +11,7 @@
## -----------------------------------------------------------------------
##
-## Linux vfat, ext2/ext3/ext4 and btrfs installer
+## Linux vfat, ntfs, ext2/ext3/ext4 and btrfs installer
##
topdir = ..
@@ -22,9 +22,10 @@ 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 \
@@ -54,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..73f3fbe1 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];
@@ -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;
@@ -215,7 +217,7 @@ int patch_file_and_bootblock(int fd, const char *dir, int devfd)
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;
}
+/*
+ * * 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;
+}
+
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;
}
}
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..2e317d0e 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
@@ -192,7 +193,7 @@ struct syslinux_extent {
} __attribute__((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;
@@ -241,10 +242,74 @@ struct boot_sector {
uint16_t bsSignature;
} __attribute__ ((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;
+} __attribute__((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 d4674917..5ec156ac 100644
--- a/libinstaller/syslxmod.c
+++ b/libinstaller/syslxmod.c
@@ -109,7 +109,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 b9dac179..08a3ed49 100644
--- a/linux/Makefile
+++ b/linux/Makefile
@@ -11,14 +11,14 @@
## -----------------------------------------------------------------------
##
-## Linux FAT installer
+## Linux FAT/NTFS installer
##
topdir = ..
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 =
@@ -28,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
@@ -57,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/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/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 286ea405..36689979 100644
--- a/memdisk/Makefile
+++ b/memdisk/Makefile
@@ -20,7 +20,7 @@ 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/mk/com32.mk b/mk/com32.mk
index 32973407..89ede83e 100644
--- a/mk/com32.mk
+++ b/mk/com32.mk
@@ -79,8 +79,7 @@ LNXCFLAGS = -I$(com32)/libutil/include $(GCCWARN) -O -g \
LNXSFLAGS = -g
LNXLDFLAGS = -g
-C_LIBS = $(com32)/libutil/libutil_com.a $(GPLLIB) \
- $(com32)/lib/libcom32.c32 $(LIBGCC)
+C_LIBS = $(GPLLIB) $(com32)/lib/libcom32.c32 $(LIBGCC)
C_LNXLIBS = $(com32)/libutil/libutil_lnx.a
.SUFFIXES: .lss .c .lo .o .elf .c32 .lnx
diff --git a/mk/devel.mk b/mk/devel.mk
index c05d76e8..8184c30f 100644
--- a/mk/devel.mk
+++ b/mk/devel.mk
@@ -1,2 +1,3 @@
# Useful while doing development, but not for production.
GCCWARN += -Wno-clobbered
+# GCCWARN += -DDEBUG_PORT=0x3f8 -DDEBUG=1
diff --git a/mk/elf.mk b/mk/elf.mk
index 13e2190e..bc83359c 100644
--- a/mk/elf.mk
+++ b/mk/elf.mk
@@ -44,6 +44,7 @@ GCCOPT += $(call gcc_ok,-falign-labels=0,-malign-labels=0)
GCCOPT += $(call gcc_ok,-falign-loops=0,-malign-loops=0)
com32 = $(topdir)/com32
+core = $(topdir)/core
ifneq ($(NOGPL),1)
GPLLIB = $(com32)/gpllib/libcom32gpl.c32
@@ -57,9 +58,9 @@ CFLAGS = $(GCCOPT) -W -Wall \
-fomit-frame-pointer -D__COM32__ -DDYNAMIC_MODULE \
-nostdinc -iwithprefix include \
-I$(com32)/libutil/include -I$(com32)/include \
- -I$(com32)/include/sys $(GPLINCLUDE)
+ -I$(com32)/include/sys $(GPLINCLUDE) -I$(core)/include
SFLAGS = $(GCCOPT) -D__COM32__
-LDFLAGS = -m elf_$(ARCH) -shared --hash-style=gnu -T $(com32)/lib/$(ARCH)/elf.ld
+LDFLAGS = -m elf_$(ARCH) -shared --hash-style=gnu -T $(com32)/lib/$(ARCH)/elf.ld --as-needed
LIBGCC := $(shell $(CC) $(GCCOPT) --print-libgcc)
LNXCFLAGS = -I$(com32)/libutil/include -W -Wall -O -g -D_GNU_SOURCE
@@ -67,7 +68,7 @@ LNXSFLAGS = -g
LNXLDFLAGS = -g
C_LIBS = $(com32)/libutil/libutil_com.c32 $(GPLLIB) \
- $(com32)/lib/libcom32.c32 $(LIBGCC)
+ $(com32)/lib/libcom32.c32
C_LNXLIBS = $(com32)/libutil/libutil_lnx.a \
$(com32)/elflink/ldlinux/ldlinux_lnx.a
@@ -93,5 +94,5 @@ C_LNXLIBS = $(com32)/libutil/libutil_lnx.a \
%.lnx: %.lo $(LNXLIBS) $(C_LNXLIBS)
$(CC) $(LNXCFLAGS) -o $@ $^
-%.c32: %.o
- $(LD) $(LDFLAGS) -o $@ $^
+%.c32: %.o $(LIBS)
+ $(LD) $(LDFLAGS_$^) $(LDFLAGS) -o $@ $^
diff --git a/mk/lib.mk b/mk/lib.mk
index 13022e20..14bb327f 100644
--- a/mk/lib.mk
+++ b/mk/lib.mk
@@ -63,51 +63,41 @@ endif
REQFLAGS += $(EFIINC)
endif
CFLAGS = $(OPTFLAGS) $(REQFLAGS) $(WARNFLAGS) $(LIBFLAGS)
-LDFLAGS = -m elf_$(ARCH) --hash-style=gnu
LIBOTHER_OBJS = \
atoi.o atol.o atoll.o calloc.o creat.o \
- ctypes.o errno.o fgetc.o fgets.o fopen.o fprintf.o fputc.o \
- fclose.o putchar.o setjmp.o \
- fputs.o fread2.o fread.o fwrite2.o fwrite.o \
+ fgets.o fprintf.o fputc.o \
+ putchar.o \
getopt.o getopt_long.o \
- lrand48.o stack.o memccpy.o memchr.o memcmp.o \
- memcpy.o mempcpy.o memmem.o memmove.o memset.o memswap.o \
- perror.o printf.o puts.o qsort.o seed48.o snprintf.o \
- sprintf.o srand48.o sscanf.o strcasecmp.o strcat.o \
- strchr.o strcmp.o strcpy.o strdup.o strerror.o strlen.o \
+ lrand48.o stack.o memccpy.o memchr.o \
+ mempcpy.o memmem.o memmove.o memswap.o \
+ perror.o qsort.o seed48.o \
+ srand48.o sscanf.o strcasecmp.o strcat.o \
+ strerror.o \
strnlen.o \
- strncat.o strncmp.o strncpy.o strndup.o \
- strncasecmp.o \
- stpcpy.o stpncpy.o \
- strntoimax.o strntoumax.o strrchr.o strsep.o strspn.o strstr.o \
+ strncat.o strndup.o \
+ stpncpy.o \
+ strntoimax.o strntoumax.o strsep.o strspn.o strstr.o \
strtoimax.o strtok.o strtol.o strtoll.o strtoul.o strtoull.o \
- strtoumax.o vfprintf.o vprintf.o vsnprintf.o vsprintf.o \
- asprintf.o vasprintf.o strlcpy.o strlcat.o \
+ strtoumax.o vprintf.o vsprintf.o \
+ asprintf.o vasprintf.o \
vsscanf.o \
skipspace.o \
chrreplace.o \
bufprintf.o \
- inet.o \
- \
- lmalloc.o lstrdup.o \
- \
- dprintf.o vdprintf.o \
+ inet.o dhcppack.o dhcpunpack.o \
+ strreplace.o \
+ lstrdup.o \
\
suffix_number.o \
\
getcwd.o fdopendir.o \
\
- libgcc/__ashldi3.o libgcc/__udivdi3.o \
- libgcc/__negdi2.o libgcc/__ashrdi3.o libgcc/__lshrdi3.o \
- libgcc/__muldi3.o libgcc/__udivmoddi4.o libgcc/__umoddi3.o \
- libgcc/__divdi3.o libgcc/__moddi3.o \
- \
- sys/openconsole.o sys/line_input.o \
+ sys/line_input.o \
sys/colortable.o sys/screensize.o \
\
sys/stdcon_read.o sys/stdcon_write.o sys/rawcon_read.o \
- sys/rawcon_write.o sys/err_read.o sys/err_write.o \
+ sys/rawcon_write.o \
sys/null_read.o sys/null_write.o sys/serial_write.o \
\
sys/xserial_write.o \
@@ -121,8 +111,9 @@ LIBOTHER_OBJS = \
pci/writeb.o pci/writew.o pci/writel.o \
\
sys/x86_init_fpu.o math/pow.o math/strtod.o \
+ syslinux/disk.o \
\
- syslinux/memscan.o
+ syslinux/setup_data.o
## CORE OBJECTS, INCLUDED IN THE ROOT COM32 MODULE
LIBENTRY_OBJS = \
@@ -133,6 +124,8 @@ LIBENTRY_OBJS = \
sys/openmem.o \
sys/isatty.o sys/fstat.o \
\
+ dprintf.o vdprintf.o \
+ \
syslinux/idle.o \
\
exit.o
@@ -148,9 +141,9 @@ LIBCONSOLE_OBJS = \
sys/openconsole.o sys/line_input.o \
sys/colortable.o sys/screensize.o \
\
- sys/stdcon_read.o sys/stdcon_write.o sys/rawcon_read.o \
- sys/rawcon_write.o sys/err_read.o sys/err_write.o \
- sys/null_read.o sys/null_write.o sys/serial_write.o \
+ sys/stdcon_read.o sys/rawcon_read.o \
+ sys/rawcon_write.o \
+ sys/null_write.o sys/serial_write.o \
\
sys/xserial_write.o \
\
@@ -176,7 +169,7 @@ LIBLOAD_OBJS = \
syslinux/initramfs_archive.o
LIBMODULE_OBJS = \
- sys/module/$(ARCH)/common.o sys/module/$(ARCH)/elf_module.o \
+ sys/module/common.o sys/module/$(ARCH)/elf_module.o \
sys/module/$(ARCH)/shallow_module.o sys/module/elfutils.o \
sys/module/exec.o
@@ -188,15 +181,33 @@ LIBZLIB_OBJS = \
sys/zfile.o sys/zfopen.o
MINLIBOBJS = \
+ syslinux/ipappend.o \
+ syslinux/dsinfo.o \
$(LIBOTHER_OBJS) \
- $(LIBENTRY_OBJS) \
$(LIBGCC_OBJS) \
$(LIBCONSOLE_OBJS) \
$(LIBLOAD_OBJS) \
- $(LIBMODULE_OBJS) \
$(LIBZLIB_OBJS)
# $(LIBVESA_OBJS)
+CORELIBOBJS = \
+ memcpy.o memset.o memcmp.o printf.o strncmp.o vfprintf.o \
+ strlen.o vsnprintf.o snprintf.o stpcpy.o strcmp.o strdup.o \
+ strcpy.o strncpy.o setjmp.o fopen.o fread.o fread2.o puts.o \
+ sprintf.o strlcat.o strchr.o strlcpy.o strncasecmp.o ctypes.o \
+ fputs.o fwrite2.o fwrite.o fgetc.o fclose.o errno.o lmalloc.o \
+ sys/err_read.o sys/err_write.o sys/null_read.o \
+ sys/stdcon_write.o sys/openconsole.o \
+ syslinux/memscan.o strrchr.o \
+ libgcc/__ashldi3.o libgcc/__udivdi3.o \
+ libgcc/__negdi2.o libgcc/__ashrdi3.o libgcc/__lshrdi3.o \
+ libgcc/__muldi3.o libgcc/__udivmoddi4.o libgcc/__umoddi3.o \
+ libgcc/__divdi3.o libgcc/__moddi3.o \
+ $(LIBENTRY_OBJS) \
+ $(LIBMODULE_OBJS)
+
+LDFLAGS = -m elf_$(ARCH) --hash-style=gnu -T $(com32)/lib/$(ARCH)/elf.ld
+
.SUFFIXES: .c .o .a .so .lo .i .S .s .ls .ss .lss
% : %.c # Cancel default rule
diff --git a/mk/syslinux.mk b/mk/syslinux.mk
index 2367af62..cab80102 100644
--- a/mk/syslinux.mk
+++ b/mk/syslinux.mk
@@ -54,7 +54,9 @@ STRIP = strip
AR = ar
NM = nm
RANLIB = ranlib
+STRIP = strip
GZIPPROG = gzip
+XZ = xz
PNGTOPNM = pngtopnm
MCOPY = mcopy
MFORMAT = mformat
@@ -84,7 +86,7 @@ UMAKEDEPS = -Wp,-MT,$@,-MMD,$(dir $@).$(notdir $@).d
# Items that are only appropriate during development; this file is
# removed when tarballs are generated.
--include $(makefiledir)/devel.mk
+-include $(MAKEDIR)/devel.mk
# Local additions, like -DDEBUG can go here
--include $(makefiledir)/local.mk
+-include $(MAKEDIR)/local.mk
diff --git a/mtools/Makefile b/mtools/Makefile
index 04e9d7de..78cea1e2 100755
--- a/mtools/Makefile
+++ b/mtools/Makefile
@@ -5,10 +5,10 @@ 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 \
@@ -37,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/utils/Makefile b/utils/Makefile
index eed07bba..be739935 100644
--- a/utils/Makefile
+++ b/utils/Makefile
@@ -19,12 +19,15 @@ 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
@@ -48,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 $@ $^
@@ -70,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..ac04bfd4 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 & 0x00000000000000FF) << 56 | (s & 0xFF00000000000000) >> 56
+ | (s & 0x000000000000FF00) << 40 | (s & 0x00FF000000000000) >> 40
+ | (s & 0x0000000000FF0000) << 24 | (s & 0x0000FF0000000000) >> 24
+ | (s & 0x00000000FF000000) << 8 | (s & 0x000000FF00000000) >> 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(0x5452415020494645);
+ 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/version b/version
index 3ef663b0..65698a3d 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-5.00 2010
+5.00 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