Add pxechain.com; new modules direction; reorganize installation
authorH. Peter Anvin <hpa@zytor.com>
Wed, 27 Aug 2008 23:23:24 +0000 (16:23 -0700)
committerH. Peter Anvin <hpa@zytor.com>
Wed, 27 Aug 2008 23:23:24 +0000 (16:23 -0700)
Add the pxechain module from Jeffery Hutzelman at CMU.
Create new modules directory for non-com32 modules.
Centralize installation, since we have three types of install, and
only one of them was distributed.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Makefile
com32/menu/Makefile
com32/modules/Makefile
modules/Makefile [new file with mode: 0644]
modules/pxechain.asm [new file with mode: 0644]

index 6c056d8..040a7ed 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -28,6 +28,11 @@ include $(topdir)/MCONFIG
 # directories.
 #
 
+# List of module objects that should be installed for all derivatives
+MODULES = memdisk/memdisk memdump/memdump.com \
+         modules/*.com com32/menu/*.c32 com32/modules/*.c32
+
+
 # syslinux.exe is BTARGET so as to not require everyone to have the
 # mingw suite installed
 BTARGET  = version.gen version.h version.mk
@@ -35,7 +40,7 @@ BOBJECTS = $(BTARGET) \
        mbr/mbr.bin mbr/gptmbr.bin \
        core/pxelinux.0 core/isolinux.bin core/isolinux-debug.bin \
        gpxe/gpxelinux.0 dos/syslinux.com win32/syslinux.exe \
-       memdisk/memdisk memdump/memdump.com
+       $(MODULES)
 
 # BSUBDIRs build the on-target binary components.
 # ISUBDIRs build the installer (host) components.
@@ -58,20 +63,19 @@ INSTALL_SBIN  = extlinux/extlinux
 INSTALL_AUX   =        core/pxelinux.0 gpxe/gpxelinux.0 core/isolinux.bin \
                core/isolinux-debug.bin \
                dos/syslinux.com dos/copybs.com win32/syslinux.exe \
-               memdisk/memdisk memdump/memdump.com \
-               mbr/mbr.bin mbr/gptmbr.bin
+               mbr/mbr.bin mbr/gptmbr.bin \
+               $(MODULES)
 INSTALL_AUX_OPT = win32/syslinux.exe
 
 # These directories manage their own installables
 INSTALLSUBDIRS = com32 utils
 
 # Things to install in /boot/extlinux
-EXTBOOTINSTALL = memdisk/memdisk memdump/memdump.com \
-                com32/menu/*.c32 com32/modules/*.c32
+EXTBOOTINSTALL = $(MODULES)
 
 # Things to install in /tftpboot
-NETINSTALLABLE = core/pxelinux.0 gpxe/gpxelinux.0 memdisk/memdisk \
-                memdump/memdump.com com32/menu/*.c32 com32/modules/*.c32
+NETINSTALLABLE = core/pxelinux.0 gpxe/gpxelinux.0 \
+                $(MODULES)
 
 all:
        $(MAKE) all-local
index 9b856c2..44212c3 100644 (file)
@@ -44,7 +44,5 @@ spotless: clean
        rm -f *~ \#*
 
 install: all
-       mkdir -m 755 -p $(INSTALLROOT)$(AUXDIR)
-       install -m 644 $(MODULES) $(INSTALLROOT)$(AUXDIR)
 
 -include .*.d
index 691e929..eb3a9a1 100644 (file)
@@ -47,7 +47,5 @@ spotless: clean
        rm -f *~ \#*
 
 install: all
-       mkdir -m 755 -p $(INSTALLROOT)$(AUXDIR)
-       install -m 644 $(MODULES) $(INSTALLROOT)$(AUXDIR)
 
 -include .*.d
diff --git a/modules/Makefile b/modules/Makefile
new file mode 100644 (file)
index 0000000..5caf5e6
--- /dev/null
@@ -0,0 +1,63 @@
+## -----------------------------------------------------------------------
+##
+##   Copyright 2001-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.
+##
+## -----------------------------------------------------------------------
+
+##
+## Non-COM32 simple Syslinux modules
+##
+
+topdir = ..
+include $(topdir)/MCONFIG.embedded
+
+INCLUDES   = -I$(com32)/include
+
+BINS = pxechain.com
+
+all: $(BINS)
+
+.PRECIOUS: %.o
+%.o: %.S
+       $(CC) $(SFLAGS) -c -o $@ $<
+
+.PRECIOUS: %.o
+%.o: %.c
+       $(CC) $(CFLAGS) -c -o $@ $<
+
+.PRECIOUS: %.elf
+%.elf: c32entry.o %.o $(LIB)
+       $(LD) -Ttext 0x101000 -e _start -o $@ $^
+
+%.c32: %.elf
+       $(OBJCOPY) -O binary $< $@
+
+%.com: %.asm
+       $(NASM) $(NASMOPT) -f bin -o $@ -l $*.lst $<
+
+$(LIB): $(LIBOBJS)
+       rm -f $@
+       $(AR) cq $@ $^
+       $(RANLIB) $@
+
+%.lss: %.ppm.gz $(PPMTOLSS16)
+       $(GZIPPROG) -cd $< | \
+               $(PPMTOLSS16) \#000000=0 \#d0d0d0=7 \#f6f6f6=15 \
+               > $@
+
+%.ppm.gz: %.png
+       $(PNGTOPNM) $< | gzip -9 > $@
+
+tidy dist:
+       rm -f *.o *.a *.lst *.elf
+
+clean: tidy
+       rm -f $(BINS)
+
+spotless: clean
diff --git a/modules/pxechain.asm b/modules/pxechain.asm
new file mode 100644 (file)
index 0000000..b11d0ea
--- /dev/null
@@ -0,0 +1,561 @@
+; "$Id: pxechain.asm,v 1.2 2007/12/16 08:15:39 jhutz Exp $"
+; -*- fundamental -*- (asm-mode sucks)  vim:noet:com=\:;
+; ****************************************************************************
+;
+;  pxechain.asm
+;
+;  A comboot program to chain from PXELINUX to another PXE network
+;  bootstrap program (NBP).  This improves on PXELINUX's built-in PXE
+;  chaining support by arranging for the server address and boot filename
+;  reported by the PXE stack to be those from which the new NBP was
+;  loaded, allowing PXELINUX to be used to select from multiple NBP's,
+;  such as gPXE, another PXELINUX(*), Windows RIS, and so on.
+;
+;  (*) This seems unnecessary at first, but it is very helpful when
+;  selecting from among self-contained network boot images.
+;
+;   Copyright (c) 2007 Carnegie Mellon University
+;   Copyright (C) 1994-2007  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 DEBUG
+;%define NO_RUN
+
+               absolute 0
+pspInt20:      resw 1
+pspNextP:      resw 1
+               resb 124
+pspCmdLen:     resb 1
+pspCmdArg:     resb 127
+
+               section .text
+               org     0x100
+
+%ifdef DEBUG
+%macro MARK 1.nolist
+               mov ah,0x02
+               mov dl,%1&0xff
+               int 0x21
+%if (%1 >> 8) & 0xff
+               mov dl,(%1 >> 8) & 0xff
+               int 0x21
+%if (%1 >> 16) & 0xff
+               mov dl,(%1 >> 16) & 0xff
+               int 0x21
+%if (%1 >> 24) & 0xff
+               mov dl,(%1 >> 24) & 0xff
+               int 0x21
+%endif
+%endif
+%endif
+               mov dl,' '
+               int 0x21
+%endmacro
+%macro SHOWD 1.nolist
+               mov al,%1
+               call print_dec
+               mov ah,0x02
+               mov dl,' '
+               int 0x21
+%endmacro
+%macro SHOWX 1.nolist
+               mov bx,%1
+               call print_hex
+               mov ah,0x02
+               mov dl,' '
+               int 0x21
+%endmacro
+%else
+%macro MARK 1.nolist
+%endmacro
+%macro SHOWD 1.nolist
+%endmacro
+%macro SHOWX 1.nolist
+%endmacro
+%endif
+
+_start:
+               MARK 'INIT'
+
+; There should be exactly one command-line argument, which is of the form
+; [[ipaddress]::]tftp_filename, just like filenames given to PXELINUX.
+; Too few or too many arguments is an error.
+;
+; This code is based on mangle_name in pxelinux.asm
+parse_args:
+               cld
+               xor cx,cx
+               mov cl,[pspCmdLen]
+               dec cx
+               mov si,pspCmdArg+1
+               and cx,cx
+               je near usage           ; no args is bad
+               add si,cx
+               dec si
+               std
+.chomp:                lodsb
+               cmp al,' '
+               loopz .chomp
+               inc cx
+               cld
+               mov [pspCmdLen],cl
+               mov si,pspCmdArg+1
+               cmp word [si],'::'      ; Leading ::?
+               je near gotprefix
+               dec cx
+               jz noip
+               MARK 'SCAN'
+
+.more:
+               inc si
+               cmp byte [si],' '
+               je near usage
+               cmp word [si],'::'
+               je near parse_ip
+               loop .more
+
+noip:
+               MARK 'NOIP'
+               mov ax,0x0e             ; get config file name
+               int 0x22
+               mov si,bx
+%ifdef DEBUG
+               mov ah,0x02
+               mov dl,'['
+               int 0x21
+               mov ax,0x02
+               int 0x22
+               mov ah,0x02
+               mov dl,']'
+               int 0x21
+               mov dl,' '
+               int 0x21
+%endif
+               push ds
+               push es
+               pop ds
+               pop es
+               push es
+.find_prefix:
+               lodsb
+               and al,al
+               jnz .find_prefix
+               dec si
+
+               mov cx,si
+               sub cx,bx
+               MARK 'LEN'
+               SHOWD cl                ; assume it's <256 for debugging
+               dec si
+               std
+.find_slash:
+               lodsb
+               cmp al,'/'
+               je .slash
+               loop .find_slash
+.slash:
+               cmp cx,127
+               cld
+               jna .copy_prefix
+               pop ds
+               jmp too_long
+
+.copy_prefix:
+               SHOWD cl
+               MARK 'PFX'
+               mov si,bx
+               mov di,tftp_filename
+               mov bx,128
+               sub bx,cx
+               rep movsb
+               pop ds
+
+               mov cl,[pspCmdLen]
+               mov si,pspCmdArg+1
+               jmp prefix_done
+
+usage:
+               xor cx,cx
+               mov si,msg_usage
+               jmp fail
+
+too_long:
+               xor cx,cx
+               mov si,msg_too_long
+               jmp fail
+
+parse_ip:
+               MARK 'PIP'
+               mov di,si
+               mov si,pspCmdArg+1
+               call parse_dotquad
+               jc .notdq
+               cmp si,di               ; is it the same place?
+               jne .notdq
+               mov [tftp_siaddr],eax
+               jmp gotprefix
+.notdq:
+               MARK 'NDQ'
+               mov si,di
+               mov bx,pspCmdArg+1
+               mov ax,0x0010           ; DNS resolve
+               int 0x22
+               and eax,eax
+               jz noip
+               mov [tftp_siaddr],eax
+gotprefix:
+               MARK 'GOTP'
+               dec cx                  ; skip the ::
+               dec cx
+               inc si
+               inc si
+               mov di,tftp_filename
+               mov bx,128
+
+prefix_done:
+               SHOWD bl
+               MARK 'LEFT'
+
+; SI points at the filename, plus remaining arguments,
+; CX contains their combined length.
+; DI points to where the filename should be stored
+; BX says how much space is left for the filename and NUL
+
+               and cx,cx
+               jz usage                ; no args is bad
+.copy_filename:
+               lodsb
+%ifdef DEBUG
+               mov dl,al
+               mov ah,0x2
+               int 0x21
+%endif
+               cmp al,' '
+               je usage
+               dec bx
+               jz too_long
+               stosb
+               loop .copy_filename
+               xor eax,eax
+               stosb
+
+; get PXE cached data
+               MARK 'GCI'
+               mov ax,0x0009           ; call PXE stack
+               mov bx,0x0071           ; PXENV_GET_CACHED_INFO
+               mov di,PXECacheParms
+               int 0x22
+               and eax,eax
+               jz .fix_siaddr
+               mov cx,[gci_status]
+               mov si,msg_get_cache
+               jmp fail
+
+.fix_siaddr:
+               mov bx,[gci_bufferseg]
+               mov es,bx
+               mov bx,[gci_buffer]
+               mov eax,[es:bx+12]      ; save our address (ciaddr)
+               mov [open_ciaddr],eax   ; ... in case we have to do UDP open
+               mov eax,[tftp_siaddr]
+               and eax,eax
+               jnz .replace_addr
+               MARK 'ADDR'
+               mov eax,[es:bx+20]      ; siaddr
+               mov [tftp_siaddr],eax
+               jmp .addr_done
+.replace_addr:
+               mov [es:bx+20],eax
+.addr_done:
+               mov si,tftp_filename    ; copy the new filename...
+               lea di,[es:bx+108]      ; to the "cached DHCP response"
+               mov cx,128
+               rep movsb
+               mov bx,ds               ; restore es before proceeding
+               mov es,bx
+
+; print out what we are doing
+%ifdef DEBUG
+               mov ah,0x02             ; write character
+               mov dl,0x0d             ; print a CRLF first
+               int 0x21
+               mov dl,0x0a
+               int 0x21
+%endif
+               mov ax,0x0002           ; write string
+               mov bx,msg_booting
+               int 0x22
+               mov ebx,[tftp_siaddr]
+               call print_dotquad
+               mov ah,0x02             ; write character
+               mov dl,' '
+               int 0x21
+               mov ax,0x0002           ; write string
+               mov bx,tftp_filename
+               int 0x22
+               mov ah,0x02             ; write character
+               mov dl,0x0d
+               int 0x21
+               mov dl,0x0a
+               int 0x21
+
+%ifndef NO_RUN
+               mov ax,0x0009           ; call PXE stack
+               mov bx,0x0031           ; PXENV_UDP_CLOSE
+               mov di,PXECloseParms
+               int 0x22
+               mov cx,[close_status]
+               mov si,msg_udp_close
+               and ax,ax
+               jnz fail
+
+               mov ax,0x0009           ; call PXE stack
+               mov bx,0x0073           ; PXENV_RESTART_TFTP
+               mov di,PXERestartTFTPParms
+               int 0x22
+               mov cx,[tftp_status]
+               mov si,msg_rst_tftp
+               call fail
+
+               mov ax,0x0009           ; call PXE stack
+               mov bx,0x0030           ; PXENV_UDP_OPEN
+               mov di,PXEOpenParms
+               int 0x22
+               mov cx,[open_status]
+               mov si,msg_udp_open
+               and ax,ax
+               jnz fail
+               ret
+%endif
+
+fail:
+               MARK 'FAIL'
+               SHOWX cs
+               SHOWX ds
+               SHOWX es
+               SHOWX si
+%ifdef DEBUG
+               mov ah,0x02             ; write character
+               mov dl,0x0d             ; print a CRLF first
+               int 0x21
+               mov dl,0x0a
+               int 0x21
+%endif
+               mov ax,0x0002           ; write string
+               mov bx,msg_progname     ; print our name
+               int 0x22
+               mov bx,si               ; ... the error message
+               int 0x22
+               mov ah,0x02             ; write character
+               jcxz .done
+               mov dl,' '              ; ... and the error code, in []
+               int 0x21
+               mov dl,'['
+               int 0x21
+               mov bx,cx
+               call print_hex
+               mov ah,0x02             ; write character
+               mov dl,']'
+               int 0x21
+.done:
+               mov dl,0x0d             ; and finally a CRLF
+               int 0x21
+               mov dl,0x0a
+               int 0x21
+               ret
+
+
+; print_hex
+;
+; Take a 16-bit integer in BX and print it as 2 hex digits.
+; Destroys AX and DL.
+;
+print_hex:
+               mov al,bh
+               aam 16
+               cmp ah,10
+               jb .lt_a000
+               add ah,'A'-'0'-10
+.lt_a000:      add ah,'0'
+               mov dl,ah
+               mov ah,0x02             ; write character
+               int 0x21
+
+               cmp al,10
+               jb .lt_a00
+               add al,'A'-'0'-10
+.lt_a00:       add al,'0'
+               mov dl,al
+               mov ah,0x02             ; write character
+               int 0x21
+
+               mov al,bl
+               aam 16
+               cmp ah,10
+               jb .lt_a0
+               add ah,'A'-'0'-10
+.lt_a0:                add ah,'0'
+               mov dl,ah
+               mov ah,0x02             ; write character
+               int 0x21
+
+               cmp al,10
+               jb .lt_a
+               add al,'A'-'0'-10
+.lt_a:         add al,'0'
+               mov dl,al
+               mov ah,0x02             ; write character
+               int 0x21
+               ret
+
+
+; print_dec
+;
+; Take an 8-bit integer in AL and print it in decimal.
+; Destroys AX and DL.
+;
+print_dec:
+               cmp al,10               ; < 10?
+               jb .lt10                ; If so, skip first 2 digits
+
+               cmp al,100              ; < 100
+               jb .lt100               ; If so, skip first digit
+
+               aam 100
+               ; Now AH = 100-digit; AL = remainder
+               add ah,'0'
+               mov dl,ah
+               mov ah,0x02
+               int 0x21
+
+.lt100:
+               aam 10
+               ; Now AH = 10-digit; AL = remainder
+               add ah,'0'
+               mov dl,ah
+               mov ah,0x02
+               int 0x21
+
+.lt10:
+               add al,'0'
+               mov dl,al
+               mov ah,0x02
+               int 0x21
+               ret
+
+
+; print_dotquad
+;
+; Take an IP address (in network byte order) in EBX and print it 
+; as a dotted quad.
+; Destroys EAX, EBX, ECX, EDX
+;
+print_dotquad:
+               mov cx,3
+.octet:
+               mov al,bl
+               call print_dec
+               jcxz .done
+               mov ah,0x02
+               mov dl,'.'
+               int 0x21
+               ror ebx,8       ; Move next char into LSB
+               dec cx
+               jmp .octet
+.done:
+               ret
+
+
+; parse_dotquad:
+;              Read a dot-quad pathname in DS:SI and output an IP
+;              address in EAX, with SI pointing to the first
+;              nonmatching character.
+;
+;              Return CF=1 on error.
+;
+;              No segment assumptions permitted.
+;
+parse_dotquad:
+               push cx
+               mov cx,4
+               xor eax,eax
+.parseloop:
+               mov ch,ah
+               mov ah,al
+               lodsb
+               sub al,'0'
+               jb .notnumeric
+               cmp al,9
+               ja .notnumeric
+               aad                             ; AL += 10 * AH; AH = 0;
+               xchg ah,ch
+               jmp .parseloop
+.notnumeric:
+               cmp al,'.'-'0'
+               pushf
+               mov al,ah
+               mov ah,ch
+               xor ch,ch
+               ror eax,8
+               popf
+               jne .error
+               loop .parseloop
+               jmp .done
+.error:
+               loop .realerror                 ; If CX := 1 then we're done
+               clc
+               jmp .done
+.realerror:
+               stc
+.done:
+               dec si                          ; CF unchanged!
+               pop cx
+               ret
+
+               section .data
+msg_booting:   db 'TFTP boot: ',0
+msg_progname:  db 'pxechain: ',0
+msg_usage:     db 'usage: pxechain.cbt [[ipaddress]::]filename',0dh,0ah,0
+msg_too_long:  db 'pxechain: filename is too long (max 127)',0dh,0ah,0
+msg_get_cache: db 'PXENV_GET_CACHED_INFO',0
+msg_rst_tftp:  db 'PXENV_RESTART_TFTP',0
+msg_udp_close: db 'PXENV_UDP_CLOSE',0
+msg_udp_open:  db 'PXENV_UDP_OPEN',0
+
+PXECacheParms:
+gci_status:    dw 0
+gci_packettype:        dw 3                    ; PXENV_PACKET_TYPE_CACHED_REPLY
+gci_buffersize:        dw 0
+gci_buffer:    dw 0
+gci_bufferseg: dw 0
+gci_bufferlim: dw 0
+
+PXERestartTFTPParms:
+tftp_status:   dw 0
+tftp_filename: times 128 db 0
+tftp_bufsize:  dd 0x00090000           ; available memory for NBP
+tftp_bufaddr:  dd 0x00007c00           ; PXE NBP load address
+tftp_siaddr:   dd 0
+tftp_giaddr:   dd 0
+tftp_mcaddr:   dd 0
+tftp_mcport:   dw 0
+tftp_msport:   dw 0
+tftp_timeout:  dw 0
+tftp_reopendly:        dw 0
+
+PXECloseParms:
+close_status:  dw 0
+
+PXEOpenParms:
+open_status:   dw 0
+open_ciaddr:    dd 0
+
+               section .bss
+ipaddrbuf:     resb 16