Ver código fonte

[pxe] Provide PXENV_FILE_EXIT_HOOK only for ipxelinux.0 builds

PXENV_FILE_EXIT_HOOK is designed to allow ipxelinux.0 to unload both
the iPXE and pxelinux components without affecting the underlying PXE
stack.  Unfortunately, it causes unexpected behaviour in other
situations, such as when loading a non-embedded pxelinux.0 via
undionly.kpxe.  For example:

  PXE ROM -> undionly.kpxe -> pxelinux.0 -> chain.c32 to boot hd0

would cause control to return to iPXE instead of booting from the hard
disk.  In some cases, this would result in a harmless but confusing
"No more network devices" message; in other cases stranger things
would happen, such as being returned to the iPXE shell prompt.

The fundamental problem is that when pxelinux detects
PXENV_FILE_EXIT_HOOK, it may attempt to specify an exit hook and then
exit back to iPXE, assuming that iPXE will in turn exit cleanly via
the specified exit hook.  This is not a valid assumption in the
general case, since the action of exiting back to iPXE does not
directly cause iPXE to exit itself.  (In the specific case of
ipxelinux.0, this will work since the embedded script exits as soon as
pxelinux.0 exits.)

Fix the unexpected behaviour in the non-ipxelinux.0 cases by including
support for PXENV_FILE_EXIT_HOOK only when using a new .kkkpxe format.
The ipxelinux.0 build process should therefore now use undionly.kkkpxe
instead of undionly.kkpxe.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 12 anos atrás
pai
commit
9a93db3f09

+ 1
- 0
src/arch/i386/Makefile.pcbios Ver arquivo

19
 MEDIA		+= pxe
19
 MEDIA		+= pxe
20
 MEDIA		+= kpxe
20
 MEDIA		+= kpxe
21
 MEDIA		+= kkpxe
21
 MEDIA		+= kkpxe
22
+MEDIA		+= kkkpxe
22
 MEDIA		+= lkrn
23
 MEDIA		+= lkrn
23
 MEDIA		+= dsk
24
 MEDIA		+= dsk
24
 MEDIA		+= nbi
25
 MEDIA		+= nbi

+ 6
- 0
src/arch/i386/include/pxe_api.h Ver arquivo

