Просмотр исходного кода

Split PXE code into preboot, udp, tftp, undi and loader units.

PXE code now compiles without errors (though it won't actually work).
tags/v0.9.3
Michael Brown 19 лет назад
Родитель
Сommit
809933d9f7

+ 0
- 1
src/arch/i386/image/pxe_image.c Просмотреть файл

@@ -13,7 +13,6 @@
13 13
 
14 14
 #include "etherboot.h"
15 15
 #include "pxe_callbacks.h"
16
-#include "pxe_export.h"
17 16
 #include "pxe.h"
18 17
 
19 18
 unsigned long pxe_load_offset;

+ 0
- 18
src/arch/i386/include/pxe_addr.h Просмотреть файл

@@ -8,28 +8,10 @@
8 8
 #ifndef PXE_ADDR_H
9 9
 #define PXE_ADDR_H
10 10
 
11
-/* SEGOFF16_t defined in separate header
12
- */
13
-#include "realmode.h"
14
-typedef segoff_t I386_SEGOFF16_t;
15
-#define SEGOFF16_t I386_SEGOFF16_t
16
-
17 11
 #define IS_NULL_SEGOFF16(x) ( ( (x).segment == 0 ) && ( (x).offset == 0 ) )
18 12
 #define SEGOFF16_TO_PTR(x) ( VIRTUAL( (x).segment, (x).offset ) )
19 13
 #define PTR_TO_SEGOFF16(ptr,segoff16) \
20 14
 	(segoff16).segment = SEGMENT(ptr); \
21 15
 	(segoff16).offset  = OFFSET(ptr);
22 16
 
23
-typedef struct {
24
-	uint16_t		Seg_Addr;
25
-	uint32_t		Phy_Addr;
26
-	uint16_t		Seg_Size;
27
-} PACKED I386_SEGDESC_t;  /* PACKED is required, otherwise gcc pads
28
-			  * this out to 12 bytes -
29
-			  * mbrown@fensystems.co.uk (mcb30) 17/5/03 */
30
-#define SEGDESC_t I386_SEGDESC_t
31
-
32
-typedef	uint16_t I386_SEGSEL_t;
33
-#define SEGSEL_t I386_SEGSEL_t
34
-
35 17
 #endif /* PXE_ADDR_H */

+ 5
- 5
src/arch/i386/include/pxe_callbacks.h Просмотреть файл

@@ -5,12 +5,12 @@
5 5
 #define PXE_CALLBACKS_H
6 6
 
7 7
 #include "etherboot.h"
8
-#include "pxe.h"
8
+#include "pxe_types.h"
9 9
 
10 10
 typedef struct {
11
-	segoff_t	orig_retaddr;
12
-	uint16_t	opcode;
13
-	segoff_t	segoff;
11
+	SEGOFF16_t	orig_retaddr;
12
+	UINT16_t	opcode;
13
+	SEGOFF16_t	segoff;
14 14
 } PACKED pxe_call_params_t;
15 15
 
16 16
 /*
@@ -22,7 +22,7 @@ typedef struct {
22 22
 
23 23
 /* Function prototypes
24 24
  */
25
-extern pxe_stack_t * install_pxe_stack ( void *base );
25
+extern struct pxe_stack * install_pxe_stack ( void *base );
26 26
 extern void use_undi_ds_for_rm_stack ( uint16_t ds );
27 27
 extern int hook_pxe_stack ( void );
28 28
 extern int unhook_pxe_stack ( void );

+ 0
- 1445
src/core/pxe.c
Разница между файлами не показана из-за своего большого размера
Просмотреть файл


+ 21
- 6
src/include/pxe.h Просмотреть файл

@@ -3,6 +3,7 @@
3 3
 
4 4
 #include "pxe_types.h"
5 5
 #include "pxe_api.h"
6
+#include "etherboot.h"
6 7
 
7 8
 /* Union used for PXE API calls; we don't know the type of the
8 9
  * structure until we interpret the opcode.  Also, Status is available
@@ -14,7 +15,7 @@ union u_PXENV_ANY {
14 15
 	PXENV_STATUS_t				Status;
15 16
 	struct s_PXENV_UNLOAD_STACK		unload_stack;
16 17
 	struct s_PXENV_GET_CACHED_INFO		get_cached_info;
17
-	struct s_PXENV_RESTART_TFTP		restart_tftp;
18
+	struct s_PXENV_TFTP_READ_FILE		restart_tftp;
18 19
 	struct s_PXENV_START_UNDI		start_undi;
19 20
 	struct s_PXENV_STOP_UNDI		stop_undi;
20 21
 	struct s_PXENV_START_BASE		start_base;
@@ -31,7 +32,7 @@ union u_PXENV_ANY {
31 32
 	struct s_PXENV_UNDI_STARTUP		undi_startup;
32 33
 	struct s_PXENV_UNDI_CLEANUP		undi_cleanup;
33 34
 	struct s_PXENV_UNDI_INITIALIZE		undi_initialize;
34
-	struct s_PXENV_UNDI_RESET_ADAPTER	undi_reset_adapter;
35
+	struct s_PXENV_UNDI_RESET		undi_reset_adapter;
35 36
 	struct s_PXENV_UNDI_SHUTDOWN		undi_shutdown;
36 37
 	struct s_PXENV_UNDI_OPEN		undi_open;
37 38
 	struct s_PXENV_UNDI_CLOSE		undi_close;
@@ -62,16 +63,26 @@ typedef enum {
62 63
 	READY
63 64
 } pxe_stack_state_t;
64 65
 
66
+#define ENSURE_CAN_UNLOAD(structure) if ( ! ensure_pxe_state(CAN_UNLOAD) ) { \
67
+			structure->Status = PXENV_STATUS_UNDI_INVALID_STATE; \
68
+			return PXENV_EXIT_FAILURE; }
69
+#define ENSURE_MIDWAY(structure) if ( ! ensure_pxe_state(MIDWAY) ) { \
70
+			structure->Status = PXENV_STATUS_UNDI_INVALID_STATE; \
71
+			return PXENV_EXIT_FAILURE; }
72
+#define ENSURE_READY(structure) if ( ! ensure_pxe_state(READY) ) { \
73
+			structure->Status = PXENV_STATUS_UNDI_INVALID_STATE; \
74
+			return PXENV_EXIT_FAILURE; }
75
+
65 76
 /* Data structures installed as part of a PXE stack.  Architectures
66 77
  * will have extra information to append to the end of this.
67 78
  */
68 79
 #define PXE_TFTP_MAGIC_COOKIE ( ( 'P'<<24 ) | ( 'x'<<16 ) | ( 'T'<<8 ) | 'f' )
69
-typedef struct {
70
-	pxe_t		pxe	__attribute__ ((aligned(16)));
71
-	pxenv_t		pxenv	__attribute__ ((aligned(16)));
80
+typedef struct pxe_stack {
81
+	struct s_PXE		pxe	__attribute__ ((aligned(16)));
82
+	struct s_PXENV		pxenv	__attribute__ ((aligned(16)));
72 83
 	pxe_stack_state_t state;
73 84
 	union {
74
-		BOOTPLAYER	cached_info;
85
+		BOOTPLAYER_t	cached_info;
75 86
 		char		packet[ETH_FRAME_LEN];
76 87
 		struct {
77 88
 			uint32_t magic_cookie;
@@ -88,6 +99,10 @@ typedef struct {
88 99
 	struct {}	arch_data __attribute__ ((aligned(16)));
89 100
 } pxe_stack_t;
90 101
 
102
+extern int ensure_pxe_state ( pxe_stack_state_t wanted );
103
+
104
+extern pxe_stack_t *pxe_stack;
105
+
91 106
 extern PXENV_EXIT_t pxe_api_call ( int opcode, union u_PXENV_ANY *any );
92 107
 
93 108
 #endif /* PXE_H */

+ 88
- 85
src/include/pxe_api.h Просмотреть файл

@@ -200,89 +200,6 @@ typedef struct s_PXE PXE_t;
200 200
 
201 201
 /** @} */ /* pxe_api_call */
202 202
 
203
-/** @defgroup pxe_loader_api PXE Loader API
204
- *
205
- * The UNDI ROM loader API
206
- *
207
- * @{
208
- */
209
-
210
-/** The UNDI ROM ID structure */
211
-struct s_UNDI_ROM_ID {
212
-	/** Signature
213
-	 *
214
-	 * Contains the bytes 'U', 'N', 'D', 'I'.
215
-	 */
216
-	UINT32_t Signature;
217
-	UINT8_t StructLength;		/**< Length of this structure */
218
-	/** Checksum
219
-	 *
220
-	 * The byte checksum of this structure (using the length in
221
-	 * #StructLength) must be zero.
222
-	 */
223
-	UINT8_t StructCksum;
224
-	/** Revision of this structure
225
-	 *
226
-	 * For PXE version 2.1, this field must be zero.
227
-	 */
228
-	UINT8_t StructRev;
229
-	/** UNDI revision
230
-	 *
231
-	 * UNDI revision, least significant byte first.  For UNDI
232
-	 * version 2.1.0, this field will contain { 0x00, 0x01, 0x02 }.
233
-	 */
234
-	UINT8_t UNDIRev[3];
235
-	/** UNDI loader routine entry point
236
-	 *
237
-	 * This is the entry point for calling undi_loader().
238
-	 */
239
-	UINT16_t UNDILoader;
240
-	/** Minimum required stack segment size */
241
-	UINT16_t StackSize;
242
-	/** Minimum required data segment size */
243
-	UINT16_t DataSize;
244
-	/** Minimum required code segment size */
245
-	UINT16_t CodeSize;
246
-} PACKED;
247
-
248
-typedef struct s_UNDI_ROM_ID UNDI_ROM_ID_t;
249
-
250
-/** Parameter block for undi_loader() */
251
-struct s_UNDI_LOADER {
252
-	/** struct s_UNDI_LOADER starts with a struct s_PXENV_START_UNDI */
253
-	union undi_loader_start_undi {
254
-		PXENV_STATUS_t Status;		/**< PXE status code */
255
-		/** Parameters to pass to pxenv_start_undi() */
256
-		struct s_PXENV_START_UNDI start_undi;
257
-	} u;
258
-	/** UNDI data segment
259
-	 *
260
-	 * @note The PXE specification defines the type of this field
261
-	 * as #UINT16_t.  For x86, #SEGSEL_t and #UINT16_t are
262
-	 * equivalent anyway; for other architectures #SEGSEL_t makes
263
-	 * more sense.
264
-	 */
265
-	SEGSEL_t	undi_ds;
266
-	/** UNDI code segment
267
-	 *
268
-	 * @note The PXE specification defines the type of this field
269
-	 * as #UINT16_t.  For x86, #SEGSEL_t and #UINT16_t are
270
-	 * equivalent anyway; for other architectures #SEGSEL_t makes
271
-	 * more sense.
272
-	 */
273
-	SEGSEL_t	undi_cs;
274
-	/** Address of the !PXE structure (a struct s_PXE) */
275
-	SEGOFF16_t	pxe_ptr;
276
-	/** Address of the PXENV+ structure (a struct s_PXENV) */
277
-	SEGOFF16_t	pxenv_ptr;
278
-} PACKED;
279
-
280
-typedef struct s_UNDI_LOADER UNDI_LOADER_t;
281
-
282
-extern PXENV_EXIT_t undi_loader ( struct s_UNDI_LOADER *undi_loader );
283
-
284
-/** @} */ /* pxe_loader_api */
285
-
286 203
 /** @defgroup pxe_preboot_api PXE Preboot API
287 204
  *
288 205
  * General high-level functions: #PXENV_UNLOAD_STACK, #PXENV_START_UNDI etc.
@@ -364,6 +281,9 @@ typedef struct s_PXENV_GET_CACHED_INFO PXENV_GET_CACHED_INFO_t;
364 281
 
365 282
 #define VM_RFC1048	0x63825363L	/**< DHCP magic cookie */
366 283
 
284
+/** Maximum length of DHCP options */
285
+#define BOOTP_DHCPVEND	1024
286
+
367 287
 /** Format of buffer filled in by pxenv_get_cached_info()
368 288
  *
369 289
  * This somewhat convoluted data structure simply describes the layout
@@ -986,13 +906,13 @@ struct s_PXENV_UNDI_MCAST_ADDRESS {
986 906
 typedef struct s_PXENV_UNDI_MCAST_ADDRESS PXENV_UNDI_MCAST_ADDRESS_t;
987 907
 
988 908
 /** Parameter block for pxenv_undi_reset_adapter() */
989
-struct s_PXENV_UNDI_RESET_ADAPTER {
909
+struct s_PXENV_UNDI_RESET {
990 910
 	PXENV_STATUS_t	Status;		/**< PXE status code */
991 911
 	/** Multicast MAC addresses */
992 912
 	struct s_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf;
993 913
 } PACKED;
994 914
 
995
-typedef struct s_PXENV_UNDI_RESET_ADAPTER PXENV_UNDI_RESET_ADAPTER_t;
915
+typedef struct s_PXENV_UNDI_RESET PXENV_UNDI_RESET_t;
996 916
 
997 917
 extern PXENV_EXIT_t pxenv_undi_reset_adapter ( struct s_PXENV_UNDI_RESET
998 918
 					       *undi_reset_adapter );
@@ -1626,6 +1546,89 @@ extern PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr );
1626 1546
 
1627 1547
 /** @} */ /* pxe_undi_api */
1628 1548
 
1549
+/** @defgroup pxe_loader_api PXE Loader API
1550
+ *
1551
+ * The UNDI ROM loader API
1552
+ *
1553
+ * @{
1554
+ */
1555
+
1556
+/** The UNDI ROM ID structure */
1557
+struct s_UNDI_ROM_ID {
1558
+	/** Signature
1559
+	 *
1560
+	 * Contains the bytes 'U', 'N', 'D', 'I'.
1561
+	 */
1562
+	UINT32_t Signature;
1563
+	UINT8_t StructLength;		/**< Length of this structure */
1564
+	/** Checksum
1565
+	 *
1566
+	 * The byte checksum of this structure (using the length in
1567
+	 * #StructLength) must be zero.
1568
+	 */
1569
+	UINT8_t StructCksum;
1570
+	/** Revision of this structure
1571
+	 *
1572
+	 * For PXE version 2.1, this field must be zero.
1573
+	 */
1574
+	UINT8_t StructRev;
1575
+	/** UNDI revision
1576
+	 *
1577
+	 * UNDI revision, least significant byte first.  For UNDI
1578
+	 * version 2.1.0, this field will contain { 0x00, 0x01, 0x02 }.
1579
+	 */
1580
+	UINT8_t UNDIRev[3];
1581
+	/** UNDI loader routine entry point
1582
+	 *
1583
+	 * This is the entry point for calling undi_loader().
1584
+	 */
1585
+	UINT16_t UNDILoader;
1586
+	/** Minimum required stack segment size */
1587
+	UINT16_t StackSize;
1588
+	/** Minimum required data segment size */
1589
+	UINT16_t DataSize;
1590
+	/** Minimum required code segment size */
1591
+	UINT16_t CodeSize;
1592
+} PACKED;
1593
+
1594
+typedef struct s_UNDI_ROM_ID UNDI_ROM_ID_t;
1595
+
1596
+/** Parameter block for undi_loader() */
1597
+struct s_UNDI_LOADER {
1598
+	/** struct s_UNDI_LOADER starts with a struct s_PXENV_START_UNDI */
1599
+	union undi_loader_start_undi {
1600
+		PXENV_STATUS_t Status;		/**< PXE status code */
1601
+		/** Parameters to pass to pxenv_start_undi() */
1602
+		struct s_PXENV_START_UNDI start_undi;
1603
+	} u;
1604
+	/** UNDI data segment
1605
+	 *
1606
+	 * @note The PXE specification defines the type of this field
1607
+	 * as #UINT16_t.  For x86, #SEGSEL_t and #UINT16_t are
1608
+	 * equivalent anyway; for other architectures #SEGSEL_t makes
1609
+	 * more sense.
1610
+	 */
1611
+	SEGSEL_t	undi_ds;
1612
+	/** UNDI code segment
1613
+	 *
1614
+	 * @note The PXE specification defines the type of this field
1615
+	 * as #UINT16_t.  For x86, #SEGSEL_t and #UINT16_t are
1616
+	 * equivalent anyway; for other architectures #SEGSEL_t makes
1617
+	 * more sense.
1618
+	 */
1619
+	SEGSEL_t	undi_cs;
1620
+	/** Address of the !PXE structure (a struct s_PXE) */
1621
+	SEGOFF16_t	pxe_ptr;
1622
+	/** Address of the PXENV+ structure (a struct s_PXENV) */
1623
+	SEGOFF16_t	pxenv_ptr;
1624
+} PACKED;
1625
+
1626
+typedef struct s_UNDI_LOADER UNDI_LOADER_t;
1627
+
1628
+extern PXENV_EXIT_t undi_loader ( struct s_UNDI_LOADER *undi_loader );
1629
+
1630
+/** @} */ /* pxe_loader_api */
1631
+
1629 1632
 /** @} */ /* pxe */
1630 1633
 
1631 1634
 #endif /* PXE_API_H */

+ 0
- 61
src/include/pxe_export.h Просмотреть файл

@@ -1,61 +0,0 @@
1
-/* Header for pxe_export.c
2
- */
3
-
4
-#ifndef PXE_EXPORT_H
5
-#define PXE_EXPORT_H
6
-
7
-#include "pxe.h"
8
-
9
-/* Function prototypes */
10
-extern int ensure_pxe_state ( pxe_stack_state_t wanted );
11
-
12
-extern PXENV_EXIT_t pxenv_start_undi ( t_PXENV_START_UNDI * );
13
-extern PXENV_EXIT_t pxenv_undi_startup ( t_PXENV_UNDI_STARTUP * );
14
-extern PXENV_EXIT_t pxenv_undi_cleanup ( t_PXENV_UNDI_CLEANUP * );
15
-extern PXENV_EXIT_t pxenv_undi_initialize ( t_PXENV_UNDI_INITIALIZE * );
16
-extern PXENV_EXIT_t pxenv_undi_reset_adapter ( t_PXENV_UNDI_RESET_ADAPTER * );
17
-extern PXENV_EXIT_t pxenv_undi_shutdown ( t_PXENV_UNDI_SHUTDOWN * );
18
-extern PXENV_EXIT_t pxenv_undi_open ( t_PXENV_UNDI_OPEN * );
19
-extern PXENV_EXIT_t pxenv_undi_close ( t_PXENV_UNDI_CLOSE * );
20
-extern PXENV_EXIT_t pxenv_undi_transmit ( t_PXENV_UNDI_TRANSMIT * );
21
-extern PXENV_EXIT_t pxenv_undi_set_mcast_address (
22
-					    t_PXENV_UNDI_SET_MCAST_ADDRESS * );
23
-extern PXENV_EXIT_t pxenv_undi_set_station_address (
24
-					  t_PXENV_UNDI_SET_STATION_ADDRESS * );
25
-extern PXENV_EXIT_t pxenv_undi_set_packet_filter (
26
-					    t_PXENV_UNDI_SET_PACKET_FILTER * );
27
-extern PXENV_EXIT_t pxenv_undi_get_information (
28
-					      t_PXENV_UNDI_GET_INFORMATION * );
29
-extern PXENV_EXIT_t pxenv_undi_get_statistics ( t_PXENV_UNDI_GET_STATISTICS* );
30
-extern PXENV_EXIT_t pxenv_undi_clear_statistics (
31
-					     t_PXENV_UNDI_CLEAR_STATISTICS * );
32
-extern PXENV_EXIT_t pxenv_undi_initiate_diags ( t_PXENV_UNDI_INITIATE_DIAGS* );
33
-extern PXENV_EXIT_t pxenv_undi_force_interrupt (
34
-					      t_PXENV_UNDI_FORCE_INTERRUPT * );
35
-extern PXENV_EXIT_t pxenv_undi_get_mcast_address (
36
-					    t_PXENV_UNDI_GET_MCAST_ADDRESS * );
37
-extern PXENV_EXIT_t pxenv_undi_get_nic_type ( t_PXENV_UNDI_GET_NIC_TYPE * );
38
-extern PXENV_EXIT_t pxenv_undi_get_iface_info ( t_PXENV_UNDI_GET_IFACE_INFO *);
39
-extern PXENV_EXIT_t pxenv_undi_isr ( t_PXENV_UNDI_ISR * );
40
-extern PXENV_EXIT_t pxenv_stop_undi ( t_PXENV_STOP_UNDI * );
41
-extern PXENV_EXIT_t pxenv_tftp_open ( t_PXENV_TFTP_OPEN * );
42
-extern PXENV_EXIT_t pxenv_tftp_close ( t_PXENV_TFTP_CLOSE * );
43
-extern PXENV_EXIT_t pxenv_tftp_read ( t_PXENV_TFTP_READ * );
44
-extern PXENV_EXIT_t pxenv_tftp_read_file ( t_PXENV_TFTP_READ_FILE * );
45
-extern PXENV_EXIT_t pxenv_tftp_get_fsize ( t_PXENV_TFTP_GET_FSIZE * );
46
-extern PXENV_EXIT_t pxenv_udp_open ( t_PXENV_UDP_OPEN * );
47
-extern PXENV_EXIT_t pxenv_udp_close ( t_PXENV_UDP_CLOSE * );
48
-extern PXENV_EXIT_t pxenv_udp_read ( t_PXENV_UDP_READ * );
49
-extern PXENV_EXIT_t pxenv_udp_write ( t_PXENV_UDP_WRITE * );
50
-extern PXENV_EXIT_t pxenv_unload_stack ( t_PXENV_UNLOAD_STACK * );
51
-extern PXENV_EXIT_t pxenv_get_cached_info ( t_PXENV_GET_CACHED_INFO * );
52
-extern PXENV_EXIT_t pxenv_restart_tftp ( t_PXENV_RESTART_TFTP * );
53
-extern PXENV_EXIT_t pxenv_start_base ( t_PXENV_START_BASE * );
54
-extern PXENV_EXIT_t pxenv_stop_base ( t_PXENV_STOP_BASE * );
55
-
56
-extern PXENV_EXIT_t pxe_api_call ( int opcode, t_PXENV_ANY *params );
57
-
58
-/* Static variables */
59
-extern pxe_stack_t *pxe_stack;
60
-
61
-#endif /* PXE_EXPORT_H */

+ 1
- 1
src/include/pxe_types.h Просмотреть файл

@@ -117,7 +117,7 @@ typedef struct s_SEGDESC {
117 117
 	SEGSEL_t	segment_address;	/**< Segment selector */
118 118
 	ADDR32_t	physical_address;	/**< Segment base address */
119 119
 	OFF16_t		seg_size;		/**< Size of the segment */
120
-} PACKED __SEGDESC_t;
120
+} PACKED SEGDESC_t;
121 121
 
122 122
 /** @} */ /* pxe_types */
123 123
 

+ 311
- 0
src/interface/pxe/pxe.c Просмотреть файл

@@ -0,0 +1,311 @@
1
+/** @file
2
+ *
3
+ * 
4
+ *
5
+ */
6
+
7
+/*
8
+ * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
9
+ *
10
+ * This program is free software; you can redistribute it and/or
11
+ * modify it under the terms of the GNU General Public License as
12
+ * published by the Free Software Foundation; either version 2 of the
13
+ * License, or any later version.
14
+ *
15
+ * This program is distributed in the hope that it will be useful, but
16
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18
+ * General Public License for more details.
19
+ *
20
+ * You should have received a copy of the GNU General Public License
21
+ * along with this program; if not, write to the Free Software
22
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
+ */
24
+
25
+#include "pxe.h"
26
+
27
+/* Global pointer to currently installed PXE stack */
28
+pxe_stack_t *pxe_stack = NULL;
29
+
30
+/* Various startup/shutdown routines.  The startup/shutdown call
31
+ * sequence is incredibly badly defined in the Intel PXE spec, for
32
+ * example:
33
+ *
34
+ *   PXENV_UNDI_INITIALIZE says that the parameters used to initialize
35
+ *   the adaptor should be those supplied to the most recent
36
+ *   PXENV_UNDI_STARTUP call.  PXENV_UNDI_STARTUP takes no parameters.
37
+ *
38
+ *   PXENV_UNDI_CLEANUP says that the rest of the API will not be
39
+ *   available after making this call.  Figure 3-3 ("Early UNDI API
40
+ *   usage") shows a call to PXENV_UNDI_CLEANUP being followed by a
41
+ *   call to the supposedly now unavailable PXENV_STOP_UNDI.
42
+ *
43
+ *   PXENV_UNLOAD_BASE_STACK talks about freeing up the memory
44
+ *   occupied by the PXE stack.  Figure 4-3 ("PXE IPL") shows a call
45
+ *   to PXENV_STOP_UNDI being made after the call to
46
+ *   PXENV_UNLOAD_BASE_STACK, by which time the entire PXE stack
47
+ *   should have been freed (and, potentially, zeroed).
48
+ *
49
+ *   Nothing, anywhere, seems to mention who's responsible for freeing
50
+ *   up the base memory allocated for the stack segment.  It's not
51
+ *   even clear whether or not this is expected to be in free base
52
+ *   memory rather than claimed base memory.
53
+ *
54
+ * Consequently, we adopt a rather defensive strategy, designed to
55
+ * work with any conceivable sequence of initialisation or shutdown
56
+ * calls.  We have only two things that we care about:
57
+ *
58
+ *   1. Have we hooked INT 1A and INT 15,E820(etc.)?
59
+ *   2. Is the NIC initialised?
60
+ *
61
+ * The NIC should never be initialised without the vectors being
62
+ * hooked, similarly the vectors should never be unhooked with the NIC
63
+ * still initialised.  We do, however, want to be able to have the
64
+ * vectors hooked with the NIC shutdown.  We therefore have three
65
+ * possible states:
66
+ *
67
+ *   1. Ready to unload: interrupts unhooked, NIC shutdown.
68
+ *   2. Midway: interrupts hooked, NIC shutdown.
69
+ *   3. Fully ready: interrupts hooked, NIC initialised.
70
+ *
71
+ * We provide the three states CAN_UNLOAD, MIDWAY and READY to define
72
+ * these, and the call pxe_ensure_state() to ensure that the stack is
73
+ * in the specified state.  All our PXE API call implementations
74
+ * should use this call to ensure that the state is as required for
75
+ * that PXE API call.  This enables us to cope with whatever the
76
+ * end-user's interpretation of the PXE spec may be.  It even allows
77
+ * for someone calling e.g. PXENV_START_UNDI followed by
78
+ * PXENV_UDP_WRITE, without bothering with any of the intervening
79
+ * calls.
80
+ *
81
+ * pxe_ensure_state() returns 1 for success, 0 for failure.  In the
82
+ * event of failure (which can arise from e.g. asking for state READY
83
+ * when we don't know where our NIC is), the error code
84
+ * PXENV_STATUS_UNDI_INVALID_STATE should be returned to the user.
85
+ * The macros ENSURE_XXX() can be used to achieve this without lots of
86
+ * duplicated code.
87
+ */
88
+
89
+/* pxe_[un]hook_stack are architecture-specific and provided in
90
+ * pxe_callbacks.c
91
+ */
92
+
93
+int pxe_initialise_nic ( void ) {
94
+	if ( pxe_stack->state >= READY ) return 1;
95
+
96
+#warning "device probing mechanism has completely changed"
97
+#if 0
98
+
99
+	/* Check if NIC is initialised.  dev.disable is set to 0
100
+	 * when disable() is called, so we use this.
101
+	 */
102
+	if ( dev.disable ) {
103
+		/* NIC may have been initialised independently
104
+		 * (e.g. when we set up the stack prior to calling the
105
+		 * NBP).
106
+		 */
107
+		pxe_stack->state = READY;
108
+		return 1;
109
+	}
110
+
111
+	/* If we already have a NIC defined, reuse that one with
112
+	 * PROBE_AWAKE.  If one was specifed via PXENV_START_UNDI, try
113
+	 * that one first.  Otherwise, set PROBE_FIRST.
114
+	 */
115
+
116
+	if ( dev.state.pci.dev.use_specified == 1 ) {
117
+		dev.how_probe = PROBE_NEXT;
118
+		DBG ( " initialising NIC specified via START_UNDI" );
119
+	} else if ( dev.state.pci.dev.driver ) {
120
+		DBG ( " reinitialising NIC" );
121
+		dev.how_probe = PROBE_AWAKE;
122
+	} else {
123
+		DBG ( " probing for any NIC" );
124
+		dev.how_probe = PROBE_FIRST;
125
+	}
126
+
127
+	/* Call probe routine to bring up the NIC */
128
+	if ( eth_probe ( &dev ) != PROBE_WORKED ) {
129
+		DBG ( " failed" );
130
+		return 0;
131
+	}
132
+#endif
133
+	
134
+
135
+	pxe_stack->state = READY;
136
+	return 1;
137
+}
138
+
139
+int pxe_shutdown_nic ( void ) {
140
+	if ( pxe_stack->state <= MIDWAY ) return 1;
141
+
142
+	eth_irq ( DISABLE );
143
+	disable ( &dev );
144
+	pxe_stack->state = MIDWAY;
145
+	return 1;
146
+}
147
+
148
+int ensure_pxe_state ( pxe_stack_state_t wanted ) {
149
+	int success = 1;
150
+
151
+	if ( ! pxe_stack ) return 0;
152
+	if ( wanted >= MIDWAY )
153
+		success = success & hook_pxe_stack();
154
+	if ( wanted > MIDWAY ) {
155
+		success = success & pxe_initialise_nic();
156
+	} else {
157
+		success = success & pxe_shutdown_nic();
158
+	}
159
+	if ( wanted < MIDWAY )
160
+		success = success & unhook_pxe_stack();
161
+	return success;
162
+}
163
+
164
+/* API call dispatcher
165
+ *
166
+ * Status: complete
167
+ */
168
+PXENV_EXIT_t pxe_api_call ( int opcode, union u_PXENV_ANY *any ) {
169
+	PXENV_EXIT_t ret = PXENV_EXIT_FAILURE;
170
+
171
+	/* Set default status in case child routine fails to do so */
172
+	any->Status = PXENV_STATUS_FAILURE;
173
+
174
+	DBG ( "[" );
175
+
176
+	/* Hand off to relevant API routine */
177
+	switch ( opcode ) {
178
+	case PXENV_START_UNDI:
179
+		ret = pxenv_start_undi ( &any->start_undi );
180
+		break;
181
+	case PXENV_UNDI_STARTUP:
182
+		ret = pxenv_undi_startup ( &any->undi_startup );
183
+		break;
184
+	case PXENV_UNDI_CLEANUP:
185
+		ret = pxenv_undi_cleanup ( &any->undi_cleanup );
186
+		break;
187
+	case PXENV_UNDI_INITIALIZE:
188
+		ret = pxenv_undi_initialize ( &any->undi_initialize );
189
+		break;
190
+	case PXENV_UNDI_RESET_ADAPTER:
191
+		ret = pxenv_undi_reset_adapter ( &any->undi_reset_adapter );
192
+		break;
193
+	case PXENV_UNDI_SHUTDOWN:
194
+		ret = pxenv_undi_shutdown ( &any->undi_shutdown );
195
+		break;
196
+	case PXENV_UNDI_OPEN:
197
+		ret = pxenv_undi_open ( &any->undi_open );
198
+		break;
199
+	case PXENV_UNDI_CLOSE:
200
+		ret = pxenv_undi_close ( &any->undi_close );
201
+		break;
202
+	case PXENV_UNDI_TRANSMIT:
203
+		ret = pxenv_undi_transmit ( &any->undi_transmit );
204
+		break;
205
+	case PXENV_UNDI_SET_MCAST_ADDRESS:
206
+		ret = pxenv_undi_set_mcast_address (
207
+						&any->undi_set_mcast_address );
208
+		break;
209
+	case PXENV_UNDI_SET_STATION_ADDRESS:
210
+		ret = pxenv_undi_set_station_address (
211
+					      &any->undi_set_station_address );
212
+		break;
213
+	case PXENV_UNDI_SET_PACKET_FILTER:
214
+		ret = pxenv_undi_set_packet_filter (
215
+						&any->undi_set_packet_filter );
216
+		break;
217
+	case PXENV_UNDI_GET_INFORMATION:
218
+		ret = pxenv_undi_get_information (
219
+					       &any->undi_get_information );
220
+		break;
221
+	case PXENV_UNDI_GET_STATISTICS:
222
+		ret = pxenv_undi_get_statistics ( &any->undi_get_statistics );
223
+		break;
224
+	case PXENV_UNDI_CLEAR_STATISTICS:
225
+		ret = pxenv_undi_clear_statistics (
226
+						 &any->undi_clear_statistics );
227
+		break;
228
+	case PXENV_UNDI_INITIATE_DIAGS:
229
+		ret = pxenv_undi_initiate_diags ( &any->undi_initiate_diags );
230
+						 
231
+		break;
232
+	case PXENV_UNDI_FORCE_INTERRUPT:
233
+		ret = pxenv_undi_force_interrupt (
234
+					       &any->undi_force_interrupt );
235
+		break;
236
+	case PXENV_UNDI_GET_MCAST_ADDRESS:
237
+		ret = pxenv_undi_get_mcast_address (
238
+					     &any->undi_get_mcast_address );
239
+		break;
240
+	case PXENV_UNDI_GET_NIC_TYPE:
241
+		ret = pxenv_undi_get_nic_type ( &any->undi_get_nic_type );
242
+		break;
243
+	case PXENV_UNDI_GET_IFACE_INFO:
244
+		ret = pxenv_undi_get_iface_info ( &any->undi_get_iface_info );
245
+		break;
246
+	case PXENV_UNDI_ISR:
247
+		ret = pxenv_undi_isr ( &any->undi_isr );
248
+		break;
249
+	case PXENV_STOP_UNDI:
250
+		ret = pxenv_stop_undi ( &any->stop_undi );
251
+		break;
252
+	case PXENV_TFTP_OPEN:
253
+		ret = pxenv_tftp_open ( &any->tftp_open );
254
+		break;
255
+	case PXENV_TFTP_CLOSE:
256
+		ret = pxenv_tftp_close ( &any->tftp_close );
257
+		break;
258
+	case PXENV_TFTP_READ:
259
+		ret = pxenv_tftp_read ( &any->tftp_read );
260
+		break;
261
+	case PXENV_TFTP_READ_FILE:
262
+		ret = pxenv_tftp_read_file ( &any->tftp_read_file );
263
+		break;
264
+	case PXENV_TFTP_GET_FSIZE:
265
+		ret = pxenv_tftp_get_fsize ( &any->tftp_get_fsize );
266
+		break;
267
+	case PXENV_UDP_OPEN:
268
+		ret = pxenv_udp_open ( &any->udp_open );
269
+		break;
270
+	case PXENV_UDP_CLOSE:
271
+		ret = pxenv_udp_close ( &any->udp_close );
272
+		break;
273
+	case PXENV_UDP_READ:
274
+		ret = pxenv_udp_read ( &any->udp_read );
275
+		break;
276
+	case PXENV_UDP_WRITE:
277
+		ret = pxenv_udp_write ( &any->udp_write );
278
+		break;
279
+	case PXENV_UNLOAD_STACK:
280
+		ret = pxenv_unload_stack ( &any->unload_stack );
281
+		break;
282
+	case PXENV_GET_CACHED_INFO:
283
+		ret = pxenv_get_cached_info ( &any->get_cached_info );
284
+		break;
285
+	case PXENV_RESTART_TFTP:
286
+		ret = pxenv_restart_tftp ( &any->restart_tftp );
287
+		break;
288
+	case PXENV_START_BASE:
289
+		ret = pxenv_start_base ( &any->start_base );
290
+		break;
291
+	case PXENV_STOP_BASE:
292
+		ret = pxenv_stop_base ( &any->stop_base );
293
+		break;
294
+		
295
+	default:
296
+		DBG ( "PXENV_UNKNOWN_%hx", opcode );
297
+		any->Status = PXENV_STATUS_UNSUPPORTED;
298
+		ret = PXENV_EXIT_FAILURE;
299
+		break;
300
+	}
301
+
302
+	if ( any->Status != PXENV_STATUS_SUCCESS ) {
303
+		DBG ( " %hx", any->Status );
304
+	}
305
+	if ( ret != PXENV_EXIT_SUCCESS ) {
306
+		DBG ( ret == PXENV_EXIT_FAILURE ? " err" : " ??" );
307
+	}
308
+	DBG ( "]" );
309
+
310
+	return ret;
311
+}

+ 83
- 0
src/interface/pxe/pxe_loader.c Просмотреть файл

@@ -0,0 +1,83 @@
1
+/** @file
2
+ *
3
+ * PXE UNDI loader
4
+ *
5
+ */
6
+
7
+/*
8
+ * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
9
+ *
10
+ * This program is free software; you can redistribute it and/or
11
+ * modify it under the terms of the GNU General Public License as
12
+ * published by the Free Software Foundation; either version 2 of the
13
+ * License, or any later version.
14
+ *
15
+ * This program is distributed in the hope that it will be useful, but
16
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18
+ * General Public License for more details.
19
+ *
20
+ * You should have received a copy of the GNU General Public License
21
+ * along with this program; if not, write to the Free Software
22
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
+ */
24
+
25
+#include "pxe.h"
26
+
27
+/* PXENV_UNDI_LOADER
28
+ *
29
+ * Status: working
30
+ *
31
+ * NOTE: This is not a genuine PXE API call; the loader has a separate
32
+ * entry point.  However, to simplify the mapping of the PXE API to
33
+ * the internal Etherboot API, both are directed through the same
34
+ * interface.
35
+ */
36
+PXENV_EXIT_t undi_loader ( struct s_UNDI_LOADER *undi_loader ) {
37
+	uint32_t loader_phys = virt_to_phys ( undi_loader );
38
+
39
+	DBG ( "PXENV_UNDI_LOADER" );
40
+	
41
+	/* Set UNDI DS as our real-mode stack */
42
+	use_undi_ds_for_rm_stack ( undi_loader->undi_ds );
43
+
44
+	/* FIXME: These lines are borrowed from main.c.  There should
45
+	 * probably be a single initialise() function that does all
46
+	 * this, but it's currently split interestingly between main()
47
+	 * and main_loop()...
48
+	 */
49
+
50
+
51
+	/* CHECKME: Our init functions have probably already been
52
+	   called by the ROM prefix's call to setup(), haven't
53
+	   they? */
54
+
55
+
56
+
57
+	/* We have relocated; the loader pointer is now invalid */
58
+	undi_loader = phys_to_virt ( loader_phys );
59
+
60
+	/* Install PXE stack to area specified by NBP */
61
+	install_pxe_stack ( VIRTUAL ( undi_loader->undi_cs, 0 ) );
62
+	
63
+	/* Call pxenv_start_undi to set parameters.  Why the hell PXE
64
+	 * requires these parameters to be provided twice is beyond
65
+	 * the wit of any sane man.  Don't worry if it fails; the NBP
66
+	 * should call PXENV_START_UNDI separately anyway.
67
+	 */
68
+	pxenv_start_undi ( &undi_loader->u.start_undi );
69
+	/* Unhook stack; the loader is not meant to hook int 1a etc,
70
+	 * but the call the pxenv_start_undi will cause it to happen.
71
+	 */
72
+
73
+	/* FIXME: can't use ENSURE_CAN_UNLOAD() thanks to newer gcc's
74
+	 * barfing on unnamed struct/unions. */
75
+	/*	ENSURE_CAN_UNLOAD ( undi_loader ); */
76
+
77
+	/* Fill in addresses of !PXE and PXENV+ structures */
78
+	PTR_TO_SEGOFF16 ( &pxe_stack->pxe, undi_loader->pxe_ptr );
79
+	PTR_TO_SEGOFF16 ( &pxe_stack->pxenv, undi_loader->pxenv_ptr );
80
+	
81
+	undi_loader->u.Status = PXENV_STATUS_SUCCESS;
82
+	return PXENV_EXIT_SUCCESS;
83
+}

+ 249
- 0
src/interface/pxe/pxe_preboot.c Просмотреть файл

@@ -0,0 +1,249 @@
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., 675 Mass Ave, Cambridge, MA 02139, USA.
24
+ */
25
+
26
+#include "pxe.h"
27
+#include "pxe_callbacks.h"
28
+
29
+/**
30
+ * UNLOAD BASE CODE STACK
31
+ *
32
+ * @v None
33
+ * @ret ...
34
+ *
35
+ */
36
+PXENV_EXIT_t pxenv_unload_stack ( struct s_PXENV_UNLOAD_STACK *unload_stack ) {
37
+	int success;
38
+
39
+	DBG ( "PXENV_UNLOAD_STACK" );
40
+	success = ensure_pxe_state ( CAN_UNLOAD );
41
+
42
+	/* We need to call cleanup() at some point.  The network card
43
+	 * has already been disabled by ENSURE_CAN_UNLOAD(), but for
44
+	 * the sake of completeness we should call the console_fini()
45
+	 * etc. that are part of cleanup().
46
+	 *
47
+	 * There seems to be a lack of consensus on which is the final
48
+	 * PXE API call to make, but it's a fairly safe bet that all
49
+	 * the potential shutdown sequences will include a call to
50
+	 * PXENV_UNLOAD_STACK at some point, so we may as well do it
51
+	 * here.
52
+	 */
53
+	cleanup();
54
+
55
+	if ( ! success ) {
56
+		unload_stack->Status = PXENV_STATUS_KEEP_ALL;
57
+		return PXENV_EXIT_FAILURE;
58
+	}
59
+
60
+	unload_stack->Status = PXENV_STATUS_SUCCESS;
61
+	return PXENV_EXIT_SUCCESS;
62
+}
63
+
64
+/* PXENV_GET_CACHED_INFO
65
+ *
66
+ * Status: working
67
+ */
68
+PXENV_EXIT_t pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO
69
+				     *get_cached_info ) {
70
+	BOOTPLAYER_t *cached_info = &pxe_stack->cached_info;
71
+	DBG ( "PXENV_GET_CACHED_INFO %d", get_cached_info->PacketType );
72
+	ENSURE_READY ( get_cached_info );
73
+
74
+	/* Fill in cached_info structure in our pxe_stack */
75
+
76
+	/* I don't think there's actually any way we can be called in
77
+	 * the middle of a DHCP request... 
78
+	 */
79
+	cached_info->opcode = BOOTP_REP;
80
+	/* We only have Ethernet drivers */
81
+	cached_info->Hardware = ETHER_TYPE;
82
+	cached_info->Hardlen = ETH_ALEN;
83
+	/* PXESPEC: "Client sets" says the spec, but who's filling in
84
+	 * this structure?  It ain't the client.
85
+	 */
86
+	cached_info->Gatehops = 0;
87
+	cached_info->ident = 0;
88
+	cached_info->seconds = 0;
89
+	cached_info->Flags = BOOTP_BCAST;
90
+	/* PXESPEC: What do 'Client' and 'Your' IP address refer to? */
91
+	cached_info->cip = arptable[ARP_CLIENT].ipaddr.s_addr;
92
+	cached_info->yip = arptable[ARP_CLIENT].ipaddr.s_addr;
93
+	cached_info->sip = arptable[ARP_SERVER].ipaddr.s_addr;
94
+	/* PXESPEC: Does "GIP" mean "Gateway" or "Relay agent"? */
95
+	cached_info->gip = arptable[ARP_GATEWAY].ipaddr.s_addr;
96
+	memcpy ( cached_info->CAddr, arptable[ARP_CLIENT].node, ETH_ALEN );
97
+	/* Nullify server name */
98
+	cached_info->Sname[0] = '\0';
99
+	memcpy ( cached_info->bootfile, KERNEL_BUF,
100
+		 sizeof(cached_info->bootfile) );
101
+	/* Copy DHCP vendor options */
102
+	memcpy ( &cached_info->vendor.d, BOOTP_DATA_ADDR->bootp_reply.bp_vend,
103
+		 sizeof(cached_info->vendor.d) );
104
+	
105
+	/* Copy to user-specified buffer, or set pointer to our buffer */
106
+	get_cached_info->BufferLimit = sizeof(*cached_info);
107
+	/* PXESPEC: says to test for Buffer == NULL *and* BufferSize =
108
+	 * 0, but what are we supposed to do with a null buffer of
109
+	 * non-zero size?!
110
+	 */
111
+	if ( IS_NULL_SEGOFF16 ( get_cached_info->Buffer ) ) {
112
+		/* Point back to our buffer */
113
+		PTR_TO_SEGOFF16 ( cached_info, get_cached_info->Buffer );
114
+		get_cached_info->BufferSize = sizeof(*cached_info);
115
+	} else {
116
+		/* Copy to user buffer */
117
+		size_t size = sizeof(*cached_info);
118
+		void *buffer = SEGOFF16_TO_PTR ( get_cached_info->Buffer );
119
+		if ( get_cached_info->BufferSize < size )
120
+			size = get_cached_info->BufferSize;
121
+		DBG ( " to %x", virt_to_phys ( buffer ) );
122
+		memcpy ( buffer, cached_info, size );
123
+		/* PXESPEC: Should we return an error if the user
124
+		 * buffer is too small?  We do return the actual size
125
+		 * of the buffer via BufferLimit, so the user does
126
+		 * have a way to detect this already.
127
+		 */
128
+	}
129
+
130
+	get_cached_info->Status = PXENV_STATUS_SUCCESS;
131
+	return PXENV_EXIT_SUCCESS;
132
+}
133
+
134
+/* PXENV_RESTART_TFTP
135
+ *
136
+ * Status: working
137
+ */
138
+PXENV_EXIT_t pxenv_restart_tftp ( struct s_PXENV_TFTP_READ_FILE
139
+				  *restart_tftp ) {
140
+	PXENV_EXIT_t tftp_exit;
141
+
142
+	DBG ( "PXENV_RESTART_TFTP" );
143
+	ENSURE_READY ( restart_tftp );
144
+
145
+	/* Words cannot describe the complete mismatch between the PXE
146
+	 * specification and any possible version of reality...
147
+	 */
148
+	restart_tftp->Buffer = PXE_LOAD_ADDRESS; /* Fixed by spec, apparently */
149
+	restart_tftp->BufferSize = get_free_base_memory() - PXE_LOAD_ADDRESS; /* Near enough */
150
+	DBG ( "(" );
151
+	tftp_exit = pxe_api_call ( PXENV_TFTP_READ_FILE, (union u_PXENV_ANY*)restart_tftp );
152
+	DBG ( ")" );
153
+	if ( tftp_exit != PXENV_EXIT_SUCCESS ) return tftp_exit;
154
+
155
+	/* Fire up the new NBP */
156
+	restart_tftp->Status = xstartpxe();
157
+
158
+	/* Not sure what "SUCCESS" actually means, since we can only
159
+	 * return if the new NBP failed to boot...
160
+	 */
161
+	return PXENV_EXIT_SUCCESS;
162
+}
163
+
164
+/* PXENV_START_UNDI
165
+ *
166
+ * Status: working
167
+ */
168
+PXENV_EXIT_t pxenv_start_undi ( struct s_PXENV_START_UNDI *start_undi ) {
169
+	unsigned char bus, devfn;
170
+
171
+	DBG ( "PXENV_START_UNDI" );
172
+	ENSURE_MIDWAY(start_undi);
173
+
174
+	/* Record PCI bus & devfn passed by caller, so we know which
175
+	 * NIC they want to use.
176
+	 *
177
+	 * If they don't match our already-existing NIC structure, set
178
+	 * values to ensure that the specified NIC is used at the next
179
+	 * call to pxe_intialise_nic().
180
+	 */
181
+	bus = ( start_undi->AX >> 8 ) & 0xff;
182
+	devfn = start_undi->AX & 0xff;
183
+
184
+#warning "device probing mechanism has completely changed"
185
+#if 0
186
+	if ( ( pci->dev.driver == NULL ) ||
187
+	     ( pci->dev.bus != bus ) || ( pci->dev.devfn != devfn ) ) {
188
+		/* This is quite a bit of a hack and relies on
189
+		 * knowledge of the internal operation of Etherboot's
190
+		 * probe mechanism.
191
+		 */
192
+		DBG ( " set PCI %hhx:%hhx.%hhx",
193
+		      bus, PCI_SLOT(devfn), PCI_FUNC(devfn) );
194
+		dev->type = BOOT_NIC;
195
+		dev->to_probe = PROBE_PCI;
196
+		memset ( &dev->state, 0, sizeof(dev->state) );
197
+		pci->advance = 1;
198
+		pci->dev.use_specified = 1;
199
+		pci->dev.bus = bus;
200
+		pci->dev.devfn = devfn;
201
+	}
202
+#endif
203
+
204
+	start_undi->Status = PXENV_STATUS_SUCCESS;
205
+	return PXENV_EXIT_SUCCESS;
206
+}
207
+
208
+/* PXENV_STOP_UNDI
209
+ *
210
+ * Status: working
211
+ */
212
+PXENV_EXIT_t pxenv_stop_undi ( struct s_PXENV_STOP_UNDI *stop_undi ) {
213
+	DBG ( "PXENV_STOP_UNDI" );
214
+
215
+	if ( ! ensure_pxe_state(CAN_UNLOAD) ) {
216
+		stop_undi->Status = PXENV_STATUS_KEEP_UNDI;
217
+		return PXENV_EXIT_FAILURE;
218
+	}
219
+
220
+	stop_undi->Status = PXENV_STATUS_SUCCESS;
221
+	return PXENV_EXIT_SUCCESS;
222
+}
223
+
224
+/* PXENV_START_BASE
225
+ *
226
+ * Status: won't implement (requires major structural changes)
227
+ */
228
+PXENV_EXIT_t pxenv_start_base ( struct s_PXENV_START_BASE *start_base ) {
229
+	DBG ( "PXENV_START_BASE" );
230
+	/* ENSURE_READY ( start_base ); */
231
+	start_base->Status = PXENV_STATUS_UNSUPPORTED;
232
+	return PXENV_EXIT_FAILURE;
233
+}
234
+
235
+/* PXENV_STOP_BASE
236
+ *
237
+ * Status: working
238
+ */
239
+PXENV_EXIT_t pxenv_stop_base ( struct s_PXENV_STOP_BASE *stop_base ) {
240
+	DBG ( "PXENV_STOP_BASE" );
241
+
242
+	/* The only time we will be called is when the NBP is trying
243
+	 * to shut down the PXE stack.  There's nothing we need to do
244
+	 * in this call.
245
+	 */
246
+
247
+	stop_base->Status = PXENV_STATUS_SUCCESS;
248
+	return PXENV_EXIT_SUCCESS;
249
+}

+ 199
- 0
src/interface/pxe/pxe_tftp.c Просмотреть файл

@@ -0,0 +1,199 @@
1
+/** @file
2
+ *
3
+ * PXE TFTP API
4
+ *
5
+ */
6
+
7
+/*
8
+ * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
9
+ *
10
+ * This program is free software; you can redistribute it and/or
11
+ * modify it under the terms of the GNU General Public License as
12
+ * published by the Free Software Foundation; either version 2 of the
13
+ * License, or any later version.
14
+ *
15
+ * This program is distributed in the hope that it will be useful, but
16
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18
+ * General Public License for more details.
19
+ *
20
+ * You should have received a copy of the GNU General Public License
21
+ * along with this program; if not, write to the Free Software
22
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
+ */
24
+
25
+#include "pxe.h"
26
+
27
+/* PXENV_TFTP_OPEN
28
+ *
29
+ * Status: working
30
+ */
31
+PXENV_EXIT_t pxenv_tftp_open ( struct s_PXENV_TFTP_OPEN *tftp_open ) {
32
+	struct sockaddr_in tftp_server;
33
+	struct tftpreq_info_t request;
34
+	struct tftpblk_info_t block;
35
+
36
+	DBG ( "PXENV_TFTP_OPEN" );
37
+	ENSURE_READY ( tftp_open );
38
+
39
+	/* Set server address and port */
40
+	tftp_server.sin_addr.s_addr = tftp_open->ServerIPAddress
41
+		? tftp_open->ServerIPAddress
42
+		: arptable[ARP_SERVER].ipaddr.s_addr;
43
+	tftp_server.sin_port = ntohs ( tftp_open->TFTPPort );
44
+#ifdef WORK_AROUND_BPBATCH_BUG        
45
+	/* Force use of port 69; BpBatch tries to use port 4 for some         
46
+	* bizarre reason.         */        
47
+	tftp_server.sin_port = TFTP_PORT;
48
+#endif
49
+	/* Ignore gateway address; we can route properly */
50
+	/* Fill in request structure */
51
+	request.server = &tftp_server;
52
+	request.name = tftp_open->FileName;
53
+	request.blksize = tftp_open->PacketSize;
54
+	DBG ( " %@:%d/%s (%d)", tftp_open->ServerIPAddress,
55
+	      tftp_open->TFTPPort, request.name, request.blksize );
56
+	if ( !request.blksize ) request.blksize = TFTP_DEFAULTSIZE_PACKET;
57
+	/* Make request and get first packet */
58
+	if ( !tftp_block ( &request, &block ) ) {
59
+		tftp_open->Status = PXENV_STATUS_TFTP_FILE_NOT_FOUND;
60
+		return PXENV_EXIT_FAILURE;
61
+	}
62
+	/* Fill in PacketSize */
63
+	tftp_open->PacketSize = request.blksize;
64
+	/* Store first block for later retrieval by TFTP_READ */
65
+	pxe_stack->tftpdata.magic_cookie = PXE_TFTP_MAGIC_COOKIE;
66
+	pxe_stack->tftpdata.len = block.len;
67
+	pxe_stack->tftpdata.eof = block.eof;
68
+	memcpy ( pxe_stack->tftpdata.data, block.data, block.len );
69
+
70
+	tftp_open->Status = PXENV_STATUS_SUCCESS;
71
+	return PXENV_EXIT_SUCCESS;
72
+}
73
+
74
+/* PXENV_TFTP_CLOSE
75
+ *
76
+ * Status: working
77
+ */
78
+PXENV_EXIT_t pxenv_tftp_close ( struct s_PXENV_TFTP_CLOSE *tftp_close ) {
79
+	DBG ( "PXENV_TFTP_CLOSE" );
80
+	ENSURE_READY ( tftp_close );
81
+	tftp_close->Status = PXENV_STATUS_SUCCESS;
82
+	return PXENV_EXIT_SUCCESS;
83
+}
84
+
85
+/* PXENV_TFTP_READ
86
+ *
87
+ * Status: working
88
+ */
89
+PXENV_EXIT_t pxenv_tftp_read ( struct s_PXENV_TFTP_READ *tftp_read ) {
90
+	struct tftpblk_info_t block;
91
+
92
+	DBG ( "PXENV_TFTP_READ" );
93
+	ENSURE_READY ( tftp_read );
94
+
95
+	/* Do we have a block pending */
96
+	if ( pxe_stack->tftpdata.magic_cookie == PXE_TFTP_MAGIC_COOKIE ) {
97
+		block.data = pxe_stack->tftpdata.data;
98
+		block.len = pxe_stack->tftpdata.len;
99
+		block.eof = pxe_stack->tftpdata.eof;
100
+		block.block = 1; /* Will be the first block */
101
+		pxe_stack->tftpdata.magic_cookie = 0;
102
+	} else {
103
+		if ( !tftp_block ( NULL, &block ) ) {
104
+			tftp_read->Status = PXENV_STATUS_TFTP_FILE_NOT_FOUND;
105
+			return PXENV_EXIT_FAILURE;
106
+		}
107
+	}
108
+
109
+	/* Return data */
110
+	tftp_read->PacketNumber = block.block;
111
+	tftp_read->BufferSize = block.len;
112
+	memcpy ( SEGOFF16_TO_PTR(tftp_read->Buffer), block.data, block.len );
113
+	DBG ( " %d to %hx:%hx", block.len, tftp_read->Buffer.segment,
114
+	      tftp_read->Buffer.offset );
115
+ 
116
+	tftp_read->Status = PXENV_STATUS_SUCCESS;
117
+	return PXENV_EXIT_SUCCESS;
118
+}
119
+
120
+/* PXENV_TFTP_READ_FILE
121
+ *
122
+ * Status: working
123
+ */
124
+
125
+int pxe_tftp_read_block ( unsigned char *data, unsigned int block __unused,
126
+			  unsigned int len, int eof ) {
127
+	if ( pxe_stack->readfile.buffer ) {
128
+		if ( pxe_stack->readfile.offset + len >=
129
+		     pxe_stack->readfile.bufferlen ) return -1;
130
+		memcpy ( pxe_stack->readfile.buffer +
131
+			 pxe_stack->readfile.offset, data, len );
132
+	}
133
+	pxe_stack->readfile.offset += len;
134
+	return eof ? 0 : 1;
135
+}
136
+
137
+PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE
138
+				    *tftp_read_file ) {
139
+	struct sockaddr_in tftp_server;
140
+	int rc;
141
+
142
+	DBG ( "PXENV_TFTP_READ_FILE %s to [%x,%x)", tftp_read_file->FileName,
143
+	      tftp_read_file->Buffer,
144
+	      tftp_read_file->Buffer + tftp_read_file->BufferSize );
145
+	ENSURE_READY ( tftp_read_file );
146
+
147
+	/* inserted by Klaus Wittemeier */
148
+	/* KERNEL_BUF stores the name of the last required file */
149
+	/* This is a fix to make Microsoft Remote Install Services work (RIS) */
150
+	memcpy(KERNEL_BUF, tftp_read_file->FileName, sizeof(KERNEL_BUF));
151
+	/* end of insertion */
152
+
153
+	/* Set server address and port */
154
+	tftp_server.sin_addr.s_addr = tftp_read_file->ServerIPAddress
155
+		? tftp_read_file->ServerIPAddress
156
+		: arptable[ARP_SERVER].ipaddr.s_addr;
157
+	tftp_server.sin_port = ntohs ( tftp_read_file->TFTPSrvPort );
158
+
159
+	pxe_stack->readfile.buffer = phys_to_virt ( tftp_read_file->Buffer );
160
+	pxe_stack->readfile.bufferlen = tftp_read_file->BufferSize;
161
+	pxe_stack->readfile.offset = 0;
162
+
163
+	rc = tftp ( NULL, &tftp_server, tftp_read_file->FileName,
164
+		    pxe_tftp_read_block );
165
+	if ( rc ) {
166
+		tftp_read_file->Status = PXENV_STATUS_FAILURE;
167
+		return PXENV_EXIT_FAILURE;
168
+	}
169
+	tftp_read_file->Status = PXENV_STATUS_SUCCESS;
170
+	return PXENV_EXIT_SUCCESS;
171
+}
172
+
173
+/* PXENV_TFTP_GET_FSIZE
174
+ *
175
+ * Status: working, though ugly (we actually read the whole file,
176
+ * because it's too ugly to make Etherboot request the tsize option
177
+ * and hand it to us).
178
+ */
179
+PXENV_EXIT_t pxenv_tftp_get_fsize ( struct s_PXENV_TFTP_GET_FSIZE
180
+				    *tftp_get_fsize ) {
181
+	int rc;
182
+
183
+	DBG ( "PXENV_TFTP_GET_FSIZE" );
184
+	ENSURE_READY ( tftp_get_fsize );
185
+
186
+	pxe_stack->readfile.buffer = NULL;
187
+	pxe_stack->readfile.bufferlen = 0;
188
+	pxe_stack->readfile.offset = 0;
189
+
190
+#warning "Rewrite pxenv_tftp_get_fsize, please"
191
+	if ( rc ) {
192
+		tftp_get_fsize->FileSize = 0;
193
+		tftp_get_fsize->Status = PXENV_STATUS_FAILURE;
194
+		return PXENV_EXIT_FAILURE;
195
+	}
196
+	tftp_get_fsize->FileSize = pxe_stack->readfile.offset;
197
+	tftp_get_fsize->Status = PXENV_STATUS_SUCCESS;
198
+	return PXENV_EXIT_SUCCESS;
199
+}

+ 44
- 22
src/interface/pxe/pxe_udp.c Просмотреть файл

@@ -5,6 +5,8 @@
5 5
  */
6 6
 
7 7
 #include "pxe.h"
8
+#include "io.h"
9
+#include "string.h"
8 10
 
9 11
 /*
10 12
  * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
@@ -25,13 +27,13 @@
25 27
  */
26 28
 
27 29
 /**
28
- * UDP OPEN (#PXENV_UDP_OPEN)
30
+ * UDP OPEN
29 31
  *
30 32
  * @v udp_open				Pointer to a struct s_PXENV_UDP_OPEN
31 33
  * @v s_PXENV_UDP_OPEN::src_ip		IP address of this station, or 0.0.0.0
32
- * @ret PXENV_EXIT_SUCCESS		Always
34
+ * @ret #PXENV_EXIT_SUCCESS		Always
33 35
  * @ret s_PXENV_UDP_OPEN::Status	PXE status code
34
- * @err PXENV_STATUS_UNDI_INVALID_STATE	NIC could not be initialised
36
+ * @err #PXENV_STATUS_UNDI_INVALID_STATE NIC could not be initialised
35 37
  *
36 38
  * Prepares the PXE stack for communication using pxenv_udp_write()
37 39
  * and pxenv_udp_read().  The IP address supplied in
@@ -49,11 +51,16 @@
49 51
  *   - you take the multiple connections into account when calling
50 52
  *     pxenv_udp_read().
51 53
  *
52
- * You can call pxenv_udp_open() in real mode, 16-bit protected mode
53
- * with a 16-bit stack segment, 16-bit protected mode with a 32-bit
54
- * stack segment, or V86 mode.  The pxe::StatusCallout field may be
55
- * zero even in protected mode.
54
+ * On x86, you can call pxenv_udp_open() in real mode, 16-bit
55
+ * protected mode with a 16-bit stack segment, 16-bit protected mode
56
+ * with a 32-bit stack segment, or V86 mode.  The pxe::StatusCallout
57
+ * field may be zero even in protected mode.
56 58
  * 
59
+ * @note The PXE specification states that you have only one UDP
60
+ * connection open at a time, and that you cannot have a UDP
61
+ * connection open simultaneously with a TFTP connection.  Etherboot
62
+ * does not enforce this unnecessary restriction.
63
+ *
57 64
  */
58 65
 PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *udp_open ) {
59 66
 	DBG ( "PXENV_UDP_OPEN" );
@@ -71,10 +78,10 @@ PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *udp_open ) {
71 78
 }
72 79
 
73 80
 /**
74
- * UDP CLOSE (#PXENV_UDP_CLOSE)
81
+ * UDP CLOSE
75 82
  *
76 83
  * @v udp_close				Pointer to a struct s_PXENV_UDP_CLOSE
77
- * @ret PXENV_EXIT_SUCCESS		Always
84
+ * @ret #PXENV_EXIT_SUCCESS		Always
78 85
  * @ret s_PXENV_UDP_CLOSE::Status	PXE status code
79 86
  * @err None
80 87
  *
@@ -89,6 +96,11 @@ PXENV_EXIT_t pxenv_udp_open ( struct s_PXENV_UDP_OPEN *udp_open ) {
89 96
  * stack segment, or V86 mode.  The pxe::StatusCallout field may be
90 97
  * zero even in protected mode.
91 98
  *
99
+ * @note The PXE specification states that you have only one UDP
100
+ * connection open at a time, and that you cannot have a UDP
101
+ * connection open simultaneously with a TFTP connection.  Etherboot
102
+ * does not enforce this unnecessary restriction.
103
+ *
92 104
  */
93 105
 PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *udp_close __unused ) {
94 106
 	DBG ( "PXENV_UDP_CLOSE" );
@@ -97,7 +109,7 @@ PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *udp_close __unused ) {
97 109
 }
