⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pxelinux.asm

📁 linux内核
💻 ASM
📖 第 1 页 / 共 4 页
字号:
		jnz .get_opt_name		; Not end of packet		; ZF == 1		; Success, done!.done_pkt:		pop si			; Junk			pop si			; We want the packet ptr in SI		mov eax,[si+tftp_filesize]		cmp eax,-1		jz .no_tsize		mov edx,eax		shr edx,16		; DX:AX == EAX		and eax,eax		; Set ZF depending on file size		pop bp			; Junk		pop bp			; Junk (retry counter)		jz .error_si		; ZF = 1 need to free the socket.ret:		pop bp		pop cx		pop bx		pop es		ret.no_tsize:.err_reply:	; Option negotiation error.  Send ERROR reply.		; ServerIP and gateway are already programmed in		mov si,[bp-6]		mov ax,[si+tftp_remoteport]		mov word [pxe_udp_write_pkt.rport],ax		mov word [pxe_udp_write_pkt.buffer],tftp_opt_err		mov word [pxe_udp_write_pkt.buffersize],tftp_opt_err_len		mov di,pxe_udp_write_pkt		mov bx,PXENV_UDP_WRITE		call pxenv		; Write an error message and explode		mov si,err_oldtftp		call writestr		jmp kaboom.bailnow:	mov word [bp-2],1	; Immediate error - no retry.failure:	pop bx			; Junk		pop bx		pop si		pop ax		dec ax			; Retry counter		jnz .sendreq		; Try again.error:		mov si,bx		; Socket pointer.error_si:				; Socket pointer already in SI		call free_socket	; ZF <- 1, SI <- 0		jmp .ret;; allocate_socket: Allocate a local UDP port structure;;		If successful:;		  ZF set;		  BX     = socket pointer;               If unsuccessful:;                 ZF clear;allocate_socket:		push cx		mov bx,Files		mov cx,MAX_OPEN.check:		cmp word [bx], byte 0		je .found		add bx,open_file_t_size		loop .check		xor cx,cx			; ZF = 1		pop cx		ret		; Allocate a socket number.  Socket numbers are made		; guaranteed unique by including the socket slot number		; (inverted, because we use the loop counter cx); add a		; counter value to keep the numbers from being likely to		; get immediately reused.		;		; The NextSocket variable also contains the top two bits		; set.  This generates a value in the range 49152 to		; 57343..found:		dec cx		push ax		mov ax,[NextSocket]		inc ax		and ax,((1 << (13-MAX_OPEN_LG2))-1) | 0xC000		mov [NextSocket],ax		shl cx,13-MAX_OPEN_LG2		add cx,ax			; ZF = 0		xchg ch,cl			; Convert to network byte order		mov [bx],cx			; Socket in use		pop ax		pop cx		ret;; Free socket: socket in SI; return SI = 0, ZF = 1 for convenience;free_socket:		push es		pusha		xor ax,ax		mov es,ax		mov di,si		mov cx,tftp_pktbuf >> 1		; tftp_pktbuf is not cleared		rep stosw		popa		pop es		xor si,si		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.;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;; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed;	       to by ES:DI; ends on encountering any whitespace.;;	       This verifies that a filename is < FILENAME_MAX characters;	       and doesn't contain whitespace, and zero-pads the output buffer,;	       so "repe cmpsb" can do a compare.;;	       The first four bytes of the manged name is the IP address of;	       the download host.;mangle_name:		push si		mov eax,[ServerIP]		cmp byte [si],0		je .noip			; Null filename?!?!		cmp word [si],'::'		; Leading ::?		je .gotprefix.more:		inc si		cmp byte [si],0		je .noip		cmp word [si],'::'		jne .more		; We have a :: prefix of some sort, it could be either		; a DNS name or a dot-quad IP address.  Try the dot-quad		; first....here:		pop si		push si		call parse_dotquad		jc .notdq		cmp word [si],'::'		je .gotprefix.notdq:		pop si		push si		call dns_resolv		cmp word [si],'::'		jne .noip		and eax,eax		jnz .gotprefix.noip:		pop si		xor eax,eax		jmp .prefix_done.gotprefix:		pop cx				; Adjust stack		inc si				; Skip double colon		inc si.prefix_done:		stosd				; Save IP address prefix		mov cx,FILENAME_MAX-5.mn_loop:		lodsb		cmp al,' '			; If control or space, end		jna .mn_end		stosb		loop .mn_loop.mn_end:		inc cx				; At least one null byte		xor ax,ax			; Zero-fill name		rep stosb			; Doesn't do anything if CX=0		ret				; Done;; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled;                filename to the conventional representation.  This is needed;                for the BOOT_IMAGE= parameter for the kernel.;                NOTE: A 13-byte buffer is mandatory, even if the string is;                known to be shorter.;;                DS:SI -> input mangled file name;                ES:DI -> output buffer;;                On return, DI points to the first byte after the output name,;                which is set to a null byte.;unmangle_name:		push eax		lodsd		and eax,eax		jz .noip		call gendotquad		mov ax,'::'		stosw.noip:		call strcpy		dec di				; Point to final null byte		pop eax		ret;; 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.;pxenv:%if USE_PXE_PROVIDED_STACK == 0		mov [cs:PXEStack],sp		mov [cs:PXEStack+2],ss		lss sp,[cs:InitStack]%endif.jump:		call 0:pxe_thunk		; Default to calling the thunk%if USE_PXE_PROVIDED_STACK == 0		lss sp,[cs:PXEStack]%endif		cld				; Make sure DF <- 0		ret; Must be after function def due to NASM bugPXENVEntry	equ pxenv.jump+1;; pxe_thunk;; Convert from the PXENV+ calling convention (BX, ES, DI) to the !PXE; calling convention (using the stack.);; This is called as a far routine so that we can just stick it into; the PXENVEntry variable.;pxe_thunk:	push es		push di		push bx.jump:		call 0:0		add sp,byte 6		cmp ax,byte 1		cmc				; Set CF unless ax == 0		retf; Must be after function def due to NASM bugPXEEntry	equ pxe_thunk.jump+1;; getfssec: Get multiple clusters from a file, given the starting cluster.;;	In this case, get multiple blocks from a specific TCP connection.;;  On entry:;	ES:BX	-> Buffer;	SI	-> TFTP socket pointer;	CX	-> 512-byte block count; 0FFFFh = until end of file;  On exit:;	SI	-> TFTP socket pointer (or 0 on EOF);	CF = 1	-> Hit EOF;getfssec:	push si		push fs		mov di,bx		mov bx,si		mov ax,pktbuf_seg		mov fs,ax		movzx ecx,cx		shl ecx,TFTP_BLOCKSIZE_LG2	; Convert to bytes		jz .hit_eof			; Nothing to do?		.need_more:		push ecx		movzx eax,word [bx+tftp_bytesleft]		cmp ecx,eax		jna .ok_size		mov ecx,eax		jcxz .need_packet		; No bytes available?.ok_size:		mov ax,cx			; EAX<31:16> == ECX<31:16> == 0		mov si,[bx+tftp_dataptr]		sub [bx+tftp_bytesleft],cx		fs rep movsb			; Copy from packet buffer		mov [bx+tftp_dataptr],si		pop ecx		sub ecx,eax		jnz .need_more.hit_eof:		pop fs		pop si		; Is there anything left of this?		mov eax,[si+tftp_filesize]		sub eax,[si+tftp_filepos]		jnz .bytes_left	; CF <- 0		cmp [si+tftp_bytesleft],ax		jnz .bytes_left	; CF <- 0		; The socket is closed and the buffer drained		; Close socket structure and re-init for next user		call free_socket		stc.bytes_left:		ret;; No data in buffer, check to see if we can get a packet...;.need_packet:		pop ecx		mov eax,[bx+tftp_filesize]		cmp eax,[bx+tftp_filepos]		je .hit_eof			; Already EOF'd; socket already closed		pushad		push es		mov si,bx		call get_packet		pop es		popad		jmp .need_more;; Get a fresh packet; expects fs -> pktbuf_seg and ds:si -> socket structure;get_packet:		mov ax,ds		mov es,ax	.packet_loop:		; Start by ACKing the previous packet; this should cause the		; next packet to be sent.		mov cx,PKT_RETRY		mov word [PktTimeout],PKT_TIMEOUT.send_ack:	push cx				; <D> Retry count		mov ax,[si+tftp_lastpkt]		call ack_packet			; Send ACK		; We used to test the error code here, but sometimes		; PXE would return negative status even though we really		; did send the ACK.  Now, just treat a failed send as		; a normally lost packet, and let it time out in due		; course of events..send_ok:	; Now wait for packet.		mov dx,[BIOS_timer]		; Get current time		mov cx,[PktTimeout].wait_data:	push cx				; <E> Timeout		push dx				; <F> Old time		mov bx,[si+tftp_pktbuf]		mov [pxe_udp_read_pkt.buffer],bx		mov [pxe_udp_read_pkt.buffer+2],fs		mov [pxe_udp_read_pkt.buffersize],word PKTBUF_SIZE		mov eax,[si+tftp_remoteip]		mov [pxe_udp_read_pkt.sip],eax		mov eax,[MyIP]		mov [pxe_udp_read_pkt.dip],eax		mov ax,[si+tftp_remoteport]		mov [pxe_udp_read_pkt.rport],ax		mov ax,[si+tftp_localport]		mov [pxe_udp_read_pkt.lport],ax		mov di,pxe_udp_read_pkt		mov bx,PXENV_UDP_READ		push si				; <G>		call pxenv		pop si				; <G>		and ax,ax		jz .recv_ok		; No packet, or receive failure		mov dx,[BIOS_timer]		pop ax				; <F> Old time		pop cx				; <E> Timeout		cmp ax,dx			; Same time -> don't advance timeout		je .wait_data			; Same clock tick		loop .wait_data			; Decrease timeout				pop cx				; <D> Didn't get any, send another ACK		shl word [PktTimeout],1		; Exponential backoff		loop .send_ack		jmp kaboom			; Forget it....recv_ok:	pop dx				; <F>		pop cx				; <E>		cmp word [pxe_udp_read_pkt.buffersize],byte 4		jb .wait_data			; Bad size for a DATA packet		mov bx,[si+tftp_pktbuf]		cmp word [fs:bx],TFTP_DATA	; Not a data packet?		jne .wait_data			; Then wait for something else		mov ax,[si+tftp_lastpkt]		xchg ah,al			; Host byte order		inc ax				; Which packet are we waiting for?		xchg ah,al			; Network byte order		cmp [fs:bx+2],ax		je .right_packet		; Wrong packet, ACK the packet and then try again		; This is presumably because the ACK got lost,		; so the server just resent the previous packet		mov ax,[fs:bx+2]		call ack_packet		jmp .send_ok			; Reset timeout.right_packet:	; It's the packet we want.  We're also EOF if the size < blocksize		pop cx				; <D> Don't need the retry count anymore		mov [si+tftp_lastpkt],ax	; Update last packet number		movzx ecx,word [pxe_udp_read_pkt.buffersize]		sub cx,byte 4			; Skip TFTP header		; If this is a zero-length block, don't mess with the pointers,		; since we may have just set up the previous block that way		jz .last_block		; Set pointer to data block		lea ax,[bx+4]			; Data past TFTP header		mov [si+tftp_dataptr],ax		add [si+tftp_filepos],ecx		mov [si+tftp_bytesleft],cx		cmp cx,[si+tftp_blksize]	; Is it a full block?		jb .last_block			; If so, it's not EOF		; If we had the exact right number of bytes, always get		; one more packet to get the (zero-byte) EOF packet and		; close the socket.		mov eax,[si+tftp_filepos]		cmp [si+tftp_filesize],eax		je .packet_loop		ret.last_block:	; Last block - ACK packet immediately		mov ax,[fs:bx+2]		call ack_packet		; Make sure we know we are at end of file		mov eax,[si+tftp_filepos]		mov [si+tftp_filesize],eax			ret;; ack_packet:;; Send ACK packet.  This is a common operation and so is worth canning.;; Entry:;	SI 	= TFTP block;	AX 	= Packet # to ack (network byte order); Exit:;	ZF = 0 -> Error;	All registers preserved;; This function uses the pxe_udp_write_pkt but not the packet_buf.;ack_packet:		pushad		mov [ack_packet_buf+2],ax	; Packet number to ack		mov ax,[si]		mov [pxe_udp_write_pkt.lport],ax		mov ax,[si+tftp_remoteport]		mov [pxe_udp_write_pkt.rport],ax		mov eax,[si+tftp_remoteip]		mov [pxe_udp_write_pkt.sip],eax		xor eax,[MyIP]		and eax,[Netmask]		jz .nogw		mov eax,[Gateway].nogw:		mov [pxe_udp_write_pkt.gip],eax		mov [pxe_udp_write_pkt.buffer],word ack_packet_buf		mov [pxe_udp_write_pkt.buffersize], word 4		mov di,pxe_udp_write_pkt		mov bx,PXENV_UDP_WRITE		call pxenv		cmp ax,byte 0			; ZF = 1 if write OK		popad		ret;; unload_pxe:;; This function unloads the PXE and UNDI stacks and unclaims; the memory.;unload_pxe:		test byte [KeepPXE],01h		; Should we keep PXE around?		jnz reset_pxe		push ds		push es		mov ax,cs		mov ds,ax		mov es,ax		mov si,new_api_unload		cmp byte [APIVer+1],2		; Major API version >= 2?		jae .new_api		mov si,old_api_unload.new_api:		.call_loop:	xor ax,ax		lodsb		and ax,ax		jz .call_done		xchg bx,ax		mov di,pxe_unload_stack_pkt		push di		xor ax,ax		mov cx,pxe_unload_stack_pkt_len >> 1		rep stosw		pop di		call pxenv		jc .cant_free		mov ax,word [pxe_unload_stack_pkt.status]		cmp ax,PXENV_STATUS_SUCCESS		jne .cant_free		jmp .call_loop.call_done:;; This isn't necessary anymore; we can use the memory area previously; used by the PXE stack indefinitely, and the chainload code sets up; a new stack independently.  Leave the source code in here for now,; but expect to rip it out soonish.;%if 0 ; USE_PXE_PROVIDED_STACK		; We need to switch to our local stack here...		pusha		pushf		push gs		mov si,sp		mov ax,ss		mov gs,ax		sub ax,[BaseStack+4]		; Are we using the base stack		je .is_base_stack		; (as opposed to the COMBOOT stack)?		lgs si,[SavedSSSP]		; COMBOOT stack.is_base_stack:		mov cx,[InitStack]		mov di,StackBuf		mov [BaseStack],di		mov [BaseStack+4],es		sub cx,si		sub di,cx		mov [SavedSSSP],di		; New SP		mov [SavedSSSP+2],es		gs rep movsb		and ax,ax			; Remember which stack		jne .combootstack		; Update the base stack pointer since it's in use		lss sp,[SavedSSSP]		.combootstack:		pop gs		popf		popa%endif		mov bx,0FF00h		mov dx,[RealBaseMem]		cmp dx,[BIOS_fbm]		; Sanity check		jna .cant_free		inc bx		; Check that PXE actually unhooked the INT 1Ah chain		movzx eax,word [4*0x1a]

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -