Browse Source

[pxe] Separate parent PXE API caller from UNDINET driver

Calling the parent PXE stack (the stack that loaded us, for
undionly.kkpxe) can be useful for more than UNDI calls; for instance,
it lets us get cached DHCP packets to avoid re-DHCP when working with
embedded images.

Signed-off-by: Marty Connor <mdc@etherboot.org>
tags/v1.0.0-rc1
Joshua Oreman 14 years ago
parent
commit
337e1ed4b4

+ 1
- 0
src/arch/i386/Makefile View File

@@ -80,6 +80,7 @@ SRCDIRS		+= arch/i386/drivers
80 80
 SRCDIRS		+= arch/i386/drivers/net
81 81
 SRCDIRS		+= arch/i386/interface/pcbios
82 82
 SRCDIRS		+= arch/i386/interface/pxe
83
+SRCDIRS		+= arch/i386/interface/pxeparent
83 84
 SRCDIRS 	+= arch/i386/interface/syslinux
84 85
 SRCDIRS		+= arch/i386/hci/commands
85 86
 

+ 2
- 2
src/arch/i386/drivers/net/undiisr.S View File

@@ -31,7 +31,7 @@ undiisr:
31 31
 	movw	%ax, %ds
32 32
 
33 33
 	/* Check that we have an UNDI entry point */
34
-	cmpw	$0, undinet_entry_point
34
+	cmpw	$0, pxeparent_entry_point
35 35
 	je	chain
36 36
 	
37 37
 	/* Issue UNDI API call */
@@ -42,7 +42,7 @@ undiisr:
42 42
 	pushw	%es
43 43
 	pushw	%di
44 44
 	pushw	%bx
45
-	lcall	*undinet_entry_point
45
+	lcall	*pxeparent_entry_point
46 46
 	cli	/* Just in case */
47 47
 	addw	$6, %sp
48 48
 	cmpw	$PXENV_UNDI_ISR_OUT_OURS, funcflag

+ 47
- 214
src/arch/i386/drivers/net/undinet.c View File

@@ -32,6 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
32 32
 #include <gpxe/ethernet.h>
33 33
 #include <undi.h>
34 34
 #include <undinet.h>
35
+#include <pxeparent.h>
35 36
 
36 37
 
