[pxe] Introduce PXE exit hook for NBP chaining
authorShao Miller <shao.miller@yrdsb.edu.on.ca>
Sun, 24 Jan 2010 03:12:27 +0000 (22:12 -0500)
committerMarty Connor <mdc@etherboot.org>
Sun, 24 Jan 2010 12:54:42 +0000 (07:54 -0500)
It might be the case that we wish to chain to an NBP without
being "in the way".  We now implement a hook in our exit path
for gPXE *.*pxe build targets.  The hook is a pointer to a
SEG16:OFF16 which we try to jump to during exit.  By default,
this pointer results in the usual exit path.

We also implement the "pxenv_file_exit_hook" PXE API routine
to allow the user to specify an alternate SEG16:OFF16 to jump
to during exit.

Unfortunately, this additional PXE extension has a cost
in code size.  Fortunately, a look at the size difference
for a gPXE .rom build target shows zero size difference
after compression.

The routine is documented in doc/pxe_extensions as follows:

FILE EXIT HOOK

Op-Code: PXENV_FILE_EXIT_HOOK (00e7h)

Input: Far pointer to a t_PXENV_FILE_EXIT_HOOK parameter
structure that has been initialized by the caller.

Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be
returned in AX.  The Status field in the parameter
structure must be set to one of the values represented
by the PXENV_STATUS_xxx constants.

Description:Modify the exit path to jump to the specified code.
Only valid for pxeprefix-based builds.

typedef struct s_PXENV_FILE_EXIT_HOOK {
        PXENV_STATUS_t Status;
        SEGOFF16_t Hook;
} t_PXENV_FILE_EXIT_HOOK;

Set before calling API service:

Hook: The SEG16:OFF16 of the code to jump to.

Returned from API service:

Status: See PXENV_STATUS_xxx constants.

Requested-by: H. Peter Anvin <hpa@zytor.com>
Signed-off-by: Shao Miller <shao.miller@yrdsb.edu.on.ca>
Signed-off-by: Marty Connor <mdc@etherboot.org>
src/arch/i386/include/pxe.h
src/arch/i386/include/pxe_api.h
src/arch/i386/interface/pxe/pxe_call.c
src/arch/i386/interface/pxe/pxe_file.c
src/arch/i386/prefix/pxeprefix.S
src/doc/pxe_extensions

index b0cabef..041ee7b 100644 (file)
@@ -67,6 +67,7 @@ union u_PXENV_ANY {
        struct s_PXENV_GET_FILE_SIZE            get_file_size;
        struct s_PXENV_FILE_EXEC                file_exec;
        struct s_PXENV_FILE_API_CHECK           file_api_check;
+       struct s_PXENV_FILE_EXIT_HOOK           file_exit_hook;
 };
 
 typedef union u_PXENV_ANY PXENV_ANY_t;
