Chameleon

Chameleon Commit Details

Date:2010-09-14 07:04:41 (8 years 10 months ago)
Author:Evan Lojewski
Commit:521
Parents: 520
Message:Modules, Modules everywhere
Changes:
D/branches/meklort/i386/boot2/picopng.c
D/branches/meklort/i386/boot2/graphic_utils.h
D/branches/meklort/i386/boot2/picopng.h
D/branches/meklort/i386/libsaio/dram_controllers.c
D/branches/meklort/i386/libsaio/dram_controllers.h
D/branches/meklort/i386/libsaio/spd.c
D/branches/meklort/i386/libsaio/spd.h
D/branches/meklort/i386/libsaio/resolution.c
D/branches/meklort/i386/libsaio/edid.c
D/branches/meklort/i386/libsaio/resolution.h
D/branches/meklort/i386/libsaio/edid.h
D/branches/meklort/i386/libsaio/mem.c
D/branches/meklort/i386/libsaio/mem.h
D/branches/meklort/i386/boot2/gui.c
D/branches/meklort/i386/boot2/gui.h
D/branches/meklort/i386/boot2/graphic_utils.c
A/branches/meklort/i386/boot2/options.h
A/branches/meklort/i386/modules/GUI/Makefile
A/branches/meklort/i386/modules/Resolution
A/branches/meklort/i386/modules/Memory/mem.c
A/branches/meklort/i386/modules/Memory
A/branches/meklort/i386/modules/Memory/mem.h
A/branches/meklort/i386/modules/Resolution/Makefile
A/branches/meklort/i386/modules/GUI
A/branches/meklort/i386/modules/GUI/gui.c
A/branches/meklort/i386/modules/Resolution/edid.c
A/branches/meklort/i386/modules/GUI/gui.h
A/branches/meklort/i386/modules/GUI/GUI_module.c
A/branches/meklort/i386/modules/Resolution/edid.h
A/branches/meklort/i386/modules/Memory/Memory.c
A/branches/meklort/i386/modules/Memory/dram_controllers.c
A/branches/meklort/i386/modules/GUI/graphic_utils.c
A/branches/meklort/i386/modules/GUI/picopng.c
A/branches/meklort/i386/modules/Memory/dram_controllers.h
A/branches/meklort/i386/modules/GUI/graphic_utils.h
A/branches/meklort/i386/modules/GUI/picopng.h
A/branches/meklort/i386/modules/Memory/spd.c
A/branches/meklort/i386/modules/Memory/spd.h
A/branches/meklort/i386/modules/Memory/Makefile
A/branches/meklort/i386/modules/Resolution/915resolution.c
A/branches/meklort/i386/modules/Resolution/Resolution.c
A/branches/meklort/i386/modules/Resolution/915resolution.h
M/branches/meklort/i386/libsaio/console.c
M/branches/meklort/i386/boot2/resume.c
M/branches/meklort/i386/boot2/boot.c
M/branches/meklort/i386/modules/GraphicsEnabler/GraphicsEnabler.c
M/branches/meklort/i386/modules/Symbols/Makefile
M/branches/meklort/i386/boot2/boot.h
M/branches/meklort/i386/libsaio/sys.c
M/branches/meklort/i386/boot2/mboot.c
M/branches/meklort/i386/libsaio/platform.c
M/branches/meklort/i386/libsaio/pci_setup.c
M/branches/meklort/i386/libsaio/Makefile
M/branches/meklort/i386/boot2/graphics.c
M/branches/meklort/i386/boot2/boot2.s
M/branches/meklort/i386/boot2/graphics.h
M/branches/meklort/i386/modules/GraphicsEnabler/Makefile
M/branches/meklort/i386/boot2/modules.h
M/branches/meklort/i386/modules/Makefile
M/branches/meklort/i386/boot2/WKdmDecompress.c
M/branches/meklort/i386/boot2/ramdisk.c
M/branches/meklort/i386/boot2/options.c
M/branches/meklort/i386/boot2/Makefile

File differences