37 38
 /** @file
@@ -62,178 +63,8 @@ struct undi_nic {
62 63
 
63 64
 static void undinet_close ( struct net_device *netdev );
64 65
 
65
-/*****************************************************************************
66
- *
67
- * UNDI API call
68
- *
69
- *****************************************************************************
70
- */
71
-
72
-/**
73
- * Name UNDI API call
74
- *
75
- * @v function		API call number
76
- * @ret name		API call name
77
- */
78
-static inline __attribute__ (( always_inline )) const char *
79
-undinet_function_name ( unsigned int function ) {
80
-	switch ( function ) {
81
-	case PXENV_START_UNDI:
82
-		return "PXENV_START_UNDI";
83
-	case PXENV_STOP_UNDI:
84
-		return "PXENV_STOP_UNDI";
85
-	case PXENV_UNDI_STARTUP:
86
-		return "PXENV_UNDI_STARTUP";
87
-	case PXENV_UNDI_CLEANUP:
88
-		return "PXENV_UNDI_CLEANUP";
89
-	case PXENV_UNDI_INITIALIZE:
90
-		return "PXENV_UNDI_INITIALIZE";
91
-	case PXENV_UNDI_RESET_ADAPTER:
92
-		return "PXENV_UNDI_RESET_ADAPTER";
93
-	case PXENV_UNDI_SHUTDOWN:
94
-		return "PXENV_UNDI_SHUTDOWN";
95
-	case PXENV_UNDI_OPEN:
96
-		return "PXENV_UNDI_OPEN";
97
-	case PXENV_UNDI_CLOSE:
98
-		return "PXENV_UNDI_CLOSE";
99
-	case PXENV_UNDI_TRANSMIT:
100
-		return "PXENV_UNDI_TRANSMIT";
101
-	case PXENV_UNDI_SET_MCAST_ADDRESS:
102
-		return "PXENV_UNDI_SET_MCAST_ADDRESS";
103
-	case PXENV_UNDI_SET_STATION_ADDRESS:
104
-		return "PXENV_UNDI_SET_STATION_ADDRESS";
105
-	case PXENV_UNDI_SET_PACKET_FILTER:
106
-		return "PXENV_UNDI_SET_PACKET_FILTER";
107
-	case PXENV_UNDI_GET_INFORMATION:
108
-		return "PXENV_UNDI_GET_INFORMATION";
109
-	case PXENV_UNDI_GET_STATISTICS:
110
-		return "PXENV_UNDI_GET_STATISTICS";
111
-	case PXENV_UNDI_CLEAR_STATISTICS:
112
-		return "PXENV_UNDI_CLEAR_STATISTICS";
113
-	case PXENV_UNDI_INITIATE_DIAGS:
114
-		return "PXENV_UNDI_INITIATE_DIAGS";
115
-	case PXENV_UNDI_FORCE_INTERRUPT:
116
-		return "PXENV_UNDI_FORCE_INTERRUPT";
117
-	case PXENV_UNDI_GET_MCAST_ADDRESS:
118
-		return "PXENV_UNDI_GET_MCAST_ADDRESS";
119
-	case PXENV_UNDI_GET_NIC_TYPE:
120
-		return "PXENV_UNDI_GET_NIC_TYPE";
121
-	case PXENV_UNDI_GET_IFACE_INFO:
122
-		return "PXENV_UNDI_GET_IFACE_INFO";
123
-	/*
124
-	 * Duplicate case value; this is a bug in the PXE specification.
125
-	 *
126
-	 *	case PXENV_UNDI_GET_STATE:
127
-	 *		return "PXENV_UNDI_GET_STATE";
128
-	 */
129
-	case PXENV_UNDI_ISR:
130
-		return "PXENV_UNDI_ISR";
131
-	default:
132
-		return "UNKNOWN API CALL";
133
-	}
134
-}
135
-
136
-/**
137
- * UNDI parameter block
138
- *
139
- * Used as the paramter block for all UNDI API calls.  Resides in base
140
- * memory.
141
- */
142
-static union u_PXENV_ANY __bss16 ( undinet_params );
143
-#define undinet_params __use_data16 ( undinet_params )
144
-
145
-/** UNDI entry point
146
- *
147
- * Used as the indirection vector for all UNDI API calls.  Resides in
148
- * base memory.
149
- */
150
-SEGOFF16_t __bss16 ( undinet_entry_point );
151
-#define undinet_entry_point __use_data16 ( undinet_entry_point )
152
-
153
-/**
154
- * Issue UNDI API call
155
- *
156
- * @v undinic		UNDI NIC
157
- * @v function		API call number
158
- * @v params		UNDI parameter block
159
- * @v params_len	Length of UNDI parameter block
160
- * @ret rc		Return status code
161
- */
162
-static int undinet_call ( struct undi_nic *undinic, unsigned int function,
163
-			  void *params, size_t params_len ) {
164
-	PXENV_EXIT_t exit;
165
-	int discard_b, discard_D;
166
-	int rc;
167
-
168
-	/* Copy parameter block and entry point */
169
-	assert ( params_len <= sizeof ( undinet_params ) );
170
-	memcpy ( &undinet_params, params, params_len );
171
-
172
-	/* Call real-mode entry point.  This calling convention will
173
-	 * work with both the !PXE and the PXENV+ entry points.
174
-	 */
175
-	__asm__ __volatile__ ( REAL_CODE ( "pushw %%es\n\t"
176
-					   "pushw %%di\n\t"
177
-					   "pushw %%bx\n\t"
178
-					   "lcall *undinet_entry_point\n\t"
179
-					   "addw $6, %%sp\n\t" )
180
-			       : "=a" ( exit ), "=b" ( discard_b ),
181
-			         "=D" ( discard_D )
182
-			       : "b" ( function ),
183
-			         "D" ( __from_data16 ( &undinet_params ) )
184
-			       : "ecx", "edx", "esi", "ebp" );
185
-
186
-	/* UNDI API calls may rudely change the status of A20 and not
187
-	 * bother to restore it afterwards.  Intel is known to be
188
-	 * guilty of this.
189
-	 *
190
-	 * Note that we will return to this point even if A20 gets
191
-	 * screwed up by the UNDI driver, because Etherboot always
192
-	 * resides in an even megabyte of RAM.
193
-	 */	
194
-	gateA20_set();
195
-
196
-	/* Determine return status code based on PXENV_EXIT and
197
-	 * PXENV_STATUS
198
-	 */
199
-	if ( exit == PXENV_EXIT_SUCCESS ) {
200
-		rc = 0;
201
-	} else {
202
-		rc = -undinet_params.Status;
203
-		/* Paranoia; don't return success for the combination
204
-		 * of PXENV_EXIT_FAILURE but PXENV_STATUS_SUCCESS
205
-		 */
206
-		if ( rc == 0 )
207
-			rc = -EIO;
208
-	}
209
-
210
-	/* If anything goes wrong, print as much debug information as
211
-	 * it's possible to give.
212
-	 */
213
-	if ( rc != 0 ) {
214
-		SEGOFF16_t rm_params = {
215
-			.segment = rm_ds,
216
-			.offset = __from_data16 ( &undinet_params ),
217
-		};
218
-
219
-		DBGC ( undinic, "UNDINIC %p %s failed: %s\n", undinic,
220
-		       undinet_function_name ( function ), strerror ( rc ) );
221
-		DBGC ( undinic, "UNDINIC %p parameters at %04x:%04x length "
222
-		       "%#02zx, entry point at %04x:%04x\n", undinic,
223
-		       rm_params.segment, rm_params.offset, params_len,
224
-		       undinet_entry_point.segment,
225
-		       undinet_entry_point.offset );
226
-		DBGC ( undinic, "UNDINIC %p parameters provided:\n", undinic );
227
-		DBGC_HDA ( undinic, rm_params, params, params_len );
228
-		DBGC ( undinic, "UNDINIC %p parameters returned:\n", undinic );
229
-		DBGC_HDA ( undinic, rm_params, &undinet_params, params_len );
230
-	}
231
-
232
-	/* Copy parameter block back */
233
-	memcpy ( params, &undinet_params, params_len );
234
-
235
-	return rc;
236
-}
66
+/** Address of UNDI entry point */
67
+static SEGOFF16_t undinet_entry;
237 68
 
