Browse Source

[image] Simplify image management

Refactor the {load,exec} image operations as {probe,exec}.  This makes
the probe mechanism cleaner, eliminates some forward declarations,
avoids holding magic state in image->priv, eliminates the possibility
of screwing up between the "load" and "exec" stages, and makes the
documentation simpler since the concept of "loading" (as distinct from
"executing") no longer needs to be explained.

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

+ 30
- 40
src/arch/i386/image/bzimage.c View File

@@ -41,8 +41,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
41 41
 
42 42
 FEATURE ( FEATURE_IMAGE, "bzImage", DHCP_EB_FEATURE_BZIMAGE, 1 );
43 43
 
44
-struct image_type bzimage_image_type __image_type ( PROBE_NORMAL );
45
-
46 44
 /**
47 45
  * bzImage context
48 46
  */
@@ -111,8 +109,8 @@ static int bzimage_parse_header ( struct image *image,
111 109
 			 sizeof ( bzimg->bzhdr ) );
112 110
 
113 111
 	/* Calculate size of real-mode portion */
114
-	bzimg->rm_filesz =
115
-		( ( bzimg->bzhdr.setup_sects ? bzimg->bzhdr.setup_sects : 4 ) + 1 ) << 9;
112
+	bzimg->rm_filesz = ( ( ( bzimg->bzhdr.setup_sects ?
113
+				 bzimg->bzhdr.setup_sects : 4 ) + 1 ) << 9 );
116 114
 	if ( bzimg->rm_filesz > image->len ) {
117 115
 		DBGC ( image, "bzImage %p too short for %zd byte of setup\n",
118 116
 		       image, bzimg->rm_filesz );
@@ -455,11 +453,33 @@ static int bzimage_exec ( struct image *image ) {
455 453
 	const char *cmdline = ( image->cmdline ? image->cmdline : "" );
456 454
 	int rc;
457 455
 
458
-	/* Read and parse header from loaded kernel */
456
+	/* Read and parse header from image */
459 457
 	if ( ( rc = bzimage_parse_header ( image, &bzimg,
460
-					   image->priv.user ) ) != 0 )
458
+					   image->data ) ) != 0 )
459
+		return rc;
460
+
461
+	/* Prepare segments */
462
+	if ( ( rc = prep_segment ( bzimg.rm_kernel, bzimg.rm_filesz,
463
+				   bzimg.rm_memsz ) ) != 0 ) {
464
+		DBGC ( image, "bzImage %p could not prepare RM segment: %s\n",
465
+		       image, strerror ( rc ) );
466
+		return rc;
467
+	}
468
+	if ( ( rc = prep_segment ( bzimg.pm_kernel, bzimg.pm_sz,
469
+				   bzimg.pm_sz ) ) != 0 ) {
470
+		DBGC ( image, "bzImage %p could not prepare PM segment: %s\n",
471
+		       image, strerror ( rc ) );
461 472
 		return rc;
462
-	assert ( bzimg.rm_kernel == image->priv.user );
473
+	}
474
+
475
+	/* Load segments */
476
+	memcpy_user ( bzimg.rm_kernel, 0, image->data,
477
+		      0, bzimg.rm_filesz );
478
+	memcpy_user ( bzimg.pm_kernel, 0, image->data,
479
+		      bzimg.rm_filesz, bzimg.pm_sz );
480
+
481
+	/* Update and write out header */
482
+	bzimage_update_header ( image, &bzimg, bzimg.rm_kernel );
463 483
 
464 484
 	/* Parse command line for bootloader parameters */
465 485
 	if ( ( rc = bzimage_parse_cmdline ( image, &bzimg, cmdline ) ) != 0)
@@ -506,12 +526,12 @@ static int bzimage_exec ( struct image *image ) {
506 526
 }
507 527
 
508 528
 /**
509
- * Load bzImage image into memory
529
+ * Probe bzImage image
510 530
  *
511 531
  * @v image		bzImage file
512 532
  * @ret rc		Return status code
513 533
  */
514
-int bzimage_load ( struct image *image ) {
534
+int bzimage_probe ( struct image *image ) {
515 535
 	struct bzimage_context bzimg;
516 536
 	int rc;
517 537
 
@@ -520,42 +540,12 @@ int bzimage_load ( struct image *image ) {
520 540
 					   image->data ) ) != 0 )
521 541
 		return rc;
522 542
 
523
-	/* This is a bzImage image, valid or otherwise */
524
-	if ( ! image->type )
525
-		image->type = &bzimage_image_type;
526
-
527
-	/* Prepare segments */
528
-	if ( ( rc = prep_segment ( bzimg.rm_kernel, bzimg.rm_filesz,
529
-				   bzimg.rm_memsz ) ) != 0 ) {
530
-		DBGC ( image, "bzImage %p could not prepare RM segment: %s\n",
531
-		       image, strerror ( rc ) );
532
-		return rc;
533
-	}
534
-	if ( ( rc = prep_segment ( bzimg.pm_kernel, bzimg.pm_sz,
535
-				   bzimg.pm_sz ) ) != 0 ) {
536
-		DBGC ( image, "bzImage %p could not prepare PM segment: %s\n",
537
-		       image, strerror ( rc ) );
538
-		return rc;
539
-	}
540
-
541
-	/* Load segments */
542
-	memcpy_user ( bzimg.rm_kernel, 0, image->data,
543
-		      0, bzimg.rm_filesz );
544
-	memcpy_user ( bzimg.pm_kernel, 0, image->data,
545
-		      bzimg.rm_filesz, bzimg.pm_sz );
546
-
547
-	/* Update and write out header */
548
-	bzimage_update_header ( image, &bzimg, bzimg.rm_kernel );
549
-
550
-	/* Record real-mode segment in image private data field */
551
-	image->priv.user = bzimg.rm_kernel;
552
-
553 543
 	return 0;
554 544
 }
555 545
 
556 546
 /** Linux bzImage image type */
557 547
 struct image_type bzimage_image_type __image_type ( PROBE_NORMAL ) = {
558 548
 	.name = "bzImage",
559
-	.load = bzimage_load,
549
+	.probe = bzimage_probe,
560 550
 	.exec = bzimage_exec,
561 551
 };

+ 20
- 15
src/arch/i386/image/com32.c View File

@@ -40,8 +40,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
40 40
 #include <ipxe/init.h>
41 41
 #include <ipxe/io.h>
42 42
 
