From ed70ab271905bfe455ac79edd2813480664ee73f Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Wed, 26 Mar 2008 14:59:51 -0700 Subject: [PATCH] PXELINUX: add gPXE PXENV_FILE_API_CHECK call; clean up pxenv Add gPXE PXENV_FILE_API_CHECK call, and rationalize the pxenv wrapper subroutine. We now always accept the return value in AX and convert it to a carry, and we always preserve all registers. --- pxe.inc | 2 + pxelinux.asm | 120 +++++++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 86 insertions(+), 36 deletions(-) diff --git a/pxe.inc b/pxe.inc index 5b77117..7471c4f 100644 --- a/pxe.inc +++ b/pxe.inc @@ -69,6 +69,8 @@ %define PXENV_FILE_SELECT 0x00e2 %define PXENV_FILE_READ 0x00e3 %define PXENV_GET_FILE_SIZE 0x00e4 +%define PXENV_FILE_EXEC 0x00e5 +%define PXENV_FILE_API_CHECK 0x00e6 ; Exit codes %define PXENV_EXIT_SUCCESS 0x0000 diff --git a/pxelinux.asm b/pxelinux.asm index 00adc83..6a57966 100644 --- a/pxelinux.asm +++ b/pxelinux.asm @@ -409,7 +409,7 @@ old_api: ; Need to use a PXENV+ structure call writestr mov eax,[es:bx+0Ah] ; PXE RM API - mov [PXENVEntry],eax + mov [PXEEntry],eax mov si,undi_data_msg call writestr @@ -450,11 +450,11 @@ old_api: ; Need to use a PXENV+ structure mov si,pxenventry_msg call writestr - mov ax,[PXENVEntry+2] + mov ax,[PXEEntry+2] call writehex4 mov al,':' call writechr - mov ax,[PXENVEntry] + mov ax,[PXEEntry] call writehex4 call crlf jmp have_entrypoint @@ -1090,7 +1090,7 @@ searchdir: call strcpy ; Filename %if GPXE mov si,packet_buf+2 - call is_url + call is_gpxe jnc .gpxe %endif @@ -1146,8 +1146,7 @@ searchdir: mov di,pxe_udp_read_pkt mov bx,PXENV_UDP_READ call pxenv - and ax,ax - jz .got_packet ; Wait for packet + jnc .got_packet ; Wait for packet .no_packet: mov dx,[BIOS_timer] cmp dx,[bp-12] @@ -1360,6 +1359,7 @@ searchdir: .gpxe: push bx ; Socket pointer mov di,gpxe_file_open + mov word [di],2 ; PXENV_STATUS_BAD_FUNC mov word [di+4],packet_buf+2 ; Completed URL mov [di+6],ds mov bx,PXENV_FILE_OPEN @@ -1518,6 +1518,55 @@ is_url: .not_url: stc jmp .done + +; +; is_gpxe: Return CF=0 if and only if the buffer pointed to by +; DS:SI is a URL (contains ://) *and* the gPXE extensions +; API is available. No registers modified. +; +is_gpxe: + call is_url + jc .ret ; Not a URL, don't bother +.again: + cmp byte [HasGPXE],1 + ja .unknown + ; CF=1 if not available (0), + ; CF=0 if known available (1). +.ret: ret + +.unknown: + ; If we get here, the gPXE status is unknown. + push es + pushad + push ds + pop es + mov di,gpxe_file_api_check + mov bx,PXENV_FILE_API_CHECK ; BH = 0 + call pxenv + jc .nogood + cmp dword [di+4],0xe9c17b20 + jne .nogood + mov ax,[di+12] ; Don't care about the upper half... + not ax ; Set bits of *missing* functions... + and ax,01001011b ; The functions we care about + setz bh + jz .done +.nogood: + mov si,gpxe_warning_msg + call writestr +.done: + mov [HasGPXE],bh + popad + pop es + jmp .again + + section .data +gpxe_warning_msg + db 'URL syntax, but gPXE extensions not detected, ' + db 'trying plain TFTP...', CR, LF, 0 +HasGPXE db -1 ; Unknown + section .text + %endif ; @@ -1642,43 +1691,39 @@ unmangle_name: ; some PXE stacks seem to not like being invoked from anything but ; the initial stack, so humour it. ; - +; While we're at it, save and restore all registers. +; pxenv: + pushad %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 + ; This works either for the PXENV+ or the !PXE calling + ; convention, as long as we ignore CF (which is redundant + ; with AX anyway.) + push es + push di + push bx +.jump: call 0:0 + add sp,6 + add ax,-1 ; Set CF unless AX was 0 + %if USE_PXE_PROVIDED_STACK == 0 lss sp,[cs:PXEStack] %endif + + ; This clobbers the AX return, but we don't use it + ; except for testing it against zero (and setting CF), + ; which we did above. For anything else, + ; use the Status field in the reply. + popad cld ; Make sure DF <- 0 ret ; Must be after function def due to NASM bug -PXENVEntry 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 bug -PXEEntry equ pxe_thunk.jump+1 +PXEEntry equ pxenv.jump+1 ; ; getfssec: Get multiple clusters from a file, given the starting cluster. @@ -1840,11 +1885,8 @@ fill_buffer: mov [pxe_udp_read_pkt.lport],ax mov di,pxe_udp_read_pkt mov bx,PXENV_UDP_READ - push si ; call pxenv - pop si ; - and ax,ax - jz .recv_ok + jnc .recv_ok ; No packet, or receive failure mov dx,[BIOS_timer] @@ -1929,7 +1971,6 @@ fill_buffer: ; 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. @@ -1954,7 +1995,6 @@ ack_packet: mov di,pxe_udp_write_pkt mov bx,PXENV_UDP_WRITE call pxenv - cmp ax,byte 0 ; ZF = 1 if write OK popad ret @@ -2764,6 +2804,14 @@ pxe_udp_read_pkt: %if GPXE +gpxe_file_api_check: +.status: dw 0 ; Status +.size: dw 20 ; Size in bytes +.magic: dd 0x91d447b2 ; Magic number +.provider: dd 0 +.apimask: dd 0 +.flags: dd 0 + gpxe_file_open: .status: dw 0 ; Status .filehandle: dw 0 ; FileHandle -- 2.7.4