Chameleon

Chameleon Commit Details

Date:2011-06-25 18:21:17 (7 years 11 months ago)
Author:Evan Lojewski
Commit:1068
Parents: 1067
Message:Remove some libsaio files...
Changes:
D/branches/rewrite/i386/libsaio/hpet.c
D/branches/rewrite/i386/libsaio/hpet.h
D/branches/rewrite/i386/libsaio/dram_controllers.c
D/branches/rewrite/i386/libsaio/pci.c
D/branches/rewrite/i386/libsaio/dram_controllers.h
D/branches/rewrite/i386/libsaio/device_tree.c
D/branches/rewrite/i386/libsaio/aml_generator.c
D/branches/rewrite/i386/libsaio/pci.h
D/branches/rewrite/i386/libsaio/convert.c
D/branches/rewrite/i386/libsaio/device_tree.h
D/branches/rewrite/i386/libsaio/platform.c
D/branches/rewrite/i386/libsaio/aml_generator.h
D/branches/rewrite/i386/libsaio/convert.h
D/branches/rewrite/i386/libsaio/spd.c
D/branches/rewrite/i386/libsaio/cpu.c
D/branches/rewrite/i386/libsaio/platform.h
D/branches/rewrite/i386/libsaio/spd.h
D/branches/rewrite/i386/libsaio/cpu.h
M/branches/rewrite/i386/boot2/boot.c
M/branches/rewrite/i386/libsaio/allocate.c
M/branches/rewrite/i386/libsaio/Makefile

File differences

branches/rewrite/i386/libsaio/device_tree.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
/*
* Copyright (c) 2005 Apple Computer, Inc. All Rights Reserved.
*/
#if 1
/*
Structures for a Flattened Device Tree
*/
#define kPropNameLength 32
typedef struct DeviceTreeNodeProperty {
char name[kPropNameLength]; // NUL terminated property name
unsigned long length; // Length (bytes) of folloing prop value
// unsigned long value[1]; // Variable length value of property
// Padded to a multiple of a longword?
} DeviceTreeNodeProperty;
typedef struct OpaqueDTEntry {
unsigned long nProperties; // Number of props[] elements (0 => end)
unsigned long nChildren; // Number of children[] elements
// DeviceTreeNodeProperty props[];// array size == nProperties
// DeviceTreeNode children[]; // array size == nChildren
} DeviceTreeNode;
typedef char DTPropertyNameBuf[32];
/* Entry Name Definitions (Entry Names are C-Strings)*/
enum {
kDTMaxEntryNameLength = 31 /* Max length of a C-String Entry Name (terminator not included) */
};
/* length of DTEntryNameBuf = kDTMaxEntryNameLength +1*/
typedef char DTEntryNameBuf[32];
#endif
#include "libsaio.h"
#include "device_tree.h"
#if DEBUG
#define DPRINTF(args...) printf(args)
void
DT__PrintTree(Node *node);
#else
#define DPRINTF(args...)
#endif
#define RoundToLong(x)(((x) + 3) & ~3)
static struct _DTSizeInfo {
uint32_t numNodes;
uint32_t numProperties;
uint32_t totalPropertySize;
} DTInfo;
#define kAllocSize 4096
static Node *rootNode;
static Node *freeNodes, *allocedNodes;
static Property *freeProperties, *allocedProperties;
Property *
DT__AddProperty(Node *node, const char *name, uint32_t length, void *value)
{
Property *prop;
DPRINTF("DT__AddProperty([Node '%s'], '%s', %d, 0x%x)\n", DT__GetName(node), name, length, value);
if (freeProperties == NULL) {
void *buf = malloc(kAllocSize);
int i;
DPRINTF("Allocating more free properties\n");
if (buf == 0) return 0;
bzero(buf, kAllocSize);
// Use the first property to record the allocated buffer
// for later freeing.
prop = (Property *)buf;
prop->next = allocedProperties;
allocedProperties = prop;
prop->value = buf;
prop++;
for (i=1; i<(kAllocSize / sizeof(Property)); i++) {
prop->next = freeProperties;
freeProperties = prop;
prop++;
}
}
prop = freeProperties;
freeProperties = prop->next;
prop->name = name;
prop->length = length;
prop->value = value;
// Always add to end of list
if (node->properties == 0) {
node->properties = prop;
} else {
node->last_prop->next = prop;
}
node->last_prop = prop;
prop->next = 0;
DPRINTF("Done [0x%x]\n", prop);
DTInfo.numProperties++;
DTInfo.totalPropertySize += RoundToLong(length);
return prop;
}
Node *
DT__AddChild(Node *parent, const char *name)
{
Node *node;
if (freeNodes == NULL) {
void *buf = malloc(kAllocSize);
int i;
DPRINTF("Allocating more free nodes\n");
if (buf == 0) return 0;
bzero(buf, kAllocSize);
node = (Node *)buf;
// Use the first node to record the allocated buffer
// for later freeing.
node->next = allocedNodes;
allocedNodes = node;
node->children = (Node *)buf;
node++;
for (i=1; i<(kAllocSize / sizeof(Node)); i++) {
node->next = freeNodes;
freeNodes = node;
node++;
}
}
DPRINTF("DT__AddChild(0x%x, '%s')\n", parent, name);
node = freeNodes;
freeNodes = node->next;
DPRINTF("Got free node 0x%x\n", node);
DPRINTF("prop = 0x%x, children = 0x%x, next = 0x%x\n", node->properties, node->children, node->next);
if (parent == NULL) {
rootNode = node;
node->next = 0;
} else {
node->next = parent->children;
parent->children = node;
}
DTInfo.numNodes++;
DT__AddProperty(node, "name", strlen(name) + 1, (void *) name);
return node;
}
void
DT__FreeProperty(Property *prop)
{
prop->next = freeProperties;
freeProperties = prop;
}
void
DT__FreeNode(Node *node)
{
node->next = freeNodes;
freeNodes = node;
}
void
DT__Initialize(void)
{
DPRINTF("DT__Initialize\n");
freeNodes = 0;
allocedNodes = 0;
freeProperties = 0;
allocedProperties = 0;
DTInfo.numNodes = 0;
DTInfo.numProperties = 0;
DTInfo.totalPropertySize = 0;
rootNode = DT__AddChild(NULL, "/");
DPRINTF("DT__Initialize done\n");
}
/*
* Free up memory used by in-memory representation
* of device tree.
*/
void
DT__Finalize(void)
{
Node *node;
Property *prop;
DPRINTF("DT__Finalize\n");
for (prop = allocedProperties; prop != NULL; prop = prop->next) {
free(prop->value);
}
allocedProperties = NULL;
freeProperties = NULL;
for (node = allocedNodes; node != NULL; node = node->next) {
free((void *)node->children);
}
allocedNodes = NULL;
freeNodes = NULL;
rootNode = NULL;
// XXX leaks any created strings
DTInfo.numNodes = 0;
DTInfo.numProperties = 0;
DTInfo.totalPropertySize = 0;
}
static void *
FlattenNodes(Node *node, void *buffer)
{
Property *prop;
DeviceTreeNode *flatNode;
DeviceTreeNodeProperty *flatProp;
int count;
if (node == 0) return buffer;
flatNode = (DeviceTreeNode *)buffer;
buffer += sizeof(DeviceTreeNode);
for (count = 0, prop = node->properties; prop != 0; count++, prop = prop->next) {
flatProp = (DeviceTreeNodeProperty *)buffer;
strcpy(flatProp->name, prop->name);
flatProp->length = prop->length;
buffer += sizeof(DeviceTreeNodeProperty);
bcopy(prop->value, buffer, prop->length);
buffer += RoundToLong(prop->length);
}
flatNode->nProperties = count;
for (count = 0, node = node->children; node != 0; count++, node = node->next) {
buffer = FlattenNodes(node, buffer);
}
flatNode->nChildren = count;
return buffer;
}
/*
* Flatten the in-memory representation of the device tree
* into a binary DT block.
* To get the buffer size needed, call with result = 0.
* To have a buffer allocated for you, call with *result = 0.
* To use your own buffer, call with *result = &buffer.
*/
void
DT__FlattenDeviceTree(void **buffer_p, uint32_t *length)
{
uint32_t totalSize;
void *buf;
DPRINTF("DT__FlattenDeviceTree(0x%x, 0x%x)\n", buffer_p, length);
#if DEBUG
if (buffer_p) DT__PrintTree(rootNode);
#endif
totalSize = DTInfo.numNodes * sizeof(DeviceTreeNode) +
DTInfo.numProperties * sizeof(DeviceTreeNodeProperty) +
DTInfo.totalPropertySize;
DPRINTF("Total size 0x%x\n", totalSize);
if (buffer_p != 0) {
if (totalSize == 0) {
buf = 0;
} else {
if (*buffer_p == 0) {
buf = malloc(totalSize);
} else {
buf = *buffer_p;
}
bzero(buf, totalSize);
FlattenNodes(rootNode, buf);
}
*buffer_p = buf;
}
if (length)
*length = totalSize;
}
char *
DT__GetName(Node *node)
{
Property *prop;
//DPRINTF("DT__GetName(0x%x)\n", node);
//DPRINTF("Node properties = 0x%x\n", node->properties);
for (prop = node->properties; prop; prop = prop->next) {
//DPRINTF("Prop '%s'\n", prop->name);
if (strcmp(prop->name, "name") == 0) {
return prop->value;
}
}
//DPRINTF("DT__GetName returns 0\n");
return "(null)";
}
Node *
DT__FindNode(const char *path, bool createIfMissing)
{
Node *node, *child;
DTPropertyNameBuf nameBuf;
char *bp;
int i;
DPRINTF("DT__FindNode('%s', %d)\n", path, createIfMissing);
// Start at root
node = rootNode;
DPRINTF("root = 0x%x\n", rootNode);
while (node) {
// Skip leading slash
while (*path == '/') path++;
for (i=0, bp = nameBuf; ++i < kDTMaxEntryNameLength && *path && *path != '/'; bp++, path++) *bp = *path;
*bp = '\0';
if (nameBuf[0] == '\0') {
// last path entry
break;
}
DPRINTF("Node '%s'\n", nameBuf);
for (child = node->children; child != 0; child = child->next) {
DPRINTF("Child 0x%x\n", child);
if (strcmp(DT__GetName(child), nameBuf) == 0) {
break;
}
}
if (child == 0 && createIfMissing) {
DPRINTF("Creating node\n");
char *str = malloc(strlen(nameBuf) + 1);
// XXX this will leak
strcpy(str, nameBuf);
child = DT__AddChild(node, str);
}
node = child;
}
return node;
}
#if DEBUG
void
DT__PrintNode(Node *node, int level)
{
char spaces[10], *cp = spaces;
Property *prop;
if (level > 9) level = 9;
while (level--) *cp++ = ' ';
*cp = '\0';
printf("%s===Node===\n", spaces);
for (prop = node->properties; prop; prop = prop->next) {
char c = *((char *)prop->value);
if (prop->length < 64 && (
strcmp(prop->name, "name") == 0 ||
(c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') || c == '_')) {
printf("%s Property '%s' [%d] = '%s'\n", spaces, prop->name, prop->length, prop->value);
} else {
printf("%s Property '%s' [%d] = (data)\n", spaces, prop->name, prop->length);
}
}
printf("%s==========\n", spaces);
}
static void
_PrintTree(Node *node, int level)
{
DT__PrintNode(node, level);
level++;
for (node = node->children; node; node = node->next)
_PrintTree(node, level);
}
void
DT__PrintTree(Node *node)
{
if (node == 0) node = rootNode;
_PrintTree(node, 0);
}
void
DT__PrintFlattenedNode(DTEntry entry, int level)
{
char spaces[10], *cp = spaces;
DTPropertyIterator propIter;
char *name;
void *prop;
int propSize;
if (level > 9) level = 9;
while (level--) *cp++ = ' ';
*cp = '\0';
printf("%s===Entry %p===\n", spaces, entry);
if (kSuccess != DTCreatePropertyIterator(entry, &propIter)) {
printf("Couldn't create property iterator\n");
return;
}
while( kSuccess == DTIterateProperties( propIter, &name)) {
if( kSuccess != DTGetProperty( entry, name, &prop, &propSize ))
continue;
printf("%s Property %s = %s\n", spaces, name, prop);
}
DTDisposePropertyIterator(propIter);
printf("%s==========\n", spaces);
}
static void
_PrintFlattenedTree(DTEntry entry, int level)
{
DTEntryIterator entryIter;
PrintFlattenedNode(entry, level);
if (kSuccess != DTCreateEntryIterator(entry, &entryIter)) {
printf("Couldn't create entry iterator\n");
return;
}
level++;
while (kSuccess == DTIterateEntries( entryIter, &entry )) {
_PrintFlattenedTree(entry, level);
}
DTDisposeEntryIterator(entryIter);
}
void
DT__PrintFlattenedTree(DTEntry entry)
{
_PrintFlattenedTree(entry, 0);
}
int
main(int argc, char **argv)
{
DTEntry dtEntry;
DTPropertyIterator propIter;
DTEntryIterator entryIter;
void*prop;
intpropSize;
char*name;
void *flatTree;
uint32_t flatSize;
Node *node;
node = AddChild(NULL, "device-tree");
AddProperty(node, "potato", 4, "foo");
AddProperty(node, "chemistry", 4, "bar");
AddProperty(node, "physics", 4, "baz");
node = AddChild(node, "dev");
AddProperty(node, "one", 4, "one");
AddProperty(node, "two", 4, "two");
AddProperty(node, "three", 6, "three");
node = AddChild(rootNode, "foo");
AddProperty(node, "aaa", 4, "aab");
AddProperty(node, "bbb", 4, "bbc");
AddProperty(node, "cccc", 6, "ccccd");
node = FindNode("/this/is/a/test", 1);
AddProperty(node, "dddd", 12, "abcdefghijk");
printf("In-memory tree:\n\n");
PrintTree(rootNode);
FlattenDeviceTree(&flatTree, &flatSize);
printf("Flat tree = %p, size %d\n", flatTree, flatSize);
dtEntry = (DTEntry)flatTree;
printf("\n\nPrinting flat tree\n\n");
DTInit(dtEntry);
PrintFlattenedTree((DTEntry)flatTree);
#if 0
printf("=== Entry %p ===\n", dtEntry);
if (kSuccess != DTCreatePropertyIterator(dtEntry, &propIter)) {
printf("Couldn't create property iterator\n");
return 1;
}
while( kSuccess == DTIterateProperties( propIter, &name)) {
if( kSuccess != DTGetProperty( dtEntry, name, &prop, &propSize ))
continue;
printf(" Property %s = %s\n", name, prop);
}
DTDisposePropertyIterator(propIter);
printf("========\n");
if (kSuccess != DTCreateEntryIterator(dtEntry, &entryIter)) {
printf("Couldn't create entry iterator\n");
return 1;
}
while (kSuccess == DTIterateEntries( entryIter, &dtEntry )) {
printf("=== Entry %p ===\n", dtEntry);
if (kSuccess != DTCreatePropertyIterator(dtEntry, &propIter)) {
printf("Couldn't create property iterator\n");
return 1;
}
while( kSuccess == DTIterateProperties( propIter, &name)) {
if( kSuccess != DTGetProperty( dtEntry, name, &prop, &propSize ))
continue;
printf(" Property %s = %s\n", name, prop);
}
DTDisposePropertyIterator(propIter);
printf("========\n");
}
DTDisposeEntryIterator(entryIter);
#endif
return 0;
}
#endif
branches/rewrite/i386/libsaio/device_tree.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/*
* Copyright (c) 2005 Apple Computer, Inc. All Rights Reserved.
*/
#ifndef __DEVICE_TREE_H
#define __DEVICE_TREE_H
#include <stdbool.h>
#include <stdint.h>
typedef struct _Property {
const char * name;
uint32_t length;
void * value;
struct _Property * next;
} Property;
typedef struct _Node {
struct _Property * properties;
struct _Property * last_prop;
struct _Node * children;
struct _Node * next;
} Node;
extern Property *
DT__AddProperty(Node *node, const char *name, uint32_t length, void *value);
extern Node *
DT__AddChild(Node *parent, const char *name);
Node *
DT__FindNode(const char *path, bool createIfMissing);
extern void
DT__FreeProperty(Property *prop);
extern void
DT__FreeNode(Node *node);
extern char *
DT__GetName(Node *node);
void
DT__Initialize(void);
/*
* Free up memory used by in-memory representation
* of device tree.
*/
extern void
DT__Finalize(void);
void
DT__FlattenDeviceTree(void **result, uint32_t *length);
#endif /* __DEVICE_TREE_H */
branches/rewrite/i386/libsaio/spd.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
/*
* spd.c - serial presence detect memory information
*
* Originally restored from pcefi10.5
* Dynamic mem detection original impl. by Rekursor
* System profiler fix and other fixes by Mozodojo.
*/
#include "libsaio.h"
#include "pci.h"
#include "platform.h"
#include "spd.h"
#include "cpu.h"
#include "saio_internal.h"
#include "memvendors.h"
#ifndef DEBUG_SPD
#define DEBUG_SPD 0
#endif
#if DEBUG_SPD
#define DBG(x...)printf(x)
#else
#define DBG(x...)msglog(x)
#endif
static const char *spd_memory_types[] =
{
"RAM", /* 00h Undefined */
"FPM", /* 01h FPM */
"EDO", /* 02h EDO */
"",/* 03h PIPELINE NIBBLE */
"SDRAM", /* 04h SDRAM */
"",/* 05h MULTIPLEXED ROM */
"DDR SGRAM",/* 06h SGRAM DDR */
"DDR SDRAM",/* 07h SDRAM DDR */
"DDR2 SDRAM", /* 08h SDRAM DDR 2 */
"",/* 09h Undefined */
"",/* 0Ah Undefined */
"DDR3 SDRAM"/* 0Bh SDRAM DDR 3 */
};
#define UNKNOWN_MEM_TYPE 2
static uint8_t spd_mem_to_smbios[] =
{
UNKNOWN_MEM_TYPE,/* 00h Undefined */
UNKNOWN_MEM_TYPE,/* 01h FPM */
UNKNOWN_MEM_TYPE,/* 02h EDO */
UNKNOWN_MEM_TYPE,/* 03h PIPELINE NIBBLE */
SMB_MEM_TYPE_SDRAM,/* 04h SDRAM */
SMB_MEM_TYPE_ROM,/* 05h MULTIPLEXED ROM */
SMB_MEM_TYPE_SGRAM,/* 06h SGRAM DDR */
SMB_MEM_TYPE_DDR,/* 07h SDRAM DDR */
SMB_MEM_TYPE_DDR2,/* 08h SDRAM DDR 2 */
UNKNOWN_MEM_TYPE,/* 09h Undefined */
UNKNOWN_MEM_TYPE,/* 0Ah Undefined */
SMB_MEM_TYPE_DDR3/* 0Bh SDRAM DDR 3 */
};
#define SPD_TO_SMBIOS_SIZE (sizeof(spd_mem_to_smbios)/sizeof(uint8_t))
#define rdtsc(low,high) \
__asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
#define SMBHSTSTS 0
#define SMBHSTCNT 2
#define SMBHSTCMD 3
#define SMBHSTADD 4
#define SMBHSTDAT 5
#define SBMBLKDAT 7
/** Read one byte from the intel i2c, used for reading SPD on intel chipsets only. */
unsigned char smb_read_byte_intel(uint32_t base, uint8_t adr, uint8_t cmd)
{
int l1, h1, l2, h2;
unsigned long long t;
outb(base + SMBHSTSTS, 0x1f);// reset SMBus Controller
outb(base + SMBHSTDAT, 0xff);
rdtsc(l1, h1);
while ( inb(base + SMBHSTSTS) & 0x01) // wait until read
{
rdtsc(l2, h2);
t = ((h2 - h1) * 0xffffffff + (l2 - l1)) / (Platform.CPU.TSCFrequency / 100);
if (t > 5)
return 0xFF; // break
}
outb(base + SMBHSTCMD, cmd);
outb(base + SMBHSTADD, (adr << 1) | 0x01 );
outb(base + SMBHSTCNT, 0x48 );
rdtsc(l1, h1);
while (!( inb(base + SMBHSTSTS) & 0x02))// wait til command finished
{
rdtsc(l2, h2);
t = ((h2 - h1) * 0xffffffff + (l2 - l1)) / (Platform.CPU.TSCFrequency / 100);
if (t > 5)
break;// break after 5ms
}
return inb(base + SMBHSTDAT);
}
/* SPD i2c read optimization: prefetch only what we need, read non prefetcheable bytes on the fly */
#define READ_SPD(spd, base, slot, x) spd[x] = smb_read_byte_intel(base, 0x50 + slot, x)
int spd_indexes[] = {
SPD_MEMORY_TYPE,
SPD_DDR3_MEMORY_BANK,
SPD_DDR3_MEMORY_CODE,
SPD_NUM_ROWS,
SPD_NUM_COLUMNS,
SPD_NUM_DIMM_BANKS,
SPD_NUM_BANKS_PER_SDRAM,
4,7,8,9,12,64, /* TODO: give names to these values */
95,96,97,98, 122,123,124,125 /* UIS */
};
#define SPD_INDEXES_SIZE (sizeof(spd_indexes) / sizeof(int))
/** Read from spd *used* values only*/
static void init_spd(char * spd, uint32_t base, int slot)
{
int i;
for (i=0; i< SPD_INDEXES_SIZE; i++) {
READ_SPD(spd, base, slot, spd_indexes[i]);
}
}
/** Get Vendor Name from spd, 2 cases handled DDR3 and DDR2,
have different formats, always return a valid ptr.*/
const char * getVendorName(RamSlotInfo_t* slot, uint32_t base, int slot_num)
{
uint8_t bank = 0;
uint8_t code = 0;
int i = 0;
uint8_t * spd = (uint8_t *) slot->spd;
if (spd[SPD_MEMORY_TYPE]==SPD_MEMORY_TYPE_SDRAM_DDR3) { // DDR3
bank = (spd[SPD_DDR3_MEMORY_BANK] & 0x07f); // constructors like Patriot use b7=1
code = spd[SPD_DDR3_MEMORY_CODE];
for (i=0; i < VEN_MAP_SIZE; i++)
if (bank==vendorMap[i].bank && code==vendorMap[i].code)
return vendorMap[i].name;
}
else if (spd[SPD_MEMORY_TYPE]==SPD_MEMORY_TYPE_SDRAM_DDR2) {
if(spd[64]==0x7f) {
for (i=64; i<72 && spd[i]==0x7f;i++) {
bank++;
READ_SPD(spd, base, slot_num,i+1); // prefetch next spd byte to read for next loop
}
READ_SPD(spd, base, slot_num,i);
code = spd[i];
} else {
code = spd[64];
bank = 0;
}
for (i=0; i < VEN_MAP_SIZE; i++)
if (bank==vendorMap[i].bank && code==vendorMap[i].code)
return vendorMap[i].name;
}
/* OK there is no vendor id here lets try to match the partnum if it exists */
if (strstr(slot->PartNo,"GU332") == slot->PartNo) // Unifosa fingerprint
return "Unifosa";
return "NoName";
}
/** Get Default Memory Module Speed (no overclocking handled) */
int getDDRspeedMhz(const char * spd)
{
if (spd[SPD_MEMORY_TYPE]==SPD_MEMORY_TYPE_SDRAM_DDR3) {
switch(spd[12]) {
case 0x0f:
return 1066;
case 0x0c:
return 1333;
case 0x0a:
return 1600;
case 0x14:
default:
return 800;
}
}
else if (spd[SPD_MEMORY_TYPE]==SPD_MEMORY_TYPE_SDRAM_DDR2) {
switch(spd[9]) {
case 0x50:
return 400;
case 0x3d:
return 533;
case 0x30:
return 667;
case 0x25:
default:
return 800;
}
}
return 800; // default freq for unknown types
}
#define SMST(a) ((uint8_t)((spd[a] & 0xf0) >> 4))
#define SLST(a) ((uint8_t)(spd[a] & 0x0f))
/** Get DDR3 or DDR2 serial number, 0 most of the times, always return a valid ptr */
const char *getDDRSerial(const char* spd)
{
static char asciiSerial[16];
if (spd[SPD_MEMORY_TYPE]==SPD_MEMORY_TYPE_SDRAM_DDR3) // DDR3
{
sprintf(asciiSerial, "%X%X%X%X%X%X%X%X", SMST(122) /*& 0x7*/, SLST(122), SMST(123), SLST(123), SMST(124), SLST(124), SMST(125), SLST(125));
}
else if (spd[SPD_MEMORY_TYPE]==SPD_MEMORY_TYPE_SDRAM_DDR2) // DDR2 or DDR
{
sprintf(asciiSerial, "%X%X%X%X%X%X%X%X", SMST(95) /*& 0x7*/, SLST(95), SMST(96), SLST(96), SMST(97), SLST(97), SMST(98), SLST(98));
}
return strdup(asciiSerial);
}
/** Get DDR3 or DDR2 Part Number, always return a valid ptr */
const char * getDDRPartNum(char* spd, uint32_t base, int slot)
{
static char asciiPartNo[32];
int i, start=0, index = 0;
if (spd[SPD_MEMORY_TYPE]==SPD_MEMORY_TYPE_SDRAM_DDR3) {
start = 128;
}
else if (spd[SPD_MEMORY_TYPE]==SPD_MEMORY_TYPE_SDRAM_DDR2) {
start = 73;
}
// Check that the spd part name is zero terminated and that it is ascii:
bzero(asciiPartNo, sizeof(asciiPartNo));
char c;
for (i=start; i < start + sizeof(asciiPartNo); i++) {
READ_SPD(spd, base, slot, i); // only read once the corresponding model part (ddr3 or ddr2)
c = spd[i];
if (isalpha(c) || isdigit(c) || ispunct(c)) // It seems that System Profiler likes only letters and digits...
asciiPartNo[index++] = c;
else if (!isascii(c))
break;
}
return strdup(asciiPartNo);
}
int mapping []= {0,2,1,3,4,6,5,7,8,10,9,11};
/** Read from smbus the SPD content and interpret it for detecting memory attributes */
static void read_smb_intel(pci_dt_t *smbus_dev)
{
int i, speed;
uint8_t spd_size, spd_type;
uint32_t base, mmio, hostc;
// bool dump = false;
RamSlotInfo_t* slot;
uint16_t cmd = pci_config_read16(smbus_dev->dev.addr, 0x04);
DBG("SMBus CmdReg: 0x%x\n", cmd);
pci_config_write16(smbus_dev->dev.addr, 0x04, cmd | 1);
mmio = pci_config_read32(smbus_dev->dev.addr, 0x10);// & ~0x0f;
base = pci_config_read16(smbus_dev->dev.addr, 0x20) & 0xFFFE;
hostc = pci_config_read8(smbus_dev->dev.addr, 0x40);
verbose("Scanning SMBus [%04x:%04x], mmio: 0x%x, ioport: 0x%x, hostc: 0x%x\n",
smbus_dev->vendor_id, smbus_dev->device_id, mmio, base, hostc);
//Azi: no use for this!
// getBoolForKey("DumpSPD", &dump, &bootInfo->bootConfig);
// needed at least for laptops
bool fullBanks = Platform.DMI.MemoryModules == Platform.DMI.CntMemorySlots;
char spdbuf[MAX_SPD_SIZE];
// Search MAX_RAM_SLOTS slots
for (i = 0; i < MAX_RAM_SLOTS; i++){
slot = &Platform.RAM.DIMM[i];
spd_size = smb_read_byte_intel(base, 0x50 + i, 0);
DBG("SPD[0] (size): %d @0x%x\n", spd_size, 0x50 + i);
// Check spd is present
if (spd_size && (spd_size != 0xff))
{
slot->spd = spdbuf;
slot->InUse = true;
bzero(slot->spd, spd_size);
// Copy spd data into buffer
//for (x = 0; x < spd_size; x++) slot->spd[x] = smb_read_byte_intel(base, 0x50 + i, x);
init_spd(slot->spd, base, i);
switch (slot->spd[SPD_MEMORY_TYPE]) {
case SPD_MEMORY_TYPE_SDRAM_DDR2:
slot->ModuleSize = ((1 << (slot->spd[SPD_NUM_ROWS] & 0x0f) + (slot->spd[SPD_NUM_COLUMNS] & 0x0f) - 17) *
((slot->spd[SPD_NUM_DIMM_BANKS] & 0x7) + 1) * slot->spd[SPD_NUM_BANKS_PER_SDRAM]);
break;
case SPD_MEMORY_TYPE_SDRAM_DDR3:
slot->ModuleSize = ((slot->spd[4] & 0x0f) + 28 ) + ((slot->spd[8] & 0x7) + 3 );
slot->ModuleSize -= (slot->spd[7] & 0x7) + 25;
slot->ModuleSize = ((1 << slot->ModuleSize) * (((slot->spd[7] >> 3) & 0x1f) + 1));
break;
}
spd_type = (slot->spd[SPD_MEMORY_TYPE] < ((char) 12) ? slot->spd[SPD_MEMORY_TYPE] : 0);
slot->Type = spd_mem_to_smbios[spd_type];
slot->PartNo = getDDRPartNum(slot->spd, base, i);
slot->Vendor = getVendorName(slot, base, i);
slot->SerialNo = getDDRSerial(slot->spd);
// determine spd speed
speed = getDDRspeedMhz(slot->spd);
if (slot->Frequency<speed) slot->Frequency = speed;
// pci memory controller if available, is more reliable
if (Platform.RAM.Frequency > 0) {
uint32_t freq = (uint32_t)Platform.RAM.Frequency / 500000;
// now round off special cases
uint32_t fmod100 = freq %100;
switch(fmod100) {
case 1:freq--;break;
case 32:freq++;break;
case 65:freq++; break;
case 98:freq+=2;break;
case 99:freq++; break;
}
slot->Frequency = freq;
}
verbose("Slot: %d Type %d %dMB (%s) %dMHz Vendor=%s\n PartNo=%s SerialNo=%s\n",
i,
(int)slot->Type,
slot->ModuleSize,
spd_memory_types[spd_type],
slot->Frequency,
slot->Vendor,
slot->PartNo,
slot->SerialNo);
}
// laptops sometimes show slot 0 and 2 with slot 1 empty when only 2 slots are presents so:
Platform.DMI.DIMM[i]=
i>0 && Platform.RAM.DIMM[1].InUse==false && fullBanks && Platform.DMI.CntMemorySlots == 2 ?
mapping[i] : i; // for laptops case, mapping setup would need to be more generic than this
slot->spd = NULL;
} // for
}
static struct smbus_controllers_t smbus_controllers[] = {
{0x8086, 0x269B, "ESB2",read_smb_intel },
{0x8086, 0x25A4, "6300ESB",read_smb_intel },
{0x8086, 0x24C3, "ICH4",read_smb_intel },
{0x8086, 0x24D3, "ICH5",read_smb_intel },
{0x8086, 0x266A, "ICH6",read_smb_intel },
{0x8086, 0x27DA, "ICH7",read_smb_intel },
{0x8086, 0x283E, "ICH8",read_smb_intel },
{0x8086, 0x2930, "ICH9",read_smb_intel },
{0x8086, 0x3A30, "ICH10R",read_smb_intel },
{0x8086, 0x3A60, "ICH10B",read_smb_intel },
{0x8086, 0x3B30, "5 Series",read_smb_intel },
{0x8086, 0x1C22, "6 Series",read_smb_intel },
{0x8086, 0x5032, "EP80579",read_smb_intel }
};
// initial call : pci_dt = root_pci_dev;
// find_and_read_smbus_controller(root_pci_dev);
bool find_and_read_smbus_controller(pci_dt_t* pci_dt)
{
pci_dt_t*current = pci_dt;
int i;
while (current) {
#if 0
printf("%02x:%02x.%x [%04x] [%04x:%04x] :: %s\n",
current->dev.bits.bus, current->dev.bits.dev, current->dev.bits.func,
current->class_id, current->vendor_id, current->device_id,
get_pci_dev_path(current));
#endif
for ( i = 0; i < sizeof(smbus_controllers) / sizeof(smbus_controllers[0]); i++ )
{
if (current->vendor_id == smbus_controllers[i].vendor &&
current->device_id == smbus_controllers[i].device)
{
smbus_controllers[i].read_smb(current); // read smb
return true;
}
}
find_and_read_smbus_controller(current->children);
current = current->next;
}
return false; // not found
}
void scan_spd(PlatformInfo_t *p)
{
find_and_read_smbus_controller(root_pci_dev);
}
branches/rewrite/i386/libsaio/spd.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/*
* Copyright 2010 AsereBLN. All rights reserved. <aserebln@googlemail.com>
*
* spd.h
*/
#ifndef __LIBSAIO_SPD_H
#define __LIBSAIO_SPD_H
#include "platform.h"
#include "libsaio.h"
void scan_spd(PlatformInfo_t *p);
struct smbus_controllers_t {
uint32_tvendor;
uint32_tdevice;
char*name;
void (*read_smb)(pci_dt_t *smbus_dev);
};
/*
* Serial Presence Detect (SPD) data stored on SDRAM modules.
*
* Datasheet:
* - Name: PC SDRAM Serial Presence Detect (SPD) Specification
* Revision 1.2A, December, 1997
* - PDF: http://www.intel.com/design/chipsets/memory/spdsd12a.pdf
*
* Datasheet (alternative):
* - Name: SERIAL PRESENCE DETECT STANDARD, General Standard
* JEDEC Standard No. 21-C
* - PDF: http://www.jedec.org/download/search/4_01_02_00R9.PDF
*/
/* Byte numbers. */
#define SPD_NUM_MANUFACTURER_BYTES 0 /* Number of bytes used by module manufacturer */
#define SPD_TOTAL_SPD_MEMORY_SIZE 1 /* Total SPD memory size */
#define SPD_MEMORY_TYPE 2 /* (Fundamental) memory type */
#define SPD_NUM_ROWS 3 /* Number of row address bits */
#define SPD_NUM_COLUMNS 4 /* Number of column address bits */
#define SPD_NUM_DIMM_BANKS 5 /* Number of module rows (banks) */
#define SPD_MODULE_DATA_WIDTH_LSB 6 /* Module data width (LSB) */
#define SPD_MODULE_DATA_WIDTH_MSB 7 /* Module data width (MSB) */
#define SPD_MODULE_VOLTAGE 8 /* Module interface signal levels */
#define SPD_MIN_CYCLE_TIME_AT_CAS_MAX 9 /* SDRAM cycle time (highest CAS latency), RAS access time (tRAC) */
#define SPD_ACCESS_TIME_FROM_CLOCK 10 /* SDRAM access time from clock (highest CAS latency), CAS access time (Tac, tCAC) */
#define SPD_DIMM_CONFIG_TYPE 11 /* Module configuration type */
#define SPD_REFRESH 12 /* Refresh rate/type */
#define SPD_PRIMARY_SDRAM_WIDTH 13 /* SDRAM width (primary SDRAM) */
#define SPD_ERROR_CHECKING_SDRAM_WIDTH 14 /* Error checking SDRAM (data) width */
#define SPD_MIN_CLOCK_DELAY_B2B_RAND_COLUMN 15 /* SDRAM device attributes, minimum clock delay for back to back random column */
#define SPD_SUPPORTED_BURST_LENGTHS 16 /* SDRAM device attributes, burst lengths supported */
#define SPD_NUM_BANKS_PER_SDRAM 17 /* SDRAM device attributes, number of banks on SDRAM device */
#define SPD_ACCEPTABLE_CAS_LATENCIES 18 /* SDRAM device attributes, CAS latency */
#define SPD_CS_LATENCY 19 /* SDRAM device attributes, CS latency */
#define SPD_WE_LATENCY 20 /* SDRAM device attributes, WE latency */
#define SPD_MODULE_ATTRIBUTES 21 /* SDRAM module attributes */
#define SPD_DEVICE_ATTRIBUTES_GENERAL 22 /* SDRAM device attributes, general */
#define SPD_SDRAM_CYCLE_TIME_2ND 23 /* SDRAM cycle time (2nd highest CAS latency) */
#define SPD_ACCESS_TIME_FROM_CLOCK_2ND 24 /* SDRAM access from clock (2nd highest CAS latency) */
#define SPD_SDRAM_CYCLE_TIME_3RD 25 /* SDRAM cycle time (3rd highest CAS latency) */
#define SPD_ACCESS_TIME_FROM_CLOCK_3RD 26 /* SDRAM access from clock (3rd highest CAS latency) */
#define SPD_MIN_ROW_PRECHARGE_TIME 27 /* Minimum row precharge time (Trp) */
#define SPD_MIN_ROWACTIVE_TO_ROWACTIVE 28 /* Minimum row active to row active (Trrd) */
#define SPD_MIN_RAS_TO_CAS_DELAY 29 /* Minimum RAS to CAS delay (Trcd) */
#define SPD_MIN_ACTIVE_TO_PRECHARGE_DELAY 30 /* Minimum RAS pulse width (Tras) */
#define SPD_DENSITY_OF_EACH_ROW_ON_MODULE 31 /* Density of each row on module */
#define SPD_CMD_SIGNAL_INPUT_SETUP_TIME 32 /* Command and address signal input setup time */
#define SPD_CMD_SIGNAL_INPUT_HOLD_TIME 33 /* Command and address signal input hold time */
#define SPD_DATA_SIGNAL_INPUT_SETUP_TIME 34 /* Data signal input setup time */
#define SPD_DATA_SIGNAL_INPUT_HOLD_TIME 35 /* Data signal input hold time */
#define SPD_WRITE_RECOVERY_TIME 36 /* Write recovery time (tWR) */
#define SPD_INT_WRITE_TO_READ_DELAY 37 /* Internal write to read command delay (tWTR) */
#define SPD_INT_READ_TO_PRECHARGE_DELAY 38 /* Internal read to precharge command delay (tRTP) */
#define SPD_MEM_ANALYSIS_PROBE_PARAMS 39 /* Memory analysis probe characteristics */
#define SPD_BYTE_41_42_EXTENSION 40 /* Extension of byte 41 (tRC) and byte 42 (tRFC) */
#define SPD_MIN_ACT_TO_ACT_AUTO_REFRESH 41 /* Minimum active to active auto refresh (tRCmin) */
#define SPD_MIN_AUTO_REFRESH_TO_ACT 42 /* Minimum auto refresh to active/auto refresh (tRFC) */
#define SPD_MAX_DEVICE_CYCLE_TIME 43 /* Maximum device cycle time (tCKmax) */
#define SPD_MAX_DQS_DQ_SKEW 44 /* Maximum skew between DQS and DQ (tDQSQ) */
#define SPD_MAX_READ_DATAHOLD_SKEW 45 /* Maximum read data-hold skew factor (tQHS) */
#define SPD_PLL_RELOCK_TIME 46 /* PLL relock time */
#define SPD_SPD_DATA_REVISION_CODE 62 /* SPD data revision code */
#define SPD_CHECKSUM_FOR_BYTES_0_TO_62 63 /* Checksum for bytes 0-62 */
#define SPD_MANUFACTURER_JEDEC_ID_CODE 64 /* Manufacturer's JEDEC ID code, per EIA/JEP106 (bytes 64-71) */
#define SPD_MANUFACTURING_LOCATION 72 /* Manufacturing location */
#define SPD_MANUFACTURER_PART_NUMBER 73 /* Manufacturer's part number, in 6-bit ASCII (bytes 73-90) */
#define SPD_REVISION_CODE 91 /* Revision code (bytes 91-92) */
#define SPD_MANUFACTURING_DATE 93 /* Manufacturing date (byte 93: year, byte 94: week) */
#define SPD_ASSEMBLY_SERIAL_NUMBER 95 /* Assembly serial number (bytes 95-98) */
#define SPD_MANUFACTURER_SPECIFIC_DATA 99 /* Manufacturer specific data (bytes 99-125) */
#define SPD_INTEL_SPEC_FOR_FREQUENCY 126 /* Intel specification for frequency */
#define SPD_INTEL_SPEC_100_MHZ 127 /* Intel specification details for 100MHz support */
#define SPD_DDR3_MEMORY_BANK 0x75
#define SPD_DDR3_MEMORY_CODE 0x76
/* DRAM specifications use the following naming conventions for SPD locations */
#define SPD_tRP SPD_MIN_ROW_PRECHARGE_TIME
#define SPD_tRRD SPD_MIN_ROWACTIVE_TO_ROWACTIVE
#define SPD_tRCD SPD_MIN_RAS_TO_CAS_DELAY
#define SPD_tRAS SPD_MIN_ACTIVE_TO_PRECHARGE_DELAY
#define SPD_BANK_DENSITY SPD_DENSITY_OF_EACH_ROW_ON_MODULE
#define SPD_ADDRESS_CMD_HOLD SPD_CMD_SIGNAL_INPUT_HOLD_TIME
#define SPD_tRC41/* SDRAM Device Minimum Active to Active/Auto Refresh Time (tRC) */
#define SPD_tRFC42/* SDRAM Device Minimum Auto Refresh to Active/Auto Refresh (tRFC) */
/* SPD_MEMORY_TYPE values. */
#define SPD_MEMORY_TYPE_FPM_DRAM1
#define SPD_MEMORY_TYPE_EDO2
#define SPD_MEMORY_TYPE_PIPELINED_NIBBLE3
#define SPD_MEMORY_TYPE_SDRAM4
#define SPD_MEMORY_TYPE_MULTIPLEXED_ROM5
#define SPD_MEMORY_TYPE_SGRAM_DDR6
#define SPD_MEMORY_TYPE_SDRAM_DDR7
#define SPD_MEMORY_TYPE_SDRAM_DDR28
#define SPD_MEMORY_TYPE_SDRAM_DDR30xb
/* SPD_MODULE_VOLTAGE values. */
#define SPD_VOLTAGE_TTL0 /* 5.0 Volt/TTL */
#define SPD_VOLTAGE_LVTTL1 /* LVTTL */
#define SPD_VOLTAGE_HSTL2 /* HSTL 1.5 */
#define SPD_VOLTAGE_SSTL33 /* SSTL 3.3 */
#define SPD_VOLTAGE_SSTL24 /* SSTL 2.5 */
/* SPD_DIMM_CONFIG_TYPE values. */
#define ERROR_SCHEME_NONE0
#define ERROR_SCHEME_PARITY1
#define ERROR_SCHEME_ECC2
/* SPD_ACCEPTABLE_CAS_LATENCIES values. */
// TODO: Check values.
#define SPD_CAS_LATENCY_1_00x01
#define SPD_CAS_LATENCY_1_50x02
#define SPD_CAS_LATENCY_2_00x04
#define SPD_CAS_LATENCY_2_50x08
#define SPD_CAS_LATENCY_3_00x10
#define SPD_CAS_LATENCY_3_50x20
#define SPD_CAS_LATENCY_4_00x40
#define SPD_CAS_LATENCY_DDR2_3(1 << 3)
#define SPD_CAS_LATENCY_DDR2_4(1 << 4)
#define SPD_CAS_LATENCY_DDR2_5(1 << 5)
#define SPD_CAS_LATENCY_DDR2_6(1 << 6)
/* SPD_SUPPORTED_BURST_LENGTHS values. */
#define SPD_BURST_LENGTH_11
#define SPD_BURST_LENGTH_22
#define SPD_BURST_LENGTH_44
#define SPD_BURST_LENGTH_88
#define SPD_BURST_LENGTH_PAGE(1 << 7)
/* SPD_MODULE_ATTRIBUTES values. */
#define MODULE_BUFFERED1
#define MODULE_REGISTERED2
#endif /* !__LIBSAIO_SPD_H */
branches/rewrite/i386/libsaio/aml_generator.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
/*
* aml_generator.c
* Chameleon
*
* Created by Mozodojo on 20/07/10.
* Copyright 2010 mozo. All rights reserved.
*
*/
#include "aml_generator.h"
bool aml_add_to_parent(struct aml_chunk* parent, struct aml_chunk* node)
{
if (parent && node)
{
switch (parent->Type)
{
case AML_CHUNK_NONE:
case AML_CHUNK_BYTE:
case AML_CHUNK_WORD:
case AML_CHUNK_DWORD:
case AML_CHUNK_QWORD:
case AML_CHUNK_ALIAS:
verbose("aml_add_to_parent: node doesn't support child nodes!\n");
return false;
case AML_CHUNK_NAME:
if (parent->First)
{
verbose("aml_add_to_parent: name node supports only one child node!\n");
return false;
}
break;
default:
break;
}
if (!parent->First)
parent->First = node;
if (parent->Last)
parent->Last->Next = node;
parent->Last = node;
return true;
}
return false;
}
struct aml_chunk* aml_create_node(struct aml_chunk* parent)
{
struct aml_chunk* node = (struct aml_chunk*)malloc(sizeof(struct aml_chunk));
aml_add_to_parent(parent, node);
return node;
}
void aml_destroy_node(struct aml_chunk* node)
{
// Delete child nodes
struct aml_chunk* child = node->First;
while (child)
{
struct aml_chunk* next = child->Next;
if (child->Buffer)
free(child->Buffer);
free(child);
child = next;
}
// Free node
if (node->Buffer)
free(node->Buffer);
free(node);
}
struct aml_chunk* aml_add_buffer(struct aml_chunk* parent, const char* buffer, unsigned int size)
{
struct aml_chunk* node = aml_create_node(parent);
if (node)
{
node->Type = AML_CHUNK_NONE;
node->Length = size;
node->Buffer = malloc(node->Length);
memcpy(node->Buffer, buffer, node->Length);
}
return node;
}
struct aml_chunk* aml_add_byte(struct aml_chunk* parent, unsigned char value)
{
struct aml_chunk* node = aml_create_node(parent);
if (node)
{
node->Type = AML_CHUNK_BYTE;
node->Length = 1;
node->Buffer = malloc(node->Length);
node->Buffer[0] = value;
}
return node;
}
struct aml_chunk* aml_add_word(struct aml_chunk* parent, unsigned int value)
{
struct aml_chunk* node = aml_create_node(parent);
if (node)
{
node->Type = AML_CHUNK_WORD;
node->Length = 2;
node->Buffer = malloc(node->Length);
node->Buffer[0] = value & 0xff;
node->Buffer[1] = value >> 8;
}
return node;
}
struct aml_chunk* aml_add_dword(struct aml_chunk* parent, unsigned long value)
{
struct aml_chunk* node = aml_create_node(parent);
if (node)
{
node->Type = AML_CHUNK_DWORD;
node->Length = 4;
node->Buffer = malloc(node->Length);
node->Buffer[0] = value & 0xff;
node->Buffer[1] = (value >> 8) & 0xff;
node->Buffer[2] = (value >> 16) & 0xff;
node->Buffer[3] = (value >> 24) & 0xff;
}
return node;
}
struct aml_chunk* aml_add_qword(struct aml_chunk* parent, unsigned long long value)
{
struct aml_chunk* node = aml_create_node(parent);
if (node)
{
node->Type = AML_CHUNK_QWORD;
node->Length = 8;
node->Buffer = malloc(node->Length);
node->Buffer[0] = value & 0xff;
node->Buffer[1] = (value >> 8) & 0xff;
node->Buffer[2] = (value >> 16) & 0xff;
node->Buffer[3] = (value >> 24) & 0xff;
node->Buffer[4] = (value >> 32) & 0xff;
node->Buffer[5] = (value >> 40) & 0xff;
node->Buffer[6] = (value >> 48) & 0xff;
node->Buffer[7] = (value >> 56) & 0xff;
}
return node;
}
unsigned int aml_fill_simple_name(char* buffer, const char* name)
{
if (strlen(name) < 4)
{
verbose("aml_fill_simple_name: simple name %s has incorrect lengh! Must be 4.\n", name);
return 0;
}
memcpy(buffer, name, 4);
return 4;
}
unsigned int aml_fill_name(struct aml_chunk* node, const char* name)
{
if (!node)
return 0;
int len = strlen(name), offset = 0, count = len / 4;
if ((len % 4) > 1 || count == 0)
{
verbose("aml_fill_name: pathname %s has incorrect length! Must be 4, 8, 12, 16, etc...\n", name);
return 0;
}
unsigned int root = 0;
if ((len % 4) == 1 && name[0] == '\\')
root++;
if (count == 1)
{
node->Length = 4 + root;
node->Buffer = malloc(node->Length);
memcpy(node->Buffer, name, 4 + root);
return node->Length;
}
if (count == 2)
{
node->Length = 2 + 8;
node->Buffer = malloc(node->Length);
node->Buffer[offset++] = 0x5c; // Root Char
node->Buffer[offset++] = 0x2e; // Double name
memcpy(node->Buffer+offset, name + root, 8);
return node->Length;
}
node->Length = 3 + count*4;
node->Buffer = malloc(node->Length);
node->Buffer[offset++] = 0x5c; // Root Char
node->Buffer[offset++] = 0x2f; // Multi name
node->Buffer[offset++] = count; // Names count
memcpy(node->Buffer+offset, name + root, count*4);
return node->Length;
}
struct aml_chunk* aml_add_scope(struct aml_chunk* parent, const char* name)
{
struct aml_chunk* node = aml_create_node(parent);
if (node)
{
node->Type = AML_CHUNK_SCOPE;
aml_fill_name(node, name);
}
return node;
}
struct aml_chunk* aml_add_name(struct aml_chunk* parent, const char* name)
{
struct aml_chunk* node = aml_create_node(parent);
if (node)
{
node->Type = AML_CHUNK_NAME;
aml_fill_name(node, name);
}
return node;
}
struct aml_chunk* aml_add_package(struct aml_chunk* parent)
{
struct aml_chunk* node = aml_create_node(parent);
if (node)
{
node->Type = AML_CHUNK_PACKAGE;
node->Length = 1;
node->Buffer = malloc(node->Length);
}
return node;
}
struct aml_chunk* aml_add_alias(struct aml_chunk* parent, const char* name1, const char* name2)
{
struct aml_chunk* node = aml_create_node(parent);
if (node)
{
node->Type = AML_CHUNK_ALIAS;
node->Length = 8;
node->Buffer = malloc(node->Length);
aml_fill_simple_name(node->Buffer, name1);
aml_fill_simple_name(node->Buffer+4, name2);
}
return node;
}
unsigned char aml_get_size_length(unsigned int size)
{
if (size + 1 <= 0x3f)
return 1;
else if (size + 2 <= 0x3fff)
return 2;
else if (size + 3 <= 0x3fffff)
return 3;
return 4;
}
unsigned int aml_calculate_size(struct aml_chunk* node)
{
if (node)
{
node->Size = 0;
// Calculate child nodes size
struct aml_chunk* child = node->First;
unsigned char child_count = 0;
while (child)
{
child_count++;
node->Size += aml_calculate_size(child);
child = child->Next;
}
switch (node->Type)
{
case AML_CHUNK_NONE:
node->Size += node->Length;
break;
case AML_CHUNK_SCOPE:
node->Size += 1 + node->Length;
node->Size += aml_get_size_length(node->Size);
break;
case AML_CHUNK_PACKAGE:
node->Buffer[0] = child_count;
node->Size += 1 + node->Length;
node->Size += aml_get_size_length(node->Size);
break;
case AML_CHUNK_BYTE:
if (node->Buffer[0] == 0x0 || node->Buffer[0] == 0x1)
{
node->Size += node->Length;
}
else
{
node->Size += 1 + node->Length;
}
break;
case AML_CHUNK_WORD:
case AML_CHUNK_DWORD:
case AML_CHUNK_QWORD:
case AML_CHUNK_ALIAS:
case AML_CHUNK_NAME:
node->Size += 1 + node->Length;
break;
}
return node->Size;
}
return 0;
}
unsigned int aml_write_byte(unsigned char value, char* buffer, unsigned int offset)
{
buffer[offset++] = value;
return offset;
}
unsigned int aml_write_word(unsigned int value, char* buffer, unsigned int offset)
{
buffer[offset++] = value & 0xff;
buffer[offset++] = value >> 8;
return offset;
}
unsigned int aml_write_dword(unsigned long value, char* buffer, unsigned int offset)
{
buffer[offset++] = value & 0xff;
buffer[offset++] = (value >> 8) & 0xff;
buffer[offset++] = (value >> 16) & 0xff;
buffer[offset++] = (value >> 24) & 0xff;
return offset;
}
unsigned int aml_write_qword(unsigned long long value, char* buffer, unsigned int offset)
{
buffer[offset++] = value & 0xff;
buffer[offset++] = (value >> 8) & 0xff;
buffer[offset++] = (value >> 16) & 0xff;
buffer[offset++] = (value >> 24) & 0xff;
buffer[offset++] = (value >> 32) & 0xff;
buffer[offset++] = (value >> 40) & 0xff;
buffer[offset++] = (value >> 48) & 0xff;
buffer[offset++] = (value >> 56) & 0xff;
return offset;
}
unsigned int aml_write_buffer(const char* value, unsigned int size, char* buffer, unsigned int offset)
{
if (size > 0)
{
memcpy(buffer + offset, value, size);
}
return offset + size;
}
unsigned int aml_write_size(unsigned int size, char* buffer, unsigned int offset)
{
if (size <= 0x3f)
{
buffer[offset++] = size;
}
else if (size <= 0x3fff)
{
buffer[offset++] = 0x40 | (size & 0xf);
buffer[offset++] = (size >> 4) & 0xff;
}
else if (size <= 0x3fffff)
{
buffer[offset++] = 0x80 | (size & 0xf);
buffer[offset++] = (size >> 4) & 0xff;
buffer[offset++] = (size >> 12) & 0xff;
}
else
{
buffer[offset++] = 0xc0 | (size & 0xf);
buffer[offset++] = (size >> 4) & 0xff;
buffer[offset++] = (size >> 12) & 0xff;
buffer[offset++] = (size >> 20) & 0xff;
}
return offset;
}
unsigned int aml_write_node(struct aml_chunk* node, char* buffer, unsigned int offset)
{
if (node && buffer)
{
unsigned int old = offset;
switch (node->Type)
{
case AML_CHUNK_NONE:
offset = aml_write_buffer(node->Buffer, node->Length, buffer, offset);
break;
case AML_CHUNK_SCOPE:
case AML_CHUNK_PACKAGE:
offset = aml_write_byte(node->Type, buffer, offset);
offset = aml_write_size(node->Size-1, buffer, offset);
offset = aml_write_buffer(node->Buffer, node->Length, buffer, offset);
break;
case AML_CHUNK_BYTE:
if (node->Buffer[0] == 0x0 || node->Buffer[0] == 0x1)
{
offset = aml_write_buffer(node->Buffer, node->Length, buffer, offset);
}
else
{
offset = aml_write_byte(node->Type, buffer, offset);
offset = aml_write_buffer(node->Buffer, node->Length, buffer, offset);
}
break;
case AML_CHUNK_WORD:
case AML_CHUNK_DWORD:
case AML_CHUNK_QWORD:
case AML_CHUNK_ALIAS:
case AML_CHUNK_NAME:
offset = aml_write_byte(node->Type, buffer, offset);
offset = aml_write_buffer(node->Buffer, node->Length, buffer, offset);
break;
default:
break;
}
struct aml_chunk* child = node->First;
while (child)
{
offset = aml_write_node(child, buffer, offset);
child = child->Next;
}
if (offset - old != node->Size)
verbose("Node size incorrect: 0x%x\n", node->Type);
}
return offset;
}
branches/rewrite/i386/libsaio/aml_generator.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/*
* aml_generator.h
* Chameleon
*
* Created by Mozodojo on 20/07/10.
* Copyright 2010 mozo. All rights reserved.
*
*/
#ifndef __LIBSAIO_AML_GENERATOR_H
#define __LIBSAIO_AML_GENERATOR_H
#include "libsaio.h"
#defineAML_CHUNK_NONE0xff
#defineAML_CHUNK_ZERO0x00
#defineAML_CHUNK_ONE0x01
#defineAML_CHUNK_ALIAS0x06
#defineAML_CHUNK_NAME0x08
#defineAML_CHUNK_BYTE0x0A
#defineAML_CHUNK_WORD0x0B
#defineAML_CHUNK_DWORD0x0C
#defineAML_CHUNK_STRING0x0D
#defineAML_CHUNK_QWORD0x0E
#defineAML_CHUNK_SCOPE0x10
#defineAML_CHUNK_PACKAGE0x12
struct aml_chunk
{
unsigned charType;
unsigned intLength;
char*Buffer;
unsigned intSize;
struct aml_chunk*Next;
struct aml_chunk*First;
struct aml_chunk*Last;
};
static inline bool aml_isvalidchar(char c)
{
return isupper(c) || isdigit(c) || c == '_';
};
bool aml_add_to_parent(struct aml_chunk* parent, struct aml_chunk* node);
struct aml_chunk* aml_create_node(struct aml_chunk* parent);
void aml_destroy_node(struct aml_chunk* node);
struct aml_chunk* aml_add_buffer(struct aml_chunk* parent, const char* buffer, unsigned int size);
struct aml_chunk* aml_add_byte(struct aml_chunk* parent, unsigned char value);
struct aml_chunk* aml_add_word(struct aml_chunk* parent, unsigned int value);
struct aml_chunk* aml_add_dword(struct aml_chunk* parent, unsigned long value);
struct aml_chunk* aml_add_qword(struct aml_chunk* parent, unsigned long long value);
struct aml_chunk* aml_add_scope(struct aml_chunk* parent, const char* name);
struct aml_chunk* aml_add_name(struct aml_chunk* parent, const char* name);
struct aml_chunk* aml_add_package(struct aml_chunk* parent);
struct aml_chunk* aml_add_alias(struct aml_chunk* parent, const char* name1, const char* name2);
unsigned int aml_calculate_size(struct aml_chunk* node);
unsigned int aml_write_node(struct aml_chunk* node, char* buffer, unsigned int offset);
#endif /* !__LIBSAIO_AML_GENERATOR_H */
branches/rewrite/i386/libsaio/dram_controllers.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
/*
* dram controller access and scan from the pci host controller
* Integrated and adapted for chameleon 2.0 RC5 by Rekursor from bs0d work
* original source comes from:
*
* memtest86
*
* Released under version 2 of the Gnu Public License.
* By Chris Brady, cbrady@sgi.com
* ----------------------------------------------------
* MemTest86+ V4.00 Specific code (GPL V2.0)
* By Samuel DEMEULEMEESTER, sdemeule@memtest.org
* http://www.canardpc.com - http://www.memtest.org
*/
#include "libsaio.h"
#include "pci.h"
#include "platform.h"
#include "dram_controllers.h"
#ifndef DEBUG_DRAM
#define DEBUG_DRAM 0
#endif
#if DEBUG_DRAM
#define DBG(x...) printf(x)
#else
#define DBG(x...)
#endif
/*
* Initialise memory controller functions
*/
// Setup P35 Memory Controller
static void setup_p35(pci_dt_t *dram_dev)
{
uint32_t dev0;
// Activate MMR I/O
dev0 = pci_config_read32(dram_dev->dev.addr, 0x48);
if (!(dev0 & 0x1))
pci_config_write8(dram_dev->dev.addr, 0x48, (dev0 | 1));
}
int nhm_bus = 0x3F;
// Setup Nehalem Integrated Memory Controller
static void setup_nhm(pci_dt_t *dram_dev)
{
static long possible_nhm_bus[] = {0xFF, 0x7F, 0x3F};
unsigned long did, vid;
int i;
// Nehalem supports Scrubbing
// First, locate the PCI bus where the MCH is located
for(i = 0; i < sizeof(possible_nhm_bus); i++)
{
vid = pci_config_read16(PCIADDR(possible_nhm_bus[i], 3, 4), PCI_VENDOR_ID);
did = pci_config_read16(PCIADDR(possible_nhm_bus[i], 3, 4), PCI_DEVICE_ID);
vid &= 0xFFFF;
did &= 0xFF00;
if(vid == 0x8086 && did >= 0x2C00)
nhm_bus = possible_nhm_bus[i];
}
}
/*
* Retrieve memory controller fsb functions
*/
// Get i965 Memory Speed
static void get_fsb_i965(pci_dt_t *dram_dev)
{
uint32_t dev0, mch_ratio, mch_cfg, mch_fsb;
long *ptr;
// Find Ratio
dev0 = pci_config_read32(dram_dev->dev.addr, 0x48);
dev0 &= 0xFFFFC000;
ptr = (long*)(dev0 + 0xC00);
mch_cfg = *ptr & 0xFFFF;
mch_ratio = 100000;
switch (mch_cfg & 7)
{
case 0: mch_fsb = 1066; break;
case 1: mch_fsb = 533; break;
default:
case 2: mch_fsb = 800; break;
case 3: mch_fsb = 667; break;
case 4: mch_fsb = 1333; break;
case 6: mch_fsb = 1600; break;
}
DBG("mch_fsb %d\n", mch_fsb);
switch (mch_fsb)
{
case 533:
switch ((mch_cfg >> 4) & 7)
{
case 1:mch_ratio = 200000; break;
case 2:mch_ratio = 250000; break;
case 3:mch_ratio = 300000; break;
}
break;
default:
case 800:
switch ((mch_cfg >> 4) & 7)
{
case 0:mch_ratio = 100000; break;
case 1:mch_ratio = 125000; break;
case 2:mch_ratio = 166667; break; // 1.666666667
case 3:mch_ratio = 200000; break;
case 4:mch_ratio = 266667; break; // 2.666666667
case 5:mch_ratio = 333333; break; // 3.333333333
}
break;
case 1066:
switch ((mch_cfg >> 4) & 7)
{
case 1:mch_ratio = 100000; break;
case 2:mch_ratio = 125000; break;
case 3:mch_ratio = 150000; break;
case 4:mch_ratio = 200000; break;
case 5:mch_ratio = 250000; break;
}
break;
case 1333:
switch ((mch_cfg >> 4) & 7)
{
case 2:mch_ratio = 100000; break;
case 3:mch_ratio = 120000; break;
case 4:mch_ratio = 160000; break;
case 5:mch_ratio = 200000; break;
}
break;
case 1600:
switch ((mch_cfg >> 4) & 7)
{
case 3:mch_ratio = 100000; break;
case 4:mch_ratio = 133333; break; // 1.333333333
case 5:mch_ratio = 150000; break;
case 6:mch_ratio = 200000; break;
}
break;
}
DBG("mch_ratio %d\n", mch_ratio);
// Compute RAM Frequency
Platform.RAM.Frequency = (Platform.CPU.FSBFrequency * mch_ratio) / 100000;
DBG("ram_fsb %d\n", Platform.RAM.Frequency);
}
// Get i965m Memory Speed
static void get_fsb_im965(pci_dt_t *dram_dev)
{
uint32_t dev0, mch_ratio, mch_cfg, mch_fsb;
long *ptr;
// Find Ratio
dev0 = pci_config_read32(dram_dev->dev.addr, 0x48);
dev0 &= 0xFFFFC000;
ptr = (long*)(dev0 + 0xC00);
mch_cfg = *ptr & 0xFFFF;
mch_ratio = 100000;
switch (mch_cfg & 7)
{
case 1: mch_fsb = 533; break;
default:
case 2:mch_fsb = 800; break;
case 3:mch_fsb = 667; break;
case 6:mch_fsb = 1066; break;
}
switch (mch_fsb)
{
case 533:
switch ((mch_cfg >> 4) & 7)
{
case 1:mch_ratio = 125000; break;
case 2:mch_ratio = 150000; break;
case 3:mch_ratio = 200000; break;
}
break;
case 667:
switch ((mch_cfg >> 4)& 7)
{
case 1:mch_ratio = 100000; break;
case 2:mch_ratio = 120000; break;
case 3:mch_ratio = 160000; break;
case 4:mch_ratio = 200000; break;
case 5:mch_ratio = 240000; break;
}
break;
default:
case 800:
switch ((mch_cfg >> 4) & 7)
{
case 1:mch_ratio = 83333; break; // 0.833333333
case 2:mch_ratio = 100000; break;
case 3:mch_ratio = 133333; break; // 1.333333333
case 4:mch_ratio = 166667; break; // 1.666666667
case 5:mch_ratio = 200000; break;
}
break;
case 1066:
switch ((mch_cfg >> 4)&7) {
case 5:mch_ratio = 150000; break;
case 6:mch_ratio = 200000; break;
}
}
// Compute RAM Frequency
Platform.RAM.Frequency = (Platform.CPU.FSBFrequency * mch_ratio) / 100000;
}
// Get iCore7 Memory Speed
static void get_fsb_nhm(pci_dt_t *dram_dev)
{
uint32_t mch_ratio, mc_dimm_clk_ratio;
// Get the clock ratio
mc_dimm_clk_ratio = pci_config_read16(PCIADDR(nhm_bus, 3, 4), 0x54 );
mch_ratio = (mc_dimm_clk_ratio & 0x1F);
// Compute RAM Frequency
Platform.RAM.Frequency = Platform.CPU.FSBFrequency * mch_ratio / 2;
}
/*
* Retrieve memory controller info functions
*/
// Get i965 Memory Timings
static void get_timings_i965(pci_dt_t *dram_dev)
{
// Thanks for CDH optis
uint32_t dev0, c0ckectrl, c1ckectrl, offset;
uint32_t ODT_Control_Register, Precharge_Register, ACT_Register, Read_Register, Misc_Register;
long *ptr;
// Read MMR Base Address
dev0 = pci_config_read32(dram_dev->dev.addr, 0x48);
dev0 &= 0xFFFFC000;
ptr = (long*)(dev0 + 0x260);
c0ckectrl = *ptr & 0xFFFFFFFF;
ptr = (long*)(dev0 + 0x660);
c1ckectrl = *ptr & 0xFFFFFFFF;
// If DIMM 0 not populated, check DIMM 1
((c0ckectrl) >> 20 & 0xF) ? (offset = 0) : (offset = 0x400);
ptr = (long*)(dev0 + offset + 0x29C);
ODT_Control_Register = *ptr & 0xFFFFFFFF;
ptr = (long*)(dev0 + offset + 0x250);
Precharge_Register = *ptr & 0xFFFFFFFF;
ptr = (long*)(dev0 + offset + 0x252);
ACT_Register = *ptr & 0xFFFFFFFF;
ptr = (long*)(dev0 + offset + 0x258);
Read_Register = *ptr & 0xFFFFFFFF;
ptr = (long*)(dev0 + offset + 0x244);
Misc_Register = *ptr & 0xFFFFFFFF;
// 965 Series only support DDR2
Platform.RAM.Type = SMB_MEM_TYPE_DDR2;
// CAS Latency (tCAS)
Platform.RAM.CAS = ((ODT_Control_Register >> 17) & 7) + 3;
// RAS-To-CAS (tRCD)
Platform.RAM.TRC = (Read_Register >> 16) & 0xF;
// RAS Precharge (tRP)
Platform.RAM.TRP = (ACT_Register >> 13) & 0xF;
// RAS Active to precharge (tRAS)
Platform.RAM.RAS = (Precharge_Register >> 11) & 0x1F;
if ((c0ckectrl >> 20 & 0xF) && (c1ckectrl >> 20 & 0xF))
Platform.RAM.Channels = SMB_MEM_CHANNEL_DUAL;
else
Platform.RAM.Channels = SMB_MEM_CHANNEL_SINGLE;
}
// Get im965 Memory Timings
static void get_timings_im965(pci_dt_t *dram_dev)
{
// Thanks for CDH optis
uint32_t dev0, c0ckectrl, c1ckectrl, offset, ODT_Control_Register, Precharge_Register;
long *ptr;
// Read MMR Base Address
dev0 = pci_config_read32(dram_dev->dev.addr, 0x48);
dev0 &= 0xFFFFC000;
ptr = (long*)(dev0 + 0x1200);
c0ckectrl = *ptr & 0xFFFFFFFF;
ptr = (long*)(dev0 + 0x1300);
c1ckectrl = *ptr & 0xFFFFFFFF;
// If DIMM 0 not populated, check DIMM 1
((c0ckectrl) >> 20 & 0xF) ? (offset = 0) : (offset = 0x100);
ptr = (long*)(dev0 + offset + 0x121C);
ODT_Control_Register = *ptr & 0xFFFFFFFF;
ptr = (long*)(dev0 + offset + 0x1214);
Precharge_Register = *ptr & 0xFFFFFFFF;
// Series only support DDR2
Platform.RAM.Type = SMB_MEM_TYPE_DDR2;
// CAS Latency (tCAS)
Platform.RAM.CAS = ((ODT_Control_Register >> 23) & 7) + 3;
// RAS-To-CAS (tRCD)
Platform.RAM.TRC = ((Precharge_Register >> 5) & 7) + 2;
// RAS Precharge (tRP)
Platform.RAM.TRP= (Precharge_Register & 7) + 2;
// RAS Active to precharge (tRAS)
Platform.RAM.RAS = (Precharge_Register >> 21) & 0x1F;
if ((c0ckectrl >> 20 & 0xF) && (c1ckectrl >> 20 & 0xF))
Platform.RAM.Channels = SMB_MEM_CHANNEL_DUAL;
else
Platform.RAM.Channels = SMB_MEM_CHANNEL_SINGLE;
}
// Get P35 Memory Timings
static void get_timings_p35(pci_dt_t *dram_dev)
{
// Thanks for CDH optis
unsigned long dev0, Memory_Check, c0ckectrl, c1ckectrl, offset;
unsigned long ODT_Control_Register, Precharge_Register, ACT_Register, Read_Register, Misc_Register;
long *ptr;
//Device_ID = pci_config_read16(dram_dev->dev.addr, 0x02);
//Device_ID &= 0xFFFF;
// Now, read MMR Base Address
dev0 = pci_config_read32(dram_dev->dev.addr, 0x48);
dev0 &= 0xFFFFC000;
ptr = (long*)(dev0 + 0x260);
c0ckectrl = *ptr & 0xFFFFFFFF;
ptr = (long*)(dev0 + 0x660);
c1ckectrl = *ptr & 0xFFFFFFFF;
// If DIMM 0 not populated, check DIMM 1
((c0ckectrl) >> 20 & 0xF) ? (offset = 0) : (offset = 0x400);
ptr = (long*)(dev0 + offset + 0x265);
ODT_Control_Register = *ptr & 0xFFFFFFFF;
ptr = (long*)(dev0 + offset + 0x25D);
Precharge_Register = *ptr & 0xFFFFFFFF;
ptr = (long*)(dev0 + offset + 0x252);
ACT_Register = *ptr & 0xFFFFFFFF;
ptr = (long*)(dev0 + offset + 0x258);
Read_Register = *ptr & 0xFFFFFFFF;
ptr = (long*)(dev0 + offset + 0x244);
Misc_Register = *ptr & 0xFFFFFFFF;
ptr = (long*)(dev0 + offset + 0x1E8);
Memory_Check = *ptr & 0xFFFFFFFF;
// On P45, check 1A8
if(dram_dev->device_id > 0x2E00) {
ptr = (long*)(dev0 + offset + 0x1A8);
Memory_Check = *ptr & 0xFFFFFFFF;
Memory_Check >>= 2;
Memory_Check &= 1;
Memory_Check = !Memory_Check;
} else {
ptr = (long*)(dev0 + offset + 0x1E8);
Memory_Check = *ptr & 0xFFFFFFFF;
}
// Determine DDR-II or DDR-III
if (Memory_Check & 1)
Platform.RAM.Type = SMB_MEM_TYPE_DDR2;
else
Platform.RAM.Type = SMB_MEM_TYPE_DDR3;
// CAS Latency (tCAS)
if(dram_dev->device_id > 0x2E00)
Platform.RAM.CAS = ((ODT_Control_Register >> 8) & 0x3F) - 6;
else
Platform.RAM.CAS = ((ODT_Control_Register >> 8) & 0x3F) - 9;
// RAS-To-CAS (tRCD)
Platform.RAM.TRC = (Read_Register >> 17) & 0xF;
// RAS Precharge (tRP)
Platform.RAM.TRP = (ACT_Register >> 13) & 0xF;
// RAS Active to precharge (tRAS)
Platform.RAM.RAS = Precharge_Register & 0x3F;
// Channel configuration
if (((c0ckectrl >> 20) & 0xF) && ((c1ckectrl >> 20) & 0xF))
Platform.RAM.Channels = SMB_MEM_CHANNEL_DUAL;
else
Platform.RAM.Channels = SMB_MEM_CHANNEL_SINGLE;
}
// Get Nehalem Memory Timings
static void get_timings_nhm(pci_dt_t *dram_dev)
{
unsigned long mc_channel_bank_timing, mc_control, mc_channel_mrs_value;
int fvc_bn = 4;
// Find which channels are populated
mc_control = pci_config_read16(PCIADDR(nhm_bus, 3, 0), 0x48);
mc_control = (mc_control >> 8) & 0x7;
// DDR-III
Platform.RAM.Type = SMB_MEM_TYPE_DDR3;
// Get the first valid channel
if(mc_control & 1)
fvc_bn = 4;
else if(mc_control & 2)
fvc_bn = 5;
else if(mc_control & 7)
fvc_bn = 6;
// Now, detect timings
mc_channel_bank_timing = pci_config_read32(PCIADDR(nhm_bus, fvc_bn, 0), 0x88);
mc_channel_mrs_value = pci_config_read32(PCIADDR(nhm_bus, fvc_bn, 0), 0x70);
// CAS Latency (tCAS)
Platform.RAM.CAS = ((mc_channel_mrs_value >> 4) & 0xF ) + 4;
// RAS-To-CAS (tRCD)
Platform.RAM.TRC = (mc_channel_bank_timing >> 9) & 0xF;
// RAS Active to precharge (tRAS)
Platform.RAM.RAS = (mc_channel_bank_timing >> 4) & 0x1F;
// RAS Precharge (tRP)
Platform.RAM.TRP = mc_channel_bank_timing & 0xF;
// Single , Dual or Triple Channels
if (mc_control == 1 || mc_control == 2 || mc_control == 4 )
Platform.RAM.Channels = SMB_MEM_CHANNEL_SINGLE;
else if (mc_control == 7)
Platform.RAM.Channels = SMB_MEM_CHANNEL_TRIPLE;
else
Platform.RAM.Channels = SMB_MEM_CHANNEL_DUAL;
}
static struct mem_controller_t dram_controllers[] = {
// Default unknown chipset
{ 0, 0, "",NULL, NULL, NULL },
// Intel
{ 0x8086, 0x7190, "VMWare",NULL, NULL, NULL },
{ 0x8086, 0x1A30, "i845",NULL, NULL, NULL },
{ 0x8086, 0x2970, "i946PL/GZ",setup_p35, get_fsb_i965,get_timings_i965},
{ 0x8086, 0x2990, "Q963/Q965",setup_p35, get_fsb_i965,get_timings_i965},
{ 0x8086, 0x29A0, "P965/G965",setup_p35, get_fsb_i965,get_timings_i965},
{ 0x8086, 0x2A00, "GM965/GL960",setup_p35, get_fsb_im965,get_timings_im965},
{ 0x8086, 0x2A10, "GME965/GLE960",setup_p35, get_fsb_im965,get_timings_im965},
{ 0x8086, 0x2A40, "PM/GM45/47",setup_p35, get_fsb_im965,get_timings_im965},
{ 0x8086, 0x29B0, "Q35",setup_p35, get_fsb_i965,get_timings_p35},
{ 0x8086, 0x29C0, "P35/G33",setup_p35, get_fsb_i965,get_timings_p35},
{ 0x8086, 0x29D0, "Q33",setup_p35, get_fsb_i965,get_timings_p35},
{ 0x8086, 0x29E0, "X38/X48",setup_p35, get_fsb_i965,get_timings_p35},
{ 0x8086, 0x2E00, "Eaglelake",setup_p35, get_fsb_i965,get_timings_p35},
{ 0x8086, 0x2E10, "Q45/Q43",setup_p35, get_fsb_i965,get_timings_p35},
{ 0x8086, 0x2E20, "P45/G45",setup_p35, get_fsb_i965,get_timings_p35},
{ 0x8086, 0x2E30, "G41",setup_p35, get_fsb_i965,get_timings_p35},
{ 0x8086, 0xD131, "NHM IMC",setup_nhm, get_fsb_nhm,get_timings_nhm},
{ 0x8086, 0xD132, "NHM IMC",setup_nhm, get_fsb_nhm,get_timings_nhm},
{ 0x8086, 0x3400, "NHM IMC",setup_nhm, get_fsb_nhm,get_timings_nhm},
{ 0x8086, 0x3401, "NHM IMC",setup_nhm, get_fsb_nhm,get_timings_nhm},
{ 0x8086, 0x3402, "NHM IMC",setup_nhm, get_fsb_nhm,get_timings_nhm},
{ 0x8086, 0x3403, "NHM IMC",setup_nhm, get_fsb_nhm,get_timings_nhm},
{ 0x8086, 0x3404, "NHM IMC",setup_nhm, get_fsb_nhm,get_timings_nhm},
{ 0x8086, 0x3405, "NHM IMC",setup_nhm, get_fsb_nhm,get_timings_nhm},
{ 0x8086, 0x3406, "NHM IMC",setup_nhm, get_fsb_nhm,get_timings_nhm},
{ 0x8086, 0x3407, "NHM IMC",setup_nhm, get_fsb_nhm,get_timings_nhm},
};
static const char *memory_channel_types[] =
{
"Unknown", "Single", "Dual", "Triple"
};
void scan_dram_controller(pci_dt_t *dram_dev)
{
int i;
for(i = 1; i < sizeof(dram_controllers) / sizeof(dram_controllers[0]); i++)
if ((dram_controllers[i].vendor == dram_dev->vendor_id)
&& (dram_controllers[i].device == dram_dev->device_id))
{
verbose("%s%s DRAM Controller [%4x:%4x] at %02x:%02x.%x\n",
(dram_dev->vendor_id == 0x8086) ? "Intel " : "" ,
dram_controllers[i].name, dram_dev->vendor_id, dram_dev->device_id,
dram_dev->dev.bits.bus, dram_dev->dev.bits.dev, dram_dev->dev.bits.func);
if (dram_controllers[i].initialise != NULL)
dram_controllers[i].initialise(dram_dev);
if (dram_controllers[i].poll_timings != NULL)
dram_controllers[i].poll_timings(dram_dev);
if (dram_controllers[i].poll_speed != NULL)
dram_controllers[i].poll_speed(dram_dev);
verbose("Frequency detected: %d MHz (%d) %s Channel \n\tCAS:%d tRC:%d tRP:%d RAS:%d (%d-%d-%d-%d)\n",
(uint32_t)Platform.RAM.Frequency / 1000000,
(uint32_t)Platform.RAM.Frequency / 500000,
memory_channel_types[Platform.RAM.Channels]
,Platform.RAM.CAS, Platform.RAM.TRC, Platform.RAM.TRP, Platform.RAM.RAS
,Platform.RAM.CAS, Platform.RAM.TRC, Platform.RAM.TRP, Platform.RAM.RAS
);
//getchar();
}
}
branches/rewrite/i386/libsaio/dram_controllers.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/*
* dram controller access and scan from the pci host controller
* Integrated and adapted for chameleon 2.0 RC5 by Rekursor from bs0d work
* original source comes from:
*
* memtest86
*
* Released under version 2 of the Gnu Public License.
* By Chris Brady, cbrady@sgi.com
* ----------------------------------------------------
* MemTest86+ V4.00 Specific code (GPL V2.0)
* By Samuel DEMEULEMEESTER, sdemeule@memtest.org
* http://www.canardpc.com - http://www.memtest.org
*/
#ifndef __LIBSAIO_DRAM_CONTROLLERS_H
#define __LIBSAIO_DRAM_CONTROLLERS_H
#include "libsaio.h"
void scan_dram_controller();
struct mem_controller_t {
uint16_t vendor;
uint16_t device;
char *name;
void (*initialise)(pci_dt_t *dram_dev);
void (*poll_speed)(pci_dt_t *dram_dev);
void (*poll_timings)(pci_dt_t *dram_dev);
};
#endif /* !__LIBSAIO_DRAM_CONTROLLERS_H */
branches/rewrite/i386/libsaio/platform.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/*
* platform.c
*
* AsereBLN: cleanup
*/
#include "libsaio.h"
#include "boot.h"
#include "pci.h"
#include "platform.h"
#include "cpu.h"
#include "spd.h"
#include "dram_controllers.h"
#ifndef DEBUG_PLATFORM
#define DEBUG_PLATFORM 0
#endif
#if DEBUG_PLATFORM
#define DBG(x...)printf(x)
#else
#define DBG(x...)
#endif
PlatformInfo_t Platform;
pci_dt_t * dram_controller_dev = NULL;
/** Return if a CPU feature specified by feature is activated (true) or not (false) */
bool platformCPUFeature(uint32_t feature)
{
if (Platform.CPU.Features & feature) {
return true;
} else {
return false;
}
}
/**
Scan platform hardware information, called by the main entry point (common_boot() )
_before_ bootConfig xml parsing settings are loaded
*/
void scan_platform(void)
{
memset(&Platform, 0, sizeof(Platform));
build_pci_dt();
scan_cpu(&Platform);
}
branches/rewrite/i386/libsaio/cpu.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
/*
* Copyright 2008 Islam Ahmed Zaid. All rights reserved. <azismed@gmail.com>
* AsereBLN: 2009: cleanup and bugfix
*/
#include "libsaio.h"
#include "platform.h"
#include "cpu.h"
#include "boot.h"
#ifndef DEBUG_CPU
#define DEBUG_CPU 0
#endif
#if DEBUG_CPU
#define DBG(x...)printf(x)
#else
#define DBG(x...)msglog(x)
#endif
/*
* DFE: Measures the TSC frequency in Hz (64-bit) using the ACPI PM timer
*/
static uint64_t measure_tsc_frequency(void)
{
uint64_t tscStart;
uint64_t tscEnd;
uint64_t tscDelta = 0xffffffffffffffffULL;
unsigned long pollCount;
uint64_t retval = 0;
int i;
/* Time how many TSC ticks elapse in 30 msec using the 8254 PIT
* counter 2. We run this loop 3 times to make sure the cache
* is hot and we take the minimum delta from all of the runs.
* That is to say that we're biased towards measuring the minimum
* number of TSC ticks that occur while waiting for the timer to
* expire. That theoretically helps avoid inconsistencies when
* running under a VM if the TSC is not virtualized and the host
* steals time. The TSC is normally virtualized for VMware.
*/
for(i = 0; i < 10; ++i)
{
enable_PIT2();
set_PIT2_mode0(CALIBRATE_LATCH);
tscStart = rdtsc64();
pollCount = poll_PIT2_gate();
tscEnd = rdtsc64();
/* The poll loop must have run at least a few times for accuracy */
if(pollCount <= 1)
continue;
/* The TSC must increment at LEAST once every millisecond. We
* should have waited exactly 30 msec so the TSC delta should
* be >= 30. Anything less and the processor is way too slow.
*/
if((tscEnd - tscStart) <= CALIBRATE_TIME_MSEC)
continue;
// tscDelta = MIN(tscDelta, (tscEnd - tscStart))
if( (tscEnd - tscStart) < tscDelta )
tscDelta = tscEnd - tscStart;
}
/* tscDelta is now the least number of TSC ticks the processor made in
* a timespan of 0.03 s (e.g. 30 milliseconds)
* Linux thus divides by 30 which gives the answer in kiloHertz because
* 1 / ms = kHz. But we're xnu and most of the rest of the code uses
* Hz so we need to convert our milliseconds to seconds. Since we're
* dividing by the milliseconds, we simply multiply by 1000.
*/
/* Unlike linux, we're not limited to 32-bit, but we do need to take care
* that we're going to multiply by 1000 first so we do need at least some
* arithmetic headroom. For now, 32-bit should be enough.
* Also unlike Linux, our compiler can do 64-bit integer arithmetic.
*/
if(tscDelta > (1ULL<<32))
retval = 0;
else
{
retval = tscDelta * 1000 / 30;
}
disable_PIT2();
return retval;
}
/*
* Calculates the FSB and CPU frequencies using specific MSRs for each CPU
* - multi. is read from a specific MSR. In the case of Intel, there is:
* a max multi. (used to calculate the FSB freq.),
* and a current multi. (used to calculate the CPU freq.)
* - fsbFrequency = tscFrequency / multi
* - cpuFrequency = fsbFrequency * multi
*/
void scan_cpu(PlatformInfo_t *p)
{
uint64_ttscFrequency, fsbFrequency, cpuFrequency;
uint64_tmsr, flex_ratio;
uint8_tmaxcoef, maxdiv, currcoef, bus_ratio_max, currdiv;
int myfsb;
uint8_t bus_ratio_min;
uint32_t max_ratio, min_ratio;
max_ratio = min_ratio = myfsb = bus_ratio_min = 0;
maxcoef = maxdiv = bus_ratio_max = currcoef = currdiv = 0;
/* get cpuid values */
do_cpuid(0x00000000, p->CPU.CPUID[CPUID_0]);
do_cpuid(0x00000001, p->CPU.CPUID[CPUID_1]);
do_cpuid(0x00000002, p->CPU.CPUID[CPUID_2]);
do_cpuid(0x00000003, p->CPU.CPUID[CPUID_3]);
do_cpuid2(0x00000004, 0, p->CPU.CPUID[CPUID_4]);
do_cpuid(0x80000000, p->CPU.CPUID[CPUID_80]);
if ((p->CPU.CPUID[CPUID_80][0] & 0x0000000f) >= 1) {
do_cpuid(0x80000001, p->CPU.CPUID[CPUID_81]);
}
#if DEBUG_CPU
{
inti;
printf("CPUID Raw Values:\n");
for (i=0; i<CPUID_MAX; i++) {
printf("%02d: %08x-%08x-%08x-%08x\n", i,
p->CPU.CPUID[i][0], p->CPU.CPUID[i][1],
p->CPU.CPUID[i][2], p->CPU.CPUID[i][3]);
}
}
#endif
p->CPU.Vendor= p->CPU.CPUID[CPUID_0][1];
p->CPU.Signature= p->CPU.CPUID[CPUID_1][0];
p->CPU.Stepping= bitfield(p->CPU.CPUID[CPUID_1][0], 3, 0);
p->CPU.Model= bitfield(p->CPU.CPUID[CPUID_1][0], 7, 4);
p->CPU.Family= bitfield(p->CPU.CPUID[CPUID_1][0], 11, 8);
p->CPU.ExtModel= bitfield(p->CPU.CPUID[CPUID_1][0], 19, 16);
p->CPU.ExtFamily= bitfield(p->CPU.CPUID[CPUID_1][0], 27, 20);
p->CPU.Model += (p->CPU.ExtModel << 4);
if (p->CPU.Vendor == 0x756E6547 /* Intel */ &&
p->CPU.Family == 0x06 &&
p->CPU.Model >= CPUID_MODEL_NEHALEM &&
p->CPU.Model != CPUID_MODEL_ATOM // MSR is *NOT* available on the Intel Atom CPU
){
msr = rdmsr64(MSR_CORE_THREAD_COUNT);// Undocumented MSR in Nehalem and newer CPUs
p->CPU.NoCores= bitfield((uint32_t)msr, 31, 16);// Using undocumented MSR to get actual values
p->CPU.NoThreads= bitfield((uint32_t)msr, 15, 0);// Using undocumented MSR to get actual values
} else {
p->CPU.NoThreads= bitfield(p->CPU.CPUID[CPUID_1][1], 23, 16);// Use previous method for Cores and Threads
p->CPU.NoCores= bitfield(p->CPU.CPUID[CPUID_4][0], 31, 26) + 1;
}
/* get brand string (if supported) */
/* Copyright: from Apple's XNU cpuid.c */
if (p->CPU.CPUID[CPUID_80][0] > 0x80000004) {
uint32_treg[4];
char str[128], *s;
/*
* The brand string 48 bytes (max), guaranteed to
* be NULL terminated.
*/
do_cpuid(0x80000002, reg);
bcopy((char *)reg, &str[0], 16);
do_cpuid(0x80000003, reg);
bcopy((char *)reg, &str[16], 16);
do_cpuid(0x80000004, reg);
bcopy((char *)reg, &str[32], 16);
for (s = str; *s != '\0'; s++) {
if (*s != ' ') break;
}
strlcpy(p->CPU.BrandString,s, sizeof(p->CPU.BrandString));
if (!strncmp(p->CPU.BrandString, CPU_STRING_UNKNOWN, MIN(sizeof(p->CPU.BrandString), strlen(CPU_STRING_UNKNOWN) + 1))) {
/*
* This string means we have a firmware-programmable brand string,
* and the firmware couldn't figure out what sort of CPU we have.
*/
p->CPU.BrandString[0] = '\0';
}
}
/* setup features */
if ((bit(23) & p->CPU.CPUID[CPUID_1][3]) != 0) {
p->CPU.Features |= CPU_FEATURE_MMX;
}
if ((bit(25) & p->CPU.CPUID[CPUID_1][3]) != 0) {
p->CPU.Features |= CPU_FEATURE_SSE;
}
if ((bit(26) & p->CPU.CPUID[CPUID_1][3]) != 0) {
p->CPU.Features |= CPU_FEATURE_SSE2;
}
if ((bit(0) & p->CPU.CPUID[CPUID_1][2]) != 0) {
p->CPU.Features |= CPU_FEATURE_SSE3;
}
if ((bit(19) & p->CPU.CPUID[CPUID_1][2]) != 0) {
p->CPU.Features |= CPU_FEATURE_SSE41;
}
if ((bit(20) & p->CPU.CPUID[CPUID_1][2]) != 0) {
p->CPU.Features |= CPU_FEATURE_SSE42;
}
if ((bit(29) & p->CPU.CPUID[CPUID_81][3]) != 0) {
p->CPU.Features |= CPU_FEATURE_EM64T;
}
if ((bit(5) & p->CPU.CPUID[CPUID_1][3]) != 0) {
p->CPU.Features |= CPU_FEATURE_MSR;
}
//if ((bit(28) & p->CPU.CPUID[CPUID_1][3]) != 0) {
if (p->CPU.NoThreads > p->CPU.NoCores) {
p->CPU.Features |= CPU_FEATURE_HTT;
}
tscFrequency = measure_tsc_frequency();
fsbFrequency = 0;
cpuFrequency = 0;
if ((p->CPU.Vendor == 0x756E6547 /* Intel */) && ((p->CPU.Family == 0x06) || (p->CPU.Family == 0x0f))) {
int intelCPU = p->CPU.Model;
if ((p->CPU.Family == 0x06 && p->CPU.Model >= 0x0c) || (p->CPU.Family == 0x0f && p->CPU.Model >= 0x03)) {
/* Nehalem CPU model */
if (p->CPU.Family == 0x06 && (p->CPU.Model == CPU_MODEL_NEHALEM ||
p->CPU.Model == CPU_MODEL_FIELDS ||
p->CPU.Model == CPU_MODEL_DALES ||
p->CPU.Model == CPU_MODEL_DALES_32NM ||
p->CPU.Model == CPU_MODEL_WESTMERE ||
p->CPU.Model == CPU_MODEL_NEHALEM_EX ||
p->CPU.Model == CPU_MODEL_WESTMERE_EX ||
p->CPU.Model == CPU_MODEL_SANDY ||
p->CPU.Model == CPU_MODEL_SANDY_XEON)) {
msr = rdmsr64(MSR_PLATFORM_INFO);
DBG("msr(%d): platform_info %08x\n", __LINE__, msr & 0xffffffff);
bus_ratio_max = (msr >> 8) & 0xff;
bus_ratio_min = (msr >> 40) & 0xff; //valv: not sure about this one (Remarq.1)
msr = rdmsr64(MSR_FLEX_RATIO);
DBG("msr(%d): flex_ratio %08x\n", __LINE__, msr & 0xffffffff);
if ((msr >> 16) & 0x01) {
flex_ratio = (msr >> 8) & 0xff;
/* bcc9: at least on the gigabyte h67ma-ud2h,
where the cpu multipler can't be changed to
allow overclocking, the flex_ratio msr has unexpected (to OSX)
contents. These contents cause mach_kernel to
fail to compute the bus ratio correctly, instead
causing the system to crash since tscGranularity
is inadvertently set to 0.
*/
if (flex_ratio == 0) {
/* Clear bit 16 (evidently the
presence bit) */
wrmsr64(MSR_FLEX_RATIO, (msr & 0xFFFFFFFFFFFEFFFFULL));
msr = rdmsr64(MSR_FLEX_RATIO);
verbose("Unusable flex ratio detected. Patched MSR now %08x\n", msr & 0xffffffff);
} else {
if (bus_ratio_max > flex_ratio) {
bus_ratio_max = flex_ratio;
}
}
}
if (bus_ratio_max) {
fsbFrequency = (tscFrequency / bus_ratio_max);
}
//valv: Turbo Ratio Limit
if ((intelCPU != 0x2e) && (intelCPU != 0x2f)) {
msr = rdmsr64(MSR_TURBO_RATIO_LIMIT);
cpuFrequency = bus_ratio_max * fsbFrequency;
max_ratio = bus_ratio_max * 10;
} else {
cpuFrequency = tscFrequency;
}
//valv: to be uncommented if Remarq.1 didn't stick
/*if(bus_ratio_max > 0) bus_ratio = flex_ratio;*/
p->CPU.MaxRatio = max_ratio;
p->CPU.MinRatio = min_ratio;
myfsb = fsbFrequency / 1000000;
verbose("Sticking with [BCLK: %dMhz, Bus-Ratio: %d]\n", myfsb, max_ratio);
currcoef = bus_ratio_max;
} else {
msr = rdmsr64(MSR_IA32_PERF_STATUS);
DBG("msr(%d): ia32_perf_stat 0x%08x\n", __LINE__, msr & 0xffffffff);
currcoef = (msr >> 8) & 0x1f;
/* Non-integer bus ratio for the max-multi*/
maxdiv = (msr >> 46) & 0x01;
/* Non-integer bus ratio for the current-multi (undocumented)*/
currdiv = (msr >> 14) & 0x01;
if ((p->CPU.Family == 0x06 && p->CPU.Model >= 0x0e) || (p->CPU.Family == 0x0f)) // This will always be model >= 3
{
/* On these models, maxcoef defines TSC freq */
maxcoef = (msr >> 40) & 0x1f;
} else {
/* On lower models, currcoef defines TSC freq */
/* XXX */
maxcoef = currcoef;
}
if (maxcoef) {
if (maxdiv) {
fsbFrequency = ((tscFrequency * 2) / ((maxcoef * 2) + 1));
} else {
fsbFrequency = (tscFrequency / maxcoef);
}
if (currdiv) {
cpuFrequency = (fsbFrequency * ((currcoef * 2) + 1) / 2);
} else {
cpuFrequency = (fsbFrequency * currcoef);
}
DBG("max: %d%s current: %d%s\n", maxcoef, maxdiv ? ".5" : "",currcoef, currdiv ? ".5" : "");
}
}
}
/* Mobile CPU */
if (rdmsr64(MSR_IA32_PLATFORM_ID) & (1<<28)) {
p->CPU.Features |= CPU_FEATURE_MOBILE;
}
}
#if 0
else if((p->CPU.Vendor == 0x68747541 /* AMD */) && (p->CPU.Family == 0x0f)) {
if(p->CPU.ExtFamily == 0x00 /* K8 */) {
msr = rdmsr64(K8_FIDVID_STATUS);
currcoef = (msr & 0x3f) / 2 + 4;
currdiv = (msr & 0x01) * 2;
} else if(p->CPU.ExtFamily >= 0x01 /* K10+ */) {
msr = rdmsr64(K10_COFVID_STATUS);
if(p->CPU.ExtFamily == 0x01 /* K10 */)
currcoef = (msr & 0x3f) + 0x10;
else /* K11+ */
currcoef = (msr & 0x3f) + 0x08;
currdiv = (2 << ((msr >> 6) & 0x07));
}
if (currcoef) {
if (currdiv) {
fsbFrequency = ((tscFrequency * currdiv) / currcoef);
DBG("%d.%d\n", currcoef / currdiv, ((currcoef % currdiv) * 100) / currdiv);
} else {
fsbFrequency = (tscFrequency / currcoef);
DBG("%d\n", currcoef);
}
fsbFrequency = (tscFrequency / currcoef);
cpuFrequency = tscFrequency;
}
}
if (!fsbFrequency) {
fsbFrequency = (DEFAULT_FSB * 1000);
cpuFrequency = tscFrequency;
DBG("0 ! using the default value for FSB !\n");
}
#endif
p->CPU.MaxCoef = maxcoef;
p->CPU.MaxDiv = maxdiv;
p->CPU.CurrCoef = currcoef;
p->CPU.CurrDiv = currdiv;
p->CPU.TSCFrequency = tscFrequency;
p->CPU.FSBFrequency = fsbFrequency;
p->CPU.CPUFrequency = cpuFrequency;
DBG("CPU: Brand String: %s\n",p->CPU.BrandString);
DBG("CPU: Vendor/Family/ExtFamily: 0x%x/0x%x/0x%x\n",p->CPU.Vendor, p->CPU.Family, p->CPU.ExtFamily);
DBG("CPU: Model/ExtModel/Stepping: 0x%x/0x%x/0x%x\n",p->CPU.Model, p->CPU.ExtModel, p->CPU.Stepping);
DBG("CPU: MaxCoef/CurrCoef: 0x%x/0x%x\n",p->CPU.MaxCoef, p->CPU.CurrCoef);
DBG("CPU: MaxDiv/CurrDiv: 0x%x/0x%x\n",p->CPU.MaxDiv, p->CPU.CurrDiv);
DBG("CPU: TSCFreq: %dMHz\n",p->CPU.TSCFrequency / 1000000);
DBG("CPU: FSBFreq: %dMHz\n",p->CPU.FSBFrequency / 1000000);
DBG("CPU: CPUFreq: %dMHz\n",p->CPU.CPUFrequency / 1000000);
DBG("CPU: NoCores/NoThreads: %d/%d\n",p->CPU.NoCores, p->CPU.NoThreads);
DBG("CPU: Features: 0x%08x\n",p->CPU.Features);
#if DEBUG_CPU
pause();
#endif
}
branches/rewrite/i386/libsaio/platform.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*
* platform.h
* AsereBLN: reworked and extended
*
*/
#ifndef __LIBSAIO_PLATFORM_H
#define __LIBSAIO_PLATFORM_H
//#include "libsaio.h"
extern bool platformCPUFeature(uint32_t);
extern void scan_platform(void);
extern void dumpPhysAddr(const char * title, void * a, int len);
/* CPUID index into cpuid_raw */
#define CPUID_00
#define CPUID_11
#define CPUID_22
#define CPUID_33
#define CPUID_44
#define CPUID_805
#define CPUID_816
#define CPUID_MAX7
#define CPU_MODEL_YONAH0x0E// Sossaman, Yonah
#define CPU_MODEL_MEROM0x0F// Allendale, Conroe, Kentsfield, Woodcrest, Clovertown, Tigerton, Merom
#define CPU_MODEL_PENRYN0x17// Wolfdale, Yorkfield, Harpertown, Penryn
#define CPU_MODEL_NEHALEM0x1A// Bloomfield. Nehalem-EP, Nehalem-WS, Gainestown
#define CPU_MODEL_ATOM0x1C// Atom
#define CPU_MODEL_FIELDS0x1E// Lynnfield, Clarksfield, Jasper Forest
#define CPU_MODEL_DALES0x1F// Havendale, Auburndale
#define CPU_MODEL_DALES_32NM0x25// Clarkdale, Arrandale
#define CPU_MODEL_SANDY0x2A// Sandy Bridge
#define CPU_MODEL_WESTMERE0x2C// Gulftown, Westmere-EP, Westmere-WS
#define CPU_MODEL_SANDY_XEON0x2D// Sandy Bridge Xeon
#define CPU_MODEL_NEHALEM_EX0x2E// Beckton
#define CPU_MODEL_WESTMERE_EX0x2F
/* CPU Features */
#define CPU_FEATURE_MMX0x00000001// MMX Instruction Set
#define CPU_FEATURE_SSE0x00000002// SSE Instruction Set
#define CPU_FEATURE_SSE20x00000004// SSE2 Instruction Set
#define CPU_FEATURE_SSE30x00000008// SSE3 Instruction Set
#define CPU_FEATURE_SSE410x00000010// SSE41 Instruction Set
#define CPU_FEATURE_SSE420x00000020// SSE42 Instruction Set
#define CPU_FEATURE_EM64T0x00000040// 64Bit Support
#define CPU_FEATURE_HTT0x00000080// HyperThreading
#define CPU_FEATURE_MOBILE0x00000100// Mobile CPU
#define CPU_FEATURE_MSR0x00000200// MSR Support
/* SMBIOS Memory Types */
#define SMB_MEM_TYPE_UNDEFINED0
#define SMB_MEM_TYPE_OTHER1
#define SMB_MEM_TYPE_UNKNOWN2
#define SMB_MEM_TYPE_DRAM3
#define SMB_MEM_TYPE_EDRAM4
#define SMB_MEM_TYPE_VRAM5
#define SMB_MEM_TYPE_SRAM6
#define SMB_MEM_TYPE_RAM7
#define SMB_MEM_TYPE_ROM8
#define SMB_MEM_TYPE_FLASH9
#define SMB_MEM_TYPE_EEPROM10
#define SMB_MEM_TYPE_FEPROM11
#define SMB_MEM_TYPE_EPROM12
#define SMB_MEM_TYPE_CDRAM13
#define SMB_MEM_TYPE_3DRAM14
#define SMB_MEM_TYPE_SDRAM15
#define SMB_MEM_TYPE_SGRAM16
#define SMB_MEM_TYPE_RDRAM17
#define SMB_MEM_TYPE_DDR18
#define SMB_MEM_TYPE_DDR219
#define SMB_MEM_TYPE_FBDIMM20
#define SMB_MEM_TYPE_DDR324// Supported in 10.5.6+ AppleSMBIOS
/* Memory Configuration Types */
#define SMB_MEM_CHANNEL_UNKNOWN0
#define SMB_MEM_CHANNEL_SINGLE1
#define SMB_MEM_CHANNEL_DUAL2
#define SMB_MEM_CHANNEL_TRIPLE3
/* Maximum number of ram slots */
#define MAX_RAM_SLOTS8
#define RAM_SLOT_ENUMERATOR{0, 2, 4, 1, 3, 5, 6, 8, 10, 7, 9, 11}
/* Maximum number of SPD bytes */
#define MAX_SPD_SIZE256
/* Size of SMBIOS UUID in bytes */
#define UUID_LEN16
typedef struct _RamSlotInfo_t {
uint32_tModuleSize;// Size of Module in MB
uint32_tFrequency;// in Mhz
const char*Vendor;
const char*PartNo;
const char*SerialNo;
char*spd;// SPD Dump
boolInUse;
uint8_tType;
uint8_tBankConnections;// table type 6, see (3.3.7)
uint8_tBankConnCnt;
} RamSlotInfo_t;
typedef struct _PlatformInfo_t {
struct CPU {
uint32_tFeatures;// CPU Features like MMX, SSE2, VT, MobileCPU
uint32_tVendor;// Vendor
uint32_tSignature;// Signature
uint32_tStepping;// Stepping
uint32_tModel;// Model
uint32_tExtModel;// Extended Model
uint32_tFamily;// Family
uint32_tExtFamily;// Extended Family
uint32_tNoCores;// No Cores per Package
uint32_tNoThreads;// Threads per Package
uint8_tMaxCoef;// Max Multiplier
uint8_tMaxDiv;
uint8_tCurrCoef;// Current Multiplier
uint8_tCurrDiv;
uint64_tTSCFrequency;// TSC Frequency Hz
uint64_tFSBFrequency;// FSB Frequency Hz
uint64_tCPUFrequency;// CPU Frequency Hz
uint32_tMaxRatio;// Max Bus Ratio
uint32_tMinRatio;// Min Bus Ratio
charBrandString[48];// 48 Byte Branding String
uint32_tCPUID[CPUID_MAX][4];// CPUID 0..4, 80..81 Raw Values
} CPU;
struct RAM {
uint64_tFrequency;// Ram Frequency
uint32_tDivider;// Memory divider
uint8_tCAS;// CAS 1/2/2.5/3/4/5/6/7
uint8_tTRC;
uint8_tTRP;
uint8_tRAS;
uint8_tChannels;// Channel Configuration Single,Dual or Triple
uint8_tNoSlots;// Maximum no of slots available
uint8_tType;// Standard SMBIOS v2.5 Memory Type
RamSlotInfo_tDIMM[MAX_RAM_SLOTS];// Information about each slot
} RAM;
struct DMI {
intMaxMemorySlots;// number of memory slots populated by SMBIOS
intCntMemorySlots;// number of memory slots counted
intMemoryModules;// number of memory modules installed
intDIMM[MAX_RAM_SLOTS];// Information and SPD mapping for each slot
} DMI;
uint8_tType; // System Type: 1=Desktop, 2=Portable... according ACPI2.0 (FACP: PM_Profile)
uint8_t*UUID;
} PlatformInfo_t;
extern PlatformInfo_t Platform;
#endif /* !__LIBSAIO_PLATFORM_H */
branches/rewrite/i386/libsaio/cpu.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/*
* Copyright 2008 Islam Ahmed Zaid. All rights reserved. <azismed@gmail.com>
* AsereBLN: 2009: cleanup and bugfix
*/
#ifndef __LIBSAIO_CPU_H
#define __LIBSAIO_CPU_H
//#include "libsaio.h"
extern void scan_cpu(PlatformInfo_t *);
#define bit(n)(1UL << (n))
#define bitmask(h,l)((bit(h)|(bit(h)-1)) & ~(bit(l)-1))
#define bitfield(x,h,l)(((x) & bitmask(h,l)) >> l)
#define CPU_STRING_UNKNOWN"Unknown CPU Type"
#defineMSR_IA32_PERF_STATUS0x198
#define MSR_IA32_PERF_CONTROL0x199
#define MSR_IA32_EXT_CONFIG0x00EE
#define MSR_FLEX_RATIO0x194
#define MSR_TURBO_RATIO_LIMIT0x1AD
#defineMSR_PLATFORM_INFO0xCE
#define MSR_CORE_THREAD_COUNT0x35// Undocumented
#define MSR_IA32_PLATFORM_ID0x17
#define K8_FIDVID_STATUS0xC0010042
#define K10_COFVID_STATUS0xC0010071
#define DEFAULT_FSB100000 /* for now, hardcoding 100MHz for old CPUs */
// DFE: This constant comes from older xnu:
#define CLKNUM1193182/* formerly 1193167 */
// DFE: These two constants come from Linux except CLOCK_TICK_RATE replaced with CLKNUM
#define CALIBRATE_TIME_MSEC30/* 30 msecs */
#define CALIBRATE_LATCH((CLKNUM * CALIBRATE_TIME_MSEC + 1000/2)/1000)
// CPUID Values
#define CPUID_MODEL_YONAH14// Intel Mobile Core Solo, Duo
#define CPUID_MODEL_MEROM15// Intel Mobile Core 2 Solo, Duo, Xeon 30xx, Xeon 51xx, Xeon X53xx, Xeon E53xx, Xeon X32xx
#define CPUID_MODEL_PENRYN23// Intel Core 2 Solo, Duo, Quad, Extreme, Xeon X54xx, Xeon X33xx
#define CPUID_MODEL_NEHALEM26// Intel Core i7, Xeon W35xx, Xeon X55xx, Xeon E55xx LGA1366 (45nm)
#define CPUID_MODEL_ATOM28// Intel Atom (45nm)
#define CPUID_MODEL_FIELDS30// Intel Core i5, i7, Xeon X34xx LGA1156 (45nm)
#define CPUID_MODEL_DALES31// Havendale, Auburndale
#define CPUID_MODEL_DALES_32NM37// Intel Core i3, i5 LGA1156 (32nm)
#define CPUID_MODEL_SANDY42// Intel Core i3, i5, i7 LGA1155 (32nm)
#define CPUID_MODEL_WESTMERE44// Intel Core i7, Xeon X56xx, Xeon E56xx, Xeon W36xx LGA1366 (32nm) 6 Core
#define CPUID_MODEL_NEHALEM_EX46// Intel Xeon X75xx, Xeon X65xx, Xeon E75xx, Xeon E65x
#define CPUID_MODEL_WESTMERE_EX47// Intel Xeon E7
static inline uint64_t rdtsc64(void)
{
uint64_t ret;
__asm__ volatile("rdtsc" : "=A" (ret));
return ret;
}
static inline uint64_t rdmsr64(uint32_t msr)
{
uint64_t ret;
__asm__ volatile("rdmsr" : "=A" (ret) : "c" (msr));
return ret;
}
static inline void wrmsr64(uint32_t msr, uint64_t val)
{
__asm__ volatile("wrmsr" : : "c" (msr), "A" (val));
}
static inline void intel_waitforsts(void) {
uint32_t inline_timeout = 100000;
while (rdmsr64(MSR_IA32_PERF_STATUS) & (1 << 21)) { if (!inline_timeout--) break; }
}
static inline void do_cpuid(uint32_t selector, uint32_t *data)
{
asm volatile ("cpuid"
: "=a" (data[0]),
"=b" (data[1]),
"=c" (data[2]),
"=d" (data[3])
: "a" (selector));
}
static inline void do_cpuid2(uint32_t selector, uint32_t selector2, uint32_t *data)
{
asm volatile ("cpuid"
: "=a" (data[0]),
"=b" (data[1]),
"=c" (data[2]),
"=d" (data[3])
: "a" (selector), "c" (selector2));
}
// DFE: enable_PIT2 and disable_PIT2 come from older xnu
/*
* Enable or disable timer 2.
* Port 0x61 controls timer 2:
* bit 0 gates the clock,
* bit 1 gates output to speaker.
*/
static inline void enable_PIT2(void)
{
/* Enable gate, disable speaker */
__asm__ volatile(
" inb $0x61,%%al \n\t"
" and $0xFC,%%al \n\t" /* & ~0x03 */
" or $1,%%al \n\t"
" outb %%al,$0x61 \n\t"
: : : "%al" );
}
static inline void disable_PIT2(void)
{
/* Disable gate and output to speaker */
__asm__ volatile(
" inb $0x61,%%al \n\t"
" and $0xFC,%%al \n\t"/* & ~0x03 */
" outb %%al,$0x61 \n\t"
: : : "%al" );
}
// DFE: set_PIT2_mode0, poll_PIT2_gate, and measure_tsc_frequency are
// roughly based on Linux code
/* Set the 8254 channel 2 to mode 0 with the specified value.
In mode 0, the counter will initially set its gate low when the
timer expires. For this to be useful, you ought to set it high
before calling this function. The enable_PIT2 function does this.
*/
static inline void set_PIT2_mode0(uint16_t value)
{
__asm__ volatile(
" movb $0xB0,%%al \n\t"
" outb%%al,$0x43\n\t"
" movb%%dl,%%al\n\t"
" outb%%al,$0x42\n\t"
" movb%%dh,%%al\n\t"
" outb%%al,$0x42"
: : "d"(value) /*: no clobber */ );
}
/* Returns the number of times the loop ran before the PIT2 signaled */
static inline unsigned long poll_PIT2_gate(void)
{
unsigned long count = 0;
unsigned char nmi_sc_val;
do {
++count;
__asm__ volatile(
"inb$0x61,%0"
: "=q"(nmi_sc_val) /*:*/ /* no input */ /*:*/ /* no clobber */);
} while( (nmi_sc_val & 0x20) == 0);
return count;
}
#endif /* !__LIBSAIO_CPU_H */
branches/rewrite/i386/libsaio/hpet.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/*
*
*/
#include "libsaio.h"
#include "pci.h"
#include "hpet.h"
#ifndef DEBUG_HPET
#define DEBUG_HPET 0
#endif
#if DEBUG_HPET
#define DBG(x...) printf(x)
#else
#define DBG(x...)
#endif
static struct lpc_controller_t lpc_controllers[] = {
// Default unknown chipset
{ 0, 0, "" },
// Intel
{ 0x8086, 0x24dc, "ICH5" },
{ 0x8086, 0x2640, "ICH6" },
{ 0x8086, 0x2641, "ICH6M" },
{ 0x8086, 0x27b0, "ICH7 DH" },
{ 0x8086, 0x27b8, "ICH7" },
{ 0x8086, 0x27b9, "ICH7M" },
{ 0x8086, 0x27bd, "ICH7M DH" },
{ 0x8086, 0x2810, "ICH8R" },
{ 0x8086, 0x2811, "ICH8M-E" },
{ 0x8086, 0x2812, "ICH8DH" },
{ 0x8086, 0x2814, "ICH8DO" },
{ 0x8086, 0x2815, "ICH8M" },
{ 0x8086, 0x2912, "ICH9DH" },
{ 0x8086, 0x2914, "ICH9DO" },
{ 0x8086, 0x2916, "ICH9R" },
{ 0x8086, 0x2917, "ICH9M-E" },
{ 0x8086, 0x2918, "ICH9" },
{ 0x8086, 0x2919, "ICH9M" },
{ 0x8086, 0x3a14, "ICH10DO" },
{ 0x8086, 0x3a16, "ICH10R" },
{ 0x8086, 0x3a18, "ICH10" },
{ 0x8086, 0x3a1a, "ICH10D" },
};
void force_enable_hpet(pci_dt_t *lpc_dev)
{
int i;
uint32_tval, hpet_address = 0xFED00000;
void*rcba;
/* LPC on Intel ICH is always (?) at 00:1f.0 */
for(i = 1; i < sizeof(lpc_controllers) / sizeof(lpc_controllers[0]); i++)
if ((lpc_controllers[i].vendor == lpc_dev->vendor_id)
&& (lpc_controllers[i].device == lpc_dev->device_id))
{
rcba = (void *)(pci_config_read32(lpc_dev->dev.addr, 0xF0) & 0xFFFFC000);
DBG("Intel(R) %s LPC Interface [%04x:%04x], MMIO @ 0x%lx\n",
lpc_controllers[i].name, lpc_dev->vendor_id, lpc_dev->device_id, rcba);
if (rcba == 0)
printf(" RCBA disabled; cannot force enable HPET\n");
else
{
val = REG32(rcba, 0x3404);
if (val & 0x80)
{
// HPET is enabled in HPTC. Just not reported by BIOS
DBG(" HPET is enabled in HPTC, just not reported by BIOS\n");
hpet_address |= (val & 3) << 12 ;
DBG(" HPET MMIO @ 0x%lx\n", hpet_address);
}
else
{
// HPET disabled in HPTC. Trying to enable
DBG(" HPET is disabled in HPTC, trying to enable\n");
REG32(rcba, 0x3404) = val | 0x80;
hpet_address |= (val & 3) << 12 ;
DBG(" Force enabled HPET, MMIO @ 0x%lx\n", hpet_address);
}
// verify if the job is done
val = REG32(rcba, 0x3404);
if (!(val & 0x80))
printf(" Failed to force enable HPET\n");
}
break;
}
#if DEBUG_HPET
printf("Press [Enter] to continue...\n");
getchar();
#endif
}
branches/rewrite/i386/libsaio/hpet.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
*
*/
#ifndef __LIBSAIO_HPET_H
#define __LIBSAIO_HPET_H
#include "libsaio.h"
#define REG32(base, reg) ((volatile uint32_t *)base)[(reg) >> 2]
void force_enable_hpet(pci_dt_t *lpc_dev);
struct lpc_controller_t {
unsigned vendor;
unsigned device;
char *name;
};
#endif /* !__LIBSAIO_HPET_H */
branches/rewrite/i386/libsaio/pci.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/*
*
* Copyright 2008 by Islam M. Ahmed Zaid. All rights reserved.
*
*/
#include "libsaio.h"
#include "pci.h"
#ifndef DEBUG_PCI
#define DEBUG_PCI 0
#endif
#if DEBUG_PCI
#define DBG(x...)printf(x)
#else
#define DBG(x...)
#endif
pci_dt_t*root_pci_dev;
uint8_t pci_config_read8(uint32_t pci_addr, uint8_t reg)
{
pci_addr |= reg & ~3;
outl(PCI_ADDR_REG, pci_addr);
return inb(PCI_DATA_REG + (reg & 3));
}
uint16_t pci_config_read16(uint32_t pci_addr, uint8_t reg)
{
pci_addr |= reg & ~3;
outl(PCI_ADDR_REG, pci_addr);
return inw(PCI_DATA_REG + (reg & 2));
}
uint32_t pci_config_read32(uint32_t pci_addr, uint8_t reg)
{
pci_addr |= reg & ~3;
outl(PCI_ADDR_REG, pci_addr);
return inl(PCI_DATA_REG);
}
void pci_config_write8(uint32_t pci_addr, uint8_t reg, uint8_t data)
{
pci_addr |= reg & ~3;
outl(PCI_ADDR_REG, pci_addr);
outb(PCI_DATA_REG + (reg & 3), data);
}
void pci_config_write16(uint32_t pci_addr, uint8_t reg, uint16_t data)
{
pci_addr |= reg & ~3;
outl(PCI_ADDR_REG, pci_addr);
outw(PCI_DATA_REG + (reg & 2), data);
}
void pci_config_write32(uint32_t pci_addr, uint8_t reg, uint32_t data)
{
pci_addr |= reg & ~3;
outl(PCI_ADDR_REG, pci_addr);
outl(PCI_DATA_REG, data);
}
void scan_pci_bus(pci_dt_t *start, uint8_t bus)
{
pci_dt_t*new;
pci_dt_t**current = &start->children;
uint32_tid;
uint32_tpci_addr;
uint8_tdev;
uint8_tfunc;
uint8_tsecondary_bus;
uint8_theader_type;
for (dev = 0; dev < 32; dev++) {
for (func = 0; func < 8; func++) {
pci_addr = PCIADDR(bus, dev, func);
id = pci_config_read32(pci_addr, PCI_VENDOR_ID);
if (!id || id == 0xffffffff) {
continue;
}
new = (pci_dt_t*)malloc(sizeof(pci_dt_t));
bzero(new, sizeof(pci_dt_t));
new->dev.addr= pci_addr;
new->vendor_id= id & 0xffff;
new->device_id= (id >> 16) & 0xffff;
new->subsys_id.subsys_id= pci_config_read32(pci_addr, PCI_SUBSYSTEM_VENDOR_ID);
new->class_id= pci_config_read16(pci_addr, PCI_CLASS_DEVICE);
new->parent= start;
header_type = pci_config_read8(pci_addr, PCI_HEADER_TYPE);
switch (header_type & 0x7f) {
case PCI_HEADER_TYPE_BRIDGE:
case PCI_HEADER_TYPE_CARDBUS:
secondary_bus = pci_config_read8(pci_addr, PCI_SECONDARY_BUS);
if (secondary_bus != 0) {
scan_pci_bus(new, secondary_bus);
}
break;
}
*current = new;
current = &new->next;
if ((func == 0) && ((header_type & 0x80) == 0)) {
break;
}
}
}
}
void enable_pci_devs(void)
{
uint16_t id;
uint32_t rcba, *fd;
id = pci_config_read16(PCIADDR(0, 0x00, 0), 0x00);
/* make sure we're on Intel chipset */
if (id != 0x8086)
return;
rcba = pci_config_read32(PCIADDR(0, 0x1f, 0), 0xf0) & ~1;
fd = (uint32_t *)(rcba + 0x3418);
/* set SMBus Disable (SD) to 0 */
*fd &= ~0x8;
/* and all devices? */
//*fd = 0x1;
}
void build_pci_dt(void)
{
root_pci_dev = malloc(sizeof(pci_dt_t));
bzero(root_pci_dev, sizeof(pci_dt_t));
enable_pci_devs();
scan_pci_bus(root_pci_dev, 0);
#if DEBUG_PCI
dump_pci_dt(root_pci_dev->children);
pause();
#endif
}
static char dev_path[256];
char *get_pci_dev_path(pci_dt_t *pci_dt)
{
pci_dt_t*current;
pci_dt_t*end;
chartmp[64];
dev_path[0] = 0;
end = root_pci_dev;
int uid = 0; //getPciRootUID();
while (end != pci_dt)
{
current = pci_dt;
while (current->parent != end)
current = current->parent;
end = current;
if (current->parent == root_pci_dev)
{
sprintf(tmp, "PciRoot(0x%x)/Pci(0x%x,0x%x)", uid,
current->dev.bits.dev, current->dev.bits.func);
} else {
sprintf(tmp, "/Pci(0x%x,0x%x)",
current->dev.bits.dev, current->dev.bits.func);
}
strcat(dev_path, tmp);
}
return dev_path;
}
void dump_pci_dt(pci_dt_t *pci_dt)
{
pci_dt_t*current;
current = pci_dt;
while (current) {
printf("%02x:%02x.%x [%04x] [%04x:%04x] (subsys [%04x:%04x]):: %s\n",
current->dev.bits.bus, current->dev.bits.dev, current->dev.bits.func,
current->class_id, current->vendor_id, current->device_id,
current->subsys_id.subsys.vendor_id, current->subsys_id.subsys.device_id,
get_pci_dev_path(current));
dump_pci_dt(current->children);
current = current->next;
}
}
branches/rewrite/i386/libsaio/convert.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
* Convert.c
* Implement conversion utility functions
* Create UUID parsing functions and gather other conversion routines
* --Rek
*/
#include "convert.h"
/** Transform a 16 bytes hexadecimal value UUID to a string */
const char * getStringFromUUID(const EFI_CHAR8* eUUID)
{
static char msg[UUID_LEN*2 + 8] = "";
if (!eUUID) return "";
const unsigned char * uuid = (unsigned char*) eUUID;
sprintf(msg, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
uuid[0], uuid[1], uuid[2], uuid[3],
uuid[4], uuid[5], uuid[6], uuid[7],
uuid[8], uuid[9], uuid[10],uuid[11],
uuid[12],uuid[13],uuid[14],uuid[15]);
return msg ;
}
/** Parse an UUID string into an (EFI_CHAR8*) buffer */
EFI_CHAR8* getUUIDFromString(const char *source)
{
if (!source) return 0;
char*p = (char *)source;
inti;
charbuf[3];
static EFI_CHAR8 uuid[UUID_LEN+1]="";
buf[2] = '\0';
for (i=0; i<UUID_LEN; i++) {
if (p[0] == '\0' || p[1] == '\0' || !isxdigit(p[0]) || !isxdigit(p[1])) {
verbose("[ERROR] UUID='%s' syntax error\n", source);
return 0;
}
buf[0] = *p++;
buf[1] = *p++;
uuid[i] = (unsigned char) strtoul(buf, NULL, 16);
if (*p == '-' && (i % 2) == 1 && i < UUID_LEN - 1) {
p++;
}
}
uuid[UUID_LEN]='\0';
if (*p != '\0') {
verbose("[ERROR] UUID='%s' syntax error\n", source);
return 0;
}
return uuid;
}
/** XXX AsereBLN replace by strtoul */
uint32_t ascii_hex_to_int(char *buff)
{
uint32_tvalue = 0, i, digit;
for(i = 0; i < strlen(buff); i++)
{
if (buff[i] >= 48 && buff[i] <= 57)// '0' through '9'
digit = buff[i] - 48;
else if (buff[i] >= 65 && buff[i] <= 70)// 'A' through 'F'
digit = buff[i] - 55;
else if (buff[i] >= 97 && buff[i] <= 102)// 'a' through 'f'
digit = buff[i] - 87;
else
return value;
value = digit + 16 * value;
}
returnvalue;
}
void *convertHexStr2Binary(const char *hexStr, int *outLength)
{
int len;
char hexNibble;
char hexByte[2];
uint8_t binChar;
uint8_t *binStr;
int hexStrIdx, binStrIdx, hexNibbleIdx;
len = strlen(hexStr);
if (len > 1)
{
// the resulting binary will be the half size of the input hex string
binStr = malloc(len / 2);
binStrIdx = 0;
hexNibbleIdx = 0;
for (hexStrIdx = 0; hexStrIdx < len; hexStrIdx++)
{
hexNibble = hexStr[hexStrIdx];
// ignore all chars except valid hex numbers
if (hexNibble >= '0' && hexNibble <= '9'
|| hexNibble >= 'A' && hexNibble <= 'F'
|| hexNibble >= 'a' && hexNibble <= 'f')
{
hexByte[hexNibbleIdx++] = hexNibble;
// found both two nibbles, convert to binary
if (hexNibbleIdx == 2)
{
binChar = 0;
for (hexNibbleIdx = 0; hexNibbleIdx < sizeof(hexByte); hexNibbleIdx++)
{
if (hexNibbleIdx > 0) binChar = binChar << 4;
if (hexByte[hexNibbleIdx] <= '9') binChar += hexByte[hexNibbleIdx] - '0';
else if (hexByte[hexNibbleIdx] <= 'F') binChar += hexByte[hexNibbleIdx] - ('A' - 10);
else if (hexByte[hexNibbleIdx] <= 'f') binChar += hexByte[hexNibbleIdx] - ('a' - 10);
}
binStr[binStrIdx++] = binChar;
hexNibbleIdx = 0;
}
}
}
*outLength = binStrIdx;
return binStr;
}
else
{
*outLength = 0;
return NULL;
}
}
// FIXME: can't use my original code here,
// Ironically, trying to reuse convertHexStr2Binary() would RESET the system!
/*
static EFI_CHAR8* getUUIDFromString2(const char * szInUUID)
{
char szUUID[UUID_LEN+1], *p=szUUID;
int size=0;
void* ret;
if (!szInUUID || strlen(szInUUID)<UUID_LEN) return (EFI_CHAR8*) 0;
while(*szInUUID) if (*szInUUID!='-') *p++=*szInUUID++; else szInUUID++;
*p='\0';
ret = convertHexStr2Binary(szUUID, &size);
if (!ret || size!=UUID_LEN)
{
verbose("UUID: cannot convert string <%s> to valid UUID.\n", szUUID);
return (EFI_CHAR8*) 0;
}
return (EFI_CHAR8*) ret; // new allocated buffer containing the converted string to bin
}
*/
branches/rewrite/i386/libsaio/pci.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
/*
*
* Copyright 2008 by Islam M. Ahmed Zaid. All rights reserved.
*
*/
#ifndef __LIBSAIO_PCI_H
#define __LIBSAIO_PCI_H
typedef struct {
uint32_t:2;
uint32_treg :6;
uint32_tfunc:3;
uint32_tdev :5;
uint32_tbus :8;
uint32_t:7;
uint32_teb:1;
} pci_addr_t;
typedef union {
pci_addr_tbits;
uint32_taddr;
} pci_dev_t;
typedef struct pci_dt_t {
pci_dev_tdev;
uint16_tvendor_id;
uint16_tdevice_id;
union {
struct {
uint16_tvendor_id;
uint16_tdevice_id;
} subsys;
uint32_tsubsys_id;
}subsys_id;
uint16_tclass_id;
struct pci_dt_t*parent;
struct pci_dt_t*children;
struct pci_dt_t*next;
} pci_dt_t;
#define PCIADDR(bus, dev, func) (1 << 31) | (bus << 16) | (dev << 11) | (func << 8)
#define PCI_ADDR_REG0xcf8
#define PCI_DATA_REG0xcfc
extern pci_dt_t*root_pci_dev;
extern uint8_tpci_config_read8(uint32_t, uint8_t);
extern uint16_tpci_config_read16(uint32_t, uint8_t);
extern uint32_tpci_config_read32(uint32_t, uint8_t);
extern voidpci_config_write8(uint32_t, uint8_t, uint8_t);
extern voidpci_config_write16(uint32_t, uint8_t, uint16_t);
extern voidpci_config_write32(uint32_t, uint8_t, uint32_t);
extern char*get_pci_dev_path(pci_dt_t *);
extern voidbuild_pci_dt(void);
extern voiddump_pci_dt(pci_dt_t *);
/* Option ROM header */
typedef struct {
uint16_tsignature;// 0xAA55
uint8_trom_size;
uint32_tentry_point;
uint8_treserved[15];
uint16_tpci_header_offset;
uint16_texpansion_header_offset;
} option_rom_header_t;
/* Option ROM PCI Data Structure */
typedef struct {
uint32_tsignature;// ati - 0x52494350, nvidia - 0x50434952, 'PCIR'
uint16_tvendor_id;
uint16_tdevice_id;
uint16_tvital_product_data_offset;
uint16_tstructure_length;
uint8_tstructure_revision;
uint8_tclass_code[3];
uint16_timage_length;
uint16_timage_revision;
uint8_tcode_type;
uint8_tindicator;
uint16_treserved;
} option_rom_pci_header_t;
//-----------------------------------------------------------------------------
// added by iNDi
typedef struct {
uint32_tsignature;// 0x24506E50 '$PnP'
uint8_trevision;//1
uint8_tlength;
uint16_toffset;
uint8_tchecksum;
uint32_tidentifier;
uint16_tmanufacturer;
uint16_tproduct;
uint8_tclass[3];
uint8_tindicators;
uint16_tboot_vector;
uint16_tdisconnect_vector;
uint16_tbootstrap_vector;
uint16_treserved;
uint16_tresource_vector;
} option_rom_pnp_header_t;
/*
* Under PCI, each device has 256 bytes of configuration address space,
* of which the first 64 bytes are standardized as follows:
*/
#define PCI_VENDOR_ID0x00/* 16 bits */
#define PCI_DEVICE_ID0x02/* 16 bits */
#define PCI_COMMAND0x04/* 16 bits */
#define PCI_COMMAND_IO0x1/* Enable response in I/O space */
#define PCI_COMMAND_MEMORY0x2/* Enable response in Memory space */
#define PCI_COMMAND_MASTER0x4/* Enable bus mastering */
#define PCI_COMMAND_SPECIAL0x8/* Enable response to special cycles */
#define PCI_COMMAND_INVALIDATE0x10/* Use memory write and invalidate */
#define PCI_COMMAND_VGA_PALETTE0x20/* Enable palette snooping */
#define PCI_COMMAND_PARITY0x40/* Enable parity checking */
#define PCI_COMMAND_WAIT0x80/* Enable address/data stepping */
#define PCI_COMMAND_SERR0x100/* Enable SERR */
#define PCI_COMMAND_FAST_BACK0x200/* Enable back-to-back writes */
#define PCI_COMMAND_DISABLE_INTx0x400/* PCIE: Disable INTx interrupts */
#define PCI_STATUS0x06/* 16 bits */
#define PCI_STATUS_INTx0x08/* PCIE: INTx interrupt pending */
#define PCI_STATUS_CAP_LIST0x10/* Support Capability List */
#define PCI_STATUS_66MHZ0x20/* Support 66 Mhz PCI 2.1 bus */
#define PCI_STATUS_UDF0x40/* Support User Definable Features [obsolete] */
#define PCI_STATUS_FAST_BACK0x80/* Accept fast-back to back */
#define PCI_STATUS_PARITY0x100/* Detected parity error */
#define PCI_STATUS_DEVSEL_MASK0x600/* DEVSEL timing */
#define PCI_STATUS_DEVSEL_FAST0x000
#define PCI_STATUS_DEVSEL_MEDIUM0x200
#define PCI_STATUS_DEVSEL_SLOW0x400
#define PCI_STATUS_SIG_TARGET_ABORT 0x800/* Set on target abort */
#define PCI_STATUS_REC_TARGET_ABORT 0x1000/* Master ack of " */
#define PCI_STATUS_REC_MASTER_ABORT 0x2000/* Set on master abort */
#define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000/* Set when we drive SERR */
#define PCI_STATUS_DETECTED_PARITY0x8000/* Set on parity error */
#define PCI_CLASS_REVISION0x08/* High 24 bits are class, low 8 revision */
#define PCI_REVISION_ID0x08/* Revision ID */
#define PCI_CLASS_PROG0x09/* Reg. Level Programming Interface */
#define PCI_CLASS_DEVICE0x0a/* Device class */
#define PCI_CACHE_LINE_SIZE0x0c/* 8 bits */
#define PCI_LATENCY_TIMER0x0d/* 8 bits */
#define PCI_HEADER_TYPE0x0e/* 8 bits */
#define PCI_HEADER_TYPE_NORMAL0
#define PCI_HEADER_TYPE_BRIDGE1
#define PCI_HEADER_TYPE_CARDBUS2
#define PCI_BIST0x0f/* 8 bits */
#define PCI_BIST_CODE_MASK0x0f/* Return result */
#define PCI_BIST_START0x40/* 1 to start BIST, 2 secs or less */
#define PCI_BIST_CAPABLE0x80/* 1 if BIST capable */
/*
* Base addresses specify locations in memory or I/O space.
* Decoded size can be determined by writing a value of
* 0xffffffff to the register, and reading it back. Only
* 1 bits are decoded.
*/
#define PCI_BASE_ADDRESS_00x10/* 32 bits */
#define PCI_BASE_ADDRESS_10x14/* 32 bits [htype 0,1 only] */
#define PCI_BASE_ADDRESS_20x18/* 32 bits [htype 0 only] */
#define PCI_BASE_ADDRESS_30x1c/* 32 bits */
#define PCI_BASE_ADDRESS_40x20/* 32 bits */
#define PCI_BASE_ADDRESS_50x24/* 32 bits */
#define PCI_BASE_ADDRESS_SPACE0x01/* 0 = memory, 1 = I/O */
#define PCI_BASE_ADDRESS_SPACE_IO0x01
#define PCI_BASE_ADDRESS_SPACE_MEMORY0x00
#define PCI_BASE_ADDRESS_MEM_TYPE_MASK0x06
#define PCI_BASE_ADDRESS_MEM_TYPE_320x00/* 32 bit address */
#define PCI_BASE_ADDRESS_MEM_TYPE_1M0x02/* Below 1M [obsolete] */
#define PCI_BASE_ADDRESS_MEM_TYPE_640x04/* 64 bit address */
#define PCI_BASE_ADDRESS_MEM_PREFETCH0x08/* prefetchable? */
#define PCI_BASE_ADDRESS_MEM_MASK(~(pciaddr_t)0x0f)
#define PCI_BASE_ADDRESS_IO_MASK(~(pciaddr_t)0x03)
/* bit 1 is reserved if address_space = 1 */
/* Header type 0 (normal devices) */
#define PCI_CARDBUS_CIS0x28
#define PCI_SUBSYSTEM_VENDOR_ID0x2c
#define PCI_SUBSYSTEM_ID0x2e
#define PCI_ROM_ADDRESS0x30/* Bits 31..11 are address, 10..1 reserved */
#define PCI_ROM_ADDRESS_ENABLE0x01
#define PCI_ROM_ADDRESS_MASK(~(pciaddr_t)0x7ff)
#define PCI_CAPABILITY_LIST0x34/* Offset of first capability list entry */
/* 0x35-0x3b are reserved */
#define PCI_INTERRUPT_LINE0x3c/* 8 bits */
#define PCI_INTERRUPT_PIN0x3d/* 8 bits */
#define PCI_MIN_GNT0x3e/* 8 bits */
#define PCI_MAX_LAT0x3f/* 8 bits */
/* Header type 1 (PCI-to-PCI bridges) */
#define PCI_PRIMARY_BUS0x18/* Primary bus number */
#define PCI_SECONDARY_BUS0x19/* Secondary bus number */
#define PCI_SUBORDINATE_BUS0x1a/* Highest bus number behind the bridge */
#define PCI_SEC_LATENCY_TIMER0x1b/* Latency timer for secondary interface */
#define PCI_IO_BASE0x1c/* I/O range behind the bridge */
#define PCI_IO_LIMIT0x1d
#define PCI_IO_RANGE_TYPE_MASK0x0f/* I/O bridging type */
#define PCI_IO_RANGE_TYPE_160x00
#define PCI_IO_RANGE_TYPE_320x01
#define PCI_IO_RANGE_MASK~0x0f
#define PCI_SEC_STATUS0x1e/* Secondary status register */
#define PCI_MEMORY_BASE0x20/* Memory range behind */
#define PCI_MEMORY_LIMIT0x22
#define PCI_MEMORY_RANGE_TYPE_MASK0x0f
#define PCI_MEMORY_RANGE_MASK~0x0f
#define PCI_PREF_MEMORY_BASE0x24/* Prefetchable memory range behind */
#define PCI_PREF_MEMORY_LIMIT0x26
#define PCI_PREF_RANGE_TYPE_MASK0x0f
#define PCI_PREF_RANGE_TYPE_320x00
#define PCI_PREF_RANGE_TYPE_640x01
#define PCI_PREF_RANGE_MASK~0x0f
#define PCI_PREF_BASE_UPPER320x28/* Upper half of prefetchable memory range */
#define PCI_PREF_LIMIT_UPPER320x2c
#define PCI_IO_BASE_UPPER160x30/* Upper half of I/O addresses */
#define PCI_IO_LIMIT_UPPER160x32
/* 0x34 same as for htype 0 */
/* 0x35-0x3b is reserved */
#define PCI_ROM_ADDRESS10x38/* Same as PCI_ROM_ADDRESS, but for htype 1 */
/* 0x3c-0x3d are same as for htype 0 */
#define PCI_BRIDGE_CONTROL0x3e
#define PCI_BRIDGE_CTL_PARITY0x01/* Enable parity detection on secondary interface */
#define PCI_BRIDGE_CTL_SERR0x02/* The same for SERR forwarding */
#define PCI_BRIDGE_CTL_NO_ISA0x04/* Disable bridging of ISA ports */
#define PCI_BRIDGE_CTL_VGA0x08/* Forward VGA addresses */
#define PCI_BRIDGE_CTL_MASTER_ABORT0x20/* Report master aborts */
#define PCI_BRIDGE_CTL_BUS_RESET0x40/* Secondary bus reset */
#define PCI_BRIDGE_CTL_FAST_BACK0x80/* Fast Back2Back enabled on secondary interface */
#define PCI_BRIDGE_CTL_PRI_DISCARD_TIMER 0x100/* PCI-X? */
#define PCI_BRIDGE_CTL_SEC_DISCARD_TIMER 0x200/* PCI-X? */
#define PCI_BRIDGE_CTL_DISCARD_TIMER_STATUS 0x400/* PCI-X? */
#define PCI_BRIDGE_CTL_DISCARD_TIMER_SERR_EN 0x800/* PCI-X? */
/* Header type 2 (CardBus bridges) */
/* 0x14-0x15 reserved */
#define PCI_CB_SEC_STATUS0x16/* Secondary status */
#define PCI_CB_PRIMARY_BUS0x18/* PCI bus number */
#define PCI_CB_CARD_BUS0x19/* CardBus bus number */
#define PCI_CB_SUBORDINATE_BUS0x1a/* Subordinate bus number */
#define PCI_CB_LATENCY_TIMER0x1b/* CardBus latency timer */
#define PCI_CB_MEMORY_BASE_00x1c
#define PCI_CB_MEMORY_LIMIT_00x20
#define PCI_CB_MEMORY_BASE_10x24
#define PCI_CB_MEMORY_LIMIT_10x28
#define PCI_CB_IO_BASE_00x2c
#define PCI_CB_IO_BASE_0_HI0x2e
#define PCI_CB_IO_LIMIT_00x30
#define PCI_CB_IO_LIMIT_0_HI0x32
#define PCI_CB_IO_BASE_10x34
#define PCI_CB_IO_BASE_1_HI0x36
#define PCI_CB_IO_LIMIT_10x38
#define PCI_CB_IO_LIMIT_1_HI0x3a
#define PCI_CB_IO_RANGE_MASK~0x03
/* 0x3c-0x3d are same as for htype 0 */
#define PCI_CB_BRIDGE_CONTROL0x3e
#define PCI_CB_BRIDGE_CTL_PARITY0x01/* Similar to standard bridge control register */
#define PCI_CB_BRIDGE_CTL_SERR0x02
#define PCI_CB_BRIDGE_CTL_ISA0x04
#define PCI_CB_BRIDGE_CTL_VGA0x08
#define PCI_CB_BRIDGE_CTL_MASTER_ABORT0x20
#define PCI_CB_BRIDGE_CTL_CB_RESET0x40/* CardBus reset */
#define PCI_CB_BRIDGE_CTL_16BIT_INT0x80/* Enable interrupt for 16-bit cards */
#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100/* Prefetch enable for both memory regions */
#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200
#define PCI_CB_BRIDGE_CTL_POST_WRITES0x400
#define PCI_CB_SUBSYSTEM_VENDOR_ID0x40
#define PCI_CB_SUBSYSTEM_ID0x42
#define PCI_CB_LEGACY_MODE_BASE0x44/* 16-bit PC Card legacy mode base address (ExCa) */
/* 0x48-0x7f reserved */
/* Capability lists */
#define PCI_CAP_LIST_ID0/* Capability ID */
#define PCI_CAP_ID_PM0x01/* Power Management */
#define PCI_CAP_ID_AGP0x02/* Accelerated Graphics Port */
#define PCI_CAP_ID_VPD0x03/* Vital Product Data */
#define PCI_CAP_ID_SLOTID0x04/* Slot Identification */
#define PCI_CAP_ID_MSI0x05/* Message Signaled Interrupts */
#define PCI_CAP_ID_CHSWP0x06/* CompactPCI HotSwap */
#define PCI_CAP_ID_PCIX0x07/* PCI-X */
#define PCI_CAP_ID_HT0x08/* HyperTransport */
#define PCI_CAP_ID_VNDR0x09/* Vendor specific */
#define PCI_CAP_ID_DBG0x0A/* Debug port */
#define PCI_CAP_ID_CCRC0x0B/* CompactPCI Central Resource Control */
#define PCI_CAP_ID_HOTPLUG0x0C/* PCI hot-plug */
#define PCI_CAP_ID_SSVID0x0D/* Bridge subsystem vendor/device ID */
#define PCI_CAP_ID_AGP30x0E/* AGP 8x */
#define PCI_CAP_ID_SECURE0x0F/* Secure device (?) */
#define PCI_CAP_ID_EXP0x10/* PCI Express */
#define PCI_CAP_ID_MSIX0x11/* MSI-X */
#define PCI_CAP_ID_SATA0x12/* Serial-ATA HBA */
#define PCI_CAP_ID_AF0x13/* Advanced features of PCI devices integrated in PCIe root cplx */
#define PCI_CAP_LIST_NEXT1/* Next capability in the list */
#define PCI_CAP_FLAGS2/* Capability defined flags (16 bits) */
#define PCI_CAP_SIZEOF4
/* Capabilities residing in the
PCI Express extended configuration space */
#define PCI_EXT_CAP_ID_AER0x01/* Advanced Error Reporting */
#define PCI_EXT_CAP_ID_VC0x02/* Virtual Channel */
#define PCI_EXT_CAP_ID_DSN0x03/* Device Serial Number */
#define PCI_EXT_CAP_ID_PB0x04/* Power Budgeting */
#define PCI_EXT_CAP_ID_RCLINK0x05/* Root Complex Link Declaration */
#define PCI_EXT_CAP_ID_RCILINK0x06/* Root Complex Internal Link Declaration */
#define PCI_EXT_CAP_ID_RCECOLL0x07/* Root Complex Event Collector */
#define PCI_EXT_CAP_ID_MFVC0x08/* Multi-Function Virtual Channel */
#define PCI_EXT_CAP_ID_RBCB0x0a/* Root Bridge Control Block */
#define PCI_EXT_CAP_ID_VNDR0x0b/* Vendor specific */
#define PCI_EXT_CAP_ID_ACS0x0d/* Access Controls */
#define PCI_EXT_CAP_ID_ARI0x0e/* Alternative Routing-ID Interpretation */
#define PCI_EXT_CAP_ID_ATS0x0f/* Address Translation Service */
#define PCI_EXT_CAP_ID_SRIOV0x10/* Single Root I/O Virtualization */
/* Power Management Registers */
#define PCI_PM_CAP_VER_MASK0x0007/* Version (2=PM1.1) */
#define PCI_PM_CAP_PME_CLOCK0x0008