Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

memsizes.c 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. #include "stdint.h"
  2. #include "stddef.h"
  3. #include "realmode.h"
  4. #include "init.h"
  5. #include "etherboot.h"
  6. #include "memsizes.h"
  7. #define CF ( 1 << 0 )
  8. /* by Eric Biederman */
  9. struct meminfo meminfo;
  10. /**************************************************************************
  11. BASEMEMSIZE - Get size of the conventional (base) memory
  12. **************************************************************************/
  13. static unsigned short basememsize ( void ) {
  14. uint16_t int12_basememsize, fbms_basememsize;
  15. uint16_t basememsize;
  16. /* There are two methods for retrieving the base memory size:
  17. * INT 12 and the BIOS FBMS counter at 40:13. We read both
  18. * and use the smaller value, to be paranoid.
  19. *
  20. * We then store the smaller value in the BIOS FBMS counter so
  21. * that other code (e.g. basemem.c) can rely on it and not
  22. * have to use INT 12. This is especially important because
  23. * basemem.c functions can be called in a context in which
  24. * there is no real-mode stack (e.g. when trying to allocate
  25. * memory for a real-mode stack...)
  26. */
  27. REAL_EXEC ( rm_basememsize,
  28. "int $0x12\n\t",
  29. 1,
  30. OUT_CONSTRAINTS ( "=a" ( int12_basememsize ) ),
  31. IN_CONSTRAINTS (),
  32. CLOBBER ( "ebx", "ecx", "edx", "ebp", "esi", "edi" ) );
  33. get_real ( fbms_basememsize, 0x40, 0x13 );
  34. basememsize = ( int12_basememsize < fbms_basememsize ?
  35. int12_basememsize : fbms_basememsize );
  36. put_real ( basememsize, 0x40, 0x13 );
  37. return basememsize;
  38. }
  39. /**************************************************************************
  40. MEMSIZE - Determine size of extended memory, in kB
  41. **************************************************************************/
  42. static unsigned int memsize ( void ) {
  43. uint16_t extmem_1m_to_16m_k, extmem_16m_plus_64k;
  44. uint16_t confmem_1m_to_16m_k, confmem_16m_plus_64k;
  45. uint16_t flags;
  46. int memsize;
  47. /* Try INT 15,e801 first
  48. *
  49. * Some buggy BIOSes don't clear/set carry on pass/error of
  50. * e801h memory size call or merely pass cx,dx through without
  51. * changing them, so we set carry and zero cx,dx before call.
  52. */
  53. REAL_EXEC ( rm_mem_e801,
  54. "stc\n\t"
  55. "int $0x15\n\t"
  56. "pushfw\n\t" /* flags -> %di */
  57. "popw %%di\n\t",
  58. 5,
  59. OUT_CONSTRAINTS ( "=a" ( extmem_1m_to_16m_k ),
  60. "=b" ( extmem_16m_plus_64k ),
  61. "=c" ( confmem_1m_to_16m_k ),
  62. "=d" ( confmem_16m_plus_64k ),
  63. "=D" ( flags ) ),
  64. IN_CONSTRAINTS ( "a" ( 0xe801 ),
  65. "c" ( 0 ),
  66. "d" ( 0 ) ),
  67. CLOBBER ( "ebp", "esi" ) );
  68. if ( ! ( flags & CF ) ) {
  69. /* INT 15,e801 succeeded */
  70. if ( confmem_1m_to_16m_k || confmem_16m_plus_64k ) {
  71. /* Use confmem (cx,dx) values */
  72. memsize = confmem_1m_to_16m_k +
  73. ( confmem_16m_plus_64k << 6 );
  74. } else {
  75. /* Use extmem (ax,bx) values */
  76. memsize = extmem_1m_to_16m_k +
  77. ( extmem_16m_plus_64k << 6 );
  78. }
  79. } else {
  80. /* INT 15,e801 failed; fall back to INT 15,88
  81. *
  82. * CF is apparently unreliable and should be ignored.
  83. */
  84. REAL_EXEC ( rm_mem_88,
  85. "int $0x15\n\t",
  86. 1,
  87. OUT_CONSTRAINTS ( "=a" ( extmem_1m_to_16m_k ) ),
  88. IN_CONSTRAINTS ( "a" ( 0x88 << 8 ) ),
  89. CLOBBER ( "ebx", "ecx", "edx",
  90. "ebp", "esi", "edi" ) );
  91. memsize = extmem_1m_to_16m_k;
  92. }
  93. return memsize;
  94. }
  95. /**************************************************************************
  96. MEME820 - Retrieve the E820 BIOS memory map
  97. **************************************************************************/
  98. #define SMAP ( 0x534d4150 ) /* "SMAP" */
  99. static int meme820 ( struct e820entry *buf, int count ) {
  100. int index;
  101. uint16_t basemem_entry;
  102. uint32_t smap, next;
  103. uint16_t flags;
  104. uint32_t discard_c, discard_d;
  105. index = 0;
  106. next = 0;
  107. do {
  108. basemem_entry = BASEMEM_PARAMETER_INIT ( buf[index] );
  109. REAL_EXEC ( rm_mem_e820,
  110. "int $0x15\n\t"
  111. "pushfw\n\t" /* flags -> %di */
  112. "popw %%di\n\t",
  113. 5,
  114. OUT_CONSTRAINTS ( "=a" ( smap ),
  115. "=b" ( next ),
  116. "=c" ( discard_c ),
  117. "=d" ( discard_d ),
  118. "=D" ( flags ) ),
  119. IN_CONSTRAINTS ( "a" ( 0xe820 ),
  120. "b" ( next ),
  121. "c" ( sizeof (struct e820entry) ),
  122. "d" ( SMAP ),
  123. "D" ( basemem_entry ) ),
  124. CLOBBER ( "ebp", "esi" ) );
  125. BASEMEM_PARAMETER_DONE ( buf[index] );
  126. if ( smap != SMAP ) return 0;
  127. if ( flags & CF ) break;
  128. index++;
  129. } while ( ( index < count ) && ( next != 0 ) );
  130. return index;
  131. }
  132. /**************************************************************************
  133. GET_MEMSIZES - Retrieve the system memory map via any available means
  134. **************************************************************************/
  135. void get_memsizes ( void ) {
  136. /* Ensure we don't stomp bios data structutres.
  137. * the interrupt table: 0x000 - 0x3ff
  138. * the bios data area: 0x400 - 0x502
  139. * Dos variables: 0x502 - 0x5ff
  140. */
  141. static const unsigned min_addr = 0x600;
  142. unsigned i;
  143. unsigned basemem;
  144. /* Retrieve memory information from the BIOS */
  145. meminfo.basememsize = basememsize();
  146. basemem = meminfo.basememsize << 10;
  147. meminfo.memsize = memsize();
  148. #ifndef IGNORE_E820_MAP
  149. meminfo.map_count = meme820 ( meminfo.map, E820MAX );
  150. #else
  151. meminfo.map_count = 0;
  152. #endif
  153. /* If we don't have an e820 memory map fake it */
  154. if ( meminfo.map_count == 0 ) {
  155. meminfo.map_count = 2;
  156. meminfo.map[0].addr = 0;
  157. meminfo.map[0].size = meminfo.basememsize << 10;
  158. meminfo.map[0].type = E820_RAM;
  159. meminfo.map[1].addr = 1024*1024;
  160. meminfo.map[1].size = meminfo.memsize << 10;
  161. meminfo.map[1].type = E820_RAM;
  162. }
  163. /* Scrub the e820 map */
  164. for ( i = 0; i < meminfo.map_count; i++ ) {
  165. if ( meminfo.map[i].type != E820_RAM ) {
  166. continue;
  167. }
  168. /* Reserve the bios data structures */
  169. if ( meminfo.map[i].addr < min_addr ) {
  170. unsigned long delta;
  171. delta = min_addr - meminfo.map[i].addr;
  172. if ( delta > meminfo.map[i].size ) {
  173. delta = meminfo.map[i].size;
  174. }
  175. meminfo.map[i].addr = min_addr;
  176. meminfo.map[i].size -= delta;
  177. }
  178. /* Ensure the returned e820 map is in sync with the
  179. * actual memory state
  180. */
  181. if ( ( meminfo.map[i].addr < 0xa0000 ) &&
  182. (( meminfo.map[i].addr+meminfo.map[i].size ) > basemem )){
  183. if ( meminfo.map[i].addr <= basemem ) {
  184. meminfo.map[i].size = basemem
  185. - meminfo.map[i].addr;
  186. } else {
  187. meminfo.map[i].addr = basemem;
  188. meminfo.map[i].size = 0;
  189. }
  190. }
  191. }
  192. #ifdef DEBUG_MEMSIZES
  193. printf ( "basememsize %d\n", meminfo.basememsize );
  194. printf ( "memsize %d\n", meminfo.memsize );
  195. printf ( "Memory regions(%d):\n", meminfo.map_count );
  196. for ( i = 0; i < meminfo.map_count; i++ ) {
  197. unsigned long long r_start, r_end;
  198. r_start = meminfo.map[i].addr;
  199. r_end = r_start + meminfo.map[i].size;
  200. printf ( "[%X%X, %X%X) type %d\n",
  201. ( unsigned long ) ( r_start >> 32 ),
  202. ( unsigned long ) r_start,
  203. ( unsigned long ) ( r_end >> 32 ),
  204. ( unsigned long ) r_end,
  205. meminfo.map[i].type );
  206. }
  207. #endif
  208. }
  209. INIT_FN ( INIT_MEMSIZES, get_memsizes, NULL, NULL );