Home | History | Annotate | Download | only in image
      1 #include <errno.h>
      2 #include <assert.h>
      3 #include <realmode.h>
      4 #include <gateA20.h>
      5 #include <memsizes.h>
      6 #include <basemem_packet.h>
      7 #include <gpxe/uaccess.h>
      8 #include <gpxe/segment.h>
      9 #include <gpxe/init.h>
     10 #include <gpxe/netdevice.h>
     11 #include <gpxe/fakedhcp.h>
     12 #include <gpxe/image.h>
     13 #include <gpxe/features.h>
     14 
     15 /** @file
     16  *
     17  * NBI image format.
     18  *
     19  * The Net Boot Image format is defined by the "Draft Net Boot Image
     20  * Proposal 0.3" by Jamie Honan, Gero Kuhlmann and Ken Yap.  It is now
     21  * considered to be a legacy format, but it still included because a
     22  * large amount of software (e.g. nymph, LTSP) makes use of NBI files.
     23  *
     24  * Etherboot does not implement the INT 78 callback interface
     25  * described by the NBI specification.  For a callback interface on
     26  * x86 architecture, use PXE.
     27  *
     28  */
     29 
     30 FEATURE ( FEATURE_IMAGE, "NBI", DHCP_EB_FEATURE_NBI, 1 );
     31 
     32 struct image_type nbi_image_type __image_type ( PROBE_NORMAL );
     33 
     34 /**
     35  * An NBI image header
     36  *
     37  * Note that the length field uses a peculiar encoding; use the
     38  * NBI_LENGTH() macro to decode the actual header length.
     39  *
     40  */
     41 struct imgheader {
     42 	unsigned long magic;		/**< Magic number (NBI_MAGIC) */
     43 	union {
     44 		unsigned char length;	/**< Nibble-coded header length */
     45 		unsigned long flags;	/**< Image flags */
     46 	};
     47 	segoff_t location;		/**< 16-bit seg:off header location */
     48 	union {
     49 		segoff_t segoff;	/**< 16-bit seg:off entry point */
     50 		unsigned long linear;	/**< 32-bit entry point */
     51 	} execaddr;
     52 } __attribute__ (( packed ));
     53 
     54 /** NBI magic number */
     55 #define NBI_MAGIC 0x1B031336UL
     56 
     57 /* Interpretation of the "length" fields */
     58 #define NBI_NONVENDOR_LENGTH(len)	( ( (len) & 0x0f ) << 2 )
     59 #define NBI_VENDOR_LENGTH(len)		( ( (len) & 0xf0 ) >> 2 )
     60 #define NBI_LENGTH(len) ( NBI_NONVENDOR_LENGTH(len) + NBI_VENDOR_LENGTH(len) )
     61 
     62 /* Interpretation of the "flags" fields */
     63 #define	NBI_PROGRAM_RETURNS(flags)	( (flags) & ( 1 << 8 ) )
     64 #define	NBI_LINEAR_EXEC_ADDR(flags)	( (flags) & ( 1 << 31 ) )
     65 
     66 /** NBI header length */
     67 #define NBI_HEADER_LENGTH	512
     68 
     69 /**
     70  * An NBI segment header
     71  *
     72  * Note that the length field uses a peculiar encoding; use the
     73  * NBI_LENGTH() macro to decode the actual header length.
     74  *
     75  */
     76 struct segheader {
     77 	unsigned char length;		/**< Nibble-coded header length */
     78 	unsigned char vendortag;	/**< Vendor-defined private tag */
     79 	unsigned char reserved;
     80 	unsigned char flags;		/**< Segment flags */
     81 	unsigned long loadaddr;		/**< Load address */
     82 	unsigned long imglength;	/**< Segment length in NBI file */
     83 	unsigned long memlength;	/**< Segment length in memory */
     84 };
     85 
     86 /* Interpretation of the "flags" fields */
     87 #define NBI_LOADADDR_FLAGS(flags)	( (flags) & 0x03 )
     88 #define NBI_LOADADDR_ABS		0x00
     89 #define NBI_LOADADDR_AFTER		0x01
     90 #define NBI_LOADADDR_END		0x02
     91 #define NBI_LOADADDR_BEFORE		0x03
     92 #define NBI_LAST_SEGHEADER(flags)	( (flags) & ( 1 << 2 ) )
     93 
     94 /* Define a type for passing info to a loaded program */
     95 struct ebinfo {
     96 	uint8_t  major, minor;  /* Version */
     97 	uint16_t flags;         /* Bit flags */
     98 };
     99 
    100 /** Info passed to NBI image */
    101 static struct ebinfo loaderinfo = {
    102 	VERSION_MAJOR, VERSION_MINOR,
    103 	0
    104 };
    105 
    106 /**
    107  * Prepare a segment for an NBI image
    108  *
    109  * @v image		NBI image
    110  * @v offset		Offset within NBI image
    111  * @v filesz		Length of initialised-data portion of the segment
    112  * @v memsz		Total length of the segment
    113  * @v src		Source for initialised data
    114  * @ret rc		Return status code
    115  */
    116 static int nbi_prepare_segment ( struct image *image, size_t offset __unused,
    117 				 userptr_t dest, size_t filesz, size_t memsz ){
    118 	int rc;
    119 
    120 	if ( ( rc = prep_segment ( dest, filesz, memsz ) ) != 0 ) {
    121 		DBGC ( image, "NBI %p could not prepare segment: %s\n",
    122 		       image, strerror ( rc ) );
    123 		return rc;
    124 	}
    125 
    126 	return 0;
    127 }
    128 
    129 /**
    130  * Load a segment for an NBI image
    131  *
    132  * @v image		NBI image
    133  * @v offset		Offset within NBI image
    134  * @v filesz		Length of initialised-data portion of the segment
    135  * @v memsz		Total length of the segment
    136  * @v src		Source for initialised data
    137  * @ret rc		Return status code
    138  */
    139 static int nbi_load_segment ( struct image *image, size_t offset,
    140 			      userptr_t dest, size_t filesz,
    141 			      size_t memsz __unused ) {
    142 	memcpy_user ( dest, 0, image->data, offset, filesz );
    143 	return 0;
    144 }
    145 
    146 /**
    147  * Process segments of an NBI image
    148  *
    149  * @v image		NBI image
    150  * @v imgheader		Image header information
    151  * @v process		Function to call for each segment
    152  * @ret rc		Return status code
    153  */
    154 static int nbi_process_segments ( struct image *image,
    155 				  struct imgheader *imgheader,
    156 				  int ( * process ) ( struct image *image,
    157 						      size_t offset,
    158 						      userptr_t dest,
    159 						      size_t filesz,
    160 						      size_t memsz ) ) {
    161 	struct segheader sh;
    162 	size_t offset = 0;
    163 	size_t sh_off;
    164 	userptr_t dest;
    165 	size_t filesz;
    166 	size_t memsz;
    167 	int rc;
    168 
    169 	/* Copy image header to target location */
    170 	dest = real_to_user ( imgheader->location.segment,
    171 			      imgheader->location.offset );
    172 	filesz = memsz = NBI_HEADER_LENGTH;
    173 	if ( ( rc = process ( image, offset, dest, filesz, memsz ) ) != 0 )
    174 		return rc;
    175 	offset += filesz;
    176 
    177 	/* Process segments in turn */
    178 	sh_off = NBI_LENGTH ( imgheader->length );
    179 	do {
    180 		/* Read segment header */
    181 		copy_from_user ( &sh, image->data, sh_off, sizeof ( sh ) );
    182 		if ( sh.length == 0 ) {
    183 			/* Avoid infinite loop? */
    184 			DBGC ( image, "NBI %p invalid segheader length 0\n",
    185 			       image );
    186 			return -ENOEXEC;
    187 		}
    188 
    189 		/* Calculate segment load address */
    190 		switch ( NBI_LOADADDR_FLAGS ( sh.flags ) ) {
    191 		case NBI_LOADADDR_ABS:
    192 			dest = phys_to_user ( sh.loadaddr );
    193 			break;
    194 		case NBI_LOADADDR_AFTER:
    195 			dest = userptr_add ( dest, memsz + sh.loadaddr );
    196 			break;
    197 		case NBI_LOADADDR_BEFORE:
    198 			dest = userptr_add ( dest, -sh.loadaddr );
    199 			break;
    200 		case NBI_LOADADDR_END:
    201 			/* Not correct according to the spec, but
    202 			 * maintains backwards compatibility with
    203 			 * previous versions of Etherboot.
    204 			 */
    205 			dest = phys_to_user ( ( extmemsize() + 1024 ) * 1024
    206 					      - sh.loadaddr );
    207 			break;
    208 		default:
    209 			/* Cannot be reached */
    210 			assert ( 0 );
    211 		}
    212 
    213 		/* Process this segment */
    214 		filesz = sh.imglength;
    215 		memsz = sh.memlength;
    216 		if ( ( offset + filesz ) > image->len ) {
    217 			DBGC ( image, "NBI %p segment outside file\n", image );
    218 			return -ENOEXEC;
    219 		}
    220 		if ( ( rc = process ( image, offset, dest,
    221 				      filesz, memsz ) ) != 0 ) {
    222 			return rc;
    223 		}
    224 		offset += filesz;
    225 
    226 		/* Next segheader */
    227 		sh_off += NBI_LENGTH ( sh.length );
    228 		if ( sh_off >= NBI_HEADER_LENGTH ) {
    229 			DBGC ( image, "NBI %p header overflow\n", image );
    230 			return -ENOEXEC;
    231 		}
    232 
    233 	} while ( ! NBI_LAST_SEGHEADER ( sh.flags ) );
    234 
    235 	if ( offset != image->len ) {
    236 		DBGC ( image, "NBI %p length wrong (file %zd, metadata %zd)\n",
    237 		       image, image->len, offset );
    238 		return -ENOEXEC;
    239 	}
    240 
    241 	return 0;
    242 }
    243 
    244 /**
    245  * Load an NBI image into memory
    246  *
    247  * @v image		NBI image
    248  * @ret rc		Return status code
    249  */
    250 static int nbi_load ( struct image *image ) {
    251 	struct imgheader imgheader;
    252 	int rc;
    253 
    254 	/* If we don't have enough data give up */
    255 	if ( image->len < NBI_HEADER_LENGTH ) {
    256 		DBGC ( image, "NBI %p too short for an NBI image\n", image );
    257 		return -ENOEXEC;
    258 	}
    259 
    260 	/* Check image header */
    261 	copy_from_user ( &imgheader, image->data, 0, sizeof ( imgheader ) );
    262 	if ( imgheader.magic != NBI_MAGIC ) {
    263 		DBGC ( image, "NBI %p has no NBI signature\n", image );
    264 		return -ENOEXEC;
    265 	}
    266 
    267 	/* This is an NBI image, valid or otherwise */
    268 	if ( ! image->type )
    269 		image->type = &nbi_image_type;
    270 
    271 	DBGC ( image, "NBI %p placing header at %hx:%hx\n", image,
    272 	       imgheader.location.segment, imgheader.location.offset );
    273 
    274 	/* NBI files can have overlaps between segments; the bss of
    275 	 * one segment may overlap the initialised data of another.  I
    276 	 * assume this is a design flaw, but there are images out
    277 	 * there that we need to work with.  We therefore do two
    278 	 * passes: first to initialise the segments, then to copy the
    279 	 * data.  This avoids zeroing out already-copied data.
    280 	 */
    281 	if ( ( rc = nbi_process_segments ( image, &imgheader,
    282 					   nbi_prepare_segment ) ) != 0 )
    283 		return rc;
    284 	if ( ( rc = nbi_process_segments ( image, &imgheader,
    285 					   nbi_load_segment ) ) != 0 )
    286 		return rc;
    287 
    288 	/* Record header address in image private data field */
    289 	image->priv.user = real_to_user ( imgheader.location.segment,
    290 					  imgheader.location.offset );
    291 
    292 	return 0;
    293 }
    294 
    295 /**
    296  * Boot a 16-bit NBI image
    297  *
    298  * @v imgheader		Image header information
    299  * @ret rc		Return status code, if image returns
    300  */
    301 static int nbi_boot16 ( struct image *image, struct imgheader *imgheader ) {
    302 	int discard_D, discard_S, discard_b;
    303 	int rc;
    304 
    305 	DBGC ( image, "NBI %p executing 16-bit image at %04x:%04x\n", image,
    306 	       imgheader->execaddr.segoff.segment,
    307 	       imgheader->execaddr.segoff.offset );
    308 
    309 	gateA20_unset();
    310 
    311 	__asm__ __volatile__ (
    312 		REAL_CODE ( "pushw %%ds\n\t"	/* far pointer to bootp data */
    313 			    "pushw %%bx\n\t"
    314 			    "pushl %%esi\n\t"	/* location */
    315 			    "pushw %%cs\n\t"	/* lcall execaddr */
    316 			    "call 1f\n\t"
    317 			    "jmp 2f\n\t"
    318 			    "\n1:\n\t"
    319 			    "pushl %%edi\n\t"
    320 			    "lret\n\t"
    321 			    "\n2:\n\t"
    322 			    "addw $8,%%sp\n\t"	/* clean up stack */ )
    323 		: "=a" ( rc ), "=D" ( discard_D ), "=S" ( discard_S ),
    324 		  "=b" ( discard_b )
    325 		: "D" ( imgheader->execaddr.segoff ),
    326 		  "S" ( imgheader->location ),
    327 		  "b" ( __from_data16 ( basemem_packet ) )
    328 		: "ecx", "edx", "ebp" );
    329 
    330 	gateA20_set();
    331 
    332 	return rc;
    333 }
    334 
    335 /**
    336  * Boot a 32-bit NBI image
    337  *
    338  * @v imgheader		Image header information
    339  * @ret rc		Return status code, if image returns
    340  */
    341 static int nbi_boot32 ( struct image *image, struct imgheader *imgheader ) {
    342 	int discard_D, discard_S, discard_b;
    343 	int rc;
    344 
    345 	DBGC ( image, "NBI %p executing 32-bit image at %lx\n",
    346 	       image, imgheader->execaddr.linear );
    347 
    348 	/* no gateA20_unset for PM call */
    349 
    350 	/* Jump to OS with flat physical addressing */
    351 	__asm__ __volatile__ (
    352 		PHYS_CODE ( "pushl %%ebx\n\t" /* bootp data */
    353 			    "pushl %%esi\n\t" /* imgheader */
    354 			    "pushl %%eax\n\t" /* loaderinfo */
    355 			    "call *%%edi\n\t"
    356 			    "addl $12, %%esp\n\t" /* clean up stack */ )
    357 		: "=a" ( rc ), "=D" ( discard_D ), "=S" ( discard_S ),
    358 		  "=b" ( discard_b )
    359 		: "D" ( imgheader->execaddr.linear ),
    360 		  "S" ( ( imgheader->location.segment << 4 ) +
    361 			imgheader->location.offset ),
    362 		  "b" ( virt_to_phys ( basemem_packet ) ),
    363 		  "a" ( virt_to_phys ( &loaderinfo ) )
    364 		: "ecx", "edx", "ebp", "memory" );
    365 
    366 	return rc;
    367 }
    368 
    369 /**
    370  * Prepare DHCP parameter block for NBI image
    371  *
    372  * @v image		NBI image
    373  * @ret rc		Return status code
    374  */
    375 static int nbi_prepare_dhcp ( struct image *image ) {
    376 	struct net_device *boot_netdev;
    377 	int rc;
    378 
    379 	boot_netdev = last_opened_netdev();
    380 	if ( ! boot_netdev ) {
    381 		DBGC ( image, "NBI %p could not identify a network device\n",
    382 		       image );
    383 		return -ENODEV;
    384 	}
    385 
    386 	if ( ( rc = create_fakedhcpack ( boot_netdev, basemem_packet,
    387 					 sizeof ( basemem_packet ) ) ) != 0 ) {
    388 		DBGC ( image, "NBI %p failed to build DHCP packet\n", image );
    389 		return rc;
    390 	}
    391 
    392 	return 0;
    393 }
    394 
    395 /**
    396  * Execute a loaded NBI image
    397  *
    398  * @v image		NBI image
    399  * @ret rc		Return status code
    400  */
    401 static int nbi_exec ( struct image *image ) {
    402 	struct imgheader imgheader;
    403 	int may_return;
    404 	int rc;
    405 
    406 	copy_from_user ( &imgheader, image->priv.user, 0,
    407 			 sizeof ( imgheader ) );
    408 
    409 	/* Prepare DHCP option block */
    410 	if ( ( rc = nbi_prepare_dhcp ( image ) ) != 0 )
    411 		return rc;
    412 
    413 	/* Shut down now if NBI image will not return */
    414 	may_return = NBI_PROGRAM_RETURNS ( imgheader.flags );
    415 	if ( ! may_return )
    416 		shutdown ( SHUTDOWN_BOOT );
    417 
    418 	/* Execute NBI image */
    419 	if ( NBI_LINEAR_EXEC_ADDR ( imgheader.flags ) ) {
    420 		rc = nbi_boot32 ( image, &imgheader );
    421 	} else {
    422 	        rc = nbi_boot16 ( image, &imgheader );
    423 	}
    424 
    425 	if ( ! may_return ) {
    426 		/* Cannot continue after shutdown() called */
    427 		DBGC ( image, "NBI %p returned %d from non-returnable image\n",
    428 		       image, rc  );
    429 		while ( 1 ) {}
    430 	}
    431 
    432 	DBGC ( image, "NBI %p returned %d\n", image, rc );
    433 
    434 	return rc;
    435 }
    436 
    437 /** NBI image type */
    438 struct image_type nbi_image_type __image_type ( PROBE_NORMAL ) = {
    439 	.name = "NBI",
    440 	.load = nbi_load,
    441 	.exec = nbi_exec,
    442 };
    443