pxe_call.c
Go to the documentation of this file.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 <gpxe/uaccess.h>
00022 #include <gpxe/init.h>
00023 #include <registers.h>
00024 #include <biosint.h>
00025 #include <pxe.h>
00026 #include <pxe_call.h>
00027
00028
00029
00030
00031
00032
00033
00034 extern struct segoff __text16 ( pxe_int_1a_vector );
00035 #define pxe_int_1a_vector __use_text16 ( pxe_int_1a_vector )
00036
00037
00038 extern void pxe_int_1a ( void );
00039
00040
00041 static int int_1a_hooked = 0;
00042
00043
00044
00045
00046
00047 union pxenv_call {
00048 PXENV_EXIT_t ( * any ) ( union u_PXENV_ANY * );
00049 PXENV_EXIT_t ( * unknown ) ( struct s_PXENV_UNKNOWN * );
00050 PXENV_EXIT_t ( * unload_stack ) ( struct s_PXENV_UNLOAD_STACK * );
00051 PXENV_EXIT_t ( * get_cached_info )
00052 ( struct s_PXENV_GET_CACHED_INFO * );
00053 PXENV_EXIT_t ( * restart_tftp ) ( struct s_PXENV_TFTP_READ_FILE * );
00054 PXENV_EXIT_t ( * start_undi ) ( struct s_PXENV_START_UNDI * );
00055 PXENV_EXIT_t ( * stop_undi ) ( struct s_PXENV_STOP_UNDI * );
00056 PXENV_EXIT_t ( * start_base ) ( struct s_PXENV_START_BASE * );
00057 PXENV_EXIT_t ( * stop_base ) ( struct s_PXENV_STOP_BASE * );
00058 PXENV_EXIT_t ( * tftp_open ) ( struct s_PXENV_TFTP_OPEN * );
00059 PXENV_EXIT_t ( * tftp_close ) ( struct s_PXENV_TFTP_CLOSE * );
00060 PXENV_EXIT_t ( * tftp_read ) ( struct s_PXENV_TFTP_READ * );
00061 PXENV_EXIT_t ( * tftp_read_file ) ( struct s_PXENV_TFTP_READ_FILE * );
00062 PXENV_EXIT_t ( * tftp_get_fsize ) ( struct s_PXENV_TFTP_GET_FSIZE * );
00063 PXENV_EXIT_t ( * udp_open ) ( struct s_PXENV_UDP_OPEN * );
00064 PXENV_EXIT_t ( * udp_close ) ( struct s_PXENV_UDP_CLOSE * );
00065 PXENV_EXIT_t ( * udp_write ) ( struct s_PXENV_UDP_WRITE * );
00066 PXENV_EXIT_t ( * udp_read ) ( struct s_PXENV_UDP_READ * );
00067 PXENV_EXIT_t ( * undi_startup ) ( struct s_PXENV_UNDI_STARTUP * );
00068 PXENV_EXIT_t ( * undi_cleanup ) ( struct s_PXENV_UNDI_CLEANUP * );
00069 PXENV_EXIT_t ( * undi_initialize )
00070 ( struct s_PXENV_UNDI_INITIALIZE * );
00071 PXENV_EXIT_t ( * undi_reset_adapter ) ( struct s_PXENV_UNDI_RESET * );
00072 PXENV_EXIT_t ( * undi_shutdown ) ( struct s_PXENV_UNDI_SHUTDOWN * );
00073 PXENV_EXIT_t ( * undi_open ) ( struct s_PXENV_UNDI_OPEN * );
00074 PXENV_EXIT_t ( * undi_close ) ( struct s_PXENV_UNDI_CLOSE * );
00075 PXENV_EXIT_t ( * undi_transmit ) ( struct s_PXENV_UNDI_TRANSMIT * );
00076 PXENV_EXIT_t ( * undi_set_mcast_address )
00077 ( struct s_PXENV_UNDI_SET_MCAST_ADDRESS * );
00078 PXENV_EXIT_t ( * undi_set_station_address )
00079 ( struct s_PXENV_UNDI_SET_STATION_ADDRESS * );
00080 PXENV_EXIT_t ( * undi_set_packet_filter )
00081 ( struct s_PXENV_UNDI_SET_PACKET_FILTER * );
00082 PXENV_EXIT_t ( * undi_get_information )
00083 ( struct s_PXENV_UNDI_GET_INFORMATION * );
00084 PXENV_EXIT_t ( * undi_get_statistics )
00085 ( struct s_PXENV_UNDI_GET_STATISTICS * );
00086 PXENV_EXIT_t ( * undi_clear_statistics )
00087 ( struct s_PXENV_UNDI_CLEAR_STATISTICS * );
00088 PXENV_EXIT_t ( * undi_initiate_diags )
00089 ( struct s_PXENV_UNDI_INITIATE_DIAGS * );
00090 PXENV_EXIT_t ( * undi_force_interrupt )
00091 ( struct s_PXENV_UNDI_FORCE_INTERRUPT * );
00092 PXENV_EXIT_t ( * undi_get_mcast_address )
00093 ( struct s_PXENV_UNDI_GET_MCAST_ADDRESS * );
00094 PXENV_EXIT_t ( * undi_get_nic_type )
00095 ( struct s_PXENV_UNDI_GET_NIC_TYPE * );
00096 PXENV_EXIT_t ( * undi_get_iface_info )
00097 ( struct s_PXENV_UNDI_GET_IFACE_INFO * );
00098 PXENV_EXIT_t ( * undi_get_state ) ( struct s_PXENV_UNDI_GET_STATE * );
00099 PXENV_EXIT_t ( * undi_isr ) ( struct s_PXENV_UNDI_ISR * );
00100 PXENV_EXIT_t ( * file_open ) ( struct s_PXENV_FILE_OPEN * );
00101 PXENV_EXIT_t ( * file_close ) ( struct s_PXENV_FILE_CLOSE * );
00102 PXENV_EXIT_t ( * file_select ) ( struct s_PXENV_FILE_SELECT * );
00103 PXENV_EXIT_t ( * file_read ) ( struct s_PXENV_FILE_READ * );
00104 PXENV_EXIT_t ( * get_file_size ) ( struct s_PXENV_GET_FILE_SIZE * );
00105 PXENV_EXIT_t ( * file_exec ) ( struct s_PXENV_FILE_EXEC * );
00106 PXENV_EXIT_t ( * file_api_check ) ( struct s_PXENV_FILE_API_CHECK * );
00107 PXENV_EXIT_t ( * file_exit_hook ) ( struct s_PXENV_FILE_EXIT_HOOK * );
00108 };
00109
00110
00111
00112
00113
00114
00115
00116
00117 static PXENV_EXIT_t pxenv_unknown ( struct s_PXENV_UNKNOWN *pxenv_unknown ) {
00118 pxenv_unknown->Status = PXENV_STATUS_UNSUPPORTED;
00119 return PXENV_EXIT_FAILURE;
00120 }
00121
00122
00123
00124
00125
00126
00127
00128
00129 __asmcall void pxe_api_call ( struct i386_all_regs *ix86 ) {
00130 int opcode = ix86->regs.bx;
00131 userptr_t parameters = real_to_user ( ix86->segs.es, ix86->regs.di );
00132 size_t param_len;
00133 union u_PXENV_ANY pxenv_any;
00134 union pxenv_call pxenv_call;
00135 PXENV_EXIT_t ret;
00136
00137 switch ( opcode ) {
00138 case PXENV_UNLOAD_STACK:
00139 pxenv_call.unload_stack = pxenv_unload_stack;
00140 param_len = sizeof ( pxenv_any.unload_stack );
00141 break;
00142 case PXENV_GET_CACHED_INFO:
00143 pxenv_call.get_cached_info = pxenv_get_cached_info;
00144 param_len = sizeof ( pxenv_any.get_cached_info );
00145 break;
00146 case PXENV_RESTART_TFTP:
00147 pxenv_call.restart_tftp = pxenv_restart_tftp;
00148 param_len = sizeof ( pxenv_any.restart_tftp );
00149 break;
00150 case PXENV_START_UNDI:
00151 pxenv_call.start_undi = pxenv_start_undi;
00152 param_len = sizeof ( pxenv_any.start_undi );
00153 break;
00154 case PXENV_STOP_UNDI:
00155 pxenv_call.stop_undi = pxenv_stop_undi;
00156 param_len = sizeof ( pxenv_any.stop_undi );
00157 break;
00158 case PXENV_START_BASE:
00159 pxenv_call.start_base = pxenv_start_base;
00160 param_len = sizeof ( pxenv_any.start_base );
00161 break;
00162 case PXENV_STOP_BASE:
00163 pxenv_call.stop_base = pxenv_stop_base;
00164 param_len = sizeof ( pxenv_any.stop_base );
00165 break;
00166 case PXENV_TFTP_OPEN:
00167 pxenv_call.tftp_open = pxenv_tftp_open;
00168 param_len = sizeof ( pxenv_any.tftp_open );
00169 break;
00170 case PXENV_TFTP_CLOSE:
00171 pxenv_call.tftp_close = pxenv_tftp_close;
00172 param_len = sizeof ( pxenv_any.tftp_close );
00173 break;
00174 case PXENV_TFTP_READ:
00175 pxenv_call.tftp_read = pxenv_tftp_read;
00176 param_len = sizeof ( pxenv_any.tftp_read );
00177 break;
00178 case PXENV_TFTP_READ_FILE:
00179 pxenv_call.tftp_read_file = pxenv_tftp_read_file;
00180 param_len = sizeof ( pxenv_any.tftp_read_file );
00181 break;
00182 case PXENV_TFTP_GET_FSIZE:
00183 pxenv_call.tftp_get_fsize = pxenv_tftp_get_fsize;
00184 param_len = sizeof ( pxenv_any.tftp_get_fsize );
00185 break;
00186 case PXENV_UDP_OPEN:
00187 pxenv_call.udp_open = pxenv_udp_open;
00188 param_len = sizeof ( pxenv_any.udp_open );
00189 break;
00190 case PXENV_UDP_CLOSE:
00191 pxenv_call.udp_close = pxenv_udp_close;
00192 param_len = sizeof ( pxenv_any.udp_close );
00193 break;
00194 case PXENV_UDP_WRITE:
00195 pxenv_call.udp_write = pxenv_udp_write;
00196 param_len = sizeof ( pxenv_any.udp_write );
00197 break;
00198 case PXENV_UDP_READ:
00199 pxenv_call.udp_read = pxenv_udp_read;
00200 param_len = sizeof ( pxenv_any.udp_read );
00201 break;
00202 case PXENV_UNDI_STARTUP:
00203 pxenv_call.undi_startup = pxenv_undi_startup;
00204 param_len = sizeof ( pxenv_any.undi_startup );
00205 break;
00206 case PXENV_UNDI_CLEANUP:
00207 pxenv_call.undi_cleanup = pxenv_undi_cleanup;
00208 param_len = sizeof ( pxenv_any.undi_cleanup );
00209 break;
00210 case PXENV_UNDI_INITIALIZE:
00211 pxenv_call.undi_initialize = pxenv_undi_initialize;
00212 param_len = sizeof ( pxenv_any.undi_initialize );
00213 break;
00214 case PXENV_UNDI_RESET_ADAPTER:
00215 pxenv_call.undi_reset_adapter = pxenv_undi_reset_adapter;
00216 param_len = sizeof ( pxenv_any.undi_reset_adapter );
00217 break;
00218 case PXENV_UNDI_SHUTDOWN:
00219 pxenv_call.undi_shutdown = pxenv_undi_shutdown;
00220 param_len = sizeof ( pxenv_any.undi_shutdown );
00221 break;
00222 case PXENV_UNDI_OPEN:
00223 pxenv_call.undi_open = pxenv_undi_open;
00224 param_len = sizeof ( pxenv_any.undi_open );
00225 break;
00226 case PXENV_UNDI_CLOSE:
00227 pxenv_call.undi_close = pxenv_undi_close;
00228 param_len = sizeof ( pxenv_any.undi_close );
00229 break;
00230 case PXENV_UNDI_TRANSMIT:
00231 pxenv_call.undi_transmit = pxenv_undi_transmit;
00232 param_len = sizeof ( pxenv_any.undi_transmit );
00233 break;
00234 case PXENV_UNDI_SET_MCAST_ADDRESS:
00235 pxenv_call.undi_set_mcast_address =
00236 pxenv_undi_set_mcast_address;
00237 param_len = sizeof ( pxenv_any.undi_set_mcast_address );
00238 break;
00239 case PXENV_UNDI_SET_STATION_ADDRESS:
00240 pxenv_call.undi_set_station_address =
00241 pxenv_undi_set_station_address;
00242 param_len = sizeof ( pxenv_any.undi_set_station_address );
00243 break;
00244 case PXENV_UNDI_SET_PACKET_FILTER:
00245 pxenv_call.undi_set_packet_filter =
00246 pxenv_undi_set_packet_filter;
00247 param_len = sizeof ( pxenv_any.undi_set_packet_filter );
00248 break;
00249 case PXENV_UNDI_GET_INFORMATION:
00250 pxenv_call.undi_get_information = pxenv_undi_get_information;
00251 param_len = sizeof ( pxenv_any.undi_get_information );
00252 break;
00253 case PXENV_UNDI_GET_STATISTICS:
00254 pxenv_call.undi_get_statistics = pxenv_undi_get_statistics;
00255 param_len = sizeof ( pxenv_any.undi_get_statistics );
00256 break;
00257 case PXENV_UNDI_CLEAR_STATISTICS:
00258 pxenv_call.undi_clear_statistics = pxenv_undi_clear_statistics;
00259 param_len = sizeof ( pxenv_any.undi_clear_statistics );
00260 break;
00261 case PXENV_UNDI_INITIATE_DIAGS:
00262 pxenv_call.undi_initiate_diags = pxenv_undi_initiate_diags;
00263 param_len = sizeof ( pxenv_any.undi_initiate_diags );
00264 break;
00265 case PXENV_UNDI_FORCE_INTERRUPT:
00266 pxenv_call.undi_force_interrupt = pxenv_undi_force_interrupt;
00267 param_len = sizeof ( pxenv_any.undi_force_interrupt );
00268 break;
00269 case PXENV_UNDI_GET_MCAST_ADDRESS:
00270 pxenv_call.undi_get_mcast_address =
00271 pxenv_undi_get_mcast_address;
00272 param_len = sizeof ( pxenv_any.undi_get_mcast_address );
00273 break;
00274 case PXENV_UNDI_GET_NIC_TYPE:
00275 pxenv_call.undi_get_nic_type = pxenv_undi_get_nic_type;
00276 param_len = sizeof ( pxenv_any.undi_get_nic_type );
00277 break;
00278 case PXENV_UNDI_GET_IFACE_INFO:
00279 pxenv_call.undi_get_iface_info = pxenv_undi_get_iface_info;
00280 param_len = sizeof ( pxenv_any.undi_get_iface_info );
00281 break;
00282 case PXENV_UNDI_ISR:
00283 pxenv_call.undi_isr = pxenv_undi_isr;
00284 param_len = sizeof ( pxenv_any.undi_isr );
00285 break;
00286 case PXENV_FILE_OPEN:
00287 pxenv_call.file_open = pxenv_file_open;
00288 param_len = sizeof ( pxenv_any.file_open );
00289 break;
00290 case PXENV_FILE_CLOSE:
00291 pxenv_call.file_close = pxenv_file_close;
00292 param_len = sizeof ( pxenv_any.file_close );
00293 break;
00294 case PXENV_FILE_SELECT:
00295 pxenv_call.file_select = pxenv_file_select;
00296 param_len = sizeof ( pxenv_any.file_select );
00297 break;
00298 case PXENV_FILE_READ:
00299 pxenv_call.file_read = pxenv_file_read;
00300 param_len = sizeof ( pxenv_any.file_read );
00301 break;
00302 case PXENV_GET_FILE_SIZE:
00303 pxenv_call.get_file_size = pxenv_get_file_size;
00304 param_len = sizeof ( pxenv_any.get_file_size );
00305 break;
00306 case PXENV_FILE_EXEC:
00307 pxenv_call.file_exec = pxenv_file_exec;
00308 param_len = sizeof ( pxenv_any.file_exec );
00309 break;
00310 case PXENV_FILE_API_CHECK:
00311 pxenv_call.file_api_check = pxenv_file_api_check;
00312 param_len = sizeof ( pxenv_any.file_api_check );
00313 break;
00314 case PXENV_FILE_EXIT_HOOK:
00315 pxenv_call.file_exit_hook = pxenv_file_exit_hook;
00316 param_len = sizeof ( pxenv_any.file_exit_hook );
00317 break;
00318 default:
00319 DBG ( "PXENV_UNKNOWN_%hx", opcode );
00320 pxenv_call.unknown = pxenv_unknown;
00321 param_len = sizeof ( pxenv_any.unknown );
00322 break;
00323 }
00324
00325
00326 copy_from_user ( &pxenv_any, parameters, 0, param_len );
00327
00328
00329 pxenv_any.Status = PXENV_STATUS_FAILURE;
00330
00331
00332 DBG ( "[" );
00333 ret = pxenv_call.any ( &pxenv_any );
00334 if ( pxenv_any.Status != PXENV_STATUS_SUCCESS ) {
00335 DBG ( " %02x", pxenv_any.Status );
00336 }
00337 if ( ret != PXENV_EXIT_SUCCESS ) {
00338 DBG ( ret == PXENV_EXIT_FAILURE ? " err" : " ??" );
00339 }
00340 DBG ( "]" );
00341
00342
00343 copy_to_user ( parameters, 0, &pxenv_any, param_len );
00344 ix86->regs.ax = ret;
00345 }
00346
00347
00348
00349
00350
00351
00352
00353 int _pxe_api_call_weak ( struct i386_all_regs *ix86 )
00354 {
00355 pxe_api_call ( ix86 );
00356 return 0;
00357 }
00358
00359
00360
00361
00362
00363
00364
00365 __asmcall void pxe_loader_call ( struct i386_all_regs *ix86 ) {
00366 userptr_t uparams = real_to_user ( ix86->segs.es, ix86->regs.di );
00367 struct s_UNDI_LOADER params;
00368 PXENV_EXIT_t ret;
00369
00370
00371 copy_from_user ( ¶ms, uparams, 0, sizeof ( params ) );
00372
00373
00374 ppxe.UNDIROMID.segment = ix86->segs.ds;
00375
00376
00377 params.Status = PXENV_STATUS_FAILURE;
00378
00379
00380 ret = undi_loader ( ¶ms );
00381
00382
00383 copy_to_user ( uparams, 0, ¶ms, sizeof ( params ) );
00384 ix86->regs.ax = ret;
00385 }
00386
00387
00388
00389
00390
00391
00392
00393
00394 static uint8_t pxe_checksum ( void *data, size_t size ) {
00395 uint8_t *bytes = data;
00396 uint8_t sum = 0;
00397
00398 while ( size-- ) {
00399 sum += *bytes++;
00400 }
00401 return sum;
00402 }
00403
00404
00405
00406
00407
00408 static void pxe_init_structures ( void ) {
00409 uint32_t rm_cs_phys = ( rm_cs << 4 );
00410 uint32_t rm_ds_phys = ( rm_ds << 4 );
00411
00412
00413 ppxe.EntryPointSP.segment = rm_cs;
00414 ppxe.EntryPointESP.segment = rm_cs;
00415 ppxe.Stack.segment_address = rm_ds;
00416 ppxe.Stack.Physical_address = rm_ds_phys;
00417 ppxe.UNDIData.segment_address = rm_ds;
00418 ppxe.UNDIData.Physical_address = rm_ds_phys;
00419 ppxe.UNDICode.segment_address = rm_cs;
00420 ppxe.UNDICode.Physical_address = rm_cs_phys;
00421 ppxe.UNDICodeWrite.segment_address = rm_cs;
00422 ppxe.UNDICodeWrite.Physical_address = rm_cs_phys;
00423 pxenv.RMEntry.segment = rm_cs;
00424 pxenv.StackSeg = rm_ds;
00425 pxenv.UNDIDataSeg = rm_ds;
00426 pxenv.UNDICodeSeg = rm_cs;
00427 pxenv.PXEPtr.segment = rm_cs;
00428
00429
00430 ppxe.StructCksum -= pxe_checksum ( &ppxe, sizeof ( ppxe ) );
00431 pxenv.Checksum -= pxe_checksum ( &pxenv, sizeof ( pxenv ) );
00432 }
00433
00434
00435 struct init_fn pxe_init_fn __init_fn ( INIT_NORMAL ) = {
00436 .initialise = pxe_init_structures,
00437 };
00438
00439
00440
00441
00442
00443
00444 void pxe_activate ( struct net_device *netdev ) {
00445
00446
00447 if ( ! int_1a_hooked ) {
00448 hook_bios_interrupt ( 0x1a, ( unsigned int ) pxe_int_1a,
00449 &pxe_int_1a_vector );
00450 int_1a_hooked = 1;
00451 }
00452
00453
00454 pxe_set_netdev ( netdev );
00455 }
00456
00457
00458
00459
00460
00461
00462 int pxe_deactivate ( void ) {
00463 int rc;
00464
00465
00466 pxe_set_netdev ( NULL );
00467
00468
00469 if ( int_1a_hooked ) {
00470 if ( ( rc = unhook_bios_interrupt ( 0x1a,
00471 (unsigned int) pxe_int_1a,
00472 &pxe_int_1a_vector ))!= 0){
00473 DBG ( "Could not unhook INT 1A: %s\n",
00474 strerror ( rc ) );
00475 return rc;
00476 }
00477 int_1a_hooked = 0;
00478 }
00479
00480 return 0;
00481 }
00482
00483
00484
00485
00486
00487
00488 int pxe_start_nbp ( void ) {
00489 int discard_b, discard_c, discard_d, discard_D;
00490 uint16_t rc;
00491
00492
00493 __asm__ __volatile__ ( REAL_CODE ( "movw %%cx, %%es\n\t"
00494 "pushw %%es\n\t"
00495 "pushw %%di\n\t"
00496 "sti\n\t"
00497 "lcall $0, $0x7c00\n\t"
00498 "addw $4, %%sp\n\t" )
00499 : "=a" ( rc ), "=b" ( discard_b ),
00500 "=c" ( discard_c ), "=d" ( discard_d ),
00501 "=D" ( discard_D )
00502 : "a" ( 0 ), "b" ( __from_text16 ( &pxenv ) ),
00503 "c" ( rm_cs ),
00504 "d" ( virt_to_phys ( &pxenv ) ),
00505 "D" ( __from_text16 ( &ppxe ) )
00506 : "esi", "ebp", "memory" );
00507
00508 return rc;
00509 }