summaryrefslogtreecommitdiffstats
path: root/contrib/syslinux-4.02/modules/pxechain.asm
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/syslinux-4.02/modules/pxechain.asm')
-rw-r--r--contrib/syslinux-4.02/modules/pxechain.asm558
1 files changed, 558 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/modules/pxechain.asm b/contrib/syslinux-4.02/modules/pxechain.asm
new file mode 100644
index 0000000..35c1969
--- /dev/null
+++ b/contrib/syslinux-4.02/modules/pxechain.asm
@@ -0,0 +1,558 @@
+; "$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