diff options
Diffstat (limited to 'gpxe/src/arch/i386/interface/pxe/pxe_call.c')
-rw-r--r-- | gpxe/src/arch/i386/interface/pxe/pxe_call.c | 509 |
1 files changed, 0 insertions, 509 deletions
diff --git a/gpxe/src/arch/i386/interface/pxe/pxe_call.c b/gpxe/src/arch/i386/interface/pxe/pxe_call.c deleted file mode 100644 index 66a9b1e2..00000000 --- a/gpxe/src/arch/i386/interface/pxe/pxe_call.c +++ /dev/null @@ -1,509 +0,0 @@ -/* - * Copyright (C) 2006 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/uaccess.h> -#include <gpxe/init.h> -#include <registers.h> -#include <biosint.h> -#include <pxe.h> -#include <pxe_call.h> - -/** @file - * - * PXE API entry point - */ - -/** Vector for chaining INT 1A */ -extern struct segoff __text16 ( pxe_int_1a_vector ); -#define pxe_int_1a_vector __use_text16 ( pxe_int_1a_vector ) - -/** INT 1A handler */ -extern void pxe_int_1a ( void ); - -/** INT 1A hooked flag */ -static int int_1a_hooked = 0; - -/** A function pointer to hold any PXE API call - * - * Used by pxe_api_call() to avoid large swathes of duplicated code. - */ -union pxenv_call { - PXENV_EXIT_t ( * any ) ( union u_PXENV_ANY * ); - PXENV_EXIT_t ( * unknown ) ( struct s_PXENV_UNKNOWN * ); - PXENV_EXIT_t ( * unload_stack ) ( struct s_PXENV_UNLOAD_STACK * ); - PXENV_EXIT_t ( * get_cached_info ) - ( struct s_PXENV_GET_CACHED_INFO * ); - PXENV_EXIT_t ( * restart_tftp ) ( struct s_PXENV_TFTP_READ_FILE * ); - PXENV_EXIT_t ( * start_undi ) ( struct s_PXENV_START_UNDI * ); - PXENV_EXIT_t ( * stop_undi ) ( struct s_PXENV_STOP_UNDI * ); - PXENV_EXIT_t ( * start_base ) ( struct s_PXENV_START_BASE * ); - PXENV_EXIT_t ( * stop_base ) ( struct s_PXENV_STOP_BASE * ); - PXENV_EXIT_t ( * tftp_open ) ( struct s_PXENV_TFTP_OPEN * ); - PXENV_EXIT_t ( * tftp_close ) ( struct s_PXENV_TFTP_CLOSE * ); - PXENV_EXIT_t ( * tftp_read ) ( struct s_PXENV_TFTP_READ * ); - PXENV_EXIT_t ( * tftp_read_file ) ( struct s_PXENV_TFTP_READ_FILE * ); - PXENV_EXIT_t ( * tftp_get_fsize ) ( struct s_PXENV_TFTP_GET_FSIZE * ); - PXENV_EXIT_t ( * udp_open ) ( struct s_PXENV_UDP_OPEN * ); - PXENV_EXIT_t ( * udp_close ) ( struct s_PXENV_UDP_CLOSE * ); - PXENV_EXIT_t ( * udp_write ) ( struct s_PXENV_UDP_WRITE * ); - PXENV_EXIT_t ( * udp_read ) ( struct s_PXENV_UDP_READ * ); - PXENV_EXIT_t ( * undi_startup ) ( struct s_PXENV_UNDI_STARTUP * ); - PXENV_EXIT_t ( * undi_cleanup ) ( struct s_PXENV_UNDI_CLEANUP * ); - PXENV_EXIT_t ( * undi_initialize ) - ( struct s_PXENV_UNDI_INITIALIZE * ); - PXENV_EXIT_t ( * undi_reset_adapter ) ( struct s_PXENV_UNDI_RESET * ); - PXENV_EXIT_t ( * undi_shutdown ) ( struct s_PXENV_UNDI_SHUTDOWN * ); - PXENV_EXIT_t ( * undi_open ) ( struct s_PXENV_UNDI_OPEN * ); - PXENV_EXIT_t ( * undi_close ) ( struct s_PXENV_UNDI_CLOSE * ); - PXENV_EXIT_t ( * undi_transmit ) ( struct s_PXENV_UNDI_TRANSMIT * ); - PXENV_EXIT_t ( * undi_set_mcast_address ) - ( struct s_PXENV_UNDI_SET_MCAST_ADDRESS * ); - PXENV_EXIT_t ( * undi_set_station_address ) - ( struct s_PXENV_UNDI_SET_STATION_ADDRESS * ); - PXENV_EXIT_t ( * undi_set_packet_filter ) - ( struct s_PXENV_UNDI_SET_PACKET_FILTER * ); - PXENV_EXIT_t ( * undi_get_information ) - ( struct s_PXENV_UNDI_GET_INFORMATION * ); - PXENV_EXIT_t ( * undi_get_statistics ) - ( struct s_PXENV_UNDI_GET_STATISTICS * ); - PXENV_EXIT_t ( * undi_clear_statistics ) - ( struct s_PXENV_UNDI_CLEAR_STATISTICS * ); - PXENV_EXIT_t ( * undi_initiate_diags ) - ( struct s_PXENV_UNDI_INITIATE_DIAGS * ); - PXENV_EXIT_t ( * undi_force_interrupt ) - ( struct s_PXENV_UNDI_FORCE_INTERRUPT * ); - PXENV_EXIT_t ( * undi_get_mcast_address ) - ( struct s_PXENV_UNDI_GET_MCAST_ADDRESS * ); - PXENV_EXIT_t ( * undi_get_nic_type ) - ( struct s_PXENV_UNDI_GET_NIC_TYPE * ); - PXENV_EXIT_t ( * undi_get_iface_info ) - ( struct s_PXENV_UNDI_GET_IFACE_INFO * ); - PXENV_EXIT_t ( * undi_get_state ) ( struct s_PXENV_UNDI_GET_STATE * ); - PXENV_EXIT_t ( * undi_isr ) ( struct s_PXENV_UNDI_ISR * ); - PXENV_EXIT_t ( * file_open ) ( struct s_PXENV_FILE_OPEN * ); - PXENV_EXIT_t ( * file_close ) ( struct s_PXENV_FILE_CLOSE * ); - PXENV_EXIT_t ( * file_select ) ( struct s_PXENV_FILE_SELECT * ); - PXENV_EXIT_t ( * file_read ) ( struct s_PXENV_FILE_READ * ); - 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 * ); -}; - -/** - * Handle an unknown PXE API call - * - * @v pxenv_unknown Pointer to a struct s_PXENV_UNKNOWN - * @ret #PXENV_EXIT_FAILURE Always - * @err #PXENV_STATUS_UNSUPPORTED Always - */ -static PXENV_EXIT_t pxenv_unknown ( struct s_PXENV_UNKNOWN *pxenv_unknown ) { - pxenv_unknown->Status = PXENV_STATUS_UNSUPPORTED; - return PXENV_EXIT_FAILURE; -} - -/** - * Dispatch PXE API call - * - * @v bx PXE opcode - * @v es:di Address of PXE parameter block - * @ret ax PXE exit code - */ -__asmcall void pxe_api_call ( struct i386_all_regs *ix86 ) { - int opcode = ix86->regs.bx; - userptr_t parameters = real_to_user ( ix86->segs.es, ix86->regs.di ); - size_t param_len; - union u_PXENV_ANY pxenv_any; - union pxenv_call pxenv_call; - PXENV_EXIT_t ret; - - switch ( opcode ) { - case PXENV_UNLOAD_STACK: - pxenv_call.unload_stack = pxenv_unload_stack; - param_len = sizeof ( pxenv_any.unload_stack ); - break; - case PXENV_GET_CACHED_INFO: - pxenv_call.get_cached_info = pxenv_get_cached_info; - param_len = sizeof ( pxenv_any.get_cached_info ); - break; - case PXENV_RESTART_TFTP: - pxenv_call.restart_tftp = pxenv_restart_tftp; - param_len = sizeof ( pxenv_any.restart_tftp ); - break; - case PXENV_START_UNDI: - pxenv_call.start_undi = pxenv_start_undi; - param_len = sizeof ( pxenv_any.start_undi ); - break; - case PXENV_STOP_UNDI: - pxenv_call.stop_undi = pxenv_stop_undi; - param_len = sizeof ( pxenv_any.stop_undi ); - break; - case PXENV_START_BASE: - pxenv_call.start_base = pxenv_start_base; - param_len = sizeof ( pxenv_any.start_base ); - break; - case PXENV_STOP_BASE: - pxenv_call.stop_base = pxenv_stop_base; - param_len = sizeof ( pxenv_any.stop_base ); - break; - case PXENV_TFTP_OPEN: - pxenv_call.tftp_open = pxenv_tftp_open; - param_len = sizeof ( pxenv_any.tftp_open ); - break; - case PXENV_TFTP_CLOSE: - pxenv_call.tftp_close = pxenv_tftp_close; - param_len = sizeof ( pxenv_any.tftp_close ); - break; - case PXENV_TFTP_READ: - pxenv_call.tftp_read = pxenv_tftp_read; - param_len = sizeof ( pxenv_any.tftp_read ); - break; - case PXENV_TFTP_READ_FILE: - pxenv_call.tftp_read_file = pxenv_tftp_read_file; - param_len = sizeof ( pxenv_any.tftp_read_file ); - break; - case PXENV_TFTP_GET_FSIZE: - pxenv_call.tftp_get_fsize = pxenv_tftp_get_fsize; - param_len = sizeof ( pxenv_any.tftp_get_fsize ); - break; - case PXENV_UDP_OPEN: - pxenv_call.udp_open = pxenv_udp_open; - param_len = sizeof ( pxenv_any.udp_open ); - break; - case PXENV_UDP_CLOSE: - pxenv_call.udp_close = pxenv_udp_close; - param_len = sizeof ( pxenv_any.udp_close ); - break; - case PXENV_UDP_WRITE: - pxenv_call.udp_write = pxenv_udp_write; - param_len = sizeof ( pxenv_any.udp_write ); - break; - case PXENV_UDP_READ: - pxenv_call.udp_read = pxenv_udp_read; - param_len = sizeof ( pxenv_any.udp_read ); - break; - case PXENV_UNDI_STARTUP: - pxenv_call.undi_startup = pxenv_undi_startup; - param_len = sizeof ( pxenv_any.undi_startup ); - break; - case PXENV_UNDI_CLEANUP: - pxenv_call.undi_cleanup = pxenv_undi_cleanup; - param_len = sizeof ( pxenv_any.undi_cleanup ); - break; - case PXENV_UNDI_INITIALIZE: - pxenv_call.undi_initialize = pxenv_undi_initialize; - param_len = sizeof ( pxenv_any.undi_initialize ); - break; - case PXENV_UNDI_RESET_ADAPTER: - pxenv_call.undi_reset_adapter = pxenv_undi_reset_adapter; - param_len = sizeof ( pxenv_any.undi_reset_adapter ); - break; - case PXENV_UNDI_SHUTDOWN: - pxenv_call.undi_shutdown = pxenv_undi_shutdown; - param_len = sizeof ( pxenv_any.undi_shutdown ); - break; - case PXENV_UNDI_OPEN: - pxenv_call.undi_open = pxenv_undi_open; - param_len = sizeof ( pxenv_any.undi_open ); - break; - case PXENV_UNDI_CLOSE: - pxenv_call.undi_close = pxenv_undi_close; - param_len = sizeof ( pxenv_any.undi_close ); - break; - case PXENV_UNDI_TRANSMIT: - pxenv_call.undi_transmit = pxenv_undi_transmit; - param_len = sizeof ( pxenv_any.undi_transmit ); - break; - case PXENV_UNDI_SET_MCAST_ADDRESS: - pxenv_call.undi_set_mcast_address = - pxenv_undi_set_mcast_address; - param_len = sizeof ( pxenv_any.undi_set_mcast_address ); - break; - case PXENV_UNDI_SET_STATION_ADDRESS: - pxenv_call.undi_set_station_address = - pxenv_undi_set_station_address; - param_len = sizeof ( pxenv_any.undi_set_station_address ); - break; - case PXENV_UNDI_SET_PACKET_FILTER: - pxenv_call.undi_set_packet_filter = - pxenv_undi_set_packet_filter; - param_len = sizeof ( pxenv_any.undi_set_packet_filter ); - break; - case PXENV_UNDI_GET_INFORMATION: - pxenv_call.undi_get_information = pxenv_undi_get_information; - param_len = sizeof ( pxenv_any.undi_get_information ); - break; - case PXENV_UNDI_GET_STATISTICS: - pxenv_call.undi_get_statistics = pxenv_undi_get_statistics; - param_len = sizeof ( pxenv_any.undi_get_statistics ); - break; - case PXENV_UNDI_CLEAR_STATISTICS: - pxenv_call.undi_clear_statistics = pxenv_undi_clear_statistics; - param_len = sizeof ( pxenv_any.undi_clear_statistics ); - break; - case PXENV_UNDI_INITIATE_DIAGS: - pxenv_call.undi_initiate_diags = pxenv_undi_initiate_diags; - param_len = sizeof ( pxenv_any.undi_initiate_diags ); - break; - case PXENV_UNDI_FORCE_INTERRUPT: - pxenv_call.undi_force_interrupt = pxenv_undi_force_interrupt; - param_len = sizeof ( pxenv_any.undi_force_interrupt ); - break; - case PXENV_UNDI_GET_MCAST_ADDRESS: - pxenv_call.undi_get_mcast_address = - pxenv_undi_get_mcast_address; - param_len = sizeof ( pxenv_any.undi_get_mcast_address ); - break; - case PXENV_UNDI_GET_NIC_TYPE: - pxenv_call.undi_get_nic_type = pxenv_undi_get_nic_type; - param_len = sizeof ( pxenv_any.undi_get_nic_type ); - break; - case PXENV_UNDI_GET_IFACE_INFO: - pxenv_call.undi_get_iface_info = pxenv_undi_get_iface_info; - param_len = sizeof ( pxenv_any.undi_get_iface_info ); - break; - case PXENV_UNDI_ISR: - pxenv_call.undi_isr = pxenv_undi_isr; - param_len = sizeof ( pxenv_any.undi_isr ); - break; - case PXENV_FILE_OPEN: - pxenv_call.file_open = pxenv_file_open; - param_len = sizeof ( pxenv_any.file_open ); - break; - case PXENV_FILE_CLOSE: - pxenv_call.file_close = pxenv_file_close; - param_len = sizeof ( pxenv_any.file_close ); - break; - case PXENV_FILE_SELECT: - pxenv_call.file_select = pxenv_file_select; - param_len = sizeof ( pxenv_any.file_select ); - break; - case PXENV_FILE_READ: - pxenv_call.file_read = pxenv_file_read; - param_len = sizeof ( pxenv_any.file_read ); - break; - case PXENV_GET_FILE_SIZE: - pxenv_call.get_file_size = pxenv_get_file_size; - param_len = sizeof ( pxenv_any.get_file_size ); - break; - case PXENV_FILE_EXEC: - pxenv_call.file_exec = pxenv_file_exec; - param_len = sizeof ( pxenv_any.file_exec ); - break; - case PXENV_FILE_API_CHECK: - 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; - param_len = sizeof ( pxenv_any.unknown ); - break; - } - - /* Copy parameter block from caller */ - copy_from_user ( &pxenv_any, parameters, 0, param_len ); - - /* Set default status in case child routine fails to do so */ - pxenv_any.Status = PXENV_STATUS_FAILURE; - - /* Hand off to relevant API routine */ - DBG ( "[" ); - ret = pxenv_call.any ( &pxenv_any ); - if ( pxenv_any.Status != PXENV_STATUS_SUCCESS ) { - DBG ( " %02x", pxenv_any.Status ); - } - if ( ret != PXENV_EXIT_SUCCESS ) { - DBG ( ret == PXENV_EXIT_FAILURE ? " err" : " ??" ); - } - DBG ( "]" ); - - /* Copy modified parameter block back to caller and return */ - copy_to_user ( parameters, 0, &pxenv_any, param_len ); - ix86->regs.ax = ret; -} - -/** - * Dispatch weak PXE API call with PXE stack available - * - * @v ix86 Registers for PXE call - * @ret present Zero (PXE stack present) - */ -int _pxe_api_call_weak ( struct i386_all_regs *ix86 ) -{ - pxe_api_call ( ix86 ); - return 0; -} - -/** - * Dispatch PXE loader call - * - * @v es:di Address of PXE parameter block - * @ret ax PXE exit code - */ -__asmcall 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 ( ¶ms, uparams, 0, sizeof ( params ) ); - - /* Fill in ROM segment address */ - ppxe.UNDIROMID.segment = ix86->segs.ds; - - /* Set default status in case child routine fails to do so */ - params.Status = PXENV_STATUS_FAILURE; - - /* Call UNDI loader */ - ret = undi_loader ( ¶ms ); - - /* Copy modified parameter block back to caller and return */ - copy_to_user ( uparams, 0, ¶ms, sizeof ( params ) ); - ix86->regs.ax = ret; -} - -/** - * Calculate byte checksum as used by PXE - * - * @v data Data - * @v size Length of data - * @ret sum Checksum - */ -static uint8_t pxe_checksum ( void *data, size_t size ) { - uint8_t *bytes = data; - uint8_t sum = 0; - - while ( size-- ) { - sum += *bytes++; - } - return sum; -} - -/** - * Initialise !PXE and PXENV+ structures - * - */ -static void pxe_init_structures ( void ) { - uint32_t rm_cs_phys = ( rm_cs << 4 ); - uint32_t rm_ds_phys = ( rm_ds << 4 ); - - /* Fill in missing segment fields */ - ppxe.EntryPointSP.segment = rm_cs; - ppxe.EntryPointESP.segment = rm_cs; - ppxe.Stack.segment_address = rm_ds; - ppxe.Stack.Physical_address = rm_ds_phys; - ppxe.UNDIData.segment_address = rm_ds; - ppxe.UNDIData.Physical_address = rm_ds_phys; - ppxe.UNDICode.segment_address = rm_cs; - ppxe.UNDICode.Physical_address = rm_cs_phys; - ppxe.UNDICodeWrite.segment_address = rm_cs; - ppxe.UNDICodeWrite.Physical_address = rm_cs_phys; - pxenv.RMEntry.segment = rm_cs; - pxenv.StackSeg = rm_ds; - pxenv.UNDIDataSeg = rm_ds; - pxenv.UNDICodeSeg = rm_cs; - pxenv.PXEPtr.segment = rm_cs; - - /* Update checksums */ - ppxe.StructCksum -= pxe_checksum ( &ppxe, sizeof ( ppxe ) ); - pxenv.Checksum -= pxe_checksum ( &pxenv, sizeof ( pxenv ) ); -} - -/** PXE structure initialiser */ -struct init_fn pxe_init_fn __init_fn ( INIT_NORMAL ) = { - .initialise = pxe_init_structures, -}; - -/** - * Activate PXE stack - * - * @v netdev Net device to use as PXE net device - */ -void pxe_activate ( struct net_device *netdev ) { - - /* Ensure INT 1A is hooked */ - if ( ! int_1a_hooked ) { - hook_bios_interrupt ( 0x1a, ( unsigned int ) pxe_int_1a, - &pxe_int_1a_vector ); - int_1a_hooked = 1; - } - - /* Set PXE network device */ - pxe_set_netdev ( netdev ); -} - -/** - * Deactivate PXE stack - * - * @ret rc Return status code - */ -int pxe_deactivate ( void ) { - int rc; - - /* Clear PXE network device */ - pxe_set_netdev ( NULL ); - - /* Ensure INT 1A is unhooked, if possible */ - if ( int_1a_hooked ) { - if ( ( rc = unhook_bios_interrupt ( 0x1a, - (unsigned int) pxe_int_1a, - &pxe_int_1a_vector ))!= 0){ - DBG ( "Could not unhook INT 1A: %s\n", - strerror ( rc ) ); - return rc; - } - int_1a_hooked = 0; - } - - return 0; -} - -/** - * Start PXE NBP at 0000:7c00 - * - * @ret rc Return status code - */ -int pxe_start_nbp ( void ) { - int discard_b, discard_c, discard_d, discard_D; - uint16_t rc; - - /* Far call to PXE NBP */ - __asm__ __volatile__ ( REAL_CODE ( "movw %%cx, %%es\n\t" - "pushw %%es\n\t" - "pushw %%di\n\t" - "sti\n\t" - "lcall $0, $0x7c00\n\t" - "addw $4, %%sp\n\t" ) - : "=a" ( rc ), "=b" ( discard_b ), - "=c" ( discard_c ), "=d" ( discard_d ), - "=D" ( discard_D ) - : "a" ( 0 ), "b" ( __from_text16 ( &pxenv ) ), - "c" ( rm_cs ), - "d" ( virt_to_phys ( &pxenv ) ), - "D" ( __from_text16 ( &ppxe ) ) - : "esi", "ebp", "memory" ); - - return rc; -} |