238 69
 /*****************************************************************************
239 70
  *
@@ -336,7 +167,6 @@ static struct s_PXENV_UNDI_TBD __data16 ( undinet_tbd );
336 167
  */
337 168
 static int undinet_transmit ( struct net_device *netdev,
338 169
 			      struct io_buffer *iobuf ) {
339
-	struct undi_nic *undinic = netdev->priv;
340 170
 	struct s_PXENV_UNDI_TRANSMIT undi_transmit;
341 171
 	size_t len = iob_len ( iobuf );
342 172
 	int rc;
@@ -369,9 +199,9 @@ static int undinet_transmit ( struct net_device *netdev,
369 199
 	undinet_tbd.Xmit.offset = __from_data16 ( basemem_packet );
370 200
 
371 201
 	/* Issue PXE API call */
372
-	if ( ( rc = undinet_call ( undinic, PXENV_UNDI_TRANSMIT,
373
-				   &undi_transmit,
374
-				   sizeof ( undi_transmit ) ) ) != 0 )
202
+	if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_TRANSMIT,
203
+				     &undi_transmit,
204
+				     sizeof ( undi_transmit ) ) ) != 0 )
375 205
 		goto done;
376 206
 
377 207
 	/* Free I/O buffer */
@@ -441,8 +271,9 @@ static void undinet_poll ( struct net_device *netdev ) {
441 271
 
442 272
 	/* Run through the ISR loop */
443 273
 	while ( 1 ) {
444
-		if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr,
445
-					   sizeof ( undi_isr ) ) ) != 0 )
274
+		if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_ISR,
275
+					     &undi_isr,
276
+					     sizeof ( undi_isr ) ) ) != 0 )
446 277
 			break;
