]>
Commit | Line | Data |
---|---|---|
93afd047 MT |
1 | #include <stdio.h> |
2 | #include <stdlib.h> | |
3 | #include <string.h> | |
4 | #include <unistd.h> | |
5 | ||
6 | #ifdef __ia64__ | |
7 | #include <fcntl.h> | |
8 | #include <errno.h> | |
9 | #include <stdint.h> | |
10 | #include <sys/mman.h> | |
11 | #endif | |
12 | ||
13 | #ifdef __powerpc__ | |
14 | #include <sys/utsname.h> | |
15 | #endif | |
16 | ||
17 | #include "hd.h" | |
18 | #include "hd_int.h" | |
19 | #include "klog.h" | |
20 | #include "cpu.h" | |
21 | ||
22 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
23 | * cpu info | |
24 | * | |
25 | * Note: on other architectures, entries differ (cf. Alpha)!!! | |
26 | * | |
27 | * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
28 | */ | |
29 | ||
30 | static void read_cpuinfo(hd_data_t *hd_data); | |
31 | static void dump_cpu_data(hd_data_t *hd_data); | |
32 | ||
33 | #if defined(__i386__) || defined(__x86_64__) | |
34 | static inline unsigned units_per_cpu(); | |
35 | #endif | |
36 | #ifdef __ia64__ | |
37 | static int ia64DetectSMP(hd_data_t *hd_data); | |
38 | #endif | |
39 | ||
40 | void hd_scan_cpu(hd_data_t *hd_data) | |
41 | { | |
42 | hd_t *hd0, *hd; | |
43 | int i, cpus; | |
44 | unsigned u; | |
45 | ||
46 | if(!hd_probe_feature(hd_data, pr_cpu)) return; | |
47 | ||
48 | hd_data->module = mod_cpu; | |
49 | ||
50 | /* some clean-up */ | |
51 | remove_hd_entries(hd_data); | |
52 | hd_data->cpu = free_str_list(hd_data->cpu); | |
53 | ||
54 | PROGRESS(1, 0, "cpuinfo"); | |
55 | ||
56 | read_cpuinfo(hd_data); | |
57 | ||
58 | for(hd0 = hd_data->hd; hd0; hd0 = hd0->next) { | |
59 | if(hd0->base_class.id == bc_internal && hd0->sub_class.id == sc_int_cpu) break; | |
60 | } | |
61 | ||
62 | if(!hd0 || hd0->next) return; /* 0 or > 1 entries */ | |
63 | ||
64 | /* only one entry, maybe UP kernel on SMP system */ | |
65 | ||
66 | cpus = 0; | |
67 | ||
68 | #ifdef __ia64__ | |
69 | cpus = ia64DetectSMP(hd_data); | |
70 | #endif | |
71 | ||
72 | for(i = 1; i < cpus; i++) { | |
73 | hd = add_hd_entry(hd_data, __LINE__, 0); | |
74 | u = hd->idx; | |
75 | hd_copy(hd, hd0); | |
76 | hd->idx = u; | |
77 | hd->slot = i; | |
78 | } | |
79 | } | |
80 | ||
81 | ||
82 | void read_cpuinfo(hd_data_t *hd_data) | |
83 | { | |
84 | hd_t *hd; | |
85 | unsigned cpus = 0; | |
86 | cpu_info_t *ct; | |
87 | str_list_t *sl; | |
88 | ||
89 | #if defined(__i386__) || defined (__x86_64__) | |
90 | char model_id[80], vendor_id[80], features[0x100]; | |
91 | unsigned bogo, mhz, cache, family, model, stepping; | |
92 | char *t0, *t; | |
93 | #endif | |
94 | ||
95 | #ifdef __ia64__ | |
96 | char model_id[80], vendor_id[80], features[0x100]; | |
97 | unsigned mhz, stepping; | |
98 | char *t0, *t; | |
99 | #endif | |
100 | ||
101 | #ifdef __alpha__ | |
102 | char model_id[80], system_id[80], serial_number[80], platform[80]; | |
103 | unsigned cpu_variation, cpu_revision, u, hz; | |
104 | cpu_info_t *ct1; | |
105 | #endif | |
106 | ||
107 | #ifdef __PPC__ | |
108 | char model_id[80], vendor_id[80], motherboard[80]; | |
109 | unsigned bogo, mhz, cache, family, model, stepping; | |
110 | struct utsname un; | |
111 | #endif | |
112 | ||
113 | #ifdef __sparc__ | |
114 | char cpu_id[80], fpu_id[80], promlib[80], prom[80], type[80], mmu[80]; | |
115 | unsigned u, bogo, cpus_active; | |
116 | #endif | |
117 | ||
118 | #if defined(__s390__) || defined(__s390x__) | |
119 | char vendor_id[80]; | |
120 | unsigned bogo; | |
121 | unsigned u0, u1, u2, u3; | |
122 | #endif | |
123 | ||
124 | hd_data->cpu = read_file(PROC_CPUINFO, 0, 0); | |
125 | if((hd_data->debug & HD_DEB_CPU)) dump_cpu_data(hd_data); | |
126 | if(!hd_data->cpu) return; | |
127 | ||
128 | #ifdef __alpha__ | |
129 | *model_id = *system_id = *serial_number = *platform = 0; | |
130 | cpu_variation = cpu_revision = hz = 0; | |
131 | ||
132 | for(sl = hd_data->cpu; sl; sl = sl->next) { | |
133 | if(sscanf(sl->str, "cpu model : %79[^\n]", model_id) == 1) continue; | |
134 | if(sscanf(sl->str, "system type : %79[^\n]", system_id) == 1) continue; | |
135 | if(sscanf(sl->str, "cpu variation : %u", &cpu_variation) == 1) continue; | |
136 | if(sscanf(sl->str, "cpu revision : %u", &cpu_revision) == 1) continue; | |
137 | if(sscanf(sl->str, "system serial number : %79[^\n]", serial_number) == 1) continue; | |
138 | if(sscanf(sl->str, "cpus detected : %u", &cpus) == 1) continue; | |
139 | if(sscanf(sl->str, "cycle frequency [Hz] : %u", &hz) == 1) continue; | |
140 | if(sscanf(sl->str, "system variation : %79[^\n]", platform) == 1) continue; | |
141 | } | |
142 | ||
143 | if(*model_id || *system_id) { /* at least one of those */ | |
144 | ct = new_mem(sizeof *ct); | |
145 | ct->architecture = arch_alpha; | |
146 | if(model_id) ct->model_name = new_str(model_id); | |
147 | if(system_id) ct->vend_name = new_str(system_id); | |
148 | if(strncmp(serial_number, "MILO", 4) == 0) | |
149 | hd_data->boot = boot_milo; | |
150 | else | |
151 | hd_data->boot = boot_aboot; | |
152 | ||
153 | ct->family = cpu_variation; | |
154 | ct->model = cpu_revision; | |
155 | ct->stepping = 0; | |
156 | ct->cache = 0; | |
157 | ct->clock = (hz + 500000) / 1000000; | |
158 | ||
159 | if(platform && strcmp(platform, "0")) { | |
160 | ct->platform = new_str(platform); | |
161 | } | |
162 | ||
163 | if(!cpus) cpus = 1; /* at least 1 machine had a "cpus: 0" entry... */ | |
164 | for(u = 0; u < cpus; u++) { | |
165 | hd = add_hd_entry(hd_data, __LINE__, 0); | |
166 | hd->base_class.id = bc_internal; | |
167 | hd->sub_class.id = sc_int_cpu; | |
168 | hd->slot = u; | |
169 | hd->detail = new_mem(sizeof *hd->detail); | |
170 | hd->detail->type = hd_detail_cpu; | |
171 | if(u) { | |
172 | hd->detail->cpu.data = ct1 = new_mem(sizeof *ct); | |
173 | *ct1 = *ct; | |
174 | ct1->model_name = new_str(ct1->model_name); | |
175 | ct1->vend_name = new_str(ct1->vend_name); | |
176 | ct1->platform = new_str(ct1->platform); | |
177 | } | |
178 | else { | |
179 | hd->detail->cpu.data = ct; | |
180 | } | |
181 | } | |
182 | ||
183 | } | |
184 | #endif /* __alpha__ */ | |
185 | ||
186 | ||
187 | #ifdef __sparc__ | |
188 | *cpu_id = *fpu_id = *promlib = *prom = *type = *mmu = 0; | |
189 | cpus = cpus_active = bogo = 0; | |
190 | ||
191 | for(sl = hd_data->cpu; sl; sl = sl->next) { | |
192 | if(sscanf(sl->str, "cpu : %79[^\n]", cpu_id) == 1); | |
193 | if(sscanf(sl->str, "fpu : %79[^\n]", fpu_id) == 1); | |
194 | if(sscanf(sl->str, "promlib : %79[^\n]", promlib) == 1); | |
195 | if(sscanf(sl->str, "prom : %79[^\n]", prom) == 1); | |
196 | if(sscanf(sl->str, "type : %79[^\n]", type) == 1); | |
197 | if(sscanf(sl->str, "ncpus probed : %u", &cpus) == 1); | |
198 | if(sscanf(sl->str, "ncpus active : %u", &cpus_active) == 1); | |
199 | if(sscanf(sl->str, "BogoMips : %u", &bogo) == 1); | |
200 | if(sscanf(sl->str, "MMU Type : %79[^\n]", mmu) == 1); | |
201 | } | |
202 | ||
203 | if(*cpu_id) { | |
204 | for(u = 0; u < cpus; u++) { | |
205 | ct = new_mem(sizeof *ct); | |
206 | ct->platform = new_str (type); | |
207 | if(strcmp (type, "sun4u") == 0) | |
208 | ct->architecture = arch_sparc64; | |
209 | else | |
210 | ct->architecture = arch_sparc; | |
211 | ||
212 | ct->model_name = new_str(cpu_id); | |
213 | hd_data->boot = boot_silo; | |
214 | ||
215 | hd = add_hd_entry(hd_data, __LINE__, 0); | |
216 | hd->base_class.id = bc_internal; | |
217 | hd->sub_class.id = sc_int_cpu; | |
218 | hd->slot = u; | |
219 | hd->detail = new_mem(sizeof *hd->detail); | |
220 | hd->detail->type = hd_detail_cpu; | |
221 | hd->detail->cpu.data = ct; | |
222 | } | |
223 | } | |
224 | #endif /* sparc */ | |
225 | ||
226 | ||
227 | #if defined(__i386__) || defined (__x86_64__) | |
228 | *model_id = *vendor_id = *features = 0; | |
229 | bogo = mhz = cache = family = model = stepping = 0; | |
230 | ||
231 | for(sl = hd_data->cpu; sl; sl = sl->next) { | |
232 | if(sscanf(sl->str, "model name : %79[^\n]", model_id) == 1); | |
233 | if(sscanf(sl->str, "vendor_id : %79[^\n]", vendor_id) == 1); | |
234 | if(sscanf(sl->str, "flags : %255[^\n]", features) == 1); | |
235 | if(sscanf(sl->str, "bogomips : %u", &bogo) == 1); | |
236 | if(sscanf(sl->str, "cpu MHz : %u", &mhz) == 1); | |
237 | if(sscanf(sl->str, "cache size : %u KB", &cache) == 1); | |
238 | ||
239 | if(sscanf(sl->str, "cpu family : %u", &family) == 1); | |
240 | if(sscanf(sl->str, "model : %u", &model) == 1); | |
241 | if(sscanf(sl->str, "stepping : %u", &stepping) == 1); | |
242 | ||
243 | if(strstr(sl->str, "processor") == sl->str || !sl->next) { /* EOF */ | |
244 | if(*model_id || *vendor_id) { /* at least one of those */ | |
245 | ct = new_mem(sizeof *ct); | |
246 | #ifdef __i386__ | |
247 | ct->architecture = arch_intel; | |
248 | #endif | |
249 | #ifdef __x86_64__ | |
250 | ct->architecture = arch_x86_64; | |
251 | #endif | |
252 | if(model_id) ct->model_name = new_str(model_id); | |
253 | if(vendor_id) ct->vend_name = new_str(vendor_id); | |
254 | ct->family = family; | |
255 | ct->model = model; | |
256 | ct->stepping = stepping; | |
257 | ct->cache = cache; | |
258 | hd_data->boot = boot_grub; | |
259 | ||
260 | /* round clock to typical values */ | |
261 | if(mhz >= 38 && mhz <= 42) | |
262 | mhz = 40; | |
263 | else if(mhz >= 88 && mhz <= 92) | |
264 | mhz = 90; | |
265 | else { | |
266 | unsigned u, v; | |
267 | ||
268 | u = (mhz + 2) % 100; | |
269 | v = (mhz + 2) / 100; | |
270 | if(u <= 4) | |
271 | u = 2; | |
272 | else if(u >= 25 && u <= 29) | |
273 | u = 25 + 2; | |
274 | else if(u >= 33 && u <= 37) | |
275 | u = 33 + 2; | |
276 | else if(u >= 50 && u <= 54) | |
277 | u = 50 + 2; | |
278 | else if(u >= 66 && u <= 70) | |
279 | u = 66 + 2; | |
280 | else if(u >= 75 && u <= 79) | |
281 | u = 75 + 2; | |
282 | else if(u >= 80 && u <= 84) /* there are 180MHz PPros */ | |
283 | u = 80 + 2; | |
284 | u -= 2; | |
285 | mhz = v * 100 + u; | |
286 | } | |
287 | ||
288 | ct->clock = mhz; | |
289 | ||
290 | hd = add_hd_entry(hd_data, __LINE__, 0); | |
291 | hd->base_class.id = bc_internal; | |
292 | hd->sub_class.id = sc_int_cpu; | |
293 | hd->slot = cpus; | |
294 | hd->detail = new_mem(sizeof *hd->detail); | |
295 | hd->detail->type = hd_detail_cpu; | |
296 | hd->detail->cpu.data = ct; | |
297 | ||
298 | if(*features) { | |
299 | for(t0 = features; (t = strsep(&t0, " ")); ) { | |
300 | add_str_list(&ct->features, t); | |
301 | if(!strcmp(t, "ht")) ct->units = units_per_cpu(); | |
302 | } | |
303 | } | |
304 | ||
305 | *model_id = *vendor_id = 0; | |
306 | bogo = mhz = cache = family = model= 0; | |
307 | cpus++; | |
308 | } | |
309 | } | |
310 | } | |
311 | #endif /* __i386__ || __x86_64__ */ | |
312 | ||
313 | ||
314 | #ifdef __PPC__ | |
315 | *model_id = *vendor_id = *motherboard = 0; | |
316 | bogo = mhz = cache = family = model = stepping = 0; | |
317 | ||
318 | for(sl = hd_data->cpu; sl; sl = sl->next) { | |
319 | if(sscanf(sl->str, "machine : %79[^\n]", vendor_id) == 1); | |
320 | } | |
321 | ||
322 | for(sl = hd_data->cpu; sl; sl = sl->next) { | |
323 | if(sscanf(sl->str, "cpu : %79[^\n]", model_id) == 1); | |
324 | if(sscanf(sl->str, "motherboard : %79[^\n]", motherboard) == 1); | |
325 | if(sscanf(sl->str, "bogomips : %u", &bogo) == 1); | |
326 | if(sscanf(sl->str, "clock : %u", &mhz) == 1); | |
327 | if(sscanf(sl->str, "L2 cache : %u KB", &cache) == 1); | |
328 | ||
329 | if(strstr(sl->str, "processor") == sl->str || !sl->next) { /* EOF */ | |
330 | if(*model_id) { /* at least one of those */ | |
331 | ct = new_mem(sizeof *ct); | |
332 | ct->architecture = arch_ppc; | |
333 | if(model_id) { | |
334 | ct->model_name = new_str(model_id); | |
335 | } | |
336 | ||
337 | if(!uname(&un)) | |
338 | if(strstr(un.machine,"ppc64")) | |
339 | ct->architecture = arch_ppc64; | |
340 | ||
341 | if(vendor_id) ct->vend_name = new_str(vendor_id); | |
342 | if(motherboard) ct->platform = new_str(motherboard); | |
343 | ct->family = family; | |
344 | ct->model = model; | |
345 | ct->stepping = stepping; | |
346 | ct->cache = cache; | |
347 | hd_data->boot = boot_ppc; | |
348 | ct->clock = mhz; | |
349 | ||
350 | hd = add_hd_entry(hd_data, __LINE__, 0); | |
351 | hd->base_class.id = bc_internal; | |
352 | hd->sub_class.id = sc_int_cpu; | |
353 | hd->slot = cpus; | |
354 | hd->detail = new_mem(sizeof *hd->detail); | |
355 | hd->detail->type = hd_detail_cpu; | |
356 | hd->detail->cpu.data = ct; | |
357 | ||
358 | if(ct->vend_name && !strcmp(ct->vend_name, "PowerBook") && !hd_data->color_code) { | |
359 | hd_data->color_code = 7; // black | |
360 | } | |
361 | ||
362 | *model_id = 0; | |
363 | bogo = mhz = cache = family = model= 0; | |
364 | cpus++; | |
365 | } | |
366 | } | |
367 | } | |
368 | #endif /* __PPC__ */ | |
369 | ||
370 | ||
371 | #ifdef __ia64__ | |
372 | *model_id = *vendor_id = *features = 0; | |
373 | mhz = stepping = 0; | |
374 | ||
375 | for(sl = hd_data->cpu; sl; sl = sl->next) { | |
376 | if(sscanf(sl->str, "family : %79[^\n]", model_id) == 1); | |
377 | if(sscanf(sl->str, "vendor : %79[^\n]", vendor_id) == 1); | |
378 | if(sscanf(sl->str, "features : %255[^\n]", features) == 1); | |
379 | if(sscanf(sl->str, "cpu MHz : %u", &mhz) == 1); | |
380 | if(sscanf(sl->str, "revision : %u", &stepping) == 1); | |
381 | ||
382 | if(strstr(sl->str, "processor") == sl->str || !sl->next) { /* EOF */ | |
383 | if(*model_id || *vendor_id) { /* at least one of those */ | |
384 | ct = new_mem(sizeof *ct); | |
385 | ct->architecture = arch_ia64; | |
386 | if(model_id) ct->model_name = new_str(model_id); | |
387 | if(vendor_id) ct->vend_name = new_str(vendor_id); | |
388 | ct->stepping = stepping; | |
389 | hd_data->boot = boot_elilo; | |
390 | ||
391 | /* round clock to typical values */ | |
392 | if(mhz >= 38 && mhz <= 42) | |
393 | mhz = 40; | |
394 | else if(mhz >= 88 && mhz <= 92) | |
395 | mhz = 90; | |
396 | else { | |
397 | unsigned u, v; | |
398 | ||
399 | u = (mhz + 2) % 100; | |
400 | v = (mhz + 2) / 100; | |
401 | if(u <= 4) | |
402 | u = 2; | |
403 | else if(u >= 25 && u <= 29) | |
404 | u = 25 + 2; | |
405 | else if(u >= 33 && u <= 37) | |
406 | u = 33 + 2; | |
407 | else if(u >= 50 && u <= 54) | |
408 | u = 50 + 2; | |
409 | else if(u >= 66 && u <= 70) | |
410 | u = 66 + 2; | |
411 | else if(u >= 75 && u <= 79) | |
412 | u = 75 + 2; | |
413 | else if(u >= 80 && u <= 84) /* there are 180MHz PPros */ | |
414 | u = 80 + 2; | |
415 | u -= 2; | |
416 | mhz = v * 100 + u; | |
417 | } | |
418 | ||
419 | ct->clock = mhz; | |
420 | ||
421 | hd = add_hd_entry(hd_data, __LINE__, 0); | |
422 | hd->base_class.id = bc_internal; | |
423 | hd->sub_class.id = sc_int_cpu; | |
424 | hd->slot = cpus; | |
425 | hd->detail = new_mem(sizeof *hd->detail); | |
426 | hd->detail->type = hd_detail_cpu; | |
427 | hd->detail->cpu.data = ct; | |
428 | ||
429 | if(*features) { | |
430 | for(t0 = features; (t = strsep(&t0, " ")); ) { | |
431 | add_str_list(&ct->features, t); | |
432 | } | |
433 | } | |
434 | ||
435 | *model_id = *vendor_id = 0; | |
436 | mhz = 0; | |
437 | cpus++; | |
438 | } | |
439 | } | |
440 | } | |
441 | ||
442 | #endif /* __ia64__ */ | |
443 | ||
444 | ||
445 | #if defined(__s390__) || defined(__s390x__) | |
446 | *vendor_id = 0; | |
447 | bogo = 0; | |
448 | ||
449 | for(sl = hd_data->cpu; sl; sl = sl->next) { | |
450 | if(sscanf(sl->str, "vendor_id : %79[^\n]", vendor_id) == 1); | |
451 | if(sscanf(sl->str, "bogomips per cpu : %u", &bogo) == 1); | |
452 | } | |
453 | ||
454 | for(sl = hd_data->cpu; sl; sl = sl->next) { | |
455 | if( | |
456 | sscanf(sl->str, "processor %u : version = %x , identification = %x , machine = %x", &u0, &u1, &u2, &u3) == 4 | |
457 | ) { | |
458 | ct = new_mem(sizeof *ct); | |
459 | #ifdef __s390x__ | |
460 | ct->architecture = arch_s390x; | |
461 | #else | |
462 | ct->architecture = arch_s390; | |
463 | #endif | |
464 | if(vendor_id) ct->vend_name = new_str(vendor_id); | |
465 | ct->stepping = u1; | |
466 | hd_data->boot = boot_s390; | |
467 | ||
468 | hd = add_hd_entry(hd_data, __LINE__, 0); | |
469 | hd->base_class.id = bc_internal; | |
470 | hd->sub_class.id = sc_int_cpu; | |
471 | hd->slot = cpus; | |
472 | hd->detail = new_mem(sizeof *hd->detail); | |
473 | hd->detail->type = hd_detail_cpu; | |
474 | hd->detail->cpu.data = ct; | |
475 | ||
476 | bogo = 0; | |
477 | cpus++; | |
478 | } | |
479 | } | |
480 | #endif /* defined(__s390__) || defined(__s390x__) */ | |
481 | } | |
482 | ||
483 | /* | |
484 | * Add some cpu data to the global log. | |
485 | */ | |
486 | void dump_cpu_data(hd_data_t *hd_data) | |
487 | { | |
488 | str_list_t *sl; | |
489 | ||
490 | ADD2LOG("----- /proc/cpuinfo -----\n"); | |
491 | for(sl = hd_data->cpu; sl; sl = sl->next) { | |
492 | ADD2LOG(" %s", sl->str); | |
493 | } | |
494 | ADD2LOG("----- /proc/cpuinfo end -----\n"); | |
495 | } | |
496 | ||
497 | ||
498 | #if defined(__i386__) || defined(__x86_64__) | |
499 | inline unsigned units_per_cpu() | |
500 | { | |
501 | unsigned u; | |
502 | ||
503 | asm( | |
504 | #ifdef __i386__ | |
505 | "push %%ebx\n\t" | |
506 | #else | |
507 | "push %%rbx\n\t" | |
508 | #endif | |
509 | "mov $1,%%eax\n\t" | |
510 | "cpuid\n\t" | |
511 | "shr $8,%%ebx\n\t" | |
512 | "movzx %%bh,%%eax\n\t" | |
513 | #ifdef __i386__ | |
514 | "pop %%ebx" | |
515 | #else | |
516 | "pop %%rbx" | |
517 | #endif | |
518 | : "=a" (u) | |
519 | :: "%ecx", "%edx" | |
520 | ); | |
521 | ||
522 | return u; | |
523 | } | |
524 | #endif | |
525 | ||
526 | ||
527 | #ifdef __ia64__ | |
528 | ||
529 | /* | |
530 | * IA64 SMP detection code | |
531 | */ | |
532 | ||
533 | #define PAGE_OFFSET(addr) ((uintptr_t) (addr) & (getpagesize () - 1)) | |
534 | ||
535 | typedef struct | |
536 | { | |
537 | uint8_t type; | |
538 | uint8_t length; | |
539 | } __attribute__ ((packed)) acpi_table_entry_header; | |
540 | ||
541 | struct acpi20_table_rsdp | |
542 | { | |
543 | char signature[8]; | |
544 | uint8_t checksum; | |
545 | char oem_id[6]; | |
546 | uint8_t revision; | |
547 | uint32_t rsdt_address; | |
548 | uint32_t length; | |
549 | unsigned long xsdt_address; | |
550 | uint8_t ext_checksum; | |
551 | uint8_t reserved[3]; | |
552 | } __attribute__ ((packed)); | |
553 | ||
554 | struct acpi_table_header | |
555 | { | |
556 | char signature[4]; | |
557 | uint32_t length; | |
558 | uint8_t revision; | |
559 | uint8_t checksum; | |
560 | char oem_id[6]; | |
561 | char oem_table_id[8]; | |
562 | uint32_t oem_revision; | |
563 | char asl_compiler_id[4]; | |
564 | uint32_t asl_compiler_revision; | |
565 | }; | |
566 | ||
567 | #define ACPI_XSDT_SIG "XSDT" | |
568 | struct acpi_table_xsdt | |
569 | { | |
570 | struct acpi_table_header header; | |
571 | unsigned long entry[0]; | |
572 | } __attribute__ ((packed)); | |
573 | ||
574 | #define ACPI_MADT_SIG "ACPI" | |
575 | struct acpi_table_madt | |
576 | { | |
577 | struct acpi_table_header header; | |
578 | uint32_t lapic_address; | |
579 | struct | |
580 | { | |
581 | uint32_t pcat_compat:1; | |
582 | uint32_t reserved:31; | |
583 | } flags; | |
584 | } __attribute__ ((packed)); | |
585 | ||
586 | #define ACPI_MADT_LSAPIC 7 | |
587 | ||
588 | struct acpi_table_lsapic | |
589 | { | |
590 | acpi_table_entry_header header; | |
591 | uint8_t acpi_id; | |
592 | uint8_t id; | |
593 | uint8_t eid; | |
594 | uint8_t reserved[3]; | |
595 | struct | |
596 | { | |
597 | uint32_t enabled:1; | |
598 | uint32_t reserved:31; | |
599 | } flags; | |
600 | } __attribute__ ((packed)); | |
601 | ||
602 | /* | |
603 | * Map an ACPI table into virtual memory | |
604 | */ | |
605 | static struct acpi_table_header * | |
606 | acpi_map_table (int mem, unsigned long addr, char *signature) | |
607 | { | |
608 | /* mmap header to determine table size */ | |
609 | struct acpi_table_header *table = NULL; | |
610 | unsigned long offset = PAGE_OFFSET (addr); | |
611 | uint8_t *mapped = mmap (NULL, | |
612 | sizeof (struct acpi_table_header) + offset, | |
613 | PROT_READ, | |
614 | MAP_PRIVATE, | |
615 | mem, | |
616 | (unsigned long) addr - offset); | |
617 | table = (struct acpi_table_header *) (mapped != MAP_FAILED | |
618 | ? mapped + offset | |
619 | : NULL); | |
620 | if (table) | |
621 | { | |
622 | if (memcmp (table->signature, signature, sizeof (table->signature))) | |
623 | { | |
624 | munmap ((char *) table - offset, | |
625 | sizeof (struct acpi_table_header) + offset); | |
626 | return NULL; | |
627 | } | |
628 | { | |
629 | /* re-mmap entire table */ | |
630 | unsigned long size = table->length; | |
631 | munmap ((uint8_t *) table - offset, | |
632 | sizeof (struct acpi_table_header) + offset); | |
633 | mapped = mmap (NULL, size + offset, PROT_READ, MAP_PRIVATE, mem, | |
634 | (unsigned long) addr - offset); | |
635 | table = (struct acpi_table_header *) (mapped != MAP_FAILED | |
636 | ? mapped + offset | |
637 | : NULL); | |
638 | } | |
639 | } | |
640 | return table; | |
641 | } | |
642 | ||
643 | /* | |
644 | * Unmap an ACPI table from virtual memory | |
645 | */ | |
646 | static void | |
647 | acpi_unmap_table (struct acpi_table_header * table) | |
648 | { | |
649 | if (table) | |
650 | { | |
651 | unsigned long offset = PAGE_OFFSET (table); | |
652 | munmap ((uint8_t *) table - offset, table->length + offset); | |
653 | } | |
654 | } | |
655 | ||
656 | int | |
657 | acpi_parse_lsapic (acpi_table_entry_header *p) | |
658 | { | |
659 | struct acpi_table_lsapic *lsapic = (struct acpi_table_lsapic *) p; | |
660 | ||
661 | return lsapic->flags.enabled; | |
662 | } | |
663 | ||
664 | static int | |
665 | acpi_parse_madt (struct acpi_table_madt *madt) | |
666 | { | |
667 | acpi_table_entry_header *p, *end; | |
668 | int n_cpu = 0; | |
669 | ||
670 | p = (acpi_table_entry_header *) (madt + 1); | |
671 | end = (acpi_table_entry_header *) ((char *) madt + madt->header.length); | |
672 | ||
673 | while (p < end) | |
674 | { | |
675 | if (p->type == ACPI_MADT_LSAPIC) | |
676 | n_cpu += acpi_parse_lsapic (p); | |
677 | ||
678 | p = (acpi_table_entry_header *) ((char *) p + p->length); | |
679 | } | |
680 | ||
681 | return n_cpu; | |
682 | } | |
683 | ||
684 | static int | |
685 | acpi_parse_rsdp (int mem_fd, struct acpi20_table_rsdp *rsdp) | |
686 | { | |
687 | int n_cpu = 0; | |
688 | int i; | |
689 | struct acpi_table_xsdt *xsdt = 0; | |
690 | int tables; | |
691 | ||
692 | if (rsdp->xsdt_address) | |
693 | xsdt = (struct acpi_table_xsdt *) acpi_map_table (mem_fd, rsdp->xsdt_address, | |
694 | ACPI_XSDT_SIG); | |
695 | if (xsdt) | |
696 | { | |
697 | tables = (xsdt->header.length - sizeof (struct acpi_table_header)) / 8; | |
698 | for (i = 0; i < tables; i++) | |
699 | { | |
700 | struct acpi_table_header *dt | |
701 | = acpi_map_table (mem_fd, xsdt->entry[i], ACPI_MADT_SIG); | |
702 | if (dt) | |
703 | n_cpu += acpi_parse_madt ((struct acpi_table_madt *) dt); | |
704 | acpi_unmap_table (dt); | |
705 | } | |
706 | acpi_unmap_table ((struct acpi_table_header *) xsdt); | |
707 | } | |
708 | return n_cpu; | |
709 | } | |
710 | ||
711 | int ia64DetectSMP(hd_data_t *hd_data) | |
712 | { | |
713 | int n_cpu = 0, mem_fd, systab_fd; | |
714 | struct acpi20_table_rsdp rsdp; | |
715 | uint8_t *mapped; | |
716 | unsigned long addr = 0, offset; | |
717 | int ok = 0; | |
718 | str_list_t *sl; | |
719 | const char *rsd_klog = "ACPI 2.0="; | |
720 | const char *rsd_systab = "ACPI20="; | |
721 | char *s; | |
722 | ||
723 | mem_fd = open("/dev/mem", O_RDONLY); | |
724 | if(mem_fd == -1) return -1; | |
725 | ||
726 | systab_fd = open("/proc/efi/systab", O_RDONLY); | |
727 | if (systab_fd != -1) | |
728 | { | |
729 | char buffer[512]; | |
730 | int n_read = read(systab_fd, buffer, sizeof(buffer) - 1); | |
731 | close(systab_fd); | |
732 | if (n_read > 0) | |
733 | { | |
734 | buffer[n_read] = 0; | |
735 | if ((s = strstr(buffer, rsd_systab)) != NULL && | |
736 | sscanf(s + strlen(rsd_systab), "%lx", &addr) == 1) | |
737 | goto found_it; | |
738 | } | |
739 | } | |
740 | ||
741 | if(!hd_data->klog) read_klog(hd_data); | |
742 | ||
743 | for(sl = hd_data->klog; sl; sl = sl->next) { | |
744 | if((s = strstr(sl->str, rsd_klog))) { | |
745 | if(sscanf(s + strlen(rsd_klog), "%lx", &addr) == 1) { | |
746 | found_it: | |
747 | offset= PAGE_OFFSET (addr); | |
748 | mapped = mmap(NULL, sizeof rsdp + offset, PROT_READ, MAP_PRIVATE, | |
749 | mem_fd, (unsigned long) addr - offset); | |
750 | if(mapped != MAP_FAILED) { | |
751 | ADD2LOG("seek to 0x%lx\n", addr); | |
752 | memcpy(&rsdp, mapped + offset, sizeof rsdp); | |
753 | munmap(mapped, sizeof rsdp + offset); | |
754 | ok = 1; | |
755 | } | |
756 | break; | |
757 | } | |
758 | } | |
759 | } | |
760 | ||
761 | if(ok) { | |
762 | n_cpu = acpi_parse_rsdp(mem_fd, &rsdp); | |
763 | if(n_cpu) { | |
764 | ADD2LOG("RSDP found at 0x%lx\n", addr); | |
765 | } | |
766 | } | |
767 | ||
768 | close (mem_fd); | |
769 | ||
770 | ADD2LOG("n_cpu = %d\n", n_cpu); | |
771 | ||
772 | return n_cpu; | |
773 | } | |
774 | ||
775 | ||
776 | #endif /* __ia64__ */ | |
777 |