43
-struct image_type com32_image_type __image_type ( PROBE_NORMAL );
44
-
45 43
 struct idt_register com32_external_idtr = {
46 44
 	.limit = COM32_NUM_IDT_ENTRIES * sizeof ( struct idt_descriptor ) - 1,
47 45
 	.base = COM32_IDT
@@ -55,7 +53,7 @@ struct idt_register com32_internal_idtr;
55 53
  * @v image		COM32 image
56 54
  * @ret rc		Return status code
57 55
  */
58
-static int com32_exec ( struct image *image ) {
56
+static int com32_exec_loop ( struct image *image ) {
59 57
 	struct memory_map memmap;
60 58
 	unsigned int i;
61 59
 	int state;
@@ -137,7 +135,6 @@ static int com32_exec ( struct image *image ) {
137 135
 		       image, comboot_replacement_image );
138 136
 		image->replacement = comboot_replacement_image;
139 137
 		comboot_replacement_image = NULL;
140
-		image_autoload ( image->replacement );
141 138
 		break;
142 139
 
143 140
 	case COMBOOT_EXIT_COMMAND:
@@ -207,7 +204,7 @@ static int com32_identify ( struct image *image ) {
207 204
  * @v image		COM32 image
208 205
  * @ret rc		Return status code
209 206
  */
210
-static int comboot_load_image ( struct image *image ) {
207
+static int com32_load_image ( struct image *image ) {
211 208
 	physaddr_t com32_irq_wrapper_phys;
212 209
 	struct idt_descriptor *idt;
213 210
 	struct ijb_entry *ijb;
@@ -262,7 +259,7 @@ static int comboot_load_image ( struct image *image ) {
262 259
  * @v image		COM32 image
263 260
  * @ret rc		Return status code
264 261
  */
265
-static int comboot_prepare_bounce_buffer ( struct image * image ) {
262
+static int com32_prepare_bounce_buffer ( struct image * image ) {
266 263
 	unsigned int seg;
267 264
 	userptr_t seg_userptr;
268 265
 	size_t filesz, memsz;
@@ -286,12 +283,12 @@ static int comboot_prepare_bounce_buffer ( struct image * image ) {
286 283
 }
287 284
 
288 285
 /**
289
- * Load COM32 image into memory
286
+ * Probe COM32 image
290 287
  *
291 288
  * @v image		COM32 image
292 289
  * @ret rc		Return status code
293 290
  */
294
-static int com32_load ( struct image *image ) {
291
+static int com32_probe ( struct image *image ) {
295 292
 	int rc;
296 293
 
297 294
 	DBGC ( image, "COM32 %p: name '%s', cmdline '%s'\n",
@@ -302,26 +299,34 @@ static int com32_load ( struct image *image ) {
302 299
 		return rc;
303 300
 	}
304 301
 
305
-	/* This is a COM32 image, valid or otherwise */
306
-	if ( ! image->type )
307
-		image->type = &com32_image_type;
302
+	return 0;
303
+}
304
+
305
+/**
306
+ * Execute COMBOOT image
307
+ *
308
+ * @v image		COM32 image
309
+ * @ret rc		Return status code
310
+ */
311
+static int com32_exec ( struct image *image ) {
312
+	int rc;
308 313
 
309 314
 	/* Load image */
310
-	if ( ( rc = comboot_load_image ( image ) ) != 0 ) {
315
+	if ( ( rc = com32_load_image ( image ) ) != 0 ) {
311 316
 		return rc;
312 317
 	}
313 318
 
314 319
 	/* Prepare bounce buffer segment */
315
-	if ( ( rc = comboot_prepare_bounce_buffer ( image ) ) != 0 ) {
320
+	if ( ( rc = com32_prepare_bounce_buffer ( image ) ) != 0 ) {
316 321
 		return rc;
317 322
 	}
318 323
 
319
-	return 0;
324
+	return com32_exec_loop ( image );
320 325
 }
321 326
 
322 327
 /** SYSLINUX COM32 image type */
323 328
 struct image_type com32_image_type __image_type ( PROBE_NORMAL ) = {
324 329
 	.name = "COM32",
325
-	.load = com32_load,
330
+	.probe = com32_probe,
326 331
 	.exec = com32_exec,
327 332
 };

+ 16
- 11
src/arch/i386/image/comboot.c View File

@@ -42,8 +42,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
42 42
 
43 43
 FEATURE ( FEATURE_IMAGE, "COMBOOT", DHCP_EB_FEATURE_COMBOOT, 1 );
44 44
 
45
-struct image_type comboot_image_type __image_type ( PROBE_NORMAL );
46
-
47 45
 /**
48 46
  * COMBOOT PSP, copied to offset 0 of code segment
49 47
  */
@@ -131,7 +129,7 @@ static void comboot_init_psp ( struct image * image, userptr_t seg_userptr ) {
131 129
  * @v image		COMBOOT image
132 130
  * @ret rc		Return status code
133 131
  */
134
-static int comboot_exec ( struct image *image ) {
132
+static int comboot_exec_loop ( struct image *image ) {
135 133
 	userptr_t seg_userptr = real_to_user ( COMBOOT_PSP_SEG, 0 );
136 134
 	int state;
137 135
 
@@ -194,7 +192,6 @@ static int comboot_exec ( struct image *image ) {
194 192
 		       image, comboot_replacement_image );
195 193
 		image->replacement = comboot_replacement_image;
196 194
 		comboot_replacement_image = NULL;
197
-		image_autoload ( image->replacement );
198 195
 		break;
199 196
 
200 197
 	case COMBOOT_EXIT_COMMAND:
@@ -278,12 +275,12 @@ static int comboot_prepare_segment ( struct image *image )
278 275
 }
279 276
 
280 277
 /**
281
- * Load COMBOOT image into memory
278
+ * Probe COMBOOT image
282 279
  *
283 280
  * @v image		COMBOOT image
284 281
  * @ret rc		Return status code
285 282
  */
286
-static int comboot_load ( struct image *image ) {
283
+static int comboot_probe ( struct image *image ) {
287 284
 	int rc;
288 285
 
289 286
 	DBGC ( image, "COMBOOT %p: name '%s'\n",
@@ -295,9 +292,17 @@ static int comboot_load ( struct image *image ) {
295 292
 		return rc;
296 293
 	}
297 294
 
298
-	/* This is a 16-bit COMBOOT image, valid or otherwise */
299
-	if ( ! image->type )
300
-		image->type = &comboot_image_type;
295
+	return 0;
296
+}
297
+
298
+/**
299
+ * Execute COMBOOT image
300
+ *
301
+ * @v image		COMBOOT image
302
+ * @ret rc		Return status code
303
+ */
304
+static int comboot_exec ( struct image *image ) {
305
+	int rc;
301 306
 	
302 307
 	/* Sanity check for filesize */
303 308
 	if( image->len >= 0xFF00 ) {
@@ -311,12 +316,12 @@ static int comboot_load ( struct image *image ) {
311 316
 		return rc;
312 317
 	}
313 318
 
314
-	return 0;
319
+	return comboot_exec_loop ( image );
315 320
 }
316 321
 
317 322
 /** SYSLINUX COMBOOT (16-bit) image type */
318 323
 struct image_type comboot_image_type __image_type ( PROBE_NORMAL ) = {
319 324
 	.name = "COMBOOT",
320
-	.load = comboot_load,
325
+	.probe = comboot_probe,
321 326
 	.exec = comboot_exec,
322 327
 };

+ 12
- 18
src/arch/i386/image/elfboot.c View File

@@ -34,8 +34,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
34 34
 
35 35
 FEATURE ( FEATURE_IMAGE, "ELF", DHCP_EB_FEATURE_ELF, 1 );
36 36
 
37
-struct image_type elfboot_image_type __image_type ( PROBE_NORMAL );
38
-
39 37
 /**
40 38
  * Execute ELF image
41 39
  *
@@ -43,7 +41,15 @@ struct image_type elfboot_image_type __image_type ( PROBE_NORMAL );
43 41
  * @ret rc		Return status code
44 42
  */
45 43
 static int elfboot_exec ( struct image *image ) {
46
-	physaddr_t entry = image->priv.phys;
44
+	physaddr_t entry;
45
+	int rc;
46
+
47
+	/* Load the image using core ELF support */
48
+	if ( ( rc = elf_load ( image, &entry ) ) != 0 ) {
49
+		DBGC ( image, "ELF %p could not load: %s\n",
50
+		       image, strerror ( rc ) );
51
+		return rc;
52
+	}
47 53
 
48 54
 	/* An ELF image has no callback interface, so we need to shut
49 55
 	 * down before invoking it.
@@ -66,12 +72,12 @@ static int elfboot_exec ( struct image *image ) {
66 72
 }
67 73
 
68 74
 /**
69
- * Load ELF image into memory
75
+ * Probe ELF image
70 76
  *
71 77
  * @v image		ELF file
72 78
  * @ret rc		Return status code
73 79
  */
74
-static int elfboot_load ( struct image *image ) {
80
+static int elfboot_probe ( struct image *image ) {
75 81
 	Elf32_Ehdr ehdr;
76 82
 	static const uint8_t e_ident[] = {
77 83
 		[EI_MAG0]	= ELFMAG0,
@@ -82,7 +88,6 @@ static int elfboot_load ( struct image *image ) {
82 88
 		[EI_DATA]	= ELFDATA2LSB,
83 89
 		[EI_VERSION]	= EV_CURRENT,
84 90
 	};
85
-	int rc;
86 91
 
87 92
 	/* Read ELF header */
88 93
 	copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) );
@@ -91,23 +96,12 @@ static int elfboot_load ( struct image *image ) {
91 96
 		return -ENOEXEC;
92 97
 	}
93 98
 
94
-	/* This is an ELF image, valid or otherwise */
95
-	if ( ! image->type )
96
-		image->type = &elfboot_image_type;
97
-
98
-	/* Load the image using core ELF support */
99
-	if ( ( rc = elf_load ( image ) ) != 0 ) {
100
-		DBGC ( image, "ELF %p could not load: %s\n",
101
-		       image, strerror ( rc ) );
102
-		return rc;
103
-	}
104
-
105 99
 	return 0;
106 100
 }
107 101
 
108 102
 /** ELF image type */
109 103
 struct image_type elfboot_image_type __image_type ( PROBE_NORMAL ) = {
110 104
 	.name = "ELF",
111
-	.load = elfboot_load,
105
+	.probe = elfboot_probe,
112 106
 	.exec = elfboot_exec,
113 107
 };

+ 76
- 70
src/arch/i386/image/multiboot.c View File

@@ -40,8 +40,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
40 40
 
41 41
 FEATURE ( FEATURE_IMAGE, "MBOOT", DHCP_EB_FEATURE_MULTIBOOT, 1 );
42 42
 
43
-struct image_type multiboot_image_type __image_type ( PROBE_MULTIBOOT );
44
-
45 43
 /**
46 44
  * Maximum number of modules we will allow for
47 45
  *
@@ -254,57 +252,6 @@ static struct multiboot_memory_map
254 252
 static struct multiboot_module __bss16_array ( mbmodules, [MAX_MODULES] );
255 253
 #define mbmodules __use_data16 ( mbmodules )
256 254
 
257
-/**
258
- * Execute multiboot image
259
- *
260
- * @v image		Multiboot image
261
- * @ret rc		Return status code
262
- */
263
-static int multiboot_exec ( struct image *image ) {
264
-	physaddr_t entry = image->priv.phys;
265
-
266
-	/* Populate multiboot information structure */
267
-	memset ( &mbinfo, 0, sizeof ( mbinfo ) );
268
-	mbinfo.flags = ( MBI_FLAG_LOADER | MBI_FLAG_MEM | MBI_FLAG_MMAP |
269
-			 MBI_FLAG_CMDLINE | MBI_FLAG_MODS );
270
-	mb_cmdline_offset = 0;
271
-	mbinfo.cmdline = multiboot_add_cmdline ( image->name, image->cmdline );
272
-	mbinfo.mods_count = multiboot_build_module_list ( image, mbmodules,
273
-				( sizeof(mbmodules) / sizeof(mbmodules[0]) ) );
274
-	mbinfo.mods_addr = virt_to_phys ( mbmodules );
275
-	mbinfo.mmap_addr = virt_to_phys ( mbmemmap );
276
-	mbinfo.boot_loader_name = virt_to_phys ( mb_bootloader_name );
277
-
278
-	/* Multiboot images may not return and have no callback
279
-	 * interface, so shut everything down prior to booting the OS.
280
-	 */
281
-	shutdown_boot();
282
-
283
-	/* Build memory map after unhiding bootloader memory regions as part of
284
-	 * shutting everything down.
285
-	 */
286
-	multiboot_build_memmap ( image, &mbinfo, mbmemmap,
287
-				 ( sizeof(mbmemmap) / sizeof(mbmemmap[0]) ) );
288
-
289
-	/* Jump to OS with flat physical addressing */
290
-	DBGC ( image, "MULTIBOOT %p starting execution at %lx\n",
291
-	       image, entry );
292
-	__asm__ __volatile__ ( PHYS_CODE ( "pushl %%ebp\n\t"
293
-					   "call *%%edi\n\t"
294
-					   "popl %%ebp\n\t" )
295
-			       : : "a" ( MULTIBOOT_BOOTLOADER_MAGIC ),
296
-			           "b" ( virt_to_phys ( &mbinfo ) ),
297
-			           "D" ( entry )
298
-			       : "ecx", "edx", "esi", "memory" );
299
-
300
-	DBGC ( image, "MULTIBOOT %p returned\n", image );
301
-
302
-	/* It isn't safe to continue after calling shutdown() */
303
-	while ( 1 ) {}
304
-
305
-	return -ECANCELED;  /* -EIMPOSSIBLE, anyone? */
306
-}
307
-
308 255
 /**
309 256
  * Find multiboot header
310 257
  *
@@ -357,10 +304,12 @@ static int multiboot_find_header ( struct image *image,
357 304
  *
358 305
  * @v image		Multiboot file
359 306
  * @v hdr		Multiboot header descriptor
307
+ * @ret entry		Entry point
360 308
  * @ret rc		Return status code
361 309
  */
362 310
 static int multiboot_load_raw ( struct image *image,
363
-				struct multiboot_header_info *hdr ) {
311
+				struct multiboot_header_info *hdr,
312
+				physaddr_t *entry ) {
364 313
 	size_t offset;
365 314
 	size_t filesz;
366 315
 	size_t memsz;
@@ -391,8 +340,8 @@ static int multiboot_load_raw ( struct image *image,
391 340
 	/* Copy image to segment */
392 341
 	memcpy_user ( buffer, 0, image->data, offset, filesz );
393 342
 
394
-	/* Record execution entry point in image private data field */
395
-	image->priv.phys = hdr->mb.entry_addr;
343
+	/* Record execution entry point */
344
+	*entry = hdr->mb.entry_addr;
396 345
 
397 346
 	return 0;
398 347
 }
@@ -401,13 +350,14 @@ static int multiboot_load_raw ( struct image *image,
401 350
  * Load ELF multiboot image into memory
402 351
  *
403 352
  * @v image		Multiboot file
353
+ * @ret entry		Entry point
404 354
  * @ret rc		Return status code
405 355
  */
406
-static int multiboot_load_elf ( struct image *image ) {
356
+static int multiboot_load_elf ( struct image *image, physaddr_t *entry ) {
407 357
 	int rc;
408 358
 
409 359
 	/* Load ELF image*/
410
-	if ( ( rc = elf_load ( image ) ) != 0 ) {
360
+	if ( ( rc = elf_load ( image, entry ) ) != 0 ) {
411 361
 		DBGC ( image, "MULTIBOOT %p ELF image failed to load: %s\n",
412 362
 		       image, strerror ( rc ) );
413 363
 		return rc;
@@ -417,13 +367,14 @@ static int multiboot_load_elf ( struct image *image ) {
417 367
 }
418 368
 
419 369
 /**
420
- * Load multiboot image into memory
370
+ * Execute multiboot image
421 371
  *
422
- * @v image		Multiboot file
372
+ * @v image		Multiboot image
423 373
  * @ret rc		Return status code
424 374
  */
425
-static int multiboot_load ( struct image *image ) {
375
+static int multiboot_exec ( struct image *image ) {
426 376
 	struct multiboot_header_info hdr;
377
+	physaddr_t entry;
427 378
 	int rc;
428 379
 
429 380
 	/* Locate multiboot header, if present */
@@ -432,12 +383,6 @@ static int multiboot_load ( struct image *image ) {
432 383
 		       image );
433 384
 		return rc;
434 385
 	}
435
-	DBGC ( image, "MULTIBOOT %p found header with flags %08x\n",
436
-	       image, hdr.mb.flags );
437
-
438
-	/* This is a multiboot image, valid or otherwise */
439
-	if ( ! image->type )
440
-		image->type = &multiboot_image_type;
441 386
 
442 387
 	/* Abort if we detect flags that we cannot support */
443 388
 	if ( hdr.mb.flags & MB_UNSUPPORTED_FLAGS ) {
@@ -451,16 +396,77 @@ static int multiboot_load ( struct image *image ) {
451 396
 	 * the ELF header if present, and Solaris relies on this
452 397
 	 * behaviour.
453 398
 	 */
454
-	if ( ( ( rc = multiboot_load_elf ( image ) ) != 0 ) &&
455
-	     ( ( rc = multiboot_load_raw ( image, &hdr ) ) != 0 ) )
399
+	if ( ( ( rc = multiboot_load_elf ( image, &entry ) ) != 0 ) &&
400
+	     ( ( rc = multiboot_load_raw ( image, &hdr, &entry ) ) != 0 ) )
456 401
 		return rc;
457 402
 
403
+	/* Populate multiboot information structure */
404
+	memset ( &mbinfo, 0, sizeof ( mbinfo ) );
405
+	mbinfo.flags = ( MBI_FLAG_LOADER | MBI_FLAG_MEM | MBI_FLAG_MMAP |
406
+			 MBI_FLAG_CMDLINE | MBI_FLAG_MODS );
407
+	mb_cmdline_offset = 0;
408
+	mbinfo.cmdline = multiboot_add_cmdline ( image->name, image->cmdline );
409
+	mbinfo.mods_count = multiboot_build_module_list ( image, mbmodules,
410
+				( sizeof(mbmodules) / sizeof(mbmodules[0]) ) );
411
+	mbinfo.mods_addr = virt_to_phys ( mbmodules );
412
+	mbinfo.mmap_addr = virt_to_phys ( mbmemmap );
413
+	mbinfo.boot_loader_name = virt_to_phys ( mb_bootloader_name );
414
+
415
+	/* Multiboot images may not return and have no callback
416
+	 * interface, so shut everything down prior to booting the OS.
417
+	 */
418
+	shutdown_boot();
419
+
420
+	/* Build memory map after unhiding bootloader memory regions as part of
421
+	 * shutting everything down.
422
+	 */
423
+	multiboot_build_memmap ( image, &mbinfo, mbmemmap,
424
+				 ( sizeof(mbmemmap) / sizeof(mbmemmap[0]) ) );
425
+
426
+	/* Jump to OS with flat physical addressing */
427
+	DBGC ( image, "MULTIBOOT %p starting execution at %lx\n",
428
+	       image, entry );
429
+	__asm__ __volatile__ ( PHYS_CODE ( "pushl %%ebp\n\t"
430
+					   "call *%%edi\n\t"
431
+					   "popl %%ebp\n\t" )
432
+			       : : "a" ( MULTIBOOT_BOOTLOADER_MAGIC ),
433
+			           "b" ( virt_to_phys ( &mbinfo ) ),
434
+			           "D" ( entry )
435
+			       : "ecx", "edx", "esi", "memory" );
436
+
437
+	DBGC ( image, "MULTIBOOT %p returned\n", image );
438
+
439
+	/* It isn't safe to continue after calling shutdown() */
440
+	while ( 1 ) {}
441
+
442
+	return -ECANCELED;  /* -EIMPOSSIBLE, anyone? */
443
+}
444
+
445
+/**
446
+ * Probe multiboot image
447
+ *
448
+ * @v image		Multiboot file
449
+ * @ret rc		Return status code
450
+ */
451
+static int multiboot_probe ( struct image *image ) {
452
+	struct multiboot_header_info hdr;
453
+	int rc;
454
+
455
+	/* Locate multiboot header, if present */
456
+	if ( ( rc = multiboot_find_header ( image, &hdr ) ) != 0 ) {
457
+		DBGC ( image, "MULTIBOOT %p has no multiboot header\n",
458
+		       image );
459
+		return rc;
460
+	}
461
+	DBGC ( image, "MULTIBOOT %p found header with flags %08x\n",
462
+	       image, hdr.mb.flags );
463
+
458 464
 	return 0;
459 465
 }
460 466
 
461 467
 /** Multiboot image type */
462 468
 struct image_type multiboot_image_type __image_type ( PROBE_MULTIBOOT ) = {
463 469
 	.name = "Multiboot",
464
-	.load = multiboot_load,
470
+	.probe = multiboot_probe,
465 471
 	.exec = multiboot_exec,
466 472
 };

+ 45
- 56
src/arch/i386/image/nbi.c View File

@@ -28,8 +28,6 @@
28 28
 
29 29
 FEATURE ( FEATURE_IMAGE, "NBI", DHCP_EB_FEATURE_NBI, 1 );
30 30
 
31
-struct image_type nbi_image_type __image_type ( PROBE_NORMAL );
32
-
33 31
 /**
34 32
  * An NBI image header
35 33
  *
@@ -240,57 +238,6 @@ static int nbi_process_segments ( struct image *image,
240 238
 	return 0;
241 239
 }
242 240
 
243
-/**
244
- * Load an NBI image into memory
245
- *
246
- * @v image		NBI image
247
- * @ret rc		Return status code
248
- */
249
-static int nbi_load ( struct image *image ) {
250
-	struct imgheader imgheader;
251
-	int rc;
252
-
253
-	/* If we don't have enough data give up */
254
-	if ( image->len < NBI_HEADER_LENGTH ) {
255
-		DBGC ( image, "NBI %p too short for an NBI image\n", image );
256
-		return -ENOEXEC;
257
-	}
258
-
259
-	/* Check image header */
260
-	copy_from_user ( &imgheader, image->data, 0, sizeof ( imgheader ) );
261
-	if ( imgheader.magic != NBI_MAGIC ) {
262
-		DBGC ( image, "NBI %p has no NBI signature\n", image );
263
-		return -ENOEXEC;
264
-	}
265
-
266
-	/* This is an NBI image, valid or otherwise */
267
-	if ( ! image->type )
268
-		image->type = &nbi_image_type;
269
-
270
-	DBGC ( image, "NBI %p placing header at %hx:%hx\n", image,
271
-	       imgheader.location.segment, imgheader.location.offset );
272
-
273
-	/* NBI files can have overlaps between segments; the bss of
274
-	 * one segment may overlap the initialised data of another.  I
275
-	 * assume this is a design flaw, but there are images out
276
-	 * there that we need to work with.  We therefore do two
277
-	 * passes: first to initialise the segments, then to copy the
278
-	 * data.  This avoids zeroing out already-copied data.
279
-	 */
280
-	if ( ( rc = nbi_process_segments ( image, &imgheader,
281
-					   nbi_prepare_segment ) ) != 0 )
282
-		return rc;
283
-	if ( ( rc = nbi_process_segments ( image, &imgheader,
284
-					   nbi_load_segment ) ) != 0 )
285
-		return rc;
286
-
287
-	/* Record header address in image private data field */
288
-	image->priv.user = real_to_user ( imgheader.location.segment,
289
-					  imgheader.location.offset );
290
-
291
-	return 0;
292
-}
293
-
294 241
 /**
295 242
  * Boot a 16-bit NBI image
296 243
  *
@@ -396,8 +343,25 @@ static int nbi_exec ( struct image *image ) {
396 343
 	int may_return;
397 344
 	int rc;
398 345
 
399
-	copy_from_user ( &imgheader, image->priv.user, 0,
400
-			 sizeof ( imgheader ) );
346
+	/* Retrieve image header */
347
+	copy_from_user ( &imgheader, image->data, 0, sizeof ( imgheader ) );
348
+
349
+	DBGC ( image, "NBI %p placing header at %hx:%hx\n", image,
350
+	       imgheader.location.segment, imgheader.location.offset );
351
+
352
+	/* NBI files can have overlaps between segments; the bss of
353
+	 * one segment may overlap the initialised data of another.  I
354
+	 * assume this is a design flaw, but there are images out
355
+	 * there that we need to work with.  We therefore do two
356
+	 * passes: first to initialise the segments, then to copy the
357
+	 * data.  This avoids zeroing out already-copied data.
358
+	 */
359
+	if ( ( rc = nbi_process_segments ( image, &imgheader,
360
+					   nbi_prepare_segment ) ) != 0 )
361
+		return rc;
362
+	if ( ( rc = nbi_process_segments ( image, &imgheader,
363
+					   nbi_load_segment ) ) != 0 )
364
+		return rc;
401 365
 
402 366
 	/* Prepare DHCP option block */
403 367
 	if ( ( rc = nbi_prepare_dhcp ( image ) ) != 0 )
@@ -427,9 +391,34 @@ static int nbi_exec ( struct image *image ) {
427 391
 	return rc;
428 392
 }
429 393
 
394
+/**
395
+ * Probe NBI image
396
+ *
397
+ * @v image		NBI image
398
+ * @ret rc		Return status code
399
+ */
400
+static int nbi_probe ( struct image *image ) {
401
+	struct imgheader imgheader;
402
+
403
+	/* If we don't have enough data give up */
404
+	if ( image->len < NBI_HEADER_LENGTH ) {
405
+		DBGC ( image, "NBI %p too short for an NBI image\n", image );
406
+		return -ENOEXEC;
407
+	}
408
+
409
+	/* Check image header */
410
+	copy_from_user ( &imgheader, image->data, 0, sizeof ( imgheader ) );
411
+	if ( imgheader.magic != NBI_MAGIC ) {
412
+		DBGC ( image, "NBI %p has no NBI signature\n", image );
413
+		return -ENOEXEC;
414
+	}
415
+
416
+	return 0;
417
+}
418
+
430 419
 /** NBI image type */
431 420
 struct image_type nbi_image_type __image_type ( PROBE_NORMAL ) = {
432 421
 	.name = "NBI",
433
-	.load = nbi_load,
422
+	.probe = nbi_probe,
434 423
 	.exec = nbi_exec,
435 424
 };

+ 16
- 25
src/arch/i386/image/pxe_image.c View File

@@ -35,8 +35,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
35 35
 
36 36
 FEATURE ( FEATURE_IMAGE, "PXE", DHCP_EB_FEATURE_PXE, 1 );
37 37
 
38
-struct image_type pxe_image_type __image_type ( PROBE_PXE );
39
-
40 38
 /**
41 39
  * Execute PXE image
42 40
  *
@@ -44,9 +42,20 @@ struct image_type pxe_image_type __image_type ( PROBE_PXE );
44 42
  * @ret rc		Return status code
45 43
  */
46 44
 static int pxe_exec ( struct image *image ) {
45
+	userptr_t buffer = real_to_user ( 0, 0x7c00 );
47 46
 	struct net_device *netdev;
48 47
 	int rc;
49 48
 
49
+	/* Verify and prepare segment */
50
+	if ( ( rc = prep_segment ( buffer, image->len, image->len ) ) != 0 ) {
51
+		DBGC ( image, "IMAGE %p could not prepare segment: %s\n",
52
+		       image, strerror ( rc ) );
53
+		return rc;
54
+	}
55
+
56
+	/* Copy image to segment */
57
+	memcpy_user ( buffer, 0, image->data, 0, image->len );
58
+
50 59
 	/* Arbitrarily pick the most recently opened network device */
51 60
 	if ( ( netdev = last_opened_netdev() ) == NULL ) {
52 61
 		DBGC ( image, "IMAGE %p could not locate PXE net device\n",
@@ -67,51 +76,33 @@ static int pxe_exec ( struct image *image ) {
67 76
 }
68 77
 
69 78
 /**
70
- * Load PXE image into memory
79
+ * Probe PXE image
71 80
  *
72 81
  * @v image		PXE file
73 82
  * @ret rc		Return status code
74 83
  */
75
-int pxe_load ( struct image *image ) {
76
-	userptr_t buffer = real_to_user ( 0, 0x7c00 );
77
-	size_t filesz = image->len;
78
-	size_t memsz = image->len;
79
-	int rc;
84
+int pxe_probe ( struct image *image ) {
80 85
 
81 86
 	/* Images too large to fit in base memory cannot be PXE
82 87
 	 * images.  We include this check to help prevent unrecognised
83 88
 	 * images from being marked as PXE images, since PXE images
84 89
 	 * have no signature we can check against.
85 90
 	 */
86
-	if ( filesz > ( 0xa0000 - 0x7c00 ) )
91
+	if ( image->len > ( 0xa0000 - 0x7c00 ) )
87 92
 		return -ENOEXEC;
88 93
 
89 94
 	/* Rejecting zero-length images is also useful, since these
90 95
 	 * end up looking to the user like bugs in iPXE.
91 96
 	 */
92
-	if ( ! filesz )
97
+	if ( ! image->len )
93 98
 		return -ENOEXEC;
94 99
 
95
-	/* There are no signature checks for PXE; we will accept anything */
96
-	if ( ! image->type )
97
-		image->type = &pxe_image_type;
98
-
99
-	/* Verify and prepare segment */
100
-	if ( ( rc = prep_segment ( buffer, filesz, memsz ) ) != 0 ) {
101
-		DBGC ( image, "IMAGE %p could not prepare segment: %s\n",
102
-		       image, strerror ( rc ) );
103
-		return rc;
104
-	}
105
-
106
-	/* Copy image to segment */
107
-	memcpy_user ( buffer, 0, image->data, 0, filesz );
108
-
109 100
 	return 0;
110 101
 }
111 102
 
112 103
 /** PXE image type */
113 104
 struct image_type pxe_image_type __image_type ( PROBE_PXE ) = {
114 105
 	.name = "PXE",
115
-	.load = pxe_load,
106
+	.probe = pxe_probe,
116 107
 	.exec = pxe_exec,
117 108
 };

+ 1
- 1
src/arch/i386/interface/syslinux/comboot_call.c View File

@@ -217,7 +217,7 @@ static int comboot_fetch_kernel ( char *kernel_file, char *cmdline ) {
217 217
 		goto out;
218 218
 	}
219 219
 	if ( ( rc = imgfetch ( kernel, kernel_file,
220
-			       register_image ) ) != 0 ) {
220
+			       register_and_select_image ) ) != 0 ) {
221 221
 		DBG ( "COMBOOT: could not fetch kernel: %s\n",
222 222
 		      strerror ( rc ) );
223 223
 		goto out;

+ 1
- 2
src/core/downloader.c View File

@@ -218,8 +218,7 @@ static struct interface_descriptor downloader_job_desc =
218 218
  * @ret rc		Return status code
219 219
  *
220 220
  * Instantiates a downloader object to download the specified URI into
221
- * the specified image object.  If the download is successful, the
222
- * image registration routine @c register_image() will be called.
221
+ * the specified image object.
223 222
  */
224 223
 int create_downloader ( struct interface *job, struct image *image,
225 224
 			int type, ... ) {

+ 88
- 94
src/core/image.c View File

@@ -32,7 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
32 32
 
33 33
 /** @file
34 34
  *
35
- * Executable/loadable images
35
+ * Executable images
36 36
  *
37 37
  */
38 38
 
@@ -40,7 +40,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
40 40
 struct list_head images = LIST_HEAD_INIT ( images );
41 41
 
42 42
 /**
43
- * Free executable/loadable image
43
+ * Free executable image
44 44
  *
45 45
  * @v refcnt		Reference counter
46 46
  */
@@ -52,13 +52,13 @@ static void free_image ( struct refcnt *refcnt ) {
52 52
 	ufree ( image->data );
53 53
 	image_put ( image->replacement );
54 54
 	free ( image );
55
-	DBGC ( image, "IMAGE %p freed\n", image );
55
+	DBGC ( image, "IMAGE %s freed\n", image->name );
56 56
 }
57 57
 
58 58
 /**
59
- * Allocate executable/loadable image
59
+ * Allocate executable image
60 60
  *
61
- * @ret image		Executable/loadable image
61
+ * @ret image		Executable image
62 62
  */
63 63
 struct image * alloc_image ( void ) {
64 64
 	struct image *image;
@@ -75,12 +75,11 @@ struct image * alloc_image ( void ) {
75 75
  *
76 76
  * @v image		Image
77 77
  * @v URI		New image URI
78
- * @ret rc		Return status code
79 78
  *
80 79
  * If no name is set, the name will be updated to the base name of the
81 80
  * URI path (if any).
82 81
  */
83
-int image_set_uri ( struct image *image, struct uri *uri ) {
82
+void image_set_uri ( struct image *image, struct uri *uri ) {
84 83
 	const char *path = uri->path;
85 84
 
86 85
 	/* Replace URI reference */
@@ -90,8 +89,6 @@ int image_set_uri ( struct image *image, struct uri *uri ) {
90 89
 	/* Set name if none already specified */
91 90
 	if ( path && ( ! image->name[0] ) )
92 91
 		image_set_name ( image, basename ( ( char * ) path ) );
93
-
94
-	return 0;
95 92
 }
96 93
 
97 94
 /**
@@ -110,9 +107,9 @@ int image_set_cmdline ( struct image *image, const char *cmdline ) {
110 107
 }
111 108
 
112 109
 /**
113
- * Register executable/loadable image
110
+ * Register executable image
114 111
  *
115
- * @v image		Executable/loadable image
112
+ * @v image		Executable image
116 113
  * @ret rc		Return status code
117 114
  */
118 115
 int register_image ( struct image *image ) {
@@ -127,20 +124,20 @@ int register_image ( struct image *image ) {
127 124
 	/* Add to image list */
128 125
 	image_get ( image );
129 126
 	list_add_tail ( &image->list, &images );
130
-	DBGC ( image, "IMAGE %p at [%lx,%lx) registered as %s\n",
131
-	       image, user_to_phys ( image->data, 0 ),
132
-	       user_to_phys ( image->data, image->len ), image->name );
127
+	DBGC ( image, "IMAGE %s at [%lx,%lx) registered\n",
128
+	       image->name, user_to_phys ( image->data, 0 ),
129
+	       user_to_phys ( image->data, image->len ) );
133 130
 
134 131
 	return 0;
135 132
 }
136 133
 
137 134
 /**
138
- * Unregister executable/loadable image
135
+ * Unregister executable image
139 136
  *
140
- * @v image		Executable/loadable image
137
+ * @v image		Executable image
141 138
  */
142 139
 void unregister_image ( struct image *image ) {
143
-	DBGC ( image, "IMAGE %p unregistered\n", image );
140
+	DBGC ( image, "IMAGE %s unregistered\n", image->name );
144 141
 	list_del ( &image->list );
145 142
 	image_put ( image );
146 143
 }
@@ -149,7 +146,7 @@ void unregister_image ( struct image *image ) {
149 146
  * Find image by name
150 147
  *
151 148
  * @v name		Image name
152
- * @ret image		Executable/loadable image, or NULL
149
+ * @ret image		Executable image, or NULL
153 150
  */
154 151
 struct image * find_image ( const char *name ) {
155 152
 	struct image *image;
@@ -163,75 +160,39 @@ struct image * find_image ( const char *name ) {
163 160
 }
164 161
 
165 162
 /**
166
- * Load executable/loadable image into memory
167
- *
168
- * @v image		Executable/loadable image
169
- * @v type		Executable/loadable image type
170
- * @ret rc		Return status code
171
- */
172
-static int image_load_type ( struct image *image, struct image_type *type ) {
173
-	int rc;
174
-
175
-	/* Check image is actually loadable */
176
-	if ( ! type->load )
177
-		return -ENOEXEC;
178
-
179
-	/* Try the image loader */
180
-	if ( ( rc = type->load ( image ) ) != 0 ) {
181
-		DBGC ( image, "IMAGE %p could not load as %s: %s\n",
182
-		       image, type->name, strerror ( rc ) );
183
-		return rc;
184
-	}
185
-
186
-	/* Flag as loaded */
187
-	image->flags |= IMAGE_LOADED;
188
-	return 0;
189
-}
190
-
191
-/**
192
- * Load executable/loadable image into memory
193
- *
194
- * @v image		Executable/loadable image
195
- * @ret rc		Return status code
196
- */
197
-int image_load ( struct image *image ) {
198
-
199
-	assert ( image->type != NULL );
200
-
201
-	return image_load_type ( image, image->type );
202
-}
203
-
204
-/**
205
- * Autodetect image type and load executable/loadable image into memory
163
+ * Determine image type
206 164
  *
207
- * @v image		Executable/loadable image
165
+ * @v image		Executable image
208 166
  * @ret rc		Return status code
209 167
  */
210
-int image_autoload ( struct image *image ) {
168
+int image_probe ( struct image *image ) {
211 169
 	struct image_type *type;
212 170
 	int rc;
213 171
 
214
-	/* If image already has a type, use it */
172
+	/* Succeed if we already have a type */
215 173
 	if ( image->type )
216
-		return image_load ( image );
174
+		return 0;
217 175
 
218
-	/* Otherwise probe for a suitable type */
176
+	/* Try each type in turn */
219 177
 	for_each_table_entry ( type, IMAGE_TYPES ) {
220
-		DBGC ( image, "IMAGE %p trying type %s\n", image, type->name );
221
-		rc = image_load_type ( image, type );
222
-		if ( image->type == NULL )
223
-			continue;
224
-		return rc;
178
+		if ( ( rc = type->probe ( image ) ) == 0 ) {
179
+			image->type = type;
180
+			DBGC ( image, "IMAGE %s is %s\n",
181
+			       image->name, type->name );
182
+			return 0;
183
+		}
184
+		DBGC ( image, "IMAGE %s is not %s: %s\n", image->name,
185
+		       type->name, strerror ( rc ) );
225 186
 	}
226 187
 
227
-	DBGC ( image, "IMAGE %p format not recognised\n", image );
188
+	DBGC ( image, "IMAGE %s format not recognised\n", image->name );
228 189
 	return -ENOEXEC;
229 190
 }
230 191
 
231 192
 /**
232
- * Execute loaded image
193
+ * Execute image
233 194
  *
234
- * @v image		Loaded image
195
+ * @v image		Executable image
235 196
  * @ret rc		Return status code
236 197
  */
237 198
 int image_exec ( struct image *image ) {
@@ -239,18 +200,9 @@ int image_exec ( struct image *image ) {
239 200
 	struct uri *old_cwuri;
240 201
 	int rc;
241 202
 
242
-	/* Image must be loaded first */
243
-	if ( ! ( image->flags & IMAGE_LOADED ) ) {
244
-		DBGC ( image, "IMAGE %p could not execute: not loaded\n",
245
-		       image );
246
-		return -ENOTTY;
247
-	}
248
-
249
-	assert ( image->type != NULL );
250
-
251
-	/* Check that image is actually executable */
252
-	if ( ! image->type->exec )
253
-		return -ENOEXEC;
203
+	/* Check that this image can be executed */
204
+	if ( ( rc = image_probe ( image ) ) != 0 )
205
+		return rc;
254 206
 
255 207
 	/* Switch current working directory to be that of the image itself */
256 208
 	old_cwuri = uri_get ( cwuri );
@@ -264,8 +216,8 @@ int image_exec ( struct image *image ) {
264 216
 
265 217
 	/* Try executing the image */
266 218
 	if ( ( rc = image->type->exec ( image ) ) != 0 ) {
267
-		DBGC ( image, "IMAGE %p could not execute: %s\n",
268
-		       image, strerror ( rc ) );
219
+		DBGC ( image, "IMAGE %s could not execute: %s\n",
220
+		       image->name, strerror ( rc ) );
269 221
 		/* Do not return yet; we still have clean-up to do */
270 222
 	}
271 223
 
@@ -283,8 +235,8 @@ int image_exec ( struct image *image ) {
283 235
 
284 236
 	/* Tail-recurse into replacement image, if one exists */
285 237
 	if ( replacement ) {
286
-		DBGC ( image, "IMAGE %p replacing self with IMAGE %p\n",
287
-		       image, replacement );
238
+		DBGC ( image, "IMAGE %s replacing self with IMAGE %s\n",
239
+		       image->name, replacement->name );
288 240
 		if ( ( rc = image_exec ( replacement ) ) != 0 )
289 241
 			return rc;
290 242
 	}
@@ -293,33 +245,75 @@ int image_exec ( struct image *image ) {
293 245
 }
294 246
 
295 247
 /**
296
- * Register and autoload an image
248
+ * Select image for execution
297 249
  *
298
- * @v image		Image
250
+ * @v image		Executable image
299 251
  * @ret rc		Return status code
300 252
  */
301
-int register_and_autoload_image ( struct image *image ) {
253
+int image_select ( struct image *image ) {
254
+	struct image *tmp;
255
+	int rc;
256
+
257
+	/* Unselect all other images */
258
+	for_each_image ( tmp )
259
+		tmp->flags &= ~IMAGE_SELECTED;
260
+
261
+	/* Check that this image can be executed */
262
+	if ( ( rc = image_probe ( image ) ) != 0 )
263
+		return rc;
264
+
265
+	/* Mark image as selected */
266
+	image->flags |= IMAGE_SELECTED;
267
+
268
+	return 0;
269
+}
270
+
271
+/**
272
+ * Find selected image
273
+ *
274
+ * @ret image		Executable image, or NULL
275
+ */
276
+struct image * image_find_selected ( void ) {
277
+	struct image *image;
278
+
279
+	for_each_image ( image ) {
280
+		if ( image->flags & IMAGE_SELECTED )
281
+			return image;
282
+	}
283
+	return NULL;
284
+}
285
+
286
+/**
287
+ * Register and select an image
288
+ *
289
+ * @v image		Executable image
290
+ * @ret rc		Return status code
291
+ */
292
+int register_and_select_image ( struct image *image ) {
302 293
 	int rc;
303 294
 
304 295
 	if ( ( rc = register_image ( image ) ) != 0 )
305 296
 		return rc;
306 297
 
307
-	if ( ( rc = image_autoload ( image ) ) != 0 )
298
+	if ( ( rc = image_probe ( image ) ) != 0 )
299
+		return rc;
300
+
301
+	if ( ( rc = image_select ( image ) ) != 0 )
308 302
 		return rc;
309 303
 
310 304
 	return 0;
311 305
 }
312 306
 
313 307
 /**
314
- * Register and autoexec an image
308
+ * Register and boot an image
315 309
  *
316 310
  * @v image		Image
317 311
  * @ret rc		Return status code
318 312
  */
319
-int register_and_autoexec_image ( struct image *image ) {
313
+int register_and_boot_image ( struct image *image ) {
320 314
 	int rc;
321 315
 
322
-	if ( ( rc = register_and_autoload_image ( image ) ) != 0 )
316
+	if ( ( rc = register_and_select_image ( image ) ) != 0 )
323 317
 		return rc;
324 318
 
325 319
 	if ( ( rc = image_exec ( image ) ) != 0 )

+ 30
- 34
src/hci/commands/image_cmd.c View File

@@ -86,28 +86,18 @@ static struct command_descriptor imgfetch_cmd =
86 86
 	COMMAND_DESC ( struct imgfetch_options, imgfetch_opts, 1, MAX_ARGUMENTS,
87 87
 		       "[--name <name>] <uri> [<arguments>...]" );
88 88
 
89
-/** "kernel" command descriptor */
90
-static struct command_descriptor kernel_cmd =
91
-	COMMAND_DESC ( struct imgfetch_options, imgfetch_opts, 1, MAX_ARGUMENTS,
92
-		       "[--name <name>] <uri> [<arguments>...]" );
93
-
94
-/** "chain" command descriptor */
95
-static struct command_descriptor chain_cmd =
96
-	COMMAND_DESC ( struct imgfetch_options, imgfetch_opts, 1, MAX_ARGUMENTS,
97
-		       "[--name <name>] <uri> [<arguments>...]" );
98
-
99 89
 /**
100 90
  * The "imgfetch" and friends command body
101 91
  *
102 92
  * @v argc		Argument count
103 93
  * @v argv		Argument list
104 94
  * @v cmd		Command descriptor
105
- * @v image_register	Image registration action
95
+ * @v action		Action to take upon a successful download
106 96
  * @ret rc		Return status code
107 97
  */
108 98
 static int imgfetch_core_exec ( int argc, char **argv,
109 99
 				struct command_descriptor *cmd,
110
-				int ( * image_register ) ( struct image * ) ) {
100
+				int ( * action ) ( struct image *image ) ) {
111 101
 	struct imgfetch_options opts;
112 102
 	struct image *image;
113 103
 	char *uri_string;
@@ -139,7 +129,7 @@ static int imgfetch_core_exec ( int argc, char **argv,
139 129
 		return rc;
140 130
 
141 131
 	/* Fetch the image */
142
-	if ( ( rc = imgfetch ( image, uri_string, image_register ) ) != 0 ) {
132
+	if ( ( rc = imgfetch ( image, uri_string, action ) ) != 0 ) {
143 133
 		printf ( "Could not fetch %s: %s\n",
144 134
 			 uri_string, strerror ( rc ) );
145 135
 		image_put ( image );
@@ -172,8 +162,8 @@ static int imgfetch_exec ( int argc, char **argv ) {
172 162
  */
173 163
 static int kernel_exec ( int argc, char **argv ) {
174 164
 
175
-	return imgfetch_core_exec ( argc, argv, &kernel_cmd,
176
-				    register_and_autoload_image );
165
+	return imgfetch_core_exec ( argc, argv, &imgfetch_cmd,
166
+				    register_and_select_image );
177 167
 }
178 168
 
179 169
 /**
@@ -185,34 +175,35 @@ static int kernel_exec ( int argc, char **argv ) {
185 175
  */
186 176
 static int chain_exec ( int argc, char **argv) {
187 177
 
188
-	return imgfetch_core_exec ( argc, argv, &chain_cmd,
189
-				    register_and_autoexec_image );
178
+	return imgfetch_core_exec ( argc, argv, &imgfetch_cmd,
179
+				    register_and_boot_image );
190 180
 }
191 181
 
192
-/** "imgload" options */
193
-struct imgload_options {};
182
+/** "imgselect" options */
183
+struct imgselect_options {};
194 184
 
195
-/** "imgload" option list */
196
-static struct option_descriptor imgload_opts[] = {};
185
+/** "imgselect" option list */
186
+static struct option_descriptor imgselect_opts[] = {};
197 187
 
198
-/** "imgload" command descriptor */
199
-static struct command_descriptor imgload_cmd =
200
-	COMMAND_DESC ( struct imgload_options, imgload_opts, 1, 1, "<image>" );
188
+/** "imgselect" command descriptor */
189
+static struct command_descriptor imgselect_cmd =
190
+	COMMAND_DESC ( struct imgselect_options, imgselect_opts, 1, 1,
191
+		       "<image>" );
201 192
 
202 193
 /**
203
- * The "imgload" command
194
+ * The "imgselect" command
204 195
  *
205 196
  * @v argc		Argument count
206 197
  * @v argv		Argument list
207 198
  * @ret rc		Return status code
208 199
  */
209
-static int imgload_exec ( int argc, char **argv ) {
210
-	struct imgload_options opts;
200
+static int imgselect_exec ( int argc, char **argv ) {
201
+	struct imgselect_options opts;
211 202
 	struct image *image;
212 203
 	int rc;
213 204
 
214 205
 	/* Parse options */
215
-	if ( ( rc = parse_options ( argc, argv, &imgload_cmd, &opts ) ) != 0 )
206
+	if ( ( rc = parse_options ( argc, argv, &imgselect_cmd, &opts ) ) != 0 )
216 207
 		return rc;
217 208
 
218 209
 	/* Parse image name */
@@ -220,8 +211,8 @@ static int imgload_exec ( int argc, char **argv ) {
220 211
 		return rc;
221 212
 
222 213
 	/* Load image */
223
-	if ( ( rc = imgload ( image ) ) != 0 ) {
224
-		printf ( "Could not load %s: %s\n",
214
+	if ( ( rc = imgselect ( image ) ) != 0 ) {
215
+		printf ( "Could not select %s: %s\n",
225 216
 			 image->name, strerror ( rc ) );
226 217
 		return rc;
227 218
 	}
@@ -302,8 +293,9 @@ static int imgexec_exec ( int argc, char **argv ) {
302 293
 	} else {
303 294
 		image = imgautoselect();
304 295
 		if ( ! image ) {
305
-			printf ( "No (unique) loaded image\n" );
306
-			return -ENOTTY;
296
+			rc = -ENOTTY;
297
+			printf ( "No image selected: %s\n", strerror ( rc ) );
298
+			return rc;
307 299
 		}
308 300
 	}
309 301
 
@@ -417,8 +409,12 @@ struct command image_commands[] __command = {
417 409
 		.exec = chain_exec,
418 410
 	},
419 411
 	{
420
-		.name = "imgload",
421
-		.exec = imgload_exec,
412
+		.name = "imgselect",
413
+		.exec = imgselect_exec,
414
+	},
415
+	{
416
+		.name = "imgload", /* synonym for "imgselect" */
417
+		.exec = imgselect_exec,
422 418
 	},
423 419
 	{
424 420
 		.name = "imgargs",

+ 3
- 9
src/image/efi_image.c View File

@@ -26,8 +26,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
26 26
 
27 27
 FEATURE ( FEATURE_IMAGE, "EFI", DHCP_EB_FEATURE_EFI, 1 );
28 28
 
29
-struct image_type efi_image_type __image_type ( PROBE_NORMAL );
30
-
31 29
 /** Event used to signal shutdown */
32 30
 static EFI_EVENT efi_shutdown_event;
33 31
 
@@ -99,12 +97,12 @@ done:
99 97
 }
100 98
 
101 99
 /**
102
- * Load EFI image into memory
100
+ * Probe EFI image
103 101
  *
104 102
  * @v image		EFI file
105 103
  * @ret rc		Return status code
106 104
  */
107
-static int efi_image_load ( struct image *image ) {
105
+static int efi_image_probe ( struct image *image ) {
108 106
 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
109 107
 	EFI_HANDLE handle;
110 108
 	EFI_STATUS efirc;
@@ -119,10 +117,6 @@ static int efi_image_load ( struct image *image ) {
119 117
 		return -ENOEXEC;
120 118
 	}
121 119
 
122
-	/* This is an EFI image */
123
-	if ( ! image->type )
124
-		image->type = &efi_image_type;
125
-
126 120
 	/* Unload the image.  We can't leave it loaded, because we
127 121
 	 * have no "unload" operation.
128 122
 	 */
@@ -134,6 +128,6 @@ static int efi_image_load ( struct image *image ) {
134 128
 /** EFI image type */
135 129
 struct image_type efi_image_type __image_type ( PROBE_NORMAL ) = {
136 130
 	.name = "EFI",
137
-	.load = efi_image_load,
131
+	.probe = efi_image_probe,
138 132
 	.exec = efi_image_exec,
139 133
 };

+ 15
- 14
src/image/elf.c View File

@@ -45,10 +45,11 @@ typedef Elf32_Off	Elf_Off;
45 45
  * @v image		ELF file
46 46
  * @v phdr		ELF program header
47 47
  * @v ehdr		ELF executable header
48
+ * @ret entry		Entry point, if found
48 49
  * @ret rc		Return status code
49 50
  */
50 51
 static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
51
-			      Elf_Ehdr *ehdr ) {
52
+			      Elf_Ehdr *ehdr, physaddr_t *entry ) {
52 53
 	physaddr_t dest;
53 54
 	userptr_t buffer;
54 55
 	unsigned long e_offset;
@@ -96,15 +97,15 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
96 97
 
97 98
 	/* Set execution address, if it lies within this segment */
98 99
 	if ( ( e_offset = ( ehdr->e_entry - dest ) ) < phdr->p_filesz ) {
99
-		image->priv.phys = ehdr->e_entry;
100
+		*entry = ehdr->e_entry;
100 101
 		DBGC ( image, "ELF %p found physical entry point at %lx\n",
101
-		       image, image->priv.phys );
102
+		       image, *entry );
102 103
 	} else if ( ( e_offset = ( ehdr->e_entry - phdr->p_vaddr ) )
103 104
 		    < phdr->p_filesz ) {
104
-		if ( ! image->priv.phys ) {
105
-			image->priv.phys = ( dest + e_offset );
105
+		if ( ! *entry ) {
106
+			*entry = ( dest + e_offset );
106 107
 			DBGC ( image, "ELF %p found virtual entry point at %lx"
107
-			       " (virt %lx)\n", image, image->priv.phys,
108
+			       " (virt %lx)\n", image, *entry,
108 109
 			       ( ( unsigned long ) ehdr->e_entry ) );
109 110
 		}
110 111
 	}
@@ -116,18 +117,16 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr,
116 117
  * Load ELF image into memory
117 118
  *
118 119
  * @v image		ELF file
120
+ * @ret entry		Entry point
119 121
  * @ret rc		Return status code
120 122
  */
121
-int elf_load ( struct image *image ) {
123
+int elf_load ( struct image *image, physaddr_t *entry ) {
122 124
 	Elf_Ehdr ehdr;
123 125
 	Elf_Phdr phdr;
124 126
 	Elf_Off phoff;
125 127
 	unsigned int phnum;
126 128
 	int rc;
127 129
 
128
-	/* Image type must already have been set by caller */
129
-	assert ( image->type != NULL );
130
-
131 130
 	/* Read ELF header */
132 131
 	copy_from_user ( &ehdr, image->data, 0, sizeof ( ehdr ) );
133 132
 	if ( memcmp ( &ehdr.e_ident[EI_MAG0], ELFMAG, SELFMAG ) != 0 ) {
@@ -135,8 +134,8 @@ int elf_load ( struct image *image ) {
135 134
 		return -ENOEXEC;
136 135
 	}
137 136
 
138
-	/* Invalidate execution address */
139
-	image->priv.phys = 0;
137
+	/* Invalidate entry point */
138
+	*entry = 0;
140 139
 
141 140
 	/* Read ELF program headers */
142 141
 	for ( phoff = ehdr.e_phoff , phnum = ehdr.e_phnum ; phnum ;
@@ -147,12 +146,14 @@ int elf_load ( struct image *image ) {
147 146
 			return -ENOEXEC;
148 147
 		}
149 148
 		copy_from_user ( &phdr, image->data, phoff, sizeof ( phdr ) );
150
-		if ( ( rc = elf_load_segment ( image, &phdr, &ehdr ) ) != 0 )
149
+		if ( ( rc = elf_load_segment ( image, &phdr, &ehdr,
150
+					       entry ) ) != 0 ) {
151 151
 			return rc;
152
+		}
152 153
 	}
153 154
 
154 155
 	/* Check for a valid execution address */
155
-	if ( ! image->priv.phys ) {
156
+	if ( ! *entry ) {
156 157
 		DBGC ( image, "ELF %p entry point %lx outside image\n",
157 158
 		       image, ( ( unsigned long ) ehdr.e_entry ) );
158 159
 		return -ENOEXEC;

+ 3
- 3
src/image/embedded.c View File

@@ -76,10 +76,10 @@ static void embedded_init ( void ) {
76 76
 		}
77 77
 	}
78 78
 
79
-	/* Load the first image */
79
+	/* Select the first image */
80 80
 	image = &embedded_images[0];
81
-	if ( ( rc = image_autoload ( image ) ) != 0 ) {
82
-		DBG ( "Could not load embedded image \"%s\": %s\n",
81
+	if ( ( rc = image_select ( image ) ) != 0 ) {
82
+		DBG ( "Could not select embedded image \"%s\": %s\n",
83 83
 		      image->name, strerror ( rc ) );
84 84
 		return;
85 85
 	}

+ 3
- 12
src/image/script.c View File

@@ -36,8 +36,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
36 36
 #include <ipxe/image.h>
37 37
 #include <ipxe/shell.h>
38 38
 
39
-struct image_type script_image_type __image_type ( PROBE_NORMAL );
40
-
41 39
 /** Currently running script
42 40
  *
43 41
  * This is a global in order to allow goto_exec() to update the
@@ -165,12 +163,12 @@ static int script_exec ( struct image *image ) {
165 163
 }
166 164
 
167 165
 /**
168
- * Load script into memory
166
+ * Probe script image
169 167
  *
170 168
  * @v image		Script
171 169
  * @ret rc		Return status code
172 170
  */
173
-static int script_load ( struct image *image ) {
171
+static int script_probe ( struct image *image ) {
174 172
 	static const char ipxe_magic[] = "#!ipxe";
175 173
 	static const char gpxe_magic[] = "#!gpxe";
176 174
 	linker_assert ( sizeof ( ipxe_magic ) == sizeof ( gpxe_magic ),
@@ -193,20 +191,13 @@ static int script_load ( struct image *image ) {
193 191
 		return -ENOEXEC;
194 192
 	}
195 193
 
196
-	/* This is a script */
197
-	image->type = &script_image_type;
198
-
199
-	/* We don't actually load it anywhere; we will pick the lines
200
-	 * out of the image as we need them.
201
-	 */
202
-
203 194
 	return 0;
204 195
 }
205 196
 
206 197
 /** Script image type */
207 198
 struct image_type script_image_type __image_type ( PROBE_NORMAL ) = {
208 199
 	.name = "script",
209
-	.load = script_load,
200
+	.probe = script_probe,
210 201
 	.exec = script_exec,
211 202
 };
212 203
 

+ 1
- 1
src/include/ipxe/elf.h View File

@@ -12,6 +12,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
12 12
 
13 13
 #include <elf.h>
14 14
 
15
-extern int elf_load ( struct image *image );
15
+extern int elf_load ( struct image *image, physaddr_t *entry );
16 16
 
17 17
 #endif /* _IPXE_ELF_H */

+ 20
- 42
src/include/ipxe/image.h View File

@@ -4,7 +4,7 @@
4 4
 /**
5 5
  * @file
6 6
  *
7
- * Executable/loadable images
7
+ * Executable images
8 8
  *
9 9
  */
10 10
 
@@ -18,7 +18,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
18 18
 struct uri;
19 19
 struct image_type;
20 20
 
21
-/** An executable or loadable image */
21
+/** An executable image */
22 22
 struct image {
23 23
 	/** Reference count */
24 24
 	struct refcnt refcnt;
@@ -42,20 +42,13 @@ struct image {
42 42
 
43 43
 	/** Image type, if known */
44 44
 	struct image_type *type;
45
-	/** Image type private data */
46
-	union {
47
-		physaddr_t phys;
48
-		userptr_t user;
49
-		unsigned long ul;
50
-	} priv;
51 45
 
52 46
 	/** Replacement image
53 47
 	 *
54 48
 	 * An image wishing to replace itself with another image (in a
55 49
 	 * style similar to a Unix exec() call) should return from its
56 50
 	 * exec() method with the replacement image set to point to
57
-	 * the new image.  The new image must already be in a suitable
58
-	 * state for execution (i.e. loaded).
51
+	 * the new image.
59 52
 	 *
60 53
 	 * If an image unregisters itself as a result of being
61 54
 	 * executed, it must make sure that its replacement image (if
@@ -65,41 +58,26 @@ struct image {
65 58
 	struct image *replacement;
66 59
 };
67 60
 
68
-/** Image is loaded */
69
-#define IMAGE_LOADED 0x0001
61
+/** Image is selected for execution */
62
+#define IMAGE_SELECTED 0x0001
70 63
 
71
-/** An executable or loadable image type */
64
+/** An executable image type */
72 65
 struct image_type {
73 66
 	/** Name of this image type */
74 67
 	char *name;
75
-	/**
76
-	 * Load image into memory
68
+	/** Probe image
77 69
 	 *
78
-	 * @v image		Executable/loadable image
70
+	 * @v image		Executable image
79 71
 	 * @ret rc		Return status code
80 72
 	 *
81
-	 * Load the image into memory at the correct location as
82
-	 * determined by the file format.
83
-	 *
84
-	 * If the file image is in the correct format, the method must
85
-	 * update @c image->type to point to its own type (unless @c
86
-	 * image->type is already set).  This allows the autoloading
87
-	 * code to disambiguate between "this is not my image format"
88
-	 * and "there is something wrong with this image".  In
89
-	 * particular, setting @c image->type and then returning an
90
-	 * error will cause image_autoload() to abort and return an
91
-	 * error, rather than continuing to the next image type.
73
+	 * Return success if the image is of this image type.
92 74
 	 */
93
-	int ( * load ) ( struct image *image );
75
+	int ( * probe ) ( struct image *image );
94 76
 	/**
95
-	 * Execute loaded image
77
+	 * Execute image
96 78
 	 *
97
-	 * @v image		Loaded image
79
+	 * @v image		Executable image
98 80
 	 * @ret rc		Return status code
99
-	 *
100
-	 * Note that the image may be invalidated by the act of
101
-	 * execution, i.e. an image is allowed to choose to unregister
102
-	 * (and so potentially free) itself.
103 81
 	 */
104 82
 	int ( * exec ) ( struct image *image );
105 83
 };
@@ -125,10 +103,10 @@ struct image_type {
125 103
  */
126 104
 #define PROBE_PXE 03
127 105
 
128
-/** Executable or loadable image type table */
106
+/** Executable image type table */
129 107
 #define IMAGE_TYPES __table ( struct image_type, "image_types" )
130 108
 
131
-/** An executable or loadable image type */
109
+/** An executable image type */
132 110
 #define __image_type( probe_order ) __table_entry ( IMAGE_TYPES, probe_order )
133 111
 
134 112
 extern struct list_head images;
@@ -147,17 +125,17 @@ static inline int have_images ( void ) {
147 125
 }
148 126
 
149 127
 extern struct image * alloc_image ( void );
150
-extern int image_set_uri ( struct image *image, struct uri *uri );
128
+extern void image_set_uri ( struct image *image, struct uri *uri );
151 129
 extern int image_set_cmdline ( struct image *image, const char *cmdline );
152 130
 extern int register_image ( struct image *image );
153 131
 extern void unregister_image ( struct image *image );
154
-extern void promote_image ( struct image *image );
155 132
 struct image * find_image ( const char *name );
156
-extern int image_load ( struct image *image );
157
-extern int image_autoload ( struct image *image );
133
+extern int image_probe ( struct image *image );
158 134
 extern int image_exec ( struct image *image );
159
-extern int register_and_autoload_image ( struct image *image );
160
-extern int register_and_autoexec_image ( struct image *image );
135
+extern int image_select ( struct image *image );
136
+extern struct image * image_find_selected ( void );
137
+extern int register_and_select_image ( struct image *image );
138
+extern int register_and_boot_image ( struct image *image );
161 139
 
162 140
 /**
163 141
  * Increment reference count on an image

+ 30
- 4
src/include/usr/imgmgmt.h View File

@@ -9,16 +9,42 @@
9 9
 
10 10
 FILE_LICENCE ( GPL2_OR_LATER );
11 11
 
12
-struct image;
12
+#include <ipxe/image.h>
13 13
 
14 14
 extern int imgdownload ( struct image *image, struct uri *uri,
15 15
 			 int ( * action ) ( struct image *image ) );
16 16
 extern int imgfetch ( struct image *image, const char *uri_string,
17 17
 		      int ( * action ) ( struct image *image ) );
18
-extern int imgload ( struct image *image );
19
-extern int imgexec ( struct image *image );
20
-extern struct image * imgautoselect ( void );
21 18
 extern void imgstat ( struct image *image );
22 19
 extern void imgfree ( struct image *image );
23 20
 
21
+/**
22
+ * Select an image for execution
23
+ *
24
+ * @v image		Image
25
+ * @ret rc		Return status code
26
+ */
27
+static inline int imgselect ( struct image *image ) {
28
+	return image_select ( image );
29
+}
30
+
31
+/**
32
+ * Find the previously-selected image
33
+ *
34
+ * @ret image		Image, or NULL
35
+ */
36
+static inline struct image * imgautoselect ( void ) {
37
+	return image_find_selected();
38
+}
39
+
40
+/**
41
+ * Execute an image
42
+ *
43
+ * @v image		Image
44
+ * @ret rc		Return status code
45
+ */
46
+static inline int imgexec ( struct image *image ) {
47
+	return image_exec ( image );
48
+}
49
+
24 50
 #endif /* _USR_IMGMGMT_H */

+ 1
- 1
src/usr/autoboot.c View File

@@ -184,7 +184,7 @@ int uriboot ( struct uri *filename, struct uri *root_path ) {
184 184
 	/* Attempt filename boot if applicable */
185 185
 	if ( filename ) {
186 186
 		if ( ( rc = imgdownload ( image, filename,
187
-					  register_and_autoexec_image ) ) !=0){
187
+					  register_and_boot_image ) ) != 0 ) {
188 188
 			printf ( "\nCould not chain image: %s\n",
189 189
 				 strerror ( rc ) );
190 190
 			/* Fall through to (possibly) attempt a SAN boot

+ 3
- 49
src/usr/imgmgmt.c View File

@@ -99,63 +99,17 @@ int imgfetch ( struct image *image, const char *uri_string,
99 99
 	return rc;
100 100
 }
101 101
 
102
-/**
103
- * Load an image
104
- *
105
- * @v image		Image
106
- * @ret rc		Return status code
107
- */
108
-int imgload ( struct image *image ) {
109
-	int rc;
110
-
111
-	/* Try to load image */
112
-	if ( ( rc = image_autoload ( image ) ) != 0 )
113
-		return rc;
114
-
115
-	return 0;
116
-}
117
-
118
-/**
119
- * Execute an image
120
- *
121
- * @v image		Image
122
- * @ret rc		Return status code
123
- */
124
-int imgexec ( struct image *image ) {
125
-	return image_exec ( image );
126
-}
127
-
128
-/**
129
- * Identify the only loaded image
130
- *
131
- * @ret image		Image, or NULL if 0 or >1 images are loaded
132
- */
133
-struct image * imgautoselect ( void ) {
134
-	struct image *image;
135
-	struct image *selected_image = NULL;
136
-	int flagged_images = 0;
137
-
138
-	for_each_image ( image ) {
139
-		if ( image->flags & IMAGE_LOADED ) {
140
-			selected_image = image;
141
-			flagged_images++;
142
-		}
143
-	}
144
-
145
-	return ( ( flagged_images == 1 ) ? selected_image : NULL );
146
-}
147
-
148 102
 /**
149 103
  * Display status of an image
150 104
  *
151 105
  * @v image		Executable/loadable image
152 106
  */
153 107
 void imgstat ( struct image *image ) {
154
-	printf ( "%s: %zd bytes", image->name, image->len );
108
+	printf ( "%s : %zd bytes", image->name, image->len );
155 109
 	if ( image->type )
156 110
 		printf ( " [%s]", image->type->name );
157
-	if ( image->flags & IMAGE_LOADED )
158
-		printf ( " [LOADED]" );
111
+	if ( image->flags & IMAGE_SELECTED )
112
+		printf ( " [SELECTED]" );
159 113
 	if ( image->cmdline )
160 114
 		printf ( " \"%s\"", image->cmdline );
161 115
 	printf ( "\n" );

Loading…
Cancel
Save