nbi.c 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. #include "image.h"
  2. #include "memsizes.h"
  3. #include "realmode.h"
  4. #include "gateA20.h"
  5. #include "osloader.h"
  6. #include "etherboot.h"
  7. #include "errno.h"
  8. /** @file
  9. *
  10. * NBI image format.
  11. *
  12. * The Net Boot Image format is defined by the "Draft Net Boot Image
  13. * Proposal 0.3" by Jamie Honan, Gero Kuhlmann and Ken Yap. It is now
  14. * considered to be a legacy format, but it still included because a
  15. * large amount of software (e.g. nymph, LTSP) makes use of NBI files.
  16. *
  17. * Etherboot does not implement the INT 78 callback interface
  18. * described by the NBI specification. For a callback interface on
  19. * x86 architecture, use PXE.
  20. *
  21. */
  22. /**
  23. * An NBI image header
  24. *
  25. * Note that the length field uses a peculiar encoding; use the
  26. * NBI_LENGTH() macro to decode the actual header length.
  27. *
  28. */
  29. struct imgheader {
  30. unsigned long magic; /**< Magic number (NBI_MAGIC) */
  31. union {
  32. unsigned char length; /**< Nibble-coded header length */
  33. unsigned long flags; /**< Image flags */
  34. };
  35. segoff_t location; /**< 16-bit seg:off header location */
  36. union {
  37. segoff_t segoff; /**< 16-bit seg:off entry point */
  38. unsigned long linear; /**< 32-bit entry point */
  39. } execaddr;
  40. } __attribute__ (( packed ));
  41. /** NBI magic number */
  42. #define NBI_MAGIC 0x1B031336UL
  43. /* Interpretation of the "length" fields */
  44. #define NBI_NONVENDOR_LENGTH(len) ( ( (len) & 0x0f ) << 2 )
  45. #define NBI_VENDOR_LENGTH(len) ( ( (len) & 0xf0 ) >> 2 )
  46. #define NBI_LENGTH(len) ( NBI_NONVENDOR_LENGTH(len) + NBI_VENDOR_LENGTH(len) )
  47. /* Interpretation of the "flags" fields */
  48. #define NBI_PROGRAM_RETURNS(flags) ( (flags) & ( 1 << 8 ) )
  49. #define NBI_LINEAR_EXEC_ADDR(flags) ( (flags) & ( 1 << 31 ) )
  50. /** NBI header length */
  51. #define NBI_HEADER_LENGTH 512
  52. /**
  53. * An NBI segment header
  54. *
  55. * Note that the length field uses a peculiar encoding; use the
  56. * NBI_LENGTH() macro to decode the actual header length.
  57. *
  58. */
  59. struct segheader {
  60. unsigned char length; /**< Nibble-coded header length */
  61. unsigned char vendortag; /**< Vendor-defined private tag */
  62. unsigned char reserved;
  63. unsigned char flags; /**< Segment flags */
  64. unsigned long loadaddr; /**< Load address */
  65. unsigned long imglength; /**< Segment length in NBI file */
  66. unsigned long memlength; /**< Segment length in memory */
  67. };
  68. /* Interpretation of the "flags" fields */
  69. #define NBI_LOADADDR_FLAGS(flags) ( (flags) & 0x03 )
  70. #define NBI_LOADADDR_ABS 0x00
  71. #define NBI_LOADADDR_AFTER 0x01
  72. #define NBI_LOADADDR_END 0x02
  73. #define NBI_LOADADDR_BEFORE 0x03
  74. #define NBI_LAST_SEGHEADER(flags) ( (flags) & ( 1 << 2 ) )
  75. /** Info passed to NBI image */
  76. static struct ebinfo loaderinfo = {
  77. VERSION_MAJOR, VERSION_MINOR,
  78. 0
  79. };
  80. /**
  81. * Determine whether or not this is a valid NBI image
  82. *
  83. * @v start Address of the image
  84. * @v len Length of the image
  85. * @v context NBI image context
  86. * @ret True Image is a valid NBI image
  87. * @ret False Image is not a valid NBI image
  88. * @err ENOEXEC Image is not a valid NBI image
  89. *
  90. * "context" is filled in with a context pointer suitable for passing to
  91. * nbi_load() and nbi_boot().
  92. *
  93. */
  94. static int nbi_probe ( physaddr_t start, off_t len, void **context ) {
  95. static struct imgheader imgheader;
  96. if ( (unsigned)len < sizeof ( imgheader ) ) {
  97. DBG ( "NBI image too small\n" );
  98. errno = ENOEXEC;
  99. return 0;
  100. }
  101. copy_from_phys ( &imgheader, start, sizeof ( imgheader ) );
  102. if ( imgheader.magic != NBI_MAGIC ) {
  103. errno = ENOEXEC;
  104. return 0;
  105. }
  106. /* Record image context */
  107. DBG ( "NBI found valid image\n" );
  108. *context = &imgheader;
  109. return 1;
  110. }
  111. /**
  112. * Prepare a segment for an NBI image
  113. *
  114. * @v dest Address of segment
  115. * @v imglen Length of initialised-data portion of the segment
  116. * @v memlen Total length of the segment
  117. * @v src Source for initialised data
  118. * @ret True Segment can be used
  119. * @ret False Segment cannot be used
  120. * @err other As returned by prep_segment()
  121. *
  122. */
  123. static int nbi_prepare_segment ( physaddr_t dest, off_t imglen, off_t memlen,
  124. physaddr_t src __unused ) {
  125. DBG ( "NBI preparing segment [%x,%x) (imglen %d memlen %d)\n",
  126. dest, dest + memlen, imglen, memlen );
  127. return prep_segment ( dest, dest + imglen, dest + memlen );
  128. }
  129. /**
  130. * Load a segment for an NBI image
  131. *
  132. * @v dest Address of segment
  133. * @v imglen Length of initialised-data portion of the segment
  134. * @v memlen Total length of the segment
  135. * @v src Source for initialised data
  136. * @ret True Always
  137. *
  138. */
  139. static int nbi_load_segment ( physaddr_t dest, off_t imglen,
  140. off_t memlen __unused, physaddr_t src ) {
  141. DBG ( "NBI loading segment [%x,%x)\n", dest, dest + imglen );
  142. copy_phys_to_phys ( dest, src, imglen );
  143. return 1;
  144. }
  145. /**
  146. * Process segments of an NBI image
  147. *
  148. * @v start Address of the image
  149. * @v len Length of the image
  150. * @v imgheader Image header information
  151. * @v process Function to call for each segment
  152. * @ret True All segments were processed successfully
  153. * @ret False An error occurred processing a segment
  154. * @err ENOEXEC Image is not a valid NBI image
  155. * @err other As returned by the "process" function
  156. *
  157. */
  158. static int nbi_process_segments ( physaddr_t start, off_t len,
  159. struct imgheader *imgheader,
  160. int ( * process ) ( physaddr_t dest,
  161. off_t imglen,
  162. off_t memlen,
  163. physaddr_t src ) ) {
  164. struct segheader sh;
  165. off_t offset = 0;
  166. off_t sh_off;
  167. physaddr_t dest;
  168. off_t dest_imglen, dest_memlen;
  169. /* Copy header to target location */
  170. dest = ( ( imgheader->location.segment << 4 ) +
  171. imgheader->location.offset );
  172. dest_imglen = dest_memlen = NBI_HEADER_LENGTH;
  173. if ( ! process ( dest, dest_imglen, dest_memlen, start + offset ) )
  174. return 0;
  175. offset += dest_imglen;
  176. /* Process segments in turn */
  177. sh_off = NBI_LENGTH ( imgheader->length );
  178. do {
  179. /* Read segment header */
  180. copy_from_phys ( &sh, start + sh_off, sizeof ( sh ) );
  181. if ( sh.length == 0 ) {
  182. /* Avoid infinite loop? */
  183. DBG ( "NBI invalid segheader length 0\n" );
  184. errno = ENOEXEC;
  185. return 0;
  186. }
  187. /* Calculate segment load address */
  188. switch ( NBI_LOADADDR_FLAGS ( sh.flags ) ) {
  189. case NBI_LOADADDR_ABS:
  190. dest = sh.loadaddr;
  191. break;
  192. case NBI_LOADADDR_AFTER:
  193. dest = dest + dest_memlen + sh.loadaddr;
  194. break;
  195. case NBI_LOADADDR_BEFORE:
  196. dest = dest - sh.loadaddr;
  197. break;
  198. case NBI_LOADADDR_END:
  199. /* Not correct according to the spec, but
  200. * maintains backwards compatibility with
  201. * previous versions of Etherboot.
  202. */
  203. dest = ( meminfo.memsize * 1024 + 0x100000UL )
  204. - sh.loadaddr;
  205. break;
  206. default:
  207. /* Cannot be reached */
  208. DBG ( "NBI can't count up to three!\n" );
  209. }
  210. /* Process this segment */
  211. dest_imglen = sh.imglength;
  212. dest_memlen = sh.memlength;
  213. if ( ! process ( dest, dest_imglen, dest_memlen,
  214. start + offset ) )
  215. return 0;
  216. offset += dest_imglen;
  217. /* Next segheader */
  218. sh_off += NBI_LENGTH ( sh.length );
  219. if ( sh_off >= NBI_HEADER_LENGTH ) {
  220. DBG ( "NBI header overflow\n" );
  221. errno = ENOEXEC;
  222. return 0;
  223. }
  224. } while ( ! NBI_LAST_SEGHEADER ( sh.flags ) );
  225. if ( offset != len ) {
  226. DBG ( "NBI length mismatch (file %d, metadata %d)\n",
  227. len, offset );
  228. errno = ENOEXEC;
  229. return 0;
  230. }
  231. return 1;
  232. }
  233. /**
  234. * Load an NBI image into memory
  235. *
  236. * @v start Address of image
  237. * @v len Length of image
  238. * @v context NBI context (as returned by nbi_probe())
  239. * @ret True Image loaded into memory
  240. * @ret False Image not loaded into memory
  241. * @err ENOEXEC Image is not a valid NBI image
  242. * @err other As returned by nbi_process_segments()
  243. * @err other As returned by nbi_prepare_segment()
  244. * @err other As returned by nbi_load_segment()
  245. *
  246. */
  247. static int nbi_load ( physaddr_t start, off_t len, void *context ) {
  248. struct imgheader *imgheader = context;
  249. /* If we don't have enough data give up */
  250. if ( len < NBI_HEADER_LENGTH ) {
  251. errno = ENOEXEC;
  252. return 0;
  253. }
  254. DBG ( "NBI placing header at %hx:%hx\n",
  255. imgheader->location.segment, imgheader->location.offset );
  256. /* NBI files can have overlaps between segments; the bss of
  257. * one segment may overlap the initialised data of another. I
  258. * assume this is a design flaw, but there are images out
  259. * there that we need to work with. We therefore do two
  260. * passes: first to initialise the segments, then to copy the
  261. * data. This avoids zeroing out already-copied data.
  262. */
  263. if ( ! nbi_process_segments ( start, len, imgheader,
  264. nbi_prepare_segment ) )
  265. return 0;
  266. if ( ! nbi_process_segments ( start, len, imgheader,
  267. nbi_load_segment ) )
  268. return 0;
  269. return 1;
  270. }
  271. /**
  272. * Boot a 16-bit NBI image
  273. *
  274. * @v imgheader Image header information
  275. * @ret Never NBI program booted successfully
  276. * @ret False NBI program returned
  277. * @err ECANCELED NBI program returned
  278. *
  279. */
  280. static int nbi_boot16 ( struct imgheader *imgheader ) {
  281. uint16_t basemem_bootp;
  282. int discard_D, discard_S, discard_b;
  283. DBG ( "NBI executing 16-bit image at %hx:%hx\n",
  284. imgheader->execaddr.segoff.segment,
  285. imgheader->execaddr.segoff.offset );
  286. gateA20_unset();
  287. basemem_bootp = BASEMEM_PARAMETER_INIT ( bootp_data );
  288. REAL_EXEC ( rm_xstart16,
  289. "pushw %%ds\n\t" /* far pointer to bootp data copy */
  290. "pushw %%bx\n\t"
  291. "pushl %%esi\n\t" /* location */
  292. "pushw %%cs\n\t" /* lcall execaddr */
  293. "call 1f\n\t"
  294. "jmp 2f\n\t"
  295. "\n1:\n\t"
  296. "pushl %%edi\n\t"
  297. "lret\n\t"
  298. "\n2:\n\t"
  299. "addw $8,%%sp\n\t", /* pop location and bootp ptr */
  300. 3,
  301. OUT_CONSTRAINTS ( "=D" ( discard_D ), "=S" ( discard_S ),
  302. "=b" ( discard_b ) ),
  303. IN_CONSTRAINTS ( "D" ( imgheader->execaddr.segoff ),
  304. "S" ( imgheader->location ),
  305. "b" ( basemem_bootp ) ),
  306. CLOBBER ( "eax", "ecx", "edx", "ebp" ) );
  307. BASEMEM_PARAMETER_DONE ( bootp_data );
  308. errno = ECANCELED;
  309. return 0;
  310. }
  311. /**
  312. * Boot a 32-bit NBI image
  313. *
  314. * @v imgheader Image header information
  315. * @ret False NBI program should not have returned
  316. * @ret other As returned by NBI program
  317. * @err ECANCELED NBI program should not have returned
  318. *
  319. * To distinguish between the case of an NBI program returning false,
  320. * and an NBI program that should not have returned, check errno.
  321. * errno will be set to ECANCELED only if the NBI program should not
  322. * have returned.
  323. *
  324. */
  325. static int nbi_boot32 ( struct imgheader *imgheader ) {
  326. int rc = 0;
  327. DBG ( "NBI executing 32-bit image at %x\n",
  328. imgheader->execaddr.linear );
  329. /* no gateA20_unset for PM call */
  330. errno = ENOERR;
  331. rc = xstart32 ( imgheader->execaddr.linear,
  332. virt_to_phys ( &loaderinfo ),
  333. ( ( imgheader->location.segment << 4 ) +
  334. imgheader->location.offset ),
  335. virt_to_phys ( &bootp_data ) );
  336. printf ( "Secondary program returned %d\n", rc );
  337. if ( ! NBI_PROGRAM_RETURNS ( imgheader->flags ) ) {
  338. /* We shouldn't have returned */
  339. errno = ECANCELED;
  340. rc = 0;
  341. }
  342. return rc;
  343. }
  344. /**
  345. * Boot a loaded NBI image
  346. *
  347. * @v context NBI context (as returned by nbi_probe())
  348. * @ret Never NBI program booted successfully
  349. * @ret False NBI program should not have returned
  350. * @ret other As returned by NBI program
  351. * @err ECANCELED NBI program should not have returned
  352. *
  353. * See also nbi_boot16() and nbi_boot32().
  354. *
  355. */
  356. static int nbi_boot ( void *context ) {
  357. struct imgheader *imgheader = context;
  358. if ( NBI_LINEAR_EXEC_ADDR ( imgheader->flags ) ) {
  359. return nbi_boot32 ( imgheader );
  360. } else {
  361. return nbi_boot16 ( imgheader );
  362. }
  363. }
  364. /** Declaration of the NBI image format */
  365. struct image nbi_image __image = {
  366. .name = "NBI",
  367. .probe = nbi_probe,
  368. .load = nbi_load,
  369. .boot = nbi_boot,
  370. };