]>
Commit | Line | Data |
---|---|---|
a6316ce4 MT |
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 |