Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

memsizes.c 6.4KB

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