X-Git-Url: http://git.etherboot.org/gpxe.git/blobdiff_plain/80cc27cbc44cf6b692141840ab2ef7abf0a2c1a0..92b8f2fc2eb9c8571a5fad8b19113cb75a7c7877:/src/arch/i386/drivers/net/undiload.c diff --git a/src/arch/i386/drivers/net/undiload.c b/src/arch/i386/drivers/net/undiload.c index fc8d9194..8271b508 100644 --- a/src/arch/i386/drivers/net/undiload.c +++ b/src/arch/i386/drivers/net/undiload.c @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +FILE_LICENCE ( GPL2_OR_LATER ); + #include #include #include @@ -36,11 +38,11 @@ */ /** Parameter block for calling UNDI loader */ -static struct s_UNDI_LOADER __data16 ( undi_loader ); +static struct s_UNDI_LOADER __bss16 ( undi_loader ); #define undi_loader __use_data16 ( undi_loader ) /** UNDI loader entry point */ -static SEGOFF16_t __data16 ( undi_loader_entry ); +static SEGOFF16_t __bss16 ( undi_loader_entry ); #define undi_loader_entry __use_data16 ( undi_loader_entry ) /** @@ -56,6 +58,12 @@ int undi_load ( struct undi_device *undi, struct undi_rom *undirom ) { uint16_t exit; int rc; + /* Only one UNDI instance may be loaded at any given time */ + if ( undi_loader_entry.segment ) { + DBG ( "UNDI %p cannot load multiple instances\n", undi ); + return -EBUSY; + } + /* Set up START_UNDI parameters */ memset ( &undi_loader, 0, sizeof ( undi_loader ) ); undi_loader.AX = undi->pci_busdevfn; @@ -90,24 +98,16 @@ int undi_load ( struct undi_device *undi, struct undi_rom *undirom ) { undi_loader_entry = undirom->loader_entry; __asm__ __volatile__ ( REAL_CODE ( "pushw %%ds\n\t" "pushw %%ax\n\t" - "lcall *%c2\n\t" + "lcall *undi_loader_entry\n\t" "addw $4, %%sp\n\t" ) : "=a" ( exit ) - : "a" ( & __from_data16 ( undi_loader ) ), - "p" ( & __from_data16 ( undi_loader_entry ) ) + : "a" ( __from_data16 ( &undi_loader ) ) : "ebx", "ecx", "edx", "esi", "edi", "ebp" ); - /* UNDI API calls may rudely change the status of A20 and not - * bother to restore it afterwards. Intel is known to be - * guilty of this. - * - * Note that we will return to this point even if A20 gets - * screwed up by the UNDI driver, because Etherboot always - * resides in an even megabyte of RAM. - */ - gateA20_set(); - if ( exit != PXENV_EXIT_SUCCESS ) { + /* Clear entry point */ + memset ( &undi_loader_entry, 0, sizeof ( undi_loader_entry ) ); + rc = -undi_loader.Status; if ( rc == 0 ) /* Paranoia */ rc = -EIO; @@ -150,6 +150,9 @@ int undi_unload ( struct undi_device *undi ) { DBGC ( undi, "UNDI %p unloading\n", undi ); + /* Clear entry point */ + memset ( &undi_loader_entry, 0, sizeof ( undi_loader_entry ) ); + /* Erase signatures */ if ( undi->pxenv.segment ) put_real ( dead, undi->pxenv.segment, undi->pxenv.offset );