iPXE
pxe_preboot.c
Go to the documentation of this file.
1/** @file
2 *
3 * PXE Preboot API
4 *
5 */
6
7/* PXE API interface for Etherboot.
8 *
9 * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation; either version 2 of the
14 * License, or any later version.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 * 02110-1301, USA.
25 *
26 * You can also choose to distribute this program under the terms of
27 * the Unmodified Binary Distribution Licence (as given in the file
28 * COPYING.UBDL), provided that you have satisfied its requirements.
29 */
30
31FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
32
33#include <stdint.h>
34#include <string.h>
35#include <stdlib.h>
36#include <ipxe/dhcp.h>
37#include <ipxe/fakedhcp.h>
38#include <ipxe/device.h>
39#include <ipxe/netdevice.h>
40#include <ipxe/isapnp.h>
41#include <ipxe/init.h>
42#include <ipxe/if_ether.h>
43#include <basemem_packet.h>
44#include <biosint.h>
45#include <rmsetjmp.h>
46#include "pxe.h"
47#include "pxe_call.h"
48
49/* Avoid dragging in isapnp.o unnecessarily */
51
52/** Zero-based versions of PXENV_GET_CACHED_INFO::PacketType */
59
60/** A cached DHCP packet */
63 /* This buffer must be *exactly* the size of a BOOTPLAYER_t
64 * structure, otherwise WinPE will die horribly. It takes the
65 * size of *our* buffer and feeds it in to us as the size of
66 * one of *its* buffers. If our buffer is larger than it
67 * expects, we therefore end up overwriting part of its data
68 * segment, since it tells us to do so. (D'oh!)
69 *
70 * Note that a BOOTPLAYER_t is not necessarily large enough to
71 * hold a DHCP packet; this is a flaw in the PXE spec.
72 */
74} __attribute__ (( packed ));
75
76/** A PXE DHCP packet creator */
78 /** Create DHCP packet
79 *
80 * @v netdev Network device
81 * @v data Buffer for DHCP packet
82 * @v max_len Size of DHCP packet buffer
83 * @ret rc Return status code
84 */
85 int ( * create ) ( struct net_device *netdev, void *data,
86 size_t max_len );
87};
88
89/** PXE DHCP packet creators */
95
96/**
97 * Name PXENV_GET_CACHED_INFO packet type
98 *
99 * @v packet_type Packet type
100 * @ret name Name of packet type
101 */
102static inline __attribute__ (( always_inline )) const char *
103pxenv_get_cached_info_name ( int packet_type ) {
104 switch ( packet_type ) {
106 return "DHCPDISCOVER";
108 return "DHCPACK";
110 return "BINL";
111 default:
112 return "<INVALID>";
113 }
114}
115
116/* The case in which the caller doesn't supply a buffer is really
117 * awkward to support given that we have multiple sources of options,
118 * and that we don't actually store the DHCP packets. (We may not
119 * even have performed DHCP; we may have obtained all configuration
120 * from non-volatile stored options or from the command line.)
121 *
122 * Some NBPs rely on the buffers we provide being persistent, so we
123 * can't just use the temporary packet buffer. 4.5kB of base memory
124 * always wasted just because some clients are too lazy to provide
125 * their own buffers...
126 */
128#define cached_info __use_data16 ( cached_info )
129
130/**
131 * Construct cached DHCP packets
132 *
133 */
134void pxe_fake_cached_info ( void ) {
135 struct pxe_dhcp_packet_creator *creator;
136 union pxe_cached_info *info;
137 unsigned int i;
138 int rc;
139
140 /* Sanity check */
141 assert ( pxe_netdev != NULL );
142
143 /* Erase any stale packets */
144 memset ( cached_info, 0, sizeof ( cached_info ) );
145
146 /* Construct all DHCP packets */
147 for ( i = 0 ; i < ( sizeof ( pxe_dhcp_packet_creators ) /
148 sizeof ( pxe_dhcp_packet_creators[0] ) ) ; i++ ) {
149
150 /* Construct DHCP packet */
151 creator = &pxe_dhcp_packet_creators[i];
152 info = &cached_info[i];
153 if ( ( rc = creator->create ( pxe_netdev, info,
154 sizeof ( *info ) ) ) != 0 ) {
155 DBGC ( &pxe_netdev, " failed to build packet: %s\n",
156 strerror ( rc ) );
157 /* Continue constructing remaining packets */
158 }
159 }
160}
161
162/**
163 * UNLOAD BASE CODE STACK
164 *
165 * @v None -
166 * @ret ...
167 *
168 */
169static PXENV_EXIT_t
170pxenv_unload_stack ( struct s_PXENV_UNLOAD_STACK *unload_stack ) {
171 DBGC ( &pxe_netdev, "PXENV_UNLOAD_STACK\n" );
172
173 unload_stack->Status = PXENV_STATUS_SUCCESS;
174 return PXENV_EXIT_SUCCESS;
175}
176
177/* PXENV_GET_CACHED_INFO
178 *
179 * Status: working
180 */
181static PXENV_EXIT_t
183 union pxe_cached_info *info;
184 unsigned int idx;
185 size_t len;
186 void *buffer;
187
188 DBGC ( &pxe_netdev, "PXENV_GET_CACHED_INFO %s to %04x:%04x+%x",
189 pxenv_get_cached_info_name ( get_cached_info->PacketType ),
190 get_cached_info->Buffer.segment,
191 get_cached_info->Buffer.offset, get_cached_info->BufferSize );
192
193 /* Sanity check */
194 idx = ( get_cached_info->PacketType - 1 );
195 if ( idx >= NUM_CACHED_INFOS ) {
196 DBGC ( &pxe_netdev, " bad PacketType %d\n",
197 get_cached_info->PacketType );
198 get_cached_info->Status = PXENV_STATUS_UNSUPPORTED;
199 return PXENV_EXIT_FAILURE;
200 }
201 info = &cached_info[idx];
202
203 /* Copy packet (if applicable) */
204 len = get_cached_info->BufferSize;
205 if ( len == 0 ) {
206 /* Point client at our cached buffer.
207 *
208 * To add to the fun, Intel decided at some point in
209 * the evolution of the PXE specification to add the
210 * BufferLimit field, which we are meant to fill in
211 * with the length of our packet buffer, so that the
212 * caller can safely modify the boot server reply
213 * packet stored therein. However, this field was not
214 * present in earlier versions of the PXE spec, and
215 * there is at least one PXE NBP (Altiris) which
216 * allocates only exactly enough space for this
217 * earlier, shorter version of the structure. If we
218 * actually fill in the BufferLimit field, we
219 * therefore risk trashing random areas of the
220 * caller's memory. If we *don't* fill it in, then
221 * the caller is at liberty to assume that whatever
222 * random value happened to be in that location
223 * represents the length of the buffer we've just
224 * passed back to it.
225 *
226 * Since older PXE stacks won't fill this field in
227 * anyway, it's probably safe to assume that no
228 * callers actually rely on it, so we choose to not
229 * fill it in.
230 */
231 get_cached_info->Buffer.segment = rm_ds;
232 get_cached_info->Buffer.offset = __from_data16 ( info );
233 get_cached_info->BufferSize = sizeof ( *info );
234 DBGC ( &pxe_netdev, " using %04x:%04x+%04x['%x']",
235 get_cached_info->Buffer.segment,
236 get_cached_info->Buffer.offset,
237 get_cached_info->BufferSize,
238 get_cached_info->BufferLimit );
239 } else {
240 /* Copy packet to client buffer */
241 if ( len > sizeof ( *info ) )
242 len = sizeof ( *info );
243 if ( len < sizeof ( *info ) )
244 DBGC ( &pxe_netdev, " buffer may be too short" );
245 buffer = real_to_virt ( get_cached_info->Buffer.segment,
246 get_cached_info->Buffer.offset );
247 memcpy ( buffer, info, len );
248 get_cached_info->BufferSize = len;
249 }
250
251 DBGC ( &pxe_netdev, "\n" );
252 get_cached_info->Status = PXENV_STATUS_SUCCESS;
253 return PXENV_EXIT_SUCCESS;
254}
255
256/* PXENV_RESTART_TFTP
257 *
258 * Status: working
259 */
260static PXENV_EXIT_t
262 PXENV_EXIT_t tftp_exit;
263
264 DBGC ( &pxe_netdev, "PXENV_RESTART_TFTP\n" );
265
266 /* Words cannot describe the complete mismatch between the PXE
267 * specification and any possible version of reality...
268 */
269 restart_tftp->Buffer = PXE_LOAD_PHYS; /* Fixed by spec, apparently */
270 restart_tftp->BufferSize = ( 0xa0000 - PXE_LOAD_PHYS ); /* Near enough */
271 tftp_exit = pxenv_tftp_read_file ( restart_tftp );
272 if ( tftp_exit != PXENV_EXIT_SUCCESS )
273 return tftp_exit;
274
275 /* Restart NBP */
277}
278
279/* PXENV_START_UNDI
280 *
281 * Status: working
282 */
283static PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi ) {
284 unsigned int bus_type;
285 unsigned int location;
286 struct net_device *netdev;
287
288 DBGC ( &pxe_netdev, "PXENV_START_UNDI %04x:%04x:%04x\n",
289 start_undi->AX, start_undi->BX, start_undi->DX );
290
291 /* Determine bus type and location. Use a heuristic to decide
292 * whether we are PCI or ISAPnP
293 */
294 if ( ( start_undi->DX >= ISAPNP_READ_PORT_MIN ) &&
295 ( start_undi->DX <= ISAPNP_READ_PORT_MAX ) &&
296 ( start_undi->BX >= ISAPNP_CSN_MIN ) &&
297 ( start_undi->BX <= ISAPNP_CSN_MAX ) ) {
298 bus_type = BUS_TYPE_ISAPNP;
299 location = start_undi->BX;
300 /* Record ISAPnP read port for use by isapnp.c */
301 isapnp_read_port = start_undi->DX;
302 } else {
303 bus_type = BUS_TYPE_PCI;
304 location = start_undi->AX;
305 }
306
307 /* Probe for devices, etc. */
308 startup();
309
310 /* Look for a matching net device */
311 netdev = find_netdev_by_location ( bus_type, location );
312 if ( ! netdev ) {
313 DBGC ( &pxe_netdev, "PXENV_START_UNDI could not find matching "
314 "net device\n" );
316 return PXENV_EXIT_FAILURE;
317 }
318 DBGC ( &pxe_netdev, "PXENV_START_UNDI found net device %s\n",
319 netdev->name );
320
321 /* Activate PXE */
323
324 start_undi->Status = PXENV_STATUS_SUCCESS;
325 return PXENV_EXIT_SUCCESS;
326}
327
328/* PXENV_STOP_UNDI
329 *
330 * Status: working
331 */
332static PXENV_EXIT_t pxenv_stop_undi ( struct s_PXENV_STOP_UNDI *stop_undi ) {
333 DBGC ( &pxe_netdev, "PXENV_STOP_UNDI\n" );
334
335 /* Deactivate PXE */
337
338 /* Prepare for unload */
340
341 /* Check to see if we still have any hooked interrupts */
342 if ( hooked_bios_interrupts != 0 ) {
343 DBGC ( &pxe_netdev, "PXENV_STOP_UNDI failed: %d interrupts "
344 "still hooked\n", hooked_bios_interrupts );
345 stop_undi->Status = PXENV_STATUS_KEEP_UNDI;
346 return PXENV_EXIT_FAILURE;
347 }
348
349 stop_undi->Status = PXENV_STATUS_SUCCESS;
350 return PXENV_EXIT_SUCCESS;
351}
352
353/* PXENV_START_BASE
354 *
355 * Status: won't implement (requires major structural changes)
356 */
357static PXENV_EXIT_t pxenv_start_base ( struct s_PXENV_START_BASE *start_base ) {
358 DBGC ( &pxe_netdev, "PXENV_START_BASE\n" );
359
360 start_base->Status = PXENV_STATUS_UNSUPPORTED;
361 return PXENV_EXIT_FAILURE;
362}
363
364/* PXENV_STOP_BASE
365 *
366 * Status: working
367 */
368static PXENV_EXIT_t pxenv_stop_base ( struct s_PXENV_STOP_BASE *stop_base ) {
369 DBGC ( &pxe_netdev, "PXENV_STOP_BASE\n" );
370
371 /* The only time we will be called is when the NBP is trying
372 * to shut down the PXE stack. There's nothing we need to do
373 * in this call.
374 */
375
376 stop_base->Status = PXENV_STATUS_SUCCESS;
377 return PXENV_EXIT_SUCCESS;
378}
379
380/** PXE preboot API */
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
u32 info
Definition ar9003_mac.h:0
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned short uint16_t
Definition stdint.h:11
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
#define hooked_bios_interrupts
Definition biosint.h:25
Device model.
#define BUS_TYPE_PCI
PCI bus type.
Definition device.h:44
#define BUS_TYPE_ISAPNP
ISAPnP bus type.
Definition device.h:47
ring len
Length.
Definition dwmac.h:226
uint8_t data[48]
Additional event data.
Definition ena.h:11
int create_fakedhcpdiscover(struct net_device *netdev, void *data, size_t max_len)
Create fake DHCPDISCOVER packet.
Definition fakedhcp.c:110
int create_fakepxebsack(struct net_device *netdev, void *data, size_t max_len)
Create fake PXE Boot Server ACK packet.
Definition fakedhcp.c:179
int create_fakedhcpack(struct net_device *netdev, void *data, size_t max_len)
Create fake DHCPACK packet.
Definition fakedhcp.c:137
Fake DHCP packets.
static struct net_device * netdev
Definition gdbudp.c:53
#define DBGC(...)
Definition compiler.h:505
uint32_t buffer
Buffer index (or NETVSC_RNDIS_NO_BUFFER)
Definition netvsc.h:5
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define PXENV_EXIT_FAILURE
An error occurred.
Definition pxe_types.h:46
#define PXENV_EXIT_SUCCESS
No error occurred.
Definition pxe_types.h:45
UINT16_t PXENV_EXIT_t
A PXE exit code.
Definition pxe_types.h:44
#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC
Definition pxe_error.h:74
#define PXENV_STATUS_UNSUPPORTED
Definition pxe_error.h:22
#define PXENV_STATUS_SUCCESS
Definition pxe_error.h:19
#define PXENV_STATUS_KEEP_UNDI
Definition pxe_error.h:23
struct bootph BOOTPLAYER_t
Definition pxe_api.h:406
#define PXENV_PACKET_TYPE_CACHED_REPLY
The Boot Server's Discover Reply packet.
Definition pxe_api.h:283
#define PXENV_PACKET_TYPE_DHCP_DISCOVER
The client's DHCPDISCOVER packet.
Definition pxe_api.h:273
#define PXENV_GET_CACHED_INFO
PXE API function code for pxenv_get_cached_info()
Definition pxe_api.h:270
#define PXENV_PACKET_TYPE_DHCP_ACK
The DHCP server's DHCPACK packet.
Definition pxe_api.h:276
#define PXENV_RESTART_TFTP
PXE API function code for pxenv_restart_tftp()
Definition pxe_api.h:418
#define PXENV_START_BASE
PXE API function code for pxenv_start_base()
Definition pxe_api.h:524
#define PXENV_START_UNDI
PXE API function code for pxenv_start_undi()
Definition pxe_api.h:435
#define PXENV_STOP_BASE
PXE API function code for pxenv_stop_base()
Definition pxe_api.h:543
#define PXENV_STOP_UNDI
PXE API function code for pxenv_stop_undi()
Definition pxe_api.h:505
#define PXENV_UNLOAD_STACK
PXE API function code for pxenv_unload_stack()
Definition pxe_api.h:250
#define __attribute__(x)
Definition compiler.h:10
Dynamic Host Configuration Protocol.
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void * memset(void *dest, int character, size_t len) __nonnull
void startup(void)
Start up iPXE.
Definition init.c:70
static void shutdown_boot(void)
Shut down system for OS boot.
Definition init.h:78
uint16_t isapnp_read_port
ISAPnP Read Port address.
Definition isapnp.c:76
#define ISAPNP_CSN_MIN
Definition isapnp.h:65
#define ISAPNP_CSN_MAX
Definition isapnp.h:66
#define ISAPNP_READ_PORT_MAX
Definition isapnp.h:61
#define ISAPNP_READ_PORT_MIN
Definition isapnp.h:59
#define rm_ds
Definition libkir.h:39
#define __from_data16(pointer)
Definition libkir.h:22
#define __bss16_array(variable, array)
Definition libkir.h:17
struct net_device * find_netdev_by_location(unsigned int bus_type, unsigned int location)
Get network device by PCI bus:dev.fn address.
Definition netdevice.c:1030
Network device management.
#define PXE_API_CALL(_opcode, _entry, _params_type)
Define a PXE API call.
Definition pxe.h:106
#define __pxe_api_call
Declare a PXE API call.
Definition pxe.h:96
rmjmp_buf pxe_restart_nbp
Jump buffer for PXENV_RESTART_TFTP.
Definition pxe_call.c:323
void pxe_activate(struct net_device *netdev)
Activate PXE stack.
Definition pxe_call.c:269
int pxe_deactivate(void)
Deactivate PXE stack.
Definition pxe_call.c:300
PXE API entry point.
#define PXE_LOAD_PHYS
PXE physical load address.
Definition pxe_call.h:24
static const char * pxenv_get_cached_info_name(int packet_type)
Name PXENV_GET_CACHED_INFO packet type.
#define cached_info
static PXENV_EXIT_t pxenv_start_base(struct s_PXENV_START_BASE *start_base)
static struct pxe_dhcp_packet_creator pxe_dhcp_packet_creators[]
PXE DHCP packet creators.
Definition pxe_preboot.c:90
static PXENV_EXIT_t pxenv_stop_base(struct s_PXENV_STOP_BASE *stop_base)
static PXENV_EXIT_t pxenv_stop_undi(struct s_PXENV_STOP_UNDI *stop_undi)
static PXENV_EXIT_t pxenv_restart_tftp(struct s_PXENV_TFTP_READ_FILE *restart_tftp)
static PXENV_EXIT_t pxenv_get_cached_info(struct s_PXENV_GET_CACHED_INFO *get_cached_info)
static PXENV_EXIT_t pxenv_unload_stack(struct s_PXENV_UNLOAD_STACK *unload_stack)
UNLOAD BASE CODE STACK.
static PXENV_EXIT_t pxenv_start_undi(struct s_PXENV_START_UNDI *start_undi)
pxe_cached_info_indices
Zero-based versions of PXENV_GET_CACHED_INFO::PacketType.
Definition pxe_preboot.c:53
@ CACHED_INFO_DHCPDISCOVER
Definition pxe_preboot.c:54
@ CACHED_INFO_DHCPACK
Definition pxe_preboot.c:55
@ NUM_CACHED_INFOS
Definition pxe_preboot.c:57
@ CACHED_INFO_BINL
Definition pxe_preboot.c:56
void pxe_fake_cached_info(void)
Construct cached DHCP packets.
PXENV_EXIT_t pxenv_tftp_read_file(struct s_PXENV_TFTP_READ_FILE *tftp_read_file)
TFTP/MTFTP read file.
Definition pxe_tftp.c:478
struct net_device * pxe_netdev
Definition pxe_undi.c:59
static __always_inline void * real_to_virt(unsigned int segment, unsigned int offset)
Convert segment:offset address to virtual address.
Definition realmode.h:77
#define rmlongjmp(_env, _val)
Definition rmsetjmp.h:22
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
A network device.
Definition netdevice.h:353
A PXE API call.
Definition pxe.h:81
A PXE DHCP packet creator.
Definition pxe_preboot.c:77
int(* create)(struct net_device *netdev, void *data, size_t max_len)
Create DHCP packet.
Definition pxe_preboot.c:85
Parameter block for pxenv_get_cached_info()
Definition pxe_api.h:286
SEGOFF16_t Buffer
Buffer address.
Definition pxe_api.h:295
UINT16_t BufferLimit
Maximum buffer size.
Definition pxe_api.h:296
UINT16_t BufferSize
Buffer size.
Definition pxe_api.h:294
UINT16_t PacketType
Packet type.
Definition pxe_api.h:293
PXENV_STATUS_t Status
PXE status code.
Definition pxe_api.h:287
Parameter block for pxenv_start_base()
Definition pxe_api.h:527
PXENV_STATUS_t Status
PXE status code.
Definition pxe_api.h:528
Parameter block for pxenv_start_undi()
Definition pxe_api.h:438
PXENV_STATUS_t Status
PXE status code.
Definition pxe_api.h:439
UINT16_t DX
dx register as passed to the Option ROM initialisation routine.
Definition pxe_api.h:462
UINT16_t BX
bx register as passed to the Option ROM initialisation routine.
Definition pxe_api.h:453
UINT16_t AX
ax register as passed to the Option ROM initialisation routine.
Definition pxe_api.h:446
Parameter block for pxenv_stop_base()
Definition pxe_api.h:546
PXENV_STATUS_t Status
PXE status code.
Definition pxe_api.h:547
Parameter block for pxenv_stop_undi()
Definition pxe_api.h:508
PXENV_STATUS_t Status
PXE status code.
Definition pxe_api.h:509
Parameter block for pxenv_tftp_read_file()
Definition pxe_api.h:645
ADDR32_t Buffer
Address of data buffer.
Definition pxe_api.h:649
UINT32_t BufferSize
Size of data buffer.
Definition pxe_api.h:648
Parameter block for pxenv_unload_stack()
Definition pxe_api.h:253
PXENV_STATUS_t Status
PXE status code.
Definition pxe_api.h:254
A cached DHCP packet.
Definition pxe_preboot.c:61
BOOTPLAYER_t packet
Definition pxe_preboot.c:73
struct dhcphdr dhcphdr
Definition pxe_preboot.c:62