📄 pxelinux.asm
字号:
; -*- fundamental -*- (asm-mode sucks); $Id: pxelinux.asm,v 1.146 2004/05/29 22:11:23 hpa Exp $; ****************************************************************************;; 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 (C) 1994-2004 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., 675 Mass Ave, Cambridge MA 02139,; USA; either version 2 of the License, or (at your option) any later; version; incorporated herein by reference.; ; ****************************************************************************%define IS_PXELINUX 1%include "macros.inc"%include "config.inc"%include "kernel.inc"%include "bios.inc"%include "tracers.inc"%include "pxe.inc";; Some semi-configurable constants... change on your own risk.;my_id equ pxelinux_idFILENAME_MAX_LG2 equ 7 ; log2(Max filename size Including final null)FILENAME_MAX equ (1 << FILENAME_MAX_LG2)NULLFILE equ 0 ; Zero byte == null file nameREBOOT_TIME equ 5*60 ; If failure, time until full reset%assign HIGHMEM_SLOP 128*1024 ; Avoid this much memory near the topMAX_SOCKETS_LG2 equ 5 ; log2(Max number of open sockets)MAX_SOCKETS equ (1 << MAX_SOCKETS_LG2)PKTBUF_SIZE equ (65536/MAX_SOCKETS) ; Per-socket packet buffer sizeTFTP_PORT equ htons(69) ; Default TFTP port PKT_RETRY equ 6 ; Packet transmit retry countPKT_TIMEOUT equ 12 ; Initial timeout, timer ticks @ 55 ms; Desired TFTP block size; For Ethernet MTU is normally 1500. Unfortunately there seems to; be a fair number of networks with "substandard" MTUs which break.; The code assumes TFTP_LARGEBLK <= 2K.TFTP_MTU equ 1472TFTP_LARGEBLK equ (TFTP_MTU-20-8-4) ; MTU - IP hdr - UDP hdr - TFTP hdr; Standard TFTP block sizeTFTP_BLOCKSIZE_LG2 equ 9 ; log2(bytes/block)TFTP_BLOCKSIZE equ (1 << TFTP_BLOCKSIZE_LG2)%assign USE_PXE_PROVIDED_STACK 1 ; Use stack provided by PXE?;; This is what we need to do when idle;%macro RESET_IDLE 0 call reset_idle%endmacro%macro DO_IDLE 0 call check_for_arp%endmacro;; TFTP operation codes;TFTP_RRQ equ htons(1) ; Read requestTFTP_WRQ equ htons(2) ; Write requestTFTP_DATA equ htons(3) ; Data packetTFTP_ACK equ htons(4) ; ACK packetTFTP_ERROR equ htons(5) ; ERROR packetTFTP_OACK equ htons(6) ; OACK packet;; TFTP error codes;TFTP_EUNDEF equ htons(0) ; Unspecified errorTFTP_ENOTFOUND equ htons(1) ; File not foundTFTP_EACCESS equ htons(2) ; Access violationTFTP_ENOSPACE equ htons(3) ; Disk fullTFTP_EBADOP equ htons(4) ; Invalid TFTP operationTFTP_EBADID equ htons(5) ; Unknown transferTFTP_EEXISTS equ htons(6) ; File existsTFTP_ENOUSER equ htons(7) ; No such userTFTP_EOPTNEG equ htons(8) ; Option negotiation failure;; 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 at vk_seg:0000 and copy them down before we need them.;; Note: this structure can be added to, but it must ;%define vk_power 6 ; log2(max number of vkernels)%define max_vk (1 << vk_power) ; Maximum number of vkernels%define vk_shift (16-vk_power) ; Number of bits to shift%define vk_size (1 << vk_shift) ; Size of a vkernel buffer struc vkernelvk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!**vk_rname: resb FILENAME_MAX ; Real namevk_ipappend: resb 1 ; "IPAPPEND" flag resb 1 ; Padvk_appendlen: resw 1 alignb 4vk_append: resb max_cmd_len+1 ; Command line alignb 4vk_end: equ $ ; Should be <= vk_size endstruc%ifndef DEPEND%if (vk_end > vk_size) || (vk_size*max_vk > 65536)%error "Too many vkernels defined, reduce vk_power"%endif%endif;; Segment assignments in the bottom 640K; 0000h - main code/data segment (and BIOS segment);real_mode_seg equ 4000hvk_seg equ 3000h ; Virtual kernelsxfer_buf_seg equ 2000h ; Bounce buffer for I/O to high mempktbuf_seg equ 1000h ; Packet buffers segmentscomboot_seg equ real_mode_seg ; COMBOOT image loading zone;; BOOTP/DHCP packet pattern; struc bootp_t bootp:.opcode resb 1 ; BOOTP/DHCP "opcode".hardware resb 1 ; ARP hardware type.hardlen resb 1 ; Hardware address length.gatehops resb 1 ; Used by forwarders.ident resd 1 ; Transaction ID.seconds resw 1 ; Seconds elapsed.flags resw 1 ; Broadcast flags.cip resd 1 ; Client IP.yip resd 1 ; "Your" IP.sip resd 1 ; Next server IP.gip resd 1 ; Relay agent IP.macaddr resb 16 ; Client MAC address.sname resb 64 ; Server name (optional).bootfile resb 128 ; Boot file name.option_magic resd 1 ; Vendor option magic cookie.options resb 1260 ; Vendor options endstruc BOOTP_OPTION_MAGIC equ htonl(0x63825363) ; See RFC 2132;; TFTP connection data structure. Each one of these corresponds to a local; UDP port. The size of this structure must be a power of 2.; HBO = host byte order; NBO = network byte order; (*) = written by options negotiation code, must be dword sized; struc tftp_port_ttftp_localport resw 1 ; Local port number (0 = not in use)tftp_remoteport resw 1 ; Remote port numbertftp_remoteip resd 1 ; Remote IP addresstftp_filepos resd 1 ; Bytes downloaded (including buffer)tftp_filesize resd 1 ; Total file size(*)tftp_blksize resd 1 ; Block size for this connection(*)tftp_bytesleft resw 1 ; Unclaimed data bytestftp_lastpkt resw 1 ; Sequence number of last packet (NBO)tftp_dataptr resw 1 ; Pointer to available data resw 2 ; Currently unusued ; At end since it should not be zeroed on socked closetftp_pktbuf resw 1 ; Packet buffer offset endstructftp_clear_words equ (tftp_pktbuf/2) ; Number of words to zero on socket close%ifndef DEPEND%if (tftp_port_t_size & (tftp_port_t_size-1))%error "tftp_port_t is not a power of 2"%endif%endif; ---------------------------------------------------------------------------; BEGIN CODE; ---------------------------------------------------------------------------;; Memory below this point is reserved for the BIOS and the MBR; absolute 1000htrackbuf resb 8192 ; Track buffer goes heretrackbufsize equ $-trackbuf; trackbuf ends at 3000h;; Constants for the xfer_buf_seg;; The xfer_buf_seg is also used to store message file buffers. We; need two trackbuffers (text and graphics), plus a work buffer; for the graphics decompressor.;xbs_textbuf equ 0 ; Also hard-coded, do not changexbs_vgabuf equ trackbufsizexbs_vgatmpbuf equ 2*trackbufsize absolute 4000h ; Here we keep our BSS stuffVKernelBuf: resb vk_size ; "Current" vkernel alignb 4AppendBuf resb max_cmd_len+1 ; append=Ontimeout resb max_cmd_len+1 ; ontimeoutOnerror resb max_cmd_len+1 ; onerrorKbdMap resb 256 ; Keyboard mapPathPrefix resb 256 ; Path prefix derived from the aboveBootFile resb 256 ; Boot file from DHCP packetConfigName resb 256 ; Configuration file from DHCP optionFKeyName resb 10*FILENAME_MAX ; File names for F-key help alignb FILENAME_MAXKernelName resb FILENAME_MAX ; Mangled name for kernelKernelCName resb FILENAME_MAX ; Unmangled kernel nameInitRDCName resb FILENAME_MAX ; Unmangled initrd nameMNameBuf resb FILENAME_MAXInitRD resb FILENAME_MAX; 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. absolute 6000hNumBuf resb 15 ; Buffer to load numberNumBufEnd resb 1 ; Last byte in NumBufDotQuadBuf resb 16 ; Buffer for dotted-quad IP addressIPOption resb 80 ; ip= option bufferMACLen resb 1 ; MAC address lenMACType resb 1 ; MAC address typeMAC resb 16 ; Actual MAC addressMACStr resb 3*17 ; MAC address as a stringPartInfo resb 16 ; Partition table entryE820Buf resd 5 ; INT 15:E820 data bufferE820Mem resd 1 ; Memory detected by E820E820Max resd 1 ; Is E820 memory capped?HiLoadAddr resd 1 ; Address pointer for high load loopHighMemSize resd 1 ; End of memory pointer (bytes)RamdiskMax resd 1 ; Highest address for a ramdiskKernelSize resd 1 ; Size of kernel (bytes)SavedSSSP resd 1 ; Our SS:SP while running a COMBOOT imagePMESP resd 1 ; Protected-mode ESPInitStack resd 1 ; Pointer to reset stackRebootTime resd 1 ; Reboot timeout, if set by optionKernelClust resd 1 ; Kernel size in clustersStrucPtr resd 1 ; Pointer to PXENV+ or !PXE structureFBytes equ $ ; Used by open/getcFBytes1 resw 1FBytes2 resw 1FClust resw 1 ; Number of clusters in open/getc fileFNextClust resw 1 ; Pointer to next cluster in d:oFPtr resw 1 ; Pointer to next char in bufferCmdOptPtr resw 1 ; Pointer to first option on cmd lineKernelCNameLen resw 1 ; Length of unmangled kernel nameInitRDCNameLen resw 1 ; Length of unmangled initrd nameNextCharJump resw 1 ; Routine to interpret next print charSetupSecs resw 1 ; Number of setup sectorsA20Test resw 1 ; Counter for testing status of A20A20Type resw 1 ; A20 typeCmdLineLen resw 1 ; Length of command line including nullGraphXSize resw 1 ; Width of splash screen fileVGAPos resw 1 ; Pointer into VGA memoryVGACluster resw 1 ; Cluster pointer for VGA image fileVGAFilePtr resw 1 ; Pointer into VGAFileBufCom32SysSP resw 1 ; SP saved during COM32 syscallConfigFile resw 1 ; Socket for config filePktTimeout resw 1 ; Timeout for current packetKernelExtPtr resw 1 ; During search, final null pointerIPOptionLen resw 1 ; Length of IPOptionLocalBootType resw 1 ; Local boot return codeRealBaseMem resw 1 ; Amount of DOS memory after freeingAPIVer resw 1 ; PXE API version foundIdleTimer resw 1 ; Time to check for ARP?CursorDX equ $CursorCol resb 1 ; Cursor column for message fileCursorRow resb 1 ; Cursor row for message fileScreenSize equ $VidCols resb 1 ; Columns on screen-1VidRows resb 1 ; Rows on screen-1BaudDivisor resw 1 ; Baud rate divisorFlowControl equ $FlowOutput resb 1 ; Outputs to assert for serial flowFlowInput resb 1 ; Input bits for serial flowFlowIgnore resb 1 ; Ignore input unless these bits setTextAttribute resb 1 ; Text attribute for message fileRetryCount resb 1 ; Used for disk access retriesKbdFlags resb 1 ; Check for keyboard escapesLoadFlags resb 1 ; Loadflags from kernelA20Tries resb 1 ; Times until giving up on A20FuncFlag resb 1 ; == 1 if <Ctrl-F> pressedDisplayMask resb 1 ; Display modes maskOverLoad resb 1 ; Set if DHCP packet uses "overloading"TextColorReg resb 17 ; VGA color registers for text modeVGAFileBuf resb FILENAME_MAX ; Unmangled VGA image nameVGAFileBufEnd equ $VGAFileMBuf resb FILENAME_MAX ; Mangled VGA image name;; PXE packets which don't need static initialization; alignb 4pxe_unload_stack_pkt:.status: resw 1 ; Status.reserved: resw 10 ; Reservedpxe_unload_stack_pkt_len equ $-pxe_unload_stack_pkt alignb tftp_port_t_sizeSockets resb MAX_SOCKETS*tftp_port_t_size alignb 16 ; BOOTP/DHCP packet buffer alignb 16packet_buf resb 2048 ; Transfer packetpacket_buf_size equ $-packet_buf section .text org 7C00hStackBuf equ $-44 ; Base of stack if we use our own;; Primary entry point.;bootsec equ $_start: jmp 0:_start1 ; Canonicalize address_start1: pushfd ; Paranoia... in case of return to PXE pushad ; ... save as much state as possible push ds push es push fs push gs mov bp,sp les bx,[bp+48] ; ES:BX -> !PXE or PXENV+ structure mov ax,cs mov ds,ax ; 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%if USE_PXE_PROVIDED_STACK ; Apparently some platforms go bonkers if we ; set up our own stack... mov [BaseStack],sp mov [BaseStack+4],ss%endif cli ; Paranoia lss esp,[BaseStack] sti ; Stack set up and ready cld ; Copy upwards;; Initialize screen (if we're using one); ; Now set up screen parameters call adjust_screen ; Wipe the F-key area mov al,NULLFILE mov di,FKeyName mov cx,10*(1 << FILENAME_MAX_LG2) push es ; Save ES -> PXE structure push ds ; ES <- DS pop es rep stosb pop es ; Restore ES;; Tell the user we got this far; mov si,syslinux_banner call writestr mov si,copyright_str call writestr;; Assume API version 2.1, in case we find the !PXE structure without; finding the PXENV+ structure. This should really look at the Base; Code ROM ID structure in have_pxe, but this is adequate for now --; if we have !PXE, we have to be 2.1 or higher, and we don't care; about higher versions than that.; mov word [APIVer],0201h;; Now we need to find the !PXE structure. It's *supposed* to be pointed; to by SS:[SP+4], but support INT 1Ah, AX=5650h method as well.; FIX: ES:BX should point to the PXENV+ structure on entry as well.; We should make that the second test, and not trash ES:BX...; cmp dword [es:bx], '!PXE' je have_pxe ; Uh-oh, not there... try plan B mov ax, 5650h int 1Ah ; May trash regs jc no_pxe cmp ax,564Eh jne no_pxe ; Okay, that gave us the PXENV+ structure, find !PXE ; structure from that (if available) cmp dword [es:bx], 'PXEN' jne no_pxe cmp word [es:bx+4], 'V+' je have_pxenv ; Nothing there either. Last-ditch: scan memory call memory_scan_for_pxe_struct ; !PXE scan jnc have_pxe call memory_scan_for_pxenv_struct ; PXENV+ scan jnc have_pxenvno_pxe: mov si,err_nopxe call writestr jmp kaboomhave_pxenv: mov [StrucPtr],bx mov [StrucPtr+2],es mov si,found_pxenv call writestr mov si,apiver_str call writestr mov ax,[es:bx+6] mov [APIVer],ax call writehex4 call crlf cmp ax,0201h ; API version 2.1 or higher jb old_api mov si,bx mov ax,es les bx,[es:bx+28h] ; !PXE structure pointer cmp dword [es:bx],'!PXE' je 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. call memory_scan_for_pxe_struct jnc have_pxe ; Otherwise, no dice, use PXENV+ structure mov bx,si mov es,axold_api: ; Need to use a PXENV+ structure mov si,using_pxenv_msg call writestr mov eax,[es:bx+0Ah] ; PXE RM API mov [PXENVEntry],eax mov si,undi_data_msg ; *** call writestr mov ax,[es:bx+20h] call writehex4 call crlf mov si,undi_data_len_msg call writestr mov ax,[es:bx+22h] call writehex4 call crlf mov si,undi_code_msg call writestr mov ax,[es:bx+24h] call writehex4 call crlf mov si,undi_code_len_msg call writestr mov ax,[es:bx+26h] call writehex4 call crlf ; Compute base memory size from PXENV+ structure xor esi,esi movzx eax,word [es:bx+20h] ; UNDI data seg cmp ax,[es:bx+24h] ; UNDI code seg ja .use_data mov ax,[es:bx+24h] mov si,[es:bx+26h] jmp short .combine.use_data: mov si,[es:bx+22h].combine: shl eax,4 add eax,esi shr eax,10 ; Convert to kilobytes mov [RealBaseMem],ax mov si,pxenventry_msg call writestr mov ax,[PXENVEntry+2] call writehex4 mov al,':' call writechr mov ax,[PXENVEntry] call writehex4 call crlf jmp have_entrypointhave_pxe: mov [StrucPtr],bx mov [StrucPtr+2],es mov eax,[es:bx+10h] mov [PXEEntry],eax mov si,undi_data_msg ; *** call writestr mov eax,[es:bx+2Ah] call writehex8 call crlf mov si,undi_data_len_msg call writestr mov ax,[es:bx+2Eh]
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -