This commit was manufactured by cvs2svn to create tag
[opensuse:hwinfo.git] / src / hd / memory.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <sys/stat.h>
6
7 #include "hd.h"
8 #include "hd_int.h"
9 #include "memory.h"
10 #include "klog.h"
11
12 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
13  * memory stuff
14  *
15  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
16  */
17
18 uint64_t kcore_mem(hd_data_t *hd_data);
19 uint64_t klog_mem(hd_data_t *hd_data, uint64_t *alt);
20 uint64_t klog_mem2(hd_data_t *hd_data);
21 uint64_t meminfo_mem(hd_data_t *hd_data);
22
23 void hd_scan_memory(hd_data_t *hd_data)
24 {
25   hd_t *hd;
26   uint64_t kcore, klog, klog_alt, klog2, meminfo, msize0, msize1, u;
27   hd_res_t *res;
28   int i;
29   int exact;
30
31   if(!hd_probe_feature(hd_data, pr_memory)) return;
32
33   hd_data->module = mod_memory;
34
35   /* some clean-up */
36   remove_hd_entries(hd_data);
37
38   PROGRESS(1, 0, "main memory size");
39
40   kcore = kcore_mem(hd_data);
41   klog = klog_mem(hd_data, &klog_alt);
42   klog2 = klog_mem2(hd_data);
43   if(klog2 > klog) klog = klog2;
44   meminfo = meminfo_mem(hd_data);
45
46   msize0 = meminfo > klog ? meminfo : klog;
47   if(!msize0) msize0 = kcore;
48
49   exact = 0;
50   if(msize0 && kcore >= msize0 && ((kcore - msize0) << 4) / msize0 == 0) {
51     /* trust kcore value if it's approx. msize0 */
52     msize0 = kcore;
53     exact = 1;
54   }
55   msize1 = msize0;
56   if(meminfo > msize1) { msize1 = meminfo; exact = 0; }
57   if(klog_alt > msize0) msize0 = klog_alt;
58
59   hd = add_hd_entry(hd_data, __LINE__, 0);
60   hd->base_class.id = bc_internal;
61   hd->sub_class.id = sc_int_main_mem;
62
63   res = add_res_entry(&hd->res, new_mem(sizeof *res));
64   res->mem.type = res_mem;
65   res->mem.range = msize0;
66   res->mem.access = acc_rw;
67   res->mem.enabled = 1;
68
69   /* round it somewhat */
70   for(i = 0, u = msize1; u; i++) {
71     u >>= 1;
72   }
73   if(i > 10) {  /* We *do* have at least 1k memory, do we? */
74     msize1 >>= i - (exact ? 8 : 5);
75     msize1++;
76     msize1 >>= 1;
77     msize1 <<= i - (exact ? 7 : 4);
78   }
79
80   res = add_res_entry(&hd->res, new_mem(sizeof *res));
81   res->phys_mem.type = res_phys_mem;
82   res->phys_mem.range = msize1;
83 }
84
85 uint64_t kcore_mem(hd_data_t *hd_data)
86 {
87   uint64_t u = 0;
88   size_t ps = getpagesize();
89   struct stat sb;
90
91   if(!stat(PROC_KCORE, &sb)) {
92     u = sb.st_size;
93     if(u > ps) u -= ps;
94
95 #if 0
96     /* we'll assume no mem modules with less than 256k */
97     u += 1 << 17;
98     u &= -1 << 18;
99 #endif
100   }
101
102   ADD2LOG("  kcore mem:  0x%"PRIx64"\n", u);
103
104   return u;
105 }
106
107
108 uint64_t klog_mem(hd_data_t *hd_data, uint64_t *alt)
109 {
110   uint64_t u = 0, u0, u1, u2, u3, mem0 = 0, mem1 = 0;
111   str_list_t *sl;
112   char *s;
113   int i;
114
115   if(!hd_data->klog) read_klog(hd_data);
116
117   for(sl = hd_data->klog; sl; sl = sl->next) {
118     if(strstr(sl->str, "<6>Memory: ") == sl->str) {
119       if(sscanf(sl->str, "<6>Memory: %"SCNu64"k/%"SCNu64"k", &u0, &u1) == 2) {
120         mem0 = u1 << 10;
121       }
122       if(
123         (i = sscanf(sl->str, "<6>Memory: %"SCNu64"k available (%"SCNu64"k kernel code, %"SCNu64"k data, %"SCNu64"k", &u0, &u1, &u2, &u3))  == 4 || i == 1
124       ) {
125         mem0 = (i == 1 ? u0 : u0 + u1 + u2 + u3) << 10;
126       }
127       if(
128         (s = strstr(sl->str, "[")) &&
129         sscanf(s, "[%"SCNx64",%"SCNx64"]", &u0, &u1) == 2 &&
130         u1 > u0
131       ) {
132         mem1 = u1 - u0;
133       }
134       break;
135     }
136   }
137
138   u = mem0 ? mem0 : mem1;
139
140 #if 0
141   /* round it somewhat */
142   for(i = 0, u0 = u; u0; i++) {
143     u0 >>= 1;
144   }
145   if(i > 10) {  /* We *do* have at least 1k memory, do we? */
146     u >>= i - 6;
147     u++;
148     u >>= 1;
149     u <<= i - 5;
150   }
151 #endif
152
153   ADD2LOG("  klog mem 0: 0x%"PRIx64"\n", mem0);
154   ADD2LOG("  klog mem 1: 0x%"PRIx64"\n", mem1);
155   ADD2LOG("  klog mem:   0x%"PRIx64"\n", u);
156
157   *alt = mem1;
158
159   return u;
160 }
161
162 uint64_t klog_mem2(hd_data_t *hd_data)
163 {
164   uint64_t u0, u1, mem = 0;
165   str_list_t *sl;
166   char buf[64];
167
168   if(!hd_data->klog) read_klog(hd_data);
169
170   for(sl = hd_data->klog; sl; sl = sl->next) {
171     if(strstr(sl->str, "<6>BIOS-provided physical RAM map:") == sl->str) {
172       for(sl = sl->next ; sl; sl = sl->next) {
173         ADD2LOG(" -- %s", sl->str);
174         if(sscanf(sl->str, "<4> BIOS-e820: %"SCNx64" - %"SCNx64" (%63s", &u0, &u1, buf) != 3) break;
175         if(strcmp(buf, "usable)")) continue;
176         if(u1 < u0) break;
177         mem += u1 - u0;
178       }
179       break;
180     }
181   }
182
183   ADD2LOG("  bios mem:   0x%"PRIx64"\n", mem);
184
185   return mem;
186 }
187
188 uint64_t meminfo_mem(hd_data_t *hd_data)
189 {
190   uint64_t u = 0, u0;
191   str_list_t *sl;
192
193   sl = read_file(PROC_MEMINFO, 0, 1);
194
195   if(sl && sscanf(sl->str, "MemTotal: %"SCNu64"", &u0) == 1) {
196     u = u0 << 10;
197   }
198
199   free_str_list(sl);
200
201   ADD2LOG("  meminfo:    0x%"PRIx64"\n", u);
202
203   return u;
204 }
205
206