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.

realmode.c 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. /* Real-mode interface: C portions.
  2. *
  3. * Initial version by Michael Brown <mbrown@fensystems.co.uk>, January 2004.
  4. */
  5. #include "etherboot.h"
  6. #include "realmode.h"
  7. #include "segoff.h"
  8. #define RM_STACK_SIZE ( 0x1000 )
  9. /* gcc won't let us use extended asm outside a function (compiler
  10. * bug), ao we have to put these asm statements inside a dummy
  11. * function.
  12. */
  13. static void work_around_gcc_bug ( void ) __attribute__ ((used));
  14. static void work_around_gcc_bug ( void ) {
  15. /* Export _real_mode_stack_size as absolute linker symbol */
  16. __asm__ ( ".globl _real_mode_stack_size" );
  17. __asm__ ( ".equ _real_mode_stack_size, %c0" : : "i" (RM_STACK_SIZE) );
  18. }
  19. /* While Etherboot remains in base memory the real-mode stack is
  20. * placed in the Etherboot main stack. The first allocation or
  21. * deallocation of base memory will cause a 'proper' real-mode stack
  22. * to be allocated. This will happen before Etherboot is relocated to
  23. * high memory.
  24. */
  25. uint32_t real_mode_stack = 0;
  26. size_t real_mode_stack_size = RM_STACK_SIZE;
  27. int lock_real_mode_stack = 0; /* Set to make stack immobile */
  28. /* Make a call to a real-mode code block.
  29. */
  30. /* These is the structure that exists on the stack as the paramters
  31. * passed in to _real_call. We pass a pointer to this struct to
  32. * prepare_real_call(), to save stack space.
  33. */
  34. typedef struct {
  35. void *fragment;
  36. int fragment_len;
  37. void *in_stack;
  38. int in_stack_len;
  39. void *out_stack;
  40. int out_stack_len;
  41. } real_call_params_t;
  42. uint32_t prepare_real_call ( real_call_params_t *p,
  43. int local_stack_len, char *local_stack ) {
  44. char *stack_base;
  45. char *stack_end;
  46. char *stack;
  47. char *s;
  48. prot_to_real_params_t *p2r_params;
  49. real_to_prot_params_t *r2p_params;
  50. /* Work out where we're putting the stack */
  51. if ( virt_to_phys(local_stack) < 0xa0000 ) {
  52. /* Current stack is in base memory. We can therefore
  53. * use it directly, with a constraint on the size that
  54. * we don't know; assume that we can use up to
  55. * real_mode_stack_size. (Not a valid assumption, but
  56. * it will do).
  57. */
  58. stack_end = local_stack + local_stack_len;
  59. stack_base = stack_end - real_mode_stack_size;
  60. } else {
  61. if (!real_mode_stack) {
  62. allot_real_mode_stack();
  63. }
  64. /* Use the allocated real-mode stack in base memory.
  65. * This has fixed start and end points.
  66. */
  67. stack_base = phys_to_virt(real_mode_stack);
  68. stack_end = stack_base + real_mode_stack_size;
  69. }
  70. s = stack = stack_end - local_stack_len;
  71. /* Compile input stack and trampoline code to stack */
  72. if ( p->in_stack_len ) {
  73. memcpy ( s, p->in_stack, p->in_stack_len );
  74. s += p->in_stack_len;
  75. }
  76. memcpy ( s, _prot_to_real_prefix, prot_to_real_prefix_size );
  77. s += prot_to_real_prefix_size;
  78. p2r_params = (prot_to_real_params_t*) ( s - sizeof(*p2r_params) );
  79. memcpy ( s, p->fragment, p->fragment_len );
  80. s += p->fragment_len;
  81. memcpy ( s, _real_to_prot_suffix, real_to_prot_suffix_size );
  82. s += real_to_prot_suffix_size;
  83. r2p_params = (real_to_prot_params_t*) ( s - sizeof(*r2p_params) );
  84. /* Set parameters within compiled stack */
  85. p2r_params->ss = p2r_params->cs = SEGMENT ( stack_base );
  86. p2r_params->esp = virt_to_phys ( stack );
  87. p2r_params->r2p_params = virt_to_phys ( r2p_params );
  88. r2p_params->out_stack = ( p->out_stack == NULL ) ?
  89. 0 : virt_to_phys ( p->out_stack );
  90. r2p_params->out_stack_len = p->out_stack_len;
  91. return virt_to_phys ( stack + p->in_stack_len );
  92. }
  93. /* Parameters are not genuinely unused; they are passed to
  94. * prepare_real_call() as part of a real_call_params_t struct.
  95. */
  96. uint16_t _real_call ( void *fragment, int fragment_len,
  97. void *in_stack __unused, int in_stack_len,
  98. void *out_stack __unused, int out_stack_len __unused ) {
  99. uint16_t retval;
  100. /* This code is basically equivalent to
  101. *
  102. * uint32_t trampoline;
  103. * char local_stack[ in_stack_len + prot_to_real_prefix_size +
  104. * fragment_len + real_to_prot_suffix_size ];
  105. * trampoline = prepare_real_call ( &fragment, local_stack );
  106. * __asm__ ( "call _virt_to_phys\n\t"
  107. * "call %%eax\n\t"
  108. * "call _phys_to_virt\n\t"
  109. * : "=a" (retval) : "0" (trampoline) );
  110. *
  111. * but implemented in assembly to avoid problems with not
  112. * being certain exactly how gcc handles %esp.
  113. */
  114. __asm__ ( "pushl %%ebp\n\t"
  115. "movl %%esp, %%ebp\n\t" /* %esp preserved via %ebp */
  116. "subl %%ecx, %%esp\n\t" /* space for inline RM stack */
  117. "pushl %%esp\n\t" /* set up RM stack */
  118. "pushl %%ecx\n\t"
  119. "pushl %%eax\n\t"
  120. "call prepare_real_call\n\t" /* %eax = trampoline addr */
  121. "addl $12, %%esp\n\t"
  122. "call _virt_to_phys\n\t" /* switch to phys addr */
  123. "call *%%eax\n\t" /* call to trampoline */
  124. "call _phys_to_virt\n\t" /* switch to virt addr */
  125. "movl %%ebp, %%esp\n\t" /* restore %esp & %ebp */
  126. "popl %%ebp\n\t"
  127. : "=a" ( retval )
  128. : "0" ( &fragment )
  129. , "c" ( ( ( in_stack_len + prot_to_real_prefix_size +
  130. fragment_len + real_to_prot_suffix_size )
  131. + 0x3 ) & ~0x3 ) );
  132. return retval;
  133. }