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.

pxe_callbacks.c 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. /* PXE callback mechanisms. This file contains only the portions
  2. * specific to i386: i.e. the low-level mechanisms for calling in from
  3. * an NBP to the PXE stack and for starting an NBP from the PXE stack.
  4. */
  5. #warning "pxe_callbacks.c is temporarily broken"
  6. void xstartpxe ( void ) {
  7. }
  8. void install_pxe_stack ( void ) {
  9. }
  10. void remove_pxe_stack ( void ) {
  11. }
  12. void hook_pxe_stack ( void ) {
  13. }
  14. void unhook_pxe_stack ( void ) {
  15. }
  16. void pxe_in_call ( void ) {
  17. }
  18. void use_undi_ds_for_rm_stack ( void ) {
  19. }
  20. #if 0
  21. #ifdef PXE_EXPORT
  22. #include "etherboot.h"
  23. #include "callbacks.h"
  24. #include "realmode.h"
  25. #include "pxe.h"
  26. #include "pxe_callbacks.h"
  27. #include "pxe_export.h"
  28. #include "hidemem.h"
  29. #include <stdarg.h>
  30. #define INSTALLED(x) ( (typeof(&x)) ( (void*)(&x) \
  31. - &pxe_callback_interface \
  32. + (void*)&pxe_stack->arch_data ) )
  33. #define pxe_intercept_int1a INSTALLED(_pxe_intercept_int1a)
  34. #define pxe_intercepted_int1a INSTALLED(_pxe_intercepted_int1a)
  35. #define pxe_pxenv_location INSTALLED(_pxe_pxenv_location)
  36. #define INT1A_VECTOR ( (segoff_t*) ( phys_to_virt( 4 * 0x1a ) ) )
  37. /* The overall size of the PXE stack is ( sizeof(pxe_stack_t) +
  38. * pxe_callback_interface_size + rm_callback_interface_size ).
  39. * Unfortunately, this isn't a compile-time constant, since
  40. * {pxe,rm}_callback_interface_size depend on the length of the
  41. * assembly code in these interfaces.
  42. *
  43. * We used to have a function pxe_stack_size() which returned this
  44. * value. However, it actually needs to be a link-time constant, so
  45. * that it can appear in the UNDIROMID structure in romprefix.S. We
  46. * therefore export the three component sizes as absolute linker
  47. * symbols, get the linker to add them together and generate a new
  48. * absolute symbol _pxe_stack_size. We then import this value into a
  49. * C variable pxe_stack_size, for access from C code.
  50. */
  51. /* gcc won't let us use extended asm outside a function (compiler
  52. * bug), ao we have to put these asm statements inside a dummy
  53. * function.
  54. */
  55. static void work_around_gcc_bug ( void ) __attribute__ ((used));
  56. static void work_around_gcc_bug ( void ) {
  57. /* Export sizeof(pxe_stack_t) as absolute linker symbol */
  58. __asm__ ( ".globl _pxe_stack_t_size" );
  59. __asm__ ( ".equ _pxe_stack_t_size, %c0"
  60. : : "i" (sizeof(pxe_stack_t)) );
  61. }
  62. /* Import _pxe_stack_size absolute linker symbol into C variable */
  63. extern int pxe_stack_size;
  64. __asm__ ( "pxe_stack_size: .long _pxe_stack_size" );
  65. /* Utility routine: byte checksum
  66. */
  67. uint8_t byte_checksum ( void *address, size_t size ) {
  68. unsigned int i, sum = 0;
  69. for ( i = 0; i < size; i++ ) {
  70. sum += ((uint8_t*)address)[i];
  71. }
  72. return (uint8_t)sum;
  73. }
  74. /* install_pxe_stack(): install PXE stack.
  75. *
  76. * Use base = NULL for auto-allocation of base memory
  77. *
  78. * IMPORTANT: no further allocation of base memory should take place
  79. * before the PXE stack is removed. This is to work around a small
  80. * but important deficiency in the PXE specification.
  81. */
  82. pxe_stack_t * install_pxe_stack ( void *base ) {
  83. pxe_t *pxe;
  84. pxenv_t *pxenv;
  85. void *pxe_callback_code;
  86. void (*pxe_in_call_far)(void);
  87. void (*pxenv_in_call_far)(void);
  88. void *rm_callback_code;
  89. void *e820mangler_code;
  90. void *end;
  91. /* If already installed, just return */
  92. if ( pxe_stack != NULL ) return pxe_stack;
  93. /* Allocate base memory if requested to do so
  94. */
  95. if ( base == NULL ) {
  96. base = allot_base_memory ( pxe_stack_size );
  97. if ( base == NULL ) return NULL;
  98. }
  99. /* Round address up to 16-byte physical alignment */
  100. pxe_stack = (pxe_stack_t *)
  101. ( phys_to_virt ( ( virt_to_phys(base) + 0xf ) & ~0xf ) );
  102. /* Zero out allocated stack */
  103. memset ( pxe_stack, 0, sizeof(*pxe_stack) );
  104. /* Calculate addresses for portions of the stack */
  105. pxe = &(pxe_stack->pxe);
  106. pxenv = &(pxe_stack->pxenv);
  107. pxe_callback_code = &(pxe_stack->arch_data);
  108. pxe_in_call_far = _pxe_in_call_far +
  109. ( pxe_callback_code - &pxe_callback_interface );
  110. pxenv_in_call_far = _pxenv_in_call_far +
  111. ( pxe_callback_code - &pxe_callback_interface );
  112. rm_callback_code = pxe_callback_code + pxe_callback_interface_size;
  113. e820mangler_code = (void*)(((int)rm_callback_code +
  114. rm_callback_interface_size + 0xf ) & ~0xf);
  115. end = e820mangler_code + e820mangler_size;
  116. /* Initialise !PXE data structures */
  117. memcpy ( pxe->Signature, "!PXE", 4 );
  118. pxe->StructLength = sizeof(*pxe);
  119. pxe->StructRev = 0;
  120. pxe->reserved_1 = 0;
  121. /* We don't yet have an UNDI ROM ID structure */
  122. pxe->UNDIROMID.segment = 0;
  123. pxe->UNDIROMID.offset = 0;
  124. /* or a BC ROM ID structure */
  125. pxe->BaseROMID.segment = 0;
  126. pxe->BaseROMID.offset = 0;
  127. pxe->EntryPointSP.segment = SEGMENT(pxe_stack);
  128. pxe->EntryPointSP.offset = (void*)pxe_in_call_far - (void*)pxe_stack;
  129. /* No %esp-compatible entry point yet */
  130. pxe->EntryPointESP.segment = 0;
  131. pxe->EntryPointESP.offset = 0;
  132. pxe->StatusCallout.segment = -1;
  133. pxe->StatusCallout.offset = -1;
  134. pxe->reserved_2 = 0;
  135. pxe->SegDescCn = 7;
  136. pxe->FirstSelector = 0;
  137. /* PXE specification doesn't say anything about when the stack
  138. * space should get freed. We work around this by claiming it
  139. * as our data segment as well.
  140. */
  141. pxe->Stack.Seg_Addr = pxe->UNDIData.Seg_Addr = real_mode_stack >> 4;
  142. pxe->Stack.Phy_Addr = pxe->UNDIData.Phy_Addr = real_mode_stack;
  143. pxe->Stack.Seg_Size = pxe->UNDIData.Seg_Size = real_mode_stack_size;
  144. /* Code segment has to be the one containing the data structures... */
  145. pxe->UNDICode.Seg_Addr = SEGMENT(pxe_stack);
  146. pxe->UNDICode.Phy_Addr = virt_to_phys(pxe_stack);
  147. pxe->UNDICode.Seg_Size = end - (void*)pxe_stack;
  148. /* No base code loaded */
  149. pxe->BC_Data.Seg_Addr = 0;
  150. pxe->BC_Data.Phy_Addr = 0;
  151. pxe->BC_Data.Seg_Size = 0;
  152. pxe->BC_Code.Seg_Addr = 0;
  153. pxe->BC_Code.Phy_Addr = 0;
  154. pxe->BC_Code.Seg_Size = 0;
  155. pxe->BC_CodeWrite.Seg_Addr = 0;
  156. pxe->BC_CodeWrite.Phy_Addr = 0;
  157. pxe->BC_CodeWrite.Seg_Size = 0;
  158. pxe->StructCksum -= byte_checksum ( pxe, sizeof(*pxe) );
  159. /* Initialise PXENV+ data structures */
  160. memcpy ( pxenv->Signature, "PXENV+", 6 );
  161. pxenv->Version = 0x201;
  162. pxenv->Length = sizeof(*pxenv);
  163. pxenv->RMEntry.segment = SEGMENT(pxe_stack);
  164. pxenv->RMEntry.offset = (void*)pxenv_in_call_far - (void*)pxe_stack;
  165. pxenv->PMOffset = 0; /* "Do not use" says the PXE spec */
  166. pxenv->PMSelector = 0; /* "Do not use" says the PXE spec */
  167. pxenv->StackSeg = pxenv->UNDIDataSeg = real_mode_stack >> 4;
  168. pxenv->StackSize = pxenv->UNDIDataSize = real_mode_stack_size;
  169. pxenv->BC_CodeSeg = 0;
  170. pxenv->BC_CodeSize = 0;
  171. pxenv->BC_DataSeg = 0;
  172. pxenv->BC_DataSize = 0;
  173. /* UNDIData{Seg,Size} set above */
  174. pxenv->UNDICodeSeg = SEGMENT(pxe_stack);
  175. pxenv->UNDICodeSize = end - (void*)pxe_stack;
  176. pxenv->PXEPtr.segment = SEGMENT(pxe);
  177. pxenv->PXEPtr.offset = OFFSET(pxe);
  178. pxenv->Checksum -= byte_checksum ( pxenv, sizeof(*pxenv) );
  179. /* Mark stack as inactive */
  180. pxe_stack->state = CAN_UNLOAD;
  181. /* Install PXE and RM callback code and E820 mangler */
  182. memcpy ( pxe_callback_code, &pxe_callback_interface,
  183. pxe_callback_interface_size );
  184. install_rm_callback_interface ( rm_callback_code, 0 );
  185. install_e820mangler ( e820mangler_code );
  186. return pxe_stack;
  187. }
  188. /* Use the UNDI data segment as our real-mode stack. This is for when
  189. * we have been loaded via the UNDI loader
  190. */
  191. void use_undi_ds_for_rm_stack ( uint16_t ds ) {
  192. forget_real_mode_stack();
  193. real_mode_stack = virt_to_phys ( VIRTUAL ( ds, 0 ) );
  194. lock_real_mode_stack = 1;
  195. }
  196. /* Activate PXE stack (i.e. hook interrupt vectors). The PXE stack
  197. * *can* be used before it is activated, but it really shoudln't.
  198. */
  199. int hook_pxe_stack ( void ) {
  200. if ( pxe_stack == NULL ) return 0;
  201. if ( pxe_stack->state >= MIDWAY ) return 1;
  202. /* Hook INT15 handler */
  203. hide_etherboot();
  204. /* Hook INT1A handler */
  205. *pxe_intercepted_int1a = *INT1A_VECTOR;
  206. pxe_pxenv_location->segment = SEGMENT(pxe_stack);
  207. pxe_pxenv_location->offset = (void*)&pxe_stack->pxenv
  208. - (void*)pxe_stack;
  209. INT1A_VECTOR->segment = SEGMENT(&pxe_stack->arch_data);
  210. INT1A_VECTOR->offset = (void*)pxe_intercept_int1a
  211. - (void*)&pxe_stack->arch_data;
  212. /* Mark stack as active */
  213. pxe_stack->state = MIDWAY;
  214. return 1;
  215. }
  216. /* Deactivate the PXE stack (i.e. unhook interrupt vectors).
  217. */
  218. int unhook_pxe_stack ( void ) {
  219. if ( pxe_stack == NULL ) return 0;
  220. if ( pxe_stack->state <= CAN_UNLOAD ) return 1;
  221. /* Restore original INT15 and INT1A handlers */
  222. *INT1A_VECTOR = *pxe_intercepted_int1a;
  223. if ( !unhide_etherboot() ) {
  224. /* Cannot unhook INT15. We're up the creek without
  225. * even a suitable log out of which to fashion a
  226. * paddle. There are some very badly behaved NBPs
  227. * that will ignore plaintive pleas such as
  228. * PXENV_KEEP_UNDI and just zero out our code anyway.
  229. * This means they end up vapourising an active INT15
  230. * handler, which is generally not a good thing to do.
  231. */
  232. return 0;
  233. }
  234. /* Mark stack as inactive */
  235. pxe_stack->state = CAN_UNLOAD;
  236. return 1;
  237. }
  238. /* remove_pxe_stack(): remove PXE stack installed by install_pxe_stack()
  239. */
  240. void remove_pxe_stack ( void ) {
  241. /* Ensure stack is deactivated, then free up the memory */
  242. if ( ensure_pxe_state ( CAN_UNLOAD ) ) {
  243. forget_base_memory ( pxe_stack, pxe_stack_size );
  244. pxe_stack = NULL;
  245. } else {
  246. printf ( "Cannot remove PXE stack!\n" );
  247. }
  248. }
  249. /* xstartpxe(): start up a PXE image
  250. */
  251. int xstartpxe ( void ) {
  252. int nbp_exit;
  253. struct {
  254. reg16_t bx;
  255. reg16_t es;
  256. segoff_t pxe;
  257. } PACKED in_stack;
  258. /* Set up registers and stack parameters to pass to PXE NBP */
  259. in_stack.es.word = SEGMENT(&(pxe_stack->pxenv));
  260. in_stack.bx.word = OFFSET(&(pxe_stack->pxenv));
  261. in_stack.pxe.segment = SEGMENT(&(pxe_stack->pxe));
  262. in_stack.pxe.offset = OFFSET(&(pxe_stack->pxe));
  263. /* Real-mode trampoline fragment used to jump to PXE NBP
  264. */
  265. RM_FRAGMENT(jump_to_pxe_nbp,
  266. "popw %bx\n\t"
  267. "popw %es\n\t"
  268. "lcall $" RM_STR(PXE_LOAD_SEGMENT) ", $" RM_STR(PXE_LOAD_OFFSET) "\n\t"
  269. );
  270. /* Call to PXE image */
  271. gateA20_unset();
  272. nbp_exit = real_call ( jump_to_pxe_nbp, &in_stack, NULL );
  273. gateA20_set();
  274. return nbp_exit;
  275. }
  276. int pxe_in_call ( in_call_data_t *in_call_data, va_list params ) {
  277. /* i386 calling conventions; the only two defined by Intel's
  278. * PXE spec.
  279. *
  280. * Assembly code must pass a long containing the PXE version
  281. * code (i.e. 0x201 for !PXE, 0x200 for PXENV+) as the first
  282. * parameter after the in_call opcode. This is used to decide
  283. * whether to take parameters from the stack (!PXE) or from
  284. * registers (PXENV+).
  285. */
  286. uint32_t api_version = va_arg ( params, typeof(api_version) );
  287. uint16_t opcode;
  288. segoff_t segoff;
  289. t_PXENV_ANY *structure;
  290. if ( api_version >= 0x201 ) {
  291. /* !PXE calling convention */
  292. pxe_call_params_t pxe_params
  293. = va_arg ( params, typeof(pxe_params) );
  294. opcode = pxe_params.opcode;
  295. segoff = pxe_params.segoff;
  296. } else {
  297. /* PXENV+ calling convention */
  298. opcode = in_call_data->pm->regs.bx;
  299. segoff.segment = in_call_data->rm->seg_regs.es;
  300. segoff.offset = in_call_data->pm->regs.di;
  301. }
  302. structure = VIRTUAL ( segoff.segment, segoff.offset );
  303. return pxe_api_call ( opcode, structure );
  304. }
  305. #ifdef TEST_EXCLUDE_ALGORITHM
  306. /* This code retained because it's a difficult algorithm to tweak with
  307. * confidence
  308. */
  309. int ___test_exclude ( int start, int len, int estart, int elen, int fixbase );
  310. void __test_exclude ( int start, int len, int estart, int elen, int fixbase ) {
  311. int newrange = ___test_exclude ( start, len, estart, elen, fixbase );
  312. int newstart = ( newrange >> 16 ) & 0xffff;
  313. int newlen = ( newrange & 0xffff );
  314. printf ( "[%x,%x): excluding [%x,%x) %s gives [%x,%x)\n",
  315. start, start + len,
  316. estart, estart + elen,
  317. ( fixbase == 0 ) ? " " : "fb",
  318. newstart, newstart + newlen );
  319. }
  320. void _test_exclude ( int start, int len, int estart, int elen ) {
  321. __test_exclude ( start, len, estart, elen, 0 );
  322. __test_exclude ( start, len, estart, elen, 1 );
  323. }
  324. void test_exclude ( void ) {
  325. _test_exclude ( 0x8000, 0x1000, 0x0400, 0x200 ); /* before */
  326. _test_exclude ( 0x8000, 0x1000, 0x9000, 0x200 ); /* after */
  327. _test_exclude ( 0x8000, 0x1000, 0x7f00, 0x200 ); /* before overlap */
  328. _test_exclude ( 0x8000, 0x1000, 0x8f00, 0x200 ); /* after overlap */
  329. _test_exclude ( 0x8000, 0x1000, 0x8000, 0x200 ); /* align start */
  330. _test_exclude ( 0x8000, 0x1000, 0x8e00, 0x200 ); /* align end */
  331. _test_exclude ( 0x8000, 0x1000, 0x8100, 0x200 ); /* early overlap */
  332. _test_exclude ( 0x8000, 0x1000, 0x8d00, 0x200 ); /* late overlap */
  333. _test_exclude ( 0x8000, 0x1000, 0x7000, 0x3000 ); /* total overlap */
  334. _test_exclude ( 0x8000, 0x1000, 0x8000, 0x1000 ); /* exact overlap */
  335. }
  336. #endif /* TEST_EXCLUDE_ALGORITHM */
  337. #else /* PXE_EXPORT */
  338. /* Define symbols used by the linker scripts, to prevent link errors */
  339. __asm__ ( ".globl _pxe_stack_t_size" );
  340. __asm__ ( ".equ _pxe_stack_t_size, 0" );
  341. #endif /* PXE_EXPORT */
  342. #endif /* 0 */