david/ipxe
david
/
ipxe
Archived
1
0
Fork 0

Merge branch 'master' of git://git.etherboot.org/scm/gpxe

This commit is contained in:
Holger Lubitz 2007-08-08 01:01:09 +02:00
commit b79d438080
9 changed files with 516 additions and 62 deletions

View File

@ -91,6 +91,11 @@ union pxenv_call {
( 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 * );
};
/**
@ -269,6 +274,26 @@ __cdecl void pxe_api_call ( struct i386_all_regs *ix86 ) {
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;
default:
DBG ( "PXENV_UNKNOWN_%hx", opcode );
pxenv_call.unknown = pxenv_unknown;

View File

@ -237,6 +237,7 @@ int image_autoload ( struct image *image ) {
* @ret rc Return status code
*/
int image_exec ( struct image *image ) {
struct uri *old_cwuri;
int rc;
/* Image must be loaded first */
@ -252,15 +253,23 @@ int image_exec ( struct image *image ) {
if ( ! image->type->exec )
return -ENOEXEC;
/* Switch current working directory to be that of the image itself */
old_cwuri = uri_get ( cwuri );
churi ( image->uri );
/* Try executing the image */
if ( ( rc = image->type->exec ( image ) ) != 0 ) {
DBGC ( image, "IMAGE %p could not execute: %s\n",
image, strerror ( rc ) );
return rc;
goto done;
}
/* Well, some formats might return... */
return 0;
done:
/* Reset current working directory */
churi ( old_cwuri );
uri_put ( old_cwuri );
return rc;
}
/**

View File

@ -60,12 +60,6 @@ struct posix_file {
/** List of open files */
static LIST_HEAD ( posix_files );
/** Minimum file descriptor that will ever be allocated */
#define POSIX_FD_MIN ( 1 )
/** Maximum file descriptor that will ever be allocated */
#define POSIX_FD_MAX ( 255 )
/**
* Free open file
*
@ -251,6 +245,38 @@ int open ( const char *uri_string ) {
return rc;
}
/**
* Check file descriptors for readiness
*
* @v readfds File descriptors to check
* @v wait Wait until data is ready
* @ret nready Number of ready file descriptors
*/
int select ( fd_set *readfds, int wait ) {
struct posix_file *file;
int fd;
do {
for ( fd = POSIX_FD_MIN ; fd <= POSIX_FD_MAX ; fd++ ) {
if ( ! FD_ISSET ( fd, readfds ) )
continue;
file = posix_fd_to_file ( fd );
if ( ! file )
return -EBADF;
if ( ( list_empty ( &file->data ) ) &&
( file->rc != -EINPROGRESS ) )
continue;
/* Data is available or status has changed */
FD_ZERO ( readfds );
FD_SET ( fd, readfds );
return 1;
}
step();
} while ( wait );
return 0;
}
/**
* Read data from file
*
@ -258,47 +284,45 @@ int open ( const char *uri_string ) {
* @v offset Starting offset within data buffer
* @v len Maximum length to read
* @ret len Actual length read, or negative error number
*
* This call is non-blocking; if no data is available to read then
* -EWOULDBLOCK will be returned.
*/
ssize_t read_user ( int fd, userptr_t buffer, off_t offset, size_t max_len ) {
struct posix_file *file;
struct io_buffer *iobuf;
size_t frag_len;
ssize_t len = 0;
size_t len;
/* Identify file */
file = posix_fd_to_file ( fd );
if ( ! file )
return -EBADF;
while ( 1 ) {
/* Try to fetch more data if none available */
if ( list_empty ( &file->data ) )
step();
/* Dequeue at most one received I/O buffer into user buffer */
list_for_each_entry ( iobuf, &file->data, list ) {
frag_len = iob_len ( iobuf );
if ( frag_len > max_len )
frag_len = max_len;
copy_to_user ( buffer, offset, iobuf->data,
frag_len );
iob_pull ( iobuf, frag_len );
if ( ! iob_len ( iobuf ) ) {
list_del ( &iobuf-> list );
free_iob ( iobuf );
}
file->pos += frag_len;
len += frag_len;
offset += frag_len;
max_len -= frag_len;
break;
/* Try to fetch more data if none available */
if ( list_empty ( &file->data ) )
step();
/* Dequeue at most one received I/O buffer into user buffer */
list_for_each_entry ( iobuf, &file->data, list ) {
len = iob_len ( iobuf );
if ( len > max_len )
len = max_len;
copy_to_user ( buffer, offset, iobuf->data, len );
iob_pull ( iobuf, len );
if ( ! iob_len ( iobuf ) ) {
list_del ( &iobuf->list );
free_iob ( iobuf );
}
/* If buffer is full, return */
if ( ! max_len )
return len;
/* If file has completed, return */
if ( file->rc != -EINPROGRESS )
return ( file->rc ? file->rc : len );
file->pos += len;
return len;
}
/* If file has completed, return (after returning all data) */
if ( file->rc != -EINPROGRESS )
return file->rc;
/* No data ready and file still in progress; return -WOULDBLOCK */
return -EWOULDBLOCK;
}
/**

View File

@ -27,7 +27,6 @@
#include <stdlib.h>
#include <errno.h>
#include <gpxe/image.h>
#include <gpxe/uri.h>
struct image_type script_image_type __image_type ( PROBE_NORMAL );
@ -38,7 +37,6 @@ struct image_type script_image_type __image_type ( PROBE_NORMAL );
* @ret rc Return status code
*/
static int script_exec ( struct image *image ) {
struct uri *old_cwuri;
char cmdbuf[256];
size_t offset = 0;
size_t remaining;
@ -53,10 +51,6 @@ static int script_exec ( struct image *image ) {
image_get ( image );
unregister_image ( image );
/* Switch current working directory to be that of the script itself */
old_cwuri = uri_get ( cwuri );
churi ( image->uri );
while ( offset < image->len ) {
/* Read up to cmdbuf bytes from script into buffer */
@ -93,9 +87,7 @@ static int script_exec ( struct image *image ) {
rc = 0;
done:
/* Reset current working directory, re-register image and return */
churi ( old_cwuri );
uri_put ( old_cwuri );
/* Re-register image and return */
register_image ( image );
image_put ( image );
return rc;

View File

@ -10,12 +10,66 @@
#include <stdint.h>
#include <gpxe/uaccess.h>
/** Minimum file descriptor that will ever be allocated */
#define POSIX_FD_MIN ( 1 )
/** Maximum file descriptor that will ever be allocated */
#define POSIX_FD_MAX ( 31 )
/** File descriptor set as used for select() */
typedef uint32_t fd_set;
extern int open ( const char *uri_string );
extern ssize_t read_user ( int fd, userptr_t buffer,
off_t offset, size_t len );
extern int select ( fd_set *readfds, int wait );
extern ssize_t fsize ( int fd );
extern int close ( int fd );
/**
* Zero a file descriptor set
*
* @v set File descriptor set
*/
static inline __attribute__ (( always_inline )) void
FD_ZERO ( fd_set *set ) {
*set = 0;
}
/**
* Set a bit within a file descriptor set
*
* @v fd File descriptor
* @v set File descriptor set
*/
static inline __attribute__ (( always_inline )) void
FD_SET ( int fd, fd_set *set ) {
*set |= ( 1 << fd );
}
/**
* Clear a bit within a file descriptor set
*
* @v fd File descriptor
* @v set File descriptor set
*/
static inline __attribute__ (( always_inline )) void
FD_CLR ( int fd, fd_set *set ) {
*set &= ~( 1 << fd );
}
/**
* Test a bit within a file descriptor set
*
* @v fd File descriptor
* @v set File descriptor set
* @ret is_set Corresponding bit is set
*/
static inline __attribute__ (( always_inline )) int
FD_ISSET ( int fd, fd_set *set ) {
return ( *set & ( 1 << fd ) );
}
/**
* Read data from file
*

View File

@ -58,6 +58,11 @@ union u_PXENV_ANY {
struct s_PXENV_UNDI_GET_IFACE_INFO undi_get_iface_info;
struct s_PXENV_UNDI_GET_STATE undi_get_state;
struct s_PXENV_UNDI_ISR undi_isr;
struct s_PXENV_FILE_OPEN file_open;
struct s_PXENV_FILE_CLOSE file_close;
struct s_PXENV_FILE_SELECT file_select;
struct s_PXENV_FILE_READ file_read;
struct s_PXENV_GET_FILE_SIZE get_file_size;
};
typedef union u_PXENV_ANY PXENV_ANY_t;

View File

@ -1555,6 +1555,137 @@ extern PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr );
/** @} */ /* pxe_undi_api */
/** @defgroup pxe_file_api PXE FILE API
*
* POSIX-like file operations
*
* @{
*/
/** @defgroup pxenv_file_open PXENV_FILE_OPEN
*
* FILE OPEN
*
* @{
*/
/** PXE API function code for pxenv_file_open() */
#define PXENV_FILE_OPEN 0x00e0
/** Parameter block for pxenv_file_open() */
struct s_PXENV_FILE_OPEN {
PXENV_STATUS_t Status; /**< PXE status code */
UINT16_t FileHandle; /**< File handle */
SEGOFF16_t FileName; /**< File URL */
UINT32_t Reserved; /**< Reserved */
} PACKED;
typedef struct s_PXENV_FILE_OPEN PXENV_FILE_OPEN_t;
extern PXENV_EXIT_t pxenv_file_open ( struct s_PXENV_FILE_OPEN *file_open );
/** @} */ /* pxenv_file_open */
/** @defgroup pxenv_file_close PXENV_FILE_CLOSE
*
* FILE CLOSE
*
* @{
*/
/** PXE API function code for pxenv_file_close() */
#define PXENV_FILE_CLOSE 0x00e1
/** Parameter block for pxenv_file_close() */
struct s_PXENV_FILE_CLOSE {
PXENV_STATUS_t Status; /**< PXE status code */
UINT16_t FileHandle; /**< File handle */
} PACKED;
typedef struct s_PXENV_FILE_CLOSE PXENV_FILE_CLOSE_t;
extern PXENV_EXIT_t pxenv_file_close ( struct s_PXENV_FILE_CLOSE
*file_close );
/** @} */ /* pxenv_file_close */
/** @defgroup pxenv_file_select PXENV_FILE_SELECT
*
* FILE SELECT
*
* @{
*/
/** PXE API function code for pxenv_file_select() */
#define PXENV_FILE_SELECT 0x00e2
/** File is ready for reading */
#define RDY_READ 0x0001
/** Parameter block for pxenv_file_select() */
struct s_PXENV_FILE_SELECT {
PXENV_STATUS_t Status; /**< PXE status code */
UINT16_t FileHandle; /**< File handle */
UINT16_t Ready; /**< Indication of readiness */
} PACKED;
typedef struct s_PXENV_FILE_SELECT PXENV_FILE_SELECT_t;
extern PXENV_EXIT_t pxenv_file_select ( struct s_PXENV_FILE_SELECT
*file_select );
/** @} */ /* pxenv_file_select */
/** @defgroup pxenv_file_read PXENV_FILE_READ
*
* FILE READ
*
* @{
*/
/** PXE API function code for pxenv_file_read() */
#define PXENV_FILE_READ 0x00e3
/** Parameter block for pxenv_file_read() */
struct s_PXENV_FILE_READ {
PXENV_STATUS_t Status; /**< PXE status code */
UINT16_t FileHandle; /**< File handle */
UINT16_t BufferSize; /**< Data buffer size */
SEGOFF16_t Buffer; /**< Data buffer */
} PACKED;
typedef struct s_PXENV_FILE_READ PXENV_FILE_READ_t;
extern PXENV_EXIT_t pxenv_file_read ( struct s_PXENV_FILE_READ *file_read );
/** @} */ /* pxenv_file_read */
/** @defgroup pxenv_get_file_size PXENV_GET_FILE_SIZE
*
* GET FILE SIZE
*
* @{
*/
/** PXE API function code for pxenv_get_file_size() */
#define PXENV_GET_FILE_SIZE 0x00e4
/** Parameter block for pxenv_get_file_size() */
struct s_PXENV_GET_FILE_SIZE {
PXENV_STATUS_t Status; /**< PXE status code */
UINT16_t FileHandle; /**< File handle */
UINT32_t FileSize; /**< File size */
} PACKED;
typedef struct s_PXENV_GET_FILE_SIZE PXENV_GET_FILE_SIZE_t;
extern PXENV_EXIT_t pxenv_get_file_size ( struct s_PXENV_GET_FILE_SIZE
*get_file_size );
/** @} */ /* pxenv_get_file_size */
/** @} */ /* pxe_file_api */
/** @defgroup pxe_loader_api PXE Loader API
*
* The UNDI ROM loader API

View File

@ -0,0 +1,191 @@
/** @file
*
* PXE FILE API
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <byteswap.h>
#include <gpxe/uaccess.h>
#include <gpxe/posix_io.h>
#include <gpxe/features.h>
#include <pxe.h>
/*
* 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.
*/
FEATURE ( FEATURE_MISC, "PXEXT", DHCP_EB_FEATURE_PXE_EXT, 1 );
/**
* FILE OPEN
*
* @v file_open Pointer to a struct s_PXENV_FILE_OPEN
* @v s_PXENV_FILE_OPEN::FileName URL of file to open
* @ret #PXENV_EXIT_SUCCESS File was opened
* @ret #PXENV_EXIT_FAILURE File was not opened
* @ret s_PXENV_FILE_OPEN::Status PXE status code
* @ret s_PXENV_FILE_OPEN::FileHandle Handle of opened file
*
*/
PXENV_EXIT_t pxenv_file_open ( struct s_PXENV_FILE_OPEN *file_open ) {
userptr_t filename;
size_t filename_len;
int fd;
DBG ( "PXENV_FILE_OPEN" );
/* Copy name from external program, and open it */
filename = real_to_user ( file_open->FileName.segment,
file_open->FileName.offset );
filename_len = strlen_user ( filename, 0 );
{
char uri_string[ filename_len + 1 ];
copy_from_user ( uri_string, filename, 0,
sizeof ( uri_string ) );
DBG ( " %s", uri_string );
fd = open ( uri_string );
}
if ( fd < 0 ) {
file_open->Status = PXENV_STATUS ( fd );
return PXENV_EXIT_FAILURE;
}
DBG ( " as file %d", fd );
file_open->FileHandle = fd;
file_open->Status = PXENV_STATUS_SUCCESS;
return PXENV_EXIT_SUCCESS;
}
/**
* FILE CLOSE
*
* @v file_close Pointer to a struct s_PXENV_FILE_CLOSE
* @v s_PXENV_FILE_CLOSE::FileHandle File handle
* @ret #PXENV_EXIT_SUCCESS File was closed
* @ret #PXENV_EXIT_FAILURE File was not closed
* @ret s_PXENV_FILE_CLOSE::Status PXE status code
*
*/
PXENV_EXIT_t pxenv_file_close ( struct s_PXENV_FILE_CLOSE *file_close ) {
DBG ( "PXENV_FILE_CLOSE %d", file_close->FileHandle );
close ( file_close->FileHandle );
file_close->Status = PXENV_STATUS_SUCCESS;
return PXENV_EXIT_SUCCESS;
}
/**
* FILE SELECT
*
* @v file_select Pointer to a struct s_PXENV_FILE_SELECT
* @v s_PXENV_FILE_SELECT::FileHandle File handle
* @ret #PXENV_EXIT_SUCCESS File has been checked for readiness
* @ret #PXENV_EXIT_FAILURE File has not been checked for readiness
* @ret s_PXENV_FILE_SELECT::Status PXE status code
* @ret s_PXENV_FILE_SELECT::Ready Indication of readiness
*
*/
PXENV_EXIT_t pxenv_file_select ( struct s_PXENV_FILE_SELECT *file_select ) {
fd_set fdset;
int ready;
DBG ( "PXENV_FILE_SELECT %d", file_select->FileHandle );
FD_ZERO ( &fdset );
FD_SET ( file_select->FileHandle, &fdset );
if ( ( ready = select ( &fdset, 0 ) ) < 0 ) {
file_select->Status = PXENV_STATUS ( ready );
return PXENV_EXIT_FAILURE;
}
file_select->Ready = ( ready ? RDY_READ : 0 );
file_select->Status = PXENV_STATUS_SUCCESS;
return PXENV_EXIT_SUCCESS;
}
/**
* FILE READ
*
* @v file_read Pointer to a struct s_PXENV_FILE_READ
* @v s_PXENV_FILE_READ::FileHandle File handle
* @v s_PXENV_FILE_READ::BufferSize Size of data buffer
* @v s_PXENV_FILE_READ::Buffer Data buffer
* @ret #PXENV_EXIT_SUCCESS Data has been read from file
* @ret #PXENV_EXIT_FAILURE Data has not been read from file
* @ret s_PXENV_FILE_READ::Status PXE status code
* @ret s_PXENV_FILE_READ::Ready Indication of readiness
* @ret s_PXENV_FILE_READ::BufferSize Length of data read
*
*/
PXENV_EXIT_t pxenv_file_read ( struct s_PXENV_FILE_READ *file_read ) {
userptr_t buffer;
ssize_t len;
DBG ( "PXENV_FILE_READ %d to %04x:%04x+%04x", file_read->FileHandle,
file_read->Buffer.segment, file_read->Buffer.offset,
file_read->BufferSize );
buffer = real_to_user ( file_read->Buffer.segment,
file_read->Buffer.offset );
if ( ( len = read_user ( file_read->FileHandle, buffer, 0,
file_read->BufferSize ) ) < 0 ) {
file_read->Status = PXENV_STATUS ( len );
return PXENV_EXIT_FAILURE;
}
DBG ( " read %04zx", ( ( size_t ) len ) );
file_read->BufferSize = len;
file_read->Status = PXENV_STATUS_SUCCESS;
return PXENV_EXIT_SUCCESS;
}
/**
* GET FILE SIZE
*
* @v get_file_size Pointer to a struct s_PXENV_GET_FILE_SIZE
* @v s_PXENV_GET_FILE_SIZE::FileHandle File handle
* @ret #PXENV_EXIT_SUCCESS File size has been determined
* @ret #PXENV_EXIT_FAILURE File size has not been determined
* @ret s_PXENV_GET_FILE_SIZE::Status PXE status code
* @ret s_PXENV_GET_FILE_SIZE::FileSize Size of file
*/
PXENV_EXIT_t pxenv_get_file_size ( struct s_PXENV_GET_FILE_SIZE
*get_file_size ) {
ssize_t filesize;
DBG ( "PXENV_GET_FILE_SIZE %d", get_file_size->FileHandle );
filesize = fsize ( get_file_size->FileHandle );
if ( filesize < 0 ) {
get_file_size->Status = PXENV_STATUS ( filesize );
return PXENV_EXIT_FAILURE;
}
DBG ( " is %zd", ( ( size_t ) filesize ) );
get_file_size->FileSize = filesize;
get_file_size->Status = PXENV_STATUS_SUCCESS;
return PXENV_EXIT_SUCCESS;
}

View File

@ -78,6 +78,37 @@ static void pxe_tftp_build_uri ( char *uri_string,
( ( filename[0] == '/' ) ? "" : "/" ), filename );
}
/**
* Read as much as possible from file
*
* @v fd File descriptor
* @v buffer Data buffer
* @v max_len Maximum length to read
* @ret len Actual length read, or negative error
*/
static ssize_t pxe_tftp_read_all ( int fd, userptr_t buffer,
size_t max_len ) {
fd_set fdset;
off_t offset = 0;
int ready;
ssize_t len;
do {
FD_ZERO ( &fdset );
FD_SET ( fd, &fdset );
ready = select ( &fdset, 1 );
if ( ready < 0 )
return ready;
len = read_user ( fd, buffer, offset, max_len );
if ( len < 0 )
return len;
offset += len;
max_len -= len;
} while ( max_len && len );
return offset;
}
/**
* TFTP OPEN
*
@ -251,11 +282,12 @@ PXENV_EXIT_t pxenv_tftp_read ( struct s_PXENV_TFTP_READ *tftp_read ) {
buffer = real_to_user ( tftp_read->Buffer.segment,
tftp_read->Buffer.offset );
len = read_user ( pxe_single_fd, buffer, 0, pxe_single_blksize );
len = pxe_tftp_read_all ( pxe_single_fd, buffer, pxe_single_blksize );
if ( len < 0 ) {
tftp_read->Status = PXENV_STATUS ( len );
return PXENV_EXIT_FAILURE;
}
tftp_read->BufferSize = len;
tftp_read->PacketNumber = ++pxe_single_blkidx;
@ -359,10 +391,8 @@ PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE
char uri_string[PXE_URI_LEN];
int fd;
userptr_t buffer;
size_t max_len;
ssize_t frag_len;
size_t len = 0;
int rc = -ENOBUFS;
ssize_t len;
int rc = 0;
DBG ( "PXENV_TFTP_READ_FILE" );
@ -384,16 +414,9 @@ PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE
/* Read file */
buffer = phys_to_user ( tftp_read_file->Buffer );
max_len = tftp_read_file->BufferSize;
while ( max_len ) {
frag_len = read_user ( fd, buffer, len, max_len );
if ( frag_len <= 0 ) {
rc = frag_len;
break;
}
len += frag_len;
max_len -= frag_len;
}
len = pxe_tftp_read_all ( fd, buffer, tftp_read_file->BufferSize );
if ( len < 0 )
rc = len;
close ( fd );
tftp_read_file->BufferSize = len;