1511
  * @{
1511
  * @{
1512
  */
1512
  */
1513
 
1513
 
1514
+/** Minimum possible opcode used within PXE FILE API */
1515
+#define PXENV_FILE_MIN 0x00e0
1516
+
1517
+/** Minimum possible opcode used within PXE FILE API */
1518
+#define PXENV_FILE_MAX 0x00ef
1519
+
1514
 /** @defgroup pxenv_file_open PXENV_FILE_OPEN
1520
 /** @defgroup pxenv_file_open PXENV_FILE_OPEN
1515
  *
1521
  *
1516
  * FILE OPEN
1522
  * FILE OPEN

+ 60
- 0
src/arch/i386/interface/pxe/pxe_exit_hook.c Ver arquivo

1
+/** @file
2
+ *
3
+ * PXE exit hook
4
+ *
5
+ */
6
+
7
+/*
8
+ * Copyright (C) 2010 Shao Miller <shao.miller@yrdsb.edu.on.ca>.
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
+FILE_LICENCE ( GPL2_OR_LATER );
26
+
27
+#include <stdint.h>
28
+#include <realmode.h>
29
+#include <pxe.h>
30
+
31
+/** PXE exit hook */
32
+extern segoff_t __data16 ( pxe_exit_hook );
33
+#define pxe_exit_hook __use_data16 ( pxe_exit_hook )
34
+
35
+/**
36
+ * FILE EXIT HOOK
37
+ *
38
+ * @v file_exit_hook			Pointer to a struct
39
+ *					s_PXENV_FILE_EXIT_HOOK
40
+ * @v s_PXENV_FILE_EXIT_HOOK::Hook	SEG16:OFF16 to jump to
41
+ * @ret #PXENV_EXIT_SUCCESS		Successfully set hook
42
+ * @ret #PXENV_EXIT_FAILURE		We're not an NBP build
43
+ * @ret s_PXENV_FILE_EXIT_HOOK::Status	PXE status code
44
+ *
45
+ */
46
+static PXENV_EXIT_t
47
+pxenv_file_exit_hook ( struct s_PXENV_FILE_EXIT_HOOK *file_exit_hook ) {
48
+	DBG ( "PXENV_FILE_EXIT_HOOK" );
49
+
50
+	/* We'll jump to the specified SEG16:OFF16 during exit */
51
+	pxe_exit_hook.segment = file_exit_hook->Hook.segment;
52
+	pxe_exit_hook.offset = file_exit_hook->Hook.offset;
53
+	file_exit_hook->Status = PXENV_STATUS_SUCCESS;
54
+	return PXENV_EXIT_SUCCESS;
55
+}
56
+
57
+/** PXE file API */
58
+struct pxe_api_call pxe_file_api_exit_hook __pxe_api_call =
59
+	PXE_API_CALL ( PXENV_FILE_EXIT_HOOK, pxenv_file_exit_hook,
60
+		       struct s_PXENV_FILE_EXIT_HOOK );

+ 23
- 47
src/arch/i386/interface/pxe/pxe_file.c Ver arquivo

16
 
16
 
17
 /*
17
 /*
18
  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
18
  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
19
- * Portions (C) 2010 Shao Miller <shao.miller@yrdsb.edu.on.ca>.
20
- *              [PXE exit hook logic]
21
  *
19
  *
22
  * This program is free software; you can redistribute it and/or
20
  * This program is free software; you can redistribute it and/or
23
  * modify it under the terms of the GNU General Public License as
21
  * modify it under the terms of the GNU General Public License as
234
 	return PXENV_EXIT_SUCCESS;
232
 	return PXENV_EXIT_SUCCESS;
235
 }
233
 }
236
 
234
 
237
-segoff_t __data16 ( pxe_exit_hook ) = { 0, 0 };
238
-#define pxe_exit_hook __use_data16 ( pxe_exit_hook )
239
-
240
 /**
235
 /**
241
  * FILE API CHECK
236
  * FILE API CHECK
242
  *
237
  *
253
  */
248
  */
254
 static PXENV_EXIT_t
249
 static PXENV_EXIT_t
255
 pxenv_file_api_check ( struct s_PXENV_FILE_API_CHECK *file_api_check ) {
250
 pxenv_file_api_check ( struct s_PXENV_FILE_API_CHECK *file_api_check ) {
251
+	struct pxe_api_call *call;
252
+	unsigned int mask = 0;
253
+	unsigned int offset;
254
+
256
 	DBG ( "PXENV_FILE_API_CHECK" );
255
 	DBG ( "PXENV_FILE_API_CHECK" );
257
 
256
 
257
+	/* Check for magic value */
258
 	if ( file_api_check->Magic != 0x91d447b2 ) {
258
 	if ( file_api_check->Magic != 0x91d447b2 ) {
259
 		file_api_check->Status = PXENV_STATUS_BAD_FUNC;
259
 		file_api_check->Status = PXENV_STATUS_BAD_FUNC;
260
 		return PXENV_EXIT_FAILURE;
260
 		return PXENV_EXIT_FAILURE;
261
-	} else if ( file_api_check->Size <
262
-		    sizeof(struct s_PXENV_FILE_API_CHECK) ) {
261
+	}
262
+
263
+	/* Check for required parameter size */
264
+	if ( file_api_check->Size < sizeof ( *file_api_check ) ) {
263
 		file_api_check->Status = PXENV_STATUS_OUT_OF_RESOURCES;
265
 		file_api_check->Status = PXENV_STATUS_OUT_OF_RESOURCES;
264
 		return PXENV_EXIT_FAILURE;
266
 		return PXENV_EXIT_FAILURE;
265
-	} else {
266
-		file_api_check->Status   = PXENV_STATUS_SUCCESS;
267
-		file_api_check->Size     = sizeof(struct s_PXENV_FILE_API_CHECK);
268
-		file_api_check->Magic    = 0xe9c17b20;
269
-		file_api_check->Provider = 0x45585067; /* "iPXE" */
270
-		file_api_check->APIMask  = 0x0000007f; /* Functions e0-e6 */
271
-		/* Check to see if we have a PXE exit hook */
272
-		if ( pxe_exit_hook.segment | pxe_exit_hook.offset )
273
-			/* Function e7, also */
274
-			file_api_check->APIMask |= 0x00000080;
275
-		file_api_check->Flags    = 0;	       /* None defined */
276
-		return PXENV_EXIT_SUCCESS;
277
 	}
267
 	}
278
-}
279
 
268
 
280
-/**
281
- * FILE EXIT HOOK
282
- *
283
- * @v file_exit_hook			Pointer to a struct
284
- *					s_PXENV_FILE_EXIT_HOOK
285
- * @v s_PXENV_FILE_EXIT_HOOK::Hook	SEG16:OFF16 to jump to
286
- * @ret #PXENV_EXIT_SUCCESS		Successfully set hook
287
- * @ret #PXENV_EXIT_FAILURE		We're not an NBP build
288
- * @ret s_PXENV_FILE_EXIT_HOOK::Status	PXE status code
289
- *
290
- */
291
-static PXENV_EXIT_t
292
-pxenv_file_exit_hook ( struct s_PXENV_FILE_EXIT_HOOK *file_exit_hook ) {
293
-	DBG ( "PXENV_FILE_EXIT_HOOK" );
294
-
295
-	/* Check to see if we have a PXE exit hook */
296
-	if ( pxe_exit_hook.segment | pxe_exit_hook.offset ) {
297
-		/* We'll jump to the specified SEG16:OFF16 during exit */
298
-		pxe_exit_hook.segment = file_exit_hook->Hook.segment;
299
-		pxe_exit_hook.offset = file_exit_hook->Hook.offset;
300
-		file_exit_hook->Status = PXENV_STATUS_SUCCESS;
301
-		return PXENV_EXIT_SUCCESS;
269
+	/* Determine supported calls */
270
+	for_each_table_entry ( call, PXE_API_CALLS ) {
271
+		offset = ( call->opcode - PXENV_FILE_MIN );
272
+		if ( offset <= ( PXENV_FILE_MAX - PXENV_FILE_MIN ) )
273
+			mask |= ( 1 << offset );
302
 	}
274
 	}
303
 
275
 
304
-	DBG ( " not NBP" );
305
-	file_exit_hook->Status = PXENV_STATUS_UNSUPPORTED;
306
-	return PXENV_EXIT_FAILURE;
276
+	/* Fill in parameters */
277
+	file_api_check->Size = sizeof ( *file_api_check );
278
+	file_api_check->Magic = 0xe9c17b20;
279
+	file_api_check->Provider = 0x45585067; /* "iPXE" */
280
+	file_api_check->APIMask = mask;
281
+	file_api_check->Flags = 0; /* None defined */
282
+
283
+	file_api_check->Status = PXENV_STATUS_SUCCESS;
284
+	return PXENV_EXIT_SUCCESS;
307
 }
285
 }
308
 
286
 
309
 /** PXE file API */
287
 /** PXE file API */
322
 		       struct s_PXENV_FILE_EXEC ),
300
 		       struct s_PXENV_FILE_EXEC ),