98 110
 
99 111
 /**
100
- * UDP WRITE (#PXENV_UDP_WRITE)
112
+ * UDP WRITE
101 113
  *
102 114
  * @v udp_write				Pointer to a struct s_PXENV_UDP_WRITE
103 115
  * @v s_PXENV_UDP_WRITE::ip		Destination IP address
@@ -106,11 +118,11 @@ PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *udp_close __unused ) {
106 118
  * @v s_PXENV_UDP_WRITE::dst_port	Destination UDP port
107 119
  * @v s_PXENV_UDP_WRITE::buffer_size	Length of the UDP payload
108 120
  * @v s_PXENV_UDP_WRITE::buffer		Address of the UDP payload
109
- * @ret PXENV_EXIT_SUCCESS		Packet was transmitted successfully
110
- * @ret PXENV_EXIT_FAILURE		Packet could not be transmitter
121
+ * @ret #PXENV_EXIT_SUCCESS		Packet was transmitted successfully
122
+ * @ret #PXENV_EXIT_FAILURE		Packet could not be transmitter
111 123
  * @ret s_PXENV_UDP_WRITE::Status	PXE status code
112
- * @err PXENV_STATUS_UNDI_INVALID_STATE	NIC could not be initialised
113
- * @err PXENV_STATUS_OUT_OF_RESOURCES	Packet was too large to transmit
124
+ * @err #PXENV_STATUS_UNDI_INVALID_STATE NIC could not be initialised
125
+ * @err #PXENV_STATUS_OUT_OF_RESOURCES	Packet was too large to transmit
114 126
  * @err other				Any error from pxenv_undi_transmit()
115 127
  *
116 128
  * Transmits a single UDP packet.  A valid IP and UDP header will be
@@ -136,6 +148,11 @@ PXENV_EXIT_t pxenv_udp_close ( struct s_PXENV_UDP_CLOSE *udp_close __unused ) {
136 148
  * stack segment, or V86 mode.  The pxe::StatusCallout field may be
137 149
  * zero even in protected mode.
138 150
  *
151
+ * @note The PXE specification states that you have only one UDP
152
+ * connection open at a time, and that you cannot have a UDP
153
+ * connection open simultaneously with a TFTP connection.  Etherboot
154
+ * does not enforce this unnecessary restriction.
155
+ *
139 156
  * @bug s_PXENV_UDP_WRITE::gw is ignored; the default routing table is
140 157
  * always used.
141 158
  *
@@ -187,7 +204,7 @@ static int await_pxe_udp ( int ival __unused, void *ptr,
187 204
 			   unsigned short ptype __unused,
188 205
 			   struct iphdr *ip, struct udphdr *udp,
189 206
 			   struct tcphdr *tcp __unused ) {
190
-	t_PXENV_UDP_READ *udp_read = (t_PXENV_UDP_READ*)ptr;
207
+	struct s_PXENV_UDP_READ *udp_read = (struct s_PXENV_UDP_READ*)ptr;
191 208
 	uint16_t d_port;
192 209
 	size_t size;
193 210
 
@@ -237,24 +254,24 @@ static int await_pxe_udp ( int ival __unused, void *ptr,
237 254
 }
238 255
 
239 256
 /**
240
- * UDP READ (#PXENV_UDP_READ)
257
+ * UDP READ
241 258
  *
242 259
  * @v udp_read				Pointer to a struct s_PXENV_UDP_READ
243 260
  * @v s_PXENV_UDP_READ::dest_ip		Destination IP address, or 0.0.0.0
244 261
  * @v s_PXENV_UDP_READ::d_port		Destination UDP port, or 0
245 262
  * @v s_PXENV_UDP_READ::buffer_size	Size of the UDP payload buffer
246 263
  * @v s_PXENV_UDP_READ::buffer		Address of the UDP payload buffer
247
- * @ret PXENV_EXIT_SUCCESS		A packet has been received
248
- * @ret PXENV_EXIT_FAILURE		No packet has been received
264
+ * @ret #PXENV_EXIT_SUCCESS		A packet has been received
265
+ * @ret #PXENV_EXIT_FAILURE		No packet has been received
249 266
  * @ret s_PXENV_UDP_READ::Status	PXE status code
250 267
  * @ret s_PXENV_UDP_READ::src_ip	Source IP address
251
- * @ret s_PXEND_UDP_READ::dest_ip	Destination IP address
268
+ * @ret s_PXENV_UDP_READ::dest_ip	Destination IP address
252 269
  * @ret s_PXENV_UDP_READ::s_port	Source UDP port
253 270
  * @ret s_PXENV_UDP_READ::d_port	Destination UDP port
254 271
  * @ret s_PXENV_UDP_READ::buffer_size	Length of UDP payload
255
- * @err PXENV_STATUS_UNDI_INVALID_STATE	NIC could not be initialised
256
- * @err PXENV_STATUS_OUT_OF_RESOURCES	Buffer was too small for payload
257
- * @err PXENV_STATUS_FAILURE		No packet was ready to read
272
+ * @err #PXENV_STATUS_UNDI_INVALID_STATE NIC could not be initialised
273
+ * @err #PXENV_STATUS_OUT_OF_RESOURCES	Buffer was too small for payload
274
+ * @err #PXENV_STATUS_FAILURE		No packet was ready to read
258 275
  *
259 276
  * Receive a single UDP packet.  This is a non-blocking call; if no
260 277
  * packet is ready to read, the call will return instantly with
@@ -277,6 +294,11 @@ static int await_pxe_udp ( int ival __unused, void *ptr,
277 294
  * stack segment, or V86 mode.  The pxe::StatusCallout field may be
278 295
  * zero even in protected mode.
279 296
  *
297
+ * @note The PXE specification states that you have only one UDP
298
+ * connection open at a time, and that you cannot have a UDP
299
+ * connection open simultaneously with a TFTP connection.  Etherboot
300
+ * does not enforce this unnecessary restriction.
301
+ *
280 302
  * @note The PXE specification (version 2.1) does not state that we
281 303
  * should fill in s_PXENV_UDP_READ::dest_ip and
282 304
  * s_PXENV_UDP_READ::d_port, but Microsoft Windows' NTLDR program

+ 538
- 0
src/interface/pxe/pxe_undi.c Просмотреть файл

@@ -0,0 +1,538 @@
1
+/** @file
2
+ *
3
+ * PXE UNDI API
4
+ *
5
+ */
6
+
7
+/*
8
+ * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
9
+ *
10
+ * This program is free software; you can redistribute it and/or
11
+ * modify it under the terms of the GNU General Public License as
12
+ * published by the Free Software Foundation; either version 2 of the
13
+ * License, or any later version.
14
+ *
15
+ * This program is distributed in the hope that it will be useful, but
16
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18
+ * General Public License for more details.
19
+ *
20
+ * You should have received a copy of the GNU General Public License
21
+ * along with this program; if not, write to the Free Software
22
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
+ */
24
+
25
+#include "pxe.h"
26
+
27
+typedef struct {
28
+	char dest[ETH_ALEN];
29
+	char source[ETH_ALEN];
30
+	uint16_t nstype;
31
+} media_header_t;
32
+
33
+static const char broadcast_mac[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF };
34
+
35
+/* PXENV_UNDI_STARTUP
36
+ *
37
+ * Status: working
38
+ */
39
+PXENV_EXIT_t pxenv_undi_startup ( struct s_PXENV_UNDI_STARTUP *undi_startup ) {
40
+	DBG ( "PXENV_UNDI_STARTUP" );
41
+	ENSURE_MIDWAY(undi_startup);
42
+
43
+	undi_startup->Status = PXENV_STATUS_SUCCESS;
44
+	return PXENV_EXIT_SUCCESS;
45
+}
46
+
47
+/* PXENV_UNDI_CLEANUP
48
+ *
49
+ * Status: working
50
+ */
51
+PXENV_EXIT_t pxenv_undi_cleanup ( struct s_PXENV_UNDI_CLEANUP *undi_cleanup ) {
52
+	DBG ( "PXENV_UNDI_CLEANUP" );
53
+	ENSURE_CAN_UNLOAD ( undi_cleanup );
54
+
55
+	undi_cleanup->Status = PXENV_STATUS_SUCCESS;
56
+	return PXENV_EXIT_SUCCESS;
57
+}
58
+
59
+/* PXENV_UNDI_INITIALIZE
60
+ *
61
+ * Status: working
62
+ */
63
+PXENV_EXIT_t pxenv_undi_initialize ( struct s_PXENV_UNDI_INITIALIZE
64
+				     *undi_initialize ) {
65
+	DBG ( "PXENV_UNDI_INITIALIZE" );
66
+	ENSURE_MIDWAY ( undi_initialize );
67
+
68
+	undi_initialize->Status = PXENV_STATUS_SUCCESS;
69
+	return PXENV_EXIT_SUCCESS;
70
+}
71
+
72
+/* PXENV_UNDI_RESET_ADAPTER
73
+ *
74
+ * Status: working
75
+ */
76
+PXENV_EXIT_t pxenv_undi_reset_adapter ( struct s_PXENV_UNDI_RESET
77
+					*undi_reset_adapter ) {
78
+	DBG ( "PXENV_UNDI_RESET_ADAPTER" );
79
+
80
+	ENSURE_MIDWAY ( undi_reset_adapter );
81
+	ENSURE_READY ( undi_reset_adapter );
82
+
83
+	undi_reset_adapter->Status = PXENV_STATUS_SUCCESS;
84
+	return PXENV_EXIT_SUCCESS;
85
+}
86
+
87
+/* PXENV_UNDI_SHUTDOWN
88
+ *
89
+ * Status: working
90
+ */
91
+PXENV_EXIT_t pxenv_undi_shutdown ( struct s_PXENV_UNDI_SHUTDOWN
92
+				   *undi_shutdown ) {
93
+	DBG ( "PXENV_UNDI_SHUTDOWN" );
94
+	ENSURE_MIDWAY ( undi_shutdown );
95
+
96
+	undi_shutdown->Status = PXENV_STATUS_SUCCESS;
97
+	return PXENV_EXIT_SUCCESS;
98
+}
99
+
100
+/* PXENV_UNDI_OPEN
101
+ *
102
+ * Status: working
103
+ */
104
+PXENV_EXIT_t pxenv_undi_open ( struct s_PXENV_UNDI_OPEN *undi_open ) {
105
+	DBG ( "PXENV_UNDI_OPEN" );
106
+	ENSURE_READY ( undi_open );
107
+
108
+	/* PXESPEC: This is where we choose to enable interrupts.
109
+	 * Can't actually find where we're meant to in the PXE spec,
110
+	 * but this should work.
111
+	 */
112
+	eth_irq ( ENABLE );
113
+
114
+	undi_open->Status = PXENV_STATUS_SUCCESS;
115
+	return PXENV_EXIT_SUCCESS;
116
+}
117
+
118
+/* PXENV_UNDI_CLOSE
119
+ *
120
+ * Status: working
121
+ */
122
+PXENV_EXIT_t pxenv_undi_close ( struct s_PXENV_UNDI_CLOSE *undi_close ) {
123
+	DBG ( "PXENV_UNDI_CLOSE" );
124
+	ENSURE_MIDWAY ( undi_close );
125
+
126
+	undi_close->Status = PXENV_STATUS_SUCCESS;
127
+	return PXENV_EXIT_SUCCESS;
128
+}
129
+
130
+/* PXENV_UNDI_TRANSMIT
131
+ *
132
+ * Status: working
133
+ */
134
+PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT
135
+				   *undi_transmit ) {
136
+	struct s_PXENV_UNDI_TBD *tbd;
137
+	const char *dest;
138
+	unsigned int type;
139
+	unsigned int length;
140
+	const char *data;
141
+	media_header_t *media_header;
142
+
143
+	DBG ( "PXENV_UNDI_TRANSMIT" );
144
+	ENSURE_READY ( undi_transmit );
145
+
146
+	/* We support only the "immediate" portion of the TBD.  Who
147
+	 * knows what Intel's "engineers" were smoking when they came
148
+	 * up with the array of transmit data blocks...
149
+	 */
150
+	tbd = SEGOFF16_TO_PTR ( undi_transmit->TBD );
151
+	if ( tbd->DataBlkCount > 0 ) {
152
+		undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
153
+		return PXENV_EXIT_FAILURE;
154
+	}
155
+	data = SEGOFF16_TO_PTR ( tbd->Xmit );
156
+	length = tbd->ImmedLength;
157
+
158
+	/* If destination is broadcast, we need to supply the MAC address */
159
+	if ( undi_transmit->XmitFlag == XMT_BROADCAST ) {
160
+		dest = broadcast_mac;
161
+	} else {
162
+		dest = SEGOFF16_TO_PTR ( undi_transmit->DestAddr );
163
+	}
164
+
165
+	/* We can't properly support P_UNKNOWN without rewriting all
166
+	 * the driver transmit() methods, so we cheat: if P_UNKNOWN is
167
+	 * specified we rip the destination address and type out of
168
+	 * the pre-assembled packet, then skip over the header.
169
+	 */
170
+	switch ( undi_transmit->Protocol ) {
171
+	case P_IP:	type = IP;	break;
172
+	case P_ARP:	type = ARP;	break;
173
+	case P_RARP:	type = RARP;	break;
174
+	case P_UNKNOWN:
175
+		media_header = (media_header_t*)data;
176
+		dest = media_header->dest;
177
+		type = ntohs ( media_header->nstype );
178
+		data += ETH_HLEN;
179
+		length -= ETH_HLEN;
180
+		break;
181
+	default:
182
+		undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
183
+		return PXENV_EXIT_FAILURE;
184
+	}
185
+
186
+	/* Send the packet */
187
+	eth_transmit ( dest, type, length, data );
188
+	
189
+	undi_transmit->Status = PXENV_STATUS_SUCCESS;
190
+	return PXENV_EXIT_SUCCESS;
191
+}
192
+
193
+/* PXENV_UNDI_SET_MCAST_ADDRESS
194
+ *
195
+ * Status: stub (no PXE multicast support)
196
+ */
197
+PXENV_EXIT_t
198
+pxenv_undi_set_mcast_address ( struct s_PXENV_UNDI_SET_MCAST_ADDRESS
199
+			       *undi_set_mcast_address ) {
200
+	DBG ( "PXENV_UNDI_SET_MCAST_ADDRESS" );
201
+	/* ENSURE_READY ( undi_set_mcast_address ); */
202
+	undi_set_mcast_address->Status = PXENV_STATUS_UNSUPPORTED;
203
+	return PXENV_EXIT_FAILURE;
204
+}
205
+
206
+/* PXENV_UNDI_SET_STATION_ADDRESS
207
+ *
208
+ * Status: working (deliberately incomplete)
209
+ */
210
+PXENV_EXIT_t 
211
+pxenv_undi_set_station_address ( struct s_PXENV_UNDI_SET_STATION_ADDRESS
212
+				 *undi_set_station_address ) {
213
+	DBG ( "PXENV_UNDI_SET_STATION_ADDRESS" );
214
+	ENSURE_READY ( undi_set_station_address );
215
+
216
+	/* We don't offer a facility to set the MAC address; this
217
+	 * would require adding extra code to all the Etherboot
218
+	 * drivers, for very little benefit.  If we're setting it to
219
+	 * the current value anyway then return success, otherwise
220
+	 * return UNSUPPORTED.
221
+	 */
222
+	if ( memcmp ( nic.node_addr,
223
+		      &undi_set_station_address->StationAddress,
224
+		      ETH_ALEN ) == 0 ) {
225
+		undi_set_station_address->Status = PXENV_STATUS_SUCCESS;
226
+		return PXENV_EXIT_SUCCESS;
227
+	}
228
+	undi_set_station_address->Status = PXENV_STATUS_UNSUPPORTED;
229
+	return PXENV_EXIT_FAILURE;
230
+}
231
+
232
+/* PXENV_UNDI_SET_PACKET_FILTER
233
+ *
234
+ * Status: won't implement (would require driver API changes for no
235
+ * real benefit)
236
+ */
237
+PXENV_EXIT_t
238
+pxenv_undi_set_packet_filter ( struct s_PXENV_UNDI_SET_PACKET_FILTER
239
+			       *undi_set_packet_filter ) {
240
+	DBG ( "PXENV_UNDI_SET_PACKET_FILTER" );
241
+	/* ENSURE_READY ( undi_set_packet_filter ); */
242
+	undi_set_packet_filter->Status = PXENV_STATUS_UNSUPPORTED;
243
+	return PXENV_EXIT_FAILURE;
244
+}
245
+
246
+/* PXENV_UNDI_GET_INFORMATION
247
+ *
248
+ * Status: working
249
+ */
250
+PXENV_EXIT_t pxenv_undi_get_information ( struct s_PXENV_UNDI_GET_INFORMATION
251
+					  *undi_get_information ) {
252
+	DBG ( "PXENV_UNDI_GET_INFORMATION" );
253
+	ENSURE_READY ( undi_get_information );
254
+
255
+	undi_get_information->BaseIo = nic.ioaddr;
256
+	undi_get_information->IntNumber = nic.irqno;
257
+	/* Cheat: assume all cards can cope with this */
258
+	undi_get_information->MaxTranUnit = ETH_MAX_MTU;
259
+	/* Cheat: we only ever have Ethernet cards */
260
+	undi_get_information->HwType = ETHER_TYPE;
261
+	undi_get_information->HwAddrLen = ETH_ALEN;
262
+	/* Cheat: assume card is always configured with its permanent
263
+	 * node address.  This is a valid assumption within Etherboot
264
+	 * at the time of writing.
265
+	 */
266
+	memcpy ( &undi_get_information->CurrentNodeAddress, nic.node_addr,
267
+		 ETH_ALEN );
268
+	memcpy ( &undi_get_information->PermNodeAddress, nic.node_addr,
269
+		 ETH_ALEN );
270
+	undi_get_information->ROMAddress = 0;
271
+		/* nic.rom_info->rom_segment; */
272
+	/* We only provide the ability to receive or transmit a single
273
+	 * packet at a time.  This is a bootloader, not an OS.
274
+	 */
275
+	undi_get_information->RxBufCt = 1;
276
+	undi_get_information->TxBufCt = 1;
277
+	undi_get_information->Status = PXENV_STATUS_SUCCESS;
278
+	return PXENV_EXIT_SUCCESS;
279
+}
280
+
281
+/* PXENV_UNDI_GET_STATISTICS
282
+ *
283
+ * Status: won't implement (would require driver API changes for no
284
+ * real benefit)
285
+ */
286
+PXENV_EXIT_t pxenv_undi_get_statistics ( struct s_PXENV_UNDI_GET_STATISTICS
287
+					 *undi_get_statistics ) {
288
+	DBG ( "PXENV_UNDI_GET_STATISTICS" );
289
+	/* ENSURE_READY ( undi_get_statistics ); */
290
+	undi_get_statistics->Status = PXENV_STATUS_UNSUPPORTED;
291
+	return PXENV_EXIT_FAILURE;
292
+}
293
+
294
+/* PXENV_UNDI_CLEAR_STATISTICS
295
+ *
296
+ * Status: won't implement (would require driver API changes for no
297
+ * real benefit)
298
+ */
299
+PXENV_EXIT_t pxenv_undi_clear_statistics ( struct s_PXENV_UNDI_CLEAR_STATISTICS
300
+					   *undi_clear_statistics ) {
301
+	DBG ( "PXENV_UNDI_CLEAR_STATISTICS" );
302
+	/* ENSURE_READY ( undi_clear_statistics ); */
303
+	undi_clear_statistics->Status = PXENV_STATUS_UNSUPPORTED;
304
+	return PXENV_EXIT_FAILURE;
305
+}
306
+
307
+/* PXENV_UNDI_INITIATE_DIAGS
308
+ *
309
+ * Status: won't implement (would require driver API changes for no
310
+ * real benefit)
311
+ */
312
+PXENV_EXIT_t pxenv_undi_initiate_diags ( struct s_PXENV_UNDI_INITIATE_DIAGS
313
+					 *undi_initiate_diags ) {
314
+	DBG ( "PXENV_UNDI_INITIATE_DIAGS" );
315
+	/* ENSURE_READY ( undi_initiate_diags ); */
316
+	undi_initiate_diags->Status = PXENV_STATUS_UNSUPPORTED;
317
+	return PXENV_EXIT_FAILURE;
318
+}
319
+
320
+/* PXENV_UNDI_FORCE_INTERRUPT
321
+ *
322
+ * Status: working
323
+ */
324
+PXENV_EXIT_t pxenv_undi_force_interrupt ( struct s_PXENV_UNDI_FORCE_INTERRUPT
325
+					  *undi_force_interrupt ) {
326
+	DBG ( "PXENV_UNDI_FORCE_INTERRUPT" );
327
+	ENSURE_READY ( undi_force_interrupt );
328
+
329
+	eth_irq ( FORCE );
330
+	undi_force_interrupt->Status = PXENV_STATUS_SUCCESS;
331
+	return PXENV_EXIT_SUCCESS;
332
+}
333
+
334
+/* PXENV_UNDI_GET_MCAST_ADDRESS
335
+ *
336
+ * Status: stub (no PXE multicast support)
337
+ */
338
+PXENV_EXIT_t
339
+pxenv_undi_get_mcast_address ( struct s_PXENV_UNDI_GET_MCAST_ADDRESS
340
+			       *undi_get_mcast_address ) {
341
+	DBG ( "PXENV_UNDI_GET_MCAST_ADDRESS" );
342
+	/* ENSURE_READY ( undi_get_mcast_address ); */
343
+	undi_get_mcast_address->Status = PXENV_STATUS_UNSUPPORTED;
344
+	return PXENV_EXIT_FAILURE;
345
+}
346
+
347
+/* PXENV_UNDI_GET_NIC_TYPE
348
+ *
349
+ * Status: working
350
+ */
351
+PXENV_EXIT_t pxenv_undi_get_nic_type ( struct s_PXENV_UNDI_GET_NIC_TYPE
352
+				       *undi_get_nic_type ) {
353
+#warning "device probing mechanism has changed completely"
354
+
355
+#if 0
356
+	struct dev *dev = &dev;
357
+	
358
+	DBG ( "PXENV_UNDI_GET_NIC_TYPE" );
359
+	ENSURE_READY ( undi_get_nic_type );
360
+	
361
+	if ( dev->to_probe == PROBE_PCI ) {
362
+		struct pci_device *pci = &dev->state.pci.dev;
363
+
364
+		undi_get_nic_type->NicType = PCI_NIC;
365
+		undi_get_nic_type->info.pci.Vendor_ID = pci->vendor;
366
+		undi_get_nic_type->info.pci.Dev_ID = pci->dev_id;
367
+		undi_get_nic_type->info.pci.Base_Class = pci->class >> 8;
368
+		undi_get_nic_type->info.pci.Sub_Class = pci->class & 0xff;
369
+		undi_get_nic_type->info.pci.BusDevFunc =
370
+			( pci->bus << 8 ) | pci->devfn;
371
+		/* Cheat: these fields are probably unnecessary, and
372
+		 * would require adding extra code to pci.c.
373
+		 */
374
+		undi_get_nic_type->info.pci.Prog_Intf = 0;
375
+		undi_get_nic_type->info.pci.Rev = 0;
376
+		undi_get_nic_type->info.pci.SubVendor_ID = 0xffff;
377
+		undi_get_nic_type->info.pci.SubDevice_ID = 0xffff;
378
+	} else if ( dev->to_probe == PROBE_ISA ) {
379
+		/* const struct isa_driver *isa = dev->state.isa.driver; */
380
+
381
+		undi_get_nic_type->NicType = PnP_NIC;
382
+		/* Don't think anything fills these fields in, and
383
+		 * probably no-one will ever be interested in them.
384
+		 */
385
+		undi_get_nic_type->info.pnp.EISA_Dev_ID = 0;
386
+		undi_get_nic_type->info.pnp.Base_Class = 0;
387
+		undi_get_nic_type->info.pnp.Sub_Class = 0;
388
+		undi_get_nic_type->info.pnp.Prog_Intf = 0;
389
+		undi_get_nic_type->info.pnp.CardSelNum = 0;
390
+	} else {
391
+		/* PXESPEC: There doesn't seem to be an "unknown type"
392
+		 * defined.
393
+		 */
394
+		undi_get_nic_type->NicType = 0;
395
+	}
396
+	undi_get_nic_type->Status = PXENV_STATUS_SUCCESS;
397
+	return PXENV_EXIT_SUCCESS;
398
+
399
+#endif
400
+}
401
+
402
+/* PXENV_UNDI_GET_IFACE_INFO
403
+ *
404
+ * Status: working
405
+ */
406
+PXENV_EXIT_t pxenv_undi_get_iface_info ( struct s_PXENV_UNDI_GET_IFACE_INFO
407
+					 *undi_get_iface_info ) {
408
+	DBG ( "PXENV_UNDI_GET_IFACE_INFO" );
409
+	ENSURE_READY ( undi_get_iface_info );
410
+
411
+	/* Just hand back some info, doesn't really matter what it is.
412
+	 * Most PXE stacks seem to take this approach.
413
+	 */
414
+	sprintf ( undi_get_iface_info->IfaceType, "Etherboot" );
415
+	undi_get_iface_info->LinkSpeed = 10000000; /* 10 Mbps */
416
+	undi_get_iface_info->ServiceFlags = 0;
417
+	memset ( undi_get_iface_info->Reserved, 0,
418
+		 sizeof(undi_get_iface_info->Reserved) );
419
+	undi_get_iface_info->Status = PXENV_STATUS_SUCCESS;
420
+	return PXENV_EXIT_SUCCESS;
421
+}
422
+
423
+/* PXENV_UNDI_GET_STATE
424
+ *
425
+ * Status: impossible
426
+ */
427
+PXENV_EXIT_t pxenv_undi_get_state ( struct s_PXENV_UNDI_GET_STATE
428
+				    *undi_get_state ) {
429
+	undi_get_state->Status = PXENV_STATUS_UNSUPPORTED;
430
+	return PXENV_EXIT_FAILURE;
431
+};
432
+
433
+/* PXENV_UNDI_ISR
434
+ *
435
+ * Status: working
436
+ */
437
+PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
438
+	media_header_t *media_header = (media_header_t*)nic.packet;
439
+
440
+	DBG ( "PXENV_UNDI_ISR" );
441
+	/* We can't call ENSURE_READY, because this could be being
442
+	 * called as part of an interrupt service routine.  Instead,
443
+	 * we should simply die if we're not READY.
444
+	 */
445
+	if ( ( pxe_stack == NULL ) || ( pxe_stack->state < READY ) ) {
446
+		undi_isr->Status = PXENV_STATUS_UNDI_INVALID_STATE;
447
+		return PXENV_EXIT_FAILURE;
448
+	}
449
+	
450
+	/* Just in case some idiot actually looks at these fields when
451
+	 * we weren't meant to fill them in...
452
+	 */
453
+	undi_isr->BufferLength = 0;
454
+	undi_isr->FrameLength = 0;
455
+	undi_isr->FrameHeaderLength = 0;
456
+	undi_isr->ProtType = 0;
457
+	undi_isr->PktType = 0;
458
+
459
+	switch ( undi_isr->FuncFlag ) {
460
+	case PXENV_UNDI_ISR_IN_START :
461
+		/* Is there a packet waiting?  If so, disable
462
+		 * interrupts on the NIC and return "it's ours".  Do
463
+		 * *not* necessarily acknowledge the interrupt; this
464
+		 * can happen later when eth_poll(1) is called.  As
465
+		 * long as the interrupt is masked off so that it
466
+		 * doesn't immediately retrigger the 8259A then all
467
+		 * should be well.
468
+		 */
469
+		DBG ( " START" );
470
+		if ( eth_poll ( 0 ) ) {
471
+			DBG ( " OURS" );
472
+			eth_irq ( DISABLE );
473
+			undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS;
474
+		} else {
475
+			DBG ( " NOT_OURS" );
476
+			undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_NOT_OURS;
477
+		}
478
+		break;
479
+	case PXENV_UNDI_ISR_IN_PROCESS :
480
+		/* Call poll(), return packet.  If no packet, return "done".
481
+		 */
482
+		DBG ( " PROCESS" );
483
+		if ( eth_poll ( 1 ) ) {
484
+			DBG ( " RECEIVE %d", nic.packetlen );
485
+			if ( nic.packetlen > sizeof(pxe_stack->packet) ) {
486
+				/* Should never happen */
487
+				undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
488
+				undi_isr->Status =
489
+					PXENV_STATUS_OUT_OF_RESOURCES;
490
+				return PXENV_EXIT_FAILURE;
491
+			}
492
+			undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE;
493
+			undi_isr->BufferLength = nic.packetlen;
494
+			undi_isr->FrameLength = nic.packetlen;
495
+			undi_isr->FrameHeaderLength = ETH_HLEN;
496
+			memcpy ( pxe_stack->packet, nic.packet, nic.packetlen);
497
+			PTR_TO_SEGOFF16 ( pxe_stack->packet, undi_isr->Frame );
498
+			switch ( ntohs(media_header->nstype) ) {
499
+			case IP :	undi_isr->ProtType = P_IP;	break;
500
+			case ARP :	undi_isr->ProtType = P_ARP;	break;
501
+			case RARP :	undi_isr->ProtType = P_RARP;	break;
502
+			default :	undi_isr->ProtType = P_UNKNOWN;
503
+			}
504
+			if ( memcmp ( media_header->dest, broadcast_mac,
505
+				      sizeof(broadcast_mac) ) ) {
506
+				undi_isr->PktType = XMT_BROADCAST;
507
+			} else {
508
+				undi_isr->PktType = XMT_DESTADDR;
509
+			}
510
+			break;
511
+		} else {
512
+			/* No break - fall through to IN_GET_NEXT */
513
+		}
514
+	case PXENV_UNDI_ISR_IN_GET_NEXT :
515
+		/* We only ever return one frame at a time */
516
+		DBG ( " GET_NEXT DONE" );
517
+		/* Re-enable interrupts */
518
+		eth_irq ( ENABLE );
519
+		/* Force an interrupt if there's a packet still
520
+		 * waiting, since we only handle one packet per
521
+		 * interrupt.
522
+		 */
523
+		if ( eth_poll ( 0 ) ) {
524
+			DBG ( " (RETRIGGER)" );
525
+			eth_irq ( FORCE );
526
+		}
527
+		undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
528
+		break;
529
+	default :
530
+		/* Should never happen */
531
+		undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
532
+		undi_isr->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
533
+		return PXENV_EXIT_FAILURE;
534
+	}
535
+
536
+	undi_isr->Status = PXENV_STATUS_SUCCESS;
537
+	return PXENV_EXIT_SUCCESS;
538
+}

Загрузка…
Отмена
Сохранить