📄 pxelinux.asm
字号:
call writehex4 call crlf mov si,undi_code_msg call writestr mov ax,[es:bx+32h] call writehex8 call crlf mov si,undi_code_len_msg call writestr mov ax,[es:bx+36h] call writehex4 call crlf ; Compute base memory size from !PXE structure xor esi,esi mov eax,[es:bx+2Ah] cmp eax,[es:bx+32h] ja .use_data mov eax,[es:bx+32h] mov si,[es:bx+36h] jmp short .combine.use_data: mov si,[es:bx+2Eh].combine: add eax,esi shr eax,10 mov [RealBaseMem],ax mov si,pxeentry_msg call writestr mov ax,[PXEEntry+2] call writehex4 mov al,':' call writechr mov ax,[PXEEntry] call writehex4 call crlfhave_entrypoint:;; Clear Sockets structures;clear_sockets: mov ax,ds ; Set ES <- DS mov es,ax mov di,Sockets mov cx,(MAX_SOCKETS*tftp_port_t_size)/4 xor eax,eax push di rep stosd pop di ; di <- Sockets mov cx,MAX_SOCKETS.setbufptr: mov [di+tftp_pktbuf],ax add di,tftp_port_t_size add ax,PKTBUF_SIZE loop .setbufptr;; Now attempt to get the BOOTP/DHCP packet that brought us life (and an IP; address). This lives in the DHCPACK packet (query info 2).;query_bootp: mov di,pxe_bootp_query_pkt_2 mov bx,PXENV_GET_CACHED_INFO call pxenv push word [pxe_bootp_query_pkt_2.status] jc .pxe_err1 cmp ax,byte 0 je .pxe_ok.pxe_err1: mov di,pxe_bootp_size_query_pkt mov bx,PXENV_GET_CACHED_INFO call pxenv jc .pxe_err.pxe_size: mov ax,[pxe_bootp_size_query_pkt.buffersize] call writehex4 call crlf.pxe_err: mov si,err_pxefailed call writestr call writehex4 mov al, ' ' call writechr pop ax ; Status call writehex4 call crlf jmp kaboom ; We're dead.pxe_ok: pop cx ; Forget status mov cx,[pxe_bootp_query_pkt_2.buffersize] call parse_dhcp ; Parse DHCP packet;; Save away MAC address (assume this is in query info 2. If this; turns out to be problematic it might be better getting it from; the query info 1 packet.);.save_mac: movzx cx,byte [trackbuf+bootp.hardlen] mov [MACLen],cl mov al,[trackbuf+bootp.hardware] mov [MACType],al mov si,trackbuf+bootp.macaddr mov di,MAC push cx rep movsb mov cx,MAC+16 sub cx,di xor ax,ax rep stosb pop cx mov si,MACType mov di,MACStr inc cx mov bx,hextbl_lower.hexify_mac: lodsb mov ah,al shr al,4 xlatb stosb mov al,ah and al,0Fh xlatb stosb mov al,'-' stosb loop .hexify_mac mov [di-1],byte 0 ; Null-terminate and strip final colon;; Now, get the boot file and other info. This lives in the CACHED_REPLY; packet (query info 3).; mov [pxe_bootp_size_query_pkt.packettype], byte 3 mov di,pxe_bootp_query_pkt_3 mov bx,PXENV_GET_CACHED_INFO call pxenv push word [pxe_bootp_query_pkt_3.status] jc .pxe_err1 cmp ax,byte 0 jne .pxe_err1 ; Packet loaded OK... pop cx ; Forget status mov cx,[pxe_bootp_query_pkt_3.buffersize] call parse_dhcp ; Parse DHCP packet;; Generate ip= option; call genipopt;; Print IP address; mov eax,[MyIP] mov di,DotQuadBuf push di call gendotquad ; This takes network byte order input xchg ah,al ; Convert to host byte order ror eax,16 ; (BSWAP doesn't work on 386) xchg ah,al mov si,myipaddr_msg call writestr call writehex8 mov al,' ' call writechr pop si ; DotQuadBuf call writestr call crlf mov si,IPOption call writestr call crlf;; Check to see if we got any PXELINUX-specific DHCP options; in particular,; if we didn't get the magic enable, do not recognize any other options.;check_dhcp_magic: test byte [DHCPMagic], 1 ; If we didn't get the magic enable... jnz .got_magic mov byte [DHCPMagic], 0 ; If not, kill all other options.got_magic: ;; Initialize UDP stack;udp_init: mov eax,[MyIP] mov [pxe_udp_open_pkt.sip],eax mov di,pxe_udp_open_pkt mov bx,PXENV_UDP_OPEN call pxenv jc .failed cmp word [pxe_udp_open_pkt.status], byte 0 je .success.failed: mov si,err_udpinit call writestr jmp kaboom.success:;; Common initialization code;%include "cpuinit.inc";; Now we're all set to start with our *real* business. First load the; configuration file (if any) and parse it.;; In previous versions I avoided using 32-bit registers because of a; rumour some BIOSes clobbered the upper half of 32-bit registers at; random. I figure, though, that if there are any of those still left; they probably won't be trying to install Linux on them...;; The code is still ripe with 16-bitisms, though. Not worth the hassle; to take'm out. In fact, we may want to put them back if we're going; to boot ELKS at some point.; mov si,linuxauto_cmd ; Default command: "linux auto" mov di,default_cmd mov cx,linuxauto_len rep movsb mov di,KbdMap ; Default keymap 1:1 xor al,al mov cx,256mkkeymap: stosb inc al loop mkkeymap;; Store standard filename prefix;prefix: test byte [DHCPMagic], 04h ; Did we get a path prefix option jnz .got_prefix mov si,BootFile mov di,PathPrefix cld call strcpy lea cx,[di-PathPrefix-1] std lea si,[di-2] ; Skip final null!.find_alnum: lodsb or al,20h cmp al,'.' ; Count . or - as alphanum je .alnum cmp al,'-' je .alnum cmp al,'0' jb .notalnum cmp al,'9' jbe .alnum cmp al,'a' jb .notalnum cmp al,'z' ja .notalnum.alnum: loop .find_alnum dec si.notalnum: mov byte [si+2],0 ; Zero-terminate after delimiter cld.got_prefix: mov si,tftpprefix_msg call writestr mov si,PathPrefix call writestr call crlf;; Load configuration file;find_config: mov di,trackbuf mov si,cfgprefix mov cx,cfgprefix_len rep movsb;; Begin looking for configuration file;config_scan: test byte [DHCPMagic], 02h jz .no_option ; We got a DHCP option, try it first push di mov si,trying_msg call writestr mov di,ConfigName mov si,di call writestr call crlf call open pop di jnz .success.no_option: ; Have to guess config file name ; Try loading by MAC address push di mov si,MACStr mov cx,(3*17+1)/2 rep movsw mov si,trying_msg call writestr mov di,trackbuf mov si,di call writestr call crlf call open pop di jnz .success.scan_ip: mov cx,8 mov eax,[MyIP] xchg ah,al ; Convert to host byte order ror eax,16 xchg ah,al.hexify_loop: rol eax,4 push eax and al,0Fh cmp al,10 jae .high.low: add al,'0' jmp short .char.high: add al,'A'-10.char: stosb pop eax loop .hexify_loop mov cx,9 ; Up to 9 attempts.tryagain: mov byte [di],0 cmp cx,byte 1 jne .not_default pusha mov si,default_str mov cx,default_len rep movsb ; Copy "default" string popa.not_default: pusha mov si,trying_msg call writestr mov di,trackbuf mov si,di call writestr call crlf call open popa jnz .success dec di loop .tryagain jmp no_config_file.success:;; Now we have the config file open. Parse the config file and; run the user interface.;%include "ui.inc";; Linux kernel loading code is common. However, we need to define; a couple of helper macros...;; Handle "ipappend" option%define HAVE_SPECIAL_APPEND%macro SPECIAL_APPEND 0 test byte [IPAppend],01h ; ip= jz .noipappend1 mov si,IPOption mov cx,[IPOptionLen] rep movsb mov al,' ' stosb.noipappend1: test byte [IPAppend],02h jz .noipappend2 mov si,bootif_str mov cx,bootif_str_len rep movsb mov si,MACStr call strcpy mov byte [es:di-1],' ' ; Replace null with space.noipappend2:%endmacro; Unload PXE stack%define HAVE_UNLOAD_PREP%macro UNLOAD_PREP 0 call unload_pxe%endmacro%include "runkernel.inc";; COMBOOT-loading code;%include "comboot.inc"%include "com32.inc"%include "cmdline.inc";; Boot sector loading code;%include "bootsect.inc";; Boot to the local disk by returning the appropriate PXE magic.; AX contains the appropriate return code.;local_boot: mov si,cs mov ds,si ; Restore DI lss esp,[BaseStack] mov [LocalBootType],ax call vgaclearmode mov si,localboot_msg call writestr ; Restore the environment we were called with lss sp,[InitStack] pop gs pop fs pop es pop ds popad mov ax,[cs:LocalBootType] popfd retf ; Return to PXE;; abort_check: let the user abort with <ESC> or <Ctrl-C>;abort_check: call pollchar jz ac_ret1 pusha call getchar cmp al,27 ; <ESC> je ac_kill cmp al,3 ; <Ctrl-C> jne ac_ret2ac_kill: mov si,aborted_msg;; abort_load: Called by various routines which wants to print a fatal; error message and return to the command prompt. Since this; may happen at just about any stage of the boot process, assume; our state is messed up, and just reset the segment registers; and the stack forcibly.;; SI = offset (in _text) of error message to print;abort_load: mov ax,cs ; Restore CS = DS = ES mov ds,ax mov es,ax lss esp,[BaseStack] sti call cwritestr ; Expects SI -> error msgal_ok: jmp enter_command ; Return to command prompt;; End of abort_check;ac_ret2: popaac_ret1: ret;; kaboom: write a message and bail out. Wait for quite a while,; or a user keypress, then do a hard reboot.;kaboom: mov ax,cs mov es,ax mov ds,ax lss esp,[BaseStack] sti.patch: mov si,bailmsg call writestr ; Returns with AL = 0.drain: call pollchar jz .drained call getchar jmp short .drain.drained: mov edi,[RebootTime] mov al,[DHCPMagic] and al,09h ; Magic+Timeout cmp al,09h je .time_set mov edi,REBOOT_TIME.time_set: mov cx,18.wait1: push cx mov ecx,edi.wait2: mov dx,[BIOS_timer].wait3: call pollchar jnz .keypress cmp dx,[BIOS_timer] je .wait3 loop .wait2,ecx mov al,'.' call writechr pop cx loop .wait1.keypress: call crlf mov word [BIOS_magic],0 ; Cold reboot jmp 0F000h:0FFF0h ; Reset vector address;; memory_scan_for_pxe_struct:;; If none of the standard methods find the !PXE structure, look for it; by scanning memory.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -