Add (untested) UNDI loader C-level implementation.
authorMichael Brown <mcb30@etherboot.org>
Tue, 3 Jul 2007 22:41:35 +0000 (23:41 +0100)
committerMichael Brown <mcb30@etherboot.org>
Tue, 3 Jul 2007 22:41:35 +0000 (23:41 +0100)
src/arch/i386/interface/pxe/pxe_call.c
src/interface/pxe/pxe_loader.c
src/interface/pxe/pxe_preboot.c

index 8ecacf1..834ca73 100644 (file)
@@ -298,6 +298,31 @@ void pxe_api_call ( struct i386_all_regs *ix86 ) {
        ix86->regs.ax = ret;
 }
 
+/**
+ * Dispatch PXE loader call
+ *
+ * @v es:di            Address of PXE parameter block
+ * @ret ax             PXE exit code
+ */
+void pxe_loader_call ( struct i386_all_regs *ix86 ) {
+       userptr_t uparams = real_to_user ( ix86->segs.es, ix86->regs.di );
+       struct s_UNDI_LOADER params;
+       PXENV_EXIT_t ret;
+
+       /* Copy parameter block from caller */
+       copy_from_user ( &params, uparams, 0, sizeof ( params ) );
+
+       /* Set default status in case child routine fails to do so */
+       params.Status = PXENV_STATUS_FAILURE;
+
+       /* Call UNDI loader */
+       ret = undi_loader ( &params );
+
+       /* Copy modified parameter block back to caller and return */
+       copy_to_user ( uparams, 0, &params, sizeof ( params ) );
+       ix86->regs.ax = ret;
+}
+
 /**
  * Hook INT 1A for PXE
  *
index d72838f..1f2f8ca 100644 (file)
@@ -1,11 +1,5 @@
-/** @file
- *
- * PXE UNDI loader
- *
- */
-
 /*
- * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#warning "Currently broken"
-#if 0
+#include <gpxe/init.h>
 #include "pxe.h"
+#include "pxe_call.h"
 
-/* PXENV_UNDI_LOADER
+/** @file
+ *
+ * PXE UNDI loader
  *
- * Status: working
+ */
+
+/* PXENV_UNDI_LOADER
  *
- * NOTE: This is not a genuine PXE API call; the loader has a separate
- * entry point.  However, to simplify the mapping of the PXE API to
- * the internal Etherboot API, both are directed through the same
- * interface.
  */
 PXENV_EXIT_t undi_loader ( struct s_UNDI_LOADER *undi_loader ) {
-       uint32_t loader_phys = virt_to_phys ( undi_loader );
-
-       DBG ( "PXENV_UNDI_LOADER" );
-       
-       /* Set UNDI DS as our real-mode stack */
-       use_undi_ds_for_rm_stack ( undi_loader->undi_ds );
-
-       /* FIXME: These lines are borrowed from main.c.  There should
-        * probably be a single initialise() function that does all
-        * this, but it's currently split interestingly between main()
-        * and main_loop()...
-        */
-
-
-       /* CHECKME: Our init functions have probably already been
-          called by the ROM prefix's call to setup(), haven't
-          they? */
-
 
+       DBG ( "[PXENV_UNDI_LOADER]" );
 
-       /* We have relocated; the loader pointer is now invalid */
-       undi_loader = phys_to_virt ( loader_phys );
+       /* Perform one-time initialisation (e.g. heap) */
+       initialise();
 
-       /* Install PXE stack to area specified by NBP */
-       install_pxe_stack ( VIRTUAL ( undi_loader->undi_cs, 0 ) );
-       
-       /* Call pxenv_start_undi to set parameters.  Why the hell PXE
-        * requires these parameters to be provided twice is beyond
-        * the wit of any sane man.  Don't worry if it fails; the NBP
-        * should call PXENV_START_UNDI separately anyway.
-        */
-       pxenv_start_undi ( &undi_loader->u.start_undi );
-       /* Unhook stack; the loader is not meant to hook int 1a etc,
-        * but the call the pxenv_start_undi will cause it to happen.
-        */
+       /* Set up PXE data structures */
+       pxe_init_structures();
 
-       /* FIXME: can't use ENSURE_CAN_UNLOAD() thanks to newer gcc's
-        * barfing on unnamed struct/unions. */
-       /*      ENSURE_CAN_UNLOAD ( undi_loader ); */
+       /* Fill in UNDI loader structure */
+       undi_loader->PXEptr.segment = rm_ds;
+       undi_loader->PXEptr.offset =
+               ( ( unsigned ) & __from_text16 ( ppxe ) );
+       undi_loader->PXENVptr.segment = rm_ds;
+       undi_loader->PXENVptr.offset =
+               ( ( unsigned ) & __from_text16 ( pxenv ) );
 
-       /* Fill in addresses of !PXE and PXENV+ structures */
-       PTR_TO_SEGOFF16 ( &pxe_stack->pxe, undi_loader->pxe_ptr );
-       PTR_TO_SEGOFF16 ( &pxe_stack->pxenv, undi_loader->pxenv_ptr );
-       
-       undi_loader->u.Status = PXENV_STATUS_SUCCESS;
+       undi_loader->Status = PXENV_STATUS_SUCCESS;
        return PXENV_EXIT_SUCCESS;
 }