447 278
 		switch ( undi_isr.FuncFlag ) {
448 279
 		case PXENV_UNDI_ISR_OUT_TRANSMIT:
@@ -538,8 +369,8 @@ static int undinet_open ( struct net_device *netdev ) {
538 369
 	 */
539 370
 	memcpy ( undi_set_address.StationAddress, netdev->ll_addr,
540 371
 		 sizeof ( undi_set_address.StationAddress ) );
541
-	undinet_call ( undinic, PXENV_UNDI_SET_STATION_ADDRESS,
542
-		       &undi_set_address, sizeof ( undi_set_address ) );
372
+	pxeparent_call ( undinet_entry, PXENV_UNDI_SET_STATION_ADDRESS,
373
+			 &undi_set_address, sizeof ( undi_set_address ) );
543 374
 
544 375
 	/* Open NIC.  We ask for promiscuous operation, since it's the
545 376
 	 * only way to ask for all multicast addresses.  On any
@@ -548,8 +379,8 @@ static int undinet_open ( struct net_device *netdev ) {
548 379
 	 */
549 380
 	memset ( &undi_open, 0, sizeof ( undi_open ) );
550 381
 	undi_open.PktFilter = ( FLTR_DIRECTED | FLTR_BRDCST | FLTR_PRMSCS );
551
-	if ( ( rc = undinet_call ( undinic, PXENV_UNDI_OPEN, &undi_open,
552
-				   sizeof ( undi_open ) ) ) != 0 )
382
+	if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_OPEN,
383
+				     &undi_open, sizeof ( undi_open ) ) ) != 0 )
553 384
 		goto err;
554 385
 
555 386
 	DBGC ( undinic, "UNDINIC %p opened\n", undinic );
@@ -574,8 +405,9 @@ static void undinet_close ( struct net_device *netdev ) {
574 405
 	/* Ensure ISR has exited cleanly */
575 406
 	while ( undinic->isr_processing ) {
576 407
 		undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
577
-		if ( ( rc = undinet_call ( undinic, PXENV_UNDI_ISR, &undi_isr,
578
-					   sizeof ( undi_isr ) ) ) != 0 )
408
+		if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_ISR,
409
+					     &undi_isr,
410
+					     sizeof ( undi_isr ) ) ) != 0 )
579 411
 			break;
580 412
 		switch ( undi_isr.FuncFlag ) {
581 413
 		case PXENV_UNDI_ISR_OUT_TRANSMIT:
@@ -590,8 +422,8 @@ static void undinet_close ( struct net_device *netdev ) {
590 422
 	}
591 423
 
592 424
 	/* Close NIC */
593
-	undinet_call ( undinic, PXENV_UNDI_CLOSE, &undi_close,
594
-		       sizeof ( undi_close ) );
425
+	pxeparent_call ( undinet_entry, PXENV_UNDI_CLOSE,
426
+			 &undi_close, sizeof ( undi_close ) );
595 427
 
596 428
 	/* Disable interrupt and unhook ISR */
597 429
 	disable_irq ( undinic->irq );
@@ -651,7 +483,7 @@ int undinet_probe ( struct undi_device *undi ) {
651 483
 	undi_set_drvdata ( undi, netdev );
652 484
 	netdev->dev = &undi->dev;
653 485
 	memset ( undinic, 0, sizeof ( *undinic ) );
654
-	undinet_entry_point = undi->entry;
486
+	undinet_entry = undi->entry;
655 487
 	DBGC ( undinic, "UNDINIC %p using UNDI %p\n", undinic, undi );
656 488
 
657 489
 	/* Hook in UNDI stack */
@@ -662,9 +494,9 @@ int undinet_probe ( struct undi_device *undi ) {
662 494
 		start_undi.DX = undi->isapnp_read_port;
663 495
 		start_undi.ES = BIOS_SEG;
664 496
 		start_undi.DI = find_pnp_bios();
665
-		if ( ( rc = undinet_call ( undinic, PXENV_START_UNDI,
666
-					   &start_undi,
667
-					   sizeof ( start_undi ) ) ) != 0 )
497
+		if ( ( rc = pxeparent_call ( undinet_entry, PXENV_START_UNDI,
498
+					     &start_undi,
499
+					     sizeof ( start_undi ) ) ) != 0 )
668 500
 			goto err_start_undi;
669 501
 	}
670 502
 	undi->flags |= UNDI_FL_STARTED;
@@ -672,22 +504,23 @@ int undinet_probe ( struct undi_device *undi ) {
672 504
 	/* Bring up UNDI stack */
673 505
 	if ( ! ( undi->flags & UNDI_FL_INITIALIZED ) ) {
674 506
 		memset ( &undi_startup, 0, sizeof ( undi_startup ) );
675
-		if ( ( rc = undinet_call ( undinic, PXENV_UNDI_STARTUP,
676
-					   &undi_startup,
677
-					   sizeof ( undi_startup ) ) ) != 0 )
507
+		if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_STARTUP,
508
+					     &undi_startup,
509
+					     sizeof ( undi_startup ) ) ) != 0 )
678 510
 			goto err_undi_startup;
679 511
 		memset ( &undi_initialize, 0, sizeof ( undi_initialize ) );
680
-		if ( ( rc = undinet_call ( undinic, PXENV_UNDI_INITIALIZE,
681
-					   &undi_initialize,
682
-					   sizeof ( undi_initialize ))) != 0 )
512
+		if ( ( rc = pxeparent_call ( undinet_entry,
513
+					     PXENV_UNDI_INITIALIZE,
514
+					     &undi_initialize,
515
+					     sizeof ( undi_initialize ))) != 0 )
683 516
 			goto err_undi_initialize;
684 517
 	}
