Chameleon

Chameleon Commit Details

Date:2011-06-25 18:05:07 (7 years 11 months ago)
Author:Evan Lojewski
Commit:1065
Parents: 1064
Message:Stripping out a bunch of code...
Changes:
D/branches/rewrite/i386/boot2/options.c
D/branches/rewrite/i386/boot2/graphic_utils.c
D/branches/rewrite/i386/boot2/ramdisk.h
D/branches/rewrite/i386/boot2/picopng.c
D/branches/rewrite/i386/boot2/resume.c
D/branches/rewrite/i386/boot2/graphic_utils.h
D/branches/rewrite/i386/boot2/picopng.h
D/branches/rewrite/i386/boot2/WKdm.h
D/branches/rewrite/i386/boot2/drivers.c
D/branches/rewrite/i386/boot2/bmdecompress.c
D/branches/rewrite/i386/boot2/appleClut8.h
D/branches/rewrite/i386/boot2/IOHibernatePrivate.h
D/branches/rewrite/i386/boot2/lzss.c
D/branches/rewrite/i386/boot2/graphics.h
D/branches/rewrite/i386/boot2/prompt.c
D/branches/rewrite/i386/boot2/gui.c
D/branches/rewrite/i386/boot2/WKdmDecompress.c
D/branches/rewrite/i386/boot2/gui.h
D/branches/rewrite/i386/boot2/ramdisk.c
D/branches/rewrite/i386/boot2/appleboot.h
M/branches/rewrite/i386/boot2/Makefile
M/branches/rewrite/i386/libsaio/console.c
M/branches/rewrite/i386/boot2/boot.c
M/branches/rewrite/i386/libsaio/sys.c
M/branches/rewrite/i386/libsaio/load.c
M/branches/rewrite/i386/boot2/mboot.c
M/branches/rewrite/i386/libsaio/platform.c
M/branches/rewrite/i386/libsaio/allocate.c
M/branches/rewrite/i386/libsaio/cpu.c
M/branches/rewrite/i386/libsaio/disk.c
M/branches/rewrite/i386/libsaio/Makefile
M/branches/rewrite/i386/libsaio/pci.c
M/branches/rewrite/i386/libsaio/stringTable.c
M/branches/rewrite/i386/boot2/Cconfig

File differences