-#endif
index b2ae537..b4e2206 100644 (file)
@@ -45,6 +45,9 @@
  */
 static char *pxe_ris_filename = NULL;
 
+/* Avoid dragging in isapnp.o unnecessarily */
+uint16_t isapnp_read_port;
+
 /**
  * UNLOAD BASE CODE STACK
  *
@@ -180,9 +183,6 @@ PXENV_EXIT_t pxenv_restart_tftp ( struct s_PXENV_TFTP_READ_FILE
  * Status: working
  */
 PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi ) {
-       unsigned int isapnp_read_port;
-       unsigned int isapnp_csn;
-       unsigned int pci_busdevfn;
        unsigned int bus_type;
        unsigned int location;
        struct net_device *netdev;
@@ -190,26 +190,25 @@ PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi ) {
        DBG ( "PXENV_START_UNDI %04x:%04x:%04x",
              start_undi->AX, start_undi->BX, start_undi->DX );
 
-       /* Probe for devices, etc. */
-       startup();
-
-       /* Determine bus type and location */
-       isapnp_read_port = start_undi->DX;
-       isapnp_csn = start_undi->BX;
-       pci_busdevfn = start_undi->AX;
-
-       /* Use a heuristic to decide whether we are PCI or ISAPnP */
-       if ( ( isapnp_read_port >= ISAPNP_READ_PORT_MIN ) &&
-            ( isapnp_read_port <= ISAPNP_READ_PORT_MAX ) &&
-            ( isapnp_csn >= ISAPNP_CSN_MIN ) &&
-            ( isapnp_csn <= ISAPNP_CSN_MAX ) ) {
+       /* Determine bus type and location.  Use a heuristic to decide
+        * whether we are PCI or ISAPnP
+        */
+       if ( ( start_undi->DX >= ISAPNP_READ_PORT_MIN ) &&
+            ( start_undi->DX <= ISAPNP_READ_PORT_MAX ) &&
+            ( start_undi->BX >= ISAPNP_CSN_MIN ) &&
+            ( start_undi->BX <= ISAPNP_CSN_MAX ) ) {
                bus_type = BUS_TYPE_ISAPNP;
-               location = isapnp_csn;
+               location = start_undi->BX;
+               /* Record ISAPnP read port for use by isapnp.c */
+               isapnp_read_port = start_undi->DX;
        } else {
                bus_type = BUS_TYPE_PCI;
-               location = pci_busdevfn;
+               location = start_undi->AX;
        }
 
+       /* Probe for devices, etc. */
+       startup();
+
        /* Look for a matching net device */
        netdev = find_netdev_by_location ( bus_type, location );
        if ( ! netdev ) {