685 518
 	undi->flags |= UNDI_FL_INITIALIZED;
686 519
 
687 520
 	/* Get device information */
688 521
 	memset ( &undi_info, 0, sizeof ( undi_info ) );
689
-	if ( ( rc = undinet_call ( undinic, PXENV_UNDI_GET_INFORMATION,
690
-				   &undi_info, sizeof ( undi_info ) ) ) != 0 )
522
+	if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_GET_INFORMATION,
523
+				     &undi_info, sizeof ( undi_info ) ) ) != 0 )
691 524
 		goto err_undi_get_information;
692 525
 	memcpy ( netdev->hw_addr, undi_info.PermNodeAddress, ETH_ALEN );
693 526
 	undinic->irq = undi_info.IntNumber;
@@ -701,9 +534,9 @@ int undinet_probe ( struct undi_device *undi ) {
701 534
 
702 535
 	/* Get interface information */
703 536
 	memset ( &undi_iface, 0, sizeof ( undi_iface ) );
704
-	if ( ( rc = undinet_call ( undinic, PXENV_UNDI_GET_IFACE_INFO,
705
-				   &undi_iface,
706
-				   sizeof ( undi_iface ) ) ) != 0 )
537
+	if ( ( rc = pxeparent_call ( undinet_entry, PXENV_UNDI_GET_IFACE_INFO,
538
+				     &undi_iface,
539
+				     sizeof ( undi_iface ) ) ) != 0 )
707 540
 		goto err_undi_get_iface_info;
708 541
 	DBGC ( undinic, "UNDINIC %p has type %s, speed %d, flags %08x\n",
709 542
 	       undinic, undi_iface.IfaceType, undi_iface.LinkSpeed,
@@ -732,17 +565,17 @@ int undinet_probe ( struct undi_device *undi ) {
732 565
  err_undi_initialize:
733 566
 	/* Shut down UNDI stack */
734 567
 	memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) );
735
-	undinet_call ( undinic, PXENV_UNDI_SHUTDOWN, &undi_shutdown,
736
-		       sizeof ( undi_shutdown ) );
568
+	pxeparent_call ( undinet_entry, PXENV_UNDI_SHUTDOWN, &undi_shutdown,
569
+			 sizeof ( undi_shutdown ) );
737 570
 	memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) );
738
-	undinet_call ( undinic, PXENV_UNDI_CLEANUP, &undi_cleanup,
739
-		       sizeof ( undi_cleanup ) );
571
+	pxeparent_call ( undinet_entry, PXENV_UNDI_CLEANUP, &undi_cleanup,
572
+			 sizeof ( undi_cleanup ) );
740 573
 	undi->flags &= ~UNDI_FL_INITIALIZED;
741 574
  err_undi_startup:
742 575
 	/* Unhook UNDI stack */
