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 11KB

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