branches/meklort/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
/*
* 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 "saio_internal.h"
#include "bootstruct.h"
#include "memvendors.h"
#ifndef DEBUG_SPD
#define DEBUG_SPD 0
#endif
#if DEBUG_SPD
#define DBG(x...)printf(x)
#else
#define DBG(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);
while( inb(base + SMBHSTSTS) & 0x01);// wait until ready
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);
return NULL;
}
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;
bool dump = false;
RamSlotInfo_t* slot;
base = pci_config_read16(smbus_dev->dev.addr, 0x20) & 0xFFFE;
DBG("Scanning smbus_dev <%04x, %04x> ...\n",smbus_dev->vendor_id, smbus_dev->device_id);
getBoolForKey("DumpSPD", &dump, &bootInfo->bootConfig);
bool fullBanks = // needed at least for laptops
Platform.DMI.MemoryModules == Platform.DMI.MaxMemorySlots;
// Search MAX_RAM_SLOTS slots
char spdbuf[256];
for (i = 0; i < MAX_RAM_SLOTS; i++){
slot = &Platform.RAM.DIMM[i];
spd_size = smb_read_byte_intel(base, 0x50 + i, 0);
// 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);
if(DEBUG_SPD) {
dumpPhysAddr("spd content: ",slot->spd, spd_size);
getc();
}
}
// 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.MaxMemorySlots==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, "P55", 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/meklort/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/meklort/i386/libsaio/mem.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
/*
* Copyright 2010 AsereBLN. All rights reserved. <aserebln@googlemail.com>
*
* mem.c - obtain system memory information
*/
#include "libsaio.h"
#include "pci.h"
#include "platform.h"
#include "cpu.h"
#include "mem.h"
#include "smbios_patcher.h"
#ifndef DEBUG_MEM
#define DEBUG_MEM 0
#endif
#if DEBUG_MEM
#define DBG(x...)printf(x)
#else
#define DBG(x...)
#endif
#define DC(c) (c >= 0x20 && c < 0x7f ? (char) c : '.')
#define STEP 16
void dumpPhysAddr(const char * title, void * a, int len)
{
int i,j;
u_int8_t* ad = (u_int8_t*) a;
char buffer[80];
char str[16];
if(ad==NULL) return;
printf("%s addr=0x%08x len=%04d\n",title ? title : "Dump of ", a, len);
printf("Ofs-00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F ASCII\n");
i = (len/STEP)*STEP;
for (j=0; j < i; j+=STEP)
{
printf("%02x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
j,
ad[j], ad[j+1], ad[j+2], ad[j+3] , ad[j+4], ad[j+5], ad[j+6], ad[j+7],
ad[j+8], ad[j+9], ad[j+10], ad[j+11] , ad[j+12], ad[j+13], ad[j+14], ad[j+15],
DC(ad[j]), DC(ad[j+1]), DC(ad[j+2]), DC(ad[j+3]) , DC(ad[j+4]), DC(ad[j+5]), DC(ad[j+6]), DC(ad[j+7]),
DC(ad[j+8]), DC(ad[j+9]), DC(ad[j+10]), DC(ad[j+11]) , DC(ad[j+12]), DC(ad[j+13]), DC(ad[j+14]), DC(ad[j+15])
);
}
if (len%STEP==0) return;
sprintf(buffer,"%02x:", i);
for (j=0; j < STEP; j++) {
if (j<(len%STEP))
sprintf(str, " %02x", ad[i+j]);
else
strcpy(str, " " );
strncat(buffer, str, sizeof(buffer));
}
strncat(buffer," ", sizeof(buffer));
for (j=0; j < (len%STEP); j++) {
sprintf(str, "%c", DC(ad[i+j]));
strncat(buffer, str, sizeof(buffer));
}
printf("%s\n",buffer);
}
void dumpAllTablesOfType(int i)
{
char title[32];
struct DMIHeader * dmihdr;
for(dmihdr = FindFirstDmiTableOfType(i, 4);
dmihdr;
dmihdr = FindNextDmiTableOfType(i, 4)) {
sprintf(title,"Table (type %d) :" , i);
dumpPhysAddr(title, dmihdr, dmihdr->length+32);
}
}
const char * getDMIString(struct DMIHeader * dmihdr, uint8_t strNum)
{
const char * ret =NULL;
const char * startAddr = (const char *) dmihdr;
const char * limit = NULL;
if (!dmihdr || dmihdr->length<4 || strNum==0) return NULL;
startAddr += dmihdr->length;
limit = startAddr + 256;
for(; strNum; strNum--) {
if ((*startAddr)==0 && *(startAddr+1)==0) break;
if (*startAddr && strNum<=1) {
ret = startAddr; // current str
break;
}
while(*startAddr && startAddr<limit) startAddr++;
if (startAddr==limit) break; // no terminator found
else if((*startAddr==0) && *(startAddr+1)==0) break;
else startAddr++;
}
return ret;
}
void scan_memory(PlatformInfo_t *p)
{
int i=0;
struct DMIHeader * dmihdr = NULL;
struct DMIMemoryModuleInfo* memInfo[MAX_RAM_SLOTS]; // 6
struct DMIPhysicalMemoryArray* physMemArray; // 16
struct DMIMemoryDevice* memDev[MAX_RAM_SLOTS]; //17
/* We mainly don't use obsolete tables 5,6 because most of computers don't handle it anymore */
Platform.DMI.MemoryModules = 0;
/* Now lets peek info rom table 16,17 as for some bios, table 5 & 6 are not used */
physMemArray = (struct DMIPhysicalMemoryArray*) FindFirstDmiTableOfType(16, 4);
Platform.DMI.MaxMemorySlots = physMemArray ? physMemArray->numberOfMemoryDevices : 0;
i = 0;
for(dmihdr = FindFirstDmiTableOfType(17, 4);
dmihdr;
dmihdr = FindNextDmiTableOfType(17, 4) ) {
memDev[i] = (struct DMIMemoryDevice*) dmihdr;
if (memDev[i]->size !=0 ) Platform.DMI.MemoryModules++;
if (memDev[i]->speed>0) Platform.RAM.DIMM[i].Frequency = memDev[i]->speed; // take it here for now but we'll check spd and dmi table 6 as well
i++;
}
// for table 6, we only have a look at the current speed
i = 0;
for(dmihdr = FindFirstDmiTableOfType(6, 4);
dmihdr;
dmihdr = FindNextDmiTableOfType(6, 4) ) {
memInfo[i] = (struct DMIMemoryModuleInfo*) dmihdr;
if (memInfo[i]->currentSpeed > Platform.RAM.DIMM[i].Frequency)
Platform.RAM.DIMM[i].Frequency = memInfo[i]->currentSpeed; // favor real overclocked speed if any
i++;
}
#if 0
dumpAllTablesOfType(17);
getc();
#endif
}
branches/meklort/i386/libsaio/mem.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*
* Copyright 2010 AsereBLN. All rights reserved. <aserebln@googlemail.com>
*
* mem.h
*/
#ifndef __LIBSAIO_MEM_H
#define __LIBSAIO_MEM_H
#include "platform.h"
extern void scan_memory(PlatformInfo_t *);
#endif/* __LIBSAIO_MEM_H */
branches/meklort/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
562
/*
* 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 "bootstruct.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), 0x00);
did = pci_config_read16(PCIADDR(possible_nhm_bus[i], 3, 4), 0x02);
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 Precharge (tRP)
Platform.RAM.CAS = (mc_channel_bank_timing >> 4) & 0x1F;
// RAS Active to precharge (tRAS)
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 %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
);
}
}
branches/meklort/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/meklort/i386/libsaio/resolution.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
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
/*
* resolution.h
*
*NOTE: I don't beleive this code is production ready / should be in trunk
* Atleast, not in it's current state.
*
* Created by Evan Lojewski on 3/4/10.
* Copyright 2009. All rights reserved.
*
*/
#ifndef _RESOLUTION_H_
#define _RESOLUTION_H_
#include "libsaio.h"
#include "edid.h"
#include "resolution.h"
void patchVideoBios()
{
UInt32 x = 0, y = 0, bp = 0;
getResolution(&x, &y, &bp);
if (x != 0 &&
y != 0 &&
bp != 0)
{
vbios_map * map;
map = open_vbios(CT_UNKWN);
if(map)
{
unlock_vbios(map);
set_mode(map, x, y, bp, 0, 0);
relock_vbios(map);
close_vbios(map);
}
}
}
/* Copied from 915 resolution created by steve tomljenovic
*
* This code is based on the techniques used in :
*
* - 855patch. Many thanks to Christian Zietz (czietz gmx net)
* for demonstrating how to shadow the VBIOS into system RAM
* and then modify it.
*
* - 1280patch by Andrew Tipton (andrewtipton null li).
*
* - 855resolution by Alain Poirier
*
* This source code is into the public domain.
*/
/**
**
**/
#define CONFIG_MECH_ONE_ADDR0xCF8
#define CONFIG_MECH_ONE_DATA0xCFC
int freqs[] = { 60, 75, 85 };
UInt32 get_chipset_id(void)
{
outl(CONFIG_MECH_ONE_ADDR, 0x80000000);
return inl(CONFIG_MECH_ONE_DATA);
}
chipset_type get_chipset(UInt32 id)
{
chipset_type type;
switch (id) {
case 0x35758086:
type = CT_830;
break;
case 0x25608086:
type = CT_845G;
break;
case 0x35808086:
type = CT_855GM;
break;
case 0x25708086:
type = CT_865G;
break;
case 0x25808086:
type = CT_915G;
break;
case 0x25908086:
type = CT_915GM;
break;
case 0x27708086:
type = CT_945G;
break;
case 0x27a08086:
type = CT_945GM;
break;
case 0x27ac8086:
type = CT_945GME;
break;
case 0x29708086:
type = CT_946GZ;
break;
case 0x27748086:
type = CT_955X;
break;
case 0x277c8086:
type = CT_975X;
break;
case 0x29a08086:
type = CT_G965;
break;
case 0x29908086:
type = CT_Q965;
break;
case 0x81008086:
type = CT_500;
break;
case 0x2e108086:
case 0X2e908086:
type = CT_B43;
break;
case 0x2e208086:
type = CT_P45;
break;
case 0x2e308086:
type = CT_G41;
break;
case 0x29c08086:
type = CT_G31;
break;
case 0x29208086:
type = CT_G45;
break;
case 0xA0108086:
type = CT_3150;
break;
case 0x2a008086:
type = CT_965GM;
break;
case 0x29e08086:
type = CT_X48;
break;
case 0x2a408086:
type = CT_GM45;
break;
default:
if((id & 0x0000FFFF) == 0x00008086) // Intel chipset
{
//printf("Unknown chipset 0x%llX, please email id to meklort@gmail.com", id);
//getc();
type = CT_UNKWN_INTEL;
}
type = CT_UNKWN;
break;
}
return type;
}
vbios_resolution_type1 * map_type1_resolution(vbios_map * map, UInt16 res)
{
vbios_resolution_type1 * ptr = ((vbios_resolution_type1*)(map->bios_ptr + res));
return ptr;
}
vbios_resolution_type2 * map_type2_resolution(vbios_map * map, UInt16 res)
{
vbios_resolution_type2 * ptr = ((vbios_resolution_type2*)(map->bios_ptr + res));
return ptr;
}
vbios_resolution_type3 * map_type3_resolution(vbios_map * map, UInt16 res)
{
vbios_resolution_type3 * ptr = ((vbios_resolution_type3*)(map->bios_ptr + res));
return ptr;
}
char detect_bios_type(vbios_map * map, char modeline, int entry_size)
{
UInt32 i;
UInt16 r1, r2;
r1 = r2 = 32000;
for (i=0; i < map->mode_table_size; i++)
{
if (map->mode_table[i].resolution <= r1)
{
r1 = map->mode_table[i].resolution;
}
else
{
if (map->mode_table[i].resolution <= r2)
{
r2 = map->mode_table[i].resolution;
}
}
/*printf("r1 = %d r2 = %d\n", r1, r2);*/
}
return (r2-r1-6) % entry_size == 0;
}
void close_vbios(vbios_map * map);
char detect_ati_bios_type(vbios_map * map)
{
return map->mode_table_size % sizeof(ATOM_MODE_TIMING) == 0;
}
vbios_map * open_vbios(chipset_type forced_chipset)
{
UInt32 z;
vbios_map * map = malloc(sizeof(vbios_map));
for(z=0; z<sizeof(vbios_map); z++) ((char*)map)[z]=0;
/*
* Determine chipset
*/
if (forced_chipset == CT_UNKWN)
{
map->chipset_id = get_chipset_id();
map->chipset = get_chipset(map->chipset_id);
}
else if (forced_chipset != CT_UNKWN)
{
map->chipset = forced_chipset;
}
if (map->chipset == CT_UNKWN)
{
//verbose("Unknown chipset type.\n");
//verbose("915resolution only works with Intel 800/900 series graphic chipsets.\n");
//verbose("Chipset Id: %x\n", map->chipset_id);
close_vbios(map);
return 0;
}
/*
* Map the video bios to memory
*/
map->bios_ptr=(char*)VBIOS_START;
/*
* check if we have ATI Radeon
*/
map->ati_tables.base = map->bios_ptr;
map->ati_tables.AtomRomHeader = (ATOM_ROM_HEADER *) (map->bios_ptr + *(unsigned short *) (map->bios_ptr + OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER));
if (strcmp ((char *) map->ati_tables.AtomRomHeader->uaFirmWareSignature, "ATOM") == 0)
{
// ATI Radeon Card
map->bios = BT_ATI_1;
map->ati_tables.MasterDataTables = (unsigned short *) &((ATOM_MASTER_DATA_TABLE *) (map->bios_ptr + map->ati_tables.AtomRomHeader->usMasterDataTableOffset))->ListOfDataTables;
unsigned short std_vesa_offset = (unsigned short) ((ATOM_MASTER_LIST_OF_DATA_TABLES *)map->ati_tables.MasterDataTables)->StandardVESA_Timing;
ATOM_STANDARD_VESA_TIMING * std_vesa = (ATOM_STANDARD_VESA_TIMING *) (map->bios_ptr + std_vesa_offset);
map->ati_mode_table = (char *) &std_vesa->aModeTimings;
if (map->ati_mode_table == 0)
{
printf("Unable to locate the mode table.\n");
printf("Please run the program 'dump_bios' as root and\n");
printf("email the file 'vbios.dmp' to stomljen@yahoo.com.\n");
printf("Chipset: %d\n", map->chipset);
close_vbios(map);
return 0;
}
map->mode_table_size = std_vesa->sHeader.usStructureSize - sizeof(ATOM_COMMON_TABLE_HEADER);
if (!detect_ati_bios_type(map)) map->bios = BT_ATI_2;
}
else {
/*
* check if we have NVIDIA
*/
int i = 0;
while (i < 512)
{ // we don't need to look through the whole bios, just the firs 512 bytes
if ((map->bios_ptr[i] == 'N')
&& (map->bios_ptr[i+1] == 'V')
&& (map->bios_ptr[i+2] == 'I')
&& (map->bios_ptr[i+3] == 'D'))
{
map->bios = BT_NVDA;
unsigned short nv_data_table_offset = 0;
unsigned short * nv_data_table;
NV_VESA_TABLE * std_vesa;
int i = 0;
while (i < 0x300)
{ //We don't need to look for the table in the whole bios, the 768 first bytes only
if ((map->bios_ptr[i] == 0x44)
&& (map->bios_ptr[i+1] == 0x01)
&& (map->bios_ptr[i+2] == 0x04)
&& (map->bios_ptr[i+3] == 0x00))
{
nv_data_table_offset = (unsigned short) (map->bios_ptr[i+4] | (map->bios_ptr[i+5] << 8));
break;
}
i++;
}
nv_data_table = (unsigned short *) (map->bios_ptr + (nv_data_table_offset + OFFSET_TO_VESA_TABLE_INDEX));
std_vesa = (NV_VESA_TABLE *) (map->bios_ptr + *nv_data_table);
map->nv_mode_table = (char *) std_vesa->sModelines;
if (map->nv_mode_table == 0)
{
printf("Unable to locate the mode table.\n");
printf("Please run the program 'dump_bios' as root and\n");
printf("email the file 'vbios.dmp' to stomljen@yahoo.com.\n");
printf("Chipset: %s\n", map->chipset);
close_vbios(map);
return 0;
}
map->mode_table_size = std_vesa->sHeader.usTable_Size;
break;
}
i++;
}
}
/*
* check if we have Intel
*/
/*if (map->chipset == CT_UNKWN && memmem(map->bios_ptr, VBIOS_SIZE, INTEL_SIGNATURE, strlen(INTEL_SIGNATURE))) {
printf( "Intel chipset detected. However, 915resolution was unable to determine the chipset type.\n");
printf("Chipset Id: %x\n", map->chipset_id);
printf("Please report this problem to stomljen@yahoo.com\n");
close_vbios(map);
return 0;
}*/
/*
* check for others
*/
/*
* Figure out where the mode table is
*/
if ((map->bios != BT_ATI_1) && (map->bios != BT_NVDA))
{
char* p = map->bios_ptr + 16;
char* limit = map->bios_ptr + VBIOS_SIZE - (3 * sizeof(vbios_mode));
while (p < limit && map->mode_table == 0)
{
vbios_mode * mode_ptr = (vbios_mode *) p;
if (((mode_ptr[0].mode & 0xf0) == 0x30) && ((mode_ptr[1].mode & 0xf0) == 0x30) &&
((mode_ptr[2].mode & 0xf0) == 0x30) && ((mode_ptr[3].mode & 0xf0) == 0x30))
{
map->mode_table = mode_ptr;
}
p++;
}
if (map->mode_table == 0)
{
close_vbios(map);
return 0;
}
}
/*
* Determine size of mode table
*/
if ((map->bios != BT_ATI_1) && (map->bios != BT_ATI_2) && (map->bios != BT_NVDA))
{
vbios_mode * mode_ptr = map->mode_table;
while (mode_ptr->mode != 0xff)
{
map->mode_table_size++;
mode_ptr++;
}
}
/*
* Figure out what type of bios we have
* order of detection is important
*/
if ((map->bios != BT_ATI_1) && (map->bios != BT_ATI_2) && (map->bios != BT_NVDA))
{
if (detect_bios_type(map, TRUE, sizeof(vbios_modeline_type3)))
{
map->bios = BT_3;
}
else if (detect_bios_type(map, TRUE, sizeof(vbios_modeline_type2)))
{
map->bios = BT_2;
}
else if (detect_bios_type(map, FALSE, sizeof(vbios_resolution_type1)))
{
map->bios = BT_1;
}
else {
return 0;
}
}
return map;
}
void close_vbios(vbios_map * map)
{
free(map);
}
void unlock_vbios(vbios_map * map)
{
map->unlocked = TRUE;
switch (map->chipset) {
case CT_UNKWN:
break;
case CT_830:
case CT_855GM:
outl(CONFIG_MECH_ONE_ADDR, 0x8000005a);
map->b1 = inb(CONFIG_MECH_ONE_DATA + 2);
outl(CONFIG_MECH_ONE_ADDR, 0x8000005a);
outb(CONFIG_MECH_ONE_DATA + 2, 0x33);
break;
case CT_845G:
case CT_865G:
case CT_915G:
case CT_915GM:
case CT_945G:
case CT_945GM:
case CT_945GME:
case CT_946GZ:
case CT_G965:
case CT_Q965:
case CT_965GM:
case CT_975X:
case CT_P35:
case CT_955X:
case CT_X48:
case CT_B43:
case CT_Q45:
case CT_P45:
case CT_GM45:
case CT_G45:
case CT_G41:
case CT_G31:
case CT_500:
case CT_3150:
case CT_UNKWN_INTEL:// Assume newer intel chipset is the same as before
outl(CONFIG_MECH_ONE_ADDR, 0x80000090);
map->b1 = inb(CONFIG_MECH_ONE_DATA + 1);
map->b2 = inb(CONFIG_MECH_ONE_DATA + 2);
outl(CONFIG_MECH_ONE_ADDR, 0x80000090);
outb(CONFIG_MECH_ONE_DATA + 1, 0x33);
outb(CONFIG_MECH_ONE_DATA + 2, 0x33);
break;
}
#if DEBUG
{
UInt32 t = inl(CONFIG_MECH_ONE_DATA);
verbose("unlock PAM: (0x%08x)\n", t);
}
#endif
}
void relock_vbios(vbios_map * map)
{
map->unlocked = FALSE;
switch (map->chipset)
{
case CT_UNKWN:
break;
case CT_830:
case CT_855GM:
outl(CONFIG_MECH_ONE_ADDR, 0x8000005a);
outb(CONFIG_MECH_ONE_DATA + 2, map->b1);
break;
case CT_845G:
case CT_865G:
case CT_915G:
case CT_915GM:
case CT_945G:
case CT_945GM:
case CT_945GME:
case CT_946GZ:
case CT_G965:
case CT_955X:
case CT_G45:
case CT_Q965:
case CT_965GM:
case CT_975X:
case CT_P35:
case CT_X48:
case CT_B43:
case CT_Q45:
case CT_P45:
case CT_GM45:
case CT_G41:
case CT_G31:
case CT_500:
case CT_3150:
case CT_UNKWN_INTEL:
outl(CONFIG_MECH_ONE_ADDR, 0x80000090);
outb(CONFIG_MECH_ONE_DATA + 1, map->b1);
outb(CONFIG_MECH_ONE_DATA + 2, map->b2);
break;
}
#if DEBUG
{
UInt32 t = inl(CONFIG_MECH_ONE_DATA);
verbose("relock PAM: (0x%08x)\n", t);
}
#endif
}
int getMode(edid_mode *mode)
{
char* edidInfo = readEDID();
if(!edidInfo) return 1;
mode->pixel_clock = (edidInfo[55] << 8) | edidInfo[54];
mode->h_active = edidInfo[56] | ((edidInfo[58] & 0xF0) << 4);
mode->h_blanking = ((edidInfo[58] & 0x0F) << 8) | edidInfo[57];
mode->v_active = edidInfo[59] | ((edidInfo[61] & 0xF0) << 4);
mode->v_blanking = ((edidInfo[61] & 0x0F) << 8) | edidInfo[60];
mode->h_sync_offset = ((edidInfo[65] & 0xC0) >> 2) | edidInfo[62];
mode->h_sync_width = (edidInfo[65] & 0x30) | edidInfo[63];
mode->v_sync_offset = (edidInfo[65] & 0x0C) | ((edidInfo[64] & 0x0C) >> 2);
mode->v_sync_width = ((edidInfo[65] & 0x3) << 2) | (edidInfo[64] & 0x03);
free( edidInfo );
if(!mode->h_active) return 1;
return 0;
}
static void gtf_timings(UInt32 x, UInt32 y, UInt32 freq,
unsigned long *clock,
UInt16 *hsyncstart, UInt16 *hsyncend, UInt16 *hblank,
UInt16 *vsyncstart, UInt16 *vsyncend, UInt16 *vblank)
{
UInt32 hbl, vbl, vfreq;
vbl = y + (y+1)/(20000.0/(11*freq) - 1) + 1.5;
vfreq = vbl * freq;
hbl = 16 * (int)(x * (30.0 - 300000.0 / vfreq) /
+ (70.0 + 300000.0 / vfreq) / 16.0 + 0.5);
*vsyncstart = y;
*vsyncend = y + 3;
*vblank = vbl - 1;
*hsyncstart = x + hbl / 2 - (x + hbl + 50) / 100 * 8 - 1;
*hsyncend = x + hbl / 2 - 1;
*hblank = x + hbl - 1;
*clock = (x + hbl) * vfreq / 1000;
}
void set_mode(vbios_map * map, /*UInt32 mode,*/ UInt32 x, UInt32 y, UInt32 bp, UInt32 htotal, UInt32 vtotal) {
UInt32 xprev, yprev;
UInt32 i = 0, j;
// patch first available mode
//for (i=0; i < map->mode_table_size; i++) {
//if (map->mode_table[0].mode == mode) {
switch(map->bios) {
case BT_1:
{
vbios_resolution_type1 * res = map_type1_resolution(map, map->mode_table[i].resolution);
if (bp) {
map->mode_table[i].bits_per_pixel = bp;
}
res->x2 = (htotal?(((htotal-x) >> 8) & 0x0f) : (res->x2 & 0x0f)) | ((x >> 4) & 0xf0);
res->x1 = (x & 0xff);
res->y2 = (vtotal?(((vtotal-y) >> 8) & 0x0f) : (res->y2 & 0x0f)) | ((y >> 4) & 0xf0);
res->y1 = (y & 0xff);
if (htotal)
res->x_total = ((htotal-x) & 0xff);
if (vtotal)
res->y_total = ((vtotal-y) & 0xff);
break;
}
case BT_2:
{
vbios_resolution_type2 * res = map_type2_resolution(map, map->mode_table[i].resolution);
res->xchars = x / 8;
res->ychars = y / 16 - 1;
xprev = res->modelines[0].x1;
yprev = res->modelines[0].y1;
for(j=0; j < 3; j++) {
vbios_modeline_type2 * modeline = &res->modelines[j];
if (modeline->x1 == xprev && modeline->y1 == yprev) {
modeline->x1 = modeline->x2 = x-1;
modeline->y1 = modeline->y2 = y-1;
gtf_timings(x, y, freqs[j], &modeline->clock,
&modeline->hsyncstart, &modeline->hsyncend,
&modeline->hblank, &modeline->vsyncstart,
&modeline->vsyncend, &modeline->vblank);
if (htotal)
modeline->htotal = htotal;
else
modeline->htotal = modeline->hblank;
if (vtotal)
modeline->vtotal = vtotal;
else
modeline->vtotal = modeline->vblank;
}
}
break;
}
case BT_3:
{
vbios_resolution_type3 * res = map_type3_resolution(map, map->mode_table[i].resolution);
xprev = res->modelines[0].x1;
yprev = res->modelines[0].y1;
for (j=0; j < 3; j++) {
vbios_modeline_type3 * modeline = &res->modelines[j];
if (modeline->x1 == xprev && modeline->y1 == yprev) {
modeline->x1 = modeline->x2 = x-1;
modeline->y1 = modeline->y2 = y-1;
gtf_timings(x, y, freqs[j], &modeline->clock,
&modeline->hsyncstart, &modeline->hsyncend,
&modeline->hblank, &modeline->vsyncstart,
&modeline->vsyncend, &modeline->vblank);
if (htotal)
modeline->htotal = htotal;
else
modeline->htotal = modeline->hblank;
if (vtotal)
modeline->vtotal = vtotal;
else
modeline->vtotal = modeline->vblank;
modeline->timing_h = y-1;
modeline->timing_v = x-1;
}
}
break;
}
case BT_ATI_1:
{
edid_mode mode;
ATOM_MODE_TIMING *mode_timing = (ATOM_MODE_TIMING *) map->ati_mode_table;
//if (mode.pixel_clock && (mode.h_active == x) && (mode.v_active == y) && !force) {
if (!getMode(&mode)) {
mode_timing->usCRTC_H_Total = mode.h_active + mode.h_blanking;
mode_timing->usCRTC_H_Disp = mode.h_active;
mode_timing->usCRTC_H_SyncStart = mode.h_active + mode.h_sync_offset;
mode_timing->usCRTC_H_SyncWidth = mode.h_sync_width;
mode_timing->usCRTC_V_Total = mode.v_active + mode.v_blanking;
mode_timing->usCRTC_V_Disp = mode.v_active;
mode_timing->usCRTC_V_SyncStart = mode.v_active + mode.v_sync_offset;
mode_timing->usCRTC_V_SyncWidth = mode.v_sync_width;
mode_timing->usPixelClock = mode.pixel_clock;
}
/*else
{
vbios_modeline_type2 modeline;
cvt_timings(x, y, freqs[0], &modeline.clock,
&modeline.hsyncstart, &modeline.hsyncend,
&modeline.hblank, &modeline.vsyncstart,
&modeline.vsyncend, &modeline.vblank, 0);
mode_timing->usCRTC_H_Total = x + modeline.hblank;
mode_timing->usCRTC_H_Disp = x;
mode_timing->usCRTC_H_SyncStart = modeline.hsyncstart;
mode_timing->usCRTC_H_SyncWidth = modeline.hsyncend - modeline.hsyncstart;
mode_timing->usCRTC_V_Total = y + modeline.vblank;
mode_timing->usCRTC_V_Disp = y;
mode_timing->usCRTC_V_SyncStart = modeline.vsyncstart;
mode_timing->usCRTC_V_SyncWidth = modeline.vsyncend - modeline.vsyncstart;
mode_timing->usPixelClock = modeline.clock;
}*/
break;
}
case BT_ATI_2:
{
edid_mode mode;
ATOM_DTD_FORMAT *mode_timing = (ATOM_DTD_FORMAT *) map->ati_mode_table;
/*if (mode.pixel_clock && (mode.h_active == x) && (mode.v_active == y) && !force) {*/
if (!getMode(&mode)) {
mode_timing->usHBlanking_Time = mode.h_blanking;
mode_timing->usHActive = mode.h_active;
mode_timing->usHSyncOffset = mode.h_sync_offset;
mode_timing->usHSyncWidth = mode.h_sync_width;
mode_timing->usVBlanking_Time = mode.v_blanking;
mode_timing->usVActive = mode.v_active;
mode_timing->usVSyncOffset = mode.v_sync_offset;
mode_timing->usVSyncWidth = mode.v_sync_width;
mode_timing->usPixClk = mode.pixel_clock;
}
/*else
{
vbios_modeline_type2 modeline;
cvt_timings(x, y, freqs[0], &modeline.clock,
&modeline.hsyncstart, &modeline.hsyncend,
&modeline.hblank, &modeline.vsyncstart,
&modeline.vsyncend, &modeline.vblank, 0);
mode_timing->usHBlanking_Time = modeline.hblank;
+mode_timing->usHActive = x;
+mode_timing->usHSyncOffset = modeline.hsyncstart - x;
+mode_timing->usHSyncWidth = modeline.hsyncend - modeline.hsyncstart;
+
+mode_timing->usVBlanking_Time = modeline.vblank;
+mode_timing->usVActive = y;
+mode_timing->usVSyncOffset = modeline.vsyncstart - y;
+mode_timing->usVSyncWidth = modeline.hsyncend - modeline.hsyncstart;
+
+mode_timing->usPixClk = modeline.clock;
+}*/
break;
}
case BT_NVDA:
{
edid_mode mode;
NV_MODELINE *mode_timing = (NV_MODELINE *) map->nv_mode_table;
/*if (mode.pixel_clock && (mode.h_active == x) && (mode.v_active == y) && !force) {*/
if (!getMode(&mode)) {
mode_timing[i].usH_Total = mode.h_active + mode.h_blanking;
mode_timing[i].usH_Active = mode.h_active;
mode_timing[i].usH_SyncStart = mode.h_active + mode.h_sync_offset;
mode_timing[i].usH_SyncEnd = mode.h_active + mode.h_sync_offset + mode.h_sync_width;
mode_timing[i].usV_Total = mode.v_active + mode.v_blanking;
mode_timing[i].usV_Active = mode.v_active;
mode_timing[i].usV_SyncStart = mode.v_active + mode.v_sync_offset;
mode_timing[i].usV_SyncEnd = mode.v_active + mode.v_sync_offset + mode.v_sync_width;
mode_timing[i].usPixel_Clock = mode.pixel_clock;
}
/*else
{
vbios_modeline_type2 modeline;
cvt_timings(x, y, freqs[0], &modeline.clock,
&modeline.hsyncstart, &modeline.hsyncend,
&modeline.hblank, &modeline.vsyncstart,
&modeline.vsyncend, &modeline.vblank, 0);
mode_timing[i].usH_Total = x + modeline.hblank - 1;
mode_timing[i].usH_Active = x;
mode_timing[i].usH_SyncStart = modeline.hsyncstart - 1;
mode_timing[i].usH_SyncEnd = modeline.hsyncend - 1;
mode_timing[i].usV_Total = y + modeline.vblank - 1;
mode_timing[i].usV_Active = y;
mode_timing[i].usV_SyncStart = modeline.vsyncstart - 1;
mode_timing[i].usV_SyncEnd = modeline.vsyncend - 1;
mode_timing[i].usPixel_Clock = modeline.clock;
}*/
break;
}
case BT_UNKWN:
{
break;
}
}
//}
//}
}
#endif // _RESOLUTION_H_
branches/meklort/i386/libsaio/edid.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
/*
* edid.c
*
*
* Created by Evan Lojewski on 12/1/09.
* Copyright 2009. All rights reserved.
*
*/
#include "libsaio.h"
#include "edid.h"
#include "vbe.h"
#include "graphics.h"
#include "boot.h"
void getResolution(UInt32* x, UInt32* y, UInt32* bp)
{
int val;
static UInt32 xResolution, yResolution, bpResolution;
if(getIntForKey(kScreenWidth, &val, &bootInfo->bootConfig))
{
xResolution = val;
}
if(getIntForKey(kScreenHeight, &val, &bootInfo->bootConfig))
{
yResolution = val;
}
bpResolution = 32;// assume 32bits
if(!xResolution || !yResolution || !bpResolution)
{
char* edidInfo = readEDID();
if(!edidInfo) return;
// TODO: check *all* resolutions reported and either use the highest, or the native resolution (if there is a flag for that)
xResolution = edidInfo[56] | ((edidInfo[58] & 0xF0) << 4);
yResolution = edidInfo[59] | ((edidInfo[61] & 0xF0) << 4);
//printf("H Active = %d", edidInfo[56] | ((edidInfo[58] & 0xF0) << 4) );
//printf("V Active = %d", edidInfo[59] | ((edidInfo[61] & 0xF0) << 4) );
free( edidInfo );
if(!xResolution) xResolution = DEFAULT_SCREEN_WIDTH;
if(!yResolution) yResolution = DEFAULT_SCREEN_HEIGHT;
}
*x = xResolution;
*y = yResolution;
*bp = bpResolution;
}
char* readEDID()
{
SInt16 last_reported = -1;
UInt8 edidInfo[EDID_BLOCK_SIZE];
UInt8 header1[] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00};
UInt8 header2[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
SInt16 status;
UInt16 blocks_left = 1;
do
{
// TODO: This currently only retrieves the *last* block, make the block buffer expand as needed / calculated from the first block
bzero( edidInfo, EDID_BLOCK_SIZE);
status = getEDID(edidInfo, blocks_left);
//printf("Buffer location: 0x%X\n", SEG(buffer) << 16 | OFF(buffer));
/*
int j, i;
for (j = 0; j < 8; j++) {
for(i = 0; i < 16; i++) printf("0x%X ", ebiosInfo[((i+1) * (j + 1)) - 1]);
}
printf("\n");
*/
if(status == 0)
{
//if( edidInfo[0] == 0x00 || edidInfo[0] == 0xFF)
if((memcmp(edidInfo, header1, sizeof(header1)) != 0) ||
(memcmp(edidInfo, header2, sizeof(header2)) != 0) )
{
blocks_left--;
int reported = edidInfo[ EDID_V1_BLOCKS_TO_GO_OFFSET ];
if ( reported > blocks_left )
{
printf("EDID claims %d more blocks left\n", reported);
}
if ( (last_reported <= reported && last_reported != -1)
|| reported == 0xff
/* 0xff frequently comes up in corrupt edids */
//|| reported == MAGIC
)
{
printf("Last reported %d\n", last_reported);
printf( "EDID blocks left is wrong.\n"
"Your EDID is probably invalid.\n");
return 0;
}
else
{
//printf("Reading EDID block\n");
//printf("H Active = %d", ebiosInfo[56] | ((ebiosInfo[58] & 0xF0) << 4) );
//printf("V Active = %d", ebiosInfo[59] | ((ebiosInfo[61] & 0xF0) << 4) );
last_reported = reported;
blocks_left = reported;
}
}
else
{
printf("Invalid block %d\n", blocks_left);
printf("Header1 = %d", memcmp(edidInfo, header1, sizeof(header1)) );
printf("Header2 = %d", memcmp(edidInfo, header2, sizeof(header2)) );
return 0;
}
}
blocks_left = 0;
} while(blocks_left);
char* ret = malloc(sizeof(edidInfo));
memcpy(ret, edidInfo, sizeof(edidInfo));
return ret;
}
branches/meklort/i386/libsaio/resolution.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
/*
* resolution.h
*
*
* Created by Evan Lojewski on 3/4/10.
* Copyright 2009. All rights reserved.
*
*/
#include "shortatombios.h"
#include "edid.h"
#ifndef __RESOLUTION_H
#define __RESOLUTION_H
typedef struct _edid_mode {
unsigned short pixel_clock;
unsigned short h_active;
unsigned short h_blanking;
unsigned short v_active;
unsigned short v_blanking;
unsigned short h_sync_offset;
unsigned short h_sync_width;
unsigned short v_sync_offset;
unsigned short v_sync_width;
} edid_mode;
void patchVideoBios();
/* Copied from 915 resolution created by steve tomljenovic
*
* This code is based on the techniques used in :
*
* - 855patch. Many thanks to Christian Zietz (czietz gmx net)
* for demonstrating how to shadow the VBIOS into system RAM
* and then modify it.
*
* - 1280patch by Andrew Tipton (andrewtipton null li).
*
* - 855resolution by Alain Poirier
*
* This source code is into the public domain.
*/
#define VBIOS_START 0xc0000
#define VBIOS_SIZE 0x10000
#define FALSE 0
#define TRUE 1
#define MODE_TABLE_OFFSET_845G 617
#define ATI_SIGNATURE1 "ATI MOBILITY RADEON"
#define ATI_SIGNATURE2 "ATI Technologies Inc"
#define NVIDIA_SIGNATURE "NVIDIA Corp"
#define INTEL_SIGNATURE "Intel Corp"
/*
* NVidia Defines and structures
*/
#define OFFSET_TO_VESA_TABLE_INDEX 2
typedef struct {
unsigned charucTable_Major;
unsigned charucTable_Minor;
unsigned charucTable_Rev;
unsigned shortusTable_Size;
} NV_COMMON_TABLE_HEADER;
typedef struct {
short reserved1;
short reserved2;
short reserved3;
} NV_RESERVED;
typedef struct {
unsigned shortusPixel_Clock;
unsigned shortusH_Active;
NV_RESERVEDreserved1;
unsigned shortusH_SyncStart;
unsigned shortusH_SyncEnd;
unsigned shortusH_Total;
unsigned shortusV_Active;
NV_RESERVEDreserved2;
unsigned shortusV_SyncStart;
unsigned shortusV_SyncEnd;
unsigned shortusV_Total;
unsigned shortreserved3;
} NV_MODELINE;
typedef struct {
NV_COMMON_TABLE_HEADERsHeader;
NV_MODELINE*sModelines;
} NV_VESA_TABLE;
/*---*/
typedef enum {
CT_UNKWN, CT_UNKWN_INTEL, CT_830, CT_845G, CT_855GM, CT_865G,
CT_915G, CT_915GM, CT_945G, CT_945GM, CT_945GME, CT_946GZ,
CT_955X, CT_G965, CT_Q965, CT_965GM, CT_975X,
CT_P35, CT_X48, CT_B43, CT_Q45, CT_P45,
CT_GM45, CT_G41, CT_G31, CT_G45, CT_500, CT_3150
} chipset_type;
typedef enum {
BT_UNKWN, BT_1, BT_2, BT_3, BT_ATI_1, BT_ATI_2, BT_NVDA
} bios_type;
typedef struct {
char *base;
ATOM_ROM_HEADER *AtomRomHeader;
unsigned short *MasterCommandTables;
unsigned short *MasterDataTables;
} bios_tables_t;
typedef struct {
UInt8 mode;
UInt8 bits_per_pixel;
UInt16 resolution;
UInt8 unknown;
} __attribute__((packed)) vbios_mode;
typedef struct {
UInt8 unknow1[2];
UInt8 x1;
UInt8 x_total;
UInt8 x2;
UInt8 y1;
UInt8 y_total;
UInt8 y2;
} __attribute__((packed)) vbios_resolution_type1;
typedef struct {
unsigned long clock;
UInt16 x1;
UInt16 htotal;
UInt16 x2;
UInt16 hblank;
UInt16 hsyncstart;
UInt16 hsyncend;
UInt16 y1;
UInt16 vtotal;
UInt16 y2;
UInt16 vblank;
UInt16 vsyncstart;
UInt16 vsyncend;
} __attribute__((packed)) vbios_modeline_type2;
typedef struct {
UInt8 xchars;
UInt8 ychars;
UInt8 unknown[4];
vbios_modeline_type2 modelines[];
} __attribute__((packed)) vbios_resolution_type2;
typedef struct {
unsigned long clock;
UInt16 x1;
UInt16 htotal;
UInt16 x2;
UInt16 hblank;
UInt16 hsyncstart;
UInt16 hsyncend;
UInt16 y1;
UInt16 vtotal;
UInt16 y2;
UInt16 vblank;
UInt16 vsyncstart;
UInt16 vsyncend;
UInt16 timing_h;
UInt16 timing_v;
UInt8 unknown[6];
} __attribute__((packed)) vbios_modeline_type3;
typedef struct {
unsigned char unknown[6];
vbios_modeline_type3 modelines[];
} __attribute__((packed)) vbios_resolution_type3;
typedef struct {
UInt32 chipset_id;
chipset_type chipset;
bios_type bios;
bios_tables_t ati_tables;
UInt32 bios_fd;
char* bios_ptr;
vbios_mode * mode_table;
char * ati_mode_table;
char * nv_mode_table;
UInt32 mode_table_size;
UInt8 b1, b2;
UInt8 unlocked;
} vbios_map;
vbios_map * open_vbios(chipset_type);
void close_vbios (vbios_map*);
void unlock_vbios(vbios_map*);
void relock_vbios(vbios_map*);
void set_mode(vbios_map*, UInt32, UInt32, UInt32, UInt32, UInt32);
#endif //__RESOLUTION_H
branches/meklort/i386/libsaio/edid.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*
* edid.h
*
*
* Created by Evan Lojewski on 12/1/09.
* Copyright 2009. All rights reserved.
*
*/
#define EDID_BLOCK_SIZE128
#define EDID_V1_BLOCKS_TO_GO_OFFSET 126
char* readEDID();
void getResolution(UInt32* x, UInt32* y, UInt32* bp);
branches/meklort/i386/libsaio/console.c
6464
6565
6666
67
67
6868
6969
7070
......
160160
161161
162162
163
164
165
166
167163
164
165
168166
169167
170168
......
191189
192190
193191
194
195
196
197
192
198193
199194
200195
......
221216
222217
223218
224
225
226
227
219
220
221
228222
229223
230224
......
235229
236230
237231
238
239
240
241
242
232
233
234
243235
244236
245237
char * last_str;
};
static void sputc(int c, struct putc_info * pi)
void sputc(int c, struct putc_info * pi)
{
if (pi->last_str)
if (pi->str == pi->last_str)
{
va_list ap;
va_start(ap, fmt);
if (bootArgs->Video.v_display == VGA_TEXT_MODE)
prf(fmt, ap, putchar, 0);
else
vprf(fmt, ap);
prf(fmt, ap, putchar, 0);
{
/* Kabyl: BooterLog */
struct putc_info pi;
va_start(ap, fmt);
if (gVerboseMode)
{
if (bootArgs->Video.v_display == VGA_TEXT_MODE)
prf(fmt, ap, putchar, 0);
else
vprf(fmt, ap);
prf(fmt, ap, putchar, 0);
}
{
va_list ap;
gErrors = true;
va_start(ap, fmt);
if (bootArgs->Video.v_display == VGA_TEXT_MODE)
prf(fmt, ap, putchar, 0);
else
vprf(fmt, ap);
prf(fmt, ap, putchar, 0);
va_end(ap);
return(0);
}
printf("\n");
va_start(ap, fmt);
if (bootArgs->Video.v_display == VGA_TEXT_MODE) {
prf(fmt, ap, putchar, 0);
} else {
vprf(fmt, ap);
}
prf(fmt, ap, putchar, 0);
va_end(ap);
printf("\nThis is a non recoverable error! System HALTED!!!");
halt();
branches/meklort/i386/libsaio/Makefile
4141
4242
4343
44
44
4545
46
46
4747
4848
4949
xml.o ntfs.o msdos.o md5c.o device_tree.o \
cpu.o platform.o acpi_patcher.o \
smbios_patcher.o fake_efi.o ext2fs.o \
hpet.o dram_controllers.o spd.o usb.o pci_setup.o \
hpet.o usb.o pci_setup.o \
device_inject.o pci_root.o \
convert.o mem.o aml_generator.o resolution.o edid.o
convert.o aml_generator.o
SAIO_EXTERN_OBJS = console.o
branches/meklort/i386/libsaio/sys.c
7979
8080
8181
82
8283
8384
85
8486
8587
8688
......
815817
816818
817819
820
818821
819822
820823
821824
822
825
823826
824827
825828
UUID_DEFINE( kFSUUIDNamespaceSHA1, 0xB3, 0xE2, 0x0F, 0x39, 0xF2, 0x92, 0x11, 0xD6, 0x97, 0xA4, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC );
#endif
#ifdef UNUSED
extern int multiboot_partition;
extern int multiboot_partition_set;
#endif
struct devsw {
const char * name;
if (chain->filtered) filteredChain = true;
#ifdef UNUSED
if (multiboot_partition_set)
for ( bvr = chain; bvr; bvr = bvr->next )
if ( bvr->part_no == multiboot_partition && bvr->biosdev == gBIOSDev )
return bvr;
#endif
/*
* Checking "Default Partition" key in system configuration - use format: hd(x,y), the volume UUID or label -
* to override the default selection.
branches/meklort/i386/libsaio/platform.c
1010
1111
1212
13
14
15
13
1614
1715
1816
......
4240
4341
4442
45
43
4644
4745
46
4847
49
50
51
52
53
48
5449
5550
5651
#include "pci.h"
#include "platform.h"
#include "cpu.h"
#include "mem.h"
#include "spd.h"
#include "dram_controllers.h"
#include "modules.h"
#ifndef DEBUG_PLATFORM
#define DEBUG_PLATFORM 0
static bool done = false;
if (done) return;
bool useAutodetection = true;
bool useAutodetection = true;
getBoolForKey(kUseMemDetect, &useAutodetection, &bootInfo->bootConfig);
if (useAutodetection) {
if (dram_controller_dev!=NULL) {
scan_dram_controller(dram_controller_dev); // Rek: pci dev ram controller direct and fully informative scan ...
}
scan_memory(&Platform); // unfortunately still necesary for some comp where spd cant read correct speed
scan_spd(&Platform);
execute_hook("ScanMemory", NULL, NULL, NULL, NULL);
//getc();
}
done = true;
branches/meklort/i386/libsaio/pci_setup.c
88
99
1010
11
1211
1312
1413
......
2221
2322
2423
25
26
27
28
29
30
24
25
26
3127
3228
3329
3430
35
36
37
38
3931
4032
4133
extern void notify_usb_dev(pci_dt_t *pci_dev);
extern void force_enable_hpet(pci_dt_t *lpc_dev);
extern pci_dt_t *dram_controller_dev;
void setup_pci_devs(pci_dt_t *pci_dt)
{
while (current)
{
switch (current->class_id)
{
case PCI_CLASS_BRIDGE_HOST:
dram_controller_dev = current;
break;
execute_hook("PCIDevice", current, NULL, NULL, NULL);
switch (current->class_id) {
case PCI_CLASS_NETWORK_ETHERNET:
if (do_eth_devprop)
set_eth_builtin(current);
break;
case PCI_CLASS_DISPLAY_VGA:
execute_hook("GraphicsEnabler", current, NULL, NULL, NULL);
break;
case PCI_CLASS_SERIAL_USB:
notify_usb_dev(current);
branches/meklort/i386/boot2/picopng.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
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
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
// picoPNG version 20080503 (cleaned up and ported to c by kaitek)
// Copyright (c) 2005-2008 Lode Vandevenne
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
#include "libsa.h"
#include "picopng.h"
/*************************************************************************************************/
typedef struct png_alloc_node {
struct png_alloc_node *prev, *next;
void *addr;
size_t size;
} png_alloc_node_t;
png_alloc_node_t *png_alloc_head = NULL;
png_alloc_node_t *png_alloc_tail = NULL;
png_alloc_node_t *png_alloc_find_node(void *addr)
{
png_alloc_node_t *node;
for (node = png_alloc_head; node; node = node->next)
if (node->addr == addr)
break;
return node;
}
void png_alloc_add_node(void *addr, size_t size)
{
png_alloc_node_t *node;
if (png_alloc_find_node(addr))
return;
node = malloc(sizeof (png_alloc_node_t));
node->addr = addr;
node->size = size;
node->prev = png_alloc_tail;
node->next = NULL;
png_alloc_tail = node;
if (node->prev)
node->prev->next = node;
if (!png_alloc_head)
png_alloc_head = node;
}
void png_alloc_remove_node(png_alloc_node_t *node)
{
if (node->prev)
node->prev->next = node->next;
if (node->next)
node->next->prev = node->prev;
if (node == png_alloc_head)
png_alloc_head = node->next;
if (node == png_alloc_tail)
png_alloc_tail = node->prev;
node->prev = node->next = node->addr = NULL;
free(node);
}
void *png_alloc_malloc(size_t size)
{
void *addr = malloc(size);
png_alloc_add_node(addr, size);
return addr;
}
void *png_alloc_realloc(void *addr, size_t size)
{
void *new_addr;
if (!addr)
return png_alloc_malloc(size);
new_addr = realloc(addr, size);
if (new_addr != addr) {
png_alloc_node_t *old_node;
old_node = png_alloc_find_node(addr);
png_alloc_remove_node(old_node);
png_alloc_add_node(new_addr, size);
}
return new_addr;
}
void png_alloc_free(void *addr)
{
png_alloc_node_t *node = png_alloc_find_node(addr);
if (!node)
return;
png_alloc_remove_node(node);
free(addr);
}
void png_alloc_free_all()
{
while (png_alloc_tail) {
void *addr = png_alloc_tail->addr;
png_alloc_remove_node(png_alloc_tail);
free(addr);
}
}
/*************************************************************************************************/
__unused void vector32_cleanup(vector32_t *p)
{
p->size = p->allocsize = 0;
if (p->data)
png_alloc_free(p->data);
p->data = NULL;
}
uint32_t vector32_resize(vector32_t *p, size_t size)
{// returns 1 if success, 0 if failure ==> nothing done
if (size * sizeof (uint32_t) > p->allocsize) {
size_t newsize = size * sizeof (uint32_t) * 2;
void *data = png_alloc_realloc(p->data, newsize);
if (data) {
p->allocsize = newsize;
p->data = (uint32_t *) data;
p->size = size;
} else
return 0;
} else
p->size = size;
return 1;
}
uint32_t vector32_resizev(vector32_t *p, size_t size, uint32_t value)
{// resize and give all new elements the value
size_t oldsize = p->size, i;
if (!vector32_resize(p, size))
return 0;
for (i = oldsize; i < size; i++)
p->data[i] = value;
return 1;
}
void vector32_init(vector32_t *p)
{
p->data = NULL;
p->size = p->allocsize = 0;
}
vector32_t *vector32_new(size_t size, uint32_t value)
{
vector32_t *p = png_alloc_malloc(sizeof (vector32_t));
vector32_init(p);
if (size && !vector32_resizev(p, size, value))
return NULL;
return p;
}
/*************************************************************************************************/
__unused void vector8_cleanup(vector8_t *p)
{
p->size = p->allocsize = 0;
if (p->data)
png_alloc_free(p->data);
p->data = NULL;
}
uint32_t vector8_resize(vector8_t *p, size_t size)
{// returns 1 if success, 0 if failure ==> nothing done
// xxx: the use of sizeof uint32_t here seems like a bug (this descends from the lodepng vector
// compatibility functions which do the same). without this there is corruption in certain cases,
// so this was probably done to cover up allocation bug(s) in the original picopng code!
if (size * sizeof (uint32_t) > p->allocsize) {
size_t newsize = size * sizeof (uint32_t) * 2;
void *data = png_alloc_realloc(p->data, newsize);
if (data) {
p->allocsize = newsize;
p->data = (uint8_t *) data;
p->size = size;
} else
return 0; // error: not enough memory
} else
p->size = size;
return 1;
}
uint32_t vector8_resizev(vector8_t *p, size_t size, uint8_t value)
{// resize and give all new elements the value
size_t oldsize = p->size, i;
if (!vector8_resize(p, size))
return 0;
for (i = oldsize; i < size; i++)
p->data[i] = value;
return 1;
}
void vector8_init(vector8_t *p)
{
p->data = NULL;
p->size = p->allocsize = 0;
}
vector8_t *vector8_new(size_t size, uint8_t value)
{
vector8_t *p = png_alloc_malloc(sizeof (vector8_t));
vector8_init(p);
if (size && !vector8_resizev(p, size, value))
return NULL;
return p;
}
vector8_t *vector8_copy(vector8_t *p)
{
vector8_t *q = vector8_new(p->size, 0);
uint32_t n;
for (n = 0; n < q->size; n++)
q->data[n] = p->data[n];
return q;
}
/*************************************************************************************************/
const uint32_t LENBASE[29] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51,
59, 67, 83, 99, 115, 131, 163, 195, 227, 258 };
const uint32_t LENEXTRA[29] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4,
4, 5, 5, 5, 5, 0 };
const uint32_t DISTBASE[30] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385,
513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 };
const uint32_t DISTEXTRA[30] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,
10, 10, 11, 11, 12, 12, 13, 13 };
// code length code lengths
const uint32_t CLCL[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
/*************************************************************************************************/
typedef struct {
// 2D representation of a huffman tree: The one dimension is "0" or "1", the other contains all
// nodes and leaves of the tree.
vector32_t *tree2d;
} HuffmanTree;
HuffmanTree *HuffmanTree_new()
{
HuffmanTree *tree = png_alloc_malloc(sizeof (HuffmanTree));
tree->tree2d = NULL;
return tree;
}
int HuffmanTree_makeFromLengths(HuffmanTree *tree, const vector32_t *bitlen, uint32_t maxbitlen)
{// make tree given the lengths
uint32_t bits, n, i;
uint32_t numcodes = (uint32_t) bitlen->size, treepos = 0, nodefilled = 0;
vector32_t *tree1d, *blcount, *nextcode;
tree1d = vector32_new(numcodes, 0);
blcount = vector32_new(maxbitlen + 1, 0);
nextcode = vector32_new(maxbitlen + 1, 0);
for (bits = 0; bits < numcodes; bits++)
blcount->data[bitlen->data[bits]]++; // count number of instances of each code length
for (bits = 1; bits <= maxbitlen; bits++)
nextcode->data[bits] = (nextcode->data[bits - 1] + blcount->data[bits - 1]) << 1;
for (n = 0; n < numcodes; n++)
if (bitlen->data[n] != 0)
tree1d->data[n] = nextcode->data[bitlen->data[n]]++; // generate all the codes
// 0x7fff here means the tree2d isn't filled there yet
vector32_t *tree2d = vector32_new(numcodes * 2, 0x7fff);
tree->tree2d = tree2d;
for (n = 0; n < numcodes; n++) // the codes
for (i = 0; i < bitlen->data[n]; i++) { // the bits for this code
uint32_t bit = (tree1d->data[n] >> (bitlen->data[n] - i - 1)) & 1;
if (treepos > numcodes - 2)
return 55;
if (tree2d->data[2 * treepos + bit] == 0x7fff) { // not yet filled in
if (i + 1 == bitlen->data[n]) { // last bit
tree2d->data[2 * treepos + bit] = n;
treepos = 0;
} else { // addresses are encoded as values > numcodes
tree2d->data[2 * treepos + bit] = ++nodefilled + numcodes;
treepos = nodefilled;
}
} else // subtract numcodes from address to get address value
treepos = tree2d->data[2 * treepos + bit] - numcodes;
}
return 0;
}
int HuffmanTree_decode(const HuffmanTree *tree, bool *decoded, uint32_t *result, size_t *treepos,
uint32_t bit)
{// Decodes a symbol from the tree
const vector32_t *tree2d = tree->tree2d;
uint32_t numcodes = (uint32_t) tree2d->size / 2;
if (*treepos >= numcodes)
return 11; // error: you appeared outside the codetree
*result = tree2d->data[2 * (*treepos) + bit];
*decoded = (*result < numcodes);
*treepos = *decoded ? 0 : *result - numcodes;
return 0;
}
/*************************************************************************************************/
int Inflator_error;
uint32_t Zlib_readBitFromStream(size_t *bitp, const uint8_t *bits)
{
uint32_t result = (bits[*bitp >> 3] >> (*bitp & 0x7)) & 1;
(*bitp)++;
return result;
}
uint32_t Zlib_readBitsFromStream(size_t *bitp, const uint8_t *bits, size_t nbits)
{
uint32_t i, result = 0;
for (i = 0; i < nbits; i++)
result += (Zlib_readBitFromStream(bitp, bits)) << i;
return result;
}
void Inflator_generateFixedTrees(HuffmanTree *tree, HuffmanTree *treeD)
{// get the tree of a deflated block with fixed tree
size_t i;
vector32_t *bitlen, *bitlenD;
bitlen = vector32_new(288, 8);
bitlenD = vector32_new(32, 5);
for (i = 144; i <= 255; i++)
bitlen->data[i] = 9;
for (i = 256; i <= 279; i++)
bitlen->data[i] = 7;
HuffmanTree_makeFromLengths(tree, bitlen, 15);
HuffmanTree_makeFromLengths(treeD, bitlenD, 15);
}
uint32_t Inflator_huffmanDecodeSymbol(const uint8_t *in, size_t *bp, const HuffmanTree *codetree,
size_t inlength)
{// decode a single symbol from given list of bits with given code tree. returns the symbol
bool decoded = false;
uint32_t ct = 0;
size_t treepos = 0;
for (;;) {
if ((*bp & 0x07) == 0 && (*bp >> 3) > inlength) {
Inflator_error = 10; // error: end reached without endcode
return 0;
}
Inflator_error = HuffmanTree_decode(codetree, &decoded, &ct, &treepos,
Zlib_readBitFromStream(bp, in));
if (Inflator_error)
return 0; // stop, an error happened
if (decoded)
return ct;
}
}
void Inflator_getTreeInflateDynamic(HuffmanTree *tree, HuffmanTree *treeD, const uint8_t *in,
size_t *bp, size_t inlength)
{// get the tree of a deflated block with dynamic tree, the tree itself is also Huffman
// compressed with a known tree
size_t i, n;
HuffmanTree *codelengthcodetree = HuffmanTree_new(); // the code tree for code length codes
vector32_t *bitlen, *bitlenD;
bitlen = vector32_new(288, 0);
bitlenD = vector32_new(32, 0);
if (*bp >> 3 >= inlength - 2) {
Inflator_error = 49; // the bit pointer is or will go past the memory
return;
}
size_t HLIT = Zlib_readBitsFromStream(bp, in, 5) + 257;// number of literal/length codes + 257
size_t HDIST = Zlib_readBitsFromStream(bp, in, 5) + 1;// number of dist codes + 1
size_t HCLEN = Zlib_readBitsFromStream(bp, in, 4) + 4;// number of code length codes + 4
vector32_t *codelengthcode; // lengths of tree to decode the lengths of the dynamic tree
codelengthcode = vector32_new(19, 0);
for (i = 0; i < 19; i++)
codelengthcode->data[CLCL[i]] = (i < HCLEN) ? Zlib_readBitsFromStream(bp, in, 3) : 0;
Inflator_error = HuffmanTree_makeFromLengths(codelengthcodetree, codelengthcode, 7);
if (Inflator_error)
return;
size_t replength;
for (i = 0; i < HLIT + HDIST; ) {
uint32_t code = Inflator_huffmanDecodeSymbol(in, bp, codelengthcodetree, inlength);
if (Inflator_error)
return;
if (code <= 15) { // a length code
if (i < HLIT)
bitlen->data[i++] = code;
else
bitlenD->data[i++ - HLIT] = code;
} else if (code == 16) { // repeat previous
if (*bp >> 3 >= inlength) {
Inflator_error = 50; // error, bit pointer jumps past memory
return;
}
replength = 3 + Zlib_readBitsFromStream(bp, in, 2);
uint32_t value; // set value to the previous code
if ((i - 1) < HLIT)
value = bitlen->data[i - 1];
else
value = bitlenD->data[i - HLIT - 1];
for (n = 0; n < replength; n++) { // repeat this value in the next lengths
if (i >= HLIT + HDIST) {
Inflator_error = 13; // error: i is larger than the amount of codes
return;
}
if (i < HLIT)
bitlen->data[i++] = value;
else
bitlenD->data[i++ - HLIT] = value;
}
} else if (code == 17) { // repeat "0" 3-10 times
if (*bp >> 3 >= inlength) {
Inflator_error = 50; // error, bit pointer jumps past memory
return;
}
replength = 3 + Zlib_readBitsFromStream(bp, in, 3);
for (n = 0; n < replength; n++) { // repeat this value in the next lengths
if (i >= HLIT + HDIST) {
Inflator_error = 14; // error: i is larger than the amount of codes
return;
}
if (i < HLIT)
bitlen->data[i++] = 0;
else
bitlenD->data[i++ - HLIT] = 0;
}
} else if (code == 18) { // repeat "0" 11-138 times
if (*bp >> 3 >= inlength) {
Inflator_error = 50; // error, bit pointer jumps past memory
return;
}
replength = 11 + Zlib_readBitsFromStream(bp, in, 7);
for (n = 0; n < replength; n++) { // repeat this value in the next lengths
if (i >= HLIT + HDIST) {
Inflator_error = 15; // error: i is larger than the amount of codes
return;
}
if (i < HLIT)
bitlen->data[i++] = 0;
else
bitlenD->data[i++ - HLIT] = 0;
}
} else {
Inflator_error = 16; // error: an nonexitent code appeared. This can never happen.
return;
}
}
if (bitlen->data[256] == 0) {
Inflator_error = 64; // the length of the end code 256 must be larger than 0
return;
}
// now we've finally got HLIT and HDIST, so generate the code trees, and the function is done
Inflator_error = HuffmanTree_makeFromLengths(tree, bitlen, 15);
if (Inflator_error)
return;
Inflator_error = HuffmanTree_makeFromLengths(treeD, bitlenD, 15);
if (Inflator_error)
return;
}
void Inflator_inflateHuffmanBlock(vector8_t *out, const uint8_t *in, size_t *bp, size_t *pos,
size_t inlength, uint32_t btype)
{
HuffmanTree *codetree, *codetreeD; // the code tree for Huffman codes, dist codes
codetree = HuffmanTree_new();
codetreeD = HuffmanTree_new();
if (btype == 1)
Inflator_generateFixedTrees(codetree, codetreeD);
else if (btype == 2) {
Inflator_getTreeInflateDynamic(codetree, codetreeD, in, bp, inlength);
if (Inflator_error)
return;
}
for (;;) {
uint32_t code = Inflator_huffmanDecodeSymbol(in, bp, codetree, inlength);
if (Inflator_error)
return;
if (code == 256) // end code
return;
else if (code <= 255) { // literal symbol
if (*pos >= out->size)
vector8_resize(out, (*pos + 1) * 2); // reserve more room
out->data[(*pos)++] = (uint8_t) code;
} else if (code >= 257 && code <= 285) { // length code
size_t length = LENBASE[code - 257], numextrabits = LENEXTRA[code - 257];
if ((*bp >> 3) >= inlength) {
Inflator_error = 51; // error, bit pointer will jump past memory
return;
}
length += Zlib_readBitsFromStream(bp, in, numextrabits);
uint32_t codeD = Inflator_huffmanDecodeSymbol(in, bp, codetreeD, inlength);
if (Inflator_error)
return;
if (codeD > 29) {
Inflator_error = 18; // error: invalid dist code (30-31 are never used)
return;
}
uint32_t dist = DISTBASE[codeD], numextrabitsD = DISTEXTRA[codeD];
if ((*bp >> 3) >= inlength) {
Inflator_error = 51; // error, bit pointer will jump past memory
return;
}
dist += Zlib_readBitsFromStream(bp, in, numextrabitsD);
size_t start = *pos, back = start - dist; // backwards
if (*pos + length >= out->size)
vector8_resize(out, (*pos + length) * 2); // reserve more room
size_t i;
for (i = 0; i < length; i++) {
out->data[(*pos)++] = out->data[back++];
if (back >= start)
back = start - dist;
}
}
}
}
void Inflator_inflateNoCompression(vector8_t *out, const uint8_t *in, size_t *bp, size_t *pos,
size_t inlength)
{
while ((*bp & 0x7) != 0)
(*bp)++; // go to first boundary of byte
size_t p = *bp / 8;
if (p >= inlength - 4) {
Inflator_error = 52; // error, bit pointer will jump past memory
return;
}
uint32_t LEN = in[p] + 256 * in[p + 1], NLEN = in[p + 2] + 256 * in[p + 3];
p += 4;
if (LEN + NLEN != 65535) {
Inflator_error = 21; // error: NLEN is not one's complement of LEN
return;
}
if (*pos + LEN >= out->size)
vector8_resize(out, *pos + LEN);
if (p + LEN > inlength) {
Inflator_error = 23; // error: reading outside of in buffer
return;
}
uint32_t n;
for (n = 0; n < LEN; n++)
out->data[(*pos)++] = in[p++]; // read LEN bytes of literal data
*bp = p * 8;
}
void Inflator_inflate(vector8_t *out, const vector8_t *in, size_t inpos)
{
size_t bp = 0, pos = 0; // bit pointer and byte pointer
Inflator_error = 0;
uint32_t BFINAL = 0;
while (!BFINAL && !Inflator_error) {
if (bp >> 3 >= in->size) {
Inflator_error = 52; // error, bit pointer will jump past memory
return;
}
BFINAL = Zlib_readBitFromStream(&bp, &in->data[inpos]);
uint32_t BTYPE = Zlib_readBitFromStream(&bp, &in->data[inpos]);
BTYPE += 2 * Zlib_readBitFromStream(&bp, &in->data[inpos]);
if (BTYPE == 3) {
Inflator_error = 20; // error: invalid BTYPE
return;
}
else if (BTYPE == 0)
Inflator_inflateNoCompression(out, &in->data[inpos], &bp, &pos, in->size);
else
Inflator_inflateHuffmanBlock(out, &in->data[inpos], &bp, &pos, in->size, BTYPE);
}
if (!Inflator_error)
vector8_resize(out, pos); // Only now we know the true size of out, resize it to that
}
/*************************************************************************************************/
int Zlib_decompress(vector8_t *out, const vector8_t *in) // returns error value
{
if (in->size < 2)
return 53; // error, size of zlib data too small
if ((in->data[0] * 256 + in->data[1]) % 31 != 0)
// error: 256 * in->data[0] + in->data[1] must be a multiple of 31, the FCHECK value is
// supposed to be made that way
return 24;
uint32_t CM = in->data[0] & 15, CINFO = (in->data[0] >> 4) & 15, FDICT = (in->data[1] >> 5) & 1;
if (CM != 8 || CINFO > 7)
// error: only compression method 8: inflate with sliding window of 32k is supported by
// the PNG spec
return 25;
if (FDICT != 0)
// error: the specification of PNG says about the zlib stream: "The additional flags shall
// not specify a preset dictionary."
return 26;
Inflator_inflate(out, in, 2);
return Inflator_error; // note: adler32 checksum was skipped and ignored
}
/*************************************************************************************************/
#define PNG_SIGNATURE0x0a1a0a0d474e5089ull
#define CHUNK_IHDR0x52444849
#define CHUNK_IDAT0x54414449
#define CHUNK_IEND0x444e4549
#define CHUNK_PLTE0x45544c50
#define CHUNK_tRNS0x534e5274
int PNG_error;
uint32_t PNG_readBitFromReversedStream(size_t *bitp, const uint8_t *bits)
{
uint32_t result = (bits[*bitp >> 3] >> (7 - (*bitp & 0x7))) & 1;
(*bitp)++;
return result;
}
uint32_t PNG_readBitsFromReversedStream(size_t *bitp, const uint8_t *bits, uint32_t nbits)
{
uint32_t i, result = 0;
for (i = nbits - 1; i < nbits; i--)
result += ((PNG_readBitFromReversedStream(bitp, bits)) << i);
return result;
}
void PNG_setBitOfReversedStream(size_t *bitp, uint8_t *bits, uint32_t bit)
{
bits[*bitp >> 3] |= (bit << (7 - (*bitp & 0x7)));
(*bitp)++;
}
uint32_t PNG_read32bitInt(const uint8_t *buffer)
{
return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
}
int PNG_checkColorValidity(uint32_t colorType, uint32_t bd) // return type is a LodePNG error code
{
if ((colorType == 2 || colorType == 4 || colorType == 6)) {
if (!(bd == 8 || bd == 16))
return 37;
else
return 0;
} else if (colorType == 0) {
if (!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16))
return 37;
else
return 0;
} else if (colorType == 3) {
if (!(bd == 1 || bd == 2 || bd == 4 || bd == 8))
return 37;
else
return 0;
} else
return 31; // nonexistent color type
}
uint32_t PNG_getBpp(const PNG_info_t *info)
{
uint32_t bitDepth, colorType;
bitDepth = info->bitDepth;
colorType = info->colorType;
if (colorType == 2)
return (3 * bitDepth);
else if (colorType >= 4)
return (colorType - 2) * bitDepth;
else
return bitDepth;
}
void PNG_readPngHeader(PNG_info_t *info, const uint8_t *in, size_t inlength)
{// read the information from the header and store it in the Info
if (inlength < 29) {
PNG_error = 27; // error: the data length is smaller than the length of the header
return;
}
if (*(uint64_t *) in != PNG_SIGNATURE) {
PNG_error = 28; // no PNG signature
return;
}
if (*(uint32_t *) &in[12] != CHUNK_IHDR) {
PNG_error = 29; // error: it doesn't start with a IHDR chunk!
return;
}
info->width = PNG_read32bitInt(&in[16]);
info->height = PNG_read32bitInt(&in[20]);
info->bitDepth = in[24];
info->colorType = in[25];
info->compressionMethod = in[26];
if (in[26] != 0) {
PNG_error = 32; // error: only compression method 0 is allowed in the specification
return;
}
info->filterMethod = in[27];
if (in[27] != 0) {
PNG_error = 33; // error: only filter method 0 is allowed in the specification
return;
}
info->interlaceMethod = in[28];
if (in[28] > 1) {
PNG_error = 34; // error: only interlace methods 0 and 1 exist in the specification
return;
}
PNG_error = PNG_checkColorValidity(info->colorType, info->bitDepth);
}
int PNG_paethPredictor(int a, int b, int c) // Paeth predicter, used by PNG filter type 4
{
int p, pa, pb, pc;
p = a + b - c;
pa = p > a ? (p - a) : (a - p);
pb = p > b ? (p - b) : (b - p);
pc = p > c ? (p - c) : (c - p);
return (pa <= pb && pa <= pc) ? a : (pb <= pc ? b : c);
}
void PNG_unFilterScanline(uint8_t *recon, const uint8_t *scanline, const uint8_t *precon,
size_t bytewidth, uint32_t filterType, size_t length)
{
size_t i;
switch (filterType) {
case 0:
for (i = 0; i < length; i++)
recon[i] = scanline[i];
break;
case 1:
for (i = 0; i < bytewidth; i++)
recon[i] = scanline[i];
for (i = bytewidth; i < length; i++)
recon[i] = scanline[i] + recon[i - bytewidth];
break;
case 2:
if (precon)
for (i = 0; i < length; i++)
recon[i] = scanline[i] + precon[i];
else
for (i = 0; i < length; i++)
recon[i] = scanline[i];
break;
case 3:
if (precon) {
for (i = 0; i < bytewidth; i++)
recon[i] = scanline[i] + precon[i] / 2;
for (i = bytewidth; i < length; i++)
recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2);
} else {
for (i = 0; i < bytewidth; i++)
recon[i] = scanline[i];
for (i = bytewidth; i < length; i++)
recon[i] = scanline[i] + recon[i - bytewidth] / 2;
}
break;
case 4:
if (precon) {
for (i = 0; i < bytewidth; i++)
recon[i] = (uint8_t) (scanline[i] + PNG_paethPredictor(0, precon[i], 0));
for (i = bytewidth; i < length; i++)
recon[i] = (uint8_t) (scanline[i] + PNG_paethPredictor(recon[i - bytewidth],
precon[i], precon[i - bytewidth]));
} else {
for (i = 0; i < bytewidth; i++)
recon[i] = scanline[i];
for (i = bytewidth; i < length; i++)
recon[i] = (uint8_t) (scanline[i] + PNG_paethPredictor(recon[i - bytewidth], 0, 0));
}
break;
default:
PNG_error = 36; // error: nonexistent filter type given
return;
}
}
void PNG_adam7Pass(uint8_t *out, uint8_t *linen, uint8_t *lineo, const uint8_t *in, uint32_t w,
size_t passleft, size_t passtop, size_t spacex, size_t spacey, size_t passw, size_t passh,
uint32_t bpp)
{// filter and reposition the pixels into the output when the image is Adam7 interlaced. This
// function can only do it after the full image is already decoded. The out buffer must have
// the correct allocated memory size already.
if (passw == 0)
return;
size_t bytewidth = (bpp + 7) / 8, linelength = 1 + ((bpp * passw + 7) / 8);
uint32_t y;
for (y = 0; y < passh; y++) {
size_t i, b;
uint8_t filterType = in[y * linelength], *prevline = (y == 0) ? 0 : lineo;
PNG_unFilterScanline(linen, &in[y * linelength + 1], prevline, bytewidth, filterType,
(w * bpp + 7) / 8);
if (PNG_error)
return;
if (bpp >= 8)
for (i = 0; i < passw; i++)
for (b = 0; b < bytewidth; b++) // b = current byte of this pixel
out[bytewidth * w * (passtop + spacey * y) + bytewidth *
(passleft + spacex * i) + b] = linen[bytewidth * i + b];
else
for (i = 0; i < passw; i++) {
size_t obp, bp;
obp = bpp * w * (passtop + spacey * y) + bpp * (passleft + spacex * i);
bp = i * bpp;
for (b = 0; b < bpp; b++)
PNG_setBitOfReversedStream(&obp, out, PNG_readBitFromReversedStream(&bp, linen));
}
uint8_t *temp = linen;
linen = lineo;
lineo = temp; // swap the two buffer pointers "line old" and "line new"
}
}
int PNG_convert(const PNG_info_t *info, vector8_t *out, const uint8_t *in)
{// converts from any color type to 32-bit. return value = LodePNG error code
size_t i, c;
uint32_t bitDepth, colorType;
bitDepth = info->bitDepth;
colorType = info->colorType;
size_t numpixels = info->width * info->height, bp = 0;
vector8_resize(out, numpixels * 4);
uint8_t *out_data = out->size ? out->data : 0;
if (bitDepth == 8 && colorType == 0) // greyscale
for (i = 0; i < numpixels; i++) {
out_data[4 * i + 0] = out_data[4 * i + 1] = out_data[4 * i + 2] = in[i];
out_data[4 * i + 3] = (info->key_defined && (in[i] == info->key_r)) ? 0 : 255;
}
else if (bitDepth == 8 && colorType == 2) // RGB color
for (i = 0; i < numpixels; i++) {
for (c = 0; c < 3; c++)
out_data[4 * i + c] = in[3 * i + c];
out_data[4 * i + 3] = (info->key_defined && (in[3 * i + 0] == info->key_r) &&
(in[3 * i + 1] == info->key_g) && (in[3 * i + 2] == info->key_b)) ? 0 : 255;
}
else if (bitDepth == 8 && colorType == 3) // indexed color (palette)
for (i = 0; i < numpixels; i++) {
if (4U * in[i] >= info->palette->size)
return 46;
for (c = 0; c < 4; c++) // get rgb colors from the palette
out_data[4 * i + c] = info->palette->data[4 * in[i] + c];
}
else if (bitDepth == 8 && colorType == 4) // greyscale with alpha
for (i = 0; i < numpixels; i++) {
out_data[4 * i + 0] = out_data[4 * i + 1] = out_data[4 * i + 2] = in[2 * i + 0];
out_data[4 * i + 3] = in[2 * i + 1];
}
else if (bitDepth == 8 && colorType == 6)
for (i = 0; i < numpixels; i++)
for (c = 0; c < 4; c++)
out_data[4 * i + c] = in[4 * i + c]; // RGB with alpha
else if (bitDepth == 16 && colorType == 0) // greyscale
for (i = 0; i < numpixels; i++) {
out_data[4 * i + 0] = out_data[4 * i + 1] = out_data[4 * i + 2] = in[2 * i];
out_data[4 * i + 3] = (info->key_defined && (256U * in[i] + in[i + 1] == info->key_r))
? 0 : 255;
}
else if (bitDepth == 16 && colorType == 2) // RGB color
for (i = 0; i < numpixels; i++) {
for (c = 0; c < 3; c++)
out_data[4 * i + c] = in[6 * i + 2 * c];
out_data[4 * i + 3] = (info->key_defined &&
(256U * in[6 * i + 0] + in[6 * i + 1] == info->key_r) &&
(256U * in[6 * i + 2] + in[6 * i + 3] == info->key_g) &&
(256U * in[6 * i + 4] + in[6 * i + 5] == info->key_b)) ? 0 : 255;
}
else if (bitDepth == 16 && colorType == 4) // greyscale with alpha
for (i = 0; i < numpixels; i++) {
out_data[4 * i + 0] = out_data[4 * i + 1] = out_data[4 * i + 2] = in[4 * i]; // msb
out_data[4 * i + 3] = in[4 * i + 2];
}
else if (bitDepth == 16 && colorType == 6)
for (i = 0; i < numpixels; i++)
for (c = 0; c < 4; c++)
out_data[4 * i + c] = in[8 * i + 2 * c]; // RGB with alpha
else if (bitDepth < 8 && colorType == 0) // greyscale
for (i = 0; i < numpixels; i++) {
uint32_t value = (PNG_readBitsFromReversedStream(&bp, in, bitDepth) * 255) /
((1 << bitDepth) - 1); // scale value from 0 to 255
out_data[4 * i + 0] = out_data[4 * i + 1] = out_data[4 * i + 2] = (uint8_t) value;
out_data[4 * i + 3] = (info->key_defined && value &&
(((1U << bitDepth) - 1U) == info->key_r) && ((1U << bitDepth) - 1U)) ? 0 : 255;
}
else if (bitDepth < 8 && colorType == 3) // palette
for (i = 0; i < numpixels; i++) {
uint32_t value = PNG_readBitsFromReversedStream(&bp, in, bitDepth);
if (4 * value >= info->palette->size)
return 47;
for (c = 0; c < 4; c++) // get rgb colors from the palette
out_data[4 * i + c] = info->palette->data[4 * value + c];
}
return 0;
}
PNG_info_t *PNG_info_new()
{
PNG_info_t *info = png_alloc_malloc(sizeof (PNG_info_t));
uint32_t i;
for (i = 0; i < sizeof (PNG_info_t); i++)
((uint8_t *) info)[i] = 0;
info->palette = vector8_new(0, 0);
info->image = vector8_new(0, 0);
return info;
}
PNG_info_t *PNG_decode(const uint8_t *in, uint32_t size)
{
PNG_info_t *info;
PNG_error = 0;
if (size == 0 || in == 0) {
PNG_error = 48; // the given data is empty
return NULL;
}
info = PNG_info_new();
PNG_readPngHeader(info, in, size);
if (PNG_error)
return NULL;
size_t pos = 33; // first byte of the first chunk after the header
vector8_t *idat = NULL; // the data from idat chunks
bool IEND = false, known_type = true;
info->key_defined = false;
// loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. IDAT data is
// put at the start of the in buffer
while (!IEND) {
size_t i, j;
if (pos + 8 >= size) {
PNG_error = 30; // error: size of the in buffer too small to contain next chunk
return NULL;
}
size_t chunkLength = PNG_read32bitInt(&in[pos]);
pos += 4;
if (chunkLength > 0x7fffffff) {
PNG_error = 63;
return NULL;
}
if (pos + chunkLength >= size) {
PNG_error = 35; // error: size of the in buffer too small to contain next chunk
return NULL;
}
uint32_t chunkType = *(uint32_t *) &in[pos];
if (chunkType == CHUNK_IDAT) { // IDAT: compressed image data chunk
size_t offset = 0;
if (idat) {
offset = idat->size;
vector8_resize(idat, offset + chunkLength);
} else
idat = vector8_new(chunkLength, 0);
for (i = 0; i < chunkLength; i++)
idat->data[offset + i] = in[pos + 4 + i];
pos += (4 + chunkLength);
} else if (chunkType == CHUNK_IEND) { // IEND
pos += 4;
IEND = true;
} else if (chunkType == CHUNK_PLTE) { // PLTE: palette chunk
pos += 4; // go after the 4 letters
vector8_resize(info->palette, 4 * (chunkLength / 3));
if (info->palette->size > (4 * 256)) {
PNG_error = 38; // error: palette too big
return NULL;
}
for (i = 0; i < info->palette->size; i += 4) {
for (j = 0; j < 3; j++)
info->palette->data[i + j] = in[pos++]; // RGB
info->palette->data[i + 3] = 255; // alpha
}
} else if (chunkType == CHUNK_tRNS) { // tRNS: palette transparency chunk
pos += 4; // go after the 4 letters
if (info->colorType == 3) {
if (4 * chunkLength > info->palette->size) {
PNG_error = 39; // error: more alpha values given than there are palette entries
return NULL;
}
for (i = 0; i < chunkLength; i++)
info->palette->data[4 * i + 3] = in[pos++];
} else if (info->colorType == 0) {
if (chunkLength != 2) {
PNG_error = 40; // error: this chunk must be 2 bytes for greyscale image
return NULL;
}
info->key_defined = true;
info->key_r = info->key_g = info->key_b = 256 * in[pos] + in[pos + 1];
pos += 2;
} else if (info->colorType == 2) {
if (chunkLength != 6) {
PNG_error = 41; // error: this chunk must be 6 bytes for RGB image
return NULL;
}
info->key_defined = true;
info->key_r = 256 * in[pos] + in[pos + 1];
pos += 2;
info->key_g = 256 * in[pos] + in[pos + 1];
pos += 2;
info->key_b = 256 * in[pos] + in[pos + 1];
pos += 2;
} else {
PNG_error = 42; // error: tRNS chunk not allowed for other color models
return NULL;
}
} else { // it's not an implemented chunk type, so ignore it: skip over the data
if (!(in[pos + 0] & 32)) {
// error: unknown critical chunk (5th bit of first byte of chunk type is 0)
PNG_error = 69;
return NULL;
}
pos += (chunkLength + 4); // skip 4 letters and uninterpreted data of unimplemented chunk
known_type = false;
}
pos += 4; // step over CRC (which is ignored)
}
uint32_t bpp = PNG_getBpp(info);
vector8_t *scanlines; // now the out buffer will be filled
scanlines = vector8_new(((info->width * (info->height * bpp + 7)) / 8) + info->height, 0);
PNG_error = Zlib_decompress(scanlines, idat);
if (PNG_error)
return NULL; // stop if the zlib decompressor returned an error
size_t bytewidth = (bpp + 7) / 8, outlength = (info->height * info->width * bpp + 7) / 8;
vector8_resize(info->image, outlength); // time to fill the out buffer
uint8_t *out_data = outlength ? info->image->data : 0;
if (info->interlaceMethod == 0) { // no interlace, just filter
size_t y, obp, bp;
size_t linestart, linelength;
linestart = 0;
// length in bytes of a scanline, excluding the filtertype byte
linelength = (info->width * bpp + 7) / 8;
if (bpp >= 8) // byte per byte
for (y = 0; y < info->height; y++) {
uint32_t filterType = scanlines->data[linestart];
const uint8_t *prevline;
prevline = (y == 0) ? 0 : &out_data[(y - 1) * info->width * bytewidth];
PNG_unFilterScanline(&out_data[linestart - y], &scanlines->data[linestart + 1],
prevline, bytewidth, filterType, linelength);
if (PNG_error)
return NULL;
linestart += (1 + linelength); // go to start of next scanline
} else { // less than 8 bits per pixel, so fill it up bit per bit
vector8_t *templine; // only used if bpp < 8
templine = vector8_new((info->width * bpp + 7) >> 3, 0);
for (y = 0, obp = 0; y < info->height; y++) {
uint32_t filterType = scanlines->data[linestart];
const uint8_t *prevline;
prevline = (y == 0) ? 0 : &out_data[(y - 1) * info->width * bytewidth];
PNG_unFilterScanline(templine->data, &scanlines->data[linestart + 1], prevline,
bytewidth, filterType, linelength);
if (PNG_error)
return NULL;
for (bp = 0; bp < info->width * bpp;)
PNG_setBitOfReversedStream(&obp, out_data, PNG_readBitFromReversedStream(&bp,
templine->data));
linestart += (1 + linelength); // go to start of next scanline
}
}
} else { // interlaceMethod is 1 (Adam7)
int i;
size_t passw[7] = {
(info->width + 7) / 8, (info->width + 3) / 8, (info->width + 3) / 4,
(info->width + 1) / 4, (info->width + 1) / 2, (info->width + 0) / 2,
(info->width + 0) / 1
};
size_t passh[7] = {
(info->height + 7) / 8, (info->height + 7) / 8, (info->height + 3) / 8,
(info->height + 3) / 4, (info->height + 1) / 4, (info->height + 1) / 2,
(info->height + 0) / 2
};
size_t passstart[7] = { 0 };
size_t pattern[28] = { 0, 4, 0, 2, 0, 1, 0, 0, 0, 4, 0, 2, 0, 1, 8, 8, 4, 4, 2, 2, 1, 8, 8,
8, 4, 4, 2, 2 }; // values for the adam7 passes
for (i = 0; i < 6; i++)
passstart[i + 1] = passstart[i] + passh[i] * ((passw[i] ? 1 : 0) + (passw[i] * bpp + 7) / 8);
vector8_t *scanlineo, *scanlinen; // "old" and "new" scanline
scanlineo = vector8_new((info->width * bpp + 7) / 8, 0);
scanlinen = vector8_new((info->width * bpp + 7) / 8, 0);
for (i = 0; i < 7; i++)
PNG_adam7Pass(out_data, scanlinen->data, scanlineo->data, &scanlines->data[passstart[i]],
info->width, pattern[i], pattern[i + 7], pattern[i + 14], pattern[i + 21],
passw[i], passh[i], bpp);
}
if (info->colorType != 6 || info->bitDepth != 8) { // conversion needed
vector8_t *copy = vector8_copy(info->image); // xxx: is this copy necessary?
PNG_error = PNG_convert(info, info->image, copy->data);
}
return info;
}
/*************************************************************************************************/
#ifdef TEST
#include <stdio.h>
#include <sys/stat.h>
int main(int argc, char **argv)
{
char *fname = (argc > 1) ? argv[1] : "test.png";
PNG_info_t *info;
struct stat statbuf;
uint32_t insize, outsize;
FILE *infp, *outfp;
uint8_t *inbuf;
uint32_t n;
if (stat(fname, &statbuf) != 0) {
perror("stat");
return 1;
} else if (!statbuf.st_size) {
printf("file empty\n");
return 1;
}
insize = (uint32_t) statbuf.st_size;
inbuf = malloc(insize);
infp = fopen(fname, "rb");
if (!infp) {
perror("fopen");
return 1;
} else if (fread(inbuf, 1, insize, infp) != insize) {
perror("fread");
return 1;
}
fclose(infp);
printf("input file: %s (size: %d)\n", fname, insize);
info = PNG_decode(inbuf, insize);
free(inbuf);
printf("PNG_error: %d\n", PNG_error);
if (PNG_error != 0)
return 1;
printf("width: %d, height: %d\nfirst 16 bytes: ", info->width, info->height);
for (n = 0; n < 16; n++)
printf("%02x ", info->image->data[n]);
printf("\n");
outsize = info->width * info->height * 4;
printf("image size: %d\n", outsize);
if (outsize != info->image->size) {
printf("error: image size doesn't match dimensions\n");
return 1;
}
outfp = fopen("out.bin", "wb");
if (!outfp) {
perror("fopen");
return 1;