|  | @@ -5,6 +5,7 @@
 | 
		
	
		
			
			| 5 | 5 |  #include <memsizes.h>
 | 
		
	
		
			
			| 6 | 6 |  #include <gpxe/uaccess.h>
 | 
		
	
		
			
			| 7 | 7 |  #include <gpxe/segment.h>
 | 
		
	
		
			
			|  | 8 | +#include <gpxe/shutdown.h>
 | 
		
	
		
			
			| 8 | 9 |  #include <gpxe/image.h>
 | 
		
	
		
			
			| 9 | 10 |  
 | 
		
	
		
			
			| 10 | 11 |  /** @file
 | 
		
	
	
		
			
			|  | @@ -289,13 +290,11 @@ int nbi_load ( struct image *image ) {
 | 
		
	
		
			
			| 289 | 290 |   * Boot a 16-bit NBI image
 | 
		
	
		
			
			| 290 | 291 |   *
 | 
		
	
		
			
			| 291 | 292 |   * @v imgheader		Image header information
 | 
		
	
		
			
			| 292 |  | - * @ret Never		NBI program booted successfully
 | 
		
	
		
			
			| 293 |  | - * @ret False		NBI program returned
 | 
		
	
		
			
			| 294 |  | - * @err ECANCELED	NBI program returned
 | 
		
	
		
			
			| 295 |  | - *
 | 
		
	
		
			
			|  | 293 | + * @ret rc		Return status code, if image returns
 | 
		
	
		
			
			| 296 | 294 |   */
 | 
		
	
		
			
			| 297 | 295 |  static int nbi_boot16 ( struct image *image, struct imgheader *imgheader ) {
 | 
		
	
		
			
			| 298 | 296 |  	int discard_D, discard_S, discard_b;
 | 
		
	
		
			
			|  | 297 | +	int rc;
 | 
		
	
		
			
			| 299 | 298 |  
 | 
		
	
		
			
			| 300 | 299 |  	DBGC ( image, "NBI %p executing 16-bit image at %04x:%04x\n", image,
 | 
		
	
		
			
			| 301 | 300 |  	       imgheader->execaddr.segoff.segment,
 | 
		
	
	
		
			
			|  | @@ -316,27 +315,22 @@ static int nbi_boot16 ( struct image *image, struct imgheader *imgheader ) {
 | 
		
	
		
			
			| 316 | 315 |  			    "lret\n\t"
 | 
		
	
		
			
			| 317 | 316 |  			    "\n2:\n\t"
 | 
		
	
		
			
			| 318 | 317 |  			    "addw $8,%%sp\n\t"	/* clean up stack */ )
 | 
		
	
		
			
			| 319 |  | -		: "=D" ( discard_D ), "=S" ( discard_S ), "=b" ( discard_b )
 | 
		
	
		
			
			|  | 318 | +		: "=a" ( rc ), "=D" ( discard_D ), "=S" ( discard_S ),
 | 
		
	
		
			
			|  | 319 | +		  "=b" ( discard_b )
 | 
		
	
		
			
			| 320 | 320 |  		: "D" ( imgheader->execaddr.segoff ),
 | 
		
	
		
			
			| 321 | 321 |  		  "S" ( imgheader->location ), "b" ( 0 /* bootp data */ )
 | 
		
	
		
			
			| 322 |  | -		: "eax", "ecx", "edx", "ebp" );
 | 
		
	
		
			
			| 323 |  | -	
 | 
		
	
		
			
			| 324 |  | -	return -ECANCELED;
 | 
		
	
		
			
			|  | 322 | +		: "ecx", "edx", "ebp" );
 | 
		
	
		
			
			|  | 323 | +
 | 
		
	
		
			
			|  | 324 | +	gateA20_set();
 | 
		
	
		
			
			|  | 325 | +
 | 
		
	
		
			
			|  | 326 | +	return rc;
 | 
		
	
		
			
			| 325 | 327 |  }
 | 
		
	
		
			
			| 326 | 328 |  
 | 
		
	
		
			
			| 327 | 329 |  /**
 | 
		
	
		
			
			| 328 | 330 |   * Boot a 32-bit NBI image
 | 
		
	
		
			
			| 329 | 331 |   *
 | 
		
	
		
			
			| 330 | 332 |   * @v imgheader		Image header information
 | 
		
	
		
			
			| 331 |  | - * @ret False		NBI program should not have returned
 | 
		
	
		
			
			| 332 |  | - * @ret other		As returned by NBI program
 | 
		
	
		
			
			| 333 |  | - * @err ECANCELED	NBI program should not have returned
 | 
		
	
		
			
			| 334 |  | - *
 | 
		
	
		
			
			| 335 |  | - * To distinguish between the case of an NBI program returning false,
 | 
		
	
		
			
			| 336 |  | - * and an NBI program that should not have returned, check errno.
 | 
		
	
		
			
			| 337 |  | - * errno will be set to ECANCELED only if the NBI program should not
 | 
		
	
		
			
			| 338 |  | - * have returned.
 | 
		
	
		
			
			| 339 |  | - *
 | 
		
	
		
			
			|  | 333 | + * @ret rc		Return status code, if image returns
 | 
		
	
		
			
			| 340 | 334 |   */
 | 
		
	
		
			
			| 341 | 335 |  static int nbi_boot32 ( struct image *image, struct imgheader *imgheader ) {
 | 
		
	
		
			
			| 342 | 336 |  	int rc;
 | 
		
	
	
		
			
			|  | @@ -347,21 +341,21 @@ static int nbi_boot32 ( struct image *image, struct imgheader *imgheader ) {
 | 
		
	
		
			
			| 347 | 341 |  	/* no gateA20_unset for PM call */
 | 
		
	
		
			
			| 348 | 342 |  
 | 
		
	
		
			
			| 349 | 343 |  #warning "Should be providing bootp data"
 | 
		
	
		
			
			| 350 |  | -#warning "xstart32 no longer exists"
 | 
		
	
		
			
			| 351 |  | -#if 0
 | 
		
	
		
			
			| 352 |  | -	rc = xstart32 ( imgheader->execaddr.linear,
 | 
		
	
		
			
			| 353 |  | -			virt_to_phys ( &loaderinfo ),
 | 
		
	
		
			
			| 354 |  | -			( ( imgheader->location.segment << 4 ) +
 | 
		
	
		
			
			| 355 |  | -			  imgheader->location.offset ),
 | 
		
	
		
			
			| 356 |  | -			0 /* bootp data */ );
 | 
		
	
		
			
			| 357 |  | -#endif
 | 
		
	
		
			
			| 358 |  | -
 | 
		
	
		
			
			| 359 |  | -	DBGC ( image, "NBI %p returned %d\n", image, rc );
 | 
		
	
		
			
			| 360 | 344 |  
 | 
		
	
		
			
			| 361 |  | -	if ( ! NBI_PROGRAM_RETURNS ( imgheader->flags ) ) {
 | 
		
	
		
			
			| 362 |  | -		/* We shouldn't have returned */
 | 
		
	
		
			
			| 363 |  | -		rc = -ECANCELED;
 | 
		
	
		
			
			| 364 |  | -	}
 | 
		
	
		
			
			|  | 345 | +	/* Jump to OS with flat physical addressing */
 | 
		
	
		
			
			|  | 346 | +	__asm__ __volatile__ (
 | 
		
	
		
			
			|  | 347 | +		PHYS_CODE ( "pushl $0\n\t" /* bootp data */
 | 
		
	
		
			
			|  | 348 | +			    "pushl %3\n\t" /* imgheader */
 | 
		
	
		
			
			|  | 349 | +			    "pushl %2\n\t" /* loaderinfo */
 | 
		
	
		
			
			|  | 350 | +			    "xchgw %%bx,%%bx\n\t"
 | 
		
	
		
			
			|  | 351 | +			    "call *%1\n\t"
 | 
		
	
		
			
			|  | 352 | +			    "addl $12, %%esp\n\t" /* clean up stack */ )
 | 
		
	
		
			
			|  | 353 | +		: "=a" ( rc )
 | 
		
	
		
			
			|  | 354 | +		: "D" ( imgheader->execaddr.linear ),
 | 
		
	
		
			
			|  | 355 | +		  "a" ( virt_to_phys ( &loaderinfo ) ),
 | 
		
	
		
			
			|  | 356 | +		  "S" ( ( imgheader->location.segment << 4 ) +
 | 
		
	
		
			
			|  | 357 | +			imgheader->location.offset )
 | 
		
	
		
			
			|  | 358 | +		: "ebx", "ecx", "edx", "ebp", "memory" );
 | 
		
	
		
			
			| 365 | 359 |  
 | 
		
	
		
			
			| 366 | 360 |  	return rc;
 | 
		
	
		
			
			| 367 | 361 |  }
 | 
		
	
	
		
			
			|  | @@ -374,15 +368,32 @@ static int nbi_boot32 ( struct image *image, struct imgheader *imgheader ) {
 | 
		
	
		
			
			| 374 | 368 |   */
 | 
		
	
		
			
			| 375 | 369 |  static int nbi_exec ( struct image *image ) {
 | 
		
	
		
			
			| 376 | 370 |  	struct imgheader imgheader;
 | 
		
	
		
			
			|  | 371 | +	int may_return;
 | 
		
	
		
			
			|  | 372 | +	int rc;
 | 
		
	
		
			
			| 377 | 373 |  
 | 
		
	
		
			
			| 378 | 374 |  	copy_from_user ( &imgheader, image->priv.user, 0,
 | 
		
	
		
			
			| 379 | 375 |  			 sizeof ( imgheader ) );
 | 
		
	
		
			
			| 380 | 376 |  
 | 
		
	
		
			
			|  | 377 | +	may_return = NBI_PROGRAM_RETURNS ( imgheader.flags );
 | 
		
	
		
			
			|  | 378 | +	if ( ! may_return )
 | 
		
	
		
			
			|  | 379 | +		shutdown();
 | 
		
	
		
			
			|  | 380 | +
 | 
		
	
		
			
			| 381 | 381 |  	if ( NBI_LINEAR_EXEC_ADDR ( imgheader.flags ) ) {
 | 
		
	
		
			
			| 382 |  | -		return nbi_boot32 ( image, &imgheader );
 | 
		
	
		
			
			|  | 382 | +		rc = nbi_boot32 ( image, &imgheader );
 | 
		
	
		
			
			| 383 | 383 |  	} else {
 | 
		
	
		
			
			| 384 |  | -		return nbi_boot16 ( image, &imgheader );
 | 
		
	
		
			
			|  | 384 | +	        rc = nbi_boot16 ( image, &imgheader );
 | 
		
	
		
			
			|  | 385 | +	}
 | 
		
	
		
			
			|  | 386 | +
 | 
		
	
		
			
			|  | 387 | +	if ( ! may_return ) {
 | 
		
	
		
			
			|  | 388 | +		/* Cannot continue after shutdown() called */
 | 
		
	
		
			
			|  | 389 | +		DBGC ( image, "NBI %p returned %d from non-returnable image\n",
 | 
		
	
		
			
			|  | 390 | +		       image, rc  );
 | 
		
	
		
			
			|  | 391 | +		while ( 1 ) {}
 | 
		
	
		
			
			| 385 | 392 |  	}
 | 
		
	
		
			
			|  | 393 | +
 | 
		
	
		
			
			|  | 394 | +	DBGC ( image, "NBI %p returned %d\n", image, rc );
 | 
		
	
		
			
			|  | 395 | +
 | 
		
	
		
			
			|  | 396 | +	return rc;
 | 
		
	
		
			
			| 386 | 397 |  }
 | 
		
	
		
			
			| 387 | 398 |  
 | 
		
	
		
			
			| 388 | 399 |  /** NBI image type */
 |