pxe_preboot.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
00020
00021
00022
00023
00024
00025
00026 FILE_LICENCE ( GPL2_OR_LATER );
00027
00028 #include <stdint.h>
00029 #include <string.h>
00030 #include <stdlib.h>
00031 #include <gpxe/uaccess.h>
00032 #include <gpxe/dhcp.h>
00033 #include <gpxe/fakedhcp.h>
00034 #include <gpxe/device.h>
00035 #include <gpxe/netdevice.h>
00036 #include <gpxe/isapnp.h>
00037 #include <gpxe/init.h>
00038 #include <gpxe/if_ether.h>
00039 #include <basemem_packet.h>
00040 #include <biosint.h>
00041 #include "pxe.h"
00042 #include "pxe_call.h"
00043
00044
00045 uint16_t isapnp_read_port;
00046
00047
00048 enum pxe_cached_info_indices {
00049 CACHED_INFO_DHCPDISCOVER = ( PXENV_PACKET_TYPE_DHCP_DISCOVER - 1 ),
00050 CACHED_INFO_DHCPACK = ( PXENV_PACKET_TYPE_DHCP_ACK - 1 ),
00051 CACHED_INFO_BINL = ( PXENV_PACKET_TYPE_CACHED_REPLY - 1 ),
00052 NUM_CACHED_INFOS
00053 };
00054
00055
00056 union pxe_cached_info {
00057 struct dhcphdr dhcphdr;
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068 BOOTPLAYER_t packet;
00069 } __attribute__ (( packed ));
00070
00071
00072 struct pxe_dhcp_packet_creator {
00073
00074
00075
00076
00077
00078
00079
00080 int ( * create ) ( struct net_device *netdev, void *data,
00081 size_t max_len );
00082 };
00083
00084
00085 static struct pxe_dhcp_packet_creator pxe_dhcp_packet_creators[] = {
00086 [CACHED_INFO_DHCPDISCOVER] = { create_fakedhcpdiscover },
00087 [CACHED_INFO_DHCPACK] = { create_fakedhcpack },
00088 [CACHED_INFO_BINL] = { create_fakepxebsack },
00089 };
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102 static union pxe_cached_info __bss16_array ( cached_info, [NUM_CACHED_INFOS] );
00103 #define cached_info __use_data16 ( cached_info )
00104
00105
00106
00107
00108
00109
00110
00111
00112 PXENV_EXIT_t pxenv_unload_stack ( struct s_PXENV_UNLOAD_STACK *unload_stack ) {
00113 DBG ( "PXENV_UNLOAD_STACK" );
00114
00115 unload_stack->Status = PXENV_STATUS_SUCCESS;
00116 return PXENV_EXIT_SUCCESS;
00117 }
00118
00119
00120
00121
00122
00123 PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO
00124 *get_cached_info ) {
00125 struct pxe_dhcp_packet_creator *creator;
00126 union pxe_cached_info *info;
00127 unsigned int idx;
00128 size_t len;
00129 userptr_t buffer;
00130 int rc;
00131
00132 DBG ( "PXENV_GET_CACHED_INFO %d", get_cached_info->PacketType );
00133
00134 DBG ( " to %04x:%04x+%x", get_cached_info->Buffer.segment,
00135 get_cached_info->Buffer.offset, get_cached_info->BufferSize );
00136
00137
00138 idx = ( get_cached_info->PacketType - 1 );
00139 if ( idx >= NUM_CACHED_INFOS ) {
00140 DBG ( " bad PacketType" );
00141 goto err;
00142 }
00143 info = &cached_info[idx];
00144
00145
00146 if ( ! info->dhcphdr.op ) {
00147
00148 creator = &pxe_dhcp_packet_creators[idx];
00149 if ( ( rc = creator->create ( pxe_netdev, info,
00150 sizeof ( *info ) ) ) != 0 ) {
00151 DBG ( " failed to build packet" );
00152 goto err;
00153 }
00154 }
00155
00156 len = get_cached_info->BufferSize;
00157 if ( len == 0 ) {
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183 get_cached_info->Buffer.segment = rm_ds;
00184 get_cached_info->Buffer.offset = __from_data16 ( info );
00185 get_cached_info->BufferSize = sizeof ( *info );
00186 DBG ( " returning %04x:%04x+%04x['%x']",
00187 get_cached_info->Buffer.segment,
00188 get_cached_info->Buffer.offset,
00189 get_cached_info->BufferSize,
00190 get_cached_info->BufferLimit );
00191 } else {
00192
00193 if ( len > sizeof ( *info ) )
00194 len = sizeof ( *info );
00195 if ( len < sizeof ( *info ) )
00196 DBG ( " buffer may be too short" );
00197 buffer = real_to_user ( get_cached_info->Buffer.segment,
00198 get_cached_info->Buffer.offset );
00199 copy_to_user ( buffer, 0, info, len );
00200 get_cached_info->BufferSize = len;
00201 }
00202
00203 get_cached_info->Status = PXENV_STATUS_SUCCESS;
00204 return PXENV_EXIT_SUCCESS;
00205
00206 err:
00207 get_cached_info->Status = PXENV_STATUS_OUT_OF_RESOURCES;
00208 return PXENV_EXIT_FAILURE;
00209 }
00210
00211
00212
00213
00214
00215 PXENV_EXIT_t pxenv_restart_tftp ( struct s_PXENV_TFTP_READ_FILE
00216 *restart_tftp ) {
00217 PXENV_EXIT_t tftp_exit;
00218
00219 DBG ( "PXENV_RESTART_TFTP " );
00220
00221
00222
00223
00224 restart_tftp->Buffer = PXE_LOAD_PHYS;
00225 restart_tftp->BufferSize = ( 0xa0000 - PXE_LOAD_PHYS );
00226 tftp_exit = pxenv_tftp_read_file ( restart_tftp );
00227 if ( tftp_exit != PXENV_EXIT_SUCCESS )
00228 return tftp_exit;
00229
00230
00231 restart_tftp->Status = pxe_start_nbp();
00232
00233
00234
00235
00236 return PXENV_EXIT_SUCCESS;
00237 }
00238
00239
00240
00241
00242
00243 PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi ) {
00244 unsigned int bus_type;
00245 unsigned int location;
00246 struct net_device *netdev;
00247
00248 DBG ( "PXENV_START_UNDI %04x:%04x:%04x",
00249 start_undi->AX, start_undi->BX, start_undi->DX );
00250
00251
00252
00253
00254 if ( ( start_undi->DX >= ISAPNP_READ_PORT_MIN ) &&
00255 ( start_undi->DX <= ISAPNP_READ_PORT_MAX ) &&
00256 ( start_undi->BX >= ISAPNP_CSN_MIN ) &&
00257 ( start_undi->BX <= ISAPNP_CSN_MAX ) ) {
00258 bus_type = BUS_TYPE_ISAPNP;
00259 location = start_undi->BX;
00260
00261 isapnp_read_port = start_undi->DX;
00262 } else {
00263 bus_type = BUS_TYPE_PCI;
00264 location = start_undi->AX;
00265 }
00266
00267
00268 startup();
00269
00270
00271 netdev = find_netdev_by_location ( bus_type, location );
00272 if ( ! netdev ) {
00273 DBG ( " no net device found" );
00274 start_undi->Status = PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC;
00275 return PXENV_EXIT_FAILURE;
00276 }
00277 DBG ( " using netdev %s", netdev->name );
00278
00279
00280 pxe_activate ( netdev );
00281
00282 start_undi->Status = PXENV_STATUS_SUCCESS;
00283 return PXENV_EXIT_SUCCESS;
00284 }
00285
00286
00287
00288
00289
00290 PXENV_EXIT_t pxenv_stop_undi ( struct s_PXENV_STOP_UNDI *stop_undi ) {
00291 DBG ( "PXENV_STOP_UNDI" );
00292
00293
00294 pxe_deactivate();
00295
00296
00297 shutdown ( SHUTDOWN_BOOT );
00298
00299
00300 if ( hooked_bios_interrupts != 0 ) {
00301 DBG ( "PXENV_STOP_UNDI failed: %d interrupts still hooked\n",
00302 hooked_bios_interrupts );
00303 stop_undi->Status = PXENV_STATUS_KEEP_UNDI;
00304 return PXENV_EXIT_FAILURE;
00305 }
00306
00307 stop_undi->Status = PXENV_STATUS_SUCCESS;
00308 return PXENV_EXIT_SUCCESS;
00309 }
00310
00311
00312
00313
00314
00315 PXENV_EXIT_t pxenv_start_base ( struct s_PXENV_START_BASE *start_base ) {
00316 DBG ( "PXENV_START_BASE" );
00317
00318 start_base->Status = PXENV_STATUS_UNSUPPORTED;
00319 return PXENV_EXIT_FAILURE;
00320 }
00321
00322
00323
00324
00325
00326 PXENV_EXIT_t pxenv_stop_base ( struct s_PXENV_STOP_BASE *stop_base ) {
00327 DBG ( "PXENV_STOP_BASE" );
00328
00329
00330
00331
00332
00333
00334 stop_base->Status = PXENV_STATUS_SUCCESS;
00335 return PXENV_EXIT_SUCCESS;
00336 }