diff --git a/src/arch/i386/image/pxe_image.c b/src/arch/i386/image/pxe_image.c index fde8f09b..63429f87 100644 --- a/src/arch/i386/image/pxe_image.c +++ b/src/arch/i386/image/pxe_image.c @@ -44,27 +44,24 @@ struct image_type pxe_image_type __image_type ( PROBE_PXE ); * @ret rc Return status code */ static int pxe_exec ( struct image *image ) { + struct net_device *netdev; int rc; - /* Ensure that PXE stack is ready to use */ - pxe_hook_int1a(); - /* Arbitrarily pick the most recently opened network device */ - pxe_set_netdev ( last_opened_netdev() ); - - /* Many things will break if pxe_netdev is NULL */ - if ( ! pxe_netdev ) { + if ( ( netdev = last_opened_netdev() ) == NULL ) { DBGC ( image, "IMAGE %p could not locate PXE net device\n", image ); return -ENODEV; } + /* Activate PXE */ + pxe_activate ( netdev ); + /* Start PXE NBP */ rc = pxe_start_nbp(); /* Deactivate PXE */ - pxe_set_netdev ( NULL ); - pxe_unhook_int1a(); + pxe_deactivate(); return rc; } diff --git a/src/arch/i386/include/pxe_call.h b/src/arch/i386/include/pxe_call.h index 05d70516..50667e62 100644 --- a/src/arch/i386/include/pxe_call.h +++ b/src/arch/i386/include/pxe_call.h @@ -11,6 +11,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include +struct net_device; + /** PXE load address segment */ #define PXE_LOAD_SEGMENT 0 @@ -28,8 +30,8 @@ extern struct s_PXE __text16 ( ppxe ); extern struct s_PXENV __text16 ( pxenv ); #define pxenv __use_text16 ( pxenv ) -extern void pxe_hook_int1a ( void ); -extern int pxe_unhook_int1a ( void ); +extern void pxe_activate ( struct net_device *netdev ); +extern int pxe_deactivate ( void ); extern int pxe_start_nbp ( void ); extern __asmcall void pxe_api_call ( struct i386_all_regs *ix86 ); diff --git a/src/arch/i386/interface/pxe/pxe_call.c b/src/arch/i386/interface/pxe/pxe_call.c index e15a8c14..705afcab 100644 --- a/src/arch/i386/interface/pxe/pxe_call.c +++ b/src/arch/i386/interface/pxe/pxe_call.c @@ -37,6 +37,9 @@ extern struct segoff __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. @@ -364,25 +367,6 @@ __asmcall void pxe_loader_call ( struct i386_all_regs *ix86 ) { ix86->regs.ax = ret; } -/** - * Hook INT 1A for PXE - * - */ -void pxe_hook_int1a ( 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_int1a ( void ) { - return unhook_bios_interrupt ( 0x1a, ( unsigned int ) pxe_int_1a, - &pxe_int_1a_vector ); -} - /** * Calculate byte checksum as used by PXE * @@ -435,6 +419,50 @@ 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 * diff --git a/src/arch/i386/interface/pxe/pxe_preboot.c b/src/arch/i386/interface/pxe/pxe_preboot.c index 5ea06e92..21461a5a 100644 --- a/src/arch/i386/interface/pxe/pxe_preboot.c +++ b/src/arch/i386/interface/pxe/pxe_preboot.c @@ -296,11 +296,8 @@ PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi ) { } DBG ( " using netdev %s", netdev->name ); - /* Save as PXE net device */ - pxe_set_netdev ( netdev ); - - /* Hook INT 1A */ - pxe_hook_int1a(); + /* Activate PXE */ + pxe_activate ( netdev ); start_undi->Status = PXENV_STATUS_SUCCESS; return PXENV_EXIT_SUCCESS; @@ -313,11 +310,8 @@ PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi ) { PXENV_EXIT_t pxenv_stop_undi ( struct s_PXENV_STOP_UNDI *stop_undi ) { DBG ( "PXENV_STOP_UNDI" ); - /* Unhook INT 1A */ - pxe_unhook_int1a(); - - /* Clear PXE net device */ - pxe_set_netdev ( NULL ); + /* Deactivate PXE */ + pxe_deactivate(); /* Prepare for unload */ shutdown ( SHUTDOWN_BOOT );