323
 	PXE_API_CALL ( PXENV_FILE_API_CHECK, pxenv_file_api_check,
301
 	PXE_API_CALL ( PXENV_FILE_API_CHECK, pxenv_file_api_check,
324
 		       struct s_PXENV_FILE_API_CHECK ),
302
 		       struct s_PXENV_FILE_API_CHECK ),
325
-	PXE_API_CALL ( PXENV_FILE_EXIT_HOOK, pxenv_file_exit_hook,
326
-		       struct s_PXENV_FILE_EXIT_HOOK ),
327
 };
303
 };

+ 19
- 0
src/arch/i386/prefix/kkkpxeprefix.S Ver arquivo

1
+/*****************************************************************************
2
+ * PXE prefix that keeps the whole PXE stack present and provides an exit hook
3
+ *
4
+ * This prefix is essentially intended solely for the case of ipxelinux.0
5
+ *****************************************************************************
6
+ */
7
+
8
+FILE_LICENCE ( GPL2_OR_LATER )
9
+
10
+/* Since we have the whole stack, we can use cached DHCP information */
11
+REQUIRE_OBJECT ( pxeparent_dhcp )
12
+
13
+/* Provide the PXENV_FILE_EXIT_HOOK API call */
14
+REQUIRE_OBJECT ( pxe_exit_hook )
15
+
16
+#define PXELOADER_KEEP_UNDI
17
+#define PXELOADER_KEEP_PXE
18
+#define _pxe_start _kkkpxe_start
19
+#include "pxeprefix.S"

+ 9
- 6
src/arch/i386/prefix/pxeprefix.S Ver arquivo

721
 	.section ".text16", "ax", @progbits
721
 	.section ".text16", "ax", @progbits
722
 1:
722
 1:
723
 	/* Update the exit hook */
723
 	/* Update the exit hook */
724
-	movw	%cs,pxe_exit_hook+2
725
-	push	%ax
726
-	mov	$2f,%ax
727
-	mov	%ax,pxe_exit_hook
728
-	pop	%ax
724
+	movw	%cs, ( pxe_exit_hook + 2 )
729
 
725
 
730
 	/* Run main program */
726
 	/* Run main program */
731
 	pushl	$main
727
 	pushl	$main
743
 	/* Jump to hook if applicable */
739
 	/* Jump to hook if applicable */
744
 	ljmpw	*pxe_exit_hook
740
 	ljmpw	*pxe_exit_hook
745
 
741
 
746
-2:	/* Check PXE stack magic */
742
+	.section ".data16", "aw", @progbits
743
+	.globl	pxe_exit_hook
744
+pxe_exit_hook:
745
+	.word	exit_ipxe, 0
746
+	.previous
747
+
748
+exit_ipxe:
749
+	/* Check PXE stack magic */
747
 	popl	%eax
750
 	popl	%eax
748
 	cmpl	$STACK_MAGIC, %eax
751
 	cmpl	$STACK_MAGIC, %eax
749
 	jne	1f
752
 	jne	1f

Carregando…
Cancelar
Salvar