Skip to content

Commit

Permalink
Updated PXE UDP implementation to use the new Etherboot UDP API.
Browse files Browse the repository at this point in the history
Updated PXE API dispatcher to use copy_{to,from}_user, and moved to
arch/i386 since the implementation is quite architecture-dependent.
(The individual PXE API calls can be largely
architecture-independent.)
  • Loading branch information
Michael Brown committed Aug 2, 2006
1 parent e24a6cb commit a0a872f
Show file tree
Hide file tree
Showing 10 changed files with 558 additions and 323 deletions.
1 change: 1 addition & 0 deletions src/arch/i386/Makefile
Expand Up @@ -7,6 +7,7 @@ SRCDIRS += arch/i386/drivers/bus
SRCDIRS += arch/i386/drivers/net
SRCDIRS += arch/i386/drivers/disk
SRCDIRS += arch/i386/interface/pcbios
SRCDIRS += arch/i386/interface/pxe

# The various xxx_loader.c files are #included into core/loader.c and
# should not be compiled directly.
Expand Down
290 changes: 290 additions & 0 deletions src/arch/i386/interface/pxe/pxe_call.c
@@ -0,0 +1,290 @@
/*
* 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.
*/

#include <gpxe/uaccess.h>
#include <registers.h>
#include <pxe.h>

/** @file
*
* PXE API entry point
*/

/** 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 * );
};

/**
* 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
*/
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;
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;
}
5 changes: 5 additions & 0 deletions src/include/gpxe/udp.h
Expand Up @@ -64,6 +64,9 @@ struct udp_operations {
* @v conn UDP connection
* @v data Data
* @v len Length of data
* @v st_src Source address
* @v st_dest Destination address
* @ret rc Return status code
*/
int ( * newdata ) ( struct udp_connection *conn, void *data,
size_t len, struct sockaddr_tcpip *st_src,
Expand Down Expand Up @@ -92,8 +95,10 @@ struct udp_connection {
*/

extern int udp_bind ( struct udp_connection *conn, uint16_t local_port );
extern void udp_bind_promisc ( struct udp_connection *conn );
extern void udp_connect ( struct udp_connection *conn,
struct sockaddr_tcpip *peer );
extern void udp_connect_promisc ( struct udp_connection *conn );
extern int udp_open ( struct udp_connection *conn, uint16_t local_port );
extern void udp_close ( struct udp_connection *conn );

Expand Down
30 changes: 9 additions & 21 deletions src/include/pxe.h
Expand Up @@ -3,8 +3,13 @@

#include "pxe_types.h"
#include "pxe_api.h"
#include "etherboot.h"
#include "tftp.h"

/* Parameter block for pxenv_unknown() */
struct s_PXENV_UNKNOWN {
PXENV_STATUS_t Status; /**< PXE status code */
} PACKED;

typedef struct s_PXENV_UNKNOWN PXENV_UNKNOWN_t;

/* Union used for PXE API calls; we don't know the type of the
* structure until we interpret the opcode. Also, Status is available
Expand All @@ -14,6 +19,7 @@
union u_PXENV_ANY {
/* Make it easy to read status for any operation */
PXENV_STATUS_t Status;
struct s_PXENV_UNKNOWN unknown;
struct s_PXENV_UNLOAD_STACK unload_stack;
struct s_PXENV_GET_CACHED_INFO get_cached_info;
struct s_PXENV_TFTP_READ_FILE restart_tftp;
Expand Down Expand Up @@ -81,29 +87,11 @@ typedef enum {
typedef struct pxe_stack {
struct s_PXE pxe __attribute__ ((aligned(16)));
struct s_PXENV pxenv __attribute__ ((aligned(16)));
pxe_stack_state_t state;
union {
BOOTPLAYER_t cached_info;
char packet[ETH_FRAME_LEN];
struct {
uint32_t magic_cookie;
unsigned int len;
int eof;
char data[TFTP_MAX_BLKSIZE];
} tftpdata;
struct {
char *buffer;
uint32_t offset;
uint32_t bufferlen;
} readfile;
};
struct {} arch_data __attribute__ ((aligned(16)));
pxe_stack_state_t state;
} pxe_stack_t;

extern int ensure_pxe_state ( pxe_stack_state_t wanted );

extern pxe_stack_t *pxe_stack;

extern PXENV_EXIT_t pxe_api_call ( int opcode, union u_PXENV_ANY *any );

#endif /* PXE_H */

0 comments on commit a0a872f

Please sign in to comment.