You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

nbi.c 12KB

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