diff options
author | Sebastian Schmelzer | 2010-10-25 16:53:54 +0200 |
---|---|---|
committer | Sebastian Schmelzer | 2010-10-25 16:53:54 +0200 |
commit | 3050a9253437f4a4b5ad4bf3b3efdc3c660a5137 (patch) | |
tree | 91ac22153e416aac7ca20916b314b5e2ffa871b1 /contrib/syslinux-4.02/core | |
download | preboot-master.tar.gz preboot-master.tar.xz preboot-master.zip |
Diffstat (limited to 'contrib/syslinux-4.02/core')
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(®s, 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, ®s, ®s); + 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(®s, 0, sizeof regs); + regs.ebx.w[0] = opcode; + regs.es = SEG(data); + regs.edi.w[0] = OFFS(data); + call16(pxenv, ®s, ®s); + + 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(®s, 0, sizeof regs); + regs.edi.w[0] = OFFS_WRT(KernelName, 0); + call16(core_open, ®s, ®s); + 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(®s, 0, sizeof regs); + regs.eax.w[0] = 0x5650; + call16(pxe_int1a, ®s, ®s); + 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 |