9
#if defined(__i386__) || defined (__x86_64__) || defined(__ia64__)
21
* @defgroup BIOSint BIOS information
22
* @ingroup libhdINFOint
23
* @brief BIOS information scan
28
#if defined(__i386__) || defined (__x86_64__) || defined (__ia64__)
30
#include "ibm-notebooks.h"
31
static int tp_lookup(char *key, unsigned *width, unsigned *height, unsigned *xsize, unsigned *ysize);
34
unsigned short xsize; /* mm */
35
unsigned short ysize; /* mm */
37
unsigned short height;
41
} __attribute((packed)) panel_data[] = {
42
{ 0, 0, 1400, 1050, "IBM", "73geu99", NULL },
43
{ 0, 0, 800, 600, "Fujitsu Siemens", "LiteLine", "LF6" },
44
{ 0, 0, 1024, 768, "ASUSTEK", "L2000D", NULL },
45
{ 0, 0, 1024, 768, "ASUSTeK Computer Inc.", "L8400C series Notebook PC", NULL },
46
{ 0, 0, 1024, 768, "ASUSTeK Computer Inc.", "S5N", NULL },
47
{ 0, 0, 1024, 768, "Acer", "TravelMate 720", NULL },
48
{ 0, 0, 1024, 768, "COMPAL", "N30T5", NULL },
49
{ 0, 0, 1024, 768, "Dell Computer Corporation", "Inspiron 5000", NULL },
50
{ 0, 0, 1024, 768, "Dell Computer Corporation", "Latitude C400", NULL },
51
{ 0, 0, 1024, 768, "Dell Computer Corporation", "Latitude C600", NULL },
52
{ 0, 0, 1024, 768, "Dell Computer Corporation", "Latitude CPt C400GT", NULL },
53
{ 0, 0, 1024, 768, "Dell Computer Corporation", "Latitude CPx J650GT", NULL },
54
{ 0, 0, 1024, 768, "Hewlett-Packard", "HP OmniBook PC", "HP OmniBook 4150 B" },
55
{ 0, 0, 1280, 800, "Hewlett-Packard", "hp compaq nx9105 (DU367T#ABD)", "03" },
56
{ 330, 210, 1280, 800, "Hewlett-Packard", "hp compaq nx9105 (DU367T#ABD)", "F.21" },
57
{ 0, 0, 1280, 800, "Hewlett-Packard", "Pavilion zv5000 (PA456EA#ABD)", "F.11" },
58
{ 0, 0, 1024, 768, "KDST", "KDS6KSUMO", NULL },
59
{ 0, 0, 1024, 768, "Sony Corporation", "PCG-F370(UC)", NULL },
60
{ 0, 0, 1024, 768, "Sony Corporation", "PCG-N505SN", NULL },
61
{ 0, 0, 1024, 768, "TOSHIBA", "S2400-103", NULL },
62
{ 0, 0, 1280, 800, "Acer", "Aspire 1520", NULL },
63
{ 0, 0, 1440, 900, "FUJITSU SIEMENS", "Amilo M3438 Series", NULL },
64
{ 0, 0, 1400, 1050, "Acer", "TravelMate 660", NULL },
65
{ 0, 0, 1400, 1050, "Dell Computer Corporation", "Inspiron 8000", NULL },
66
{ 286, 214, 1400, 1050, "Dell Computer Corporation", "Latitude D600", NULL },
67
{ 0, 0, 1400, 1050, "TOSHIBA", "TECRA 9100", NULL },
68
{ 0, 0, 1600, 1200, "Dell Computer Corporation", "Inspiron 8200", NULL },
69
{ 0, 0, 1600, 1200, "Dell Computer Corporation", "Latitude C840", NULL },
70
{ 190, 110, 1024, 600, "FUJITSU SIEMENS", "LIFEBOOK P1510", NULL },
71
{ 285, 215, 1024, 768, "FUJITSU SIEMENS", "LIFEBOOK S7020", NULL },
72
{ 305, 230, 1400, 1050, "Samsung Electronics", "SX20S", "Revision PR" },
73
{ 290, 200, 1280, 800, "TOSHIBA", "Satellite M30X", "PSA72E-00J020GR" },
74
{ 305, 230, 1400, 1050, "ASUSTeK Computer Inc.", "M6V", "1.0" },
75
{ 246, 185, 1024, 768, "FUJITSU SIEMENS", "LifeBook T Series", NULL },
76
{ 304, 190, 1400, 1050, "Hewlett-Packard", "HP Compaq nc6000 (PN887PA#ABG)", "F.0F" },
77
{ 332, 208, 1280, 800, "MICRO-STAR INT'L CO.,LTD.", "MS-1011", "0101" },
83
unsigned eax, ebx, ecx, edx, esi, edi, eip, es, iret, cli;
86
static void read_memory(hd_data_t *hd_data, memory_range_t *mem);
87
static void dump_memory(hd_data_t *hd_data, memory_range_t *mem, int sparse, char *label);
88
static void get_pnp_support_status(memory_range_t *mem, bios_info_t *bt);
89
static void smbios_get_info(hd_data_t *hd_data, memory_range_t *mem, bios_info_t *bt);
90
static void get_fsc_info(hd_data_t *hd_data, memory_range_t *mem, bios_info_t *bt);
92
static void add_panel_info(hd_data_t *hd_data, bios_info_t *bt);
94
static void add_mouse_info(hd_data_t *hd_data, bios_info_t *bt);
95
static unsigned char crc(unsigned char *mem, unsigned len);
96
static int get_smp_info(hd_data_t *hd_data, memory_range_t *mem, smp_info_t *smp);
97
static void parse_mpconfig(hd_data_t *hd_data, memory_range_t *mem, smp_info_t *smp);
98
static int get_bios32_info(hd_data_t *hd_data, memory_range_t *mem, bios32_info_t *bios32);
100
int detect_smp_bios(hd_data_t *hd_data)
107
if(!hd_data->bios_ram.data) return -1; /* hd_scan_bios() not called */
109
for(bt = NULL, hd = hd_data->hd; hd; hd = hd->next) {
111
hd->base_class.id == bc_internal &&
112
hd->sub_class.id == sc_int_bios &&
114
hd->detail->type == hd_detail_bios &&
115
(bt = hd->detail->bios.data)
125
/* look at smbios data in case there's no mp table */
126
if(hd_data->smbios) {
127
for(sm = hd_data->smbios; sm; sm = sm->next) {
129
sm->any.type == sm_processor &&
130
sm->processor.pr_type.id == 3 && /* cpu */
131
sm->processor.cpu_status.id == 1 /* enabled */
136
ADD2LOG(" smp detect: mp %d cpus, smbios %d cpus\n", bt->smp.ok ? bt->smp.cpus_en : 0, cpus);
139
if(bt->smp.ok && bt->smp.cpus_en) cpus = bt->smp.cpus_en;
145
void hd_scan_bios(hd_data_t *hd_data)
150
unsigned char *bios_ram;
161
if(!hd_probe_feature(hd_data, pr_bios)) return;
163
/* we better do nothing on a SGI Altix machine */
164
if(hd_is_sgi_altix(hd_data)) return;
166
hd_data->module = mod_bios;
169
remove_hd_entries(hd_data);
171
PROGRESS(1, 0, "cmdline");
173
hd = add_hd_entry(hd_data, __LINE__, 0);
174
hd->base_class.id = bc_internal;
175
hd->sub_class.id = sc_int_bios;
176
hd->detail = new_mem(sizeof *hd->detail);
177
hd->detail->type = hd_detail_bios;
178
hd->detail->bios.data = bt = new_mem(sizeof *bt);
181
* first, look for APM support
183
if((s = get_cmd_param(hd_data, 1))) {
184
if(strlen(s) >= 10) {
185
bt->apm_supported = 1;
186
bt->apm_ver = hex(s, 1);
187
bt->apm_subver = hex(s + 1, 1);
188
bt->apm_bios_flags = hex(s + 2, 2);
190
* Bitfields for APM flags (from Ralf Brown's list):
192
* 0 16-bit protected mode interface supported
193
* 1 32-bit protected mode interface supported
194
* 2 CPU idle call reduces processor speed
195
* 3 BIOS power management disabled
196
* 4 BIOS power management disengaged (APM v1.1)
199
bt->apm_enabled = (bt->apm_bios_flags & 8) ? 0 : 1;
201
bt->vbe_ver = hex(s + 4, 2);
202
bt->vbe_ver = (((bt->vbe_ver >> 4) & 0xf) << 8) + (bt->vbe_ver & 0xf);
203
bt->vbe_video_mem = hex(s + 6, 4) << 16;
209
if((s = get_cmd_param(hd_data, 2))) {
211
if(s[8] == '.') bt->lba_support = 1;
217
PROGRESS(1, 1, "apm");
220
str_list_t *sl0, *sl;
222
sl0 = read_file(PROC_APM, 0, 0);
224
bt->apm_supported = 1;
226
ADD2LOG("----- %s -----\n", PROC_APM);
227
for(sl = sl0; sl; sl = sl->next) {
228
ADD2LOG(" %s", sl->str);
230
ADD2LOG("----- %s end -----\n", PROC_APM);
236
* get the i/o ports for the parallel & serial interfaces from the BIOS
237
* memory area starting at 0x40:0
239
PROGRESS(2, 0, "ram");
241
hd_data->bios_ram.start = BIOS_RAM_START;
242
hd_data->bios_ram.size = BIOS_RAM_SIZE;
243
read_memory(hd_data, &hd_data->bios_ram);
245
hd_data->bios_rom.start = BIOS_ROM_START;
246
hd_data->bios_rom.size = BIOS_ROM_SIZE;
247
read_memory(hd_data, &hd_data->bios_rom);
249
if(hd_data->bios_ram.data) {
250
bios_ram = hd_data->bios_ram.data;
252
bt->ser_port0 = (bios_ram[1] << 8) + bios_ram[0];
253
bt->ser_port1 = (bios_ram[3] << 8) + bios_ram[2];
254
bt->ser_port2 = (bios_ram[5] << 8) + bios_ram[4];
255
bt->ser_port3 = (bios_ram[7] << 8) + bios_ram[6];
257
bt->par_port0 = (bios_ram[ 9] << 8) + bios_ram[ 8];
258
bt->par_port1 = (bios_ram[0xb] << 8) + bios_ram[0xa];
259
bt->par_port2 = (bios_ram[0xd] << 8) + bios_ram[0xc];
261
bt->led.scroll_lock = bios_ram[0x97] & 1;
262
bt->led.num_lock = (bios_ram[0x97] >> 1) & 1;
263
bt->led.caps_lock = (bios_ram[0x97] >> 2) & 1;
267
* do some consistency checks:
269
* ports must be < 0x1000 and not appear twice
271
if(bt->ser_port0 >= 0x1000) bt->ser_port0 = 0;
274
bt->ser_port1 >= 0x1000 ||
275
bt->ser_port1 == bt->ser_port0
279
bt->ser_port2 >= 0x1000 ||
280
bt->ser_port2 == bt->ser_port0 ||
281
bt->ser_port2 == bt->ser_port1
285
bt->ser_port3 >= 0x1000 ||
286
bt->ser_port3 == bt->ser_port0 ||
287
bt->ser_port3 == bt->ser_port1 ||
288
bt->ser_port3 == bt->ser_port2
291
if(bt->par_port0 >= 0x1000) bt->par_port0 = 0;
294
bt->par_port1 >= 0x1000 ||
295
bt->par_port1 == bt->par_port0
299
bt->par_port2 >= 0x1000 ||
300
bt->par_port2 == bt->par_port0 ||
301
bt->par_port2 == bt->par_port1
304
ADD2LOG(" bios: %u disks\n", bios_ram[0x75]);
306
bt->low_mem_size = ((bios_ram[0x14] << 8) + bios_ram[0x13]) << 10;
308
if(bt->low_mem_size) {
309
ADD2LOG(" bios: %uk low mem\n", bt->low_mem_size >> 10);
313
if(bt->low_mem_size >= (768 << 10) || bt->low_mem_size < (384 << 10)) {
314
bt->low_mem_size = 0;
317
hd_data->bios_ebda.start = hd_data->bios_ebda.size = 0;
318
hd_data->bios_ebda.data = free_mem(hd_data->bios_ebda.data);
319
u = ((bios_ram[0x0f] << 8) + bios_ram[0x0e]) << 4;
321
hd_data->bios_ebda.start = u;
322
hd_data->bios_ebda.size = 1; /* just one byte */
323
read_memory(hd_data, &hd_data->bios_ebda);
324
if(hd_data->bios_ebda.data) {
325
u1 = hd_data->bios_ebda.data[0];
326
if(u1 > 0 && u1 <= 64) { /* be sensible, typically only 1k */
328
if(u + u1 <= (1 << 20)) {
329
hd_data->bios_ebda.size = u1;
330
read_memory(hd_data, &hd_data->bios_ebda);
336
if(hd_data->bios_ebda.data) {
338
" bios: EBDA 0x%05x bytes at 0x%05x\n",
339
hd_data->bios_ebda.size, hd_data->bios_ebda.start
345
* read the bios rom and look for useful things there...
347
PROGRESS(2, 0, "rom");
349
if(hd_data->bios_rom.data) {
350
get_pnp_support_status(&hd_data->bios_rom, bt);
351
smbios_get_info(hd_data, &hd_data->bios_rom, bt);
352
get_fsc_info(hd_data, &hd_data->bios_rom, bt);
354
add_panel_info(hd_data, bt);
356
add_mouse_info(hd_data, bt);
359
PROGRESS(3, 0, "smp");
363
mem = hd_data->bios_ebda;
364
smp_ok = get_smp_info(hd_data, &mem, &bt->smp);
367
mem = hd_data->bios_rom;
369
mem.size -= 0xf0000 - mem.start;
370
mem.data += 0xf0000 - mem.start;
372
if(mem.size < (1 << 20)) smp_ok = get_smp_info(hd_data, &mem, &bt->smp);
378
mem.start = 639 << 10;
380
read_memory(hd_data, &mem);
381
if(mem.data) smp_ok = get_smp_info(hd_data, &mem, &bt->smp);
382
mem.data = free_mem(mem.data);
385
if(bt->smp.ok && bt->smp.mpconfig) {
386
mem.start = bt->smp.mpconfig;
389
read_memory(hd_data, &mem);
390
parse_mpconfig(hd_data, &mem, &bt->smp);
391
mem.data = free_mem(mem.data);
394
if((hd_data->debug & HD_DEB_BIOS)) {
395
dump_memory(hd_data, &hd_data->bios_ram, 0, "BIOS data");
396
dump_memory(hd_data, &hd_data->bios_ebda, hd_data->bios_ebda.size <= (8 << 10) ? 0 : 1, "EBDA");
397
// dump_memory(hd_data, &hd_data->bios_rom, 1, "BIOS ROM");
399
if(bt->smp.ok && bt->smp.mpfp) {
400
mem.start = bt->smp.mpfp;
403
read_memory(hd_data, &mem);
404
dump_memory(hd_data, &mem, 0, "MP FP");
405
mem.data = free_mem(mem.data);
408
if(bt->smp.ok && bt->smp.mpconfig && bt->smp.mpconfig_size) {
409
mem.start = bt->smp.mpconfig;
410
mem.size = bt->smp.mpconfig_size;
412
read_memory(hd_data, &mem);
413
dump_memory(hd_data, &mem, 0, "MP config table");
414
mem.data = free_mem(mem.data);
419
if(hd_probe_feature(hd_data, pr_bios_vesa)) {
420
PROGRESS(4, 0, "vbe");
425
if(!hd_data->klog) read_klog(hd_data);
426
for(sl = hd_data->klog; sl; sl = sl->next) {
427
if(sscanf(sl->str, "<6>PCI: Using configuration type %u", &u) == 1) {
428
hd_data->pci_config_type = u;
429
ADD2LOG(" klog: pci config type %u\n", hd_data->pci_config_type);
433
get_vbe_info(hd_data, vbe);
436
bt->vbe_ver = vbe->version;
439
if(vbe->ok && vbe->fb_start) {
440
hd = add_hd_entry(hd_data, __LINE__, 0);
441
hd->base_class.id = bc_framebuffer;
442
hd->sub_class.id = sc_fb_vesa;
444
hd_set_hw_class(hd, hw_vbe);
447
hd->detail = new_mem(sizeof *hd->detail);
448
hd->detail->type = hd_detail_bios;
449
hd->detail->bios.data = bt = new_mem(sizeof *bt);
452
hd->vendor.name = new_str(vbe->vendor_name);
453
hd->device.name = new_str(vbe->product_name);
454
hd->sub_vendor.name = new_str(vbe->oem_name);
455
hd->revision.name = new_str(vbe->product_revision);
457
res = add_res_entry(&hd->res, new_mem(sizeof *res));
458
res->phys_mem.type = res_phys_mem;
459
res->phys_mem.range = vbe->memory;
461
res = add_res_entry(&hd->res, new_mem(sizeof *res));
462
res->mem.type = res_mem;
463
res->mem.base = vbe->fb_start;
464
res->mem.range = vbe->memory;
465
res->mem.access = acc_rw;
466
res->mem.enabled = 1;
469
for(u = 0; u < vbe->modes; u++) {
472
(mi->attributes & 1) && /* mode supported */
474
mi->pixel_size != -1u /* text mode */
476
res = add_res_entry(&hd->res, new_mem(sizeof *res));
477
res->framebuffer.type = res_framebuffer;
478
res->framebuffer.width = mi->width;
479
res->framebuffer.bytes_p_line = mi->bytes_p_line;
480
res->framebuffer.height = mi->height;
481
res->framebuffer.colorbits = mi->pixel_size;
482
res->framebuffer.mode = mi->number + 0x200;
490
!strcmp(hd->vend_name, "Matrox") &&
493
strstr(hd->dev_name, "G200") ||
494
strstr(hd->dev_name, "G400") ||
495
strstr(hd->dev_name, "G450")
504
#endif /* LIBHD_TINY */
506
PROGRESS(5, 0, "32");
508
mem = hd_data->bios_rom;
510
mem.size -= 0xe0000 - mem.start;
511
mem.data += 0xe0000 - mem.start;
513
if(mem.size < (1 << 20)) get_bios32_info(hd_data, &mem, &bt->bios32);
517
mem = hd_data->bios_rom;
520
mem.start <= 0xfffea &&
521
mem.start + mem.size >= 0xfffea + 6 &&
522
!memcmp(mem.data + 0xfffea - mem.start, "COMPAQ", 6)
524
bt->bios32.compaq = 1;
525
ADD2LOG(" bios32: compaq machine\n");
532
void read_memory(hd_data_t *hd_data, memory_range_t *mem)
535
char *s = getenv("LIBHD_MEM");
538
#ifdef LIBHD_MEMCHECK
540
if(libhd_log) fprintf(libhd_log, ">%p\n", CALLED_FROM(read_memory, mem));
544
if(mem->data) free_mem(mem->data);
545
mem->data = new_mem(mem->size);
547
hd_read_mmap(hd_data, s ?: DEV_MEM, mem->data, mem->start, mem->size);
549
hd_read_mmap(hd_data, DEV_MEM, mem->data, mem->start, mem->size);
552
#ifdef LIBHD_MEMCHECK
554
if(libhd_log) fprintf(libhd_log, "<%p\n", CALLED_FROM(read_memory, mem));
560
void dump_memory(hd_data_t *hd_data, memory_range_t *mem, int sparse, char *label)
564
if(!mem->size || !mem->data) return;
567
step = sparse ? 0x1000 : 0x10;
572
ADD2LOG("----- %s 0x%05x - 0x%05x -----\n", label, mem->start, mem->start + mem->size - 1);
573
for(u = 0; u < mem->size; u += step) {
574
ADD2LOG(" %03x ", u + mem->start);
575
hexdump(&hd_data->log, 1, mem->size - u > 0x10 ? 0x10 : mem->size - u, mem->data + u);
578
ADD2LOG("----- %s end -----\n", label);
582
void get_pnp_support_status(memory_range_t *mem, bios_info_t *bt)
585
unsigned char pnp[4] = { '$', 'P', 'n', 'P' };
589
if(!mem->data) return;
591
for(i = 0xf0000 - mem->start; (unsigned) i < mem->size; i += 0x10) {
593
if(t[0] == pnp[0] && t[1] == pnp[1] && t[2] == pnp[2] && t[3] == pnp[3]) {
594
for(l = cs = 0; l < t[5]; l++) { cs += t[l]; }
595
if((cs & 0xff) == 0) { // checksum ok
597
// printf("0x%x bytes at 0x%x, cs = 0x%x\n", t[5], i, cs);
598
bt->pnp_id = t[0x17] + (t[0x18] << 8) + (t[0x19] << 16) + (t[0x20] << 24);
604
unsigned char crc(unsigned char *mem, unsigned len)
606
unsigned char uc = 0;
608
while(len--) uc += *mem++;
614
void smbios_get_info(hd_data_t *hd_data, memory_range_t *mem, bios_info_t *bt)
616
unsigned u, u1, u2, ok, hlen = 0, ofs;
617
unsigned addr = 0, len = 0, scnt;
618
unsigned structs = 0, type, slen;
620
memory_range_t memory;
623
if(!mem->data || mem->size < 0x10) return;
625
for(u = ok = 0; u <= mem->size - 0x10; u += 0x10) {
626
if(*(unsigned *) (mem->data + u) == 0x5f4d535f) { /* "_SM_" */
627
hlen = mem->data[u + 5];
628
if(hlen < 0x1e || u + hlen > mem->size) continue;
629
addr = *(unsigned *) (mem->data + u + 0x18);
630
len = *(unsigned short *) (mem->data + u + 0x16);
631
structs = *(unsigned short *) (mem->data + u + 0x1c);
632
ok = crc(mem->data + u, hlen) == 0 && len;
634
bt->smbios_ver = (mem->data[u + 6] << 8) + mem->data[u + 7];
638
/* Also look for legacy DMI entry point */
639
if(memcmp(mem->data + u, "_DMI_", 5) == 0) {
641
addr = *(unsigned *) (mem->data + u + 0x08);
642
len = *(unsigned short *) (mem->data + u + 0x06);
643
structs = *(unsigned short *) (mem->data + u + 0x0c);
644
ok = crc(mem->data + u, hlen) == 0 && len;
646
bt->smbios_ver = ((mem->data[u + 0x0e] & 0xf0) << 4) + (mem->data[u + 0x0e] & 0x0f);
654
hd_data->smbios = smbios_free(hd_data->smbios);
656
memory.start = mem->start + u;
658
memory.data = mem->data + u;
659
dump_memory(hd_data, &memory, 0, "SMBIOS Entry Point");
664
read_memory(hd_data, &memory);
667
" SMBIOS Structure Table at 0x%05x (size 0x%x)\n",
672
dump_memory(hd_data, &memory, 0, "SMBIOS Structure Table");
675
for(type = 0, u = 0, ofs = 0; u < structs && ofs + 3 < len; u++) {
676
type = memory.data[ofs];
677
slen = memory.data[ofs + 1];
678
if(ofs + slen > len || slen < 4) break;
679
sm = smbios_add_entry(&hd_data->smbios, new_mem(sizeof *sm));
681
sm->any.data_len = slen;
682
sm->any.data = new_mem(slen);
683
memcpy(sm->any.data, memory.data + ofs, slen);
684
sm->any.handle = memory.data[ofs + 2] + (memory.data[ofs + 3] << 8);
685
ADD2LOG(" type 0x%02x [0x%04x]: ", type, sm->any.handle);
686
if(slen) hexdump(&hd_data->log, 0, slen, sm->any.data);
688
if(type == sm_end) break;
693
while(ofs + 1 < len) {
694
if(!memory.data[ofs]) {
696
s = canon_str(memory.data + u1, strlen(memory.data + u1));
697
add_str_list(&sm->any.strings, s);
699
if(*s) ADD2LOG(" str%d: \"%s\"\n", scnt, s);
704
if(!memory.data[ofs + 1]) {
715
ADD2LOG(" smbios: stopped at end tag\n");
718
ADD2LOG(" smbios oops: only %d of %d structs found\n", u, structs);
722
memory.data = free_mem(memory.data);
724
smbios_parse(hd_data);
728
void get_fsc_info(hd_data_t *hd_data, memory_range_t *mem, bios_info_t *bt)
730
unsigned u, mtype, fsc_id;
735
if(!mem->data || mem->size < 0x20) return;
737
for(sm = hd_data->smbios; sm; sm = sm->next) {
738
if(sm->any.type == sm_sysinfo) {
739
vendor = sm->sysinfo.manuf;
744
vendor = vendor && !strcasecmp(vendor, "Fujitsu") ? "Fujitsu" : "Fujitsu Siemens";
746
for(u = 0; u <= mem->size - 0x20; u += 0x10) {
748
*(unsigned *) (mem->data + u) == 0x696a7546 &&
749
*(unsigned *) (mem->data + u + 4) == 0x20757374
751
mtype = *(unsigned *) (mem->data + u + 0x14);
752
if(!crc(mem->data + u, 0x20) && !(mtype & 0xf0000000)) {
753
fsc_id = (mtype >> 12) & 0xf;
793
bt->lcd.vendor = new_str(vendor);
794
bt->lcd.name = new_str("Notebook LCD");
799
ADD2LOG(" found FSC LCD: %d (%ux%u)\n", fsc_id, x, y);
808
void add_panel_info(hd_data_t *hd_data, bios_info_t *bt)
810
unsigned width, height, xsize = 0, ysize = 0;
811
char *vendor, *name, *version;
815
if(!hd_data->smbios) return;
817
vendor = name = version = NULL;
820
for(sm = hd_data->smbios; sm; sm = sm->next) {
821
if(sm->any.type == sm_sysinfo) {
822
vendor = sm->sysinfo.manuf;
823
name = sm->sysinfo.product;
824
version = sm->sysinfo.version;
829
if(!vendor || !name) return;
832
!strcmp(vendor, "IBM") &&
833
tp_lookup(name, &width, &height, &xsize, &ysize)
835
bt->lcd.vendor = new_str(vendor);
836
bt->lcd.name = new_str("Notebook LCD");
837
bt->lcd.width = width;
838
bt->lcd.height = height;
839
bt->lcd.xsize = xsize;
840
bt->lcd.ysize = ysize;
845
for(u = 0; u < sizeof panel_data / sizeof *panel_data; u++) {
847
!strcmp(vendor, panel_data[u].vendor) &&
848
!strcmp(name, panel_data[u].name) &&
849
(version || !panel_data[u].version) &&
850
(!version || !panel_data[u].version || !strcmp(version, panel_data[u].version))
852
bt->lcd.vendor = new_str(vendor);
853
bt->lcd.name = new_str("Notebook LCD");
854
bt->lcd.width = panel_data[u].width;
855
bt->lcd.height = panel_data[u].height;
856
bt->lcd.xsize = panel_data[u].xsize;
857
bt->lcd.ysize = panel_data[u].ysize;
864
void add_mouse_info(hd_data_t *hd_data, bios_info_t *bt)
866
unsigned compat_vend, compat_dev, bus;
867
char *vendor, *name, *type;
870
if(bt->mouse.compat_vend || !hd_data->smbios) return;
872
vendor = name = type = NULL;
873
compat_vend = compat_dev = bus = 0;
875
for(sm = hd_data->smbios; sm; sm = sm->next) {
876
if(sm->any.type == sm_sysinfo) {
877
vendor = sm->sysinfo.manuf;
878
name = sm->sysinfo.product;
881
sm->any.type == sm_mouse &&
882
!compat_vend /* take the first entry */
884
compat_vend = compat_dev = bus = 0;
887
switch(sm->mouse.interface.id) {
889
case 7: /* bus mouse (dell notebooks report this) */
891
compat_vend = MAKE_ID(TAG_SPECIAL, 0x0200);
892
compat_dev = MAKE_ID(TAG_SPECIAL, sm->mouse.buttons == 3 ? 0x0007 : 0x0006);
895
type = sm->mouse.mtype.name;
896
if(sm->mouse.mtype.id == 1) type = "Touch Pad"; /* Why??? */
897
if(sm->mouse.mtype.id == 2) type = NULL; /* "Other" */
901
if(!vendor || !name) return;
904
if(!strcmp(vendor, "Sony Corporation") && strstr(name, "PCG-") == name) {
907
compat_vend = MAKE_ID(TAG_SPECIAL, 0x0200);
908
compat_dev = MAKE_ID(TAG_SPECIAL, 0x0006);
914
bt->mouse.vendor = new_str(vendor);
915
bt->mouse.type = new_str(type);
917
bt->mouse.compat_vend = compat_vend;
918
bt->mouse.compat_dev = compat_dev;
922
int get_smp_info(hd_data_t *hd_data, memory_range_t *mem, smp_info_t *smp)
926
unsigned addr = 0, len;
928
if(mem->size < 0x10) return 0;
930
for(u = ok = 0; u <= mem->size - 0x10; u++) {
931
if(*(unsigned *) (mem->data + u) == 0x5f504d5f) { /* "_MP_" */
932
addr = *(unsigned *) (mem->data + u + 4);
933
len = mem->data[u + 8];
934
ok = len == 1 && crc(mem->data + u, 0x10) == 0 ? 1 : 0;
936
" smp: %svalid MP FP at 0x%05x (size 0x%x, rev %u), MP config at 0x%05x\n",
937
ok ? "" : "in", u + mem->start, len << 4, mem->data[u + 9], addr
945
smp->mpfp = mem->start + u;
946
smp->rev = mem->data[u + 9];
947
smp->mpconfig = addr;
948
memcpy(smp->feature, mem->data + u + 11, 5);
958
void parse_mpconfig(hd_data_t *hd_data, memory_range_t *mem, smp_info_t *smp)
960
unsigned cfg_len, xcfg_len;
961
unsigned char u0, ux0;
962
unsigned u, type, len, entries, entry_cnt;
965
cfg_len = xcfg_len = 0;
967
if(*(unsigned *) (mem->data) == 0x504d4350) { /* "PCMP" */
968
cfg_len = mem->data[0x04] + (mem->data[0x05] << 8);
969
smp->mpconfig_size = cfg_len;
970
u0 = crc(mem->data, cfg_len);
972
smp->mpconfig_ok = 1;
973
smp->cpus = smp->cpus_en = 0;
974
xcfg_len = mem->data[0x28] + (mem->data[0x29] << 8);
975
ux0 = crc(mem->data + cfg_len, xcfg_len) + mem->data[0x2a];
977
smp->mpconfig_size += xcfg_len;
985
s = canon_str(mem->data + 8, 8);
986
strcpy(smp->oem_id, s);
988
s = canon_str(mem->data + 0x10, 12);
989
strcpy(smp->prod_id, s);
992
entries = mem->data[0x22] + (mem->data[0x23] << 8);
993
ADD2LOG(" base MP config table (%u entries):\n", entries);
995
for(u = 0x2c; u < cfg_len - 1; u += len, entry_cnt++) {
997
len = type == 0 ? 20 : type <= 4 ? 8 : 16;
998
ADD2LOG(" %stype %u, len %u\n ", type > 4 ? "unknown ": "", type, len);
999
if(len + u > cfg_len) len = cfg_len - u;
1000
hexdump(&hd_data->log, 1, len, mem->data + u);
1005
if((mem->data[u + 3] & 1)) smp->cpus_en++;
1008
if(entry_cnt != entries) {
1009
ADD2LOG(" oops: %u entries instead of %u found\n", entry_cnt, entries);
1014
ADD2LOG(" extended MP config table:\n");
1015
for(u = 0; u < xcfg_len - 2; u += len) {
1016
type = mem->data[u + cfg_len];
1017
len = mem->data[u + cfg_len + 1];
1018
ADD2LOG(" type %u, len %u\n ", type, len);
1019
if(len + u > xcfg_len) len = xcfg_len - u;
1020
hexdump(&hd_data->log, 1, len, mem->data + cfg_len + u);
1023
ADD2LOG(" oops: invalid record lenght\n");
1031
int get_bios32_info(hd_data_t *hd_data, memory_range_t *mem, bios32_info_t *bios32)
1034
unsigned addr = 0, len;
1036
if(mem->size < 0x10) return 0;
1038
for(u = ok = 0; u <= mem->size - 0x10; u += 0x10) {
1039
if(*(unsigned *) (mem->data + u) == 0x5f32335f) { /* "_32_" */
1040
addr = *(unsigned *) (mem->data + u + 4);
1041
len = mem->data[u + 9];
1042
ok = len == 1 && crc(mem->data + u, 0x10) == 0 && addr < (1 << 20) ? 1 : 0;
1044
" bios32: %svalid SD header at 0x%05x (size 0x%x, rev %u), SD at 0x%05x\n",
1045
ok ? "" : "in", u + mem->start, len << 4, mem->data[u + 8], addr
1053
bios32->entry = addr;
1060
* db format (32 bits):
1061
* leaf: 1, last: 1, key: 6, range: 4, ofs: 20
1063
int tp_lookup(char *key_str, unsigned *width, unsigned *height, unsigned *xsize, unsigned *ysize)
1066
unsigned key, range, ofs, last, leaf = 0;
1068
if(strlen(key_str) != 7) return 0;
1070
for(u = 0; u < 7; u++) {
1071
if(key_str[u] < '0' || key_str[u] >= '0' + 64) return 0;
1074
for(u = 0; u < sizeof tp_db / sizeof *tp_db; u++) {
1075
key = (tp_db[u] >> 24) & 0x3f;
1076
range = (tp_db[u] >> 20) & 0xf;
1077
ofs = tp_db[u] & ((1 << 20) - 1);
1078
// printf("key = %d, range = %d, ofs = %d, str = %d\n", key, range, ofs, *key_str - '0');
1079
if(*key_str - '0' >= key && *key_str - '0' <= key + range) {
1080
// printf("match\n");
1081
leaf = (tp_db[u] >> 31) & 1;
1084
// printf("%d\n", *key_str);
1085
if(ofs >= sizeof tp_db / sizeof *tp_db || !*key_str) return 0;
1087
// printf("next1 = %u\n", ofs);
1091
last = (tp_db[u] >> 30) & 1;
1093
// printf("next2 = %u\n", u + 1);
1098
if(ofs >= sizeof tp_values / sizeof *tp_values) return 0;
1099
*width = tp_values[ofs].width;
1100
*height = tp_values[ofs].height;
1101
*xsize = tp_values[ofs].xsize;
1102
*ysize = tp_values[ofs].ysize;
1108
#endif /* defined(__i386__) || defined (__x86_64__) */