📄 pxelinux.asm
字号:
movzx ecx,word [4*0x1a+2] shl ecx,4 add eax,ecx shr eax,10 cmp ax,dx ; Not in range jae .ok cmp ax,[BIOS_fbm] jae .cant_free ; inc bx.ok: mov [BIOS_fbm],dx.pop_ret: pop es pop ds ret .cant_free: mov si,cant_free_msg call writestr push ax xchg bx,ax call writehex4 mov al,'-' call writechr pop ax call writehex4 mov al,'-' call writechr mov eax,[4*0x1a] call writehex8 call crlf jmp .pop_ret ; We want to keep PXE around, but still we should reset ; it to the standard bootup configurationreset_pxe: push es push cs pop es mov bx,PXENV_UDP_CLOSE mov di,pxe_udp_close_pkt call pxenv pop es ret;; gendotquad;; Take an IP address (in network byte order) in EAX and; output a dotted quad string to ES:DI.; DI points to terminal null at end of string on exit.;gendotquad: push eax push cx mov cx,4.genchar: push eax 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 [es:di],ah inc di.lt100: aam 10 ; Now AH = 10-digit; AL = remainder add ah,'0' mov [es:di],ah inc di.lt10: add al,'0' stosb mov al,'.' stosb pop eax ror eax,8 ; Move next char into LSB loop .genchar dec di mov [es:di], byte 0 pop cx pop eax ret;; 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; ServerIP - boot server IP address; Netmask - network mask; Gateway - default gateway router IP; BootFile - boot file name; DNSServers - DNS server IPs; LocalDomain - Local domain name;; This assumes the DHCP packet is in "trackbuf" and the length; of the packet in in CX on entry.;parse_dhcp: mov byte [OverLoad],0 ; Assume no overload mov eax, [trackbuf+bootp.yip] and eax, eax jz .noyip cmp al,224 ; Class D or higher -> bad jae .noyip mov [MyIP], eax.noyip: mov eax, [trackbuf+bootp.sip] and eax, eax jz .nosip cmp al,224 ; Class D or higher -> bad jae .nosip mov [ServerIP], eax.nosip: sub cx, bootp.options jbe .nooptions mov si, trackbuf+bootp.option_magic lodsd cmp eax, BOOTP_OPTION_MAGIC jne .nooptions call parse_dhcp_options.nooptions: mov si, trackbuf+bootp.bootfile test byte [OverLoad],1 jz .nofileoverload mov cx,128 call parse_dhcp_options jmp short .parsed_file.nofileoverload: cmp byte [si], 0 jz .parsed_file ; No bootfile name mov di,BootFile mov cx,32 rep movsd xor al,al stosb ; Null-terminate.parsed_file: mov si, trackbuf+bootp.sname test byte [OverLoad],2 jz .nosnameoverload mov cx,64 call parse_dhcp_options.nosnameoverload: ret;; Parse a sequence of DHCP options, pointed to by DS:SI; the field; size is CX -- some DHCP servers leave option fields unterminated; in violation of the spec.;; For parse_some_dhcp_options, DH contains the minimum value for; the option to recognize -- this is used to restrict parsing to; PXELINUX-specific options only.;parse_dhcp_options: xor dx,dxparse_some_dhcp_options:.loop: and cx,cx jz .done lodsb dec cx jz .done ; Last byte; must be PAD, END or malformed cmp al, 0 ; PAD option je .loop cmp al,255 ; END option je .done ; Anything else will have a length field mov dl,al ; DL <- option number xor ax,ax lodsb ; AX <- option length dec cx sub cx,ax ; Decrement bytes left counter jb .done ; Malformed option: length > field size cmp dl,dh ; Is the option value valid? jb .opt_done cmp dl,1 ; SUBNET MASK option jne .not_subnet mov ebx,[si] mov [Netmask],ebx jmp .opt_done.not_subnet: cmp dl,3 ; ROUTER option jne .not_router mov ebx,[si] mov [Gateway],ebx jmp .opt_done.not_router: cmp dl,6 ; DNS SERVERS option jne .not_dns pusha mov cx,ax shr cx,2 cmp cl,DNS_MAX_SERVERS jna .oklen mov cl,DNS_MAX_SERVERS.oklen: mov di,DNSServers rep movsd mov [LastDNSServer],di popa jmp .opt_done.not_dns: cmp dl,15 ; DNS LOCAL DOMAIN option jne .not_localdomain pusha mov bx,si add bx,ax xor ax,ax xchg [bx],al ; Zero-terminate option mov di,LocalDomain call dns_mangle ; Convert to DNS label set mov [bx],al ; Restore ending byte popa jmp .opt_done.not_localdomain: cmp dl,43 ; VENDOR ENCAPSULATED option jne .not_vendor pusha mov dh,208 ; Only recognize PXELINUX options mov cx,ax ; Length of option = max bytes to parse call parse_some_dhcp_options ; Parse recursive structure popa jmp .opt_done.not_vendor: cmp dl,52 ; OPTION OVERLOAD option jne .not_overload mov bl,[si] mov [OverLoad],bl jmp .opt_done.not_overload: cmp dl,67 ; BOOTFILE NAME option jne .not_bootfile mov di,BootFile jmp short .copyoption.done: ret ; This is here to make short jumps easier.not_bootfile: cmp dl,208 ; PXELINUX MAGIC option jne .not_pl_magic cmp al,4 ; Must have length == 4 jne .opt_done cmp dword [si], htonl(0xF100747E) ; Magic number jne .opt_done or byte [DHCPMagic], byte 1 ; Found magic # jmp short .opt_done.not_pl_magic: cmp dl,209 ; PXELINUX CONFIGFILE option jne .not_pl_config mov di,ConfigName or byte [DHCPMagic], byte 2 ; Got config file jmp short .copyoption.not_pl_config: cmp dl,210 ; PXELINUX PATHPREFIX option jne .not_pl_prefix mov di,PathPrefix or byte [DHCPMagic], byte 4 ; Got path prefix jmp short .copyoption.not_pl_prefix: cmp dl,211 ; PXELINUX REBOOTTIME option jne .not_pl_timeout cmp al,4 jne .opt_done mov ebx,[si] xchg bl,bh ; Convert to host byte order rol ebx,16 xchg bl,bh mov [RebootTime],ebx or byte [DHCPMagic], byte 8 ; Got RebootTime ; jmp short .opt_done.not_pl_timeout: ; Unknown option. Skip to the next one..opt_done: add si,ax.opt_done_noskip: jmp .loop ; Common code for copying an option verbatim.copyoption: xchg cx,ax rep movsb xchg cx,ax ; Now ax == 0 stosb ; Null-terminate jmp short .opt_done_noskip;; genipopt;; Generate an ip=<client-ip>:<boot-server-ip>:<gw-ip>:<netmask>; option into IPOption based on a DHCP packet in trackbuf.; Assumes CS == DS == ES.;genipopt: pushad mov di,IPOption mov eax,'ip=' stosd dec di mov eax,[MyIP] call gendotquad mov al,':' stosb mov eax,[ServerIP] call gendotquad mov al,':' stosb mov eax,[Gateway] call gendotquad mov al,':' stosb mov eax,[Netmask] call gendotquad ; Zero-terminates its output sub di,IPOption mov [IPOptionLen],di popad ret;; Call the receive loop while idle. This is done mostly so we can respond to; ARP messages, but perhaps in the future this can be used to do network; console.;; hpa sez: people using automatic control on the serial port get very; unhappy if we poll for ARP too often (the PXE stack is pretty slow,; typically.) Therefore, only poll if at least 4 BIOS timer ticks have; passed since the last poll, and reset this when a character is; received (RESET_IDLE).;reset_idle: push ax mov ax,[cs:BIOS_timer] mov [cs:IdleTimer],ax pop ax retcheck_for_arp: push ax mov ax,[cs:BIOS_timer] sub ax,[cs:IdleTimer] cmp ax,4 pop ax jae .need_poll ret.need_poll: pushad push ds push es mov ax,cs mov ds,ax mov es,ax mov di,packet_buf mov [pxe_udp_read_pkt.status],al ; 0 mov [pxe_udp_read_pkt.buffer],di mov [pxe_udp_read_pkt.buffer+2],ds mov word [pxe_udp_read_pkt.buffersize],packet_buf_size mov eax,[MyIP] mov [pxe_udp_read_pkt.dip],eax mov word [pxe_udp_read_pkt.lport],htons(9) ; discard port mov di,pxe_udp_read_pkt mov bx,PXENV_UDP_READ call pxenv ; Ignore result... pop es pop ds popad RESET_IDLE ret; -----------------------------------------------------------------------------; Common modules; -----------------------------------------------------------------------------%include "getc.inc" ; getc et al%include "conio.inc" ; Console I/O%include "writestr.inc" ; String outputwritestr equ cwritestr%include "writehex.inc" ; Hexadecimal output%include "parseconfig.inc" ; High-level config file handling%include "parsecmd.inc" ; Low-level config file handling%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 "rawcon.inc" ; Console I/O w/o using the console functions%include "dnsresolv.inc" ; DNS resolver; -----------------------------------------------------------------------------; Begin data section; ----------------------------------------------------------------------------- section .datahextbl_lower db '0123456789abcdef'copyright_str db ' Copyright (C) 1994-', year, ' H. Peter Anvin' db CR, LF, 0boot_prompt db 'boot: ', 0wipe_char db BS, ' ', BS, 0err_notfound db 'Could not find kernel image: ',0err_notkernel db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0err_noram db 'It appears your computer has less than ' asciidec dosram_k db 'K of low ("DOS")' db CR, LF db 'RAM. Linux 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, 0err_badcfg db 'Unknown keyword in config file.', CR, LF, 0err_noparm db 'Missing parameter in config file.', CR, LF, 0err_noinitrd db CR, LF, 'Could not find ramdisk image: ', 0err_nohighmem db 'Not enough memory to load specified kernel.', CR, LF, 0err_highload db CR, LF, 'Kernel transfer failure.', CR, LF, 0err_oldkernel db 'Cannot load a ramdisk with an old kernel image.' db CR, LF, 0err_notdos db ': attempted DOS system call', CR, LF, 0err_comlarge db 'COMBOOT image too large.', CR, LF, 0err_bssimage db 'BSS images not supported.', CR, LF, 0err_a20 db CR, LF, 'A20 gate not responding!', CR, LF, 0err_bootfailed db CR, LF, 'Boot failed: press a key to retry, or wait for reset...', CR, LF, 0bailmsg equ err_bootfailederr_nopxe db "No !PXE or PXENV+ API found; we're dead...", CR, LF, 0err_pxefailed db 'PXE API call failed, error ', 0err_udpinit db 'Failed to initialize UDP stack', CR, LF, 0err_oldtftp db 'TFTP server does not support the tsize option', CR, LF, 0found_pxenv db 'Found PXENV+ structure', CR, LF, 0using_pxenv_msg db 'Old PXE API detected, using PXENV+ structure', CR, LF, 0apiver_str db 'PXE API version is ',0pxeentry_msg db 'PXE entry point found (we hope) at ', 0pxenventry_msg db 'PXENV entry point found (we hope) at ', 0trymempxe_msg db 'Scanning memory for !PXE structure... ', 0trymempxenv_msg db 'Scanning memory for PXENV+ structure... ', 0undi_data_msg db 'UNDI data segment at: ',0undi_data_len_msg db 'UNDI data segment size: ',0 undi_code_msg db 'UNDI code segment at: ',0undi_code_len_msg db 'UNDI code segment size: ',0 cant_free_msg db 'Failed to free base memory, error ', 0notfound_msg db 'not found', CR, LF, 0myipaddr_msg db 'My IP address seems to be ',0tftpprefix_msg db 'TFTP prefix: ', 0localboot_msg db 'Booting from local disk...', CR, LF, 0cmdline_msg db 'Command line: ', CR, LF, 0ready_msg db 'Ready.', CR, LF, 0trying_msg db 'Trying to load: ', 0crlfloading_msg db CR, LF ; Fall throughloading_msg db 'Loading ', 0dotdot_msg db '.'dot_msg db '.', 0fourbs_msg db BS, BS, BS, BS, 0aborted_msg db ' aborted.' ; Fall through to crlf_msg!crlf_msg db CR, LFnull_msg db 0crff_msg db CR, FF, 0default_str db 'default', 0default_len equ ($-default_str)syslinux_banner db CR, LF, 'PXELINUX ', version_str, ' ', date, ' ', 0cfgprefix db 'pxelinux.cfg/' ; No final null!cfgprefix_len equ ($-cfgprefix);; Command line options we'd like to take a look at;; mem= and vga= are handled as normal 32-bit integer valuesinitrd_cmd db 'initrd='initrd_cmd_len equ $-initrd_cmd; This one we make ourselvesbootif_str db 'BOOTIF='bootif_str_len equ $-bootif_str;; Config file keyword table;%include "keywords.inc";; Extensions to search for (in *forward* order).; (.bs and .bss are disabled for PXELINUX, since they are not supported); align 4, db 0exten_table: db '.cbt' ; COMBOOT (specific) db '.0', 0, 0 ; PXE bootstrap program db '.com' ; COMBOOT (same as DOS) db '.c32' ; COM32exten_table_end: dd 0, 0 ; Need 8 null bytes here;; PXE unload sequences;new_api_unload: db PXENV_UDP_CLOSE db PXENV_UNDI_SHUTDOWN db PXENV_UNLOAD_STACK db PXENV_STOP_UNDI db 0old_api_unload: db PXENV_UDP_CLOSE db PXENV_UNDI_SHUTDOWN db PXENV_UNLOAD_STACK db PXENV_UNDI_CLEANUP db 0;; PXE query packets partially filled in;pxe_bootp_query_pkt_2:.status: dw 0 ; Status.packettype: dw 2 ; DHCPACK packet.buffersize: dw trackbufsize ; Packet size.buffer: dw trackbuf, 0 ; seg:off of buffer.bufferlimit: dw trackbufsize ; Unusedpxe_bootp_query_pkt_3:.status: dw 0 ; Status.packettype: dw 3 ; Boot server packet.buffersize: dw trackbufsize ; Packet size.buffer: dw trackbuf, 0 ; seg:off of buffer.bufferlimit: dw trackbufsize ; Unusedpxe_bootp_size_query_pkt:.status: dw 0 ; Status.packettype: dw 2 ; DHCPACK packet.buffersize: dw 0 ; Packet size.buffer: dw 0, 0 ; seg:off of buffer.bufferlimit: dw 0 ; Unusedpxe_udp_open_pkt:.status: dw 0 ; Status.sip: dd 0 ; Source (our) IPpxe_udp_close_pkt:.status: dw 0 ; Statuspxe_udp_write_pkt:.status: dw 0 ; Status.sip: dd 0 ; Server IP.gip: dd 0 ; Gateway IP.lport: dw 0 ; Local port.rport: dw 0 ; Remote port.buffersize: dw 0 ; Size of packet.buffer: dw 0, 0 ; seg:off of bufferpxe_udp_read_pkt:.status: dw 0 ; Status.sip: dd 0 ; Source IP.dip: dd 0 ; Destination (our) IP.rport: dw 0 ; Remote port.lport: dw 0 ; Local port.buffersize: dw 0 ; Max packet size.buffer: dw 0, 0 ; seg:off of buffer;; Misc initialized (data) variables; alignb 4, db 0BaseStack dd StackBuf ; ESP of base stack dw 0 ; SS of base stackNextSocket dw 49152 ; Counter for allocating socket numbersKeepPXE db 0 ; Should PXE be kept around?;; TFTP commands;tftp_tail db 'octet', 0 ; Octet modetsize_str db 'tsize' ,0 ; Request sizetsize_len equ ($-tsize_str) db '0', 0blksize_str db 'blksize', 0 ; Request large blocksblksize_len equ ($-blksize_str) asciidec TFTP_LARGEBLK db 0tftp_tail_len equ ($-tftp_tail) alignb 2, db 0;; Options negotiation parsing table (string pointer, string len, offset; into socket structure);tftp_opt_table: dw tsize_str, tsize_len, tftp_filesize dw blksize_str, blksize_len, tftp_blksizetftp_opts equ ($-tftp_opt_table)/6;; Error packet to return on options negotiation error;tftp_opt_err dw TFTP_ERROR ; ERROR packet dw TFTP_EOPTNEG ; ERROR 8: bad options db 'tsize option required', 0 ; Error messagetftp_opt_err_len equ ($-tftp_opt_err) alignb 4, db 0ack_packet_buf: dw TFTP_ACK, 0 ; TFTP ACK packet;; IP information (initialized to "unknown" values)MyIP dd 0 ; My IP addressServerIP dd 0 ; IP address of boot serverNetmask dd 0 ; Netmask of this subnetGateway dd 0 ; Default routerServerPort dw TFTP_PORT ; TFTP server port;; Variables that are uninitialized in SYSLINUX but initialized here; alignb 4, db 0BufSafe dw trackbufsize/TFTP_BLOCKSIZE ; Clusters we can load into trackbufBufSafeSec dw trackbufsize/512 ; = how many sectors?BufSafeBytes dw trackbufsize ; = how many bytes?EndOfGetCBuf dw getcbuf+trackbufsize ; = getcbuf+BufSafeBytes%ifndef DEPEND%if ( trackbufsize % TFTP_BLOCKSIZE ) != 0%error trackbufsize must be a multiple of TFTP_BLOCKSIZE%endif%endifIPAppend db 0 ; Default IPAPPEND optionDHCPMagic db 0 ; DHCP site-specific option info
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -