您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

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