Browse Source

[pxe] Treat PXENV_RESTART_TFTP as unreturnable

Microsoft WDS can end up calling PXENV_RESTART_TFTP to execute a
second-stage NBP which then exits.  Specifically, wdsnbp.com uses
PXENV_RESTART_TFTP to execute pxeboot.com, which will exit if the user
does not press F12.  iPXE currently treats PXENV_RESTART_TFTP as a
normal PXE API call, and so attempts to return to wdsnbp.com, which
has just been vaporised by pxeboot.com.

Use rmsetjmp/rmlongjmp to preserve the stack state as of the initial
NBP execution, and to restore this state immediately prior to
executing the NBP loaded via PXENV_RESTART_TFTP.  This matches the
behaviour in the PXE spec (which says that "if TFTP is restarted,
control is never returned to the caller"), and allows pxeboot.com to
exit relatively cleanly back to iPXE.

As with all usage of setjmp/longjmp, there may be subtle corner case
bugs due to not gracefully unwinding any state accumulated by the time
of the longjmp call, but this seems to be the only viable way to
provide the specified behaviour.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 14 years ago
parent
commit
dc8eb04647

+ 4
- 0
src/arch/i386/include/pxe_call.h View File

10
 
10
 
11
 #include <pxe_api.h>
11
 #include <pxe_api.h>
12
 #include <realmode.h>
12
 #include <realmode.h>
13
+#include <setjmp.h>
13
 
14
 
14
 struct net_device;
15
 struct net_device;
15
 
16
 
30
 extern struct s_PXENV __text16 ( pxenv );
31
 extern struct s_PXENV __text16 ( pxenv );
31
 #define pxenv __use_text16 ( pxenv )
32
 #define pxenv __use_text16 ( pxenv )
32
 
33
 
34
+/** PXENV_RESTART_TFTP jump buffer */
35
+extern rmjmp_buf pxe_restart_nbp;
36
+
33
 extern void pxe_activate ( struct net_device *netdev );
37
 extern void pxe_activate ( struct net_device *netdev );
34
 extern int pxe_deactivate ( void );
38
 extern int pxe_deactivate ( void );
35
 extern int pxe_start_nbp ( void );
39
 extern int pxe_start_nbp ( void );

+ 10
- 0
src/arch/i386/interface/pxe/pxe_call.c View File

20
 
20
 
21
 #include <ipxe/uaccess.h>
21
 #include <ipxe/uaccess.h>
22
 #include <ipxe/init.h>
22
 #include <ipxe/init.h>
23
+#include <setjmp.h>
23
 #include <registers.h>
24
 #include <registers.h>
24
 #include <biosint.h>
25
 #include <biosint.h>
25
 #include <pxe.h>
26
 #include <pxe.h>
480
 	return 0;
481
 	return 0;
481
 }
482
 }
482
 
483
 
484
+/** Jump buffer for PXENV_RESTART_TFTP */
485
+rmjmp_buf pxe_restart_nbp;
486
+
483
 /**
487
 /**
484
  * Start PXE NBP at 0000:7c00
488
  * Start PXE NBP at 0000:7c00
485
  *
489
  *
486
  * @ret rc		Return status code
490
  * @ret rc		Return status code
487
  */
491
  */
488
 int pxe_start_nbp ( void ) {
492
 int pxe_start_nbp ( void ) {
493
+	int jmp;
489
 	int discard_b, discard_c, discard_d, discard_D;
494
 	int discard_b, discard_c, discard_d, discard_D;
490
 	uint16_t rc;
495
 	uint16_t rc;
491
 
496
 
497
+	/* Allow restarting NBP via PXENV_RESTART_TFTP */
498
+	jmp = rmsetjmp ( pxe_restart_nbp );
499
+	if ( jmp )
500
+		DBG ( "Restarting NBP (%x)\n", jmp );
501
+
492
 	/* Far call to PXE NBP */
502
 	/* Far call to PXE NBP */
493
 	__asm__ __volatile__ ( REAL_CODE ( "movw %%cx, %%es\n\t"
503
 	__asm__ __volatile__ ( REAL_CODE ( "movw %%cx, %%es\n\t"
494
 					   "pushw %%es\n\t"
504
 					   "pushw %%es\n\t"

+ 3
- 7
src/arch/i386/interface/pxe/pxe_preboot.c View File

28
 #include <stdint.h>
28
 #include <stdint.h>
29
 #include <string.h>
29
 #include <string.h>
30
 #include <stdlib.h>
30
 #include <stdlib.h>
31
+#include <setjmp.h>
31
 #include <ipxe/uaccess.h>
32
 #include <ipxe/uaccess.h>
32
 #include <ipxe/dhcp.h>
33
 #include <ipxe/dhcp.h>
33
 #include <ipxe/fakedhcp.h>
34
 #include <ipxe/fakedhcp.h>
227
 	if ( tftp_exit != PXENV_EXIT_SUCCESS )
228
 	if ( tftp_exit != PXENV_EXIT_SUCCESS )
228
 		return tftp_exit;
229
 		return tftp_exit;
229
 
230
 
230
-	/* Fire up the new NBP */
231
-	restart_tftp->Status = pxe_start_nbp();
232
-
233
-	/* Not sure what "SUCCESS" actually means, since we can only
234
-	 * return if the new NBP failed to boot...
235
-	 */
236
-	return PXENV_EXIT_SUCCESS;
231
+	/* Restart NBP */
232
+	rmlongjmp ( pxe_restart_nbp, PXENV_RESTART_TFTP );
237
 }
233
 }
238
 
234
 
239
 /* PXENV_START_UNDI
235
 /* PXENV_START_UNDI

Loading…
Cancel
Save