index ba0dbdc..92f046f 100644 (file)
@@ -1778,6 +1778,28 @@ extern PXENV_EXIT_t pxenv_file_api_check ( struct s_PXENV_FILE_API_CHECK *file_a
 
 /** @} */ /* pxenv_file_api_check */
 
+/** @defgroup pxenv_file_exit_hook PXENV_FILE_EXIT_HOOK
+ *
+ * FILE EXIT HOOK
+ *
+ * @{
+ */
+
+/** PXE API function code for pxenv_file_exit_hook() */
+#define PXENV_FILE_EXIT_HOOK                   0x00e7
+
+/** Parameter block for pxenv_file_exit_hook() */
+struct s_PXENV_FILE_EXIT_HOOK {
+       PXENV_STATUS_t Status;          /**< PXE status code */
+       SEGOFF16_t Hook;                /**< SEG16:OFF16 to jump to */
+} PACKED;
+
+typedef struct s_PXENV_FILE_EXIT_HOOK PXENV_FILE_EXIT_HOOK_t;
+
+extern PXENV_EXIT_t pxenv_file_exit_hook ( struct s_PXENV_FILE_EXIT_HOOK *file_exit_hook );
+
+/** @} */ /* pxenv_file_exit_hook */
+
 /** @} */ /* pxe_file_api */
 
 /** @defgroup pxe_loader_api PXE Loader API
index a50d643..66a9b1e 100644 (file)
@@ -104,6 +104,7 @@ union pxenv_call {
        PXENV_EXIT_t ( * get_file_size ) ( struct s_PXENV_GET_FILE_SIZE * );
        PXENV_EXIT_t ( * file_exec ) ( struct s_PXENV_FILE_EXEC * );
        PXENV_EXIT_t ( * file_api_check ) ( struct s_PXENV_FILE_API_CHECK * );
+       PXENV_EXIT_t ( * file_exit_hook ) ( struct s_PXENV_FILE_EXIT_HOOK * );
 };
 
 /**
@@ -310,6 +311,10 @@ __asmcall void pxe_api_call ( struct i386_all_regs *ix86 ) {
                pxenv_call.file_api_check = pxenv_file_api_check;
                param_len = sizeof ( pxenv_any.file_api_check );
                break;
+       case PXENV_FILE_EXIT_HOOK:
+               pxenv_call.file_exit_hook = pxenv_file_exit_hook;
+               param_len = sizeof ( pxenv_any.file_exit_hook );
+               break;
        default:
                DBG ( "PXENV_UNKNOWN_%hx", opcode );
                pxenv_call.unknown = pxenv_unknown;
index 552a1a1..8d83212 100644 (file)
 #include <gpxe/posix_io.h>
 #include <gpxe/features.h>
 #include <pxe.h>
+#include <realmode.h>
 
 /*
  * 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
@@ -230,6 +233,9 @@ 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
  *
@@ -260,7 +266,41 @@ PXENV_EXIT_t pxenv_file_api_check ( struct s_PXENV_FILE_API_CHECK *file_api_chec
                file_api_check->Magic    = 0xe9c17b20;
                file_api_check->Provider = 0x45585067; /* "gPXE" */
                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
+ *
+ */
+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;
+}
+
index b541e4b..e728c48 100644 (file)
@@ -718,6 +718,13 @@ run_gpxe:
        lret
        .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
+
        /* Run main program */
        pushl   $main
        pushw   %cs
@@ -731,7 +738,10 @@ run_gpxe:
        movw    %di, %ss
        movl    %ebp, %esp
 
-       /* Check PXE stack magic */
+       /* Jump to hook if applicable */
+       ljmpw   *pxe_exit_hook
+
+2:     /* Check PXE stack magic */
        popl    %eax
        cmpl    $STACK_MAGIC, %eax
        jne     1f
index 92269cf..8ff14a9 100644 (file)
@@ -277,3 +277,36 @@ Provider:  Set to 0x45585067 ("gPXE").  Another implementation of this
 APIMask:       Bitmask of supported API functions (one bit for each function
                in the range 00e0h to 00ffh).
 Flags:         Set to zero, reserved for future use.
+
+
+
+
+FILE EXIT HOOK
+
+Op-Code:       PXENV_FILE_EXIT_HOOK (00e7h)
+
+Input:         Far pointer to a t_PXENV_FILE_EXIT_HOOK parameter
+               structure that has been initialized by the caller.
+
+Output:                PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be
+               returned in AX.  The Status field in the parameter
+               structure must be set to one of the values represented
+               by the PXENV_STATUS_xxx constants.
+
+Description:   Modify the exit path to jump to the specified code.
+               Only valid for pxeprefix-based builds.
+
+typedef struct s_PXENV_FILE_EXIT_HOOK {
+        PXENV_STATUS_t Status;
+        SEGOFF16_t Hook;
+} t_PXENV_FILE_EXIT_HOOK;
+
+
+Set before calling API service:
+
+Hook:          The SEG16:OFF16 of the code to jump to.
+
+
+Returned from API service:
+
+Status:                See PXENV_STATUS_xxx constants.