]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[pxe] Provide PXENV_FILE_EXIT_HOOK only for ipxelinux.0 builds
authorMichael Brown <mcb30@ipxe.org>
Sun, 11 Dec 2011 02:11:45 +0000 (02:11 +0000)
committerMichael Brown <mcb30@ipxe.org>
Sun, 11 Dec 2011 02:28:04 +0000 (02:28 +0000)
PXENV_FILE_EXIT_HOOK is designed to allow ipxelinux.0 to unload both
the iPXE and pxelinux components without affecting the underlying PXE
stack.  Unfortunately, it causes unexpected behaviour in other
situations, such as when loading a non-embedded pxelinux.0 via
undionly.kpxe.  For example:

  PXE ROM -> undionly.kpxe -> pxelinux.0 -> chain.c32 to boot hd0

would cause control to return to iPXE instead of booting from the hard
disk.  In some cases, this would result in a harmless but confusing
"No more network devices" message; in other cases stranger things
would happen, such as being returned to the iPXE shell prompt.

The fundamental problem is that when pxelinux detects
PXENV_FILE_EXIT_HOOK, it may attempt to specify an exit hook and then
exit back to iPXE, assuming that iPXE will in turn exit cleanly via
the specified exit hook.  This is not a valid assumption in the
general case, since the action of exiting back to iPXE does not
directly cause iPXE to exit itself.  (In the specific case of
ipxelinux.0, this will work since the embedded script exits as soon as
pxelinux.0 exits.)

Fix the unexpected behaviour in the non-ipxelinux.0 cases by including
support for PXENV_FILE_EXIT_HOOK only when using a new .kkkpxe format.
The ipxelinux.0 build process should therefore now use undionly.kkkpxe
instead of undionly.kkpxe.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/arch/i386/Makefile.pcbios
src/arch/i386/include/pxe_api.h
src/arch/i386/interface/pxe/pxe_exit_hook.c [new file with mode: 0644]
src/arch/i386/interface/pxe/pxe_file.c
src/arch/i386/prefix/kkkpxeprefix.S [new file with mode: 0644]
src/arch/i386/prefix/pxeprefix.S

index 258c5d7d83dc2df211f8eb847a6007bb56dd428e..e1b226f5aab429c407aca99cd803928b4029afdb 100644 (file)
@@ -19,6 +19,7 @@ MEDIA         += mrom
 MEDIA          += pxe
 MEDIA          += kpxe
 MEDIA          += kkpxe
+MEDIA          += kkkpxe
 MEDIA          += lkrn
 MEDIA          += dsk
 MEDIA          += nbi
index f40138467bfea4a6feb06cb9240c49fc739c751b..d01c262d2ba55cbfc32d522f12191ae536d170d7 100644 (file)
@@ -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 (file)
index 0000000..507229d
--- /dev/null
@@ -0,0 +1,60 @@
+/** @file
+ *
+ * PXE exit hook
+ *
+ */
+
+/*
+ * Copyright (C) 2010 Shao Miller <shao.miller@yrdsb.edu.on.ca>.
+ *
+ * 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 <stdint.h>
+#include <realmode.h>
+#include <pxe.h>
+
+/** 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 );
index de1cd9be4e0799747d9556ffa7dadac311c4f920..7daaf919a95e80fd9570435bd4162fea040fe85e 100644 (file)
@@ -16,8 +16,6 @@
 
 /*
  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
- * Portions (C) 2010 Shao Miller <shao.miller@yrdsb.edu.on.ca>.
- *              [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;
+       /* 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 );
        }
 
-       DBG ( " not NBP" );
-       file_exit_hook->Status = PXENV_STATUS_UNSUPPORTED;
-       return PXENV_EXIT_FAILURE;
+       /* 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 (file)
index 0000000..27ed231
--- /dev/null
@@ -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"
index b7468cdf05b50a10a7600d1e5f97c47a784286db..f59e347ad20dfacdaaff8ac4c9ed689435b18f92 100644 (file)
@@ -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