X-Git-Url: http://git.etherboot.org/gpxe.git/blobdiff_plain/fdc97499bf83ef958db8a50985fdd321835dccf3..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 70008a49..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 @@ -23,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -35,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 ) /** @@ -51,11 +54,16 @@ static SEGOFF16_t __data16 ( undi_loader_entry ); */ int undi_load ( struct undi_device *undi, struct undi_rom *undirom ) { struct s_PXE ppxe; - uint16_t fbms; unsigned int fbms_seg; 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; @@ -65,9 +73,8 @@ int undi_load ( struct undi_device *undi, struct undi_rom *undirom ) { undi_loader.DI = find_pnp_bios(); /* Allocate base memory for PXE stack */ - get_real ( fbms, BDA_SEG, BDA_FBMS ); - undi->restore_fbms = fbms; - fbms_seg = ( fbms << 6 ); + undi->restore_fbms = get_fbms(); + fbms_seg = ( undi->restore_fbms << 6 ); fbms_seg -= ( ( undirom->code_size + 0x0f ) >> 4 ); undi_loader.UNDI_CS = fbms_seg; fbms_seg -= ( ( undirom->data_size + 0x0f ) >> 4 ); @@ -91,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; @@ -129,9 +128,8 @@ int undi_load ( struct undi_device *undi, struct undi_rom *undirom ) { undi->entry.segment, undi->entry.offset ); /* Update free base memory counter */ - fbms = ( fbms_seg >> 6 ); - put_real ( fbms, BDA_SEG, BDA_FBMS ); - undi->fbms = fbms; + undi->fbms = ( fbms_seg >> 6 ); + set_fbms ( undi->fbms ); DBGC ( undi, "UNDI %p using [%d,%d) kB of base memory\n", undi, undi->fbms, undi->restore_fbms ); @@ -149,10 +147,12 @@ int undi_load ( struct undi_device *undi, struct undi_rom *undirom ) { */ int undi_unload ( struct undi_device *undi ) { static uint32_t dead = 0xdeaddead; - uint16_t fbms; 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 ); @@ -160,12 +160,10 @@ int undi_unload ( struct undi_device *undi ) { put_real ( dead, undi->ppxe.segment, undi->ppxe.offset ); /* Free base memory, if possible */ - get_real ( fbms, BDA_SEG, BDA_FBMS ); - if ( fbms == undi->fbms ) { + if ( undi->fbms == get_fbms() ) { DBGC ( undi, "UNDI %p freeing [%d,%d) kB of base memory\n", undi, undi->fbms, undi->restore_fbms ); - fbms = undi->restore_fbms; - put_real ( fbms, BDA_SEG, BDA_FBMS ); + set_fbms ( undi->restore_fbms ); return 0; } else { DBGC ( undi, "UNDI %p leaking [%d,%d) kB of base memory\n",