diff --git a/src/arch/i386/Makefile.pcbios b/src/arch/i386/Makefile.pcbios index 258c5d7d..e1b226f5 100644 --- a/src/arch/i386/Makefile.pcbios +++ b/src/arch/i386/Makefile.pcbios @@ -19,6 +19,7 @@ MEDIA += mrom MEDIA += pxe MEDIA += kpxe MEDIA += kkpxe +MEDIA += kkkpxe MEDIA += lkrn MEDIA += dsk MEDIA += nbi diff --git a/src/arch/i386/include/pxe_api.h b/src/arch/i386/include/pxe_api.h index f4013846..d01c262d 100644 --- a/src/arch/i386/include/pxe_api.h +++ b/src/arch/i386/include/pxe_api.h @@ -1511,6 +1511,12 @@ typedef struct s_PXENV_UNDI_ISR PXENV_UNDI_ISR_t; * @{ */ +/** Minimum possible opcode used within PXE FILE API */ +#define PXENV_FILE_MIN 0x00e0 + +/** Minimum possible opcode used within PXE FILE API */ +#define PXENV_FILE_MAX 0x00ef + /** @defgroup pxenv_file_open PXENV_FILE_OPEN * * FILE OPEN diff --git a/src/arch/i386/interface/pxe/pxe_exit_hook.c b/src/arch/i386/interface/pxe/pxe_exit_hook.c new file mode 100644 index 00000000..507229d8 --- /dev/null +++ b/src/arch/i386/interface/pxe/pxe_exit_hook.c @@ -0,0 +1,60 @@ +/** @file + * + * PXE exit hook + * + */ + +/* + * Copyright (C) 2010 Shao Miller . + * + * 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; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include +#include +#include + +/** PXE exit hook */ +extern segoff_t __data16 ( pxe_exit_hook ); +#define pxe_exit_hook __use_data16 ( pxe_exit_hook ) + +/** + * FILE EXIT HOOK + * + * @v file_exit_hook Pointer to a struct + * s_PXENV_FILE_EXIT_HOOK + * @v s_PXENV_FILE_EXIT_HOOK::Hook SEG16:OFF16 to jump to + * @ret #PXENV_EXIT_SUCCESS Successfully set hook + * @ret #PXENV_EXIT_FAILURE We're not an NBP build + * @ret s_PXENV_FILE_EXIT_HOOK::Status PXE status code + * + */ +static PXENV_EXIT_t +pxenv_file_exit_hook ( struct s_PXENV_FILE_EXIT_HOOK *file_exit_hook ) { + DBG ( "PXENV_FILE_EXIT_HOOK" ); + + /* We'll jump to the specified SEG16:OFF16 during exit */ + pxe_exit_hook.segment = file_exit_hook->Hook.segment; + pxe_exit_hook.offset = file_exit_hook->Hook.offset; + file_exit_hook->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; +} + +/** PXE file API */ +struct pxe_api_call pxe_file_api_exit_hook __pxe_api_call = + PXE_API_CALL ( PXENV_FILE_EXIT_HOOK, pxenv_file_exit_hook, + struct s_PXENV_FILE_EXIT_HOOK ); diff --git a/src/arch/i386/interface/pxe/pxe_file.c b/src/arch/i386/interface/pxe/pxe_file.c index de1cd9be..7daaf919 100644 --- a/src/arch/i386/interface/pxe/pxe_file.c +++ b/src/arch/i386/interface/pxe/pxe_file.c @@ -16,8 +16,6 @@ /* * Copyright (C) 2007 Michael Brown . - * Portions (C) 2010 Shao Miller . - * [PXE exit hook logic] * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -234,9 +232,6 @@ static PXENV_EXIT_t pxenv_file_exec ( struct s_PXENV_FILE_EXEC *file_exec ) { return PXENV_EXIT_SUCCESS; } -segoff_t __data16 ( pxe_exit_hook ) = { 0, 0 }; -#define pxe_exit_hook __use_data16 ( pxe_exit_hook ) - /** * FILE API CHECK * @@ -253,57 +248,40 @@ segoff_t __data16 ( pxe_exit_hook ) = { 0, 0 }; */ static PXENV_EXIT_t pxenv_file_api_check ( struct s_PXENV_FILE_API_CHECK *file_api_check ) { + struct pxe_api_call *call; + unsigned int mask = 0; + unsigned int offset; + DBG ( "PXENV_FILE_API_CHECK" ); + /* Check for magic value */ if ( file_api_check->Magic != 0x91d447b2 ) { file_api_check->Status = PXENV_STATUS_BAD_FUNC; return PXENV_EXIT_FAILURE; - } else if ( file_api_check->Size < - sizeof(struct s_PXENV_FILE_API_CHECK) ) { + } + + /* Check for required parameter size */ + if ( file_api_check->Size < sizeof ( *file_api_check ) ) { file_api_check->Status = PXENV_STATUS_OUT_OF_RESOURCES; return PXENV_EXIT_FAILURE; - } else { - file_api_check->Status = PXENV_STATUS_SUCCESS; - file_api_check->Size = sizeof(struct s_PXENV_FILE_API_CHECK); - file_api_check->Magic = 0xe9c17b20; - file_api_check->Provider = 0x45585067; /* "iPXE" */ - file_api_check->APIMask = 0x0000007f; /* Functions e0-e6 */ - /* Check to see if we have a PXE exit hook */ - if ( pxe_exit_hook.segment | pxe_exit_hook.offset ) - /* Function e7, also */ - file_api_check->APIMask |= 0x00000080; - file_api_check->Flags = 0; /* None defined */ - return PXENV_EXIT_SUCCESS; - } -} - -/** - * FILE EXIT HOOK - * - * @v file_exit_hook Pointer to a struct - * s_PXENV_FILE_EXIT_HOOK - * @v s_PXENV_FILE_EXIT_HOOK::Hook SEG16:OFF16 to jump to - * @ret #PXENV_EXIT_SUCCESS Successfully set hook - * @ret #PXENV_EXIT_FAILURE We're not an NBP build - * @ret s_PXENV_FILE_EXIT_HOOK::Status PXE status code - * - */ -static PXENV_EXIT_t -pxenv_file_exit_hook ( struct s_PXENV_FILE_EXIT_HOOK *file_exit_hook ) { - DBG ( "PXENV_FILE_EXIT_HOOK" ); - - /* Check to see if we have a PXE exit hook */ - if ( pxe_exit_hook.segment | pxe_exit_hook.offset ) { - /* We'll jump to the specified SEG16:OFF16 during exit */ - pxe_exit_hook.segment = file_exit_hook->Hook.segment; - pxe_exit_hook.offset = file_exit_hook->Hook.offset; - file_exit_hook->Status = PXENV_STATUS_SUCCESS; - return PXENV_EXIT_SUCCESS; } - DBG ( " not NBP" ); - file_exit_hook->Status = PXENV_STATUS_UNSUPPORTED; - return PXENV_EXIT_FAILURE; + /* Determine supported calls */ + for_each_table_entry ( call, PXE_API_CALLS ) { + offset = ( call->opcode - PXENV_FILE_MIN ); + if ( offset <= ( PXENV_FILE_MAX - PXENV_FILE_MIN ) ) + mask |= ( 1 << offset ); + } + + /* Fill in parameters */ + file_api_check->Size = sizeof ( *file_api_check ); + file_api_check->Magic = 0xe9c17b20; + file_api_check->Provider = 0x45585067; /* "iPXE" */ + file_api_check->APIMask = mask; + file_api_check->Flags = 0; /* None defined */ + + file_api_check->Status = PXENV_STATUS_SUCCESS; + return PXENV_EXIT_SUCCESS; } /** PXE file API */ @@ -322,6 +300,4 @@ struct pxe_api_call pxe_file_api[] __pxe_api_call = { struct s_PXENV_FILE_EXEC ), PXE_API_CALL ( PXENV_FILE_API_CHECK, pxenv_file_api_check, struct s_PXENV_FILE_API_CHECK ), - PXE_API_CALL ( PXENV_FILE_EXIT_HOOK, pxenv_file_exit_hook, - struct s_PXENV_FILE_EXIT_HOOK ), }; diff --git a/src/arch/i386/prefix/kkkpxeprefix.S b/src/arch/i386/prefix/kkkpxeprefix.S new file mode 100644 index 00000000..27ed231e --- /dev/null +++ b/src/arch/i386/prefix/kkkpxeprefix.S @@ -0,0 +1,19 @@ +/***************************************************************************** + * PXE prefix that keeps the whole PXE stack present and provides an exit hook + * + * This prefix is essentially intended solely for the case of ipxelinux.0 + ***************************************************************************** + */ + +FILE_LICENCE ( GPL2_OR_LATER ) + +/* Since we have the whole stack, we can use cached DHCP information */ +REQUIRE_OBJECT ( pxeparent_dhcp ) + +/* Provide the PXENV_FILE_EXIT_HOOK API call */ +REQUIRE_OBJECT ( pxe_exit_hook ) + +#define PXELOADER_KEEP_UNDI +#define PXELOADER_KEEP_PXE +#define _pxe_start _kkkpxe_start +#include "pxeprefix.S" diff --git a/src/arch/i386/prefix/pxeprefix.S b/src/arch/i386/prefix/pxeprefix.S index b7468cdf..f59e347a 100644 --- a/src/arch/i386/prefix/pxeprefix.S +++ b/src/arch/i386/prefix/pxeprefix.S @@ -721,11 +721,7 @@ run_ipxe: .section ".text16", "ax", @progbits 1: /* Update the exit hook */ - movw %cs,pxe_exit_hook+2 - push %ax - mov $2f,%ax - mov %ax,pxe_exit_hook - pop %ax + movw %cs, ( pxe_exit_hook + 2 ) /* Run main program */ pushl $main @@ -743,7 +739,14 @@ run_ipxe: /* Jump to hook if applicable */ ljmpw *pxe_exit_hook -2: /* Check PXE stack magic */ + .section ".data16", "aw", @progbits + .globl pxe_exit_hook +pxe_exit_hook: + .word exit_ipxe, 0 + .previous + +exit_ipxe: + /* Check PXE stack magic */ popl %eax cmpl $STACK_MAGIC, %eax jne 1f