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.

memsizes.c 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. #ifdef PCBIOS
  2. #include "etherboot.h"
  3. #include "realmode.h"
  4. #define CF ( 1 << 0 )
  5. #ifndef MEMSIZES_DEBUG
  6. #define MEMSIZES_DEBUG 0
  7. #endif
  8. /* by Eric Biederman */
  9. struct meminfo meminfo;
  10. /**************************************************************************
  11. BASEMEMSIZE - Get size of the conventional (base) memory
  12. **************************************************************************/
  13. unsigned short basememsize ( void )
  14. {
  15. RM_FRAGMENT(rm_basememsize,
  16. "int $0x12\n\t"
  17. );
  18. return real_call ( rm_basememsize, NULL, NULL );
  19. }
  20. /**************************************************************************
  21. MEMSIZE - Determine size of extended memory
  22. **************************************************************************/
  23. unsigned int memsize ( void )
  24. {
  25. struct {
  26. reg16_t ax;
  27. } PACKED in_stack;
  28. struct {
  29. reg16_t ax;
  30. reg16_t bx;
  31. reg16_t cx;
  32. reg16_t dx;
  33. reg16_t flags;
  34. } PACKED out_stack;
  35. int memsize;
  36. RM_FRAGMENT(rm_memsize,
  37. /* Some buggy BIOSes don't clear/set carry on pass/error of
  38. * e801h memory size call or merely pass cx,dx through without
  39. * changing them, so we set carry and zero cx,dx before call.
  40. */
  41. "stc\n\t"
  42. "xorw %cx,%cx\n\t"
  43. "xorw %dx,%dx\n\t"
  44. "popw %ax\n\t"
  45. "int $0x15\n\t"
  46. "pushfw\n\t"
  47. "pushw %dx\n\t"
  48. "pushw %cx\n\t"
  49. "pushw %bx\n\t"
  50. "pushw %ax\n\t"
  51. );
  52. /* Try INT 15,e801 first */
  53. in_stack.ax.word = 0xe801;
  54. real_call ( rm_memsize, &in_stack, &out_stack );
  55. if ( out_stack.flags.word & CF ) {
  56. /* INT 15,e801 not supported: try INT 15,88 */
  57. in_stack.ax.word = 0x8800;
  58. memsize = real_call ( rm_memsize, &in_stack, &out_stack );
  59. } else {
  60. /* Some BIOSes report extended memory via ax,bx rather
  61. * than cx,dx
  62. */
  63. if ( (out_stack.cx.word==0) && (out_stack.dx.word==0) ) {
  64. /* Use ax,bx */
  65. memsize = ( out_stack.bx.word<<6 ) + out_stack.ax.word;
  66. } else {
  67. /* Use cx,dx */
  68. memsize = ( out_stack.dx.word<<6 ) + out_stack.cx.word;
  69. }
  70. }
  71. return memsize;
  72. }
  73. #define SMAP ( 0x534d4150 )
  74. int meme820 ( struct e820entry *buf, int count )
  75. {
  76. struct {
  77. reg16_t flags;
  78. reg32_t eax;
  79. reg32_t ebx;
  80. struct e820entry entry;
  81. } PACKED stack;
  82. int index = 0;
  83. RM_FRAGMENT(rm_meme820,
  84. "addw $6, %sp\n\t" /* skip flags, eax */
  85. "popl %ebx\n\t"
  86. "pushw %ss\n\t" /* es:di = ss:sp */
  87. "popw %es\n\t"
  88. "movw %sp, %di\n\t"
  89. "movl $0xe820, %eax\n\t"
  90. "movl $" RM_STR(SMAP) ", %edx\n\t"
  91. "movl $" RM_STR(E820ENTRY_SIZE) ", %ecx\n\t"
  92. "int $0x15\n\t"
  93. "pushl %ebx\n\t"
  94. "pushl %eax\n\t"
  95. "pushfw\n\t"
  96. );
  97. stack.ebx.dword = 0; /* 'EOF' marker */
  98. while ( ( index < count ) &&
  99. ( ( index == 0 ) || ( stack.ebx.dword != 0 ) ) ) {
  100. real_call ( rm_meme820, &stack, &stack );
  101. if ( stack.eax.dword != SMAP ) return 0;
  102. if ( stack.flags.word & CF ) return 0;
  103. buf[index++] = stack.entry;
  104. }
  105. return index;
  106. }
  107. void get_memsizes(void)
  108. {
  109. /* Ensure we don't stomp bios data structutres.
  110. * the interrupt table: 0x000 - 0x3ff
  111. * the bios data area: 0x400 - 0x502
  112. * Dos variables: 0x502 - 0x5ff
  113. */
  114. static const unsigned min_addr = 0x600;
  115. unsigned i;
  116. unsigned basemem;
  117. basemem = get_free_base_memory();
  118. meminfo.basememsize = basememsize();
  119. meminfo.memsize = memsize();
  120. #ifndef IGNORE_E820_MAP
  121. meminfo.map_count = meme820(meminfo.map, E820MAX);
  122. #else
  123. meminfo.map_count = 0;
  124. #endif
  125. if (meminfo.map_count == 0) {
  126. /* If we don't have an e820 memory map fake it */
  127. meminfo.map_count = 2;
  128. meminfo.map[0].addr = 0;
  129. meminfo.map[0].size = meminfo.basememsize << 10;
  130. meminfo.map[0].type = E820_RAM;
  131. meminfo.map[1].addr = 1024*1024;
  132. meminfo.map[1].size = meminfo.memsize << 10;
  133. meminfo.map[1].type = E820_RAM;
  134. }
  135. /* Scrub the e820 map */
  136. for(i = 0; i < meminfo.map_count; i++) {
  137. if (meminfo.map[i].type != E820_RAM) {
  138. continue;
  139. }
  140. /* Reserve the bios data structures */
  141. if (meminfo.map[i].addr < min_addr) {
  142. unsigned long delta;
  143. delta = min_addr - meminfo.map[i].addr;
  144. if (delta > meminfo.map[i].size) {
  145. delta = meminfo.map[i].size;
  146. }
  147. meminfo.map[i].addr = min_addr;
  148. meminfo.map[i].size -= delta;
  149. }
  150. /* Ensure the returned e820 map is in sync
  151. * with the actual memory state
  152. */
  153. if ((meminfo.map[i].addr < 0xa0000) &&
  154. ((meminfo.map[i].addr + meminfo.map[i].size) > basemem))
  155. {
  156. if (meminfo.map[i].addr <= basemem) {
  157. meminfo.map[i].size = basemem - meminfo.map[i].addr;
  158. } else {
  159. meminfo.map[i].addr = basemem;
  160. meminfo.map[i].size = 0;
  161. }
  162. }
  163. }
  164. #if MEMSIZES_DEBUG
  165. {
  166. int i;
  167. printf("basememsize %d\n", meminfo.basememsize);
  168. printf("memsize %d\n", meminfo.memsize);
  169. printf("Memory regions(%d):\n", meminfo.map_count);
  170. for(i = 0; i < meminfo.map_count; i++) {
  171. unsigned long long r_start, r_end;
  172. r_start = meminfo.map[i].addr;
  173. r_end = r_start + meminfo.map[i].size;
  174. printf("[%X%X, %X%X) type %d\n",
  175. (unsigned long)(r_start >> 32),
  176. (unsigned long)r_start,
  177. (unsigned long)(r_end >> 32),
  178. (unsigned long)r_end,
  179. meminfo.map[i].type);
  180. #if defined(CONSOLE_FIRMWARE)
  181. sleep(1); /* No way to see 32 entries on a standard 80x25 screen... */
  182. #endif
  183. }
  184. }
  185. #endif
  186. }
  187. #endif /* PCBIOS */