743 576
 	memset ( &stop_undi, 0, sizeof ( stop_undi ) );
744
-	undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi,
745
-		       sizeof ( stop_undi ) );
577
+	pxeparent_call ( undinet_entry, PXENV_STOP_UNDI, &stop_undi,
578
+			 sizeof ( stop_undi ) );
746 579
 	undi->flags &= ~UNDI_FL_STARTED;
747 580
  err_start_undi:
748 581
 	netdev_nullify ( netdev );
@@ -773,22 +606,22 @@ void undinet_remove ( struct undi_device *undi ) {
773 606
 
774 607
 		/* Shut down UNDI stack */
775 608
 		memset ( &undi_shutdown, 0, sizeof ( undi_shutdown ) );
776
-		undinet_call ( undinic, PXENV_UNDI_SHUTDOWN, &undi_shutdown,
777
-			       sizeof ( undi_shutdown ) );
609
+		pxeparent_call ( undinet_entry, PXENV_UNDI_SHUTDOWN,
610
+				 &undi_shutdown, sizeof ( undi_shutdown ) );
778 611
 		memset ( &undi_cleanup, 0, sizeof ( undi_cleanup ) );
779
-		undinet_call ( undinic, PXENV_UNDI_CLEANUP, &undi_cleanup,
780
-			       sizeof ( undi_cleanup ) );
612
+		pxeparent_call ( undinet_entry, PXENV_UNDI_CLEANUP,
613
+				 &undi_cleanup, sizeof ( undi_cleanup ) );
781 614
 		undi->flags &= ~UNDI_FL_INITIALIZED;
782 615
 
783 616
 		/* Unhook UNDI stack */
784 617
 		memset ( &stop_undi, 0, sizeof ( stop_undi ) );
785
-		undinet_call ( undinic, PXENV_STOP_UNDI, &stop_undi,
786
-			       sizeof ( stop_undi ) );
618
+		pxeparent_call ( undinet_entry, PXENV_STOP_UNDI, &stop_undi,
619
+				 sizeof ( stop_undi ) );
787 620
 		undi->flags &= ~UNDI_FL_STARTED;
788 621
 	}
789 622
 
790 623
 	/* Clear entry point */
791
-	memset ( &undinet_entry_point, 0, sizeof ( undinet_entry_point ) );
624
+	memset ( &undinet_entry, 0, sizeof ( undinet_entry ) );
792 625
 
793 626
 	/* Free network device */
794 627
 	netdev_nullify ( netdev );

+ 1
- 0
src/arch/i386/include/bits/errfile.h View File

@@ -14,6 +14,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
14 14
 #define ERRFILE_bios_smbios	( ERRFILE_ARCH | ERRFILE_CORE | 0x00030000 )
15 15
 #define ERRFILE_biosint		( ERRFILE_ARCH | ERRFILE_CORE | 0x00040000 )
16 16
 #define ERRFILE_int13		( ERRFILE_ARCH | ERRFILE_CORE | 0x00050000 )
17
+#define ERRFILE_pxeparent	( ERRFILE_ARCH | ERRFILE_CORE | 0x00060000 )
17 18
 
18 19
 #define ERRFILE_bootsector     ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
19 20
 #define ERRFILE_bzimage	       ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )

+ 11
- 0
src/arch/i386/include/pxeparent.h View File

@@ -0,0 +1,11 @@
1
+#ifndef PXEPARENT_H
2
+#define PXEPARENT_H
3
+
4
+FILE_LICENCE ( GPL2_OR_LATER );
5
+
6
+#include <pxe_types.h>
7
+
8
+extern int pxeparent_call ( SEGOFF16_t entry, unsigned int function,
9
+			    void *params, size_t params_len );
10
+
11
+#endif

+ 201
- 0
src/arch/i386/interface/pxeparent/pxeparent.c View File

