Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

undi.c 46KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458
  1. /**************************************************************************
  2. Etherboot - BOOTP/TFTP Bootstrap Program
  3. UNDI NIC driver for Etherboot
  4. This file Copyright (C) 2003 Michael Brown <mbrown@fensystems.co.uk>
  5. of Fen Systems Ltd. (http://www.fensystems.co.uk/). All rights
  6. reserved.
  7. $Id$
  8. ***************************************************************************/
  9. /*
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License as
  12. * published by the Free Software Foundation; either version 2, or (at
  13. * your option) any later version.
  14. */
  15. #ifdef PCBIOS
  16. /* to get some global routines like printf */
  17. #include "etherboot.h"
  18. /* to get the interface to the body of the program */
  19. #include "nic.h"
  20. /* to get the PCI support functions, if this is a PCI NIC */
  21. #include "pci.h"
  22. /* UNDI and PXE defines. Includes pxe.h. */
  23. #include "undi.h"
  24. /* 8259 PIC defines */
  25. #include "pic8259.h"
  26. /* Real-mode calls */
  27. #include "realmode.h"
  28. /* E820 map mangler */
  29. #include "hidemem.h"
  30. /* NIC specific static variables go here */
  31. static undi_t undi = {
  32. .pnp_bios = NULL,
  33. .rom = NULL,
  34. .undi_rom_id = NULL,
  35. .pxe = NULL,
  36. .pxs = NULL,
  37. .xmit_data = NULL,
  38. .base_mem_data = NULL,
  39. .driver_code = NULL,
  40. .driver_code_size = 0,
  41. .driver_data = NULL,
  42. .driver_data_size = 0,
  43. .xmit_buffer = NULL,
  44. .prestarted = 0,
  45. .started = 0,
  46. .initialized = 0,
  47. .opened = 0,
  48. .pci = { 0, 0, 0, NULL, 0, 0, 0, 0, 0, 0, 0, NULL },
  49. .irq = IRQ_NONE
  50. };
  51. /* Function prototypes */
  52. static int allocate_base_mem_data ( void );
  53. static int free_base_mem_data ( void );
  54. static int eb_pxenv_undi_shutdown ( void );
  55. static int eb_pxenv_stop_undi ( void );
  56. static int undi_unload_base_code ( void );
  57. static int undi_full_shutdown ( void );
  58. /* Trivial/nontrivial IRQ handler selection */
  59. #ifdef UNDI_NONTRIVIAL_IRQ
  60. static void nontrivial_irq_handler ( void );
  61. static void nontrivial_irq_handler_end ( void );
  62. static int install_nontrivial_irq_handler ( irq_t irq );
  63. static int remove_nontrivial_irq_handler ( irq_t irq );
  64. static int nontrivial_irq_triggered ( irq_t irq );
  65. static int copy_nontrivial_irq_handler ( void *target, size_t target_size );
  66. #define NONTRIVIAL_IRQ_HANDLER_SIZE FRAGMENT_SIZE(nontrivial_irq_handler)
  67. #define install_undi_irq_handler(irq) install_nontrivial_irq_handler(irq)
  68. #define remove_undi_irq_handler(irq) remove_nontrivial_irq_handler(irq)
  69. #define undi_irq_triggered(irq) nontrivial_irq_triggered(irq)
  70. #define UNDI_IRQ_HANDLER_SIZE NONTRIVIAL_IRQ_HANDLER_SIZE
  71. #define copy_undi_irq_handler(dest,size) copy_nontrivial_irq_handler(dest,size)
  72. #else
  73. #define install_undi_irq_handler(irq) install_trivial_irq_handler(irq)
  74. #define remove_undi_irq_handler(irq) remove_trivial_irq_handler(irq)
  75. #define undi_irq_triggered(irq) trivial_irq_triggered(irq)
  76. #define UNDI_IRQ_HANDLER_SIZE TRIVIAL_IRQ_HANDLER_SIZE
  77. #define copy_undi_irq_handler(dest,size) copy_trivial_irq_handler(dest,size)
  78. #endif /* UNDI_NONTRIVIAL_IRQ */
  79. /* Size of variable-length data in base_mem_data */
  80. #define BASE_MEM_VARDATA_SIZE ( UNDI_IRQ_HANDLER_SIZE > e820mangler_size ? \
  81. UNDI_IRQ_HANDLER_SIZE : e820mangler_size )
  82. /**************************************************************************
  83. * Utility functions
  84. **************************************************************************/
  85. /* Checksum a block.
  86. */
  87. static uint8_t checksum ( void *block, size_t size ) {
  88. uint8_t sum = 0;
  89. uint16_t i = 0;
  90. for ( i = 0; i < size; i++ ) {
  91. sum += ( ( uint8_t * ) block )[i];
  92. }
  93. return sum;
  94. }
  95. /* Print the status of a !PXE structure
  96. */
  97. static void pxe_dump ( void ) {
  98. printf ( "API %hx:%hx St %hx:%hx UD %hx:%hx UC %hx:%hx "
  99. "BD %hx:%hx BC %hx:%hx\n",
  100. undi.pxe->EntryPointSP.segment, undi.pxe->EntryPointSP.offset,
  101. undi.pxe->Stack.Seg_Addr, undi.pxe->Stack.Seg_Size,
  102. undi.pxe->UNDIData.Seg_Addr, undi.pxe->UNDIData.Seg_Size,
  103. undi.pxe->UNDICode.Seg_Addr, undi.pxe->UNDICode.Seg_Size,
  104. undi.pxe->BC_Data.Seg_Addr, undi.pxe->BC_Data.Seg_Size,
  105. undi.pxe->BC_Code.Seg_Addr, undi.pxe->BC_Code.Seg_Size );
  106. }
  107. /* Allocate/free space for structures that must reside in base memory
  108. */
  109. static int allocate_base_mem_data ( void ) {
  110. /* Allocate space in base memory.
  111. * Initialise pointers to base memory structures.
  112. */
  113. if ( undi.base_mem_data == NULL ) {
  114. undi.base_mem_data =
  115. allot_base_memory ( sizeof(undi_base_mem_data_t) +
  116. BASE_MEM_VARDATA_SIZE );
  117. if ( undi.base_mem_data == NULL ) {
  118. printf ( "Failed to allocate base memory\n" );
  119. free_base_mem_data();
  120. return 0;
  121. }
  122. memset ( undi.base_mem_data, 0, sizeof(undi_base_mem_data_t) );
  123. undi.pxs = &undi.base_mem_data->pxs;
  124. undi.xmit_data = &undi.base_mem_data->xmit_data;
  125. undi.xmit_buffer = undi.base_mem_data->xmit_buffer;
  126. }
  127. return 1;
  128. }
  129. static int free_base_mem_data ( void ) {
  130. if ( undi.base_mem_data != NULL ) {
  131. forget_base_memory ( undi.base_mem_data,
  132. sizeof(undi_base_mem_data_t) +
  133. BASE_MEM_VARDATA_SIZE );
  134. undi.base_mem_data = NULL;
  135. undi.pxs = NULL;
  136. undi.xmit_data = NULL;
  137. undi.xmit_buffer = NULL;
  138. copy_undi_irq_handler ( NULL, 0 );
  139. }
  140. return 1;
  141. }
  142. static void assemble_firing_squad ( firing_squad_lineup_t *lineup,
  143. void *start, size_t size,
  144. firing_squad_shoot_t shoot ) {
  145. int target;
  146. int index;
  147. int bit;
  148. int start_kb = virt_to_phys(start) >> 10;
  149. int end_kb = ( virt_to_phys(start+size) + (1<<10) - 1 ) >> 10;
  150. for ( target = start_kb; target <= end_kb; target++ ) {
  151. index = FIRING_SQUAD_TARGET_INDEX ( target );
  152. bit = FIRING_SQUAD_TARGET_BIT ( target );
  153. lineup->targets[index] = ( shoot << bit ) |
  154. ( lineup->targets[index] & ~( 1 << bit ) );
  155. }
  156. }
  157. static void shoot_targets ( firing_squad_lineup_t *lineup ) {
  158. int shoot_this_target = 0;
  159. int shoot_last_target = 0;
  160. int start_target = 0;
  161. int target;
  162. for ( target = 0; target <= 640; target++ ) {
  163. shoot_this_target = ( target == 640 ? 0 :
  164. ( 1 << FIRING_SQUAD_TARGET_BIT(target) ) &
  165. lineup->targets[FIRING_SQUAD_TARGET_INDEX(target)] );
  166. if ( shoot_this_target && !shoot_last_target ) {
  167. start_target = target;
  168. } else if ( shoot_last_target && !shoot_this_target ) {
  169. size_t range_size = ( target - start_target ) << 10;
  170. forget_base_memory ( phys_to_virt( start_target<<10 ),
  171. range_size );
  172. }
  173. shoot_last_target = shoot_this_target;
  174. }
  175. }
  176. /* Debug macros
  177. */
  178. #ifdef TRACE_UNDI
  179. #define DBG(...) printf ( __VA_ARGS__ )
  180. #else
  181. #define DBG(...)
  182. #endif
  183. #define UNDI_STATUS(pxs) ( (pxs)->Status == PXENV_EXIT_SUCCESS ? \
  184. "SUCCESS" : \
  185. ( (pxs)->Status == PXENV_EXIT_FAILURE ? \
  186. "FAILURE" : "UNKNOWN" ) )
  187. /**************************************************************************
  188. * Base memory scanning functions
  189. **************************************************************************/
  190. /* Locate the $PnP structure indicating a PnP BIOS.
  191. */
  192. static int hunt_pnp_bios ( void ) {
  193. uint32_t off = 0x10000;
  194. printf ( "Hunting for PnP BIOS..." );
  195. while ( off > 0 ) {
  196. off -= 16;
  197. undi.pnp_bios = (pnp_bios_t *) phys_to_virt ( 0xf0000 + off );
  198. if ( undi.pnp_bios->signature == PNP_BIOS_SIGNATURE ) {
  199. printf ( "found $PnP at f000:%hx...", off );
  200. if ( checksum(undi.pnp_bios,sizeof(pnp_bios_t)) !=0) {
  201. printf ( "invalid checksum\n..." );
  202. continue;
  203. }
  204. printf ( "ok\n" );
  205. return 1;
  206. }
  207. }
  208. printf ( "none found\n" );
  209. undi.pnp_bios = NULL;
  210. return 0;
  211. }
  212. /* Locate the !PXE structure indicating a loaded UNDI driver.
  213. */
  214. static int hunt_pixie ( void ) {
  215. static uint32_t ptr = 0;
  216. pxe_t *pxe = NULL;
  217. printf ( "Hunting for pixies..." );
  218. if ( ptr == 0 ) ptr = 0xa0000;
  219. while ( ptr > 0x10000 ) {
  220. ptr -= 16;
  221. pxe = (pxe_t *) phys_to_virt ( ptr );
  222. if ( memcmp ( pxe->Signature, "!PXE", 4 ) == 0 ) {
  223. printf ( "found !PXE at %x...", ptr );
  224. if ( checksum ( pxe, sizeof(pxe_t) ) != 0 ) {
  225. printf ( "invalid checksum\n..." );
  226. continue;
  227. }
  228. if ( ptr < get_free_base_memory() ) {
  229. printf ( "in free base memory!\n\n"
  230. "WARNING: a valid !PXE structure was "
  231. "found in an area of memory marked "
  232. "as free!\n\n" );
  233. undi.pxe = pxe;
  234. pxe_dump();
  235. undi.pxe = NULL;
  236. printf ( "\nIgnoring and continuing, but this "
  237. "may cause problems later!\n\n" );
  238. continue;
  239. }
  240. printf ( "ok\n" );
  241. undi.pxe = pxe;
  242. pxe_dump();
  243. printf ( "Resetting pixie...\n" );
  244. undi_unload_base_code();
  245. eb_pxenv_stop_undi();
  246. pxe_dump();
  247. return 1;
  248. }
  249. }
  250. printf ( "none found\n" );
  251. ptr = 0;
  252. return 0;
  253. }
  254. /* Locate PCI PnP ROMs.
  255. */
  256. static int hunt_rom ( void ) {
  257. static uint32_t ptr = 0;
  258. /* If we are not a PCI device, we cannot search for a ROM that
  259. * matches us (?)
  260. */
  261. if ( ! undi.pci.vendor )
  262. return 0;
  263. printf ( "Hunting for ROMs..." );
  264. if ( ptr == 0 ) ptr = 0x100000;
  265. while ( ptr > 0x0c0000 ) {
  266. ptr -= 0x800;
  267. undi.rom = ( rom_t * ) phys_to_virt ( ptr );
  268. if ( undi.rom->signature == ROM_SIGNATURE ) {
  269. pcir_header_t *pcir_header = NULL;
  270. pnp_header_t *pnp_header = NULL;
  271. printf ( "found 55AA at %x...", ptr );
  272. if ( undi.rom->pcir_off == 0 ) {
  273. printf ( "not a PCI ROM\n..." );
  274. continue;
  275. }
  276. pcir_header = (pcir_header_t*)( ( void * ) undi.rom +
  277. undi.rom->pcir_off );
  278. if ( pcir_header->signature != PCIR_SIGNATURE ) {
  279. printf ( "invalid PCI signature\n..." );
  280. continue;
  281. }
  282. printf ( "PCI:%hx:%hx...", pcir_header->vendor_id,
  283. pcir_header->device_id );
  284. if ( ( pcir_header->vendor_id != undi.pci.vendor ) ||
  285. ( pcir_header->device_id != undi.pci.dev_id ) ) {
  286. printf ( "not me (%hx:%hx)\n...",
  287. undi.pci.vendor,
  288. undi.pci.dev_id );
  289. continue;
  290. }
  291. if ( undi.rom->pnp_off == 0 ) {
  292. printf ( "not a PnP ROM\n..." );
  293. continue;
  294. }
  295. pnp_header = (pnp_header_t*)( ( void * ) undi.rom +
  296. undi.rom->pnp_off );
  297. if ( pnp_header->signature != PNP_SIGNATURE ) {
  298. printf ( "invalid $PnP signature\n..." );
  299. continue;
  300. }
  301. if ( checksum(pnp_header,sizeof(pnp_header_t)) != 0 ) {
  302. printf ( "invalid PnP checksum\n..." );
  303. continue;
  304. }
  305. printf ( "ok\nROM contains %s by %s\n",
  306. pnp_header->product_str_off==0 ? "(unknown)" :
  307. (void*)undi.rom+pnp_header->product_str_off,
  308. pnp_header->manuf_str_off==0 ? "(unknown)" :
  309. (void*)undi.rom+pnp_header->manuf_str_off );
  310. return 1;
  311. }
  312. }
  313. printf ( "none found\n" );
  314. ptr = 0;
  315. undi.rom = NULL;
  316. return 0;
  317. }
  318. /* Locate ROMs containing UNDI drivers.
  319. */
  320. static int hunt_undi_rom ( void ) {
  321. while ( hunt_rom() ) {
  322. if ( undi.rom->undi_rom_id_off == 0 ) {
  323. printf ( "Not a PXE ROM\n" );
  324. continue;
  325. }
  326. undi.undi_rom_id = (undi_rom_id_t *)
  327. ( (void *)undi.rom + undi.rom->undi_rom_id_off );
  328. if ( undi.undi_rom_id->signature != UNDI_SIGNATURE ) {
  329. printf ( "Invalid UNDI signature\n" );
  330. continue;
  331. }
  332. if ( checksum ( undi.undi_rom_id,
  333. undi.undi_rom_id->struct_length ) != 0 ) {
  334. printf ( "Invalid checksum\n" );
  335. continue;
  336. }
  337. printf ( "Located UNDI ROM supporting revision %d.%d.%d\n",
  338. undi.undi_rom_id->undi_rev[2],
  339. undi.undi_rom_id->undi_rev[1],
  340. undi.undi_rom_id->undi_rev[0] );
  341. return 1;
  342. }
  343. return 0;
  344. }
  345. /**************************************************************************
  346. * Low-level UNDI API call wrappers
  347. **************************************************************************/
  348. /* Make a real-mode UNDI API call to the UNDI routine at
  349. * routine_seg:routine_off, passing in three uint16 parameters on the
  350. * real-mode stack.
  351. */
  352. static PXENV_EXIT_t _undi_call ( uint16_t routine_seg,
  353. uint16_t routine_off, uint16_t st0,
  354. uint16_t st1, uint16_t st2 ) {
  355. PXENV_EXIT_t ret = PXENV_EXIT_FAILURE;
  356. struct {
  357. segoff_t routine;
  358. uint16_t st0;
  359. uint16_t st1;
  360. uint16_t st2;
  361. } PACKED in_stack = {
  362. { routine_off, routine_seg }, st0, st1, st2
  363. };
  364. RM_FRAGMENT(rm_undi_call,
  365. "popw %di\n\t" /* %es:di = routine */
  366. "popw %es\n\t"
  367. "pushw %cs\n\t" /* set up return address */
  368. "call 1f\n\t1:popw %bx\n\t"
  369. "leaw (2f-1b)(%bx), %ax\n\t"
  370. "pushw %ax\n\t"
  371. "pushw %es\n\t" /* routine address to stack */
  372. "pushw %di\n\t"
  373. "lret\n\t" /* calculated lcall */
  374. "\n2:\n\t" /* continuation point */
  375. );
  376. /* Parameters are left on stack: set out_stack = in_stack */
  377. ret = real_call ( rm_undi_call, &in_stack, &in_stack );
  378. /* UNDI API calls may rudely change the status of A20 and not
  379. * bother to restore it afterwards. Intel is known to be
  380. * guilty of this.
  381. *
  382. * Note that we will return to this point even if A20 gets
  383. * screwed up by the UNDI driver, because Etherboot always
  384. * resides in an even megabyte of RAM.
  385. */
  386. gateA20_set();
  387. return ret;
  388. }
  389. /* Make a real-mode call to the UNDI loader routine at
  390. * routine_seg:routine_off, passing in the seg:off address of a
  391. * pxenv_structure on the real-mode stack.
  392. */
  393. static int undi_call_loader ( void ) {
  394. PXENV_EXIT_t pxenv_exit = PXENV_EXIT_FAILURE;
  395. /* Hide Etherboot around the loader, so that the PXE stack
  396. * doesn't trash our memory areas
  397. */
  398. install_e820mangler ( undi.base_mem_data->e820mangler );
  399. hide_etherboot();
  400. pxenv_exit = _undi_call ( SEGMENT( undi.rom ),
  401. undi.undi_rom_id->undi_loader_off,
  402. OFFSET( undi.pxs ),
  403. SEGMENT( undi.pxs ),
  404. 0 /* Unused for UNDI loader API */ );
  405. if ( !unhide_etherboot() ) {
  406. printf ( "FATAL: corrupt INT15\n" );
  407. return 0;
  408. }
  409. /* Return 1 for success, to be consistent with other routines */
  410. if ( pxenv_exit == PXENV_EXIT_SUCCESS ) return 1;
  411. printf ( "UNDI loader call failed with status %#hx\n",
  412. undi.pxs->Status );
  413. return 0;
  414. }
  415. /* Make a real-mode UNDI API call, passing in the opcode and the
  416. * seg:off address of a pxenv_structure on the real-mode stack.
  417. *
  418. * Two versions: undi_call() will automatically report any failure
  419. * codes, undi_call_silent() will not.
  420. */
  421. static int undi_call_silent ( uint16_t opcode ) {
  422. PXENV_EXIT_t pxenv_exit = PXENV_EXIT_FAILURE;
  423. pxenv_exit = _undi_call ( undi.pxe->EntryPointSP.segment,
  424. undi.pxe->EntryPointSP.offset,
  425. opcode,
  426. OFFSET( undi.pxs ),
  427. SEGMENT( undi.pxs ) );
  428. /* Return 1 for success, to be consistent with other routines */
  429. return pxenv_exit == PXENV_EXIT_SUCCESS ? 1 : 0;
  430. }
  431. static int undi_call ( uint16_t opcode ) {
  432. if ( undi_call_silent ( opcode ) ) return 1;
  433. printf ( "UNDI API call %#hx failed with status %#hx\n",
  434. opcode, undi.pxs->Status );
  435. return 0;
  436. }
  437. #ifdef UNDI_NONTRIVIAL_IRQ
  438. /* IRQ handler that actually calls PXENV_UNDI_ISR. It's probably
  439. * better to use the trivial IRQ handler, since this seems to work for
  440. * just about all known NICs and doesn't involve making a PXE API call
  441. * in interrupt context.
  442. *
  443. * This routine is mainly used for testing the Etherboot PXE stack's
  444. * ability to be called in interrupt context. It is not compiled in
  445. * by default.
  446. *
  447. * This code has fewer safety checks than those in the
  448. * trivial_irq_handler routines. These are omitted because this code
  449. * is not intended for mainstream use.
  450. */
  451. uint16_t nontrivial_irq_previous_trigger_count = 0;
  452. static int copy_nontrivial_irq_handler ( void *target,
  453. size_t target_size __unused ) {
  454. RM_FRAGMENT(nontrivial_irq_handler,
  455. /* Will be installed on a paragraph boundary, so access variables
  456. * using %cs:(xxx-irqstart)
  457. */
  458. "\n\t"
  459. "irqstart:\n\t"
  460. /* Fields here must match those in undi_irq_handler_t */
  461. "chain_to:\t.word 0,0\n\t"
  462. "irq_chain:\t.byte 0,0,0,0\n\t"
  463. "entry:\t.word 0,0\n\t"
  464. "count_all:\t.word 0\n\t"
  465. "count_ours:\t.word 0\n\t"
  466. "undi_isr:\n\t"
  467. "undi_isr_Status:\t.word 0\n\t"
  468. "undi_isr_FuncFlag:\t.word 0\n\t"
  469. "undi_isr_others:\t.word 0,0,0,0,0,0\n\t"
  470. "handler:\n\t"
  471. /* Assume that PXE stack will corrupt everything */
  472. "pushal\n\t"
  473. "push %ds\n\t"
  474. "push %es\n\t"
  475. "push %fs\n\t"
  476. "push %gs\n\t"
  477. /* Set DS == CS */
  478. "pushw %cs\n\t"
  479. "popw %ds\n\t"
  480. /* Set up parameters for call */
  481. "movw $" RM_STR(PXENV_UNDI_ISR_IN_START) ", %ds:(undi_isr_FuncFlag-irqstart)\n\t"
  482. "pushw %cs\n\t"
  483. "popw %es\n\t"
  484. "movw $(undi_isr-irqstart), %di\n\t"
  485. "movw $" RM_STR(PXENV_UNDI_ISR) ", %bx\n\t"
  486. "pushw %es\n\t" /* Registers for PXENV+, stack for !PXE */
  487. "pushw %di\n\t"
  488. "pushw %bx\n\t"
  489. /* Make PXE API call */
  490. "lcall *%ds:(entry-irqstart)\n\t"
  491. "addw $6, %sp\n\t"
  492. /* Set DS == CS */
  493. "pushw %cs\n\t"
  494. "popw %ds\n\t"
  495. /* Check return status to see if it's one of our interrupts */
  496. "cmpw $" RM_STR(PXENV_STATUS_SUCCESS) ", %cs:(undi_isr_Status-irqstart)\n\t"
  497. "jne 1f\n\t"
  498. "cmpw $" RM_STR(PXENV_UNDI_ISR_OUT_OURS) ", %cs:(undi_isr_FuncFlag-irqstart)\n\t"
  499. "jne 1f\n\t"
  500. /* Increment count_ours if so */
  501. "incw %ds:(count_ours-irqstart)\n\t"
  502. "1:\n\t"
  503. /* Increment count_all anyway */
  504. "incw %ds:(count_all-irqstart)\n\t"
  505. /* Restore registers and return */
  506. "popw %gs\n\t"
  507. "popw %fs\n\t"
  508. "popw %es\n\t"
  509. "popw %ds\n\t"
  510. "popal\n\t"
  511. "\n\t"
  512. /* Chain to acknowledge the interrupt */
  513. "cmpb $0, %cs:(irq_chain-irqstart)\n\t"
  514. "jz 2f\n\t"
  515. "ljmp %cs:(chain_to-irqstart)\n\t"
  516. "2:\n\t"
  517. "\n\t"
  518. "iret\n\t"
  519. "\n\t"
  520. );
  521. /* Copy handler */
  522. memcpy ( target, nontrivial_irq_handler, NONTRIVIAL_IRQ_HANDLER_SIZE );
  523. return 1;
  524. }
  525. static int install_nontrivial_irq_handler ( irq_t irq ) {
  526. undi_irq_handler_t *handler =
  527. &undi.base_mem_data->nontrivial_irq_handler;
  528. segoff_t isr_segoff;
  529. printf ( "WARNING: using non-trivial IRQ handler [EXPERIMENTAL]\n" );
  530. /*
  531. * This code is deliberately quick and dirty. The whole
  532. * nontrivial IRQ stuff is only present in order to test out
  533. * calling our PXE stack in interrupt context. Do NOT use
  534. * this in production code.
  535. */
  536. disable_irq ( irq );
  537. handler->count_all = 0;
  538. handler->count_ours = 0;
  539. handler->entry = undi.pxe->EntryPointSP;
  540. nontrivial_irq_previous_trigger_count = 0;
  541. isr_segoff.segment = SEGMENT(handler);
  542. isr_segoff.offset = (void*)&handler->code - (void*)handler;
  543. install_irq_handler( irq, &isr_segoff,
  544. &handler->irq_chain, &handler->chain_to);
  545. enable_irq ( irq );
  546. return 1;
  547. }
  548. static int remove_nontrivial_irq_handler ( irq_t irq ) {
  549. undi_irq_handler_t *handler =
  550. &undi.base_mem_data->nontrivial_irq_handler;
  551. segoff_t isr_segoff;
  552. isr_segoff.segment = SEGMENT(handler);
  553. isr_segoff.offset = (char*)&handler->code - (char*)handler;
  554. remove_irq_handler( irq, &isr_segoff,
  555. &handler->irq_chain, &handler->chain_to);
  556. return 1;
  557. }
  558. static int nontrivial_irq_triggered ( irq_t irq __unused ) {
  559. undi_irq_handler_t *handler =
  560. &undi.base_mem_data->nontrivial_irq_handler;
  561. uint16_t nontrivial_irq_this_trigger_count = handler->count_ours;
  562. int triggered = ( nontrivial_irq_this_trigger_count -
  563. nontrivial_irq_previous_trigger_count );
  564. nontrivial_irq_previous_trigger_count =
  565. nontrivial_irq_this_trigger_count;
  566. return triggered ? 1 : 0;
  567. }
  568. static void nontrivial_irq_debug ( irq_t irq ) {
  569. undi_irq_handler_t *handler =
  570. &undi.base_mem_data->nontrivial_irq_handler;
  571. printf ( "IRQ %d triggered %d times (%d of which were ours)\n",
  572. irq, handler->count_all, handler->count_ours );
  573. }
  574. #endif /* UNDI_NONTRIVIAL_IRQ */
  575. /**************************************************************************
  576. * High-level UNDI API call wrappers
  577. **************************************************************************/
  578. /* Install the UNDI driver from a located UNDI ROM.
  579. */
  580. static int undi_loader ( void ) {
  581. pxe_t *pxe = NULL;
  582. if ( ! undi.pci.vendor ) {
  583. printf ( "ERROR: attempted to call loader of an ISA ROM?\n" );
  584. return 0;
  585. }
  586. /* AX contains PCI bus:devfn (PCI specification) */
  587. undi.pxs->loader.ax = ( undi.pci.bus << 8 ) | undi.pci.devfn;
  588. /* BX and DX set to 0xffff for non-ISAPnP devices
  589. * (BIOS boot specification)
  590. */
  591. undi.pxs->loader.bx = 0xffff;
  592. undi.pxs->loader.dx = 0xffff;
  593. /* ES:DI points to PnP BIOS' $PnP structure
  594. * (BIOS boot specification)
  595. */
  596. if ( undi.pnp_bios ) {
  597. undi.pxs->loader.es = 0xf000;
  598. undi.pxs->loader.di = virt_to_phys ( undi.pnp_bios ) - 0xf0000;
  599. } else {
  600. /* Set to a NULL pointer and hope that we don't need it */
  601. undi.pxs->loader.es = 0x0000;
  602. undi.pxs->loader.di = 0x0000;
  603. }
  604. /* Allocate space for UNDI driver's code and data segments */
  605. undi.driver_code_size = undi.undi_rom_id->code_size;
  606. undi.driver_code = allot_base_memory ( undi.driver_code_size );
  607. if ( undi.driver_code == NULL ) {
  608. printf ( "Could not allocate %d bytes for UNDI code segment\n",
  609. undi.driver_code_size );
  610. return 0;
  611. }
  612. undi.pxs->loader.undi_cs = SEGMENT( undi.driver_code );
  613. undi.driver_data_size = undi.undi_rom_id->data_size;
  614. undi.driver_data = allot_base_memory ( undi.driver_data_size );
  615. if ( undi.driver_data == NULL ) {
  616. printf ( "Could not allocate %d bytes for UNDI code segment\n",
  617. undi.driver_data_size );
  618. return 0;
  619. }
  620. undi.pxs->loader.undi_ds = SEGMENT( undi.driver_data );
  621. printf ( "Installing UNDI driver code to %hx:0000, data at %hx:0000\n",
  622. undi.pxs->loader.undi_cs, undi.pxs->loader.undi_ds );
  623. /* Do the API call to install the loader */
  624. if ( ! undi_call_loader () ) return 0;
  625. pxe = VIRTUAL( undi.pxs->loader.undi_cs,
  626. undi.pxs->loader.pxe_ptr.offset );
  627. printf ( "UNDI driver created a pixie at %hx:%hx...",
  628. undi.pxs->loader.undi_cs, undi.pxs->loader.pxe_ptr.offset );
  629. if ( memcmp ( pxe->Signature, "!PXE", 4 ) != 0 ) {
  630. printf ( "invalid signature\n" );
  631. return 0;
  632. }
  633. if ( checksum ( pxe, sizeof(pxe_t) ) != 0 ) {
  634. printf ( "invalid checksum\n" );
  635. return 0;
  636. }
  637. printf ( "ok\n" );
  638. undi.pxe = pxe;
  639. pxe_dump();
  640. return 1;
  641. }
  642. /* Start the UNDI driver.
  643. */
  644. static int eb_pxenv_start_undi ( void ) {
  645. int success = 0;
  646. /* AX contains PCI bus:devfn (PCI specification) */
  647. undi.pxs->start_undi.ax = ( undi.pci.bus << 8 ) | undi.pci.devfn;
  648. /* BX and DX set to 0xffff for non-ISAPnP devices
  649. * (BIOS boot specification)
  650. */
  651. undi.pxs->start_undi.bx = 0xffff;
  652. undi.pxs->start_undi.dx = 0xffff;
  653. /* ES:DI points to PnP BIOS' $PnP structure
  654. * (BIOS boot specification)
  655. */
  656. if ( undi.pnp_bios ) {
  657. undi.pxs->start_undi.es = 0xf000;
  658. undi.pxs->start_undi.di =
  659. virt_to_phys ( undi.pnp_bios ) - 0xf0000;
  660. } else {
  661. /* Set to a NULL pointer and hope that we don't need it */
  662. undi.pxs->start_undi.es = 0x0000;
  663. undi.pxs->start_undi.di = 0x0000;
  664. }
  665. DBG ( "PXENV_START_UNDI => AX=%hx BX=%hx DX=%hx ES:DI=%hx:%hx\n",
  666. undi.pxs->start_undi.ax,
  667. undi.pxs->start_undi.bx, undi.pxs->start_undi.dx,
  668. undi.pxs->start_undi.es, undi.pxs->start_undi.di );
  669. success = undi_call ( PXENV_START_UNDI );
  670. DBG ( "PXENV_START_UNDI <= Status=%s\n", UNDI_STATUS(undi.pxs) );
  671. if ( success ) undi.prestarted = 1;
  672. return success;
  673. }
  674. static int eb_pxenv_undi_startup ( void ) {
  675. int success = 0;
  676. DBG ( "PXENV_UNDI_STARTUP => (void)\n" );
  677. success = undi_call ( PXENV_UNDI_STARTUP );
  678. DBG ( "PXENV_UNDI_STARTUP <= Status=%s\n", UNDI_STATUS(undi.pxs) );
  679. if ( success ) undi.started = 1;
  680. return success;
  681. }
  682. static int eb_pxenv_undi_cleanup ( void ) {
  683. int success = 0;
  684. DBG ( "PXENV_UNDI_CLEANUP => (void)\n" );
  685. success = undi_call ( PXENV_UNDI_CLEANUP );
  686. DBG ( "PXENV_UNDI_CLEANUP <= Status=%s\n", UNDI_STATUS(undi.pxs) );
  687. return success;
  688. }
  689. static int eb_pxenv_undi_initialize ( void ) {
  690. int success = 0;
  691. undi.pxs->undi_initialize.ProtocolIni = 0;
  692. memset ( &undi.pxs->undi_initialize.reserved, 0,
  693. sizeof ( undi.pxs->undi_initialize.reserved ) );
  694. DBG ( "PXENV_UNDI_INITIALIZE => ProtocolIni=%x\n" );
  695. success = undi_call ( PXENV_UNDI_INITIALIZE );
  696. DBG ( "PXENV_UNDI_INITIALIZE <= Status=%s\n", UNDI_STATUS(undi.pxs) );
  697. if ( success ) undi.initialized = 1;
  698. return success;
  699. }
  700. static int eb_pxenv_undi_shutdown ( void ) {
  701. int success = 0;
  702. DBG ( "PXENV_UNDI_SHUTDOWN => (void)\n" );
  703. success = undi_call ( PXENV_UNDI_SHUTDOWN );
  704. DBG ( "PXENV_UNDI_SHUTDOWN <= Status=%s\n", UNDI_STATUS(undi.pxs) );
  705. if ( success ) {
  706. undi.initialized = 0;
  707. undi.started = 0;
  708. }
  709. return success;
  710. }
  711. static int eb_pxenv_undi_open ( void ) {
  712. int success = 0;
  713. undi.pxs->undi_open.OpenFlag = 0;
  714. undi.pxs->undi_open.PktFilter = FLTR_DIRECTED | FLTR_BRDCST;
  715. /* Multicast support not yet implemented */
  716. undi.pxs->undi_open.R_Mcast_Buf.MCastAddrCount = 0;
  717. DBG ( "PXENV_UNDI_OPEN => OpenFlag=%hx PktFilter=%hx "
  718. "MCastAddrCount=%hx\n",
  719. undi.pxs->undi_open.OpenFlag, undi.pxs->undi_open.PktFilter,
  720. undi.pxs->undi_open.R_Mcast_Buf.MCastAddrCount );
  721. success = undi_call ( PXENV_UNDI_OPEN );
  722. DBG ( "PXENV_UNDI_OPEN <= Status=%s\n", UNDI_STATUS(undi.pxs) );
  723. if ( success ) undi.opened = 1;
  724. return success;
  725. }
  726. static int eb_pxenv_undi_close ( void ) {
  727. int success = 0;
  728. DBG ( "PXENV_UNDI_CLOSE => (void)\n" );
  729. success = undi_call ( PXENV_UNDI_CLOSE );
  730. DBG ( "PXENV_UNDI_CLOSE <= Status=%s\n", UNDI_STATUS(undi.pxs) );
  731. if ( success ) undi.opened = 0;
  732. return success;
  733. }
  734. static int eb_pxenv_undi_transmit_packet ( void ) {
  735. int success = 0;
  736. static const uint8_t broadcast[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF };
  737. /* XMitFlag selects unicast / broadcast */
  738. if ( memcmp ( undi.xmit_data->destaddr, broadcast,
  739. sizeof(broadcast) ) == 0 ) {
  740. undi.pxs->undi_transmit.XmitFlag = XMT_BROADCAST;
  741. } else {
  742. undi.pxs->undi_transmit.XmitFlag = XMT_DESTADDR;
  743. }
  744. /* Zero reserved dwords */
  745. undi.pxs->undi_transmit.Reserved[0] = 0;
  746. undi.pxs->undi_transmit.Reserved[1] = 0;
  747. /* Segment:offset pointer to DestAddr in base memory */
  748. undi.pxs->undi_transmit.DestAddr.segment =
  749. SEGMENT( undi.xmit_data->destaddr );
  750. undi.pxs->undi_transmit.DestAddr.offset =
  751. OFFSET( undi.xmit_data->destaddr );
  752. /* Segment:offset pointer to TBD in base memory */
  753. undi.pxs->undi_transmit.TBD.segment = SEGMENT( &undi.xmit_data->tbd );
  754. undi.pxs->undi_transmit.TBD.offset = OFFSET( &undi.xmit_data->tbd );
  755. /* Use only the "immediate" part of the TBD */
  756. undi.xmit_data->tbd.DataBlkCount = 0;
  757. DBG ( "PXENV_UNDI_TRANSMIT_PACKET => Protocol=%hx XmitFlag=%hx ...\n"
  758. "... DestAddr=%hx:%hx TBD=%hx:%hx ...\n",
  759. undi.pxs->undi_transmit.Protocol,
  760. undi.pxs->undi_transmit.XmitFlag,
  761. undi.pxs->undi_transmit.DestAddr.segment,
  762. undi.pxs->undi_transmit.DestAddr.offset,
  763. undi.pxs->undi_transmit.TBD.segment,
  764. undi.pxs->undi_transmit.TBD.offset );
  765. DBG ( "... TBD { ImmedLength=%hx Xmit=%hx:%hx DataBlkCount=%hx }\n",
  766. undi.xmit_data->tbd.ImmedLength,
  767. undi.xmit_data->tbd.Xmit.segment,
  768. undi.xmit_data->tbd.Xmit.offset,
  769. undi.xmit_data->tbd.DataBlkCount );
  770. success = undi_call ( PXENV_UNDI_TRANSMIT );
  771. DBG ( "PXENV_UNDI_TRANSMIT_PACKET <= Status=%s\n",
  772. UNDI_STATUS(undi.pxs) );
  773. return success;
  774. }
  775. static int eb_pxenv_undi_set_station_address ( void ) {
  776. /* This will spuriously fail on some cards. Ignore failures.
  777. * We only ever use it to set the MAC address to the card's
  778. * permanent value anyway, so it's a useless call (although we
  779. * make it because PXE spec says we should).
  780. */
  781. DBG ( "PXENV_UNDI_SET_STATION_ADDRESS => "
  782. "StationAddress=%!\n",
  783. undi.pxs->undi_set_station_address.StationAddress );
  784. undi_call_silent ( PXENV_UNDI_SET_STATION_ADDRESS );
  785. DBG ( "PXENV_UNDI_SET_STATION_ADDRESS <= Status=%s\n",
  786. UNDI_STATUS(undi.pxs) );
  787. return 1;
  788. }
  789. static int eb_pxenv_undi_get_information ( void ) {
  790. int success = 0;
  791. memset ( undi.pxs, 0, sizeof ( undi.pxs ) );
  792. DBG ( "PXENV_UNDI_GET_INFORMATION => (void)\n" );
  793. success = undi_call ( PXENV_UNDI_GET_INFORMATION );
  794. DBG ( "PXENV_UNDI_GET_INFORMATION <= Status=%s "
  795. "BaseIO=%hx IntNumber=%hx ...\n"
  796. "... MaxTranUnit=%hx HwType=%hx HwAddrlen=%hx ...\n"
  797. "... CurrentNodeAddress=%! PermNodeAddress=%! ...\n"
  798. "... ROMAddress=%hx RxBufCt=%hx TxBufCt=%hx\n",
  799. UNDI_STATUS(undi.pxs),
  800. undi.pxs->undi_get_information.BaseIo,
  801. undi.pxs->undi_get_information.IntNumber,
  802. undi.pxs->undi_get_information.MaxTranUnit,
  803. undi.pxs->undi_get_information.HwType,
  804. undi.pxs->undi_get_information.HwAddrLen,
  805. undi.pxs->undi_get_information.CurrentNodeAddress,
  806. undi.pxs->undi_get_information.PermNodeAddress,
  807. undi.pxs->undi_get_information.ROMAddress,
  808. undi.pxs->undi_get_information.RxBufCt,
  809. undi.pxs->undi_get_information.TxBufCt );
  810. return success;
  811. }
  812. static int eb_pxenv_undi_get_iface_info ( void ) {
  813. int success = 0;
  814. DBG ( "PXENV_UNDI_GET_IFACE_INFO => (void)\n" );
  815. success = undi_call ( PXENV_UNDI_GET_IFACE_INFO );
  816. DBG ( "PXENV_UNDI_GET_IFACE_INFO <= Status=%s IfaceType=%s ...\n"
  817. "... LinkSpeed=%x ServiceFlags=%x\n",
  818. UNDI_STATUS(undi.pxs),
  819. undi.pxs->undi_get_iface_info.IfaceType,
  820. undi.pxs->undi_get_iface_info.LinkSpeed,
  821. undi.pxs->undi_get_iface_info.ServiceFlags );
  822. return success;
  823. }
  824. static int eb_pxenv_undi_isr ( void ) {
  825. int success = 0;
  826. DBG ( "PXENV_UNDI_ISR => FuncFlag=%hx\n",
  827. undi.pxs->undi_isr.FuncFlag );
  828. success = undi_call ( PXENV_UNDI_ISR );
  829. DBG ( "PXENV_UNDI_ISR <= Status=%s FuncFlag=%hx BufferLength=%hx ...\n"
  830. "... FrameLength=%hx FrameHeaderLength=%hx Frame=%hx:%hx "
  831. "ProtType=%hhx ...\n... PktType=%hhx\n",
  832. UNDI_STATUS(undi.pxs), undi.pxs->undi_isr.FuncFlag,
  833. undi.pxs->undi_isr.BufferLength,
  834. undi.pxs->undi_isr.FrameLength,
  835. undi.pxs->undi_isr.FrameHeaderLength,
  836. undi.pxs->undi_isr.Frame.segment,
  837. undi.pxs->undi_isr.Frame.offset,
  838. undi.pxs->undi_isr.ProtType,
  839. undi.pxs->undi_isr.PktType );
  840. return success;
  841. }
  842. static int eb_pxenv_stop_undi ( void ) {
  843. int success = 0;
  844. DBG ( "PXENV_STOP_UNDI => (void)\n" );
  845. success = undi_call ( PXENV_STOP_UNDI );
  846. DBG ( "PXENV_STOP_UNDI <= Status=%s\n", UNDI_STATUS(undi.pxs) );
  847. if ( success ) undi.prestarted = 0;
  848. return success;
  849. }
  850. static int eb_pxenv_unload_stack ( void ) {
  851. int success = 0;
  852. memset ( undi.pxs, 0, sizeof ( undi.pxs ) );
  853. DBG ( "PXENV_UNLOAD_STACK => (void)\n" );
  854. success = undi_call_silent ( PXENV_UNLOAD_STACK );
  855. DBG ( "PXENV_UNLOAD_STACK <= Status=%s ...\n... (%s)\n",
  856. UNDI_STATUS(undi.pxs),
  857. ( undi.pxs->Status == PXENV_STATUS_SUCCESS ?
  858. "base-code is ready to be removed" :
  859. ( undi.pxs->Status == PXENV_STATUS_FAILURE ?
  860. "the size of free base memory has been changed" :
  861. ( undi.pxs->Status == PXENV_STATUS_KEEP_ALL ?
  862. "the NIC interrupt vector has been changed" :
  863. "UNEXPECTED STATUS CODE" ) ) ) );
  864. return success;
  865. }
  866. static int eb_pxenv_stop_base ( void ) {
  867. int success = 0;
  868. DBG ( "PXENV_STOP_BASE => (void)\n" );
  869. success = undi_call ( PXENV_STOP_BASE );
  870. DBG ( "PXENV_STOP_BASE <= Status=%s\n", UNDI_STATUS(undi.pxs) );
  871. return success;
  872. }
  873. /* Unload UNDI base code (if any present) and free memory.
  874. */
  875. static int undi_unload_base_code ( void ) {
  876. void *bc_code = VIRTUAL( undi.pxe->BC_Code.Seg_Addr, 0 );
  877. size_t bc_code_size = undi.pxe->BC_Code.Seg_Size;
  878. void *bc_data = VIRTUAL( undi.pxe->BC_Data.Seg_Addr, 0 );
  879. size_t bc_data_size = undi.pxe->BC_Data.Seg_Size;
  880. void *bc_stck = VIRTUAL( undi.pxe->Stack.Seg_Addr, 0 );
  881. size_t bc_stck_size = undi.pxe->Stack.Seg_Size;
  882. firing_squad_lineup_t lineup;
  883. /* Since we never start the base code, the only time we should
  884. * reach this is if we were loaded via PXE. There are many
  885. * different and conflicting versions of the "correct" way to
  886. * unload the PXE base code, several of which appear within
  887. * the PXE specification itself. This one seems to work for
  888. * our purposes.
  889. *
  890. * We always call PXENV_STOP_BASE and PXENV_UNLOAD_STACK even
  891. * if the !PXE structure indicates that no base code is
  892. * present. We do this for the case that there is a
  893. * base-code-less UNDI driver loaded that has hooked some
  894. * interrupts. If the base code really is absent, then these
  895. * calls will fail, we will ignore the failure, and our
  896. * subsequent memory-freeing code is robust enough to handle
  897. * whatever's thrown at it.
  898. */
  899. eb_pxenv_stop_base();
  900. eb_pxenv_unload_stack();
  901. if ( ( undi.pxs->unload_stack.Status != PXENV_STATUS_SUCCESS ) &&
  902. ( undi.pxs->unload_stack.Status != PXENV_STATUS_FAILURE ) &&
  903. ( undi.pxe->BC_Code.Seg_Addr != 0 ) )
  904. {
  905. printf ( "Could not free memory allocated to PXE base code: "
  906. "possible memory leak\n" );
  907. return 0;
  908. }
  909. /* Free data structures. Forget what the PXE specification
  910. * says about how to calculate the new size of base memory;
  911. * basemem.c takes care of all that for us. Note that we also
  912. * have to free the stack (even though PXE spec doesn't say
  913. * anything about it) because nothing else is going to do so.
  914. *
  915. * Structures will almost certainly not be kB-aligned and
  916. * there's a reasonable chance that the UNDI code or data
  917. * portions will lie in the same kB as the base code. Since
  918. * forget_base_memory works only in 1kB increments, this means
  919. * we have to do some arcane trickery.
  920. */
  921. memset ( &lineup, 0, sizeof(lineup) );
  922. if ( SEGMENT(bc_code) != 0 )
  923. assemble_firing_squad( &lineup, bc_code, bc_code_size, SHOOT );
  924. if ( SEGMENT(bc_data) != 0 )
  925. assemble_firing_squad( &lineup, bc_data, bc_data_size, SHOOT );
  926. if ( SEGMENT(bc_stck) != 0 )
  927. assemble_firing_squad( &lineup, bc_stck, bc_stck_size, SHOOT );
  928. /* Don't shoot any bits of the UNDI driver code or data */
  929. assemble_firing_squad ( &lineup,
  930. VIRTUAL(undi.pxe->UNDICode.Seg_Addr, 0),
  931. undi.pxe->UNDICode.Seg_Size, DONTSHOOT );
  932. assemble_firing_squad ( &lineup,
  933. VIRTUAL(undi.pxe->UNDIData.Seg_Addr, 0),
  934. undi.pxe->UNDIData.Seg_Size, DONTSHOOT );
  935. shoot_targets ( &lineup );
  936. undi.pxe->BC_Code.Seg_Addr = 0;
  937. undi.pxe->BC_Data.Seg_Addr = 0;
  938. undi.pxe->Stack.Seg_Addr = 0;
  939. /* Free and reallocate our own base memory data structures, to
  940. * allow the freed base-code blocks to be fully released.
  941. */
  942. free_base_mem_data();
  943. if ( ! allocate_base_mem_data() ) {
  944. printf ( "FATAL: memory unaccountably lost\n" );
  945. while ( 1 ) {};
  946. }
  947. return 1;
  948. }
  949. /* UNDI full initialization
  950. *
  951. * This calls all the various UNDI initialization routines in sequence.
  952. */
  953. static int undi_full_startup ( void ) {
  954. if ( ! eb_pxenv_start_undi() ) return 0;
  955. if ( ! eb_pxenv_undi_startup() ) return 0;
  956. if ( ! eb_pxenv_undi_initialize() ) return 0;
  957. if ( ! eb_pxenv_undi_get_information() ) return 0;
  958. undi.irq = undi.pxs->undi_get_information.IntNumber;
  959. copy_undi_irq_handler ( undi.base_mem_data->irq_handler,
  960. UNDI_IRQ_HANDLER_SIZE );
  961. if ( ! install_undi_irq_handler ( undi.irq ) ) {
  962. undi.irq = IRQ_NONE;
  963. return 0;
  964. }
  965. memmove ( &undi.pxs->undi_set_station_address.StationAddress,
  966. &undi.pxs->undi_get_information.PermNodeAddress,
  967. sizeof (undi.pxs->undi_set_station_address.StationAddress) );
  968. if ( ! eb_pxenv_undi_set_station_address() ) return 0;
  969. if ( ! eb_pxenv_undi_open() ) return 0;
  970. return 1;
  971. }
  972. /* UNDI full shutdown
  973. *
  974. * This calls all the various UNDI shutdown routines in sequence and
  975. * also frees any memory that it can.
  976. */
  977. static int undi_full_shutdown ( void ) {
  978. if ( undi.pxe != NULL ) {
  979. /* In case we didn't allocate the driver's memory in the first
  980. * place, try to grab the code and data segments and sizes
  981. * from the !PXE structure.
  982. */
  983. if ( undi.driver_code == NULL ) {
  984. undi.driver_code = VIRTUAL(undi.pxe->UNDICode.Seg_Addr,
  985. 0 );
  986. undi.driver_code_size = undi.pxe->UNDICode.Seg_Size;
  987. }
  988. if ( undi.driver_data == NULL ) {
  989. undi.driver_data = VIRTUAL(undi.pxe->UNDIData.Seg_Addr,
  990. 0 );
  991. undi.driver_data_size = undi.pxe->UNDIData.Seg_Size;
  992. }
  993. /* Ignore errors and continue in the hope of shutting
  994. * down anyway
  995. */
  996. if ( undi.opened ) eb_pxenv_undi_close();
  997. if ( undi.started ) {
  998. eb_pxenv_undi_cleanup();
  999. /* We may get spurious UNDI API errors at this
  1000. * point. If startup() succeeded but
  1001. * initialize() failed then according to the
  1002. * spec, we should call shutdown(). However,
  1003. * some NICS will fail with a status code
  1004. * 0x006a (INVALID_STATE).
  1005. */
  1006. eb_pxenv_undi_shutdown();
  1007. }
  1008. if ( undi.irq != IRQ_NONE ) {
  1009. remove_undi_irq_handler ( undi.irq );
  1010. undi.irq = IRQ_NONE;
  1011. }
  1012. undi_unload_base_code();
  1013. if ( undi.prestarted ) {
  1014. eb_pxenv_stop_undi();
  1015. /* Success OR Failure indicates that memory
  1016. * can be freed. Any other status code means
  1017. * that it can't.
  1018. */
  1019. if (( undi.pxs->Status == PXENV_STATUS_KEEP_UNDI ) ||
  1020. ( undi.pxs->Status == PXENV_STATUS_KEEP_ALL ) ) {
  1021. printf ("Could not free memory allocated to "
  1022. "UNDI driver: possible memory leak\n");
  1023. return 0;
  1024. }
  1025. }
  1026. }
  1027. /* Free memory allocated to UNDI driver */
  1028. if ( undi.driver_code != NULL ) {
  1029. /* Clear contents in order to eliminate !PXE and PXENV
  1030. * signatures to prevent spurious detection via base
  1031. * memory scan.
  1032. */
  1033. memset ( undi.driver_code, 0, undi.driver_code_size );
  1034. forget_base_memory ( undi.driver_code, undi.driver_code_size );
  1035. undi.driver_code = NULL;
  1036. undi.driver_code_size = 0;
  1037. }
  1038. if ( undi.driver_data != NULL ) {
  1039. forget_base_memory ( undi.driver_data, undi.driver_data_size );
  1040. undi.driver_data = NULL;
  1041. undi.driver_data_size = 0;
  1042. }
  1043. /* !PXE structure now gone; memory freed */
  1044. undi.pxe = NULL;
  1045. return 1;
  1046. }
  1047. /**************************************************************************
  1048. POLL - Wait for a frame
  1049. ***************************************************************************/
  1050. static int undi_poll(struct nic *nic, int retrieve)
  1051. {
  1052. /* Fun, fun, fun. UNDI drivers don't use polling; they use
  1053. * interrupts. We therefore cheat and pretend that an
  1054. * interrupt has occurred every time undi_poll() is called.
  1055. * This isn't too much of a hack; PCI devices share IRQs and
  1056. * so the first thing that a proper ISR should do is call
  1057. * PXENV_UNDI_ISR to determine whether or not the UNDI NIC
  1058. * generated the interrupt; there is no harm done by spurious
  1059. * calls to PXENV_UNDI_ISR. Similarly, we wouldn't be
  1060. * handling them any more rapidly than the usual rate of
  1061. * undi_poll() being called even if we did implement a full
  1062. * ISR. So it should work. Ha!
  1063. *
  1064. * Addendum (21/10/03). Some cards don't play nicely with
  1065. * this trick, so instead of doing it the easy way we have to
  1066. * go to all the hassle of installing a genuine interrupt
  1067. * service routine and dealing with the wonderful 8259
  1068. * Programmable Interrupt Controller. Joy.
  1069. */
  1070. /* See if a hardware interrupt has occurred since the last poll().
  1071. */
  1072. if ( ! undi_irq_triggered ( undi.irq ) ) return 0;
  1073. /* Given the frailty of PXE stacks, it's probably not safe to
  1074. * risk calling PXENV_UNDI_ISR with
  1075. * FuncFlag=PXENV_UNDI_ISR_START twice for the same interrupt,
  1076. * so we cheat slightly and assume that there is something
  1077. * ready to retrieve as long as an interrupt has occurred.
  1078. */
  1079. if ( ! retrieve ) return 1;
  1080. #ifdef UNDI_NONTRIVIAL_IRQ
  1081. /* With the nontrivial IRQ handler, we have already called
  1082. * PXENV_UNDI_ISR with PXENV_UNDI_ISR_IN_START and determined
  1083. * that it is one of ours.
  1084. */
  1085. #else
  1086. /* Ask the UNDI driver if this is "our" interrupt.
  1087. */
  1088. undi.pxs->undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_START;
  1089. if ( ! eb_pxenv_undi_isr() ) return 0;
  1090. if ( undi.pxs->undi_isr.FuncFlag == PXENV_UNDI_ISR_OUT_NOT_OURS ) {
  1091. /* "Not our interrupt" translates to "no packet ready
  1092. * to read".
  1093. */
  1094. /* FIXME: Technically, we shouldn't be the one sending
  1095. * EOI. However, since our IRQ handlers don't yet
  1096. * support chaining, nothing else gets the chance to.
  1097. * One nice side-effect of doing this is that it means
  1098. * we can cheat and claim the timer interrupt as our
  1099. * NIC interrupt; it will be inefficient but will
  1100. * work.
  1101. */
  1102. send_specific_eoi ( undi.irq );
  1103. return 0;
  1104. }
  1105. #endif
  1106. /* At this stage, the device should have cleared its interrupt
  1107. * line so we can send EOI to the 8259.
  1108. */
  1109. send_specific_eoi ( undi.irq );
  1110. /* We might have received a packet, or this might be a
  1111. * "transmit completed" interrupt. Zero nic->packetlen,
  1112. * increment whenever we receive a bit of a packet, test
  1113. * nic->packetlen when we're done to see whether or not we
  1114. * actually received anything.
  1115. */
  1116. nic->packetlen = 0;
  1117. undi.pxs->undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
  1118. if ( ! eb_pxenv_undi_isr() ) return 0;
  1119. while ( undi.pxs->undi_isr.FuncFlag != PXENV_UNDI_ISR_OUT_DONE ) {
  1120. switch ( undi.pxs->undi_isr.FuncFlag ) {
  1121. case PXENV_UNDI_ISR_OUT_TRANSMIT:
  1122. /* We really don't care about transmission complete
  1123. * interrupts.
  1124. */
  1125. break;
  1126. case PXENV_UNDI_ISR_OUT_BUSY:
  1127. /* This should never happen.
  1128. */
  1129. printf ( "UNDI ISR thinks it's being re-entered!\n"
  1130. "Aborting receive\n" );
  1131. return 0;
  1132. case PXENV_UNDI_ISR_OUT_RECEIVE:
  1133. /* Copy data to receive buffer */
  1134. memcpy ( nic->packet + nic->packetlen,
  1135. VIRTUAL( undi.pxs->undi_isr.Frame.segment,
  1136. undi.pxs->undi_isr.Frame.offset ),
  1137. undi.pxs->undi_isr.BufferLength );
  1138. nic->packetlen += undi.pxs->undi_isr.BufferLength;
  1139. break;
  1140. default:
  1141. printf ( "UNDI ISR returned bizzare status code %d\n",
  1142. undi.pxs->undi_isr.FuncFlag );
  1143. }
  1144. undi.pxs->undi_isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
  1145. if ( ! eb_pxenv_undi_isr() ) return 0;
  1146. }
  1147. return nic->packetlen > 0 ? 1 : 0;
  1148. }
  1149. /**************************************************************************
  1150. TRANSMIT - Transmit a frame
  1151. ***************************************************************************/
  1152. static void undi_transmit(
  1153. struct nic *nic __unused,
  1154. const char *d, /* Destination */
  1155. unsigned int t, /* Type */
  1156. unsigned int s, /* size */
  1157. const char *p) /* Packet */
  1158. {
  1159. /* Copy destination to buffer in base memory */
  1160. memcpy ( undi.xmit_data->destaddr, d, sizeof(MAC_ADDR) );
  1161. /* Translate packet type to UNDI packet type */
  1162. switch ( t ) {
  1163. case IP : undi.pxs->undi_transmit.Protocol = P_IP; break;
  1164. case ARP: undi.pxs->undi_transmit.Protocol = P_ARP; break;
  1165. case RARP: undi.pxs->undi_transmit.Protocol = P_RARP; break;
  1166. default: printf ( "Unknown packet type %hx\n", t );
  1167. return;
  1168. }
  1169. /* Store packet length in TBD */
  1170. undi.xmit_data->tbd.ImmedLength = s;
  1171. /* Check to see if data to be transmitted is currently in base
  1172. * memory. If not, allocate temporary storage in base memory
  1173. * and copy it there.
  1174. */
  1175. if ( SEGMENT( p ) <= 0xffff ) {
  1176. undi.xmit_data->tbd.Xmit.segment = SEGMENT( p );
  1177. undi.xmit_data->tbd.Xmit.offset = OFFSET( p );
  1178. } else {
  1179. memcpy ( undi.xmit_buffer, p, s );
  1180. undi.xmit_data->tbd.Xmit.segment = SEGMENT( undi.xmit_buffer );
  1181. undi.xmit_data->tbd.Xmit.offset = OFFSET( undi.xmit_buffer );
  1182. }
  1183. eb_pxenv_undi_transmit_packet();
  1184. }
  1185. /**************************************************************************
  1186. DISABLE - Turn off ethernet interface
  1187. ***************************************************************************/
  1188. static void undi_disable ( struct dev *dev __unused ) {
  1189. undi_full_shutdown();
  1190. free_base_mem_data();
  1191. }
  1192. /**************************************************************************
  1193. PROBE - Look for an adapter, this routine's visible to the outside
  1194. ***************************************************************************/
  1195. /* Locate an UNDI driver by first scanning through base memory for an
  1196. * installed driver and then by scanning for UNDI ROMs and attempting
  1197. * to install their drivers.
  1198. */
  1199. static int hunt_pixies_and_undi_roms ( void ) {
  1200. static uint8_t hunt_type = HUNT_FOR_PIXIES;
  1201. if ( hunt_type == HUNT_FOR_PIXIES ) {
  1202. if ( hunt_pixie() ) {
  1203. return 1;
  1204. }
  1205. }
  1206. hunt_type = HUNT_FOR_UNDI_ROMS;
  1207. while ( hunt_undi_rom() ) {
  1208. if ( undi_loader() ) {
  1209. return 1;
  1210. }
  1211. undi_full_shutdown(); /* Free any allocated memory */
  1212. }
  1213. hunt_type = HUNT_FOR_PIXIES;
  1214. return 0;
  1215. }
  1216. /* The actual Etherboot probe routine.
  1217. */
  1218. static int undi_probe(struct dev *dev, struct pci_device *pci)
  1219. {
  1220. struct nic *nic = (struct nic *)dev;
  1221. /* Zero out global undi structure */
  1222. memset ( &undi, 0, sizeof(undi) );
  1223. /* Store PCI parameters; we will need them to initialize the
  1224. * UNDI driver later. If not a PCI device, leave as 0.
  1225. */
  1226. if ( pci ) {
  1227. memcpy ( &undi.pci, pci, sizeof(undi.pci) );
  1228. }
  1229. /* Find the BIOS' $PnP structure */
  1230. if ( ! hunt_pnp_bios() ) {
  1231. /* Not all PXE stacks actually insist on a PnP BIOS.
  1232. * In particular, an Etherboot PXE stack will work
  1233. * just fine without one.
  1234. *
  1235. * We used to make this a fatal error, but now we just
  1236. * warn and continue. Note that this is necessary in
  1237. * order to be able to debug the Etherboot PXE stack
  1238. * under Bochs, since Bochs' BIOS is non-PnP.
  1239. */
  1240. printf ( "WARNING: No PnP BIOS found\n" );
  1241. }
  1242. /* Allocate base memory data structures */
  1243. if ( ! allocate_base_mem_data() ) return 0;
  1244. /* Search thoroughly for UNDI drivers */
  1245. for ( ; hunt_pixies_and_undi_roms(); undi_full_shutdown() ) {
  1246. /* Try to initialise UNDI driver */
  1247. printf ( "Initializing UNDI driver. Please wait...\n" );
  1248. if ( ! undi_full_startup() ) {
  1249. if ( undi.pxs->Status ==
  1250. PXENV_STATUS_UNDI_MEDIATEST_FAILED ) {
  1251. printf ( "Cable not connected (code %#hx)\n",
  1252. PXENV_STATUS_UNDI_MEDIATEST_FAILED );
  1253. }
  1254. continue;
  1255. }
  1256. /* Basic information: MAC, IO addr, IRQ */
  1257. if ( ! eb_pxenv_undi_get_information() ) continue;
  1258. printf ( "Initialized UNDI NIC with IO %#hx, IRQ %d, MAC %!\n",
  1259. undi.pxs->undi_get_information.BaseIo,
  1260. undi.pxs->undi_get_information.IntNumber,
  1261. undi.pxs->undi_get_information.CurrentNodeAddress );
  1262. /* Fill out MAC address in nic structure */
  1263. memcpy ( nic->node_addr,
  1264. undi.pxs->undi_get_information.CurrentNodeAddress,
  1265. ETH_ALEN );
  1266. /* More diagnostic information including link speed */
  1267. if ( ! eb_pxenv_undi_get_iface_info() ) continue;
  1268. printf ( "NDIS type %s interface at %d Mbps\n",
  1269. undi.pxs->undi_get_iface_info.IfaceType,
  1270. undi.pxs->undi_get_iface_info.LinkSpeed / 1000000 );
  1271. dev->disable = undi_disable;
  1272. nic->poll = undi_poll;
  1273. nic->transmit = undi_transmit;
  1274. return 1;
  1275. }
  1276. undi_disable ( dev ); /* To free base memory structures */
  1277. return 0;
  1278. }
  1279. static int undi_isa_probe ( struct dev *dev,
  1280. unsigned short *probe_addrs __unused ) {
  1281. return undi_probe ( dev, NULL );
  1282. }
  1283. /* UNDI driver states that it is suitable for any PCI NIC (i.e. any
  1284. * PCI device of class PCI_CLASS_NETWORK_ETHERNET). If there are any
  1285. * obscure UNDI NICs that have the incorrect PCI class, add them to
  1286. * this list.
  1287. */
  1288. static struct pci_id undi_nics[] = {
  1289. PCI_ROM(0x0000, 0x0000, "undi", "UNDI driver support"),
  1290. };
  1291. static struct pci_driver undi_driver __pci_driver = {
  1292. .type = NIC_DRIVER,
  1293. .name = "UNDI",
  1294. .probe = undi_probe,
  1295. .ids = undi_nics,
  1296. .id_count = sizeof(undi_nics)/sizeof(undi_nics[0]),
  1297. .class = PCI_CLASS_NETWORK_ETHERNET,
  1298. };
  1299. static struct isa_driver undi_isa_driver __isa_driver = {
  1300. .type = NIC_DRIVER,
  1301. .name = "UNDI",
  1302. .probe = undi_isa_probe,
  1303. .ioaddrs = 0,
  1304. };
  1305. #endif /* PCBIOS */