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.

callbacks.c 3.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. /* Callout/callback interface for Etherboot
  2. *
  3. * This file provides the mechanisms for making calls from Etherboot
  4. * to external programs and vice-versa.
  5. *
  6. * Initial version by Michael Brown <mbrown@fensystems.co.uk>, January 2004.
  7. */
  8. #include "etherboot.h"
  9. #include "callbacks.h"
  10. #include "realmode.h"
  11. #include <stdarg.h>
  12. /* Maximum amount of stack data that prefix may request to be passed
  13. * to its exit routine
  14. */
  15. #define MAX_PREFIX_STACK_DATA 16
  16. /* Prefix exit routine is defined in prefix object */
  17. extern void prefix_exit ( void );
  18. extern void prefix_exit_end ( void );
  19. /*****************************************************************************
  20. *
  21. * IN_CALL INTERFACE
  22. *
  23. *****************************************************************************
  24. */
  25. /* in_call(): entry point for calls in to Etherboot from external code.
  26. *
  27. * Parameters: some set up by assembly code _in_call(), others as
  28. * passed from external code.
  29. */
  30. uint32_t i386_in_call ( va_list ap, i386_pm_in_call_data_t pm_data,
  31. uint32_t opcode ) {
  32. uint32_t ret;
  33. i386_rm_in_call_data_t rm_data;
  34. in_call_data_t in_call_data = { &pm_data, NULL };
  35. struct {
  36. int data[MAX_PREFIX_STACK_DATA/4];
  37. } in_stack;
  38. /* Fill out rm_data if we were called from real mode */
  39. if ( opcode & EB_CALL_FROM_REAL_MODE ) {
  40. in_call_data.rm = &rm_data;
  41. rm_data = va_arg ( ap, typeof(rm_data) );
  42. /* Null return address indicates to use the special
  43. * prefix exit mechanism, and that there are
  44. * parameters on the stack that the prefix wants
  45. * handed to its exit routine.
  46. */
  47. if ( rm_data.ret_addr.offset == 0 ) {
  48. int n = va_arg ( ap, int ) / 4;
  49. int i;
  50. for ( i = 0; i < n; i++ ) {
  51. in_stack.data[i] = va_arg ( ap, int );
  52. }
  53. }
  54. }
  55. /* Hand off to main in_call() routine */
  56. ret = in_call ( &in_call_data, opcode, ap );
  57. /* If real-mode return address is null, it means that we
  58. * should exit via the prefix's exit path, which is part of
  59. * our image. (This arrangement is necessary since the prefix
  60. * code itself may have been vapourised by the time we want to
  61. * return.)
  62. */
  63. if ( ( opcode & EB_CALL_FROM_REAL_MODE ) &&
  64. ( rm_data.ret_addr.offset == 0 ) ) {
  65. real_call ( prefix_exit, &in_stack, NULL );
  66. /* Should never return */
  67. }
  68. return ret;
  69. }
  70. #ifdef CODE16
  71. /* install_rm_callback_interface(): install real-mode callback
  72. * interface at specified address.
  73. *
  74. * Real-mode code may then call to this address (or lcall to this
  75. * address plus RM_IN_CALL_FAR) in order to make an in_call() to
  76. * Etherboot.
  77. *
  78. * Returns the size of the installed code, or 0 if the code could not
  79. * be installed.
  80. */
  81. int install_rm_callback_interface ( void *address, size_t available ) {
  82. if ( available &&
  83. ( available < rm_callback_interface_size ) ) return 0;
  84. /* Inform RM code where to find Etherboot */
  85. rm_etherboot_location = virt_to_phys(_text);
  86. /* Install callback interface */
  87. memcpy ( address, &rm_callback_interface,
  88. rm_callback_interface_size );
  89. return rm_callback_interface_size;
  90. }
  91. #endif /* CODE16 */