@@ -0,0 +1,201 @@
1
+/*
2
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+FILE_LICENCE ( GPL2_OR_LATER );
20
+
21
+#include <gpxe/dhcp.h>
22
+#include <pxeparent.h>
23
+#include <pxe_api.h>
24
+#include <pxe_types.h>
25
+#include <pxe.h>
26
+
27
+/** @file
28
+ *
29
+ * Call interface to parent PXE stack
30
+ *
31
+ */
32
+
33
+/**
34
+ * Name PXE API call
35
+ *
36
+ * @v function		API call number
37
+ * @ret name		API call name
38
+ */
39
+static inline __attribute__ (( always_inline )) const char *
40
+pxeparent_function_name ( unsigned int function ) {
41
+	switch ( function ) {
42
+	case PXENV_START_UNDI:
43
+		return "PXENV_START_UNDI";
44
+	case PXENV_STOP_UNDI:
45
+		return "PXENV_STOP_UNDI";
46
+	case PXENV_UNDI_STARTUP:
47
+		return "PXENV_UNDI_STARTUP";
48
+	case PXENV_UNDI_CLEANUP:
49
+		return "PXENV_UNDI_CLEANUP";
50
+	case PXENV_UNDI_INITIALIZE:
51
+		return "PXENV_UNDI_INITIALIZE";
52
+	case PXENV_UNDI_RESET_ADAPTER:
53
+		return "PXENV_UNDI_RESET_ADAPTER";
54
+	case PXENV_UNDI_SHUTDOWN:
55
+		return "PXENV_UNDI_SHUTDOWN";
56
+	case PXENV_UNDI_OPEN:
57
+		return "PXENV_UNDI_OPEN";
58
+	case PXENV_UNDI_CLOSE:
59
+		return "PXENV_UNDI_CLOSE";
60
+	case PXENV_UNDI_TRANSMIT:
61
+		return "PXENV_UNDI_TRANSMIT";
62
+	case PXENV_UNDI_SET_MCAST_ADDRESS:
63
+		return "PXENV_UNDI_SET_MCAST_ADDRESS";
64
+	case PXENV_UNDI_SET_STATION_ADDRESS:
65
+		return "PXENV_UNDI_SET_STATION_ADDRESS";
66
+	case PXENV_UNDI_SET_PACKET_FILTER:
67
+		return "PXENV_UNDI_SET_PACKET_FILTER";
68
+	case PXENV_UNDI_GET_INFORMATION:
69
+		return "PXENV_UNDI_GET_INFORMATION";
70
+	case PXENV_UNDI_GET_STATISTICS:
71
+		return "PXENV_UNDI_GET_STATISTICS";
72
+	case PXENV_UNDI_CLEAR_STATISTICS:
73
+		return "PXENV_UNDI_CLEAR_STATISTICS";
74
+	case PXENV_UNDI_INITIATE_DIAGS:
75
+		return "PXENV_UNDI_INITIATE_DIAGS";
76
+	case PXENV_UNDI_FORCE_INTERRUPT:
77
+		return "PXENV_UNDI_FORCE_INTERRUPT";
78
+	case PXENV_UNDI_GET_MCAST_ADDRESS:
79
+		return "PXENV_UNDI_GET_MCAST_ADDRESS";
80
+	case PXENV_UNDI_GET_NIC_TYPE:
81
+		return "PXENV_UNDI_GET_NIC_TYPE";
82
+	case PXENV_UNDI_GET_IFACE_INFO:
83
+		return "PXENV_UNDI_GET_IFACE_INFO";
84
+	/*
85
+	 * Duplicate case value; this is a bug in the PXE specification.
86
+	 *
87
+	 *	case PXENV_UNDI_GET_STATE:
88
+	 *		return "PXENV_UNDI_GET_STATE";
89
+	 */
90
+	case PXENV_UNDI_ISR:
91
+		return "PXENV_UNDI_ISR";
92
+	case PXENV_GET_CACHED_INFO:
93
+		return "PXENV_GET_CACHED_INFO";
94
+	default:
95
+		return "UNKNOWN API CALL";
96
+	}
97
+}
98
+
99
+/**
100
+ * PXE parent parameter block
101
+ *
102
+ * Used as the paramter block for all parent PXE API calls.  Resides in base
103
+ * memory.
104
+ */
105
+static union u_PXENV_ANY __bss16 ( pxeparent_params );
106
+#define pxeparent_params __use_data16 ( pxeparent_params )
107
+
108
+/** PXE parent entry point
109
+ *
110
+ * Used as the indirection vector for all parent PXE API calls.  Resides in
111
+ * base memory.
112
+ */
113
+SEGOFF16_t __bss16 ( pxeparent_entry_point );
114
+#define pxeparent_entry_point __use_data16 ( pxeparent_entry_point )
115
+
116
+/**
117
+ * Issue parent PXE API call
118
+ *
119
+ * @v entry		Parent PXE stack entry point
120
+ * @v function		API call number
121
+ * @v params		PXE parameter block
122
+ * @v params_len	Length of PXE parameter block
123
+ * @ret rc		Return status code
124
+ */
125
+int pxeparent_call ( SEGOFF16_t entry, unsigned int function,
126
+		     void *params, size_t params_len ) {
127
+	PXENV_EXIT_t exit;
128
+	int discard_b, discard_D;
129
+	int rc;
130
+
131
+	/* Copy parameter block and entry point */
132
+	assert ( params_len <= sizeof ( pxeparent_params ) );
133
+	memcpy ( &pxeparent_params, params, params_len );
134
+	memcpy ( &pxeparent_entry_point, &entry, sizeof ( entry ) );
135
+
136
+	/* Call real-mode entry point.  This calling convention will
137
+	 * work with both the !PXE and the PXENV+ entry points.
138
+	 */
139
+	__asm__ __volatile__ ( REAL_CODE ( "pushw %%es\n\t"
140
+					   "pushw %%di\n\t"
141
+					   "pushw %%bx\n\t"
142
+					   "lcall *pxeparent_entry_point\n\t"
143
+					   "addw $6, %%sp\n\t" )
144
+			       : "=a" ( exit ), "=b" ( discard_b ),
145
+			         "=D" ( discard_D )
146
+			       : "b" ( function ),
147
+			         "D" ( __from_data16 ( &pxeparent_params ) )
148
+			       : "ecx", "edx", "esi", "ebp" );
149
+
150
+	/* PXE API calls may rudely change the status of A20 and not
151
+	 * bother to restore it afterwards.  Intel is known to be
152
+	 * guilty of this.
153
+	 *
154
+	 * Note that we will return to this point even if A20 gets
155
+	 * screwed up by the parent PXE stack, because Etherboot always
156
+	 * resides in an even megabyte of RAM.
157
+	 */
158
+	gateA20_set();
159
+
160
+	/* Determine return status code based on PXENV_EXIT and
161
+	 * PXENV_STATUS
162
+	 */
163
+	if ( exit == PXENV_EXIT_SUCCESS ) {
164
+		rc = 0;
165
+	} else {
166
+		rc = -pxeparent_params.Status;
167
+		/* Paranoia; don't return success for the combination
168
+		 * of PXENV_EXIT_FAILURE but PXENV_STATUS_SUCCESS
169
+		 */
170
+		if ( rc == 0 )
171
+			rc = -EIO;
172
+	}
173
+
174
+	/* If anything goes wrong, print as much debug information as
175
+	 * it's possible to give.
176
+	 */
177
+	if ( rc != 0 ) {
178
+		SEGOFF16_t rm_params = {
179
+			.segment = rm_ds,
180
+			.offset = __from_data16 ( &pxeparent_params ),
181
+		};
182
+
183
+		DBG ( "PXEPARENT %s failed: %s\n",
184
+		       pxeparent_function_name ( function ), strerror ( rc ) );
185
+		DBG ( "PXEPARENT parameters at %04x:%04x length "
186
+		       "%#02zx, entry point at %04x:%04x\n",
187
+		       rm_params.segment, rm_params.offset, params_len,
188
+		       pxeparent_entry_point.segment,
189
+		       pxeparent_entry_point.offset );
190
+		DBG ( "PXEPARENT parameters provided:\n" );
191
+		DBG_HDA ( rm_params, params, params_len );
192
+		DBG ( "PXEPARENT parameters returned:\n" );
193
+		DBG_HDA ( rm_params, &pxeparent_params, params_len );
194
+	}
195
+
196
+	/* Copy parameter block back */
197
+	memcpy ( params, &pxeparent_params, params_len );
198
+
199
+	return rc;
200
+}
201
+

Loading…
Cancel
Save