You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

pxe.c 9.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. /** @file
  2. *
  3. *
  4. *
  5. */
  6. /*
  7. * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License as
  11. * published by the Free Software Foundation; either version 2 of the
  12. * License, or any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful, but
  15. * WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22. */
  23. #include "dev.h"
  24. #include "pxe.h"
  25. /* Global pointer to currently installed PXE stack */
  26. pxe_stack_t *pxe_stack = NULL;
  27. /* Various startup/shutdown routines. The startup/shutdown call
  28. * sequence is incredibly badly defined in the Intel PXE spec, for
  29. * example:
  30. *
  31. * PXENV_UNDI_INITIALIZE says that the parameters used to initialize
  32. * the adaptor should be those supplied to the most recent
  33. * PXENV_UNDI_STARTUP call. PXENV_UNDI_STARTUP takes no parameters.
  34. *
  35. * PXENV_UNDI_CLEANUP says that the rest of the API will not be
  36. * available after making this call. Figure 3-3 ("Early UNDI API
  37. * usage") shows a call to PXENV_UNDI_CLEANUP being followed by a
  38. * call to the supposedly now unavailable PXENV_STOP_UNDI.
  39. *
  40. * PXENV_UNLOAD_BASE_STACK talks about freeing up the memory
  41. * occupied by the PXE stack. Figure 4-3 ("PXE IPL") shows a call
  42. * to PXENV_STOP_UNDI being made after the call to
  43. * PXENV_UNLOAD_BASE_STACK, by which time the entire PXE stack
  44. * should have been freed (and, potentially, zeroed).
  45. *
  46. * Nothing, anywhere, seems to mention who's responsible for freeing
  47. * up the base memory allocated for the stack segment. It's not
  48. * even clear whether or not this is expected to be in free base
  49. * memory rather than claimed base memory.
  50. *
  51. * Consequently, we adopt a rather defensive strategy, designed to
  52. * work with any conceivable sequence of initialisation or shutdown
  53. * calls. We have only two things that we care about:
  54. *
  55. * 1. Have we hooked INT 1A and INT 15,E820(etc.)?
  56. * 2. Is the NIC initialised?
  57. *
  58. * The NIC should never be initialised without the vectors being
  59. * hooked, similarly the vectors should never be unhooked with the NIC
  60. * still initialised. We do, however, want to be able to have the
  61. * vectors hooked with the NIC shutdown. We therefore have three
  62. * possible states:
  63. *
  64. * 1. Ready to unload: interrupts unhooked, NIC shutdown.
  65. * 2. Midway: interrupts hooked, NIC shutdown.
  66. * 3. Fully ready: interrupts hooked, NIC initialised.
  67. *
  68. * We provide the three states CAN_UNLOAD, MIDWAY and READY to define
  69. * these, and the call pxe_ensure_state() to ensure that the stack is
  70. * in the specified state. All our PXE API call implementations
  71. * should use this call to ensure that the state is as required for
  72. * that PXE API call. This enables us to cope with whatever the
  73. * end-user's interpretation of the PXE spec may be. It even allows
  74. * for someone calling e.g. PXENV_START_UNDI followed by
  75. * PXENV_UDP_WRITE, without bothering with any of the intervening
  76. * calls.
  77. *
  78. * pxe_ensure_state() returns 1 for success, 0 for failure. In the
  79. * event of failure (which can arise from e.g. asking for state READY
  80. * when we don't know where our NIC is), the error code
  81. * PXENV_STATUS_UNDI_INVALID_STATE should be returned to the user.
  82. * The macros ENSURE_XXX() can be used to achieve this without lots of
  83. * duplicated code.
  84. */
  85. /* pxe_[un]hook_stack are architecture-specific and provided in
  86. * pxe_callbacks.c
  87. */
  88. int pxe_initialise_nic ( void ) {
  89. if ( pxe_stack->state >= READY ) return 1;
  90. #warning "device probing mechanism has completely changed"
  91. #if 0
  92. /* Check if NIC is initialised. dev.disable is set to 0
  93. * when disable() is called, so we use this.
  94. */
  95. if ( dev.disable ) {
  96. /* NIC may have been initialised independently
  97. * (e.g. when we set up the stack prior to calling the
  98. * NBP).
  99. */
  100. pxe_stack->state = READY;
  101. return 1;
  102. }
  103. /* If we already have a NIC defined, reuse that one with
  104. * PROBE_AWAKE. If one was specifed via PXENV_START_UNDI, try
  105. * that one first. Otherwise, set PROBE_FIRST.
  106. */
  107. if ( dev.state.pci.dev.use_specified == 1 ) {
  108. dev.how_probe = PROBE_NEXT;
  109. DBG ( " initialising NIC specified via START_UNDI" );
  110. } else if ( dev.state.pci.dev.driver ) {
  111. DBG ( " reinitialising NIC" );
  112. dev.how_probe = PROBE_AWAKE;
  113. } else {
  114. DBG ( " probing for any NIC" );
  115. dev.how_probe = PROBE_FIRST;
  116. }
  117. /* Call probe routine to bring up the NIC */
  118. if ( eth_probe ( &dev ) != PROBE_WORKED ) {
  119. DBG ( " failed" );
  120. return 0;
  121. }
  122. #endif
  123. pxe_stack->state = READY;
  124. return 1;
  125. }
  126. int pxe_shutdown_nic ( void ) {
  127. if ( pxe_stack->state <= MIDWAY ) return 1;
  128. eth_irq ( DISABLE );
  129. disable ( &dev );
  130. pxe_stack->state = MIDWAY;
  131. return 1;
  132. }
  133. int ensure_pxe_state ( pxe_stack_state_t wanted ) {
  134. int success = 1;
  135. if ( ! pxe_stack ) return 0;
  136. if ( wanted >= MIDWAY )
  137. success = success & hook_pxe_stack();
  138. if ( wanted > MIDWAY ) {
  139. success = success & pxe_initialise_nic();
  140. } else {
  141. success = success & pxe_shutdown_nic();
  142. }
  143. if ( wanted < MIDWAY )
  144. success = success & unhook_pxe_stack();
  145. return success;
  146. }
  147. /* API call dispatcher
  148. *
  149. * Status: complete
  150. */
  151. PXENV_EXIT_t pxe_api_call ( int opcode, union u_PXENV_ANY *any ) {
  152. PXENV_EXIT_t ret = PXENV_EXIT_FAILURE;
  153. /* Set default status in case child routine fails to do so */
  154. any->Status = PXENV_STATUS_FAILURE;
  155. DBG ( "[" );
  156. /* Hand off to relevant API routine */
  157. switch ( opcode ) {
  158. case PXENV_START_UNDI:
  159. ret = pxenv_start_undi ( &any->start_undi );
  160. break;
  161. case PXENV_UNDI_STARTUP:
  162. ret = pxenv_undi_startup ( &any->undi_startup );
  163. break;
  164. case PXENV_UNDI_CLEANUP:
  165. ret = pxenv_undi_cleanup ( &any->undi_cleanup );
  166. break;
  167. case PXENV_UNDI_INITIALIZE:
  168. ret = pxenv_undi_initialize ( &any->undi_initialize );
  169. break;
  170. case PXENV_UNDI_RESET_ADAPTER:
  171. ret = pxenv_undi_reset_adapter ( &any->undi_reset_adapter );
  172. break;
  173. case PXENV_UNDI_SHUTDOWN:
  174. ret = pxenv_undi_shutdown ( &any->undi_shutdown );
  175. break;
  176. case PXENV_UNDI_OPEN:
  177. ret = pxenv_undi_open ( &any->undi_open );
  178. break;
  179. case PXENV_UNDI_CLOSE:
  180. ret = pxenv_undi_close ( &any->undi_close );
  181. break;
  182. case PXENV_UNDI_TRANSMIT:
  183. ret = pxenv_undi_transmit ( &any->undi_transmit );
  184. break;
  185. case PXENV_UNDI_SET_MCAST_ADDRESS:
  186. ret = pxenv_undi_set_mcast_address (
  187. &any->undi_set_mcast_address );
  188. break;
  189. case PXENV_UNDI_SET_STATION_ADDRESS:
  190. ret = pxenv_undi_set_station_address (
  191. &any->undi_set_station_address );
  192. break;
  193. case PXENV_UNDI_SET_PACKET_FILTER:
  194. ret = pxenv_undi_set_packet_filter (
  195. &any->undi_set_packet_filter );
  196. break;
  197. case PXENV_UNDI_GET_INFORMATION:
  198. ret = pxenv_undi_get_information (
  199. &any->undi_get_information );
  200. break;
  201. case PXENV_UNDI_GET_STATISTICS:
  202. ret = pxenv_undi_get_statistics ( &any->undi_get_statistics );
  203. break;
  204. case PXENV_UNDI_CLEAR_STATISTICS:
  205. ret = pxenv_undi_clear_statistics (
  206. &any->undi_clear_statistics );
  207. break;
  208. case PXENV_UNDI_INITIATE_DIAGS:
  209. ret = pxenv_undi_initiate_diags ( &any->undi_initiate_diags );
  210. break;
  211. case PXENV_UNDI_FORCE_INTERRUPT:
  212. ret = pxenv_undi_force_interrupt (
  213. &any->undi_force_interrupt );
  214. break;
  215. case PXENV_UNDI_GET_MCAST_ADDRESS:
  216. ret = pxenv_undi_get_mcast_address (
  217. &any->undi_get_mcast_address );
  218. break;
  219. case PXENV_UNDI_GET_NIC_TYPE:
  220. ret = pxenv_undi_get_nic_type ( &any->undi_get_nic_type );
  221. break;
  222. case PXENV_UNDI_GET_IFACE_INFO:
  223. ret = pxenv_undi_get_iface_info ( &any->undi_get_iface_info );
  224. break;
  225. case PXENV_UNDI_ISR:
  226. ret = pxenv_undi_isr ( &any->undi_isr );
  227. break;
  228. case PXENV_STOP_UNDI:
  229. ret = pxenv_stop_undi ( &any->stop_undi );
  230. break;
  231. case PXENV_TFTP_OPEN:
  232. ret = pxenv_tftp_open ( &any->tftp_open );
  233. break;
  234. case PXENV_TFTP_CLOSE:
  235. ret = pxenv_tftp_close ( &any->tftp_close );
  236. break;
  237. case PXENV_TFTP_READ:
  238. ret = pxenv_tftp_read ( &any->tftp_read );
  239. break;
  240. case PXENV_TFTP_READ_FILE:
  241. ret = pxenv_tftp_read_file ( &any->tftp_read_file );
  242. break;
  243. case PXENV_TFTP_GET_FSIZE:
  244. ret = pxenv_tftp_get_fsize ( &any->tftp_get_fsize );
  245. break;
  246. case PXENV_UDP_OPEN:
  247. ret = pxenv_udp_open ( &any->udp_open );
  248. break;
  249. case PXENV_UDP_CLOSE:
  250. ret = pxenv_udp_close ( &any->udp_close );
  251. break;
  252. case PXENV_UDP_READ:
  253. ret = pxenv_udp_read ( &any->udp_read );
  254. break;
  255. case PXENV_UDP_WRITE:
  256. ret = pxenv_udp_write ( &any->udp_write );
  257. break;
  258. case PXENV_UNLOAD_STACK:
  259. ret = pxenv_unload_stack ( &any->unload_stack );
  260. break;
  261. case PXENV_GET_CACHED_INFO:
  262. ret = pxenv_get_cached_info ( &any->get_cached_info );
  263. break;
  264. case PXENV_RESTART_TFTP:
  265. ret = pxenv_restart_tftp ( &any->restart_tftp );
  266. break;
  267. case PXENV_START_BASE:
  268. ret = pxenv_start_base ( &any->start_base );
  269. break;
  270. case PXENV_STOP_BASE:
  271. ret = pxenv_stop_base ( &any->stop_base );
  272. break;
  273. default:
  274. DBG ( "PXENV_UNKNOWN_%hx", opcode );
  275. any->Status = PXENV_STATUS_UNSUPPORTED;
  276. ret = PXENV_EXIT_FAILURE;
  277. break;
  278. }
  279. if ( any->Status != PXENV_STATUS_SUCCESS ) {
  280. DBG ( " %hx", any->Status );
  281. }
  282. if ( ret != PXENV_EXIT_SUCCESS ) {
  283. DBG ( ret == PXENV_EXIT_FAILURE ? " err" : " ??" );
  284. }
  285. DBG ( "]" );
  286. return ret;
  287. }