diff options
Diffstat (limited to 'contrib/syslinux-4.02/gpxe/src/arch/i386/interface/pxeparent')
-rw-r--r-- | contrib/syslinux-4.02/gpxe/src/arch/i386/interface/pxeparent/pxeparent.c | 201 | ||||
-rw-r--r-- | contrib/syslinux-4.02/gpxe/src/arch/i386/interface/pxeparent/pxeparent_dhcp.c | 69 |
2 files changed, 270 insertions, 0 deletions
diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/interface/pxeparent/pxeparent.c b/contrib/syslinux-4.02/gpxe/src/arch/i386/interface/pxeparent/pxeparent.c new file mode 100644 index 0000000..582db5d --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/interface/pxeparent/pxeparent.c @@ -0,0 +1,201 @@ +/* + * 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 + * 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 <gpxe/dhcp.h> +#include <pxeparent.h> +#include <pxe_api.h> +#include <pxe_types.h> +#include <pxe.h> + +/** @file + * + * Call interface to parent PXE stack + * + */ + +/** + * Name PXE API call + * + * @v function API call number + * @ret name API call name + */ +static inline __attribute__ (( always_inline )) const char * +pxeparent_function_name ( unsigned int function ) { + switch ( function ) { + case PXENV_START_UNDI: + return "PXENV_START_UNDI"; + case PXENV_STOP_UNDI: + return "PXENV_STOP_UNDI"; + case PXENV_UNDI_STARTUP: + return "PXENV_UNDI_STARTUP"; + case PXENV_UNDI_CLEANUP: + return "PXENV_UNDI_CLEANUP"; + case PXENV_UNDI_INITIALIZE: + return "PXENV_UNDI_INITIALIZE"; + case PXENV_UNDI_RESET_ADAPTER: + return "PXENV_UNDI_RESET_ADAPTER"; + case PXENV_UNDI_SHUTDOWN: + return "PXENV_UNDI_SHUTDOWN"; + case PXENV_UNDI_OPEN: + return "PXENV_UNDI_OPEN"; + case PXENV_UNDI_CLOSE: + return "PXENV_UNDI_CLOSE"; + case PXENV_UNDI_TRANSMIT: + return "PXENV_UNDI_TRANSMIT"; + case PXENV_UNDI_SET_MCAST_ADDRESS: + return "PXENV_UNDI_SET_MCAST_ADDRESS"; + case PXENV_UNDI_SET_STATION_ADDRESS: + return "PXENV_UNDI_SET_STATION_ADDRESS"; + case PXENV_UNDI_SET_PACKET_FILTER: + return "PXENV_UNDI_SET_PACKET_FILTER"; + case PXENV_UNDI_GET_INFORMATION: + return "PXENV_UNDI_GET_INFORMATION"; + case PXENV_UNDI_GET_STATISTICS: + return "PXENV_UNDI_GET_STATISTICS"; + case PXENV_UNDI_CLEAR_STATISTICS: + return "PXENV_UNDI_CLEAR_STATISTICS"; + case PXENV_UNDI_INITIATE_DIAGS: + return "PXENV_UNDI_INITIATE_DIAGS"; + case PXENV_UNDI_FORCE_INTERRUPT: + return "PXENV_UNDI_FORCE_INTERRUPT"; + case PXENV_UNDI_GET_MCAST_ADDRESS: + return "PXENV_UNDI_GET_MCAST_ADDRESS"; + case PXENV_UNDI_GET_NIC_TYPE: + return "PXENV_UNDI_GET_NIC_TYPE"; + case PXENV_UNDI_GET_IFACE_INFO: + return "PXENV_UNDI_GET_IFACE_INFO"; + /* + * Duplicate case value; this is a bug in the PXE specification. + * + * case PXENV_UNDI_GET_STATE: + * return "PXENV_UNDI_GET_STATE"; + */ + case PXENV_UNDI_ISR: + return "PXENV_UNDI_ISR"; + case PXENV_GET_CACHED_INFO: + return "PXENV_GET_CACHED_INFO"; + default: + return "UNKNOWN API CALL"; + } +} + +/** + * PXE parent parameter block + * + * Used as the paramter block for all parent PXE API calls. Resides in base + * memory. + */ +static union u_PXENV_ANY __bss16 ( pxeparent_params ); +#define pxeparent_params __use_data16 ( pxeparent_params ) + +/** PXE parent entry point + * + * Used as the indirection vector for all parent PXE API calls. Resides in + * base memory. + */ +SEGOFF16_t __bss16 ( pxeparent_entry_point ); +#define pxeparent_entry_point __use_data16 ( pxeparent_entry_point ) + +/** + * Issue parent PXE API call + * + * @v entry Parent PXE stack entry point + * @v function API call number + * @v params PXE parameter block + * @v params_len Length of PXE parameter block + * @ret rc Return status code + */ +int pxeparent_call ( SEGOFF16_t entry, unsigned int function, + void *params, size_t params_len ) { + PXENV_EXIT_t exit; + int discard_b, discard_D; + int rc; + + /* Copy parameter block and entry point */ + assert ( params_len <= sizeof ( pxeparent_params ) ); + memcpy ( &pxeparent_params, params, params_len ); + memcpy ( &pxeparent_entry_point, &entry, sizeof ( entry ) ); + + /* Call real-mode entry point. This calling convention will + * work with both the !PXE and the PXENV+ entry points. + */ + __asm__ __volatile__ ( REAL_CODE ( "pushw %%es\n\t" + "pushw %%di\n\t" + "pushw %%bx\n\t" + "lcall *pxeparent_entry_point\n\t" + "addw $6, %%sp\n\t" ) + : "=a" ( exit ), "=b" ( discard_b ), + "=D" ( discard_D ) + : "b" ( function ), + "D" ( __from_data16 ( &pxeparent_params ) ) + : "ecx", "edx", "esi", "ebp" ); + + /* PXE API calls may rudely change the status of A20 and not + * bother to restore it afterwards. Intel is known to be + * guilty of this. + * + * Note that we will return to this point even if A20 gets + * screwed up by the parent PXE stack, because Etherboot always + * resides in an even megabyte of RAM. + */ + gateA20_set(); + + /* Determine return status code based on PXENV_EXIT and + * PXENV_STATUS + */ + if ( exit == PXENV_EXIT_SUCCESS ) { + rc = 0; + } else { + rc = -pxeparent_params.Status; + /* Paranoia; don't return success for the combination + * of PXENV_EXIT_FAILURE but PXENV_STATUS_SUCCESS + */ + if ( rc == 0 ) + rc = -EIO; + } + + /* If anything goes wrong, print as much debug information as + * it's possible to give. + */ + if ( rc != 0 ) { + SEGOFF16_t rm_params = { + .segment = rm_ds, + .offset = __from_data16 ( &pxeparent_params ), + }; + + DBG ( "PXEPARENT %s failed: %s\n", + pxeparent_function_name ( function ), strerror ( rc ) ); + DBG ( "PXEPARENT parameters at %04x:%04x length " + "%#02zx, entry point at %04x:%04x\n", + rm_params.segment, rm_params.offset, params_len, + pxeparent_entry_point.segment, + pxeparent_entry_point.offset ); + DBG ( "PXEPARENT parameters provided:\n" ); + DBG_HDA ( rm_params, params, params_len ); + DBG ( "PXEPARENT parameters returned:\n" ); + DBG_HDA ( rm_params, &pxeparent_params, params_len ); + } + + /* Copy parameter block back */ + memcpy ( params, &pxeparent_params, params_len ); + + return rc; +} + diff --git a/contrib/syslinux-4.02/gpxe/src/arch/i386/interface/pxeparent/pxeparent_dhcp.c b/contrib/syslinux-4.02/gpxe/src/arch/i386/interface/pxeparent/pxeparent_dhcp.c new file mode 100644 index 0000000..6605943 --- /dev/null +++ b/contrib/syslinux-4.02/gpxe/src/arch/i386/interface/pxeparent/pxeparent_dhcp.c @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2009 Joshua Oreman <oremanj@rwcr.net>. + * + * 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 <string.h> +#include <gpxe/dhcp.h> +#include <gpxe/netdevice.h> +#include <undipreload.h> +#include <pxeparent.h> +#include <realmode.h> +#include <pxe_api.h> + +/** + * Present cached DHCP packet if it exists + */ +void __weak_impl ( get_cached_dhcpack ) ( void ) { + struct undi_device *undi; + struct s_PXENV_GET_CACHED_INFO get_cached_info; + int rc; + + /* Use preloaded UNDI device to get at PXE entry point */ + undi = &preloaded_undi; + if ( ! undi->entry.segment ) { + DBG ( "PXEDHCP no preloaded UNDI device found\n" ); + return; + } + + /* Check that stack is available to get cached info */ + if ( ! ( undi->flags & UNDI_FL_KEEP_ALL ) ) { + DBG ( "PXEDHCP stack was unloaded, no cache available\n" ); + return; + } + + /* Obtain cached DHCP packet */ + memset ( &get_cached_info, 0, sizeof ( get_cached_info ) ); + get_cached_info.PacketType = PXENV_PACKET_TYPE_DHCP_ACK; + + if ( ( rc = pxeparent_call ( undi->entry, PXENV_GET_CACHED_INFO, + &get_cached_info, + sizeof ( get_cached_info ) ) ) != 0 ) { + DBG ( "PXEDHCP GET_CACHED_INFO failed: %s\n", strerror ( rc ) ); + return; + } + + DBG ( "PXEDHCP got cached info at %04x:%04x length %d\n", + get_cached_info.Buffer.segment, get_cached_info.Buffer.offset, + get_cached_info.BufferSize ); + + /* Present cached DHCP packet */ + store_cached_dhcpack ( real_to_user ( get_cached_info.Buffer.segment, + get_cached_info.Buffer.offset ), + get_cached_info.BufferSize ); +} |