branches/rewrite/i386/libsaio/console.c
4848
4949
5050
51
52
5351
5452
5553
......
173171
174172
175173
176
177
178
179
180174
175
176
181177
182178
183179
......
204200
205201
206202
207
208
209
210
203
211204
212205
213206
......
234227
235228
236229
237
238
239
240
230
241231
242232
243233
......
248238
249239
250240
251
252
253
254
255
241
256242
257243
258244
#include "bootstruct.h"
#include <vers.h>
extern intvprf(const char * fmt, va_list ap);
bool gVerboseMode;
bool gErrors;
{
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/rewrite/i386/libsaio/allocate.c
2727
2828
2929
30
31
3230
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
31
#include "bootstruct.h"
#include "device_tree.h"
static long gImageLastKernelAddr;
#define kPageSize 4096
#define RoundPage(x) ((((unsigned)(x)) + kPageSize - 1) & ~(kPageSize - 1))
long
AllocateMemoryRange(char * rangeName, long start, long length, long type)
{
char *nameBuf;
uint32_t *buffer;
nameBuf = malloc(strlen(rangeName) + 1);
if (nameBuf == 0) return -1;
strcpy(nameBuf, rangeName);
buffer = malloc(2 * sizeof(uint32_t));
if (buffer == 0) return -1;
buffer[0] = start;
buffer[1] = length;
DT__AddProperty(gMemoryMapNode, nameBuf, 2 * sizeof(uint32_t), (char *)buffer);
return 0;
}
long
AllocateKernelMemory( long inSize )
{
long addr;
if (gImageLastKernelAddr == 0) {
gImageLastKernelAddr = RoundPage( bootArgs->kaddr +
bootArgs->ksize );
}
addr = gImageLastKernelAddr;
gImageLastKernelAddr += RoundPage(inSize);
if ( gImageLastKernelAddr >= (KERNEL_ADDR + KERNEL_LEN) ) {
stop ("AllocateKernelMemory error");
}
bootArgs->ksize = gImageLastKernelAddr - bootArgs->kaddr;
return addr;
}
#define RoundPage(x) ((((unsigned)(x)) + kPageSize - 1) & ~(kPageSize - 1))
branches/rewrite/i386/libsaio/Makefile
2929
3030
3131
32
33
32
33
3434
3535
3636
37
38
39
40
41
37
38
39
40
41
4242
43
43
4444
4545
4646
INC = -I. -I$(SYMROOT) -I$(LIBSADIR) -I$(BOOT2DIR) -I${SRCROOT}/i386/include
SAIO_OBJS = table.o asm.o bios.o biosfn.o \
disk.o sys.o cache.o bootstruct.o \
stringTable.o load.o pci.o allocate.o misc.o \
disk.o sys.o cache.o \
stringTable.o allocate.o misc.o \
ufs.o ufs_byteorder.o \
vbe.o nbp.o hfs.o hfs_compare.o \
xml.o ntfs.o msdos.o md5c.o device_tree.o \
cpu.o platform.o acpi_patcher.o \
smbios.o smbios_getters.o smbios_decode.o \
fake_efi.o ext2fs.o \
hpet.o dram_controllers.o spd.o usb.o pci_setup.o \
device_inject.o nvidia.o ati.o pci_root.o \
cpu.o platform.o pci.o \
\
ext2fs.o \
hpet.o dram_controllers.o spd.o \
load.o\
convert.o aml_generator.o console.o
#OLD: acpi_patcher.o fake_efi.o smbios.o smbios_getters.o smbios_decode.o pci_setup.o pci_root.o device_inject.o bootstruct.o nvidia.o ati.o usb.o
LIBS = libsaio.a
LIBS := $(addprefix $(SYMROOT)/, $(LIBS))
branches/rewrite/i386/libsaio/sys.c
6363
6464
6565
66
6766
6867
6968
......
816815
817816
818817
819
818
820819
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837820
838821
839822
......
10251008
10261009
10271010
1028
1029
10301011
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
10431012
10441013
10451014
#include "boot.h"
#include "bootstruct.h"
#include "disk.h"
#include "ramdisk.h"
#include "xml.h"
#include <libkern/crypto/md5.h>
for ( bvr = chain; bvr; bvr = bvr->next )
if ( bvr->part_no == multiboot_partition && bvr->biosdev == gBIOSDev )
return bvr;
/*
* Checking "Default Partition" key in system configuration - use format: hd(x,y), the volume UUID or label -
* to override the default selection.
* We accept only kBVFlagSystemVolume or kBVFlagForeignBoot volumes.
*/
char *val = XMLDecode(getStringForKey(kDefaultPartition, &bootInfo->bootConfig));
if (val) {
for ( bvr = chain; bvr; bvr = bvr->next ) {
if (matchVolumeToString(bvr, val, false)) {
free(val);
return bvr;
}
}
free(val);
}
/*
* Scannig the volume chain backwards and trying to find
* a HFS+ volume with valid boot record signature.
* If not found any active partition then we will
bvr = bvr1 = NULL;
// Try resolving "rd" and "bt" devices first.
if (biosdev == kPseudoBIOSDevRAMDisk)
{
if (gRAMDiskVolume)
bvr1 = gRAMDiskVolume;
}
else if (biosdev == kPseudoBIOSDevBooter)
{
if (gRAMDiskVolume != NULL && gRAMDiskBTAliased)
bvr1 = gRAMDiskVolume;
else
bvr1 = gBIOSBootVolume;
}
else
{
// Fetch the volume list from the device.
scanBootVolumes( biosdev, NULL );
branches/rewrite/i386/libsaio/load.c
324324
325325
326326
327
327
328328
329
329
330330
331331
332332
totalSize = symsSize + symTab->strsize;
gSymbolTableSize = totalSize + sizeof(struct symtab_command);
gSymbolTableAddr = AllocateKernelMemory(gSymbolTableSize);
// gSymbolTableAddr = AllocateKernelMemory(gSymbolTableSize);
// Add the SymTab to the memory-map.
AllocateMemoryRange("Kernel-__SYMTAB", gSymbolTableAddr, gSymbolTableSize, -1);
// AllocateMemoryRange("Kernel-__SYMTAB", gSymbolTableAddr, gSymbolTableSize, -1);
symTableSave = (struct symtab_command *)gSymbolTableAddr;
tmpAddr = gSymbolTableAddr + sizeof(struct symtab_command);
branches/rewrite/i386/libsaio/platform.c
3636
3737
3838
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
6139
6240
6341
......
6745
6846
6947
70
7148
}
}
/** scan mem for memory autodection purpose */
void scan_mem() {
static bool done = false;
if (done) return;
/* our code only works on Intel chipsets so make sure here */
if (pci_config_read16(PCIADDR(0, 0x00, 0), 0x00) != 0x8086)
bootInfo->memDetect = false;
else
bootInfo->memDetect = true;
/* manually */
getBoolForKey(kUseMemDetect, &bootInfo->memDetect, &bootInfo->bootConfig);
if (bootInfo->memDetect) {
if (dram_controller_dev != NULL) {
scan_dram_controller(dram_controller_dev); // Rek: pci dev ram controller direct and fully informative scan ...
}
scan_spd(&Platform);
}
done = true;
}
/**
Scan platform hardware information, called by the main entry point (common_boot() )
_before_ bootConfig xml parsing settings are loaded
memset(&Platform, 0, sizeof(Platform));
build_pci_dt();
scan_cpu(&Platform);
//scan_mem(); Rek: called after pci devs init in fake_efi now ...
}
branches/rewrite/i386/libsaio/cpu.c
9797
9898
9999
100
101
100
102101
103102
104103
......
266265
267266
268267
269
270
271
272
273268
274
275
276
277
278
279
280
281
282
283
284
285269
286270
287271
uint64_ttscFrequency, fsbFrequency, cpuFrequency;
uint64_tmsr, flex_ratio;
uint8_tmaxcoef, maxdiv, currcoef, bus_ratio_max, currdiv;
const char *newratio;
int len, myfsb;
int myfsb;
uint8_t bus_ratio_min;
uint32_t max_ratio, min_ratio;
} else {
cpuFrequency = tscFrequency;
}
if ((getValueForKey(kbusratio, &newratio, &len, &bootInfo->bootConfig)) && (len <= 4)) {
max_ratio = atoi(newratio);
max_ratio = (max_ratio * 10);
if (len >= 3) max_ratio = (max_ratio + 5);
verbose("Bus-Ratio: min=%d, max=%s\n", bus_ratio_min, newratio);
// extreme overclockers may love 320 ;)
if ((max_ratio >= min_ratio) && (max_ratio <= 320)) {
cpuFrequency = (fsbFrequency * max_ratio) / 10;
if (len >= 3) maxdiv = 1;
else maxdiv = 0;
} else {
max_ratio = (bus_ratio_max * 10);
}
}
//valv: to be uncommented if Remarq.1 didn't stick
/*if(bus_ratio_max > 0) bus_ratio = flex_ratio;*/
p->CPU.MaxRatio = max_ratio;
branches/rewrite/i386/libsaio/disk.c
129129
130130
131131
132
133
134132
135133
136134
......
335333
336334
337335
338
339
340336
341337
342338
......
15631559
15641560
15651561
1566
1567
1568
1569
15701562
1571
1572
1573
1574
1575
1576
15771563
15781564
15791565
......
16061592
16071593
16081594
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
16271595
16281596
16291597
......
16511619
16521620
16531621
1654
16551622
16561623
16571624
......
17351702
17361703
17371704
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
17901705
17911706
17921707
......
18091724
18101725
18111726
1812
1813
1814
1815
1816
1817
18181727
18191728
18201729
......
19551864
19561865
19571866
1958
19591867
19601868
19611869
......
19911899
19921900
19931901
1994
19951902
19961903
19971904
int (*p_get_ramdisk_info)(int biosdev, struct driveInfo *dip) = NULL;
extern void spinActivityIndicator(int sectors);
//==========================================================================
static int getDriveInfo( int biosdev, struct driveInfo *dip )
biosbuf = trackbuf + (secno % divisor) * BPS;
xbiosdev = biosdev;
spinActivityIndicator(xnsecs);
return rc;
}
struct DiskBVMap * map = NULL;
int bvCount = 0;
const char *raw = 0;
char* val = 0;
int len;
getValueForKey(kHidePartition, &raw, &len, &bootInfo->bootConfig);
if(raw)
{
val = XMLDecode(raw);
}
/*
* Traverse gDISKBVmap to get references for
* individual bvr chains of each drive.
newBVR->visible = true;
/*
* Looking for "Hide Partition" entries in 'hd(x,y)|uuid|"label" hd(m,n)|uuid|"label"' format,
* to be able to hide foreign partitions from the boot menu.
*
*/
if ( (newBVR->flags & kBVFlagForeignBoot) )
{
char *start, *next = val;
long len = 0;
do
{
start = strbreak(next, &next, &len);
if(len && matchVolumeToString(newBVR, start, len) )
newBVR->visible = false;
}
while ( next && *next );
}
/*
* Use the first bvr entry as the starting chain pointer.
*/
if (!chain)
*count = bvCount;
free(val);
return chain;
}
return false;
}
/* If Rename Partition has defined an alias, then extract it for description purpose.
* The format for the rename string is the following:
* hd(x,y)|uuid|"label" "alias";hd(m,n)|uuid|"label" "alias"; etc...
*/
bool getVolumeLabelAlias(BVRef bvr, char* str, long strMaxLen)
{
char *aliasList, *entryStart, *entryNext;
if ( !str || strMaxLen <= 0)
return false;
aliasList = XMLDecode(getStringForKey(kRenamePartition, &bootInfo->bootConfig));
if ( !aliasList )
return false;
for ( entryStart = entryNext = aliasList;
entryNext && *entryNext;
entryStart = entryNext )
{
char *volStart, *volEnd, *aliasStart;
long volLen, aliasLen;
// Delimit current entry
entryNext = strchr(entryStart, ';');
if ( entryNext )
{
*entryNext = '\0';
entryNext++;
}
volStart = strbreak(entryStart, &volEnd, &volLen);
if(!volLen)
continue;
aliasStart = strbreak(volEnd, 0, &aliasLen);
if(!aliasLen)
continue;
if ( matchVolumeToString(bvr, volStart, volLen) )
{
strncat(str, aliasStart, MIN(strMaxLen, aliasLen));
free(aliasList);
return true;
}
}
free(aliasList);
return false;
}
void getBootVolumeDescription( BVRef bvr, char * str, long strMaxLen, bool useDeviceDescription )
{
unsigned char type;
p += len;
}
/* See if a partition rename is preferred */
if(getVolumeLabelAlias(bvr, p, strMaxLen)) {
strncpy(bvr->label, p, strMaxLen);
return; // we're done here no need to seek for real name
}
//
// Get the volume label using filesystem specific functions
// or use the alternate volume label if available.
len -= copy_len;
cbuf += copy_len;
secno += secs;
spinActivityIndicator(secs);
}
return 0;
len -= copy_len;
cbuf += copy_len;
secno += secs;
spinActivityIndicator(secs);
}
return 0;
branches/rewrite/i386/libsaio/pci.c
152152
153153
154154
155
155
156156
157157
158158
dev_path[0] = 0;
end = root_pci_dev;
int uid = getPciRootUID();
int uid = 0; //getPciRootUID();
while (end != pci_dt)
{
current = pci_dt;
branches/rewrite/i386/libsaio/stringTable.c
481481
482482
483483
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
484
519485
520486
521487
bool getValueForKey( const char *key, const char **val, int *size, config_file_t *config )
{
const char *overrideVal;
int overrideSize;
bool override, ret;
if (getValueForBootKey(bootArgs->CommandLine, key, val, size))
return true;
ret = getValueForConfigTableKey(config, key, val, size);
// Try to find alternate keys in bootInfo->overrideConfig
// and prefer its values with the exceptions for
// "Kernel"="mach_kernel" and "Kernel Flags"="".
if (config->canOverride)
{
if (getValueForConfigTableKey(&bootInfo->overrideConfig, key, &overrideVal, &overrideSize))
{
override = true;
if (ret && (strcmp(key, "Kernel") == 0) && (strcmp(overrideVal, "mach_kernel") == 0))
override = false;
if (ret && (strcmp(key, "Kernel Flags") == 0) && (overrideSize == 0))
override = false;
if (override)
{
*val = overrideVal;
*size = overrideSize;
return true;
}
}
}
return ret;
return getValueForConfigTableKey(config, key, val, size);
}
branches/rewrite/i386/boot2/ramdisk.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
/*
* Supplemental ramdisk functions for the multiboot ramdisk driver
* Copyright 2009 Tamas Kosarszky. All rights reserved.
*
*/
#ifndef __BOOT_RAMDISK_H
#define __BOOT_RAMDISK_H
#define RAMDISKCONFIG_FILENAME "rd(0,0)/RAMDisk.plist"
//#define kPostbootRamdisk
void md0Ramdisk();
typedef struct RAMDiskParam
{
ppnum_t base;
unsigned int size;
} RAMDiskParam;
/* mboot.c */
extern struct multiboot_info *gMI;
extern int multibootRamdiskReadBytes( int biosdev, unsigned int blkno,
unsigned int byteoff,
unsigned int byteCount, void * buffer );
extern int multiboot_get_ramdisk_info(int biosdev, struct driveInfo *dip);
//
extern BVRef gRAMDiskVolume;
extern bool gRAMDiskBTAliased;
extern void setRAMDiskBTHook(bool mode);
extern int mountRAMDisk(const char * param);
extern void processRAMDiskCommand(char ** argPtr, const char * cmd);
extern int loadPrebootRAMDisk();
#endif /* !__BOOT_RAMDISK_H */
branches/rewrite/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
1151
// 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 <sys/types.h>
#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;
} else if (fwrite(info->image->data, 1, outsize, outfp) != outsize) {
perror("fwrite");
return 1;
}
fclose(outfp);
#ifdef ALLOC_DEBUG
png_alloc_node_t *node;
for (node = png_alloc_head, n = 1; node; node = node->next, n++)
printf("node %d (%p) addr = %p, size = %ld\n", n, node, node->addr, node->size);
#endif
png_alloc_free_all(); // also frees info and image data from PNG_decode
return 0;
}
#endif
branches/rewrite/i386/boot2/graphic_utils.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
/* Graphic utility functions and data types
* Prashant Vaibhav (C) 12/12/2008
* Chameleon
*/
// Everything here is 32 bits per pixel non-premultiplied ARGB format
//
#ifndef GRAPHIC_UTILS_H
#define GRAPHIC_UTILS_H
#include "boot.h"
typedef union {
struct {
uint8_t b;
uint8_t g;
uint8_t r;
uint8_t a;
} ch;
uint8_t channel[4];
uint32_t value;
} pixel_t;
typedef struct {
uint16_theight;
uint16_twidth;
pixel_t*pixels;
} pixmap_t;
typedef struct {
uint32_t x;
uint32_t y;
} position_t;
// Blends the given pixmap into the given background at the given position
// Uses the alpha channels to blend, and preserves the final alpha (so the
// resultant pixmap can be blended again with another background).
// ported from www.stereopsis.com/doubleblend.html
void blend( const pixmap_t *blendThis, // Source image
pixmap_t *blendInto, // Dest image
const position_t position); // Where to place the source image
// Returns the topleft co-ordinate where if you put the 'toCenter' pixmap,
// it is centered in the background.
position_t centeredIn( const pixmap_t *background, const pixmap_t *toCenter );
// Returns the topleft co-ordinate where if you put the given pixmap, its
// center will coincide with the th given center.
position_t centeredAt( const pixmap_t *pixmap, const position_t center );
// Utility function returns a position_t struct given the x and y coords as uint16
position_t pos(const uint16_t x, const uint16_t y);
// Flips the R and B components of all pixels in the given pixmap
void flipRB(pixmap_t *p);
// Utility function to get pixel at (x,y) in a pixmap
#define pixel(p,x,y) ((p)->pixels[(x) + (y) * (p)->width])
#endif//GRAPHIC_UTILS_H
branches/rewrite/i386/boot2/picopng.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
#ifndef _PICOPNG_H
#define _PICOPNG_H
#include <stdint.h>
typedef struct {
uint32_t *data;
size_t size;
size_t allocsize;
} vector32_t;
typedef struct {
uint8_t *data;
size_t size;
size_t allocsize;
} vector8_t;
typedef struct {
uint32_t width, height;
uint32_t colorType, bitDepth;
uint32_t compressionMethod, filterMethod, interlaceMethod;
uint32_t key_r, key_g, key_b;
bool key_defined; // is a transparent color key given?
vector8_t *palette;
vector8_t *image;
} PNG_info_t;
PNG_info_t *PNG_decode(const uint8_t *in, uint32_t size);
void png_alloc_free_all();
extern int PNG_error;
#endif
branches/rewrite/i386/boot2/graphics.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
/*
* graphics.h
*
*
* Created by fassl on 22.12.08.
* Copyright 2008 __MyCompanyName__. All rights reserved.
*
*/
#include "boot.h"
#include "bootstruct.h"
#include "graphic_utils.h"
#ifndef __BOOT_GRAPHICS_H
#define __BOOT_GRAPHICS_H
#define DEFAULT_SCREEN_WIDTH 1024
#define DEFAULT_SCREEN_HEIGHT 768
int loadPngImage(const char *filename, uint16_t *width, uint16_t *height, uint8_t **imageData);
unsigned long lookUpCLUTIndex( unsigned char index, unsigned char depth );
void drawColorRectangle( unsigned short x, unsigned short y, unsigned short width, unsigned short height, unsigned char colorIndex );
void drawDataRectangle( unsigned short x, unsigned short y, unsigned short width, unsigned short height, unsigned char * data );
int convertImage( unsigned short width, unsigned short height, const unsigned char *imageData, unsigned char **newImageData );
int initGraphicsMode ();
void drawCheckerBoard();
void blendImage(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t *data);
void drawCheckerBoard();
void blendImage(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t *data);
int loadEmbeddedPngImage(uint8_t *pngData, int pngSize, uint16_t *width, uint16_t *height, uint8_t **imageData);
char *getVBEInfoString();
char *getVBEModeInfoString();
void getGraphicModeParams(unsigned long params[]);
#endif /* !__BOOT_GRAPHICS_H */
branches/rewrite/i386/boot2/drivers.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
/*
* Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
* Reserved. This file contains Original Code and/or Modifications of
* Original Code as defined in and that are subject to the Apple Public
* Source License Version 2.0 (the 'License'). You may not use this file
* except in compliance with the License. Please obtain a copy of the
* License at http://www.apple.com/publicsource and read it before using
* this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* drivers.c - Driver Loading Functions.
*
* Copyright (c) 2000 Apple Computer, Inc.
*
* DRI: Josh de Cesare
*/
#include <mach-o/fat.h>
#include <libkern/OSByteOrder.h>
#include <mach/machine.h>
#include "sl.h"
#include "boot.h"
#include "bootstruct.h"
#include "xml.h"
#include "ramdisk.h"
#include "modules.h"
//extern char gMacOSVersion[8];
struct Module {
struct Module *nextModule;
long willLoad;
TagPtr dict;
char *plistAddr;
long plistLength;
char *executablePath;
char *bundlePath;
long bundlePathLength;
};
typedef struct Module Module, *ModulePtr;
struct DriverInfo {
char *plistAddr;
long plistLength;
void *executableAddr;
long executableLength;
void *bundlePathAddr;
long bundlePathLength;
};
typedef struct DriverInfo DriverInfo, *DriverInfoPtr;
#define kDriverPackageSignature1 'MKXT'
#define kDriverPackageSignature2 'MOSX'
struct DriversPackage {
unsigned long signature1;
unsigned long signature2;
unsigned long length;
unsigned long adler32;
unsigned long version;
unsigned long numDrivers;
unsigned long reserved1;
unsigned long reserved2;
};
typedef struct DriversPackage DriversPackage;
enum {
kCFBundleType2,
kCFBundleType3
};
long (*LoadExtraDrivers_p)(FileLoadDrivers_t FileLoadDrivers_p);
/*static*/ unsigned long Adler32( unsigned char * buffer, long length );
static long FileLoadDrivers(char *dirSpec, long plugin);
static long NetLoadDrivers(char *dirSpec);
static long LoadDriverMKext(char *fileSpec);
static long LoadDriverPList(char *dirSpec, char *name, long bundleType);
static long LoadMatchedModules(void);
static long MatchPersonalities(void);
static long MatchLibraries(void);
#ifdef NOTDEF
static ModulePtr FindModule(char *name);
static void ThinFatFile(void **loadAddrP, unsigned long *lengthP);
#endif
static long ParseXML(char *buffer, ModulePtr *module, TagPtr *personalities);
static long InitDriverSupport(void);
static ModulePtr gModuleHead, gModuleTail;
static TagPtr gPersonalityHead, gPersonalityTail;
static char * gExtensionsSpec;
static char * gDriverSpec;
static char * gFileSpec;
static char * gTempSpec;
static char * gFileName;
/*static*/ unsigned long
Adler32( unsigned char * buffer, long length )
{
long cnt;
unsigned long result, lowHalf, highHalf;
lowHalf = 1;
highHalf = 0;
for ( cnt = 0; cnt < length; cnt++ )
{
if ((cnt % 5000) == 0)
{
lowHalf %= 65521L;
highHalf %= 65521L;
}
lowHalf += buffer[cnt];
highHalf += lowHalf;
}
lowHalf %= 65521L;
highHalf %= 65521L;
result = (highHalf << 16) | lowHalf;
return result;
}
//==========================================================================
// InitDriverSupport
static long
InitDriverSupport( void )
{
gExtensionsSpec = malloc( 4096 );
gDriverSpec = malloc( 4096 );
gFileSpec = malloc( 4096 );
gTempSpec = malloc( 4096 );
gFileName = malloc( 4096 );
if ( !gExtensionsSpec || !gDriverSpec || !gFileSpec || !gTempSpec || !gFileName )
stop("InitDriverSupport error");
return 0;
}
//==========================================================================
// LoadDrivers
long LoadDrivers( char * dirSpec )
{
char dirSpecExtra[1024];
if ( InitDriverSupport() != 0 )
return 0;
// Load extra drivers if a hook has been installed.
if (LoadExtraDrivers_p != NULL)
{
(*LoadExtraDrivers_p)(&FileLoadDrivers);
}
if ( gBootFileType == kNetworkDeviceType )
{
if (NetLoadDrivers(dirSpec) != 0) {
error("Could not load drivers from the network\n");
return -1;
}
}
else if ( gBootFileType == kBlockDeviceType )
{
// First try to load Extra extensions from the ramdisk if isn't aliased as bt(0,0).
if (gRAMDiskVolume && !gRAMDiskBTAliased)
{
strcpy(dirSpecExtra, "rd(0,0)/Extra/");
FileLoadDrivers(dirSpecExtra, 0);
}
// Next try to load Extra extensions from the selected root partition.
strcpy(dirSpecExtra, "/Extra/");
if (FileLoadDrivers(dirSpecExtra, 0) != 0)
{
// If failed, then try to load Extra extensions from the boot partition
// in case we have a separate booter partition or a bt(0,0) aliased ramdisk.
if ( !(gBIOSBootVolume->biosdev == gBootVolume->biosdev && gBIOSBootVolume->part_no == gBootVolume->part_no)
|| (gRAMDiskVolume && gRAMDiskBTAliased) )
{
// Next try a specfic OS version folder ie 10.5
sprintf(dirSpecExtra, "bt(0,0)/Extra/%s/", &gMacOSVersion);
if (FileLoadDrivers(dirSpecExtra, 0) != 0)
{
// Next we'll try the base
strcpy(dirSpecExtra, "bt(0,0)/Extra/");
FileLoadDrivers(dirSpecExtra, 0);
}
}
}
// Also try to load Extensions from boot helper partitions.
if (gBootVolume->flags & kBVFlagBooter)
{
strcpy(dirSpecExtra, "/com.apple.boot.P/System/Library/");
if (FileLoadDrivers(dirSpecExtra, 0) != 0)
{
strcpy(dirSpecExtra, "/com.apple.boot.R/System/Library/");
if (FileLoadDrivers(dirSpecExtra, 0) != 0)
{
strcpy(dirSpecExtra, "/com.apple.boot.S/System/Library/");
FileLoadDrivers(dirSpecExtra, 0);
}
}
}
if (gMKextName[0] != '\0')
{
verbose("LoadDrivers: Loading from [%s]\n", gMKextName);
if ( LoadDriverMKext(gMKextName) != 0 )
{
error("Could not load %s\n", gMKextName);
return -1;
}
}
else
{
strcpy(gExtensionsSpec, dirSpec);
strcat(gExtensionsSpec, "System/Library/");
FileLoadDrivers(gExtensionsSpec, 0);
}
}
else
{
return 0;
}
MatchPersonalities();
MatchLibraries();
LoadMatchedModules();
return 0;
}
//==========================================================================
// FileLoadMKext
static long
FileLoadMKext( const char * dirSpec, const char * extDirSpec )
{
longret, flags, time, time2;
charaltDirSpec[512];
sprintf (altDirSpec, "%s%s", dirSpec, extDirSpec);
ret = GetFileInfo(altDirSpec, "Extensions.mkext", &flags, &time);
if ((ret == 0) && ((flags & kFileTypeMask) == kFileTypeFlat))
{
ret = GetFileInfo(dirSpec, "Extensions", &flags, &time2);
if ((ret != 0)
|| ((flags & kFileTypeMask) != kFileTypeDirectory)
|| (((gBootMode & kBootModeSafe) == 0) && (time == (time2 + 1))))
{
sprintf(gDriverSpec, "%sExtensions.mkext", altDirSpec);
if (LoadDriverMKext(gDriverSpec) == 0)
return 0;
}
}
return -1;
}
//==========================================================================
// FileLoadDrivers
static long
FileLoadDrivers( char * dirSpec, long plugin )
{
long ret, length, flags, time, bundleType;
long long index;
long result = -1;
const char * name;
if ( !plugin )
{
// First try 10.6's path for loading Extensions.mkext.
if (FileLoadMKext(dirSpec, "Caches/com.apple.kext.caches/Startup/") == 0)
return 0;
// Next try the legacy path.
else if (FileLoadMKext(dirSpec, "") == 0)
return 0;
strcat(dirSpec, "Extensions");
}
index = 0;
while (1) {
ret = GetDirEntry(dirSpec, &index, &name, &flags, &time);
if (ret == -1) break;
// Make sure this is a directory.
if ((flags & kFileTypeMask) != kFileTypeDirectory) continue;
// Make sure this is a kext.
length = strlen(name);
if (strcmp(name + length - 5, ".kext")) continue;
// Save the file name.
strcpy(gFileName, name);
// Determine the bundle type.
sprintf(gTempSpec, "%s/%s", dirSpec, gFileName);
ret = GetFileInfo(gTempSpec, "Contents", &flags, &time);
if (ret == 0) bundleType = kCFBundleType2;
else bundleType = kCFBundleType3;
if (!plugin)
sprintf(gDriverSpec, "%s/%s/%sPlugIns", dirSpec, gFileName,
(bundleType == kCFBundleType2) ? "Contents/" : "");
ret = LoadDriverPList(dirSpec, gFileName, bundleType);
if (result != 0)
result = ret;
if (!plugin)
FileLoadDrivers(gDriverSpec, 1);
}
return result;
}
//==========================================================================
//
static long
NetLoadDrivers( char * dirSpec )
{
long tries;
#if NODEF
long cnt;
// Get the name of the kernel
cnt = strlen(gBootFile);
while (cnt--) {
if ((gBootFile[cnt] == '\\') || (gBootFile[cnt] == ',')) {
cnt++;
break;
}
}
#endif
// INTEL modification
sprintf(gDriverSpec, "%s%s.mkext", dirSpec, bootInfo->bootFile);
verbose("NetLoadDrivers: Loading from [%s]\n", gDriverSpec);
tries = 3;
while (tries--)
{
if (LoadDriverMKext(gDriverSpec) == 0) break;
}
if (tries == -1) return -1;
return 0;
}
//==========================================================================
// loadDriverMKext
static long
LoadDriverMKext( char * fileSpec )
{
unsigned long driversAddr, driversLength;
long length;
char segName[32];
DriversPackage * package;
#define GetPackageElement(e) OSSwapBigToHostInt32(package->e)
// Load the MKext.
length = LoadThinFatFile(fileSpec, (void **)&package);
if (length < sizeof (DriversPackage)) return -1;
// call hook to notify modules that the mkext has been loaded
execute_hook("LoadDriverMKext", (void*)fileSpec, (void*)package, (void*) &length, NULL);
// Verify the MKext.
if (( GetPackageElement(signature1) != kDriverPackageSignature1) ||
( GetPackageElement(signature2) != kDriverPackageSignature2) ||
( GetPackageElement(length) > kLoadSize ) ||
( GetPackageElement(adler32) !=
Adler32((unsigned char *)&package->version, GetPackageElement(length) - 0x10) ) )
{
return -1;
}
// Make space for the MKext.
driversLength = GetPackageElement(length);
driversAddr = AllocateKernelMemory(driversLength);
// Copy the MKext.
memcpy((void *)driversAddr, (void *)package, driversLength);
// Add the MKext to the memory map.
sprintf(segName, "DriversPackage-%lx", driversAddr);
AllocateMemoryRange(segName, driversAddr, driversLength,
kBootDriverTypeMKEXT);
return 0;
}
//==========================================================================
// LoadDriverPList
static long
LoadDriverPList( char * dirSpec, char * name, long bundleType )
{
long length, executablePathLength, bundlePathLength;
ModulePtr module;
TagPtr personalities;
char * buffer = 0;
char * tmpExecutablePath = 0;
char * tmpBundlePath = 0;
long ret = -1;
do {
// Save the driver path.
sprintf(gFileSpec, "%s/%s/%s", dirSpec, name,
(bundleType == kCFBundleType2) ? "Contents/MacOS/" : "");
executablePathLength = strlen(gFileSpec) + 1;
tmpExecutablePath = malloc(executablePathLength);
if (tmpExecutablePath == 0) break;
strcpy(tmpExecutablePath, gFileSpec);
sprintf(gFileSpec, "%s/%s", dirSpec, name);
bundlePathLength = strlen(gFileSpec) + 1;
tmpBundlePath = malloc(bundlePathLength);
if (tmpBundlePath == 0) break;
strcpy(tmpBundlePath, gFileSpec);
// Construct the file spec to the plist, then load it.
sprintf(gFileSpec, "%s/%s/%sInfo.plist", dirSpec, name,
(bundleType == kCFBundleType2) ? "Contents/" : "");
length = LoadFile(gFileSpec);
if (length == -1) break;
length = length + 1;
buffer = malloc(length);
if (buffer == 0) break;
strlcpy(buffer, (char *)kLoadAddr, length);
// Parse the plist.
ret = ParseXML(buffer, &module, &personalities);
if (ret != 0) { break; }
// Allocate memory for the driver path and the plist.
module->executablePath = tmpExecutablePath;
module->bundlePath = tmpBundlePath;
module->bundlePathLength = bundlePathLength;
module->plistAddr = malloc(length);
if ((module->executablePath == 0) || (module->bundlePath == 0) || (module->plistAddr == 0))
break;
// Save the driver path in the module.
//strcpy(module->driverPath, tmpDriverPath);
tmpExecutablePath = 0;
tmpBundlePath = 0;
// Add the plist to the module.
strlcpy(module->plistAddr, (char *)kLoadAddr, length);
module->plistLength = length;
// Add the module to the end of the module list.
if (gModuleHead == 0)
gModuleHead = module;
else
gModuleTail->nextModule = module;
gModuleTail = module;
// Add the persionalities to the personality list.
if (personalities) personalities = personalities->tag;
while (personalities != 0)
{
if (gPersonalityHead == 0)
gPersonalityHead = personalities->tag;
else
gPersonalityTail->tagNext = personalities->tag;
gPersonalityTail = personalities->tag;
personalities = personalities->tagNext;
}
ret = 0;
}
while (0);
if ( buffer ) free( buffer );
if ( tmpExecutablePath ) free( tmpExecutablePath );
if ( tmpBundlePath ) free( tmpBundlePath );
return ret;
}
//==========================================================================
// LoadMatchedModules
static long
LoadMatchedModules( void )
{
TagPtr prop;
ModulePtr module;
char *fileName, segName[32];
DriverInfoPtr driver;
long length, driverAddr, driverLength;
void *executableAddr = 0;
module = gModuleHead;
while (module != 0)
{
if (module->willLoad)
{
prop = XMLGetProperty(module->dict, kPropCFBundleExecutable);
if (prop != 0)
{
fileName = prop->string;
sprintf(gFileSpec, "%s%s", module->executablePath, fileName);
length = LoadThinFatFile(gFileSpec, &executableAddr);
if (length == 0)
{
length = LoadFile(gFileSpec);
executableAddr = (void *)kLoadAddr;
}
//printf("%s length = %d addr = 0x%x\n", gFileSpec, length, driverModuleAddr); getchar();
}
else
length = 0;
if (length != -1)
{
//driverModuleAddr = (void *)kLoadAddr;
//if (length != 0)
//{
//ThinFatFile(&driverModuleAddr, &length);
//}
// Make make in the image area.
driverLength = sizeof(DriverInfo) + module->plistLength + length + module->bundlePathLength;
driverAddr = AllocateKernelMemory(driverLength);
// Set up the DriverInfo.
driver = (DriverInfoPtr)driverAddr;
driver->plistAddr = (char *)(driverAddr + sizeof(DriverInfo));
driver->plistLength = module->plistLength;
if (length != 0)
{
driver->executableAddr = (void *)(driverAddr + sizeof(DriverInfo) +
module->plistLength);
driver->executableLength = length;
}
else
{
driver->executableAddr = 0;
driver->executableLength = 0;
}
driver->bundlePathAddr = (void *)(driverAddr + sizeof(DriverInfo) +
module->plistLength + driver->executableLength);
driver->bundlePathLength = module->bundlePathLength;
// Save the plist, module and bundle.
strcpy(driver->plistAddr, module->plistAddr);
if (length != 0)
{
memcpy(driver->executableAddr, executableAddr, length);
}
strcpy(driver->bundlePathAddr, module->bundlePath);
// Add an entry to the memory map.
sprintf(segName, "Driver-%lx", (unsigned long)driver);
AllocateMemoryRange(segName, driverAddr, driverLength,
kBootDriverTypeKEXT);
}
}
module = module->nextModule;
}
return 0;
}
//==========================================================================
// MatchPersonalities
static long
MatchPersonalities( void )
{
/* IONameMatch support not implemented */
return 0;
}
//==========================================================================
// MatchLibraries
static long
MatchLibraries( void )
{
TagPtr prop, prop2;
ModulePtr module, module2;
long done;
do {
done = 1;
module = gModuleHead;
while (module != 0)
{
if (module->willLoad == 1)
{
prop = XMLGetProperty(module->dict, kPropOSBundleLibraries);
if (prop != 0)
{
prop = prop->tag;
while (prop != 0)
{
module2 = gModuleHead;
while (module2 != 0)
{
prop2 = XMLGetProperty(module2->dict, kPropCFBundleIdentifier);
if ((prop2 != 0) && (!strcmp(prop->string, prop2->string)))
{
if (module2->willLoad == 0) module2->willLoad = 1;
break;
}
module2 = module2->nextModule;
}
prop = prop->tagNext;
}
}
module->willLoad = 2;
done = 0;
}
module = module->nextModule;
}
}
while (!done);
return 0;
}
//==========================================================================
// FindModule
#if NOTDEF
static ModulePtr
FindModule( char * name )
{
ModulePtr module;
TagPtr prop;
module = gModuleHead;
while (module != 0)
{
prop = GetProperty(module->dict, kPropCFBundleIdentifier);
if ((prop != 0) && !strcmp(name, prop->string)) break;
module = module->nextModule;
}
return module;
}
#endif /* NOTDEF */
//==========================================================================
// ParseXML
static long
ParseXML( char * buffer, ModulePtr * module, TagPtr * personalities )
{
long length, pos;
TagPtr moduleDict, required;
ModulePtr tmpModule;
pos = 0;
while (1)
{
length = XMLParseNextTag(buffer + pos, &moduleDict);
if (length == -1) break;
pos += length;
if (moduleDict == 0) continue;
if (moduleDict->type == kTagTypeDict) break;
XMLFreeTag(moduleDict);
}
if (length == -1) return -1;
required = XMLGetProperty(moduleDict, kPropOSBundleRequired);
if ( (required == 0) ||
(required->type != kTagTypeString) ||
!strcmp(required->string, "Safe Boot"))
{
XMLFreeTag(moduleDict);
return -2;
}
tmpModule = malloc(sizeof(Module));
if (tmpModule == 0)
{
XMLFreeTag(moduleDict);
return -1;
}
tmpModule->dict = moduleDict;
// For now, load any module that has OSBundleRequired != "Safe Boot".
tmpModule->willLoad = 1;
*module = tmpModule;
// Get the personalities.
*personalities = XMLGetProperty(moduleDict, kPropIOKitPersonalities);
return 0;
}
#if NOTDEF
static char gPlatformName[64];
#endif
long
DecodeKernel(void *binary, entry_t *rentry, char **raddr, int *rsize)
{
long ret;
compressed_kernel_header * kernel_header = (compressed_kernel_header *) binary;
u_int32_t uncompressed_size, size;
void *buffer;
unsigned long len;
#if 0
printf("kernel header:\n");
printf("signature: 0x%x\n", kernel_header->signature);
printf("compress_type: 0x%x\n", kernel_header->compress_type);
printf("adler32: 0x%x\n", kernel_header->adler32);
printf("uncompressed_size: 0x%x\n", kernel_header->uncompressed_size);
printf("compressed_size: 0x%x\n", kernel_header->compressed_size);
getchar();
#endif
if (kernel_header->signature == OSSwapBigToHostConstInt32('comp'))
{
if (kernel_header->compress_type != OSSwapBigToHostConstInt32('lzss'))
{
error("kernel compression is bad\n");
return -1;
}
#if NOTDEF
if (kernel_header->platform_name[0] && strcmp(gPlatformName, kernel_header->platform_name))
return -1;
if (kernel_header->root_path[0] && strcmp(gBootFile, kernel_header->root_path))
return -1;
#endif
uncompressed_size = OSSwapBigToHostInt32(kernel_header->uncompressed_size);
binary = buffer = malloc(uncompressed_size);
size = decompress_lzss((u_int8_t *) binary, &kernel_header->data[0],
OSSwapBigToHostInt32(kernel_header->compressed_size));
if (uncompressed_size != size) {
error("size mismatch from lzss: %x\n", size);
return -1;
}
if (OSSwapBigToHostInt32(kernel_header->adler32) !=
Adler32(binary, uncompressed_size))
{
printf("adler mismatch\n");
return -1;
}
}
// Notify modules that the kernel has been decompressed, is about to be decoded
execute_hook("DecodeKernel", (void*)binary, NULL, NULL, NULL);
ret = ThinFatFile(&binary, &len);
if (ret == 0 && len == 0 && archCpuType==CPU_TYPE_X86_64)
{
archCpuType=CPU_TYPE_I386;
ret = ThinFatFile(&binary, &len);
}
ret = DecodeMachO(binary, rentry, raddr, rsize);
if (ret<0 && archCpuType==CPU_TYPE_X86_64)
{
archCpuType=CPU_TYPE_I386;
ret = DecodeMachO(binary, rentry, raddr, rsize);
}
return ret;
}
branches/rewrite/i386/boot2/prompt.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
/*
* Copyright (c) 1999-2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
* Reserved. This file contains Original Code and/or Modifications of
* Original Code as defined in and that are subject to the Apple Public
* Source License Version 2.0 (the "License"). You may not use this file
* except in compliance with the License. Please obtain a copy of the
* License at http://www.apple.com/publicsource and read it before using
* this file.
*
* The Original Code and all software distributed under the License are
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* Copyright 1993 NeXT, Inc.
* All rights reserved.
*/
#include <vers.h>
char bootBanner[] = "\nDarwin/x86 boot v" I386BOOT_VERSION " - Chameleon v" I386BOOT_CHAMELEONVERSION " r" I386BOOT_CHAMELEONREVISION "\n"
"Build date: " I386BOOT_BUILDDATE "\n"
"%dMB memory\n";
char bootPrompt[] =
"Press Enter to start up Darwin/x86 with no options, or you can:\n"
" Type -v and press Enter to start up with diagnostic messages\n"
" Type ? and press Enter to learn about advanced startup options\n\n"
"boot: ";
char bootRescanPrompt[] =
"Press Enter to start up Darwin/x86 with no options, or you can:\n"
" Press F5 after you swapped the media. The drive will be rescanned.\n"
" Type -v and press Enter to start up with diagnostic messages\n"
" Type ? and press Enter to learn about advanced startup options\n\n"
"boot: ";
branches/rewrite/i386/boot2/WKdmDecompress.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
#include <sys/cdefs.h>
#include "WKdm.h"
/* Part of __HIB section */
/***************************************************************************
* THE UNPACKING ROUTINES should GO HERE
*/
const char hashLookupTable [] = HASH_LOOKUP_TABLE_CONTENTS;
#if 0
#define GET_NEXT_TAG tags[tagsIndex++]
#define GET_NEXT_FULL_PATTERN fullPatterns[fullPatternsIndex++]
#define GET_NEXT_LOW_BITS lowBits[lowBitsIndex++]
#define GET_NEXT_DICTIONARY_INDEX dictionaryIndices[dictionaryIndicesIndex++]
#endif
/* WK_unpack_2bits takes any number of words containing 16 two-bit values
* and unpacks them into four times as many words containg those
* two bit values as bytes (with the low two bits of each byte holding
* the actual value.
*/
static WK_word*
WK_unpack_2bits(WK_word *input_buf,
WK_word *input_end,
WK_word *output_buf) {
register WK_word *input_next = input_buf;
register WK_word *output_next = output_buf;
register WK_word packing_mask = TWO_BITS_PACKING_MASK;
/* loop to repeatedly grab one input word and unpack it into
* 4 output words. This loop could be unrolled a little---it's
* designed to be easy to do that.
*/
while (input_next < input_end) {
register WK_word temp = input_next[0];
DEBUG_PRINT_2("Unpacked tags word: %.8x\n", temp);
output_next[0] = temp & packing_mask;
output_next[1] = (temp >> 2) & packing_mask;
output_next[2] = (temp >> 4) & packing_mask;
output_next[3] = (temp >> 6) & packing_mask;
output_next += 4;
input_next++;
}
return output_next;
}
/* unpack four bits consumes any number of words (between input_buf
* and input_end) holding 8 4-bit values per word, and unpacks them
* into twice as many words, with each value in a separate byte.
* (The four-bit values occupy the low halves of the bytes in the
* result).
*/
static WK_word*
WK_unpack_4bits(WK_word *input_buf,
WK_word *input_end,
WK_word *output_buf) {
register WK_word *input_next = input_buf;
register WK_word *output_next = output_buf;
register WK_word packing_mask = FOUR_BITS_PACKING_MASK;
/* loop to repeatedly grab one input word and unpack it into
* 4 output words. This loop should probably be unrolled
* a little---it's designed to be easy to do that.
*/
while (input_next < input_end) {
register WK_word temp = input_next[0];
DEBUG_PRINT_2("Unpacked dictionary indices word: %.8x\n", temp);
output_next[0] = temp & packing_mask;
output_next[1] = (temp >> 4) & packing_mask;
output_next += 2;
input_next++;
}
return output_next;
}
/* unpack_3_tenbits unpacks three 10-bit items from (the low 30 bits of)
* a 32-bit word
*/
static WK_word*
WK_unpack_3_tenbits(WK_word *input_buf,
WK_word *input_end,
WK_word *output_buf) {
register WK_word *input_next = input_buf;
register WK_word *output_next = output_buf;
register WK_word packing_mask = LOW_BITS_MASK;
/* loop to fetch words of input, splitting each into three
* words of output with 10 meaningful low bits. This loop
* probably ought to be unrolled and maybe coiled
*/
while (input_next < input_end) {
register WK_word temp = input_next[0];
output_next[0] = temp & packing_mask;
output_next[1] = (temp >> 10) & packing_mask;
output_next[2] = temp >> 20;
input_next++;
output_next += 3;
}
return output_next;
}
/*********************************************************************
* WKdm_decompress --- THE DECOMPRESSOR
* Expects WORD pointers to the source and destination buffers
* and a page size in words. The page size had better be 1024 unless
* somebody finds the places that are dependent on the page size and
* fixes them
*/
void
WKdm_decompress (WK_word* src_buf,
WK_word* dest_buf,
__unused unsigned int words)
{
DictionaryElement dictionary[DICTIONARY_SIZE];
/* arrays that hold output data in intermediate form during modeling */
/* and whose contents are packed into the actual output after modeling */
/* sizes of these arrays should be increased if you want to compress
* pages larger than 4KB
*/
WK_word tempTagsArray[300]; /* tags for everything */
WK_word tempQPosArray[300]; /* queue positions for matches */
WK_word tempLowBitsArray[1200]; /* low bits for partial matches */
PRELOAD_DICTIONARY;
#ifdef WK_DEBUG
printf("\nIn DECOMPRESSOR\n");
printf("tempTagsArray is at %u\n", (unsigned long int) tempTagsArray);
printf("tempQPosArray is at %u\n", (unsigned long int) tempQPosArray);
printf("tempLowBitsArray is at %u\n", (unsigned long int) tempLowBitsArray);
printf(" first four words of source buffer are:\n");
printf(" %u\n %u\n %u\n %u\n",
src_buf[0], src_buf[1], src_buf[2], src_buf[3]);
{ int i;
WK_word *arr =(src_buf + TAGS_AREA_OFFSET + (PAGE_SIZE_IN_WORDS / 16));
printf(" first 20 full patterns are: \n");
for (i = 0; i < 20; i++) {
printf(" %d", arr[i]);
}
printf("\n");
}
#endif
WK_unpack_2bits(TAGS_AREA_START(src_buf),
TAGS_AREA_END(src_buf),
tempTagsArray);
#ifdef WK_DEBUG
{ int i;
char* arr = (char *) tempTagsArray;
printf(" first 200 tags are: \n");
for (i = 0; i < 200; i++) {
printf(" %d", arr[i]);
}
printf("\n");
}
#endif
WK_unpack_4bits(QPOS_AREA_START(src_buf),
QPOS_AREA_END(src_buf),
tempQPosArray);
#ifdef WK_DEBUG
{ int i;
char* arr = (char *) tempQPosArray;
printf(" first 200 queue positions are: \n");
for (i = 0; i < 200; i++) {
printf(" %d", arr[i]);
}
printf("\n");
}
#endif
WK_unpack_3_tenbits(LOW_BITS_AREA_START(src_buf),
LOW_BITS_AREA_END(src_buf),
tempLowBitsArray);
#ifdef WK_DEBUG
printf("AFTER UNPACKING, about to enter main block \n");
#endif
{
register char *next_tag = (char *) tempTagsArray;
char *tags_area_end =
((char *) tempTagsArray) + PAGE_SIZE_IN_WORDS;
char *next_q_pos = (char *) tempQPosArray;
WK_word *next_low_bits = tempLowBitsArray;
WK_word *next_full_word = FULL_WORD_AREA_START(src_buf);
WK_word *next_output = dest_buf;
#ifdef WK_DEBUG
printf("next_output is %u\n", next_output);
printf("next_tag is %u \n", next_tag);
printf("tags_area_end is %u\n", tags_area_end);
printf("next_q_pos is %u\n", next_q_pos);
printf("next_low_bits is %u\n", next_low_bits);
printf("next_full_word is %u\n", next_full_word);
#endif
/* this loop should probably be unrolled. Maybe we should unpack
* as 4 bit values, giving two consecutive tags, and switch on
* that 16 ways to decompress 2 words at a whack
*/
while (next_tag < tags_area_end) {
char tag = next_tag[0];
switch(tag) {
case ZERO_TAG: {
*next_output = 0;
break;
}
case EXACT_TAG: {
WK_word *dict_location = dictionary + *(next_q_pos++);
/* no need to replace dict. entry if matched exactly */
*next_output = *dict_location;
break;
}
case PARTIAL_TAG: {
WK_word *dict_location = dictionary + *(next_q_pos++);
{
WK_word temp = *dict_location;
/* strip out low bits */
temp = ((temp >> NUM_LOW_BITS) << NUM_LOW_BITS);
/* add in stored low bits from temp array */
temp = temp | *(next_low_bits++);
*dict_location = temp; /* replace old value in dict. */
*next_output = temp; /* and echo it to output */
}
break;
}
case MISS_TAG: {
WK_word missed_word = *(next_full_word++);
WK_word *dict_location =
(WK_word *)
(((char *) dictionary) + HASH_TO_DICT_BYTE_OFFSET(missed_word));
*dict_location = missed_word;
*next_output = missed_word;
break;
}
}
next_tag++;
next_output++;
}
#ifdef WK_DEBUG
printf("AFTER DECOMPRESSING\n");
printf("next_output is %u\n", (unsigned long int) next_output);
printf("next_tag is %u\n", (unsigned long int) next_tag);
printf("next_full_word is %u\n", (unsigned long int) next_full_word);
printf("next_q_pos is %u\n", (unsigned long int) next_q_pos);
#endif
}
}
branches/rewrite/i386/boot2/resume.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
/*
* resume.c
*
*
* Created by mackerintel on 1/22/09.
* Copyright 2009 mackerintel. All rights reserved.
*
*/
#include "saio_internal.h"
#include "libsa.h"
#include "IOHibernatePrivate.h"
#include "memory.h"
#include "bootstruct.h"
#include "boot.h"
#include "pci.h"
extern int previewTotalSectors;
extern int previewLoadedSectors;
extern uint8_t *previewSaveunder;
static unsigned long
getmemorylimit(void)
{
int line;
int i;
MemoryRange *mp = bootInfo->memoryMap;
// Activate and clear page 1
line = 1;
for (i = 0; i < bootInfo->memoryMapCount; i++)
{
if((mp->type == 1) && ((unsigned long)mp->base == 0x100000))
{
return (unsigned long)(mp->base + mp->length);
}
mp++;
}
return 0x10000000;
}
static void WakeKernel(IOHibernateImageHeader * header)
{
uint32_t proc;
unsigned long cnt, newSP;
unsigned long *src, *dst;
unsigned int count;
unsigned int page;
unsigned int compressedSize;
int32_t byteCnt;
u_int32_t lowHalf, highHalf;
u_int32_t sum;
printf("\nWake Kernel!\n");
dst = (unsigned long *) (header->restore1CodePage << 12);
count = header->restore1PageCount;
proc = (header->restore1CodeOffset + ((uint32_t) dst));
newSP = header->restore1StackOffset + (header->restore1CodePage << 12);
src = (unsigned long *) (((u_int32_t) &header->fileExtentMap[0])
+ header->fileExtentMapSize);
sum = 0;
for (page = 0; page < count; page++)
{
compressedSize = 4096;
lowHalf = 1;
highHalf = 0;
for (cnt = 0; cnt < compressedSize; cnt += 0x20) {
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[2];
dst[3] = src[3];
dst[4] = src[4];
dst[5] = src[5];
dst[6] = src[6];
dst[7] = src[7];
for (byteCnt = 0; byteCnt < 0x20; byteCnt++) {
lowHalf += ((u_int8_t *) dst)[byteCnt];
highHalf += lowHalf;
}
src += 8;
dst += 8;
}
lowHalf %= 65521L;
highHalf %= 65521L;
sum += (highHalf << 16) | lowHalf;
}
header->actualRestore1Sum = sum;
startprog (proc, header);
return;
}
void HibernateBoot(char *image_filename)
{
long long size, imageSize, codeSize, allocSize;
long mem_base;
IOHibernateImageHeader _header;
IOHibernateImageHeader * header = &_header;
long buffer;
size = ReadFileAtOffset (image_filename, header, 0, sizeof(IOHibernateImageHeader));
printf("header read size %x\n", size);
imageSize = header->image1Size;
codeSize = header->restore1PageCount << 12;
if (kIOHibernateHeaderSignature != header->signature)
{
printf ("Incorrect image signature\n");
return;
}
if (header->encryptStart)
{
printf ("Resuming from Encrypted image is unsupported.\n"
"Uncheck \"Use secure virtual memory\" in \"Security\" pane on system preferences.\n"
"Press any key to proceed with normal boot.\n");
getchar();
return;
}
// depends on NVRAM
#if 0
{
uint32_t machineSignature;
size = GetProp(gChosenPH, kIOHibernateMachineSignatureKey,
(char *)&machineSignature, sizeof(machineSignature));
if (size != sizeof(machineSignature)) machineSignature = 0;
if (machineSignature != header->machineSignature)
break;
}
#endif
allocSize = imageSize + ((4095 + sizeof(hibernate_graphics_t)) & ~4095);
mem_base = getmemorylimit() - allocSize;//TODO: lower this
printf("mem_base %x\n", mem_base);
// Rek : hibernate fix
if (!((long long)mem_base+allocSize<1024*bootInfo->extmem+0x100000))
{
printf ("Not enough space to restore image. Press any key to proceed with normal boot.\n");
getchar();
return;
}
bcopy(header, (void *) mem_base, sizeof(IOHibernateImageHeader));
header = (IOHibernateImageHeader *) mem_base;
imageSize -= sizeof(IOHibernateImageHeader);
buffer = (long)(header + 1);
if (header->previewSize)
{
uint64_t preview_offset = header->fileExtentMapSize - sizeof(header->fileExtentMap) + codeSize;
uint8_t progressSaveUnder[kIOHibernateProgressCount][kIOHibernateProgressSaveUnderSize];
ReadFileAtOffset (image_filename, (char *)buffer, sizeof(IOHibernateImageHeader), preview_offset+header->previewSize);
drawPreview ((void *)(long)(buffer+preview_offset + header->previewPageListSize), &(progressSaveUnder[0][0]));
previewTotalSectors = (imageSize-(preview_offset+header->previewSize))/512;
previewLoadedSectors = 0;
previewSaveunder = &(progressSaveUnder[0][0]);
if (preview_offset+header->previewSize<imageSize)
ReadFileAtOffset (image_filename, (char *)(long)(buffer+preview_offset+header->previewSize),
sizeof(IOHibernateImageHeader)+preview_offset+header->previewSize,
imageSize-(preview_offset+header->previewSize));
previewTotalSectors = 0;
previewLoadedSectors = 0;
previewSaveunder = 0;
#if 0
AsereBLN:
check_vga_nvidia() didn't work as expected (recursion level > 0 & return value).
Unforutnaltely I cannot find a note why to switch back to text mode for nVidia cards only
and because it check_vga_nvidia does not work (cards normally are behind a bridge) I will
remove it completely
setVideoMode( VGA_TEXT_MODE, 0 );
#endif
}
else
ReadFileAtOffset (image_filename, (char *)buffer, sizeof(IOHibernateImageHeader), imageSize);
// Depends on NVRAM
#if 0
if (header->encryptStart) {
// decryption data
static const unsigned char first_iv[AES_BLOCK_SIZE]
= { 0xa3, 0x63, 0x65, 0xa9, 0x0b, 0x71, 0x7b, 0x1c,
0xdf, 0x9e, 0x5f, 0x32, 0xd7, 0x61, 0x63, 0xda };
hibernate_cryptvars_t _cryptvars;
hibernate_cryptvars_t * cryptvars = &_cryptvars;
aes_decrypt_key(&decryptkey,
decryptkeysize,
&cryptvars->ctx.decrypt);
// set the vector for the following decryptions
bcopy(((uint8_t *) header) + header->image1Size - AES_BLOCK_SIZE,
&cryptvars->aes_iv[0], AES_BLOCK_SIZE);
// decrypt the buffer
uint32_t len = (uint32_t)(header->image1Size - header->encryptStart);
aes_decrypt_cbc(((uint8_t *) header) + header->encryptStart,
&first_iv[0],
len >> 4,
((uint8_t *) header) + header->encryptStart,
&cryptvars->ctx.decrypt);
bzero(&cryptvars->aes_iv[0], sizeof(cryptvars));
bzero(&decryptkey, sizeof(decryptkey));
}
#endif
WakeKernel(header);
}
branches/rewrite/i386/boot2/WKdm.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
/* direct-mapped partial matching compressor with simple 22/10 split
*
* Compresses buffers using a dictionary based match and partial match
* (high bits only or full match) scheme.
*
* Paul Wilson -- wilson@cs.utexas.edu
* Scott F. Kaplan -- sfkaplan@cs.utexas.edu
* September 1997
*/
/* compressed output format, in memory order
* 1. a four-word HEADER containing four one-word values:
* i. a one-word code saying what algorithm compressed the data
* ii. an integer WORD offset into the page saying
* where the queue position area starts
* iii. an integer WORD offset into the page saying where
* the low-bits area starts
* iv. an integer WORD offset into the page saying where the
* low-bits area ends
*
* 2. a 64-word TAGS AREA holding one two-bit tag for each word in
* the original (1024-word) page, packed 16 per word
*
* 3. a variable-sized FULL WORDS AREA (always word aligned and an
* integral number of words) holding full-word patterns that
* were not in the dictionary when encoded (i.e., dictionary misses)
*
* 4. a variable-sized QUEUE POSITIONS AREA (always word aligned and
* an integral number of words) holding four-bit queue positions,
* packed eight per word.
*
* 5. a variable-sized LOW BITS AREA (always word aligned and an
* integral number of words) holding ten-bit low-bit patterns
* (from partial matches), packed three per word.
*/
#ifdef __cplusplus
extern "C" {
#endif
/* ============================================================ */
/* Included files */
//#include <stdio.h>
//#include <unistd.h>
//#include <math.h>
//#include <strings.h>
typedef unsigned long WK_word;
/* at the moment we have dependencies on the page size. That should
* be changed to work for any power-of-two size that's at least 16
* words, or something like that
*/
#define PAGE_SIZE_IN_WORDS 1024
#define PAGE_SIZE_IN_BYTES 4096
#define DICTIONARY_SIZE 16
/*
* macros defining the basic layout of stuff in a page
*/
#define HEADER_SIZE_IN_WORDS 4
#define TAGS_AREA_OFFSET 4
#define TAGS_AREA_SIZE 64
/* the next few are used during compression to write the header */
#define SET_QPOS_AREA_START(compr_dest_buf,qpos_start_addr) \
(compr_dest_buf[1] = qpos_start_addr - compr_dest_buf)
#define SET_LOW_BITS_AREA_START(compr_dest_buf,lb_start_addr) \
(compr_dest_buf[2] = lb_start_addr - compr_dest_buf)
#define SET_LOW_BITS_AREA_END(compr_dest_buf,lb_end_addr) \
(compr_dest_buf[3] = lb_end_addr - compr_dest_buf)
/* the next few are only use during decompression to read the header */
#define TAGS_AREA_START(decomp_src_buf) \
(decomp_src_buf + TAGS_AREA_OFFSET)
#define TAGS_AREA_END(decomp_src_buf) \
(TAGS_AREA_START(decomp_src_buf) + TAGS_AREA_SIZE)
#define FULL_WORD_AREA_START(the_buf) TAGS_AREA_END(the_buf)
#define QPOS_AREA_START(decomp_src_buf) \
(decomp_src_buf + decomp_src_buf[1])
#define LOW_BITS_AREA_START(decomp_src_buf) \
(decomp_src_buf + (decomp_src_buf[2]))
#define QPOS_AREA_END(the_buf) LOW_BITS_AREA_START(the_buf)
#define LOW_BITS_AREA_END(decomp_src_buf) \
(decomp_src_buf + (decomp_src_buf[3]))
/* ============================================================ */
/* Types and structures */
/* A structure to store each element of the dictionary. */
typedef WK_word DictionaryElement;
/* ============================================================ */
/* Misc constants */
#define BITS_PER_WORD 32
#define BYTES_PER_WORD 4
#define NUM_LOW_BITS 10
#define LOW_BITS_MASK 0x3FF
#define ALL_ONES_MASK 0xFFFFFFFF
#define TWO_BITS_PACKING_MASK 0x03030303
#define FOUR_BITS_PACKING_MASK 0x0F0F0F0F
#define TEN_LOW_BITS_MASK 0x000003FF
#define TWENTY_TWO_HIGH_BITS_MASK 0xFFFFFC00
/* Tag values. NOTE THAT CODE MAY DEPEND ON THE NUMBERS USED.
* Check for conditionals doing arithmetic on these things
* before changing them
*/
#define ZERO_TAG 0x0
#define PARTIAL_TAG 0x1
#define MISS_TAG 0x2
#define EXACT_TAG 0x3
#define BITS_PER_BYTE 8
/* ============================================================ */
/* Global macros */
/* Shift out the low bits of a pattern to give the high bits pattern.
The stripped patterns are used for initial tests of partial
matches. */
#define HIGH_BITS(word_pattern) (word_pattern >> NUM_LOW_BITS)
/* String the high bits of a pattern so the low order bits can
be included in an encoding of a partial match. */
#define LOW_BITS(word_pattern) (word_pattern & LOW_BITS_MASK)
#if defined DEBUG_WK
#define DEBUG_PRINT_1(string) printf (string)
#define DEBUG_PRINT_2(string,value) printf(string, value)
#else
#define DEBUG_PRINT_1(string)
#define DEBUG_PRINT_2(string, value)
#endif
/* Set up the dictionary before performing compression or
decompression. Each element is loaded with some value, the
high-bits version of that value, and a next pointer. */
#define PRELOAD_DICTIONARY { \
dictionary[0] = 1; \
dictionary[1] = 1; \
dictionary[2] = 1; \
dictionary[3] = 1; \
dictionary[4] = 1; \
dictionary[5] = 1; \
dictionary[6] = 1; \
dictionary[7] = 1; \
dictionary[8] = 1; \
dictionary[9] = 1; \
dictionary[10] = 1; \
dictionary[11] = 1; \
dictionary[12] = 1; \
dictionary[13] = 1; \
dictionary[14] = 1; \
dictionary[15] = 1; \
}
/* these are the constants for the hash function lookup table.
* Only zero maps to zero. The rest of the tabale is the result
* of appending 17 randomizations of the multiples of 4 from
* 4 to 56. Generated by a Scheme script in hash.scm.
*/
#define HASH_LOOKUP_TABLE_CONTENTS { \
0, 52, 8, 56, 16, 12, 28, 20, 4, 36, 48, 24, 44, 40, 32, 60, \
8, 12, 28, 20, 4, 60, 16, 36, 24, 48, 44, 32, 52, 56, 40, 12, \
8, 48, 16, 52, 60, 28, 56, 32, 20, 24, 36, 40, 44, 4, 8, 40, \
60, 32, 20, 44, 4, 36, 52, 24, 16, 56, 48, 12, 28, 16, 8, 40, \
36, 28, 32, 12, 4, 44, 52, 20, 24, 48, 60, 56, 40, 48, 8, 32, \
28, 36, 4, 44, 20, 56, 60, 24, 52, 16, 12, 12, 4, 48, 20, 8, \
52, 16, 60, 24, 36, 44, 28, 56, 40, 32, 36, 20, 24, 60, 40, 44, \
52, 16, 32, 4, 48, 8, 28, 56, 12, 28, 32, 40, 52, 36, 16, 20, \
48, 8, 4, 60, 24, 56, 44, 12, 8, 36, 24, 28, 16, 60, 20, 56, \
32, 40, 48, 12, 4, 44, 52, 44, 40, 12, 56, 8, 36, 24, 60, 28, \
48, 4, 32, 20, 16, 52, 60, 12, 24, 36, 8, 4, 16, 56, 48, 44, \
40, 52, 32, 20, 28, 32, 12, 36, 28, 24, 56, 40, 16, 52, 44, 4, \
20, 60, 8, 48, 48, 52, 12, 20, 32, 44, 36, 28, 4, 40, 24, 8, \
56, 60, 16, 36, 32, 8, 40, 4, 52, 24, 44, 20, 12, 28, 48, 56, \
16, 60, 4, 52, 60, 48, 20, 16, 56, 44, 24, 8, 40, 12, 32, 28, \
36, 24, 32, 12, 4, 20, 16, 60, 36, 28, 8, 52, 40, 48, 44, 56 \
}
#define HASH_TO_DICT_BYTE_OFFSET(pattern) \
(hashLookupTable[((pattern) >> 10) & 0xFF])
extern const char hashLookupTable[];
/* EMIT... macros emit bytes or words into the intermediate arrays
*/
#define EMIT_BYTE(fill_ptr, byte_value) {*fill_ptr = byte_value; fill_ptr++;}
#define EMIT_WORD(fill_ptr,word_value) {*fill_ptr = word_value; fill_ptr++;}
/* RECORD... macros record the results of modeling in the intermediate
* arrays
*/
#define RECORD_ZERO { EMIT_BYTE(next_tag,ZERO_TAG); }
#define RECORD_EXACT(queue_posn) EMIT_BYTE(next_tag,EXACT_TAG); \
EMIT_BYTE(next_qp,(queue_posn));
#define RECORD_PARTIAL(queue_posn,low_bits_pattern) { \
EMIT_BYTE(next_tag,PARTIAL_TAG); \
EMIT_BYTE(next_qp,(queue_posn)); \
EMIT_WORD(next_low_bits,(low_bits_pattern)) }
#define RECORD_MISS(word_pattern) EMIT_BYTE(next_tag,MISS_TAG); \
EMIT_WORD(next_full_patt,(word_pattern));
void
WKdm_decompress (WK_word* src_buf,
WK_word* dest_buf,
unsigned int words);
unsigned int
WKdm_compress (WK_word* src_buf,
WK_word* dest_buf,
unsigned int num_input_words);
#ifdef __cplusplus
} /* extern "C" */
#endif
branches/rewrite/i386/boot2/bmdecompress.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
/*
* Copyright (c) 1995-2002 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* The contents of this file constitute Original Code as defined in and
* are subject to the Apple Public Source License Version 1.1 (the
* "License"). You may not use this file except in compliance with the
* License. Please obtain a copy of the License at
* http://www.apple.com/publicsource and read it before using this file.
*
* This Original Code and all software distributed under the License are
* distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License.
*
* @APPLE_LICENSE_HEADER_END@
*/
#include "libsa.h"
static void
PreviewDecompress16(uint32_t * compressBuffer,
uint32_t width, uint32_t height, uint32_t row,
uint16_t * output)
{
int i, j;
uint32_t * input;
uint16_t * sc0 = malloc((width+2) * sizeof(uint16_t));
uint16_t * sc1 = malloc((width+2) * sizeof(uint16_t));
uint16_t * sc2 = malloc((width+2) * sizeof(uint16_t));
uint16_t * sc3 = malloc((width+2) * sizeof(uint16_t));
uint32_t sr0, sr1, sr2, sr3;
bzero(sc0, (width+2) * sizeof(uint16_t));
bzero(sc1, (width+2) * sizeof(uint16_t));
bzero(sc2, (width+2) * sizeof(uint16_t));
bzero(sc3, (width+2) * sizeof(uint16_t));
uint32_t tmp1, tmp2, out;
for (j = 0; j < (height + 2); j++)
{
input = compressBuffer;
if (j < height)
input += j;
else
input += height - 1;
input = (uint32_t *)(input[3] + ((uint8_t *)compressBuffer));
uint32_t data = 0, repeat = 0, fetch = 0, count = 0;
sr0 = sr1 = sr2 = sr3 = 0;
for (i = 0; i < (width + 2); i++)
{
if (i < width)
{
if (!count)
{
count = *input++;
repeat = (count & 0xff000000);
count ^= repeat;
fetch = true;
}
else
fetch = (0 == repeat);
count--;
if (fetch)
{
data = *((uint16_t *)input);
(*((uint16_t *)input))++;
// grayscale
// srgb 13933, 46871, 4732
// ntsc 19595, 38470, 7471
data = 13933 * (0x1f & (data >> 10))
+ 46871 * (0x1f & (data >> 5))
+ 4732 * (0x1f & data);
data >>= 13;
// 70% white, 30 % black
data *= 19661;
data += (103 << 16);
data >>= 16;
}
}
// gauss blur
tmp2 = sr0 + data;
sr0 = data;
tmp1 = sr1 + tmp2;
sr1 = tmp2;
tmp2 = sr2 + tmp1;
sr2 = tmp1;
tmp1 = sr3 + tmp2;
sr3 = tmp2;
tmp2 = sc0[i] + tmp1;
sc0[i] = tmp1;
tmp1 = sc1[i] + tmp2;
sc1[i] = tmp2;
tmp2 = sc2[i] + tmp1;
sc2[i] = tmp1;
out = (128 + sc3[i] + tmp2) >> 11;
sc3[i] = tmp2;
out &= 0x1f;
if ((i > 1) && (j > 1))
output[i-2] = out | (out << 5) | (out << 10);
}
if (j > 1)
output += row;
}
free(sc3);
free(sc2);
free(sc1);
free(sc0);
}
static void
PreviewDecompress32(uint32_t * compressBuffer,
uint32_t width, uint32_t height, uint32_t row,
uint32_t * output)
{
int i, j;
uint32_t * input;
uint16_t * sc0 = malloc((width+2) * sizeof(uint16_t));
uint16_t * sc1 = malloc((width+2) * sizeof(uint16_t));
uint16_t * sc2 = malloc((width+2) * sizeof(uint16_t));
uint16_t * sc3 = malloc((width+2) * sizeof(uint16_t));
uint32_t sr0, sr1, sr2, sr3;
bzero(sc0, (width+2) * sizeof(uint16_t));
bzero(sc1, (width+2) * sizeof(uint16_t));
bzero(sc2, (width+2) * sizeof(uint16_t));
bzero(sc3, (width+2) * sizeof(uint16_t));
uint32_t tmp1, tmp2, out;
for (j = 0; j < (height + 2); j++)
{
input = compressBuffer;
if (j < height)
input += j;
else
input += height - 1;
input = (uint32_t *)(input[3] + ((uint8_t *)compressBuffer));
uint32_t data = 0, repeat = 0, fetch = 0, count = 0;
sr0 = sr1 = sr2 = sr3 = 0;
for (i = 0; i < (width + 2); i++)
{
if (i < width)
{
if (!count)
{
count = *input++;
repeat = (count & 0xff000000);
count ^= repeat;
fetch = true;
}
else
fetch = (0 == repeat);
count--;
if (fetch)
{
data = *input++;
// grayscale
// srgb 13933, 46871, 4732
// ntsc 19595, 38470, 7471
data = 13933 * (0xff & (data >> 24))
+ 46871 * (0xff & (data >> 16))
+ 4732 * (0xff & data);
data >>= 16;
// 70% white, 30 % black
data *= 19661;
data += (103 << 16);
data >>= 16;
}
}
// gauss blur
tmp2 = sr0 + data;
sr0 = data;
tmp1 = sr1 + tmp2;
sr1 = tmp2;
tmp2 = sr2 + tmp1;
sr2 = tmp1;
tmp1 = sr3 + tmp2;
sr3 = tmp2;
tmp2 = sc0[i] + tmp1;
sc0[i] = tmp1;
tmp1 = sc1[i] + tmp2;
sc1[i] = tmp2;
tmp2 = sc2[i] + tmp1;
sc2[i] = tmp1;
out = (128 + sc3[i] + tmp2) >> 8;
sc3[i] = tmp2;
out &= 0xff;
if ((i > 1) && (j > 1))
output[i-2] = out | (out << 8) | (out << 16);
}
if (j > 1)
output += row;
}
free(sc3);
free(sc2);
free(sc1);
free(sc0);
}
void *
DecompressData(void *srcbase, int *dw, int *dh, int *bitsPerPixel)
{
uint32_t * src = (uint32_t *) srcbase;
void * ret;
*bitsPerPixel = 8 * ((int) src[0]);
*dw = (int) src[1];
*dh = (int) src[2];
ret = malloc ((*dw * *dh * *bitsPerPixel)/ 8);
switch(*bitsPerPixel)
{
case 32:
PreviewDecompress32((uint32_t *)srcbase, *dw, *dh, *dw, ret);
return ret;
case 16:
PreviewDecompress16((uint32_t *)srcbase, *dw, *dh, *dw, ret);
return ret;
default:
return 0;
}
}
branches/rewrite/i386/boot2/gui.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
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
/*
* gui.c
*
*
* Created by Jasmin Fazlic on 18.12.08.
* Copyright 2008/09 Jasmin Fazlic All rights reserved.
* Copyright 2008/09 iNDi All rights reserved.
*
*/
#include "gui.h"
#include "appleboot.h"
#include "vers.h"
#define IMG_REQUIRED -1
#define THEME_NAME_DEFAULT"Default"
static const char *theme_name = THEME_NAME_DEFAULT;
#ifdef CONFIG_EMBED_THEME
#include "art.h"
#endif
#define LOADPNG(img, alt_img) if (loadThemeImage(#img, alt_img) != 0) { return 1; }
#define VIDEO(x) (bootArgs->Video.v_ ## x)
#define vram VIDEO(baseAddr)
int lasttime = 0; // we need this for animating maybe
/*
* ATTENTION: the enum and the following array images[] MUST match !!!
*/
enum {
iBackground = 0,
iLogo,
iDeviceGeneric,
iDeviceGeneric_o,
iDeviceHFS,
iDeviceHFS_o,
iDeviceHFSRAID,
iDeviceHFSRAID_o,
iDeviceEXT3,
iDeviceEXT3_o,
iDeviceFAT,
iDeviceFAT_o,
iDeviceFAT16,
iDeviceFAT16_o,
iDeviceFAT32,
iDeviceFAT32_o,
iDeviceNTFS,
iDeviceNTFS_o,
iDeviceCDROM,
iDeviceCDROM_o,
iSelection,
iDeviceScrollPrev,
iDeviceScrollNext,
iMenuBoot,
iMenuVerbose,
iMenuIgnoreCaches,
iMenuSingleUser,
iMenuMemoryInfo,
iMenuVideoInfo,
iMenuHelp,
iMenuVerboseDisabled,
iMenuIgnoreCachesDisabled,
iMenuSingleUserDisabled,
iMenuSelection,
iProgressBar,
iProgressBarBackground,
iTextScrollPrev,
iTextScrollNext,
iFontConsole,
iFontSmall,
};
image_t images[] = {
{.name = "background", .image = NULL},
{.name = "logo", .image = NULL},
{.name = "device_generic", .image = NULL},
{.name = "device_generic_o", .image = NULL},
{.name = "device_hfsplus", .image = NULL},
{.name = "device_hfsplus_o", .image = NULL},
{.name = "device_hfsraid", .image = NULL},
{.name = "device_hfsraid_o", .image = NULL},
{.name = "device_ext3", .image = NULL},
{.name = "device_ext3_o", .image = NULL},
{.name = "device_fat", .image = NULL},
{.name = "device_fat_o", .image = NULL},
{.name = "device_fat16", .image = NULL},
{.name = "device_fat16_o", .image = NULL},
{.name = "device_fat32", .image = NULL},
{.name = "device_fat32_o", .image = NULL},
{.name = "device_ntfs", .image = NULL},
{.name = "device_ntfs_o", .image = NULL},
{.name = "device_cdrom", .image = NULL},
{.name = "device_cdrom_o", .image = NULL},
{.name = "device_selection", .image = NULL},
{.name = "device_scroll_prev", .image = NULL},
{.name = "device_scroll_next", .image = NULL},
{.name = "menu_boot", .image = NULL},
{.name = "menu_verbose", .image = NULL},
{.name = "menu_ignore_caches", .image = NULL},
{.name = "menu_single_user", .image = NULL},
{.name = "menu_memory_info", .image = NULL},
{.name = "menu_video_info", .image = NULL},
{.name = "menu_help", .image = NULL},
{.name = "menu_verbose_disabled", .image = NULL},
{.name = "menu_ignore_caches_disabled", .image = NULL},
{.name = "menu_single_user_disabled", .image = NULL},
{.name = "menu_selection", .image = NULL},
{.name = "progress_bar", .image = NULL},
{.name = "progress_bar_background", .image = NULL},
{.name = "text_scroll_prev", .image = NULL},
{.name = "text_scroll_next", .image = NULL},
{.name = "font_console", .image = NULL},
{.name = "font_small", .image = NULL},
};
int imageCnt = 0;
extern intgDeviceCount;
extern intselectIndex;
extern MenuItem *menuItems;
//char prompt[BOOT_STRING_LEN];
extern char gBootArgs[BOOT_STRING_LEN];
char prompt_text[] = "boot: ";
menuitem_t infoMenuItems[] =
{
{ .text = "Boot" },
{ .text = "Boot Verbose" },
{ .text = "Boot Ignore Caches" },
{ .text = "Boot Single User" },
{ .text = "Memory Info" },
{ .text = "Video Info" },
{ .text = "Help" }
};
int initFont(font_t *font, image_t *image);
void colorFont(font_t *font, uint32_t color);
void makeRoundedCorners(pixmap_t *p);
static int infoMenuSelection = 0;
static int infoMenuItemsCount = sizeof(infoMenuItems)/sizeof(infoMenuItems[0]);
static bool infoMenuNativeBoot = false;
// here we store the used screen resolution
static unsigned long screen_params[4] = {DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_HEIGHT, 32, 0};
static int getImageIndexByName(const char *name)
{
int i;
for (i = 0; i < sizeof(images) / sizeof(images[0]); i++)
{
if (strcmp(name, images[i].name) == 0)
return i; // found the name
}
return -1;
}
#ifdef CONFIG_EMBED_THEME
static int getEmbeddedImageIndexByName(const char *name)
{
int upperLimit = sizeof(embeddedImages) / sizeof(embeddedImages[0]) - 1;
int lowerLimit = 0;
int compareIndex = (upperLimit - lowerLimit) >> 1; // Midpoint
int result;
// NOTE: This algorithm assumes that the embedded images are sorted.
// This is currently done using the make file. If the array is
// generated manualy, this *will* fail to work properly.
while((result = strcmp(name, embeddedImages[compareIndex].name)) != 0)
{
if (result > 0)// We need to search a HIGHER index
{
if (compareIndex != lowerLimit)
{
lowerLimit = compareIndex;
}
else
{
return -1;
}
compareIndex = (upperLimit + lowerLimit + 1) >> 1;// Midpoint, round up
}
else // We Need to search a LOWER index
{
if (compareIndex != upperLimit)
{
upperLimit = compareIndex;
}
else
{
return -1;
}
compareIndex = (upperLimit + lowerLimit) >> 1;// Midpoint, round down
}
}
return compareIndex;
}
#endif
static int loadThemeImage(const char *image, int alt_image)
{
chardirspec[256];
int i;
#ifdef CONFIG_EMBED_THEME
int e;
#endif
uint16_twidth;
uint16_theight;
uint8_t*imagedata;
if ((strlen(image) + strlen(theme_name) + 20 ) > sizeof(dirspec)) {
return 1;
}
if ((i = getImageIndexByName(image)) >= 0)
{
if (images[i].image == NULL) {
images[i].image = malloc(sizeof(pixmap_t));
}
sprintf(dirspec, "/Extra/Themes/%s/%s.png", theme_name, image);
width = 0;
height = 0;
imagedata = NULL;
if ((loadPngImage(dirspec, &width, &height, &imagedata)) == 0)
{
images[i].image->width = width;
images[i].image->height = height;
images[i].image->pixels = (pixel_t *)imagedata;
flipRB(images[i].image);
return 0;
}
#ifdef CONFIG_EMBED_THEME
else if ((e = getEmbeddedImageIndexByName(image)) >= 0)
{
unsigned char *embed_data;
unsigned int embed_size;
embed_data = embeddedImages[e].pngdata;
embed_size = *embeddedImages[e].length;
if (loadEmbeddedPngImage(embed_data, embed_size, &width, &height, &imagedata) == 0)
{
images[i].image->width = width;
images[i].image->height = height;
images[i].image->pixels = (pixel_t *)imagedata;
flipRB(images[i].image);
return 0;
}
return 0;
}
#endif
else if (alt_image != IMG_REQUIRED && images[alt_image].image->pixels != NULL)
{
// Using the passed alternate image for non-mandatory images.
// We don't clone the already existing pixmap, but using its properties instead!
images[i].image->width = images[alt_image].image->width;
images[i].image->height = images[alt_image].image->height;
images[i].image->pixels = images[alt_image].image->pixels;
return 0;
}
else
{
#ifndef CONFIG_EMBED_THEME
printf("ERROR: GUI: could not open '%s/%s.png'!\n", theme_name, image);
sleep(2);
#endif
return 1;
}
}
return 1;
}
static int loadGraphics(void)
{
LOADPNG(background, IMG_REQUIRED);
LOADPNG(logo, IMG_REQUIRED);
LOADPNG(device_generic, IMG_REQUIRED);
LOADPNG(device_generic_o, iDeviceGeneric);
LOADPNG(device_hfsplus, iDeviceGeneric);
LOADPNG(device_hfsplus_o, iDeviceHFS);
LOADPNG(device_hfsraid, iDeviceGeneric);
LOADPNG(device_hfsraid_o, iDeviceHFSRAID);
LOADPNG(device_ext3, iDeviceGeneric);
LOADPNG(device_ext3_o, iDeviceEXT3);
LOADPNG(device_fat, iDeviceGeneric);
LOADPNG(device_fat_o, iDeviceFAT);
LOADPNG(device_fat16, iDeviceFAT);
LOADPNG(device_fat16_o, iDeviceFAT_o);
LOADPNG(device_fat32, iDeviceFAT);
LOADPNG(device_fat32_o, iDeviceFAT_o);
LOADPNG(device_ntfs, iDeviceGeneric);
LOADPNG(device_ntfs_o, iDeviceNTFS);
LOADPNG(device_cdrom, iDeviceGeneric);
LOADPNG(device_cdrom_o, iDeviceCDROM);
LOADPNG(device_selection, IMG_REQUIRED);
LOADPNG(device_scroll_prev, IMG_REQUIRED);
LOADPNG(device_scroll_next, IMG_REQUIRED);
LOADPNG(menu_boot, IMG_REQUIRED);
LOADPNG(menu_verbose, IMG_REQUIRED);
LOADPNG(menu_ignore_caches, IMG_REQUIRED);
LOADPNG(menu_single_user, IMG_REQUIRED);
LOADPNG(menu_memory_info, IMG_REQUIRED);
LOADPNG(menu_video_info, IMG_REQUIRED);
LOADPNG(menu_help, IMG_REQUIRED);
LOADPNG(menu_verbose_disabled, IMG_REQUIRED);
LOADPNG(menu_ignore_caches_disabled, IMG_REQUIRED);
LOADPNG(menu_single_user_disabled, IMG_REQUIRED);
LOADPNG(menu_selection, IMG_REQUIRED);
LOADPNG(progress_bar, IMG_REQUIRED);
LOADPNG(progress_bar_background, IMG_REQUIRED);
LOADPNG(text_scroll_prev, IMG_REQUIRED);
LOADPNG(text_scroll_next, IMG_REQUIRED);
LOADPNG(font_console, IMG_REQUIRED);
LOADPNG(font_small, IMG_REQUIRED);
initFont( &font_console, &images[iFontConsole]);
initFont( &font_small, &images[iFontSmall]);
return 0;
}
pixmap_t *getCroppedPixmapAtPosition( pixmap_t *from, position_t pos, uint16_t width, uint16_t height )
{
pixmap_t *cropped = malloc( sizeof( pixmap_t ) );
if( !cropped )
return 0;
cropped->pixels = malloc( width * height * 4 );
if ( !cropped->pixels )
return 0;
cropped->width = width;
cropped->height = height;
int destx = 0, desty = 0;
int srcx = pos.x, srcy = pos.y;
for( ; desty < height; desty++, srcy++)
{
for( destx = 0, srcx = pos.x; destx < width; destx++, srcx++ )
{
pixel( cropped, destx, desty ).value = pixel( from, srcx, srcy ).value;
}
}
return cropped;
}
int createBackBuffer( window_t *window )
{
gui.backbuffer = malloc(sizeof(pixmap_t));
if(!gui.backbuffer)
return 1;
gui.backbuffer->pixels = malloc( window->width * window->height * 4 );
if(!gui.backbuffer->pixels)
{
free(gui.backbuffer);
gui.backbuffer = 0;
return 1;
}
gui.backbuffer->width = gui.screen.width;
gui.backbuffer->height = gui.screen.height;
return 0;
}
int createWindowBuffer( window_t *window )
{
window->pixmap = malloc(sizeof(pixmap_t));
if(!window->pixmap)
return 1;
window->pixmap->pixels = malloc( window->width * window->height * 4 );
if(!window->pixmap->pixels)
{
free(window->pixmap);
window->pixmap = 0;
return 1;
}
window->pixmap->width = window->width;
window->pixmap->height = window->height;
return 0;
}
int freeWindowBuffer( window_t *window )
{
if (window->pixmap && window->pixmap->pixels)
{
free(window->pixmap->pixels);
free(window->pixmap);
return 0;
}
return 1;
}
void fillPixmapWithColor(pixmap_t *pm, uint32_t color)
{
int x,y;
// fill with given color AARRGGBB
for( x=0; x < pm->width; x++ )
for( y=0; y< pm->height; y++)
pixel(pm,x,y).value = color;
}
void drawBackground()
{
// reset text cursor
gui.screen.cursor.x = gui.screen.hborder;
gui.screen.cursor.y = gui.screen.vborder;
fillPixmapWithColor( gui.screen.pixmap, gui.screen.bgcolor);
// draw background.png into background buffer
blend( images[iBackground].image, gui.screen.pixmap, gui.background.pos );
// draw logo.png into background buffer
if (gui.logo.draw)
{
blend( images[iLogo].image, gui.screen.pixmap, gui.logo.pos);
}
memcpy( gui.backbuffer->pixels, gui.screen.pixmap->pixels, gui.backbuffer->width * gui.backbuffer->height * 4 );
}
void setupDeviceList(config_file_t *theme)
{
unsigned int pixel;
intalpha;// transparency level 0 (obligue) - 255 (transparent)
uint32_t color;// color value formatted RRGGBB
int val, len;
const char *string;
if(getIntForKey("devices_max_visible", &val, theme ))
gui.maxdevices = MIN( val, gDeviceCount );
if(getIntForKey("devices_iconspacing", &val, theme ))
gui.devicelist.iconspacing = val;
// check layout for horizontal or vertical
gui.layout = HorizontalLayout;
if(getValueForKey( "devices_layout", &string, &len, theme)) {
if (!strcmp (string, "vertical")) {
gui.layout = VerticalLayout;
}
}
switch (gui.layout) {
case VerticalLayout:
gui.devicelist.height = ((images[iSelection].image->height + font_console.chars[0]->height + gui.devicelist.iconspacing) * MIN(gui.maxdevices, gDeviceCount) + (images[iDeviceScrollPrev].image->height + images[iDeviceScrollNext].image->height) + gui.devicelist.iconspacing);
gui.devicelist.width = (images[iSelection].image->width + gui.devicelist.iconspacing);
if(getDimensionForKey("devices_pos_x", &pixel, theme, gui.screen.width , images[iSelection].image->width ) )
gui.devicelist.pos.x = pixel;
if(getDimensionForKey("devices_pos_y", &pixel, theme, gui.screen.height , gui.devicelist.height ) )
gui.devicelist.pos.y = pixel;
break;
case HorizontalLayout:
default:
gui.devicelist.width = ((images[iSelection].image->width + gui.devicelist.iconspacing) * MIN(gui.maxdevices, gDeviceCount) + (images[iDeviceScrollPrev].image->width + images[iDeviceScrollNext].image->width) + gui.devicelist.iconspacing);
gui.devicelist.height = (images[iSelection].image->height + font_console.chars[0]->height + gui.devicelist.iconspacing);
if(getDimensionForKey("devices_pos_x", &pixel, theme, gui.screen.width , gui.devicelist.width ) )
gui.devicelist.pos.x = pixel;
else
gui.devicelist.pos.x = ( gui.screen.width - gui.devicelist.width ) / 2;
if(getDimensionForKey("devices_pos_y", &pixel, theme, gui.screen.height , images[iSelection].image->height ) )
gui.devicelist.pos.y = pixel;
else
gui.devicelist.pos.y = ( gui.screen.height - gui.devicelist.height ) / 2;
break;
}
if(getColorForKey("devices_bgcolor", &color, theme))
gui.devicelist.bgcolor = (color & 0x00FFFFFF);
if(getIntForKey("devices_transparency", &alpha, theme))
gui.devicelist.bgcolor = gui.devicelist.bgcolor | (( 255 - ( alpha & 0xFF) ) << 24);
if (gui.devicelist.pixmap)
{
freeWindowBuffer(&gui.devicelist);
createWindowBuffer(&gui.devicelist);
}
}
void loadThemeValues(config_file_t *theme)
{
unsigned int screen_width = gui.screen.width;
unsigned int screen_height = gui.screen.height;
unsigned int pixel;
intalpha;// transparency level 0 (obligue) - 255 (transparent)
uint32_t color;// color value formatted RRGGBB
int val;
/*
* Parse screen parameters
*/
if(getColorForKey("screen_bgcolor", &color, theme ))
gui.screen.bgcolor = (color & 0x00FFFFFF);
if(getIntForKey("screen_textmargin_h", &val, theme))
gui.screen.hborder = MIN( gui.screen.width , val );
if(getIntForKey("screen_textmargin_v", &val, theme))
gui.screen.vborder = MIN( gui.screen.height , val );
/*
* Parse background parameters
*/
if(getDimensionForKey("background_pos_x", &pixel, theme, screen_width , images[iBackground].image->width ) )
<