00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 FILE_LICENCE ( GPL2_OR_LATER );
00020
00021 #include <stdint.h>
00022 #include <stdlib.h>
00023 #include <string.h>
00024 #include <pxe.h>
00025 #include <realmode.h>
00026 #include <bios.h>
00027 #include <pnpbios.h>
00028 #include <basemem.h>
00029 #include <gpxe/pci.h>
00030 #include <undi.h>
00031 #include <undirom.h>
00032 #include <undiload.h>
00033
00034
00035
00036
00037
00038
00039
00040
00041 static struct s_UNDI_LOADER __bss16 ( undi_loader );
00042 #define undi_loader __use_data16 ( undi_loader )
00043
00044
00045 static SEGOFF16_t __bss16 ( undi_loader_entry );
00046 #define undi_loader_entry __use_data16 ( undi_loader_entry )
00047
00048
00049
00050
00051
00052
00053
00054
00055 int undi_load ( struct undi_device *undi, struct undi_rom *undirom ) {
00056 struct s_PXE ppxe;
00057 unsigned int fbms_seg;
00058 uint16_t exit;
00059 int rc;
00060
00061
00062 if ( undi_loader_entry.segment ) {
00063 DBG ( "UNDI %p cannot load multiple instances\n", undi );
00064 return -EBUSY;
00065 }
00066
00067
00068 memset ( &undi_loader, 0, sizeof ( undi_loader ) );
00069 undi_loader.AX = undi->pci_busdevfn;
00070 undi_loader.BX = undi->isapnp_csn;
00071 undi_loader.DX = undi->isapnp_read_port;
00072 undi_loader.ES = BIOS_SEG;
00073 undi_loader.DI = find_pnp_bios();
00074
00075
00076 undi->restore_fbms = get_fbms();
00077 fbms_seg = ( undi->restore_fbms << 6 );
00078 fbms_seg -= ( ( undirom->code_size + 0x0f ) >> 4 );
00079 undi_loader.UNDI_CS = fbms_seg;
00080 fbms_seg -= ( ( undirom->data_size + 0x0f ) >> 4 );
00081 undi_loader.UNDI_DS = fbms_seg;
00082
00083
00084 DBGC ( undi, "UNDI %p loading UNDI ROM %p to CS %04x DS %04x for ",
00085 undi, undirom, undi_loader.UNDI_CS, undi_loader.UNDI_DS );
00086 if ( undi->pci_busdevfn != UNDI_NO_PCI_BUSDEVFN ) {
00087 unsigned int bus = ( undi->pci_busdevfn >> 8 );
00088 unsigned int devfn = ( undi->pci_busdevfn & 0xff );
00089 DBGC ( undi, "PCI %02x:%02x.%x\n",
00090 bus, PCI_SLOT ( devfn ), PCI_FUNC ( devfn ) );
00091 }
00092 if ( undi->isapnp_csn != UNDI_NO_ISAPNP_CSN ) {
00093 DBGC ( undi, "ISAPnP(%04x) CSN %04x\n",
00094 undi->isapnp_read_port, undi->isapnp_csn );
00095 }
00096
00097
00098 undi_loader_entry = undirom->loader_entry;
00099 __asm__ __volatile__ ( REAL_CODE ( "pushw %%ds\n\t"
00100 "pushw %%ax\n\t"
00101 "lcall *undi_loader_entry\n\t"
00102 "addw $4, %%sp\n\t" )
00103 : "=a" ( exit )
00104 : "a" ( __from_data16 ( &undi_loader ) )
00105 : "ebx", "ecx", "edx", "esi", "edi", "ebp" );
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115 gateA20_set();
00116
00117 if ( exit != PXENV_EXIT_SUCCESS ) {
00118
00119 memset ( &undi_loader_entry, 0, sizeof ( undi_loader_entry ) );
00120
00121 rc = -undi_loader.Status;
00122 if ( rc == 0 )
00123 rc = -EIO;
00124 DBGC ( undi, "UNDI %p loader failed: %s\n",
00125 undi, strerror ( rc ) );
00126 return rc;
00127 }
00128
00129
00130 undi->pxenv = undi_loader.PXENVptr;
00131 undi->ppxe = undi_loader.PXEptr;
00132 copy_from_real ( &ppxe, undi->ppxe.segment, undi->ppxe.offset,
00133 sizeof ( ppxe ) );
00134 undi->entry = ppxe.EntryPointSP;
00135 DBGC ( undi, "UNDI %p loaded PXENV+ %04x:%04x !PXE %04x:%04x "
00136 "entry %04x:%04x\n", undi, undi->pxenv.segment,
00137 undi->pxenv.offset, undi->ppxe.segment, undi->ppxe.offset,
00138 undi->entry.segment, undi->entry.offset );
00139
00140
00141 undi->fbms = ( fbms_seg >> 6 );
00142 set_fbms ( undi->fbms );
00143 DBGC ( undi, "UNDI %p using [%d,%d) kB of base memory\n",
00144 undi, undi->fbms, undi->restore_fbms );
00145
00146 return 0;
00147 }
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158 int undi_unload ( struct undi_device *undi ) {
00159 static uint32_t dead = 0xdeaddead;
00160
00161 DBGC ( undi, "UNDI %p unloading\n", undi );
00162
00163
00164 memset ( &undi_loader_entry, 0, sizeof ( undi_loader_entry ) );
00165
00166
00167 if ( undi->pxenv.segment )
00168 put_real ( dead, undi->pxenv.segment, undi->pxenv.offset );
00169 if ( undi->ppxe.segment )
00170 put_real ( dead, undi->ppxe.segment, undi->ppxe.offset );
00171
00172
00173 if ( undi->fbms == get_fbms() ) {
00174 DBGC ( undi, "UNDI %p freeing [%d,%d) kB of base memory\n",
00175 undi, undi->fbms, undi->restore_fbms );
00176 set_fbms ( undi->restore_fbms );
00177 return 0;
00178 } else {
00179 DBGC ( undi, "UNDI %p leaking [%d,%d) kB of base memory\n",
00180 undi, undi->fbms, undi->restore_fbms );
00181 return -EBUSY;
00182 }
00183 }