summaryrefslogtreecommitdiffstats
path: root/contrib/syslinux-4.02/core
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/syslinux-4.02/core')
-rw-r--r--contrib/syslinux-4.02/core/Makefile137
-rw-r--r--contrib/syslinux-4.02/core/abort.inc84
-rw-r--r--contrib/syslinux-4.02/core/adv.inc509
-rw-r--r--contrib/syslinux-4.02/core/bcopy32.inc75
-rw-r--r--contrib/syslinux-4.02/core/bcopyxx.inc318
-rw-r--r--contrib/syslinux-4.02/core/bios.inc45
-rw-r--r--contrib/syslinux-4.02/core/bootsect.inc237
-rw-r--r--contrib/syslinux-4.02/core/call16.c41
-rw-r--r--contrib/syslinux-4.02/core/callback.inc215
-rw-r--r--contrib/syslinux-4.02/core/cleanup.inc60
-rw-r--r--contrib/syslinux-4.02/core/cmdline.inc101
-rw-r--r--contrib/syslinux-4.02/core/codepage.S5
-rw-r--r--contrib/syslinux-4.02/core/com32.inc145
-rw-r--r--contrib/syslinux-4.02/core/comboot.inc1010
-rw-r--r--contrib/syslinux-4.02/core/common.inc25
-rw-r--r--contrib/syslinux-4.02/core/config.inc45
-rw-r--r--contrib/syslinux-4.02/core/configinit.inc51
-rw-r--r--contrib/syslinux-4.02/core/conio.inc431
-rw-r--r--contrib/syslinux-4.02/core/console.c22
-rw-r--r--contrib/syslinux-4.02/core/diskfs.inc173
-rw-r--r--contrib/syslinux-4.02/core/diskstart.inc874
-rw-r--r--contrib/syslinux-4.02/core/extern.inc32
-rw-r--r--contrib/syslinux-4.02/core/font.inc152
-rw-r--r--contrib/syslinux-4.02/core/fs/btrfs/btrfs.c674
-rw-r--r--contrib/syslinux-4.02/core/fs/btrfs/btrfs.h292
-rw-r--r--contrib/syslinux-4.02/core/fs/btrfs/crc32c.h50
-rw-r--r--contrib/syslinux-4.02/core/fs/cache.c125
-rw-r--r--contrib/syslinux-4.02/core/fs/chdir.c103
-rw-r--r--contrib/syslinux-4.02/core/fs/diskio.c418
-rw-r--r--contrib/syslinux-4.02/core/fs/ext2/bmap.c228
-rw-r--r--contrib/syslinux-4.02/core/fs/ext2/ext2.c335
-rw-r--r--contrib/syslinux-4.02/core/fs/ext2/ext2_fs.h310
-rw-r--r--contrib/syslinux-4.02/core/fs/fat/fat.c795
-rw-r--r--contrib/syslinux-4.02/core/fs/fat/fat_fs.h158
-rw-r--r--contrib/syslinux-4.02/core/fs/fs.c475
-rw-r--r--contrib/syslinux-4.02/core/fs/getcwd.c13
-rw-r--r--contrib/syslinux-4.02/core/fs/getfssec.c194
-rw-r--r--contrib/syslinux-4.02/core/fs/iso9660/iso9660.c346
-rw-r--r--contrib/syslinux-4.02/core/fs/iso9660/iso9660_fs.h51
-rw-r--r--contrib/syslinux-4.02/core/fs/lib/close.c9
-rw-r--r--contrib/syslinux-4.02/core/fs/lib/loadconfig.c34
-rw-r--r--contrib/syslinux-4.02/core/fs/lib/mangle.c47
-rw-r--r--contrib/syslinux-4.02/core/fs/lib/searchconfig.c40
-rw-r--r--contrib/syslinux-4.02/core/fs/loadhigh.c113
-rw-r--r--contrib/syslinux-4.02/core/fs/newconfig.c41
-rw-r--r--contrib/syslinux-4.02/core/fs/nonextextent.c13
-rw-r--r--contrib/syslinux-4.02/core/fs/pxe/dhcp_option.c258
-rw-r--r--contrib/syslinux-4.02/core/fs/pxe/dnsresolv.c349
-rw-r--r--contrib/syslinux-4.02/core/fs/pxe/idle.c112
-rw-r--r--contrib/syslinux-4.02/core/fs/pxe/portnum.c68
-rw-r--r--contrib/syslinux-4.02/core/fs/pxe/pxe.c1731
-rw-r--r--contrib/syslinux-4.02/core/fs/pxe/pxe.h252
-rw-r--r--contrib/syslinux-4.02/core/fs/readdir.c57
-rwxr-xr-xcontrib/syslinux-4.02/core/genhash.pl26
-rw-r--r--contrib/syslinux-4.02/core/getc.inc415
-rw-r--r--contrib/syslinux-4.02/core/graphics.inc353
-rw-r--r--contrib/syslinux-4.02/core/head.inc38
-rw-r--r--contrib/syslinux-4.02/core/highmem.inc158
-rw-r--r--contrib/syslinux-4.02/core/idle.c49
-rw-r--r--contrib/syslinux-4.02/core/idle.inc81
-rw-r--r--contrib/syslinux-4.02/core/include/cache.h23
-rw-r--r--contrib/syslinux-4.02/core/include/codepage.h27
-rw-r--r--contrib/syslinux-4.02/core/include/core.h78
-rw-r--r--contrib/syslinux-4.02/core/include/ctype.h25
-rw-r--r--contrib/syslinux-4.02/core/include/disk.h37
-rw-r--r--contrib/syslinux-4.02/core/include/fs.h227
-rw-r--r--contrib/syslinux-4.02/core/include/pmapi.h8
-rw-r--r--contrib/syslinux-4.02/core/init.inc133
-rw-r--r--contrib/syslinux-4.02/core/io.inc35
-rw-r--r--contrib/syslinux-4.02/core/isolinux-debug.asm2
-rw-r--r--contrib/syslinux-4.02/core/isolinux.asm1383
-rw-r--r--contrib/syslinux-4.02/core/kaboom.c16
-rw-r--r--contrib/syslinux-4.02/core/kernel.inc118
-rw-r--r--contrib/syslinux-4.02/core/keywords48
-rw-r--r--contrib/syslinux-4.02/core/keywords.inc101
-rw-r--r--contrib/syslinux-4.02/core/layout.inc171
-rw-r--r--contrib/syslinux-4.02/core/ldlinux.asm44
-rw-r--r--contrib/syslinux-4.02/core/loadhigh.inc60
-rw-r--r--contrib/syslinux-4.02/core/localboot.inc76
-rwxr-xr-xcontrib/syslinux-4.02/core/lstadjust.pl57
-rw-r--r--contrib/syslinux-4.02/core/lzo/enter.ash89
-rw-r--r--contrib/syslinux-4.02/core/lzo/leave.ash114
-rw-r--r--contrib/syslinux-4.02/core/lzo/lzo1c_d.ash184
-rw-r--r--contrib/syslinux-4.02/core/lzo/lzo1f_d.ash176
-rw-r--r--contrib/syslinux-4.02/core/lzo/lzo1x_d.ash401
-rw-r--r--contrib/syslinux-4.02/core/lzo/lzo1x_f1.S63
-rw-r--r--contrib/syslinux-4.02/core/lzo/lzo_asm.h287
-rw-r--r--contrib/syslinux-4.02/core/macros.inc116
-rw-r--r--contrib/syslinux-4.02/core/mem/free.c154
-rw-r--r--contrib/syslinux-4.02/core/mem/init.c38
-rw-r--r--contrib/syslinux-4.02/core/mem/malloc.c99
-rw-r--r--contrib/syslinux-4.02/core/mem/malloc.h82
-rw-r--r--contrib/syslinux-4.02/core/parsecmd.inc129
-rw-r--r--contrib/syslinux-4.02/core/parseconfig.inc475
-rw-r--r--contrib/syslinux-4.02/core/plaincon.inc24
-rw-r--r--contrib/syslinux-4.02/core/pm.inc450
-rw-r--r--contrib/syslinux-4.02/core/pmapi.c43
-rw-r--r--contrib/syslinux-4.02/core/pmcall.inc70
-rw-r--r--contrib/syslinux-4.02/core/prefix.inc17
-rw-r--r--contrib/syslinux-4.02/core/printf.c20
-rw-r--r--contrib/syslinux-4.02/core/pxe.inc155
-rw-r--r--contrib/syslinux-4.02/core/pxelinux.asm544
-rw-r--r--contrib/syslinux-4.02/core/rawcon.inc75
-rw-r--r--contrib/syslinux-4.02/core/regdump.inc108
-rw-r--r--contrib/syslinux-4.02/core/rllpack.c105
-rw-r--r--contrib/syslinux-4.02/core/runkernel.inc684
-rw-r--r--contrib/syslinux-4.02/core/serirq.inc219
-rw-r--r--contrib/syslinux-4.02/core/stack.inc47
-rw-r--r--contrib/syslinux-4.02/core/strcasecmp.c11
-rw-r--r--contrib/syslinux-4.02/core/strcpy.inc13
-rw-r--r--contrib/syslinux-4.02/core/strncasecmp.c24
-rw-r--r--contrib/syslinux-4.02/core/syslinux.ld380
-rw-r--r--contrib/syslinux-4.02/core/timer.inc57
-rw-r--r--contrib/syslinux-4.02/core/tracers.inc40
-rw-r--r--contrib/syslinux-4.02/core/ui.inc748
-rw-r--r--contrib/syslinux-4.02/core/writedec.inc57
-rw-r--r--contrib/syslinux-4.02/core/writehex.inc52
-rw-r--r--contrib/syslinux-4.02/core/writestr.inc47
118 files changed, 22664 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/core/Makefile b/contrib/syslinux-4.02/core/Makefile
new file mode 100644
index 0000000..1330fb9
--- /dev/null
+++ b/contrib/syslinux-4.02/core/Makefile
@@ -0,0 +1,137 @@
+## -----------------------------------------------------------------------
+##
+## Copyright 1998-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.
+##
+## -----------------------------------------------------------------------
+
+#
+# Makefile for the SYSLINUX core
+#
+
+# No builtin rules
+MAKEFLAGS += -r
+MAKE += -r
+
+topdir = ..
+include $(topdir)/MCONFIG.embedded
+-include $(topdir)/version.mk
+
+OPTFLAGS =
+INCLUDES = -I./include -I$(com32)/include
+
+# This is very similar to cp437; technically it's for Norway and Denmark,
+# but it's unlikely the characters that are different will be used in
+# filenames by other users.
+CODEPAGE = cp865
+
+# The targets to build in this directory...
+BTARGET = kwdhash.gen \
+ ldlinux.bss ldlinux.sys ldlinux.bin \
+ isolinux.bin isolinux-debug.bin pxelinux.0
+
+# All primary source files for the main syslinux files
+NASMSRC := $(wildcard *.asm)
+NASMHDR := $(wildcard *.inc)
+CSRC := $(wildcard *.c */*.c */*/*.c)
+SSRC := $(wildcard *.S */*.S */*/*.S)
+CHDR := $(wildcard *.h)
+OTHERSRC := keywords
+ALLSRC = $(NASMSRC) $(NASMHDR) $(CSRC) $(SSRC) $(CHDR) $(OTHERSRC)
+
+COBJ := $(patsubst %.c,%.o,$(CSRC))
+SOBJ := $(patsubst %.S,%.o,$(SSRC))
+
+LIB = libcore.a
+LIBS = $(LIB) $(com32)/lib/libcomcore.a $(LIBGCC)
+LIBOBJS = $(COBJ) $(SOBJ)
+
+NASMDEBUG = -g -F dwarf
+NASMOPT += $(NASMDEBUG)
+
+PREPCORE = ../lzo/prepcore
+
+# CFLAGS += -DDEBUG=1
+
+# The DATE is set on the make command line when building binaries for
+# official release. Otherwise, substitute a hex string that is pretty much
+# guaranteed to be unique to be unique from build to build.
+ifndef HEXDATE
+HEXDATE := $(shell $(PERL) ../now.pl $(SRCS))
+endif
+ifndef DATE
+DATE := $(shell sh ../gen-id.sh $(VERSION) $(HEXDATE))
+endif
+
+all: $(BTARGET)
+
+kwdhash.gen: keywords genhash.pl
+ $(PERL) genhash.pl < keywords > kwdhash.gen
+
+.PRECIOUS: %.elf
+
+%.raw: %.elf
+ $(OBJCOPY) -O binary $< $(@:.bin=.raw)
+
+%.bin: %.raw $(PREPCORE)
+ $(PREPCORE) $< $@
+
+%.o: %.asm kwdhash.gen ../version.gen
+ $(NASM) -f elf $(NASMOPT) -DDATE_STR="'$(DATE)'" \
+ -DHEXDATE="$(HEXDATE)" \
+ -l $(@:.o=.lsr) -o $@ -MP -MD .$@.d $<
+
+%.elf: %.o $(LIBS) syslinux.ld
+ $(LD) $(LDFLAGS) -T syslinux.ld -M -o $@ $< \
+ --start-group $(LIBS) --end-group \
+ > $(@:.elf=.map)
+ $(OBJDUMP) -h $@ > $(@:.elf=.sec)
+ $(PERL) lstadjust.pl $(@:.elf=.lsr) $(@:.elf=.sec) $(@:.elf=.lst)
+
+$(LIB): $(LIBOBJS)
+ rm -f $@
+ $(AR) cq $@ $^
+ $(RANLIB) $@
+
+pxelinux.0: pxelinux.bin
+ cp -f $< $@
+
+ldlinux.bss: ldlinux.bin
+ dd if=$< of=$@ bs=512 count=1
+
+ldlinux.sys: ldlinux.bin
+ dd if=$< of=$@ bs=512 skip=1
+
+codepage.cp: ../codepage/$(CODEPAGE).cp
+ cp -f $< $@
+
+codepage.o: codepage.S codepage.cp
+
+install: installer
+
+install-lib: installer
+
+install-all: install install-lib
+
+netinstall: installer
+
+tidy dist:
+ rm -f codepage.cp *.o *.elf *.a stupid.* patch.offset .depend .*.d
+ rm -f *.elf.tmp *.sym
+ rm -f *.lsr *.lst *.map *.sec *.raw
+ rm -f */*.o */*/*.o */*.lst */*/*.lst */.*.d */*/.*.d
+ rm -f $(OBSOLETE) $(LIB)
+
+clean: tidy
+
+spotless: clean
+ rm -f $(BTARGET) *.bin *_bin.c
+
+# Include dependencies file
+-include .*.d */.*.d */*/.*.d
diff --git a/contrib/syslinux-4.02/core/abort.inc b/contrib/syslinux-4.02/core/abort.inc
new file mode 100644
index 0000000..9b18136
--- /dev/null
+++ b/contrib/syslinux-4.02/core/abort.inc
@@ -0,0 +1,84 @@
+; -----------------------------------------------------------------------
+;
+; Copyright 2005-2009 H. Peter Anvin - All Rights Reserved
+; Copyright 2009 Intel Corporation; author: H. Peter Anvin
+;
+; This program is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+; Boston MA 02111-1307, USA; either version 2 of the License, or
+; (at your option) any later version; incorporated herein by reference.
+;
+; -----------------------------------------------------------------------
+
+;
+; abort.inc
+;
+; Code to terminate a kernel load
+;
+
+ section .text16
+
+;
+; dot_pause: same as abort_check, except prints a dot, too
+; assumes CS == DS
+;
+dot_pause:
+ push si
+ mov si,dot_msg
+ call writestr_qchk
+ pop si
+ ; fall through
+
+;
+; abort_check: let the user abort with <ESC> or <Ctrl-C>
+;
+abort_check:
+ call reset_idle ; Not idle despite pollchar
+ call pollchar
+ jz .ret1
+ pusha
+ call getchar
+ cmp al,27 ; <ESC>
+ je .kill
+ cmp al,3 ; <Ctrl-C>
+ je .kill
+.ret2: popa
+.ret1: ret
+
+.kill: mov si,aborted_msg
+ mov bx,enter_command
+ jmp abort_load_chain
+
+;
+; abort_load: Called by various routines which wants to print a fatal
+; error message and return to the command prompt. Since this
+; may happen at just about any stage of the boot process, assume
+; our state is messed up, and just reset the segment registers
+; and the stack forcibly.
+;
+; SI = offset (in _text) of error message to print
+; BX = future entry point (abort_load_chain)
+;
+abort_load:
+ mov bx,error_or_command
+abort_load_chain:
+ RESET_STACK_AND_SEGS AX
+ call writestr ; Expects SI -> error msg
+
+ ; Return to the command prompt
+ jmp bx
+
+;
+; error_or_command: Execute ONERROR if appropriate, otherwise enter_command
+;
+error_or_command:
+ mov cx,[OnerrorLen]
+ and cx,cx
+ jnz on_error
+ jmp enter_command
+
+ section .data16
+aborted_msg db ' aborted.', CR, LF, 0
+
+ section .text16
diff --git a/contrib/syslinux-4.02/core/adv.inc b/contrib/syslinux-4.02/core/adv.inc
new file mode 100644
index 0000000..0b45a6c
--- /dev/null
+++ b/contrib/syslinux-4.02/core/adv.inc
@@ -0,0 +1,509 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 2007-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.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; adv.inc
+;;
+;; The auxillary data vector and its routines
+;;
+;; The auxillary data vector is a 512-byte aligned block that on the
+;; disk-based derivatives can be part of the syslinux file itself. It
+;; exists in two copies; when written, both copies are written (with a
+;; sync in between, if from the operating system.) The first two
+;; dwords are magic number and inverse checksum, then follows the data
+;; area as a tagged array similar to BOOTP/DHCP, finally a tail
+;; signature.
+;;
+;; Note that unlike BOOTP/DHCP, zero terminates the chain, and FF
+;; has no special meaning.
+;;
+
+;;
+;; List of ADV tags...
+;;
+ADV_BOOTONCE equ 1
+
+;;
+;; Other ADV data...
+;;
+ADV_MAGIC1 equ 0x5a2d2fa5 ; Head signature
+ADV_MAGIC2 equ 0xa3041767 ; Total checksum
+ADV_MAGIC3 equ 0xdd28bf64 ; Tail signature
+
+ADV_LEN equ 500 ; Data bytes
+
+adv_retries equ 6 ; Disk retries
+
+ section .adv
+ ; Introduce the ADVs to valid but blank
+adv0:
+.head resd 1
+.csum resd 1
+.data resb ADV_LEN
+.tail resd 1
+.end equ $
+adv1:
+.head resd 1
+.csum resd 1
+.data resb ADV_LEN
+.tail resd 1
+.end equ $
+ section .text16
+
+ ;
+ ; This is called after config file parsing, so we know
+ ; the intended location of the ADV
+ ;
+adv_init:
+ cmp byte [ADVDrive],-1
+ jne adv_read
+
+%if IS_SYSLINUX || IS_EXTLINUX
+ cmp word [ADVSectors],2 ; Not present?
+ jb adv_verify
+
+ mov eax,[Hidden]
+ mov edx,[Hidden+4]
+ add [ADVSec0],eax
+ adc [ADVSec0+4],edx
+ add [ADVSec1],eax
+ adc [ADVSec1+4],edx
+ mov al,[DriveNumber]
+ mov [ADVDrive],al
+ jmp adv_read
+%endif
+
+ ;
+ ; Initialize the ADV data structure in memory
+ ;
+adv_verify:
+ cmp byte [ADVDrive],-1 ; No ADV configured, still?
+ je .reset ; Then unconditionally reset
+
+ mov si,adv0
+ call .check_adv
+ jz .ok ; Primary ADV okay
+ mov si,adv1
+ call .check_adv
+ jz .adv1ok
+
+ ; Neither ADV is usable; initialize to blank
+.reset:
+ mov di,adv0
+ mov eax,ADV_MAGIC1
+ stosd
+ mov eax,ADV_MAGIC2
+ stosd
+ xor eax,eax
+ mov cx,ADV_LEN/4
+ rep stosd
+ mov eax,ADV_MAGIC3
+ stosd
+
+.ok:
+ ret
+
+ ; The primary ADV is bad, but the backup is OK
+.adv1ok:
+ mov di,adv0
+ mov cx,512/4
+ rep movsd
+ ret
+
+
+ ; SI points to the putative ADV; unchanged by routine
+ ; ZF=1 on return if good
+.check_adv:
+ push si
+ lodsd
+ cmp eax,ADV_MAGIC1
+ jne .done ; ZF=0, i.e. bad
+ xor edx,edx
+ mov cx,ADV_LEN/4+1 ; Remaining dwords
+.csum:
+ lodsd
+ add edx,eax
+ loop .csum
+ cmp edx,ADV_MAGIC2
+ jne .done
+ lodsd
+ cmp eax,ADV_MAGIC3
+.done:
+ pop si
+ ret
+
+;
+; adv_get: find an ADV string if present
+;
+; Input: DL = ADV ID
+; Output: CX = byte count (zero on not found)
+; SI = pointer to data
+; DL = unchanged
+;
+; Assumes CS == DS.
+;
+
+adv_get:
+ push ax
+ mov si,adv0.data
+ xor ax,ax ; Keep AH=0 at all times
+.loop:
+ lodsb ; Read ID
+ cmp al,dl
+ je .found
+ and al,al
+ jz .end
+ lodsb ; Read length
+ add si,ax
+ cmp si,adv0.tail
+ jb .loop
+ jmp .end
+
+.found:
+ lodsb
+ mov cx,ax
+ add ax,si ; Make sure it fits
+ cmp ax,adv0.tail
+ jbe .ok
+.end:
+ xor cx,cx
+.ok:
+ pop ax
+ ret
+
+;
+; adv_set: insert a string into the ADV in memory
+;
+; Input: DL = ADV ID
+; FS:BX = input buffer
+; CX = byte count (max = 255!)
+; Output: CF=1 on error
+; CX clobbered
+;
+; Assumes CS == DS == ES.
+;
+adv_set:
+ push ax
+ push si
+ push di
+ and ch,ch
+ jnz .overflow
+
+ push cx
+ mov si,adv0.data
+ xor ax,ax
+.loop:
+ lodsb
+ cmp al,dl
+ je .found
+ and al,al
+ jz .endz
+ lodsb
+ add si,ax
+ cmp si,adv0.tail
+ jb .loop
+ jmp .end
+
+.found: ; Found, need to delete old copy
+ lodsb
+ lea di,[si-2]
+ push di
+ add si,ax
+ mov cx,adv0.tail
+ sub cx,si
+ jb .nukeit
+ rep movsb ; Remove the old one
+ mov [di],ah ; Termination zero
+ pop si
+ jmp .loop
+.nukeit:
+ pop si
+ jmp .end
+.endz:
+ dec si
+.end:
+ ; Now SI points to where we want to put our data
+ pop cx
+ mov di,si
+ jcxz .empty
+ add si,cx
+ cmp si,adv0.tail-2
+ jae .overflow ; CF=0
+
+ mov si,bx
+ mov al,dl
+ stosb
+ mov al,cl
+ stosb
+ fs rep movsb
+
+.empty:
+ mov cx,adv0.tail
+ sub cx,di
+ xor ax,ax
+ rep stosb ; Zero-fill remainder
+
+ clc
+.done:
+ pop di
+ pop si
+ pop ax
+ ret
+.overflow:
+ stc
+ jmp .done
+
+;
+; adv_cleanup: checksum adv0 and copy to adv1
+; Assumes CS == DS == ES.
+;
+adv_cleanup:
+ pushad
+ mov si,adv0.data
+ mov cx,ADV_LEN/4
+ xor edx,edx
+.loop:
+ lodsd
+ add edx,eax
+ loop .loop
+ mov eax,ADV_MAGIC2
+ sub eax,edx
+ lea di,[si+4] ; adv1
+ mov si,adv0
+ mov [si+4],eax ; Store checksum
+ mov cx,(ADV_LEN+12)/4
+ rep movsd
+ popad
+ ret
+
+;
+; adv_write: write the ADV to disk.
+;
+; Location is in memory variables.
+; Assumes CS == DS == ES.
+;
+; Returns CF=1 if the ADV cannot be written.
+;
+adv_write:
+ push eax
+ mov eax,[ADVSec0]
+ or eax,[ADVSec0+4]
+ je .bad
+ mov eax,[ADVSec1]
+ or eax,[ADVSec1+4]
+ je .bad
+ cmp byte [ADVDrive],-1
+ je .bad
+
+ call adv_cleanup
+ mov ah,3 ; Write
+ call adv_read_write
+
+ clc
+ pop eax
+ ret
+.bad: ; No location for ADV set
+ stc
+ pop eax
+ ret
+
+;
+; adv_read: read the ADV from disk
+;
+; Location is in memory variables.
+; Assumes CS == DS == ES.
+;
+adv_read:
+ push ax
+ mov ah,2 ; Read
+ call adv_read_write
+ call adv_verify
+ pop ax
+ ret
+
+;
+; adv_read_write: disk I/O for the ADV
+;
+; On input, AH=2 for read, AH=3 for write.
+; Assumes CS == DS == ES.
+;
+adv_read_write:
+ mov [ADVOp],ah
+ pushad
+
+ ; Check for EDD
+ mov bx,55AAh
+ mov ah,41h ; EDD existence query
+ mov dl,[ADVDrive]
+ int 13h
+ mov si,.cbios
+ jc .noedd
+ cmp bx,0AA55h
+ jne .noedd
+ test cl,1
+ jz .noedd
+ mov si,.ebios
+.noedd:
+
+ mov eax,[ADVSec0]
+ mov edx,[ADVSec0+4]
+ mov bx,adv0
+ call .doone
+
+ mov eax,[ADVSec1]
+ mov edx,[ADVSec1+4]
+ mov bx,adv1
+ call .doone
+
+ popad
+ ret
+
+.doone:
+ push si
+ jmp si
+
+.ebios:
+ mov cx,adv_retries
+.eb_retry:
+ ; Form DAPA on stack
+ push edx
+ push eax
+ push es
+ push bx
+ push word 1 ; Sector count
+ push word 16 ; DAPA size
+ mov si,sp
+ pushad
+ mov dl,[ADVDrive]
+ mov ax,4000h
+ or ah,[ADVOp]
+ push ds
+ push ss
+ pop ds
+ int 13h
+ pop ds
+ popad
+ lea sp,[si+16] ; Remove DAPA
+ jc .eb_error
+ pop si
+ ret
+.eb_error:
+ loop .eb_retry
+ stc
+ pop si
+ ret
+
+.cbios:
+ push edx
+ push eax
+ push bp
+
+ and edx,edx ; > 2 TiB not possible
+ jnz .cb_overflow
+
+ mov dl,[ADVDrive]
+ and dl,dl
+ ; Floppies: can't trust INT 13h 08h, we better know
+ ; the geometry a priori, which means it better be our
+ ; boot device...
+ jns .noparm ; Floppy drive... urk
+
+ mov ah,08h ; Get disk parameters
+ int 13h
+ jc .noparm
+ and ah,ah
+ jnz .noparm
+ shr dx,8
+ inc dx
+ movzx edi,dx ; EDI = heads
+ and cx,3fh
+ movzx esi,cx ; ESI = sectors/track
+ jmp .parmok
+
+.noparm:
+ ; No CHS info... this better be our boot drive, then
+%if IS_SYSLINUX || IS_EXTLINUX
+ cmp dl,[DriveNumber]
+ jne .cb_overflow ; Fatal error!
+ movzx esi,word [bsSecPerTrack]
+ movzx edi,word [bsHeads]
+%else
+ ; Not a disk-based derivative... there is no hope
+ jmp .cb_overflow
+%endif
+
+.parmok:
+ ;
+ ; Dividing by sectors to get (track,sector): we may have
+ ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
+ ;
+ xor edx,edx
+ div esi
+ xor cx,cx
+ xchg cx,dx ; CX <- sector index (0-based)
+ ; EDX <- 0
+ ; eax = track #
+ div edi ; Convert track to head/cyl
+
+ ; Watch out for overflow, we might be writing!
+ cmp eax,1023
+ ja .cb_overflow
+
+ ;
+ ; Now we have AX = cyl, DX = head, CX = sector (0-based),
+ ; BP = sectors to transfer, SI = bsSecPerTrack,
+ ; ES:BX = data target
+ ;
+
+ shl ah,6 ; Because IBM was STOOPID
+ ; and thought 8 bits were enough
+ ; then thought 10 bits were enough...
+ inc cx ; Sector numbers are 1-based, sigh
+ or cl,ah
+ mov ch,al
+ mov dh,dl
+ mov dl,[ADVDrive]
+ mov al,01h ; Transfer one sector
+ mov ah,[ADVOp] ; Operation
+
+ mov bp,adv_retries
+.cb_retry:
+ pushad
+ int 13h
+ popad
+ jc .cb_error
+
+.cb_done:
+ pop bp
+ pop eax
+ pop edx
+ pop si
+ ret
+
+.cb_error:
+ dec bp
+ jnz .cb_retry
+.cb_overflow:
+ stc
+ jmp .cb_done
+
+ section .data16
+ alignz 8
+ADVSec0 dq 0 ; Not specified
+ADVSec1 dq 0 ; Not specified
+ADVDrive db -1 ; No ADV defined
+ADVCHSInfo db -1 ; We have CHS info for this drive
+
+ section .bss16
+ADVOp resb 1
+
+ section .text16
diff --git a/contrib/syslinux-4.02/core/bcopy32.inc b/contrib/syslinux-4.02/core/bcopy32.inc
new file mode 100644
index 0000000..6537546
--- /dev/null
+++ b/contrib/syslinux-4.02/core/bcopy32.inc
@@ -0,0 +1,75 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
+;; Copyright 2009 Intel Corporation; author: H. Peter Anvin
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+;; Boston MA 02111-1307, USA; either version 2 of the License, or
+;; (at your option) any later version; incorporated herein by reference.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; bcopy32.inc
+;;
+;; 32-bit bcopy routine for real mode
+;;
+
+;
+; 32-bit bcopy routine for real mode
+;
+; We enter protected mode, set up a flat 32-bit environment, run rep movsd
+; and then exit. IMPORTANT: This code assumes cs == 0.
+;
+; This code is probably excessively anal-retentive in its handling of
+; segments, but this stuff is painful enough as it is without having to rely
+; on everything happening "as it ought to."
+;
+
+ bits 16
+ section .text16
+
+;
+; bcopy:
+; 32-bit copy, overlap safe
+;
+; Inputs:
+; ESI - source pointer (-1 means do bzero rather than bcopy)
+; EDI - target pointer
+; ECX - byte count
+;
+; Outputs:
+; ESI - first byte after source (garbage if ESI == -1 on entry)
+; EDI - first byte after target
+;
+bcopy: jecxz .ret
+ pm_call pm_bcopy
+ add edi,ecx
+ add esi,ecx
+.ret: ret
+
+;
+; shuffle_and_boot_raw:
+; The new version of shuffle and boot.
+; Inputs:
+; ESI -> Pointer to list of (dst, src, len) pairs(*)
+; EDI -> Pointer to safe area for list + shuffler
+; (must not overlap this code nor the RM stack)
+; ECX -> Byte count of list area (for initial copy)
+;
+; If src == -1: then the memory pointed to by (dst, len) is bzeroed;
+; this is handled inside the bcopy routine.
+;
+; If len == 0: this marks the end of the list; dst indicates
+; the entry point and src the mode (0 = pm, 1 = rm)
+;
+shuffle_and_boot_raw:
+ mov bx,pm_shuffle
+ jmp enter_pm
+
+;
+; The 32-bit copy and shuffle code is "special", so it is in its own file
+;
+%include "bcopyxx.inc"
diff --git a/contrib/syslinux-4.02/core/bcopyxx.inc b/contrib/syslinux-4.02/core/bcopyxx.inc
new file mode 100644
index 0000000..c669b7a
--- /dev/null
+++ b/contrib/syslinux-4.02/core/bcopyxx.inc
@@ -0,0 +1,318 @@
+;; -----------------------------------------------------------------------
+;;
+;; 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.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; bcopy32xx.inc
+;;
+
+
+;
+; 32-bit bcopy routine
+;
+; This is the actual 32-bit portion of the bcopy and shuffle and boot
+; routines. ALL THIS CODE NEEDS TO BE POSITION-INDEPENDENT, with the
+; sole exception being the actual relocation code at the beginning of
+; pm_shuffle_boot.
+;
+; It also really needs to live all in a single segment, for the
+; address calculcations to actually work.
+;
+
+ bits 32
+ section .bcopyxx.text
+ align 16
+;
+; pm_bcopy:
+;
+; This is the protected-mode core of the "bcopy" routine.
+; Try to do aligned transfers; if the src and dst are relatively
+; misaligned, align the dst.
+;
+; ECX is guaranteed to not be zero on entry.
+;
+; Clobbers ESI, EDI, ECX.
+;
+
+pm_bcopy:
+ push ebx
+ push edx
+ push eax
+
+ cmp esi,-1
+ je .bzero
+
+ cmp esi,edi ; If source < destination, we might
+ jb .reverse ; have to copy backwards
+
+.forward:
+ ; Initial alignment
+ mov edx,edi
+ shr edx,1
+ jnc .faa1
+ movsb
+ dec ecx
+.faa1:
+ mov al,cl
+ cmp ecx,2
+ jb .f_tiny
+
+ shr edx,1
+ jnc .faa2
+ movsw
+ sub ecx,2
+.faa2:
+
+ ; Bulk transfer
+ mov al,cl ; Save low bits
+ shr ecx,2 ; Convert to dwords
+ rep movsd ; Do our business
+ ; At this point ecx == 0
+
+ test al,2
+ jz .fab2
+ movsw
+.fab2:
+.f_tiny:
+ test al,1
+ jz .fab1
+ movsb
+.fab1:
+.done:
+ pop eax
+ pop edx
+ pop ebx
+ ret
+
+.reverse:
+ lea eax,[esi+ecx-1] ; Point to final byte
+ cmp edi,eax
+ ja .forward ; No overlap, do forward copy
+
+ std ; Reverse copy
+ lea edi,[edi+ecx-1]
+ mov esi,eax
+
+ ; Initial alignment
+ mov edx,edi
+ shr edx,1
+ jc .raa1
+ movsb
+ dec ecx
+.raa1:
+
+ dec esi
+ dec edi
+ mov al,cl
+ cmp ecx,2
+ jb .r_tiny
+ shr edx,1
+ jc .raa2
+ movsw
+ sub ecx,2
+.raa2:
+
+ ; Bulk copy
+ sub esi,2
+ sub edi,2
+ mov al,cl ; Save low bits
+ shr ecx,2
+ rep movsd
+
+ ; Final alignment
+.r_final:
+ add esi,2
+ add edi,2
+ test al,2
+ jz .rab2
+ movsw
+.rab2:
+.r_tiny:
+ inc esi
+ inc edi
+ test al,1
+ jz .rab1
+ movsb
+.rab1:
+ cld
+ jmp short .done
+
+.bzero:
+ xor eax,eax
+
+ ; Initial alignment
+ mov edx,edi
+ shr edx,1
+ jnc .zaa1
+ stosb
+ dec ecx
+.zaa1:
+
+ mov bl,cl
+ cmp ecx,2
+ jb .z_tiny
+ shr edx,1
+ jnc .zaa2
+ stosw
+ sub ecx,2
+.zaa2:
+
+ ; Bulk
+ mov bl,cl ; Save low bits
+ shr ecx,2
+ rep stosd
+
+ test bl,2
+ jz .zab2
+ stosw
+.zab2:
+.z_tiny:
+ test bl,1
+ jz .zab1
+ stosb
+.zab1:
+ jmp short .done
+
+;
+; shuffle_and_boot:
+;
+; This routine is used to shuffle memory around, followed by
+; invoking an entry point somewhere in low memory. This routine
+; can clobber any memory outside the bcopy special area.
+;
+; IMPORTANT: This routine does not set up any registers.
+; It is the responsibility of the caller to generate an appropriate entry
+; stub; *especially* when going to real mode.
+;
+; Inputs:
+; ESI -> Pointer to list of (dst, src, len) pairs(*)
+; EDI -> Pointer to safe area for list + shuffler
+; (must not overlap this code nor the RM stack)
+; ECX -> Byte count of list area (for initial copy)
+;
+; If src == -1: then the memory pointed to by (dst, len) is bzeroed;
+; this is handled inside the bcopy routine.
+;
+; If len == 0: this marks the end of the list; dst indicates
+; the entry point and src the mode (0 = pm, 1 = rm)
+;
+pm_shuffle:
+ cli ; End interrupt service (for good)
+ mov ebx,edi ; EBX <- descriptor list
+ lea edx,[edi+ecx+15] ; EDX <- where to relocate our code to
+ and edx,~15 ; Align 16 to benefit the GDT
+ call pm_bcopy
+ mov esi,__bcopyxx_start ; Absolute source address
+ mov edi,edx ; Absolute target address
+ sub edx,esi ; EDX <- address delta
+ mov ecx,__bcopyxx_dwords
+ lea eax,[edx+.safe] ; Resume point
+ ; Relocate this code
+ rep movsd
+ jmp eax ; Jump to safe location
+.safe:
+ ; Give ourselves a safe stack
+ lea esp,[edx+bcopyxx_stack+__bcopyxx_end]
+ add edx,bcopy_gdt ; EDX <- new GDT
+ mov [edx+2],edx ; GDT self-pointer
+ lgdt [edx] ; Switch to local GDT
+
+ ; Now for the actual shuffling...
+.loop:
+ mov edi,[ebx]
+ mov esi,[ebx+4]
+ mov ecx,[ebx+8]
+ add ebx,12
+ jecxz .done
+ call pm_bcopy
+ jmp .loop
+.done:
+ lidt [edx+RM_IDT_ptr-bcopy_gdt] ; RM-like IDT
+ push ecx ; == 0, for cleaning the flags register
+ and esi,esi
+ jz pm_shuffle_16
+ popfd ; Clean the flags
+ jmp edi ; Protected mode entry
+
+ ; We have a 16-bit entry point, so we need to return
+ ; to 16-bit mode. Note: EDX already points to the GDT.
+pm_shuffle_16:
+ mov eax,edi
+ mov [edx+PM_CS16+2],ax
+ mov [edx+PM_DS16+2],ax
+ shr eax,16
+ mov [edx+PM_CS16+4],al
+ mov [edx+PM_CS16+7],ah
+ mov [edx+PM_DS16+4],al
+ mov [edx+PM_DS16+7],ah
+ mov eax,cr0
+ and al,~1
+ popfd ; Clean the flags
+ ; No flag-changing instructions below...
+ mov dx,PM_DS16
+ mov ds,edx
+ mov es,edx
+ mov fs,edx
+ mov gs,edx
+ mov ss,edx
+ jmp PM_CS16:0
+
+ section .bcopyxx.data
+
+ alignz 16
+; GDT descriptor entry
+%macro desc 1
+bcopy_gdt.%1:
+PM_%1 equ bcopy_gdt.%1-bcopy_gdt
+%endmacro
+
+bcopy_gdt:
+ dw bcopy_gdt_size-1 ; Null descriptor - contains GDT
+ dd bcopy_gdt ; pointer for LGDT instruction
+ dw 0
+
+ ; TSS segment to keep Intel VT happy. Intel VT is
+ ; unhappy about anything that doesn't smell like a
+ ; full-blown 32-bit OS.
+ desc TSS
+ dw 104-1, DummyTSS ; 08h 32-bit task state segment
+ dd 00008900h ; present, dpl 0, 104 bytes @DummyTSS
+
+ desc CS16
+ dd 0000ffffh ; 10h Code segment, use16, readable,
+ dd 00009b00h ; present, dpl 0, cover 64K
+ desc DS16
+ dd 0000ffffh ; 18h Data segment, use16, read/write,
+ dd 00009300h ; present, dpl 0, cover 64K
+ desc CS32
+ dd 0000ffffh ; 20h Code segment, use32, readable,
+ dd 00cf9b00h ; present, dpl 0, cover all 4G
+ desc DS32
+ dd 0000ffffh ; 28h Data segment, use32, read/write,
+ dd 00cf9300h ; present, dpl 0, cover all 4G
+
+bcopy_gdt_size: equ $-bcopy_gdt
+;
+; Space for a dummy task state segment. It should never be actually
+; accessed, but just in case it is, point to a chunk of memory that
+; has a chance to not be used for anything real...
+;
+DummyTSS equ 0x580
+
+ align 4
+RM_IDT_ptr: dw 0FFFFh ; Length (nonsense, but matches CPU)
+ dd 0 ; Offset
+
+bcopyxx_stack equ 128 ; We want this much stack
+
+ bits 16
+ section .text16
diff --git a/contrib/syslinux-4.02/core/bios.inc b/contrib/syslinux-4.02/core/bios.inc
new file mode 100644
index 0000000..33a3cd4
--- /dev/null
+++ b/contrib/syslinux-4.02/core/bios.inc
@@ -0,0 +1,45 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1994-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., 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.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; bios.inc
+;;
+;; Header file for the BIOS data structures etc.
+;;
+
+%ifndef _BIOS_INC
+%define _BIOS_INC
+ global BIOS_fbm, BIOS_timer
+
+ ; Interrupt vectors
+ absolute 4*1Ch
+BIOS_timer_hook resd 1
+
+ absolute 4*1Eh
+fdctab equ $
+fdctab1 resw 1
+fdctab2 resw 1
+
+ absolute 0400h
+serial_base resw 4 ; Base addresses for 4 serial ports
+ absolute 0413h
+BIOS_fbm resw 1 ; Free Base Memory (kilobytes)
+ absolute 0462h
+BIOS_page resb 1 ; Current video page
+ absolute 046Ch
+BIOS_timer resw 1 ; Timer ticks
+ absolute 0472h
+BIOS_magic resw 1 ; BIOS reset magic
+ absolute 0484h
+BIOS_vidrows resb 1 ; Number of screen rows
+
+%endif ; _BIOS_INC
diff --git a/contrib/syslinux-4.02/core/bootsect.inc b/contrib/syslinux-4.02/core/bootsect.inc
new file mode 100644
index 0000000..b4402f1
--- /dev/null
+++ b/contrib/syslinux-4.02/core/bootsect.inc
@@ -0,0 +1,237 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
+;; Copyright 2009 Intel Corporation; author: H. Peter Anvin
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+;; Boston MA 02111-1307, USA; either version 2 of the License, or
+;; (at your option) any later version; incorporated herein by reference.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; bootsect.inc
+;;
+;; Load a boot sector (or other bootstrap program.)
+;;
+;; Unlike previous versions of this software, this doesn't require that
+;; the length is 512 bytes. This allows PXE bootstraps and WinNT
+;; "CD boot sectors" to be invoked.
+;;
+
+;
+; Load a boot sector
+;
+is_bootsector:
+%if IS_SYSLINUX
+ ; Transfer zero bytes
+ push word 0
+ jmp short load_bootsec
+
+is_bss_sector:
+ ; Transfer the superblock
+SuperSize equ $+1
+ push word superblock_len_fat16
+%endif
+load_bootsec:
+ mov edi,free_high_memory
+ mov [trackbuf+4],edi ; Copy from this address
+ xor dx,dx ; No padding
+ mov bx,abort_check ; Don't print dots, but allow abort
+ call load_high
+
+ sub edi,free_high_memory
+ mov [trackbuf+8],edi ; Save length
+
+ mov eax,7C00h ; Entry point
+ mov [trackbuf],eax ; Copy to this address
+
+%if IS_SYSLINUX
+ xor ecx,ecx
+ pop cx
+
+ ; For a BSS boot sector we have to patch.
+ mov esi,superblock
+ mov edi,free_high_memory+(superblock-bootsec)
+ call bcopy
+%endif
+ push eax ; Save entry point
+
+ xor edx,edx
+ xor esi,esi
+%if IS_SYSLINUX || IS_EXTLINUX
+ ; Restore original FDC table
+ mov eax,[OrigFDCTabPtr]
+ mov [fdctab],eax
+
+ mov dl,[DriveNumber]
+ mov si,PartInfo ; Partition info buffer
+ mov di,800h-18 ; Put partition info here
+ push di
+ mov cx,8 ; 16 bytes
+ xor ax,ax
+ rep movsw
+ pop si ; DS:SI points to partition info
+ xor bx,bx
+%elif IS_ISOLINUX
+ mov dl,[DriveNumber]
+ xor bx,bx
+%elif IS_PXELINUX
+ mov byte [KeepPXE],03h ; Chainloading + keep PXE
+ pm_call reset_pxe
+ lfs si,[InitStack]
+ ; Put restore DS, EDX and ESI to the true initial values
+ mov bx,[fs:si+6]
+ mov edx,[fs:si+28]
+ mov esi,[fs:si+12]
+%endif
+
+;
+; replace_bootstrap for the special case where we have exactly one
+; descriptor, based in low memory. We will generate a second descriptor
+; to clear remaining FBM.
+;
+
+replace_bootstrap_one:
+ mov eax,[trackbuf] ; Base address
+ add eax,[trackbuf+8] ; Length
+ movzx ecx,word [BIOS_fbm]
+ shl ecx,10 ; Free Base Memory
+ sub ecx,eax
+ mov [trackbuf+12],eax
+ or dword [trackbuf+16],-1 ; Zero memory
+ mov [trackbuf+20],ecx
+ push word 2 ; Length of descriptor list
+ ; Fall through
+
+;
+; Entrypoint for "shut down and replace bootstrap" -- also invoked by
+; the COMBOOT API. This routine expects the entry point (CS, IP) and the
+; count of the descriptor sequence on the stack; the shuffle
+; descriptors start at the first byte of the trackbuf.
+;
+; The registers EDX and ESI are passed on to the called program,
+; and BX is passed on as DS.
+;
+replace_bootstrap:
+ ;
+ ; Prepare for shutting down
+ ;
+ call vgaclearmode
+
+;
+; We jump here when loading a kernel image, so that we don't reset
+; the screen mode in "quiet" mode
+;
+replace_bootstrap_noclearmode:
+ call cleanup_hardware
+
+ ;
+ ; Set up initial stack frame (not used by PXE if keeppxe is
+ ; set - we use the PXE stack then.)
+ ;
+ xor ax,ax
+ mov ds,ax
+ mov es,ax
+
+%if IS_PXELINUX
+ cmp byte [KeepPXE],0
+ je .stdstack
+ les di,[InitStack] ; Reset stack to PXE original
+ jmp .stackok
+%endif
+.stdstack:
+ ; StackBuf is guaranteed to have 44 bytes free immediately
+ ; above it, and it will not interfere with our existing stack.
+ mov di,StackBuf
+ push di
+ mov cx,22 ; 44 bytes
+ rep stosw
+ pop di
+.stackok:
+
+ mov [es:di+28],edx ; New EDX
+ mov [es:di+12],esi ; New ESI
+ mov [es:di+6],bx ; New DS
+
+%if IS_PXELINUX == 0
+ ; 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...)
+ mov ax,[OrigESDI]
+ mov bx,[OrigESDI+2]
+
+ mov [es:di+8],ax ; New DI
+ mov [es:di+4],bx ; New ES
+%endif
+ pop ax ; List length
+
+ push di
+ push es
+
+ push ds
+ pop es
+
+ mov ebx,trackbuf
+ imul di,ax,12
+ add di,bx ; DI <- end of list
+ push di
+
+ ; Terminating entry...
+ lea eax,[replace_stub] ; Entrypoint
+ push ax
+ stosd
+ xor ax,ax ; EAX[31:16] == 0 already
+ stosd ; 16-bit mode
+ stosd ; End of list
+
+ ; Copy the stub
+ pop di
+ mov si,__replacestub_lma
+ mov cx,__replacestub_dwords
+ rep movsd
+
+ xor ecx,ecx
+ pop cx ; ECX <- length of list
+
+ pop word [replace_stub.ss]
+ pop word [replace_stub.esp]
+ pop dword [replace_stub.csip]
+
+ cli
+ mov ss,[replace_stub.ss]
+ mov esp,[replace_stub.esp]
+
+ mov edi,trackbuf
+ mov esi,edi
+
+ jmp shuffle_and_boot_raw
+
+ ; This stub gets run after the shuffle. It is copied
+ ; below 0x7c00 in order to properly handle the case
+ ; of bootstrap replacement.
+ section .replacestub
+replace_stub:
+ mov cr0,eax
+ jmp 0:.next
+.next:
+ mov ax,strict word 0
+.ss equ $-2
+ mov ss,ax
+ mov esp,strict dword 0
+.esp equ $-4
+ pop gs
+ pop fs
+ pop es
+ pop ds
+ popad
+ popfd
+ jmp 0:0
+.csip equ $-4
+
+ section .text16
diff --git a/contrib/syslinux-4.02/core/call16.c b/contrib/syslinux-4.02/core/call16.c
new file mode 100644
index 0000000..095f814
--- /dev/null
+++ b/contrib/syslinux-4.02/core/call16.c
@@ -0,0 +1,41 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * call16.c
+ *
+ * Simple wrapper to call 16-bit core functions from 32-bit code
+ */
+
+#include <stddef.h>
+#include <stdio.h>
+#include "core.h"
+
+const com32sys_t zero_regs; /* Common all-zero register set */
+
+static inline uint32_t eflags(void)
+{
+ uint32_t v;
+
+ asm volatile("pushfl ; popl %0" : "=rm" (v));
+ return v;
+}
+
+void call16(void (*func)(void), const com32sys_t *ireg, com32sys_t *oreg)
+{
+ com32sys_t xreg = *ireg;
+
+ /* Enable interrupts if and only if they are enabled in the caller */
+ xreg.eflags.l = (xreg.eflags.l & ~EFLAGS_IF) | (eflags() & EFLAGS_IF);
+
+ core_farcall((size_t)func, &xreg, oreg);
+}
diff --git a/contrib/syslinux-4.02/core/callback.inc b/contrib/syslinux-4.02/core/callback.inc
new file mode 100644
index 0000000..d98d800
--- /dev/null
+++ b/contrib/syslinux-4.02/core/callback.inc
@@ -0,0 +1,215 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
+;; Copyright 2009 Intel Corporation; author: H. Peter Anvin
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+;; Boston MA 02111-1307, USA; either version 2 of the License, or
+;; (at your option) any later version; incorporated herein by reference.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; callback.inc
+;;
+;; Callbacks from 32-bit mode to 16-bit mode
+;;
+
+;
+; 16-bit intcall/farcall handling code
+;
+
+;
+; 32-bit support code
+;
+ bits 32
+ section .text
+
+;
+; Intcall/farcall invocation. We manifest a structure on the real-mode stack,
+; containing the com32sys_t structure from <com32.h> as well as
+; the following entries (from low to high address):
+; - Target offset
+; - Target segment
+; - Return offset
+; - Return segment (== real mode cs == 0)
+; - Return flags
+;
+ global core_farcall
+core_farcall:
+ mov eax,[esp+1*4] ; CS:IP
+ jmp core_syscall
+
+ global core_intcall
+core_intcall:
+ movzx eax,byte [esp+1*4] ; INT number
+ mov eax,[eax*4] ; Get CS:IP from low memory
+
+core_syscall:
+ pushfd ; Save IF among other things...
+ push ebx
+ push ebp
+ push esi
+ push edi
+ push dword [CallbackSP]
+
+ cld
+
+ movzx edi,word [word RealModeSSSP]
+ movzx ebx,word [word RealModeSSSP+2]
+ sub edi,54 ; Allocate 54 bytes
+ mov [word RealModeSSSP],di
+ shl ebx,4
+ add edi,ebx ; Create linear address
+
+ mov esi,[esp+8*4] ; Source regs
+ xor ecx,ecx
+ mov cl,11 ; 44 bytes to copy
+ rep movsd
+
+ ; EAX is already set up to be CS:IP
+ stosd ; Save in stack frame
+ mov eax,.rm_return ; Return seg:offs
+ stosd ; Save in stack frame
+ mov eax,[edi-12] ; Return flags
+ and eax,0x200ed7 ; Mask (potentially) unsafe flags
+ mov [edi-12],eax ; Primary flags entry
+ stosw ; Return flags
+
+ mov bx,.rm
+ jmp enter_rm ; Go to real mode
+
+ bits 16
+ section .text16
+.rm:
+ mov ax,sp
+ add ax,9*4+4*2
+ mov [CallbackSP],ax
+ pop gs
+ pop fs
+ pop es
+ pop ds
+ popad
+ popfd
+ retf ; Invoke routine
+
+.rm_return:
+ ; We clean up SP here because we don't know if the
+ ; routine returned with RET, RETF or IRET
+ mov sp,[cs:CallbackSP]
+ pushfd
+ pushad
+ push ds
+ push es
+ push fs
+ push gs
+ mov ebx,.pm_return
+ jmp enter_pm
+
+ ; On return, the 44-byte return structure is on the
+ ; real-mode stack, plus the 10 additional bytes used
+ ; by the target address (see above.)
+ bits 32
+ section .text
+.pm_return:
+ movzx esi,word [word RealModeSSSP]
+ movzx eax,word [word RealModeSSSP+2]
+ mov edi,[esp+9*4] ; Dest regs
+ shl eax,4
+ add esi,eax ; Create linear address
+ and edi,edi ; NULL pointer?
+ jnz .do_copy
+.no_copy: mov edi,esi ; Do a dummy copy-to-self
+.do_copy: xor ecx,ecx
+ mov cl,11 ; 44 bytes
+ rep movsd ; Copy register block
+
+ add dword [word RealModeSSSP],54
+ ; Remove from stack
+
+ pop dword [CallbackSP]
+ pop edi
+ pop esi
+ pop ebp
+ pop ebx
+ popfd
+ ret ; Return to 32-bit program
+
+;
+; Cfarcall invocation. We copy the stack frame to the real-mode stack,
+; followed by the return CS:IP and the CS:IP of the target function.
+; The value of IF is copied from the calling routine.
+;
+ global core_cfarcall
+core_cfarcall:
+ pushfd ; Save IF among other things...
+ push ebx
+ push ebp
+ push esi
+ push edi
+ push dword [CallbackSP]
+
+ cld
+ mov ecx,[esp+9*4] ; Size of stack frame
+
+ movzx edi,word [word RealModeSSSP]
+ movzx ebx,word [word RealModeSSSP+2]
+ mov [word CallbackSP],di
+ sub edi,ecx ; Allocate space for stack frame
+ and edi,~3 ; Round
+ sub edi,4*3 ; Return pointer, return value, EFLAGS
+ mov [word RealModeSSSP],di
+ shl ebx,4
+ add edi,ebx ; Create linear address
+
+ mov eax,[esp+5*4] ; EFLAGS from entry
+ and eax,0x202 ; IF only
+ stosd
+ mov eax,[esp+7*4] ; CS:IP
+ stosd ; Save to stack frame
+ mov eax,.rm_return ; Return seg:off
+ stosd
+ mov esi,[esp+8*4] ; Stack frame
+ mov eax,ecx ; Copy the stack frame
+ shr ecx,2
+ rep movsd
+ mov ecx,eax
+ and ecx,3
+ rep movsb
+
+ mov bx,.rm
+ jmp enter_rm
+
+ bits 16
+ section .text16
+.rm:
+ popfd
+ retf
+.rm_return:
+ mov sp,[cs:CallbackSP]
+ mov esi,eax
+ mov ebx,.pm_return
+ jmp enter_pm
+
+ bits 32
+ section .text
+.pm_return:
+ mov eax,esi
+ ; EDX already set up to be the RM return value
+ pop dword [CallbackSP]
+ pop ebx
+ pop ebp
+ pop esi
+ pop edi
+ popfd
+ ret
+
+ bits 16
+ section .bss16
+ alignb 4
+CallbackSP resd 1 ; SP saved during callback
+
+ bits 16
+ section .text16
diff --git a/contrib/syslinux-4.02/core/cleanup.inc b/contrib/syslinux-4.02/core/cleanup.inc
new file mode 100644
index 0000000..300584c
--- /dev/null
+++ b/contrib/syslinux-4.02/core/cleanup.inc
@@ -0,0 +1,60 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 2007-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., 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.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; cleanup.inc
+;;
+;; Some final tidying before jumping to a kernel or bootsector
+;;
+
+ section .text16
+;
+; cleanup_hardware:
+;
+; Shut down anything transient. *No segment assumptions*.
+; Preserves all registers.
+;
+cleanup_hardware:
+ pushad
+;
+; Linux wants the floppy motor shut off before starting the kernel,
+; at least bootsect.S seems to imply so. If we don't load the floppy
+; driver, this is *definitely* so!
+;
+ xor ax,ax
+ xor dx,dx
+ int 13h
+
+%if 0 ; This bug report has not been substantiated!
+; Vmware crashes if we scroll in the decompressor! Try to detect vmware
+; and if it is Vmware, clear the screen...
+ mov eax,'VMXh'
+ xor ebx, ebx
+ mov ecx, 10 ; Get version
+ mov dx, 'VX'
+ in eax, dx
+ cmp ebx, 'VMXh'
+ jne .no_vmware
+
+ mov ax,0x0003 ; Set mode (clear screen/home cursor)
+ int 10h
+.no_vmware:
+%endif
+
+ call comboot_cleanup_api
+
+ call timer_cleanup
+
+ popad
+
+ ; If we enabled serial port interrupts, clean them up now
+ jmp sirq_cleanup
diff --git a/contrib/syslinux-4.02/core/cmdline.inc b/contrib/syslinux-4.02/core/cmdline.inc
new file mode 100644
index 0000000..3e63f9a
--- /dev/null
+++ b/contrib/syslinux-4.02/core/cmdline.inc
@@ -0,0 +1,101 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+;; Copyright 2009 Intel Corporation; author: H. Peter Anvin
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+;; Boston MA 02111-1307, USA; either version 2 of the License, or
+;; (at your option) any later version; incorporated herein by reference.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; cmdline.inc
+;;
+;; Common routine to assemble [null-terminated] command line into
+;; real_mode_seg:cmd_line_here.
+;; Not used by plain kernel due to BOOT_IMAGE= etc.
+;;
+
+ section .text16
+
+;
+; Assumes DS == CS
+;
+make_plain_cmdline:
+ push es
+ ; ui.inc has already copied any APPEND options
+ mov ax,real_mode_seg
+ mov es,ax
+
+ mov di,[CmdLinePtr]
+ call do_ip_append
+
+ mov si,[CmdOptPtr]
+
+ call strcpy
+
+ dec di
+ mov [CmdLinePtr],di
+ mov byte [es:di],0 ; Null-terminate
+
+ pop es
+ ret
+
+;
+; Actual IPAppend strings...
+;
+%if IS_PXELINUX
+ extern IPOption, BOOTIFStr, SYSUUIDStr
+ global IPAppends, numIPAppends
+
+ section .data16
+ alignz 2
+IPAppends dw IPOption
+ dw BOOTIFStr
+ dw SYSUUIDStr
+numIPAppends equ ($-IPAppends)/2
+%else
+IPAppends equ 0
+numIPAppends equ 0
+%endif
+
+;
+; Handle "ipappend" strings, if applicable
+;
+; Assumes DS == CS; pushes output to ES:DI
+;
+ section .text16
+
+do_ip_append:
+%ifndef DEPEND
+ %if numIPAppends > 0
+ push cx
+ push bx
+ push si
+
+ mov bx,IPAppends
+ mov cx,[IPAppend]
+ and cx,(1 << numIPAppends)-1
+.loop:
+ jcxz .done
+ mov si,[bx]
+ inc bx
+ inc bx
+ test cl,1
+ jz .not_this
+
+ call strcpy
+ mov byte [es:di-1],' ' ; Replace final null with space
+.not_this:
+ shr cx,1
+ jmp .loop
+.done:
+ pop si
+ pop bx
+ pop cx
+ %endif
+%endif
+ ret
diff --git a/contrib/syslinux-4.02/core/codepage.S b/contrib/syslinux-4.02/core/codepage.S
new file mode 100644
index 0000000..4f1d483
--- /dev/null
+++ b/contrib/syslinux-4.02/core/codepage.S
@@ -0,0 +1,5 @@
+ .section ".rodata","a"
+ .globl codepage
+codepage:
+ .incbin "codepage.cp"
+ .size codepage, .-codepage
diff --git a/contrib/syslinux-4.02/core/com32.inc b/contrib/syslinux-4.02/core/com32.inc
new file mode 100644
index 0000000..111590c
--- /dev/null
+++ b/contrib/syslinux-4.02/core/com32.inc
@@ -0,0 +1,145 @@
+;; -----------------------------------------------------------------------
+;;
+;; 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.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; com32.inc
+;;
+;; Common code for running a COM32 image
+;;
+
+ extern pm_api_vector
+
+;
+; Load a COM32 image. A COM32 image is the 32-bit analogue to a DOS
+; .com file. A COM32 image is loaded at address 0x101000, with %esp
+; set to the high end of usable memory.
+;
+; A COM32 image should begin with the magic bytes:
+; B8 FF 4C CD 21, which is "mov eax,0x21cd4cff" in 32-bit mode and
+; "mov ax,0x4cff; int 0x21" in 16-bit mode. This will abort the
+; program with an error if run in 16-bit mode.
+;
+com32_entry equ free_high_memory
+
+ section .text16
+is_com32_image:
+ push si ; Save file handle
+ push eax ; Save file length
+
+ call make_plain_cmdline
+ ; Copy the command line into the low cmdline buffer
+ mov ax,real_mode_seg
+ mov fs,ax
+ mov si,cmd_line_here
+ mov di,command_line
+ mov cx,[CmdLinePtr]
+ inc cx ; Include final null
+ sub cx,si
+ fs rep movsb
+
+ mov si,KernelName
+ mov di,Com32Name
+ call strcpy
+
+ call comboot_setup_api ; Set up the COMBOOT-style API
+
+ mov edi,com32_entry ; Load address
+ pop eax ; File length
+ pop si ; File handle
+ xor dx,dx ; No padding
+ mov bx,abort_check ; Don't print dots, but allow abort
+ call load_high
+
+ mov esi,com32_entry
+ mov edi,trackbuf
+ mov ecx,5
+ call bcopy
+ cmp dword [trackbuf],0xcd4cfeb8
+ jne not_com32r
+ cmp byte [trackbuf+4],0x21
+ jne not_com32r
+
+com32_start:
+ ;
+ ; Point the stack to the end of (permitted) high memory
+ ;
+ mov eax,[HighMemRsvd]
+ xor ax,ax ; Align to a 64K boundary
+ mov [PMESP],eax
+ mov ebx,.pm ; Where to go in PM
+ jmp enter_pm
+
+;
+; This is invoked right before the actually starting the COM32
+; progam, in 32-bit mode...
+;
+ bits 32
+ section .text
+.pm:
+ ; Set up the calling stack frame
+
+ push dword pm_api_vector
+ push dword Com32Name ; Module filename
+ push dword [HighMemSize] ; Memory managed by Syslinux
+ push dword core_cfarcall ; Cfarcall entry point
+ push dword core_farcall ; Farcall entry point
+ push dword (1 << 16) ; 64K bounce buffer
+ push dword core_real_mode ; Bounce buffer address
+ push dword core_intcall ; Intcall entry point
+ push dword command_line ; Command line pointer
+ push dword 9 ; Argument count
+ sti ; Interrupts OK now
+ call com32_entry ; Run the program...
+ ; ... on return, fall through to com32_exit ...
+com32_exit:
+ mov bx,comboot_return
+ jmp enter_rm
+
+ bits 16
+ section .text16
+not_com32r:
+ mov si,KernelName
+ call writestr
+ mov si,not_com32r_msg
+ call writestr
+ jmp enter_command
+
+ section .data16
+not_com32r_msg db ': not a COM32R image', CR, LF, 0
+
+ ; Ersatz com32 invocation structure, to make libcom32
+ ; code run the same if linked to the core. This is in
+ ; the .data16 segment so HighMemSize can live here.
+ ;
+ ; Danger, Will Robinson: it's not clear the use of
+ ; core_xfer_buf is safe here.
+ global __entry_esp, __com32
+ alignz 4
+__entry_esp:
+ dd 0 ; Dummy to avoid _exit issues
+__com32:
+ dd 9 ; Argument count
+ dd 0 ; No command line
+ dd core_intcall ; Intcall entry point
+ dd 0 ; Bounce buffer address
+ dd 0 ; 64K bounce buffer
+ dd core_farcall ; Farcall entry point
+ dd core_cfarcall ; Cfarcall entry point
+HighMemSize dd 0 ; End of memory pointer (bytes)
+ dd 0 ; No module name
+ dd pm_api_vector ; Protected mode functions
+
+ section .uibss
+Com32Name resb FILENAME_MAX
+
+ section .text16
diff --git a/contrib/syslinux-4.02/core/comboot.inc b/contrib/syslinux-4.02/core/comboot.inc
new file mode 100644
index 0000000..59db7ec
--- /dev/null
+++ b/contrib/syslinux-4.02/core/comboot.inc
@@ -0,0 +1,1010 @@
+;; -----------------------------------------------------------------------
+;;
+;; 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.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; comboot.inc
+;;
+;; Common code for running a COMBOOT image
+;;
+
+ section .text16
+
+; Parameter registers definition; this is the definition
+; of the stack frame used by INT 21h and INT 22h.
+%define P_FLAGS word [bp+44]
+%define P_FLAGSL byte [bp+44]
+%define P_FLAGSH byte [bp+45]
+%define P_CS word [bp+42]
+%define P_IP word [bp+40]
+%define P_CSIP dword [bp+40]
+%define P_DS word [bp+38]
+%define P_ES word [bp+36]
+%define P_FS word [bp+34]
+%define P_GS word [bp+32]
+%define P_EAX dword [bp+28]
+%define P_AX word [bp+28]
+%define P_HAX word [bp+30]
+%define P_AL byte [bp+28]
+%define P_AH byte [bp+29]
+%define P_ECX dword [bp+24]
+%define P_CX word [bp+24]
+%define P_HCX word [bp+26]
+%define P_CL byte [bp+24]
+%define P_CH byte [bp+25]
+%define P_EDX dword [bp+20]
+%define P_DX word [bp+20]
+%define P_HDX word [bp+22]
+%define P_DL byte [bp+20]
+%define P_DH byte [bp+21]
+%define P_EBX dword [bp+16]
+%define P_BX word [bp+16]
+%define P_HBX word [bp+18]
+%define P_BL byte [bp+16]
+%define P_BH byte [bp+17]
+%define P_EBP dword [bp+8]
+%define P_BP word [bp+8]
+%define P_HBP word [bp+10]
+%define P_ESI dword [bp+4]
+%define P_SI word [bp+4]
+%define P_HSI word [bp+6]
+%define P_EDI dword [bp]
+%define P_DI word [bp]
+%define P_HDI word [bp+2]
+
+; Looks like a COMBOOT image but too large
+comboot_too_large:
+ pm_call pm_close_file
+ mov si,err_comlarge
+ call writestr
+ jmp enter_command
+
+;
+; Load a COMBOOT image. A COMBOOT image is basically a DOS .COM file,
+; except that it may, of course, not contain any DOS system calls. We
+; do, however, allow the execution of INT 20h to return to SYSLINUX.
+;
+is_comboot_image:
+ push si ; Save file handle
+
+ call make_plain_cmdline
+
+ call comboot_setup_api
+
+ mov cx,comboot_seg
+ mov es,cx
+
+ xor di,di
+ mov cx,64 ; 256 bytes (size of PSP)
+ xor eax,eax ; Clear PSP
+ rep stosd
+
+ mov word [es:0], 020CDh ; INT 20h instruction
+ ; First non-free paragraph
+ ; This is valid because comboot_seg == real_mode_seg
+ ; == the highest segment used by all derivatives
+ int 12h ; Get DOS memory size
+ shl ax,6 ; Kilobytes -> paragraphs
+ mov word [es:02h],ax
+
+%ifndef DEPEND
+%if real_mode_seg != comboot_seg
+%error "This code assumes real_mode_seg == comboot_seg"
+%endif
+%endif
+ ; Copy the command line from high memory
+ mov si,cmd_line_here
+ mov cx,125 ; Max cmdline len (minus space and CR)
+ mov di,081h ; Offset in PSP for command line
+ mov al,' ' ; DOS command lines begin with a space
+ stosb
+
+.loop: es lodsb
+ and al,al
+ jz .done
+ stosb
+ loop .loop
+.done:
+
+ mov al,0Dh ; CR after last character
+ stosb
+ mov ax,di
+ sub al,82h ; Include space but not CR
+ mov [es:80h],al ; Store command line length
+
+ ; Now actually load the file...
+ pop si ; File handle
+ mov bx,100h ; Load at <seg>:0100h
+ mov cx,0FF00h ; Maximum number of bytes
+ pm_call getfsbytes
+ cmp ecx,65536-256-2 ; Maximum size
+ ja comboot_too_large
+
+ ; And invoke the program...
+ mov ax,es
+ mov ds,ax
+ mov ss,ax
+ xor sp,sp
+ push word 0 ; Return to address 0 -> exit
+
+ jmp comboot_seg:100h ; Run it
+
+;
+; Set up the COMBOOT API interrupt vectors. This is now done at
+; initialization time.
+;
+comboot_setup_api:
+ mov di,DOSErrTramp ; Error trampolines
+ mov cx,32
+ push cx
+ mov eax,02EB206Ah ; push 20h; jmp $+4
+.loop1: stosd
+ inc ah
+ loop .loop1
+ dec di
+ mov byte [di-1],0E9h
+ mov ax,comboot_bogus-2
+ sub ax,di
+ stosw
+
+ pop cx ; CX <- 32
+ mov si,4*20h ; DOS interrupt vectors
+ mov bx,comboot_vectors
+ mov di,DOSSaveVectors
+.loop2:
+ movsd
+ movzx eax,word [bx]
+ inc bx
+ inc bx
+ mov [si-4],eax
+ loop .loop2
+ ret
+
+;
+; Restore the original state of the COMBOOT API vectors, and free
+; any low memory allocated by the comboot module.
+;
+comboot_cleanup_api:
+ pusha
+ mov si,DOSSaveVectors
+ mov di,4*20h
+ mov cx,20h
+ rep movsd ; Restore DOS-range vectors
+ popa
+ ret
+
+ section .bss16
+ alignb 4
+DOSSaveVectors resd 32
+
+ section .data16
+%define comboot_err(x) (DOSErrTramp+4*((x)-20h))
+
+comboot_vectors:
+ dw comboot_return ; INT 20 = exit
+ dw comboot_int21 ; INT 21 = DOS-compatible system calls
+ dw comboot_int22 ; INT 22 = native system calls
+ dw comboot_err(23h) ; INT 23 = DOS Ctrl-C handler
+ dw comboot_err(24h) ; INT 24 = DOS critical error handler
+ dw comboot_err(25h) ; INT 25 = DOS absolute disk read
+ dw comboot_err(26h) ; INT 26 = DOS absolute disk write
+ dw comboot_err(27h) ; INT 27 = DOS TSR
+ dw comboot_int28 ; INT 28 = DOS idle interrupt
+ dw comboot_int29 ; INT 29 = DOS fast console output
+ dw comboot_err(2Ah) ; INT 2A = DOS network API (NetBIOS)
+ dw comboot_err(2Bh) ; INT 2B = DOS reserved
+ dw comboot_err(2Ch) ; INT 2C = DOS reserved
+ dw comboot_iret ; INT 2D = DOS reserved, AMIS
+ dw comboot_err(2Eh) ; INT 2E = DOS run command
+ dw comboot_iret ; INT 2F = DOS multiplex interrupt
+ dw comboot_err(30h) ; INT 30 = DOS CP/M system calls
+ dw comboot_err(31h) ; INT 31 = DPMI
+ dw comboot_err(32h) ; INT 32 = DOS reserved
+ dw comboot_iret ; INT 33 = DOS mouse API
+ dw comboot_err(34h) ; INT 34 = DOS FPU emulation
+ dw comboot_err(35h) ; INT 35 = DOS FPU emulation
+ dw comboot_err(36h) ; INT 36 = DOS FPU emulation
+ dw comboot_err(37h) ; INT 37 = DOS FPU emulation
+ dw comboot_err(38h) ; INT 38 = DOS FPU emulation
+ dw comboot_err(39h) ; INT 39 = DOS FPU emulation
+ dw comboot_err(3Ah) ; INT 3A = DOS FPU emulation
+ dw comboot_err(3Bh) ; INT 3B = DOS FPU emulation
+ dw comboot_err(3Ch) ; INT 3C = DOS FPU emulation
+ dw comboot_err(3Dh) ; INT 3D = DOS FPU emulation
+ dw comboot_err(3Eh) ; INT 3E = DOS FPU emulation
+ dw comboot_err(3Fh) ; INT 3F = DOS overlay manager
+
+ section .text16
+
+; INT 21h: generic DOS system call
+comboot_int21: sti
+ push ds
+ push es
+ push fs
+ push gs
+ pushad
+ cld
+ mov bp,cs
+ mov ds,bp
+ mov es,bp
+ mov bp,sp ; Set up stack frame
+
+ call adjust_screen ; The COMBOOT program might have changed the screen
+
+ mov cx,int21_count
+ mov si,int21_table
+.again: lodsb
+ cmp al,P_AH
+ lodsw
+ loopne .again
+ ; The last function in the list is the
+ ; "no such function" function
+ clc
+ call ax ; Call the invoked function
+comboot_resume:
+ mov bp,sp ; In case the function clobbers BP
+ setc P_FLAGSL ; Propagate CF->error
+ popad
+ pop gs
+ pop fs
+ pop es
+ pop ds
+comboot_iret:
+ iret
+
+comboot_bad_int21:
+ mov ax,P_AX
+ push P_CSIP
+ push 21h
+ ; Fall through
+
+; Attempted to execute invalid DOS system call
+; The interrupt number is on the stack.
+comboot_bogus: pop dx ; Interrupt number
+ pop edi ; CS:IP
+ mov cx,err_notdos
+ push comboot_bogus_tail
+ jmp comboot_exit_msg
+comboot_bogus_tail:
+ xchg ax,dx
+ call writehex2 ; Interrupt number
+ mov al,' '
+ call writechr
+ xchg ax,dx
+ call writehex4 ; Function number (AX)
+ mov al,' '
+ call writechr
+ mov eax,edi
+ call writehex8 ; CS:IP of the origin
+ call crlf
+ jmp enter_command
+
+; Proper return vector
+; Note: this gets invoked both via INT 21h and directly via INT 20h.
+; We don't need to cld explicitly here, because comboot_exit does that
+; when invoking RESET_STACK_AND_SEGS.
+comboot_return:
+ cli ; May not have a safe stack
+ push enter_command ; Normal return to command prompt
+ ; jmp comboot_exit
+
+;
+; Generic COMBOOT return to command line code
+; stack -> where to go next
+; CX -> message (for _msg version)
+;
+ extern comboot_cleanup_lowmem
+comboot_exit:
+ xor cx,cx
+comboot_exit_msg:
+ pop bx ; Return address
+ RESET_STACK_AND_SEGS si ; Contains sti, cld
+ pm_call comboot_cleanup_lowmem
+ call adjust_screen ; The COMBOOT program might have changed the screen
+ jcxz .nomsg
+ mov si,KernelName
+ call writestr
+ mov si,cx
+ call writestr
+.nomsg:
+ jmp bx
+
+;
+; INT 21h system calls
+;
+comboot_getkey: ; 01 = get key with echo
+ call vgashowcursor
+ call comboot_getchar
+ call vgahidecursor
+ call writechr
+ clc
+ ret
+
+comboot_writechr: ; 02 = writechr
+ mov al,P_DL
+ call writechr
+ clc
+ ret
+
+comboot_writeserial: ; 04 = write serial port
+ mov al,P_DL
+ call write_serial
+ clc
+ ret
+
+comboot_getkeynoecho: ; 08 = get key w/o echo
+ call comboot_getchar
+ clc
+ ret
+
+comboot_writestr: ; 09 = write DOS string
+ mov es,P_DS
+ mov si,P_DX
+.loop: es lodsb
+ cmp al,'$' ; End string with $ - bizarre
+ je .done
+ call writechr
+ jmp short .loop
+.done: clc
+ ret
+
+comboot_checkkey: ; 0B = check keyboard status
+ cmp byte [APIKeyFlag],00h
+ jnz .waiting
+ call pollchar
+.waiting: setz al
+ dec al ; AL = 0FFh if present, 0 if not
+ mov P_AL,al
+ clc
+ ret
+
+comboot_checkver: ; 30 = check DOS version
+ ; We return 0 in all DOS-compatible version registers,
+ ; but the high part of eax-ebx-ecx-edx spell "SYSLINUX"
+ mov P_EAX,'SY' << 16
+ mov P_EBX,'SL' << 16
+ mov P_ECX,'IN' << 16
+ mov P_EDX,'UX' << 16
+ ret
+
+comboot_getchar:
+ cmp byte [APIKeyFlag],00h
+ jne .queued
+ call getchar ; If not queued get input
+ and al,al ; Function key? (CF <- 0)
+ jnz .done
+ mov [APIKeyWait],ah ; High part of key
+ inc byte [APIKeyFlag] ; Set flag
+.done: mov P_AL,al
+ ret
+.queued: mov al,[APIKeyWait]
+ dec byte [APIKeyFlag]
+ jmp .done
+
+;
+; INT 28h - DOS idle
+;
+comboot_int28:
+ sti
+ cld
+ call do_idle
+ iret
+
+;
+; INT 29h - DOS fast write character
+;
+comboot_int29:
+ sti
+ cld
+ call writechr ; Preserves registers!
+ iret
+
+;
+; INT 22h - SYSLINUX-specific system calls
+; System call number in ax
+;
+comboot_int22:
+ sti
+ push ds
+ push es
+ push fs
+ push gs
+ pushad
+ cld
+ mov bp,cs
+ mov ds,bp
+ mov es,bp
+ mov bp,sp ; Set up stack frame
+
+ call adjust_screen ; The COMBOOT program might have changed the screen
+
+ cmp ax,int22_count
+ jb .ok
+ xor ax,ax ; Function 0 -> unimplemented
+.ok:
+ xchg ax,bx
+ add bx,bx ; CF <- 0
+ call [bx+int22_table]
+ jmp comboot_resume ; On return
+
+;
+; INT 22h AX=0000h Unimplemented call
+;
+comapi_err:
+ stc
+ ret
+
+;
+; INT 22h AX=0001h Get SYSLINUX version
+;
+comapi_get_version:
+ ; Number of API functions supported
+ mov P_AX,int22_count
+ ; SYSLINUX version
+ mov P_CX,(VERSION_MAJOR << 8)+VERSION_MINOR
+ ; SYSLINUX derivative ID byte
+ mov P_DX,my_id
+ ; For future use
+ mov P_BX,cs ; cs == 0
+
+ mov P_ES,ds
+ ; ES:SI -> version banner
+ mov P_SI,syslinux_banner + 2 ; Skip leading CR LF
+ ; ES:DI -> copyright string
+ mov P_DI,copyright_str + 1 ; Skip leading space
+
+comapi_nop:
+ clc
+ ret
+
+;
+; INT 22h AX=0002h Write string
+;
+; Write null-terminated string in ES:BX
+;
+comapi_writestr:
+ mov ds,P_ES
+ mov si,P_BX
+ call writestr
+ clc
+ ret
+
+;
+; INT 22h AX=0003h Run command
+;
+; Terminates the COMBOOT program and executes the command line in
+; ES:BX as if it had been entered by the user.
+;
+comapi_run:
+ mov ds,P_ES
+ mov si,P_BX
+ mov di,command_line
+ call strcpy
+ push load_kernel ; Run a new kernel
+ jmp comboot_exit ; Terminate task, clean up
+
+;
+; INT 22h AX=0004h Run default command
+;
+; Terminates the COMBOOT program and executes the default command line
+; as if a timeout had happened or the user pressed <Enter>.
+;
+comapi_run_default:
+ push auto_boot
+ jmp comboot_exit
+
+;
+; INT 22h AX=0005h Force text mode
+;
+; Puts the video in standard text mode
+;
+comapi_textmode:
+ call vgaclearmode
+ clc
+ ret
+
+;
+; INT 22h AX=0006h Open file
+;
+comapi_open:
+ mov es,P_ES
+ mov si,P_SI
+ pm_call pm_open_file
+ mov P_EAX,eax
+ mov P_CX,cx
+ mov P_SI,si
+ ret
+
+;
+; INT 22h AX=0007h Read file
+;
+comapi_read:
+ mov es,P_ES
+ mov bx,P_BX
+ mov si,P_SI
+ mov cx,P_CX
+ pm_call getfssec
+ jnc .noteof
+ xor si,si ; SI <- 0 on EOF, CF <- 0
+.noteof: mov P_SI,si
+ mov P_ECX,ecx
+ ret
+
+;
+; INT 22h AX=0008h Close file
+;
+comapi_close:
+ mov si,P_SI
+ pm_call pm_close_file
+ clc
+ ret
+
+;
+; INT 22h AX=0009h Call PXE stack
+;
+%if IS_PXELINUX
+comapi_pxecall:
+ mov bx,P_BX
+ mov es,P_ES
+ mov di,P_DI
+ call pxenv
+ mov ax,[PXEStatus]
+ mov P_AX,ax
+ ret
+%else
+comapi_pxecall equ comapi_err ; Not available
+%endif
+
+;
+; INT 22h AX=000Ah Get Derivative-Specific Info
+;
+comapi_derinfo:
+ mov P_AL,my_id
+%if IS_PXELINUX
+ mov ax,[APIVer]
+ mov P_DX,ax
+ mov ax,[StrucPtr]
+ mov P_BX,ax
+ mov ax,[StrucPtr+2]
+ mov P_ES,ax
+ mov ax,[InitStack]
+ mov P_SI,ax
+ mov ax,[InitStack+2]
+ mov P_FS,ax
+ mov eax,[IPInfo.MyIP]
+ mov P_ECX,eax
+ mov P_GS,0
+ mov P_DI,IPInfo
+%else
+ ; Physical medium...
+
+ mov al,[SectorShift]
+ mov P_CL,al
+ mov al,[DriveNumber]
+ mov P_DL,al
+ mov P_FS,cs
+ mov P_SI,OrigESDI
+ mov P_GS,cs
+ mov P_DI,Hidden
+%if IS_SYSLINUX || IS_EXTLINUX
+ mov P_ES,cs
+ mov P_BX,PartInfo
+%elif IS_ISOLINUX
+ mov P_ES,cs
+ mov P_BX,spec_packet
+ mov ax,[BIOSType]
+ sub ax,bios_cdrom
+ shr ax,2
+ mov P_CH,al ; Mode (el torito/cbios/ebios)
+%endif
+%endif
+ clc
+ ret
+
+;
+; INT 22h AX=000Bh Get Serial Console Configuration
+;
+comapi_serialcfg:
+ mov ax,[SerialPort]
+ mov P_DX,ax
+ mov ax,[BaudDivisor]
+ mov P_CX,ax
+ mov ax,[FlowControl]
+ or al,ah
+ mov ah,[FlowIgnore]
+ shr ah,4
+ test byte [DisplayCon],01h
+ jnz .normalconsole
+ or ah,80h
+.normalconsole:
+ mov P_BX,ax
+ clc
+ ret
+
+;
+; INT 22h AX=000Ch Perform final cleanup
+;
+comapi_cleanup:
+%if IS_PXELINUX
+ ; Unload PXE if requested
+ test dl,3
+ setnz [KeepPXE]
+ sub bp,sp ; unload_pxe may move the stack around
+ pm_call unload_pxe
+ add bp,sp ; restore frame pointer...
+%elif IS_SYSLINUX || IS_EXTLINUX
+ ; Restore original FDC table
+ mov eax,[OrigFDCTabPtr]
+ mov [fdctab],eax
+%endif
+ call cleanup_hardware
+ clc
+ ret
+
+;
+; INT 22h AX=000Dh Clean up then replace bootstrap
+;
+comapi_chainboot:
+ call comapi_cleanup
+ mov eax,P_EDI
+ mov [trackbuf+4],eax ; Copy from
+ mov eax,P_ECX
+ mov [trackbuf+8],eax ; Total bytes
+ mov eax,7C00h
+ mov [trackbuf],eax ; Copy to
+ push eax ; Entry point on stack
+ mov esi,P_ESI
+ mov edx,P_EBX
+ mov bx,P_DS
+ jmp replace_bootstrap_one
+
+;
+; INT 22h AX=000Eh Get configuration file name
+;
+comapi_configfile:
+ mov P_ES,cs
+ mov P_BX,ConfigName
+ clc
+ ret
+
+;
+; INT 22h AX=000Fh Get IPAPPEND strings
+;
+comapi_ipappend:
+ mov P_ES,cs
+ mov P_CX,numIPAppends
+ mov P_BX,IPAppends
+ clc
+ ret
+
+;
+; INT 22h AX=0010h Resolve hostname
+;
+%if IS_PXELINUX
+ extern pxe_dns_resolv
+comapi_dnsresolv:
+ mov ds,P_ES
+ mov si,P_BX
+ pm_call pxe_dns_resolv
+ mov P_EAX,eax
+ clc
+ ret
+%else
+comapi_dnsresolv equ comapi_err
+%endif
+
+ section .text16
+
+;
+; INT 22h AX=0011h Obsolete
+;
+
+;
+; INT 22h AX=0012h Obsolete
+;
+
+;
+; INT 22h AX=0013h Idle call
+;
+comapi_idle:
+ call do_idle
+ clc
+ ret
+
+;
+; INT 22h AX=0014h Local boot
+;
+%if HAS_LOCALBOOT
+comapi_localboot:
+ mov ax,P_DX
+ jmp local_boot
+%else
+comapi_localboot equ comapi_err
+%endif ; HAS_LOCALBOOT
+
+;
+; INT 22h AX=0015h Feature flags
+;
+comapi_features:
+ mov P_ES,cs
+ mov P_BX,feature_flags
+ mov P_CX,feature_flags_len
+ clc
+ ret
+
+;
+; INT 22h AX=0016h Run kernel image
+;
+comapi_runkernel:
+ mov al,P_DL
+ cmp al,VK_TYPES-1
+ ja .error
+ mov [KernelType],al
+
+ ; It's not just possible, but quite likely, that ES:BX
+ ; points into real_mode_seg or xfer_buf_seg, so we
+ ; need to exercise some special care here... use
+ ; VKernelBuf for temporary storage.
+ push ds
+ mov ds,P_ES
+ mov si,P_BX
+ mov di,VKernelBuf
+ call strcpy
+ pop ds
+
+ push ds
+ mov ds,P_DS
+ mov si,P_SI
+ mov di,KernelName
+ pm_call pm_mangle_name
+ pop ds
+ pm_call pm_searchdir
+ jz comapi_err
+
+ ; The kernel image was found, so we can load it...
+ mov [Kernel_SI],si
+ mov [Kernel_EAX],eax
+
+%if IS_PXELINUX
+ mov al,P_CL
+ mov [IPAppend],al
+%endif
+
+ call comboot_exit
+
+.finish:
+ ; Copy the command line into its proper place
+ push es
+ mov dx,real_mode_seg
+ mov es,dx
+ mov si,VKernelBuf
+ mov di,cmd_line_here
+ call strcpy
+ mov word [es:di-1],' ' ; Simulate APPEND: space plus null
+ pop es
+ mov [CmdLinePtr],di
+ mov word [CmdOptPtr],zero_string
+ jmp kernel_good_saved
+
+.error equ comapi_usingvga.error
+
+;
+; INT 22h AX=0017h Report video mode change
+;
+comapi_usingvga:
+ mov ax,P_BX
+ cmp ax,0Fh ; Unknown flags = failure
+ ja .error
+ mov [UsingVGA],al
+ mov cx,P_CX
+ mov dx,P_DX
+ mov [GXPixCols],cx
+ mov [GXPixRows],dx
+ test al,08h
+ jnz .notext
+ call adjust_screen
+.notext:
+ clc
+ ret
+.error:
+ stc
+ ret
+
+;
+; INT 22h AX=0018h Query custom font
+;
+comapi_userfont:
+ mov al,[UserFont]
+ and al,al
+ jz .done
+ mov al,[VGAFontSize]
+ mov P_ES,aux_seg
+ mov P_BX,aux.fontbuf
+
+.done: ; CF=0 here
+ mov P_AL,al
+ ret
+
+;
+; INT 22h AX=0019h Read disk
+;
+%if IS_SYSLINUX || IS_ISOLINUX || IS_EXTLINUX
+comapi_readdisk:
+ cmp P_EDI,0 ; Reserved for future expansion
+ jnz .err
+ mov eax,P_EDX
+ mov edx,P_ESI
+ mov es,P_ES
+ mov bx,P_BX
+ mov bp,P_CX ; WE CANNOT use P_* after touching bp!
+ call getlinsec
+ clc
+ ret
+.err:
+ stc
+ ret
+%else
+comapi_readdisk equ comapi_err
+%endif
+
+;
+; INT 22h AX=001Ah Obsolete
+;
+
+;
+; INT 22h AX=001Bh Obsolete
+;
+
+;
+; INT 22h AX=001Ch Get pointer to auxillary data vector
+;
+comapi_getadv:
+ mov P_ES,ds
+ mov P_BX,adv0.data
+ mov P_CX,ADV_LEN
+ ret
+
+;
+; INT 22h AX=001Dh Write auxillary data vector
+;
+comapi_writeadv equ adv_write
+
+;
+; INT 22h AX=001Eh Keyboard remapping table
+comapi_kbdtable:
+ cmp P_DX,0
+ jne .err
+ mov P_AX,1 ; Version
+ mov P_CX,256 ; Length
+ mov P_ES,cs
+ mov P_BX,KbdMap
+ ret
+.err:
+ stc
+ ret
+
+;
+; INT 22h AX=001Fh Get current working directory
+;
+comapi_getcwd:
+ mov P_ES,cs
+ mov P_BX,CurrentDirName
+ clc
+ ret
+
+;
+; INT 22h AX=0023h Query shuffler size
+;
+comapi_shufsize:
+ ; +15 is padding to guarantee alignment
+ mov P_CX,__bcopyxx_len + 15
+ ret
+
+;
+; INT 22h AX=0024h Cleanup, shuffle and boot raw
+;
+comapi_shufraw:
+ call comapi_cleanup
+ mov edi,P_EDI
+ mov esi,P_ESI
+ mov ecx,P_ECX
+ jmp shuffle_and_boot_raw
+
+ section .data16
+
+%macro int21 2
+ db %1
+ dw %2
+%endmacro
+
+int21_table:
+ int21 00h, comboot_return
+ int21 01h, comboot_getkey
+ int21 02h, comboot_writechr
+ int21 04h, comboot_writeserial
+ int21 08h, comboot_getkeynoecho
+ int21 09h, comboot_writestr
+ int21 0Bh, comboot_checkkey
+ int21 30h, comboot_checkver
+ int21 4Ch, comboot_return
+ int21 -1, comboot_bad_int21
+int21_count equ ($-int21_table)/3
+
+ alignz 2
+int22_table:
+ dw comapi_err ; 0000 unimplemented syscall
+ dw comapi_get_version ; 0001 get SYSLINUX version
+ dw comapi_writestr ; 0002 write string
+ dw comapi_run ; 0003 run specified command
+ dw comapi_run_default ; 0004 run default command
+ dw comapi_textmode ; 0005 force text mode
+ dw comapi_open ; 0006 open file
+ dw comapi_read ; 0007 read file
+ dw comapi_close ; 0008 close file
+ dw comapi_pxecall ; 0009 call PXE stack
+ dw comapi_derinfo ; 000A derivative-specific info
+ dw comapi_serialcfg ; 000B get serial port config
+ dw comapi_cleanup ; 000C perform final cleanup
+ dw comapi_err ; 000D clean up then bootstrap
+ dw comapi_configfile ; 000E get name of config file
+ dw comapi_ipappend ; 000F get ipappend strings
+ dw comapi_dnsresolv ; 0010 resolve hostname
+ dw comapi_err ; 0011 maximum shuffle descriptors
+ dw comapi_err ; 0012 cleanup, shuffle and boot
+ dw comapi_idle ; 0013 idle call
+ dw comapi_localboot ; 0014 local boot
+ dw comapi_features ; 0015 feature flags
+ dw comapi_runkernel ; 0016 run kernel image
+ dw comapi_usingvga ; 0017 report video mode change
+ dw comapi_userfont ; 0018 query custom font
+ dw comapi_readdisk ; 0019 read disk
+ dw comapi_err ; 001A cleanup, shuffle and boot to pm
+ dw comapi_err ; 001B cleanup, shuffle and boot to rm
+ dw comapi_getadv ; 001C get pointer to ADV
+ dw comapi_writeadv ; 001D write ADV to disk
+ dw comapi_kbdtable ; 001E keyboard remapping table
+ dw comapi_getcwd ; 001F get current working directory
+ dw comapi_err ; 0020 open directory
+ dw comapi_err ; 0021 read directory
+ dw comapi_err ; 0022 close directory
+ dw comapi_shufsize ; 0023 query shuffler size
+ dw comapi_shufraw ; 0024 cleanup, shuffle and boot raw
+int22_count equ ($-int22_table)/2
+
+APIKeyWait db 0
+APIKeyFlag db 0
+
+zero_string db 0 ; Empty, null-terminated string
+
+;
+; This is the feature flag array for INT 22h AX=0015h
+;
+; Note: PXELINUX clears the idle is noop flag if appropriate
+; in pxe_detect_nic_type
+;
+feature_flags:
+ db 1 ; Have local boot, idle is not noop
+feature_flags_len equ ($-feature_flags)
+
+err_notdos db ': attempted DOS system call INT ',0
+err_comlarge db 'COMBOOT image too large.', CR, LF, 0
+
+ section .bss16
+ alignb 4
+DOSErrTramp resd 33 ; Error trampolines
+
+ global ConfigName
+ConfigName resb FILENAME_MAX
+%ifndef HAVE_CURRENTDIRNAME
+ global CurrentDirName
+CurrentDirName resb FILENAME_MAX
+%endif
diff --git a/contrib/syslinux-4.02/core/common.inc b/contrib/syslinux-4.02/core/common.inc
new file mode 100644
index 0000000..7078011
--- /dev/null
+++ b/contrib/syslinux-4.02/core/common.inc
@@ -0,0 +1,25 @@
+;
+; Modules common to all derivatives. Do not include modules in this list
+; which have special section requirements (i.e. need to be in .init for
+; some derivatives.)
+;
+
+%include "getc.inc" ; getc et al
+%include "conio.inc" ; Console I/O
+%include "configinit.inc" ; Initialize configuration
+%include "parseconfig.inc" ; High-level config file handling
+%include "parsecmd.inc" ; Low-level config file handling
+%include "pm.inc" ; Protected mode
+%include "bcopy32.inc" ; 32-bit bcopy
+%include "loadhigh.inc" ; Load a file into high memory
+%include "font.inc" ; VGA font stuff
+%include "graphics.inc" ; VGA graphics
+%include "highmem.inc" ; High memory sizing
+%include "strcpy.inc" ; strcpy()
+%include "idle.inc" ; Idle handling
+%include "adv.inc" ; Auxillary Data Vector
+%include "timer.inc" ; Timer handling
+
+; Note: the prefix section is included late, to avoid problems with some
+; versions of NASM that had issues with forward references to EQU symbols.
+%include "prefix.inc" ; Prefix section for prepcore
diff --git a/contrib/syslinux-4.02/core/config.inc b/contrib/syslinux-4.02/core/config.inc
new file mode 100644
index 0000000..269e13e
--- /dev/null
+++ b/contrib/syslinux-4.02/core/config.inc
@@ -0,0 +1,45 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 2002-2009 H. Peter Anvin - All Rights Reserved
+;; Copyright 2009 Intel Corporation; author: H. Peter Anvin
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+;; Boston MA 02111-1307, USA; either version 2 of the License, or
+;; (at your option) any later version; incorporated herein by reference.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; config.inc
+;;
+;; Common configuration options. Some of these are imposed by the kernel.
+;;
+
+%ifndef _CONFIG_INC
+%define _CONFIG_INC
+
+max_cmd_len equ 2047 ; Must be &3; 2047 is the kernel limit
+HIGHMEM_MAX equ 037FFFFFFh ; DEFAULT highest address for an initrd
+DEFAULT_BAUD equ 9600 ; Default baud rate for serial port
+BAUD_DIVISOR equ 115200 ; Serial port parameter
+MAX_FKEYS equ 12 ; Number of F-key help files
+
+;
+; Local boot supported
+;
+%assign HAS_LOCALBOOT 1
+
+;
+; log2(Max filename size Including final null)
+;
+FILENAME_MAX_LG2 equ 8
+FILENAME_MAX equ (1 << FILENAME_MAX_LG2) ; Max mangled filename size
+
+;
+; Version number definitinons
+;
+%include "../version.gen"
+
+%endif ; _CONFIG_INC
diff --git a/contrib/syslinux-4.02/core/configinit.inc b/contrib/syslinux-4.02/core/configinit.inc
new file mode 100644
index 0000000..915e77f
--- /dev/null
+++ b/contrib/syslinux-4.02/core/configinit.inc
@@ -0,0 +1,51 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1994-2008 H. Peter Anvin - All Rights Reserved
+;; Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, Inc., 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.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; configinit.inc
+;;
+;; Initialize the configuration section
+;;
+
+ section .text16
+
+reset_config:
+ call highmemsize
+
+ ; Initialize the .config section
+ xor eax,eax
+ mov si,__config_lma
+ mov di,__config_start
+ mov cx,__config_dwords
+ rep movsd
+
+%ifndef DEPEND
+%if NULLFILE != 0
+ mov al,NULLFILE
+ mov di,FKeyName
+ mov cx,MAX_FKEYS*(1 << FILENAME_MAX_LG2)
+ rep stosb
+%endif
+%endif
+
+ mov di,KbdMap ; Default keymap 1:1
+ xor al,al
+ inc ch ; CX <- 256
+mkkeymap: stosb
+ inc al
+ loop mkkeymap
+
+ mov eax,[HighMemSize]
+ mov [VKernelEnd],eax
+
+ ret
diff --git a/contrib/syslinux-4.02/core/conio.inc b/contrib/syslinux-4.02/core/conio.inc
new file mode 100644
index 0000000..b450502
--- /dev/null
+++ b/contrib/syslinux-4.02/core/conio.inc
@@ -0,0 +1,431 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1994-2008 H. Peter Anvin - All Rights Reserved
+;; Copyright 2009 Intel Corporation; author: H. Peter Anvin
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+;; Boston MA 02111-1307, USA; either version 2 of the License, or
+;; (at your option) any later version; incorporated herein by reference.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; conio.inc
+;;
+;; Console I/O code, except:
+;; writechr, writestr_early - module-dependent
+;; writestr, crlf - writestr.inc
+;; writehex* - writehex.inc
+;;
+
+;
+; loadkeys: Load a LILO-style keymap; file is open on the top of the
+; getc stack.
+;
+ section .text16
+
+loadkeys:
+ mov cx,256
+ mov di,trackbuf
+ call readc
+ jc .done ; EOF already?
+
+ ; Make sure we are at EOF now...
+ call getc
+ jnc .done ; We should be at EOF now!
+
+ ; It was okay, we can now move it into the KbdMap
+ mov si,trackbuf
+ mov di,KbdMap
+ mov cx,256 >> 2
+ rep movsd
+
+.done:
+ call close
+ ret
+
+;
+; get_msg_file: Load a text file and write its contents to the screen,
+; interpreting color codes. Call with the file already
+; on the top of the open/getc stack.
+;
+; Assumes CS == DS == ES.
+;
+get_msg_file:
+ mov byte [TextAttribute],07h ; Default grey on white
+ mov byte [DisplayMask],07h ; Display text in all modes
+ call msg_initvars
+
+print_msg_file:
+.getc:
+ call getc
+ jc .done
+ cmp al,1Ah ; DOS EOF?
+ je .done
+ movzx cx,byte [UsingVGA]
+ and cl,01h
+ inc cx ; CL <- 01h = text mode,
+ ; 02h = graphics mode
+ call [NextCharJump] ; Do what shall be done
+ jmp .getc
+.done:
+ jmp close ; Tailcall!
+
+msg_putchar: ; Normal character
+ cmp al,0Fh ; ^O = color code follows
+ je msg_ctrl_o
+ cmp al,0Dh ; Ignore <CR>
+ je msg_ignore
+ cmp al,0Ah ; <LF> = newline
+ je msg_newline
+ cmp al,0Ch ; <FF> = clear screen
+ je msg_formfeed
+ cmp al,07h ; <BEL> = beep
+ je msg_beep
+ cmp al,19h ; <EM> = return to text mode
+ je msg_novga
+ cmp al,18h ; <CAN> = VGA filename follows
+ je msg_vga
+ jnb .not_modectl
+ cmp al,10h ; 10h to 17h are mode controls
+ jae msg_modectl
+.not_modectl:
+
+msg_normal: call write_serial_displaymask ; Write to serial port
+ test [DisplayMask],cl
+ jz msg_ignore ; Not screen
+ test byte [DisplayCon],01h
+ jz msg_ignore
+ mov bl,[TextAttribute]
+ mov bh,[BIOS_page]
+ mov ah,09h ; Write character/attribute
+ mov cx,1 ; One character only
+ int 10h ; Write to screen
+ mov al,[CursorCol]
+ inc ax
+ cmp al,[VidCols]
+ ja msg_line_wrap ; Screen wraparound
+ mov [CursorCol],al
+
+msg_gotoxy: mov bh,[BIOS_page]
+ mov dx,[CursorDX]
+ mov ah,02h ; Set cursor position
+ int 10h
+msg_ignore: ret
+
+msg_beep: mov ax,0E07h ; Beep
+ xor bx,bx
+ int 10h
+ ret
+
+msg_ctrl_o: ; ^O = color code follows
+ mov word [NextCharJump],msg_setbg
+ ret
+msg_newline: ; Newline char or end of line
+ mov si,crlf_msg
+ call write_serial_str_displaymask
+msg_line_wrap: ; Screen wraparound
+ test [DisplayMask],cl
+ jz msg_ignore
+ mov byte [CursorCol],0
+ mov al,[CursorRow]
+ inc ax
+ cmp al,[VidRows]
+ ja msg_scroll
+ mov [CursorRow],al
+ jmp short msg_gotoxy
+msg_scroll: xor cx,cx ; Upper left hand corner
+ mov dx,[ScreenSize]
+ mov [CursorRow],dh ; New cursor at the bottom
+ mov bh,[ScrollAttribute]
+ mov ax,0601h ; Scroll up one line
+ int 10h
+ jmp short msg_gotoxy
+msg_formfeed: ; Form feed character
+ mov si,crff_msg
+ call write_serial_str_displaymask
+ test [DisplayMask],cl
+ jz msg_ignore
+ xor cx,cx
+ mov [CursorDX],cx ; Upper lefthand corner
+ mov dx,[ScreenSize]
+ mov bh,[TextAttribute]
+ mov ax,0600h ; Clear screen region
+ int 10h
+ jmp msg_gotoxy
+msg_setbg: ; Color background character
+ call unhexchar
+ jc msg_color_bad
+ shl al,4
+ test [DisplayMask],cl
+ jz .dontset
+ mov [TextAttribute],al
+.dontset:
+ mov word [NextCharJump],msg_setfg
+ ret
+msg_setfg: ; Color foreground character
+ call unhexchar
+ jc msg_color_bad
+ test [DisplayMask],cl
+ jz .dontset
+ or [TextAttribute],al ; setbg set foreground to 0
+.dontset:
+ jmp short msg_putcharnext
+msg_vga:
+ mov word [NextCharJump],msg_filename
+ mov di, VGAFileBuf
+ jmp short msg_setvgafileptr
+
+msg_color_bad:
+ mov byte [TextAttribute],07h ; Default attribute
+msg_putcharnext:
+ mov word [NextCharJump],msg_putchar
+ ret
+
+msg_filename: ; Getting VGA filename
+ cmp al,0Ah ; <LF> = end of filename
+ je msg_viewimage
+ cmp al,' '
+ jbe msg_ret ; Ignore space/control char
+ mov di,[VGAFilePtr]
+ cmp di,VGAFileBufEnd
+ jnb msg_ret
+ mov [di],al ; Can't use stosb (DS:)
+ inc di
+msg_setvgafileptr:
+ mov [VGAFilePtr],di
+msg_ret: ret
+
+msg_novga:
+ call vgaclearmode
+ jmp short msg_initvars
+
+msg_viewimage:
+ mov si,[VGAFilePtr]
+ mov byte [si],0 ; Zero-terminate filename
+ mov si,VGAFileBuf
+ mov di,VGAFileMBuf
+ pm_call pm_mangle_name
+ call core_open
+ jz msg_putcharnext ; Not there
+ call vgadisplayfile
+ ; Fall through
+
+ ; Subroutine to initialize variables, also needed
+ ; after loading a graphics file
+msg_initvars:
+ pusha
+ mov bh,[BIOS_page]
+ mov ah,03h ; Read cursor position
+ int 10h
+ mov [CursorDX],dx
+ popa
+ jmp short msg_putcharnext ; Initialize state machine
+
+msg_modectl:
+ and al,07h
+ mov [DisplayMask],al
+ jmp short msg_putcharnext
+
+;
+; write_serial: If serial output is enabled, write character on serial port
+; write_serial_displaymask: d:o, but ignore if DisplayMask & 04h == 0
+;
+write_serial_displaymask:
+ test byte [DisplayMask], 04h
+ jz write_serial.end
+write_serial:
+ pushfd
+ pushad
+ mov bx,[SerialPort]
+ and bx,bx
+ je .noserial
+ push ax
+ mov ah,[FlowInput]
+.waitspace:
+ ; Wait for space in transmit register
+ lea dx,[bx+5] ; DX -> LSR
+ in al,dx
+ test al,20h
+ jz .waitspace
+
+ ; Wait for input flow control
+ inc dx ; DX -> MSR
+ in al,dx
+ and al,ah
+ cmp al,ah
+ jne .waitspace
+.no_flow:
+
+ xchg dx,bx ; DX -> THR
+ pop ax
+ slow_out dx,al ; Send data
+.noserial: popad
+ popfd
+.end: ret
+
+;
+; write_serial_str: write_serial for strings
+; write_serial_str_displaymask: d:o, but ignore if DisplayMask & 04h == 0
+;
+write_serial_str_displaymask:
+ test byte [DisplayMask], 04h
+ jz write_serial_str.end
+
+write_serial_str:
+.loop lodsb
+ and al,al
+ jz .end
+ call write_serial
+ jmp short .loop
+.end: ret
+
+;
+; pollchar: check if we have an input character pending (ZF = 0)
+;
+pollchar:
+ pushad
+ mov ah,11h ; Poll keyboard
+ int 16h
+ jnz .done ; Keyboard response
+ mov dx,[SerialPort]
+ and dx,dx
+ jz .done ; No serial port -> no input
+ mov ax,[SerialTail] ; Already-queued input?
+ cli
+ cmp ax,[SerialHead]
+ jne .done_sti ; If so, return ZF = 0
+ add dx,5 ; DX -> LSR
+ in al,dx
+ test al,1 ; ZF = 0 if data pending
+ jz .done_sti
+ inc dx ; DX -> MSR
+ mov ah,[FlowIgnore] ; Required status bits
+ in al,dx
+ and al,ah
+ cmp al,ah
+ setne al
+ dec al ; Set ZF = 0 if equal
+.done_sti: sti
+.done: popad
+ ret
+
+;
+; getchar: Read a character from keyboard or serial port
+;
+getchar.sti_again:
+ sti
+getchar:
+.again:
+ call do_idle
+ mov ah,11h ; Poll keyboard
+ int 16h
+ jnz .kbd ; Keyboard input?
+ mov bx,[SerialPort]
+ and bx,bx
+ jz .again
+ mov ax,[SerialTail]
+ cli
+ cmp ax,[SerialHead]
+ jne .serial_queued
+ lea dx,[bx+5] ; DX -> LSR
+ in al,dx
+ test al,1
+ jz .sti_again
+ inc dx ; DX -> MSR
+ mov ah,[FlowIgnore]
+ in al,dx
+ and al,ah
+ cmp al,ah
+ jne .sti_again
+.serial: xor ah,ah ; Avoid confusion
+ mov dx,bx ; Data port
+ in al,dx ; Read data
+ sti
+ jmp .done
+.serial_queued:
+ sti ; We already know we'll consume data
+ xchg bx,ax
+ push ds
+ mov ax,aux_seg + (aux.serial >> 4)
+ mov ds,ax
+ mov al,[bx]
+ pop ds
+ inc bx
+ and bx,serial_buf_size-1
+ mov [SerialTail],bx
+ jmp .done
+
+.kbd: mov ah,10h ; Get keyboard input
+ int 16h
+ cmp al,0E0h
+ jnz .not_ext
+ xor al,al
+.not_ext:
+ and al,al
+ jz .func_key
+ mov bx,KbdMap ; Convert character sets
+ xlatb
+.func_key:
+.done:
+ jmp reset_idle ; Character received
+
+%ifdef DEBUG_TRACERS
+;
+; debug hack to print a character with minimal code impact
+;
+debug_tracer: pushad
+ pushfd
+ mov bp,sp
+ mov bx,[bp+9*4] ; Get return address
+ mov al,[cs:bx] ; Get data byte
+ inc word [bp+9*4] ; Return to after data byte
+ call writechr
+ popfd
+ popad
+ ret
+%endif ; DEBUG_TRACERS
+
+ section .data16
+%if IS_ISOLINUX == 0 ; Defined elsewhere for ISOLINUX
+crlf_msg db CR, LF
+null_msg db 0
+%endif
+crff_msg db CR, FF, 0
+
+ section .config
+ ; This is a word to pc_setint16 can set it
+DisplayCon dw 01h ; Console display enabled
+
+ScrollAttribute db 07h ; Grey on white (normal text color)
+
+ section .bss16
+ alignb 2
+NextCharJump resw 1 ; Routine to interpret next print char
+CursorDX equ $
+CursorCol resb 1 ; Cursor column for message file
+CursorRow resb 1 ; Cursor row for message file
+ScreenSize equ $
+VidCols resb 1 ; Columns on screen-1
+VidRows resb 1 ; Rows on screen-1
+
+; Serial console stuff; don't put this in .config becasue we don't want
+; loading a new config file to undo this setting.
+ section .data16
+ alignz 4
+SerialPort dw 0 ; Serial port base (or 0 for no serial port)
+BaudDivisor dw 115200/9600 ; Baud rate divisor
+FlowControl equ $
+FlowOutput db 0 ; Outputs to assert for serial flow
+FlowInput db 0 ; Input bits for serial flow
+FlowIgnore db 0 ; Ignore input unless these bits set
+FlowDummy db 0 ; Unused
+
+ section .bss16
+TextAttribute resb 1 ; Text attribute for message file
+DisplayMask resb 1 ; Display modes mask
+
+ section .text16
+%include "serirq.inc"
diff --git a/contrib/syslinux-4.02/core/console.c b/contrib/syslinux-4.02/core/console.c
new file mode 100644
index 0000000..282c57f
--- /dev/null
+++ b/contrib/syslinux-4.02/core/console.c
@@ -0,0 +1,22 @@
+#include <stddef.h>
+#include <com32.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);
+}
+
+void myputs(const char *str)
+{
+ while (*str)
+ myputchar(*str++);
+}
diff --git a/contrib/syslinux-4.02/core/diskfs.inc b/contrib/syslinux-4.02/core/diskfs.inc
new file mode 100644
index 0000000..9f18c76
--- /dev/null
+++ b/contrib/syslinux-4.02/core/diskfs.inc
@@ -0,0 +1,173 @@
+; -*- fundamental -*- (asm-mode sucks)
+; -----------------------------------------------------------------------
+;
+; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
+; Copyright 2009 Intel Corporation; author: H. Peter Anvin
+;
+; This program is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, Inc., 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.
+;
+; -----------------------------------------------------------------------
+
+;
+; diskfs.inc
+;
+; Common code for conventional disk-based filesystems
+;
+
+;
+; Some semi-configurable constants... change on your own risk.
+;
+NULLFILE equ 0 ; Null character == empty filename
+NULLOFFSET equ 0 ; Position in which to look
+retry_count equ 16 ; How patient are we with the disk?
+%assign HIGHMEM_SLOP 0 ; Avoid this much memory near the top
+LDLINUX_MAGIC equ 0x3eb202fe ; A random number to identify ourselves with
+
+SECTOR_SHIFT equ 9
+SECTOR_SIZE equ (1 << SECTOR_SHIFT)
+
+;
+; The following structure is used for "virtual kernels"; i.e. LILO-style
+; option labels. The options we permit here are `kernel' and `append
+; Since there is no room in the bottom 64K for all of these, we
+; stick them in high memory and copy them down before we need them.
+;
+ struc vkernel
+vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!**
+vk_rname: resb FILENAME_MAX ; Real name
+vk_appendlen: resw 1
+vk_type: resb 1 ; Type of file
+ alignb 4
+vk_append: resb max_cmd_len+1 ; Command line
+ alignb 4
+vk_end: equ $ ; Should be <= vk_size
+ endstruc
+
+
+
+; ---------------------------------------------------------------------------
+; BEGIN CODE
+; ---------------------------------------------------------------------------
+
+;
+; Memory below this point is reserved for the BIOS and the MBR
+;
+ section .earlybss
+ global trackbuf
+trackbufsize equ 8192
+trackbuf resb trackbufsize ; Track buffer goes here
+ ; ends at 2800h
+
+;
+; Common bootstrap code for disk-based derivatives
+;
+%include "diskstart.inc"
+
+
+;
+; Now, everything is "up and running"... patch kaboom for more
+; verbosity and using the full screen system
+;
+ ; E9 = JMP NEAR
+ mov di,kaboom.patch
+ mov al,0e9h
+ stosb
+ mov ax,kaboom2-2
+ sub ax,di
+ stosw
+
+;
+; Now we're all set to start with our *real* business. First load the
+; configuration file (if any) and parse it.
+;
+; In previous versions I avoided using 32-bit registers because of a
+; rumour some BIOSes clobbered the upper half of 32-bit registers at
+; random. I figure, though, that if there are any of those still left
+; they probably won't be trying to install Linux on them...
+;
+; The code is still ripe with 16-bitisms, though. Not worth the hassle
+; to take'm out. In fact, we may want to put them back if we're going
+; to boot ELKS at some point.
+;
+
+;
+; Load configuration file
+;
+ pm_call load_config
+ jz no_config_file
+
+;
+; Now we have the config file open. Parse the config file and
+; run the user interface.
+;
+%include "ui.inc"
+
+;
+;
+; kaboom2: once everything is loaded, replace the part of kaboom
+; starting with "kaboom.patch" with this part
+
+kaboom2:
+ mov si,err_bootfailed
+ call writestr
+ cmp byte [kaboom.again+1],18h ; INT 18h version?
+ je .int18
+ call getchar
+ call vgaclearmode
+ int 19h ; And try once more to boot...
+.norge: jmp short .norge ; If int 19h returned; this is the end
+.int18:
+ call vgaclearmode
+ int 18h
+.noreg: jmp short .noreg ; Nynorsk
+
+; -----------------------------------------------------------------------------
+; Common modules
+; -----------------------------------------------------------------------------
+
+%include "common.inc" ; Universal modules
+%include "plaincon.inc" ; writechr
+%include "writestr.inc" ; String output
+%include "writehex.inc" ; Hexadecimal output
+%include "localboot.inc" ; Disk-based local boot
+
+; -----------------------------------------------------------------------------
+; Begin data section
+; -----------------------------------------------------------------------------
+
+ section .data16
+copyright_str db ' Copyright (C) 1994-'
+ asciidec YEAR
+ db ' H. Peter Anvin et al', CR, LF, 0
+err_bootfailed db CR, LF, 'Boot failed: please change disks and press '
+ db 'a key to continue.', CR, LF, 0
+
+;
+; Config file keyword table
+;
+%include "keywords.inc"
+
+;
+; Extensions to search for (in *forward* order).
+;
+ alignz 4
+exten_table: db '.cbt' ; COMBOOT (specific)
+%if IS_SYSLINUX
+ db '.bss' ; Boot sector (add superblock)
+%endif
+ db '.bs', 0 ; Boot sector
+ db '.com' ; COMBOOT (same as DOS)
+ db '.c32' ; COM32
+exten_table_end:
+ dd 0, 0 ; Need 8 null bytes here
+
+;
+; Misc initialized (data) variables
+;
+%ifdef debug ; This code for debugging only
+debug_magic dw 0D00Dh ; Debug code sentinel
+%endif
diff --git a/contrib/syslinux-4.02/core/diskstart.inc b/contrib/syslinux-4.02/core/diskstart.inc
new file mode 100644
index 0000000..c0ba52a
--- /dev/null
+++ b/contrib/syslinux-4.02/core/diskstart.inc
@@ -0,0 +1,874 @@
+; -----------------------------------------------------------------------
+;
+; 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., 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.
+;
+; -----------------------------------------------------------------------
+
+;
+; diskstart.inc
+;
+; Common early-bootstrap code for harddisk-based Syslinux derivatives.
+;
+
+ section .init
+;
+; Some of the things that have to be saved very early are saved
+; "close" to the initial stack pointer offset, in order to
+; reduce the code size...
+;
+
+StackBuf equ STACK_TOP-44-92 ; Start the stack here (grow down - 4K)
+PartInfo equ StackBuf
+.mbr equ PartInfo
+.gptlen equ PartInfo+16
+.gpt equ PartInfo+20
+FloppyTable equ PartInfo+76
+; Total size of PartInfo + FloppyTable == 76+16 = 92 bytes
+Hidden equ StackBuf-20 ; Partition offset
+OrigFDCTabPtr equ StackBuf-12 ; The 2nd high dword on the stack
+OrigESDI equ StackBuf-8 ; The high dword on the stack
+DriveNumber equ StackBuf-4 ; Drive number
+StackHome equ Hidden ; The start of the canonical stack
+
+;
+; Primary entry point. Tempting as though it may be, we can't put the
+; initial "cli" here; the jmp opcode in the first byte is part of the
+; "magic number" (using the term very loosely) for the DOS superblock.
+;
+bootsec equ $
+_start: jmp short start ; 2 bytes
+ nop ; 1 byte
+;
+; "Superblock" follows -- it's in the boot sector, so it's already
+; loaded and ready for us
+;
+bsOemName db MY_NAME ; The SYS command sets this, so...
+ zb 8-($-bsOemName)
+
+;
+; These are the fields we actually care about. We end up expanding them
+; all to dword size early in the code, so generate labels for both
+; the expanded and unexpanded versions.
+;
+%macro superb 1
+bx %+ %1 equ SuperInfo+($-superblock)*8+4
+bs %+ %1 equ $
+ zb 1
+%endmacro
+%macro superw 1
+bx %+ %1 equ SuperInfo+($-superblock)*8
+bs %+ %1 equ $
+ zw 1
+%endmacro
+%macro superd 1
+bx %+ %1 equ $ ; no expansion for dwords
+bs %+ %1 equ $
+ zd 1
+%endmacro
+superblock equ $
+ superw BytesPerSec
+ superb SecPerClust
+ superw ResSectors
+ superb FATs
+ superw RootDirEnts
+ superw Sectors
+ superb Media
+ superw FATsecs
+ superw SecPerTrack
+ superw Heads
+superinfo_size equ ($-superblock)-1 ; How much to expand
+ superd Hidden
+ superd HugeSectors
+ ;
+ ; This is as far as FAT12/16 and FAT32 are consistent
+ ;
+ ; FAT12/16 need 26 more bytes,
+ ; FAT32 need 54 more bytes
+ ;
+superblock_len_fat16 equ $-superblock+26
+superblock_len_fat32 equ $-superblock+54
+ zb 54 ; Maximum needed size
+superblock_max equ $-superblock
+
+ global SecPerClust
+SecPerClust equ bxSecPerClust
+
+;
+; Note we don't check the constraints above now; we did that at install
+; time (we hope!)
+;
+start:
+ cli ; No interrupts yet, please
+ cld ; Copy upwards
+;
+; Set up the stack
+;
+ xor cx,cx
+ mov ss,cx
+ mov sp,StackBuf-2 ; Just below BSS (-2 for alignment)
+ push dx ; Save drive number (in DL)
+ push es ; Save initial ES:DI -> $PnP pointer
+ push di
+ mov es,cx
+
+;
+; DS:SI may contain a partition table entry and possibly a GPT entry.
+; Preserve it for us. This saves 56 bytes of the GPT entry, which is
+; currently the maximum we care about. Total is 76 bytes.
+;
+ mov cl,(16+4+56)/2 ; Save partition info
+ mov di,PartInfo
+ rep movsw ; This puts CX back to zero
+
+ mov ds,cx ; Now we can initialize DS...
+
+;
+; Now sautee the BIOS floppy info block to that it will support decent-
+; size transfers; the floppy block is 11 bytes and is stored in the
+; INT 1Eh vector (brilliant waste of resources, eh?)
+;
+; Of course, if BIOSes had been properly programmed, we wouldn't have
+; had to waste precious space with this code.
+;
+ mov bx,fdctab
+ lfs si,[bx] ; FS:SI -> original fdctab
+ push fs ; Save on stack in case we need to bail
+ push si
+
+ ; Save the old fdctab even if hard disk so the stack layout
+ ; is the same. The instructions above do not change the flags
+ and dl,dl ; If floppy disk (00-7F), assume no
+ ; partition table
+ js harddisk
+
+floppy:
+ xor ax,ax
+ mov cl,6 ; 12 bytes (CX == 0)
+ ; es:di -> FloppyTable already
+ ; This should be safe to do now, interrupts are off...
+ mov [bx],di ; FloppyTable
+ mov [bx+2],ax ; Segment 0
+ fs rep movsw ; Faster to move words
+ mov cl,[bsSecPerTrack] ; Patch the sector count
+ mov [di-76+8],cl
+
+ push ax ; Partition offset == 0
+ push ax
+ push ax
+ push ax
+
+ int 13h ; Some BIOSes need this
+ jmp short not_harddisk
+;
+; The drive number and possibly partition information was passed to us
+; by the BIOS or previous boot loader (MBR). Current "best practice" is to
+; trust that rather than what the superblock contains.
+;
+; Note: di points to beyond the end of PartInfo
+;
+harddisk:
+ test byte [di-76],7Fh ; Sanity check: "active flag" should
+ jnz .no_partition ; be 00 or 80
+ cmp [di-76+4],cl ; Sanity check: partition type != 0
+ je .no_partition
+ cmp eax,'!GPT' ; !GPT signature?
+ jne .mbr
+ cmp byte [di-76+4],0EDh ; Synthetic GPT partition entry?
+ jne .mbr
+.gpt: ; GPT-style partition info
+ push dword [di-76+20+36]
+ push dword [di-76+20+32]
+ jmp .gotoffs
+.mbr: ; MBR-style partition info
+ push cx ; Upper half partition offset == 0
+ push cx
+ push dword [di-76+8] ; Partition offset (dword)
+ jmp .gotoffs
+.no_partition:
+;
+; No partition table given... assume that the Hidden field in the boot sector
+; tells the truth (in particular, is zero if this is an unpartitioned disk.)
+;
+ push cx
+ push cx
+ push dword [bsHidden]
+.gotoffs:
+;
+; Get disk drive parameters (don't trust the superblock.) Don't do this for
+; floppy drives -- INT 13:08 on floppy drives will (may?) return info about
+; what the *drive* supports, not about the *media*. Fortunately floppy disks
+; tend to have a fixed, well-defined geometry which is stored in the superblock.
+;
+ ; DL == drive # still
+ mov ah,08h
+ int 13h
+ jc no_driveparm
+ and ah,ah
+ jnz no_driveparm
+ shr dx,8
+ inc dx ; Contains # of heads - 1
+ mov [bsHeads],dx
+ and cx,3fh
+ mov [bsSecPerTrack],cx
+no_driveparm:
+not_harddisk:
+;
+; Ready to enable interrupts, captain
+;
+ sti
+
+;
+; Do we have EBIOS (EDD)?
+;
+eddcheck:
+ mov bx,55AAh
+ mov ah,41h ; EDD existence query
+ mov dl,[DriveNumber]
+ int 13h
+ jc .noedd
+ cmp bx,0AA55h
+ jne .noedd
+ test cl,1 ; Extended disk access functionality set
+ jz .noedd
+ ;
+ ; We have EDD support...
+ ;
+ mov byte [getonesec.jmp+1],(getonesec_ebios-(getonesec.jmp+2))
+.noedd:
+
+;
+; Load the first sector of LDLINUX.SYS; this used to be all proper
+; with parsing the superblock and root directory; it doesn't fit
+; together with EBIOS support, unfortunately.
+;
+ mov eax,strict dword 0xdeadbeef
+Sect1Ptr0 equ $-4
+ mov edx,strict dword 0xfeedface
+Sect1Ptr1 equ $-4
+ mov bx,ldlinux_sys ; Where to load it
+ call getonesec
+
+ ; Some modicum of integrity checking
+ cmp dword [ldlinux_magic+4],LDLINUX_MAGIC^HEXDATE
+ jne kaboom
+
+ ; Go for it...
+ jmp 0:ldlinux_ent
+
+
+;
+; getonesec: load a single disk linear sector EDX:EAX into the buffer
+; at ES:BX.
+;
+; This routine assumes CS == DS == SS, and trashes most registers.
+;
+; Stylistic note: use "xchg" instead of "mov" when the source is a register
+; that is dead from that point; this saves space. However, please keep
+; the order to dst,src to keep things sane.
+;
+getonesec:
+ add eax,[Hidden] ; Add partition offset
+ adc edx,[Hidden+4]
+ mov cx,retry_count
+.jmp: jmp strict short getonesec_cbios
+
+;
+; getonesec_ebios:
+;
+; getonesec implementation for EBIOS (EDD)
+;
+getonesec_ebios:
+.retry:
+ ; Form DAPA on stack
+ push edx
+ push eax
+ push es
+ push bx
+ push word 1
+ push word 16
+ mov si,sp
+ pushad
+ mov ah,42h ; Extended Read
+ call xint13
+ popad
+ lea sp,[si+16] ; Remove DAPA
+ jc .error
+ ret
+
+.error:
+ ; Some systems seem to get "stuck" in an error state when
+ ; using EBIOS. Doesn't happen when using CBIOS, which is
+ ; good, since some other systems get timeout failures
+ ; waiting for the floppy disk to spin up.
+
+ pushad ; Try resetting the device
+ xor ax,ax
+ call xint13
+ popad
+ loop .retry ; CX-- and jump if not zero
+
+ ; Total failure. Try falling back to CBIOS.
+ mov byte [getonesec.jmp+1],(getonesec_cbios-(getonesec.jmp+2))
+
+;
+; getonesec_cbios:
+;
+; getlinsec implementation for legacy CBIOS
+;
+getonesec_cbios:
+.retry:
+ pushad
+
+ movzx esi,word [bsSecPerTrack]
+ movzx edi,word [bsHeads]
+ ;
+ ; Dividing by sectors to get (track,sector): we may have
+ ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
+ ;
+ div esi
+ xor cx,cx
+ xchg cx,dx ; CX <- sector index (0-based)
+ ; EDX <- 0
+ ; eax = track #
+ div edi ; Convert track to head/cyl
+
+ cmp eax,1023 ; Outside the CHS range?
+ ja kaboom
+
+ ;
+ ; Now we have AX = cyl, DX = head, CX = sector (0-based),
+ ; SI = bsSecPerTrack, ES:BX = data target
+ ;
+ shl ah,6 ; Because IBM was STOOPID
+ ; and thought 8 bits were enough
+ ; then thought 10 bits were enough...
+ inc cx ; Sector numbers are 1-based, sigh
+ or cl,ah
+ mov ch,al
+ mov dh,dl
+ mov ax,0201h ; Read one sector
+ call xint13
+ popad
+ jc .error
+ ret
+
+.error:
+ loop .retry
+ ; Fall through to disk_error
+
+;
+; kaboom: write a message and bail out.
+;
+ global kaboom
+disk_error:
+kaboom:
+ xor si,si
+ mov ss,si
+ mov sp,OrigFDCTabPtr ; Reset stack
+ mov ds,si ; Reset data segment
+ pop dword [fdctab] ; Restore FDC table
+.patch: ; When we have full code, intercept here
+ mov si,bailmsg
+ call writestr_early
+
+ xor ax,ax
+.again: int 16h ; Wait for keypress
+ ; NB: replaced by int 18h if
+ ; chosen at install time..
+ int 19h ; And try once more to boot...
+.norge: hlt ; If int 19h returned; this is the end
+ jmp short .norge
+
+;
+;
+; writestr_early: write a null-terminated string to the console
+; This assumes we're on page 0. This is only used for early
+; messages, so it should be OK.
+;
+writestr_early:
+ pushad
+.loop: lodsb
+ and al,al
+ jz .return
+ mov ah,0Eh ; Write to screen as TTY
+ mov bx,0007h ; Attribute
+ int 10h
+ jmp short .loop
+.return: popad
+ ret
+
+;
+; INT 13h wrapper function
+;
+xint13:
+ mov dl,[DriveNumber]
+ int 13h
+ ret
+
+;
+; Error message on failure
+;
+bailmsg: db 'Boot error', 0Dh, 0Ah, 0
+
+ ; This fails if the boot sector overflowsg
+ zb 1FEh-($-$$)
+
+bootsignature dw 0xAA55
+
+;
+; ===========================================================================
+; End of boot sector
+; ===========================================================================
+; Start of LDLINUX.SYS
+; ===========================================================================
+
+LDLINUX_SYS equ ($-$$)+TEXT_START
+ldlinux_sys:
+
+syslinux_banner db CR, LF, MY_NAME, ' ', VERSION_STR, ' ', DATE_STR, ' ', 0
+ db CR, LF, 1Ah ; EOF if we "type" this in DOS
+
+ alignz 8
+ldlinux_magic dd LDLINUX_MAGIC
+ dd LDLINUX_MAGIC^HEXDATE
+
+;
+; This area is patched by the installer. It is found by looking for
+; LDLINUX_MAGIC, plus 8 bytes.
+;
+SUBVOL_MAX equ 256
+CURRENTDIR_MAX equ FILENAME_MAX
+
+patch_area:
+DataSectors dw 0 ; Number of sectors (not including bootsec)
+ADVSectors dw 0 ; Additional sectors for ADVs
+LDLDwords dd 0 ; Total dwords starting at ldlinux_sys,
+CheckSum dd 0 ; Checksum starting at ldlinux_sys
+ ; value = LDLINUX_MAGIC - [sum of dwords]
+MaxTransfer dw 127 ; Max sectors to transfer
+EPAPtr dw EPA - LDLINUX_SYS ; Pointer to the extended patch area
+
+;
+; Extended patch area -- this is in .data16 so it doesn't occupy space in
+; the first sector. Use this structure for anything that isn't used by
+; the first sector itself.
+;
+ section .data16
+ alignz 2
+EPA:
+ADVSecPtr dw ADVSec0 - LDLINUX_SYS
+CurrentDirPtr dw CurrentDirName-LDLINUX_SYS ; Current directory name string
+CurrentDirLen dw CURRENTDIR_MAX
+SubvolPtr dw SubvolName-LDLINUX_SYS
+SubvolLen dw SUBVOL_MAX
+SecPtrOffset dw SectorPtrs-LDLINUX_SYS
+SecPtrCnt dw (SectorPtrsEnd - SectorPtrs)/10
+
+;
+; Boot sector patch pointers
+;
+Sect1Ptr0Ptr dw Sect1Ptr0 - bootsec ; Pointers to Sector 1 location
+Sect1Ptr1Ptr dw Sect1Ptr1 - bootsec
+RAIDPatchPtr dw kaboom.again - bootsec ; Patch to INT 18h in RAID mode
+
+;
+; Base directory name and subvolume, if applicable.
+;
+%define HAVE_CURRENTDIRNAME
+ global CurrentDirName, SubvolName
+CurrentDirName times CURRENTDIR_MAX db 0
+SubvolName times SUBVOL_MAX db 0
+
+ section .init
+ldlinux_ent:
+;
+; Note that some BIOSes are buggy and run the boot sector at 07C0:0000
+; instead of 0000:7C00 and the like. We don't want to add anything
+; more to the boot sector, so it is written to not assume a fixed
+; value in CS, but we don't want to deal with that anymore from now
+; on.
+;
+ sti ; In case of broken INT 13h BIOSes
+
+;
+; Tell the user we got this far
+;
+ mov si,syslinux_banner
+ call writestr_early
+
+;
+; Checksum data thus far
+;
+ mov si,ldlinux_sys
+ mov cx,SECTOR_SIZE >> 2
+ mov edx,-LDLINUX_MAGIC
+.checksum:
+ lodsd
+ add edx,eax
+ loop .checksum
+ mov [CheckSum],edx ; Save intermediate result
+
+;
+; Tell the user if we're using EBIOS or CBIOS
+;
+print_bios:
+ mov si,cbios_name
+ cmp byte [getonesec.jmp+1],(getonesec_ebios-(getonesec.jmp+2))
+ jne .cbios
+ mov si,ebios_name
+ mov byte [getlinsec.jmp+1],(getlinsec_ebios-(getlinsec.jmp+2))
+.cbios:
+ mov [BIOSName],si
+ call writestr_early
+
+ section .earlybss
+%define HAVE_BIOSNAME 1
+BIOSName resw 1
+
+ section .init
+;
+; Now we read the rest of LDLINUX.SYS.
+;
+load_rest:
+ lea esi,[SectorPtrs]
+ mov ebx,TEXT_START+2*SECTOR_SIZE ; Where we start loading
+ mov cx,[DataSectors]
+ dec cx ; Minus this sector
+
+.get_chunk:
+ jcxz .done
+ mov eax,[si]
+ mov edx,[si+4]
+ movzx ebp,word [si+8]
+ sub cx,bp
+ push ebx
+ shr ebx,4 ; Convert to a segment
+ mov es,bx
+ xor bx,bx
+ call getlinsec
+ pop ebx
+ shl ebp,SECTOR_SHIFT
+ add ebx,ebp
+ add si,10
+ jmp .get_chunk
+
+.done:
+
+;
+; All loaded up, verify that we got what we needed.
+; Note: the checksum field is embedded in the checksum region, so
+; by the time we get to the end it should all cancel out.
+;
+verify_checksum:
+ mov si,ldlinux_sys + SECTOR_SIZE
+ mov ecx,[LDLDwords]
+ sub ecx,SECTOR_SIZE >> 2
+ mov eax,[CheckSum]
+.checksum:
+ add eax,[si]
+ add si,4
+ jnz .nowrap
+ ; Handle segment wrap
+ mov dx,ds
+ add dx,1000h
+ mov ds,dx
+.nowrap:
+ dec ecx
+ jnz .checksum
+
+ and eax,eax ; Should be zero
+ jz all_read ; We're cool, go for it!
+
+;
+; Uh-oh, something went bad...
+;
+ mov si,checksumerr_msg
+ call writestr_early
+ jmp kaboom
+
+;
+; -----------------------------------------------------------------------------
+; Subroutines that have to be in the first sector
+; -----------------------------------------------------------------------------
+
+
+
+;
+; getlinsec: load a sequence of BP floppy sector given by the linear sector
+; number in EAX into the buffer at ES:BX. We try to optimize
+; by loading up to a whole track at a time, but the user
+; is responsible for not crossing a 64K boundary.
+; (Yes, BP is weird for a count, but it was available...)
+;
+; On return, BX points to the first byte after the transferred
+; block.
+;
+; This routine assumes CS == DS.
+;
+ global getlinsec
+getlinsec:
+ pushad
+ add eax,[Hidden] ; Add partition offset
+ adc edx,[Hidden+4]
+.jmp: jmp strict short getlinsec_cbios
+
+;
+; getlinsec_ebios:
+;
+; getlinsec implementation for EBIOS (EDD)
+;
+getlinsec_ebios:
+.loop:
+ push bp ; Sectors left
+.retry2:
+ call maxtrans ; Enforce maximum transfer size
+ movzx edi,bp ; Sectors we are about to read
+ mov cx,retry_count
+.retry:
+
+ ; Form DAPA on stack
+ push edx
+ push eax
+ push es
+ push bx
+ push di
+ push word 16
+ mov si,sp
+ pushad
+ mov ah,42h ; Extended Read
+ push ds
+ push ss
+ pop ds
+ call xint13
+ pop ds
+ popad
+ lea sp,[si+16] ; Remove DAPA
+ jc .error
+ pop bp
+ add eax,edi ; Advance sector pointer
+ adc edx,0
+ sub bp,di ; Sectors left
+ shl di,SECTOR_SHIFT ; 512-byte sectors
+ add bx,di ; Advance buffer pointer
+ and bp,bp
+ jnz .loop
+
+ popad
+ ret
+
+.error:
+ ; Some systems seem to get "stuck" in an error state when
+ ; using EBIOS. Doesn't happen when using CBIOS, which is
+ ; good, since some other systems get timeout failures
+ ; waiting for the floppy disk to spin up.
+
+ pushad ; Try resetting the device
+ xor ax,ax
+ mov dl,[DriveNumber]
+ int 13h
+ popad
+ loop .retry ; CX-- and jump if not zero
+
+ ;shr word [MaxTransfer],1 ; Reduce the transfer size
+ ;jnz .retry2
+
+ ; Total failure. Try falling back to CBIOS.
+ mov byte [getlinsec.jmp+1],(getlinsec_cbios-(getlinsec.jmp+2))
+ ;mov byte [MaxTransfer],63 ; Max possibe CBIOS transfer
+
+ pop bp
+ ; ... fall through ...
+
+;
+; getlinsec_cbios:
+;
+; getlinsec implementation for legacy CBIOS
+;
+getlinsec_cbios:
+.loop:
+ push edx
+ push eax
+ push bp
+ push bx
+
+ movzx esi,word [bsSecPerTrack]
+ movzx edi,word [bsHeads]
+ ;
+ ; Dividing by sectors to get (track,sector): we may have
+ ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
+ ;
+ div esi
+ xor cx,cx
+ xchg cx,dx ; CX <- sector index (0-based)
+ ; EDX <- 0
+ ; eax = track #
+ div edi ; Convert track to head/cyl
+
+ cmp eax,1023 ; Outside the CHS range?
+ ja kaboom
+
+ ;
+ ; Now we have AX = cyl, DX = head, CX = sector (0-based),
+ ; BP = sectors to transfer, SI = bsSecPerTrack,
+ ; ES:BX = data target
+ ;
+
+ call maxtrans ; Enforce maximum transfer size
+
+ ; Must not cross track boundaries, so BP <= SI-CX
+ sub si,cx
+ cmp bp,si
+ jna .bp_ok
+ mov bp,si
+.bp_ok:
+
+ shl ah,6 ; Because IBM was STOOPID
+ ; and thought 8 bits were enough
+ ; then thought 10 bits were enough...
+ inc cx ; Sector numbers are 1-based, sigh
+ or cl,ah
+ mov ch,al
+ mov dh,dl
+ xchg ax,bp ; Sector to transfer count
+ mov ah,02h ; Read sectors
+ mov bp,retry_count
+.retry:
+ pushad
+ call xint13
+ popad
+ jc .error
+.resume:
+ movzx ecx,al ; ECX <- sectors transferred
+ shl ax,SECTOR_SHIFT ; Convert sectors in AL to bytes in AX
+ pop bx
+ add bx,ax
+ pop bp
+ pop eax
+ pop edx
+ add eax,ecx
+ sub bp,cx
+ jnz .loop
+ popad
+ ret
+
+.error:
+ dec bp
+ jnz .retry
+
+ xchg ax,bp ; Sectors transferred <- 0
+ shr word [MaxTransfer],1
+ jnz .resume
+ jmp kaboom
+
+maxtrans:
+ cmp bp,[MaxTransfer]
+ jna .ok
+ mov bp,[MaxTransfer]
+.ok: ret
+
+;
+; Checksum error message
+;
+checksumerr_msg db ' Load error - ', 0 ; Boot failed appended
+
+;
+; BIOS type string
+;
+cbios_name db 'CHS', 0 ; CHS/CBIOS
+ebios_name db 'EDD', 0 ; EDD/EBIOS
+
+;
+; Debug routine
+;
+%ifdef debug
+safedumpregs:
+ cmp word [Debug_Magic],0D00Dh
+ jnz nc_return
+ jmp dumpregs
+%endif
+
+rl_checkpt equ $ ; Must be <= 8000h
+
+rl_checkpt_off equ ($-$$)
+%ifndef DEPEND
+ %if rl_checkpt_off > 3F6h ; Need one extent
+ %assign rl_checkpt_overflow rl_checkpt_off - 3F6h
+ %error Sector 1 overflow by rl_checkpt_overflow bytes
+ %endif
+%endif
+
+;
+; Extent pointers... each extent contains an 8-byte LBA and an 2-byte
+; sector count. In most cases, we will only ever need a handful of
+; extents, but we have to assume a maximally fragmented system where each
+; extent contains only one sector.
+;
+ alignz 2
+MaxInitDataSize equ 96 << 10
+MaxLMA equ TEXT_START+SECTOR_SIZE+MaxInitDataSize
+SectorPtrs zb 10*(MaxInitDataSize >> SECTOR_SHIFT)
+SectorPtrsEnd equ $
+
+; ----------------------------------------------------------------------------
+; End of code and data that have to be in the first sector
+; ----------------------------------------------------------------------------
+
+ section .text16
+all_read:
+ ; We enter here with both DS and ES scrambled...
+ xor ax,ax
+ mov ds,ax
+ mov es,ax
+;
+; Let the user (and programmer!) know we got this far. This used to be
+; in Sector 1, but makes a lot more sense here.
+;
+ mov si,copyright_str
+ call writestr_early
+
+
+;
+; Insane hack to expand the DOS superblock to dwords
+;
+expand_super:
+ xor eax,eax
+ mov si,superblock
+ mov di,SuperInfo
+ mov cx,superinfo_size
+.loop:
+ lodsw
+ dec si
+ stosd ; Store expanded word
+ xor ah,ah
+ stosd ; Store expanded byte
+ loop .loop
+
+
+;
+; Common initialization code
+;
+%include "init.inc"
+
+ pushad
+ mov eax,ROOT_FS_OPS
+ movzx dx,byte [DriveNumber]
+ ; DH = 0: we are boot from disk not CDROM
+ mov ecx,[Hidden]
+ mov ebx,[Hidden+4]
+ mov si,[bsHeads]
+ mov di,[bsSecPerTrack]
+ movzx ebp,word [MaxTransfer]
+ pm_call fs_init
+ popad
+
+ section .bss16
+SuperInfo resq 16 ; The first 16 bytes expanded 8 times
+
+ section .text16
diff --git a/contrib/syslinux-4.02/core/extern.inc b/contrib/syslinux-4.02/core/extern.inc
new file mode 100644
index 0000000..64edea6
--- /dev/null
+++ b/contrib/syslinux-4.02/core/extern.inc
@@ -0,0 +1,32 @@
+;
+; extern.inc
+;
+; Prototypes for external functions
+
+%ifndef EXTERN_INC
+%define EXTERN_INC
+
+ ; rllpack.c
+ extern rllpack, rllunpack
+
+ ; fs.c
+ extern fs_init, pm_searchdir, getfssec, getfsbytes
+ extern pm_mangle_name, load_config
+ extern pm_open_file, pm_close_file
+ extern SectorSize, SectorShift
+
+ ; chdir.c
+ extern pm_realpath
+
+ ; readdir.c
+ extern opendir, readdir, closedir
+
+ ; newconfig.c
+ extern pm_is_config_file
+
+%if IS_PXELINUX
+ ; pxe.c
+ extern unload_pxe, reset_pxe
+%endif
+
+%endif ; EXTERN_INC
diff --git a/contrib/syslinux-4.02/core/font.inc b/contrib/syslinux-4.02/core/font.inc
new file mode 100644
index 0000000..1223635
--- /dev/null
+++ b/contrib/syslinux-4.02/core/font.inc
@@ -0,0 +1,152 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1994-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., 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.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; font.inc
+;;
+;; VGA font handling code
+;;
+
+ section .text16
+
+;
+; loadfont: Load a .psf font file and install it onto the VGA console
+; (if we're not on a VGA screen then ignore.)
+; The font is on top of the getc stack.
+;
+loadfont.err: jmp close ; Tailcall the close routine
+
+loadfont:
+ mov di,trackbuf
+ mov cx,4
+ call readc ; Read header
+ jc .err
+
+ mov ax,[trackbuf] ; Magic number
+ cmp ax,0436h
+ jne .err
+
+ mov al,[trackbuf+2] ; File mode
+ cmp al,5 ; Font modes 0-5 supported
+ ja .err
+
+ xor bx,bx
+ mov bh,[trackbuf+3] ; Height of font
+ cmp bh,2 ; VGA minimum
+ jb .err
+ cmp bh,32 ; VGA maximum
+ ja .err
+
+ ; Load the actual font
+ mov di,trackbuf
+ mov cx,bx ; Bytes = font height * 256
+ call readc
+ jc .err
+
+ call close
+
+ ; Copy to font buffer
+ mov si,trackbuf ; Start of font data
+ mov [VGAFontSize],bh
+ push es
+ mov cx,aux_seg
+ mov es,cx
+ mov di,aux.fontbuf
+ mov cx,bx
+ shr cx,2
+ rep movsd
+ pop es
+
+ mov [UserFont], byte 1 ; Set font flag
+
+;
+; use_font:
+; This routine activates whatever font happens to be in the
+; vgafontbuf, and updates the adjust_screen data.
+; Must be called with CS = DS
+;
+use_font:
+ test byte [UsingVGA], ~03h ; Nonstandard mode?
+ jz .modeok
+ call vgaclearmode
+
+.modeok:
+ test [UserFont], byte 1 ; Are we using a user-specified font?
+ jz adjust_screen ; If not, just do the normal stuff
+
+ push es
+ mov bp,aux_seg
+ mov es,bp
+
+ mov bp,aux.fontbuf ; ES:BP -> font
+ mov bh,[VGAFontSize]
+ xor bl,bl ; Needed by both INT 10h calls
+
+ test byte [UsingVGA], 01h ; Are we in graphics mode?
+ jz .text
+
+.graphics:
+ xor cx,cx
+ mov cl,bh ; CX = bytes/character
+ mov ax,[GXPixRows]
+ div cl ; Compute char rows per screen
+ mov dl,al
+ dec ax
+ mov [VidRows],al
+ mov ax,1121h ; Set user character table
+ int 10h
+ mov ax,[GXPixCols]
+ shr ax,3 ; 8 pixels/character
+ dec ax
+ mov [VidCols],al
+ pop es
+ ret ; No need to call adjust_screen
+
+.text:
+ mov cx,256
+ xor dx,dx
+ mov ax,1110h
+ int 10h ; Load into VGA RAM
+ pop es
+
+ xor bl,bl
+ mov ax,1103h ; Select page 0
+ int 10h
+
+;
+; adjust_screen: Set the internal variables associated with the screen size.
+; This is a subroutine in case we're loading a custom font.
+;
+adjust_screen:
+ pusha
+ mov al,[BIOS_vidrows]
+ and al,al
+ jnz vidrows_ok
+ mov al,24 ; No vidrows in BIOS, assume 25
+ ; (Remember: vidrows == rows-1)
+vidrows_ok: mov [VidRows],al
+ mov ah,0fh
+ int 10h ; Read video state
+ dec ah ; Store count-1 (same as rows)
+ mov [VidCols],ah
+ popa
+ ret
+
+ section .data16
+ alignz 2
+VGAFontSize dw 16 ; Defaults to 16 byte font
+UserFont db 0 ; Using a user-specified font
+
+ section .bss16
+ alignb 4
+GXPixCols resw 1 ; Graphics mode pixel columns
+GXPixRows resw 1 ; Graphics mode pixel rows
diff --git a/contrib/syslinux-4.02/core/fs/btrfs/btrfs.c b/contrib/syslinux-4.02/core/fs/btrfs/btrfs.c
new file mode 100644
index 0000000..b6a14e3
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/btrfs/btrfs.c
@@ -0,0 +1,674 @@
+/*
+ * btrfs.c -- readonly btrfs support for syslinux
+ * Some data structures are derivated from btrfs-tools-0.19 ctree.h
+ * Copyright 2009 Intel Corporation; author: alek.du@intel.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.
+ *
+ */
+
+#include <dprintf.h>
+#include <stdio.h>
+#include <string.h>
+#include <cache.h>
+#include <core.h>
+#include <disk.h>
+#include <fs.h>
+#include <dirent.h>
+#include "btrfs.h"
+
+/* compare function used for bin_search */
+typedef int (*cmp_func)(void *ptr1, void *ptr2);
+
+/* simple but useful bin search, used for chunk search and btree search */
+static int bin_search(void *ptr, int item_size, void *cmp_item, cmp_func func,
+ int min, int max, int *slot)
+{
+ int low = min;
+ int high = max;
+ int mid;
+ int ret;
+ unsigned long offset;
+ void *item;
+
+ while (low < high) {
+ mid = (low + high) / 2;
+ offset = mid * item_size;
+
+ item = ptr + offset;
+ ret = func(item, cmp_item);
+
+ if (ret < 0)
+ low = mid + 1;
+ else if (ret > 0)
+ high = mid;
+ else {
+ *slot = mid;
+ return 0;
+ }
+ }
+ *slot = low;
+ return 1;
+}
+
+/* XXX: these should go into the filesystem instance structure */
+static struct btrfs_chunk_map chunk_map;
+static struct btrfs_super_block sb;
+static u64 fs_tree;
+
+static int btrfs_comp_chunk_map(struct btrfs_chunk_map_item *m1,
+ struct btrfs_chunk_map_item *m2)
+{
+ if (m1->logical > m2->logical)
+ return 1;
+ if (m1->logical < m2->logical)
+ return -1;
+ return 0;
+}
+
+/* insert a new chunk mapping item */
+static void insert_map(struct btrfs_chunk_map_item *item)
+{
+ int ret;
+ int slot;
+ int i;
+
+ if (chunk_map.map == NULL) { /* first item */
+ chunk_map.map_length = BTRFS_MAX_CHUNK_ENTRIES;
+ chunk_map.map = (struct btrfs_chunk_map_item *)
+ malloc(chunk_map.map_length * sizeof(*chunk_map.map));
+ chunk_map.map[0] = *item;
+ chunk_map.cur_length = 1;
+ return;
+ }
+ ret = bin_search(chunk_map.map, sizeof(*item), item,
+ (cmp_func)btrfs_comp_chunk_map, 0,
+ chunk_map.cur_length, &slot);
+ if (ret == 0)/* already in map */
+ return;
+ if (chunk_map.cur_length == BTRFS_MAX_CHUNK_ENTRIES) {
+ /* should be impossible */
+ printf("too many chunk items\n");
+ return;
+ }
+ for (i = chunk_map.cur_length; i > slot; i--)
+ chunk_map.map[i] = chunk_map.map[i-1];
+ chunk_map.map[slot] = *item;
+ chunk_map.cur_length++;
+}
+
+/*
+ * from sys_chunk_array or chunk_tree, we can convert a logical address to
+ * a physical address we can not support multi device case yet
+ */
+static u64 logical_physical(u64 logical)
+{
+ struct btrfs_chunk_map_item item;
+ int slot, ret;
+
+ item.logical = logical;
+ ret = bin_search(chunk_map.map, sizeof(*chunk_map.map), &item,
+ (cmp_func)btrfs_comp_chunk_map, 0,
+ chunk_map.cur_length, &slot);
+ if (ret == 0)
+ slot++;
+ else if (slot == 0)
+ return -1;
+ if (logical >=
+ chunk_map.map[slot-1].logical + chunk_map.map[slot-1].length)
+ return -1;
+ return chunk_map.map[slot-1].physical + logical -
+ chunk_map.map[slot-1].logical;
+}
+
+/* cache read from disk, offset and count are bytes */
+static int btrfs_read(struct fs_info *fs, char *buf, u64 offset, u64 count)
+{
+ const char *cd;
+ size_t block_size = fs->fs_dev->cache_block_size;
+ size_t off, cnt, total;
+ block_t block;
+
+ total = count;
+ while (count > 0) {
+ block = offset / block_size;
+ off = offset % block_size;
+ cd = get_cache(fs->fs_dev, block);
+ if (!cd)
+ break;
+ cnt = block_size - off;
+ if (cnt > count)
+ cnt = count;
+ memcpy(buf, cd + off, cnt);
+ count -= cnt;
+ buf += cnt;
+ offset += cnt;
+ }
+ return total - count;
+}
+
+/* btrfs has several super block mirrors, need to calculate their location */
+static inline u64 btrfs_sb_offset(int mirror)
+{
+ u64 start = 16 * 1024;
+ if (mirror)
+ return start << (BTRFS_SUPER_MIRROR_SHIFT * mirror);
+ return BTRFS_SUPER_INFO_OFFSET;
+}
+
+/* find the most recent super block */
+static void btrfs_read_super_block(struct fs_info *fs)
+{
+ int i;
+ int ret;
+ u8 fsid[BTRFS_FSID_SIZE];
+ u64 offset;
+ u64 transid = 0;
+ struct btrfs_super_block buf;
+
+ sb.total_bytes = ~0; /* Unknown as of yet */
+
+ /* find most recent super block */
+ for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
+ offset = btrfs_sb_offset(i);
+ dprintf("btrfs super: %llu max %llu\n",
+ offset, sb.total_bytes);
+ if (offset >= sb.total_bytes)
+ break;
+
+ ret = btrfs_read(fs, (char *)&buf, offset, sizeof(buf));
+ if (ret < sizeof(buf))
+ break;
+
+ if (buf.bytenr != offset ||
+ strncmp((char *)(&buf.magic), BTRFS_MAGIC,
+ sizeof(buf.magic)))
+ continue;
+
+ if (i == 0)
+ memcpy(fsid, buf.fsid, sizeof(fsid));
+ else if (memcmp(fsid, buf.fsid, sizeof(fsid)))
+ continue;
+
+ if (buf.generation > transid) {
+ memcpy(&sb, &buf, sizeof(sb));
+ transid = buf.generation;
+ }
+ }
+}
+
+static inline unsigned long btrfs_chunk_item_size(int num_stripes)
+{
+ return sizeof(struct btrfs_chunk) +
+ sizeof(struct btrfs_stripe) * (num_stripes - 1);
+}
+
+static void clear_path(struct btrfs_path *path)
+{
+ memset(path, 0, sizeof(*path));
+}
+
+static int btrfs_comp_keys(struct btrfs_disk_key *k1, struct btrfs_disk_key *k2)
+{
+ if (k1->objectid > k2->objectid)
+ return 1;
+ if (k1->objectid < k2->objectid)
+ return -1;
+ if (k1->type > k2->type)
+ return 1;
+ if (k1->type < k2->type)
+ return -1;
+ if (k1->offset > k2->offset)
+ return 1;
+ if (k1->offset < k2->offset)
+ return -1;
+ return 0;
+}
+
+/* compare keys but ignore offset, is useful to enumerate all same kind keys */
+static int btrfs_comp_keys_type(struct btrfs_disk_key *k1,
+ struct btrfs_disk_key *k2)
+{
+ if (k1->objectid > k2->objectid)
+ return 1;
+ if (k1->objectid < k2->objectid)
+ return -1;
+ if (k1->type > k2->type)
+ return 1;
+ if (k1->type < k2->type)
+ return -1;
+ return 0;
+}
+
+/* seach tree directly on disk ... */
+static int search_tree(struct fs_info *fs, u64 loffset,
+ struct btrfs_disk_key *key, struct btrfs_path *path)
+{
+ u8 buf[BTRFS_MAX_LEAF_SIZE];
+ struct btrfs_header *header = (struct btrfs_header *)buf;
+ struct btrfs_node *node = (struct btrfs_node *)buf;
+ struct btrfs_leaf *leaf = (struct btrfs_leaf *)buf;
+ int slot, ret;
+ u64 offset;
+
+ offset = logical_physical(loffset);
+ btrfs_read(fs, (char *)header, offset, sizeof(*header));
+ if (header->level) {/*node*/
+ btrfs_read(fs, (char *)&node->ptrs[0], offset + sizeof(*header),
+ sb.nodesize - sizeof(*header));
+ path->itemsnr[header->level] = header->nritems;
+ path->offsets[header->level] = loffset;
+ ret = bin_search(&node->ptrs[0], sizeof(struct btrfs_key_ptr),
+ key, (cmp_func)btrfs_comp_keys,
+ path->slots[header->level], header->nritems, &slot);
+ if (ret && slot > path->slots[header->level])
+ slot--;
+ path->slots[header->level] = slot;
+ ret = search_tree(fs, node->ptrs[slot].blockptr, key, path);
+ } else {/*leaf*/
+ btrfs_read(fs, (char *)&leaf->items, offset + sizeof(*header),
+ sb.leafsize - sizeof(*header));
+ path->itemsnr[header->level] = header->nritems;
+ path->offsets[0] = loffset;
+ ret = bin_search(&leaf->items[0], sizeof(struct btrfs_item),
+ key, (cmp_func)btrfs_comp_keys, path->slots[0],
+ header->nritems, &slot);
+ if (ret && slot > path->slots[header->level])
+ slot--;
+ path->slots[0] = slot;
+ path->item = leaf->items[slot];
+ btrfs_read(fs, (char *)&path->data,
+ offset + sizeof(*header) + leaf->items[slot].offset,
+ leaf->items[slot].size);
+ }
+ return ret;
+}
+
+/* return 0 if leaf found */
+static int next_leaf(struct fs_info *fs, struct btrfs_disk_key *key, struct btrfs_path *path)
+{
+ int slot;
+ int level = 1;
+
+ while (level < BTRFS_MAX_LEVEL) {
+ if (!path->itemsnr[level]) /* no more nodes */
+ return 1;
+ slot = path->slots[level] + 1;
+ if (slot >= path->itemsnr[level]) {
+ level++;
+ continue;;
+ }
+ path->slots[level] = slot;
+ path->slots[level-1] = 0; /* reset low level slots info */
+ search_tree(fs, path->offsets[level], key, path);
+ break;
+ }
+ if (level == BTRFS_MAX_LEVEL)
+ return 1;
+ return 0;
+}
+
+/* return 0 if slot found */
+static int next_slot(struct fs_info *fs, struct btrfs_disk_key *key, struct btrfs_path *path)
+{
+ int slot;
+
+ if (!path->itemsnr[0])
+ return 1;
+ slot = path->slots[0] + 1;
+ if (slot >= path->itemsnr[0])
+ return 1;
+ path->slots[0] = slot;
+ search_tree(fs, path->offsets[0], key, path);
+ return 0;
+}
+
+/*
+ * read chunk_array in super block
+ */
+static void btrfs_read_sys_chunk_array(void)
+{
+ struct btrfs_chunk_map_item item;
+ struct btrfs_disk_key *key;
+ struct btrfs_chunk *chunk;
+ int cur;
+
+ /* read chunk array in superblock */
+ cur = 0;
+ while (cur < sb.sys_chunk_array_size) {
+ key = (struct btrfs_disk_key *)(sb.sys_chunk_array + cur);
+ cur += sizeof(*key);
+ chunk = (struct btrfs_chunk *)(sb.sys_chunk_array + cur);
+ cur += btrfs_chunk_item_size(chunk->num_stripes);
+ /* insert to mapping table, ignore multi stripes */
+ item.logical = key->offset;
+ item.length = chunk->length;
+ item.devid = chunk->stripe.devid;
+ item.physical = chunk->stripe.offset;/*ignore other stripes */
+ insert_map(&item);
+ }
+}
+
+/* read chunk items from chunk_tree and insert them to chunk map */
+static void btrfs_read_chunk_tree(struct fs_info *fs)
+{
+ struct btrfs_disk_key search_key;
+ struct btrfs_chunk *chunk;
+ struct btrfs_chunk_map_item item;
+ struct btrfs_path path;
+
+ if (!(sb.flags & BTRFS_SUPER_FLAG_METADUMP)) {
+ if (sb.num_devices > 1)
+ printf("warning: only support single device btrfs\n");
+ /* read chunk from chunk_tree */
+ search_key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
+ search_key.type = BTRFS_CHUNK_ITEM_KEY;
+ search_key.offset = 0;
+ clear_path(&path);
+ search_tree(fs, sb.chunk_root, &search_key, &path);
+ do {
+ do {
+ if (btrfs_comp_keys_type(&search_key,
+ &path.item.key))
+ break;
+ chunk = (struct btrfs_chunk *)(path.data);
+ /* insert to mapping table, ignore stripes */
+ item.logical = path.item.key.offset;
+ item.length = chunk->length;
+ item.devid = chunk->stripe.devid;
+ item.physical = chunk->stripe.offset;
+ insert_map(&item);
+ } while (!next_slot(fs, &search_key, &path));
+ if (btrfs_comp_keys_type(&search_key, &path.item.key))
+ break;
+ } while (!next_leaf(fs, &search_key, &path));
+ }
+}
+
+static inline u64 btrfs_name_hash(const char *name, int len)
+{
+ return btrfs_crc32c((u32)~1, name, len);
+}
+
+static struct inode *btrfs_iget_by_inr(struct fs_info *fs, u64 inr)
+{
+ struct inode *inode;
+ struct btrfs_inode_item inode_item;
+ struct btrfs_disk_key search_key;
+ struct btrfs_path path;
+ int ret;
+
+ /* FIXME: some BTRFS inode member are u64, while our logical inode
+ is u32, we may need change them to u64 later */
+ search_key.objectid = inr;
+ search_key.type = BTRFS_INODE_ITEM_KEY;
+ search_key.offset = 0;
+ clear_path(&path);
+ ret = search_tree(fs, fs_tree, &search_key, &path);
+ if (ret)
+ return NULL;
+ inode_item = *(struct btrfs_inode_item *)path.data;
+ if (!(inode = alloc_inode(fs, inr, sizeof(struct btrfs_pvt_inode))))
+ return NULL;
+ inode->ino = inr;
+ inode->size = inode_item.size;
+ inode->mode = IFTODT(inode_item.mode);
+
+ if (inode->mode == DT_REG || inode->mode == DT_LNK) {
+ struct btrfs_file_extent_item extent_item;
+ u64 offset;
+
+ /* get file_extent_item */
+ search_key.type = BTRFS_EXTENT_DATA_KEY;
+ search_key.offset = 0;
+ clear_path(&path);
+ ret = search_tree(fs, fs_tree, &search_key, &path);
+ if (ret)
+ return NULL; /* impossible */
+ extent_item = *(struct btrfs_file_extent_item *)path.data;
+ if (extent_item.type == BTRFS_FILE_EXTENT_INLINE)/* inline file */
+ offset = path.offsets[0] + sizeof(struct btrfs_header)
+ + path.item.offset
+ + offsetof(struct btrfs_file_extent_item, disk_bytenr);
+ else
+ offset = extent_item.disk_bytenr;
+ PVT(inode)->offset = offset;
+ }
+ return inode;
+}
+
+static struct inode *btrfs_iget_root(struct fs_info *fs)
+{
+ /* BTRFS_FIRST_CHUNK_TREE_OBJECTID(256) actually is first OBJECTID for FS_TREE */
+ return btrfs_iget_by_inr(fs, BTRFS_FIRST_CHUNK_TREE_OBJECTID);
+}
+
+static struct inode *btrfs_iget(const char *name, struct inode *parent)
+{
+ struct fs_info *fs = parent->fs;
+ struct btrfs_disk_key search_key;
+ struct btrfs_path path;
+ struct btrfs_dir_item dir_item;
+ int ret;
+
+ search_key.objectid = parent->ino;
+ search_key.type = BTRFS_DIR_ITEM_KEY;
+ search_key.offset = btrfs_name_hash(name, strlen(name));
+ clear_path(&path);
+ ret = search_tree(fs, fs_tree, &search_key, &path);
+ if (ret)
+ return NULL;
+ dir_item = *(struct btrfs_dir_item *)path.data;
+
+ return btrfs_iget_by_inr(fs, dir_item.location.objectid);
+}
+
+static int btrfs_readlink(struct inode *inode, char *buf)
+{
+ btrfs_read(inode->fs, buf, logical_physical(PVT(inode)->offset), inode->size);
+ buf[inode->size] = '\0';
+ return inode->size;
+}
+
+static int btrfs_readdir(struct file *file, struct dirent *dirent)
+{
+ struct fs_info *fs = file->fs;
+ struct inode *inode = file->inode;
+ struct btrfs_disk_key search_key;
+ struct btrfs_path path;
+ struct btrfs_dir_item *dir_item;
+ int ret;
+
+ /*
+ * we use file->offset to store last search key.offset, will will search
+ * key that lower that offset, 0 means first search and we will search
+ * -1UL, which is the biggest possible key
+ */
+ search_key.objectid = inode->ino;
+ search_key.type = BTRFS_DIR_ITEM_KEY;
+ search_key.offset = file->offset - 1;
+ clear_path(&path);
+ ret = search_tree(fs, fs_tree, &search_key, &path);
+
+ if (ret) {
+ if (btrfs_comp_keys_type(&search_key, &path.item.key))
+ return -1;
+ }
+
+ dir_item = (struct btrfs_dir_item *)path.data;
+ file->offset = path.item.key.offset;
+ dirent->d_ino = dir_item->location.objectid;
+ dirent->d_off = file->offset;
+ dirent->d_reclen = offsetof(struct dirent, d_name)
+ + dir_item->name_len + 1;
+ dirent->d_type = IFTODT(dir_item->type);
+ memcpy(dirent->d_name, dir_item + 1, dir_item->name_len);
+ dirent->d_name[dir_item->name_len] = '\0';
+
+ return 0;
+}
+
+static int btrfs_next_extent(struct inode *inode, uint32_t lstart)
+{
+ struct btrfs_disk_key search_key;
+ struct btrfs_file_extent_item extent_item;
+ struct btrfs_path path;
+ int ret;
+ u64 offset;
+ struct fs_info *fs = inode->fs;
+ u32 sec_shift = SECTOR_SHIFT(fs);
+ u32 sec_size = SECTOR_SIZE(fs);
+
+ search_key.objectid = inode->ino;
+ search_key.type = BTRFS_EXTENT_DATA_KEY;
+ search_key.offset = lstart << sec_shift;
+ clear_path(&path);
+ ret = search_tree(fs, fs_tree, &search_key, &path);
+ if (ret) { /* impossible */
+ printf("btrfs: search extent data error!\n");
+ return -1;
+ }
+ extent_item = *(struct btrfs_file_extent_item *)path.data;
+
+ if (extent_item.encryption) {
+ printf("btrfs: found encrypted data, cannot continue!\n");
+ return -1;
+ }
+ if (extent_item.compression) {
+ printf("btrfs: found compressed data, cannot continue!\n");
+ return -1;
+ }
+
+ if (extent_item.type == BTRFS_FILE_EXTENT_INLINE) {/* inline file */
+ /* we fake a extent here, and PVT of inode will tell us */
+ offset = path.offsets[0] + sizeof(struct btrfs_header)
+ + path.item.offset
+ + offsetof(struct btrfs_file_extent_item, disk_bytenr);
+ inode->next_extent.len =
+ (inode->size + sec_size -1) >> sec_shift;
+ } else {
+ offset = extent_item.disk_bytenr + extent_item.offset;
+ inode->next_extent.len =
+ (extent_item.num_bytes + sec_size - 1) >> sec_shift;
+ }
+ inode->next_extent.pstart =
+ logical_physical(offset) >> sec_shift;
+ PVT(inode)->offset = offset;
+ return 0;
+}
+
+static uint32_t btrfs_getfssec(struct file *file, char *buf, int sectors,
+ bool *have_more)
+{
+ u32 ret;
+ struct fs_info *fs = file->fs;
+ u32 off = PVT(file->inode)->offset % SECTOR_SIZE(fs);
+ bool handle_inline = false;
+
+ if (off && !file->offset) {/* inline file first read patch */
+ file->inode->size += off;
+ handle_inline = true;
+ }
+ ret = generic_getfssec(file, buf, sectors, have_more);
+ if (!ret)
+ return ret;
+ off = PVT(file->inode)->offset % SECTOR_SIZE(fs);
+ if (handle_inline) {/* inline file patch */
+ ret -= off;
+ memcpy(buf, buf + off, ret);
+ }
+ return ret;
+}
+
+static void btrfs_get_fs_tree(struct fs_info *fs)
+{
+ struct btrfs_disk_key search_key;
+ struct btrfs_path path;
+ struct btrfs_root_item *tree;
+ bool subvol_ok = false;
+
+ /* check if subvol is filled by installer */
+ if (*SubvolName) {
+ search_key.objectid = BTRFS_FS_TREE_OBJECTID;
+ search_key.type = BTRFS_ROOT_REF_KEY;
+ search_key.offset = 0;
+ clear_path(&path);
+ if (search_tree(fs, sb.root, &search_key, &path))
+ next_slot(fs, &search_key, &path);
+ do {
+ do {
+ struct btrfs_root_ref *ref;
+
+ if (btrfs_comp_keys_type(&search_key,
+ &path.item.key))
+ break;
+ ref = (struct btrfs_root_ref *)path.data;
+ if (!strcmp((char*)(ref + 1), SubvolName)) {
+ subvol_ok = true;
+ break;
+ }
+ } while (!next_slot(fs, &search_key, &path));
+ if (subvol_ok)
+ break;
+ if (btrfs_comp_keys_type(&search_key, &path.item.key))
+ break;
+ } while (!next_leaf(fs, &search_key, &path));
+ if (!subvol_ok) /* should be impossible */
+ printf("no subvol found!\n");
+ }
+ /* find fs_tree from tree_root */
+ if (subvol_ok)
+ search_key.objectid = path.item.key.offset;
+ else /* "default" volume */
+ search_key.objectid = BTRFS_FS_TREE_OBJECTID;
+ search_key.type = BTRFS_ROOT_ITEM_KEY;
+ search_key.offset = -1;
+ clear_path(&path);
+ search_tree(fs, sb.root, &search_key, &path);
+ tree = (struct btrfs_root_item *)path.data;
+ fs_tree = tree->bytenr;
+}
+
+/* init. the fs meta data, return the block size shift bits. */
+static int btrfs_fs_init(struct fs_info *fs)
+{
+ struct disk *disk = fs->fs_dev->disk;
+
+ btrfs_init_crc32c();
+
+ fs->sector_shift = disk->sector_shift;
+ fs->sector_size = 1 << fs->sector_shift;
+ fs->block_shift = BTRFS_BLOCK_SHIFT;
+ fs->block_size = 1 << fs->block_shift;
+
+ /* Initialize the block cache */
+ cache_init(fs->fs_dev, fs->block_shift);
+
+ btrfs_read_super_block(fs);
+ if (strncmp((char *)(&sb.magic), BTRFS_MAGIC, sizeof(sb.magic)))
+ return -1;
+ btrfs_read_sys_chunk_array();
+ btrfs_read_chunk_tree(fs);
+ btrfs_get_fs_tree(fs);
+
+ return fs->block_shift;
+}
+
+const struct fs_ops btrfs_fs_ops = {
+ .fs_name = "btrfs",
+ .fs_flags = 0,
+ .fs_init = btrfs_fs_init,
+ .iget_root = btrfs_iget_root,
+ .iget = btrfs_iget,
+ .readlink = btrfs_readlink,
+ .getfssec = btrfs_getfssec,
+ .close_file = generic_close_file,
+ .mangle_name = generic_mangle_name,
+ .next_extent = btrfs_next_extent,
+ .readdir = btrfs_readdir,
+ .load_config = generic_load_config
+};
diff --git a/contrib/syslinux-4.02/core/fs/btrfs/btrfs.h b/contrib/syslinux-4.02/core/fs/btrfs/btrfs.h
new file mode 100644
index 0000000..aa1245b
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/btrfs/btrfs.h
@@ -0,0 +1,292 @@
+#ifndef _BTRFS_H_
+#define _BTRFS_H_
+
+#include <stdint.h>
+#include <zconf.h>
+
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+/* type that store on disk, but it is same as cpu type for i386 arch */
+typedef u16 __le16;
+typedef u32 __le32;
+typedef u64 __le64;
+
+#include "crc32c.h"
+#define btrfs_crc32c crc32c_le
+
+#define BTRFS_SUPER_INFO_OFFSET (64 * 1024)
+#define BTRFS_SUPER_INFO_SIZE 4096
+#define BTRFS_MAX_LEAF_SIZE 4096
+#define BTRFS_BLOCK_SHIFT 12
+
+#define BTRFS_SUPER_MIRROR_MAX 3
+#define BTRFS_SUPER_MIRROR_SHIFT 12
+#define BTRFS_CSUM_SIZE 32
+#define BTRFS_FSID_SIZE 16
+#define BTRFS_LABEL_SIZE 256
+#define BTRFS_SYSTEM_CHUNK_ARRAY_SIZE 2048
+#define BTRFS_UUID_SIZE 16
+
+#define BTRFS_MAGIC "_BHRfS_M"
+
+#define BTRFS_SUPER_FLAG_METADUMP (1ULL << 33)
+
+#define BTRFS_DEV_ITEM_KEY 216
+#define BTRFS_CHUNK_ITEM_KEY 228
+#define BTRFS_ROOT_REF_KEY 156
+#define BTRFS_ROOT_ITEM_KEY 132
+#define BTRFS_EXTENT_DATA_KEY 108
+#define BTRFS_DIR_ITEM_KEY 84
+#define BTRFS_INODE_ITEM_KEY 1
+
+#define BTRFS_EXTENT_TREE_OBJECTID 2ULL
+#define BTRFS_FS_TREE_OBJECTID 5ULL
+
+#define BTRFS_FIRST_CHUNK_TREE_OBJECTID 256ULL
+
+#define BTRFS_FILE_EXTENT_INLINE 0
+#define BTRFS_FILE_EXTENT_REG 1
+#define BTRFS_FILE_EXTENT_PREALLOC 2
+
+#define BTRFS_MAX_LEVEL 8
+#define BTRFS_MAX_CHUNK_ENTRIES 256
+
+#define BTRFS_FT_REG_FILE 1
+#define BTRFS_FT_DIR 2
+#define BTRFS_FT_SYMLINK 7
+
+#define ROOT_DIR_WORD 0x002f
+
+struct btrfs_dev_item {
+ __le64 devid;
+ __le64 total_bytes;
+ __le64 bytes_used;
+ __le32 io_align;
+ __le32 io_width;
+ __le32 sector_size;
+ __le64 type;
+ __le64 generation;
+ __le64 start_offset;
+ __le32 dev_group;
+ u8 seek_speed;
+ u8 bandwidth;
+ u8 uuid[BTRFS_UUID_SIZE];
+ u8 fsid[BTRFS_UUID_SIZE];
+} __attribute__ ((__packed__));
+
+struct btrfs_super_block {
+ u8 csum[BTRFS_CSUM_SIZE];
+ /* the first 3 fields must match struct btrfs_header */
+ u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */
+ __le64 bytenr; /* this block number */
+ __le64 flags;
+
+ /* allowed to be different from the btrfs_header from here own down */
+ __le64 magic;
+ __le64 generation;
+ __le64 root;
+ __le64 chunk_root;
+ __le64 log_root;
+
+ /* this will help find the new super based on the log root */
+ __le64 log_root_transid;
+ __le64 total_bytes;
+ __le64 bytes_used;
+ __le64 root_dir_objectid;
+ __le64 num_devices;
+ __le32 sectorsize;
+ __le32 nodesize;
+ __le32 leafsize;
+ __le32 stripesize;
+ __le32 sys_chunk_array_size;
+ __le64 chunk_root_generation;
+ __le64 compat_flags;
+ __le64 compat_ro_flags;
+ __le64 incompat_flags;
+ __le16 csum_type;
+ u8 root_level;
+ u8 chunk_root_level;
+ u8 log_root_level;
+ struct btrfs_dev_item dev_item;
+
+ char label[BTRFS_LABEL_SIZE];
+
+ /* future expansion */
+ __le64 reserved[32];
+ u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE];
+} __attribute__ ((__packed__));
+
+struct btrfs_disk_key {
+ __le64 objectid;
+ u8 type;
+ __le64 offset;
+} __attribute__ ((__packed__));
+
+struct btrfs_stripe {
+ __le64 devid;
+ __le64 offset;
+ u8 dev_uuid[BTRFS_UUID_SIZE];
+} __attribute__ ((__packed__));
+
+struct btrfs_chunk {
+ __le64 length;
+ __le64 owner;
+ __le64 stripe_len;
+ __le64 type;
+ __le32 io_align;
+ __le32 io_width;
+ __le32 sector_size;
+ __le16 num_stripes;
+ __le16 sub_stripes;
+ struct btrfs_stripe stripe;
+} __attribute__ ((__packed__));
+
+struct btrfs_header {
+ /* these first four must match the super block */
+ u8 csum[BTRFS_CSUM_SIZE];
+ u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */
+ __le64 bytenr; /* which block this node is supposed to live in */
+ __le64 flags;
+
+ /* allowed to be different from the super from here on down */
+ u8 chunk_tree_uuid[BTRFS_UUID_SIZE];
+ __le64 generation;
+ __le64 owner;
+ __le32 nritems;
+ u8 level;
+} __attribute__ ((__packed__));
+
+struct btrfs_item {
+ struct btrfs_disk_key key;
+ __le32 offset;
+ __le32 size;
+} __attribute__ ((__packed__));
+
+struct btrfs_leaf {
+ struct btrfs_header header;
+ struct btrfs_item items[];
+} __attribute__ ((__packed__));
+
+struct btrfs_key_ptr {
+ struct btrfs_disk_key key;
+ __le64 blockptr;
+ __le64 generation;
+} __attribute__ ((__packed__));
+
+struct btrfs_node {
+ struct btrfs_header header;
+ struct btrfs_key_ptr ptrs[];
+} __attribute__ ((__packed__));
+
+/* remember how we get to a node/leaf */
+struct btrfs_path {
+ u64 offsets[BTRFS_MAX_LEVEL];
+ int itemsnr[BTRFS_MAX_LEVEL];
+ int slots[BTRFS_MAX_LEVEL];
+ /* remember last slot's item and data */
+ struct btrfs_item item;
+ u8 data[BTRFS_MAX_LEAF_SIZE];
+};
+
+/* store logical offset to physical offset mapping */
+struct btrfs_chunk_map_item {
+ u64 logical;
+ u64 length;
+ u64 devid;
+ u64 physical;
+};
+
+struct btrfs_chunk_map {
+ struct btrfs_chunk_map_item *map;
+ u32 map_length;
+ u32 cur_length;
+};
+
+struct btrfs_timespec {
+ __le64 sec;
+ __le32 nsec;
+} __attribute__ ((__packed__));
+
+struct btrfs_inode_item {
+ /* nfs style generation number */
+ __le64 generation;
+ /* transid that last touched this inode */
+ __le64 transid;
+ __le64 size;
+ __le64 nbytes;
+ __le64 block_group;
+ __le32 nlink;
+ __le32 uid;
+ __le32 gid;
+ __le32 mode;
+ __le64 rdev;
+ __le64 flags;
+
+ /* modification sequence number for NFS */
+ __le64 sequence;
+
+ /*
+ * a little future expansion, for more than this we can
+ * just grow the inode item and version it
+ */
+ __le64 reserved[4];
+ struct btrfs_timespec atime;
+ struct btrfs_timespec ctime;
+ struct btrfs_timespec mtime;
+ struct btrfs_timespec otime;
+} __attribute__ ((__packed__));
+
+struct btrfs_root_item {
+ struct btrfs_inode_item inode;
+ __le64 generation;
+ __le64 root_dirid;
+ __le64 bytenr;
+ __le64 byte_limit;
+ __le64 bytes_used;
+ __le64 last_snapshot;
+ __le64 flags;
+ __le32 refs;
+ struct btrfs_disk_key drop_progress;
+ u8 drop_level;
+ u8 level;
+} __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_file_extent_item {
+ __le64 generation;
+ __le64 ram_bytes;
+ u8 compression;
+ u8 encryption;
+ __le16 other_encoding; /* spare for later use */
+ u8 type;
+ __le64 disk_bytenr;
+ __le64 disk_num_bytes;
+ __le64 offset;
+ __le64 num_bytes;
+} __attribute__ ((__packed__));
+
+struct btrfs_root_ref {
+ __le64 dirid;
+ __le64 sequence;
+ __le16 name_len;
+} __attribute__ ((__packed__));
+
+/*
+ * btrfs private inode information
+ */
+struct btrfs_pvt_inode {
+ uint64_t offset;
+};
+
+#define PVT(i) ((struct btrfs_pvt_inode *)((i)->pvt))
+
+#endif
diff --git a/contrib/syslinux-4.02/core/fs/btrfs/crc32c.h b/contrib/syslinux-4.02/core/fs/btrfs/crc32c.h
new file mode 100644
index 0000000..2c31738
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/btrfs/crc32c.h
@@ -0,0 +1,50 @@
+/*
+ * Copied from Linux kernel crypto/crc32c.c
+ * Copyright (c) 2004 Cisco Systems, Inc.
+ * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * 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 is the CRC-32C table
+ * Generated with:
+ * width = 32 bits
+ * poly = 0x1EDC6F41
+ * reflect input bytes = true
+ * reflect output bytes = true
+ */
+
+static u32 crc32c_table[256];
+
+/*
+ * Steps through buffer one byte at at time, calculates reflected
+ * crc using table.
+ */
+
+static inline u32 crc32c_le(u32 crc, const char *data, size_t length)
+{
+ while (length--)
+ crc = crc32c_table[(u8)(crc ^ *data++)] ^ (crc >> 8);
+
+ return crc;
+}
+
+static inline void btrfs_init_crc32c(void)
+{
+ int i, j;
+ u32 v;
+ const u32 poly = 0x82F63B78; /* Bit-reflected CRC32C polynomial */
+
+ for (i = 0; i < 256; i++) {
+ v = i;
+ for (j = 0; j < 8; j++) {
+ v = (v >> 1) ^ ((v & 1) ? poly : 0);
+ }
+ crc32c_table[i] = v;
+ }
+}
diff --git a/contrib/syslinux-4.02/core/fs/cache.c b/contrib/syslinux-4.02/core/fs/cache.c
new file mode 100644
index 0000000..0d7891b
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/cache.c
@@ -0,0 +1,125 @@
+/*
+ * core/cache.c: A simple LRU-based cache implementation.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <dprintf.h>
+#include "core.h"
+#include "cache.h"
+
+
+/*
+ * Initialize the cache data structres. the _block_size_shift_ specify
+ * the block size, which is 512 byte for FAT fs of the current
+ * implementation since the block(cluster) size in FAT is a bit big.
+ *
+ */
+void cache_init(struct device *dev, int block_size_shift)
+{
+ struct cache *prev, *cur;
+ char *data = dev->cache_data;
+ struct cache *head, *cache;
+ int i;
+
+ dev->cache_block_size = 1 << block_size_shift;
+
+ if (dev->cache_size < dev->cache_block_size + 2*sizeof(struct cache)) {
+ dev->cache_head = NULL;
+ return; /* Cache unusably small */
+ }
+
+ /* We need one struct cache for the headnode plus one for each block */
+ dev->cache_entries =
+ (dev->cache_size - sizeof(struct cache))/
+ (dev->cache_block_size + sizeof(struct cache));
+
+ dev->cache_head = head = (struct cache *)
+ (data + (dev->cache_entries << block_size_shift));
+ cache = dev->cache_head + 1; /* First cache descriptor */
+
+ head->prev = &cache[dev->cache_entries-1];
+ head->next->prev = dev->cache_head;
+ head->block = -1;
+ head->data = NULL;
+
+ prev = head;
+
+ for (i = 0; i < dev->cache_entries; i++) {
+ cur = &cache[i];
+ cur->data = data;
+ cur->block = -1;
+ cur->prev = prev;
+ prev->next = cur;
+ data += dev->cache_block_size;
+ prev = cur++;
+ }
+}
+
+/*
+ * Lock a block permanently in the cache
+ */
+void cache_lock_block(struct cache *cs)
+{
+ cs->prev->next = cs->next;
+ cs->next->prev = cs->prev;
+
+ cs->next = cs->prev = NULL;
+}
+
+/*
+ * Check for a particular BLOCK in the block cache,
+ * and if it is already there, just do nothing and return;
+ * otherwise pick a victim block and update the LRU link.
+ */
+struct cache *_get_cache_block(struct device *dev, block_t block)
+{
+ struct cache *head = dev->cache_head;
+ struct cache *cs;
+ int i;
+
+ cs = dev->cache_head + 1;
+
+ for (i = 0; i < dev->cache_entries; i++) {
+ if (cs->block == block)
+ goto found;
+ cs++;
+ }
+
+ /* Not found, pick a victim */
+ cs = head->next;
+
+found:
+ /* Move to the end of the LRU chain, unless the block is already locked */
+ if (cs->next) {
+ cs->prev->next = cs->next;
+ cs->next->prev = cs->prev;
+
+ cs->prev = head->prev;
+ head->prev->next = cs;
+ cs->next = head;
+ head->prev = cs;
+ }
+
+ return cs;
+}
+
+/*
+ * Check for a particular BLOCK in the block cache,
+ * and if it is already there, just do nothing and return;
+ * otherwise load it from disk and update the LRU link.
+ * Return the data pointer.
+ */
+const void *get_cache(struct device *dev, block_t block)
+{
+ struct cache *cs;
+
+ cs = _get_cache_block(dev, block);
+ if (cs->block != block) {
+ cs->block = block;
+ getoneblk(dev->disk, cs->data, block, dev->cache_block_size);
+ }
+
+ return cs->data;
+}
diff --git a/contrib/syslinux-4.02/core/fs/chdir.c b/contrib/syslinux-4.02/core/fs/chdir.c
new file mode 100644
index 0000000..9e8dfd2
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/chdir.c
@@ -0,0 +1,103 @@
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include "fs.h"
+#include "cache.h"
+
+/*
+ * Convert a relative pathname to an absolute pathname
+ * In the future this might also resolve symlinks...
+ */
+void pm_realpath(com32sys_t *regs)
+{
+ const char *src = MK_PTR(regs->ds, regs->esi.w[0]);
+ char *dst = MK_PTR(regs->es, regs->edi.w[0]);
+
+ 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)
+{
+ 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;
+ }
+ }
+ }
+
+ if (bufsize)
+ *q = '\0';
+
+ return n;
+}
+
+size_t realpath(char *dst, const char *src, size_t bufsize)
+{
+ if (this_fs->fs_ops->realpath) {
+ return 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);
+ }
+}
+
+int chdir(const char *src)
+{
+ int rv;
+ struct file *file;
+ char cwd_buf[CURRENTDIR_MAX];
+
+ if (this_fs->fs_ops->chdir)
+ return this_fs->fs_ops->chdir(this_fs, src);
+
+ /* Otherwise it is a "conventional filesystem" */
+ rv = searchdir(src);
+ if (rv < 0)
+ return rv;
+
+ file = handle_to_file(rv);
+ if (file->inode->mode != DT_DIR) {
+ _close_file(file);
+ return -1;
+ }
+
+ put_inode(this_fs->cwd);
+ this_fs->cwd = get_inode(file->inode);
+ _close_file(file);
+
+ /* Save the current working directory */
+ realpath(cwd_buf, src, CURRENTDIR_MAX);
+
+ /* 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, "/");
+
+ return 0;
+}
diff --git a/contrib/syslinux-4.02/core/fs/diskio.c b/contrib/syslinux-4.02/core/fs/diskio.c
new file mode 100644
index 0000000..481b59b
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/diskio.c
@@ -0,0 +1,418 @@
+#include <dprintf.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+#include <klibc/compiler.h>
+#include <core.h>
+#include <fs.h>
+#include <disk.h>
+#include <ilog2.h>
+
+#define RETRY_COUNT 6
+
+static inline sector_t chs_max(const struct disk *disk)
+{
+ return (sector_t)disk->secpercyl << 10;
+}
+
+static int chs_rdwr_sectors(struct disk *disk, void *buf,
+ sector_t lba, size_t count, bool is_write)
+{
+ char *ptr = buf;
+ char *tptr;
+ size_t chunk, freeseg;
+ int sector_shift = disk->sector_shift;
+ uint32_t xlba = lba + disk->part_start; /* Truncated LBA (CHS is << 2 TB) */
+ uint32_t t;
+ uint32_t c, h, s;
+ com32sys_t ireg, oreg;
+ size_t done = 0;
+ size_t bytes;
+ int retry;
+ uint32_t maxtransfer = disk->maxtransfer;
+
+ if (lba + disk->part_start >= chs_max(disk))
+ return 0; /* Impossible CHS request */
+
+ memset(&ireg, 0, sizeof ireg);
+
+ ireg.eax.b[1] = 0x02 + is_write;
+ ireg.edx.b[0] = disk->disk_number;
+
+ while (count) {
+ chunk = count;
+ if (chunk > maxtransfer)
+ chunk = maxtransfer;
+
+ freeseg = (0x10000 - ((size_t)ptr & 0xffff)) >> sector_shift;
+
+ if ((size_t)buf <= 0xf0000 && freeseg) {
+ /* Can do a direct load */
+ tptr = ptr;
+ } else {
+ /* Either accessing high memory or we're crossing a 64K line */
+ tptr = core_xfer_buf;
+ freeseg = (0x10000 - ((size_t)tptr & 0xffff)) >> sector_shift;
+ }
+ if (chunk > freeseg)
+ chunk = freeseg;
+
+ s = xlba % disk->s;
+ t = xlba / disk->s;
+ h = t % disk->h;
+ c = t / disk->h;
+
+ if (chunk > (disk->s - s))
+ chunk = disk->s - s;
+
+ bytes = chunk << sector_shift;
+
+ if (tptr != ptr && is_write)
+ memcpy(tptr, ptr, bytes);
+
+ ireg.eax.b[0] = chunk;
+ ireg.ecx.b[1] = c;
+ ireg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1);
+ ireg.edx.b[1] = h;
+ ireg.ebx.w[0] = OFFS(tptr);
+ ireg.es = SEG(tptr);
+
+ retry = RETRY_COUNT;
+
+ for (;;) {
+ if (c < 1024) {
+ dprintf("CHS[%02x]: %u @ %llu (%u/%u/%u) %04x:%04x %s %p\n",
+ ireg.edx.b[0], chunk, xlba, c, h, s+1,
+ ireg.es, ireg.ebx.w[0],
+ (ireg.eax.b[1] & 1) ? "<-" : "->",
+ ptr);
+
+ __intcall(0x13, &ireg, &oreg);
+ if (!(oreg.eflags.l & EFLAGS_CF))
+ break;
+
+ dprintf("CHS: error AX = %04x\n", oreg.eax.w[0]);
+
+ if (retry--)
+ continue;
+
+ /*
+ * For any starting value, this will always end with
+ * ..., 1, 0
+ */
+ chunk >>= 1;
+ if (chunk) {
+ maxtransfer = chunk;
+ retry = RETRY_COUNT;
+ ireg.eax.b[0] = chunk;
+ continue;
+ }
+ }
+
+ printf("CHS: Error %04x %s sector %llu (%u/%u/%u)\n",
+ oreg.eax.w[0],
+ is_write ? "writing" : "reading",
+ lba, c, h, s+1);
+ return done; /* Failure */
+ }
+
+ bytes = chunk << sector_shift;
+
+ if (tptr != ptr && !is_write)
+ memcpy(ptr, tptr, bytes);
+
+ /* If we dropped maxtransfer, it eventually worked, so remember it */
+ disk->maxtransfer = maxtransfer;
+
+ ptr += bytes;
+ xlba += chunk;
+ count -= chunk;
+ done += chunk;
+ }
+
+ return done;
+}
+
+struct edd_rdwr_packet {
+ uint16_t size;
+ uint16_t blocks;
+ far_ptr_t buf;
+ uint64_t lba;
+};
+
+static int edd_rdwr_sectors(struct disk *disk, void *buf,
+ sector_t lba, size_t count, bool is_write)
+{
+ static __lowmem struct edd_rdwr_packet pkt;
+ char *ptr = buf;
+ char *tptr;
+ size_t chunk, freeseg;
+ int sector_shift = disk->sector_shift;
+ com32sys_t ireg, oreg, reset;
+ size_t done = 0;
+ size_t bytes;
+ int retry;
+ uint32_t maxtransfer = disk->maxtransfer;
+
+ memset(&ireg, 0, sizeof ireg);
+
+ ireg.eax.b[1] = 0x42 + is_write;
+ ireg.edx.b[0] = disk->disk_number;
+ ireg.ds = SEG(&pkt);
+ ireg.esi.w[0] = OFFS(&pkt);
+
+ memset(&reset, 0, sizeof reset);
+
+ ireg.edx.b[0] = disk->disk_number;
+
+ lba += disk->part_start;
+ while (count) {
+ chunk = count;
+ if (chunk > maxtransfer)
+ chunk = maxtransfer;
+
+ freeseg = (0x10000 - ((size_t)ptr & 0xffff)) >> sector_shift;
+
+ if ((size_t)ptr <= 0xf0000 && freeseg) {
+ /* Can do a direct load */
+ tptr = ptr;
+ } else {
+ /* Either accessing high memory or we're crossing a 64K line */
+ tptr = core_xfer_buf;
+ freeseg = (0x10000 - ((size_t)tptr & 0xffff)) >> sector_shift;
+ }
+ if (chunk > freeseg)
+ chunk = freeseg;
+
+ bytes = chunk << sector_shift;
+
+ if (tptr != ptr && is_write)
+ memcpy(tptr, ptr, bytes);
+
+ retry = RETRY_COUNT;
+
+ for (;;) {
+ pkt.size = sizeof pkt;
+ pkt.blocks = chunk;
+ pkt.buf = FAR_PTR(tptr);
+ pkt.lba = lba;
+
+ dprintf("EDD[%02x]: %u @ %llu %04x:%04x %s %p\n",
+ ireg.edx.b[0], pkt.blocks, pkt.lba,
+ pkt.buf.seg, pkt.buf.offs,
+ (ireg.eax.b[1] & 1) ? "<-" : "->",
+ ptr);
+
+ __intcall(0x13, &ireg, &oreg);
+ if (!(oreg.eflags.l & EFLAGS_CF))
+ break;
+
+ dprintf("EDD: error AX = %04x\n", oreg.eax.w[0]);
+
+ if (retry--)
+ continue;
+
+ /*
+ * Some systems seem to get "stuck" in an error state when
+ * using EBIOS. Doesn't happen when using CBIOS, which is
+ * good, since some other systems get timeout failures
+ * waiting for the floppy disk to spin up.
+ */
+ __intcall(0x13, &reset, NULL);
+
+ /* For any starting value, this will always end with ..., 1, 0 */
+ chunk >>= 1;
+ if (chunk) {
+ maxtransfer = chunk;
+ retry = RETRY_COUNT;
+ continue;
+ }
+
+ /*
+ * Total failure. There are systems which identify as
+ * EDD-capable but aren't; the known such systems return
+ * error code AH=1 (invalid function), but let's not
+ * assume that for now.
+ *
+ * Try to fall back to CHS. If the LBA is absurd, the
+ * chs_max() test in chs_rdwr_sectors() will catch it.
+ */
+ done = chs_rdwr_sectors(disk, buf, lba - disk->part_start,
+ count, is_write);
+ if (done == (count << sector_shift)) {
+ /* Successful, assume this is a CHS disk */
+ disk->rdwr_sectors = chs_rdwr_sectors;
+ return done;
+ }
+ printf("EDD: Error %04x %s sector %llu\n",
+ oreg.eax.w[0],
+ is_write ? "writing" : "reading",
+ lba);
+ return done; /* Failure */
+ }
+
+ bytes = chunk << sector_shift;
+
+ if (tptr != ptr && !is_write)
+ memcpy(ptr, tptr, bytes);
+
+ /* If we dropped maxtransfer, it eventually worked, so remember it */
+ disk->maxtransfer = maxtransfer;
+
+ ptr += bytes;
+ lba += chunk;
+ count -= chunk;
+ done += chunk;
+ }
+ return done;
+}
+
+struct edd_disk_params {
+ uint16_t len;
+ uint16_t flags;
+ uint32_t phys_c;
+ uint32_t phys_h;
+ uint32_t phys_s;
+ uint64_t sectors;
+ uint16_t sector_size;
+ far_ptr_t dpte;
+ uint16_t devpath_key;
+ uint8_t devpath_len;
+ uint8_t _pad1[3];
+ char bus_type[4];
+ char if_type[8];
+ uint8_t if_path[8];
+ uint8_t dev_path[8];
+ uint8_t _pad2;
+ uint8_t devpath_csum;
+} __attribute__((packed));
+
+static inline bool is_power_of_2(uint32_t x)
+{
+ return !(x & (x-1));
+}
+
+void getoneblk(struct disk *disk, char *buf, block_t block, int block_size)
+{
+ int sec_per_block = block_size / disk->sector_size;
+
+ disk->rdwr_sectors(disk, buf, block * sec_per_block, sec_per_block, 0);
+}
+
+
+struct disk *disk_init(uint8_t devno, bool cdrom, sector_t part_start,
+ uint16_t bsHeads, uint16_t bsSecPerTrack,
+ uint32_t MaxTransfer)
+{
+ static struct disk disk;
+ static __lowmem struct edd_disk_params edd_params;
+ com32sys_t ireg, oreg;
+ bool ebios;
+ int sector_size;
+ unsigned int hard_max_transfer;
+
+ memset(&ireg, 0, sizeof ireg);
+ ireg.edx.b[0] = devno;
+
+ if (cdrom) {
+ /*
+ * The query functions don't work right on some CD-ROM stacks.
+ * Known affected systems: ThinkPad T22, T23.
+ */
+ sector_size = 2048;
+ ebios = true;
+ hard_max_transfer = 32;
+ } else {
+ sector_size = 512;
+ ebios = false;
+ hard_max_transfer = 63;
+
+ /* CBIOS parameters */
+ disk.h = bsHeads;
+ disk.s = bsSecPerTrack;
+
+ if ((int8_t)devno < 0) {
+ /* Get hard disk geometry from BIOS */
+
+ ireg.eax.b[1] = 0x08;
+ __intcall(0x13, &ireg, &oreg);
+
+ if (!(oreg.eflags.l & EFLAGS_CF)) {
+ disk.h = oreg.edx.b[1] + 1;
+ disk.s = oreg.ecx.b[0] & 63;
+ }
+ }
+
+ /* Get EBIOS support */
+ ireg.eax.b[1] = 0x41;
+ ireg.ebx.w[0] = 0x55aa;
+ ireg.eflags.b[0] = 0x3; /* CF set */
+
+ __intcall(0x13, &ireg, &oreg);
+
+ if (!(oreg.eflags.l & EFLAGS_CF) &&
+ oreg.ebx.w[0] == 0xaa55 && (oreg.ecx.b[0] & 1)) {
+ ebios = true;
+ hard_max_transfer = 127;
+
+ /* Query EBIOS parameters */
+ edd_params.len = sizeof edd_params;
+
+ ireg.eax.b[1] = 0x48;
+ ireg.ds = SEG(&edd_params);
+ ireg.esi.w[0] = OFFS(&edd_params);
+ __intcall(0x13, &ireg, &oreg);
+
+ if (!(oreg.eflags.l & EFLAGS_CF) && oreg.eax.b[1] == 0) {
+ if (edd_params.len < sizeof edd_params)
+ memset((char *)&edd_params + edd_params.len, 0,
+ sizeof edd_params - edd_params.len);
+
+ if (edd_params.sector_size >= 512 &&
+ is_power_of_2(edd_params.sector_size))
+ sector_size = edd_params.sector_size;
+ }
+ }
+
+ }
+
+ disk.disk_number = devno;
+ disk.sector_size = sector_size;
+ disk.sector_shift = ilog2(sector_size);
+ disk.part_start = part_start;
+ disk.secpercyl = disk.h * disk.s;
+ disk.rdwr_sectors = ebios ? edd_rdwr_sectors : chs_rdwr_sectors;
+
+ if (!MaxTransfer || MaxTransfer > hard_max_transfer)
+ MaxTransfer = hard_max_transfer;
+
+ disk.maxtransfer = MaxTransfer;
+
+ dprintf("disk %02x cdrom %d type %d sector %u/%u offset %llu limit %u\n",
+ devno, cdrom, ebios, sector_size, disk.sector_shift,
+ part_start, disk.maxtransfer);
+
+ return &disk;
+}
+
+
+/*
+ * Initialize the device structure.
+ *
+ * NOTE: the disk cache needs to be revamped to support multiple devices...
+ */
+struct device * device_init(uint8_t devno, bool cdrom, sector_t part_start,
+ uint16_t bsHeads, uint16_t bsSecPerTrack,
+ uint32_t MaxTransfer)
+{
+ static struct device dev;
+ static __hugebss char diskcache[128*1024];
+
+ dev.disk = disk_init(devno, cdrom, part_start,
+ bsHeads, bsSecPerTrack, MaxTransfer);
+
+ dev.cache_data = diskcache;
+ dev.cache_size = sizeof diskcache;
+
+ return &dev;
+}
diff --git a/contrib/syslinux-4.02/core/fs/ext2/bmap.c b/contrib/syslinux-4.02/core/fs/ext2/bmap.c
new file mode 100644
index 0000000..ef2bf64
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/ext2/bmap.c
@@ -0,0 +1,228 @@
+/*
+ * The logical block -> physical block routine.
+ *
+ * Copyright (C) 2009 Liu Aleaxander -- All rights reserved. This file
+ * may be redistributed under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <dprintf.h>
+#include <fs.h>
+#include <disk.h>
+#include <cache.h>
+#include "ext2_fs.h"
+
+static const struct ext4_extent_header *
+ext4_find_leaf(struct fs_info *fs, const struct ext4_extent_header *eh,
+ block_t block)
+{
+ struct ext4_extent_idx *index;
+ block_t blk;
+ int i;
+
+ while (1) {
+ if (eh->eh_magic != EXT4_EXT_MAGIC)
+ return NULL;
+ if (eh->eh_depth == 0)
+ return eh;
+
+ index = EXT4_FIRST_INDEX(eh);
+ for (i = 0; i < (int)eh->eh_entries; i++) {
+ if (block < index[i].ei_block)
+ break;
+ }
+ if (--i < 0)
+ return NULL;
+
+ blk = index[i].ei_leaf_hi;
+ blk = (blk << 32) + index[i].ei_leaf_lo;
+ eh = get_cache(fs->fs_dev, blk);
+ }
+}
+
+/* handle the ext4 extents to get the phsical block number */
+/* XXX: still need to handle sparse files with extents */
+static block_t
+bmap_extent(struct inode *inode, uint32_t block, size_t *nblocks)
+{
+ struct fs_info *fs = inode->fs;
+ const struct ext4_extent_header *leaf;
+ const struct ext4_extent *ext;
+ int i;
+ block_t start;
+
+ leaf = ext4_find_leaf(fs, &PVT(inode)->i_extent_hdr, block);
+ if (!leaf) {
+ printf("ERROR, extent leaf not found\n");
+ return 0;
+ }
+
+ ext = EXT4_FIRST_EXTENT(leaf);
+ for (i = 0; i < leaf->eh_entries; i++) {
+ if (block < ext[i].ee_block)
+ break;
+ }
+ if (--i < 0) {
+ printf("ERROR, not find the right block\n");
+ return 0;
+ }
+
+ /* got it */
+ block -= ext[i].ee_block;
+ if (block >= ext[i].ee_len)
+ return 0;
+ start = ((block_t)ext[i].ee_start_hi << 32) + ext[i].ee_start_lo;
+
+ if (nblocks)
+ *nblocks = ext[i].ee_len - block;
+
+ return start + block;
+}
+
+/*
+ * Scan forward in a range of blocks to see if they are contiguous,
+ * then return the initial value.
+ */
+static uint32_t
+scan_set_nblocks(const uint32_t *map, unsigned int count, size_t *nblocks)
+{
+ uint32_t blk = *map;
+
+ if (nblocks) {
+ uint32_t skip = blk ? 1 : 0;
+ uint32_t next = blk + skip;
+ size_t cnt = 1;
+
+ while (--count) {
+ map++;
+ if (*map == next) {
+ cnt++;
+ next += skip;
+ } else {
+ break;
+ }
+ }
+
+ *nblocks = cnt;
+ }
+
+ return blk;
+}
+
+/*
+ * The actual indirect block map handling - the block passed in should
+ * be relative to the beginning of the particular block hierarchy.
+ */
+static block_t
+bmap_indirect(struct fs_info *fs, uint32_t start, uint32_t block,
+ int levels, size_t *nblocks)
+{
+ int addr_shift = BLOCK_SHIFT(fs) - 2;
+ uint32_t addr_count = 1 << addr_shift;
+ const uint32_t *blk = NULL;
+ uint32_t index = 0;
+
+ while (levels--) {
+ if (!start) {
+ if (nblocks)
+ *nblocks = addr_count << (levels * addr_shift);
+ return 0;
+ }
+ blk = get_cache(fs->fs_dev, start);
+ index = (block >> (levels * addr_shift)) & (addr_count - 1);
+ start = blk[index];
+ }
+
+ return scan_set_nblocks(blk + index, addr_count - index, nblocks);
+}
+
+/*
+ * Handle the traditional block map, like indirect, double indirect
+ * and triple indirect
+ */
+static block_t
+bmap_traditional(struct inode *inode, block_t block, size_t *nblocks)
+{
+ struct fs_info *fs = inode->fs;
+ const uint32_t addr_per_block = BLOCK_SIZE(fs) >> 2;
+ const int shft_per_block = BLOCK_SHIFT(fs) - 2;
+ const uint32_t direct_blocks = EXT2_NDIR_BLOCKS;
+ const uint32_t indirect_blocks = addr_per_block;
+ const uint32_t double_blocks = addr_per_block << shft_per_block;
+ const uint32_t triple_blocks = double_blocks << shft_per_block;
+
+ /* direct blocks */
+ if (block < direct_blocks)
+ return scan_set_nblocks(&PVT(inode)->i_block[block],
+ direct_blocks - block, nblocks);
+
+ /* indirect blocks */
+ block -= direct_blocks;
+ if (block < indirect_blocks)
+ return bmap_indirect(fs, PVT(inode)->i_block[EXT2_IND_BLOCK],
+ block, 1, nblocks);
+
+ /* double indirect blocks */
+ block -= indirect_blocks;
+ if (block < double_blocks)
+ return bmap_indirect(fs, PVT(inode)->i_block[EXT2_DIND_BLOCK],
+ block, 2, nblocks);
+
+ /* triple indirect block */
+ block -= double_blocks;
+ if (block < triple_blocks)
+ return bmap_indirect(fs, PVT(inode)->i_block[EXT2_TIND_BLOCK],
+ block, 3, nblocks);
+
+ /* This can't happen... */
+ return 0;
+}
+
+
+/**
+ * Map the logical block to physic block where the file data stores.
+ * In EXT4, there are two ways to handle the map process, extents and indirect.
+ * EXT4 uses a inode flag to mark extent file and indirect block file.
+ *
+ * @fs: the fs_info structure.
+ * @inode: the inode structure.
+ * @block: the logical block to be mapped.
+ * @nblocks: optional pointer to number of contiguous blocks (low estimate)
+ * @retrun: the physical block number.
+ *
+ */
+block_t ext2_bmap(struct inode *inode, block_t block, size_t *nblocks)
+{
+ block_t ret;
+
+ if (inode->flags & EXT4_EXTENTS_FLAG)
+ ret = bmap_extent(inode, block, nblocks);
+ else
+ ret = bmap_traditional(inode, block, nblocks);
+
+ return ret;
+}
+
+
+/*
+ * Next extent for getfssec
+ */
+int ext2_next_extent(struct inode *inode, uint32_t lstart)
+{
+ struct fs_info *fs = inode->fs;
+ int blktosec = BLOCK_SHIFT(fs) - SECTOR_SHIFT(fs);
+ int blkmask = (1 << blktosec) - 1;
+ block_t block;
+ size_t nblocks = 0;
+
+ block = ext2_bmap(inode, lstart >> blktosec, &nblocks);
+
+ if (!block)
+ inode->next_extent.pstart = EXTENT_ZERO;
+ else
+ inode->next_extent.pstart =
+ ((sector_t)block << blktosec) | (lstart & blkmask);
+
+ inode->next_extent.len = (nblocks << blktosec) - (lstart & blkmask);
+ return 0;
+}
diff --git a/contrib/syslinux-4.02/core/fs/ext2/ext2.c b/contrib/syslinux-4.02/core/fs/ext2/ext2.c
new file mode 100644
index 0000000..716670c
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/ext2/ext2.c
@@ -0,0 +1,335 @@
+#include <dprintf.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/dirent.h>
+#include <minmax.h>
+#include "cache.h"
+#include "core.h"
+#include "disk.h"
+#include "fs.h"
+#include "ext2_fs.h"
+
+/*
+ * Convert an ext2 file type to the global values
+ */
+static enum dirent_type ext2_cvt_type(unsigned int d_file_type)
+{
+ static const enum dirent_type inode_type[] = {
+ DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR,
+ DT_BLK, DT_FIFO, DT_SOCK, DT_LNK,
+ };
+
+ if (d_file_type > sizeof inode_type / sizeof *inode_type)
+ return DT_UNKNOWN;
+ else
+ return inode_type[d_file_type];
+}
+
+/*
+ * get the group's descriptor of group_num
+ */
+static const struct ext2_group_desc *
+ext2_get_group_desc(struct fs_info *fs, uint32_t group_num)
+{
+ struct ext2_sb_info *sbi = EXT2_SB(fs);
+ uint32_t desc_block, desc_index;
+ const struct ext2_group_desc *desc_data_block;
+
+ if (group_num >= sbi->s_groups_count) {
+ printf ("ext2_get_group_desc"
+ "block_group >= groups_count - "
+ "block_group = %d, groups_count = %d",
+ group_num, sbi->s_groups_count);
+
+ return NULL;
+ }
+
+ desc_block = group_num / sbi->s_desc_per_block;
+ desc_index = group_num % sbi->s_desc_per_block;
+
+ desc_block += sbi->s_first_data_block + 1;
+
+ desc_data_block = get_cache(fs->fs_dev, desc_block);
+ return &desc_data_block[desc_index];
+}
+
+/*
+ * Unlike strncmp, ext2_match_entry returns 1 for success, 0 for failure.
+ */
+static inline bool ext2_match_entry(const char *name, size_t len,
+ const struct ext2_dir_entry * de)
+{
+ if (!de->d_inode)
+ return false;
+ if (len != de->d_name_len)
+ return false;
+ return !memcmp(name, de->d_name, len);
+}
+
+
+/*
+ * p is at least 6 bytes before the end of page
+ */
+static inline struct ext2_dir_entry *ext2_next_entry(struct ext2_dir_entry *p)
+{
+ return (struct ext2_dir_entry *)((char*)p + p->d_rec_len);
+}
+
+/*
+ * Map a logical sector and load it into the cache
+ */
+static const void *
+ext2_get_cache(struct inode *inode, block_t lblock)
+{
+ block_t pblock = ext2_bmap(inode, lblock, NULL);
+ return get_cache(inode->fs->fs_dev, pblock);
+}
+
+/*
+ * find a dir entry, return it if found, or return NULL.
+ */
+static const struct ext2_dir_entry *
+ext2_find_entry(struct fs_info *fs, struct inode *inode, const char *dname)
+{
+ block_t index = 0;
+ uint32_t i = 0, offset, maxoffset;
+ const struct ext2_dir_entry *de;
+ const char *data;
+ size_t dname_len = strlen(dname);
+
+ while (i < inode->size) {
+ data = ext2_get_cache(inode, index++);
+ offset = 0;
+ maxoffset = min(BLOCK_SIZE(fs), i-inode->size);
+
+ /* The smallest possible size is 9 bytes */
+ while (offset < maxoffset-8) {
+ de = (const struct ext2_dir_entry *)(data + offset);
+ if (de->d_rec_len > maxoffset - offset)
+ break;
+
+ if (ext2_match_entry(dname, dname_len, de))
+ return de;
+
+ offset += de->d_rec_len;
+ }
+ i += BLOCK_SIZE(fs);
+ }
+
+ return NULL;
+}
+
+static const struct ext2_inode *
+ext2_get_inode(struct fs_info *fs, int inr)
+{
+ const struct ext2_group_desc *desc;
+ const char *data;
+ uint32_t inode_group, inode_offset;
+ uint32_t block_num, block_off;
+
+ inr--;
+ inode_group = inr / EXT2_INODES_PER_GROUP(fs);
+ inode_offset = inr % EXT2_INODES_PER_GROUP(fs);
+ desc = ext2_get_group_desc(fs, inode_group);
+ if (!desc)
+ return NULL;
+
+ block_num = desc->bg_inode_table +
+ inode_offset / EXT2_INODES_PER_BLOCK(fs);
+ block_off = inode_offset % EXT2_INODES_PER_BLOCK(fs);
+
+ data = get_cache(fs->fs_dev, block_num);
+
+ return (const struct ext2_inode *)
+ (data + block_off * EXT2_SB(fs)->s_inode_size);
+}
+
+static void fill_inode(struct inode *inode, const struct ext2_inode *e_inode)
+{
+ inode->mode = IFTODT(e_inode->i_mode);
+ inode->size = e_inode->i_size;
+ inode->atime = e_inode->i_atime;
+ inode->ctime = e_inode->i_ctime;
+ inode->mtime = e_inode->i_mtime;
+ inode->dtime = e_inode->i_dtime;
+ inode->blocks = e_inode->i_blocks;
+ inode->flags = e_inode->i_flags;
+ inode->file_acl = e_inode->i_file_acl;
+ memcpy(PVT(inode)->i_block, e_inode->i_block, sizeof PVT(inode)->i_block);
+}
+
+static struct inode *ext2_iget_by_inr(struct fs_info *fs, uint32_t inr)
+{
+ const struct ext2_inode *e_inode;
+ struct inode *inode;
+
+ e_inode = ext2_get_inode(fs, inr);
+ if (!(inode = alloc_inode(fs, inr, sizeof(struct ext2_pvt_inode))))
+ return NULL;
+ fill_inode(inode, e_inode);
+
+ return inode;
+}
+
+static struct inode *ext2_iget_root(struct fs_info *fs)
+{
+ return ext2_iget_by_inr(fs, EXT2_ROOT_INO);
+}
+
+static struct inode *ext2_iget(const char *dname, struct inode *parent)
+{
+ const struct ext2_dir_entry *de;
+ struct fs_info *fs = parent->fs;
+
+ de = ext2_find_entry(fs, parent, dname);
+ if (!de)
+ return NULL;
+
+ return ext2_iget_by_inr(fs, de->d_inode);
+}
+
+/*
+ * Read the entire contents of an inode into a memory buffer
+ */
+static int cache_get_file(struct inode *inode, void *buf, size_t bytes)
+{
+ struct fs_info *fs = inode->fs;
+ size_t block_size = BLOCK_SIZE(fs);
+ uint32_t index = 0; /* Logical block number */
+ size_t chunk;
+ const char *data;
+ char *p = buf;
+
+ if (inode->size > bytes)
+ bytes = inode->size;
+
+ while (bytes) {
+ chunk = min(bytes, block_size);
+ data = ext2_get_cache(inode, index++);
+ memcpy(p, data, chunk);
+
+ bytes -= chunk;
+ p += chunk;
+ }
+
+ return 0;
+}
+
+static int ext2_readlink(struct inode *inode, char *buf)
+{
+ struct fs_info *fs = inode->fs;
+ int sec_per_block = 1 << (fs->block_shift - fs->sector_shift);
+ bool fast_symlink;
+
+ if (inode->size > BLOCK_SIZE(fs))
+ return -1; /* Error! */
+
+ fast_symlink = (inode->file_acl ? sec_per_block : 0) == inode->blocks;
+ if (fast_symlink)
+ memcpy(buf, PVT(inode)->i_block, inode->size);
+ else
+ cache_get_file(inode, buf, inode->size);
+
+ return inode->size;
+}
+
+/*
+ * Read one directory entry at a time
+ */
+static int ext2_readdir(struct file *file, struct dirent *dirent)
+{
+ struct fs_info *fs = file->fs;
+ struct inode *inode = file->inode;
+ const struct ext2_dir_entry *de;
+ const char *data;
+ block_t index = file->offset >> fs->block_shift;
+
+ if (file->offset >= inode->size)
+ return -1; /* End of file */
+
+ data = ext2_get_cache(inode, index);
+ de = (const struct ext2_dir_entry *)
+ (data + (file->offset & (BLOCK_SIZE(fs) - 1)));
+
+ dirent->d_ino = de->d_inode;
+ dirent->d_off = file->offset;
+ dirent->d_reclen = offsetof(struct dirent, d_name) + de->d_name_len + 1;
+ dirent->d_type = ext2_cvt_type(de->d_file_type);
+ memcpy(dirent->d_name, de->d_name, de->d_name_len);
+ dirent->d_name[de->d_name_len] = '\0';
+
+ file->offset += de->d_rec_len; /* Update for next reading */
+
+ return 0;
+}
+
+/*
+ * init. the fs meta data, return the block size bits.
+ */
+static int ext2_fs_init(struct fs_info *fs)
+{
+ struct disk *disk = fs->fs_dev->disk;
+ struct ext2_sb_info *sbi;
+ struct ext2_super_block sb;
+ struct cache *cs;
+
+ /* read the super block */
+ disk->rdwr_sectors(disk, &sb, 2, 2, 0);
+
+ /* check if it is ext2, since we also support btrfs now */
+ if (sb.s_magic != EXT2_SUPER_MAGIC)
+ return -1;
+
+ sbi = malloc(sizeof(*sbi));
+ if (!sbi) {
+ malloc_error("ext2_sb_info structure");
+ return -1;
+ }
+ fs->fs_info = sbi;
+
+ if (sb.s_magic != EXT2_SUPER_MAGIC) {
+ printf("ext2 mount error: it's not a EXT2/3/4 file system!\n");
+ return 0;
+ }
+
+ fs->sector_shift = disk->sector_shift;
+ fs->block_shift = sb.s_log_block_size + 10;
+ fs->sector_size = 1 << fs->sector_shift;
+ fs->block_size = 1 << fs->block_shift;
+
+ sbi->s_inodes_per_group = sb.s_inodes_per_group;
+ sbi->s_blocks_per_group = sb.s_blocks_per_group;
+ sbi->s_inodes_per_block = BLOCK_SIZE(fs) / sb.s_inode_size;
+ if (sb.s_desc_size < sizeof(struct ext2_group_desc))
+ sb.s_desc_size = sizeof(struct ext2_group_desc);
+ sbi->s_desc_per_block = BLOCK_SIZE(fs) / sb.s_desc_size;
+ sbi->s_groups_count = (sb.s_blocks_count - sb.s_first_data_block
+ + EXT2_BLOCKS_PER_GROUP(fs) - 1)
+ / EXT2_BLOCKS_PER_GROUP(fs);
+ sbi->s_first_data_block = sb.s_first_data_block;
+ sbi->s_inode_size = sb.s_inode_size;
+
+ /* Initialize the cache, and force block zero to all zero */
+ cache_init(fs->fs_dev, fs->block_shift);
+ cs = _get_cache_block(fs->fs_dev, 0);
+ memset(cs->data, 0, fs->block_size);
+ cache_lock_block(cs);
+
+ return fs->block_shift;
+}
+
+const struct fs_ops ext2_fs_ops = {
+ .fs_name = "ext2",
+ .fs_flags = FS_THISIND | FS_USEMEM,
+ .fs_init = ext2_fs_init,
+ .searchdir = NULL,
+ .getfssec = generic_getfssec,
+ .close_file = generic_close_file,
+ .mangle_name = generic_mangle_name,
+ .load_config = generic_load_config,
+ .iget_root = ext2_iget_root,
+ .iget = ext2_iget,
+ .readlink = ext2_readlink,
+ .readdir = ext2_readdir,
+ .next_extent = ext2_next_extent,
+};
diff --git a/contrib/syslinux-4.02/core/fs/ext2/ext2_fs.h b/contrib/syslinux-4.02/core/fs/ext2/ext2_fs.h
new file mode 100644
index 0000000..8adc9bb
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/ext2/ext2_fs.h
@@ -0,0 +1,310 @@
+#ifndef __EXT2_FS_H
+#define __EXT2_FS_H
+
+#include <stdint.h>
+
+#define EXT2_SUPER_MAGIC 0xEF53
+
+#define EXT2_GOOD_OLD_REV 0 // The good old (original) format
+#define EXT2_DYNAMIC_REV 1 // V2 format w/ dynamic inode sizes
+#define EXT2_GOOD_OLD_INODE_SIZE 128
+
+// Special inode numbers
+#define EXT2_BAD_INO 1 // Bad blocks inode
+#define EXT2_ROOT_INO 2 // Root inode
+#define EXT2_BOOT_LOADER_INO 5 // Boot loader inode
+#define EXT2_UNDEL_DIR_INO 6 // Undelete directory inode
+#define EXT3_RESIZE_INO 7 // Reserved group descriptors inode
+#define EXT3_JOURNAL_INO 8 // Journal inode
+
+// We're readonly, so we only care about incompat features.
+#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
+#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
+#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004
+#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008
+#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
+#define EXT2_FEATURE_INCOMPAT_ANY 0xffffffff
+
+#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)
+
+
+/* for EXT4 extent */
+#define EXT4_EXT_MAGIC 0xf30a
+#define EXT4_EXTENTS_FLAG 0x00080000
+
+/*
+ * File types and file modes
+ */
+#define S_IFDIR 0040000 // Directory
+#define S_IFCHR 0020000 // Character device
+#define S_IFBLK 0060000 // Block device
+#define S_IFREG 0100000 // Regular file
+#define S_IFIFO 0010000 // FIFO
+#define S_IFLNK 0120000 // Symbolic link
+#define S_IFSOCK 0140000 // Socket
+
+#define S_IFSHIFT 12
+
+#define T_IFDIR (S_IFDIR >> S_IFSHIFT)
+#define T_IFCHR (S_IFCHR >> S_IFSHIFT)
+#define T_IFBLK (S_IFBLK >> S_IFSHIFT)
+#define T_IFREG (S_IFREG >> S_IFSHIFT)
+#define T_IFIFO (S_IFIFO >> S_IFSHIFT)
+#define T_IFLNK (S_IFLNK >> S_IFSHIFT)
+#define T_IFSOCK (S_IFSOCK >> S_IFSHIFT)
+
+
+#define ext2_group_desc_lg2size 5
+
+
+
+/*
+ * super block structure:
+ * include/linux/ext2_fs.h
+ */
+struct ext2_super_block {
+ uint32_t s_inodes_count; /* Inodes count */
+ uint32_t s_blocks_count; /* Blocks count */
+ uint32_t s_r_blocks_count; /* Reserved blocks count */
+ uint32_t s_free_blocks_count; /* Free blocks count */
+ uint32_t s_free_inodes_count; /* Free inodes count */
+ uint32_t s_first_data_block; /* First Data Block */
+ uint32_t s_log_block_size; /* Block size */
+ uint32_t s_log_frag_size; /* Fragment size */
+ uint32_t s_blocks_per_group; /* # Blocks per group */
+ uint32_t s_frags_per_group; /* # Fragments per group */
+ uint32_t s_inodes_per_group; /* # Inodes per group */
+ uint32_t s_mtime; /* Mount time */
+ uint32_t s_wtime; /* Write time */
+ uint16_t s_mnt_count; /* Mount count */
+ int16_t s_max_mnt_count; /* Maximal mount count */
+ uint16_t s_magic; /* Magic signature */
+ uint16_t s_state; /* File system state */
+ uint16_t s_errors; /* Behaviour when detecting errors */
+ uint16_t s_minor_rev_level;
+ uint32_t s_lastcheck; /* time of last check */
+ uint32_t s_checkinterval; /* max. time between checks */
+ uint32_t s_creator_os; /* OS */
+ uint32_t s_rev_level; /* Revision level */
+ uint16_t s_def_resuid; /* Default uid for reserved blocks */
+ uint16_t s_def_resgid; /* Default gid for reserved blocks */
+
+ uint32_t s_first_ino; /* First non-reserved inode */
+ uint16_t s_inode_size; /* size of inode structure */
+ uint16_t s_block_group_nr; /* block group # of this superblock */
+ uint32_t s_feature_compat; /* compatible feature set */
+ uint32_t s_feature_incompat; /* incompatible feature set */
+ uint32_t s_feature_ro_compat; /* readonly-compatible feature set */
+ uint8_t s_uuid[16]; /* 128-bit uuid for volume */
+ char s_volume_name[16]; /* volume name */
+ char s_last_mounted[64]; /* directory where last mounted */
+ uint32_t s_algorithm_usage_bitmap; /* For compression */
+ uint8_t s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
+ uint8_t s_prealloc_dir_blocks;
+ uint16_t s_reserved_gdt_blocks; /* Per group desc for online growth */
+ /*
+ * Journaling support valid if EXT4_FEATURE_COMPAT_HAS_JOURNAL set.
+ */
+ uint8_t s_journal_uuid[16]; /* uuid of journal superblock */
+ uint32_t s_journal_inum; /* inode number of journal file */
+ uint32_t s_journal_dev; /* device number of journal file */
+ uint32_t s_last_orphan; /* start of list of inodes to delete */
+ uint32_t s_hash_seed[4]; /* HTREE hash seed */
+ uint8_t s_def_hash_version; /* Default hash version to use */
+ uint8_t s_reserved_char_pad;
+ uint16_t s_desc_size; /* size of group descriptor */
+ uint32_t s_default_mount_opts;
+ uint32_t s_first_meta_bg; /* First metablock block group */
+ uint32_t s_mkfs_time; /* When the filesystem was created */
+ uint32_t s_jnl_blocks[17]; /* Backup of the journal inode */
+ /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */
+ uint32_t s_blocks_count_hi; /* Blocks count */
+ uint32_t s_r_blocks_count_hi; /* Reserved blocks count */
+ uint32_t s_free_blocks_count_hi;/* Free blocks count */
+ uint16_t s_min_extra_isize; /* All inodes have at least # bytes */
+ uint16_t s_want_extra_isize; /* New inodes should reserve # bytes */
+ uint32_t s_flags; /* Miscellaneous flags */
+ uint16_t s_raid_stride; /* RAID stride */
+ uint16_t s_mmp_interval; /* # seconds to wait in MMP checking */
+ uint64_t s_mmp_block; /* Block for multi-mount protection */
+ uint32_t s_raid_stripe_width; /* blocks on all data disks (N*stride)*/
+ uint8_t s_log_groups_per_flex; /* FLEX_BG group size */
+ uint8_t s_reserved_char_pad2;
+ uint16_t s_reserved_pad;
+ uint32_t s_reserved[162]; /* Padding to the end of the block */
+};
+
+/*******************************************************************************
+#ifndef DEPEND
+#if ext2_super_block_size != 1024
+#error ext2_super_block definition bogus
+#endif
+#endif
+*******************************************************************************/
+
+/*
+ * ext2 group desc structure:
+ */
+struct ext2_group_desc {
+ uint32_t bg_block_bitmap; /* Blocks bitmap block */
+ uint32_t bg_inode_bitmap; /* Inodes bitmap block */
+ uint32_t bg_inode_table; /* Inodes table block */
+ uint16_t bg_free_blocks_count; /* Free blocks count */
+ uint16_t bg_free_inodes_count; /* Free inodes count */
+ uint16_t bg_used_dirs_count; /* Directories count */
+ uint16_t bg_pad;
+ uint32_t bg_reserved[3];
+};
+
+/*******************************************************************************
+#ifndef DEPEND
+#if ext2_group_desc_size != 32
+#error ext2_group_desc definition bogus
+#endif
+#endif
+*******************************************************************************/
+
+
+/*
+ * ext2 inode structure:
+ */
+struct ext2_inode {
+ uint16_t i_mode; /* File mode */
+ uint16_t i_uid; /* Owner Uid */
+ uint32_t i_size; /* 4: Size in bytes */
+ uint32_t i_atime; /* Access time */
+ uint32_t i_ctime; /* 12: Creation time */
+ uint32_t i_mtime; /* Modification time */
+ uint32_t i_dtime; /* 20: Deletion Time */
+ uint16_t i_gid; /* Group Id */
+ uint16_t i_links_count; /* 24: Links count */
+ uint32_t i_blocks; /* Blocks count */
+ uint32_t i_flags; /* 32: File flags */
+ uint32_t l_i_reserved1;
+ uint32_t i_block[EXT2_N_BLOCKS]; /* 40: Pointers to blocks */
+ uint32_t i_version; /* File version (for NFS) */
+ uint32_t i_file_acl; /* File ACL */
+ uint32_t i_dir_acl; /* Directory ACL */
+ uint32_t i_faddr; /* Fragment address */
+ uint8_t l_i_frag; /* Fragment number */
+ uint8_t l_i_fsize; /* Fragment size */
+ uint16_t i_pad1;
+ uint32_t l_i_reserved2[2];
+};
+
+/*******************************************************************************
+#ifndef DEPEND
+#if ext2_inode_size != 128
+#error ext2_inode definition bogus
+#endif
+#endif
+*******************************************************************************/
+
+
+#define EXT2_NAME_LEN 255
+struct ext2_dir_entry {
+ unsigned int d_inode; /* Inode number */
+ unsigned short d_rec_len; /* Directory entry length */
+ unsigned char d_name_len; /* Name length */
+ unsigned char d_file_type;
+ char d_name[EXT2_NAME_LEN]; /* File name */
+};
+
+/*******************************************************************************
+#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 is the extent on-disk structure.
+ * It's used at the bottom of the tree.
+ */
+struct ext4_extent {
+ uint32_t ee_block; /* first logical block extent covers */
+ uint16_t ee_len; /* number of blocks covered by extent */
+ uint16_t ee_start_hi; /* high 16 bits of physical block */
+ uint32_t ee_start_lo; /* low 32 bits of physical block */
+};
+
+/*
+ * This is index on-disk structure.
+ * It's used at all the levels except the bottom.
+ */
+struct ext4_extent_idx {
+ uint32_t ei_block; /* index covers logical blocks from 'block' */
+ uint32_t ei_leaf_lo; /* pointer to the physical block of the next *
+ * level. leaf or next index could be there */
+ uint16_t ei_leaf_hi; /* high 16 bits of physical block */
+ uint16_t ei_unused;
+};
+
+/*
+ * Each block (leaves and indexes), even inode-stored has header.
+ */
+struct ext4_extent_header {
+ uint16_t eh_magic; /* probably will support different formats */
+ uint16_t eh_entries; /* number of valid entries */
+ uint16_t eh_max; /* capacity of store in entries */
+ uint16_t eh_depth; /* has tree real underlying blocks? */
+ uint32_t eh_generation; /* generation of the tree */
+};
+
+
+
+#define EXT4_FIRST_EXTENT(header) ( (struct ext4_extent *)(header + 1) )
+#define EXT4_FIRST_INDEX(header) ( (struct ext4_extent_idx *) (header + 1) )
+
+
+/*
+ * The ext2 super block information in memory
+ */
+struct ext2_sb_info {
+ uint32_t s_inodes_per_block;/* Number of inodes per block */
+ uint32_t s_inodes_per_group;/* Number of inodes in a group */
+ uint32_t s_blocks_per_group;/* Number of blocks in a group */
+ uint32_t s_desc_per_block; /* Number of group descriptors per block */
+ uint32_t s_groups_count; /* Number of groups in the fs */
+ uint32_t s_first_data_block; /* First Data Block */
+ int s_inode_size;
+};
+
+static inline struct ext2_sb_info *EXT2_SB(struct fs_info *fs)
+{
+ return fs->fs_info;
+}
+
+#define EXT2_BLOCKS_PER_GROUP(fs) (EXT2_SB(fs)->s_blocks_per_group)
+#define EXT2_INODES_PER_GROUP(fs) (EXT2_SB(fs)->s_inodes_per_group)
+#define EXT2_INODES_PER_BLOCK(fs) (EXT2_SB(fs)->s_inodes_per_block)
+#define EXT2_DESC_PER_BLOCK(fs) (EXT2_SB(fs)->s_desc_per_block)
+
+/*
+ * ext2 private inode information
+ */
+struct ext2_pvt_inode {
+ union {
+ uint32_t i_block[EXT2_N_BLOCKS];
+ struct ext4_extent_header i_extent_hdr;
+ };
+};
+
+#define PVT(i) ((struct ext2_pvt_inode *)((i)->pvt))
+
+/*
+ * functions
+ */
+block_t ext2_bmap(struct inode *, block_t, size_t *);
+int ext2_next_extent(struct inode *, uint32_t);
+
+#endif /* ext2_fs.h */
diff --git a/contrib/syslinux-4.02/core/fs/fat/fat.c b/contrib/syslinux-4.02/core/fs/fat/fat.c
new file mode 100644
index 0000000..5902f48
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/fat/fat.c
@@ -0,0 +1,795 @@
+#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 "codepage.h"
+#include "fat_fs.h"
+
+static struct inode * new_fat_inode(struct fs_info *fs)
+{
+ struct inode *inode = alloc_inode(fs, 0, sizeof(struct fat_pvt_inode));
+ if (!inode)
+ malloc_error("inode structure");
+
+ return inode;
+}
+
+/*
+ * Check for a particular sector in the FAT cache
+ */
+static const void *get_fat_sector(struct fs_info *fs, sector_t sector)
+{
+ return get_cache(fs->fs_dev, FAT_SB(fs)->fat + sector);
+}
+
+static uint32_t get_next_cluster(struct fs_info *fs, uint32_t clust_num)
+{
+ uint32_t next_cluster = 0;
+ sector_t fat_sector;
+ uint32_t offset;
+ uint32_t sector_mask = SECTOR_SIZE(fs) - 1;
+ const uint8_t *data;
+
+ switch(FAT_SB(fs)->fat_type) {
+ case FAT12:
+ offset = clust_num + (clust_num >> 1);
+ fat_sector = offset >> SECTOR_SHIFT(fs);
+ offset &= sector_mask;
+ data = get_fat_sector(fs, fat_sector);
+ if (offset == sector_mask) {
+ /*
+ * we got the end of the one fat sector,
+ * but we have just one byte and we need two,
+ * so store the low part, then read the next fat
+ * sector, read the high part, then combine it.
+ */
+ next_cluster = data[offset];
+ data = get_fat_sector(fs, fat_sector + 1);
+ next_cluster += data[0] << 8;
+ } else {
+ next_cluster = *(const uint16_t *)(data + offset);
+ }
+
+ if (clust_num & 0x0001)
+ next_cluster >>= 4; /* cluster number is ODD */
+ else
+ next_cluster &= 0x0fff; /* cluster number is EVEN */
+ break;
+
+ case FAT16:
+ offset = clust_num << 1;
+ fat_sector = offset >> SECTOR_SHIFT(fs);
+ offset &= sector_mask;
+ data = get_fat_sector(fs, fat_sector);
+ next_cluster = *(const uint16_t *)(data + offset);
+ break;
+
+ case FAT32:
+ offset = clust_num << 2;
+ fat_sector = offset >> SECTOR_SHIFT(fs);
+ offset &= sector_mask;
+ data = get_fat_sector(fs, fat_sector);
+ next_cluster = *(const uint32_t *)(data + offset);
+ next_cluster &= 0x0fffffff;
+ break;
+ }
+
+ return next_cluster;
+}
+
+static int fat_next_extent(struct inode *inode, uint32_t lstart)
+{
+ struct fs_info *fs = inode->fs;
+ struct fat_sb_info *sbi = FAT_SB(fs);
+ uint32_t mcluster = lstart >> sbi->clust_shift;
+ uint32_t lcluster;
+ uint32_t pcluster;
+ uint32_t tcluster;
+ uint32_t xcluster;
+ const uint32_t cluster_bytes = UINT32_C(1) << sbi->clust_byte_shift;
+ const uint32_t cluster_secs = UINT32_C(1) << sbi->clust_shift;
+ sector_t data_area = sbi->data;
+
+ tcluster = (inode->size + cluster_bytes - 1) >> sbi->clust_byte_shift;
+ if (mcluster >= tcluster)
+ goto err; /* Requested cluster beyond end of file */
+
+ lcluster = PVT(inode)->offset >> sbi->clust_shift;
+ pcluster = ((PVT(inode)->here - data_area) >> sbi->clust_shift) + 2;
+
+ if (lcluster > mcluster || PVT(inode)->here < data_area) {
+ lcluster = 0;
+ pcluster = PVT(inode)->start_cluster;
+ }
+
+ for (;;) {
+ if (pcluster-2 >= sbi->clusters) {
+ inode->size = lcluster << sbi->clust_shift;
+ goto err;
+ }
+
+ if (lcluster >= mcluster)
+ break;
+
+ lcluster++;
+ pcluster = get_next_cluster(fs, pcluster);
+ }
+
+ inode->next_extent.pstart =
+ ((sector_t)(pcluster-2) << sbi->clust_shift) + data_area;
+ inode->next_extent.len = cluster_secs;
+ xcluster = 0; /* Nonsense */
+
+ while (++lcluster < tcluster) {
+ xcluster = get_next_cluster(fs, pcluster);
+ if (xcluster != ++pcluster)
+ break; /* Not contiguous */
+ inode->next_extent.len += cluster_secs;
+ }
+
+ /* Note: ->here is bogus if ->offset >= EOF, but that's okay */
+ PVT(inode)->offset = lcluster << sbi->clust_shift;
+ PVT(inode)->here = ((xcluster-2) << sbi->clust_shift) + data_area;
+
+ return 0;
+
+err:
+ return -1;
+}
+
+static sector_t get_next_sector(struct fs_info* fs, uint32_t sector)
+{
+ struct fat_sb_info *sbi = FAT_SB(fs);
+ sector_t data_area = sbi->data;
+ sector_t data_sector;
+ uint32_t cluster;
+ int clust_shift = sbi->clust_shift;
+
+ if (sector < data_area) {
+ /* Root directory sector... */
+ sector++;
+ if (sector >= data_area)
+ sector = 0; /* Ran out of root directory, return EOF */
+ return sector;
+ }
+
+ data_sector = sector - data_area;
+ if ((data_sector + 1) & sbi->clust_mask) /* Still in the same cluster */
+ return sector + 1; /* Next sector inside cluster */
+
+ /* get a new cluster */
+ cluster = data_sector >> clust_shift;
+ cluster = get_next_cluster(fs, cluster + 2) - 2;
+
+ if (cluster >= sbi->clusters)
+ return 0;
+
+ /* return the start of the new cluster */
+ sector = (cluster << clust_shift) + data_area;
+ return sector;
+}
+
+/*
+ * The FAT is a single-linked list. We remember the last place we
+ * were, so for a forward seek we can move forward from there, but
+ * for a reverse seek we have to start over...
+ */
+static sector_t get_the_right_sector(struct file *file)
+{
+ struct inode *inode = file->inode;
+ uint32_t sector_pos = file->offset >> SECTOR_SHIFT(file->fs);
+ uint32_t where;
+ sector_t sector;
+
+ if (sector_pos < PVT(inode)->offset) {
+ /* Reverse seek */
+ where = 0;
+ sector = PVT(inode)->start;
+ } else {
+ where = PVT(inode)->offset;
+ sector = PVT(inode)->here;
+ }
+
+ while (where < sector_pos) {
+ sector = get_next_sector(file->fs, sector);
+ where++;
+ }
+
+ PVT(inode)->offset = sector_pos;
+ PVT(inode)->here = sector;
+
+ return sector;
+}
+
+/*
+ * Get the next sector in sequence
+ */
+static sector_t next_sector(struct file *file)
+{
+ struct inode *inode = file->inode;
+ sector_t sector = get_next_sector(file->fs, PVT(inode)->here);
+ PVT(inode)->offset++;
+ PVT(inode)->here = sector;
+
+ return sector;
+}
+
+/*
+ * Mangle a filename pointed to by src into a buffer pointed to by dst;
+ * ends on encountering any whitespace.
+ *
+ */
+static void vfat_mangle_name(char *dst, const char *src)
+{
+ char *p = dst;
+ 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 == '/') {
+ if (src[1] == '/' || src[1] == '\\') {
+ src++;
+ i--;
+ continue;
+ }
+ }
+ i--;
+ *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-1) != '/') && (*(dst-1) != '.'))
+ break;
+
+ dst--;
+ i++;
+ }
+
+ i++;
+ for (; i > 0; i --)
+ *dst++ = '\0';
+}
+
+/*
+ * Mangle a normal style string to DOS style string.
+ */
+static void mangle_dos_name(char *mangle_buf, const char *src)
+{
+ int i;
+ unsigned char c;
+
+ if (src[0] == '.' && (!src[1] || (src[1] == '.' && !src[2]))) {
+ /* . and .. mangle to their respective zero-padded version */
+ i = stpcpy(mangle_buf, src) - mangle_buf;
+ } else {
+ i = 0;
+ while (i < 11) {
+ c = *src++;
+
+ if ((c <= ' ') || (c == '/'))
+ break;
+
+ if (c == '.') {
+ while (i < 8)
+ mangle_buf[i++] = ' ';
+ i = 8;
+ continue;
+ }
+
+ c = codepage.upper[c];
+ if (i == 0 && c == 0xe5)
+ c = 0x05; /* Special hack for the first byte only! */
+
+ mangle_buf[i++] = c;
+ }
+ }
+
+ while (i < 11)
+ mangle_buf[i++] = ' ';
+
+ mangle_buf[i] = '\0';
+}
+
+/*
+ * Match a string name against a longname. "len" is the number of
+ * codepoints in the input; including padding.
+ *
+ * Returns true on match.
+ */
+static bool vfat_match_longname(const char *str, const uint16_t *match,
+ int len)
+{
+ unsigned char c = -1; /* Nonzero: we have not yet seen NUL */
+ uint16_t cp;
+
+ dprintf("Matching: %s\n", str);
+
+ while (len) {
+ cp = *match++;
+ len--;
+ if (!cp)
+ break;
+ c = *str++;
+ if (cp != codepage.uni[0][c] && cp != codepage.uni[1][c])
+ return false; /* Also handles c == '\0' */
+ }
+
+ /* This should have been the end of the matching string */
+ if (*str)
+ return false;
+
+ /* Any padding entries must be FFFF */
+ while (len--)
+ if (*match++ != 0xffff)
+ return false;
+
+ return true;
+}
+
+/*
+ * Convert an UTF-16 longname to the system codepage; return
+ * the length on success or -1 on failure.
+ */
+static int vfat_cvt_longname(char *entry_name, const uint16_t *long_name)
+{
+ struct unicache {
+ uint16_t utf16;
+ uint8_t cp;
+ };
+ static struct unicache unicache[256];
+ struct unicache *uc;
+ uint16_t cp;
+ unsigned int c;
+ char *p = entry_name;
+
+ do {
+ cp = *long_name++;
+ uc = &unicache[cp % 256];
+
+ if (__likely(uc->utf16 == cp)) {
+ *p++ = uc->cp;
+ } else {
+ for (c = 0; c < 512; c++) {
+ /* This is a bit hacky... */
+ if (codepage.uni[0][c] == cp) {
+ uc->utf16 = cp;
+ *p++ = uc->cp = (uint8_t)c;
+ goto found;
+ }
+ }
+ return -1; /* Impossible character */
+ found:
+ ;
+ }
+ } while (cp);
+
+ return (p-entry_name)-1;
+}
+
+static void copy_long_chunk(uint16_t *buf, const struct fat_dir_entry *de)
+{
+ const struct fat_long_name_entry *le =
+ (const struct fat_long_name_entry *)de;
+
+ memcpy(buf, le->name1, 5 * 2);
+ memcpy(buf + 5, le->name2, 6 * 2);
+ memcpy(buf + 11, le->name3, 2 * 2);
+}
+
+static uint8_t get_checksum(const char *dir_name)
+{
+ int i;
+ uint8_t sum = 0;
+
+ for (i = 11; i; i--)
+ sum = ((sum & 1) << 7) + (sum >> 1) + (uint8_t)*dir_name++;
+ return sum;
+}
+
+
+/* compute the first sector number of one dir where the data stores */
+static inline sector_t first_sector(struct fs_info *fs,
+ const struct fat_dir_entry *dir)
+{
+ const struct fat_sb_info *sbi = FAT_SB(fs);
+ sector_t first_clust;
+ sector_t sector;
+
+ first_clust = (dir->first_cluster_high << 16) + dir->first_cluster_low;
+ if (first_clust == 0)
+ sector = sbi->root; /* first_clust == 0 means root directory */
+ else
+ sector = ((first_clust - 2) << sbi->clust_shift) + sbi->data;
+
+ return sector;
+}
+
+static inline enum dirent_type get_inode_mode(uint8_t attr)
+{
+ return (attr & FAT_ATTR_DIRECTORY) ? DT_DIR : DT_REG;
+}
+
+
+static struct inode *vfat_find_entry(const char *dname, struct inode *dir)
+{
+ struct fs_info *fs = dir->fs;
+ struct inode *inode;
+ const struct fat_dir_entry *de;
+ struct fat_long_name_entry *long_de;
+
+ char mangled_name[12];
+ uint16_t long_name[260]; /* == 20*13 */
+ int long_len;
+
+ sector_t dir_sector = PVT(dir)->start;
+ uint8_t vfat_init, vfat_next, vfat_csum = 0;
+ uint8_t id;
+ int slots;
+ int entries;
+ int checksum;
+ int long_match = 0;
+
+ slots = (strlen(dname) + 12) / 13;
+ if (slots > 20)
+ return NULL; /* Name too long */
+
+ slots |= 0x40;
+ vfat_init = vfat_next = slots;
+ long_len = slots*13;
+
+ /* Produce the shortname version, in case we need it. */
+ mangle_dos_name(mangled_name, dname);
+
+ while (dir_sector) {
+ de = get_cache(fs->fs_dev, dir_sector);
+ entries = 1 << (fs->sector_shift - 5);
+
+ while (entries--) {
+ if (de->name[0] == 0)
+ return NULL;
+
+ if (de->attr == 0x0f) {
+ /*
+ * It's a long name entry.
+ */
+ long_de = (struct fat_long_name_entry *)de;
+ id = long_de->id;
+ if (id != vfat_next)
+ goto not_match;
+
+ if (id & 0x40) {
+ /* get the initial checksum value */
+ vfat_csum = long_de->checksum;
+ id &= 0x3f;
+ long_len = id * 13;
+
+ /* ZERO the long_name buffer */
+ memset(long_name, 0, sizeof long_name);
+ } else {
+ if (long_de->checksum != vfat_csum)
+ goto not_match;
+ }
+
+ vfat_next = --id;
+
+ /* got the long entry name */
+ copy_long_chunk(long_name + id*13, de);
+
+ /*
+ * If we got the last entry, check it.
+ * Or, go on with the next entry.
+ */
+ if (id == 0) {
+ if (!vfat_match_longname(dname, long_name, long_len))
+ goto not_match;
+ long_match = 1;
+ }
+ de++;
+ continue; /* Try the next entry */
+ } else {
+ /*
+ * It's a short entry
+ */
+ if (de->attr & 0x08) /* ignore volume labels */
+ goto not_match;
+
+ if (long_match) {
+ /*
+ * We already have a VFAT long name match. However, the
+ * match is only valid if the checksum matches.
+ */
+ checksum = get_checksum(de->name);
+ if (checksum == vfat_csum)
+ goto found; /* Got it */
+ } else {
+ if (!memcmp(mangled_name, de->name, 11))
+ goto found;
+ }
+ }
+
+ not_match:
+ vfat_next = vfat_init;
+ long_match = 0;
+
+ de++;
+ }
+
+ /* Try with the next sector */
+ dir_sector = get_next_sector(fs, dir_sector);
+ }
+ return NULL; /* Nothing found... */
+
+found:
+ inode = new_fat_inode(fs);
+ inode->size = de->file_size;
+ PVT(inode)->start_cluster =
+ (de->first_cluster_high << 16) + de->first_cluster_low;
+ if (PVT(inode)->start_cluster == 0) {
+ /* Root directory */
+ int root_size = FAT_SB(fs)->root_size;
+
+ PVT(inode)->start_cluster = FAT_SB(fs)->root_cluster;
+ inode->size = root_size ? root_size << fs->sector_shift : ~0;
+ PVT(inode)->start = PVT(inode)->here = FAT_SB(fs)->root;
+ } else {
+ PVT(inode)->start = PVT(inode)->here = first_sector(fs, de);
+ }
+ inode->mode = get_inode_mode(de->attr);
+
+ return inode;
+}
+
+static struct inode *vfat_iget_root(struct fs_info *fs)
+{
+ struct inode *inode = new_fat_inode(fs);
+ int root_size = FAT_SB(fs)->root_size;
+
+ /*
+ * For FAT32, the only way to get the root directory size is to
+ * follow the entire FAT chain to the end... which seems pointless.
+ */
+ PVT(inode)->start_cluster = FAT_SB(fs)->root_cluster;
+ inode->size = root_size ? root_size << fs->sector_shift : ~0;
+ PVT(inode)->start = PVT(inode)->here = FAT_SB(fs)->root;
+ inode->mode = DT_DIR;
+
+ return inode;
+}
+
+static struct inode *vfat_iget(const char *dname, struct inode *parent)
+{
+ return vfat_find_entry(dname, parent);
+}
+
+static int vfat_readdir(struct file *file, struct dirent *dirent)
+{
+ struct fs_info *fs = file->fs;
+ const struct fat_dir_entry *de;
+ const char *data;
+ const struct fat_long_name_entry *long_de;
+
+ sector_t sector = get_the_right_sector(file);
+
+ uint16_t long_name[261]; /* == 20*13 + 1 (to guarantee null) */
+ char filename[261];
+ int name_len = 0;
+
+ uint8_t vfat_init, vfat_next, vfat_csum;
+ uint8_t id;
+ int entries_left;
+ bool long_entry = false;
+ int sec_off = file->offset & ((1 << fs->sector_shift) - 1);
+
+ data = get_cache(fs->fs_dev, sector);
+ de = (const struct fat_dir_entry *)(data + sec_off);
+ entries_left = ((1 << fs->sector_shift) - sec_off) >> 5;
+
+ vfat_next = vfat_csum = 0xff;
+
+ while (1) {
+ while (entries_left--) {
+ if (de->name[0] == 0)
+ return -1; /* End of directory */
+ if ((uint8_t)de->name[0] == 0xe5)
+ goto invalid;
+
+ if (de->attr == 0x0f) {
+ /*
+ * It's a long name entry.
+ */
+ long_de = (struct fat_long_name_entry *)de;
+ id = long_de->id;
+
+ if (id & 0x40) {
+ /* init vfat_csum and vfat_init */
+ vfat_csum = long_de->checksum;
+ id &= 0x3f;
+ if (id >= 20)
+ goto invalid; /* Too long! */
+
+ vfat_init = id;
+
+ /* ZERO the long_name buffer */
+ memset(long_name, 0, sizeof long_name);
+ } else {
+ if (long_de->checksum != vfat_csum || id != vfat_next)
+ goto invalid;
+ }
+
+ vfat_next = --id;
+
+ /* got the long entry name */
+ copy_long_chunk(long_name + id*13, de);
+
+ if (id == 0) {
+ name_len = vfat_cvt_longname(filename, long_name);
+ if (name_len > 0 && name_len < sizeof(dirent->d_name))
+ long_entry = true;
+ }
+
+ goto next;
+ } else {
+ /*
+ * It's a short entry
+ */
+ if (de->attr & 0x08) /* ignore volume labels */
+ goto invalid;
+
+ if (long_entry && get_checksum(de->name) == vfat_csum) {
+ /* Got a long entry */
+ } else {
+ /* Use the shortname */
+ int i;
+ uint8_t c;
+ char *p = filename;
+
+ for (i = 0; i < 8; i++) {
+ c = de->name[i];
+ if (c == ' ')
+ break;
+ if (de->lcase & LCASE_BASE)
+ c = codepage.lower[c];
+ *p++ = c;
+ }
+ if (de->name[8] != ' ') {
+ *p++ = '.';
+ for (i = 8; i < 11; i++) {
+ c = de->name[i];
+ if (c == ' ')
+ break;
+ if (de->lcase & LCASE_EXT)
+ c = codepage.lower[c];
+ *p++ = c;
+ }
+ }
+ *p = '\0';
+ name_len = p - filename;
+ }
+ goto got; /* Got something one way or the other */
+ }
+
+ invalid:
+ long_entry = false;
+ next:
+ de++;
+ file->offset += sizeof(struct fat_dir_entry);
+ }
+
+ /* Try with the next sector */
+ sector = next_sector(file);
+ if (!sector)
+ return -1;
+ de = get_cache(fs->fs_dev, sector);
+ entries_left = 1 << (fs->sector_shift - 5);
+ }
+
+got:
+ name_len++; /* Include final null */
+ dirent->d_ino = de->first_cluster_low | (de->first_cluster_high << 16);
+ dirent->d_off = file->offset;
+ dirent->d_reclen = offsetof(struct dirent, d_name) + name_len;
+ dirent->d_type = get_inode_mode(de->attr);
+ memcpy(dirent->d_name, filename, name_len);
+
+ file->offset += sizeof(*de); /* Update for next reading */
+
+ return 0;
+}
+
+/* init. the fs meta data, return the block size in bits */
+static int vfat_fs_init(struct fs_info *fs)
+{
+ struct fat_bpb fat;
+ struct fat_sb_info *sbi;
+ struct disk *disk = fs->fs_dev->disk;
+ int sectors_per_fat;
+ uint32_t clusters;
+ sector_t total_sectors;
+
+ fs->sector_shift = fs->block_shift = disk->sector_shift;
+ fs->sector_size = 1 << fs->sector_shift;
+ fs->block_size = 1 << fs->block_shift;
+
+ disk->rdwr_sectors(disk, &fat, 0, 1, 0);
+
+ /* XXX: Find better sanity checks... */
+ if (!fat.bxResSectors || !fat.bxFATs)
+ return -1;
+ sbi = malloc(sizeof(*sbi));
+ if (!sbi)
+ malloc_error("fat_sb_info structure");
+ fs->fs_info = sbi;
+
+ sectors_per_fat = fat.bxFATsecs ? : fat.fat32.bxFATsecs_32;
+ total_sectors = fat.bxSectors ? : fat.bsHugeSectors;
+
+ sbi->fat = fat.bxResSectors;
+ sbi->root = sbi->fat + sectors_per_fat * fat.bxFATs;
+ sbi->root_size = root_dir_size(fs, &fat);
+ sbi->data = sbi->root + sbi->root_size;
+
+ sbi->clust_shift = ilog2(fat.bxSecPerClust);
+ sbi->clust_byte_shift = sbi->clust_shift + fs->sector_shift;
+ sbi->clust_mask = fat.bxSecPerClust - 1;
+ sbi->clust_size = fat.bxSecPerClust << fs->sector_shift;
+
+ clusters = (total_sectors - sbi->data) >> sbi->clust_shift;
+ if (clusters <= 0xff4) {
+ sbi->fat_type = FAT12;
+ } else if (clusters <= 0xfff4) {
+ sbi->fat_type = FAT16;
+ } else {
+ sbi->fat_type = FAT32;
+
+ if (clusters > 0x0ffffff4)
+ clusters = 0x0ffffff4; /* Maximum possible */
+
+ if (fat.fat32.extended_flags & 0x80) {
+ /* Non-mirrored FATs, we need to read the active one */
+ sbi->fat += (fat.fat32.extended_flags & 0x0f) * sectors_per_fat;
+ }
+
+ /* FAT32: root directory is a cluster chain */
+ sbi->root = sbi->data
+ + ((fat.fat32.root_cluster-2) << sbi->clust_shift);
+ }
+ sbi->clusters = clusters;
+
+ /* Initialize the cache */
+ cache_init(fs->fs_dev, fs->block_shift);
+
+ return fs->block_shift;
+}
+
+const struct fs_ops vfat_fs_ops = {
+ .fs_name = "vfat",
+ .fs_flags = FS_USEMEM | FS_THISIND,
+ .fs_init = vfat_fs_init,
+ .searchdir = NULL,
+ .getfssec = generic_getfssec,
+ .close_file = generic_close_file,
+ .mangle_name = vfat_mangle_name,
+ .load_config = generic_load_config,
+ .readdir = vfat_readdir,
+ .iget_root = vfat_iget_root,
+ .iget = vfat_iget,
+ .next_extent = fat_next_extent,
+};
diff --git a/contrib/syslinux-4.02/core/fs/fat/fat_fs.h b/contrib/syslinux-4.02/core/fs/fat/fat_fs.h
new file mode 100644
index 0000000..7ea3db8
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/fat/fat_fs.h
@@ -0,0 +1,158 @@
+#ifndef FAT_FS_H
+#define FAT_FS_H
+
+#include <stdint.h>
+
+#define FAT_DIR_ENTRY_SIZE 32
+#define DIRENT_SHIFT 5
+
+#define FAT_ATTR_READ_ONLY 0x01
+#define FAT_ATTR_HIDDEN 0x02
+#define FAT_ATTR_SYSTEM 0x04
+#define FAT_ATTR_VOLUME_ID 0x08
+#define FAT_ATTR_DIRECTORY 0x10
+#define FAT_ATTR_ARCHIVE 0x20
+
+#define FAT_MAXFILE 256
+
+#define FAT_ATTR_LONG_NAME (FAT_ATTR_READ_ONLY \
+ | FAT_ATTR_HIDDEN \
+ | FAT_ATTR_SYSTEM \
+ | FAT_ATTR_VOLUME_ID)
+
+#define FAT_ATTR_VALID (FAT_ATTR_READ_ONLY \
+ | FAT_ATTR_HIDDEN \
+ | FAT_ATTR_SYSTEM \
+ | FAT_ATTR_DIRECTORY \
+ | FAT_ATTR_ARCHIVE)
+
+enum fat_type{ FAT12, FAT16, FAT32 };
+
+/*
+ * The fat file system structures
+ */
+
+struct fat_bpb {
+ uint8_t jmp_boot[3];
+ uint8_t oem_name[8];
+ uint16_t sector_size;
+ uint8_t bxSecPerClust;
+ uint16_t bxResSectors;
+ uint8_t bxFATs;
+ uint16_t bxRootDirEnts;
+ uint16_t bxSectors;
+ uint8_t media;
+ uint16_t bxFATsecs;
+ uint16_t sectors_per_track;
+ uint16_t num_heads;
+ uint32_t num_hidden_sectors;
+ uint32_t bsHugeSectors;
+
+ union {
+ struct {
+ uint8_t num_ph_drive;
+ uint8_t reserved;
+ uint8_t boot_sig;
+ uint32_t num_serial;
+ uint8_t label[11];
+ uint8_t fstype[8];
+ } __attribute__ ((packed)) fat12_16;
+
+ struct {
+ uint32_t bxFATsecs_32;
+ uint16_t extended_flags;
+ uint16_t fs_version;
+ uint32_t root_cluster;
+ uint16_t fs_info;
+ uint16_t backup_boot_sector;
+ uint8_t reserved[12];
+ uint8_t num_ph_drive;
+ uint8_t reserved1;
+ uint8_t boot_sig;
+ uint32_t num_serial;
+ uint8_t label[11];
+ uint8_t fstype[8];
+ } __attribute__ ((packed)) fat32;
+
+ } __attribute__ ((packed));
+
+ uint8_t pad[422]; /* padding to 512 Bytes (one sector) */
+
+} __attribute__ ((packed));
+
+/*
+ * The fat file system info in memory
+ */
+struct fat_sb_info {
+ sector_t fat; /* The FAT region */
+ sector_t root; /* The root dir region */
+ sector_t data; /* The data region */
+
+ uint32_t clusters; /* Total number of clusters */
+ uint32_t root_cluster; /* Cluster number for (FAT32) root dir */
+ int root_size; /* The root dir size in sectors */
+
+ int clust_shift; /* based on sectors */
+ int clust_byte_shift; /* based on bytes */
+ int clust_mask; /* sectors per cluster mask */
+ int clust_size;
+
+ int fat_type;
+} __attribute__ ((packed));
+
+struct fat_dir_entry {
+ char name[11];
+ uint8_t attr;
+ uint8_t lcase;
+ uint8_t c_time_tenth;
+ uint16_t c_time;
+ uint16_t c_date;
+ uint16_t a_date;
+ uint16_t first_cluster_high;
+ uint16_t w_time;
+ uint16_t w_date;
+ uint16_t first_cluster_low;
+ uint32_t file_size;
+} __attribute__ ((packed));
+
+#define LCASE_BASE 8 /* basename is lower case */
+#define LCASE_EXT 16 /* extension is lower case */
+
+struct fat_long_name_entry {
+ uint8_t id;
+ uint16_t name1[5];
+ uint8_t attr;
+ uint8_t reserved;
+ uint8_t checksum;
+ uint16_t name2[6];
+ uint16_t first_cluster;
+ uint16_t name3[2];
+} __attribute__ ((packed));
+
+static inline struct fat_sb_info *FAT_SB(struct fs_info *fs)
+{
+ return fs->fs_info;
+}
+
+/*
+ * Count the root dir size in sectors
+ */
+static inline int root_dir_size(struct fs_info *fs, struct fat_bpb *fat)
+{
+ return (fat->bxRootDirEnts + SECTOR_SIZE(fs)/32 - 1)
+ >> (SECTOR_SHIFT(fs) - 5);
+}
+
+/*
+ * FAT private inode information
+ */
+struct fat_pvt_inode {
+ 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 */
+};
+
+#define PVT(i) ((struct fat_pvt_inode *)((i)->pvt))
+
+#endif /* fat_fs.h */
diff --git a/contrib/syslinux-4.02/core/fs/fs.c b/contrib/syslinux-4.02/core/fs/fs.c
new file mode 100644
index 0000000..48856c9
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/fs.c
@@ -0,0 +1,475 @@
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <dprintf.h>
+#include "fs.h"
+#include "cache.h"
+
+/* The currently mounted filesystem */
+struct fs_info *this_fs = NULL; /* Root filesystem */
+
+/* Actual file structures (we don't have malloc yet...) */
+struct file files[MAX_OPEN];
+
+/* Symlink hard limits */
+#define MAX_SYMLINK_CNT 20
+#define MAX_SYMLINK_BUF 4096
+
+/*
+ * Get a new inode structure
+ */
+struct inode *alloc_inode(struct fs_info *fs, uint32_t ino, size_t data)
+{
+ struct inode *inode = zalloc(sizeof(struct inode) + data);
+ if (inode) {
+ inode->fs = fs;
+ inode->ino = ino;
+ inode->refcnt = 1;
+ }
+ return inode;
+}
+
+/*
+ * Free a refcounted inode
+ */
+void put_inode(struct inode *inode)
+{
+ while (inode && --inode->refcnt == 0) {
+ struct inode *dead = inode;
+ inode = inode->parent;
+ free(dead);
+ }
+}
+
+/*
+ * Get an empty file structure
+ */
+static struct file *alloc_file(void)
+{
+ int i;
+ struct file *file = files;
+
+ for (i = 0; i < MAX_OPEN; i++) {
+ if (!file->fs)
+ return file;
+ file++;
+ }
+
+ return NULL;
+}
+
+/*
+ * Close and free a file structure
+ */
+static inline void free_file(struct file *file)
+{
+ memset(file, 0, sizeof *file);
+}
+
+void _close_file(struct file *file)
+{
+ if (file->fs)
+ file->fs->fs_ops->close_file(file);
+ free_file(file);
+}
+
+/*
+ * Convert between a 16-bit file handle and a file structure
+ */
+
+void load_config(void)
+{
+ int err;
+
+ err = this_fs->fs_ops->load_config();
+
+ if (err)
+ printf("ERROR: No configuration file found\n");
+}
+
+void pm_mangle_name(com32sys_t *regs)
+{
+ const char *src = MK_PTR(regs->ds, regs->esi.w[0]);
+ char *dst = MK_PTR(regs->es, regs->edi.w[0]);
+
+ mangle_name(dst, src);
+}
+
+void mangle_name(char *dst, const char *src)
+{
+ this_fs->fs_ops->mangle_name(dst, src);
+}
+
+void getfssec(com32sys_t *regs)
+{
+ int sectors;
+ bool have_more;
+ uint32_t bytes_read;
+ char *buf;
+ struct file *file;
+ uint16_t handle;
+
+ sectors = regs->ecx.w[0];
+
+ handle = regs->esi.w[0];
+ file = handle_to_file(handle);
+
+ buf = MK_PTR(regs->es, regs->ebx.w[0]);
+ bytes_read = file->fs->fs_ops->getfssec(file, buf, sectors, &have_more);
+
+ /*
+ * If we reach EOF, the filesystem driver will have already closed
+ * the underlying file... this really should be cleaner.
+ */
+ if (!have_more) {
+ _close_file(file);
+ regs->esi.w[0] = 0;
+ }
+
+ regs->ecx.l = bytes_read;
+}
+
+void getfsbytes(com32sys_t *regs)
+{
+ int sectors;
+ bool have_more;
+ uint32_t bytes_read;
+ char *buf;
+ struct file *file;
+ uint16_t handle;
+
+ handle = regs->esi.w[0];
+ file = handle_to_file(handle);
+
+ sectors = regs->ecx.w[0] >> SECTOR_SHIFT(file->fs);
+
+ buf = MK_PTR(regs->es, regs->ebx.w[0]);
+ bytes_read = file->fs->fs_ops->getfssec(file, buf, sectors, &have_more);
+
+ /*
+ * If we reach EOF, the filesystem driver will have already closed
+ * the underlying file... this really should be cleaner.
+ */
+ if (!have_more) {
+ _close_file(file);
+ regs->esi.w[0] = 0;
+ }
+
+ regs->ecx.l = bytes_read;
+}
+
+size_t pmapi_read_file(uint16_t *handle, void *buf, size_t sectors)
+{
+ bool have_more;
+ size_t bytes_read;
+ struct file *file;
+
+ file = handle_to_file(*handle);
+ bytes_read = file->fs->fs_ops->getfssec(file, buf, sectors, &have_more);
+
+ /*
+ * If we reach EOF, the filesystem driver will have already closed
+ * the underlying file... this really should be cleaner.
+ */
+ if (!have_more) {
+ _close_file(file);
+ *handle = 0;
+ }
+
+ return bytes_read;
+}
+
+void pm_searchdir(com32sys_t *regs)
+{
+ char *name = MK_PTR(regs->ds, regs->edi.w[0]);
+ int rv;
+
+ rv = searchdir(name);
+ if (rv < 0) {
+ regs->esi.w[0] = 0;
+ regs->eax.l = 0;
+ regs->eflags.l |= EFLAGS_ZF;
+ } else {
+ regs->esi.w[0] = rv;
+ regs->eax.l = handle_to_file(rv)->inode->size;
+ regs->eflags.l &= ~EFLAGS_ZF;
+ }
+}
+
+int searchdir(const char *name)
+{
+ struct inode *inode = NULL;
+ struct inode *parent = NULL;
+ struct file *file;
+ char *pathbuf = NULL;
+ char *part, *p, echar;
+ int symlink_count = MAX_SYMLINK_CNT;
+
+ if (!(file = alloc_file()))
+ goto err_no_close;
+ file->fs = this_fs;
+
+ /* if we have ->searchdir method, call it */
+ if (file->fs->fs_ops->searchdir) {
+ file->fs->fs_ops->searchdir(name, file);
+
+ if (file->inode)
+ return file_to_handle(file);
+ else
+ goto err;
+ }
+
+ /* else, try the generic-path-lookup method */
+
+ parent = get_inode(this_fs->cwd);
+ p = pathbuf = strdup(name);
+ if (!pathbuf)
+ goto err;
+
+ do {
+ got_link:
+ if (*p == '/') {
+ put_inode(parent);
+ parent = get_inode(this_fs->root);
+ }
+
+ do {
+ inode = get_inode(parent);
+
+ while (*p == '/')
+ p++;
+
+ if (!*p)
+ break;
+
+ part = p;
+ while ((echar = *p) && echar != '/')
+ p++;
+ *p++ = '\0';
+
+ if (part[0] == '.' && part[1] == '.' && part[2] == '\0') {
+ if (inode->parent) {
+ put_inode(parent);
+ parent = get_inode(inode->parent);
+ put_inode(inode);
+ inode = NULL;
+ if (!echar) {
+ /* Terminal double dots */
+ inode = parent;
+ parent = inode->parent ?
+ get_inode(inode->parent) : NULL;
+ }
+ }
+ } else if (part[0] != '.' || part[1] != '\0') {
+ inode = this_fs->fs_ops->iget(part, parent);
+ if (!inode)
+ goto err;
+ if (inode->mode == DT_LNK) {
+ char *linkbuf, *q;
+ int name_len = echar ? strlen(p) : 0;
+ int total_len = inode->size + name_len + 2;
+ int link_len;
+
+ if (!this_fs->fs_ops->readlink ||
+ --symlink_count == 0 || /* limit check */
+ total_len > MAX_SYMLINK_BUF)
+ goto err;
+
+ linkbuf = malloc(total_len);
+ if (!linkbuf)
+ goto err;
+
+ link_len = this_fs->fs_ops->readlink(inode, linkbuf);
+ if (link_len <= 0) {
+ free(linkbuf);
+ goto err;
+ }
+
+ q = linkbuf + link_len;
+
+ if (echar) {
+ if (link_len > 0 && q[-1] != '/')
+ *q++ = '/';
+
+ memcpy(q, p, name_len+1);
+ } else {
+ *q = '\0';
+ }
+
+ free(pathbuf);
+ p = pathbuf = linkbuf;
+ put_inode(inode);
+ inode = NULL;
+ goto got_link;
+ }
+
+ inode->parent = parent;
+ parent = NULL;
+
+ if (!echar)
+ break;
+
+ if (inode->mode != DT_DIR)
+ goto err;
+
+ parent = inode;
+ inode = NULL;
+ }
+ } while (echar);
+ } while (0);
+
+ free(pathbuf);
+ pathbuf = NULL;
+ put_inode(parent);
+ parent = NULL;
+
+ if (!inode)
+ goto err;
+
+ file->inode = inode;
+ file->offset = 0;
+
+ return file_to_handle(file);
+
+err:
+ put_inode(inode);
+ put_inode(parent);
+ if (pathbuf)
+ free(pathbuf);
+ _close_file(file);
+err_no_close:
+ return -1;
+}
+
+int open_file(const char *name, struct com32_filedata *filedata)
+{
+ int rv;
+ struct file *file;
+ char mangled_name[FILENAME_MAX];
+
+ mangle_name(mangled_name, name);
+ rv = searchdir(mangled_name);
+
+ if (rv < 0)
+ return rv;
+
+ file = handle_to_file(rv);
+
+ if (file->inode->mode != DT_REG) {
+ _close_file(file);
+ return -1;
+ }
+
+ filedata->size = file->inode->size;
+ filedata->blocklg2 = SECTOR_SHIFT(file->fs);
+ filedata->handle = rv;
+
+ return rv;
+}
+
+void pm_open_file(com32sys_t *regs)
+{
+ int rv;
+ struct file *file;
+ const char *name = MK_PTR(regs->es, regs->esi.w[0]);
+ char mangled_name[FILENAME_MAX];
+
+ mangle_name(mangled_name, name);
+ rv = searchdir(mangled_name);
+ if (rv < 0) {
+ regs->eflags.l |= EFLAGS_CF;
+ } else {
+ file = handle_to_file(rv);
+ regs->eflags.l &= ~EFLAGS_CF;
+ regs->eax.l = file->inode->size;
+ regs->ecx.w[0] = SECTOR_SIZE(file->fs);
+ regs->esi.w[0] = rv;
+ }
+}
+
+void close_file(uint16_t handle)
+{
+ struct file *file;
+
+ if (handle) {
+ file = handle_to_file(handle);
+ _close_file(file);
+ }
+}
+
+void pm_close_file(com32sys_t *regs)
+{
+ close_file(regs->esi.w[0]);
+}
+
+/*
+ * it will do:
+ * initialize the memory management function;
+ * set up the vfs fs structure;
+ * initialize the device structure;
+ * invoke the fs-specific init function;
+ * initialize the cache if we need one;
+ * finally, get the current inode for relative path looking.
+ */
+__bss16 uint16_t SectorSize, SectorShift;
+
+void fs_init(com32sys_t *regs)
+{
+ static struct fs_info fs; /* The actual filesystem buffer */
+ uint8_t disk_devno = regs->edx.b[0];
+ uint8_t disk_cdrom = regs->edx.b[1];
+ sector_t disk_offset = regs->ecx.l | ((sector_t)regs->ebx.l << 32);
+ uint16_t disk_heads = regs->esi.w[0];
+ uint16_t disk_sectors = regs->edi.w[0];
+ uint32_t maxtransfer = regs->ebp.l;
+ int blk_shift = -1;
+ struct device *dev = NULL;
+ /* ops is a ptr list for several fs_ops */
+ const struct fs_ops **ops = (const struct fs_ops **)regs->eax.l;
+
+ /* Initialize malloc() */
+ mem_init();
+
+ /* Default name for the root directory */
+ fs.cwd_name[0] = '/';
+
+ while ((blk_shift < 0) && *ops) {
+ /* set up the fs stucture */
+ fs.fs_ops = *ops;
+
+ /*
+ * This boldly assumes that we don't mix FS_NODEV filesystems
+ * with FS_DEV filesystems...
+ */
+ if (fs.fs_ops->fs_flags & FS_NODEV) {
+ fs.fs_dev = NULL;
+ } else {
+ if (!dev)
+ dev = device_init(disk_devno, disk_cdrom, disk_offset,
+ disk_heads, disk_sectors, maxtransfer);
+ fs.fs_dev = dev;
+ }
+ /* invoke the fs-specific init code */
+ blk_shift = fs.fs_ops->fs_init(&fs);
+ ops++;
+ }
+ if (blk_shift < 0) {
+ printf("No valid file system found!\n");
+ while (1)
+ ;
+ }
+ this_fs = &fs;
+
+ /* initialize the cache */
+ if (fs.fs_dev && fs.fs_dev->cache_data)
+ cache_init(fs.fs_dev, blk_shift);
+
+ /* start out in the root directory */
+ if (fs.fs_ops->iget_root) {
+ fs.root = fs.fs_ops->iget_root(&fs);
+ fs.cwd = get_inode(fs.root);
+ }
+
+ SectorShift = fs.sector_shift;
+ SectorSize = fs.sector_size;
+}
diff --git a/contrib/syslinux-4.02/core/fs/getcwd.c b/contrib/syslinux-4.02/core/fs/getcwd.c
new file mode 100644
index 0000000..a7b6c7a
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/getcwd.c
@@ -0,0 +1,13 @@
+#include <string.h>
+#include "fs.h"
+
+char *getcwd(char *buf, size_t size)
+{
+ char *ret = NULL;
+
+ if((buf != NULL) && (strlen(this_fs->cwd_name) < size)) {
+ strcpy(buf, this_fs->cwd_name);
+ ret = buf;
+ }
+ return ret;
+}
diff --git a/contrib/syslinux-4.02/core/fs/getfssec.c b/contrib/syslinux-4.02/core/fs/getfssec.c
new file mode 100644
index 0000000..e099b64
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/getfssec.c
@@ -0,0 +1,194 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2010 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * getfssec.c
+ *
+ * Generic getfssec implementation for disk-based filesystems, which
+ * support the next_extent() method.
+ *
+ * The expected semantics of next_extent are as follows:
+ *
+ * The second argument will contain the initial sector number to be
+ * mapped. The routine is expected to populate
+ * inode->next_extent.pstart and inode->next_extent.len (the caller
+ * will store the initial sector number into inode->next_extent.lstart
+ * on return.)
+ *
+ * If inode->next_extent.len != 0 on entry then the routine is allowed
+ * to assume inode->next_extent contains valid data from the previous
+ * usage, which can be used for optimization purposes.
+ *
+ * If the filesystem can map the entire file as a single extent
+ * (e.g. iso9660), then the filesystem can simply insert the extent
+ * information into inode->next_extent at searchdir/iget time, and leave
+ * next_extent() as NULL.
+ *
+ * Note: the filesystem driver is not required to do extent coalescing,
+ * if that is difficult to do; this routine will perform extent lookahead
+ * and coalescing.
+ */
+
+#include <dprintf.h>
+#include <minmax.h>
+#include "fs.h"
+
+static inline sector_t next_psector(sector_t psector, uint32_t skip)
+{
+ if (EXTENT_SPECIAL(psector))
+ return psector;
+ else
+ return psector + skip;
+}
+
+static inline sector_t next_pstart(const struct extent *e)
+{
+ return next_psector(e->pstart, e->len);
+}
+
+
+static void get_next_extent(struct inode *inode)
+{
+ /* The logical start address that we care about... */
+ uint32_t lstart = inode->this_extent.lstart + inode->this_extent.len;
+
+ if (inode->fs->fs_ops->next_extent(inode, lstart))
+ inode->next_extent.len = 0; /* ERROR */
+ inode->next_extent.lstart = lstart;
+
+ dprintf("Extent: inode %p @ %u start %llu len %u\n",
+ inode, inode->next_extent.lstart,
+ inode->next_extent.pstart, inode->next_extent.len);
+}
+
+uint32_t generic_getfssec(struct file *file, char *buf,
+ int sectors, bool *have_more)
+{
+ struct inode *inode = file->inode;
+ struct fs_info *fs = file->fs;
+ struct disk *disk = fs->fs_dev->disk;
+ uint32_t bytes_read = 0;
+ uint32_t bytes_left = inode->size - file->offset;
+ uint32_t sectors_left =
+ (bytes_left + SECTOR_SIZE(fs) - 1) >> SECTOR_SHIFT(fs);
+ uint32_t lsector;
+
+ if (sectors > sectors_left)
+ sectors = sectors_left;
+
+ if (!sectors)
+ return 0;
+
+ lsector = file->offset >> SECTOR_SHIFT(fs);
+ dprintf("Offset: %u lsector: %u\n", file->offset, lsector);
+
+ if (lsector < inode->this_extent.lstart ||
+ lsector >= inode->this_extent.lstart + inode->this_extent.len) {
+ /* inode->this_extent unusable, maybe next_extent is... */
+ inode->this_extent = inode->next_extent;
+ }
+
+ if (lsector < inode->this_extent.lstart ||
+ lsector >= inode->this_extent.lstart + inode->this_extent.len) {
+ /* Still nothing useful... */
+ inode->this_extent.lstart = lsector;
+ inode->this_extent.len = 0;
+ } else {
+ /* We have some usable information */
+ uint32_t delta = lsector - inode->this_extent.lstart;
+ inode->this_extent.lstart = lsector;
+ inode->this_extent.len -= delta;
+ inode->this_extent.pstart
+ = next_psector(inode->this_extent.pstart, delta);
+ }
+
+ dprintf("this_extent: lstart %u pstart %llu len %u\n",
+ inode->this_extent.lstart,
+ inode->this_extent.pstart,
+ inode->this_extent.len);
+
+ while (sectors) {
+ uint32_t chunk;
+ size_t len;
+
+ while (sectors > inode->this_extent.len) {
+ if (!inode->next_extent.len ||
+ inode->next_extent.lstart !=
+ inode->this_extent.lstart + inode->this_extent.len)
+ get_next_extent(inode);
+
+ if (!inode->this_extent.len) {
+ /* Doesn't matter if it's contiguous... */
+ inode->this_extent = inode->next_extent;
+ if (!inode->next_extent.len) {
+ sectors = 0; /* Failed to get anything... we're dead */
+ break;
+ }
+ } else if (inode->next_extent.len &&
+ inode->next_extent.pstart == next_pstart(&inode->this_extent)) {
+ /* Coalesce extents and loop */
+ inode->this_extent.len += inode->next_extent.len;
+ } else {
+ /* Discontiguous extents */
+ break;
+ }
+ }
+
+ dprintf("this_extent: lstart %u pstart %llu len %u\n",
+ inode->this_extent.lstart,
+ inode->this_extent.pstart,
+ inode->this_extent.len);
+
+ chunk = min(sectors, inode->this_extent.len);
+ len = chunk << SECTOR_SHIFT(fs);
+
+ dprintf(" I/O: inode %p @ %u start %llu len %u\n",
+ inode, inode->this_extent.lstart,
+ inode->this_extent.pstart, chunk);
+
+ if (inode->this_extent.pstart == EXTENT_ZERO) {
+ memset(buf, 0, len);
+ } else {
+ disk->rdwr_sectors(disk, buf, inode->this_extent.pstart, chunk, 0);
+ inode->this_extent.pstart += chunk;
+ }
+
+ buf += len;
+ sectors -= chunk;
+ bytes_read += len;
+ inode->this_extent.lstart += chunk;
+ inode->this_extent.len -= chunk;
+ }
+
+ bytes_read = min(bytes_read, bytes_left);
+ file->offset += bytes_read;
+
+ if (have_more)
+ *have_more = bytes_read < bytes_left;
+
+ return bytes_read;
+}
diff --git a/contrib/syslinux-4.02/core/fs/iso9660/iso9660.c b/contrib/syslinux-4.02/core/fs/iso9660/iso9660.c
new file mode 100644
index 0000000..62137d0
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/iso9660/iso9660.c
@@ -0,0 +1,346 @@
+#include <dprintf.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/dirent.h>
+#include <core.h>
+#include <cache.h>
+#include <disk.h>
+#include <fs.h>
+#include "iso9660_fs.h"
+
+/* Convert to lower case string */
+static inline char iso_tolower(char c)
+{
+ if (c >= 'A' && c <= 'Z')
+ c += 0x20;
+
+ return c;
+}
+
+static struct inode *new_iso_inode(struct fs_info *fs)
+{
+ return alloc_inode(fs, 0, sizeof(struct iso9660_pvt_inode));
+}
+
+static inline struct iso_sb_info *ISO_SB(struct fs_info *fs)
+{
+ return fs->fs_info;
+}
+
+/*
+ * 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 trailing dots and redumndant slashes, so "repe
+ * cmpsb" can do a compare, and the path-searching routine gets
+ * a bit of an easier job.
+ *
+ */
+static void iso_mangle_name(char *dst, const char *src)
+{
+ char *p = dst;
+ int i = FILENAME_MAX - 1;
+
+ while (not_whitespace(*src)) {
+ if ( *src == '/' ) {
+ if ( *(src+1) == '/' ) {
+ i--;
+ src++;
+ continue;
+ }
+ }
+
+ *dst++ = *src ++;
+ i--;
+ }
+
+ while ( 1 ) {
+ if ( dst == p )
+ break;
+
+ if ( (*(dst-1) != '.') && (*(dst-1) != '/') )
+ break;
+
+ dst --;
+ i ++;
+ }
+
+ i ++;
+ for (; i > 0; i -- )
+ *dst++ = '\0';
+}
+
+static size_t iso_convert_name(char *dst, const char *src, int len)
+{
+ char *p = dst;
+ char c;
+
+ if (len == 1) {
+ switch (*src) {
+ case 1:
+ *p++ = '.';
+ /* fall through */
+ case 0:
+ *p++ = '.';
+ goto done;
+ default:
+ /* nothing special */
+ break;
+ }
+ }
+
+ while (len-- && (c = *src++)) {
+ if (c == ';') /* Remove any filename version suffix */
+ break;
+ *p++ = iso_tolower(c);
+ }
+
+ /* Then remove any terminal dots */
+ while (p > dst+1 && p[-1] == '.')
+ p--;
+
+done:
+ *p = '\0';
+ return p - dst;
+}
+
+/*
+ * Unlike strcmp, it does return 1 on match, or reutrn 0 if not match.
+ */
+static bool iso_compare_name(const char *de_name, size_t len,
+ const char *file_name)
+{
+ char iso_file_name[256];
+ char *p = iso_file_name;
+ char c1, c2;
+ size_t i;
+
+ i = iso_convert_name(iso_file_name, de_name, len);
+ dprintf("Compare: \"%s\" to \"%s\" (len %zu)\n",
+ file_name, iso_file_name, i);
+
+ do {
+ c1 = *p++;
+ c2 = iso_tolower(*file_name++);
+
+ /* compare equal except for case? */
+ if (c1 != c2)
+ return false;
+ } while (c1);
+
+ return true;
+}
+
+/*
+ * Find a entry in the specified dir with name _dname_.
+ */
+static const struct iso_dir_entry *
+iso_find_entry(const char *dname, struct inode *inode)
+{
+ struct fs_info *fs = inode->fs;
+ block_t dir_block = PVT(inode)->lba;
+ int i = 0, offset = 0;
+ const char *de_name;
+ int de_name_len, de_len;
+ const struct iso_dir_entry *de;
+ const char *data = NULL;
+
+ dprintf("iso_find_entry: \"%s\"\n", dname);
+
+ while (1) {
+ if (!data) {
+ dprintf("Getting block %d from block %llu\n", i, dir_block);
+ if (++i > inode->blocks)
+ return NULL; /* End of directory */
+ data = get_cache(fs->fs_dev, dir_block++);
+ offset = 0;
+ }
+
+ de = (const struct iso_dir_entry *)(data + offset);
+ de_len = de->length;
+ offset += de_len;
+
+ /* Make sure we have a full directory entry */
+ if (de_len < 33 || offset > BLOCK_SIZE(fs)) {
+ /*
+ * Zero = end of sector, or corrupt directory entry
+ *
+ * ECMA-119:1987 6.8.1.1: "Each Directory Record shall end
+ * in the Logical Sector in which it begins.
+ */
+ data = NULL;
+ continue;
+ }
+
+ de_name_len = de->name_len;
+ de_name = de->name;
+ if (iso_compare_name(de_name, de_name_len, dname)) {
+ dprintf("Found.\n");
+ return de;
+ }
+ }
+}
+
+static inline enum dirent_type get_inode_mode(uint8_t flags)
+{
+ return (flags & 0x02) ? DT_DIR : DT_REG;
+}
+
+static struct inode *iso_get_inode(struct fs_info *fs,
+ const struct iso_dir_entry *de)
+{
+ struct inode *inode = new_iso_inode(fs);
+ int blktosec = BLOCK_SHIFT(fs) - SECTOR_SHIFT(fs);
+
+ if (!inode)
+ return NULL;
+
+ dprintf("Getting inode for: %.*s\n", de->name_len, de->name);
+
+ inode->mode = get_inode_mode(de->flags);
+ inode->size = de->size_le;
+ PVT(inode)->lba = de->extent_le;
+ inode->blocks = (inode->size + BLOCK_SIZE(fs) - 1) >> BLOCK_SHIFT(fs);
+
+ /* We have a single extent for all data */
+ inode->next_extent.pstart = (sector_t)de->extent_le << blktosec;
+ inode->next_extent.len = (sector_t)inode->blocks << blktosec;
+
+ return inode;
+}
+
+static struct inode *iso_iget_root(struct fs_info *fs)
+{
+ const struct iso_dir_entry *root = &ISO_SB(fs)->root;
+
+ return iso_get_inode(fs, root);
+}
+
+static struct inode *iso_iget(const char *dname, struct inode *parent)
+{
+ const struct iso_dir_entry *de;
+
+ dprintf("iso_iget %p %s\n", parent, dname);
+
+ de = iso_find_entry(dname, parent);
+ if (!de)
+ return NULL;
+
+ return iso_get_inode(parent->fs, de);
+}
+
+static int iso_readdir(struct file *file, struct dirent *dirent)
+{
+ struct fs_info *fs = file->fs;
+ struct inode *inode = file->inode;
+ const struct iso_dir_entry *de;
+ const char *data = NULL;
+
+ while (1) {
+ size_t offset = file->offset & (BLOCK_SIZE(fs) - 1);
+
+ if (!data) {
+ uint32_t i = file->offset >> BLOCK_SHIFT(fs);
+ if (i >= inode->blocks)
+ return -1;
+ data = get_cache(fs->fs_dev, PVT(inode)->lba + i);
+ }
+ de = (const struct iso_dir_entry *)(data + offset);
+
+ if (de->length < 33 || offset + de->length > BLOCK_SIZE(fs)) {
+ file->offset = (file->offset + BLOCK_SIZE(fs))
+ & ~(BLOCK_SIZE(fs) - 1); /* Start of the next block */
+ data = NULL;
+ continue;
+ }
+ break;
+ }
+
+ dirent->d_ino = 0; /* Inode number is invalid to ISO fs */
+ dirent->d_off = file->offset;
+ dirent->d_type = get_inode_mode(de->flags);
+ dirent->d_reclen = offsetof(struct dirent, d_name) + 1 +
+ iso_convert_name(dirent->d_name, de->name, de->name_len);
+
+ file->offset += de->length; /* Update for next reading */
+
+ return 0;
+}
+
+/* Load the config file, return 1 if failed, or 0 */
+static int iso_load_config(void)
+{
+ static const char *search_directories[] = {
+ "/boot/isolinux",
+ "/isolinux",
+ "/boot/syslinux",
+ "/syslinux",
+ "/",
+ NULL
+ };
+ static const char *filenames[] = {
+ "isolinux.cfg",
+ "syslinux.cfg",
+ NULL
+ };
+
+ return search_config(search_directories, filenames);
+}
+
+static int iso_fs_init(struct fs_info *fs)
+{
+ struct iso_sb_info *sbi;
+ char pvd[2048]; /* Primary Volume Descriptor */
+ uint32_t pvd_lba;
+ struct disk *disk = fs->fs_dev->disk;
+ int blktosec;
+
+ sbi = malloc(sizeof(*sbi));
+ if (!sbi) {
+ malloc_error("iso_sb_info structure");
+ return 1;
+ }
+ fs->fs_info = sbi;
+
+ /*
+ * XXX: handling iso9660 in hybrid mode on top of a 4K-logical disk
+ * will really, really hurt...
+ */
+ fs->sector_shift = fs->fs_dev->disk->sector_shift;
+ fs->block_shift = 11; /* A CD-ROM block is always 2K */
+ fs->sector_size = 1 << fs->sector_shift;
+ fs->block_size = 1 << fs->block_shift;
+ blktosec = fs->block_shift - fs->sector_shift;
+
+ pvd_lba = iso_boot_info.pvd;
+ if (!pvd_lba)
+ pvd_lba = 16; /* Default if not otherwise defined */
+
+ disk->rdwr_sectors(disk, pvd, (sector_t)pvd_lba << blktosec,
+ 1 << blktosec, false);
+ memcpy(&sbi->root, pvd + ROOT_DIR_OFFSET, sizeof(sbi->root));
+
+ /* Initialize the cache */
+ cache_init(fs->fs_dev, fs->block_shift);
+
+ return fs->block_shift;
+}
+
+
+const struct fs_ops iso_fs_ops = {
+ .fs_name = "iso",
+ .fs_flags = FS_USEMEM | FS_THISIND,
+ .fs_init = iso_fs_init,
+ .searchdir = NULL,
+ .getfssec = generic_getfssec,
+ .close_file = generic_close_file,
+ .mangle_name = iso_mangle_name,
+ .load_config = iso_load_config,
+ .iget_root = iso_iget_root,
+ .iget = iso_iget,
+ .readdir = iso_readdir,
+ .next_extent = no_next_extent,
+};
diff --git a/contrib/syslinux-4.02/core/fs/iso9660/iso9660_fs.h b/contrib/syslinux-4.02/core/fs/iso9660/iso9660_fs.h
new file mode 100644
index 0000000..a365fa1
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/iso9660/iso9660_fs.h
@@ -0,0 +1,51 @@
+#ifndef ISO9660_FS_H
+#define ISO9660_FS_H
+
+#include <klibc/compiler.h>
+#include <stdint.h>
+
+/* Boot info table */
+struct iso_boot_info {
+ uint32_t pvd; /* LBA of primary volume descriptor */
+ uint32_t file; /* LBA of boot file */
+ uint32_t length; /* Length of boot file */
+ uint32_t csum; /* Checksum of boot file */
+ uint32_t reserved[10]; /* Currently unused */
+};
+
+extern struct iso_boot_info iso_boot_info; /* In isolinux.asm */
+
+/* The root dir entry offset in the primary volume descriptor */
+#define ROOT_DIR_OFFSET 156
+
+struct iso_dir_entry {
+ uint8_t length; /* 00 */
+ uint8_t ext_attr_length; /* 01 */
+ uint32_t extent_le; /* 02 */
+ uint32_t extent_be; /* 06 */
+ uint32_t size_le; /* 0a */
+ uint32_t size_be; /* 0e */
+ uint8_t date[7]; /* 12 */
+ uint8_t flags; /* 19 */
+ uint8_t file_unit_size; /* 1a */
+ uint8_t interleave; /* 1b */
+ uint16_t volume_sequence_number_le; /* 1c */
+ uint16_t volume_sequence_number_be; /* 1e */
+ uint8_t name_len; /* 20 */
+ char name[0]; /* 21 */
+} __packed;
+
+struct iso_sb_info {
+ struct iso_dir_entry root;
+};
+
+/*
+ * iso9660 private inode information
+ */
+struct iso9660_pvt_inode {
+ uint32_t lba; /* Starting LBA of file data area*/
+};
+
+#define PVT(i) ((struct iso9660_pvt_inode *)((i)->pvt))
+
+#endif /* iso9660_fs.h */
diff --git a/contrib/syslinux-4.02/core/fs/lib/close.c b/contrib/syslinux-4.02/core/fs/lib/close.c
new file mode 100644
index 0000000..279598b
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/lib/close.c
@@ -0,0 +1,9 @@
+#include "fs.h"
+
+void generic_close_file(struct file *file)
+{
+ if (file->inode) {
+ file->offset = 0;
+ put_inode(file->inode);
+ }
+}
diff --git a/contrib/syslinux-4.02/core/fs/lib/loadconfig.c b/contrib/syslinux-4.02/core/fs/lib/loadconfig.c
new file mode 100644
index 0000000..c9652b6
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/lib/loadconfig.c
@@ -0,0 +1,34 @@
+#include <dprintf.h>
+#include <stdio.h>
+#include <string.h>
+#include <core.h>
+#include <fs.h>
+
+/*
+ * Standard version of load_config for extlinux/syslinux filesystems.
+ *
+ * This searches for extlinux.conf and syslinux.cfg in the install
+ * directory, followed by a set of fallback directories. If found,
+ * set the current working directory to match.
+ */
+int generic_load_config(void)
+{
+ static const char *search_directories[] = {
+ NULL, /* CurrentDirName */
+ "/boot/syslinux",
+ "/syslinux",
+ "/",
+ NULL
+ };
+ static const char *filenames[] = {
+ "extlinux.conf",
+ "syslinux.cfg",
+ NULL
+ };
+
+ search_directories[0] = CurrentDirName;
+
+ dprintf("CurrentDirName: \"%s\"\n", CurrentDirName);
+
+ return search_config(search_directories, filenames);
+}
diff --git a/contrib/syslinux-4.02/core/fs/lib/mangle.c b/contrib/syslinux-4.02/core/fs/lib/mangle.c
new file mode 100644
index 0000000..813099f
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/lib/mangle.c
@@ -0,0 +1,47 @@
+/**
+ * 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.
+ *
+ */
+
+#include <string.h>
+#include "fs.h"
+
+void generic_mangle_name(char *dst, const char *src)
+{
+ char *p = dst;
+ int i = FILENAME_MAX-1;
+
+ while (not_whitespace(*src)) {
+ if (*src == '/') {
+ if (src[1] == '/') {
+ src++;
+ i--;
+ continue;
+ }
+ }
+ i--;
+ *dst++ = *src++;
+ }
+
+ while (1) {
+ if (dst == p)
+ break;
+ if (dst[-1] != '/')
+ break;
+
+ dst--;
+ i++;
+ }
+
+ i++;
+ for (; i > 0; i --)
+ *dst++ = '\0';
+}
diff --git a/contrib/syslinux-4.02/core/fs/lib/searchconfig.c b/contrib/syslinux-4.02/core/fs/lib/searchconfig.c
new file mode 100644
index 0000000..24bfde3
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/lib/searchconfig.c
@@ -0,0 +1,40 @@
+#include <dprintf.h>
+#include <stdio.h>
+#include <string.h>
+#include <core.h>
+#include <fs.h>
+
+/*
+ * 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(const char *search_directories[], const char *filenames[])
+{
+ char confignamebuf[FILENAME_MAX];
+ com32sys_t regs;
+ const char *sd, **sdp;
+ const char *sf, **sfp;
+
+ for (sdp = search_directories; (sd = *sdp); sdp++) {
+ for (sfp = filenames; (sf = *sfp); sfp++) {
+ memset(&regs, 0, sizeof regs);
+ snprintf(confignamebuf, sizeof confignamebuf,
+ "%s%s%s",
+ sd, (*sd && sd[strlen(sd)-1] == '/') ? "" : "/",
+ sf);
+ realpath(ConfigName, confignamebuf, FILENAME_MAX);
+ regs.edi.w[0] = OFFS_WRT(ConfigName, 0);
+ dprintf("Config search: %s\n", ConfigName);
+ call16(core_open, &regs, &regs);
+ if (!(regs.eflags.l & EFLAGS_ZF)) {
+ chdir(sd);
+ return 0; /* Got it */
+ }
+ }
+ }
+
+ return -1;
+}
diff --git a/contrib/syslinux-4.02/core/fs/loadhigh.c b/contrib/syslinux-4.02/core/fs/loadhigh.c
new file mode 100644
index 0000000..e365b1a
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/loadhigh.c
@@ -0,0 +1,113 @@
+/*
+ * -----------------------------------------------------------------------
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * loadhigh.c
+ *
+ * An alternate interface to getfssec.
+ *
+ * Inputs: SI = file handle/cluster pointer
+ * EDI = target address in high memory
+ * EAX = maximum number of bytes to load
+ * DX = zero-padding mask (e.g. 0003h for pad to dword)
+ * BX = 16-bit subroutine to call at the top of each loop
+ * (to print status and check for abort)
+ * EBP = maximum load address
+ *
+ * Outputs: SI = file handle/cluster pointer
+ * EBX = first untouched address (not including padding)
+ * EDI = first untouched address (including padding)
+ * CF = reached EOF
+ * OF = ran out of high memory
+ */
+
+#include <com32.h>
+#include <minmax.h>
+#include "core.h"
+#include "fs.h"
+
+#define MAX_CHUNK (1 << 20) /* 1 MB */
+
+void pm_load_high(com32sys_t *regs)
+{
+ struct fs_info *fs;
+ uint32_t bytes;
+ uint32_t zero_mask;
+ bool have_more;
+ uint32_t bytes_read;
+ char *buf, *limit;
+ struct file *file;
+ uint32_t sector_mask;
+ size_t pad;
+
+ bytes = regs->eax.l;
+ zero_mask = regs->edx.w[0];
+ buf = (char *)regs->edi.l;
+ limit = (char *)(regs->ebp.l & ~zero_mask);
+ file = handle_to_file(regs->esi.w[0]);
+ fs = file->fs;
+
+ regs->eflags.l &= ~(EFLAGS_CF|EFLAGS_OF|EFLAGS_AF|
+ EFLAGS_PF|EFLAGS_ZF|EFLAGS_SF);
+
+ sector_mask = SECTOR_SIZE(fs) - 1;
+
+ while (bytes) {
+ uint32_t sectors;
+ uint32_t chunk;
+
+ if (buf + SECTOR_SIZE(fs) > limit) {
+ /* Can't fit even one more sector in... */
+ regs->eflags.l |= EFLAGS_OF;
+ break;
+ }
+
+ chunk = bytes;
+
+ if (regs->ebx.w[0]) {
+ call16((void (*)(void))(size_t)regs->ebx.w[0], &zero_regs, NULL);
+ chunk = min(chunk, MAX_CHUNK);
+ }
+
+ if (chunk > (((char *)limit - buf) & ~sector_mask))
+ chunk = ((char *)limit - buf) & ~sector_mask;
+
+ sectors = (chunk + sector_mask) >> SECTOR_SHIFT(fs);
+ bytes_read = fs->fs_ops->getfssec(file, buf, sectors, &have_more);
+
+ if (bytes_read > chunk)
+ bytes_read = chunk;
+
+ buf += bytes_read;
+ bytes -= bytes_read;
+
+ if (!have_more) {
+ /*
+ * If we reach EOF, the filesystem driver will have already closed
+ * the underlying file... this really should be cleaner.
+ */
+ _close_file(file);
+ regs->esi.w[0] = 0;
+ regs->eflags.l |= EFLAGS_CF;
+ break;
+ }
+ }
+
+ pad = (size_t)buf & zero_mask;
+ if (pad)
+ memset(buf, 0, pad);
+
+ regs->ebx.l = (size_t)buf;
+ regs->edi.l = (size_t)buf + pad;
+}
diff --git a/contrib/syslinux-4.02/core/fs/newconfig.c b/contrib/syslinux-4.02/core/fs/newconfig.c
new file mode 100644
index 0000000..58c47a5
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/newconfig.c
@@ -0,0 +1,41 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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., 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * newconfig.c
+ *
+ * Load a new configuration file
+ */
+
+#include "core.h"
+#include "fs.h"
+
+void pm_is_config_file(com32sys_t *regs)
+{
+ char target_cwd[FILENAME_MAX];
+ const char *p;
+
+ (void)regs;
+
+ /* Save configuration file as an absolute path for posterity */
+ realpath(ConfigName, KernelName, FILENAME_MAX);
+
+ /* If we got anything on the command line, do a chdir */
+ p = cmd_line;
+ while (*p && !not_whitespace(*p))
+ p++;
+
+ if (*p) {
+ mangle_name(target_cwd, p);
+ chdir(target_cwd);
+ }
+}
diff --git a/contrib/syslinux-4.02/core/fs/nonextextent.c b/contrib/syslinux-4.02/core/fs/nonextextent.c
new file mode 100644
index 0000000..0c1ce2c
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/nonextextent.c
@@ -0,0 +1,13 @@
+#include "fs.h"
+
+/*
+ * Use this routine for the next_extent() pointer when we never should
+ * be calling next_extent(), e.g. iso9660.
+ */
+int no_next_extent(struct inode *inode, uint32_t lstart)
+{
+ (void)inode;
+ (void)lstart;
+
+ return -1;
+}
diff --git a/contrib/syslinux-4.02/core/fs/pxe/dhcp_option.c b/contrib/syslinux-4.02/core/fs/pxe/dhcp_option.c
new file mode 100644
index 0000000..50f2de0
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/pxe/dhcp_option.c
@@ -0,0 +1,258 @@
+#include <stdio.h>
+#include <string.h>
+#include <core.h>
+#include <sys/cpu.h>
+#include "pxe.h"
+
+char LocalDomain[256];
+
+int over_load;
+uint8_t uuid_type;
+uint8_t uuid[16];
+
+static void parse_dhcp_options(const void *, int, uint8_t);
+
+static void subnet_mask(const void *data, int opt_len)
+{
+ if (opt_len != 4)
+ return;
+ IPInfo.netmask = *(const uint32_t *)data;
+}
+
+static void router(const void *data, int opt_len)
+{
+ if (opt_len != 4)
+ return;
+ IPInfo.gateway = *(const uint32_t *)data;
+}
+
+static void dns_servers(const void *data, int opt_len)
+{
+ const uint32_t *dp = data;
+ int num = 0;
+
+ while (num < DNS_MAX_SERVERS) {
+ uint32_t ip;
+
+ if (opt_len < 4)
+ break;
+
+ opt_len -= 4;
+ ip = *dp++;
+ if (ip_ok(ip))
+ dns_server[num++] = ip;
+ }
+ while (num < DNS_MAX_SERVERS)
+ dns_server[num++] = 0;
+}
+
+static void local_domain(const void *data, int opt_len)
+{
+ char buffer[256];
+ char *ld = LocalDomain;
+
+ memcpy(buffer, data, opt_len);
+ buffer[opt_len] = 0;
+
+ dns_mangle(&ld, buffer);
+}
+
+static void vendor_encaps(const void *data, int opt_len)
+{
+ /* Only recognize PXELINUX options */
+ parse_dhcp_options(data, opt_len, 208);
+}
+
+static void option_overload(const void *data, int opt_len)
+{
+ if (opt_len != 1)
+ return;
+ over_load = *(uint8_t *)data;
+}
+
+static void server(const void *data, int opt_len)
+{
+ uint32_t ip;
+
+ if (opt_len != 4)
+ return;
+
+ if (IPInfo.serverip)
+ return;
+
+ ip = *(uint32_t *)data;
+ if (ip_ok(ip))
+ IPInfo.serverip = ip;
+}
+
+static void client_identifier(const void *data, int opt_len)
+{
+ if (opt_len > MAC_MAX || opt_len < 2 ||
+ MAC_len != (opt_len >> 8) ||
+ *(uint8_t *)data != MAC_type)
+ return;
+
+ opt_len --;
+ MAC_len = opt_len & 0xff;
+ memcpy(MAC, data+1, opt_len);
+ MAC[opt_len] = 0;
+}
+
+static void bootfile_name(const void *data, int opt_len)
+{
+ memcpy(boot_file, data, opt_len);
+ boot_file[opt_len] = 0;
+}
+
+static void uuid_client_identifier(const void *data, int opt_len)
+{
+ int type = *(const uint8_t *)data;
+ if (opt_len != 17 || type != 0 || have_uuid)
+ return;
+
+ have_uuid = true;
+ uuid_type = type;
+ memcpy(uuid, data+1, 16);
+}
+
+static void pxelinux_configfile(const void *data, int opt_len)
+{
+ DHCPMagic |= 2;
+ memcpy(ConfigName, data, opt_len);
+ ConfigName[opt_len] = 0;
+}
+
+static void pxelinux_pathprefix(const void *data, int opt_len)
+{
+ DHCPMagic |= 4;
+ memcpy(path_prefix, data, opt_len);
+ path_prefix[opt_len] = 0;
+}
+
+static void pxelinux_reboottime(const void *data, int opt_len)
+{
+ if (opt_len != 4)
+ return;
+
+ RebootTime = ntohl(*(const uint32_t *)data);
+ DHCPMagic |= 8; /* Got reboot time */
+}
+
+
+struct dhcp_options {
+ int opt_num;
+ void (*fun)(const void *, int);
+};
+
+static const struct dhcp_options dhcp_opts[] = {
+ {1, subnet_mask},
+ {3, router},
+ {6, dns_servers},
+ {15, local_domain},
+ {43, vendor_encaps},
+ {52, option_overload},
+ {54, server},
+ {61, client_identifier},
+ {67, bootfile_name},
+ {97, uuid_client_identifier},
+ {209, pxelinux_configfile},
+ {210, pxelinux_pathprefix},
+ {211, pxelinux_reboottime}
+};
+
+/*
+ * Parse a sequence of DHCP options, pointed to by _option_;
+ * -- some DHCP servers leave option fields unterminated
+ * in violation of the spec.
+ *
+ * filter contains the minimum value for the option to recognize
+ * -- this is used to restrict parsing to PXELINUX-specific options only.
+ */
+static void parse_dhcp_options(const void *option, int size, uint8_t opt_filter)
+{
+ int opt_num;
+ int opt_len;
+ const int opt_entries = sizeof(dhcp_opts) / sizeof(dhcp_opts[0]);
+ int i = 0;
+ const uint8_t *p = option;
+ const struct dhcp_options *opt;
+
+ /* The only 1-byte options are 00 and FF, neither of which matter */
+ while (size >= 2) {
+ opt_num = *p++;
+ size--;
+
+ if (opt_num == 0)
+ continue;
+ if (opt_num == 0xff)
+ break;
+
+ /* Anything else will have a length field */
+ opt_len = *p++; /* c <- option lenght */
+ size -= opt_len + 1;
+ if (size < 0)
+ break;
+
+ if (opt_num >= opt_filter) {
+ opt = dhcp_opts;
+ for (i = 0; i < opt_entries; i++) {
+ if (opt_num == opt->opt_num) {
+ opt->fun(p, opt_len);
+ break;
+ }
+ opt++;
+ }
+ }
+
+ /* parse next */
+ p += opt_len;
+ }
+}
+
+/*
+ * parse_dhcp
+ *
+ * Parse a DHCP packet. This includes dealing with "overloaded"
+ * option fields (see RFC 2132, section 9.3)
+ *
+ * This should fill in the following global variables, if the
+ * information is present:
+ *
+ * MyIP - client IP address
+ * server_ip - boot server IP address
+ * net_mask - network mask
+ * gate_way - default gateway router IP
+ * boot_file - boot file name
+ * DNSServers - DNS server IPs
+ * 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)
+{
+ struct bootp_t *dhcp = (struct bootp_t *)trackbuf;
+ int opt_len;
+
+ IPInfo.ipv4 = 4; /* This is IPv4 only for now... */
+
+ over_load = 0;
+ if (ip_ok(dhcp->yip))
+ IPInfo.myip = dhcp->yip;
+
+ if (ip_ok(dhcp->sip))
+ IPInfo.serverip = dhcp->sip;
+
+ opt_len = (char *)dhcp + pkt_len - (char *)&dhcp->options;
+ if (opt_len && (dhcp->option_magic == BOOTP_OPTION_MAGIC))
+ parse_dhcp_options(&dhcp->options, opt_len, 0);
+
+ if (over_load & 1)
+ parse_dhcp_options(&dhcp->bootfile, 128, 0);
+ else if (dhcp->bootfile[0])
+ strcpy(boot_file, dhcp->bootfile);
+
+ if (over_load & 2)
+ parse_dhcp_options(dhcp->sname, 64, 0);
+}
diff --git a/contrib/syslinux-4.02/core/fs/pxe/dnsresolv.c b/contrib/syslinux-4.02/core/fs/pxe/dnsresolv.c
new file mode 100644
index 0000000..2b263fa
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/pxe/dnsresolv.c
@@ -0,0 +1,349 @@
+#include <stdio.h>
+#include <string.h>
+#include <core.h>
+#include "pxe.h"
+
+/* DNS CLASS values we care about */
+#define CLASS_IN 1
+
+/* DNS TYPE values we care about */
+#define TYPE_A 1
+#define TYPE_CNAME 5
+
+/*
+ * The DNS header structure
+ */
+struct dnshdr {
+ uint16_t id;
+ uint16_t flags;
+ /* number of entries in the question section */
+ uint16_t qdcount;
+ /* number of resource records in the answer section */
+ uint16_t ancount;
+ /* number of name server resource records in the authority records section*/
+ uint16_t nscount;
+ /* number of resource records in the additional records section */
+ uint16_t arcount;
+} __attribute__ ((packed));
+
+/*
+ * The DNS query structure
+ */
+struct dnsquery {
+ uint16_t qtype;
+ uint16_t qclass;
+} __attribute__ ((packed));
+
+/*
+ * The DNS Resource recodes structure
+ */
+struct dnsrr {
+ uint16_t type;
+ uint16_t class;
+ uint32_t ttl;
+ uint16_t rdlength; /* The lenght of this rr data */
+ char rdata[];
+} __attribute__ ((packed));
+
+
+uint32_t dns_server[DNS_MAX_SERVERS] = {0, };
+
+
+/*
+ * Turn a string in _src_ into a DNS "label set" in _dst_; returns the
+ * number of dots encountered. On return, *dst is updated.
+ */
+int dns_mangle(char **dst, const char *p)
+{
+ char *q = *dst;
+ char *count_ptr;
+ char c;
+ int dots = 0;
+
+ count_ptr = q;
+ *q++ = 0;
+
+ while (1) {
+ c = *p++;
+ if (c == 0 || c == ':' || c == '/')
+ break;
+ if (c == '.') {
+ dots++;
+ count_ptr = q;
+ *q++ = 0;
+ continue;
+ }
+
+ *count_ptr += 1;
+ *q++ = c;
+ }
+
+ if (*count_ptr)
+ *q++ = 0;
+
+ /* update the strings */
+ *dst = q;
+ return dots;
+}
+
+
+/*
+ * Compare two sets of DNS labels, in _s1_ and _s2_; the one in _s2_
+ * is allowed pointers relative to a packet in buf.
+ *
+ */
+static bool dns_compare(const void *s1, const void *s2, const void *buf)
+{
+ const uint8_t *q = s1;
+ const uint8_t *p = s2;
+ unsigned int c0, c1;
+
+ while (1) {
+ c0 = p[0];
+ if (c0 >= 0xc0) {
+ /* Follow pointer */
+ c1 = p[1];
+ p = (const uint8_t *)buf + ((c0 - 0xc0) << 8) + c1;
+ } else if (c0) {
+ c0++; /* Include the length byte */
+ if (memcmp(q, p, c0))
+ return false;
+ q += c0;
+ p += c0;
+ } else {
+ return *q == 0;
+ }
+ }
+}
+
+/*
+ * Copy a DNS label into a buffer, considering the possibility that we might
+ * have to follow pointers relative to "buf".
+ * Returns a pointer to the first free byte *after* the terminal null.
+ */
+static void *dns_copylabel(void *dst, const void *src, const void *buf)
+{
+ uint8_t *q = dst;
+ const uint8_t *p = src;
+ unsigned int c0, c1;
+
+ while (1) {
+ c0 = p[0];
+ if (c0 >= 0xc0) {
+ /* Follow pointer */
+ c1 = p[1];
+ p = (const uint8_t *)buf + ((c0 - 0xc0) << 8) + c1;
+ } else if (c0) {
+ c0++; /* Include the length byte */
+ memcpy(q, p, c0);
+ p += c0;
+ q += c0;
+ } else {
+ *q++ = 0;
+ return q;
+ }
+ }
+}
+
+/*
+ * Skip past a DNS label set in DS:SI
+ */
+static char *dns_skiplabel(char *label)
+{
+ uint8_t c;
+
+ while (1) {
+ c = *label++;
+ if (c >= 0xc0)
+ return ++label; /* pointer is two bytes */
+ if (c == 0)
+ return label;
+ label += c;
+ }
+}
+
+/*
+ * Actual resolver function
+ * Points to a null-terminated or :-terminated string in _name_
+ * and returns the ip addr in _ip_ if it exists and can be found.
+ * If _ip_ = 0 on exit, the lookup failed. _name_ will be updated
+ *
+ * XXX: probably need some caching here.
+ */
+uint32_t dns_resolv(const char *name)
+{
+ static char __lowmem DNSSendBuf[PKTBUF_SIZE];
+ static char __lowmem DNSRecvBuf[PKTBUF_SIZE];
+ char *p;
+ int err;
+ int dots;
+ int same;
+ int rd_len;
+ int ques, reps; /* number of questions and replies */
+ uint8_t timeout;
+ const uint8_t *timeout_ptr = TimeoutTable;
+ uint32_t oldtime;
+ uint32_t srv;
+ uint32_t *srv_ptr;
+ struct dnshdr *hd1 = (struct dnshdr *)DNSSendBuf;
+ struct dnshdr *hd2 = (struct dnshdr *)DNSRecvBuf;
+ struct dnsquery *query;
+ struct dnsrr *rr;
+ static __lowmem struct s_PXENV_UDP_WRITE udp_write;
+ static __lowmem struct s_PXENV_UDP_READ udp_read;
+ uint16_t local_port;
+ uint32_t result = 0;
+
+ /* Make sure we have at least one valid DNS server */
+ if (!dns_server[0])
+ return 0;
+
+ /* Get a local port number */
+ local_port = get_port();
+
+ /* First, fill the DNS header struct */
+ hd1->id++; /* New query ID */
+ hd1->flags = htons(0x0100); /* Recursion requested */
+ hd1->qdcount = htons(1); /* One question */
+ hd1->ancount = 0; /* No answers */
+ hd1->nscount = 0; /* No NS */
+ hd1->arcount = 0; /* No AR */
+
+ p = DNSSendBuf + sizeof(struct dnshdr);
+ dots = dns_mangle(&p, name); /* store the CNAME */
+
+ if (!dots) {
+ p--; /* Remove final null */
+ /* Uncompressed DNS label set so it ends in null */
+ strcpy(p, LocalDomain);
+ }
+
+ /* Fill the DNS query packet */
+ query = (struct dnsquery *)p;
+ query->qtype = htons(TYPE_A);
+ query->qclass = htons(CLASS_IN);
+ p += sizeof(struct dnsquery);
+
+ /* Now send it to name server */
+ timeout_ptr = TimeoutTable;
+ timeout = *timeout_ptr++;
+ srv_ptr = dns_server;
+ while (timeout) {
+ srv = *srv_ptr++;
+ if (!srv) {
+ srv_ptr = dns_server;
+ srv = *srv_ptr++;
+ }
+
+ udp_write.status = 0;
+ udp_write.ip = srv;
+ udp_write.gw = gateway(srv);
+ udp_write.src_port = local_port;
+ udp_write.dst_port = DNS_PORT;
+ udp_write.buffer_size = p - DNSSendBuf;
+ udp_write.buffer = FAR_PTR(DNSSendBuf);
+ err = pxe_call(PXENV_UDP_WRITE, &udp_write);
+ if (err || udp_write.status)
+ continue;
+
+ oldtime = jiffies();
+ do {
+ if (jiffies() - oldtime >= timeout)
+ goto again;
+
+ udp_read.status = 0;
+ udp_read.src_ip = srv;
+ udp_read.dest_ip = IPInfo.myip;
+ udp_read.s_port = DNS_PORT;
+ udp_read.d_port = local_port;
+ udp_read.buffer_size = PKTBUF_SIZE;
+ udp_read.buffer = FAR_PTR(DNSRecvBuf);
+ err = pxe_call(PXENV_UDP_READ, &udp_read);
+ } while (err || udp_read.status || hd2->id != hd1->id);
+
+ if ((hd2->flags ^ 0x80) & htons(0xf80f))
+ goto badness;
+
+ ques = htons(hd2->qdcount); /* Questions */
+ reps = htons(hd2->ancount); /* Replies */
+ p = DNSRecvBuf + sizeof(struct dnshdr);
+ while (ques--) {
+ p = dns_skiplabel(p); /* Skip name */
+ p += 4; /* Skip question trailer */
+ }
+
+ /* Parse the replies */
+ while (reps--) {
+ same = dns_compare(DNSSendBuf + sizeof(struct dnshdr),
+ p, DNSRecvBuf);
+ p = dns_skiplabel(p);
+ rr = (struct dnsrr *)p;
+ rd_len = ntohs(rr->rdlength);
+ if (same && ntohs(rr->class) == CLASS_IN) {
+ switch (ntohs(rr->type)) {
+ case TYPE_A:
+ if (rd_len == 4) {
+ result = *(uint32_t *)rr->rdata;
+ goto done;
+ }
+ break;
+ case TYPE_CNAME:
+ dns_copylabel(DNSSendBuf + sizeof(struct dnshdr),
+ rr->rdata, DNSRecvBuf);
+ /*
+ * We should probably rescan the packet from the top
+ * here, and technically we might have to send a whole
+ * new request here...
+ */
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* not the one we want, try next */
+ p += sizeof(struct dnsrr) + rd_len;
+ }
+
+ badness:
+ /*
+ *
+ ; We got back no data from this server.
+ ; Unfortunately, for a recursive, non-authoritative
+ ; query there is no such thing as an NXDOMAIN reply,
+ ; which technically means we can't draw any
+ ; conclusions. However, in practice that means the
+ ; domain doesn't exist. If this turns out to be a
+ ; problem, we may want to add code to go through all
+ ; the servers before giving up.
+
+ ; If the DNS server wasn't capable of recursion, and
+ ; isn't capable of giving us an authoritative reply
+ ; (i.e. neither AA or RA set), then at least try a
+ ; different setver...
+ */
+ if (hd2->flags == htons(0x480))
+ continue;
+
+ break; /* failed */
+
+ again:
+ continue;
+ }
+
+done:
+ free_port(local_port); /* Return port number to the free pool */
+
+ return result;
+}
+
+
+/*
+ * the one should be called from ASM file
+ */
+void pxe_dns_resolv(com32sys_t *regs)
+{
+ const char *name = MK_PTR(regs->ds, regs->esi.w[0]);
+
+ regs->eax.l = dns_resolv(name);
+}
diff --git a/contrib/syslinux-4.02/core/fs/pxe/idle.c b/contrib/syslinux-4.02/core/fs/pxe/idle.c
new file mode 100644
index 0000000..52a87c3
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/pxe/idle.c
@@ -0,0 +1,112 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <stdio.h>
+#include <string.h>
+#include <core.h>
+#include <fs.h>
+#include <minmax.h>
+#include <sys/cpu.h>
+#include "pxe.h"
+
+static int pxe_idle_poll(void)
+{
+ static __lowmem char junk_pkt[PKTBUF_SIZE];
+ static __lowmem t_PXENV_UDP_READ read_buf;
+
+ memset(&read_buf, 0, sizeof read_buf);
+
+ read_buf.src_ip = 0; /* Any destination */
+ read_buf.dest_ip = IPInfo.myip;
+ read_buf.s_port = 0; /* Any source port */
+ read_buf.d_port = htons(9); /* Discard port (not used...) */
+ read_buf.buffer_size = sizeof junk_pkt;
+ read_buf.buffer = FAR_PTR(junk_pkt);
+
+ pxe_call(PXENV_UDP_READ, &read_buf);
+
+ return 0;
+}
+
+static uint32_t pxe_detect_nic_type(void)
+{
+ static __lowmem t_PXENV_UNDI_GET_NIC_TYPE nic_type;
+
+ if (pxe_call(PXENV_UNDI_GET_NIC_TYPE, &nic_type))
+ return -1; /* Unknown NIC */
+
+ if (nic_type.NicType != PCI_NIC && nic_type.NicType != CardBus_NIC)
+ return -1; /* Not a PCI NIC */
+
+ /*
+ * Return VID:DID as a single number, with the VID in the high word
+ * -- this is opposite from the usual order, but it makes it easier to
+ * enforce that the table is sorted.
+ */
+ return (nic_type.info.pci.Vendor_ID << 16) + nic_type.info.pci.Dev_ID;
+}
+
+#define PCI_DEV(vid, did) (((vid) << 16) + (did))
+
+/* This array should be sorted!! */
+static const uint32_t pxe_need_idle_drain[] =
+{
+ /*
+ * Older Broadcom NICs: they need receive calls on idle to avoid
+ * FIFO stalls.
+ */
+ PCI_DEV(0x14e4, 0x1659), /* BCM5721 */
+ PCI_DEV(0x14e4, 0x165a), /* BCM5722 */
+ PCI_DEV(0x14e4, 0x165b), /* BCM5723 */
+ PCI_DEV(0x14e4, 0x1668), /* BCM5714 */
+ PCI_DEV(0x14e4, 0x1669), /* BCM5714S */
+ PCI_DEV(0x14e4, 0x166a), /* BCM5780 */
+ PCI_DEV(0x14e4, 0x1673), /* BCM5755M */
+ PCI_DEV(0x14e4, 0x1674), /* BCM5756ME */
+ PCI_DEV(0x14e4, 0x1678), /* BCM5715 */
+ PCI_DEV(0x14e4, 0x1679), /* BCM5715S */
+ PCI_DEV(0x14e4, 0x167b), /* BCM5755 */
+};
+
+void pxe_idle_init(void)
+{
+ uint32_t dev_id = pxe_detect_nic_type();
+ int l, h;
+ bool found;
+
+ l = 0;
+ h = sizeof pxe_need_idle_drain / sizeof pxe_need_idle_drain[0] - 1;
+
+ found = false;
+ while (h >= l) {
+ int x = (l+h) >> 1;
+ uint32_t id = pxe_need_idle_drain[x];
+
+ if (id == dev_id) {
+ found = true;
+ break;
+ } else if (id < dev_id) {
+ l = x+1;
+ } else {
+ h = x-1;
+ }
+ }
+
+ if (found)
+ idle_hook_func = pxe_idle_poll;
+}
+
+void pxe_idle_cleanup(void)
+{
+ idle_hook_func = NULL;
+}
diff --git a/contrib/syslinux-4.02/core/fs/pxe/portnum.c b/contrib/syslinux-4.02/core/fs/pxe/portnum.c
new file mode 100644
index 0000000..19af0cd
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/pxe/portnum.c
@@ -0,0 +1,68 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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., 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 <stdint.h>
+#include <stdbool.h>
+#include <netinet/in.h>
+#include "pxe.h"
+
+/* Port number bitmap - port numbers 49152 (0xc000) to 57343 (0xefff) */
+#define PORT_NUMBER_BASE 49152
+#define PORT_NUMBER_COUNT 8192 /* Power of 2, please */
+static uint32_t port_number_bitmap[PORT_NUMBER_COUNT/32];
+static uint16_t first_port_number /* = 0 */;
+
+/*
+ * Bitmap functions
+ */
+static bool test_bit(const uint32_t *bitmap, int32_t index)
+{
+ uint8_t st;
+ asm("btl %2,%1 ; setc %0" : "=qm" (st) : "m" (*bitmap), "r" (index));
+ return st;
+}
+
+static void set_bit(uint32_t *bitmap, int32_t index)
+{
+ asm volatile("btsl %1,%0" : "+m" (*bitmap) : "r" (index) : "memory");
+}
+
+static void clr_bit(uint32_t *bitmap, int32_t index)
+{
+ asm volatile("btcl %1,%0" : "+m" (*bitmap) : "r" (index) : "memory");
+}
+
+/*
+ * Get and free a port number (host byte order)
+ */
+uint16_t get_port(void)
+{
+ uint16_t port;
+
+ do {
+ port = first_port_number++;
+ first_port_number &= PORT_NUMBER_COUNT - 1;
+ } while (test_bit(port_number_bitmap, port));
+
+ set_bit(port_number_bitmap, port);
+ return htons(port + PORT_NUMBER_BASE);
+}
+
+void free_port(uint16_t port)
+{
+ port = ntohs(port) - PORT_NUMBER_BASE;
+
+ if (port >= PORT_NUMBER_COUNT)
+ return;
+
+ clr_bit(port_number_bitmap, port);
+}
diff --git a/contrib/syslinux-4.02/core/fs/pxe/pxe.c b/contrib/syslinux-4.02/core/fs/pxe/pxe.c
new file mode 100644
index 0000000..0238ed4
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/pxe/pxe.c
@@ -0,0 +1,1731 @@
+#include <dprintf.h>
+#include <stdio.h>
+#include <string.h>
+#include <core.h>
+#include <fs.h>
+#include <minmax.h>
+#include <sys/cpu.h>
+#include "pxe.h"
+
+#define GPXE 1
+
+static uint16_t real_base_mem; /* Amount of DOS memory after freeing */
+
+uint8_t MAC[MAC_MAX]; /* Actual MAC address */
+uint8_t MAC_len; /* MAC address len */
+uint8_t MAC_type; /* MAC address type */
+
+char __bss16 BOOTIFStr[7+3*(MAC_MAX+1)];
+#define MAC_str (BOOTIFStr+7) /* The actual hardware address */
+char __bss16 SYSUUIDStr[8+32+5];
+#define UUID_str (SYSUUIDStr+8) /* The actual UUID */
+
+char boot_file[256]; /* From DHCP */
+char path_prefix[256]; /* From DHCP */
+char dot_quad_buf[16];
+
+static bool has_gpxe;
+static uint32_t gpxe_funcs;
+bool have_uuid = false;
+
+/* Common receive buffer */
+static __lowmem char packet_buf[PKTBUF_SIZE] __aligned(16);
+
+const uint8_t TimeoutTable[] = {
+ 2, 2, 3, 3, 4, 5, 6, 7, 9, 10, 12, 15, 18, 21, 26, 31, 37, 44,
+ 53, 64, 77, 92, 110, 132, 159, 191, 229, 255, 255, 255, 255, 0
+};
+
+struct tftp_options {
+ const char *str_ptr; /* string pointer */
+ size_t offset; /* offset into socket structre */
+};
+
+#define IFIELD(x) offsetof(struct inode, x)
+#define PFIELD(x) (offsetof(struct inode, pvt) + \
+ offsetof(struct pxe_pvt_inode, x))
+
+static const struct tftp_options tftp_options[] =
+{
+ { "tsize", IFIELD(size) },
+ { "blksize", PFIELD(tftp_blksize) },
+};
+static const int tftp_nopts = sizeof tftp_options / sizeof tftp_options[0];
+
+static void tftp_error(struct inode *file, uint16_t errnum,
+ const char *errstr);
+
+/*
+ * Allocate a local UDP port structure and assign it a local port number.
+ * Return the inode pointer if success, or null if failure
+ */
+static struct inode *allocate_socket(struct fs_info *fs)
+{
+ struct inode *inode = alloc_inode(fs, 0, sizeof(struct pxe_pvt_inode));
+
+ if (!inode) {
+ malloc_error("socket structure");
+ } else {
+ struct pxe_pvt_inode *socket = PVT(inode);
+ socket->tftp_localport = get_port();
+ inode->mode = DT_REG; /* No other types relevant for PXE */
+ }
+
+ return inode;
+}
+
+static void free_socket(struct inode *inode)
+{
+ struct pxe_pvt_inode *socket = PVT(inode);
+
+ free_port(socket->tftp_localport);
+ free_inode(inode);
+}
+
+#if GPXE
+static void gpxe_close_file(struct inode *inode)
+{
+ struct pxe_pvt_inode *socket = PVT(inode);
+ static __lowmem struct s_PXENV_FILE_CLOSE file_close;
+
+ file_close.FileHandle = socket->tftp_remoteport;
+ pxe_call(PXENV_FILE_CLOSE, &file_close);
+}
+#endif
+
+static void pxe_close_file(struct file *file)
+{
+ struct inode *inode = file->inode;
+ struct pxe_pvt_inode *socket = PVT(inode);
+
+ if (!socket->tftp_goteof) {
+#if GPXE
+ if (socket->tftp_localport == 0xffff) {
+ gpxe_close_file(inode);
+ } else
+#endif
+ if (socket->tftp_localport != 0) {
+ tftp_error(inode, 0, "No error, file close");
+ }
+ }
+
+ free_socket(inode);
+}
+
+/**
+ * Take a nubmer of bytes in memory and convert to lower-case hxeadecimal
+ *
+ * @param: dst, output buffer
+ * @param: src, input buffer
+ * @param: count, number of bytes
+ *
+ */
+static void lchexbytes(char *dst, const void *src, int count)
+{
+ uint8_t half;
+ uint8_t c;
+ const uint8_t *s = src;
+
+ for(; count > 0; count--) {
+ c = *s++;
+ half = ((c >> 4) & 0x0f) + '0';
+ *dst++ = half > '9' ? (half + 'a' - '9' - 1) : half;
+
+ half = (c & 0x0f) + '0';
+ *dst++ = half > '9' ? (half + 'a' - '9' - 1) : half;
+ }
+}
+
+/*
+ * just like the lchexbytes, except to upper-case
+ *
+ */
+static void uchexbytes(char *dst, const void *src, int count)
+{
+ uint8_t half;
+ uint8_t c;
+ const uint8_t *s = src;
+
+ for(; count > 0; count--) {
+ c = *s++;
+ half = ((c >> 4) & 0x0f) + '0';
+ *dst++ = half > '9' ? (half + 'A' - '9' - 1) : half;
+
+ half = (c & 0x0f) + '0';
+ *dst++ = half > '9' ? (half + 'A' - '9' - 1) : half;
+ }
+}
+
+/*
+ * Parse a single hexadecimal byte, which must be complete (two
+ * digits). This is used in URL parsing.
+ */
+static int hexbyte(const char *p)
+{
+ if (!is_hex(p[0]) || !is_hex(p[1]))
+ return -1;
+ else
+ return (hexval(p[0]) << 4) + hexval(p[1]);
+}
+
+/*
+ * Tests an IP address in _ip_ for validity; return with 0 for bad, 1 for good.
+ * We used to refuse class E, but class E addresses are likely to become
+ * assignable unicast addresses in the near future.
+ *
+ */
+bool ip_ok(uint32_t ip)
+{
+ uint8_t ip_hi = (uint8_t)ip; /* First octet of the ip address */
+
+ if (ip == 0xffffffff || /* Refuse the all-ones address */
+ ip_hi == 0 || /* Refuse network zero */
+ ip_hi == 127 || /* Refuse the loopback network */
+ (ip_hi & 240) == 224) /* Refuse class D */
+ return false;
+
+ return true;
+}
+
+
+/*
+ * Take an IP address (in network byte order) in _ip_ and
+ * output a dotted quad string to _dst_, returns the length
+ * of the dotted quad ip string.
+ *
+ */
+static int gendotquad(char *dst, uint32_t ip)
+{
+ int part;
+ int i = 0, j;
+ char temp[4];
+ char *p = dst;
+
+ for (; i < 4; i++) {
+ j = 0;
+ part = ip & 0xff;
+ do {
+ temp[j++] = (part % 10) + '0';
+ }while(part /= 10);
+ for (; j > 0; j--)
+ *p++ = temp[j-1];
+ *p++ = '.';
+
+ ip >>= 8;
+ }
+ /* drop the last dot '.' and zero-terminate string*/
+ *(--p) = 0;
+
+ return p - dst;
+}
+
+/*
+ * parse the ip_str and return the ip address with *res.
+ * return the the string address after the ip string
+ *
+ */
+static const char *parse_dotquad(const char *ip_str, uint32_t *res)
+{
+ const char *p = ip_str;
+ uint8_t part = 0;
+ uint32_t ip = 0;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ while (is_digit(*p)) {
+ part = part * 10 + *p - '0';
+ p++;
+ }
+ if (i != 3 && *p != '.')
+ return NULL;
+
+ ip = (ip << 8) | part;
+ part = 0;
+ p++;
+ }
+ p--;
+
+ *res = htonl(ip);
+ return p;
+}
+
+/*
+ * the ASM pxenv function wrapper, return 1 if error, or 0
+ *
+ */
+int pxe_call(int opcode, void *data)
+{
+ extern void pxenv(void);
+ com32sys_t regs;
+
+#if 0
+ printf("pxe_call op %04x data %p\n", opcode, data);
+#endif
+
+ memset(&regs, 0, sizeof regs);
+ regs.ebx.w[0] = opcode;
+ regs.es = SEG(data);
+ regs.edi.w[0] = OFFS(data);
+ call16(pxenv, &regs, &regs);
+
+ return regs.eflags.l & EFLAGS_CF; /* CF SET if fail */
+}
+
+/**
+ * Send an ERROR packet. This is used to terminate a connection.
+ *
+ * @inode: Inode structure
+ * @errnum: Error number (network byte order)
+ * @errstr: Error string (included in packet)
+ */
+static void tftp_error(struct inode *inode, uint16_t errnum,
+ const char *errstr)
+{
+ static __lowmem struct {
+ uint16_t err_op;
+ uint16_t err_num;
+ char err_msg[64];
+ } __packed err_buf;
+ static __lowmem struct s_PXENV_UDP_WRITE udp_write;
+ int len = min(strlen(errstr), sizeof(err_buf.err_msg)-1);
+ struct pxe_pvt_inode *socket = PVT(inode);
+
+ err_buf.err_op = TFTP_ERROR;
+ err_buf.err_num = errnum;
+ memcpy(err_buf.err_msg, errstr, len);
+ err_buf.err_msg[len] = '\0';
+
+ udp_write.src_port = socket->tftp_localport;
+ udp_write.dst_port = socket->tftp_remoteport;
+ udp_write.ip = socket->tftp_remoteip;
+ udp_write.gw = gateway(udp_write.ip);
+ udp_write.buffer = FAR_PTR(&err_buf);
+ udp_write.buffer_size = 4 + len + 1;
+
+ /* If something goes wrong, there is nothing we can do, anyway... */
+ pxe_call(PXENV_UDP_WRITE, &udp_write);
+}
+
+
+/**
+ * Send ACK packet. This is a common operation and so is worth canning.
+ *
+ * @param: inode, Inode pointer
+ * @param: ack_num, Packet # to ack (network byte order)
+ *
+ */
+static void ack_packet(struct inode *inode, uint16_t ack_num)
+{
+ int err;
+ static __lowmem uint16_t ack_packet_buf[2];
+ static __lowmem struct s_PXENV_UDP_WRITE udp_write;
+ struct pxe_pvt_inode *socket = PVT(inode);
+
+ /* Packet number to ack */
+ ack_packet_buf[0] = TFTP_ACK;
+ ack_packet_buf[1] = ack_num;
+ udp_write.src_port = socket->tftp_localport;
+ udp_write.dst_port = socket->tftp_remoteport;
+ udp_write.ip = socket->tftp_remoteip;
+ udp_write.gw = gateway(udp_write.ip);
+ udp_write.buffer = FAR_PTR(ack_packet_buf);
+ udp_write.buffer_size = 4;
+
+ err = pxe_call(PXENV_UDP_WRITE, &udp_write);
+#if 0
+ printf("sent %s\n", err ? "FAILED" : "OK");
+#endif
+}
+
+
+/**
+ * Get a DHCP packet from the PXE stack into the trackbuf
+ *
+ * @param: type, packet type
+ * @return: buffer size
+ *
+ */
+static int pxe_get_cached_info(int type)
+{
+ int err;
+ static __lowmem struct s_PXENV_GET_CACHED_INFO get_cached_info;
+ printf(" %02x", type);
+
+ get_cached_info.Status = 0;
+ get_cached_info.PacketType = type;
+ get_cached_info.BufferSize = 8192;
+ get_cached_info.Buffer = FAR_PTR(trackbuf);
+ err = pxe_call(PXENV_GET_CACHED_INFO, &get_cached_info);
+ if (err) {
+ printf("PXE API call failed, error %04x\n", err);
+ kaboom();
+ }
+
+ return get_cached_info.BufferSize;
+}
+
+
+/*
+ * Return the type of pathname passed.
+ */
+enum pxe_path_type {
+ PXE_RELATIVE, /* No :: or URL */
+ PXE_HOMESERVER, /* Starting with :: */
+ PXE_TFTP, /* host:: */
+ PXE_URL_TFTP, /* tftp:// */
+ PXE_URL, /* Absolute URL syntax */
+};
+
+static enum pxe_path_type pxe_path_type(const char *str)
+{
+ const char *p;
+
+ p = str;
+
+ while (1) {
+ switch (*p) {
+ case ':':
+ if (p[1] == ':') {
+ if (p == str)
+ return PXE_HOMESERVER;
+ else
+ return PXE_TFTP;
+ } else if (p > str && p[1] == '/' && p[2] == '/') {
+ if (!strncasecmp(str, "tftp://", 7))
+ return PXE_URL_TFTP;
+ else
+ return PXE_URL;
+ }
+
+ /* else fall through */
+ case '/': case '!': case '@': case '#': case '%':
+ case '^': case '&': case '*': case '(': case ')':
+ case '[': case ']': case '{': case '}': case '\\':
+ case '|': case '=': case '`': case '~': case '\'':
+ case '\"': case ';': case '>': case '<': case '?':
+ case '\0':
+ /* Any of these characters terminate the colon search */
+ return PXE_RELATIVE;
+ default:
+ break;
+ }
+ p++;
+ }
+}
+
+#if GPXE
+
+/**
+ * Get a fresh packet from a gPXE socket
+ * @param: inode -> Inode pointer
+ *
+ */
+static void get_packet_gpxe(struct inode *inode)
+{
+ struct pxe_pvt_inode *socket = PVT(inode);
+ static __lowmem struct s_PXENV_FILE_READ file_read;
+ int err;
+
+ while (1) {
+ file_read.FileHandle = socket->tftp_remoteport;
+ file_read.Buffer = FAR_PTR(packet_buf);
+ file_read.BufferSize = PKTBUF_SIZE;
+ err = pxe_call(PXENV_FILE_READ, &file_read);
+ if (!err) /* successed */
+ break;
+
+ if (file_read.Status != PXENV_STATUS_TFTP_OPEN)
+ kaboom();
+ }
+
+ memcpy(socket->tftp_pktbuf, packet_buf, file_read.BufferSize);
+
+ socket->tftp_dataptr = socket->tftp_pktbuf;
+ socket->tftp_bytesleft = file_read.BufferSize;
+ socket->tftp_filepos += file_read.BufferSize;
+
+ if (socket->tftp_bytesleft == 0)
+ inode->size = socket->tftp_filepos;
+
+ /* if we're done here, close the file */
+ if (inode->size > socket->tftp_filepos)
+ return;
+
+ /* Got EOF, close it */
+ socket->tftp_goteof = 1;
+ gpxe_close_file(inode);
+}
+#endif /* GPXE */
+
+
+/*
+ * mangle a filename pointed to by _src_ into a buffer pointed
+ * to by _dst_; ends on encountering any whitespace.
+ *
+ */
+static void pxe_mangle_name(char *dst, const char *src)
+{
+ size_t len = FILENAME_MAX-1;
+
+ while (len-- && not_whitespace(*src))
+ *dst++ = *src++;
+
+ *dst = '\0';
+}
+
+/*
+ * Get a fresh packet if the buffer is drained, and we haven't hit
+ * EOF yet. The buffer should be filled immediately after draining!
+ */
+static void fill_buffer(struct inode *inode)
+{
+ int err;
+ int last_pkt;
+ const uint8_t *timeout_ptr;
+ uint8_t timeout;
+ uint16_t buffersize;
+ uint32_t oldtime;
+ void *data = NULL;
+ static __lowmem struct s_PXENV_UDP_READ udp_read;
+ struct pxe_pvt_inode *socket = PVT(inode);
+
+ if (socket->tftp_bytesleft || socket->tftp_goteof)
+ return;
+
+#if GPXE
+ if (socket->tftp_localport == 0xffff) {
+ get_packet_gpxe(inode);
+ return;
+ }
+#endif
+
+ /*
+ * Start by ACKing the previous packet; this should cause
+ * the next packet to be sent.
+ */
+ timeout_ptr = TimeoutTable;
+ timeout = *timeout_ptr++;
+ oldtime = jiffies();
+
+ ack_again:
+ ack_packet(inode, socket->tftp_lastpkt);
+
+ while (timeout) {
+ udp_read.buffer = FAR_PTR(packet_buf);
+ udp_read.buffer_size = PKTBUF_SIZE;
+ udp_read.src_ip = socket->tftp_remoteip;
+ udp_read.dest_ip = IPInfo.myip;
+ udp_read.s_port = socket->tftp_remoteport;
+ udp_read.d_port = socket->tftp_localport;
+ err = pxe_call(PXENV_UDP_READ, &udp_read);
+ if (err) {
+ uint32_t now = jiffies();
+
+ if (now-oldtime >= timeout) {
+ oldtime = now;
+ timeout = *timeout_ptr++;
+ if (!timeout)
+ break;
+ }
+ continue;
+ }
+
+ if (udp_read.buffer_size < 4) /* Bad size for a DATA packet */
+ continue;
+
+ data = packet_buf;
+ if (*(uint16_t *)data != TFTP_DATA) /* Not a data packet */
+ continue;
+
+ /* If goes here, recevie OK, break */
+ break;
+ }
+
+ /* time runs out */
+ if (timeout == 0)
+ kaboom();
+
+ last_pkt = socket->tftp_lastpkt;
+ last_pkt = ntohs(last_pkt); /* Host byte order */
+ last_pkt++;
+ last_pkt = htons(last_pkt); /* Network byte order */
+ if (*(uint16_t *)(data + 2) != last_pkt) {
+ /*
+ * Wrong packet, ACK the packet and try again.
+ * This is presumably because the ACK got lost,
+ * so the server just resent the previous packet.
+ */
+#if 0
+ printf("Wrong packet, wanted %04x, got %04x\n", \
+ htons(last_pkt), htons(*(uint16_t *)(data+2)));
+#endif
+ goto ack_again;
+ }
+
+ /* It's the packet we want. We're also EOF if the size < blocksize */
+ socket->tftp_lastpkt = last_pkt; /* Update last packet number */
+ buffersize = udp_read.buffer_size - 4; /* Skip TFTP header */
+ memcpy(socket->tftp_pktbuf, packet_buf + 4, buffersize);
+ socket->tftp_dataptr = socket->tftp_pktbuf;
+ socket->tftp_filepos += buffersize;
+ socket->tftp_bytesleft = buffersize;
+ if (buffersize < socket->tftp_blksize) {
+ /* it's the last block, ACK packet immediately */
+ ack_packet(inode, *(uint16_t *)(data + 2));
+
+ /* Make sure we know we are at end of file */
+ inode->size = socket->tftp_filepos;
+ socket->tftp_goteof = 1;
+ }
+}
+
+
+/**
+ * getfssec: Get multiple clusters from a file, given the starting cluster.
+ * In this case, get multiple blocks from a specific TCP connection.
+ *
+ * @param: fs, the fs_info structure address, in pxe, we don't use this.
+ * @param: buf, buffer to store the read data
+ * @param: openfile, TFTP socket pointer
+ * @param: blocks, 512-byte block count; 0FFFFh = until end of file
+ *
+ * @return: the bytes read
+ *
+ */
+static uint32_t pxe_getfssec(struct file *file, char *buf,
+ int blocks, bool *have_more)
+{
+ struct inode *inode = file->inode;
+ struct pxe_pvt_inode *socket = PVT(inode);
+ int count = blocks;
+ int chunk;
+ int bytes_read = 0;
+
+ count <<= TFTP_BLOCKSIZE_LG2;
+ while (count) {
+ fill_buffer(inode); /* If we have no 'fresh' buffer, get it */
+ if (!socket->tftp_bytesleft)
+ break;
+
+ chunk = count;
+ if (chunk > socket->tftp_bytesleft)
+ chunk = socket->tftp_bytesleft;
+ socket->tftp_bytesleft -= chunk;
+ memcpy(buf, socket->tftp_dataptr, chunk);
+ socket->tftp_dataptr += chunk;
+ buf += chunk;
+ bytes_read += chunk;
+ count -= chunk;
+ }
+
+
+ if (socket->tftp_bytesleft || (socket->tftp_filepos < inode->size)) {
+ fill_buffer(inode);
+ *have_more = 1;
+ } else if (socket->tftp_goteof) {
+ /*
+ * The socket is closed and the buffer drained; the caller will
+ * call close_file and therefore free the socket.
+ */
+ *have_more = 0;
+ }
+
+ return bytes_read;
+}
+
+/**
+ * Open a TFTP connection to the server
+ *
+ * @param:filename, the file we wanna open
+ *
+ * @out: open_file_t structure, stores in file->open_file
+ * @out: the lenght of this file, stores in file->file_len
+ *
+ */
+static void pxe_searchdir(const char *filename, struct file *file)
+{
+ struct fs_info *fs = file->fs;
+ struct inode *inode;
+ struct pxe_pvt_inode *socket;
+ char *buf;
+ const char *np;
+ char *p;
+ char *options;
+ char *data;
+ static __lowmem struct s_PXENV_UDP_WRITE udp_write;
+ static __lowmem struct s_PXENV_UDP_READ udp_read;
+ static __lowmem struct s_PXENV_FILE_OPEN file_open;
+ static const char rrq_tail[] = "octet\0""tsize\0""0\0""blksize\0""1408";
+ static __lowmem char rrq_packet_buf[2+2*FILENAME_MAX+sizeof rrq_tail];
+ const struct tftp_options *tftp_opt;
+ int i = 0;
+ int err;
+ int buffersize;
+ int rrq_len;
+ const uint8_t *timeout_ptr;
+ uint32_t timeout;
+ uint32_t oldtime;
+ uint16_t tid;
+ uint16_t opcode;
+ uint16_t blk_num;
+ uint32_t ip = 0;
+ uint32_t opdata, *opdata_ptr;
+ enum pxe_path_type path_type;
+ char fullpath[2*FILENAME_MAX];
+ uint16_t server_port = TFTP_PORT; /* TFTP server port */
+
+ inode = file->inode = NULL;
+
+ buf = rrq_packet_buf;
+ *(uint16_t *)buf = TFTP_RRQ; /* TFTP opcode */
+ buf += 2;
+
+ path_type = pxe_path_type(filename);
+ if (path_type == PXE_RELATIVE) {
+ snprintf(fullpath, sizeof fullpath, "%s%s", fs->cwd_name, filename);
+ path_type = pxe_path_type(filename = fullpath);
+ }
+
+ switch (path_type) {
+ case PXE_RELATIVE: /* Really shouldn't happen... */
+ case PXE_URL:
+ buf = stpcpy(buf, filename);
+ ip = IPInfo.serverip; /* Default server */
+ break;
+
+ case PXE_HOMESERVER:
+ buf = stpcpy(buf, filename+2);
+ ip = IPInfo.serverip;
+ break;
+
+ case PXE_TFTP:
+ np = strchr(filename, ':');
+ buf = stpcpy(buf, np+2);
+ if (parse_dotquad(filename, &ip) != np)
+ ip = dns_resolv(filename);
+ break;
+
+ case PXE_URL_TFTP:
+ np = filename + 7;
+ while (*np && *np != '/' && *np != ':')
+ np++;
+ if (np > filename + 7) {
+ if (parse_dotquad(filename + 7, &ip) != np)
+ ip = dns_resolv(filename + 7);
+ }
+ if (*np == ':') {
+ np++;
+ server_port = 0;
+ while (*np >= '0' && *np <= '9')
+ server_port = server_port * 10 + *np++ - '0';
+ server_port = server_port ? htons(server_port) : TFTP_PORT;
+ }
+ if (*np == '/')
+ np++; /* Do *NOT* eat more than one slash here... */
+ /*
+ * The ; is because of a quirk in the TFTP URI spec (RFC
+ * 3617); it is to be followed by TFTP modes, which we just ignore.
+ */
+ while (*np && *np != ';') {
+ int v;
+ if (*np == '%' && (v = hexbyte(np+1)) > 0) {
+ *buf++ = v;
+ np += 3;
+ } else {
+ *buf++ = *np++;
+ }
+ }
+ *buf = '\0';
+ break;
+ }
+
+ if (!ip)
+ return; /* No server */
+
+ buf++; /* Point *past* the final NULL */
+ memcpy(buf, rrq_tail, sizeof rrq_tail);
+ buf += sizeof rrq_tail;
+
+ rrq_len = buf - rrq_packet_buf;
+
+ inode = allocate_socket(fs);
+ if (!inode)
+ return; /* Allocation failure */
+ socket = PVT(inode);
+
+#if GPXE
+ if (path_type == PXE_URL) {
+ if (has_gpxe) {
+ file_open.Status = PXENV_STATUS_BAD_FUNC;
+ file_open.FileName = FAR_PTR(rrq_packet_buf + 2);
+ err = pxe_call(PXENV_FILE_OPEN, &file_open);
+ if (err)
+ goto done;
+
+ socket->tftp_localport = -1;
+ socket->tftp_remoteport = file_open.FileHandle;
+ inode->size = -1;
+ goto done;
+ } else {
+ static bool already = false;
+ if (!already) {
+ printf("URL syntax, but gPXE extensions not detected, "
+ "trying plain TFTP...\n");
+ already = true;
+ }
+ }
+ }
+#endif /* GPXE */
+
+ timeout_ptr = TimeoutTable; /* Reset timeout */
+
+sendreq:
+ timeout = *timeout_ptr++;
+ if (!timeout)
+ return; /* No file available... */
+ oldtime = jiffies();
+
+ socket->tftp_remoteip = ip;
+ tid = socket->tftp_localport; /* TID(local port No) */
+ udp_write.buffer = FAR_PTR(rrq_packet_buf);
+ udp_write.ip = ip;
+ udp_write.gw = gateway(udp_write.ip);
+ udp_write.src_port = tid;
+ udp_write.dst_port = server_port;
+ udp_write.buffer_size = rrq_len;
+ pxe_call(PXENV_UDP_WRITE, &udp_write);
+
+ /* If the WRITE call fails, we let the timeout take care of it... */
+
+wait_pkt:
+ for (;;) {
+ buf = packet_buf;
+ udp_read.status = 0;
+ udp_read.buffer = FAR_PTR(buf);
+ udp_read.buffer_size = PKTBUF_SIZE;
+ udp_read.dest_ip = IPInfo.myip;
+ udp_read.d_port = tid;
+ err = pxe_call(PXENV_UDP_READ, &udp_read);
+ if (err || udp_read.status) {
+ uint32_t now = jiffies();
+ if (now - oldtime >= timeout)
+ goto sendreq;
+ } else {
+ /* Make sure the packet actually came from the server */
+ if (udp_read.src_ip == socket->tftp_remoteip)
+ break;
+ }
+ }
+
+ socket->tftp_remoteport = udp_read.s_port;
+
+ /* filesize <- -1 == unknown */
+ inode->size = -1;
+ /* Default blksize unless blksize option negotiated */
+ socket->tftp_blksize = TFTP_BLOCKSIZE;
+ buffersize = udp_read.buffer_size - 2; /* bytes after opcode */
+ if (buffersize < 0)
+ goto wait_pkt; /* Garbled reply */
+
+ /*
+ * Get the opcode type, and parse it
+ */
+ opcode = *(uint16_t *)packet_buf;
+ switch (opcode) {
+ case TFTP_ERROR:
+ inode->size = 0;
+ break; /* ERROR reply; don't try again */
+
+ case TFTP_DATA:
+ /*
+ * If the server doesn't support any options, we'll get a
+ * DATA reply instead of OACK. Stash the data in the file
+ * buffer and go with the default value for all options...
+ *
+ * We got a DATA packet, meaning no options are
+ * suported. Save the data away and consider the
+ * length undefined, *unless* this is the only
+ * data packet...
+ */
+ buffersize -= 2;
+ if (buffersize < 0)
+ goto wait_pkt;
+ data = packet_buf + 2;
+ blk_num = *(uint16_t *)data;
+ data += 2;
+ if (blk_num != htons(1))
+ goto wait_pkt;
+ socket->tftp_lastpkt = blk_num;
+ if (buffersize > TFTP_BLOCKSIZE)
+ goto err_reply; /* Corrupt */
+ else if (buffersize < TFTP_BLOCKSIZE) {
+ /*
+ * This is the final EOF packet, already...
+ * We know the filesize, but we also want to
+ * ack the packet and set the EOF flag.
+ */
+ inode->size = buffersize;
+ socket->tftp_goteof = 1;
+ ack_packet(inode, blk_num);
+ }
+
+ socket->tftp_bytesleft = buffersize;
+ socket->tftp_dataptr = socket->tftp_pktbuf;
+ memcpy(socket->tftp_pktbuf, data, buffersize);
+ break;
+
+ case TFTP_OACK:
+ /*
+ * Now we need to parse the OACK packet to get the transfer
+ * and packet sizes.
+ */
+
+ options = packet_buf + 2;
+ p = options;
+
+ while (buffersize) {
+ const char *opt = p;
+
+ /*
+ * If we find an option which starts with a NUL byte,
+ * (a null option), we're either seeing garbage that some
+ * TFTP servers add to the end of the packet, or we have
+ * no clue how to parse the rest of the packet (what is
+ * an option name and what is a value?) In either case,
+ * discard the rest.
+ */
+ if (!*opt)
+ goto done;
+
+ while (buffersize) {
+ if (!*p)
+ break; /* Found a final null */
+ *p++ |= 0x20;
+ buffersize--;
+ }
+ if (!buffersize)
+ break; /* Unterminated option */
+
+ /* Consume the terminal null */
+ p++;
+ buffersize--;
+
+ if (!buffersize)
+ break; /* No option data */
+
+ /*
+ * Parse option pointed to by options; guaranteed to be
+ * null-terminated
+ */
+ tftp_opt = tftp_options;
+ for (i = 0; i < tftp_nopts; i++) {
+ if (!strcmp(opt, tftp_opt->str_ptr))
+ break;
+ tftp_opt++;
+ }
+ if (i == tftp_nopts)
+ goto err_reply; /* Non-negotitated option returned,
+ no idea what it means ...*/
+
+ /* get the address of the filed that we want to write on */
+ opdata_ptr = (uint32_t *)((char *)inode + tftp_opt->offset);
+ opdata = 0;
+
+ /* do convert a number-string to decimal number, just like atoi */
+ while (buffersize--) {
+ uint8_t d = *p++;
+ if (d == '\0')
+ break; /* found a final null */
+ d -= '0';
+ if (d > 9)
+ goto err_reply; /* Not a decimal digit */
+ opdata = opdata*10 + d;
+ }
+ *opdata_ptr = opdata;
+ }
+ break;
+
+ default:
+ printf("TFTP unknown opcode %d\n", ntohs(opcode));
+ goto err_reply;
+ }
+
+done:
+ if (!inode->size) {
+ free_socket(inode);
+ return;
+ }
+ file->inode = inode;
+ return;
+
+err_reply:
+ /* Build the TFTP error packet */
+ tftp_error(inode, TFTP_EOPTNEG, "TFTP protocol error");
+ printf("TFTP server sent an incomprehesible reply\n");
+ kaboom();
+}
+
+
+/*
+ * Store standard filename prefix
+ */
+static void get_prefix(void)
+{
+ int len;
+ char *p;
+ char c;
+
+ if (!(DHCPMagic & 0x04)) {
+ /* No path prefix option, derive from boot file */
+
+ strlcpy(path_prefix, boot_file, sizeof path_prefix);
+ len = strlen(path_prefix);
+ p = &path_prefix[len - 1];
+
+ while (len--) {
+ c = *p--;
+ c |= 0x20;
+
+ c = (c >= '0' && c <= '9') ||
+ (c >= 'a' && c <= 'z') ||
+ (c == '.' || c == '-');
+ if (!c)
+ break;
+ };
+
+ if (len < 0)
+ p --;
+
+ *(p + 2) = 0; /* Zero-terminate after delimiter */
+ }
+
+ printf("TFTP prefix: %s\n", path_prefix);
+ chdir(path_prefix);
+}
+
+/*
+ * realpath for PXE
+ */
+static size_t pxe_realpath(struct fs_info *fs, char *dst, const char *src,
+ size_t bufsize)
+{
+ enum pxe_path_type path_type = pxe_path_type(src);
+
+ return snprintf(dst, bufsize, "%s%s",
+ path_type == PXE_RELATIVE ? fs->cwd_name : "", src);
+}
+
+/*
+ * chdir for PXE
+ */
+static int pxe_chdir(struct fs_info *fs, const char *src)
+{
+ /* The cwd for PXE is just a text prefix */
+ enum pxe_path_type path_type = pxe_path_type(src);
+
+ if (path_type == PXE_RELATIVE)
+ strlcat(fs->cwd_name, src, sizeof fs->cwd_name);
+ else
+ strlcpy(fs->cwd_name, src, sizeof fs->cwd_name);
+
+ dprintf("cwd = \"%s\"\n", fs->cwd_name);
+ return 0;
+}
+
+ /*
+ * try to load a config file, if found, return 1, or return 0
+ *
+ */
+static int try_load(char *config_name)
+{
+ com32sys_t regs;
+
+ printf("Trying to load: %-50s ", config_name);
+ pxe_mangle_name(KernelName, config_name);
+
+ memset(&regs, 0, sizeof regs);
+ regs.edi.w[0] = OFFS_WRT(KernelName, 0);
+ call16(core_open, &regs, &regs);
+ if (regs.eflags.l & EFLAGS_ZF) {
+ strcpy(ConfigName, KernelName);
+ printf("\r");
+ return 0;
+ } else {
+ printf("ok\n");
+ return 1;
+ }
+}
+
+
+/* Load the config file, return 1 if failed, or 0 */
+static int pxe_load_config(void)
+{
+ const char *cfgprefix = "pxelinux.cfg/";
+ const char *default_str = "default";
+ char *config_file;
+ char *last;
+ int tries = 8;
+
+ get_prefix();
+ if (DHCPMagic & 0x02) {
+ /* We got a DHCP option, try it first */
+ if (try_load(ConfigName))
+ return 0;
+ }
+
+ /*
+ * Have to guess config file name ...
+ */
+ config_file = stpcpy(ConfigName, cfgprefix);
+
+ /* Try loading by UUID */
+ if (have_uuid) {
+ strcpy(config_file, UUID_str);
+ if (try_load(ConfigName))
+ return 0;
+ }
+
+ /* Try loading by MAC address */
+ strcpy(config_file, MAC_str);
+ if (try_load(ConfigName))
+ return 0;
+
+ /* Nope, try hexadecimal IP prefixes... */
+ uchexbytes(config_file, (uint8_t *)&IPInfo.myip, 4);
+ last = &config_file[8];
+ while (tries) {
+ *last = '\0'; /* Zero-terminate string */
+ if (try_load(ConfigName))
+ return 0;
+ last--; /* Drop one character */
+ tries--;
+ };
+
+ /* Final attempt: "default" string */
+ strcpy(config_file, default_str);
+ if (try_load(ConfigName))
+ return 0;
+
+ printf("%-68s\n", "Unable to locate configuration file");
+ kaboom();
+}
+
+/*
+ * Generate the bootif string.
+ */
+static void make_bootif_string(void)
+{
+ const uint8_t *src;
+ char *dst = BOOTIFStr;
+ int i;
+
+ dst += sprintf(dst, "BOOTIF=%02x", MAC_type);
+ src = MAC;
+ for (i = MAC_len; i; i--)
+ dst += sprintf(dst, "-%02x", *src++);
+}
+/*
+ * Generate the SYSUUID string, if we have one...
+ */
+static void make_sysuuid_string(void)
+{
+ static const uint8_t uuid_dashes[] = {4, 2, 2, 2, 6, 0};
+ const uint8_t *src = uuid;
+ const uint8_t *uuid_ptr = uuid_dashes;
+ char *dst;
+
+ SYSUUIDStr[0] = '\0'; /* If nothing there... */
+
+ /* Try loading by UUID */
+ if (have_uuid) {
+ dst = stpcpy(SYSUUIDStr, "SYSUUID=");
+
+ while (*uuid_ptr) {
+ int len = *uuid_ptr;
+
+ lchexbytes(dst, src, len);
+ dst += len * 2;
+ src += len;
+ uuid_ptr++;
+ *dst++ = '-';
+ }
+ /* Remove last dash and zero-terminate */
+ *--dst = '\0';
+ }
+}
+
+/*
+ * Generate an ip=<client-ip>:<boot-server-ip>:<gw-ip>:<netmask>
+ * option into IPOption based on a DHCP packet in trackbuf.
+ *
+ */
+char __bss16 IPOption[3+4*16];
+
+static void genipopt(void)
+{
+ char *p = IPOption;
+ const uint32_t *v = &IPInfo.myip;
+ int i;
+
+ p = stpcpy(p, "ip=");
+
+ for (i = 0; i < 4; i++) {
+ p += gendotquad(p, *v++);
+ *p++ = ':';
+ }
+ *--p = '\0';
+}
+
+
+/* Generate ip= option and print the ip adress */
+static void ip_init(void)
+{
+ uint32_t ip = IPInfo.myip;
+
+ genipopt();
+ gendotquad(dot_quad_buf, ip);
+
+ ip = ntohl(ip);
+ printf("My IP address seems to be %08X %s\n", ip, dot_quad_buf);
+}
+
+/*
+ * Print the IPAPPEND strings, in order
+ */
+extern const uint16_t IPAppends[];
+extern const char numIPAppends[];
+
+static void print_ipappend(void)
+{
+ size_t i;
+
+ for (i = 0; i < (size_t)numIPAppends; i++) {
+ const char *p = (const char *)(size_t)IPAppends[i];
+ if (*p)
+ printf("%s\n", p);
+ }
+}
+
+/*
+ * Validity check on possible !PXE structure in buf
+ * return 1 for success, 0 for failure.
+ *
+ */
+static int is_pxe(const void *buf)
+{
+ const struct pxe_t *pxe = buf;
+ const uint8_t *p = buf;
+ int i = pxe->structlength;
+ uint8_t sum = 0;
+
+ if (i < sizeof(struct pxe_t) ||
+ memcmp(pxe->signature, "!PXE", 4))
+ return 0;
+
+ while (i--)
+ sum += *p++;
+
+ return sum == 0;
+}
+
+/*
+ * Just like is_pxe, it checks PXENV+ structure
+ *
+ */
+static int is_pxenv(const void *buf)
+{
+ const struct pxenv_t *pxenv = buf;
+ const uint8_t *p = buf;
+ int i = pxenv->length;
+ uint8_t sum = 0;
+
+ /* The pxeptr field isn't present in old versions */
+ if (i < offsetof(struct pxenv_t, pxeptr) ||
+ memcmp(pxenv->signature, "PXENV+", 6))
+ return 0;
+
+ while (i--)
+ sum += *p++;
+
+ return sum == 0;
+}
+
+
+
+/*
+ * memory_scan_for_pxe_struct:
+ * memory_scan_for_pxenv_struct:
+ *
+ * If none of the standard methods find the !PXE/PXENV+ structure,
+ * look for it by scanning memory.
+ *
+ * return the corresponding pxe structure if found, or NULL;
+ */
+static const void *memory_scan(uintptr_t start, int (*func)(const void *))
+{
+ const char *ptr;
+
+ /* Scan each 16 bytes of conventional memory before the VGA region */
+ for (ptr = (const char *)start; ptr < (const char *)0xA0000; ptr += 16) {
+ if (func(ptr))
+ return ptr; /* found it! */
+ ptr += 16;
+ }
+ return NULL;
+}
+
+static const struct pxe_t *memory_scan_for_pxe_struct(void)
+{
+ extern uint16_t BIOS_fbm; /* Starting segment */
+
+ return memory_scan(BIOS_fbm << 10, is_pxe);
+}
+
+static const struct pxenv_t *memory_scan_for_pxenv_struct(void)
+{
+ return memory_scan(0x10000, is_pxenv);
+}
+
+/*
+ * Find the !PXE structure; we search for the following, in order:
+ *
+ * a. !PXE structure as SS:[SP + 4]
+ * b. PXENV+ structure at [ES:BX]
+ * c. INT 1Ah AX=0x5650 -> PXENV+
+ * d. Search memory for !PXE
+ * e. Search memory for PXENV+
+ *
+ * If we find a PXENV+ structure, we try to find a !PXE structure from
+ * if if the API version is 2.1 or later
+ *
+ */
+static int pxe_init(bool quiet)
+{
+ extern void pxe_int1a(void);
+ char plan = 'A';
+ uint16_t seg, off;
+ uint16_t code_seg, code_len;
+ uint16_t data_seg, data_len;
+ const char *base = GET_PTR(InitStack);
+ com32sys_t regs;
+ const char *type;
+ const struct pxenv_t *pxenv;
+ const struct pxe_t *pxe;
+
+ /* Assume API version 2.1 */
+ APIVer = 0x201;
+
+ /* Plan A: !PXE structure as SS:[SP + 4] */
+ off = *(const uint16_t *)(base + 48);
+ seg = *(const uint16_t *)(base + 50);
+ pxe = MK_PTR(seg, off);
+ if (is_pxe(pxe))
+ goto have_pxe;
+
+ /* Plan B: PXENV+ structure at [ES:BX] */
+ plan++;
+ off = *(const uint16_t *)(base + 24); /* Original BX */
+ seg = *(const uint16_t *)(base + 4); /* Original ES */
+ pxenv = MK_PTR(seg, off);
+ if (is_pxenv(pxenv))
+ goto have_pxenv;
+
+ /* Plan C: PXENV+ structure via INT 1Ah AX=5650h */
+ plan++;
+ memset(&regs, 0, sizeof regs);
+ regs.eax.w[0] = 0x5650;
+ call16(pxe_int1a, &regs, &regs);
+ if (!(regs.eflags.l & EFLAGS_CF) && (regs.eax.w[0] == 0x564e)) {
+ pxenv = MK_PTR(regs.es, regs.ebx.w[0]);
+ if (is_pxenv(pxenv))
+ goto have_pxenv;
+ }
+
+ /* Plan D: !PXE memory scan */
+ plan++;
+ if ((pxe = memory_scan_for_pxe_struct()))
+ goto have_pxe;
+
+ /* Plan E: PXENV+ memory scan */
+ plan++;
+ if ((pxenv = memory_scan_for_pxenv_struct()))
+ goto have_pxenv;
+
+ /* Found nothing at all !! */
+ if (!quiet)
+ printf("No !PXE or PXENV+ API found; we're dead...\n");
+ return -1;
+
+ have_pxenv:
+ APIVer = pxenv->version;
+ if (!quiet)
+ printf("Found PXENV+ structure\nPXE API version is %04x\n", APIVer);
+
+ /* if the API version number is 0x0201 or higher, use the !PXE structure */
+ if (APIVer >= 0x201) {
+ if (pxenv->length >= sizeof(struct pxenv_t)) {
+ pxe = GET_PTR(pxenv->pxeptr);
+ if (is_pxe(pxe))
+ goto have_pxe;
+ /*
+ * Nope, !PXE structure missing despite API 2.1+, or at least
+ * the pointer is missing. Do a last-ditch attempt to find it
+ */
+ if ((pxe = memory_scan_for_pxe_struct()))
+ goto have_pxe;
+ }
+ APIVer = 0x200; /* PXENV+ only, assume version 2.00 */
+ }
+
+ /* Otherwise, no dice, use PXENV+ structure */
+ data_len = pxenv->undidatasize;
+ data_seg = pxenv->undidataseg;
+ code_len = pxenv->undicodesize;
+ code_seg = pxenv->undicodeseg;
+ PXEEntry = pxenv->rmentry;
+ type = "PXENV+";
+ goto have_entrypoint;
+
+ have_pxe:
+ data_len = pxe->seg[PXE_Seg_UNDIData].size;
+ data_seg = pxe->seg[PXE_Seg_UNDIData].sel;
+ code_len = pxe->seg[PXE_Seg_UNDICode].size;
+ code_seg = pxe->seg[PXE_Seg_UNDICode].sel;
+ PXEEntry = pxe->entrypointsp;
+ type = "!PXE";
+
+ have_entrypoint:
+ if (!quiet) {
+ printf("%s entry point found (we hope) at %04X:%04X via plan %c\n",
+ type, PXEEntry.seg, PXEEntry.offs, plan);
+ printf("UNDI code segment at %04X len %04X\n", code_seg, code_len);
+ printf("UNDI data segment at %04X len %04X\n", data_seg, data_len);
+ }
+
+ code_seg = code_seg + ((code_len + 15) >> 4);
+ data_seg = data_seg + ((data_len + 15) >> 4);
+
+ real_base_mem = max(code_seg, data_seg) >> 6; /* Convert to kilobytes */
+
+ return 0;
+}
+
+/*
+ * See if we have gPXE
+ */
+static void gpxe_init(void)
+{
+ int err;
+ static __lowmem struct s_PXENV_FILE_API_CHECK api_check;
+
+ if (APIVer >= 0x201) {
+ api_check.Size = sizeof api_check;
+ api_check.Magic = 0x91d447b2;
+ err = pxe_call(PXENV_FILE_API_CHECK, &api_check);
+ if (!err && api_check.Magic == 0xe9c17b20)
+ gpxe_funcs = api_check.APIMask;
+ }
+
+ /* Necessary functions for us to use the gPXE file API */
+ has_gpxe = (~gpxe_funcs & 0x4b) == 0;
+}
+
+/*
+ * Initialize UDP stack
+ *
+ */
+static void udp_init(void)
+{
+ int err;
+ static __lowmem struct s_PXENV_UDP_OPEN udp_open;
+ udp_open.src_ip = IPInfo.myip;
+ err = pxe_call(PXENV_UDP_OPEN, &udp_open);
+ if (err || udp_open.status) {
+ printf("Failed to initialize UDP stack ");
+ printf("%d\n", udp_open.status);
+ kaboom();
+ }
+}
+
+
+/*
+ * Network-specific initialization
+ */
+static void network_init(void)
+{
+ struct bootp_t *bp = (struct bootp_t *)trackbuf;
+ int pkt_len;
+
+ *LocalDomain = 0; /* No LocalDomain received */
+
+ /*
+ * Get the DHCP client identifiers (query info 1)
+ */
+ printf("Getting cached packet ");
+ pkt_len = pxe_get_cached_info(1);
+ parse_dhcp(pkt_len);
+ /*
+ * We don't use flags from the request packet, so
+ * this is a good time to initialize DHCPMagic...
+ * Initialize it to 1 meaning we will accept options found;
+ * in earlier versions of PXELINUX bit 0 was used to indicate
+ * we have found option 208 with the appropriate magic number;
+ * we no longer require that, but MAY want to re-introduce
+ * it in the future for vendor encapsulated options.
+ */
+ *(char *)&DHCPMagic = 1;
+
+ /*
+ * Get the BOOTP/DHCP packet that brought us file (and an IP
+ * address). This lives in the DHCPACK packet (query info 2)
+ */
+ pkt_len = pxe_get_cached_info(2);
+ parse_dhcp(pkt_len);
+ /*
+ * Save away MAC address (assume this is in query info 2. If this
+ * turns out to be problematic it might be better getting it from
+ * the query info 1 packet
+ */
+ MAC_len = bp->hardlen > 16 ? 0 : bp->hardlen;
+ MAC_type = bp->hardware;
+ memcpy(MAC, bp->macaddr, MAC_len);
+
+ /*
+ * Get the boot file and other info. This lives in the CACHED_REPLY
+ * packet (query info 3)
+ */
+ pkt_len = pxe_get_cached_info(3);
+ parse_dhcp(pkt_len);
+ printf("\n");
+
+ make_bootif_string();
+ make_sysuuid_string();
+ ip_init();
+ print_ipappend();
+
+ /*
+ * Check to see if we got any PXELINUX-specific DHCP options; in particular,
+ * if we didn't get the magic enable, do not recognize any other options.
+ */
+ if ((DHCPMagic & 1) == 0)
+ DHCPMagic = 0;
+
+ udp_init();
+}
+
+/*
+ * Initialize pxe fs
+ *
+ */
+static int pxe_fs_init(struct fs_info *fs)
+{
+ (void)fs; /* drop the compile warning message */
+
+ /* This block size is actually arbitrary... */
+ fs->sector_shift = fs->block_shift = TFTP_BLOCKSIZE_LG2;
+ fs->sector_size = fs->block_size = 1 << TFTP_BLOCKSIZE_LG2;
+
+ /* This block size is actually arbitrary... */
+ fs->sector_shift = fs->block_shift = TFTP_BLOCKSIZE_LG2;
+ fs->sector_size = fs->block_size = 1 << TFTP_BLOCKSIZE_LG2;
+
+ /* Find the PXE stack */
+ if (pxe_init(false))
+ kaboom();
+
+ /* See if we also have a gPXE stack */
+ gpxe_init();
+
+ /* Network-specific initialization */
+ network_init();
+
+ /* Initialize network-card-specific idle handling */
+ pxe_idle_init();
+
+ /* Our name for the root */
+ strcpy(fs->cwd_name, "::");
+
+ return 0;
+}
+
+/*
+ * Look to see if we are on an EFI CSM system. Some EFI
+ * CSM systems put the BEV stack in low memory, which means
+ * a return to the PXE stack will crash the system. However,
+ * INT 18h works reliably, so in that case hack the stack and
+ * point the "return address" to an INT 18h instruction.
+ *
+ * Hack the stack instead of the much simpler "just invoke INT 18h
+ * if we want to reset", so that chainloading other NBPs will work.
+ *
+ * This manipulates the real-mode InitStack directly. It relies on this
+ * *not* being a currently active stack, i.e. the former
+ * USE_PXE_PROVIDED_STACK no longer works.
+ */
+extern far_ptr_t InitStack;
+
+struct efi_struct {
+ uint32_t magic;
+ uint8_t csum;
+ uint8_t len;
+} __attribute__((packed));
+#define EFI_MAGIC (('$' << 24)+('E' << 16)+('F' << 8)+'I')
+
+static inline bool is_efi(const struct efi_struct *efi)
+{
+ /*
+ * We don't verify the checksum, because it seems some CSMs leave
+ * it at zero, sigh...
+ */
+ return (efi->magic == EFI_MAGIC) && (efi->len >= 83);
+}
+
+static void install_efi_csm_hack(void)
+{
+ static const uint8_t efi_csm_hack[] =
+ {
+ 0xcd, 0x18, /* int $0x18 */
+ 0xea, 0xf0, 0xff, 0x00, 0xf0, /* ljmpw $0xf000,$0xfff0 */
+ 0xf4 /* hlt */
+ };
+ uint16_t *retcode;
+
+ retcode = GET_PTR(*(far_ptr_t *)((char *)GET_PTR(InitStack) + 44));
+
+ /* Don't do this if the return already points to int $0x18 */
+ if (*retcode != 0x18cd) {
+ uint32_t efi_ptr;
+ bool efi = false;
+
+ for (efi_ptr = 0xe0000 ; efi_ptr < 0x100000 ; efi_ptr += 16) {
+ if (is_efi((const struct efi_struct *)efi_ptr)) {
+ efi = true;
+ break;
+ }
+ }
+
+ if (efi) {
+ uint8_t *src = GET_PTR(InitStack);
+ uint8_t *dst = src - sizeof efi_csm_hack;
+
+ memmove(dst, src, 52);
+ memcpy(dst+52, efi_csm_hack, sizeof efi_csm_hack);
+ InitStack.offs -= sizeof efi_csm_hack;
+
+ /* Clobber the return address */
+ *(uint16_t *)(dst+44) = OFFS_WRT(dst+52, InitStack.seg);
+ *(uint16_t *)(dst+46) = InitStack.seg;
+ }
+ }
+}
+
+int reset_pxe(void)
+{
+ static __lowmem struct s_PXENV_UDP_CLOSE udp_close;
+ extern void gpxe_unload(void);
+ int err = 0;
+
+ pxe_idle_cleanup();
+
+ pxe_call(PXENV_UDP_CLOSE, &udp_close);
+
+ if (gpxe_funcs & 0x80) {
+ /* gPXE special unload implemented */
+ call16(gpxe_unload, &zero_regs, NULL);
+
+ /* Locate the actual vendor stack... */
+ err = pxe_init(true);
+ }
+
+ install_efi_csm_hack();
+ return err;
+}
+
+/*
+ * This function unloads the PXE and UNDI stacks and
+ * unclaims the memory.
+ */
+void unload_pxe(void)
+{
+ /* PXE unload sequences */
+ static const uint8_t new_api_unload[] = {
+ PXENV_UNDI_SHUTDOWN, PXENV_UNLOAD_STACK, PXENV_STOP_UNDI, 0
+ };
+ static const uint8_t old_api_unload[] = {
+ PXENV_UNDI_SHUTDOWN, PXENV_UNLOAD_STACK, PXENV_UNDI_CLEANUP, 0
+ };
+
+ unsigned int api;
+ const uint8_t *api_ptr;
+ int err;
+ size_t int_addr;
+ static __lowmem union {
+ struct s_PXENV_UNDI_SHUTDOWN undi_shutdown;
+ struct s_PXENV_UNLOAD_STACK unload_stack;
+ struct s_PXENV_STOP_UNDI stop_undi;
+ struct s_PXENV_UNDI_CLEANUP undi_cleanup;
+ uint16_t Status; /* All calls have this as the first member */
+ } unload_call;
+
+ dprintf("FBM before unload = %d\n", BIOS_fbm);
+
+ err = reset_pxe();
+
+ dprintf("FBM after reset_pxe = %d, err = %d\n", BIOS_fbm, err);
+
+ /* If we want to keep PXE around, we still need to reset it */
+ if (KeepPXE || err)
+ return;
+
+ dprintf("APIVer = %04x\n", APIVer);
+
+ api_ptr = APIVer >= 0x0200 ? new_api_unload : old_api_unload;
+ while((api = *api_ptr++)) {
+ dprintf("PXE call %04x\n", api);
+ memset(&unload_call, 0, sizeof unload_call);
+ err = pxe_call(api, &unload_call);
+ if (err || unload_call.Status != PXENV_STATUS_SUCCESS) {
+ dprintf("PXE unload API call %04x failed\n", api);
+ goto cant_free;
+ }
+ }
+
+ api = 0xff00;
+ if (real_base_mem <= BIOS_fbm) { /* Sanity check */
+ dprintf("FBM %d < real_base_mem %d\n", BIOS_fbm, real_base_mem);
+ goto cant_free;
+ }
+ api++;
+
+ /* Check that PXE actually unhooked the INT 0x1A chain */
+ int_addr = (size_t)GET_PTR(*(far_ptr_t *)(4 * 0x1a));
+ int_addr >>= 10;
+ if (int_addr >= real_base_mem || int_addr < BIOS_fbm) {
+ BIOS_fbm = real_base_mem;
+ dprintf("FBM after unload_pxe = %d\n", BIOS_fbm);
+ return;
+ }
+
+ dprintf("Can't free FBM, real_base_mem = %d, "
+ "FBM = %d, INT 1A = %08x (%d)\n",
+ real_base_mem, BIOS_fbm,
+ *(uint32_t *)(4 * 0x1a), int_addr);
+
+cant_free:
+ printf("Failed to free base memory error %04x-%08x (%d/%dK)\n",
+ api, *(uint32_t *)(4 * 0x1a), BIOS_fbm, real_base_mem);
+ return;
+}
+
+const struct fs_ops pxe_fs_ops = {
+ .fs_name = "pxe",
+ .fs_flags = FS_NODEV,
+ .fs_init = pxe_fs_init,
+ .searchdir = pxe_searchdir,
+ .chdir = pxe_chdir,
+ .realpath = pxe_realpath,
+ .getfssec = pxe_getfssec,
+ .close_file = pxe_close_file,
+ .mangle_name = pxe_mangle_name,
+ .load_config = pxe_load_config,
+};
diff --git a/contrib/syslinux-4.02/core/fs/pxe/pxe.h b/contrib/syslinux-4.02/core/fs/pxe/pxe.h
new file mode 100644
index 0000000..1e6fa76
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/pxe/pxe.h
@@ -0,0 +1,252 @@
+/* -----------------------------------------------------------------------
+ *
+ * Copyright 1999-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * pxe.h
+ *
+ * PXE opcodes
+ *
+ */
+#ifndef PXE_H
+#define PXE_H
+
+#include <syslinux/pxe_api.h>
+#include "fs.h" /* For MAX_OPEN, should go away */
+
+/*
+ * Some basic defines...
+ */
+#define TFTP_PORT htons(69) /* Default TFTP port */
+#define TFTP_BLOCKSIZE_LG2 9
+#define TFTP_BLOCKSIZE (1 << TFTP_BLOCKSIZE_LG2)
+#define PKTBUF_SIZE 2048 /* */
+
+#define is_digit(c) (((c) >= '0') && ((c) <= '9'))
+
+static inline bool is_hex(char c)
+{
+ return (c >= '0' && c <= '9') ||
+ (c >= 'A' && c <= 'F') ||
+ (c >= 'a' && c <= 'f');
+}
+
+static inline int hexval(char c)
+{
+ return (c >= 'A') ? (c & ~0x20) - 'A' + 10 : (c - '0');
+}
+
+/*
+ * TFTP operation codes
+ */
+#define TFTP_RRQ htons(1) // Read rest
+#define TFTP_WRQ htons(2) // Write rest
+#define TFTP_DATA htons(3) // Data packet
+#define TFTP_ACK htons(4) // ACK packet
+#define TFTP_ERROR htons(5) // ERROR packet
+#define TFTP_OACK htons(6) // OACK packet
+
+/*
+ * TFTP error codes
+ */
+#define TFTP_EUNDEF htons(0) // Unspecified error
+#define TFTP_ENOTFOUND htons(1) // File not found
+#define TFTP_EACCESS htons(2) // Access violation
+#define TFTP_ENOSPACE htons(3) // Disk full
+#define TFTP_EBADOP htons(4) // Invalid TFTP operation
+#define TFTP_EBADID htons(5) // Unknown transfer
+#define TFTP_EEXISTS htons(6) // File exists
+#define TFTP_ENOUSER htons(7) // No such user
+#define TFTP_EOPTNEG htons(8) // Option negotiation failure
+
+
+#define BOOTP_OPTION_MAGIC htonl(0x63825363)
+#define MAC_MAX 32
+
+/* Defines for DNS */
+#define DNS_PORT htons(53) /* Default DNS port */
+#define DNS_MAX_PACKET 512 /* Defined by protocol */
+#define DNS_MAX_SERVERS 4 /* Max no of DNS servers */
+
+
+/*
+ * structures
+ */
+
+struct pxenv_t {
+ uint8_t signature[6]; /* PXENV+ */
+ uint16_t version;
+ uint8_t length;
+ uint8_t checksum;
+ segoff16_t rmentry;
+ uint32_t pmoffset;
+ uint16_t pmselector;
+ uint16_t stackseg;
+ uint16_t stacksize;
+ uint16_t bc_codeseg;
+ uint16_t bc_codesize;
+ uint16_t bc_dataseg;
+ uint16_t bc_datasize;
+ uint16_t undidataseg;
+ uint16_t undidatasize;
+ uint16_t undicodeseg;
+ uint16_t undicodesize;
+ segoff16_t pxeptr;
+} __packed;
+
+struct pxe_t {
+ uint8_t signature[4]; /* !PXE */
+ uint8_t structlength;
+ uint8_t structcksum;
+ uint8_t structrev;
+ uint8_t _pad1;
+ segoff16_t undiromid;
+ segoff16_t baseromid;
+ segoff16_t entrypointsp;
+ segoff16_t entrypointesp;
+ segoff16_t statuscallout;
+ uint8_t _pad2;
+ uint8_t segdesccnt;
+ uint16_t firstselector;
+ pxe_segdesc_t seg[7];
+} __packed;
+
+enum pxe_segments {
+ PXE_Seg_Stack = 0,
+ PXE_Seg_UNDIData = 1,
+ PXE_Seg_UNDICode = 2,
+ PXE_Seg_UNDICodeWrite = 3,
+ PXE_Seg_BC_Data = 4,
+ PXE_Seg_BC_Code = 5,
+ PXE_Seg_BC_CodeWrite = 6
+};
+
+struct bootp_t {
+ uint8_t opcode; /* BOOTP/DHCP "opcode" */
+ uint8_t hardware; /* ARP hreadware type */
+ uint8_t hardlen; /* Hardware address length */
+ uint8_t gatehops; /* Used by forwarders */
+ uint32_t ident; /* Transaction ID */
+ uint16_t seconds; /* Seconds elapsed */
+ uint16_t flags; /* Broadcast flags */
+ uint32_t cip; /* Cient IP */
+ uint32_t yip; /* "Your" IP */
+ uint32_t sip; /* Next Server IP */
+ uint32_t gip; /* Relay agent IP */
+ uint8_t macaddr[16]; /* Client MAC address */
+ uint8_t sname[64]; /* Server name (optional) */
+ char bootfile[128]; /* Boot file name */
+ uint32_t option_magic; /* Vendor option magic cookie */
+ uint8_t options[1260]; /* Vendor options */
+} __attribute__ ((packed));
+
+/*
+ * Our inode private information -- this includes the packet buffer!
+ */
+struct pxe_pvt_inode {
+ uint16_t tftp_localport; /* Local port number (0=not in us)*/
+ uint16_t tftp_remoteport; /* Remote port number */
+ uint32_t tftp_remoteip; /* Remote IP address */
+ uint32_t tftp_filepos; /* bytes downloaded (includeing buffer) */
+ uint32_t tftp_blksize; /* Block size for this connection(*) */
+ uint16_t tftp_bytesleft; /* Unclaimed data bytes */
+ uint16_t tftp_lastpkt; /* Sequence number of last packet (NBO) */
+ char *tftp_dataptr; /* Pointer to available data */
+ uint8_t tftp_goteof; /* 1 if the EOF packet received */
+ uint8_t tftp_unused[3]; /* Currently unused */
+ char tftp_pktbuf[PKTBUF_SIZE];
+} __attribute__ ((packed));
+
+#define PVT(i) ((struct pxe_pvt_inode *)((i)->pvt))
+
+/*
+ * Network boot information
+ */
+struct ip_info {
+ uint32_t ipv4;
+ uint32_t myip;
+ uint32_t serverip;
+ uint32_t gateway;
+ uint32_t netmask;
+};
+
+/*
+ * Variable externs
+ */
+extern struct ip_info IPInfo;
+
+extern uint8_t MAC[];
+extern char BOOTIFStr[];
+extern uint8_t MAC_len;
+extern uint8_t MAC_type;
+
+extern uint8_t DHCPMagic;
+extern uint32_t RebootTime;
+
+extern char boot_file[];
+extern char path_prefix[];
+extern char LocalDomain[];
+
+extern char IPOption[];
+extern char dot_quad_buf[];
+
+extern uint32_t dns_server[];
+
+extern uint16_t APIVer;
+extern far_ptr_t PXEEntry;
+extern uint8_t KeepPXE;
+
+extern far_ptr_t InitStack;
+
+extern bool have_uuid;
+extern uint8_t uuid_type;
+extern uint8_t uuid[];
+
+extern uint16_t BIOS_fbm;
+extern const uint8_t TimeoutTable[];
+
+/*
+ * Compute the suitable gateway for a specific route -- too many
+ * vendor PXE stacks don't do this correctly...
+ */
+static inline uint32_t gateway(uint32_t ip)
+{
+ if ((ip ^ IPInfo.myip) & IPInfo.netmask)
+ return IPInfo.gateway;
+ else
+ return 0;
+}
+
+/*
+ * functions
+ */
+
+/* pxe.c */
+bool ip_ok(uint32_t);
+int pxe_call(int, void *);
+
+/* dhcp_options.c */
+void parse_dhcp(int);
+
+/* dnsresolv.c */
+int dns_mangle(char **, const char *);
+uint32_t dns_resolv(const char *);
+
+/* idle.c */
+void pxe_idle_init(void);
+void pxe_idle_cleanup(void);
+
+/* socknum.c */
+uint16_t get_port(void);
+void free_port(uint16_t port);
+
+#endif /* pxe.h */
diff --git a/contrib/syslinux-4.02/core/fs/readdir.c b/contrib/syslinux-4.02/core/fs/readdir.c
new file mode 100644
index 0000000..d071aff
--- /dev/null
+++ b/contrib/syslinux-4.02/core/fs/readdir.c
@@ -0,0 +1,57 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/dirent.h>
+#include "fs.h"
+#include "core.h"
+
+/*
+ * Open a directory
+ */
+DIR *opendir(const char *path)
+{
+ int rv;
+ struct file *file;
+
+ rv = searchdir(path);
+ if (rv < 0)
+ return NULL;
+
+ file = handle_to_file(rv);
+
+ if (file->inode->mode != DT_DIR) {
+ _close_file(file);
+ return NULL;
+ }
+
+ return (DIR *)file;
+}
+
+/*
+ * Read one directory entry at one time.
+ */
+struct dirent *readdir(DIR *dir)
+{
+ static struct dirent buf;
+ struct file *dd_dir = (struct file *)dir;
+ int rv = -1;
+
+ if (dd_dir) {
+ if (dd_dir->fs->fs_ops->readdir) {
+ rv = dd_dir->fs->fs_ops->readdir(dd_dir, &buf);
+ }
+ }
+
+ return rv < 0 ? NULL : &buf;
+}
+
+/*
+ * Close a directory
+ */
+int closedir(DIR *dir)
+{
+ struct file *dd_dir = (struct file *)dir;
+ _close_file(dd_dir);
+ return 0;
+}
+
+
diff --git a/contrib/syslinux-4.02/core/genhash.pl b/contrib/syslinux-4.02/core/genhash.pl
new file mode 100755
index 0000000..c79139f
--- /dev/null
+++ b/contrib/syslinux-4.02/core/genhash.pl
@@ -0,0 +1,26 @@
+#!/usr/bin/perl
+#
+# Generate hash values for keywords
+#
+
+eval { use bytes; };
+
+while ( defined($keywd = <STDIN>) ) {
+ chomp $keywd;
+
+ ($keywd,$keywdname) = split(/\s+/, $keywd);
+ $keywdname = $keywd unless ( $keywdname );
+
+ $l = length($keywd);
+ $h = 0;
+ for ( $i = 0 ; $i < $l ; $i++ ) {
+ $c = ord(substr($keywd,$i,1)) | 0x20;
+ $h = ((($h << 5)|($h >> 27)) ^ $c) & 0xFFFFFFFF;
+ }
+ if ( $seenhash{$h} ) {
+ printf STDERR "$0: hash collision (0x%08x) %s %s\n",
+ $h, $keywd, $seenhash{$h};
+ }
+ $seenhash{$h} = $keywd;
+ printf("%-23s equ 0x%08x\n", "hash_${keywdname}", $h);
+}
diff --git a/contrib/syslinux-4.02/core/getc.inc b/contrib/syslinux-4.02/core/getc.inc
new file mode 100644
index 0000000..33656b4
--- /dev/null
+++ b/contrib/syslinux-4.02/core/getc.inc
@@ -0,0 +1,415 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
+;; Copyright 2009 Intel Corporation; author: H. Peter Anvin
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+;; Boston MA 02111-1307, USA; either version 2 of the License, or
+;; (at your option) any later version; incorporated herein by reference.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; getc.inc
+;;
+;; Simple file handling library (open, getc, ungetc)
+;;
+;; WARNING: This interface uses the real_mode_seg/comboot_seg.
+;;
+
+MAX_GETC_LG2 equ 4 ; Max number of file nesting
+MAX_GETC equ (1 << MAX_GETC_LG2)
+bytes_per_getc_lg2 equ 16-MAX_GETC_LG2
+bytes_per_getc equ (1 << bytes_per_getc_lg2)
+MAX_UNGET equ 9 ; Max bytes that can be pushed back
+
+ struc getc_file
+gc_file resw 1 ; File pointer
+gc_bufbytes resw 1 ; Bytes left in buffer
+gc_bufdata resw 1 ; Pointer to data in buffer
+gc_unget_cnt resb 1 ; Character pushed back count
+gc_unget_buf resb MAX_UNGET ; Character pushed back buffer
+ endstruc
+getc_file_lg2 equ 4 ; Size of getc_file as a power of 2
+
+%ifndef DEPEND
+%if (getc_file_size != (1 << getc_file_lg2))
+%error "getc_file_size != (1 << getc_file_lg2)"
+%endif
+%endif
+
+;
+; open,getc: Load a file a character at a time for parsing in a manner
+; similar to the C library getc routine.
+; Up to MAX_GETC files can be open at the same time,
+; they are accessed in a stack-like fashion.
+;
+; All routines assume CS == DS.
+;
+; open: Input: mangled filename in DS:DI
+; Output: ZF set on file not found or zero length
+;
+; openfd: Input: file handle in SI, file size in EAX
+; Output: ZF set on getc stack overflow
+;
+; getc: Output: CF set on end of file
+; Character loaded in AL
+;
+; close: Output: CF set if nothing open
+;
+ global core_open
+core_open:
+ pm_call pm_searchdir
+ jz openfd.ret
+openfd:
+ push bx
+
+ mov bx,[CurrentGetC]
+ sub bx,getc_file_size
+ cmp bx,GetCStack
+ jb .stack_full ; Excessive nesting
+ mov [CurrentGetC],bx
+
+ mov [bx+gc_file],si ; File pointer
+ xor ax,ax
+ mov [bx+gc_bufbytes],ax ; Buffer empty
+ mov [bx+gc_unget_cnt],al ; ungetc buffer empty
+
+ inc ax ; ZF <- 0
+ pop bx
+.ret: ret
+
+.stack_full:
+ pm_call pm_close_file
+ xor ax,ax ; ZF <- 1
+ pop bx
+ ret
+
+getc:
+ push bx
+ push si
+ push di
+ push es
+
+ mov di,[CurrentGetC]
+ movzx bx,byte [di+gc_unget_cnt]
+ and bx,bx
+ jnz .have_unget
+
+ mov si,real_mode_seg ; Borrow the real_mode_seg
+ mov es,si
+
+.got_data:
+ sub word [di+gc_bufbytes],1
+ jc .get_data ; Was it zero already?
+ mov si,[di+gc_bufdata]
+ mov al,[es:si]
+ inc si
+ mov [di+gc_bufdata],si
+.done:
+ clc
+.ret:
+ pop es
+ pop di
+ pop si
+ pop bx
+ ret
+.have_unget:
+ dec bx
+ mov al,[di+bx+gc_unget_buf]
+ mov [di+gc_unget_cnt],bl
+ jmp .done
+
+.get_data:
+ pushad
+ ; Compute start of buffer
+ mov bx,di
+ sub bx,GetCStack
+ shl bx,bytes_per_getc_lg2-getc_file_lg2
+
+ mov [di+gc_bufdata],bx
+ mov si,[di+gc_file]
+ and si,si
+ mov [di+gc_bufbytes],si ; In case SI == 0
+ jz .empty
+ mov cx,bytes_per_getc
+ pm_call getfsbytes
+ mov [di+gc_bufbytes],cx
+ mov [di+gc_file],si
+ jcxz .empty
+ popad
+ TRACER 'd'
+ jmp .got_data
+
+.empty:
+ TRACER 'e'
+ ; [di+gc_bufbytes] is zero already, thus we will continue
+ ; to get EOF on any further attempts to read the file.
+ popad
+ xor al,al ; Return a predictable zero
+ stc
+ jmp .ret
+
+;
+; This is similar to getc, except that we read up to CX bytes and
+; store them in ES:DI. Eventually this could get optimized...
+;
+; On return, CX and DI are adjusted by the number of bytes actually read.
+;
+readc:
+ push ax
+.loop:
+ call getc
+ jc .out
+ stosb
+ loop .loop
+.out:
+ pop ax
+ ret
+
+;
+; close: close the top of the getc stack
+;
+close:
+ push bx
+ push si
+ mov bx,[CurrentGetC]
+ mov si,[bx+gc_file]
+ pm_call pm_close_file
+ add bx,getc_file_size
+ mov [CurrentGetC],bx
+ pop si
+ pop bx
+ ret
+
+;
+; ungetc: Push a character (in AL) back into the getc buffer
+; Note: if more than MAX_UNGET bytes are pushed back, all
+; hell will break loose.
+;
+ungetc:
+ push di
+ push bx
+ mov di,[CurrentGetC]
+ movzx bx,[di+gc_unget_cnt]
+ mov [bx+di+gc_unget_buf],al
+ inc bx
+ mov [di+gc_unget_cnt],bl
+ pop bx
+ pop di
+ ret
+
+;
+; skipspace: Skip leading whitespace using "getc". If we hit end-of-line
+; or end-of-file, return with carry set; ZF = true of EOF
+; ZF = false for EOLN; otherwise CF = ZF = 0.
+;
+; Otherwise AL = first character after whitespace
+;
+skipspace:
+.loop: call getc
+ jc .eof
+ cmp al,1Ah ; DOS EOF
+ je .eof
+ cmp al,0Ah
+ je .eoln
+ cmp al,' '
+ jbe .loop
+ ret ; CF = ZF = 0
+.eof: cmp al,al ; Set ZF
+ stc ; Set CF
+ ret
+.eoln: add al,0FFh ; Set CF, clear ZF
+ ret
+
+;
+; getint: Load an integer from the getc file.
+; Return CF if error; otherwise return integer in EBX
+;
+getint:
+ mov di,NumBuf
+.getnum: cmp di,NumBufEnd ; Last byte in NumBuf
+ jae .loaded
+ push di
+ call getc
+ pop di
+ jc .loaded
+ stosb
+ cmp al,'-'
+ jnb .getnum
+ call ungetc ; Unget non-numeric
+.loaded: mov byte [di],0
+ mov si,NumBuf
+ ; Fall through to parseint
+;
+; parseint: Convert an integer to a number in EBX
+; Get characters from string in DS:SI
+; Return CF on error
+; DS:SI points to first character after number
+;
+; Syntaxes accepted: [-]dec, [-]0+oct, [-]0x+hex, val+[KMG]
+;
+parseint:
+ push eax
+ push ecx
+ push bp
+ xor eax,eax ; Current digit (keep eax == al)
+ mov ebx,eax ; Accumulator
+ mov ecx,ebx ; Base
+ xor bp,bp ; Used for negative flag
+.begin: lodsb
+ cmp al,'-'
+ jne .not_minus
+ xor bp,1 ; Set unary minus flag
+ jmp short .begin
+.not_minus:
+ cmp al,'0'
+ jb .err
+ je .octhex
+ cmp al,'9'
+ ja .err
+ mov cl,10 ; Base = decimal
+ jmp short .foundbase
+.octhex:
+ lodsb
+ cmp al,'0'
+ jb .km ; Value is zero
+ or al,20h ; Downcase
+ cmp al,'x'
+ je .ishex
+ cmp al,'7'
+ ja .err
+ mov cl,8 ; Base = octal
+ jmp short .foundbase
+.ishex:
+ mov al,'0' ; No numeric value accrued yet
+ mov cl,16 ; Base = hex
+.foundbase:
+ call unhexchar
+ jc .km ; Not a (hex) digit
+ cmp al,cl
+ jae .km ; Invalid for base
+ imul ebx,ecx ; Multiply accumulated by base
+ add ebx,eax ; Add current digit
+ lodsb
+ jmp short .foundbase
+.km:
+ dec si ; Back up to last non-numeric
+ lodsb
+ or al,20h
+ cmp al,'k'
+ je .isk
+ cmp al,'m'
+ je .ism
+ cmp al,'g'
+ je .isg
+ dec si ; Back up
+.fini: and bp,bp
+ jz .ret ; CF=0!
+ neg ebx ; Value was negative
+.done: clc
+.ret: pop bp
+ pop ecx
+ pop eax
+ ret
+.err: stc
+ jmp short .ret
+.isg: shl ebx,10 ; * 2^30
+.ism: shl ebx,10 ; * 2^20
+.isk: shl ebx,10 ; * 2^10
+ jmp .fini
+
+ section .bss16
+ alignb 4
+NumBuf resb 15 ; Buffer to load number
+NumBufEnd resb 1 ; Last byte in NumBuf
+
+GetCStack resb getc_file_size*MAX_GETC
+.end equ $
+
+ section .data16
+CurrentGetC dw GetCStack.end ; GetCStack empty
+
+;
+; unhexchar: Convert a hexadecimal digit in AL to the equivalent number;
+; return CF=1 if not a hex digit
+;
+ section .text16
+unhexchar:
+ cmp al,'0'
+ jb .ret ; If failure, CF == 1 already
+ cmp al,'9'
+ ja .notdigit
+ sub al,'0' ; CF <- 0
+ ret
+.notdigit: or al,20h ; upper case -> lower case
+ cmp al,'a'
+ jb .ret ; If failure, CF == 1 already
+ cmp al,'f'
+ ja .err
+ sub al,'a'-10 ; CF <- 0
+ ret
+.err: stc
+.ret: ret
+
+;
+;
+; getline: Get a command line, converting control characters to spaces
+; and collapsing streches to one; a space is appended to the
+; end of the string, unless the line is empty.
+; The line is terminated by ^J, ^Z or EOF and is written
+; to ES:DI. On return, DI points to first char after string.
+; CF is set if we hit EOF.
+;
+getline:
+ call skipspace
+ mov dl,1 ; Empty line -> empty string.
+ jz .eof ; eof
+ jc .eoln ; eoln
+ call ungetc
+.fillloop: push dx
+ push di
+ call getc
+ pop di
+ pop dx
+ jc .ret ; CF set!
+ cmp al,' '
+ jna .ctrl
+ xor dx,dx
+.store: stosb
+ jmp short .fillloop
+.ctrl: cmp al,10
+ je .ret ; CF clear!
+ cmp al,26
+ je .eof
+ and dl,dl
+ jnz .fillloop ; Ignore multiple spaces
+ mov al,' ' ; Ctrl -> space
+ inc dx
+ jmp short .store
+.eoln: clc ; End of line is not end of file
+ jmp short .ret
+.eof: stc
+.ret: pushf ; We want the last char to be space!
+ and dl,dl
+ jnz .xret
+ mov al,' '
+ stosb
+.xret: popf
+ ret
+
+;
+; parseint_esdi:
+; Same as parseint, but takes the input in ES:DI
+;
+parseint_esdi:
+ push ds
+ push es
+ pop ds
+ xchg si,di
+ call parseint
+ xchg si,di
+ pop ds
+ ret
diff --git a/contrib/syslinux-4.02/core/graphics.inc b/contrib/syslinux-4.02/core/graphics.inc
new file mode 100644
index 0000000..a8d2851
--- /dev/null
+++ b/contrib/syslinux-4.02/core/graphics.inc
@@ -0,0 +1,353 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1994-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., 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.
+;;
+;; -----------------------------------------------------------------------
+
+; ----------------------------------------------------------------------------
+; VGA splash screen code
+; ----------------------------------------------------------------------------
+
+;
+; vgadisplayfile:
+; Display a graphical splash screen.
+; The file is already opened on the top of the getc stack.
+;
+; Assumes CS == DS == ES.
+;
+ section .text16
+
+vgadisplayfile:
+ ; This is a cheap and easy way to make sure the screen is
+ ; cleared in case we were in graphics mode already
+ call vgaclearmode
+ call vgasetmode
+ jnz .error_nz
+
+.graphalready:
+ ; Load the header.
+ mov cx,4+2*2+16*3
+ mov di,LSSHeader
+.gethdr:
+ call getc
+ stosb
+ loop .gethdr
+ jc .error
+
+ ; The header WILL be in the first chunk.
+ cmp dword [LSSMagic],0x1413f33d ; Magic number
+.error_nz: jne .error
+
+ mov dx,GraphColorMap ; Color map offset
+ mov ax,1012h ; Set RGB registers
+ xor bx,bx ; First register number
+ mov cx,16 ; 16 registers
+ int 10h
+
+.movecursor:
+ mov ax,[GraphYSize] ; Number of pixel rows
+ mov dx,[VGAFontSize]
+ add ax,dx
+ dec ax
+ div dl
+ xor dx,dx ; Set column to 0
+ cmp al,[VidRows]
+ jb .rowsok
+ mov al,[VidRows]
+ dec al
+.rowsok:
+ mov dh,al
+ mov ah,2
+ xor bx,bx
+ int 10h ; Set cursor below image
+
+ mov cx,[GraphYSize] ; Number of graphics rows
+ mov word [VGAPos],0
+
+.drawpixelrow:
+ push cx
+ mov di,VGARowBuffer
+ ; Pre-clear the row buffer
+ push di
+ push di
+ mov cx,640/4
+ xor eax,eax
+ rep stosd
+ pop di
+ mov cx,[GraphXSize]
+ call rledecode ; Decode one row
+ pop si
+ mov di,VGAPlaneBuffer
+ push di
+ mov bp,640
+ call packedpixel2vga
+ pop si
+ push es
+ mov di,0A000h ; VGA segment
+ mov es,di
+ mov di,[VGAPos]
+ call outputvga
+ pop es
+ add word [VGAPos],640/8
+ pop cx
+ loop .drawpixelrow
+
+.error:
+ jmp close ; Tailcall!
+
+;
+; rledecode:
+; Decode a pixel row in RLE16 format.
+;
+; getc stack -> input
+; CX -> pixel count
+; ES:DI -> output (packed pixel)
+;
+rledecode:
+ xor dx,dx ; DL = last pixel, DH = nybble buffer
+.loop:
+ call .getnybble
+ cmp al,dl
+ je .run ; Start of run sequence
+ stosb
+ mov dl,al
+ dec cx
+ jnz .loop
+.done:
+ ret
+.run:
+ xor bx,bx
+ call .getnybble
+ or bl,al
+ jz .longrun
+.dorun:
+ push cx
+ mov cx,bx
+ mov al,dl
+ rep stosb
+ pop cx
+ sub cx,bx
+ ja .loop
+ jmp short .done
+.longrun:
+ call .getnybble
+ mov bl,al
+ call .getnybble
+ shl al,4
+ or bl,al
+ add bx,16
+ jmp short .dorun
+
+.getnybble:
+ test dh,10h
+ jz .low
+ and dh,0Fh
+ mov al,dh
+ ret
+.low:
+ call getc
+ mov dh,al
+ shr dh,4
+ or dh,10h ; Nybble already read
+ and al,0Fh
+ ret
+
+;
+; packedpixel2vga:
+; Convert packed-pixel to VGA bitplanes
+;
+; DS:SI -> packed pixel string
+; BP -> pixel count (multiple of 8)
+; DS:DI -> output (four planes)
+;
+packedpixel2vga:
+ xor cx,cx
+.planeloop:
+ inc cx
+ push si
+ push bp
+.loop1:
+ mov bx,8
+.loop2:
+ lodsb
+ shr al,cl
+ rcl dl,1 ; VGA is bigendian. Sigh.
+ dec bx
+ jnz .loop2
+ mov [di],dl
+ inc di
+ sub bp,byte 8
+ ja .loop1
+ pop bp
+ pop si
+ cmp cl,3
+ jbe .planeloop
+ ret
+
+;
+; outputvga:
+; Output four subsequent lines of VGA data
+;
+; DS:SI -> four planes @ 640/8=80 bytes
+; ES:DI -> pointer into VGA memory
+;
+outputvga:
+ mov dx,3C4h ; VGA Sequencer Register select port
+ mov al,2 ; Sequencer mask
+ out dx,al ; Select the sequencer mask
+ inc dx ; VGA Sequencer Register data port
+ dec ax ; AL <- 1
+.loop1:
+ out dx,al ; Select the bit plane to write
+ push di
+ mov cx,640/32
+ rep movsd
+ pop di
+ add ax,ax
+ cmp al,8
+ jbe .loop1
+ ret
+
+;
+; vgasetmode:
+; Enable VGA graphics, if possible; return ZF=1 on success
+; DS must be set to the base segment; ES is set to DS.
+;
+vgasetmode:
+ push ds
+ pop es
+ mov al,[UsingVGA]
+ cmp al,01h
+ je .success ; Nothing to do...
+ test al,04h
+ jz .notvesa
+ ; We're in a VESA mode, which means VGA; use VESA call
+ ; to revert the mode, and then call the conventional
+ ; mode-setting for good measure...
+ mov ax,4F02h
+ mov bx,0012h
+ int 10h
+ jmp .setmode
+.notvesa:
+ mov ax,1A00h ; Get video card and monitor
+ xor bx,bx
+ int 10h
+ sub bl, 7 ; BL=07h and BL=08h OK
+ cmp bl, 1
+ ja .error ; ZF=0
+; mov bx,TextColorReg
+; mov dx,1009h ; Read color registers
+; int 10h
+.setmode:
+ mov ax,0012h ; Set mode = 640x480 VGA 16 colors
+ int 10h
+ mov dx,linear_color
+ mov ax,1002h ; Write color registers
+ int 10h
+ mov [UsingVGA], byte 1
+
+ ; Set GXPixCols and GXPixRows
+ mov dword [GXPixCols],640+(480 << 16)
+
+ call use_font ; Set graphics font/data
+ mov byte [ScrollAttribute], 00h
+
+.success:
+ xor ax,ax ; Set ZF
+.error:
+ ret
+
+;
+; vgaclearmode:
+; Disable VGA graphics. It is not safe to assume any value
+; for DS or ES.
+;
+vgaclearmode:
+ push ds
+ push es
+ pushad
+ mov ax,cs
+ mov ds,ax
+ mov es,ax
+ mov al,[UsingVGA]
+ and al,al ; Already in text mode?
+ jz .done
+ test al,04h
+ jz .notvesa
+ mov ax,4F02h ; VESA return to normal video mode
+ mov bx,0003h
+ int 10h
+.notvesa:
+ mov ax,0003h ; Return to normal video mode
+ int 10h
+; mov dx,TextColorReg ; Restore color registers
+; mov ax,1002h
+; int 10h
+ mov [UsingVGA], byte 0
+
+ mov byte [ScrollAttribute], 07h
+ call use_font ; Restore text font/data
+.done:
+ popad
+ pop es
+ pop ds
+ ret
+
+;
+; vgashowcursor/vgahidecursor:
+; If VGA graphics is enabled, draw a cursor/clear a cursor
+;
+vgashowcursor:
+ pushad
+ mov al,'_'
+ jmp short vgacursorcommon
+vgahidecursor:
+ pushad
+ mov al,' '
+vgacursorcommon:
+ cmp [UsingVGA], byte 1
+ jne .done
+ mov ah,09h
+ mov bx,0007h
+ mov cx,1
+ int 10h
+.done:
+ popad
+ ret
+
+
+ section .data16
+ ; Map colors to consecutive DAC registers
+linear_color db 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0
+
+ ; See comboot.doc, INT 22h AX=0017h for the semantics
+ ; of this byte.
+UsingVGA db 0
+
+ section .bss16
+ alignb 4
+LSSHeader equ $
+LSSMagic resd 1 ; Magic number
+GraphXSize resw 1 ; Width of splash screen file
+GraphYSize resw 1 ; Height of splash screen file
+GraphColorMap resb 3*16
+VGAPos resw 1 ; Pointer into VGA memory
+VGAFilePtr resw 1 ; Pointer into VGAFileBuf
+; TextColorReg resb 17 ; VGA color registers for text mode
+%if IS_SYSLINUX
+VGAFileBuf resb FILENAME_MAX+2 ; Unmangled VGA image name
+%else
+VGAFileBuf resb FILENAME_MAX ; Unmangled VGA image name
+%endif
+VGAFileBufEnd equ $
+VGAFileMBuf resb FILENAME_MAX ; Mangled VGA image name
+
+ alignb 4
+VGARowBuffer resb 640+80 ; Decompression buffer
+VGAPlaneBuffer resb (640/8)*4 ; Plane buffers
diff --git a/contrib/syslinux-4.02/core/head.inc b/contrib/syslinux-4.02/core/head.inc
new file mode 100644
index 0000000..18ce132
--- /dev/null
+++ b/contrib/syslinux-4.02/core/head.inc
@@ -0,0 +1,38 @@
+; -*- fundamental -*- (asm-mode sucks)
+; -----------------------------------------------------------------------
+;
+; Copyright 2006-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., 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.
+;
+; -----------------------------------------------------------------------
+
+;
+; head.inc
+;
+; Common header includes
+;
+
+%ifndef _HEAD_INC
+%define _HEAD_INC
+
+%if __NASM_MAJOR__ < 2
+ %error "NASM 2.00 or later required to compile correctly"
+%endif
+
+%include "macros.inc"
+%include "config.inc"
+%include "layout.inc"
+%include "pmcall.inc"
+%include "extern.inc"
+%include "kernel.inc"
+%include "bios.inc"
+%include "tracers.inc"
+%include "stack.inc"
+%include "io.inc"
+
+%endif ; _HEAD_INC
diff --git a/contrib/syslinux-4.02/core/highmem.inc b/contrib/syslinux-4.02/core/highmem.inc
new file mode 100644
index 0000000..ea386ff
--- /dev/null
+++ b/contrib/syslinux-4.02/core/highmem.inc
@@ -0,0 +1,158 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1994-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., 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.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; highmem.inc
+;;
+;; Probe for the size of high memory. This can be overridden by a
+;; mem= command on the command line while booting a new kernel.
+;;
+
+ section .text16
+
+;
+; This is set up as a subroutine; it will set up the global variable
+; HighMemSize. All registers are preserved.
+;
+highmemsize:
+ push es
+ pushfd
+ pushad
+
+ push cs
+ pop es
+
+;
+; First, try INT 15:E820 (get BIOS memory map)
+;
+; Note: we may have to scan this multiple times, because some (daft) BIOSes
+; report main memory as multiple contiguous ranges...
+;
+get_e820:
+ mov dword [E820Max],-(1 << 20) ; Max amount of high memory
+ mov dword [E820Mem],(1 << 20) ; End of detected high memory
+.start_over:
+ mov di,E820Buf
+ xor ax,ax
+ mov cx,10
+ rep stosw ; Clear buffer
+ xor ebx,ebx ; Start with first record
+ jmp short .do_e820 ; Skip "at end" check first time!
+.int_loop: and ebx,ebx ; If we're back at beginning...
+ jz .e820_done ; ... we're done
+.do_e820: mov eax,0000E820h
+ mov edx,534D4150h ; "SMAP" backwards
+ xor ecx,ecx
+ mov cl,20 ; ECX <- 20 (size of buffer)
+ mov di,E820Buf
+ int 15h
+ jnc .no_carry
+ ; If carry, ebx == 0 means error, ebx != 0 means we're done
+ and ebx,ebx
+ jnz .e820_done
+ jmp no_e820
+.no_carry:
+ cmp eax,534D4150h
+ jne no_e820
+ cmp cx,20
+ jb no_e820
+
+;
+; Look for a memory block starting at <= 1 MB and continuing upward
+;
+ cmp dword [E820Buf+4], byte 0
+ ja .int_loop ; Start >= 4 GB?
+ mov eax, [E820Buf]
+ cmp dword [E820Buf+16],1
+ je .is_ram ; Is it memory?
+ ;
+ ; Non-memory range. Remember this as a limit; some BIOSes get the length
+ ; of primary RAM incorrect!
+ ;
+.not_ram:
+ cmp eax, (1 << 20)
+ jb .int_loop ; Starts in lowmem region
+ cmp eax,[E820Max]
+ jae .int_loop ; Already above limit
+ mov [E820Max],eax ; Set limit
+ jmp .int_loop
+
+.is_ram:
+ cmp eax,[E820Mem]
+ ja .int_loop ; Not contiguous with our starting point
+ add eax,[E820Buf+8]
+ jc .overflow
+ cmp dword [E820Buf+12],0
+ je .nooverflow
+.overflow:
+ or eax,-1
+.nooverflow:
+ cmp eax,[E820Mem]
+ jbe .int_loop ; All is below our baseline
+ mov [E820Mem],eax
+ jmp .start_over ; Start over in case we find an adjacent range
+
+.e820_done:
+ mov eax,[E820Mem]
+ cmp eax,[E820Max]
+ jna .not_limited
+ mov eax,[E820Max]
+.not_limited:
+ cmp eax,(1 << 20)
+ ja got_highmem ; Did we actually find memory?
+ ; otherwise fall through
+
+;
+; INT 15:E820 failed. Try INT 15:E801.
+;
+no_e820:
+ mov ax,0e801h ; Query high memory (semi-recent)
+ int 15h
+ jc no_e801
+ cmp ax,3c00h
+ ja no_e801 ; > 3C00h something's wrong with this call
+ jb e801_hole ; If memory hole we can only use low part
+
+ mov ax,bx
+ shl eax,16 ; 64K chunks
+ add eax,(16 << 20) ; Add first 16M
+ jmp short got_highmem
+
+;
+; INT 15:E801 failed. Try INT 15:88.
+;
+no_e801:
+ mov ah,88h ; Query high memory (oldest)
+ int 15h
+ cmp ax,14*1024 ; Don't trust memory >15M
+ jna e801_hole
+ mov ax,14*1024
+e801_hole:
+ and eax,0ffffh
+ shl eax,10 ; Convert from kilobytes
+ add eax,(1 << 20) ; First megabyte
+got_highmem:
+%if HIGHMEM_SLOP != 0
+ sub eax,HIGHMEM_SLOP
+%endif
+ mov [HighMemSize],eax
+ popad
+ popfd
+ pop es
+ ret ; Done!
+
+ section .bss16
+ alignb 4
+E820Buf resd 5 ; INT 15:E820 data buffer
+E820Mem resd 1 ; Memory detected by E820
+E820Max resd 1 ; Is E820 memory capped?
+; HighMemSize is defined in com32.inc
diff --git a/contrib/syslinux-4.02/core/idle.c b/contrib/syslinux-4.02/core/idle.c
new file mode 100644
index 0000000..3f57393
--- /dev/null
+++ b/contrib/syslinux-4.02/core/idle.c
@@ -0,0 +1,49 @@
+/* -*- fundamental -*- ---------------------------------------------------
+ *
+ * Copyright 2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * idle.c:
+ *
+ * This function provided protected-mode access to the idle handling.
+ * It needs to be carefully coordinated with idle.inc, which provides
+ * idle services to real-mode code.
+ */
+
+#include "core.h"
+#include <sys/cpu.h>
+
+#define TICKS_TO_IDLE 4 /* Also in idle.inc */
+
+extern uint32_t _IdleTimer;
+extern uint16_t NoHalt;
+
+int (*idle_hook_func)(void);
+
+void reset_idle(void)
+{
+ _IdleTimer = jiffies();
+}
+
+void __idle(void)
+{
+ if (jiffies() - _IdleTimer < TICKS_TO_IDLE)
+ return;
+
+ if (idle_hook_func && idle_hook_func())
+ return; /* Nonzero return = do not idle */
+
+ if (NoHalt)
+ cpu_relax();
+ else
+ hlt();
+}
diff --git a/contrib/syslinux-4.02/core/idle.inc b/contrib/syslinux-4.02/core/idle.inc
new file mode 100644
index 0000000..9677c82
--- /dev/null
+++ b/contrib/syslinux-4.02/core/idle.inc
@@ -0,0 +1,81 @@
+;; -*- fundamental -*- ---------------------------------------------------
+;;
+;; Copyright 2008 H. Peter Anvin - All Rights Reserved
+;; Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+;; Boston MA 02110-1301, USA; either version 2 of the License, or
+;; (at your option) any later version; incorporated herein by reference.
+;;
+;; -----------------------------------------------------------------------
+
+ section .text16
+TICKS_TO_IDLE equ 4 ; Also in idle.c
+
+reset_idle:
+ push eax
+ mov eax,[cs:__jiffies]
+ mov [cs:_IdleTimer],eax
+ pop eax
+ sti ; Guard against BIOS/PXE brokenness...
+ ret
+
+do_idle:
+ push eax
+ push ds
+ push es
+ mov ax,cs
+ mov ds,ax
+ mov es,ax
+ pushf
+ pop ax
+ test ah,2
+ jnz .ok
+ push si
+ push cx
+ mov si,hlt_err
+ call writestr
+ mov si,sp
+ add si,10
+ mov cx,16
+.errloop:
+ ss lodsw
+ call writehex4
+ dec cx
+ jz .endloop
+ mov al,' '
+ call writechr
+ jmp .errloop
+.endloop:
+ call crlf
+ pop cx
+ pop si
+ sti
+.ok:
+ ; Don't spend time jumping to PM unless we're actually idle...
+
+ mov eax,[__jiffies]
+ sub eax,[_IdleTimer]
+ cmp eax,TICKS_TO_IDLE
+ jb .done
+
+ extern __idle
+ pm_call __idle
+.done:
+ pop es
+ pop ds
+ pop eax
+.ret: ret
+
+ section .data16
+ alignz 4
+ global _IdleTimer
+_IdleTimer dd 0
+ global NoHalt
+NoHalt dw 0
+
+hlt_err db 'ERROR: idle with IF=0', CR, LF, 0
+
+ section .text16
diff --git a/contrib/syslinux-4.02/core/include/cache.h b/contrib/syslinux-4.02/core/include/cache.h
new file mode 100644
index 0000000..1f451af
--- /dev/null
+++ b/contrib/syslinux-4.02/core/include/cache.h
@@ -0,0 +1,23 @@
+#ifndef _CACHE_H
+#define _CACHE_H
+
+#include <stdint.h>
+#include <com32.h>
+#include "disk.h"
+#include "fs.h"
+
+/* The cache structure */
+struct cache {
+ block_t block;
+ struct cache *prev;
+ struct cache *next;
+ void *data;
+};
+
+/* functions defined in cache.c */
+void cache_init(struct device *, int);
+const void *get_cache(struct device *, block_t);
+struct cache *_get_cache_block(struct device *, block_t);
+void cache_lock_block(struct cache *);
+
+#endif /* cache.h */
diff --git a/contrib/syslinux-4.02/core/include/codepage.h b/contrib/syslinux-4.02/core/include/codepage.h
new file mode 100644
index 0000000..a24d90f
--- /dev/null
+++ b/contrib/syslinux-4.02/core/include/codepage.h
@@ -0,0 +1,27 @@
+/*
+ * Codepage data structure as generated by cptable.pl
+ */
+#ifndef CODEPAGE_H
+#define CODEPAGE_H
+
+#include <stdint.h>
+
+#define CODEPAGE_MAGIC UINT64_C(0x51d21eb158a8b3d4)
+
+struct codepage {
+ uint64_t magic;
+ uint32_t reserved[6];
+
+ uint8_t upper[256]; /* Codepage upper case table */
+ uint8_t lower[256]; /* Codepage lower case table */
+
+ /*
+ * The primary Unicode match is the same case, i.e. A -> A,
+ * the secondary Unicode match is the opposite case, i.e. A -> a.
+ */
+ uint16_t uni[2][256]; /* Primary and alternate Unicode matches */
+};
+
+extern const struct codepage codepage;
+
+#endif /* CODEPAGE_H */
diff --git a/contrib/syslinux-4.02/core/include/core.h b/contrib/syslinux-4.02/core/include/core.h
new file mode 100644
index 0000000..7db5daf
--- /dev/null
+++ b/contrib/syslinux-4.02/core/include/core.h
@@ -0,0 +1,78 @@
+#ifndef CORE_H
+#define CORE_H
+
+#include <klibc/compiler.h>
+#include <com32.h>
+#include <syslinux/pmapi.h>
+
+extern char core_xfer_buf[65536];
+extern char core_cache_buf[65536];
+extern char trackbuf[];
+extern char CurrentDirName[];
+extern char SubvolName[];
+extern char ConfigName[];
+extern char KernelName[];
+extern char cmd_line[];
+extern char ConfigFile[];
+
+/* diskstart.inc isolinux.asm*/
+extern void getlinsec(void);
+
+/* getc.inc */
+extern void core_open(void);
+
+/* hello.c */
+extern void myputs(const char*);
+
+/* idle.c */
+extern int (*idle_hook_func)(void);
+extern void __idle(void);
+extern void reset_idle(void);
+
+/* mem/malloc.c, mem/free.c, mem/init.c */
+extern void *malloc(size_t);
+extern void *lmalloc(size_t);
+extern void *pmapi_lmalloc(size_t);
+extern void *zalloc(size_t);
+extern void free(void *);
+extern void mem_init(void);
+
+void __cdecl core_intcall(uint8_t, const com32sys_t *, com32sys_t *);
+void __cdecl core_farcall(uint32_t, const com32sys_t *, com32sys_t *);
+int __cdecl core_cfarcall(uint32_t, const void *, uint32_t);
+
+extern const com32sys_t zero_regs;
+void call16(void (*)(void), const com32sys_t *, com32sys_t *);
+
+/*
+ * __lowmem is in the low 1 MB; __bss16 in the low 64K
+ */
+#define __lowmem __attribute__((nocommon,section(".lowmem")))
+#define __bss16 __attribute__((nocommon,section(".bss16")))
+
+/*
+ * Section for very large aligned objects, not zeroed on startup
+ */
+#define __hugebss __attribute__((nocommon,section(".hugebss"),aligned(4096)))
+
+/*
+ * Death! The macro trick is to avoid symbol conflict with
+ * the real-mode symbol kaboom.
+ */
+__noreturn _kaboom(void);
+#define kaboom() _kaboom()
+
+/*
+ * Basic timer function...
+ */
+extern volatile uint32_t __jiffies, __ms_timer;
+static inline uint32_t jiffies(void)
+{
+ return __jiffies;
+}
+static inline uint32_t ms_timer(void)
+{
+ return __ms_timer;
+}
+
+#endif /* CORE_H */
diff --git a/contrib/syslinux-4.02/core/include/ctype.h b/contrib/syslinux-4.02/core/include/ctype.h
new file mode 100644
index 0000000..5c6d4cb
--- /dev/null
+++ b/contrib/syslinux-4.02/core/include/ctype.h
@@ -0,0 +1,25 @@
+#ifndef CTYPE_H
+#define CTYPE_H
+
+/*
+ * Small subset of <ctype.h> for parsing uses, only handles ASCII
+ * and passes the rest through.
+ */
+
+static inline int toupper(int c)
+{
+ if (c >= 'a' && c <= 'z')
+ c -= 0x20;
+
+ return c;
+}
+
+static inline int tolower(int c)
+{
+ if (c >= 'A' && c <= 'Z')
+ c += 0x20;
+
+ return c;
+}
+
+#endif /* CTYPE_H */
diff --git a/contrib/syslinux-4.02/core/include/disk.h b/contrib/syslinux-4.02/core/include/disk.h
new file mode 100644
index 0000000..ac23e92
--- /dev/null
+++ b/contrib/syslinux-4.02/core/include/disk.h
@@ -0,0 +1,37 @@
+#ifndef DISK_H
+#define DISK_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef uint64_t sector_t;
+typedef uint64_t block_t;
+
+/*
+ * struct disk: contains the information about a specific disk and also
+ * contains the I/O function.
+ */
+struct disk {
+ unsigned int disk_number; /* in BIOS style */
+ unsigned int sector_size; /* gener512B or 2048B */
+ unsigned int sector_shift;
+ unsigned int maxtransfer; /* Max sectors per transfer */
+
+ unsigned int h, s; /* CHS geometry */
+ unsigned int secpercyl; /* h*s */
+ unsigned int _pad;
+
+ sector_t part_start; /* the start address of this partition(in sectors) */
+
+ int (*rdwr_sectors)(struct disk *, void *, sector_t, size_t, bool);
+};
+
+extern void read_sectors(char *, sector_t, int);
+extern void getoneblk(struct disk *, char *, block_t, int);
+
+/* diskio.c */
+struct disk *disk_init(uint8_t, bool, sector_t, uint16_t, uint16_t, uint32_t);
+struct device *device_init(uint8_t, bool, sector_t, uint16_t, uint16_t, uint32_t);
+
+#endif /* DISK_H */
diff --git a/contrib/syslinux-4.02/core/include/fs.h b/contrib/syslinux-4.02/core/include/fs.h
new file mode 100644
index 0000000..ecd148d
--- /dev/null
+++ b/contrib/syslinux-4.02/core/include/fs.h
@@ -0,0 +1,227 @@
+#ifndef FS_H
+#define FS_H
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <string.h>
+#include <com32.h>
+#include <stdio.h>
+#include <sys/dirent.h>
+#include "core.h"
+#include "disk.h"
+
+/*
+ * Maximum number of open files. This is *currently* constrained by the
+ * fact that PXE needs to be able to fit all its packet buffers into a
+ * 64K segment; this should be fixed by moving the packet buffers to high
+ * memory.
+ */
+#define MAX_OPEN_LG2 5
+#define MAX_OPEN (1 << MAX_OPEN_LG2)
+
+#define FILENAME_MAX_LG2 8
+#define FILENAME_MAX (1 << FILENAME_MAX_LG2)
+
+#define CURRENTDIR_MAX FILENAME_MAX
+
+#define BLOCK_SIZE(fs) ((fs)->block_size)
+#define BLOCK_SHIFT(fs) ((fs)->block_shift)
+#define SECTOR_SIZE(fs) ((fs)->sector_size)
+#define SECTOR_SHIFT(fs) ((fs)->sector_shift)
+
+struct fs_info {
+ const struct fs_ops *fs_ops;
+ struct device *fs_dev;
+ void *fs_info; /* The fs-specific information */
+ int sector_shift, sector_size;
+ int block_shift, block_size;
+ struct inode *root, *cwd; /* Root and current directories */
+ char cwd_name[CURRENTDIR_MAX]; /* Current directory by name */
+};
+
+extern struct fs_info *this_fs;
+
+struct dirent; /* Directory entry structure */
+struct file;
+enum fs_flags {
+ FS_NODEV = 1 << 0,
+ FS_USEMEM = 1 << 1, /* If we need a malloc routine, set it */
+ FS_THISIND = 1 << 2, /* Set cwd based on config file location */
+};
+
+struct fs_ops {
+ /* in fact, we use fs_ops structure to find the right fs */
+ const char *fs_name;
+ enum fs_flags fs_flags;
+
+ int (*fs_init)(struct fs_info *);
+ void (*searchdir)(const char *, struct file *);
+ uint32_t (*getfssec)(struct file *, char *, int, bool *);
+ void (*close_file)(struct file *);
+ void (*mangle_name)(char *, const char *);
+ size_t (*realpath)(struct fs_info *, char *, const char *, size_t);
+ int (*chdir)(struct fs_info *, const char *);
+ int (*load_config)(void);
+
+ struct inode * (*iget_root)(struct fs_info *);
+ struct inode * (*iget)(const char *, struct inode *);
+ int (*readlink)(struct inode *, char *);
+
+ /* the _dir_ stuff */
+ int (*readdir)(struct file *, struct dirent *);
+
+ int (*next_extent)(struct inode *, uint32_t);
+};
+
+/*
+ * Extent structure: contains the mapping of some chunk of a file
+ * that is contiguous on disk.
+ */
+struct extent {
+ sector_t pstart; /* Physical start sector */
+ uint32_t lstart; /* Logical start sector */
+ uint32_t len; /* Number of contiguous sectors */
+};
+
+/* Special sector numbers used for struct extent.pstart */
+#define EXTENT_ZERO ((sector_t)-1) /* All-zero extent */
+#define EXTENT_VOID ((sector_t)-2) /* Invalid information */
+
+#define EXTENT_SPECIAL(x) ((x) >= EXTENT_VOID)
+
+/*
+ * The inode structure, including the detail file information
+ */
+struct inode {
+ struct fs_info *fs; /* The filesystem this inode is associated with */
+ struct inode *parent; /* Parent directory, if any */
+ int refcnt;
+ int mode; /* FILE , DIR or SYMLINK */
+ uint32_t size;
+ uint32_t blocks; /* How many blocks the file take */
+ uint32_t ino; /* Inode number */
+ uint32_t atime; /* Access time */
+ uint32_t mtime; /* Modify time */
+ uint32_t ctime; /* Create time */
+ uint32_t dtime; /* Delete time */
+ uint32_t flags;
+ uint32_t file_acl;
+ struct extent this_extent, next_extent;
+ char pvt[0]; /* Private filesystem data */
+};
+
+struct file {
+ struct fs_info *fs;
+ uint32_t offset; /* for next read */
+ struct inode *inode; /* The file-specific information */
+};
+
+/*
+ * Struct device contains:
+ * the pointer points to the disk structure,
+ * the cache stuff.
+ */
+struct cache;
+
+struct device {
+ struct disk *disk;
+
+ /* the cache stuff */
+ char *cache_data;
+ struct cache *cache_head;
+ uint16_t cache_block_size;
+ uint16_t cache_entries;
+ uint32_t cache_size;
+};
+
+/*
+ * Our definition of "not whitespace"
+ */
+static inline bool not_whitespace(char c)
+{
+ return (unsigned char)c > ' ';
+}
+
+/*
+ * Inode allocator/deallocator
+ */
+struct inode *alloc_inode(struct fs_info *fs, uint32_t ino, size_t data);
+static inline void free_inode(struct inode * inode)
+{
+ free(inode);
+}
+
+static inline struct inode *get_inode(struct inode *inode)
+{
+ inode->refcnt++;
+ return inode;
+}
+
+void put_inode(struct inode *inode);
+
+static inline void malloc_error(char *obj)
+{
+ printf("Out of memory: can't allocate memory for %s\n", obj);
+ kaboom();
+}
+
+/*
+ * File handle conversion functions
+ */
+extern struct file files[];
+static inline uint16_t file_to_handle(struct file *file)
+{
+ return file ? (file - files)+1 : 0;
+}
+static inline struct file *handle_to_file(uint16_t handle)
+{
+ return handle ? &files[handle-1] : NULL;
+}
+
+/* fs.c */
+void pm_mangle_name(com32sys_t *);
+void pm_searchdir(com32sys_t *);
+void mangle_name(char *, const char *);
+int searchdir(const char *name);
+void _close_file(struct file *);
+size_t pmapi_read_file(uint16_t *handle, void *buf, size_t sectors);
+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 *);
+
+/* chdir.c */
+void pm_realpath(com32sys_t *regs);
+size_t realpath(char *dst, const char *src, size_t bufsize);
+int chdir(const char *src);
+
+/* readdir.c */
+DIR *opendir(const char *pathname);
+struct dirent *readdir(DIR *dir);
+int closedir(DIR *dir);
+
+/* getcwd.c */
+char *getcwd(char *buf, size_t size);
+
+/*
+ * Generic functions that filesystem drivers may choose to use
+ */
+
+/* mangle.c */
+void generic_mangle_name(char *, const char *);
+
+/* loadconfig.c */
+int search_config(const char *search_directores[], const char *filenames[]);
+int generic_load_config(void);
+
+/* close.c */
+void generic_close_file(struct file *file);
+
+/* getfssec.c */
+uint32_t generic_getfssec(struct file *file, char *buf,
+ int sectors, bool *have_more);
+
+/* nonextextent.c */
+int no_next_extent(struct inode *, uint32_t);
+
+#endif /* FS_H */
diff --git a/contrib/syslinux-4.02/core/include/pmapi.h b/contrib/syslinux-4.02/core/include/pmapi.h
new file mode 100644
index 0000000..57d2e6f
--- /dev/null
+++ b/contrib/syslinux-4.02/core/include/pmapi.h
@@ -0,0 +1,8 @@
+#ifndef PMAPI_H
+#define PMAPI_H
+
+#include <syslinux/pmapi.h>
+
+size_t pmapi_read_file(uint16_t *, void *, size_t);
+
+#endif /* PMAPI_H */
diff --git a/contrib/syslinux-4.02/core/init.inc b/contrib/syslinux-4.02/core/init.inc
new file mode 100644
index 0000000..e06ca96
--- /dev/null
+++ b/contrib/syslinux-4.02/core/init.inc
@@ -0,0 +1,133 @@
+; -*- fundamental -*-
+; -----------------------------------------------------------------------
+;
+; Copyright 2004-2008 H. Peter Anvin - All Rights Reserved
+; Copyright 2009 Intel Corporation; author: H. Peter Anvin
+;
+; This program is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+; Boston MA 02111-1307, USA; either version 2 of the License, or
+; (at your option) any later version; incorporated herein by reference.
+;
+; -----------------------------------------------------------------------
+
+;
+; init.inc
+;
+; Common initialization code (inline)
+;
+
+ section .text16
+common_init:
+ ; Initialize PM invocation framework
+ call pm_init
+
+ ; Decompress PM code to its target location
+ pm_call pm_decompress
+ cmp eax,__pm_code_len
+ jne kaboom
+
+;
+; Initialize timer
+;
+ call timer_init
+
+;
+; Initialize configuration information
+;
+ call reset_config
+
+;
+; Set up the COMBOOT APIs
+;
+ call comboot_setup_api
+
+;
+; Now set up screen parameters
+;
+ call adjust_screen
+
+;
+; CPU-dependent initialization and related checks.
+;
+check_escapes:
+ mov ah,02h ; Check keyboard flags
+ int 16h
+ mov [KbdFlags],al ; Save for boot prompt check
+ test al,04h ; Ctrl->skip 386 check
+ jnz skip_checks
+
+;
+; 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
+;
+ int 12h
+ mov edx,__lowmem_heap + min_lowmem_heap + 1023
+ shr edx,10
+ cmp ax,dx
+ jae enough_ram
+ mov ax,dx
+ mov si,err_noram
+ mov cl,10
+ div cl
+ add [si+err_noram.size-err_noram+2],ah
+ cbw
+ div cl
+ add [si+err_noram.size-err_noram],ax
+ call writestr_early
+ jmp kaboom
+enough_ram:
+skip_checks:
+
+ section .data16
+err_noram db 'It appears your computer has less than '
+.size db '000'
+ db 'K of low ("DOS")'
+ db CR, LF
+ db 'RAM. Syslinux needs at least this amount to boot. If you get'
+ db CR, LF
+ db 'this message in error, hold down the Ctrl key while'
+ db CR, LF
+ db 'booting, and I will take your word for it.', CR, LF, 0
+
+ section .text16
+;
+; The code to decompress the PM code and initialize other segments.
+;
+ extern _lzo1x_decompress_asm_fast
+
+ section .textnr
+ bits 32
+pm_decompress:
+ push 0 ; Space for decompressed size
+ push esp ; Pointer to previous word
+ push __pm_code_start ; Target address
+ push dword [lzo_data_size] ; Compressed size
+ push dword __pm_code_lma
+ call _lzo1x_decompress_asm_fast
+ add esp,16
+ pop RM_EAX ; Decompressed size
+
+ ; Zero bss sections (but not .earlybss, since it may
+ ; contain already-live data.)
+ xor eax,eax
+ mov edi,__bss_start
+ mov ecx,__bss_dwords
+ rep stosd
+ mov edi,__bss16_start
+ mov ecx,__bss16_dwords
+ rep stosd
+ mov edi,__high_clear_start ; .uibss, .auxseg, .lowmem
+ mov ecx,__high_clear_dwords
+ rep stosd
+
+ ret
+
+ section .data16
+lzo_data_size dd 0 ; filled in by compressor
+
+ section .text16
+ bits 16
diff --git a/contrib/syslinux-4.02/core/io.inc b/contrib/syslinux-4.02/core/io.inc
new file mode 100644
index 0000000..7161346
--- /dev/null
+++ b/contrib/syslinux-4.02/core/io.inc
@@ -0,0 +1,35 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
+;; Copyright 2009 Intel Corporation; author: H. Peter Anvin
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+;; Boston MA 02111-1307, USA; either version 2 of the License, or
+;; (at your option) any later version; incorporated herein by reference.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; io.inc
+;;
+;; I/O related macros
+;;
+
+%ifndef _IO_INC
+%define _IO_INC
+
+%define IO_DELAY_PORT 80h ; Invalid port (we hope!)
+
+%macro io_delay 0.nolist
+ out IO_DELAY_PORT,al
+ out IO_DELAY_PORT,al
+%endmacro
+
+%macro slow_out 2.nolist
+ out %1,%2
+ io_delay
+%endmacro
+
+%endif ; _IO_INC
diff --git a/contrib/syslinux-4.02/core/isolinux-debug.asm b/contrib/syslinux-4.02/core/isolinux-debug.asm
new file mode 100644
index 0000000..9c74b7c
--- /dev/null
+++ b/contrib/syslinux-4.02/core/isolinux-debug.asm
@@ -0,0 +1,2 @@
+%define DEBUG_MESSAGES 1
+%include "isolinux.asm"
diff --git a/contrib/syslinux-4.02/core/isolinux.asm b/contrib/syslinux-4.02/core/isolinux.asm
new file mode 100644
index 0000000..1ef68d8
--- /dev/null
+++ b/contrib/syslinux-4.02/core/isolinux.asm
@@ -0,0 +1,1383 @@
+; -*- fundamental -*- (asm-mode sucks)
+; ****************************************************************************
+;
+; isolinux.asm
+;
+; A program to boot Linux kernels off a CD-ROM using the El Torito
+; boot standard in "no emulation" mode, making the entire filesystem
+; available. It is based on the SYSLINUX boot loader for MS-DOS
+; floppies.
+;
+; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
+; Copyright 2009 Intel Corporation; author: H. Peter Anvin
+;
+; This program is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+; Boston MA 02111-1307, USA; either version 2 of the License, or
+; (at your option) any later version; incorporated herein by reference.
+;
+; ****************************************************************************
+
+%define IS_ISOLINUX 1
+%include "head.inc"
+
+;
+; Some semi-configurable constants... change on your own risk.
+;
+my_id equ isolinux_id
+NULLFILE equ 0 ; Zero byte == null file name
+NULLOFFSET equ 0 ; Position in which to look
+retry_count equ 6 ; How patient are we with the BIOS?
+%assign HIGHMEM_SLOP 128*1024 ; Avoid this much memory near the top
+SECTOR_SHIFT equ 11 ; 2048 bytes/sector (El Torito requirement)
+SECTOR_SIZE equ (1 << SECTOR_SHIFT)
+
+ROOT_DIR_WORD equ 0x002F
+
+;
+; The following structure is used for "virtual kernels"; i.e. LILO-style
+; option labels. The options we permit here are `kernel' and `append
+; Since there is no room in the bottom 64K for all of these, we
+; stick them in high memory and copy them down before we need them.
+;
+ struc vkernel
+vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!**
+vk_rname: resb FILENAME_MAX ; Real name
+vk_appendlen: resw 1
+vk_type: resb 1 ; Type of file
+ alignb 4
+vk_append: resb max_cmd_len+1 ; Command line
+ alignb 4
+vk_end: equ $ ; Should be <= vk_size
+ endstruc
+
+;
+; File structure. This holds the information for each currently open file.
+;
+ struc open_file_t
+file_sector resd 1 ; Sector pointer (0 = structure free)
+file_bytesleft resd 1 ; Number of bytes left
+file_left resd 1 ; Number of sectors left
+ resd 1 ; Unused
+ endstruc
+
+%ifndef DEPEND
+%if (open_file_t_size & (open_file_t_size-1))
+%error "open_file_t is not a power of 2"
+%endif
+%endif
+
+; ---------------------------------------------------------------------------
+; BEGIN CODE
+; ---------------------------------------------------------------------------
+
+;
+; Memory below this point is reserved for the BIOS and the MBR
+;
+ section .earlybss
+ global trackbuf
+trackbufsize equ 8192
+trackbuf resb trackbufsize ; Track buffer goes here
+; ends at 2800h
+
+ ; Some of these are touched before the whole image
+ ; is loaded. DO NOT move this to .bss16/.uibss.
+ section .earlybss
+ alignb 4
+FirstSecSum resd 1 ; Checksum of bytes 64-2048
+ImageDwords resd 1 ; isolinux.bin size, dwords
+InitStack resd 1 ; Initial stack pointer (SS:SP)
+DiskSys resw 1 ; Last INT 13h call
+ImageSectors resw 1 ; isolinux.bin size, sectors
+; These following two are accessed as a single dword...
+GetlinsecPtr resw 1 ; The sector-read pointer
+BIOSName resw 1 ; Display string for BIOS type
+%define HAVE_BIOSNAME 1
+BIOSType resw 1
+DiskError resb 1 ; Error code for disk I/O
+DriveNumber resb 1 ; CD-ROM BIOS drive number
+ISOFlags resb 1 ; Flags for ISO directory search
+RetryCount resb 1 ; Used for disk access retries
+
+ alignb 8
+Hidden resq 1 ; Used in hybrid mode
+bsSecPerTrack resw 1 ; Used in hybrid mode
+bsHeads resw 1 ; Used in hybrid mode
+
+
+;
+; El Torito spec packet
+;
+
+ alignb 8
+_spec_start equ $
+spec_packet: resb 1 ; Size of packet
+sp_media: resb 1 ; Media type
+sp_drive: resb 1 ; Drive number
+sp_controller: resb 1 ; Controller index
+sp_lba: resd 1 ; LBA for emulated disk image
+sp_devspec: resw 1 ; IDE/SCSI information
+sp_buffer: resw 1 ; User-provided buffer
+sp_loadseg: resw 1 ; Load segment
+sp_sectors: resw 1 ; Sector count
+sp_chs: resb 3 ; Simulated CHS geometry
+sp_dummy: resb 1 ; Scratch, safe to overwrite
+
+;
+; EBIOS drive parameter packet
+;
+ alignb 8
+drive_params: resw 1 ; Buffer size
+dp_flags: resw 1 ; Information flags
+dp_cyl: resd 1 ; Physical cylinders
+dp_head: resd 1 ; Physical heads
+dp_sec: resd 1 ; Physical sectors/track
+dp_totalsec: resd 2 ; Total sectors
+dp_secsize: resw 1 ; Bytes per sector
+dp_dpte: resd 1 ; Device Parameter Table
+dp_dpi_key: resw 1 ; 0BEDDh if rest valid
+dp_dpi_len: resb 1 ; DPI len
+ resb 1
+ resw 1
+dp_bus: resb 4 ; Host bus type
+dp_interface: resb 8 ; Interface type
+db_i_path: resd 2 ; Interface path
+db_d_path: resd 2 ; Device path
+ resb 1
+db_dpi_csum: resb 1 ; Checksum for DPI info
+
+;
+; EBIOS disk address packet
+;
+ alignb 8
+dapa: resw 1 ; Packet size
+.count: resw 1 ; Block count
+.off: resw 1 ; Offset of buffer
+.seg: resw 1 ; Segment of buffer
+.lba: resd 2 ; LBA (LSW, MSW)
+
+;
+; Spec packet for disk image emulation
+;
+ alignb 8
+dspec_packet: resb 1 ; Size of packet
+dsp_media: resb 1 ; Media type
+dsp_drive: resb 1 ; Drive number
+dsp_controller: resb 1 ; Controller index
+dsp_lba: resd 1 ; LBA for emulated disk image
+dsp_devspec: resw 1 ; IDE/SCSI information
+dsp_buffer: resw 1 ; User-provided buffer
+dsp_loadseg: resw 1 ; Load segment
+dsp_sectors: resw 1 ; Sector count
+dsp_chs: resb 3 ; Simulated CHS geometry
+dsp_dummy: resb 1 ; Scratch, safe to overwrite
+
+ alignb 4
+_spec_end equ $
+_spec_len equ _spec_end - _spec_start
+
+ section .init
+;;
+;; Primary entry point. Because BIOSes are buggy, we only load the first
+;; CD-ROM sector (2K) of the file, so the number one priority is actually
+;; loading the rest.
+;;
+StackBuf equ STACK_TOP-44 ; 44 bytes needed for
+ ; the bootsector chainloading
+ ; code!
+OrigESDI equ StackBuf-4 ; The high dword on the stack
+StackHome equ OrigESDI
+
+bootsec equ $
+
+_start: ; Far jump makes sure we canonicalize the address
+ cli
+ jmp 0:_start1
+ times 8-($-$$) nop ; Pad to file offset 8
+
+ ; This table hopefully gets filled in by mkisofs using the
+ ; -boot-info-table option. If not, the values in this
+ ; table are default values that we can use to get us what
+ ; we need, at least under a certain set of assumptions.
+ global iso_boot_info
+iso_boot_info:
+bi_pvd: dd 16 ; LBA of primary volume descriptor
+bi_file: dd 0 ; LBA of boot file
+bi_length: dd 0xdeadbeef ; Length of boot file
+bi_csum: dd 0xdeadbeef ; Checksum of boot file
+bi_reserved: times 10 dd 0xdeadbeef ; Reserved
+bi_end:
+
+ ; Custom entry point for the hybrid-mode disk.
+ ; The following values will have been pushed onto the
+ ; entry stack:
+ ; - partition offset (qword)
+ ; - ES
+ ; - DI
+ ; - DX (including drive number)
+ ; - CBIOS Heads
+ ; - CBIOS Sectors
+ ; - EBIOS flag
+ ; (top of stack)
+ ;
+ ; If we had an old isohybrid, the partition offset will
+ ; be missing; we can check for that with sp >= 0x7c00.
+ ; Serious hack alert.
+%ifndef DEBUG_MESSAGES
+_hybrid_signature:
+ dd 0x7078c0fb ; An arbitrary number...
+
+_start_hybrid:
+ pop cx ; EBIOS flag
+ pop word [cs:bsSecPerTrack]
+ pop word [cs:bsHeads]
+ pop dx
+ pop di
+ pop es
+ xor eax,eax
+ xor ebx,ebx
+ cmp sp,7C00h
+ jae .nooffset
+ pop eax
+ pop ebx
+.nooffset:
+ mov si,bios_cbios
+ jcxz _start_common
+ mov si,bios_ebios
+ jmp _start_common
+%endif
+
+_start1:
+ mov si,bios_cdrom
+ xor eax,eax
+ xor ebx,ebx
+_start_common:
+ mov [cs:InitStack],sp ; Save initial stack pointer
+ mov [cs:InitStack+2],ss
+ xor cx,cx
+ mov ss,cx
+ mov sp,StackBuf ; Set up stack
+ push es ; Save initial ES:DI -> $PnP pointer
+ push di
+ mov ds,cx
+ mov es,cx
+ mov fs,cx
+ mov gs,cx
+ sti
+ cld
+
+ mov [Hidden],eax
+ mov [Hidden+4],ebx
+
+ mov [BIOSType],si
+ mov eax,[si]
+ mov [GetlinsecPtr],eax
+
+ ; Show signs of life
+ mov si,syslinux_banner
+ call writestr_early
+%ifdef DEBUG_MESSAGES
+ mov si,copyright_str
+%else
+ mov si,[BIOSName]
+%endif
+ call writestr_early
+
+ ;
+ ; Before modifying any memory, get the checksum of bytes
+ ; 64-2048
+ ;
+initial_csum: xor edi,edi
+ mov si,bi_end
+ mov cx,(SECTOR_SIZE-64) >> 2
+.loop: lodsd
+ add edi,eax
+ loop .loop
+ mov [FirstSecSum],edi
+
+ mov [DriveNumber],dl
+%ifdef DEBUG_MESSAGES
+ mov si,startup_msg
+ call writemsg
+ mov al,dl
+ call writehex2
+ call crlf
+%endif
+ ;
+ ; Initialize spec packet buffers
+ ;
+ mov di,_spec_start
+ mov cx,_spec_len >> 2
+ xor eax,eax
+ rep stosd
+
+ ; Initialize length field of the various packets
+ mov byte [spec_packet],13h
+ mov byte [drive_params],30
+ mov byte [dapa],16
+ mov byte [dspec_packet],13h
+
+ ; Other nonzero fields
+ inc word [dsp_sectors]
+
+ ; Are we just pretending to be a CD-ROM?
+ cmp word [BIOSType],bios_cdrom
+ jne found_drive ; If so, no spec packet...
+
+ ; Now figure out what we're actually doing
+ ; Note: use passed-in DL value rather than 7Fh because
+ ; at least some BIOSes will get the wrong value otherwise
+ mov ax,4B01h ; Get disk emulation status
+ mov dl,[DriveNumber]
+ mov si,spec_packet
+ call int13
+ jc award_hack ; changed for BrokenAwardHack
+ mov dl,[DriveNumber]
+ cmp [sp_drive],dl ; Should contain the drive number
+ jne spec_query_failed
+
+%ifdef DEBUG_MESSAGES
+ mov si,spec_ok_msg
+ call writemsg
+ mov al,byte [sp_drive]
+ call writehex2
+ call crlf
+%endif
+
+found_drive:
+ ; Alright, we have found the drive. Now, try to find the
+ ; boot file itself. If we have a boot info table, life is
+ ; good; if not, we have to make some assumptions, and try
+ ; to figure things out ourselves. In particular, the
+ ; assumptions we have to make are:
+ ; - single session only
+ ; - only one boot entry (no menu or other alternatives)
+
+ cmp dword [bi_file],0 ; Address of code to load
+ jne found_file ; Boot info table present :)
+
+%ifdef DEBUG_MESSAGES
+ mov si,noinfotable_msg
+ call writemsg
+%endif
+
+ ; No such luck. See if the spec packet contained one.
+ mov eax,[sp_lba]
+ and eax,eax
+ jz set_file ; Good enough
+
+%ifdef DEBUG_MESSAGES
+ mov si,noinfoinspec_msg
+ call writemsg
+%endif
+
+ ; No such luck. Get the Boot Record Volume, assuming single
+ ; session disk, and that we're the first entry in the chain.
+ mov eax,17 ; Assumed address of BRV
+ mov bx,trackbuf
+ call getonesec
+
+ mov eax,[trackbuf+47h] ; Get boot catalog address
+ mov bx,trackbuf
+ call getonesec ; Get boot catalog
+
+ mov eax,[trackbuf+28h] ; First boot entry
+ ; And hope and pray this is us...
+
+ ; Some BIOSes apparently have limitations on the size
+ ; that may be loaded (despite the El Torito spec being very
+ ; clear on the fact that it must all be loaded.) Therefore,
+ ; we load it ourselves, and *bleep* the BIOS.
+
+set_file:
+ mov [bi_file],eax
+
+found_file:
+ ; Set up boot file sizes
+ mov eax,[bi_length]
+ sub eax,SECTOR_SIZE-3 ; ... minus sector loaded
+ shr eax,2 ; bytes->dwords
+ mov [ImageDwords],eax ; boot file dwords
+ add eax,((SECTOR_SIZE-1) >> 2)
+ shr eax,SECTOR_SHIFT-2 ; dwords->sectors
+ mov [ImageSectors],ax ; boot file sectors
+
+ mov eax,[bi_file] ; Address of code to load
+ inc eax ; Don't reload bootstrap code
+%ifdef DEBUG_MESSAGES
+ mov si,offset_msg
+ call writemsg
+ call writehex8
+ call crlf
+%endif
+
+ ; Load the rest of the file. However, just in case there
+ ; are still BIOSes with 64K wraparound problems, we have to
+ ; take some extra precautions. Since the normal load
+ ; address (TEXT_START) is *not* 2K-sector-aligned, we round
+ ; the target address upward to a sector boundary,
+ ; and then move the entire thing down as a unit.
+MaxLMA equ 384*1024 ; Reasonable limit (384K)
+
+ mov bx,((TEXT_START+2*SECTOR_SIZE-1) & ~(SECTOR_SIZE-1)) >> 4
+ mov bp,[ImageSectors]
+ push bx ; Load segment address
+
+.more:
+ push bx ; Segment address
+ push bp ; Sector count
+ mov es,bx
+ mov cx,0xfff
+ and bx,cx
+ inc cx
+ sub cx,bx
+ shr cx,SECTOR_SHIFT - 4
+ jnz .notaligned
+ mov cx,0x10000 >> SECTOR_SHIFT ; Full 64K segment possible
+.notaligned:
+ cmp bp,cx
+ jbe .ok
+ mov bp,cx
+.ok:
+ xor bx,bx
+ push bp
+ call getlinsec
+ pop cx
+ mov dx,cx
+ pop bp
+ pop bx
+
+ shl cx,SECTOR_SHIFT - 4
+ add bx,cx
+ sub bp,dx
+ jnz .more
+
+ ; Move the image into place, and also verify the
+ ; checksum
+ pop ax ; Load segment address
+ mov bx,(TEXT_START + SECTOR_SIZE) >> 4
+ mov ecx,[ImageDwords]
+ mov edi,[FirstSecSum] ; First sector checksum
+ xor si,si
+
+move_verify_image:
+.setseg:
+ mov ds,ax
+ mov es,bx
+.loop:
+ mov edx,[si]
+ add edi,edx
+ dec ecx
+ mov [es:si],edx
+ jz .done
+ add si,4
+ jnz .loop
+ add ax,1000h
+ add bx,1000h
+ jmp .setseg
+.done:
+ mov ax,cs
+ mov ds,ax
+ mov es,ax
+
+ ; Verify the checksum on the loaded image.
+ cmp [bi_csum],edi
+ je integrity_ok
+
+ mov si,checkerr_msg
+ call writemsg
+ jmp kaboom
+
+integrity_ok:
+%ifdef DEBUG_MESSAGES
+ mov si,allread_msg
+ call writemsg
+%endif
+ jmp all_read ; Jump to main code
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Start of BrokenAwardHack --- 10-nov-2002 Knut_Petersen@t-online.de
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; There is a problem with certain versions of the AWARD BIOS ...
+;; the boot sector will be loaded and executed correctly, but, because the
+;; int 13 vector points to the wrong code in the BIOS, every attempt to
+;; load the spec packet will fail. We scan for the equivalent of
+;;
+;; mov ax,0201h
+;; mov bx,7c00h
+;; mov cx,0006h
+;; mov dx,0180h
+;; pushf
+;; call <direct far>
+;;
+;; and use <direct far> as the new vector for int 13. The code above is
+;; used to load the boot code into ram, and there should be no reason
+;; for anybody to change it now or in the future. There are no opcodes
+;; that use encodings relativ to IP, so scanning is easy. If we find the
+;; code above in the BIOS code we can be pretty sure to run on a machine
+;; with an broken AWARD BIOS ...
+;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ ;;
+%ifdef DEBUG_MESSAGES ;;
+ ;;
+award_notice db "Trying BrokenAwardHack first ...",CR,LF,0 ;;
+award_not_orig db "BAH: Original Int 13 vector : ",0 ;;
+award_not_new db "BAH: Int 13 vector changed to : ",0 ;;
+award_not_succ db "BAH: SUCCESS",CR,LF,0 ;;
+award_not_fail db "BAH: FAILURE" ;;
+award_not_crlf db CR,LF,0 ;;
+ ;;
+%endif ;;
+ ;;
+award_oldint13 dd 0 ;;
+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
+ ;
+%ifdef DEBUG_MESSAGES ;
+ ;
+ mov si,award_notice ; display our plan
+ call writemsg ;
+ mov si,award_not_orig ; display original int 13
+ call writemsg ; vector
+%endif ;
+ mov eax,[13h*4] ;
+ mov [award_oldint13],eax ;
+ ;
+%ifdef DEBUG_MESSAGES ;
+ ;
+ call writehex8 ;
+ mov si,award_not_crlf ;
+ call writestr_early ;
+%endif ;
+ push es ; save ES
+ mov ax,0f000h ; ES = BIOS Seg
+ mov es,ax ;
+ cld ;
+ xor di,di ; start at ES:DI = f000:0
+award_loop: push di ; save DI
+ mov si,award_string ; scan for award_string
+ mov cx,7 ; length of award_string = 7dw
+ repz cmpsw ; compare
+ pop di ; restore DI
+ jcxz award_found ; jmp if found
+ inc di ; not found, inc di
+ jno award_loop ;
+ ;
+award_failed: pop es ; No, not this way :-((
+award_fail2: ;
+ ;
+%ifdef DEBUG_MESSAGES ;
+ ;
+ mov si,award_not_fail ; display failure ...
+ call writemsg ;
+%endif ;
+ mov eax,[award_oldint13] ; restore the original int
+ or eax,eax ; 13 vector if there is one
+ jz spec_query_failed ; and try other workarounds
+ mov [13h*4],eax ;
+ jmp spec_query_failed ;
+ ;
+award_found: mov eax,[es:di+0eh] ; load possible int 13 addr
+ pop es ; restore ES
+ ;
+ cmp eax,[award_oldint13] ; give up if this is the
+ jz award_failed ; active int 13 vector,
+ mov [13h*4],eax ; otherwise change 0:13h*4
+ ;
+ ;
+%ifdef DEBUG_MESSAGES ;
+ ;
+ push eax ; display message and
+ mov si,award_not_new ; new vector address
+ call writemsg ;
+ pop eax ;
+ call writehex8 ;
+ mov si,award_not_crlf ;
+ call writestr_early ;
+%endif ;
+ mov ax,4B01h ; try to read the spec packet
+ mov dl,[DriveNumber] ; now ... it should not fail
+ mov si,spec_packet ; any longer
+ int 13h ;
+ jc award_fail2 ;
+ ;
+%ifdef DEBUG_MESSAGES ;
+ ;
+ mov si,award_not_succ ; display our SUCCESS
+ call writemsg ;
+%endif ;
+ jmp found_drive ; and leave error recovery code
+ ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; End of BrokenAwardHack ---- 10-nov-2002 Knut_Petersen@t-online.de
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+ ; INT 13h, AX=4B01h, DL=<passed in value> failed.
+ ; Try to scan the entire 80h-FFh from the end.
+
+spec_query_failed:
+
+ ; some code moved to BrokenAwardHack
+
+ mov dl,0FFh
+.test_loop: pusha
+ mov ax,4B01h
+ mov si,spec_packet
+ mov byte [si],13h ; Size of buffer
+ call int13
+ popa
+ jc .still_broken
+
+ mov si,maybe_msg
+ call writemsg
+ mov al,dl
+ call writehex2
+ call crlf
+
+ cmp byte [sp_drive],dl
+ jne .maybe_broken
+
+ ; Okay, good enough...
+ mov si,alright_msg
+ call writemsg
+.found_drive0: mov [DriveNumber],dl
+.found_drive: jmp found_drive
+
+ ; Award BIOS 4.51 apparently passes garbage in sp_drive,
+ ; but if this was the drive number originally passed in
+ ; DL then consider it "good enough"
+.maybe_broken:
+ mov al,[DriveNumber]
+ cmp al,dl
+ je .found_drive
+
+ ; Intel Classic R+ computer with Adaptec 1542CP BIOS 1.02
+ ; passes garbage in sp_drive, and the drive number originally
+ ; passed in DL does not have 80h bit set.
+ or al,80h
+ cmp al,dl
+ je .found_drive0
+
+.still_broken: dec dx
+ cmp dl, 80h
+ jnb .test_loop
+
+ ; No spec packet anywhere. Some particularly pathetic
+ ; BIOSes apparently don't even implement function
+ ; 4B01h, so we can't query a spec packet no matter
+ ; what. If we got a drive number in DL, then try to
+ ; use it, and if it works, then well...
+ mov dl,[DriveNumber]
+ cmp dl,81h ; Should be 81-FF at least
+ jb fatal_error ; If not, it's hopeless
+
+ ; Write a warning to indicate we're on *very* thin ice now
+ mov si,nospec_msg
+ call writemsg
+ mov al,dl
+ call writehex2
+ call crlf
+ mov si,trysbm_msg
+ call writemsg
+ jmp .found_drive ; Pray that this works...
+
+fatal_error:
+ mov si,nothing_msg
+ call writemsg
+
+.norge: jmp short .norge
+
+ ; Information message (DS:SI) output
+ ; Prefix with "isolinux: "
+ ;
+writemsg: push ax
+ push si
+ mov si,isolinux_str
+ call writestr_early
+ pop si
+ call writestr_early
+ pop ax
+ ret
+
+;
+; Write a character to the screen. There is a more "sophisticated"
+; version of this in the subsequent code, so we patch the pointer
+; when appropriate.
+;
+
+writechr:
+.simple:
+ pushfd
+ pushad
+ mov ah,0Eh
+ xor bx,bx
+ int 10h
+ popad
+ popfd
+ ret
+
+;
+; int13: save all the segment registers and call INT 13h.
+; Some CD-ROM BIOSes have been found to corrupt segment registers
+; and/or disable interrupts.
+;
+int13:
+ pushf
+ push bp
+ push ds
+ push es
+ push fs
+ push gs
+ int 13h
+ mov bp,sp
+ setc [bp+10] ; Propagate CF to the caller
+ pop gs
+ pop fs
+ pop es
+ pop ds
+ pop bp
+ popf
+ ret
+
+;
+; Get one sector. Convenience entry point.
+;
+getonesec:
+ mov bp,1
+ ; Fall through to getlinsec
+
+;
+; Get linear sectors - EBIOS LBA addressing, 2048-byte sectors.
+;
+; Input:
+; EAX - Linear sector number
+; ES:BX - Target buffer
+; BP - Sector count
+;
+ global getlinsec
+getlinsec: jmp word [cs:GetlinsecPtr]
+
+%ifndef DEBUG_MESSAGES
+
+;
+; First, the variants that we use when actually loading off a disk
+; (hybrid mode.) These are adapted versions of the equivalent routines
+; in ldlinux.asm.
+;
+
+;
+; getlinsec_ebios:
+;
+; getlinsec implementation for floppy/HDD EBIOS (EDD)
+;
+getlinsec_ebios:
+ xor edx,edx
+ shld edx,eax,2
+ shl eax,2 ; Convert to HDD sectors
+ add eax,[Hidden]
+ adc edx,[Hidden+4]
+ shl bp,2
+
+.loop:
+ push bp ; Sectors left
+.retry2:
+ call maxtrans ; Enforce maximum transfer size
+ movzx edi,bp ; Sectors we are about to read
+ mov cx,retry_count
+.retry:
+
+ ; Form DAPA on stack
+ push edx
+ push eax
+ push es
+ push bx
+ push di
+ push word 16
+ mov si,sp
+ pushad
+ mov dl,[DriveNumber]
+ push ds
+ push ss
+ pop ds ; DS <- SS
+ mov ah,42h ; Extended Read
+ call int13
+ pop ds
+ popad
+ lea sp,[si+16] ; Remove DAPA
+ jc .error
+ pop bp
+ add eax,edi ; Advance sector pointer
+ adc edx,0
+ sub bp,di ; Sectors left
+ shl di,9 ; 512-byte sectors
+ add bx,di ; Advance buffer pointer
+ and bp,bp
+ jnz .loop
+
+ ret
+
+.error:
+ ; Some systems seem to get "stuck" in an error state when
+ ; using EBIOS. Doesn't happen when using CBIOS, which is
+ ; good, since some other systems get timeout failures
+ ; waiting for the floppy disk to spin up.
+
+ pushad ; Try resetting the device
+ xor ax,ax
+ mov dl,[DriveNumber]
+ call int13
+ popad
+ loop .retry ; CX-- and jump if not zero
+
+ ;shr word [MaxTransfer],1 ; Reduce the transfer size
+ ;jnz .retry2
+
+ ; Total failure. Try falling back to CBIOS.
+ mov word [GetlinsecPtr], getlinsec_cbios
+ ;mov byte [MaxTransfer],63 ; Max possibe CBIOS transfer
+
+ pop bp
+ jmp getlinsec_cbios.loop
+
+;
+; getlinsec_cbios:
+;
+; getlinsec implementation for legacy CBIOS
+;
+getlinsec_cbios:
+ xor edx,edx
+ shl eax,2 ; Convert to HDD sectors
+ add eax,[Hidden]
+ shl bp,2
+
+.loop:
+ push edx
+ push eax
+ push bp
+ push bx
+
+ movzx esi,word [bsSecPerTrack]
+ movzx edi,word [bsHeads]
+ ;
+ ; Dividing by sectors to get (track,sector): we may have
+ ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
+ ;
+ div esi
+ xor cx,cx
+ xchg cx,dx ; CX <- sector index (0-based)
+ ; EDX <- 0
+ ; eax = track #
+ div edi ; Convert track to head/cyl
+
+ ; We should test this, but it doesn't fit...
+ ; cmp eax,1023
+ ; ja .error
+
+ ;
+ ; Now we have AX = cyl, DX = head, CX = sector (0-based),
+ ; BP = sectors to transfer, SI = bsSecPerTrack,
+ ; ES:BX = data target
+ ;
+
+ call maxtrans ; Enforce maximum transfer size
+
+ ; Must not cross track boundaries, so BP <= SI-CX
+ sub si,cx
+ cmp bp,si
+ jna .bp_ok
+ mov bp,si
+.bp_ok:
+
+ shl ah,6 ; Because IBM was STOOPID
+ ; and thought 8 bits were enough
+ ; then thought 10 bits were enough...
+ inc cx ; Sector numbers are 1-based, sigh
+ or cl,ah
+ mov ch,al
+ mov dh,dl
+ mov dl,[DriveNumber]
+ xchg ax,bp ; Sector to transfer count
+ mov ah,02h ; Read sectors
+ mov bp,retry_count
+.retry:
+ pushad
+ call int13
+ popad
+ jc .error
+.resume:
+ movzx ecx,al ; ECX <- sectors transferred
+ shl ax,9 ; Convert sectors in AL to bytes in AX
+ pop bx
+ add bx,ax
+ pop bp
+ pop eax
+ pop edx
+ add eax,ecx
+ sub bp,cx
+ jnz .loop
+ ret
+
+.error:
+ dec bp
+ jnz .retry
+
+ xchg ax,bp ; Sectors transferred <- 0
+ shr word [MaxTransfer],1
+ jnz .resume
+ jmp disk_error
+
+;
+; Truncate BP to MaxTransfer
+;
+maxtrans:
+ cmp bp,[MaxTransfer]
+ jna .ok
+ mov bp,[MaxTransfer]
+.ok: ret
+
+%endif
+
+;
+; This is the variant we use for real CD-ROMs:
+; LBA, 2K sectors, some special error handling.
+;
+getlinsec_cdrom:
+ mov si,dapa ; Load up the DAPA
+ mov [si+4],bx
+ mov [si+6],es
+ mov [si+8],eax
+.loop:
+ push bp ; Sectors left
+ cmp bp,[MaxTransferCD]
+ jbe .bp_ok
+ mov bp,[MaxTransferCD]
+.bp_ok:
+ mov [si+2],bp
+ push si
+ mov dl,[DriveNumber]
+ mov ah,42h ; Extended Read
+ call xint13
+ pop si
+ pop bp
+ movzx eax,word [si+2] ; Sectors we read
+ add [si+8],eax ; Advance sector pointer
+ sub bp,ax ; Sectors left
+ shl ax,SECTOR_SHIFT-4 ; 2048-byte sectors -> segment
+ add [si+6],ax ; Advance buffer pointer
+ and bp,bp
+ jnz .loop
+ mov eax,[si+8] ; Next sector
+ ret
+
+ ; INT 13h with retry
+xint13: mov byte [RetryCount],retry_count
+.try: pushad
+ call int13
+ jc .error
+ add sp,byte 8*4 ; Clean up stack
+ ret
+.error:
+ mov [DiskError],ah ; Save error code
+ popad
+ mov [DiskSys],ax ; Save system call number
+ dec byte [RetryCount]
+ jz .real_error
+ push ax
+ mov al,[RetryCount]
+ mov ah,[dapa+2] ; Sector transfer count
+ cmp al,2 ; Only 2 attempts left
+ ja .nodanger
+ mov ah,1 ; Drop transfer size to 1
+ jmp short .setsize
+.nodanger:
+ cmp al,retry_count-2
+ ja .again ; First time, just try again
+ shr ah,1 ; Otherwise, try to reduce
+ adc ah,0 ; the max transfer size, but not to 0
+.setsize:
+ mov [MaxTransferCD],ah
+ mov [dapa+2],ah
+.again:
+ pop ax
+ jmp .try
+
+.real_error: mov si,diskerr_msg
+ call writemsg
+ mov al,[DiskError]
+ call writehex2
+ mov si,oncall_str
+ call writestr_early
+ mov ax,[DiskSys]
+ call writehex4
+ mov si,ondrive_str
+ call writestr_early
+ mov al,dl
+ call writehex2
+ call crlf
+ ; Fall through to kaboom
+
+;
+; kaboom: write a message and bail out. Wait for a user keypress,
+; then do a hard reboot.
+;
+ global kaboom
+disk_error:
+kaboom:
+ RESET_STACK_AND_SEGS AX
+ mov si,err_bootfailed
+ call writestr
+ call getchar
+ cli
+ mov word [BIOS_magic],0 ; Cold reboot
+ jmp 0F000h:0FFF0h ; Reset vector address
+
+; -----------------------------------------------------------------------------
+; Common modules needed in the first sector
+; -----------------------------------------------------------------------------
+
+%include "writestr.inc" ; String output
+writestr_early equ writestr
+%include "writehex.inc" ; Hexadecimal output
+
+; -----------------------------------------------------------------------------
+; Data that needs to be in the first sector
+; -----------------------------------------------------------------------------
+
+syslinux_banner db CR, LF, MY_NAME, ' ', VERSION_STR, ' ', DATE_STR, ' ', 0
+copyright_str db ' Copyright (C) 1994-'
+ asciidec YEAR
+ db ' H. Peter Anvin et al', CR, LF, 0
+isolinux_str db 'isolinux: ', 0
+%ifdef DEBUG_MESSAGES
+startup_msg: db 'Starting up, DL = ', 0
+spec_ok_msg: db 'Loaded spec packet OK, drive = ', 0
+secsize_msg: db 'Sector size ', 0
+offset_msg: db 'Main image LBA = ', 0
+verify_msg: db 'Image checksum verified.', CR, LF, 0
+allread_msg db 'Main image read, jumping to main code...', CR, LF, 0
+%endif
+noinfotable_msg db 'No boot info table, assuming single session disk...', CR, LF, 0
+noinfoinspec_msg db 'Spec packet missing LBA information, trying to wing it...', CR, LF, 0
+spec_err_msg: db 'Loading spec packet failed, trying to wing it...', CR, LF, 0
+maybe_msg: db 'Found something at drive = ', 0
+alright_msg: db 'Looks reasonable, continuing...', CR, LF, 0
+nospec_msg db 'Extremely broken BIOS detected, last attempt with drive = ', 0
+nothing_msg: db 'Failed to locate CD-ROM device; boot failed.', CR, LF
+trysbm_msg db 'See http://syslinux.zytor.com/sbm for more information.', CR, LF, 0
+diskerr_msg: db 'Disk error ', 0
+oncall_str: db ', AX = ',0
+ondrive_str: db ', drive ', 0
+checkerr_msg: db 'Image checksum error, sorry...', CR, LF, 0
+
+err_bootfailed db CR, LF, 'Boot failed: press a key to retry...'
+bailmsg equ err_bootfailed
+crlf_msg db CR, LF
+null_msg db 0
+
+bios_cdrom_str db 'ETCD', 0
+%ifndef DEBUG_MESSAGES
+bios_cbios_str db 'CHDD', 0
+bios_ebios_str db 'EHDD' ,0
+%endif
+
+ alignz 4
+bios_cdrom: dw getlinsec_cdrom, bios_cdrom_str
+%ifndef DEBUG_MESSAGES
+bios_cbios: dw getlinsec_cbios, bios_cbios_str
+bios_ebios: dw getlinsec_ebios, bios_ebios_str
+%endif
+
+; Maximum transfer size
+MaxTransfer dw 127 ; Hard disk modes
+MaxTransferCD dw 32 ; CD mode
+
+rl_checkpt equ $ ; Must be <= 800h
+
+ ; This pads to the end of sector 0 and errors out on
+ ; overflow.
+ times 2048-($-$$) db 0
+
+; ----------------------------------------------------------------------------
+; End of code and data that have to be in the first sector
+; ----------------------------------------------------------------------------
+
+ section .text16
+
+all_read:
+
+; Test tracers
+ TRACER 'T'
+ TRACER '>'
+
+;
+; Common initialization code
+;
+%include "init.inc"
+
+ ; Patch the writechr routine to point to the full code
+ mov di,writechr
+ mov al,0e9h
+ stosb
+ mov ax,writechr_full-2
+ sub ax,di
+ stosw
+
+; Tell the user we got this far...
+%ifndef DEBUG_MESSAGES ; Gets messy with debugging on
+ mov si,copyright_str
+ call writestr_early
+%endif
+
+;
+; Now we're all set to start with our *real* business. First load the
+; configuration file (if any) and parse it.
+;
+; In previous versions I avoided using 32-bit registers because of a
+; rumour some BIOSes clobbered the upper half of 32-bit registers at
+; random. I figure, though, that if there are any of those still left
+; they probably won't be trying to install Linux on them...
+;
+; The code is still ripe with 16-bitisms, though. Not worth the hassle
+; to take'm out. In fact, we may want to put them back if we're going
+; to boot ELKS at some point.
+;
+
+;
+; Now, we need to sniff out the actual filesystem data structures.
+; mkisofs gave us a pointer to the primary volume descriptor
+; (which will be at 16 only for a single-session disk!); from the PVD
+; we should be able to find the rest of what we need to know.
+;
+init_fs:
+ pushad
+ mov eax,ROOT_FS_OPS
+ mov dl,[DriveNumber]
+ cmp word [BIOSType],bios_cdrom
+ sete dh ; 1 for cdrom, 0 for hybrid mode
+ jne .hybrid
+ movzx ebp,word [MaxTransferCD]
+ jmp .common
+.hybrid:
+ movzx ebp,word [MaxTransfer]
+.common:
+ mov ecx,[Hidden]
+ mov ebx,[Hidden+4]
+ mov si,[bsHeads]
+ mov di,[bsSecPerTrack]
+ pm_call fs_init
+ popad
+
+ section .rodata
+ alignz 4
+ROOT_FS_OPS:
+ extern iso_fs_ops
+ dd iso_fs_ops
+ dd 0
+
+ section .text16
+
+;
+; Locate the configuration file
+;
+ pm_call load_config
+
+;
+; Now we have the config file open. Parse the config file and
+; run the user interface.
+;
+%include "ui.inc"
+
+;
+; Enable disk emulation. The kind of disk we emulate is dependent on the
+; size of the file: 1200K, 1440K or 2880K floppy, otherwise harddisk.
+;
+is_disk_image:
+ TRACER CR
+ TRACER LF
+ TRACER 'D'
+ TRACER ':'
+
+ mov edx,eax ; File size
+ mov di,img_table
+ mov cx,img_table_count
+ mov eax,[si+file_sector] ; Starting LBA of file
+ mov [dsp_lba],eax ; Location of file
+ mov byte [dsp_drive], 0 ; 00h floppy, 80h hard disk
+.search_table:
+ TRACER 't'
+ mov eax,[di+4]
+ cmp edx,[di]
+ je .type_found
+ add di,8
+ loop .search_table
+
+ ; Hard disk image. Need to examine the partition table
+ ; in order to deduce the C/H/S geometry. Sigh.
+.hard_disk_image:
+ TRACER 'h'
+ cmp edx,512
+ jb .bad_image
+
+ mov bx,trackbuf
+ mov cx,1 ; Load 1 sector
+ pm_call getfssec
+
+ cmp word [trackbuf+510],0aa55h ; Boot signature
+ jne .bad_image ; Image not bootable
+
+ mov cx,4 ; 4 partition entries
+ mov di,trackbuf+446 ; Start of partition table
+
+ xor ax,ax ; Highest sector(al) head(ah)
+
+.part_scan:
+ cmp byte [di+4], 0
+ jz .part_loop
+ lea si,[di+1]
+ call .hs_check
+ add si,byte 4
+ call .hs_check
+.part_loop:
+ add di,byte 16
+ loop .part_scan
+
+ push eax ; H/S
+ push edx ; File size
+ mov bl,ah
+ xor bh,bh
+ inc bx ; # of heads in BX
+ xor ah,ah ; # of sectors in AX
+ cwde ; EAX[31:16] <- 0
+ mul bx
+ shl eax,9 ; Convert to bytes
+ ; Now eax contains the number of bytes per cylinder
+ pop ebx ; File size
+ xor edx,edx
+ div ebx
+ and edx,edx
+ jz .no_remainder
+ inc eax ; Fractional cylinder...
+ ; Now (e)ax contains the number of cylinders
+.no_remainder: cmp eax,1024
+ jna .ok_cyl
+ mov ax,1024 ; Max possible #
+.ok_cyl: dec ax ; Convert to max cylinder no
+ pop ebx ; S(bl) H(bh)
+ shl ah,6
+ or bl,ah
+ xchg ax,bx
+ shl eax,16
+ mov ah,bl
+ mov al,4 ; Hard disk boot
+ mov byte [dsp_drive], 80h ; Drive 80h = hard disk
+
+.type_found:
+ TRACER 'T'
+ mov bl,[sp_media]
+ and bl,0F0h ; Copy controller info bits
+ or al,bl
+ mov [dsp_media],al ; Emulation type
+ shr eax,8
+ mov [dsp_chs],eax ; C/H/S geometry
+ mov ax,[sp_devspec] ; Copy device spec
+ mov [dsp_devspec],ax
+ mov al,[sp_controller] ; Copy controller index
+ mov [dsp_controller],al
+
+ TRACER 'V'
+ call vgaclearmode ; Reset video
+
+ mov ax,4C00h ; Enable emulation and boot
+ mov si,dspec_packet
+ mov dl,[DriveNumber]
+ lss sp,[InitStack]
+ TRACER 'X'
+
+ call int13
+
+ ; If this returns, we have problems
+.bad_image:
+ mov si,err_disk_image
+ call writestr
+ jmp enter_command
+
+;
+; Look for the highest seen H/S geometry
+; We compute cylinders separately
+;
+.hs_check:
+ mov bl,[si] ; Head #
+ cmp bl,ah
+ jna .done_track
+ mov ah,bl ; New highest head #
+.done_track: mov bl,[si+1]
+ and bl,3Fh ; Sector #
+ cmp bl,al
+ jna .done_sector
+ mov al,bl
+.done_sector: ret
+
+
+
+; -----------------------------------------------------------------------------
+; Common modules
+; -----------------------------------------------------------------------------
+
+%include "common.inc" ; Universal modules
+%include "rawcon.inc" ; Console I/O w/o using the console functions
+%include "localboot.inc" ; Disk-based local boot
+
+; -----------------------------------------------------------------------------
+; Begin data section
+; -----------------------------------------------------------------------------
+
+ section .data16
+err_disk_image db 'Cannot load disk image (invalid file)?', CR, LF, 0
+
+;
+; Config file keyword table
+;
+%include "keywords.inc"
+
+;
+; Extensions to search for (in *forward* order).
+;
+ alignz 4
+exten_table: db '.cbt' ; COMBOOT (specific)
+ db '.img' ; Disk image
+ db '.bin' ; CD boot sector
+ db '.com' ; COMBOOT (same as DOS)
+ db '.c32' ; COM32
+exten_table_end:
+ dd 0, 0 ; Need 8 null bytes here
+
+;
+; Floppy image table
+;
+ alignz 4
+img_table_count equ 3
+img_table:
+ dd 1200*1024 ; 1200K floppy
+ db 1 ; Emulation type
+ db 80-1 ; Max cylinder
+ db 15 ; Max sector
+ db 2-1 ; Max head
+
+ dd 1440*1024 ; 1440K floppy
+ db 2 ; Emulation type
+ db 80-1 ; Max cylinder
+ db 18 ; Max sector
+ db 2-1 ; Max head
+
+ dd 2880*1024 ; 2880K floppy
+ db 3 ; Emulation type
+ db 80-1 ; Max cylinder
+ db 36 ; Max sector
+ db 2-1 ; Max head
diff --git a/contrib/syslinux-4.02/core/kaboom.c b/contrib/syslinux-4.02/core/kaboom.c
new file mode 100644
index 0000000..d639915
--- /dev/null
+++ b/contrib/syslinux-4.02/core/kaboom.c
@@ -0,0 +1,16 @@
+/*
+ * kaboom.c
+ */
+
+#include "core.h"
+
+#undef kaboom
+
+__noreturn _kaboom(void)
+{
+ extern void kaboom(void);
+ call16(kaboom, &zero_regs, NULL);
+ /* Do this if kaboom somehow returns... */
+ for (;;)
+ asm volatile("hlt");
+}
diff --git a/contrib/syslinux-4.02/core/kernel.inc b/contrib/syslinux-4.02/core/kernel.inc
new file mode 100644
index 0000000..245cd6d
--- /dev/null
+++ b/contrib/syslinux-4.02/core/kernel.inc
@@ -0,0 +1,118 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1994-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., 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.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; kernel.inc
+;;
+;; Header file for the kernel interface definitions
+;;
+
+%ifndef _KERNEL_INC
+%define _KERNEL_INC
+
+;;
+;; Structure of the real_mode_seg
+;;
+
+ struc real_mode_seg_t
+ resb 20h-($-$$) ; org 20h
+kern_cmd_magic resw 1 ; 0020 Magic # for command line
+kern_cmd_offset resw 1 ; 0022 Offset for kernel command line
+ resb 497-($-$$) ; org 497d
+bs_setupsecs resb 1 ; 01F1 Sectors for setup code (0 -> 4)
+bs_rootflags resw 1 ; 01F2 Root readonly flag
+bs_syssize resw 1 ; 01F4
+bs_swapdev resw 1 ; 01F6 Swap device (obsolete)
+bs_ramsize resw 1 ; 01F8 Ramdisk flags, formerly ramdisk size
+bs_vidmode resw 1 ; 01FA Video mode
+bs_rootdev resw 1 ; 01FC Root device
+bs_bootsign resw 1 ; 01FE Boot sector signature (0AA55h)
+su_jump resb 1 ; 0200 0EBh
+su_jump2 resb 1 ; 0201 Size of following header
+su_header resd 1 ; 0202 New setup code: header
+su_version resw 1 ; 0206 See linux/arch/i386/boot/setup.S
+su_switch resw 1 ; 0208
+su_setupseg resw 1 ; 020A
+su_startsys resw 1 ; 020C
+su_kver resw 1 ; 020E Kernel version pointer
+su_loader resb 1 ; 0210 Loader ID
+su_loadflags resb 1 ; 0211 Load high flag
+su_movesize resw 1 ; 0212
+su_code32start resd 1 ; 0214 Start of code loaded high
+su_ramdiskat resd 1 ; 0218 Start of initial ramdisk
+su_ramdisklen resd 1 ; 021C Length of initial ramdisk
+su_bsklugeoffs resw 1 ; 0220
+su_bsklugeseg resw 1 ; 0222
+su_heapend resw 1 ; 0224
+su_pad1 resw 1 ; 0226
+su_cmd_line_ptr resd 1 ; 0228
+su_ramdisk_max resd 1 ; 022C
+ resb (0f800h-12)-($-$$)
+linux_stack equ $ ; F7F4
+linux_fdctab resb 12
+cmd_line_here equ $ ; F800 Should be out of the way
+ endstruc
+
+ global cmd_line
+cmd_line equ core_real_mode + cmd_line_here
+
+;
+; Old kernel command line signature
+;
+CMD_MAGIC equ 0A33Fh ; Command line magic
+
+;
+; If we're loading the command line old-style, we need a smaller
+; heap.
+;
+old_cmd_line_here equ 9800h
+old_max_cmd_len equ 2047
+old_linux_fdctab equ old_cmd_line_here-12
+old_linux_stack equ old_linux_fdctab
+
+;
+; Magic number of su_header field
+;
+HEADER_ID equ 'HdrS' ; HdrS (in littleendian hex)
+
+;
+; Flags for the su_loadflags field
+;
+LOAD_HIGH equ 01h ; Large kernel, load high
+QUIET_FLAG equ 20h ; Quiet the kernel
+KEEP_SEGMENTS equ 40h ; Don't reload segments
+CAN_USE_HEAP equ 80h ; Boot loader reports heap size
+
+;
+; ID codes for various modules
+;
+syslinux_id equ 031h ; 3 = SYSLINUX family; 1 = SYSLINUX
+pxelinux_id equ 032h ; 3 = SYSLINUX family; 2 = PXELINUX
+isolinux_id equ 033h ; 3 = SYSLINUX family; 3 = ISOLINUX
+extlinux_id equ 034h ; 3 = SYSLINUX family; 4 = EXTLINUX
+
+;
+; Types of vkernels
+;
+VK_LOCALBOOT equ -1 ; localboot (no actual kernel loaded)
+VK_KERNEL equ 0 ; Choose by filename
+VK_LINUX equ 1 ; Linux kernel image
+VK_BOOT equ 2 ; Boot sector
+VK_BSS equ 3 ; BSS boot sector
+VK_PXE equ 4 ; PXE NBP
+VK_FDIMAGE equ 5 ; Floppy disk image
+VK_COMBOOT equ 6 ; COMBOOT image
+VK_COM32 equ 7 ; COM32 image
+VK_CONFIG equ 8 ; Configuration file
+VK_TYPES equ 9 ; Number of VK types
+
+%endif ; _KERNEL_INC
diff --git a/contrib/syslinux-4.02/core/keywords b/contrib/syslinux-4.02/core/keywords
new file mode 100644
index 0000000..c289ae2
--- /dev/null
+++ b/contrib/syslinux-4.02/core/keywords
@@ -0,0 +1,48 @@
+menu
+text
+include
+append
+initrd
+config
+default
+ui
+display
+font
+implicit
+ipappend
+kbdmap
+kernel
+linux
+boot
+bss
+pxe
+fdimage
+comboot
+com32
+label
+localboot
+prompt
+say
+serial
+console
+timeout
+totaltimeout
+allowoptions
+ontimeout
+onerror
+noescape
+nocomplete
+nohalt
+f0
+f1
+f2
+f3
+f4
+f5
+f6
+f7
+f8
+f9
+f10
+f11
+f12
diff --git a/contrib/syslinux-4.02/core/keywords.inc b/contrib/syslinux-4.02/core/keywords.inc
new file mode 100644
index 0000000..d0f7db3
--- /dev/null
+++ b/contrib/syslinux-4.02/core/keywords.inc
@@ -0,0 +1,101 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1994-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., 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.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; keywords.inc
+;;
+;; Common header file for the handling of keyword hash and macros
+;;
+
+%ifndef DEPEND ; Generated file
+%include "kwdhash.gen"
+%endif
+
+%macro keyword 2
+ dd hash_%1 ; Hash value
+ dw 0 ; No argument
+ dw %2 ; Entrypoint
+%endmacro
+
+%macro keyword 3
+ dd hash_%1 ; Hash value
+ dw %3 ; 16-bit argument
+ dw %2 ; Entrypoint
+%endmacro
+
+%macro keyword 4
+ dd hash_%1 ; Hash value
+ db %3, %4 ; 2 8-bit arguments
+ dw %2 ; Entrypoint
+%endmacro
+
+keywd_size equ 8 ; Bytes per keyword
+
+ alignz 4
+
+%define FKeyN(n) (FKeyName+(((n)-1) << FILENAME_MAX_LG2))
+
+keywd_table:
+ keyword menu, pc_comment
+ keyword text, pc_text
+ keyword include, pc_opencmd, pc_include
+ keyword append, pc_append
+ keyword initrd, pc_filename, InitRD
+ keyword default, pc_default, 1
+ keyword ui, pc_default, 2
+ keyword display, pc_opencmd, get_msg_file
+ keyword font, pc_opencmd, loadfont
+ keyword implicit, pc_setint16, AllowImplicit
+ keyword kbdmap, pc_opencmd, loadkeys
+ keyword kernel, pc_kernel, VK_KERNEL
+ keyword linux, pc_kernel, VK_LINUX
+ keyword boot, pc_kernel, VK_BOOT
+ keyword bss, pc_kernel, VK_BSS
+ keyword pxe, pc_kernel, VK_PXE
+ keyword fdimage, pc_kernel, VK_FDIMAGE
+ keyword comboot, pc_kernel, VK_COMBOOT
+ keyword com32, pc_kernel, VK_COM32
+ keyword config, pc_kernel, VK_CONFIG
+ keyword label, pc_label
+ keyword prompt, pc_setint16, ForcePrompt
+ keyword say, pc_say
+ keyword serial, pc_serial
+ keyword console, pc_setint16, DisplayCon
+ keyword timeout, pc_timeout, KbdTimeout
+ keyword totaltimeout, pc_timeout, TotalTimeout
+ keyword ontimeout, pc_ontimeout
+ keyword onerror, pc_onerror
+ keyword allowoptions, pc_setint16, AllowOptions
+ keyword noescape, pc_setint16, NoEscape
+ keyword nocomplete, pc_setint16, NoComplete
+ keyword nohalt, pc_setint16, NoHalt
+ keyword f1, pc_filename, FKeyN(1)
+ keyword f2, pc_filename, FKeyN(2)
+ keyword f3, pc_filename, FKeyN(3)
+ keyword f4, pc_filename, FKeyN(4)
+ keyword f5, pc_filename, FKeyN(5)
+ keyword f6, pc_filename, FKeyN(6)
+ keyword f7, pc_filename, FKeyN(7)
+ keyword f8, pc_filename, FKeyN(8)
+ keyword f9, pc_filename, FKeyN(9)
+ keyword f10, pc_filename, FKeyN(10)
+ keyword f0, pc_filename, FKeyN(10)
+ keyword f11, pc_filename, FKeyN(11)
+ keyword f12, pc_filename, FKeyN(12)
+%if IS_PXELINUX
+ keyword ipappend, pc_ipappend
+%endif
+%if HAS_LOCALBOOT
+ keyword localboot, pc_localboot
+%endif
+
+keywd_count equ ($-keywd_table)/keywd_size
diff --git a/contrib/syslinux-4.02/core/layout.inc b/contrib/syslinux-4.02/core/layout.inc
new file mode 100644
index 0000000..dab27dd
--- /dev/null
+++ b/contrib/syslinux-4.02/core/layout.inc
@@ -0,0 +1,171 @@
+; -----------------------------------------------------------------------
+;
+; 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,
+; Bostom MA 02111-1307, USA; either version 2 of the License, or
+; (at your option) any later version; incorporated herein by reference.
+;
+; -----------------------------------------------------------------------
+
+;
+; layout.inc
+;
+; Memory layout of segments
+;
+
+ ; Default to 16-bit code
+ bits 16
+
+; Memory below 0800h is reserved for the BIOS and the MBR.
+BSS_START equ 0800h
+
+; Text starts at the load address of 07C00h.
+TEXT_START equ 7C00h
+
+;
+; 16-bit stack layout
+;
+; PXELINUX: There are apparently some AMI BIOSes in the field which
+; put their BEV stack somewhere below 7C00h (and therefore don't
+; handle localboot properly), so avoid that immediate memory region.
+; The range that is known to be bad is approximately 75E8..7C00; the
+; lower bound is tight.
+;
+ global STACK_LEN, STACK_TOP, STACK_BASE
+STACK_LEN equ 4096
+%if IS_PXELINUX
+STACK_TOP equ 7000h
+%else
+STACK_TOP equ 7c00h
+%endif
+STACK_BASE equ STACK_TOP - STACK_LEN
+
+; The secondary BSS section, above the text; we really wish we could
+; just make it follow .bcopy32 or hang off the end,
+; but it doesn't seem to work that way.
+LATEBSS_START equ 0B800h
+
+;
+; 32-bit stack layout
+;
+ global STACK32_LEN
+STACK32_LEN equ 64*1024
+
+ section .stack nobits write align=4096
+ resb STACK32_LEN
+
+;
+; The various sections and their relationship
+;
+ ; Use .earlybss for things that MUST be in low memory.
+ section .earlybss nobits write
+ section .config write progbits align=4
+ section .replacestub exec write progbits align=16
+ section .gentextnr exec write nobits align=16
+
+ ; Use .bss16 for things that doesn't have to be in low memory;
+ ; .earlybss should be used for things that absolutely have
+ ; to be below 0x7c00.
+ section .bss16 write nobits align=16
+
+%if 0 ; IS_PXELINUX
+ ; Warning here: RBFG build 22 randomly overwrites
+ ; memory location [0x5680,0x576c), possibly more. It
+ ; seems that it gets confused and screws up the
+ ; pointer to its own internal packet buffer and starts
+ ; writing a received ARP packet into low memory.
+ section .rbfg write nobits
+RBFG_brainfuck: resb 2048 ; Bigger than an Ethernet packet...
+%endif
+
+ section .init exec write progbits align=1
+ section .text16 exec write progbits align=1
+ section .textnr exec nowrite progbits align=1
+ section .bcopyxx.text exec nowrite progbits align=16
+ section .bcopyxx.data noexec write progbits align=16
+ section .data16 noexec write progbits align=16
+
+ section .adv write nobits align=512
+
+ ; .uibss contains bss data which is guaranteed to be
+ ; safe to clobber during the loading of the image. This
+ ; is because while loading the primary image we will clobber
+ ; the spillover from the last fractional sector load.
+ section .uibss write nobits align=16
+
+ ; Symbols from linker script
+%macro SECINFO 1
+ extern __%1_start, __%1_lma, __%1_end
+ extern __%1_len, __%1_dwords
+%endmacro
+ SECINFO bss16
+ SECINFO uibss
+ SECINFO config
+ SECINFO replacestub
+ SECINFO bcopyxx
+
+ SECINFO pm_code
+ SECINFO high_clear
+
+ SECINFO bss
+
+ extern free_high_memory
+
+ global _start
+
+ section .text16
+
+;
+; Segment assignments in the bottom 640K
+; Keep the low-memory footprint as small as possible... overrun is a hard
+; failure!
+;
+
+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
+;
+ extern xfer_buf_seg
+ section .xfer_buf write nobits align=65536
+ global core_xfer_buf
+core_xfer_buf resb 65536
+
+;
+; Segment for the real mode code (needed as long as we have a in-kernel
+; loader and/or COM16 support.
+; One symbol for the segment number, one for the absolute address
+;
+ extern real_mode_seg
+ section .real_mode write nobits align=65536
+ global core_real_mode
+core_real_mode resb 65536
+comboot_seg equ real_mode_seg ; COMBOOT image loading zone
+
+;
+; At the very end, the lowmem heap
+;
+ extern __lowmem_heap
+min_lowmem_heap equ 65536
+
+ section .text16
diff --git a/contrib/syslinux-4.02/core/ldlinux.asm b/contrib/syslinux-4.02/core/ldlinux.asm
new file mode 100644
index 0000000..f62f55b
--- /dev/null
+++ b/contrib/syslinux-4.02/core/ldlinux.asm
@@ -0,0 +1,44 @@
+; -*- fundamental -*- (asm-mode sucks)
+; ****************************************************************************
+;
+; ldlinux.asm
+;
+; A program to boot Linux kernels off an MS-DOS formatted floppy disk. This
+; functionality is good to have for installation floppies, where it may
+; be hard to find a functional Linux system to run LILO off.
+;
+; This program allows manipulation of the disk to take place entirely
+; from MS-LOSS, and can be especially useful in conjunction with the
+; umsdos filesystem.
+;
+; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
+; Copyright 2009 Intel Corporation; author: H. Peter Anvin
+;
+; This program is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+; Boston MA 02111-1307, USA; either version 2 of the License, or
+; (at your option) any later version; incorporated herein by reference.
+;
+; ****************************************************************************
+
+%define IS_SYSLINUX 1
+%include "head.inc"
+
+;
+; Some semi-configurable constants... change on your own risk.
+;
+my_id equ syslinux_id
+
+ section .rodata
+ alignz 4
+ROOT_FS_OPS:
+ extern vfat_fs_ops
+ dd vfat_fs_ops
+ extern ext2_fs_ops
+ dd ext2_fs_ops
+ extern btrfs_fs_ops
+ dd btrfs_fs_ops
+ dd 0
+
+%include "diskfs.inc"
diff --git a/contrib/syslinux-4.02/core/loadhigh.inc b/contrib/syslinux-4.02/core/loadhigh.inc
new file mode 100644
index 0000000..89de5e8
--- /dev/null
+++ b/contrib/syslinux-4.02/core/loadhigh.inc
@@ -0,0 +1,60 @@
+;; -----------------------------------------------------------------------
+;;
+;; 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.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; loadhigh.inc
+;;
+;; Load a file into high memory
+;;
+
+ section .text16
+
+;
+; load_high: loads (the remainder of) a file into high memory.
+;
+; Assumes CS == DS.
+;
+; Inputs: SI = file handle/cluster pointer
+; EDI = target address in high memory
+; EAX = maximum number of bytes to load
+; DX = zero-padding mask (e.g. 0003h for pad to dword)
+; BX = subroutine to call at the top of each loop
+; (to print status and check for abort)
+; [MyHighMemSize] = maximum load address
+;
+; Outputs: SI = file handle/cluster pointer
+; EBX = first untouched address (not including padding)
+; EDI = first untouched address (including padding)
+; CF = reached EOF
+;
+ extern pm_load_high
+load_high:
+ push ebp
+ mov ebp,[MyHighMemSize]
+ pm_call pm_load_high
+ pop ebp
+ jo .overflow
+ ret
+
+.overflow: mov si,err_nohighmem
+ jmp abort_load
+
+ section .data16
+err_nohighmem db CR, LF
+ db 'Not enough memory to load specified image.', CR, LF, 0
+
+ section .bss16
+ alignb 2
+PauseBird resw 1
+
+ section .text16
diff --git a/contrib/syslinux-4.02/core/localboot.inc b/contrib/syslinux-4.02/core/localboot.inc
new file mode 100644
index 0000000..a66cf20
--- /dev/null
+++ b/contrib/syslinux-4.02/core/localboot.inc
@@ -0,0 +1,76 @@
+; -----------------------------------------------------------------------
+;
+; Copyright 1999-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.
+;
+; -----------------------------------------------------------------------
+
+;
+; localboot.inc
+;
+; Boot from a local disk, or invoke INT 18h.
+;
+
+%if HAS_LOCALBOOT
+
+;
+; Boot a specified local disk. AX specifies the BIOS disk number; or
+; -1 in case we should execute INT 18h ("next device.")
+;
+ section .text16
+
+local_boot:
+ call vgaclearmode
+ RESET_STACK_AND_SEGS dx ; dx <- 0
+ mov fs,dx
+ mov gs,dx
+ mov si,localboot_msg
+ call writestr
+ call cleanup_hardware
+ cmp ax,-1
+ je .int18
+
+ ; Load boot sector from the specified BIOS device and jump to it.
+ mov dl,al
+ xor dh,dh
+ push dx
+ xor ax,ax ; Reset drive
+ int 13h
+ mov ax,0201h ; Read one sector
+ mov cx,0001h ; C/H/S = 0/0/1 (first sector)
+ mov bx,trackbuf
+ mov bp,retry_count
+.again:
+ pusha
+ int 13h
+ popa
+ jnc .ok
+ dec bp
+ jnz .again
+ jmp kaboom ; Failure...
+.ok:
+ pop dx
+ cli ; Abandon hope, ye who enter here
+ mov si,trackbuf
+ mov di,07C00h
+ mov cx,512 ; Probably overkill, but should be safe
+ rep movsd
+ mov ss,cx ; SS <- 0
+ mov sp,7C00h
+ jmp 0:07C00h ; Jump to new boot sector
+
+.int18:
+ int 18h ; Hope this does the right thing...
+ jmp kaboom ; If we returned, oh boy...
+
+ section .data16
+localboot_msg db 'Booting from local disk...', CR, LF, 0
+
+ section .text16
+
+%endif ; HAS_LOCALBOOT
diff --git a/contrib/syslinux-4.02/core/lstadjust.pl b/contrib/syslinux-4.02/core/lstadjust.pl
new file mode 100755
index 0000000..cec5402
--- /dev/null
+++ b/contrib/syslinux-4.02/core/lstadjust.pl
@@ -0,0 +1,57 @@
+#!/usr/bin/perl
+#
+# Take a NASM list and map file and make the offsets in the list file
+# absolute. This makes debugging a lot easier.
+#
+# Usage:
+#
+# lstadjust.pl listfile mapfile outfile
+#
+
+($listfile, $mapfile, $outfile) = @ARGV;
+
+open(LST, "< $listfile\0")
+ or die "$0: cannot open: $listfile: $!\n";
+open(MAP, "< $mapfile\0")
+ or die "$0: cannot open: $mapfile: $!\n";
+open(OUT, "> $outfile\0")
+ or die "$0: cannot create: $outfile: $!\n";
+
+%vstart = ();
+
+while (defined($line = <MAP>)) {
+ if ($line =~ /^\s*([0-9]+)\s+(\S+)\s+([0-9a-f]+)\s+([0-9a-f]+)\s+([0-9a-f]+)\s+([0-9a-f]+)\s+2\*\*([0-9]+)/i) {
+ $vstart{$2} = hex $4;
+ }
+}
+close(MAP);
+
+$offset = 0;
+@ostack = ();
+
+while (defined($line = <LST>)) {
+ chomp $line;
+
+ $source = substr($line, 40);
+ if ($source =~ /^([^;]*);/) {
+ $source = $1;
+ }
+
+ ($label, $op, $arg, $tail) = split(/\s+/, $source);
+ if ($op =~ /^(|\[)section$/i) {
+ $offset = $vstart{$arg};
+ } elsif ($op =~ /^(absolute|\[absolute)$/i) {
+ $offset = 0;
+ } elsif ($op =~ /^struc$/i) {
+ push(@ostack, $offset);
+ $offset = 0;
+ } elsif ($op =~ /^endstruc$/i) {
+ $offset = pop(@ostack);
+ }
+
+ if ($line =~ /^(\s*[0-9]+ )([0-9A-F]{8})(\s.*)$/) {
+ $line = sprintf("%s%08X%s", $1, (hex $2)+$offset, $3);
+ }
+
+ print OUT $line, "\n";
+}
diff --git a/contrib/syslinux-4.02/core/lzo/enter.ash b/contrib/syslinux-4.02/core/lzo/enter.ash
new file mode 100644
index 0000000..49c455d
--- /dev/null
+++ b/contrib/syslinux-4.02/core/lzo/enter.ash
@@ -0,0 +1,89 @@
+/* enter.ash -- LZO assembler stuff
+
+ This file is part of the LZO real-time data compression library.
+
+ Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+ All Rights Reserved.
+
+ The LZO library 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.
+
+ The LZO library 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 the LZO library; see the file COPYING.
+ If not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ Markus F.X.J. Oberhumer
+ <markus@oberhumer.com>
+ http://www.oberhumer.com/opensource/lzo/
+ */
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+ pushl %ebp
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+ pushl %ecx
+ pushl %edx
+ subl $12,%esp
+
+ cld
+
+ movl INP,%esi
+ movl OUTP,%edi
+#if defined(N_3_EBP)
+ movl $3,%ebp
+#endif
+#if defined(N_255_EBP)
+ movl $255,%ebp
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT)
+#if defined(INIT_OVERRUN)
+ INIT_OVERRUN
+# undef INIT_OVERRUN
+#endif
+ leal -3(%esi),%eax /* 3 == length of EOF code */
+ addl INS,%eax
+ movl %eax,INEND
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
+#if defined(INIT_OVERRUN)
+ INIT_OVERRUN
+# undef INIT_OVERRUN
+#endif
+ movl %edi,%eax
+ movl OUTS,%edx
+ addl (%edx),%eax
+ movl %eax,OUTEND
+#endif
+
+
+/*
+vi:ts=4
+*/
+
diff --git a/contrib/syslinux-4.02/core/lzo/leave.ash b/contrib/syslinux-4.02/core/lzo/leave.ash
new file mode 100644
index 0000000..9550b46
--- /dev/null
+++ b/contrib/syslinux-4.02/core/lzo/leave.ash
@@ -0,0 +1,114 @@
+/* leave.ash -- LZO assembler stuff
+
+ This file is part of the LZO real-time data compression library.
+
+ Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+ All Rights Reserved.
+
+ The LZO library 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.
+
+ The LZO library 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 the LZO library; see the file COPYING.
+ If not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ Markus F.X.J. Oberhumer
+ <markus@oberhumer.com>
+ http://www.oberhumer.com/opensource/lzo/
+ */
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+/* check uncompressed size */
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
+ cmpl OUTEND,%edi
+ ja .L_output_overrun
+#endif
+
+/* check compressed size */
+ movl INP,%edx
+ addl INS,%edx
+ cmpl %edx,%esi /* check compressed size */
+ ja .L_input_overrun
+ jb .L_input_not_consumed
+
+.L_leave:
+ subl OUTP,%edi /* write back the uncompressed size */
+ movl OUTS,%edx
+ movl %edi,(%edx)
+
+ negl %eax
+ addl $12,%esp
+ popl %edx
+ popl %ecx
+ popl %ebx
+ popl %esi
+ popl %edi
+ popl %ebp
+#if 1
+ ret
+#else
+ jmp .L_end
+#endif
+
+
+.L_error:
+ movl $1,%eax /* LZO_E_ERROR */
+ jmp .L_leave
+
+.L_input_not_consumed:
+ movl $8,%eax /* LZO_E_INPUT_NOT_CONSUMED */
+ jmp .L_leave
+
+.L_input_overrun:
+ movl $4,%eax /* LZO_E_INPUT_OVERRUN */
+ jmp .L_leave
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
+.L_output_overrun:
+ movl $5,%eax /* LZO_E_OUTPUT_OVERRUN */
+ jmp .L_leave
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+.L_lookbehind_overrun:
+ movl $6,%eax /* LZO_E_LOOKBEHIND_OVERRUN */
+ jmp .L_leave
+#endif
+
+#if defined(LZO_DEBUG)
+.L_assert_fail:
+ movl $99,%eax
+ jmp .L_leave
+#endif
+
+.L_end:
+
+
+/*
+vi:ts=4
+*/
+
diff --git a/contrib/syslinux-4.02/core/lzo/lzo1c_d.ash b/contrib/syslinux-4.02/core/lzo/lzo1c_d.ash
new file mode 100644
index 0000000..9969c86
--- /dev/null
+++ b/contrib/syslinux-4.02/core/lzo/lzo1c_d.ash
@@ -0,0 +1,184 @@
+/* lzo1c_d.ash -- assembler implementation of the LZO1C decompression algorithm
+
+ This file is part of the LZO real-time data compression library.
+
+ Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+ All Rights Reserved.
+
+ The LZO library 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.
+
+ The LZO library 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 the LZO library; see the file COPYING.
+ If not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ Markus F.X.J. Oberhumer
+ <markus@oberhumer.com>
+ http://www.oberhumer.com/opensource/lzo/
+ */
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+ ALIGN3
+.L1:
+ xorl %eax,%eax
+ movb (%esi),%al
+ incl %esi
+ cmpb $32,%al
+ jnb .LMATCH
+
+ orb %al,%al
+ jz .L12
+ movl %eax,%ecx
+.LIT:
+ TEST_OP((%edi,%ecx),%ebx)
+ TEST_IP((%esi,%ecx),%ebx)
+ rep
+ movsb
+.LM1:
+ movb (%esi),%al
+ incl %esi
+
+ cmpb $32,%al
+ jb .LM2
+.LMATCH:
+ cmpb $64,%al
+ jb .LN3
+
+ movl %eax,%ecx
+ andb $31,%al
+ leal -1(%edi),%edx
+ shrl $5,%ecx
+ subl %eax,%edx
+ movb (%esi),%al
+ incl %esi
+
+ shll $5,%eax
+ subl %eax,%edx
+ incl %ecx
+ xchgl %esi,%edx
+ TEST_LOOKBEHIND(%esi)
+ TEST_OP((%edi,%ecx),%ebx)
+ rep
+ movsb
+ movl %edx,%esi
+ jmp .L1
+
+ ALIGN3
+.L12:
+ LODSB
+ leal 32(%eax),%ecx
+ cmpb $248,%al
+ jb .LIT
+
+ movl $280,%ecx
+ subb $248,%al
+ jz .L11
+ xchgl %eax,%ecx
+ xorb %al,%al
+ shll %cl,%eax
+ xchgl %eax,%ecx
+.L11:
+ TEST_OP((%edi,%ecx),%ebx)
+ TEST_IP((%esi,%ecx),%ebx)
+ rep
+ movsb
+ jmp .L1
+
+ ALIGN3
+.LM2:
+ leal -1(%edi),%edx
+ subl %eax,%edx
+ LODSB
+ shll $5,%eax
+ subl %eax,%edx
+ xchgl %esi,%edx
+ TEST_LOOKBEHIND(%esi)
+ TEST_OP(4(%edi),%ebx)
+ movsb
+ movsb
+ movsb
+ movl %edx,%esi
+ movsb
+ xorl %eax,%eax
+ jmp .LM1
+.LN3:
+ andb $31,%al
+ movl %eax,%ecx
+ jnz .LN6
+ movb $31,%cl
+.LN4:
+ LODSB
+ orb %al,%al
+ jnz .LN5
+ addl N_255,%ecx
+ jmp .LN4
+
+ ALIGN3
+.LN5:
+ addl %eax,%ecx
+.LN6:
+ movb (%esi),%al
+ incl %esi
+
+ movl %eax,%ebx
+ andb $63,%al
+ movl %edi,%edx
+ subl %eax,%edx
+
+ movb (%esi),%al
+ incl %esi
+
+ shll $6,%eax
+ subl %eax,%edx
+ cmpl %edi,%edx
+ jz .LEOF
+
+ xchgl %edx,%esi
+ leal 3(%ecx),%ecx
+ TEST_LOOKBEHIND(%esi)
+ TEST_OP((%edi,%ecx),%eax)
+ rep
+ movsb
+
+ movl %edx,%esi
+ xorl %eax,%eax
+ shrl $6,%ebx
+ movl %ebx,%ecx
+ jnz .LIT
+ jmp .L1
+
+.LEOF:
+/**** xorl %eax,%eax eax=0 from above */
+
+ cmpl $1,%ecx /* ecx must be 1 */
+ setnz %al
+
+
+/*
+vi:ts=4
+*/
+
diff --git a/contrib/syslinux-4.02/core/lzo/lzo1f_d.ash b/contrib/syslinux-4.02/core/lzo/lzo1f_d.ash
new file mode 100644
index 0000000..aa9279e
--- /dev/null
+++ b/contrib/syslinux-4.02/core/lzo/lzo1f_d.ash
@@ -0,0 +1,176 @@
+/* lzo1f_d.ash -- assembler implementation of the LZO1F decompression algorithm
+
+ This file is part of the LZO real-time data compression library.
+
+ Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+ All Rights Reserved.
+
+ The LZO library 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.
+
+ The LZO library 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 the LZO library; see the file COPYING.
+ If not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ Markus F.X.J. Oberhumer
+ <markus@oberhumer.com>
+ http://www.oberhumer.com/opensource/lzo/
+ */
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+ ALIGN3
+.L0:
+ xorl %eax,%eax
+ movb (%esi),%al
+ incl %esi
+ cmpb $31,%al
+ ja .LM2
+
+ orb %al,%al
+ movl %eax,%ecx
+ jnz .L2
+1:
+ LODSB
+ orb %al,%al
+ jnz 2f
+ addl N_255,%ecx
+ jmp 1b
+2:
+ lea 31(%eax,%ecx),%ecx
+.L2:
+ TEST_OP((%edi,%ecx),%ebx)
+ TEST_IP((%esi,%ecx),%ebx)
+ movb %cl,%al
+ shrl $2,%ecx
+ rep
+ movsl
+ andb $3,%al
+ jz 1f
+ movl (%esi),%ebx
+ addl %eax,%esi
+ movl %ebx,(%edi)
+ addl %eax,%edi
+1:
+ movb (%esi),%al
+ incl %esi
+.LM1:
+ cmpb $31,%al
+ jbe .LM21
+
+.LM2:
+ cmpb $223,%al
+ ja .LM3
+
+ movl %eax,%ecx
+ shrl $2,%eax
+ lea -1(%edi),%edx
+ andb $7,%al
+ shrl $5,%ecx
+ movl %eax,%ebx
+
+ movb (%esi),%al
+ leal (%ebx,%eax,8),%eax
+ incl %esi
+.LM5:
+ subl %eax,%edx
+ addl $2,%ecx
+ xchgl %edx,%esi
+ TEST_LOOKBEHIND(%esi)
+ TEST_OP((%edi,%ecx),%ebx)
+ cmpl $6,%ecx
+ jb 1f
+ cmpl $4,%eax
+ jb 1f
+ movb %cl,%al
+ shrl $2,%ecx
+ rep
+ movsl
+ andb $3,%al
+ movb %al,%cl
+1:
+ rep
+ movsb
+ movl %edx,%esi
+.LN1:
+ movb -2(%esi),%cl
+ andl $3,%ecx
+ jz .L0
+ movl (%esi),%eax
+ addl %ecx,%esi
+ movl %eax,(%edi)
+ addl %ecx,%edi
+ xorl %eax,%eax
+ movb (%esi),%al
+ incl %esi
+ jmp .LM1
+.LM21:
+ TEST_OP(3(%edi),%edx)
+ shrl $2,%eax
+ leal -0x801(%edi),%edx
+ movl %eax,%ecx
+ movb (%esi),%al
+ incl %esi
+ leal (%ecx,%eax,8),%eax
+ subl %eax,%edx
+ TEST_LOOKBEHIND(%edx)
+ movl (%edx),%eax
+ movl %eax,(%edi)
+ addl $3,%edi
+ jmp .LN1
+1:
+ LODSB
+ orb %al,%al
+ jnz 2f
+ addl N_255,%ecx
+ jmp 1b
+2:
+ lea 31(%eax,%ecx),%ecx
+ jmp .LM4
+
+ ALIGN3
+.LM3:
+ andb $31,%al
+ movl %eax,%ecx
+ jz 1b
+.LM4:
+ movl %edi,%edx
+ movw (%esi),%ax
+ addl $2,%esi
+ shrl $2,%eax
+ jnz .LM5
+
+.LEOF:
+/**** xorl %eax,%eax eax=0 from above */
+
+ cmpl $1,%ecx /* ecx must be 1 */
+ setnz %al
+
+
+/*
+vi:ts=4
+*/
+
diff --git a/contrib/syslinux-4.02/core/lzo/lzo1x_d.ash b/contrib/syslinux-4.02/core/lzo/lzo1x_d.ash
new file mode 100644
index 0000000..aa13835
--- /dev/null
+++ b/contrib/syslinux-4.02/core/lzo/lzo1x_d.ash
@@ -0,0 +1,401 @@
+/* lzo1x_d.ash -- assembler implementation of the LZO1X decompression algorithm
+
+ This file is part of the LZO real-time data compression library.
+
+ Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+ All Rights Reserved.
+
+ The LZO library 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.
+
+ The LZO library 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 the LZO library; see the file COPYING.
+ If not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ Markus F.X.J. Oberhumer
+ <markus@oberhumer.com>
+ http://www.oberhumer.com/opensource/lzo/
+ */
+
+
+#if !defined(LZO1X) && !defined(LZO1Y)
+# define LZO1X
+#endif
+
+#if defined(LZO_FAST)
+# define NN 3
+#else
+# define NN 0
+#endif
+
+
+/***********************************************************************
+// init
+************************************************************************/
+
+ xorl %eax,%eax
+ xorl %ebx,%ebx /* high bits 9-32 stay 0 */
+ lodsb
+ cmpb $17,%al
+ jbe .L01
+ subb $17-NN,%al
+#if defined(LZO_FAST)
+ jmp .LFLR
+#else
+ cmpb $4,%al
+ jae .LFLR
+#if 1
+ TEST_OP((%edi,%eax),%edx)
+ TEST_IP((%esi,%eax),%edx)
+ movl %eax,%ecx
+ jmp .LFLR2
+#else
+ jmp .LFLR3
+#endif
+#endif
+
+
+/***********************************************************************
+// literal run
+************************************************************************/
+
+0: addl N_255,%eax
+ TEST_IP(18(%esi,%eax),%edx) /* minimum */
+1: movb (%esi),%bl
+ incl %esi
+ orb %bl,%bl
+ jz 0b
+ leal 18+NN(%eax,%ebx),%eax
+ jmp 3f
+
+
+ ALIGN3
+.L00:
+#ifdef LZO_DEBUG
+ andl $0xffffff00,%eax ; jnz .L_assert_fail
+ andl $0xffffff00,%ebx ; jnz .L_assert_fail
+ xorl %eax,%eax ; xorl %ebx,%ebx
+ xorl %ecx,%ecx ; xorl %edx,%edx
+#endif
+ TEST_IP_R(%esi)
+ LODSB
+.L01:
+ cmpb $16,%al
+ jae .LMATCH
+
+/* a literal run */
+ orb %al,%al
+ jz 1b
+ addl $3+NN,%eax
+3:
+.LFLR:
+ TEST_OP(-NN(%edi,%eax),%edx)
+ TEST_IP(-NN(%esi,%eax),%edx)
+#if defined(LZO_FAST)
+ movl %eax,%ecx
+ NOTL_3(%eax)
+ shrl $2,%ecx
+ andl N_3,%eax
+ COPYL(%esi,%edi,%edx)
+ subl %eax,%esi
+ subl %eax,%edi
+#else
+ movl %eax,%ecx
+ shrl $2,%eax
+ andl N_3,%ecx
+ COPYL_C(%esi,%edi,%edx,%eax)
+.LFLR2:
+ rep
+ movsb
+#endif
+
+#ifdef LZO_DEBUG
+ andl $0xffffff00,%eax ; jnz .L_assert_fail
+ andl $0xffffff00,%ebx ; jnz .L_assert_fail
+ xorl %eax,%eax ; xorl %ebx,%ebx
+ xorl %ecx,%ecx ; xorl %edx,%edx
+#endif
+ LODSB
+ cmpb $16,%al
+ jae .LMATCH
+
+
+/***********************************************************************
+// R1
+************************************************************************/
+
+ TEST_OP(3(%edi),%edx)
+ shrl $2,%eax
+ movb (%esi),%bl
+#if defined(LZO1X)
+ leal -0x801(%edi),%edx
+#elif defined(LZO1Y)
+ leal -0x401(%edi),%edx
+#endif
+ leal (%eax,%ebx,4),%eax
+ incl %esi
+ subl %eax,%edx
+ TEST_LOOKBEHIND(%edx)
+#if defined(LZO_FAST)
+ movl (%edx),%ecx
+ movl %ecx,(%edi)
+#else
+ movb (%edx),%al
+ movb %al,(%edi)
+ movb 1(%edx),%al
+ movb %al,1(%edi)
+ movb 2(%edx),%al
+ movb %al,2(%edi)
+#endif
+ addl N_3,%edi
+ jmp .LMDONE
+
+
+/***********************************************************************
+// M2
+************************************************************************/
+
+ ALIGN3
+.LMATCH:
+ cmpb $64,%al
+ jb .LM3MATCH
+
+/* a M2 match */
+ movl %eax,%ecx
+ shrl $2,%eax
+ leal -1(%edi),%edx
+#if defined(LZO1X)
+ andl $7,%eax
+ movb (%esi),%bl
+ shrl $5,%ecx
+ leal (%eax,%ebx,8),%eax
+#elif defined(LZO1Y)
+ andl N_3,%eax
+ movb (%esi),%bl
+ shrl $4,%ecx
+ leal (%eax,%ebx,4),%eax
+#endif
+ incl %esi
+ subl %eax,%edx
+
+#if defined(LZO_FAST)
+#if defined(LZO1X)
+ addl $1+3,%ecx
+#elif defined(LZO1Y)
+ addl $2,%ecx
+#endif
+#else
+#if defined(LZO1X)
+ incl %ecx
+#elif defined(LZO1Y)
+ decl %ecx
+#endif
+#endif
+
+ cmpl N_3,%eax
+ jae .LCOPYLONG
+ jmp .LCOPYBYTE
+
+
+/***********************************************************************
+// M3
+************************************************************************/
+
+0: addl N_255,%eax
+ TEST_IP(3(%esi),%edx) /* minimum */
+1: movb (%esi),%bl
+ incl %esi
+ orb %bl,%bl
+ jz 0b
+ leal 33+NN(%eax,%ebx),%ecx
+ xorl %eax,%eax
+ jmp 3f
+
+
+ ALIGN3
+.LM3MATCH:
+ cmpb $32,%al
+ jb .LM4MATCH
+
+/* a M3 match */
+ andl $31,%eax
+ jz 1b
+ lea 2+NN(%eax),%ecx
+3:
+#ifdef LZO_DEBUG
+ andl $0xffff0000,%eax ; jnz .L_assert_fail
+#endif
+ movw (%esi),%ax
+ leal -1(%edi),%edx
+ shrl $2,%eax
+ addl $2,%esi
+ subl %eax,%edx
+
+ cmpl N_3,%eax
+ jb .LCOPYBYTE
+
+
+/***********************************************************************
+// copy match
+************************************************************************/
+
+ ALIGN1
+.LCOPYLONG: /* copy match using longwords */
+ TEST_LOOKBEHIND(%edx)
+#if defined(LZO_FAST)
+ leal -3(%edi,%ecx),%eax
+ shrl $2,%ecx
+ TEST_OP_R(%eax)
+ COPYL(%edx,%edi,%ebx)
+ movl %eax,%edi
+ xorl %ebx,%ebx
+#else
+ TEST_OP((%edi,%ecx),%eax)
+ movl %ecx,%ebx
+ shrl $2,%ebx
+ jz 2f
+ COPYL_C(%edx,%edi,%eax,%ebx)
+ andl N_3,%ecx
+ jz 1f
+2: COPYB_C(%edx,%edi,%al,%ecx)
+1:
+#endif
+
+.LMDONE:
+ movb -2(%esi),%al
+ andl N_3,%eax
+ jz .L00
+.LFLR3:
+ TEST_OP((%edi,%eax),%edx)
+ TEST_IP((%esi,%eax),%edx)
+#if defined(LZO_FAST)
+ movl (%esi),%edx
+ addl %eax,%esi
+ movl %edx,(%edi)
+ addl %eax,%edi
+#else
+ COPYB_C(%esi,%edi,%cl,%eax)
+#endif
+
+#ifdef LZO_DEBUG
+ andl $0xffffff00,%eax ; jnz .L_assert_fail
+ andl $0xffffff00,%ebx ; jnz .L_assert_fail
+ xorl %eax,%eax ; xorl %ebx,%ebx
+ xorl %ecx,%ecx ; xorl %edx,%edx
+#endif
+ LODSB
+ jmp .LMATCH
+
+
+ ALIGN3
+.LCOPYBYTE: /* copy match using bytes */
+ TEST_LOOKBEHIND(%edx)
+ TEST_OP(-NN(%edi,%ecx),%eax)
+ xchgl %edx,%esi
+#if defined(LZO_FAST)
+ subl N_3,%ecx
+#endif
+ rep
+ movsb
+ movl %edx,%esi
+ jmp .LMDONE
+
+
+/***********************************************************************
+// M4
+************************************************************************/
+
+0: addl N_255,%ecx
+ TEST_IP(3(%esi),%edx) /* minimum */
+1: movb (%esi),%bl
+ incl %esi
+ orb %bl,%bl
+ jz 0b
+ leal 9+NN(%ebx,%ecx),%ecx
+ jmp 3f
+
+
+ ALIGN3
+.LM4MATCH:
+ cmpb $16,%al
+ jb .LM1MATCH
+
+/* a M4 match */
+ movl %eax,%ecx
+ andl $8,%eax
+ shll $13,%eax /* save in bit 16 */
+ andl $7,%ecx
+ jz 1b
+ addl $2+NN,%ecx
+3:
+#ifdef LZO_DEBUG
+ movl %eax,%edx ; andl $0xfffe0000,%edx ; jnz .L_assert_fail
+#endif
+ movw (%esi),%ax
+ addl $2,%esi
+ leal -0x4000(%edi),%edx
+ shrl $2,%eax
+ jz .LEOF
+ subl %eax,%edx
+ jmp .LCOPYLONG
+
+
+/***********************************************************************
+// M1
+************************************************************************/
+
+ ALIGN3
+.LM1MATCH:
+/* a M1 match */
+ TEST_OP(2(%edi),%edx)
+ shrl $2,%eax
+ movb (%esi),%bl
+ leal -1(%edi),%edx
+ leal (%eax,%ebx,4),%eax
+ incl %esi
+ subl %eax,%edx
+ TEST_LOOKBEHIND(%edx)
+
+ movb (%edx),%al /* we must use this because edx can be edi-1 */
+ movb %al,(%edi)
+ movb 1(%edx),%bl
+ movb %bl,1(%edi)
+ addl $2,%edi
+ jmp .LMDONE
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+.LEOF:
+/**** xorl %eax,%eax eax=0 from above */
+
+ cmpl $3+NN,%ecx /* ecx must be 3/6 */
+ setnz %al
+
+
+/*
+vi:ts=4
+*/
+
diff --git a/contrib/syslinux-4.02/core/lzo/lzo1x_f1.S b/contrib/syslinux-4.02/core/lzo/lzo1x_f1.S
new file mode 100644
index 0000000..8360e34
--- /dev/null
+++ b/contrib/syslinux-4.02/core/lzo/lzo1x_f1.S
@@ -0,0 +1,63 @@
+/* lzo1x_f1.S -- fast LZO1X decompression in assembler (i386 + gcc)
+
+ This file is part of the LZO real-time data compression library.
+
+ Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+ All Rights Reserved.
+
+ The LZO library 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.
+
+ The LZO library 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 the LZO library; see the file COPYING.
+ If not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ Markus F.X.J. Oberhumer
+ <markus@oberhumer.com>
+ http://www.oberhumer.com/opensource/lzo/
+ */
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+#define LZO_FAST
+
+#include "lzo_asm.h"
+
+ .section ".textnr","ax"
+
+ LZO_PUBLIC(lzo1x_decompress_asm_fast)
+
+#include "enter.ash"
+#include "lzo1x_d.ash"
+#include "leave.ash"
+
+ LZO_PUBLIC_END(lzo1x_decompress_asm_fast)
+
+
+/*
+vi:ts=4
+*/
+
diff --git a/contrib/syslinux-4.02/core/lzo/lzo_asm.h b/contrib/syslinux-4.02/core/lzo/lzo_asm.h
new file mode 100644
index 0000000..55fdf6d
--- /dev/null
+++ b/contrib/syslinux-4.02/core/lzo/lzo_asm.h
@@ -0,0 +1,287 @@
+/* lzo_asm.h -- LZO assembler stuff
+
+ This file is part of the LZO real-time data compression library.
+
+ Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+ All Rights Reserved.
+
+ The LZO library 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.
+
+ The LZO library 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 the LZO library; see the file COPYING.
+ If not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ Markus F.X.J. Oberhumer
+ <markus@oberhumer.com>
+ http://www.oberhumer.com/opensource/lzo/
+ */
+
+
+/***********************************************************************
+// <asmconfig.h>
+************************************************************************/
+
+#if !defined(__i386__)
+# error
+#endif
+
+#if !defined(IN_CONFIGURE)
+#if defined(LZO_HAVE_CONFIG_H)
+# include <config.h>
+#else
+ /* manual configuration - see defaults below */
+# if defined(__ELF__)
+# define MFX_ASM_HAVE_TYPE
+# define MFX_ASM_NAME_NO_UNDERSCORES
+# elif defined(__linux__) /* Linux a.out */
+# define MFX_ASM_ALIGN_PTWO
+# elif defined(__DJGPP__)
+# define MFX_ASM_ALIGN_PTWO
+# elif defined(__GO32__) /* djgpp v1 */
+# define MFX_ASM_CANNOT_USE_EBP
+# elif defined(__EMX__)
+# define MFX_ASM_ALIGN_PTWO
+# define MFX_ASM_CANNOT_USE_EBP
+# endif
+#endif
+#endif
+
+#if 1 && defined(__ELF__)
+.section .note.GNU-stack,"",@progbits
+#endif
+#if 0 && defined(__ELF__)
+#undef i386
+.arch i386
+.code32
+#endif
+
+
+/***********************************************************************
+// name always uses underscores
+// [ OLD: name (default: with underscores) ]
+************************************************************************/
+
+#if !defined(LZO_ASM_NAME)
+# define LZO_ASM_NAME(n) _ ## n
+#if 0
+# if defined(MFX_ASM_NAME_NO_UNDERSCORES)
+# define LZO_ASM_NAME(n) n
+# else
+# define LZO_ASM_NAME(n) _ ## n
+# endif
+#endif
+#endif
+
+
+/***********************************************************************
+// .type (default: do not use)
+************************************************************************/
+
+#if !defined(LZO_PUBLIC)
+#if defined(__LZO_DB__)
+# define LZO_PUBLIC(func) \
+ .p2align 4 ; .byte 0,0,0,0,0,0,0 ; .ascii "LZO_START"
+# define LZO_PUBLIC_END(func) \
+ .p2align 4,0x90 ; .ascii "LZO_END"
+#elif defined(MFX_ASM_HAVE_TYPE)
+# define LZO_PUBLIC(func) \
+ ALIGN3 ; .type LZO_ASM_NAME(func),@function ; \
+ .globl LZO_ASM_NAME(func) ; LZO_ASM_NAME(func):
+# define LZO_PUBLIC_END(func) \
+ .size LZO_ASM_NAME(func),.-LZO_ASM_NAME(func)
+#else
+# define LZO_PUBLIC(func) \
+ ALIGN3 ; .globl LZO_ASM_NAME(func) ; LZO_ASM_NAME(func):
+# define LZO_PUBLIC_END(func)
+#endif
+#endif
+
+
+/***********************************************************************
+// .align (default: bytes)
+************************************************************************/
+
+#if !defined(MFX_ASM_ALIGN_BYTES) && !defined(MFX_ASM_ALIGN_PTWO)
+# define MFX_ASM_ALIGN_BYTES
+#endif
+
+#if !defined(LZO_ASM_ALIGN)
+# if defined(MFX_ASM_ALIGN_PTWO)
+# define LZO_ASM_ALIGN(x) .align x
+# else
+# define LZO_ASM_ALIGN(x) .align (1 << (x))
+# endif
+#endif
+
+#define ALIGN1 LZO_ASM_ALIGN(1)
+#define ALIGN2 LZO_ASM_ALIGN(2)
+#define ALIGN3 LZO_ASM_ALIGN(3)
+
+
+/***********************************************************************
+// ebp usage (default: can use)
+************************************************************************/
+
+#if !defined(MFX_ASM_CANNOT_USE_EBP)
+# if 1 && !defined(N_3_EBP) && !defined(N_255_EBP)
+# define N_3_EBP
+# endif
+# if 0 && !defined(N_3_EBP) && !defined(N_255_EBP)
+# define N_255_EBP
+# endif
+#endif
+
+#if defined(N_3_EBP) && defined(N_255_EBP)
+# error
+#endif
+#if defined(MFX_ASM_CANNOT_USE_EBP)
+# if defined(N_3_EBP) || defined(N_255_EBP)
+# error
+# endif
+#endif
+
+#if !defined(N_3)
+# if defined(N_3_EBP)
+# define N_3 %ebp
+# else
+# define N_3 $3
+# endif
+#endif
+
+#if !defined(N_255)
+# if defined(N_255_EBP)
+# define N_255 %ebp
+# define NOTL_3(r) xorl %ebp,r
+# else
+# define N_255 $255
+# endif
+#endif
+
+#if !defined(NOTL_3)
+# define NOTL_3(r) xorl N_3,r
+#endif
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+#ifndef INP
+#define INP 4+36(%esp)
+#define INS 8+36(%esp)
+#define OUTP 12+36(%esp)
+#define OUTS 16+36(%esp)
+#endif
+
+#define INEND 4(%esp)
+#define OUTEND (%esp)
+
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT)
+# define TEST_IP_R(r) cmpl r,INEND ; jb .L_input_overrun
+# define TEST_IP(addr,r) leal addr,r ; TEST_IP_R(r)
+#else
+# define TEST_IP_R(r)
+# define TEST_IP(addr,r)
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
+# define TEST_OP_R(r) cmpl r,OUTEND ; jb .L_output_overrun
+# define TEST_OP(addr,r) leal addr,r ; TEST_OP_R(r)
+#else
+# define TEST_OP_R(r)
+# define TEST_OP(addr,r)
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+# define TEST_LOOKBEHIND(r) cmpl OUTP,r ; jb .L_lookbehind_overrun
+#else
+# define TEST_LOOKBEHIND(r)
+#endif
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+#define LODSB movb (%esi),%al ; incl %esi
+
+#define MOVSB(r1,r2,x) movb (r1),x ; incl r1 ; movb x,(r2) ; incl r2
+#define MOVSW(r1,r2,x) movb (r1),x ; movb x,(r2) ; \
+ movb 1(r1),x ; addl $2,r1 ; \
+ movb x,1(r2) ; addl $2,r2
+#define MOVSL(r1,r2,x) movl (r1),x ; addl $4,r1 ; movl x,(r2) ; addl $4,r2
+
+#if defined(LZO_DEBUG)
+#define COPYB_C(r1,r2,x,rc) \
+ cmpl $0,rc ; jz .L_assert_fail; \
+ 9: MOVSB(r1,r2,x) ; decl rc ; jnz 9b
+#define COPYL_C(r1,r2,x,rc) \
+ cmpl $0,rc ; jz .L_assert_fail; \
+ 9: MOVSL(r1,r2,x) ; decl rc ; jnz 9b
+#else
+#define COPYB_C(r1,r2,x,rc) \
+ 9: MOVSB(r1,r2,x) ; decl rc ; jnz 9b
+#define COPYL_C(r1,r2,x,rc) \
+ 9: MOVSL(r1,r2,x) ; decl rc ; jnz 9b
+#endif
+
+#define COPYB(r1,r2,x) COPYB_C(r1,r2,x,%ecx)
+#define COPYL(r1,r2,x) COPYL_C(r1,r2,x,%ecx)
+
+
+/***********************************************************************
+// not used
+************************************************************************/
+
+#if 0
+
+#if 0
+#define REP_MOVSB(x) rep ; movsb
+#define REP_MOVSL(x) shrl $2,%ecx ; rep ; movsl
+#elif 1
+#define REP_MOVSB(x) COPYB(%esi,%edi,x)
+#define REP_MOVSL(x) shrl $2,%ecx ; COPYL(%esi,%edi,x)
+#else
+#define REP_MOVSB(x) rep ; movsb
+#define REP_MOVSL(x) jmp 9f ; 8: movsb ; decl %ecx ; \
+ 9: testl $3,%edi ; jnz 8b ; \
+ movl %ecx,x ; shrl $2,%ecx ; andl $3,x ; \
+ rep ; movsl ; movl x,%ecx ; rep ; movsb
+#endif
+
+#if 1
+#define NEGL(x) negl x
+#else
+#define NEGL(x) xorl $-1,x ; incl x
+#endif
+
+#endif
+
+
+
+/*
+vi:ts=4
+*/
+
diff --git a/contrib/syslinux-4.02/core/macros.inc b/contrib/syslinux-4.02/core/macros.inc
new file mode 100644
index 0000000..e3aedca
--- /dev/null
+++ b/contrib/syslinux-4.02/core/macros.inc
@@ -0,0 +1,116 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1994-2008 H. Peter Anvin - All Rights Reserved
+;; Copyright 2009 Intel Corporation; author: H. Peter Anvin
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+;; Boston MA 02111-1307, USA; either version 2 of the License, or
+;; (at your option) any later version; incorporated herein by reference.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; macros.inc
+;;
+;; Convenient macros
+;;
+
+%ifndef _MACROS_INC
+%define _MACROS_INC
+
+;
+; Identify the module we're compiling; the "correct" should be defined
+; in the module itself to 1
+;
+%ifdef IS_SYSLINUX
+ %define MY_NAME 'SYSLINUX'
+%else
+ %define IS_SYSLINUX 0
+%endif
+%ifdef IS_PXELINUX
+ %define MY_NAME 'PXELINUX'
+%else
+ %define IS_PXELINUX 0
+%endif
+%ifdef IS_ISOLINUX
+ %define MY_NAME 'ISOLINUX'
+%else
+ %define IS_ISOLINUX 0
+%endif
+%ifdef IS_EXTLINUX
+ %define MY_NAME 'EXTLINUX'
+%else
+ %define IS_EXTLINUX 0
+%endif
+
+;
+; Macros similar to res[bwd], but which works in the code segment (after
+; section .text16) or the data segment (section .data16)
+;
+%macro zb 1.nolist
+ times %1 db 0
+%endmacro
+
+%macro zw 1.nolist
+ times %1 dw 0
+%endmacro
+
+%macro zd 1.nolist
+ times %1 dd 0
+%endmacro
+
+;
+; Align with zero bytes in a progbits segment
+;
+%macro alignz 1.nolist
+ times (((%1) - (($-$$) % (%1))) % (%1)) db 0
+%endmacro
+
+;
+; Macro to emit an unsigned decimal number as a string
+;
+%macro asciidec 1.nolist
+ %ifndef DEPEND ; Not safe for "depend"
+ %push asciidec
+ %assign %$v %1
+ %if %$v == 0
+ db '0'
+ %else
+ %assign %$dcount 0
+ %assign %$n %$v
+ %assign %$d 1
+ %rep 20
+ %if %$n != 0
+ %assign %$dcount %$dcount + 1
+ %assign %$n %$n / 10
+ %assign %$d %$d * 10
+ %endif
+ %endrep
+ %rep %$dcount
+ %assign %$d %$d / 10
+ db ((%$v / %$d) % 10) + '0'
+ %endrep
+ %endif
+ %pop
+ %endif
+%endmacro
+
+;
+; Macros for network byte order of constants
+;
+%define htons(x) ( ( ((x) & 0FFh) << 8 ) + ( ((x) & 0FF00h) >> 8 ) )
+%define ntohs(x) htons(x)
+%define htonl(x) ( ( ((x) & 0FFh) << 24) + ( ((x) & 0FF00h) << 8 ) + ( ((x) & 0FF0000h) >> 8 ) + ( ((x) & 0FF000000h) >> 24) )
+%define ntohl(x) htonl(x)
+
+;
+; ASCII
+;
+CR equ 13 ; Carriage Return
+LF equ 10 ; Line Feed
+FF equ 12 ; Form Feed
+BS equ 8 ; Backspace
+
+%endif ; _MACROS_INC
diff --git a/contrib/syslinux-4.02/core/mem/free.c b/contrib/syslinux-4.02/core/mem/free.c
new file mode 100644
index 0000000..0becb9e
--- /dev/null
+++ b/contrib/syslinux-4.02/core/mem/free.c
@@ -0,0 +1,154 @@
+/*
+ * free.c
+ *
+ * Very simple linked-list based malloc()/free().
+ */
+
+#include <stdlib.h>
+#include <dprintf.h>
+#include "malloc.h"
+
+static struct free_arena_header *
+__free_block(struct free_arena_header *ah)
+{
+ struct free_arena_header *pah, *nah;
+ struct free_arena_header *head =
+ &__malloc_head[ARENA_HEAP_GET(ah->a.attrs)];
+
+ pah = ah->a.prev;
+ nah = ah->a.next;
+ if ( ARENA_TYPE_GET(pah->a.attrs) == ARENA_TYPE_FREE &&
+ (char *)pah+ARENA_SIZE_GET(pah->a.attrs) == (char *)ah ) {
+ /* Coalesce into the previous block */
+ ARENA_SIZE_SET(pah->a.attrs, ARENA_SIZE_GET(pah->a.attrs) +
+ ARENA_SIZE_GET(ah->a.attrs));
+ pah->a.next = nah;
+ nah->a.prev = pah;
+
+#ifdef DEBUG_MALLOC
+ ARENA_TYPE_SET(ah->a.attrs, ARENA_TYPE_DEAD);
+#endif
+
+ ah = pah;
+ pah = ah->a.prev;
+ } else {
+ /* Need to add this block to the free chain */
+ ARENA_TYPE_SET(ah->a.attrs, ARENA_TYPE_FREE);
+ ah->a.tag = MALLOC_FREE;
+
+ ah->next_free = head->next_free;
+ ah->prev_free = head;
+ head->next_free = ah;
+ ah->next_free->prev_free = ah;
+ }
+
+ /* In either of the previous cases, we might be able to merge
+ with the subsequent block... */
+ if ( ARENA_TYPE_GET(nah->a.attrs) == ARENA_TYPE_FREE &&
+ (char *)ah+ARENA_SIZE_GET(ah->a.attrs) == (char *)nah ) {
+ ARENA_SIZE_SET(ah->a.attrs, ARENA_SIZE_GET(ah->a.attrs) +
+ ARENA_SIZE_GET(nah->a.attrs));
+
+ /* Remove the old block from the chains */
+ nah->next_free->prev_free = nah->prev_free;
+ nah->prev_free->next_free = nah->next_free;
+ ah->a.next = nah->a.next;
+ nah->a.next->a.prev = ah;
+
+#ifdef DEBUG_MALLOC
+ ARENA_TYPE_SET(nah->a.attrs, ARENA_TYPE_DEAD);
+#endif
+ }
+
+ /* Return the block that contains the called block */
+ return ah;
+}
+
+void free(void *ptr)
+{
+ struct free_arena_header *ah;
+
+ dprintf("free(%p) @ %p\n", ptr, __builtin_return_address(0));
+
+ if ( !ptr )
+ return;
+
+ ah = (struct free_arena_header *)
+ ((struct arena_header *)ptr - 1);
+
+#ifdef DEBUG_MALLOC
+ assert( ARENA_TYPE_GET(ah->a.attrs) == ARENA_TYPE_USED );
+#endif
+
+ __free_block(ah);
+
+ /* Here we could insert code to return memory to the system. */
+}
+
+/*
+ * This is used to insert a block which is not previously on the
+ * free list. Only the a.size field of the arena header is assumed
+ * to be valid.
+ */
+void __inject_free_block(struct free_arena_header *ah)
+{
+ struct free_arena_header *head =
+ &__malloc_head[ARENA_HEAP_GET(ah->a.attrs)];
+ struct free_arena_header *nah;
+ size_t a_end = (size_t) ah + ARENA_SIZE_GET(ah->a.attrs);
+ size_t n_end;
+
+ dprintf("inject: %#zx bytes @ %p, heap %u (%p)\n",
+ ARENA_SIZE_GET(ah->a.attrs), ah,
+ ARENA_HEAP_GET(ah->a.attrs), head);
+
+ for (nah = head->a.next ; nah != head ; nah = nah->a.next) {
+ n_end = (size_t) nah + ARENA_SIZE_GET(nah->a.attrs);
+
+ /* Is nah entirely beyond this block? */
+ if ((size_t) nah >= a_end)
+ break;
+
+ /* Is this block entirely beyond nah? */
+ if ((size_t) ah >= n_end)
+ continue;
+
+ /* Otherwise we have some sort of overlap - reject this block */
+ return;
+ }
+
+ /* Now, nah should point to the successor block */
+ ah->a.next = nah;
+ ah->a.prev = nah->a.prev;
+ nah->a.prev = ah;
+ ah->a.prev->a.next = ah;
+
+ __free_block(ah);
+}
+
+/*
+ * Free all memory which is tagged with a specific tag.
+ */
+static void __free_tagged(malloc_tag_t tag) {
+ struct free_arena_header *fp, *head;
+ int i;
+
+ for (i = 0; i < NHEAP; i++) {
+ dprintf("__free_tagged(%u) heap %d\n", tag, i);
+ head = &__malloc_head[i];
+ for (fp = head ; fp != head ; fp = fp->a.next) {
+ if (ARENA_TYPE_GET(fp->a.attrs) == ARENA_TYPE_USED &&
+ fp->a.tag == tag)
+ fp = __free_block(fp);
+ }
+ }
+
+ dprintf("__free_tagged(%u) done\n", tag);
+}
+
+void comboot_cleanup_lowmem(com32sys_t *regs)
+{
+ (void)regs;
+
+ __free_tagged(MALLOC_MODULE);
+}
diff --git a/contrib/syslinux-4.02/core/mem/init.c b/contrib/syslinux-4.02/core/mem/init.c
new file mode 100644
index 0000000..487bbb3
--- /dev/null
+++ b/contrib/syslinux-4.02/core/mem/init.c
@@ -0,0 +1,38 @@
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include "malloc.h"
+
+struct free_arena_header __malloc_head[NHEAP];
+
+static __hugebss char main_heap[128 << 10];
+extern char __lowmem_heap[];
+
+void mem_init(void)
+{
+ struct free_arena_header *fp;
+ int i;
+ uint16_t *bios_free_mem = (uint16_t *)0x413;
+
+ /* Initialize the head nodes */
+
+ fp = &__malloc_head[0];
+ for (i = 0 ; i < NHEAP ; i++) {
+ fp->a.next = fp->a.prev = fp->next_free = fp->prev_free = fp;
+ fp->a.attrs = ARENA_TYPE_HEAD | (i << ARENA_HEAP_POS);
+ fp->a.tag = MALLOC_HEAD;
+ fp++;
+ }
+
+ /* Initialize the main heap */
+ fp = (struct free_arena_header *)main_heap;
+ fp->a.attrs = ARENA_TYPE_USED | (HEAP_MAIN << ARENA_HEAP_POS);
+ ARENA_SIZE_SET(fp->a.attrs, sizeof main_heap);
+ __inject_free_block(fp);
+
+ /* Initialize the lowmem heap */
+ fp = (struct free_arena_header *)__lowmem_heap;
+ fp->a.attrs = ARENA_TYPE_USED | (HEAP_LOWMEM << ARENA_HEAP_POS);
+ ARENA_SIZE_SET(fp->a.attrs, (*bios_free_mem << 10) - (uintptr_t)fp);
+ __inject_free_block(fp);
+}
diff --git a/contrib/syslinux-4.02/core/mem/malloc.c b/contrib/syslinux-4.02/core/mem/malloc.c
new file mode 100644
index 0000000..78f7b41
--- /dev/null
+++ b/contrib/syslinux-4.02/core/mem/malloc.c
@@ -0,0 +1,99 @@
+/*
+ * malloc.c
+ *
+ * Very simple linked-list based malloc()/free().
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <dprintf.h>
+#include "malloc.h"
+
+static void *__malloc_from_block(struct free_arena_header *fp,
+ size_t size, malloc_tag_t tag)
+{
+ size_t fsize;
+ struct free_arena_header *nfp, *na;
+ unsigned int heap = ARENA_HEAP_GET(fp->a.attrs);
+
+ fsize = ARENA_SIZE_GET(fp->a.attrs);
+
+ /* We need the 2* to account for the larger requirements of a free block */
+ if ( fsize >= size+2*sizeof(struct arena_header) ) {
+ /* Bigger block than required -- split block */
+ nfp = (struct free_arena_header *)((char *)fp + size);
+ na = fp->a.next;
+
+ ARENA_TYPE_SET(nfp->a.attrs, ARENA_TYPE_FREE);
+ ARENA_HEAP_SET(nfp->a.attrs, heap);
+ ARENA_SIZE_SET(nfp->a.attrs, fsize-size);
+ nfp->a.tag = MALLOC_FREE;
+ ARENA_TYPE_SET(fp->a.attrs, ARENA_TYPE_USED);
+ ARENA_SIZE_SET(fp->a.attrs, size);
+ fp->a.tag = tag;
+
+ /* Insert into all-block chain */
+ nfp->a.prev = fp;
+ nfp->a.next = na;
+ na->a.prev = nfp;
+ fp->a.next = nfp;
+
+ /* Replace current block on free chain */
+ nfp->next_free = fp->next_free;
+ nfp->prev_free = fp->prev_free;
+ fp->next_free->prev_free = nfp;
+ fp->prev_free->next_free = nfp;
+ } else {
+ /* Allocate the whole block */
+ ARENA_TYPE_SET(fp->a.attrs, ARENA_TYPE_USED);
+ fp->a.tag = tag;
+
+ /* Remove from free chain */
+ fp->next_free->prev_free = fp->prev_free;
+ fp->prev_free->next_free = fp->next_free;
+ }
+
+ return (void *)(&fp->a + 1);
+}
+
+static void *_malloc(size_t size, enum heap heap, malloc_tag_t tag)
+{
+ struct free_arena_header *fp;
+ struct free_arena_header *head = &__malloc_head[heap];
+ void *p = NULL;
+
+ dprintf("_malloc(%zu, %u, %u) @ %p = ",
+ size, heap, tag, __builtin_return_address(0));
+
+ if (size) {
+ /* Add the obligatory arena header, and round up */
+ size = (size + 2 * sizeof(struct arena_header) - 1) & ARENA_SIZE_MASK;
+
+ for ( fp = head->next_free ; fp != head ; fp = fp->next_free ) {
+ if ( ARENA_SIZE_GET(fp->a.attrs) >= size ) {
+ /* Found fit -- allocate out of this block */
+ p = __malloc_from_block(fp, size, tag);
+ break;
+ }
+ }
+ }
+
+ dprintf("%p\n", p);
+ return p;
+}
+
+void *malloc(size_t size)
+{
+ return _malloc(size, HEAP_MAIN, MALLOC_CORE);
+}
+
+void *lmalloc(size_t size)
+{
+ return _malloc(size, HEAP_LOWMEM, MALLOC_CORE);
+}
+
+void *pmapi_lmalloc(size_t size)
+{
+ return _malloc(size, HEAP_LOWMEM, MALLOC_MODULE);
+}
diff --git a/contrib/syslinux-4.02/core/mem/malloc.h b/contrib/syslinux-4.02/core/mem/malloc.h
new file mode 100644
index 0000000..b8ec44d
--- /dev/null
+++ b/contrib/syslinux-4.02/core/mem/malloc.h
@@ -0,0 +1,82 @@
+/*
+ * malloc.h
+ *
+ * Internals for the memory allocator
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include "core.h"
+
+/*
+ * This is a temporary hack. In Syslinux 5 this will be a pointer to
+ * the owner module.
+ */
+typedef size_t malloc_tag_t;
+enum malloc_owner {
+ MALLOC_FREE,
+ MALLOC_HEAD,
+ MALLOC_CORE,
+ MALLOC_MODULE,
+};
+
+struct free_arena_header;
+
+/*
+ * This structure should be a power of two. This becomes the
+ * alignment unit.
+ */
+struct arena_header {
+ malloc_tag_t tag;
+ size_t attrs; /* Bits 0..1: Type
+ 2..3: Heap,
+ 4..31: MSB of the size */
+ struct free_arena_header *next, *prev;
+};
+
+enum arena_type {
+ ARENA_TYPE_USED = 0,
+ ARENA_TYPE_FREE = 1,
+ ARENA_TYPE_HEAD = 2,
+ ARENA_TYPE_DEAD = 3,
+};
+enum heap {
+ HEAP_MAIN,
+ HEAP_LOWMEM,
+ NHEAP
+};
+
+#define ARENA_SIZE_MASK (~(uintptr_t)(sizeof(struct arena_header)-1))
+#define ARENA_HEAP_MASK ((size_t)0xc)
+#define ARENA_HEAP_POS 2
+#define ARENA_TYPE_MASK ((size_t)0x3)
+
+#define ARENA_ALIGN_UP(p) ((char *)(((uintptr_t)(p) + ~ARENA_SIZE_MASK) \
+ & ARENA_SIZE_MASK))
+#define ARENA_ALIGN_DOWN(p) ((char *)((uintptr_t)(p) & ARENA_SIZE_MASK))
+
+#define ARENA_SIZE_GET(attrs) ((attrs) & ARENA_SIZE_MASK)
+#define ARENA_HEAP_GET(attrs) (((attrs) & ARENA_HEAP_MASK) >> ARENA_HEAP_POS)
+#define ARENA_TYPE_GET(attrs) ((attrs) & ARENA_TYPE_MASK)
+
+#define ARENA_SIZE_SET(attrs, size) \
+ ((attrs) = ((size) & ARENA_SIZE_MASK) | ((attrs) & ~ARENA_SIZE_MASK))
+#define ARENA_HEAP_SET(attrs, heap) \
+ ((attrs) = (((heap) << ARENA_HEAP_POS) & ARENA_HEAP_MASK) | \
+ ((attrs) & ~ARENA_HEAP_MASK))
+#define ARENA_TYPE_SET(attrs, type) \
+ ((attrs) = ((attrs) & ~ARENA_TYPE_MASK) | \
+ ((type) & ARENA_TYPE_MASK))
+
+/*
+ * This structure should be no more than twice the size of the
+ * previous structure.
+ */
+struct free_arena_header {
+ struct arena_header a;
+ struct free_arena_header *next_free, *prev_free;
+ size_t _pad[2]; /* Pad to 2*sizeof(struct arena_header) */
+};
+
+extern struct free_arena_header __malloc_head[NHEAP];
+void __inject_free_block(struct free_arena_header *ah);
diff --git a/contrib/syslinux-4.02/core/parsecmd.inc b/contrib/syslinux-4.02/core/parsecmd.inc
new file mode 100644
index 0000000..30cd67f
--- /dev/null
+++ b/contrib/syslinux-4.02/core/parsecmd.inc
@@ -0,0 +1,129 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
+;; Copyright 2009 Intel Corporation; author: H. Peter Anvin
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+;; Boston MA 02111-1307, USA; either version 2 of the License, or
+;; (at your option) any later version; incorporated herein by reference.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; parsecmd.inc
+;;
+;; Command line parser code
+;;
+
+ section .text16
+
+; -------------------------------------------------------------------------
+; getcommand: Get a keyword from the current "getc" file and match it
+; against a list of keywords (keywd_table). Each entry in
+; that table should have the following form:
+; <32 bit hash value> <16 bit handler offset>
+;
+; The handler is called, and upon return this function
+; returns with CF = 0. On EOF, this function returns
+; with CF = 1.
+; -------------------------------------------------------------------------
+
+getcommand.skipline:
+ call skipline
+
+getcommand:
+.find:
+ call skipspace ; Skip leading whitespace
+ jz .eof ; End of file
+ jc .find ; End of line: try again
+
+ ; Do this explicitly so #foo is treated as a comment
+ cmp al,'#' ; Leading hash mark -> comment
+ je .skipline
+
+ ; Abuse the trackbuf by putting the keyword there for
+ ; possible error messaging...
+ mov di,trackbuf
+ stosb
+ or al,20h ; Convert to lower case
+ movzx ebx,al ; Hash for a one-char keyword
+.read_loop:
+ call getc
+ jc .eof
+ cmp al,' ' ; Whitespace
+ jbe .done
+ stosb
+ or al,20h
+ rol ebx,5
+ xor bl,al
+ jmp short .read_loop
+.done: call ungetc
+ xor ax,ax
+ stosb ; Null-terminate the trackbuf
+ call skipspace
+ jz .eof
+ jc .noparm
+ call ungetc ; Return nonwhitespace char to buf
+ mov si,keywd_table
+ mov cx,keywd_count
+.table_search:
+ lodsd
+ cmp ebx,eax
+ je .found_keywd
+ lodsd ; Skip entrypoint/argument
+ loop .table_search
+
+ ; Otherwise unrecognized keyword
+ mov si,err_badcfg
+ call writestr
+ mov si,trackbuf
+ call writestr
+ call crlf
+ jmp .skipline
+
+ ; No parameter
+.noparm:
+ mov si,err_noparm
+ call writestr
+ mov si,trackbuf
+ call writestr
+ call crlf
+ jmp .find
+
+.found_keywd: lodsw ; Load argument into ax
+ call [si]
+ clc
+ ret
+
+.eof: stc
+ ret
+
+skipline: cmp al,10 ; Search for LF
+ je .end
+ call getc
+ jnc skipline
+.end: ret
+
+ section .data16
+err_badcfg db 'Unknown keyword in configuration file: ',0
+err_noparm db 'Missing parameter in configuration file. Keyword: ',0
+
+ section .uibss
+ alignb 4
+vk_size equ (vk_end + 3) & ~3
+VKernelBuf: resb vk_size ; "Current" vkernel
+AppendBuf resb max_cmd_len+1 ; append=
+Ontimeout resb max_cmd_len+1 ; ontimeout
+Onerror resb max_cmd_len+1 ; onerror
+ ; This could be in .uibss but that makes PXELINUX overflow
+ section .bss16
+KbdMap resb 256 ; Keyboard map
+FKeyName resb MAX_FKEYS*FILENAME_MAX ; File names for F-key help
+ global KernelName
+KernelName resb FILENAME_MAX ; Mangled name for kernel
+MNameBuf resb FILENAME_MAX
+InitRD resb FILENAME_MAX
+
+ section .text16
diff --git a/contrib/syslinux-4.02/core/parseconfig.inc b/contrib/syslinux-4.02/core/parseconfig.inc
new file mode 100644
index 0000000..e7b3108
--- /dev/null
+++ b/contrib/syslinux-4.02/core/parseconfig.inc
@@ -0,0 +1,475 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
+;; Copyright 2009 Intel Corporation; author: H. Peter Anvin
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+;; Boston MA 02111-1307, USA; either version 2 of the License, or
+;; (at your option) any later version; incorporated herein by reference.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; parseconfig.inc
+;;
+;; Configuration file operations
+;;
+
+ section .text16
+;
+; "default" or "ui" command, with level (1 = default, 2 = ui)
+;
+pc_default: cmp ax,[DefaultLevel]
+ jb skipline ; == call skipline + ret
+ mov [DefaultLevel],ax
+ mov di,default_cmd
+ call getline
+ mov byte [di-1],0 ; null-terminate
+ ret
+
+;
+; "ontimeout" command
+;
+pc_ontimeout: mov di,Ontimeout
+ call getline
+ sub di,Ontimeout+1 ; Don't need final space
+ mov [OntimeoutLen],di
+ ret
+
+;
+; "onerror" command
+;
+pc_onerror: mov di,Onerror
+ call getline
+ sub di,Onerror
+ mov [OnerrorLen],di
+ ret
+
+;
+; "append" command
+;
+pc_append: cmp byte [VKernel],0
+ ja .vk
+ mov di,AppendBuf
+ call getline
+ sub di,AppendBuf
+.app1: mov [AppendLen],di
+ ret
+.vk: mov di,VKernelBuf+vk_append ; "append" command (vkernel)
+ call getline
+ sub di,VKernelBuf+vk_append
+ cmp di,byte 2
+ jne .app2
+ cmp byte [VKernelBuf+vk_append],'-'
+ jne .app2
+ xor di,di ; If "append -" -> null string
+.app2: mov [VKernelBuf+vk_appendlen],di
+ ret
+
+;
+; "ipappend" command (PXELINUX only)
+;
+%if IS_PXELINUX
+pc_ipappend: call getint
+ jc .err
+ cmp byte [VKernel],0
+ jne .vk
+ mov [IPAppend],bl
+.err: ret
+.vk: mov [VKernelBuf+vk_ipappend],bl
+ ret
+%endif
+
+;
+; "localboot" command
+;
+%if HAS_LOCALBOOT
+
+pc_localboot: call getint
+ cmp byte [VKernel],0 ; ("label" section only)
+ je .err
+ mov [VKernelBuf+vk_rname],bx
+ mov byte [VKernelBuf+vk_type],VK_LOCALBOOT
+.err: ret
+
+%endif ; HAS_LOCALBOOT
+
+;
+; "kernel", "config", ... command
+;
+pc_kernel: cmp byte [VKernel],0
+ je .err ; ("label" section only)
+ mov [VKernelBuf+vk_type],al
+ call pc_getline
+ mov di,VKernelBuf+vk_rname
+ pm_call pm_mangle_name
+.err: ret
+
+;
+; "timeout", "totaltimeout" command
+;
+; N.B. 1/10 s ~ 1.D2162AABh clock ticks
+;
+pc_timeout: push ax
+ call getint
+ pop si
+ jc .err
+ mov eax,0D2162AABh
+ mul ebx ; clock ticks per 1/10 s
+ add ebx,edx
+ mov [si],ebx
+.err: ret
+
+
+;
+; "totaltimeout" command
+;
+pc_totaltimeout:
+
+;
+; Generic integer variable setting commands:
+; "prompt", "implicit"
+;
+pc_setint16:
+ push ax
+ call getint
+ pop si
+ jc .err
+ mov [si],bx
+.err: ret
+
+;
+; Generic file-processing commands:
+; "font", "kbdmap",
+;
+pc_filecmd: push ax ; Function to tailcall
+ call pc_getline
+ mov di,MNameBuf
+ pm_call pm_mangle_name
+ pm_call pm_searchdir
+ jnz .ok
+ pop ax ; Drop the successor function
+.ok: ret ; Tailcall if OK, error return
+
+;
+; Commands that expect the file to be opened on top of the getc stack.
+; "display", "include"
+;
+pc_opencmd: push ax ; Function to tailcall
+ call pc_getline
+ mov di,MNameBuf
+ pm_call pm_mangle_name
+ call core_open
+ jnz .ok
+ pop ax ; Drop the successor function
+.ok: ret ; Tailcall if OK, error return
+
+;
+; "include" command (invoked from pc_opencmd)
+;
+pc_include: inc word [IncludeLevel]
+.err: ret
+
+;
+; "serial" command
+;
+pc_serial: call getint
+ jc .err
+ push bx ; Serial port #
+ xor eax,eax
+ mov [FlowControl],eax ; Default to no flow control
+ call skipspace
+ jc .nobaud
+ call ungetc
+ call getint
+ jc .nobaud
+.valid_baud:
+ push ebx
+ call skipspace
+ jc .no_flow
+ call ungetc
+ call getint ; Hardware flow control?
+ jnc .valid_flow
+.no_flow:
+ xor bx,bx ; Default -> no flow control
+.valid_flow:
+ and bh,0Fh ; FlowIgnore
+ shl bh,4
+ mov [FlowIgnore],bh
+ mov bh,bl
+ and bx,0F00Bh ; Valid bits
+ mov [FlowControl],bx
+ pop ebx ; Baud rate
+ jmp short .parse_baud
+.nobaud:
+ mov ebx,DEFAULT_BAUD ; No baud rate given
+.parse_baud:
+ pop di ; Serial port #
+ cmp ebx,byte 75
+ jb .err ; < 75 baud == bogus
+ mov eax,BAUD_DIVISOR
+ cdq
+ div ebx
+ mov [BaudDivisor],ax
+ push ax ; Baud rate divisor
+ cmp di,3
+ ja .port_is_io ; If port > 3 then port is I/O addr
+ shl di,1
+ mov di,[di+serial_base] ; Get the I/O port from the BIOS
+.port_is_io:
+ mov [SerialPort],di
+
+ ;
+ ; Begin code to actually set up the serial port
+ ;
+ call sirq_cleanup_nowipe ; Cleanup existing IRQ handler
+
+ lea dx,[di+3] ; DX -> LCR
+ mov al,83h ; Enable DLAB
+ slow_out dx,al
+
+ pop ax ; Divisor
+ mov dx,di ; DX -> LS
+ slow_out dx,al
+
+ inc dx ; DX -> MS
+ mov al,ah
+ slow_out dx,al
+
+ mov al,03h ; Disable DLAB
+ inc dx ; DX -> LCR
+ inc dx
+ slow_out dx,al
+
+ in al,dx ; Read back LCR (detect missing hw)
+ cmp al,03h ; If nothing here we'll read 00 or FF
+ jne .err ; Assume serial port busted
+ dec dx ; DX -> IIR/FCR
+ mov al,01h
+ slow_out dx,al ; Enable FIFOs if present
+ in al,dx
+ cmp al,0C0h ; FIFOs enabled and usable?
+ jae .fifo_ok
+ xor ax,ax ; Disable FIFO if unusable
+ slow_out dx,al
+.fifo_ok:
+
+ inc dx
+ inc dx ; DX -> MCR
+ mov al,[FlowOutput] ; Assert bits
+ slow_out dx,al
+
+ ; Enable interrupts if requested
+ test al,8
+ jz .noirq
+ call sirq_install
+.noirq:
+
+ ; Show some life
+ cmp byte [SerialNotice],0
+ je .notfirst
+ mov byte [SerialNotice],0
+
+ mov si,syslinux_banner
+ call write_serial_str
+ mov si,copyright_str
+ call write_serial_str
+.notfirst:
+ ret
+
+.err:
+ mov [SerialPort], word 0
+ ret
+
+;
+; Store mangled filename command (F-keys, "initrd")
+;
+pc_filename: push ax
+ call pc_getline
+ pop di
+ pm_call pm_mangle_name ; Mangle file name
+ ret
+
+;
+; "label" command
+;
+pc_label: call commit_vk ; Commit any current vkernel
+ mov byte [InitRD+NULLOFFSET],NULLFILE ; No "initrd" statement
+ mov di,VKernelBuf ; Erase the vkernelbuf for better compression
+ mov cx,(vk_size >> 1)
+ xor ax,ax
+ rep stosw
+ call pc_getline
+ mov di,VKernelBuf+vk_vname
+ mov cx,FILENAME_MAX-1
+.loop:
+ lodsb
+ cmp al,' '
+ jna .done
+ stosb
+ loop .loop
+.done:
+ mov byte [VKernel],1 ; We've seen a "label" statement
+ mov si,VKernelBuf+vk_vname ; By default, rname == mangled vname
+ mov di,VKernelBuf+vk_rname
+ pm_call pm_mangle_name
+ mov si,AppendBuf ; Default append==global append
+ mov di,VKernelBuf+vk_append
+ mov cx,[AppendLen]
+ mov [VKernelBuf+vk_appendlen],cx
+ rep movsb
+%if IS_PXELINUX ; PXELINUX only
+ mov al,[IPAppend] ; Default ipappend==global ipappend
+ mov [VKernelBuf+vk_ipappend],al
+%endif
+ ret
+
+;
+; "say" command
+;
+pc_say: call pc_getline ; "say" command
+ call writestr
+ jmp crlf ; tailcall
+
+;
+; "text" command; ignore everything until we get an "endtext" line
+;
+pc_text: call skipline ; Ignore rest of line
+.loop:
+ call pc_getline
+ jc .eof
+
+ ; Leading spaces are already removed...
+ lodsd
+ and eax,0xdfdfdfdf ; Upper case
+ cmp eax,'ENDT'
+ jne .loop
+ lodsd
+ and eax,0x00dfdfdf ; Upper case and mask
+ cmp eax,'EXT'
+ jne .loop
+ ; If we get here we hit ENDTEXT
+.eof:
+ ret
+
+;
+; Comment line
+;
+pc_comment: ; Fall into pc_getline
+
+;
+; Common subroutine: load line into trackbuf; returns with SI -> trackbuf
+; CF is set on EOF.
+;
+pc_getline: mov di,trackbuf
+ push di
+ call getline
+ mov byte [di],0 ; Null-terminate
+ pop si
+ ret
+
+;
+; Main loop for configuration file parsing
+;
+parse_config:
+ mov di,VKernelBuf ; Clear VKernelBuf at start
+ xor ax,ax
+ mov cx,vk_size
+ rep stosb
+
+.again:
+ call getcommand ; Parse one command
+ jnc .again ; If not EOF...
+ call close
+ dec word [IncludeLevel] ; Still parsing?
+ jnz .again
+
+ ;
+ ; The fall through to commit_vk to commit any final
+ ; VKernel being read
+ ;
+;
+; commit_vk: Store the current VKernelBuf into buffer segment
+;
+commit_vk:
+ cmp byte [VKernel],0
+ jz .nolabel ; Nothing to commit...
+
+ mov di,VKernelBuf+vk_append
+ add di,[VKernelBuf+vk_appendlen]
+
+ ; If we have an initrd statement, append it to the
+ ; append statement
+ cmp byte [InitRD+NULLOFFSET],NULLFILE
+ je .noinitrd
+
+ mov si,str_initrd
+ mov cx,7 ; "initrd="
+ rep movsb
+ mov si,InitRD
+ call strcpy
+ mov byte [es:di-1],' '
+
+ ; For better compression, clean up the append field
+.noinitrd:
+ mov ax,di
+ sub ax,VKernelBuf+vk_append
+ mov [VKernelBuf+vk_appendlen],ax
+ mov cx,max_cmd_len+1
+ sub cx,ax
+ xor ax,ax
+ rep stosb
+
+ ; Pack into high memory
+ mov esi,VKernelBuf
+ mov edi,[VKernelEnd]
+ mov ecx,vk_size
+ pm_call rllpack
+ mov [VKernelEnd],edi
+.nolabel:
+ ret
+.overflow:
+ mov si,vk_overflow_msg
+ call writestr
+ ret
+
+ section .data16
+vk_overflow_msg db 'Out of memory parsing config file', CR, LF, 0
+SerialNotice db 1 ; Only print this once
+
+ section .bss16
+ alignb 4
+VKernelEnd resd 1 ; Lowest high memory address used
+
+ ; This symbol should be used by loaders to indicate
+ ; the highest address *they* are allowed to use.
+HighMemRsvd equ VKernelEnd
+ ; by vkernels
+ section .config
+ alignz 4
+KbdTimeout dd 0 ; Keyboard timeout (if any)
+TotalTimeout dd 0 ; Total timeout (if any)
+AppendLen dw 0 ; Bytes in append= command
+OntimeoutLen dw 0 ; Bytes in ontimeout command
+OnerrorLen dw 0 ; Bytes in onerror command
+CmdLinePtr dw cmd_line_here ; Command line advancing pointer
+ForcePrompt dw 0 ; Force prompt
+NoEscape dw 0 ; No escape
+NoComplete dw 0 ; No label completion on TAB key
+AllowImplicit dw 1 ; Allow implicit kernels
+AllowOptions dw 1 ; User-specified options allowed
+IncludeLevel dw 1 ; Nesting level
+DefaultLevel dw 0 ; The current level of default
+VKernel db 0 ; Have we seen any "label" statements?
+
+%if IS_PXELINUX
+IPAppend db 0 ; Default IPAPPEND option
+%endif
+
+ section .uibss
+ alignb 4 ; For the good of REP MOVSD
+command_line resb max_cmd_len+2 ; Command line buffer
+ alignb 4
+default_cmd resb max_cmd_len+1 ; "default" command line
diff --git a/contrib/syslinux-4.02/core/plaincon.inc b/contrib/syslinux-4.02/core/plaincon.inc
new file mode 100644
index 0000000..c41629d
--- /dev/null
+++ b/contrib/syslinux-4.02/core/plaincon.inc
@@ -0,0 +1,24 @@
+;
+; writechr: Write a single character in AL to the console without
+; mangling any registers; handle video pages correctly.
+;
+ section .text16
+
+writechr:
+ call write_serial ; write to serial port if needed
+ pushfd
+ test byte [cs:UsingVGA], 08h
+ jz .videook
+ call vgaclearmode
+.videook:
+ test byte [cs:DisplayCon], 01h
+ jz .nothing
+ pushad
+ mov ah,0Eh
+ mov bl,07h ; attribute
+ mov bh,[cs:BIOS_page] ; current page
+ int 10h
+ popad
+.nothing:
+ popfd
+ ret
diff --git a/contrib/syslinux-4.02/core/pm.inc b/contrib/syslinux-4.02/core/pm.inc
new file mode 100644
index 0000000..9584cda
--- /dev/null
+++ b/contrib/syslinux-4.02/core/pm.inc
@@ -0,0 +1,450 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
+;; Copyright 2009 Intel Corporation; author: H. Peter Anvin
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+;; Boston MA 02111-1307, USA; either version 2 of the License, or
+;; (at your option) any later version; incorporated herein by reference.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; pm.inc
+;;
+;; Functions to enter and exit 32-bit protected mode, handle interrupts
+;; and cross-mode calls.
+;;
+;; PM refers to 32-bit flat protected mode; RM to 16-bit real mode.
+;;
+
+ bits 16
+ section .text16
+;
+; _pm_call: call PM routine in low memory from RM
+;
+; on stack = PM routine to call (a 32-bit address)
+;
+; ECX, ESI, EDI passed to the called function;
+; EAX = EBP in the called function points to the stack frame
+; which includes all registers (which can be changed if desired.)
+;
+; All registers and the flags saved/restored
+;
+; This routine is invoked by the pm_call macro.
+;
+_pm_call:
+ pushfd
+ pushad
+ push ds
+ push es
+ push fs
+ push gs
+ mov bp,sp
+ mov ax,cs
+ mov ebx,.pm
+ mov ds,ax
+ jmp enter_pm
+
+ bits 32
+ section .textnr
+.pm:
+ ; EAX points to the top of the RM stack, which is EFLAGS
+ test RM_FLAGSH,02h ; RM EFLAGS.IF
+ jz .no_sti
+ sti
+.no_sti:
+ call [ebp+4*2+9*4+2] ; Entrypoint on RM stack
+ mov bx,.rm
+ jmp enter_rm
+
+ bits 16
+ section .text16
+.rm:
+ pop gs
+ pop fs
+ pop es
+ pop ds
+ popad
+ popfd
+ ret 4 ; Drop entrypoint
+
+;
+; enter_pm: Go to PM with interrupt service configured
+; EBX = PM entry point
+; EAX = EBP = on exit, points to the RM stack as a 32-bit value
+; ECX, EDX, ESI, EDI preserved across this routine
+;
+; Assumes CS == DS
+;
+; This routine doesn't enable interrupts, but the target routine
+; can enable interrupts by executing STI.
+;
+ bits 16
+ section .text16
+enter_pm:
+ cli
+ xor eax,eax
+ mov ds,ax
+ mov ax,ss
+ mov [RealModeSSSP],sp
+ mov [RealModeSSSP+2],ax
+ movzx ebp,sp
+ shl eax,4
+ add ebp,eax ; EBP -> top of real-mode stack
+ cld
+ call enable_a20
+
+.a20ok:
+ mov byte [bcopy_gdt.TSS+5],89h ; Mark TSS unbusy
+
+ lgdt [bcopy_gdt] ; We can use the same GDT just fine
+ lidt [PM_IDT_ptr] ; Set up the IDT
+ mov eax,cr0
+ or al,1
+ mov cr0,eax ; Enter protected mode
+ jmp PM_CS32:.in_pm
+
+ bits 32
+ section .textnr
+.in_pm:
+ xor eax,eax ; Available for future use...
+ mov fs,eax
+ mov gs,eax
+ lldt ax
+
+ mov al,PM_DS32 ; Set up data segments
+ mov es,eax
+ mov ds,eax
+ mov ss,eax
+
+ mov al,PM_TSS ; Be nice to Intel's VT by
+ ltr ax ; giving it a valid TR
+
+ mov esp,[PMESP] ; Load protmode %esp
+ mov eax,ebp ; EAX -> top of real-mode stack
+ jmp ebx ; Go to where we need to go
+
+;
+; enter_rm: Return to RM from PM
+;
+; BX = RM entry point (CS = 0)
+; ECX, EDX, ESI, EDI preserved across this routine
+; EAX clobbered
+; EBP reserved
+;
+; This routine doesn't enable interrupts, but the target routine
+; can enable interrupts by executing STI.
+;
+ bits 32
+ section .textnr
+enter_rm:
+ cli
+ cld
+ mov [PMESP],esp ; Save exit %esp
+ jmp PM_CS16:.in_pm16 ; Return to 16-bit mode first
+
+ bits 16
+ section .text16
+.in_pm16:
+ mov ax,PM_DS16 ; Real-mode-like segment
+ mov es,ax
+ mov ds,ax
+ mov ss,ax
+ mov fs,ax
+ mov gs,ax
+
+ lidt [RM_IDT_ptr] ; Real-mode IDT (rm needs no GDT)
+ xor dx,dx
+ mov eax,cr0
+ and al,~1
+ mov cr0,eax
+ jmp 0:.in_rm
+
+.in_rm: ; Back in real mode
+ lss sp,[cs:RealModeSSSP] ; Restore stack
+ movzx esp,sp ; Make sure the high bits are zero
+ mov ds,dx ; Set up sane segments
+ mov es,dx
+ mov fs,dx
+ mov gs,dx
+ jmp bx ; Go to whereever we need to go...
+
+ section .data16
+ alignz 4
+
+ extern __stack_end
+PMESP dd __stack_end ; Protected-mode ESP
+
+PM_IDT_ptr: dw 8*256-1 ; Length
+ dd IDT ; Offset
+
+;
+; This is invoked on getting an interrupt in protected mode. At
+; this point, we need to context-switch to real mode and invoke
+; the interrupt routine.
+;
+; When this gets invoked, the registers are saved on the stack and
+; AL contains the register number.
+;
+ bits 32
+ section .textnr
+pm_irq:
+ pushad
+ movzx esi,byte [esp+8*4] ; Interrupt number
+ mov ebx,.rm
+ jmp enter_rm ; Go to real mode
+
+ bits 16
+ section .text16
+.rm:
+ pushf ; Flags on stack
+ call far [cs:esi*4] ; Call IVT entry
+ mov ebx,.pm
+ jmp enter_pm ; Go back to PM
+
+ bits 32
+ section .textnr
+.pm:
+ popad
+ add esp,4 ; Drop interrupt number
+ iretd
+
+ bits 16
+ section .text16
+;
+; Routines to enable and disable (yuck) A20. These routines are gathered
+; from tips from a couple of sources, including the Linux kernel and
+; http://www.x86.org/. The need for the delay to be as large as given here
+; is indicated by Donnie Barnes of RedHat, the problematic system being an
+; IBM ThinkPad 760EL.
+;
+
+ section .data16
+ alignz 2
+A20Ptr dw a20_dunno
+
+ section .bss16
+ alignb 4
+A20Test resd 1 ; Counter for testing A20 status
+A20Tries resb 1 ; Times until giving up on A20
+
+ section .text16
+enable_a20:
+ pushad
+ mov byte [cs:A20Tries],255 ; Times to try to make this work
+
+try_enable_a20:
+
+;
+; First, see if we are on a system with no A20 gate, or the A20 gate
+; is already enabled for us...
+;
+a20_none:
+ call a20_test
+ jnz a20_done
+ ; Otherwise, see if we had something memorized...
+ jmp word [cs:A20Ptr]
+
+;
+; Next, try the BIOS (INT 15h AX=2401h)
+;
+a20_dunno:
+a20_bios:
+ mov word [cs:A20Ptr], a20_bios
+ mov ax,2401h
+ pushf ; Some BIOSes muck with IF
+ int 15h
+ popf
+
+ call a20_test
+ jnz a20_done
+
+;
+; Enable the keyboard controller A20 gate
+;
+a20_kbc:
+ mov dl, 1 ; Allow early exit
+ call empty_8042
+ jnz a20_done ; A20 live, no need to use KBC
+
+ mov word [cs:A20Ptr], a20_kbc ; Starting KBC command sequence
+
+ mov al,0D1h ; Write output port
+ out 064h, al
+ call empty_8042_uncond
+
+ mov al,0DFh ; A20 on
+ out 060h, al
+ call empty_8042_uncond
+
+ ; Apparently the UHCI spec assumes that A20 toggle
+ ; ends with a null command (assumed to be for sychronization?)
+ ; Put it here to see if it helps anything...
+ mov al,0FFh ; Null command
+ out 064h, al
+ call empty_8042_uncond
+
+ ; Verify that A20 actually is enabled. Do that by
+ ; observing a word in low memory and the same word in
+ ; the HMA until they are no longer coherent. Note that
+ ; we don't do the same check in the disable case, because
+ ; we don't want to *require* A20 masking (SYSLINUX should
+ ; work fine without it, if the BIOS does.)
+.kbc_wait: push cx
+ xor cx,cx
+.kbc_wait_loop:
+ call a20_test
+ jnz a20_done_pop
+ loop .kbc_wait_loop
+
+ pop cx
+;
+; Running out of options here. Final attempt: enable the "fast A20 gate"
+;
+a20_fast:
+ mov word [cs:A20Ptr], a20_fast
+ in al, 092h
+ or al,02h
+ and al,~01h ; Don't accidentally reset the machine!
+ out 092h, al
+
+.fast_wait: push cx
+ xor cx,cx
+.fast_wait_loop:
+ call a20_test
+ jnz a20_done_pop
+ loop .fast_wait_loop
+
+ pop cx
+
+;
+; Oh bugger. A20 is not responding. Try frobbing it again; eventually give up
+; and report failure to the user.
+;
+ dec byte [cs:A20Tries]
+ jnz a20_dunno ; Did we get the wrong type?
+
+ mov si, err_a20
+ jmp abort_load
+
+ section .data16
+err_a20 db CR, LF, 'A20 gate not responding!', CR, LF, 0
+ section .text16
+
+;
+; A20 unmasked, proceed...
+;
+a20_done_pop: pop cx
+a20_done: popad
+ ret
+
+;
+; This routine tests if A20 is enabled (ZF = 0). This routine
+; must not destroy any register contents.
+;
+; The no-write early out avoids the io_delay in the (presumably common)
+; case of A20 already enabled (e.g. from a previous call.)
+;
+a20_test:
+ push es
+ push cx
+ push eax
+ mov cx,0FFFFh ; HMA = segment 0FFFFh
+ mov es,cx
+ mov eax,[cs:A20Test]
+ mov cx,32 ; Loop count
+ jmp .test ; First iteration = early out
+.wait: add eax,0x430aea41 ; A large prime number
+ mov [cs:A20Test],eax
+ io_delay ; Serialize, and fix delay
+.test: cmp eax,[es:A20Test+10h]
+ loopz .wait
+.done: pop eax
+ pop cx
+ pop es
+ ret
+
+;
+; Routine to empty the 8042 KBC controller. If dl != 0
+; then we will test A20 in the loop and exit if A20 is
+; suddenly enabled.
+;
+empty_8042_uncond:
+ xor dl,dl
+empty_8042:
+ call a20_test
+ jz .a20_on
+ and dl,dl
+ jnz .done
+.a20_on: io_delay
+ in al, 064h ; Status port
+ test al,1
+ jz .no_output
+ io_delay
+ in al, 060h ; Read input
+ jmp short empty_8042
+.no_output:
+ test al,2
+ jnz empty_8042
+ io_delay
+.done: ret
+
+;
+; This initializes the protected-mode interrupt thunk set
+;
+ section .text16
+pm_init:
+ xor edi,edi
+ mov bx,IDT
+ mov di,IRQStubs
+
+ mov eax,7aeb006ah ; push byte .. jmp short ..
+
+ mov cx,8 ; 8 groups of 32 IRQs
+.gloop:
+ push cx
+ mov cx,32 ; 32 entries per group
+.eloop:
+ mov [bx],di ; IDT offset [15:0]
+ mov word [bx+2],PM_CS32 ; IDT segment
+ mov dword [bx+4],08e00h ; IDT offset [31:16], 32-bit interrupt
+ ; gate, CPL 0 (we don't have a TSS
+ ; set up...)
+ add bx,8
+
+ stosd
+ ; Increment IRQ, decrement jmp short offset
+ add eax,(-4 << 24)+(1 << 8)
+
+ loop .eloop
+
+ ; At the end of each group, replace the EBxx with
+ ; the final E9xxxxxxxx
+ add di,3
+ mov byte [di-5],0E9h ; JMP NEAR
+ mov edx,pm_irq
+ sub edx,edi
+ mov [di-4],edx
+
+ add eax,(0x80 << 24) ; Proper offset for the next one
+ pop cx
+ loop .gloop
+
+ ret
+
+ ; pm_init is called before bss clearing, so put these
+ ; in .earlybss!
+ section .earlybss
+ alignb 8
+IDT: resq 256
+RealModeSSSP resd 1 ; Real-mode SS:SP
+
+ section .gentextnr ; Autogenerated 32-bit code
+IRQStubs: resb 4*256+3*8
+
+ section .text16
+
+%include "callback.inc" ; Real-mode callbacks
diff --git a/contrib/syslinux-4.02/core/pmapi.c b/contrib/syslinux-4.02/core/pmapi.c
new file mode 100644
index 0000000..4b1ccbb
--- /dev/null
+++ b/contrib/syslinux-4.02/core/pmapi.c
@@ -0,0 +1,43 @@
+/* -----------------------------------------------------------------------
+ *
+ * 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.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <inttypes.h>
+#include <com32.h>
+#include <syslinux/pmapi.h>
+#include "core.h"
+#include "fs.h"
+
+const struct com32_pmapi pm_api_vector =
+{
+ .__pmapi_size = sizeof(struct com32_pmapi),
+
+ .lmalloc = pmapi_lmalloc, /* Allocate low memory */
+ .lfree = free, /* Free low memory */
+
+ .open_file = open_file,
+ .read_file = pmapi_read_file,
+ .close_file = close_file,
+
+ .opendir = opendir,
+ .readdir = readdir,
+ .closedir = closedir,
+
+ .idle = __idle,
+ .reset_idle = reset_idle,
+
+ .chdir = chdir,
+ .getcwd = getcwd,
+
+ .jiffies = &__jiffies,
+ .ms_timer = &__ms_timer,
+};
diff --git a/contrib/syslinux-4.02/core/pmcall.inc b/contrib/syslinux-4.02/core/pmcall.inc
new file mode 100644
index 0000000..0a58015
--- /dev/null
+++ b/contrib/syslinux-4.02/core/pmcall.inc
@@ -0,0 +1,70 @@
+;;
+;; pmcall.inc
+;;
+;; Macros for the stack frame set up by pm_call, assuming ebp is left
+;; as the RM frame pointer.
+;;
+
+%ifndef PMCALL_INC
+%define PMCALL_INC
+
+%define RM_GS word [ebp]
+%define RM_FS word [ebp+2]
+%define RM_ES word [ebp+4]
+%define RM_DS word [ebp+6]
+
+%define RM_EDI dword [ebp+8]
+%define RM_DI word [ebp+8]
+%define RM_HDI word [ebp+10]
+%define RM_DIL byte [ebp+8]
+%define RM_DIH byte [ebp+9]
+
+%define RM_ESI dword [ebp+12]
+%define RM_SI word [ebp+12]
+%define RM_HSI word [ebp+14]
+%define RM_SIL byte [ebp+12]
+%define RM_SIH byte [ebp+13]
+
+%define RM_EBP dword [ebp+16]
+%define RM_BP word [ebp+16]
+%define RM_HBP word [ebp+18]
+%define RM_BPL byte [ebp+16]
+%define RM_BPH byte [ebp+17]
+
+%define RM_EBX dword [ebp+24]
+%define RM_BX word [ebp+24]
+%define RM_HBX word [ebp+26]
+%define RM_BL byte [ebp+24]
+%define RM_BH byte [ebp+25]
+
+%define RM_EDX dword [ebp+28]
+%define RM_DX word [ebp+28]
+%define RM_HDX word [ebp+30]
+%define RM_DL byte [ebp+28]
+%define RM_DH byte [ebp+29]
+
+%define RM_ECX dword [ebp+32]
+%define RM_CX word [ebp+32]
+%define RM_HCX word [ebp+34]
+%define RM_CL byte [ebp+32]
+%define RM_CH byte [ebp+33]
+
+%define RM_EAX dword [ebp+36]
+%define RM_AX word [ebp+36]
+%define RM_HAX word [ebp+38]
+%define RM_AL byte [ebp+36]
+%define RM_AH byte [ebp+37]
+
+%define RM_EFLAGS dword [ebp+40]
+%define RM_FLAGS word [ebp+40]
+%define RM_HFLAGS word [ebp+42]
+%define RM_FLAGSL byte [ebp+40]
+%define RM_FLAGSH byte [ebp+41]
+
+; Convenience macro to call a PM function
+%macro pm_call 1
+ push dword %1
+ call _pm_call
+%endmacro
+
+%endif ; PMCALL_INC
diff --git a/contrib/syslinux-4.02/core/prefix.inc b/contrib/syslinux-4.02/core/prefix.inc
new file mode 100644
index 0000000..9c8724b
--- /dev/null
+++ b/contrib/syslinux-4.02/core/prefix.inc
@@ -0,0 +1,17 @@
+;
+; The prefix is a small structure that prefaces the actual code;
+; it gives the compression program necessary information.
+;
+
+ section .prefix nowrite progbits align=16
+pfx_start dd _start ; Start of raw chunk
+pfx_compressed dd __pm_code_lma ; Start of compressed chunk
+pfx_cdatalen dd lzo_data_size ; Pointer to compressed size field
+%if IS_ISOLINUX
+pfx_checksum dd bi_length ; File length and checksum fields
+%else
+pfx_checksum dd 0 ; No checksum
+%endif
+pfx_maxlma dd MaxLMA ; Maximum size
+
+ section .text16
diff --git a/contrib/syslinux-4.02/core/printf.c b/contrib/syslinux-4.02/core/printf.c
new file mode 100644
index 0000000..b1b0466
--- /dev/null
+++ b/contrib/syslinux-4.02/core/printf.c
@@ -0,0 +1,20 @@
+#include <stdio.h>
+#include <unistd.h>
+
+#include "core.h"
+
+int printf(const char *format, ...)
+{
+ char buf[1024];
+ va_list ap;
+ int rv;
+
+ va_start(ap, format);
+ rv = vsnprintf(buf, sizeof buf, format, ap);
+ va_end(ap);
+
+ myputs(buf);
+
+ return rv;
+
+}
diff --git a/contrib/syslinux-4.02/core/pxe.inc b/contrib/syslinux-4.02/core/pxe.inc
new file mode 100644
index 0000000..2fd1edb
--- /dev/null
+++ b/contrib/syslinux-4.02/core/pxe.inc
@@ -0,0 +1,155 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1999-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., 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.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; pxe.inc
+;;
+;; PXE opcodes
+;;
+
+%ifndef _PXE_INC
+%define _PXE_INC 1
+
+%define PXENV_TFTP_OPEN 0x0020
+%define PXENV_TFTP_CLOSE 0x0021
+%define PXENV_TFTP_READ 0x0022
+%define PXENV_TFTP_READ_FILE 0x0023
+%define PXENV_TFTP_READ_FILE_PMODE 0x0024
+%define PXENV_TFTP_GET_FSIZE 0x0025
+
+%define PXENV_UDP_OPEN 0x0030
+%define PXENV_UDP_CLOSE 0x0031
+%define PXENV_UDP_READ 0x0032
+%define PXENV_UDP_WRITE 0x0033
+
+%define PXENV_START_UNDI 0x0000
+%define PXENV_UNDI_STARTUP 0x0001
+%define PXENV_UNDI_CLEANUP 0x0002
+%define PXENV_UNDI_INITIALIZE 0x0003
+%define PXENV_UNDI_RESET_NIC 0x0004
+%define PXENV_UNDI_SHUTDOWN 0x0005
+%define PXENV_UNDI_OPEN 0x0006
+%define PXENV_UNDI_CLOSE 0x0007
+%define PXENV_UNDI_TRANSMIT 0x0008
+%define PXENV_UNDI_SET_MCAST_ADDR 0x0009
+%define PXENV_UNDI_SET_STATION_ADDR 0x000A
+%define PXENV_UNDI_SET_PACKET_FILTER 0x000B
+%define PXENV_UNDI_GET_INFORMATION 0x000C
+%define PXENV_UNDI_GET_STATISTICS 0x000D
+%define PXENV_UNDI_CLEAR_STATISTICS 0x000E
+%define PXENV_UNDI_INITIATE_DIAGS 0x000F
+%define PXENV_UNDI_FORCE_INTERRUPT 0x0010
+%define PXENV_UNDI_GET_MCAST_ADDR 0x0011
+%define PXENV_UNDI_GET_NIC_TYPE 0x0012
+%define PXENV_UNDI_GET_IFACE_INFO 0x0013
+%define PXENV_UNDI_ISR 0x0014
+%define PXENV_STOP_UNDI 0x0015 ; Overlap...?
+%define PXENV_UNDI_GET_STATE 0x0015 ; Overlap...?
+
+%define PXENV_UNLOAD_STACK 0x0070
+%define PXENV_GET_CACHED_INFO 0x0071
+%define PXENV_RESTART_DHCP 0x0072
+%define PXENV_RESTART_TFTP 0x0073
+%define PXENV_MODE_SWITCH 0x0074
+%define PXENV_START_BASE 0x0075
+%define PXENV_STOP_BASE 0x0076
+
+; gPXE extensions...
+%define PXENV_FILE_OPEN 0x00e0
+%define PXENV_FILE_CLOSE 0x00e1
+%define PXENV_FILE_SELECT 0x00e2
+%define PXENV_FILE_READ 0x00e3
+%define PXENV_GET_FILE_SIZE 0x00e4
+%define PXENV_FILE_EXEC 0x00e5
+%define PXENV_FILE_API_CHECK 0x00e6
+%define PXENV_FILE_EXIT_HOOK 0x00e7
+
+; Exit codes
+%define PXENV_EXIT_SUCCESS 0x0000
+%define PXENV_EXIT_FAILURE 0x0001
+
+; Status codes
+%define PXENV_STATUS_SUCCESS 0x00
+%define PXENV_STATUS_FAILURE 0x01
+%define PXENV_STATUS_BAD_FUNC 0x02
+%define PXENV_STATUS_UNSUPPORTED 0x03
+%define PXENV_STATUS_KEEP_UNDI 0x04
+%define PXENV_STATUS_KEEP_ALL 0x05
+%define PXENV_STATUS_OUT_OF_RESOURCES 0x06
+%define PXENV_STATUS_ARP_TIMEOUT 0x11
+%define PXENV_STATUS_UDP_CLOSED 0x18
+%define PXENV_STATUS_UDP_OPEN 0x19
+%define PXENV_STATUS_TFTP_CLOSED 0x1a
+%define PXENV_STATUS_TFTP_OPEN 0x1b
+%define PXENV_STATUS_MCOPY_PROBLEM 0x20
+%define PXENV_STATUS_BIS_INTEGRITY_FAILURE 0x21
+%define PXENV_STATUS_BIS_VALIDATE_FAILURE 0x22
+%define PXENV_STATUS_BIS_INIT_FAILURE 0x23
+%define PXENV_STATUS_BIS_SHUTDOWN_FAILURE 0x24
+%define PXENV_STATUS_BIS_GBOA_FAILURE 0x25
+%define PXENV_STATUS_BIS_FREE_FAILURE 0x26
+%define PXENV_STATUS_BIS_GSI_FAILURE 0x27
+%define PXENV_STATUS_BIS_BAD_CKSUM 0x28
+%define PXENV_STATUS_TFTP_CANNOT_ARP_ADDRESS 0x30
+%define PXENV_STATUS_TFTP_OPEN_TIMEOUT 0x32
+
+%define PXENV_STATUS_TFTP_UNKNOWN_OPCODE 0x33
+%define PXENV_STATUS_TFTP_READ_TIMEOUT 0x35
+%define PXENV_STATUS_TFTP_ERROR_OPCODE 0x36
+%define PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION 0x38
+%define PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION 0x39
+%define PXENV_STATUS_TFTP_TOO_MANY_PACKAGES 0x3a
+%define PXENV_STATUS_TFTP_FILE_NOT_FOUND 0x3b
+%define PXENV_STATUS_TFTP_ACCESS_VIOLATION 0x3c
+%define PXENV_STATUS_TFTP_NO_MCAST_ADDRESS 0x3d
+%define PXENV_STATUS_TFTP_NO_FILESIZE 0x3e
+%define PXENV_STATUS_TFTP_INVALID_PACKET_SIZE 0x3f
+%define PXENV_STATUS_DHCP_TIMEOUT 0x51
+%define PXENV_STATUS_DHCP_NO_IP_ADDRESS 0x52
+%define PXENV_STATUS_DHCP_NO_BOOTFILE_NAME 0x53
+%define PXENV_STATUS_DHCP_BAD_IP_ADDRESS 0x54
+%define PXENV_STATUS_UNDI_INVALID_FUNCTION 0x60
+%define PXENV_STATUS_UNDI_MEDIATEST_FAILED 0x61
+%define PXENV_STATUS_UNDI_CANNOT_INIT_NIC_FOR_MCAST 0x62
+%define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC 0x63
+%define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_PHY 0x64
+%define PXENV_STATUS_UNDI_CANNOT_READ_CONFIG_DATA 0x65
+%define PXENV_STATUS_UNDI_CANNOT_READ_INIT_DATA 0x66
+%define PXENV_STATUS_UNDI_BAD_MAC_ADDRESS 0x67
+%define PXENV_STATUS_UNDI_BAD_EEPROM_CHECKSUM 0x68
+%define PXENV_STATUS_UNDI_ERROR_SETTING_ISR 0x69
+%define PXENV_STATUS_UNDI_INVALID_STATE 0x6a
+%define PXENV_STATUS_UNDI_TRANSMIT_ERROR 0x6b
+%define PXENV_STATUS_UNDI_INVALID_PARAMETER 0x6c
+%define PXENV_STATUS_BSTRAP_PROMPT_MENU 0x74
+%define PXENV_STATUS_BSTRAP_MCAST_ADDR 0x76
+%define PXENV_STATUS_BSTRAP_MISSING_LIST 0x77
+%define PXENV_STATUS_BSTRAP_NO_RESPONSE 0x78
+%define PXENV_STATUS_BSTRAP_FILE_TOO_BIG 0x79
+%define PXENV_STATUS_BINL_CANCELED_BY_KEYSTROKE 0xa0
+%define PXENV_STATUS_BINL_NO_PXE_SERVER 0xa1
+%define PXENV_STATUS_NOT_AVAILABLE_IN_PMODE 0xa2
+%define PXENV_STATUS_NOT_AVAILABLE_IN_RMODE 0xa3
+%define PXENV_STATUS_BUSD_DEVICE_NOT_SUPPORTED 0xb0
+%define PXENV_STATUS_LOADER_NO_FREE_BASE_MEMORY 0xc0
+%define PXENV_STATUS_LOADER_NO_BC_ROMID 0xc1
+%define PXENV_STATUS_LOADER_BAD_BC_ROMID 0xc2
+%define PXENV_STATUS_LOADER_BAD_BC_RUNTIME_IMAGE 0xc3
+%define PXENV_STATUS_LOADER_NO_UNDI_ROMID 0xc4
+%define PXENV_STATUS_LOADER_BAD_UNDI_ROMID 0xc5
+%define PXENV_STATUS_LOADER_BAD_UNDI_DRIVER_IMAGE 0xc6
+%define PXENV_STATUS_LOADER_NO_PXE_STRUCT 0xc8
+%define PXENV_STATUS_LOADER_NO_PXENV_STRUCT 0xc9
+%define PXENV_STATUS_LOADER_UNDI_START 0xca
+%define PXENV_STATUS_LOADER_BC_START 0xcb
+
+%endif ; _PXE_INC
diff --git a/contrib/syslinux-4.02/core/pxelinux.asm b/contrib/syslinux-4.02/core/pxelinux.asm
new file mode 100644
index 0000000..8084ac9
--- /dev/null
+++ b/contrib/syslinux-4.02/core/pxelinux.asm
@@ -0,0 +1,544 @@
+; -*- fundamental -*- (asm-mode sucks)
+; ****************************************************************************
+;
+; pxelinux.asm
+;
+; A program to boot Linux kernels off a TFTP server using the Intel PXE
+; network booting API. It is based on the SYSLINUX boot loader for
+; MS-DOS floppies.
+;
+; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
+; Copyright 2009 Intel Corporation; author: H. Peter Anvin
+;
+; This program is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+; Boston MA 02111-1307, USA; either version 2 of the License, or
+; (at your option) any later version; incorporated herein by reference.
+;
+; ****************************************************************************
+
+%define IS_PXELINUX 1
+%include "head.inc"
+%include "pxe.inc"
+
+; gPXE extensions support
+%define GPXE 1
+
+;
+; Some semi-configurable constants... change on your own risk.
+;
+my_id equ pxelinux_id
+NULLFILE equ 0 ; Zero byte == null file name
+NULLOFFSET equ 0 ; Position in which to look
+REBOOT_TIME equ 5*60 ; If failure, time until full reset
+%assign HIGHMEM_SLOP 128*1024 ; Avoid this much memory near the top
+TFTP_BLOCKSIZE_LG2 equ 9 ; log2(bytes/block)
+TFTP_BLOCKSIZE equ (1 << TFTP_BLOCKSIZE_LG2)
+
+SECTOR_SHIFT equ TFTP_BLOCKSIZE_LG2
+SECTOR_SIZE equ TFTP_BLOCKSIZE
+
+;
+; The following structure is used for "virtual kernels"; i.e. LILO-style
+; option labels. The options we permit here are `kernel' and `append
+; Since there is no room in the bottom 64K for all of these, we
+; stick them in high memory and copy them down before we need them.
+;
+ struc vkernel
+vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!**
+vk_rname: resb FILENAME_MAX ; Real name
+vk_ipappend: resb 1 ; "IPAPPEND" flag
+vk_type: resb 1 ; Type of file
+vk_appendlen: resw 1
+ alignb 4
+vk_append: resb max_cmd_len+1 ; Command line
+ alignb 4
+vk_end: equ $ ; Should be <= vk_size
+ endstruc
+
+
+; ---------------------------------------------------------------------------
+; BEGIN CODE
+; ---------------------------------------------------------------------------
+
+;
+; Memory below this point is reserved for the BIOS and the MBR
+;
+ section .earlybss
+ global trackbuf
+trackbufsize equ 8192
+trackbuf resb trackbufsize ; Track buffer goes here
+ ; ends at 2800h
+
+ ; These fields save information from before the time
+ ; .bss is zeroed... must be in .earlybss
+ global InitStack
+InitStack resd 1
+
+ section .bss16
+ alignb FILENAME_MAX
+PXEStack resd 1 ; Saved stack during PXE call
+
+ alignb 4
+ global DHCPMagic, RebootTime, APIVer
+RebootTime resd 1 ; Reboot timeout, if set by option
+StrucPtr resw 2 ; Pointer to PXENV+ or !PXE structure
+APIVer resw 1 ; PXE API version found
+LocalBootType resw 1 ; Local boot return code
+DHCPMagic resb 1 ; PXELINUX magic flags
+
+ section .text16
+StackBuf equ STACK_TOP-44 ; Base of stack if we use our own
+StackHome equ StackBuf
+
+ ; PXE loads the whole file, but assume it can't be more
+ ; than (384-31)K in size.
+MaxLMA equ 384*1024
+
+;
+; Primary entry point.
+;
+bootsec equ $
+_start:
+ jmp 0:_start1 ; Canonicalize the address and skip
+ ; the patch header
+
+;
+; Patch area for adding hardwired DHCP options
+;
+ align 4
+
+hcdhcp_magic dd 0x2983c8ac ; Magic number
+hcdhcp_len dd 7*4 ; Size of this structure
+hcdhcp_flags dd 0 ; Reserved for the future
+ ; Parameters to be parsed before the ones from PXE
+bdhcp_offset dd 0 ; Offset (entered by patcher)
+bdhcp_len dd 0 ; Length (entered by patcher)
+ ; Parameters to be parsed *after* the ones from PXE
+adhcp_offset dd 0 ; Offset (entered by patcher)
+adhcp_len dd 0 ; Length (entered by patcher)
+
+_start1:
+ pushfd ; Paranoia... in case of return to PXE
+ pushad ; ... save as much state as possible
+ push ds
+ push es
+ push fs
+ push gs
+
+ cld ; Copy upwards
+ xor ax,ax
+ mov ds,ax
+ mov es,ax
+
+%if 0 ; debugging code only... not intended for production use
+ ; Clobber the stack segment, to test for specific pathologies
+ mov di,STACK_BASE
+ mov cx,STACK_LEN >> 1
+ mov ax,0xf4f4
+ rep stosw
+
+ ; Clobber the tail of the 64K segment, too
+ extern __bss1_end
+ mov di,__bss1_end
+ sub cx,di ; CX = 0 previously
+ shr cx,1
+ rep stosw
+%endif
+
+ ; That is all pushed onto the PXE stack. Save the pointer
+ ; to it and switch to an internal stack.
+ mov [InitStack],sp
+ mov [InitStack+2],ss
+
+ 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)
+;
+%include "init.inc"
+
+;
+; Tell the user we got this far
+;
+ mov si,syslinux_banner
+ call writestr_early
+
+ mov si,copyright_str
+ call writestr_early
+
+;
+; do fs initialize
+;
+ mov eax,ROOT_FS_OPS
+ xor ebp,ebp
+ pm_call fs_init
+
+ section .rodata
+ alignz 4
+ROOT_FS_OPS:
+ extern pxe_fs_ops
+ dd pxe_fs_ops
+ dd 0
+
+
+ section .text16
+;
+; Initialize the idle mechanism
+;
+ call reset_idle
+
+;
+; Now we're all set to start with our *real* business. First load the
+; configuration file (if any) and parse it.
+;
+; In previous versions I avoided using 32-bit registers because of a
+; rumour some BIOSes clobbered the upper half of 32-bit registers at
+; random. I figure, though, that if there are any of those still left
+; they probably won't be trying to install Linux on them...
+;
+; The code is still ripe with 16-bitisms, though. Not worth the hassle
+; to take'm out. In fact, we may want to put them back if we're going
+; to boot ELKS at some point.
+;
+
+;
+; Load configuration file
+;
+ pm_call load_config
+
+;
+; Linux kernel loading code is common. However, we need to define
+; a couple of helper macros...
+;
+
+; Unload PXE stack
+%define HAVE_UNLOAD_PREP
+%macro UNLOAD_PREP 0
+ pm_call unload_pxe
+%endmacro
+
+;
+; Now we have the config file open. Parse the config file and
+; run the user interface.
+;
+%include "ui.inc"
+
+;
+; Boot to the local disk by returning the appropriate PXE magic.
+; AX contains the appropriate return code.
+;
+local_boot:
+ push cs
+ pop ds
+ mov [LocalBootType],ax
+ call vgaclearmode
+ mov si,localboot_msg
+ call writestr_early
+ ; Restore the environment we were called with
+ pm_call reset_pxe
+ call cleanup_hardware
+ lss sp,[InitStack]
+ pop gs
+ pop fs
+ pop es
+ pop ds
+ popad
+ mov ax,[cs:LocalBootType]
+ cmp ax,-1 ; localboot -1 == INT 18h
+ je .int18
+ popfd
+ retf ; Return to PXE
+.int18:
+ popfd
+ int 18h
+ jmp 0F000h:0FFF0h
+ hlt
+
+;
+; kaboom: write a message and bail out. Wait for quite a while,
+; or a user keypress, then do a hard reboot.
+;
+; Note: use BIOS_timer here; we may not have jiffies set up.
+;
+ global kaboom
+kaboom:
+ RESET_STACK_AND_SEGS AX
+.patch: mov si,bailmsg
+ call writestr_early ; Returns with AL = 0
+.drain: call pollchar
+ jz .drained
+ call getchar
+ jmp short .drain
+.drained:
+ mov edi,[RebootTime]
+ mov al,[DHCPMagic]
+ and al,09h ; Magic+Timeout
+ cmp al,09h
+ je .time_set
+ mov edi,REBOOT_TIME
+.time_set:
+ mov cx,18
+.wait1: push cx
+ mov ecx,edi
+.wait2: mov dx,[BIOS_timer]
+.wait3: call pollchar
+ jnz .keypress
+ call do_idle
+ cmp dx,[BIOS_timer]
+ je .wait3
+ loop .wait2,ecx
+ mov al,'.'
+ call writechr
+ pop cx
+ loop .wait1
+.keypress:
+ call crlf
+ mov word [BIOS_magic],0 ; Cold reboot
+ jmp 0F000h:0FFF0h ; Reset vector address
+
+
+;
+; pxenv
+;
+; This is the main PXENV+/!PXE entry point, using the PXENV+
+; calling convention. This is a separate local routine so
+; we can hook special things from it if necessary. In particular,
+; some PXE stacks seem to not like being invoked from anything but
+; the initial stack, so humour it.
+;
+; While we're at it, save and restore all registers.
+;
+ global pxenv
+pxenv:
+ pushfd
+ pushad
+
+ mov [cs:PXEStack],sp
+ mov [cs:PXEStack+2],ss
+ lss sp,[cs:InitStack]
+
+ ; Pre-clear the Status field
+ mov word [es:di],cs
+
+ ; This works either for the PXENV+ or the !PXE calling
+ ; convention, as long as we ignore CF (which is redundant
+ ; with AX anyway.)
+ push es
+ push di
+ push bx
+.jump: call 0:0
+ add sp,6
+ mov [cs:PXEStatus],ax
+
+ lss sp,[cs:PXEStack]
+
+ mov bp,sp
+ and ax,ax
+ setnz [bp+32] ; If AX != 0 set CF on return
+
+ ; This clobbers the AX return, but we already saved it into
+ ; the PXEStatus variable.
+ popad
+ popfd ; Restore flags (incl. IF, DF)
+ ret
+
+; Must be after function def due to NASM bug
+ global PXEEntry
+PXEEntry equ pxenv.jump+1
+
+ section .bss16
+ alignb 2
+PXEStatus resb 2
+
+
+ section .text16
+;
+; Invoke INT 1Ah on the PXE stack. This is used by the "Plan C" method
+; for finding the PXE entry point.
+;
+ global pxe_int1a
+pxe_int1a:
+ mov [cs:PXEStack],sp
+ mov [cs:PXEStack+2],ss
+ lss sp,[cs:InitStack]
+
+ int 1Ah ; May trash registers
+
+ lss sp,[cs:PXEStack]
+ ret
+
+;
+; Special unload for gPXE: this switches the InitStack from
+; gPXE to the ROM PXE stack.
+;
+%if GPXE
+ global gpxe_unload
+gpxe_unload:
+ mov bx,PXENV_FILE_EXIT_HOOK
+ mov di,pxe_file_exit_hook
+ call pxenv
+ jc .plain
+
+ ; Now we actually need to exit back to gPXE, which will
+ ; give control back to us on the *new* "original stack"...
+ pushfd
+ push ds
+ push es
+ mov [PXEStack],sp
+ mov [PXEStack+2],ss
+ lss sp,[InitStack]
+ pop gs
+ pop fs
+ pop es
+ pop ds
+ popad
+ popfd
+ xor ax,ax
+ retf
+.resume:
+ cli
+
+ ; gPXE will have a stack frame looking much like our
+ ; InitStack, except it has a magic cookie at the top,
+ ; and the segment registers are in reverse order.
+ pop eax
+ pop ax
+ pop bx
+ pop cx
+ pop dx
+ push ax
+ push bx
+ push cx
+ push dx
+ mov [cs:InitStack],sp
+ mov [cs:InitStack+2],ss
+ lss sp,[cs:PXEStack]
+ pop es
+ pop ds
+ popfd
+
+.plain:
+ ret
+
+ section .data16
+ alignz 4
+pxe_file_exit_hook:
+.status: dw 0
+.offset: dw gpxe_unload.resume
+.seg: dw 0
+%endif
+
+ section .text16
+
+; -----------------------------------------------------------------------------
+; Common modules
+; -----------------------------------------------------------------------------
+
+%include "common.inc" ; Universal modules
+%include "writestr.inc" ; String output
+writestr_early equ writestr
+%include "writehex.inc" ; Hexadecimal output
+%include "rawcon.inc" ; Console I/O w/o using the console functions
+
+; -----------------------------------------------------------------------------
+; Begin data section
+; -----------------------------------------------------------------------------
+
+ section .data16
+
+copyright_str db ' Copyright (C) 1994-'
+ asciidec YEAR
+ db ' H. Peter Anvin et al', CR, LF, 0
+err_bootfailed db CR, LF, 'Boot failed: press a key to retry, or wait for reset...', CR, LF, 0
+bailmsg equ err_bootfailed
+localboot_msg db 'Booting from local disk...', CR, LF, 0
+syslinux_banner db CR, LF, MY_NAME, ' ', VERSION_STR, ' ', DATE_STR, ' ', 0
+
+;
+; Config file keyword table
+;
+%include "keywords.inc"
+
+;
+; Extensions to search for (in *forward* order).
+; (.bs and .bss16 are disabled for PXELINUX, since they are not supported)
+;
+ alignz 4
+exten_table: db '.cbt' ; COMBOOT (specific)
+ db '.0', 0, 0 ; PXE bootstrap program
+ db '.com' ; COMBOOT (same as DOS)
+ db '.c32' ; COM32
+exten_table_end:
+ dd 0, 0 ; Need 8 null bytes here
+
+;
+; Misc initialized (data) variables
+;
+ section .data16
+ global KeepPXE
+KeepPXE db 0 ; Should PXE be kept around?
+
+;
+; IP information. Note that the field are in the same order as the
+; Linux kernel expects in the ip= option.
+;
+ section .bss16
+ alignb 4
+ global IPInfo
+IPInfo:
+.IPv4 resd 1 ; IPv4 information
+.MyIP resd 1 ; My IP address
+.ServerIP resd 1
+.GatewayIP resd 1
+.Netmask resd 1
diff --git a/contrib/syslinux-4.02/core/rawcon.inc b/contrib/syslinux-4.02/core/rawcon.inc
new file mode 100644
index 0000000..f0d434c
--- /dev/null
+++ b/contrib/syslinux-4.02/core/rawcon.inc
@@ -0,0 +1,75 @@
+;
+; writechr: Write a single character in AL to the console without
+; mangling any registers. This does raw console writes,
+; since some PXE BIOSes seem to interfere regular console I/O.
+;
+%if IS_ISOLINUX
+writechr_full:
+%else
+writechr:
+%endif
+ pushfd
+ push ds
+ push cs
+ pop ds
+ test byte [UsingVGA], 08h
+ jz .videook
+ call vgaclearmode
+.videook:
+ call write_serial ; write to serial port if needed
+ test byte [DisplayCon],01h ; Write to screen?
+ jz .nothing
+
+ pushad
+ mov bh,[BIOS_page]
+ push ax
+ mov ah,03h ; Read cursor position
+ int 10h
+ pop ax
+ cmp al,8
+ je .bs
+ cmp al,13
+ je .cr
+ cmp al,10
+ je .lf
+ push dx
+ mov bh,[BIOS_page]
+ mov bl,07h ; White on black
+ mov cx,1 ; One only
+ mov ah,09h ; Write char and attribute
+ int 10h
+ pop dx
+ inc dl
+ cmp dl,[VidCols]
+ jna .curxyok
+ xor dl,dl
+.lf: inc dh
+ cmp dh,[VidRows]
+ ja .scroll
+.curxyok: mov bh,[BIOS_page]
+ mov ah,02h ; Set cursor position
+ int 10h
+.ret: popad
+.nothing:
+ pop ds
+ popfd
+ ret
+.scroll: dec dh
+ mov bh,[BIOS_page]
+ mov ah,02h
+ int 10h
+ mov ax,0601h ; Scroll up one line
+ mov bh,[ScrollAttribute]
+ xor cx,cx
+ mov dx,[ScreenSize] ; The whole screen
+ int 10h
+ jmp short .ret
+.cr: xor dl,dl
+ jmp short .curxyok
+.bs: sub dl,1
+ jnc .curxyok
+ mov dl,[VidCols]
+ sub dh,1
+ jnc .curxyok
+ xor dh,dh
+ jmp short .curxyok
diff --git a/contrib/syslinux-4.02/core/regdump.inc b/contrib/syslinux-4.02/core/regdump.inc
new file mode 100644
index 0000000..bdb5172
--- /dev/null
+++ b/contrib/syslinux-4.02/core/regdump.inc
@@ -0,0 +1,108 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 2003-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., 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.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; regdump.inc
+;;
+;; Dump as much as possible of the register state; for debugging
+;;
+
+disk_dumpregs:
+ mov ah,02h
+ call dumpregs
+ int 13h
+ ret
+
+dumpregs:
+ push gs
+ push fs
+ push es
+ push ds
+ push ss
+ push cs
+ pushad
+ pushfd
+
+ push cs
+ pop ds
+
+ mov bp,sp
+ mov di,regnames
+
+ mov cx,9 ; 9 32-bit registers
+.reg8:
+ mov si,[di]
+ inc di
+ inc di
+ call writestr
+ mov eax,[bp]
+ add bp,4
+ call writehex8
+ loop .reg8
+
+ mov cx,7 ; 6 16-bit registers
+.reg4:
+ mov si,[di]
+ inc di
+ inc di
+ call writestr
+ mov eax,[bp]
+ inc bp
+ inc bp
+ call writehex4
+ loop .reg4
+
+ call crlf
+
+ popfd
+ popad
+ add sp,4 ; Skip CS, SS
+ pop ds
+ pop es
+ pop fs
+ pop gs
+ ret
+
+regnames:
+ dw .eflags
+ dw .edi
+ dw .esi
+ dw .ebp
+ dw .esp
+ dw .ebx
+ dw .edx
+ dw .ecx
+ dw .eax
+ dw .cs
+ dw .ss
+ dw .ds
+ dw .es
+ dw .fs
+ dw .gs
+ dw .ip
+
+.eflags db 'EFL: ', 0
+.edi db 13,10,'EDI: ', 0
+.esi db ' ESI: ', 0
+.ebp db ' EBP: ', 0
+.esp db ' ESP: ', 0
+.ebx db 13,10,'EBX: ', 0
+.edx db ' EDX: ', 0
+.ecx db ' ECX: ', 0
+.eax db ' EAX: ', 0
+.cs db 13,10,'CS: ',0
+.ss db ' SS: ',0
+.ds db ' DS: ',0
+.es db ' ES: ',0
+.fs db ' FS: ',0
+.gs db ' GS: ',0
+.ip db ' IP: ',0
diff --git a/contrib/syslinux-4.02/core/rllpack.c b/contrib/syslinux-4.02/core/rllpack.c
new file mode 100644
index 0000000..bb9f046
--- /dev/null
+++ b/contrib/syslinux-4.02/core/rllpack.c
@@ -0,0 +1,105 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2007-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * rllpack.inc
+ *
+ * Very simple RLL compressor/decompressor, used to pack binary structures
+ * together.
+ *
+ * Format of leading byte
+ * 1-128 = x verbatim bytes follow
+ * 129-223 = (x-126) times subsequent byte
+ * 224-255 = (x-224)*256+(next byte) times the following byte
+ * 0 = end of data
+ *
+ * These structures are stored *in reverse order* in high memory.
+ * High memory pointers point to one byte beyond the end.
+ */
+
+#include <com32.h>
+#include <stddef.h>
+#include <string.h>
+
+void rllpack(com32sys_t * regs)
+{
+ uint8_t *i = (uint8_t *) (regs->esi.l);
+ uint8_t *o = (uint8_t *) (regs->edi.l);
+ size_t cnt = regs->ecx.l;
+ size_t run, vrun, tcnt;
+ uint8_t *hdr = NULL;
+ uint8_t c;
+
+ vrun = (size_t)-1;
+ while (cnt) {
+ c = *i;
+
+ run = 1;
+ tcnt = (cnt > 8191) ? 8191 : cnt;
+ while (run < tcnt && i[run] == c)
+ run++;
+
+ if (run < 3) {
+ if (vrun >= 128) {
+ hdr = --o;
+ vrun = 0;
+ }
+ *--o = c;
+ *hdr = ++vrun;
+ i++;
+ cnt--;
+ } else {
+ if (run < 224 - 126) {
+ *--o = run + 126;
+ } else {
+ o -= 2;
+ *(uint16_t *) o = run + (224 << 8);
+ }
+ *--o = c;
+ vrun = (size_t)-1;
+ i += run;
+ cnt -= run;
+ }
+ }
+ *--o = 0;
+
+ regs->esi.l = (size_t)i;
+ regs->edi.l = (size_t)o;
+}
+
+void rllunpack(com32sys_t * regs)
+{
+ uint8_t *i = (uint8_t *) regs->esi.l;
+ uint8_t *o = (uint8_t *) regs->edi.l;
+ uint8_t c;
+ size_t n;
+
+ while ((c = *--i)) {
+ if (c <= 128) {
+ while (c--)
+ *o++ = *--i;
+ } else {
+ if (c < 224)
+ n = c - 126;
+ else
+ n = ((c - 224) << 8) + *--i;
+ c = *--i;
+ while (n--)
+ *o++ = c;
+ }
+ }
+
+ regs->esi.l = (size_t)i;
+ regs->ecx.l = (size_t)o - regs->edi.l;
+ regs->edi.l = (size_t)o;
+}
diff --git a/contrib/syslinux-4.02/core/runkernel.inc b/contrib/syslinux-4.02/core/runkernel.inc
new file mode 100644
index 0000000..25b073f
--- /dev/null
+++ b/contrib/syslinux-4.02/core/runkernel.inc
@@ -0,0 +1,684 @@
+;; -----------------------------------------------------------------------
+;;
+;; 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.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; runkernel.inc
+;;
+;; Common code for running a Linux kernel
+;;
+
+;
+; Hook macros, that may or may not be defined
+;
+%ifndef HAVE_UNLOAD_PREP
+%macro UNLOAD_PREP 0
+%endmacro
+%endif
+
+;
+; A Linux kernel consists of three parts: boot sector, setup code, and
+; kernel code. The boot sector is never executed when using an external
+; booting utility, but it contains some status bytes that are necessary.
+;
+; First check that our kernel is at least 1K, or else it isn't long
+; enough to have the appropriate headers.
+;
+; We used to require the kernel to be 64K or larger, but it has gotten
+; popular to use the Linux kernel format for other things, which may
+; not be so large.
+;
+; Additionally, we used to have a test for 8 MB or smaller. Equally
+; obsolete.
+;
+is_linux_kernel:
+ push si ; <A> file pointer
+
+;
+; Now start transferring the kernel
+;
+ push word real_mode_seg
+ pop es
+
+;
+; Start by loading the bootsector/setup code, to see if we need to
+; do something funky. It should fit in the first 32K (loading 64K won't
+; work since we might have funny stuff up near the end of memory).
+;
+ call abort_check ; Check for abort key
+ mov cx,8000h ; Half a moby (32K)
+ xor bx,bx
+ pop si ; <A> file pointer
+ pm_call getfsbytes
+ cmp cx,1024
+ jb kernel_corrupt
+ cmp word [es:bs_bootsign],0AA55h
+ jne kernel_corrupt ; Boot sec signature missing
+
+;
+; Save the file pointer for later...
+;
+ push si ; <A> file pointer
+
+;
+; Construct the command line (append options have already been copied)
+;
+construct_cmdline:
+ mov di,[CmdLinePtr]
+ mov si,boot_image ; BOOT_IMAGE=
+ mov cx,boot_image_len
+ rep movsb
+ mov si,KernelName ; Unmangled kernel name
+ call strcpy
+ mov byte [es:di-1],' ' ; Follow by space
+
+ call do_ip_append ; Handle IPAppend
+
+ mov si,[CmdOptPtr] ; Options from user input
+ call strcpy
+
+;
+; Scan through the command line for anything that looks like we might be
+; interested in. The original version of this code automatically assumed
+; the first option was BOOT_IMAGE=, but that is no longer certain.
+;
+parse_cmdline:
+ mov di,cmd_line_here
+.skipspace: mov al,[es:di]
+ inc di
+.skipspace_loaded:
+ and al,al
+ jz cmdline_end
+ cmp al,' '
+ jbe .skipspace
+ dec di
+
+ ; ES:DI now points to the beginning of an option
+ mov si,options_list
+.next_opt:
+ movzx cx,byte [si]
+ jcxz .skip_opt
+ push di
+ inc si
+ repe cmpsb
+ jne .no_match
+
+ ; This either needs to have been an option with parameter,
+ ; or be followed by EOL/whitespace
+ mov ax,[es:di-1] ; AL = last chr; AH = following
+ cmp al,'='
+ je .is_match
+ cmp ah,' '
+ ja .no_match
+.is_match:
+ pop ax ; Drop option pointer on stack
+ call [si]
+.skip_opt:
+ mov al,[es:di]
+ inc di
+ cmp al,' '
+ ja .skip_opt
+ jmp .skipspace_loaded
+.no_match:
+ pop di
+ add si,cx ; Skip remaining bytes
+ inc si ; Skip function pointer
+ inc si
+ jmp .next_opt
+
+opt_vga:
+ mov ax,[es:di-1]
+ mov bx,-1
+ cmp ax,'=n' ; vga=normal
+ je .vc0
+ dec bx ; bx <- -2
+ cmp ax,'=e' ; vga=ext
+ je .vc0
+ dec bx ; bx <- -3
+ cmp ax,'=a' ; vga=ask
+ je .vc0
+ mov bx,0x0f04 ; bx <- 0x0f04 (current mode)
+ cmp ax,'=c' ; vga=current
+ je .vc0
+ call parseint_esdi ; vga=<number>
+ jc .skip ; Not an integer
+.vc0: mov [es:bs_vidmode],bx ; Set video mode
+.skip:
+ ret
+
+opt_mem:
+ call parseint_esdi
+ jc .skip
+%if HIGHMEM_SLOP != 0
+ sub ebx,HIGHMEM_SLOP
+%endif
+ mov [MyHighMemSize],ebx
+.skip:
+ ret
+
+opt_quiet:
+ mov byte [QuietBoot],QUIET_FLAG
+ ret
+
+%if IS_PXELINUX
+opt_keeppxe:
+ or byte [KeepPXE],1 ; KeepPXE set by command line
+ ret
+%endif
+
+opt_initrd:
+ mov ax,di
+ cmp byte [es:di],' '
+ ja .have_initrd
+ xor ax,ax
+.have_initrd:
+ mov [InitRDPtr],ax
+ ret
+
+;
+; After command line parsing...
+;
+cmdline_end:
+ sub di,cmd_line_here
+ mov [CmdLineLen],di ; Length including final null
+
+;
+; Now check if we have a large kernel, which needs to be loaded high
+;
+prepare_header:
+ mov dword [RamdiskMax], HIGHMEM_MAX ; Default initrd limit
+ cmp dword [es:su_header],HEADER_ID ; New setup code ID
+ jne old_kernel ; Old kernel, load low
+ mov ax,[es:su_version]
+ mov [KernelVersion],ax
+ cmp ax,0200h ; Setup code version 2.0
+ jb old_kernel ; Old kernel, load low
+ cmp ax,0201h ; Version 2.01+?
+ jb new_kernel ; If 2.00, skip this step
+ ; Set up the heap (assuming loading high for now)
+ mov word [es:su_heapend],linux_stack-512
+ or byte [es:su_loadflags],80h ; Let the kernel know we care
+ cmp ax,0203h ; Version 2.03+?
+ jb new_kernel ; Not 2.03+
+ mov eax,[es:su_ramdisk_max]
+ mov [RamdiskMax],eax ; Set the ramdisk limit
+
+;
+; We definitely have a new-style kernel. Let the kernel know who we are,
+; and that we are clueful
+;
+new_kernel:
+ mov byte [es:su_loader],my_id ; Show some ID
+ xor eax,eax
+ mov [es:su_ramdisklen],eax ; No initrd loaded yet
+
+;
+; About to load the kernel. This is a modern kernel, so use the boot flags
+; we were provided.
+;
+ mov al,[es:su_loadflags]
+ or al,[QuietBoot] ; Set QUIET_FLAG if needed
+ mov [es:su_loadflags],al
+ mov [LoadFlags],al
+
+any_kernel:
+ mov si,loading_msg
+ call writestr_qchk
+ mov si,KernelName ; Print kernel name part of
+ call writestr_qchk ; "Loading" message
+
+;
+; Load the kernel. We always load it at 100000h even if we're supposed to
+; load it "low"; for a "low" load we copy it down to low memory right before
+; jumping to it.
+;
+read_kernel:
+ movzx ax,byte [es:bs_setupsecs] ; Setup sectors
+ and ax,ax
+ jnz .sects_ok
+ mov al,4 ; 0 = 4 setup sectors
+.sects_ok:
+ inc ax ; Including the boot sector
+ mov [SetupSecs],ax
+
+ call dot_pause
+
+;
+; Move the stuff beyond the setup code to high memory at 100000h
+;
+ movzx esi,word [SetupSecs] ; Setup sectors
+ shl si,9 ; Convert to bytes
+ mov ecx,8000h ; 32K
+ sub ecx,esi ; Number of bytes to copy
+ add esi,core_real_mode ; Pointer to source
+ mov edi,free_high_memory ; Copy to free high memory
+
+ call bcopy ; Transfer to high memory
+
+ pop si ; <A> File pointer
+ and si,si ; EOF already?
+ jz high_load_done
+
+ ; On exit EDI -> where to load the rest
+
+ mov bx,dot_pause
+ or eax,-1 ; Load the whole file
+ mov dx,3 ; Pad to dword
+ call load_high
+
+high_load_done:
+ mov [KernelEnd],edi
+ mov ax,real_mode_seg ; Set to real mode seg
+ mov es,ax
+
+ mov si,dot_msg
+ call writestr_qchk
+
+;
+; Some older kernels (1.2 era) would have more than 4 setup sectors, but
+; would not rely on the boot protocol to manage that. These kernels fail
+; if they see protected-mode kernel data after the setup sectors, so
+; clear that memory.
+;
+ push di
+ mov di,[SetupSecs]
+ shl di,9
+ xor eax,eax
+ mov cx,cmd_line_here
+ sub cx,di
+ shr cx,2
+ rep stosd
+ pop di
+
+;
+; Now see if we have an initial RAMdisk; if so, do requisite computation
+; We know we have a new kernel; the old_kernel code already will have objected
+; if we tried to load initrd using an old kernel
+;
+load_initrd:
+ ; Cap the ramdisk memory range if appropriate
+ mov eax,[RamdiskMax]
+ cmp eax,[MyHighMemSize]
+ ja .ok
+ mov [MyHighMemSize],eax
+.ok:
+ xor eax,eax
+ cmp [InitRDPtr],ax
+ jz .noinitrd
+ call parse_load_initrd
+.noinitrd:
+
+;
+; Abandon hope, ye that enter here! We do no longer permit aborts.
+;
+ call abort_check ; Last chance!!
+
+ mov si,ready_msg
+ call writestr_qchk
+
+ UNLOAD_PREP ; Module-specific hook
+
+;
+; Now, if we were supposed to load "low", copy the kernel down to 10000h
+; and the real mode stuff to 90000h. We assume that all bzImage kernels are
+; capable of starting their setup from a different address.
+;
+ mov ax,real_mode_seg
+ mov es,ax
+ mov fs,ax
+
+;
+; If the default root device is set to FLOPPY (0000h), change to
+; /dev/fd0 (0200h)
+;
+ cmp word [es:bs_rootdev],byte 0
+ jne root_not_floppy
+ mov word [es:bs_rootdev],0200h
+root_not_floppy:
+
+;
+; Copy command line. Unfortunately, the old kernel boot protocol requires
+; the command line to exist in the 9xxxxh range even if the rest of the
+; setup doesn't.
+;
+setup_command_line:
+ mov dx,[KernelVersion]
+ test byte [LoadFlags],LOAD_HIGH
+ jz .need_high_cmdline
+ cmp dx,0202h ; Support new cmdline protocol?
+ jb .need_high_cmdline
+ ; New cmdline protocol
+ ; Store 32-bit (flat) pointer to command line
+ ; This is the "high" location, since we have bzImage
+ mov dword [fs:su_cmd_line_ptr],cmd_line
+ mov word [HeapEnd],linux_stack
+ mov word [fs:su_heapend],linux_stack-512
+ jmp .setup_done
+
+.need_high_cmdline:
+;
+; Copy command line down to fit in high conventional memory
+; -- this happens if we have a zImage kernel or the protocol
+; is less than 2.02.
+;
+ mov si,cmd_line_here
+ mov di,old_cmd_line_here
+ mov [fs:kern_cmd_magic],word CMD_MAGIC ; Store magic
+ mov [fs:kern_cmd_offset],di ; Store pointer
+ mov word [HeapEnd],old_linux_stack
+ mov ax,255 ; Max cmdline limit
+ cmp dx,0201h
+ jb .adjusted
+ ; Protocol 2.01+
+ mov word [fs:su_heapend],old_linux_stack-512
+ jbe .adjusted
+ ; Protocol 2.02+
+ ; Note that the only reason we would end up here is
+ ; because we have a zImage, so we anticipate the move
+ ; to 90000h already...
+ mov dword [fs:su_cmd_line_ptr],0x90000+old_cmd_line_here
+ mov ax,old_max_cmd_len ; 2.02+ allow a higher limit
+.adjusted:
+
+ mov cx,[CmdLineLen]
+ cmp cx,ax
+ jna .len_ok
+ mov cx,ax ; Truncate the command line
+.len_ok:
+ fs rep movsb
+ stosb ; Final null, note AL=0 already
+ mov [CmdLineEnd],di
+ cmp dx,0200h
+ jb .nomovesize
+ mov [es:su_movesize],di ; Tell the kernel what to move
+.nomovesize:
+.setup_done:
+
+;
+; Time to start setting up move descriptors
+;
+setup_move:
+ mov di,trackbuf
+ xor cx,cx ; Number of descriptors
+
+ mov bx,es ; real_mode_seg
+ mov fs,bx
+ push ds ; We need DS == ES == CS here
+ pop es
+
+ mov edx,100000h
+ test byte [LoadFlags],LOAD_HIGH
+ jnz .loading_high
+
+; Loading low: move real_mode stuff to 90000h, then move the kernel down
+ mov eax,90000h
+ stosd
+ mov eax,core_real_mode
+ stosd
+ movzx eax,word [CmdLineEnd]
+ stosd
+ inc cx
+ mov edx,10000h ; Revised target address
+ mov bx,9000h ; Revised real mode segment
+
+.loading_high:
+ mov eax,edx ; Target address of kernel
+ stosd
+ mov eax,free_high_memory ; Where currently loaded
+ stosd
+ neg eax
+ add eax,[KernelEnd]
+ stosd
+ inc cx
+
+ cmp word [InitRDPtr],0 ; Did we have an initrd?
+ je .no_initrd
+
+ mov eax,[fs:su_ramdiskat]
+ stosd
+ mov eax,[InitRDStart]
+ stosd
+ mov eax,[fs:su_ramdisklen]
+ stosd
+ inc cx
+
+.no_initrd:
+ push dword run_linux_kernel
+ push cx ; Length of descriptor list
+
+ ; BX points to the final real mode segment, and will be loaded
+ ; into DS.
+
+ test byte [QuietBoot],QUIET_FLAG
+ jz replace_bootstrap
+ jmp replace_bootstrap_noclearmode
+
+run_linux_kernel:
+;
+; Set up segment registers and the Linux real-mode stack
+; Note: ds == the real mode segment
+;
+ cli
+ mov ax,ds
+ mov ss,ax
+ mov sp,strict word linux_stack
+ ; Point HeapEnd to the immediate of the instruction above
+HeapEnd equ $-2 ; Self-modifying code! Fun!
+ mov es,ax
+ mov fs,ax
+ mov gs,ax
+
+;
+; We're done... now RUN THAT KERNEL!!!!
+; Setup segment == real mode segment + 020h; we need to jump to offset
+; zero in the real mode segment.
+;
+ add ax,020h
+ push ax
+ push word 0h
+ retf
+
+;
+; Load an older kernel. Older kernels always have 4 setup sectors, can't have
+; initrd, and are always loaded low.
+;
+old_kernel:
+ xor ax,ax
+ cmp word [InitRDPtr],ax ; Old kernel can't have initrd
+ je .load
+ mov si,err_oldkernel
+ jmp abort_load
+.load:
+ mov byte [LoadFlags],al ; Always low
+ mov word [KernelVersion],ax ; Version 0.00
+ jmp any_kernel
+
+;
+; parse_load_initrd
+;
+; Parse an initrd= option and load the initrds. This sets
+; InitRDStart and InitRDEnd with dword padding between; we then
+; do a global memory shuffle to move it to the end of memory.
+;
+; On entry, EDI points to where to start loading.
+;
+parse_load_initrd:
+ push es
+ push ds
+ mov ax,real_mode_seg
+ mov ds,ax
+ push cs
+ pop es ; DS == real_mode_seg, ES == CS
+
+ mov [cs:InitRDStart],edi
+ mov [cs:InitRDEnd],edi
+
+ mov si,[cs:InitRDPtr]
+
+.get_chunk:
+ ; DS:SI points to the start of a name
+
+ mov bx,si
+.find_end:
+ lodsb
+ cmp al,','
+ je .got_end
+ cmp al,' '
+ jbe .got_end
+ jmp .find_end
+
+.got_end:
+ push ax ; Terminating character
+ push si ; Next filename (if any)
+ mov byte [si-1],0 ; Zero-terminate
+ mov si,bx ; Current filename
+
+ push di
+ mov di,InitRD ; Target buffer for mangled name
+ pm_call pm_mangle_name
+ pop di
+ call loadinitrd
+
+ pop si
+ pop ax
+ mov [si-1],al ; Restore ending byte
+
+ cmp al,','
+ je .get_chunk
+
+ ; Compute the initrd target location
+ ; Note: we round to a page boundary twice here. The first
+ ; time it is to make sure we don't use any fractional page
+ ; which may be valid RAM but which will be ignored by the
+ ; kernel (and therefore is inaccessible.) The second time
+ ; it is to make sure we start out on page boundary.
+ mov edx,[cs:InitRDEnd]
+ sub edx,[cs:InitRDStart]
+ mov [su_ramdisklen],edx
+ mov eax,[cs:MyHighMemSize]
+ and ax,0F000h ; Round to a page boundary
+ sub eax,edx
+ and ax,0F000h ; Round to a page boundary
+ mov [su_ramdiskat],eax
+
+ pop ds
+ pop es
+ ret
+
+;
+; Load RAM disk into high memory
+;
+; Input: InitRD - set to the mangled name of the initrd
+; EDI - location to load
+; Output: EDI - location for next initrd
+; InitRDEnd - updated
+;
+loadinitrd:
+ push ds
+ push es
+ mov ax,cs ; CS == DS == ES
+ mov ds,ax
+ mov es,ax
+ push edi
+ mov di,InitRD
+ pm_call pm_searchdir ; Look for it in directory
+ pop edi
+ jz .notthere
+
+ push si
+ mov si,crlfloading_msg ; Write "Loading "
+ call writestr_qchk
+ mov si,InitRD ; Write ramdisk name
+ call writestr_qchk
+ mov si,dotdot_msg ; Write dots
+ call writestr_qchk
+ pop si
+
+.li_skip_echo:
+ mov dx,3
+ mov bx,dot_pause
+ call load_high
+ mov [InitRDEnd],ebx
+
+ pop es
+ pop ds
+ ret
+
+.notthere:
+ mov si,err_noinitrd
+ call writestr
+ mov si,InitRD
+ call writestr
+ mov si,crlf_msg
+ jmp abort_load
+
+;
+; writestr_qchk: writestr, except allows output to be suppressed
+; assumes CS == DS
+;
+writestr_qchk:
+ test byte [QuietBoot],QUIET_FLAG
+ jz writestr
+ ret
+
+ section .data16
+crlfloading_msg db CR, LF
+loading_msg db 'Loading ', 0
+dotdot_msg db '.'
+dot_msg db '.', 0
+ready_msg db 'ready.', CR, LF, 0
+err_oldkernel db 'Cannot load a ramdisk with an old kernel image.'
+ db CR, LF, 0
+err_noinitrd db CR, LF, 'Could not find ramdisk image: ', 0
+
+boot_image db 'BOOT_IMAGE='
+boot_image_len equ $-boot_image
+
+;
+; Command line options we'd like to take a look at
+;
+%macro cmd_opt 2
+%strlen cmd_opt_len %1
+ db cmd_opt_len
+ db %1
+ dw %2
+%endmacro
+options_list:
+ cmd_opt "vga=", opt_vga
+ cmd_opt "mem=", opt_mem
+ cmd_opt "quiet", opt_quiet
+str_initrd equ $+1 ; Pointer to "initrd=" in memory
+ cmd_opt "initrd=", opt_initrd
+%if IS_PXELINUX
+ cmd_opt "keeppxe", opt_keeppxe
+%endif
+ db 0
+
+ section .bss16
+ alignb 4
+MyHighMemSize resd 1 ; Possibly adjusted highmem size
+RamdiskMax resd 1 ; Highest address for ramdisk
+KernelSize resd 1 ; Size of kernel in bytes
+KernelSects resd 1 ; Size of kernel in sectors
+KernelEnd resd 1 ; Ending address of the kernel image
+InitRDStart resd 1 ; Start of initrd (pre-relocation)
+InitRDEnd resd 1 ; End of initrd (pre-relocation)
+CmdLineLen resw 1 ; Length of command line including null
+CmdLineEnd resw 1 ; End of the command line in real_mode_seg
+SetupSecs resw 1 ; Number of setup sectors (+bootsect)
+KernelVersion resw 1 ; Kernel protocol version
+;
+; These are derived from the command-line parser
+;
+InitRDPtr resw 1 ; Pointer to initrd= option in command line
+LoadFlags resb 1 ; Loadflags from kernel
+QuietBoot resb 1 ; Set if a quiet boot is requested
diff --git a/contrib/syslinux-4.02/core/serirq.inc b/contrib/syslinux-4.02/core/serirq.inc
new file mode 100644
index 0000000..47ccd50
--- /dev/null
+++ b/contrib/syslinux-4.02/core/serirq.inc
@@ -0,0 +1,219 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 2009 Intel Corporation; author: H. Peter Anvin
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+;; Boston MA 02111-1307, USA; either version 2 of the License, or
+;; (at your option) any later version; incorporated herein by reference.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; serirq.inc
+;;
+;; Serial port IRQ code
+;;
+;; We don't know what IRQ, if any, we have, so map all of them...
+;;
+
+ section .text16
+ bits 16
+ align 8
+
+ section .bss16
+ alignb 8
+
+%assign n 0
+%rep 16
+ section .text16
+serstub_irq %+ n :
+ push dword [cs:oldirq %+ n]
+ jmp short irq_common
+
+ section .bss16
+oldirq %+ n resd 1
+%assign n n+1
+%endrep
+
+ section .text16
+irq_common:
+ pushf
+ push ax
+ push dx
+ mov dx,[cs:SerialPort]
+ add dx,5 ; DX -> LSR
+ in al,dx
+ test al,1 ; Received data
+ jnz .data
+.done:
+ pop dx
+ pop ax
+ popf
+ retf ; Chain to next handler
+.data:
+ push es
+ push di
+ mov ax,aux_seg + (aux.serial >> 4)
+ mov es,ax
+ mov di,[cs:SerialHead]
+.loop:
+ mov dx,[cs:SerialPort] ; DX -> RDR
+ in al,dx
+ stosb
+ mov ah,[cs:FlowIgnore]
+ add dx,5 ; DX -> LSR
+ in al,dx
+ push ax
+ and al,ah
+ cmp al,ah
+ jne .drop
+ and di,serial_buf_size-1 ; Wrap around if necessary
+ cmp di,[cs:SerialTail] ; Would this cause overflow?
+ je .drop ; If so, just drop the data
+ mov [cs:SerialHead],di
+.drop:
+ pop ax
+ test al,1 ; More data?
+ jnz .loop
+.full:
+ pop di
+ pop es
+ jmp .done
+
+ section .bss16
+;
+; SerialIRQPort will generally track SerialPort, but will be 0 when an
+; IRQ service is not installed.
+;
+SerialIRQPort resw 1 ; Serial port w IRQ service
+SerialHead resw 1 ; Head of serial port rx buffer
+SerialTail resw 1 ; Tail of serial port rx buffer
+
+ section .bss16
+IRQMask resw 1 ; PIC IRQ mask status
+
+ section .text16
+
+sirq_install:
+ pushad
+
+ call sirq_cleanup
+
+ ; Save the old interrupt vectors
+ mov si,4*08h
+ mov di,oldirq0
+ mov cx,8
+ rep movsd
+ mov si,4*70h
+ mov cx,8
+ rep movsd
+
+ ; Install new interrupt vectors
+ mov di,4*08h
+ mov cx,8
+ mov eax,serstub_irq0
+.pic0:
+ stosd
+ add ax,serstub_irq1 - serstub_irq0
+ loop .pic0
+ mov di,4*70h
+ mov cx,8
+.pic1:
+ stosd
+ add ax,serstub_irq1 - serstub_irq0
+ loop .pic1
+
+ mov bx,[SerialPort]
+ mov [SerialIRQPort],bx
+
+ lea dx,[bx+5] ; DX -> LCR
+ mov al,03h ; Clear DLAB (should already be...)
+ slow_out dx,al
+
+ lea dx,[bx+1] ; DX -> IER
+ mov al,1 ; Enable receive interrupt
+ slow_out dx,al
+
+ ;
+ ; Enable all ther interupt lines at the PIC. Some BIOSes
+ ; only enable the timer interrupts and other interrupts
+ ; actively in use by the BIOS.
+ ;
+ in al,0xA1 ; Secondary PIC mask register
+ mov ah,al
+ in al,0x21 ; Primary PIC mask register
+ mov [IRQMask],ax
+
+ io_delay
+
+ xor ax,ax ; Remove all interrupt masks
+ out 0x21,al
+ out 0xA1,al
+
+ popad
+ ret
+
+sirq_cleanup_nowipe:
+ pushad
+ push ds
+ push es
+ xor ax,ax
+ mov ds,ax
+ mov es,ax
+
+ mov bx,[SerialIRQPort]
+ and bx,bx
+ jz .done
+
+ lea dx,[bx+5] ; DX -> LCR
+ mov al,03h ; Clear DLAB (should already be...)
+ slow_out dx,al
+
+ lea dx,[bx+1] ; DX -> IER
+ xor ax,ax
+ slow_out dx,al ; Clear IER
+
+ ; Restore PIC masks
+ mov ax,[IRQMask]
+ out 0x21,al
+ mov al,ah
+ out 0xA1,al
+
+ ; Restore the original interrupt vectors
+ mov si,oldirq0
+ mov di,4*08h
+ mov cx,8
+ rep movsd
+ mov di,4*70h
+ mov cx,8
+ rep movsd
+
+ xor ax,ax
+ mov [SerialIRQPort],ax ; No active interrupt system
+
+.done:
+ pop es
+ pop ds
+ popad
+ ret
+
+sirq_cleanup:
+ call sirq_cleanup_nowipe
+ pushad
+ push es
+ ; Just in case it might contain a password, erase the
+ ; serial port receive buffer...
+ mov ax,aux_seg + (aux.serial >> 4)
+ mov es,ax
+ xor eax,eax
+ mov [cs:SerialHead],eax
+ mov cx,serial_buf_size >> 2
+ xor di,di
+ rep stosd
+ pop es
+ popad
+ ret
+
+ section .text16
diff --git a/contrib/syslinux-4.02/core/stack.inc b/contrib/syslinux-4.02/core/stack.inc
new file mode 100644
index 0000000..788db64
--- /dev/null
+++ b/contrib/syslinux-4.02/core/stack.inc
@@ -0,0 +1,47 @@
+; -----------------------------------------------------------------------
+;
+; Copyright 2005-2008 H. Peter Anvin - All Rights Reserved
+; Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+;
+; This program is free software; you can redistribute it and/or modify
+; it under the terms of the GNU General Public License as published by
+; the Free Software Foundation, Inc., 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.
+;
+; -----------------------------------------------------------------------
+
+;
+; stack.inc
+;
+; How to reset the stack pointer
+;
+
+%ifndef _STACK_INC
+%define _STACK_INC
+
+;
+; This macro resets the stack pointer (including SS), and sets
+; DS == ES == 0, interrupts on, DF = 0.
+;
+; It takes a 16-bit register that can be safely clobbered as parameter.
+;
+%macro RESET_STACK_AND_SEGS 1
+ xor %1,%1
+ mov ds,%1
+ mov es,%1
+ lss esp,[BaseStack]
+ mov dword [PMESP],__stack_end ; Reset PM stack
+ sti
+ cld
+%endmacro
+
+ section .data16
+ alignz 4
+ global BaseStack
+BaseStack dd StackHome ; ESP of the "home" stack pointer
+ dw 0 ; SS of the "home" stack pointer
+
+ section .text16
+
+%endif ; _STACK_INC
diff --git a/contrib/syslinux-4.02/core/strcasecmp.c b/contrib/syslinux-4.02/core/strcasecmp.c
new file mode 100644
index 0000000..2f7480d
--- /dev/null
+++ b/contrib/syslinux-4.02/core/strcasecmp.c
@@ -0,0 +1,11 @@
+/*
+ * strcasecmp.c
+ */
+
+#include <string.h>
+#include <ctype.h>
+
+int strcasecmp(const char *s1, const char *s2)
+{
+ return strncasecmp(s1, s2, -1);
+}
diff --git a/contrib/syslinux-4.02/core/strcpy.inc b/contrib/syslinux-4.02/core/strcpy.inc
new file mode 100644
index 0000000..9762cbb
--- /dev/null
+++ b/contrib/syslinux-4.02/core/strcpy.inc
@@ -0,0 +1,13 @@
+;
+; strcpy: Copy DS:SI -> ES:DI up to and including a null byte;
+; on exit SI and DI point to the byte *after* the null byte
+;
+ section .text16
+
+strcpy: push ax
+.loop: lodsb
+ stosb
+ and al,al
+ jnz .loop
+ pop ax
+ ret
diff --git a/contrib/syslinux-4.02/core/strncasecmp.c b/contrib/syslinux-4.02/core/strncasecmp.c
new file mode 100644
index 0000000..2caac0a
--- /dev/null
+++ b/contrib/syslinux-4.02/core/strncasecmp.c
@@ -0,0 +1,24 @@
+/*
+ * strncasecmp.c
+ */
+
+#include <string.h>
+#include <ctype.h>
+
+int strncasecmp(const char *s1, const char *s2, size_t n)
+{
+ const unsigned char *c1 = (const unsigned char *)s1;
+ const unsigned char *c2 = (const unsigned char *)s2;
+ unsigned char ch;
+ int d = 0;
+
+ while (n--) {
+ /* toupper() expects an unsigned char (implicitly cast to int)
+ as input, and returns an int, which is exactly what we want. */
+ d = toupper(ch = *c1++) - toupper(*c2++);
+ if (d || !ch)
+ break;
+ }
+
+ return d;
+}
diff --git a/contrib/syslinux-4.02/core/syslinux.ld b/contrib/syslinux-4.02/core/syslinux.ld
new file mode 100644
index 0000000..164c94c
--- /dev/null
+++ b/contrib/syslinux-4.02/core/syslinux.ld
@@ -0,0 +1,380 @@
+/* -----------------------------------------------------------------------
+ *
+ * Copyright 2008-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 Intel Corporation; author: H. Peter Anvin
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Linker script for the SYSLINUX core
+ */
+
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+EXTERN(_start)
+ENTRY(_start)
+
+SECTIONS
+{
+ /* Prefix structure for the compression program */
+ . = 0;
+ .prefix : {
+ *(.prefix)
+ }
+
+ /* "Early" sections (before the load) */
+ . = 0x1000;
+
+ .earlybss : {
+ __earlybss_start = .;
+ *(.earlybss)
+ __earlybss_end = .;
+ }
+ __earlybss_len = __earlybss_end - __earlybss_start;
+ __earlybss_dwords = (__earlybss_len + 3) >> 2;
+
+ . = ALIGN(4);
+ .bss16 : {
+ __bss16_start = .;
+ *(.bss16)
+ __bss16_end = .;
+ }
+ __bss16_len = __bss16_end - __bss16_start;
+ __bss16_dwords = (__bss16_len + 3) >> 2;
+
+ . = ALIGN(4);
+ .config : AT (__config_lma) {
+ __config_start = .;
+ *(.config)
+ __config_end = .;
+ }
+ __config_len = __config_end - __config_start;
+ __config_dwords = (__config_len + 3) >> 2;
+
+ /* Generated and/or copied code */
+
+ . = ALIGN(128); /* Minimum separation from mutable data */
+ .replacestub : AT (__replacestub_lma) {
+ __replacestub_start = .;
+ *(.replacestub)
+ __replacestub_end = .;
+ }
+ __replacestub_len = __replacestub_end - __replacestub_start;
+ __replacestub_dwords = (__replacestub_len + 3) >> 2;
+
+ . = ALIGN(16);
+ __gentextnr_lma = .;
+ .gentextnr : AT(__gentextnr_lma) {
+ __gentextnr_start = .;
+ *(.gentextnr)
+ __gentextnr_end = .;
+ }
+ __gentextnr_len = __gentextnr_end - __gentextnr_start;
+ __gentextnr_dwords = (__gentextnr_len + 3) >> 2;
+
+ . = STACK_BASE;
+ .stack16 : AT(STACK_BASE) {
+ __stack16_start = .;
+ . += STACK_LEN;
+ __stack16_end = .;
+ }
+ __stack16_len = __stack16_end - __stack16_start;
+ __stack16_dwords = (__stack16_len + 3) >> 2;
+
+ /* Initialized sections */
+
+ . = 0x7c00;
+ .init : {
+ FILL(0x90909090)
+ __init_start = .;
+ *(.init)
+ __init_end = .;
+ }
+ __init_len = __init_end - __init_start;
+ __init_dwords = (__init_len + 3) >> 2;
+
+ .text16 : {
+ FILL(0x90909090)
+ __text16_start = .;
+ *(.text16)
+ __text16_end = .;
+ }
+ __text16_len = __text16_end - __text16_start;
+ __text16_dwords = (__text16_len + 3) >> 2;
+
+ /*
+ * .textnr is used for 32-bit code that is used on the code
+ * path to initialize the .text segment
+ */
+ . = ALIGN(16);
+ .textnr : {
+ FILL(0x90909090)
+ __textnr_start = .;
+ *(.textnr)
+ __textnr_end = .;
+ }
+ __textnr_len = __textnr_end - __textnr_start;
+ __textnr_dwords = (__textnr_len + 3) >> 2;
+
+ . = ALIGN(16);
+ __bcopyxx_start = .;
+
+ .bcopyxx.text : {
+ FILL(0x90909090)
+ __bcopyxx_text_start = .;
+ *(.bcopyxx.text)
+ __bcopyxx_text_end = .;
+ }
+ __bcopyxx_text_len = __bcopyxx_text_end - __bcopyxx_text_start;
+ __bcopyxx_text_dwords = (__bcopyxx_text_len + 3) >> 2;
+
+ .bcopyxx.data : {
+ __bcopyxx_data_start = .;
+ *(.bcopyxx.text)
+ __bcopyxx_data_end = .;
+ }
+ __bcopyxx_data_len = __bcopyxx_data_end - __bcopyxx_data_start;
+ __bcopyxx_data_dwords = (__bcopyxx_data_len + 3) >> 2;
+
+ __bcopyxx_end = .;
+ __bcopyxx_len = __bcopyxx_end - __bcopyxx_start;
+ __bcopyxx_dwords = (__bcopyxx_len + 3) >> 2;
+
+ . = ALIGN(4);
+ .data16 : {
+ __data16_start = .;
+ *(.data16)
+ __data16_end = .;
+ }
+ __data16_len = __data16_end - __data16_start;
+ __data16_dwords = (__data16_len + 3) >> 2;
+
+ . = ALIGN(4);
+ __config_lma = .;
+ . += SIZEOF(.config);
+
+ . = ALIGN(4);
+ __replacestub_lma = .;
+ . += SIZEOF(.replacestub);
+
+ /* The 32-bit code loads above the non-progbits sections */
+
+ . = ALIGN(16);
+ __pm_code_lma = .;
+
+ __high_clear_start = .;
+
+ . = ALIGN(512);
+ .adv (NOLOAD) : {
+ __adv_start = .;
+ *(.adv)
+ __adv_end = .;
+ }
+ __adv_len = __adv_end - __adv_start;
+ __adv_dwords = (__adv_len + 3) >> 2;
+
+ /* Late uninitialized sections */
+
+ . = ALIGN(4);
+ .uibss (NOLOAD) : {
+ __uibss_start = .;
+ *(.uibss)
+ __uibss_end = .;
+ }
+ __uibss_len = __uibss_end - __uibss_start;
+ __uibss_dwords = (__uibss_len + 3) >> 2;
+
+ _end16 = .;
+ __assert_end16 = ASSERT(_end16 <= 0x10000, "64K overflow");
+
+ /*
+ * Special 16-bit segments
+ */
+
+ . = ALIGN(65536);
+ .real_mode (NOLOAD) : {
+ *(.real_mode)
+ }
+ real_mode_seg = core_real_mode >> 4;
+
+ . = ALIGN(65536);
+ .xfer_buf (NOLOAD) : {
+ *(.xfer_buf)
+ }
+ xfer_buf_seg = core_xfer_buf >> 4;
+
+ /*
+ * The auxilliary data segment is used by the 16-bit code
+ * for items that don't need to live in the bottom 64K.
+ */
+
+ . = ALIGN(16);
+ .auxseg (NOLOAD) : {
+ __auxseg_start = .;
+ *(.auxseg)
+ __auxseg_end = .;
+ }
+ __auxseg_len = __auxseg_end - __auxseg_start;
+ __auxseg_dwords = (__auxseg_len + 3) >> 2;
+ aux_seg = __auxseg_start >> 4;
+
+ /*
+ * Used to allocate lowmem buffers from 32-bit code
+ */
+ .lowmem (NOLOAD) : {
+ __lowmem_start = .;
+ *(.lowmem)
+ __lowmem_end = .;
+ }
+ __lowmem_len = __lowmem_end - __lowmem_start;
+ __lowmem_dwords = (__lowmem_len + 3) >> 2;
+
+ __high_clear_end = .;
+
+ __high_clear_len = __high_clear_end - __high_clear_start;
+ __high_clear_dwords = (__high_clear_len + 3) >> 2;
+
+ /* Start of the lowmem heap */
+ . = ALIGN(16);
+ __lowmem_heap = .;
+
+ /*
+ * 32-bit code. This is a hack for the moment due to the
+ * real-mode segments also allocated.
+ */
+
+ . = 0x100000;
+
+ __pm_code_start = .;
+
+ __text_vma = .;
+ __text_lma = __pm_code_lma;
+ .text : AT(__text_lma) {
+ FILL(0x90909090)
+ __text_start = .;
+ *(.text)
+ *(.text.*)
+ __text_end = .;
+ }
+
+ . = ALIGN(16);
+
+ __rodata_vma = .;
+ __rodata_lma = __rodata_vma + __text_lma - __text_vma;
+ .rodata : AT(__rodata_lma) {
+ __rodata_start = .;
+ *(.rodata)
+ *(.rodata.*)
+ __rodata_end = .;
+ }
+
+ . = ALIGN(4);
+
+ __ctors_vma = .;
+ __ctors_lma = __ctors_vma + __text_lma - __text_vma;
+ .ctors : AT(__ctors_lma) {
+ __ctors_start = .;
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ __ctors_end = .;
+ }
+
+ __dtors_vma = .;
+ __dtors_lma = __dtors_vma + __text_lma - __text_vma;
+ .dtors : AT(__dtors_lma) {
+ __dtors_start = .;
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ __dtors_end = .;
+ }
+
+ . = ALIGN(4);
+
+ __dynlink_vma = .;
+ __dynlink_lma = __dynlink_vma + __text_lma - __text_vma;
+ .dynlink : AT(__dynlink_lma) {
+ __dynlink_start = .;
+ *(.dynlink)
+ __dynlink_end = .;
+ }
+
+ . = ALIGN(4);
+
+ __got_vma = .;
+ __got_lma = __got_vma + __text_lma - __text_vma;
+ .got : AT(__got_lma) {
+ __got_start = .;
+ KEEP (*(.got.plt))
+ KEEP (*(.got))
+ __got_end = .;
+ }
+
+ __data_vma = .;
+ __data_lma = __data_vma + __text_lma - __text_vma;
+ .data : AT(__data_lma) {
+ __data_start = .;
+ *(.data)
+ *(.data.*)
+ __data_end = .;
+ }
+
+ __pm_code_end = .;
+ __pm_code_len = __pm_code_end - __pm_code_start;
+ __pm_code_dwords = (__pm_code_len + 3) >> 2;
+
+ . = ALIGN(128);
+
+ __bss_vma = .;
+ __bss_lma = .; /* Dummy */
+ .bss (NOLOAD) : AT (__bss_lma) {
+ __bss_start = .;
+ *(.bss)
+ *(.bss.*)
+ *(COMMON)
+ __bss_end = .;
+ }
+ __bss_len = __bss_end - __bss_start;
+ __bss_dwords = (__bss_len + 3) >> 2;
+
+ /* Very large objects which don't need to be zeroed */
+
+ __hugebss_vma = .;
+ __hugebss_lma = .; /* Dummy */
+ .hugebss (NOLOAD) : AT (__hugebss_lma) {
+ __hugebss_start = .;
+ *(.hugebss)
+ *(.hugebss.*)
+ __hugebss_end = .;
+ }
+ __hugebss_len = __hugebss_end - __hugebss_start;
+ __hugebss_dwords = (__hugebss_len + 3) >> 2;
+
+
+ /* XXX: This stack should be unified with the COM32 stack */
+ __stack_vma = .;
+ __stack_lma = .; /* Dummy */
+ .stack (NOLOAD) : AT(__stack_lma) {
+ __stack_start = .;
+ *(.stack)
+ __stack_end = .;
+ }
+ __stack_len = __stack_end - __stack_start;
+ __stack_dwords = (__stack_len + 3) >> 2;
+
+ _end = .;
+
+ /* COM32R and kernels are loaded after our own PM code */
+ . = ALIGN(65536);
+ free_high_memory = .;
+
+ /* Stuff we don't need... */
+ /DISCARD/ : {
+ *(.eh_frame)
+ }
+}
diff --git a/contrib/syslinux-4.02/core/timer.inc b/contrib/syslinux-4.02/core/timer.inc
new file mode 100644
index 0000000..b01ff91
--- /dev/null
+++ b/contrib/syslinux-4.02/core/timer.inc
@@ -0,0 +1,57 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 2009 Intel Corporation; author: H. Peter Anvin
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+;; Boston MA 02110-1301, USA; either version 2 of the License, or
+;; (at your option) any later version; incorporated herein by reference.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; timer.inc
+;;
+;; Very simple counting timer
+;;
+;; This lets us have a simple incrementing variable without worrying
+;; about the BIOS_timer variable wrapping around at "midnight" and other
+;; weird things.
+;;
+;; This also maintains a timer variable calibrated in milliseconds
+;; (wraparound time = 49.7 days!)
+;;
+
+ section .text16
+
+timer_init:
+ ; Hook INT 1Ch
+ mov eax,[BIOS_timer_hook]
+ mov [BIOS_timer_next],eax
+ mov dword [BIOS_timer_hook],timer_irq
+ ret
+
+timer_cleanup:
+ ; Unhook INT 1Ch
+ mov eax,[BIOS_timer_next]
+ mov [BIOS_timer_hook],eax
+ ret
+
+;
+; The specified frequency is 14.31818 MHz/12/65536; this turns out
+; to be a period of 54.92542 ms, or 0x36.ece8(187c) hexadecimal.
+;
+timer_irq:
+ inc dword [cs:__jiffies]
+ add word [cs:__ms_timer_adj],0xece8
+ adc dword [cs:__ms_timer],0x36
+ jmp 0:0
+BIOS_timer_next equ $-4
+
+ section .data16
+ alignz 4
+ global __jiffies, __ms_timer
+__jiffies dd 0 ; Clock tick timer
+__ms_timer dd 0 ; Millisecond timer
+__ms_timer_adj dw 0 ; Millisecond timer correction factor
diff --git a/contrib/syslinux-4.02/core/tracers.inc b/contrib/syslinux-4.02/core/tracers.inc
new file mode 100644
index 0000000..a51209f
--- /dev/null
+++ b/contrib/syslinux-4.02/core/tracers.inc
@@ -0,0 +1,40 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1994-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., 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.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; tracers.inc
+;;
+;; Debugging tracers
+;;
+
+%ifndef _TRACERS_INC
+%define _TRACERS_INC
+
+; Note: The Makefile builds one version with DEBUG_MESSAGES automatically.
+; %define DEBUG_TRACERS 1 ; Uncomment to get debugging tracers
+; %define DEBUG_MESSAGES ; Uncomment to get debugging messages
+
+%ifdef DEBUG_TRACERS
+
+%macro TRACER 1
+ call debug_tracer
+ db %1
+%endmacro
+
+%else ; DEBUG_TRACERS
+
+%macro TRACER 1
+%endmacro
+
+%endif ; DEBUG_TRACERS
+
+%endif ; _TRACERS_INC
diff --git a/contrib/syslinux-4.02/core/ui.inc b/contrib/syslinux-4.02/core/ui.inc
new file mode 100644
index 0000000..2d44447
--- /dev/null
+++ b/contrib/syslinux-4.02/core/ui.inc
@@ -0,0 +1,748 @@
+;; -----------------------------------------------------------------------
+;;
+;; 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)
+;
+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
+
+%if HAS_LOCALBOOT
+ ; Is this a "localboot" pseudo-kernel?
+ cmp al,VK_LOCALBOOT ; al == KernelType
+ mov ax,[VKernelBuf+vk_rname] ; Possible localboot type
+ je local_boot
+%endif
+ 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 .bss16
+ alignb 4
+Kernel_EAX resd 1
+Kernel_SI resw 1
+
+ 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
+
+is_config_file:
+ push si
+ call make_plain_cmdline
+ pm_call pm_is_config_file
+ pop si
+ call openfd
+ call reset_config
+ jmp load_config_file
+
+; 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
+%if IS_ISOLINUX
+ ; ok
+%else
+is_disk_image equ is_bad_image
+%endif
+
+ 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
+
+
+ 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
+ dw is_config_file ; VK_CONFIG
+
+ section .bss16
+ 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
+
+ section .text16
+;
+; Linux kernel loading code is common.
+;
+%include "runkernel.inc"
+
+;
+; COMBOOT-loading code
+;
+%include "comboot.inc"
+%include "com32.inc"
+%include "cmdline.inc"
+
+;
+; Boot sector loading code
+;
+%include "bootsect.inc"
+
+;
+; Abort loading code
+;
+%include "abort.inc"
+
+;
+; Hardware cleanup common code
+;
+%include "cleanup.inc"
diff --git a/contrib/syslinux-4.02/core/writedec.inc b/contrib/syslinux-4.02/core/writedec.inc
new file mode 100644
index 0000000..bfac099
--- /dev/null
+++ b/contrib/syslinux-4.02/core/writedec.inc
@@ -0,0 +1,57 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1994-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., 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.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; writedec.inc
+;;
+;; Write decimal numbers to the console
+;;
+
+ section .text16
+;
+; writedec[bwl]: Write an unsigned decimal number in (AL, AX, EAX)
+; to the console
+;
+writedecb:
+ pushad
+ movzx eax,al
+ jmp short writedec_common
+writedecw:
+ pushad
+ movzx eax,ax
+ jmp short writedec_common
+writedecl:
+ pushad
+writedec_common:
+ pushfd
+ mov ebx,10 ; Conversion base
+ xor cx,cx ; Number of digits
+
+.cloop:
+ div ebx
+ inc cx
+ push dx
+ and eax,eax
+ jnz .cloop
+
+.dloop:
+ pop ax
+ add al,'0'
+ call writechr
+ loop .dloop
+
+ popfd
+ popad
+ ret
+
+writechr:
+ ret
diff --git a/contrib/syslinux-4.02/core/writehex.inc b/contrib/syslinux-4.02/core/writehex.inc
new file mode 100644
index 0000000..e2bf86b
--- /dev/null
+++ b/contrib/syslinux-4.02/core/writehex.inc
@@ -0,0 +1,52 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1994-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., 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.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; writehex.inc
+;;
+;; Write hexadecimal numbers to the console
+;;
+
+;
+; writehex[248]: Write a hex number in (AL, AX, EAX) to the console
+;
+writehex2:
+ pushfd
+ pushad
+ rol eax,24
+ mov cx,2
+ jmp short writehex_common
+writehex4:
+ pushfd
+ pushad
+ rol eax,16
+ mov cx,4
+ jmp short writehex_common
+writehex8:
+ pushfd
+ pushad
+ mov cx,8
+writehex_common:
+.loop: rol eax,4
+ push eax
+ and al,0Fh
+ cmp al,10
+ jae .high
+.low: add al,'0'
+ jmp short .ischar
+.high: add al,'A'-10
+.ischar: call writechr
+ pop eax
+ loop .loop
+ popad
+ popfd
+ ret
diff --git a/contrib/syslinux-4.02/core/writestr.inc b/contrib/syslinux-4.02/core/writestr.inc
new file mode 100644
index 0000000..9c11b32
--- /dev/null
+++ b/contrib/syslinux-4.02/core/writestr.inc
@@ -0,0 +1,47 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1994-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., 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.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; writestr.inc
+;;
+;; Code to write a simple string.
+;;
+
+;
+; crlf: Print a newline
+;
+crlf: push ax
+ mov al,CR
+ call writechr
+ mov al,LF
+ call writechr
+ pop ax
+ ret
+
+;
+; writestr: write a null-terminated string to the console, saving
+; registers on entry.
+;
+; Note: writestr_early and writestr are distinct in
+; SYSLINUX and EXTLINUX, but not PXELINUX and ISOLINUX
+;
+writestr:
+ pushfd
+ pushad
+.top: lodsb
+ and al,al
+ jz .end
+ call writechr
+ jmp short .top
+.end: popad
+ popfd
+ ret