Added (not yet tested) PXE API entry point and support functions.

This commit is contained in:
Michael Brown
2006-08-08 20:43:33 +00:00
parent d12383f1d3
commit 18c112d205
2 changed files with 300 additions and 0 deletions

View File

@@ -18,6 +18,7 @@
#include <gpxe/uaccess.h>
#include <registers.h>
#include <biosint.h>
#include <pxe.h>
/** @file
@@ -25,6 +26,21 @@
* 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 );
/** !PXE structure */
extern struct s_PXE __text16 ( pxe );
#define pxe __use_text16 ( pxe )
/** PXENV+ structure */
extern struct s_PXENV __text16 ( pxenv );
#define pxenv __use_text16 ( pxenv )
/** A function pointer to hold any PXE API call
*
* Used by pxe_api_call() to avoid large swathes of duplicated code.
@@ -288,3 +304,95 @@ void pxe_api_call ( struct i386_all_regs *ix86 ) {
copy_to_user ( parameters, 0, &pxenv_any, param_len );
ix86->regs.ax = ret;
}
/**
* Hook INT 1A for PXE
*
*/
void pxe_hook_int ( void ) {
hook_bios_interrupt ( 0x1a, ( unsigned int ) pxe_int_1a,
&pxe_int_1a_vector );
}
/**
* Unhook INT 1A for PXE
*
* @ret rc Return status code
*/
int pxe_unhook_int ( void ) {
return unhook_bios_interrupt ( 0x1a, ( unsigned int ) pxe_int_1a,
&pxe_int_1a_vector );
}
/**
* 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 stack
*
*/
void init_pxe ( void ) {
uint32_t rm_cs_phys = ( rm_cs << 4 );
uint32_t rm_ds_phys = ( rm_ds << 4 );
/* Fill in missing segment fields */
pxe.EntryPointSP.segment = rm_cs;
pxe.EntryPointESP.segment = rm_cs;
pxe.Stack.segment_address = rm_ds;
pxe.Stack.Physical_address = rm_ds_phys;
pxe.UNDIData.segment_address = rm_ds;
pxe.UNDIData.Physical_address = rm_ds_phys;
pxe.UNDICode.segment_address = rm_cs;
pxe.UNDICode.Physical_address = rm_cs_phys;
pxe.UNDICodeWrite.segment_address = rm_cs;
pxe.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 */
pxe.StructCksum -= pxe_checksum ( &pxe, sizeof ( pxe ) );
pxenv.Checksum -= pxe_checksum ( &pxenv, sizeof ( pxenv ) );
}
/**
* Boot via PXE NBP
*
* @ret rc Return status code
*/
int pxe_boot ( void ) {
int discard_b, discard_c;
uint16_t rc;
/* Ensure that PXE stack is ready to use */
init_pxe();
pxe_hook_int();
/* Far call to PXE NBP */
__asm__ __volatile__ ( REAL_CODE ( "pushw %%cx\n\t"
"pushw %%ax\n\t"
"movw %%cx, %%es\n\t"
"lcall $0, $0x7c00\n\t" )
: "=a" ( rc ), "=b" ( discard_b ),
"=c" ( discard_c )
: "a" ( &pxe ), "b" ( &pxenv ), "c" ( rm_cs )
: "edx", "esi", "edi", "ebp", "memory" );
return rc;
}