Chameleon

Chameleon Commit Details

Date:2011-09-13 22:24:40 (12 years 7 months ago)
Author:armel cadet-petit
Commit:1525
Parents: 1524
Message:combo update, see changelog
Changes:
D/branches/cparm/i386/boot1/boot1.s
A/branches/cparm/i386/boot1/boot1h.s
A/branches/cparm/i386/boot0/boot0md.s
M/branches/cparm/i386/modules/HibernateEnabler/resume.c
M/branches/cparm/i386/modules/GraphicsEnabler/nvidia.c
M/branches/cparm/i386/libsaio/platform.h
M/branches/cparm/i386/libsaio/acpi_tools.c
M/branches/cparm/i386/boot1/Makefile
M/branches/cparm/i386/boot2/options.c
M/branches/cparm/i386/libsaio/console.c
M/branches/cparm/i386/modules/HibernateEnabler/IOHibernatePrivate.h
M/branches/cparm/i386/modules/ACPICodec/acpi_codec.c
M/branches/cparm/i386/modules/HibernateEnabler/HibernateEnabler.c
M/branches/cparm/CHANGES
M/branches/cparm/i386/modules/Keymapper/Keymapper.c
M/branches/cparm/Makefile
M/branches/cparm/i386/modules/GraphicsEnabler/gma.c
M/branches/cparm/i386/boot2/mboot.c
M/branches/cparm/i386/libsaio/saio_types.h
M/branches/cparm/i386/libsaio/cpu.c
M/branches/cparm/i386/libsaio/fake_efi.c
M/branches/cparm/i386/modules/ACPIPatcher/AcpiPatcher.c
M/branches/cparm/i386/boot0/Makefile
M/branches/cparm/i386/modules/GUI/gui.c
M/branches/cparm/i386/boot2/Makefile
M/branches/cparm/i386/libsaio/ppm.h
M/branches/cparm/i386/boot0/boot0.s
M/branches/cparm/i386/libsaio/smp-imps.c
M/branches/cparm/i386/boot2/boot.c
M/branches/cparm/TODO
M/branches/cparm/i386/modules/ACPICodec/ACPICodec.c
M/branches/cparm/i386/boot2/modules.c
M/branches/cparm/i386/boot2/boot.h

File differences

branches/cparm/TODO
11
22
33
4
5
46
57
68
TODO List for Chameleon Boot Loader
====================================
- Implement a Host like in bits to avoid some return issues
- Implement snprintf to avoid buffer overflow in some case
- It seems that nvram variables must be set thru efiRuntimeServices->SetVariable(...),
branches/cparm/CHANGES
1
2
3
4
5
6
7
8
9
10
111
212
313
......
515
616
717
8
18
919
1020
11
21
1222
1323
1424
......
1626
1727
1828
19
29
2030
2131
2232
- Updated keymapper ...
- Applied scorpius's patch (to get an unstretched boot screen for nVidia cards on DVI) in boot0.s , disabled by default,
see - http://forum.voodooprojects.org/index.php/topic,2158.msg10345/boardseen.html#new - for more info.
- Applied Vladimir Zidar's hibernate patch on hibernateEnabler
- Applied "Intel HD Graphics 3000" patch to gma.c (credit: ???) ,
found at - http://www.darwinx86.net/forum/61-section-francaise-/1880-espace-de-discussion-anval?limit=10&start=60#6247 -
- Added AMD support (most of the code is derived from the trunk, MUST BE ENABLED BY HAND IN CPU.C) see - http://forge.voodooprojects.org/p/chameleon/issues/163/ -
- Improved Core Ix support in AcpiCodec
- Improved c-states support in AcpiCodec
- Sync'd nvidia.c and gma.c (see GraphicEnabler module) to the trunk
- Improved compatibility with xcode4 (afaik only the modules gui and smbiosgetters will not work with xcode4, even if they are built without any errors)
- Applied JrCs's path for more protection against buffer overflow in some case (trunk v1449)
- Moved smp code to Erich Boleyn's smp-imps (not fully implemented yet)
- Added the UseKernelCache option only for compatibility with the trunk ("Yes" have no effect, since it's the default),
the Flag "-F" which do the same things is still valid
- Re-worked SSDT generation, and merged with the Intel's code
- Re-worked SSDT generation, and merged with the Bits's code
- Removed aml_generator from AcpiCodec, now use acpicode.c to generate aml file
- Added YellowIconFixer module
- Merged fsb detection with Intel's code in cpu.c (slightly faster)
- Merged fsb detection with Bits's code in cpu.c (slightly faster)
- Fixed a bug related to ACPI in AcpiCodec (thanck to StephN666 for testing)
- Fixed a bug related to ACPI and the machine with a rsd table revision > 0 (acpi_tools.c) (thanck to StephN666 for testing)
- Fixed an issue with kernelPatcher, it seems that kernelPatcher is unable to patch the kernelCache
- Applied some fixes from the trunk
- Applied many under the hood fixes
- Added Andy Vandijck Server spoof
- Added Andy Vandijck's Server spoof
- Added a Patch from Andy Vandijck in SMBiosPatcher and SMBiosGetters
- Added a Patch from Netkas in GraphicEnabler (ati.c)
- Fixed an issue where the GUI module couldn't find the themes directory
branches/cparm/i386/libsaio/console.c
137137
138138
139139
140
140
141141
142142
143143
{
int c = bgetc();
execute_hook("Keymapper", &c, NULL, NULL, NULL, NULL, NULL);
//execute_hook("Keymapper", &c, NULL, NULL, NULL, NULL, NULL);
if ((c & 0xff) == 0)
return c;
branches/cparm/i386/libsaio/smp-imps.c
244244
245245
246246
247
248
249
247
248
249
250250
251251
252252
* under the 1MB boundary.
*/
//extern char patch_code_end[];
//bootaddr = (512-64)*1024;
//memcpy((char *)bootaddr, patch_code_start, 0x5fe00);
//extern char ???[];
//bootaddr = (512-64)*1024; ???
//memcpy((char *)bootaddr, ,??? );
/*
* Generic CPU startup sequence starts here.
branches/cparm/i386/libsaio/cpu.c
1717
1818
1919
20
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
2147
2248
2349
......
146172
147173
148174
149
175
176
150177
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
151238
152239
153240
......
184271
185272
186273
187
188
189
190
274
275
276
277
191278
192279
193280
194281
195
196
197
198
282
283
284
285
199286
200287
201288
......
319406
320407
321408
322
409
323410
324411
325
326412
413
327414
328415
329416
......
335422
336423
337424
338
425
339426
340427
341428
......
351438
352439
353440
354
441
355442
356443
357444
358445
359446
360
447
361448
362449
363450
......
386473
387474
388475
389
476
390477
391478
392479
393480
394481
482
395483
396484
397485
398
399
486
487
488
489
400490
401491
402492
......
406496
407497
408498
499
500
501
502
503
504
505
506
409507
410508
411509
......
416514
417515
418516
419
517
420518
421
519
422520
423
424
425
426
427
428
429
430
431
432521
522
523
433524
434525
526
527
528
529
530
531
532
533
534
535
435536
436
537
437538
438539
439540
440541
441
542
543
442544
545
443546
444547
445
548
549
446550
447551
448552
......
453557
454558
455559
456
560
457561
458562
459563
460
461
462
463
464
564
565
566
567
568
465569
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
490594
491
595
492596
493597
494
495
598
599
496600
497601
498602
499603
500
604
605
606
501607
502
503
504
505
506
507
608
508609
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
509662
510
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
511700
512701
513702
......
533722
534723
535724
536
725
537726
538727
539728
......
567756
568757
569758
570
759
571760
572761
573762
......
582771
583772
584773
585
774
586775
587776
588777
......
604793
605794
606795
607
796
608797
609798
610799
......
617806
618807
619808
620
809
810
621811
622
812
813
623814
624815
625816
......
642833
643834
644835
836
837
645838
646839
647840
......
661854
662855
663856
664
857
665858
666859
667860
668
669
861
862
670863
671864
672865
......
688881
689882
690883
691
884
692885
693886
694
887
888
889
695890
696891
697892
698893
699
700
701
702
703
894
704895
705896
706897
707
898
899
900
708901
709902
710
711
712
713
714
715
716
717
903
904
905
906
907
908
909
910
911
912
913
914
915
718916
719917
720918
721
919
920
722921
922
723923
724
924
725925
726926
727927
#define DBG(x...)msglog(x)
#endif
#if OLD_STYLE
//#define AMD_SUPPORT
#ifndef INTEL_SUPPORT
#define INTEL_SUPPORT 0 //Default (0: nolegacy, 1 : legacy)
#endif
#ifdef AMD_SUPPORT
#ifdef LEGACY_CPU
#undef LEGACY_CPU
#endif
#ifdef INTEL_SUPPORT
#undef INTEL_SUPPORT
#endif
#define LEGACY_CPU 1
#endif
#ifdef INTEL_SUPPORT
#ifdef LEGACY_CPU
#undef LEGACY_CPU
#endif
#define LEGACY_CPU INTEL_SUPPORT
#endif
// (?) : if AMD_SUPPORT then LEGACY_CPU = 1, INTEL_SUPPORT = disabled
// else LEGACY_CPU = INTEL_SUPPORT
#if LEGACY_CPU
static uint64_t measure_tsc_frequency(void);
// DFE: enable_PIT2 and disable_PIT2 come from older xnu
return retval;
}
#else
#ifdef AMD_SUPPORT
#define MSR_AMD_APERF 0x000000E8
/*
* Original comment/code:
* "DFE: Measures the Max Performance Frequency in Hz (64-bit)"
*
* Measures the Actual Performance Frequency in Hz (64-bit)
* (just a naming change, mperf --> aperf )
*/
static uint64_t measure_aperf_frequency(void)
{
uint64_t aperfStart;
uint64_t aperfEnd;
uint64_t aperfDelta = 0xffffffffffffffffULL;
unsigned long pollCount;
uint64_t retval = 0;
int i;
/* Time how many APERF ticks elapse in 30 msec using the 8254 PIT
* counter 2. We run this loop 3 times to make sure the cache
* is hot and we take the minimum delta from all of the runs.
* That is to say that we're biased towards measuring the minimum
* number of APERF ticks that occur while waiting for the timer to
* expire.
*/
for(i = 0; i < 10; ++i)
{
enable_PIT2();
set_PIT2_mode0(CALIBRATE_LATCH);
aperfStart = rdmsr64(MSR_AMD_APERF);
pollCount = poll_PIT2_gate();
aperfEnd = rdmsr64(MSR_AMD_APERF);
/* The poll loop must have run at least a few times for accuracy */
if (pollCount <= 1)
continue;
/* The TSC must increment at LEAST once every millisecond.
* We should have waited exactly 30 msec so the APERF delta should
* be >= 30. Anything less and the processor is way too slow.
*/
if ((aperfEnd - aperfStart) <= CALIBRATE_TIME_MSEC)
continue;
// tscDelta = MIN(tscDelta, (tscEnd - tscStart))
if ( (aperfEnd - aperfStart) < aperfDelta )
aperfDelta = aperfEnd - aperfStart;
}
/* mperfDelta is now the least number of MPERF ticks the processor made in
* a timespan of 0.03 s (e.g. 30 milliseconds)
*/
if (aperfDelta > (1ULL<<32))
retval = 0;
else
{
retval = aperfDelta * 1000 / 30;
}
disable_PIT2();
return retval;
}
#endif
#endif
/*
License for x2apic_enabled, get_apicbase, compute_bclk.
Copyright (c) 2010, Intel Corporation
static inline __attribute__((always_inline)) void rdmsr32(uint32_t msr, uint32_t * lo_data_addr, uint32_t * hi_data_addr)
{
__asm__ volatile(
"rdmsr"
: "=a" (*lo_data_addr), "=d" (*hi_data_addr)
: "c" (msr)
);
"rdmsr"
: "=a" (*lo_data_addr), "=d" (*hi_data_addr)
: "c" (msr)
);
}
static inline __attribute__((always_inline)) void wrmsr32(uint32_t msr, uint32_t lo_data, uint32_t hi_data)
{
__asm__ __volatile__ (
"wrmsr"
: /* No outputs */
: "c" (msr), "a" (lo_data), "d" (hi_data)
);
"wrmsr"
: /* No outputs */
: "c" (msr), "a" (lo_data), "d" (hi_data)
);
}
#define MSR_APIC_BASE 0x1B
#define APIC_TMR_INITIAL_CNT 0x380
// Round bclk to the nearest 100/12 integer value
bclk = ((((bclk * 24) + 100) / 200) * 200) / 24;
DBG("\nCompute bclk: %dMHz\n", bclk);
return bclk;
}
#endif
/*
* Calculates the FSB and CPU frequencies using specific MSRs for each CPU
* - multi. is read from a specific MSR. In the case of Intel, there is:
void scan_cpu(PlatformInfo_t *p)
{
uint64_ttscFrequency, fsbFrequency, cpuFrequency;
uint64_ttscFrequency = 0, fsbFrequency = 0, cpuFrequency = 0;
uint64_tmsr;
uint8_tmaxcoef = 0, maxdiv = 0, currcoef = 0, currdiv = 0;
uint32_treg[4];
/* get extended cpuid results */
do_cpuid(0x80000000, reg);
uint32_t cpuid_max_ext = reg[eax];
p->CPU.cpuid_max_ext = reg[eax];
/* Begin of Copyright: from Apple's XNU cpuid.c */
/* get brand string (if supported) */
if (cpuid_max_ext > 0x80000004)
if (p->CPU.cpuid_max_ext > 0x80000004)
{
char str[128], *s;
/*
p->CPU.BrandString[0] = '\0';
}
}
/*
* Get processor signature and decode
* and bracket this with the approved procedure for reading the
* the microcode version number a.k.a. signature a.k.a. BIOS ID
*/
#ifndef AMD_SUPPORT
wrmsr64(MSR_IA32_BIOS_SIGN_ID, 0);
do_cpuid(1, reg);
p->CPU.MicrocodeVersion =
(uint32_t) (rdmsr64(MSR_IA32_BIOS_SIGN_ID) >> 32);
(uint32_t) (rdmsr64(MSR_IA32_BIOS_SIGN_ID) >> 32);
#else
do_cpuid(1, reg);
#endif
p->CPU.Signature = reg[eax];
p->CPU.Stepping = bitfield(reg[eax], 3, 0);
p->CPU.Model = bitfield(reg[eax], 7, 4);
p->CPU.Brand = bitfield(reg[ebx], 7, 0);
p->CPU.Features = quad(reg[ecx], reg[edx]);
if (p->CPU.cpuid_max_ext >= 0x80000001)
{
do_cpuid(0x80000001, reg);
p->CPU.ExtFeatures =
quad(reg[ecx], reg[edx]);
}
/* Fold extensions into family/model */
if (p->CPU.Family == 0x0f)
p->CPU.Family += p->CPU.ExtFamily;
logical_per_package =
bitfield(reg[ebx], 23, 16);
else
logical_per_package = 1;
logical_per_package = 1;
if (cpuid_max_ext >= 0x80000001)
if (p->CPU.cpuid_max_ext >= 0x80000007)
{
do_cpuid(0x80000001, reg);
p->CPU.ExtFeatures =
quad(reg[ecx], reg[edx]);
}
/* Fold in the Invariant TSC feature bit, if present */
if (cpuid_max_ext >= 0x80000007)
{
do_cpuid(0x80000007, reg);
/* Fold in the Invariant TSC feature bit, if present */
p->CPU.ExtFeatures |=
reg[edx] & (uint32_t)CPUID_EXTFEATURE_TSCI;
#ifdef AMD_SUPPORT
/* Fold in the Hardware P-State control feature bit, if present */
p->CPU.ExtFeatures |=
reg[edx] & (uint32_t)_Bit(7);
/* Fold in the read-only effective frequency interface feature bit, if present */
p->CPU.ExtFeatures |=
reg[edx] & (uint32_t)_Bit(10);
#endif
}
if (p->CPU.cpuid_max_basic >= 0x5) {
/*
* Extract the Monitor/Mwait Leaf info:
*/
do_cpuid(5, reg);
do_cpuid(5, reg);
#ifndef AMD_SUPPORT
p->CPU.sub_Cstates = reg[edx];
#endif
p->CPU.extensions = reg[ecx];
}
#ifndef AMD_SUPPORT
if (p->CPU.cpuid_max_basic >= 0x6)
{
/*
p->CPU.invariant_APIC_timer = bitfield(reg[eax], 2, 2); // "Invariant APIC Timer"
p->CPU.fine_grain_clock_mod = bitfield(reg[eax], 4, 4);
}
if ((p->CPU.Vendor == 0x756E6547 /* Intel */) &&
(p->CPU.Family == 0x06))
{
/*
* Find the number of enabled cores and threads
* (which determines whether SMT/Hyperthreading is active).
*/
switch (p->CPU.Model)
/*
* Find the number of enabled cores and threads
* (which determines whether SMT/Hyperthreading is active).
*/
switch (p->CPU.Model)
{
case CPUID_MODEL_DALES_32NM:
case CPUID_MODEL_WESTMERE:
case CPUID_MODEL_WESTMERE_EX:
{
msr = rdmsr64(MSR_CORE_THREAD_COUNT);
p->CPU.NoThreads = bitfield((uint32_t)msr, 15, 0);
p->CPU.NoCores = bitfield((uint32_t)msr, 19, 16);
break;
}
case CPUID_MODEL_NEHALEM:
case CPUID_MODEL_FIELDS:
case CPUID_MODEL_DALES:
case CPUID_MODEL_NEHALEM_EX:
case CPUID_MODEL_SANDYBRIDGE:
case CPUID_MODEL_JAKETOWN:
{
msr = rdmsr64(MSR_CORE_THREAD_COUNT);
p->CPU.NoThreads = bitfield((uint32_t)msr, 15, 0);
p->CPU.NoCores = bitfield((uint32_t)msr, 31, 16);
break;
}
}
case CPUID_MODEL_DALES_32NM:
case CPUID_MODEL_WESTMERE:
case CPUID_MODEL_WESTMERE_EX:
{
msr = rdmsr64(MSR_CORE_THREAD_COUNT);
p->CPU.NoThreads = bitfield((uint32_t)msr, 15, 0);
p->CPU.NoCores = bitfield((uint32_t)msr, 19, 16);
break;
}
case CPUID_MODEL_NEHALEM:
case CPUID_MODEL_FIELDS:
case CPUID_MODEL_DALES:
case CPUID_MODEL_NEHALEM_EX:
case CPUID_MODEL_SANDYBRIDGE:
case CPUID_MODEL_JAKETOWN:
{
msr = rdmsr64(MSR_CORE_THREAD_COUNT);
p->CPU.NoThreads = bitfield((uint32_t)msr, 15, 0);
p->CPU.NoCores = bitfield((uint32_t)msr, 31, 16);
break;
}
}
}
#endif
if (p->CPU.NoCores == 0)
{
p->CPU.NoThreads = cores_per_package;
p->CPU.NoCores = logical_per_package;
p->CPU.NoThreads = logical_per_package;
p->CPU.NoCores = cores_per_package ? cores_per_package : 1 ;
}
/* End of Copyright: from Apple's XNU cpuid.c */
#if OLD_STYLE
fsbFrequency = (uint64_t)(compute_bclk() * 1000000);
#if LEGACY_CPU
tscFrequency = measure_tsc_frequency();
fsbFrequency = 0;
#else
tscFrequency = 0;
fsbFrequency = (uint64_t)(compute_bclk() * 1000000);
#endif
cpuFrequency = 0;
#endif
#ifdef AMD_SUPPORT
#define K8_FIDVID_STATUS0xC0010042
#define K10_COFVID_STATUS0xC0010071
if (p->CPU.ExtFeatures & _Bit(10))
{
cpuFrequency = measure_aperf_frequency();
}
if ((p->CPU.Vendor == 0x68747541 /* AMD */) && (p->CPU.Family == 0x0f))
{
switch(p->CPU.ExtFamily)
{
case 0x00: /* K8 */
msr = rdmsr64(K8_FIDVID_STATUS);
maxcoef = bitfield(msr, 21, 16) / 2 + 4;
currcoef = bitfield(msr, 5, 0) / 2 + 4;
break;
case 0x01: /* K10 */
{
//uint32_t reg[4];
msr = rdmsr64(K10_COFVID_STATUS);
/*
do_cpuid2(0x00000006, 0, reg);
EffFreq: effective frequency interface
if (bitfield(reg[ecx], 0, 0) == 1)
{
uint64_t aperf = measure_aperf_frequency();
cpuFrequency = aperf;
}
*/
// NOTE: tsc runs at the maccoeff (non turbo)
//*not* at the turbo frequency.
maxcoef = bitfield(msr, 54, 49) / 2 + 4;
currcoef = bitfield(msr, 5, 0) + 0x10;
currdiv = 2 << bitfield(msr, 8, 6);
break;
}
case 0x05: /* K14 */
msr = rdmsr64(K10_COFVID_STATUS);
currcoef = (bitfield(msr, 54, 49) + 0x10) << 2;
currdiv = (bitfield(msr, 8, 4) + 1) << 2;
currdiv += bitfield(msr, 3, 0);
break;
case 0x02: /* K11 */
DBG("K11 detected, but not supported !!!\n");
// not implimented
break;
}
if ((p->CPU.Vendor == 0x756E6547 /* Intel */) &&
if (!fsbFrequency)
{
if (maxcoef)
{
if (currdiv)
{
if (!currcoef) currcoef = maxcoef;
if (!cpuFrequency)
fsbFrequency = ((tscFrequency * currdiv) / currcoef);
else
fsbFrequency = ((cpuFrequency * currdiv) / currcoef);
DBG("%d.%d\n", currcoef / currdiv, ((currcoef % currdiv) * 100) / currdiv);
} else {
if (!cpuFrequency)
fsbFrequency = (tscFrequency / maxcoef);
else
fsbFrequency = (cpuFrequency / maxcoef);
DBG("%d\n", currcoef);
}
}
else if (currcoef)
{
if (currdiv)
{
fsbFrequency = ((tscFrequency * currdiv) / currcoef);
DBG("%d.%d\n", currcoef / currdiv, ((currcoef % currdiv) * 100) / currdiv);
} else {
fsbFrequency = (tscFrequency / currcoef);
DBG("%d\n", currcoef);
}
}
}
}
#else
if ((p->CPU.Vendor == 0x756E6547 /* Intel */) &&
((p->CPU.Family == 0x06) ||
(p->CPU.Family == 0x0f)))
{
DBG("msr(%d): platform_info %08x\n", __LINE__, msr & 0xffffffff);
#endif
bus_ratio_max = (msr >> 8) & 0xff;
bus_ratio_min = (msr >> 40) & 0xff; //valv: not sure about this one (Remarq.1)
bus_ratio_min = (msr >> 40) & 0xff;
msr = rdmsr64(MSR_FLEX_RATIO);
#if DEBUG_CPU
DBG("msr(%d): flex_ratio %08x\n", __LINE__, msr & 0xffffffff);
}
}
}
#if OLD_STYLE
#if LEGACY_CPU
if (bus_ratio_max)
{
fsbFrequency = (tscFrequency / bus_ratio_max);
}
else
{
#if OLD_STYLE
#if LEGACY_CPU
cpuFrequency = tscFrequency;
#else
cpuFrequency = bus_ratio_max * fsbFrequency;
maxdiv = (msr >> 46) & 0x01;
/* Non-integer bus ratio for the current-multi (undocumented)*/
currdiv = (msr >> 14) & 0x01;
if ((p->CPU.Family == 0x06 && p->CPU.Model >= 0x0e) ||
(p->CPU.Family == 0x0f)) // This will always be model >= 3
{
/* XXX */
maxcoef = currcoef;
}
#if OLD_STYLE
if (!currcoef) currcoef = maxcoef;
#if LEGACY_CPU
if (maxcoef)
{
{
if (maxdiv)
{
fsbFrequency = ((tscFrequency * 2) / ((maxcoef * 2) + 1));
#endif
}
#else
if (currdiv)
{
cpuFrequency = (fsbFrequency * ((currcoef * 2) + 1) / 2);
{
tscFrequency = fsbFrequency * maxcoef;
}
}
}
#if DEBUG_CPU
DBG("max: %d%s current: %d%s\n", maxcoef, maxdiv ? ".5" : "",currcoef, currdiv ? ".5" : "");
#endif
#endif // OLD_STYLE
#endif // LEGACY_CPU
}
}
p->CPU.isMobile = (rdmsr64(0x17) & (1 << 28));
break;
}
// TODO: this part of code seems to work very well for the intel platforms, need to find the equivalent for AMD
DBG("%s platform found.\n", p->CPU.isMobile?"Mobile":"Desktop");
}
#endif
if (!cpuFrequency) cpuFrequency = tscFrequency;
p->CPU.MaxCoef = maxcoef;
p->CPU.MaxDiv = maxdiv;
p->CPU.CurrCoef = currcoef;
p->CPU.CurrDiv = currdiv;
//p->CPU.TSCFrequency = (tscFrequency / 1000000) * 1000000;
//p->CPU.FSBFrequency = (fsbFrequency / 1000000) * 1000000;
//p->CPU.CPUFrequency = (cpuFrequency / 1000000) * 1000000;
p->CPU.TSCFrequency = tscFrequency ;
p->CPU.FSBFrequency = fsbFrequency ;
p->CPU.CPUFrequency = cpuFrequency ;
#ifdef AMD_SUPPORT
msglog("AMD CPU Detection Enabled\n");
#endif
DBG("CPU: Vendor/Model/ExtModel: 0x%x/0x%x/0x%x\n", p->CPU.Vendor, p->CPU.Model, p->CPU.ExtModel);
DBG("CPU: Family/ExtFamily: 0x%x/0x%x\n", p->CPU.Family, p->CPU.ExtFamily);
DBG("CPU: TSCFreq: %dMHz\n", p->CPU.TSCFrequency / 1000000);
if(p->CPU.Vendor == 0x756E6547 /* Intel */)
{
DBG("CPU: FSBFreq: %dMHz\n", p->CPU.FSBFrequency / 1000000);
DBG("CPU: CPUFreq: %dMHz\n", p->CPU.CPUFrequency / 1000000);
DBG("CPU: MaxCoef/CurrCoef: 0x%x/0x%x\n", p->CPU.MaxCoef, p->CPU.CurrCoef);
DBG("CPU: MaxDiv/CurrDiv: 0x%x/0x%x\n", p->CPU.MaxDiv, p->CPU.CurrDiv);
}
#ifdef AMD_SUPPORT
DBG("CPU (AMD): TSCFreq: %dMHz\n", p->CPU.TSCFrequency / 1000000);
DBG("CPU (AMD): FSBFreq: %dMHz\n", p->CPU.FSBFrequency / 1000000);
DBG("CPU (AMD): CPUFreq: %dMHz\n", p->CPU.CPUFrequency / 1000000);
DBG("CPU (AMD): MaxCoef/CurrCoef: 0x%x/0x%x\n", p->CPU.MaxCoef, p->CPU.CurrCoef);
DBG("CPU (AMD): MaxDiv/CurrDiv: 0x%x/0x%x\n", p->CPU.MaxDiv, p->CPU.CurrDiv);
#else
DBG("CPU: TSCFreq: %dMHz\n", p->CPU.TSCFrequency / 1000000);
DBG("CPU: FSBFreq: %dMHz\n", p->CPU.FSBFrequency / 1000000);
DBG("CPU: CPUFreq: %dMHz\n", p->CPU.CPUFrequency / 1000000);
DBG("CPU: MaxCoef/CurrCoef: 0x%x/0x%x\n", p->CPU.MaxCoef, p->CPU.CurrCoef);
DBG("CPU: MaxDiv/CurrDiv: 0x%x/0x%x\n", p->CPU.MaxDiv, p->CPU.CurrDiv);
#endif
DBG("CPU: NoCores/NoThreads: %d/%d\n", p->CPU.NoCores, p->CPU.NoThreads);
DBG("CPU: Features: 0x%08x\n", p->CPU.Features);
DBG("CPU: ExtFeatures: 0x%08x\n", p->CPU.ExtFeatures);
DBG("CPU: ExtFeatures: 0x%08x\n", p->CPU.ExtFeatures);
#ifndef AMD_SUPPORT
DBG("CPU: MicrocodeVersion: %d\n", p->CPU.MicrocodeVersion);
#endif
#if DEBUG_CPU
pause();
pause();
#endif
}
branches/cparm/i386/libsaio/platform.h
131131
132132
133133
134
134135
135136
136137
boolean_tfine_grain_clock_mod;
uint32_t cpuid_max_basic;
uint32_t cpuid_max_ext;
uint32_tsub_Cstates;
uint32_t extensions;
branches/cparm/i386/libsaio/acpi_tools.c
8989
9090
9191
92
92
9393
9494
9595
......
192192
193193
194194
195
195196
196197
197198
198199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
199220
200221
201222
......
210231
211232
212233
234
213235
214236
215
216237
217238
218239
......
259280
260281
261282
262
283
263284
264285
265286
// Init memory address as F000 segment and scan 64KB region
if (!success)
success = GetRsdtPointer((void *)0x0F0000, 0x10000, acpi_tables);
if (!success)
return (0ul);
// Procedure: GetTablePtr64 - Find ACPI table in XSDT with input signature.
//
//-------------------------------------------------------------------------------
#if 0
static ACPI_TABLE_HEADER *GetTablePtr64(ACPI_TABLE_XSDT * xsdt, U32 signature)
{
U32 index;
U32 num_tables;
ACPI_TABLE_HEADER *table = (ACPI_TABLE_HEADER *) xsdt->TableOffsetEntry;
// Compute number of table pointers included in XSDT
num_tables = get_num_tables64(xsdt);
for (index = 0; index < num_tables; index++) {
if (((U32) (table->Signature) == signature) &&
(GetChecksum(table, table->Length) == 0)) {
return (table);
}
// Move array pointer to next 64-bit pointer
table = (ACPI_TABLE_HEADER *) ((U32) table + sizeof(U64));
}
return (0);
}
#else
static ACPI_TABLE_HEADER *GetTablePtr64(ACPI_TABLE_XSDT * xsdt, U32 signature)
{
U32 index;
U32 num_tables;
// Compute number of table pointers included in XSDT
num_tables = get_num_tables64(xsdt);
}
return (0);
}
#endif
//-------------------------------------------------------------------------------
//
// Procedure: GetChecksum - Performs byte checksum
// RSD pointer structure checksum okay, lookup the RSDT pointer.
acpi_tables->RsdPointer = (ACPI_TABLE_RSDP *)current;
acpi_tables->RsdtPointer = (ACPI_TABLE_RSDT *) acpi_tables->RsdPointer->RsdtPhysicalAddress;
if ((acpi_tables->RsdPointer != 0) && (acpi_tables->RsdtPointer != 0))
if ((acpi_tables->RsdPointer != (void*)0ul) && (acpi_tables->RsdtPointer != (void*)0ul))
return (1ul);
else
return (0ul);
branches/cparm/i386/libsaio/ppm.h
138138
139139
140140
141
141142
142143
143
144
144145
145146
146147
......
196197
197198
198199
200
199201
202
200203
201204
202205
typedef enum cpu_cstate {
CPU_C1 = 1,
//CPU_C2 = 2,
CPU_C3_ACPI_C2 = 3,
CPU_C3_ACPI_C3 = 4,
CPU_C3_ACPI_C4 = 5,
CPU_C4 = 5,
CPU_C6 = 6,
CPU_C7 = 7,
} CPU_CSTATE;
U32 package_cstate_limit;
U32 core_c1_supported;
U32 core_c2_supported;
U32 core_c3_supported;
U32 core_c4_supported;
U32 core_c6_supported;
U32 core_c7_supported;
U32 mwait_supported;
branches/cparm/i386/libsaio/saio_types.h
236236
237237
238238
239
240
241
242
243
244
245
246
247
248
249
250239
251240
252241
//#define BIOS_DEV_TYPE(d) ((d) & kBIOSDevTypeMask)
#define BIOS_DEV_UNIT(bvr) ((bvr)->biosdev - (bvr)->type)
/*
* KernBootStruct device types.
*/
/*
enum {
DEV_SD = 0,
DEV_HD = 1,
DEV_FD = 2,
DEV_EN = 3
};
*/
#ifndef max
#define max(a,b) ((a) > (b) ? (a) : (b))
#endif
branches/cparm/i386/libsaio/fake_efi.c
429429
430430
431431
432
432433
434
435
433436
434
435437
436438
437439
......
469471
470472
471473
472
474
473475
474476
475477
......
708710
709711
710712
711
713
714
715
712716
713
714
717
718
715719
716720
717
721
718722
719723
720
724
725
726
721727
722728
723729
......
928934
929935
930936
937
931938
932939
933940
......
939946
940947
941948
942
943
949
950
944951
945952
946
953
947954
948
955
949956
950
951
957
952958
953959
954960
......
970976
971977
972978
973
979
980
974981
975982
976983
*/
/* These should be const but DT__AddProperty takes char* */
#if UNUSED
static const char const TSC_Frequency_prop[] = "TSCFrequency";
static const char const CPU_Frequency_prop[] = "CPUFrequency";
#endif
static const char const FSB_Frequency_prop[] = "FSBFrequency";
static const char const CPU_Frequency_prop[] = "CPUFrequency";
/*==========================================================================
* SMBIOS
{
EFI_STATUS ret = EFI_UNSUPPORTED;
execute_hook("setupEfiConfigurationTable", &ret, NULL, NULL, NULL, NULL, NULL);
execute_hook("setupAcpiEfi", &ret, NULL, NULL, NULL, NULL, NULL);
if (ret != EFI_SUCCESS)
{
DT__AddProperty(chosenNode, "boot-args", strlen(bootArgs->CommandLine)+1, (EFI_CHAR16*)bootArgs->CommandLine);
if (uuidSet &&bootInfo->uuidStr[0])
// "boot-uuid" MAIN GOAL IS SYMPLY TO BOOT FROM THE UUID SET IN THE DT AND DECREASE BOOT TIME, SEE IOKitBSDInit.cpp
// additionally this value can be used by third-party apps or osx components (ex: pre-10.7 kextcache, ...)
if (bootInfo->uuidStr[0])
DT__AddProperty(chosenNode, kBootUUIDKey, strlen(bootInfo->uuidStr)+1, bootInfo->uuidStr);
/*if (gRootPath[0])
#if 0
if (gRootPath[0])
{
DT__AddProperty(chosenNode, "rootpath", 256, gRootPath);
DT__AddProperty(chosenNode, "rootpath" or try "root-matching", strlen(gRootPath)+1, gRootPath);
}
else */if (gRootDevice)
else
#endif
if (gRootDevice)
{
DT__AddProperty(chosenNode, "boot-device-path", strlen(gRootDevice)+1, gRootDevice);
if (smbios_p)
addConfigurationTable(&gEfiSmbiosTableGuid, &smbios_p, NULL);
if (Platform->CPU.Vendor == 0x756E6547 /* Intel */)
{
int num_cpus;
addConfigurationTable(&gEfiMpsTableGuid, &mps, NULL);
}
#if DEBUG_ACPI
#if DEBUG_EFI
if (num_cpus != Platform->CPU.NoCores)
{
DBG("Warning: SMP nb of core mismatch with the value found in cpu.c \n");
printf("Warning: SMP nb of core (%d) mismatch with the value found in cpu.c (%d) \n",num_cpus,Platform->CPU.NoCores);
}
#endif
#endif
}
// PM_Model
if (Platform->CPU.isServer == true)
{
setup_acpi();
setup_machine_signature();
// We now have to write the systemm-type in ioregs: we cannot do it before in setupDeviceTree()
// We now have to write the system-type in ioregs: we cannot do it before in setupDeviceTree()
// because we need to take care of facp original content, if it is correct.
setupSystemType();
branches/cparm/i386/boot0/boot0.s
6060
6161
6262
63
64
65
66
67
6368
6469
6570
......
230235
231236
232237
238
239
240
241
233242
234243
235244
......
775784
776785
777786
778
787
779788
789
790
791
792
793
794
795
796
797
798
799
800
780801
781802
782803
783804
784805
806
807
808
809
785810
786811
787812
VERBOSEEQU 1
;
; Set to 1 to enable unstretch mode (WARNING: Verbose and Debug must be disabled)
;
UNSTRETCHEQU 0
;
; Various constants.
;
kBoot0SegmentEQU 0x0000
call print_hex
%endif
%if UNSTRETCH
call disable_scaler
%endif
;
; Since this code may not always reside in the MBR, always start by
; loading the MBR to kMBRBuffer and LBA1 to kGPTBuffer.
ret
%endif ;DEBUG
%if UNSTRETCH
;--------------------------------------------------------------------------
; Disable On-Chip Scaling for nVidia Cards
;
disable_scaler:
mov ax,4F14h ;VESA VBE OEM function
mov bl,2 ;Subfunction 02 = Set Panel Expansion/Centering
mov bh,1 ;00 = Return Current Setting, 01 = Set Centering/Expansion
mov cx,0001h ;Exp. mode: 00 = Scaled, 01 = Centered 1:1, 02 = Left Corner 1:1
int 10h ;call VGA/VBE service
LogString(nv_scaler_str)
ret
%endif
;--------------------------------------------------------------------------
; NULL terminated strings.
;
log_title_strdb 10, 13, 'boot0: ', 0
boot_error_str db 'error', 0
%if UNSTRETCH
nv_scaler_strdb 'Unstretch', 0
%endif ;DEBUG
%if VERBOSE
gpt_strdb 'GPT', 0
test_strdb 'test', 0
branches/cparm/i386/boot0/boot0md.s
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
; 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@
;
; Boot Loader: boot0
;
; A small boot sector program written in x86 assembly whose only
; responsibility is to locate the active partition, load the
; partition booter into memory, and jump to the booter's entry point.
; It leaves the boot drive in DL and a pointer to the partition entry in SI.
;
; This boot loader must be placed in the Master Boot Record.
;
; In order to coexist with a fdisk partition table (64 bytes), and
; leave room for a two byte signature (0xAA55) in the end, boot0 is
; restricted to 446 bytes (512 - 64 - 2). If boot0 did not have to
; live in the MBR, then we would have 510 bytes to work with.
;
; boot0 is always loaded by the BIOS or another booter to 0:7C00h.
;
; This code is written for the NASM assembler.
; nasm boot0.s -o boot0
;
; This version of boot0 implements hybrid GUID/MBR partition scheme support
;
;
; Turbo added EFI System Partition boot support
;
; Added KillerJK's switchPass2 modifications
;
; dmazar: 10/7/2011 added scanning of all BIOS accessible drives:
; - iterates over all drives and searches for HSF bootable partition (with boot1h)
; and loads from it
; - if not found, itarates over drives again and searches for active partition and
; loads from it
;
;
; Set to 1 to enable obscure debug messages.
;
DEBUGEQU 0
;
; Set to 1 to enable verbose mode
;
VERBOSEEQU 1
;
; Various constants.
;
kBoot0SegmentEQU 0x0000
kBoot0StackEQU 0xFFF0; boot0 stack pointer
kBoot0LoadAddrEQU 0x7C00; boot0 load address
kBoot0RelocAddrEQU 0xE000; boot0 relocated address
kMBRBufferEQU 0x1000; MBR buffer address
kLBA1BufferEQU 0x1200; LBA1 - GPT Partition Table Header buffer address
kGPTABufferEQU 0x1400; GUID Partition Entry Array buffer address
kPartTableOffsetEQU 0x1be
kMBRPartTableEQU kMBRBuffer + kPartTableOffset
kSectorBytesEQU 512; sector size in bytes
kBootSignatureEQU 0xAA55; boot sector signature
kHFSPSignatureEQU 'H+'; HFS+ volume signature
kHFSPCaseSignatureEQU 'HX'; HFS+ volume case-sensitive signature
kFAT32BootCodeOffset EQU 0x5a; offset of boot code in FAT32 boot sector
kBoot1FAT32MagicEQU 'BO'; Magic string to detect our boot1f32 code
kGPTSignatureLowEQU 'EFI '; GUID Partition Table Header Signature
kGPTSignatureHighEQU 'PART'
kGUIDLastDwordOffsEQU 12; last 4 byte offset of a GUID
kPartCountEQU 4; number of paritions per table
kPartTypeHFSEQU 0xaf; HFS+ Filesystem type
kPartTypePMBREQU 0xee; On all GUID Partition Table disks a Protective MBR (PMBR)
; in LBA 0 (that is, the first block) precedes the
; GUID Partition Table Header to maintain compatibility
; with existing tools that do not understand GPT partition structures.
; The Protective MBR has the same format as a legacy MBR
; and contains one partition entry with an OSType set to 0xEE
; reserving the entire space used on the disk by the GPT partitions,
; including all headers.
kPartActive EQU 0x80; active flag enabled
kPartInactive EQU 0x00; active flag disabled
kHFSGUID EQU 0x48465300; first 4 bytes of Apple HFS Partition Type GUID.
kAppleGUIDEQU 0xACEC4365; last 4 bytes of Apple type GUIDs.
kEFISystemGUIDEQU 0x3BC93EC9; last 4 bytes of EFI System Partition Type GUID:
; C12A7328-F81F-11D2-BA4B-00A0C93EC93B
%ifdef FLOPPY
kDriveNumberEQU 0x00
%else
kDriveNumberEQU 0x80
%endif
;
; Format of fdisk partition entry.
;
; The symbol 'part_size' is automatically defined as an `EQU'
; giving the size of the structure.
;
struc part
.bootid resb 1 ; bootable or not
.head resb 1 ; starting head, sector, cylinder
.sect resb 1 ;
.cyl resb 1 ;
.type resb 1 ; partition type
.endhead resb 1 ; ending head, sector, cylinder
.endsect resb 1 ;
.endcyl resb 1 ;
.lba resd 1 ; starting lba
.sectors resd 1 ; size in sectors
endstruc
;
; Format of GPT Partition Table Header
;
strucgpth
.Signature resb8
.Revision resb4
.HeaderSizeresb4
.HeaderCRC32resb4
.Reservedresb4
.MyLBAresb8
.AlternateLBAresb8
.FirstUsableLBAresb8
.LastUsableLBAresb8
.DiskGUIDresb16
.PartitionEntryLBAresb8
.NumberOfPartitionEntriesresb4
.SizeOfPartitionEntryresb4
.PartitionEntryArrayCRC32resb4
endstruc
;
; Format of GUID Partition Entry Array
;
strucgpta
.PartitionTypeGUIDresb16
.UniquePartitionGUIDresb16
.StartingLBAresb8
.EndingLBAresb8
.Attributesresb8
.PartitionNameresb72
endstruc
;
; Macros.
;
%macro DebugCharMacro 1
mov al, %1
call print_char
%endmacro
%macro LogString 1
mov di, %1
call log_string
%endmacro
%if DEBUG
%define DebugChar(x) DebugCharMacro x
%else
%define DebugChar(x)
%endif
;--------------------------------------------------------------------------
; Start of text segment.
SEGMENT .text
ORG kBoot0RelocAddr
;--------------------------------------------------------------------------
; Boot code is loaded at 0:7C00h.
;
start:
;
; Set up the stack to grow down from kBoot0Segment:kBoot0Stack.
; Interrupts should be off while the stack is being manipulated.
;
cli ; interrupts off
xor ax, ax ; zero ax
mov ss, ax ; ss <- 0
mov sp, kBoot0Stack ; sp <- top of stack
sti ; reenable interrupts
mov es, ax ; es <- 0
mov ds, ax ; ds <- 0
;
; Relocate boot0 code.
;
mov si, kBoot0LoadAddr ; si <- source
mov di, kBoot0RelocAddr ; di <- destination
cld ; auto-increment SI and/or DI registers
mov cx, kSectorBytes/2 ; copy 256 words
repnz movsw ; repeat string move (word) operation
;
; Code relocated, jump to start_reloc in relocated location.
;
jmp kBoot0Segment:start_reloc
;--------------------------------------------------------------------------
; Start execution from the relocated location.
;
start_reloc:
pushdx; save dl (boot drive) for second pass.
; will stay on stack if booter loaded in first pass.
; this should not be a problem
movbh, 1; BH = 1. two pass scanning (active or hfs partition).
; actuall use of it (scanning) is in find_boot
scan_drives:
DebugChar('>')
%if DEBUG
mov al, dl
call print_hex
%endif
;
; Since this code may not always reside in the MBR, always start by
; loading the MBR to kMBRBuffer and LBA1 to kGPTBuffer.
;
pushbx; save BH (scan pass counter)
xor eax, eax
mov [my_lba], eax; store LBA sector 0 for read_lba function
mov al, 2; load two sectors: MBR and LBA1
mov bx, kMBRBuffer; MBR load address
call load
popbx; restore BH
jc .mbr_load_error; MBR load error - normally because we scanned all drives
;
; Look for the booter partition in the MBR partition table,
; which is at offset kMBRPartTable.
;
mov si, kMBRPartTable; pointer to partition table
call find_boot; will not return on success
; if returns - booter partition not found
; try next drive
; if next drive does not exists - will break on above MBR load error
incdl
jmpscan_drives
.mbr_load_error:
; all drives scanned - see if we need to run second pass
popdx; restore orig boot drive
decbh; decrement scan pass counter
jzscan_drives; if zero - run seccond pass
; we ran two passes - nothing found - error
error:
LogString(boot_error_str)
hang:
hlt
jmp hang
;--------------------------------------------------------------------------
; Find the active (boot) partition and load the booter from the partition.
;
; Arguments:
; DL = drive number (0x80 + unit number)
; SI = pointer to fdisk partition table.
; BH = pass counter (1=first pass, 0=second pass)
;
; Clobber list:
; EAX, BX, EBP
;
find_boot:
;
; Check for boot block signature 0xAA55 following the 4 partition
; entries.
;
cmp WORD [si + part_size * kPartCount], kBootSignature
jne .exit ; boot signature not found.
xor bl, bl; BL will be set to 1 later in case of
; Protective MBR has been found
.start_scan:
mov cx, kPartCount ; number of partition entries per table
.loop:
;
; First scan through the partition table looking for the active
; partition.
;
%if DEBUG
mov al, [si + part.type] ; print partition type
call print_hex
%endif
mov eax, [si + part.lba]; save starting LBA of current
mov [my_lba], eax; MBR partition entry for read_lba function
cmp BYTE [si + part.type], 0; unused partition?
je .continue ; skip to next entry
cmp BYTE [si + part.type], kPartTypePMBR; check for Protective MBR
jne .testPass
mov BYTE [si + part.bootid], kPartInactive; found Protective MBR
; clear active flag to make sure this protective
; partition won't be used as a bootable partition.
mov bl, 1; Assume we can deal with GPT but try to scan
; later if not found any other bootable partitions.
.testPass:
cmp bh, 1
jne .Pass2
.Pass1:
cmp BYTE [si + part.type], kPartTypeHFS; In pass 1 we're going to find a HFS+ partition
; equipped with boot1h in its boot record
; regardless if it's active or not.
jne .continue
movdh, 1 ; Argument for loadBootSector to check HFS+ partition signature.
jmp .tryToBoot
.Pass2:
cmp BYTE [si + part.bootid], kPartActive; In pass 2 we are walking on the standard path
; by trying to hop on the active partition.
jne .continue
xordh, dh ; Argument for loadBootSector to skip HFS+ partition
; signature check.
DebugChar('*')
;
; Found boot partition, read boot sector to memory.
;
.tryToBoot:
call loadBootSector
jne .continue
jmp SHORT initBootLoader
.continue:
add si, BYTE part_size ; advance SI to next partition entry
loop .loop ; loop through all partition entries
;
; Scanned all partitions but not found any with active flag enabled
; Anyway if we found a protective MBR before we still have a chance
; for a possible GPT Header at LBA 1
;
dec bl
jnz .exit; didn't find Protective MBR before
call checkGPT
.exit:
ret; Giving up.
;
; Jump to partition booter. The drive number is already in register DL.
; SI is pointing to the modified partition entry.
;
initBootLoader:
DebugChar('J')
%if VERBOSE
LogString(done_str)
%endif
jmp kBoot0LoadAddr
;
; Found Protective MBR Partition Type: 0xEE
; Check for 'EFI PART' string at the beginning
; of LBA1 for possible GPT Table Header
;
checkGPT:
push bx
mov di, kLBA1Buffer; address of GUID Partition Table Header
cmp DWORD [di], kGPTSignatureLow; looking for 'EFI '
jne .exit; not found. Giving up.
cmp DWORD [di + 4], kGPTSignatureHigh ; looking for 'PART'
jne .exit; not found. Giving up indeed.
mov si, di
;
; Loading GUID Partition Table Array
;
mov eax, [si + gpth.PartitionEntryLBA] ; starting LBA of GPT Array
mov [my_lba], eax; save starting LBA for read_lba function
mov cx, [si + gpth.NumberOfPartitionEntries]; number of GUID Partition Array entries
mov bx, [si + gpth.SizeOfPartitionEntry]; size of GUID Partition Array entry
push bx; push size of GUID Partition entry
;
; Calculating number of sectors we need to read for loading a GPT Array
;
; push dx; preserve DX (DL = BIOS drive unit number)
; mov ax, cx; AX * BX = number of entries * size of one entry
; mul bx; AX = total byte size of GPT Array
; pop dx; restore DX
; shr ax, 9; convert to sectors
;
; ... or:
; Current GPT Arrays uses 128 partition entries each 128 bytes long
; 128 entries * 128 bytes long GPT Array entries / 512 bytes per sector = 32 sectors
;
moval, 32; maximum sector size of GPT Array (hardcoded method)
mov bx, kGPTABuffer
push bx; push address of GPT Array
call load; read GPT Array
pop si; SI = address of GPT Array
pop bx; BX = size of GUID Partition Array entry
jc error
;
; Walk through GUID Partition Table Array
; and load boot record from first available HFS+ partition.
;
; If it has boot signature (0xAA55) then jump to it
; otherwise skip to next partition.
;
%if VERBOSE
LogString(gpt_str)
%endif
.gpt_loop:
mov eax, [si + gpta.PartitionTypeGUID + kGUIDLastDwordOffs]
cmpeax, kAppleGUID; check current GUID Partition for Apple's GUID type
je.gpt_ok
;
; Turbo - also try EFI System Partition
;
cmpeax, kEFISystemGUID; check current GUID Partition for EFI System Partition GUID type
jne.gpt_continue
.gpt_ok:
;
; Found HFS Partition
;
mov eax, [si + gpta.StartingLBA]; load boot sector from StartingLBA
mov [my_lba], eax
movdh, 1; Argument for loadBootSector to check HFS+ partition signature.
call loadBootSector
jne .gpt_continue; no boot loader signature
mov si, kMBRPartTable; fake the current GUID Partition
mov [si + part.lba], eax; as MBR style partition for boot1h
mov BYTE [si + part.type], kPartTypeHFS; with HFS+ filesystem type (0xAF)
jmp SHORT initBootLoader
.gpt_continue:
add si, bx; advance SI to next partition entry
loop .gpt_loop; loop through all partition entries
.exit:
pop bx
ret; no more GUID partitions. Giving up.
;--------------------------------------------------------------------------
; loadBootSector - Load boot sector
;
; Arguments:
; DL = drive number (0x80 + unit number)
; DH = 0 skip HFS+ partition signature checking
; 1 enable HFS+ partition signature checking
; [my_lba] = starting LBA.
;
; Returns:
; ZF = 0 if boot sector hasn't kBootSignature
; 1 if boot sector has kBootSignature
;
loadBootSector:
pusha
mov al, 3
mov bx, kBoot0LoadAddr
call load
jc error
ordh, dh
jz.checkBootSignature
.checkHFSSignature:
%if VERBOSE
;LogString(test_str); dmazar: removed to get space
%endif
;
; Looking for HFSPlus ('H+') or HFSPlus case-sensitive ('HX') signature.
;
movax, [kBoot0LoadAddr + 2 * kSectorBytes]
cmp ax, kHFSPSignature; 'H+'
je.checkBootSignature
cmpax, kHFSPCaseSignature; 'HX'
je.checkBootSignature
;
; Looking for boot1f32 magic string.
;
movax, [kBoot0LoadAddr + kFAT32BootCodeOffset]
cmpax, kBoot1FAT32Magic
jne .exit
.checkBootSignature:
;
; Check for boot block signature 0xAA55
;
mov di, bx
cmp WORD [di + kSectorBytes - 2], kBootSignature
.exit:
popa
ret
;--------------------------------------------------------------------------
; load - Load one or more sectors from a partition.
;
; Arguments:
; AL = number of 512-byte sectors to read.
; ES:BX = pointer to where the sectors should be stored.
; DL = drive number (0x80 + unit number)
; [my_lba] = starting LBA.
;
; Returns:
; CF = 0 success
; 1 error
;
load:
push cx
.ebios:
mov cx, 5 ; load retry count
.ebios_loop:
call read_lba ; use INT13/F42
jnc .exit
loop .ebios_loop
.exit:
pop cx
ret
;--------------------------------------------------------------------------
; read_lba - Read sectors from a partition using LBA addressing.
;
; Arguments:
; AL = number of 512-byte sectors to read (valid from 1-127).
; ES:BX = pointer to where the sectors should be stored.
; DL = drive number (0x80 + unit number)
; [my_lba] = starting LBA.
;
; Returns:
; CF = 0 success
; 1 error
;
read_lba:
pushad ; save all registers
mov bp, sp ; save current SP
;
; Create the Disk Address Packet structure for the
; INT13/F42 (Extended Read Sectors) on the stack.
;
; push DWORD 0 ; offset 12, upper 32-bit LBA
push ds ; For sake of saving memory,
push ds ; push DS register, which is 0.
mov ecx, [my_lba] ; offset 8, lower 32-bit LBA
push ecx
push es ; offset 6, memory segment
push bx ; offset 4, memory offset
xor ah, ah ; offset 3, must be 0
push ax ; offset 2, number of sectors
; It pushes 2 bytes with a smaller opcode than if WORD was used
push BYTE 16 ; offset 0-1, packet size
DebugChar('<')
%if DEBUG
mov eax, ecx
call print_hex
%endif
;
; INT13 Func 42 - Extended Read Sectors
;
; Arguments:
; AH = 0x42
; DL = drive number (80h + drive unit)
; DS:SI = pointer to Disk Address Packet
;
; Returns:
; AH = return status (sucess is 0)
; carry = 0 success
; 1 error
;
; Packet offset 2 indicates the number of sectors read
; successfully.
;
mov si, sp
mov ah, 0x42
int 0x13
jnc .exit
DebugChar('R') ; indicate INT13/F42 error
;
; Issue a disk reset on error.
; Should this be changed to Func 0xD to skip the diskette controller
; reset?
;
xor ax, ax ; Func 0
int 0x13 ; INT 13
stc ; set carry to indicate error
.exit:
mov sp, bp ; restore SP
popad
ret
;--------------------------------------------------------------------------
; Write a string with 'boot0: ' prefix to the console.
;
; Arguments:
; ES:DI pointer to a NULL terminated string.
;
; Clobber list:
; DI
;
log_string:
pusha
pushdi
movsi, log_title_str
callprint_string
popsi
callprint_string
popa
ret
;--------------------------------------------------------------------------
; Write a string to the console.
;
; Arguments:
; DS:SI pointer to a NULL terminated string.
;
; Clobber list:
; AX, BX, SI
;
print_string:
mov bx, 1 ; BH=0, BL=1 (blue)
cld ; increment SI after each lodsb call
.loop:
lodsb ; load a byte from DS:SI into AL
cmp al, 0 ; Is it a NULL?
je .exit ; yes, all done
mov ah, 0xE ; INT10 Func 0xE
int 0x10 ; display byte in tty mode
jmp short .loop
.exit:
ret
%if DEBUG
;--------------------------------------------------------------------------
; Write a ASCII character to the console.
;
; Arguments:
; AL = ASCII character.
;
print_char:
pusha
mov bx, 1 ; BH=0, BL=1 (blue)
mov ah, 0x0e ; bios INT 10, Function 0xE
int 0x10 ; display byte in tty mode
popa
ret
;--------------------------------------------------------------------------
; Write the 4-byte value to the console in hex.
;
; Arguments:
; EAX = Value to be displayed in hex.
;
print_hex:
pushad
mov cx, WORD 4
bswap eax
.loop:
push ax
ror al, 4
call print_nibble ; display upper nibble
pop ax
call print_nibble ; display lower nibble
ror eax, 8
loop .loop
mov al, 10 ; carriage return
call print_char
mov al, 13
call print_char
popad
ret
print_nibble:
and al, 0x0f
add al, '0'
cmp al, '9'
jna .print_ascii
add al, 'A' - '9' - 1
.print_ascii:
call print_char
ret
getc:
pusha
mov ah, 0
int 0x16
popa
ret
%endif ;DEBUG
;--------------------------------------------------------------------------
; NULL terminated strings.
;
log_title_strdb 10, 13, 'boot0: ', 0
boot_error_str db 'error', 0
%if VERBOSE
gpt_strdb 'GPT', 0
;test_strdb 'test', 0
done_strdb 'done', 0
%endif
;--------------------------------------------------------------------------
; Pad the rest of the 512 byte sized booter with zeroes. The last
; two bytes is the mandatory boot sector signature.
;
; If the booter code becomes too large, then nasm will complain
; that the 'times' argument is negative.
;
; According to EFI specification, maximum boot code size is 440 bytes
;
pad_boot:
times 440-($-$$) db 0
pad_table_and_sig:
times 510-($-$$) db 0
dw kBootSignature
ABSOLUTE 0xE400
;
; In memory variables.
;
my_lbaresd1; Starting LBA for read_lba function
; END
branches/cparm/i386/boot0/Makefile
66
77
88
9
9
1010
1111
1212
......
1717
1818
1919
20
21
22
2023
21
24
2225
2326
2427
INSTALLDIR = $(DSTROOT)/usr/standalone/i386
DIRS_NEEDED = $(SYMROOT)
all embedtheme: $(DIRS_NEEDED) boot0 boot0hfs chain0
all embedtheme: $(DIRS_NEEDED) boot0 boot0hfs chain0 boot0md
boot0: boot0.s Makefile $(NASM)
$(NASM) boot0.s -o $(SYMROOT)/$@
chain0: chain0.s Makefile $(NASM)
$(NASM) chain0.s -o $(SYMROOT)/$@
boot0md: boot0md.s Makefile $(NASM)
$(NASM) boot0md.s -o $(SYMROOT)/$@
install_i386:: all $(INSTALLDIR)
cp $(SYMROOT)/boot0 $(SYMROOT)/chain0 $(INSTALLDIR)
cp $(SYMROOT)/boot0 $(SYMROOT)/chain0 $(SYMROOT)/boot0md $(INSTALLDIR)
cd $(INSTALLDIR); chmod u+w boot0
include ../MakeInc.dir
branches/cparm/i386/boot1/boot1.s
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
; 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@
;
; Partition Boot Loader: boot1h
;
; This program is designed to reside in sector 0+1 of an HFS+ partition.
; It expects that the MBR has left the drive number in DL
; and a pointer to the partition entry in SI.
;
; This version requires a BIOS with EBIOS (LBA) support.
;
; This code is written for the NASM assembler.
; nasm boot1.s -o boot1h
;
; This version of boot1h tries to find a stage2 boot file in the root folder.
;
; NOTE: this is an experimental version with multiple extent support.
;
;
;
; Set to 1 to enable obscure debug messages.
;
DEBUGEQU0
;
; Set to 1 to enable unused code.
;
UNUSEDEQU0
;
; Set to 1 to enable verbose mode.
;
VERBOSEEQU1
;
; Various constants.
;
NULL EQU0
CREQU0x0D
LFEQU0x0A
mallocStartEQU0x1000; start address of local workspace area
maxSectorCountEQU64; maximum sector count for readSectors
maxNodeSizeEQU16384
kSectorBytesEQU512; sector size in bytes
kBootSignatureEQU0xAA55; boot sector signature
kBoot1StackAddressEQU0xFFF0; boot1 stack pointer
kBoot1LoadAddrEQU0x7C00; boot1 load address
kBoot1RelocAddrEQU0xE000; boot1 relocated address
kBoot1Sector1AddrEQUkBoot1RelocAddr + kSectorBytes; boot1 load address for sector 1
kHFSPlusBufferEQUkBoot1Sector1Addr + kSectorBytes; HFS+ Volume Header address
kBoot2SectorsEQU(448 * 1024 - 512) / kSectorBytes; max size of 'boot' file in sectors
kBoot2SegmentEQU0x2000; boot2 load segment
kBoot2AddressEQUkSectorBytes; boot2 load address
;
; Format of fdisk partition entry.
;
; The symbol 'part_size' is automatically defined as an `EQU'
; giving the size of the structure.
;
struc part
.bootidresb 1; bootable or not
.headresb 1; starting head, sector, cylinder
.sectresb 1;
.cylresb 1;
.typeresb 1; partition type
.endheadresb 1; ending head, sector, cylinder
.endsectresb 1;
.endcylresb 1;
.lbaresd 1; starting lba
.sectorsresd 1; size in sectors
endstruc
;-------------------------------------------------------------------------
; HFS+ related structures and constants
;
kHFSPlusSignatureEQU'H+'; HFS+ volume signature
kHFSPlusCaseSignatureEQU'HX'; HFS+ volume case-sensitive signature
kHFSPlusCaseSigXEQU'X'; upper byte of HFS+ volume case-sensitive signature
kHFSPlusExtentDensityEQU8; 8 extent descriptors / extent record
;
; HFSUniStr255
;
strucHFSUniStr255
.lengthresw1
.unicoderesw255
endstruc
;
; HFSPlusExtentDescriptor
;
strucHFSPlusExtentDescriptor
.startBlockresd1
.blockCountresd1
endstruc
;
; HFSPlusForkData
;
strucHFSPlusForkData
.logicalSizeresq1
.clumpSizeresd1
.totalBlocksresd1
.extentsresbkHFSPlusExtentDensity * HFSPlusExtentDescriptor_size
endstruc
;
; HFSPlusVolumeHeader
;
strucHFSPlusVolumeHeader
.signatureresw1
.versionresw1
.attributesresd1
.lastMountedVersion resd1
.journalInfoBlockresd1
.createDateresd1
.modifyDateresd1
.backupDateresd1
.checkedDateresd1
.fileCountresd1
.folderCountresd1
.blockSizeresd1
.totalBlocksresd1
.freeBlocksresd1
.nextAllocationresd1
.rsrcClumpSizeresd1
.dataClumpSizeresd1
.nextCatalogIDresd1
.writeCountresd1
.encodingsBitmapresq1
.finderInforesd8
.allocationFileresbHFSPlusForkData_size
.extentsFileresbHFSPlusForkData_size
.catalogFileresbHFSPlusForkData_size
.attributesFileresbHFSPlusForkData_size
.startupFileresbHFSPlusForkData_size
endstruc
;
; B-tree related structures and constants
;
kBTIndexNodeEQU0
kBTMaxRecordLengthEQU264; sizeof(kHFSPlusFileThreadRecord)
kHFSRootParentIDEQU1; Parent ID of the root folder
kHFSRootFolderIDEQU2; Folder ID of the root folder
kHFSExtentsFileIDEQU3; File ID of the extents overflow file
kHFSCatalogFileIDEQU4; File ID of the catalog file
kHFSPlusFileRecordEQU0x200
kForkTypeDataEQU0
kForkTypeResourceEQU0xFF
;
; BTNodeDescriptor
;
strucBTNodeDescriptor
.fLinkresd1
.bLinkresd1
.kindresb1
.heightresb1
.numRecordsresw1
.reservedresw1
endstruc
;
; BTHeaderRec
;
strucBTHeaderRec
.treeDepthresw1
.rootNoderesd1
.leafRecordsresd1
.firstLeafNoderesd1
.lastLeafNoderesd1
.nodeSizeresw1
.maxKeyLengthresw1
.totalNodesresd1
.freeNodesresd1
.reserved1resw1
.clumpSizeresd1
.btreeTyperesb1
.keyCompareTyperesb1
.attributesresd1
.reserved3resd16
endstruc
;
; BTIndexRec
;
strucBTIndexRec
.childIDresd1
endstruc
;
; HFSPlusCatalogKey
;
strucHFSPlusCatalogKey
;
; won't use the keyLength field for easier addressing data inside this structure
;
;.keyLengthresw1
.parentIDresd1
.nodeNameresbHFSUniStr255_size
endstruc
;
; HFSPlusExtentKey
;
strucHFSPlusExtentKey
;
; won't use the keyLength field for easier addressing data inside this structure
;
;.keyLengthresw1
.forkTyperesb1
.padresb1
.fileIDresd1
.startBlockresd1
endstruc
;
; HFSPlusBSDInfo
;
strucHFSPlusBSDInfo
.ownerIDresd1
.groupIDresd1
.adminFlagsresb1
.ownerFlagsresb1
.fileModeresw1
.specialresd1
endstruc
;
; FileInfo
;
strucFileInfo
.fileTyperesd1
.fileCreatorresd1
.finderFlagsresw1
.locationresw2
.reservedFieldresw1
endstruc
;
; ExtendedFileInfo
;
strucExtendedFileInfo
.reserved1resw4
.extFinderFlagsresw1
.reserved2resw1
.putAwayFolderIDresd1
endstruc
;
; HFSPlusCatalogFile
;
strucHFSPlusCatalogFile
.recordTyperesw1
.flagsresw1
.reserved1resd1
.fileIDresd1
.createDateresd1
.contentModDateresd1
.attributeModDateresd1
.accessDateresd1
.backupDateresd1
.permissionsresbHFSPlusBSDInfo_size
.userInforesbFileInfo_size
.finderInforesbExtendedFileInfo_size
.textEncodingresd1
.reserved2resd1
.dataForkresbHFSPlusForkData_size
.resourceForkresbHFSPlusForkData_size
endstruc
;
; Macros.
;
%macro jmpabs 1
pushWORD %1
ret
%endmacro
%macro DebugCharMacro 1
pushad
moval, %1
callprint_char
callgetc
popad
%endmacro
%macro PrintCharMacro 1
pushad
moval, %1
callprint_char
popad
%endmacro
%macro PutCharMacro 1
callprint_char
%endmacro
%macro PrintHexMacro 1
callprint_hex
%endmacro
%macro PrintString 1
movsi, %1
callprint_string
%endmacro
%macro LogString 1
movdi, %1
calllog_string
%endmacro
%if DEBUG
%define DebugChar(x) DebugCharMacro x
%define PrintChar(x) PrintCharMacro x
%define PutChar(x) PutCharMacro
%define PrintHex(x) PrintHexMacro x
%else
%define DebugChar(x)
%define PrintChar(x)
%define PutChar(x)
%define PrintHex(x)
%endif
;--------------------------------------------------------------------------
; Start of text segment.
SEGMENT .text
ORGkBoot1RelocAddr
;--------------------------------------------------------------------------
; Boot code is loaded at 0:7C00h.
;
start:
;
; Set up the stack to grow down from kBoot1StackSegment:kBoot1StackAddress.
; Interrupts should be off while the stack is being manipulated.
;
cli ; interrupts off
xorax, ax ; zero ax
movss, ax ; ss <- 0
mov sp, kBoot1StackAddress ; sp <- top of stack
sti ; reenable interrupts
mov ds, ax ; ds <- 0
mov es, ax ; es <- 0
;
; Relocate boot1 code.
;
pushsi
movsi, kBoot1LoadAddr; si <- source
movdi, kBoot1RelocAddr; di <- destination
cld; auto-increment SI and/or DI registers
movcx, kSectorBytes; copy 256 words
repmovsb; repeat string move (word) operation
popsi
;
; Code relocated, jump to startReloc in relocated location.
;
; FIXME: Is there any way to instruct NASM to compile a near jump
; using absolute address instead of relative displacement?
;
jmpabsstartReloc
;--------------------------------------------------------------------------
; Start execution from the relocated location.
;
startReloc:
;
; Initializing global variables.
;
mov eax, [si + part.lba]
mov [gPartLBA], eax; save the current partition LBA offset
mov [gBIOSDriveNumber], dl; save BIOS drive number
movWORD [gMallocPtr], mallocStart; set free space pointer
;
; Loading upper 512 bytes of boot1h and HFS+ Volume Header.
;
xorecx, ecx; sector 1 of current partition
incecx
mov al, 2; read 2 sectors: sector 1 of boot1h + HFS+ Volume Header
mov edx, kBoot1Sector1Addr
call readLBA
;
; Initializing more global variables.
;
moveax, [kHFSPlusBuffer + HFSPlusVolumeHeader.blockSize]
bswapeax; convert to little-endian
shreax, 9; convert to sector unit
mov[gBlockSize], eax; save blockSize as little-endian sector unit!
;
; Looking for HFSPlus ('H+') or HFSPlus case-sensitive ('HX') signature.
;
movax, [kHFSPlusBuffer + HFSPlusVolumeHeader.signature]
cmpax, kHFSPlusCaseSignature
jefindRootBoot
cmp ax, kHFSPlusSignature
jne error
;--------------------------------------------------------------------------
; Find stage2 boot file in a HFS+ Volume's root folder.
;
findRootBoot:
moval, kHFSCatalogFileID
leasi, [searchCatalogKey]
leadi, [kHFSPlusBuffer + HFSPlusVolumeHeader.catalogFile + HFSPlusForkData.extents]
calllookUpBTree
jneerror
leasi, [bp + BTree.recordDataPtr]
movsi, [si]
cmpWORD [si], kHFSPlusFileRecord
jneerror
; EAX = Catalog File ID
; BX = read size in sectors
; ECX = file offset in sectors
; EDX = address of read buffer
; DI = address of HFSPlusForkData
;
; Use the second big-endian double-word as the file length in HFSPlusForkData.logicalSize
;
movebx, [si + HFSPlusCatalogFile.dataFork + HFSPlusForkData.logicalSize + 4]
bswapebx; convert file size to little-endian
addebx, kSectorBytes - 1; adjust size before unit conversion
shrebx, 9; convert file size to sector unit
cmpbx, kBoot2Sectors; check if bigger than max stage2 size
jaerror
moveax, [si + HFSPlusCatalogFile.fileID]
bswapeax; convert fileID to little-endian
xorecx, ecx
movedx, (kBoot2Segment << 4) + kBoot2Address
leadi, [si + HFSPlusCatalogFile.dataFork + HFSPlusForkData.extents]
callreadExtent
%if VERBOSE
LogString(root_str)
%endif
boot2:
%if DEBUG
DebugChar ('!')
%endif
%if UNUSED
;
; Waiting for a key press.
;
mov ah, 0
int0x16
%endif
mov dl, [gBIOSDriveNumber]; load BIOS drive number
jmp kBoot2Segment:kBoot2Address
error:
%if VERBOSE
LogString(error_str)
%endif
hang:
hlt
jmp hang
;--------------------------------------------------------------------------
; readSectors - Reads more than 127 sectors using LBA addressing.
;
; Arguments:
; AX = number of 512-byte sectors to read (valid from 1-1280).
; EDX = pointer to where the sectors should be stored.
; ECX = sector offset in partition
;
; Returns:
; CF = 0 success
; 1 error
;
readSectors:
pushad
movbx, ax
.loop:
xoreax, eax; EAX = 0
moval, bl; assume we reached the last block.
cmpbx, maxSectorCount; check if we really reached the last block
jb.readBlock; yes, BX < MaxSectorCount
moval, maxSectorCount; no, read MaxSectorCount
.readBlock:
callreadLBA
subbx, ax; decrease remaning sectors with the read amount
jz.exit; exit if no more sectors left to be loaded
addecx, eax; adjust LBA sector offset
shlax, 9; convert sectors to bytes
addedx, eax; adjust target memory location
jmp.loop; read remaining sectors
.exit:
popad
ret
;--------------------------------------------------------------------------
; readLBA - Read sectors from a partition using LBA addressing.
;
; Arguments:
; AL = number of 512-byte sectors to read (valid from 1-127).
; EDX = pointer to where the sectors should be stored.
; ECX = sector offset in partition
; [bios_drive_number] = drive number (0x80 + unit number)
;
; Returns:
; CF = 0 success
; 1 error
;
readLBA:
pushad ; save all registers
push es; save ES
mov bp, sp ; save current SP
;
; Convert EDX to segment:offset model and set ES:BX
;
; Some BIOSes do not like offset to be negative while reading
; from hard drives. This usually leads to "boot1: error" when trying
; to boot from hard drive, while booting normally from USB flash.
; The routines, responsible for this are apparently different.
; Thus we split linear address slightly differently for these
; capricious BIOSes to make sure offset is always positive.
;
movbx, dx; save offset to BX
andbh, 0x0f; keep low 12 bits
shredx, 4; adjust linear address to segment base
xordl, dl; mask low 8 bits
moves, dx; save segment to ES
;
; Create the Disk Address Packet structure for the
; INT13/F42 (Extended Read Sectors) on the stack.
;
; push DWORD 0 ; offset 12, upper 32-bit LBA
push ds ; For sake of saving memory,
push ds ; push DS register, which is 0.
add ecx, [gPartLBA] ; offset 8, lower 32-bit LBA
push ecx
push es ; offset 6, memory segment
push bx ; offset 4, memory offset
xor ah, ah ; offset 3, must be 0
push ax ; offset 2, number of sectors
push WORD 16 ; offset 0-1, packet size
;
; INT13 Func 42 - Extended Read Sectors
;
; Arguments:
; AH = 0x42
; [bios_drive_number] = drive number (0x80 + unit number)
; DS:SI = pointer to Disk Address Packet
;
; Returns:
; AH = return status (success is 0)
; carry = 0 success
; 1 error
;
; Packet offset 2 indicates the number of sectors read
; successfully.
;
mov dl, [gBIOSDriveNumber]; load BIOS drive number
mov si, sp
mov ah, 0x42
int 0x13
jcerror
;
; Issue a disk reset on error.
; Should this be changed to Func 0xD to skip the diskette controller
; reset?
;
;xor ax, ax ; Func 0
;int 0x13 ; INT 13
;stc ; set carry to indicate error
.exit:
mov sp, bp ; restore SP
pop es; restore ES
popad
ret
%if VERBOSE
;--------------------------------------------------------------------------
; Write a string with 'boot1: ' prefix to the console.
;
; Arguments:
; ES:DI pointer to a NULL terminated string.
;
; Clobber list:
; DI
;
log_string:
pushad
pushdi
movsi, log_title_str
callprint_string
popsi
callprint_string
popad
ret
;-------------------------------------------------------------------------
; Write a string to the console.
;
; Arguments:
; DS:SI pointer to a NULL terminated string.
;
; Clobber list:
; AX, BX, SI
;
print_string:
mov bx, 1 ; BH=0, BL=1 (blue)
.loop:
lodsb ; load a byte from DS:SI into AL
cmp al, 0 ; Is it a NULL?
je .exit ; yes, all done
mov ah, 0xE ; INT10 Func 0xE
int 0x10 ; display byte in tty mode
jmp .loop
.exit:
ret
%endif ; VERBOSE
%if DEBUG
;--------------------------------------------------------------------------
; Write the 4-byte value to the console in hex.
;
; Arguments:
; EAX = Value to be displayed in hex.
;
print_hex:
pushad
mov cx, WORD 4
bswap eax
.loop:
push ax
ror al, 4
call print_nibble ; display upper nibble
pop ax
call print_nibble ; display lower nibble
ror eax, 8
loop .loop
%if UNUSED
mov al, 10; carriage return
call print_char
mov al, 13
call print_char
%endif ; UNUSED
popad
ret
print_nibble:
and al, 0x0f
add al, '0'
cmp al, '9'
jna .print_ascii
add al, 'A' - '9' - 1
.print_ascii:
call print_char
ret
;--------------------------------------------------------------------------
; getc - wait for a key press
;
getc:
pushad
mov ah, 0
int0x16
popad
ret
;--------------------------------------------------------------------------
; Write a ASCII character to the console.
;
; Arguments:
; AL = ASCII character.
;
print_char:
pushad
mov bx, 1 ; BH=0, BL=1 (blue)
mov ah, 0x0e ; bios INT 10, Function 0xE
int 0x10 ; display byte in tty mode
popad
ret
%endif ; DEBUG
%if UNUSED
;--------------------------------------------------------------------------
; Convert null terminated string to HFSUniStr255
;
; Arguments:
; DS:DX pointer to a NULL terminated string.
; ES:DI pointer to result.
;
ConvertStrToUni:
pushad; save registers
pushdi; save DI for unicode string length pointer
movsi, dx; use SI as source string pointer
xorax, ax; AX = unicode character
movcl, al; CL = string length
.loop:
stosw; store unicode character (length 0 at first run)
lodsb; load next character to AL
inccl; increment string length count
cmpal, NULL; check for string terminator
jne.loop
popdi; restore unicode string length pointer
deccl; ignoring terminator from length count
mov[di], cl; save string length
popad; restore registers
ret
%endif ; UNUSED
;--------------------------------------------------------------------------
; Convert big-endian HFSUniStr255 to little-endian
;
; Arguments:
; DS:SI = pointer to big-endian HFSUniStr255
;ES:DI = pointer to result buffer
;
ConvertHFSUniStr255ToLE:
pushad
lodsw
xchgah, al
stosw
cmpal, 0
je.exit
movcx, ax
.loop:
lodsw
xchgah, al; convert AX to little-endian
;
; When working with a case-sensitive HFS+ (HX) filesystem, we shouldn't change the case.
;
cmpBYTE [kHFSPlusBuffer + HFSPlusVolumeHeader.signature + 1], kHFSPlusCaseSigX
je.keepcase
orax, ax
jne.convertToLE
decax; NULL must be the strongest char
.convertToLE:
cmpah, 0
ja.keepcase
cmpal, 'A'
jb.keepcase
cmpal, 'Z'
ja.keepcase
addal, 32; convert to lower-case
.keepcase:
stosw
loop.loop
.exit:
popad
ret
;--------------------------------------------------------------------------
; compare HFSPlusExtentKey structures
;
; Arguments:
; DS:SI = search key
; ES:DI = trial key
;
; Returns:
;[BTree.searchResult] = result
;FLAGS = relation between search and trial keys
;
compareHFSPlusExtentKeys:
pushad
movdl, 0; DL = result of comparison, DH = bestGuess
moveax, [si + HFSPlusExtentKey.fileID]
cmpeax, [di + HFSPlusExtentKey.fileID]
jne.checkFlags
cmpBYTE [si + HFSPlusExtentKey.forkType], kForkTypeData
jne.checkFlags
moveax, [si + HFSPlusExtentKey.startBlock]
cmpeax, [di + HFSPlusExtentKey.startBlock]
jecompareHFSPlusCatalogKeys.exit
.checkFlags:
jacompareHFSPlusCatalogKeys.searchKeyGreater; search key > trial key
jbcompareHFSPlusCatalogKeys.trialKeyGreater; search key < trial key
;--------------------------------------------------------------------------
; Compare HFSPlusCatalogKey structures
;
; Arguments:
; DS:SI = search key
; ES:DI = trial key
;
; Returns:
;[BTree.searchResult] = result
;FLAGS = relation between search and trial keys
;
compareHFSPlusCatalogKeys:
pushad
xordx, dx; DL = result of comparison, DH = bestGuess
xchgsi, di
lodsd
movecx, eax; ECX = trial parentID
xchgsi, di
lodsd; EAX = search parentID
cmpeax, ecx
ja.searchKeyGreater; search parentID > trial parentID
jb.trialKeyGreater; search parentID < trial parentID
.compareNodeName:; search parentID = trial parentID
xchgsi, di
lodsw
movcx, ax; CX = trial nodeName.length
xchgsi, di
lodsw; AX = search nodeName.length
cmpcl, 0; trial nodeName.length = 0?
je.searchKeyGreater
cmpax, cx
je.strCompare
ja.searchStrLonger
.trialStrLonger:
decdh
movcx, ax
jmp.strCompare
.searchStrLonger:
incdh
.strCompare:
repecmpsw
ja.searchKeyGreater
jb.trialKeyGreater
movdl, dh
jmp.exit
.trialKeyGreater:
decdl
jmp.exit
.searchKeyGreater:
incdl
.exit:
mov[bp + BTree.searchResult], dl
cmpdl, 0; set flags to check relation between keys
popad
ret
;--------------------------------------------------------------------------
; Allocate memory
;
; Arguments:
; CX = size of requested memory
;
; Returns:
; BP = start address of allocated memory
;
; Clobber list:
; CX
;
malloc:
pushax; save AX
pushdi; save DI
movdi, [gMallocPtr]; start address of free space
pushdi; save free space start address
incdi;
incdi; keep the first word untouched
deccx; for the last memory block pointer.
deccx;
moval, NULL; fill with zero
repstosb; repeat fill
mov[gMallocPtr], di; adjust free space pointer
popbp; BP = start address of allocated memory
mov[di], bp; set start address of allocated memory at next
; allocation block's free space address.
popdi; restore DI
popax; restore AX
ret
%if UNUSED
;--------------------------------------------------------------------------
; Free allocated memory
;
; Returns:
; BP = start address of previously allocated memory
;
free:
leabp, [gMallocPtr]
movbp, [bp]
mov[gMallocPtr], bp
ret
%endif ; UNUSED
;--------------------------------------------------------------------------
; Static data.
;
%if VERBOSE
root_strdb'/boot', NULL
%endif
;--------------------------------------------------------------------------
; Pad the rest of the 512 byte sized sector with zeroes. The last
; two bytes is the mandatory boot sector signature.
;
; If the booter code becomes too large, then nasm will complain
; that the 'times' argument is negative.
pad_table_and_sig:
times510-($-$$) db 0
dwkBootSignature
;
; Sector 1 code area
;
;--------------------------------------------------------------------------
; lookUpBTree - initializes a new BTree instance and
; look up for HFSPlus Catalog File or Extent Overflow keys
;
; Arguments:
; AL = kHFSPlusFileID (Catalog or Extents Overflow)
;SI = address of searchKey
; DI = address of HFSPlusForkData.extents
;
; Returns:
; BP = address of BTree instance
; ECX = rootNode's logical offset in sectors
;
lookUpBTree:
movcx, BTree_size; allocate memory with BTree_size
callmalloc; BP = start address of allocated memory.
mov[bp + BTree.fileID], al; save fileFileID
movedx, [di]; first extent of current file
callblockToSector; ECX = converted to sector unit
moval, 1; 1 sector is enough for
xoredx, edx; reading current file's header.
leadx, [bp + BTree.BTHeaderBuffer]; load into BTreeHeaderBuffer
callreadLBA; read
movax, [bp + BTree.BTHeaderBuffer + BTNodeDescriptor_size + BTHeaderRec.nodeSize]
xchgah, al; convert to little-endian
mov[bp + BTree.nodeSize], ax; save nodeSize
;
; Always start the lookup process with the root node.
;
movedx, [bp + BTree.BTHeaderBuffer + BTNodeDescriptor_size + BTHeaderRec.rootNode]
.readNode:
;
; Converting nodeID to sector unit
;
movax, [bp + BTree.nodeSize]
shrax, 9; convert nodeSize to sectors
movbx, ax; BX = read sector count
cwde
bswapedx; convert node ID to little-endian
muledx; multiply with nodeSize converted to sector unit
movecx, eax; ECX = file offset in BTree
moveax, [bp + BTree.fileID]
leaedx, [bp + BTree.nodeBuffer]
callreadExtent
;
; AX = lowerBound = 0
;
xorax, ax
;
; BX = upperBound = numRecords - 1
;
movbx, [bp + BTree.nodeBuffer + BTNodeDescriptor.numRecords]
xchgbh, bl
decbx
.bsearch:
cmpax, bx
ja.checkResult; jump if lowerBound > upperBound
movcx, ax
addcx, bx
shrcx, 1; test index = (lowerBound + upperBound / 2)
callgetBTreeRecord
%if UNUSED
pushad
jl.csearchLessThanTrial
jg.csearchGreaterThanTrial
PrintChar('=')
jmp.csearchCont
.csearchGreaterThanTrial:
PrintChar('>')
jmp.csearchCont
.csearchLessThanTrial:
PrintChar('<')
.csearchCont:
popad
%endif ; UNUSED
.adjustBounds:
je.checkResult
jl.searchLessThanTrial
jg.searchGreaterThanTrial
jmp.bsearch
.searchLessThanTrial:
movbx, cx
decbx; upperBound = index - 1
jmp.bsearch
.searchGreaterThanTrial:
movax, cx
incax; lowerBound = index + 1
jmp.bsearch
.checkResult:
cmpBYTE [bp + BTree.searchResult], 0
jge.foundKey
movcx, bx
callgetBTreeRecord
.foundKey:
cmpBYTE [bp + BTree.nodeBuffer + BTNodeDescriptor.kind], kBTIndexNode
jne.exit
leabx, [bp + BTree.recordDataPtr]
movbx, [bx]
movedx, [bx]
jmp.readNode
.exit:
cmpBYTE [bp + BTree.searchResult], 0
ret
;--------------------------------------------------------------------------
; getBTreeRecord - read and compare BTree record
;
; Arguments:
; CX = record index
; SI = address of search key
;
; Returns:
; [BTree.searchResult] = result of key compare
; [BTree.recordDataPtr] = address of record data
;
getBTreeRecord:
pushad
pushsi; save SI
leadi, [bp + BTree.nodeBuffer]; DI = start of nodeBuffer
pushdi; use later
movax, [bp + BTree.nodeSize]; get nodeSize
adddi, ax; DI = beyond nodeBuffer
inccx; increment index
shlcx, 1; * 2
subdi, cx; DI = pointer to record
movax, [di]; offset to record
xchgah, al; convert to little-endian
popdi; start of nodeBuffer
adddi, ax; DI = address of record key
movsi, di; save to SI
movax, [di]; keyLength
xchgah, al; convert to little-endian
incax; suppress keySize (2 bytes)
incax;
adddi, ax; DI = address of record data
mov[bp + BTree.recordDataPtr], di; save address of record data
leadi, [bp + BTree.trialKey]
pushdi; save address of trialKey
lodsw; suppress keySize (2 bytes)
;
; Don't need to compare as DWORD since all reserved CNIDs fits to a single byte
;
cmpBYTE [bp + BTree.fileID], kHFSCatalogFileID
je.prepareTrialCatalogKey
.prepareTrialExtentKey:
movbx, compareHFSPlusExtentKeys
movsw; copy forkType + pad
movcx, 2; copy fileID + startBlock
.extentLoop:
lodsd
bswapeax; convert to little-endian
stosd
loop.extentLoop
jmp.exit
.prepareTrialCatalogKey:
movbx, compareHFSPlusCatalogKeys
lodsd
bswapeax; convert ParentID to little-endian
stosd
callConvertHFSUniStr255ToLE; convert nodeName to little-endian
.exit:
popdi; restore address of trialKey
%if UNUSED
;
; Print catalog trial key
;
pushad
movsi, di
lodsd
PrintChar('k')
PrintHex()
lodsw
cmpax, 0
je.printExit
movcx, ax
.printLoop:
lodsw
callprint_char
loop.printLoop
.printExit:
popad
;
;
;
%endif ; UNUSED
%if UNUSED
;
; Print extent trial key
;
pushad
PrintChar('k')
movsi, di
xoreax, eax
lodsw
PrintHex()
lodsd
PrintHex()
lodsd
PrintHex()
popad
;
;
;
%endif ; UNUSED
popsi; restore SI
callbx; call key compare proc
popad
ret
;--------------------------------------------------------------------------
; readExtent - read extents from a HFS+ file (multiple extent support)
;
; Arguments:
; EAX = Catalog File ID
; BX = read size in sectors
; ECX = file offset in sectors
; EDX = address of read buffer
; DI = address of HFSPlusForkData.extents
;
readExtent:
pushad
;
; Save Catalog File ID as part of a search HFSPlusExtentKey
; for a possible Extents Overflow lookup.
;
mov[bp + BTree.searchExtentKey + HFSPlusExtentKey.fileID], eax
mov[bp + BTree.readBufferPtr], edx
movax, bx
cwde
mov[bp + BTree.readSize], eax
movebx, ecx; EBX = file offset
xoreax, eax
mov[bp + BTree.currentExtentOffs], eax
.beginExtentBlock:
movBYTE [bp + BTree.extentCount], 0
.extentSearch:
cmpBYTE [bp + BTree.extentCount], kHFSPlusExtentDensity
jb.continue
.getNextExtentBlock:
pushebx
moveax, [bp + BTree.currentExtentOffs]
;
; Converting sector unit to HFS+ allocation block unit.
;
xoredx, edx
divDWORD [gBlockSize]; divide with blockSize
;
; Preparing searchExtentKey's startBlock field.
;
mov[bp + BTree.searchExtentKey + HFSPlusExtentKey.startBlock], eax
moval, kHFSExtentsFileID
leasi, [bp + BTree.searchExtentKey]
leadi, [kHFSPlusBuffer + HFSPlusVolumeHeader.extentsFile + HFSPlusForkData.extents]
calllookUpBTree
jnzNEAR .exit
;
; BP points to the new workspace allocated by lookUpBTree.
;
leadi, [bp + BTree.recordDataPtr]
movdi, [di]
;
; Switch back to the previous workspace.
;
leabp, [gMallocPtr]
movbp, [bp]
mov[gMallocPtr], bp
popebx
jmp.beginExtentBlock
.continue:
movedx, [di + HFSPlusExtentDescriptor.blockCount]
callblockToSector; ECX = converted current extent's blockCount to sectors
moveax, [bp + BTree.currentExtentOffs]; EAX = current extent's start offset (sector)
movedx, eax
addedx, ecx; EDX = next extent's start offset (sector)
cmpebx, edx
mov[bp + BTree.currentExtentOffs], edx; set currentExtentOffs as the next extent's start offset
jae.nextExtent; jump to next extent if file offset > next extent's start offset
.foundExtent:
movedx, ebx
subedx, eax; EDX = relative offset within current extent
moveax, edx; will be used below to determine read size
movesi, [bp + BTree.readSize]; ESI = remaining sectors to be read
addedx, esi
cmpedx, ecx; test if relative offset + readSize fits to this extent
jbe.read; read all remaining sectors from this extent
.splitRead:
subecx, eax; read amount of sectors beginning at relative offset
movesi, ecx; of current extent up to the end of current extent
.read:
movedx, [di + HFSPlusExtentDescriptor.startBlock]
callblockToSector; ECX = converted to sectors
addecx, eax; file offset converted to sectors
pushsi
movax, si
movedx, [bp + BTree.readBufferPtr]
callreadSectors
popsi
addebx, esi
movax, si
cwde
shlax, 9; convert SI (read sector count) to byte unit
add[bp + BTree.readBufferPtr], eax
sub[bp + BTree.readSize], esi
jz.exit
.nextExtent:
adddi, kHFSPlusExtentDensity
incBYTE [bp + BTree.extentCount]
jmp.extentSearch
.exit:
popad
ret
;--------------------------------------------------------------------------
; Convert big-endian HFSPlus allocation block to sector unit
;
; Arguments:
; EDX = allocation block
;
; Returns:
; ECX = allocation block converted to sector unit
;
; Clobber list:
; EDX
;
blockToSector:
pusheax
moveax, [gBlockSize]
bswapedx; convert allocation block to little-endian
muledx ; multiply with block number
movecx, eax; result in EAX
popeax
ret
%if UNUSED
;--------------------------------------------------------------------------
; Convert sector unit to HFSPlus allocation block unit
;
; Arguments:
; EDX = sector
;
; Returns:
; ECX = converted to allocation block unit
;
; Clobber list:
; EDX
;
sectorToBlock:
pusheax
moveax, edx
xoredx, edx
divDWORD [gBlockSize]; divide with blockSize
movecx, eax; result in EAX
popeax
ret
%endif ; UNUSED
%if UNUSED
;--------------------------------------------------------------------------
; Convert big-endian BTree node ID to sector unit
;
; Arguments:
; EDX = node ID
;
; Returns:
; ECX = node ID converted to sector unit
;
; Clobber list:
; EDX
;
nodeToSector:
pusheax
movax, [bp + BTree.nodeSize]
shrax, 9; convert nodeSize to sectors
cwde
bswapedx; convert node ID to little-endian
muledx; multiply with node ID
movecx, eax; result in EAX
popeax
ret
%endif ; UNUSED
;--------------------------------------------------------------------------
; Static data.
;
%if VERBOSE
log_title_strdbCR, LF, 'boot1: ', NULL
error_strdb'error', NULL
%endif
searchCatalogKeyddkHFSRootFolderID
dwsearchCatKeyNameLen
searchCatKeyNamedw'b', 'o', 'o', 't'; must be lower case
searchCatKeyNameLenEQU($ - searchCatKeyName) / 2
;--------------------------------------------------------------------------
; Pad the rest of the 512 byte sized sector with zeroes. The last
; two bytes is the mandatory boot sector signature.
;
pad_sector_1:
times1022-($-$$) db 0
dwkBootSignature
;
; Local BTree variables
;
strucBTree
.mallocLinkresw1; pointer to previously allocated memory block
.fileIDresd1; will use as BYTE
.nodeSizeresd1; will use as WORD
.searchExtentKeyresbHFSPlusExtentKey_size
.searchResultresb1
.trialKeyresbkBTMaxRecordLength
.recordDataPtrresw1
.readBufferPtrresd1
.currentExtentOffsresd1
.readSizeresd1
.extentCountresb1
ALIGNB2
.BTHeaderBufferresbkSectorBytes
.nodeBufferresbmaxNodeSize
endstruc
;
; Global variables
;
ABSOLUTEkHFSPlusBuffer + HFSPlusVolumeHeader_size
gPartLBAresd1
gBIOSDriveNumberresw1
gBlockSizeresd1
gMallocPtrresw1
; END
branches/cparm/i386/boot1/Makefile
1919
2020
2121
22
23
22
23
2424
2525
2626
all embedtheme: $(DIRS_NEEDED) $(VERSIONED_FILES)
boot1h: boot1.s Makefile
$(NASM) boot1.s -o $(SYMROOT)/boot1h
boot1h: boot1h.s Makefile
$(NASM) boot1h.s -o $(SYMROOT)/boot1h
$(NASM) boot1hp.s -o $(SYMROOT)/boot1hp
$(NASM) boot1he.s -o $(SYMROOT)/boot1he
$(NASM) boot1f32.s -o $(SYMROOT)/boot1f32
branches/cparm/i386/boot1/boot1h.s
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
; 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@
;
; Partition Boot Loader: boot1h
;
; This program is designed to reside in sector 0+1 of an HFS+ partition.
; It expects that the MBR has left the drive number in DL
; and a pointer to the partition entry in SI.
;
; This version requires a BIOS with EBIOS (LBA) support.
;
; This code is written for the NASM assembler.
; nasm boot1.s -o boot1h
;
; This version of boot1h tries to find a stage2 boot file in the root folder.
;
; NOTE: this is an experimental version with multiple extent support.
;
;
;
; Set to 1 to enable obscure debug messages.
;
DEBUGEQU0
;
; Set to 1 to enable unused code.
;
UNUSEDEQU0
;
; Set to 1 to enable verbose mode.
;
VERBOSEEQU1
;
; Various constants.
;
NULL EQU0
CREQU0x0D
LFEQU0x0A
mallocStartEQU0x1000; start address of local workspace area
maxSectorCountEQU64; maximum sector count for readSectors
maxNodeSizeEQU16384
kSectorBytesEQU512; sector size in bytes
kBootSignatureEQU0xAA55; boot sector signature
kBoot1StackAddressEQU0xFFF0; boot1 stack pointer
kBoot1LoadAddrEQU0x7C00; boot1 load address
kBoot1RelocAddrEQU0xE000; boot1 relocated address
kBoot1Sector1AddrEQUkBoot1RelocAddr + kSectorBytes; boot1 load address for sector 1
kHFSPlusBufferEQUkBoot1Sector1Addr + kSectorBytes; HFS+ Volume Header address
kBoot2SectorsEQU(448 * 1024 - 512) / kSectorBytes; max size of 'boot' file in sectors
kBoot2SegmentEQU0x2000; boot2 load segment
kBoot2AddressEQUkSectorBytes; boot2 load address
;
; Format of fdisk partition entry.
;
; The symbol 'part_size' is automatically defined as an `EQU'
; giving the size of the structure.
;
struc part
.bootidresb 1; bootable or not
.headresb 1; starting head, sector, cylinder
.sectresb 1;
.cylresb 1;
.typeresb 1; partition type
.endheadresb 1; ending head, sector, cylinder
.endsectresb 1;
.endcylresb 1;
.lbaresd 1; starting lba
.sectorsresd 1; size in sectors
endstruc
;-------------------------------------------------------------------------
; HFS+ related structures and constants
;
kHFSPlusSignatureEQU'H+'; HFS+ volume signature
kHFSPlusCaseSignatureEQU'HX'; HFS+ volume case-sensitive signature
kHFSPlusCaseSigXEQU'X'; upper byte of HFS+ volume case-sensitive signature
kHFSPlusExtentDensityEQU8; 8 extent descriptors / extent record
;
; HFSUniStr255
;
strucHFSUniStr255
.lengthresw1
.unicoderesw255
endstruc
;
; HFSPlusExtentDescriptor
;
strucHFSPlusExtentDescriptor
.startBlockresd1
.blockCountresd1
endstruc
;
; HFSPlusForkData
;
strucHFSPlusForkData
.logicalSizeresq1
.clumpSizeresd1
.totalBlocksresd1
.extentsresbkHFSPlusExtentDensity * HFSPlusExtentDescriptor_size
endstruc
;
; HFSPlusVolumeHeader
;
strucHFSPlusVolumeHeader
.signatureresw1
.versionresw1
.attributesresd1
.lastMountedVersion resd1
.journalInfoBlockresd1
.createDateresd1
.modifyDateresd1
.backupDateresd1
.checkedDateresd1
.fileCountresd1
.folderCountresd1
.blockSizeresd1
.totalBlocksresd1
.freeBlocksresd1
.nextAllocationresd1
.rsrcClumpSizeresd1
.dataClumpSizeresd1
.nextCatalogIDresd1
.writeCountresd1
.encodingsBitmapresq1
.finderInforesd8
.allocationFileresbHFSPlusForkData_size
.extentsFileresbHFSPlusForkData_size
.catalogFileresbHFSPlusForkData_size
.attributesFileresbHFSPlusForkData_size
.startupFileresbHFSPlusForkData_size
endstruc
;
; B-tree related structures and constants
;
kBTIndexNodeEQU0
kBTMaxRecordLengthEQU264; sizeof(kHFSPlusFileThreadRecord)
kHFSRootParentIDEQU1; Parent ID of the root folder
kHFSRootFolderIDEQU2; Folder ID of the root folder
kHFSExtentsFileIDEQU3; File ID of the extents overflow file
kHFSCatalogFileIDEQU4; File ID of the catalog file
kHFSPlusFileRecordEQU0x200
kForkTypeDataEQU0
kForkTypeResourceEQU0xFF
;
; BTNodeDescriptor
;
strucBTNodeDescriptor
.fLinkresd1
.bLinkresd1
.kindresb1
.heightresb1
.numRecordsresw1
.reservedresw1
endstruc
;
; BTHeaderRec
;
strucBTHeaderRec
.treeDepthresw1
.rootNoderesd1
.leafRecordsresd1
.firstLeafNoderesd1
.lastLeafNoderesd1
.nodeSizeresw1
.maxKeyLengthresw1
.totalNodesresd1
.freeNodesresd1
.reserved1resw1
.clumpSizeresd1
.btreeTyperesb1
.keyCompareTyperesb1
.attributesresd1
.reserved3resd16
endstruc
;
; BTIndexRec
;
strucBTIndexRec
.childIDresd1
endstruc
;
; HFSPlusCatalogKey
;
strucHFSPlusCatalogKey
;
; won't use the keyLength field for easier addressing data inside this structure
;
;.keyLengthresw1
.parentIDresd1
.nodeNameresbHFSUniStr255_size
endstruc
;
; HFSPlusExtentKey
;
strucHFSPlusExtentKey
;
; won't use the keyLength field for easier addressing data inside this structure
;
;.keyLengthresw1
.forkTyperesb1
.padresb1
.fileIDresd1
.startBlockresd1
endstruc
;
; HFSPlusBSDInfo
;
strucHFSPlusBSDInfo
.ownerIDresd1
.groupIDresd1
.adminFlagsresb1
.ownerFlagsresb1
.fileModeresw1
.specialresd1
endstruc
;
; FileInfo
;
strucFileInfo
.fileTyperesd1
.fileCreatorresd1
.finderFlagsresw1
.locationresw2
.reservedFieldresw1
endstruc
;
; ExtendedFileInfo
;
strucExtendedFileInfo
.reserved1resw4
.extFinderFlagsresw1
.reserved2resw1
.putAwayFolderIDresd1
endstruc
;
; HFSPlusCatalogFile
;
strucHFSPlusCatalogFile
.recordTyperesw1
.flagsresw1
.reserved1resd1
.fileIDresd1
.createDateresd1
.contentModDateresd1
.attributeModDateresd1
.accessDateresd1
.backupDateresd1
.permissionsresbHFSPlusBSDInfo_size
.userInforesbFileInfo_size
.finderInforesbExtendedFileInfo_size
.textEncodingresd1
.reserved2resd1
.dataForkresbHFSPlusForkData_size
.resourceForkresbHFSPlusForkData_size
endstruc
;
; Macros.
;
%macro jmpabs 1
pushWORD %1
ret
%endmacro
%macro DebugCharMacro 1
pushad
moval, %1
callprint_char
callgetc
popad
%endmacro
%macro PrintCharMacro 1
pushad
moval, %1
callprint_char
popad
%endmacro
%macro PutCharMacro 1
callprint_char
%endmacro
%macro PrintHexMacro 1
callprint_hex
%endmacro
%macro PrintString 1
movsi, %1
callprint_string
%endmacro
%macro LogString 1
movdi, %1
calllog_string
%endmacro
%if DEBUG
%define DebugChar(x) DebugCharMacro x
%define PrintChar(x) PrintCharMacro x
%define PutChar(x) PutCharMacro
%define PrintHex(x) PrintHexMacro x
%else
%define DebugChar(x)
%define PrintChar(x)
%define PutChar(x)
%define PrintHex(x)
%endif
;--------------------------------------------------------------------------
; Start of text segment.
SEGMENT .text
ORGkBoot1RelocAddr
;--------------------------------------------------------------------------
; Boot code is loaded at 0:7C00h.
;
start:
;
; Set up the stack to grow down from kBoot1StackSegment:kBoot1StackAddress.
; Interrupts should be off while the stack is being manipulated.
;
cli ; interrupts off
xorax, ax ; zero ax
movss, ax ; ss <- 0
mov sp, kBoot1StackAddress ; sp <- top of stack
sti ; reenable interrupts
mov ds, ax ; ds <- 0
mov es, ax ; es <- 0
;
; Relocate boot1 code.
;
pushsi
movsi, kBoot1LoadAddr; si <- source
movdi, kBoot1RelocAddr; di <- destination
cld; auto-increment SI and/or DI registers
movcx, kSectorBytes; copy 256 words
repmovsb; repeat string move (word) operation
popsi
;
; Code relocated, jump to startReloc in relocated location.
;
; FIXME: Is there any way to instruct NASM to compile a near jump
; using absolute address instead of relative displacement?
;
jmpabsstartReloc
;--------------------------------------------------------------------------
; Start execution from the relocated location.
;
startReloc:
;
; Initializing global variables.
;
mov eax, [si + part.lba]
mov [gPartLBA], eax; save the current partition LBA offset
mov [gBIOSDriveNumber], dl; save BIOS drive number
movWORD [gMallocPtr], mallocStart; set free space pointer
;
; Loading upper 512 bytes of boot1h and HFS+ Volume Header.
;
xorecx, ecx; sector 1 of current partition
incecx
mov al, 2; read 2 sectors: sector 1 of boot1h + HFS+ Volume Header
mov edx, kBoot1Sector1Addr
call readLBA
;
; Initializing more global variables.
;
moveax, [kHFSPlusBuffer + HFSPlusVolumeHeader.blockSize]
bswapeax; convert to little-endian
shreax, 9; convert to sector unit
mov[gBlockSize], eax; save blockSize as little-endian sector unit!
;
; Looking for HFSPlus ('H+') or HFSPlus case-sensitive ('HX') signature.
;
movax, [kHFSPlusBuffer + HFSPlusVolumeHeader.signature]
cmpax, kHFSPlusCaseSignature
jefindRootBoot
cmp ax, kHFSPlusSignature
jne error
;--------------------------------------------------------------------------
; Find stage2 boot file in a HFS+ Volume's root folder.
;
findRootBoot:
moval, kHFSCatalogFileID
leasi, [searchCatalogKey]
leadi, [kHFSPlusBuffer + HFSPlusVolumeHeader.catalogFile + HFSPlusForkData.extents]
calllookUpBTree
jneerror
leasi, [bp + BTree.recordDataPtr]
movsi, [si]
cmpWORD [si], kHFSPlusFileRecord
jneerror
; EAX = Catalog File ID
; BX = read size in sectors
; ECX = file offset in sectors
; EDX = address of read buffer
; DI = address of HFSPlusForkData
;
; Use the second big-endian double-word as the file length in HFSPlusForkData.logicalSize
;
movebx, [si + HFSPlusCatalogFile.dataFork + HFSPlusForkData.logicalSize + 4]
bswapebx; convert file size to little-endian
addebx, kSectorBytes - 1; adjust size before unit conversion
shrebx, 9; convert file size to sector unit
cmpbx, kBoot2Sectors; check if bigger than max stage2 size
jaerror
moveax, [si + HFSPlusCatalogFile.fileID]
bswapeax; convert fileID to little-endian
xorecx, ecx
movedx, (kBoot2Segment << 4) + kBoot2Address
leadi, [si + HFSPlusCatalogFile.dataFork + HFSPlusForkData.extents]
callreadExtent
%if VERBOSE
LogString(root_str)
%endif
boot2:
%if DEBUG
DebugChar ('!')
%endif
%if UNUSED
;
; Waiting for a key press.
;
mov ah, 0
int0x16
%endif
mov dl, [gBIOSDriveNumber]; load BIOS drive number
jmp kBoot2Segment:kBoot2Address
error:
%if VERBOSE
LogString(error_str)
%endif
hang:
hlt
jmp hang
;--------------------------------------------------------------------------
; readSectors - Reads more than 127 sectors using LBA addressing.
;
; Arguments:
; AX = number of 512-byte sectors to read (valid from 1-1280).
; EDX = pointer to where the sectors should be stored.
; ECX = sector offset in partition
;
; Returns:
; CF = 0 success
; 1 error
;
readSectors:
pushad
movbx, ax
.loop:
xoreax, eax; EAX = 0
moval, bl; assume we reached the last block.
cmpbx, maxSectorCount; check if we really reached the last block
jb.readBlock; yes, BX < MaxSectorCount
moval, maxSectorCount; no, read MaxSectorCount
.readBlock:
callreadLBA
subbx, ax; decrease remaning sectors with the read amount
jz.exit; exit if no more sectors left to be loaded
addecx, eax; adjust LBA sector offset
shlax, 9; convert sectors to bytes
addedx, eax; adjust target memory location
jmp.loop; read remaining sectors
.exit:
popad
ret
;--------------------------------------------------------------------------
; readLBA - Read sectors from a partition using LBA addressing.
;
; Arguments:
; AL = number of 512-byte sectors to read (valid from 1-127).
; EDX = pointer to where the sectors should be stored.
; ECX = sector offset in partition
; [bios_drive_number] = drive number (0x80 + unit number)
;
; Returns:
; CF = 0 success
; 1 error
;
readLBA:
pushad ; save all registers
push es; save ES
mov bp, sp ; save current SP
;
; Convert EDX to segment:offset model and set ES:BX
;
; Some BIOSes do not like offset to be negative while reading
; from hard drives. This usually leads to "boot1: error" when trying
; to boot from hard drive, while booting normally from USB flash.
; The routines, responsible for this are apparently different.
; Thus we split linear address slightly differently for these
; capricious BIOSes to make sure offset is always positive.
;
movbx, dx; save offset to BX
andbh, 0x0f; keep low 12 bits
shredx, 4; adjust linear address to segment base
xordl, dl; mask low 8 bits
moves, dx; save segment to ES
;
; Create the Disk Address Packet structure for the
; INT13/F42 (Extended Read Sectors) on the stack.
;
; push DWORD 0 ; offset 12, upper 32-bit LBA
push ds ; For sake of saving memory,
push ds ; push DS register, which is 0.
add ecx, [gPartLBA] ; offset 8, lower 32-bit LBA
push ecx
push es ; offset 6, memory segment
push bx ; offset 4, memory offset
xor ah, ah ; offset 3, must be 0
push ax ; offset 2, number of sectors
push WORD 16 ; offset 0-1, packet size
;
; INT13 Func 42 - Extended Read Sectors
;
; Arguments:
; AH = 0x42
; [bios_drive_number] = drive number (0x80 + unit number)
; DS:SI = pointer to Disk Address Packet
;
; Returns:
; AH = return status (success is 0)
; carry = 0 success
; 1 error
;
; Packet offset 2 indicates the number of sectors read
; successfully.
;
mov dl, [gBIOSDriveNumber]; load BIOS drive number
mov si, sp
mov ah, 0x42
int 0x13
jcerror
;
; Issue a disk reset on error.
; Should this be changed to Func 0xD to skip the diskette controller
; reset?
;
;xor ax, ax ; Func 0
;int 0x13 ; INT 13
;stc ; set carry to indicate error
.exit:
mov sp, bp ; restore SP
pop es; restore ES
popad
ret
%if VERBOSE
;--------------------------------------------------------------------------
; Write a string with 'boot1: ' prefix to the console.
;
; Arguments:
; ES:DI pointer to a NULL terminated string.
;
; Clobber list:
; DI
;
log_string:
pushad
pushdi
movsi, log_title_str
callprint_string
popsi
callprint_string
popad
ret
;-------------------------------------------------------------------------
; Write a string to the console.
;
; Arguments:
; DS:SI pointer to a NULL terminated string.
;
; Clobber list:
; AX, BX, SI
;
print_string:
mov bx, 1 ; BH=0, BL=1 (blue)
.loop:
lodsb ; load a byte from DS:SI into AL
cmp al, 0 ; Is it a NULL?
je .exit ; yes, all done
mov ah, 0xE ; INT10 Func 0xE
int 0x10 ; display byte in tty mode
jmp .loop
.exit:
ret
%endif ; VERBOSE
%if DEBUG
;--------------------------------------------------------------------------
; Write the 4-byte value to the console in hex.
;
; Arguments:
; EAX = Value to be displayed in hex.
;
print_hex:
pushad
mov cx, WORD 4
bswap eax
.loop:
push ax
ror al, 4
call print_nibble ; display upper nibble
pop ax
call print_nibble ; display lower nibble
ror eax, 8
loop .loop
%if UNUSED
mov al, 10; carriage return
call print_char
mov al, 13
call print_char
%endif ; UNUSED
popad
ret
print_nibble:
and al, 0x0f
add al, '0'
cmp al, '9'
jna .print_ascii
add al, 'A' - '9' - 1
.print_ascii:
call print_char
ret
;--------------------------------------------------------------------------
; getc - wait for a key press
;
getc:
pushad
mov ah, 0
int0x16
popad
ret
;--------------------------------------------------------------------------
; Write a ASCII character to the console.
;
; Arguments:
; AL = ASCII character.
;
print_char:
pushad
mov bx, 1 ; BH=0, BL=1 (blue)
mov ah, 0x0e ; bios INT 10, Function 0xE
int 0x10 ; display byte in tty mode
popad
ret
%endif ; DEBUG
%if UNUSED
;--------------------------------------------------------------------------
; Convert null terminated string to HFSUniStr255
;
; Arguments:
; DS:DX pointer to a NULL terminated string.
; ES:DI pointer to result.
;
ConvertStrToUni:
pushad; save registers
pushdi; save DI for unicode string length pointer
movsi, dx; use SI as source string pointer
xorax, ax; AX = unicode character
movcl, al; CL = string length
.loop:
stosw; store unicode character (length 0 at first run)
lodsb; load next character to AL
inccl; increment string length count
cmpal, NULL; check for string terminator
jne.loop
popdi; restore unicode string length pointer
deccl; ignoring terminator from length count
mov[di], cl; save string length
popad; restore registers
ret
%endif ; UNUSED
;--------------------------------------------------------------------------
; Convert big-endian HFSUniStr255 to little-endian
;
; Arguments:
; DS:SI = pointer to big-endian HFSUniStr255
;ES:DI = pointer to result buffer
;
ConvertHFSUniStr255ToLE:
pushad
lodsw
xchgah, al
stosw
cmpal, 0
je.exit
movcx, ax
.loop:
lodsw
xchgah, al; convert AX to little-endian
;
; When working with a case-sensitive HFS+ (HX) filesystem, we shouldn't change the case.
;
cmpBYTE [kHFSPlusBuffer + HFSPlusVolumeHeader.signature + 1], kHFSPlusCaseSigX
je.keepcase
orax, ax
jne.convertToLE
decax; NULL must be the strongest char
.convertToLE:
cmpah, 0
ja.keepcase
cmpal, 'A'
jb.keepcase
cmpal, 'Z'
ja.keepcase
addal, 32; convert to lower-case
.keepcase:
stosw
loop.loop
.exit:
popad
ret
;--------------------------------------------------------------------------
; compare HFSPlusExtentKey structures
;
; Arguments:
; DS:SI = search key
; ES:DI = trial key
;
; Returns:
;[BTree.searchResult] = result
;FLAGS = relation between search and trial keys
;
compareHFSPlusExtentKeys:
pushad
movdl, 0; DL = result of comparison, DH = bestGuess
moveax, [si + HFSPlusExtentKey.fileID]
cmpeax, [di + HFSPlusExtentKey.fileID]
jne.checkFlags
cmpBYTE [si + HFSPlusExtentKey.forkType], kForkTypeData
jne.checkFlags
moveax, [si + HFSPlusExtentKey.startBlock]
cmpeax, [di + HFSPlusExtentKey.startBlock]
jecompareHFSPlusCatalogKeys.exit
.checkFlags:
jacompareHFSPlusCatalogKeys.searchKeyGreater; search key > trial key
jbcompareHFSPlusCatalogKeys.trialKeyGreater; search key < trial key
;--------------------------------------------------------------------------
; Compare HFSPlusCatalogKey structures
;
; Arguments:
; DS:SI = search key
; ES:DI = trial key
;
; Returns:
;[BTree.searchResult] = result
;FLAGS = relation between search and trial keys
;
compareHFSPlusCatalogKeys:
pushad
xordx, dx; DL = result of comparison, DH = bestGuess
xchgsi, di
lodsd
movecx, eax; ECX = trial parentID
xchgsi, di
lodsd; EAX = search parentID
cmpeax, ecx
ja.searchKeyGreater; search parentID > trial parentID
jb.trialKeyGreater; search parentID < trial parentID
.compareNodeName:; search parentID = trial parentID
xchgsi, di
lodsw
movcx, ax; CX = trial nodeName.length
xchgsi, di
lodsw; AX = search nodeName.length
cmpcl, 0; trial nodeName.length = 0?
je.searchKeyGreater
cmpax, cx
je.strCompare
ja.searchStrLonger
.trialStrLonger:
decdh
movcx, ax
jmp.strCompare
.searchStrLonger:
incdh
.strCompare:
repecmpsw
ja.searchKeyGreater
jb.trialKeyGreater
movdl, dh
jmp.exit
.trialKeyGreater:
decdl
jmp.exit
.searchKeyGreater:
incdl
.exit:
mov[bp + BTree.searchResult], dl
cmpdl, 0; set flags to check relation between keys
popad
ret
;--------------------------------------------------------------------------
; Allocate memory
;
; Arguments:
; CX = size of requested memory
;
; Returns:
; BP = start address of allocated memory
;
; Clobber list:
; CX
;
malloc:
pushax; save AX
pushdi; save DI
movdi, [gMallocPtr]; start address of free space
pushdi; save free space start address
incdi;
incdi; keep the first word untouched
deccx; for the last memory block pointer.
deccx;
moval, NULL; fill with zero
repstosb; repeat fill
mov[gMallocPtr], di; adjust free space pointer
popbp; BP = start address of allocated memory
mov[di], bp; set start address of allocated memory at next
; allocation block's free space address.
popdi; restore DI
popax; restore AX
ret
%if UNUSED
;--------------------------------------------------------------------------
; Free allocated memory
;
; Returns:
; BP = start address of previously allocated memory
;
free:
leabp, [gMallocPtr]
movbp, [bp]
mov[gMallocPtr], bp
ret
%endif ; UNUSED
;--------------------------------------------------------------------------
; Static data.
;
%if VERBOSE
root_strdb'/boot', NULL
%endif
;--------------------------------------------------------------------------
; Pad the rest of the 512 byte sized sector with zeroes. The last
; two bytes is the mandatory boot sector signature.
;
; If the booter code becomes too large, then nasm will complain
; that the 'times' argument is negative.
pad_table_and_sig:
times510-($-$$) db 0
dwkBootSignature
;
; Sector 1 code area
;
;--------------------------------------------------------------------------
; lookUpBTree - initializes a new BTree instance and
; look up for HFSPlus Catalog File or Extent Overflow keys
;
; Arguments:
; AL = kHFSPlusFileID (Catalog or Extents Overflow)
;SI = address of searchKey
; DI = address of HFSPlusForkData.extents
;
; Returns:
; BP = address of BTree instance
; ECX = rootNode's logical offset in sectors
;
lookUpBTree:
movcx, BTree_size; allocate memory with BTree_size
callmalloc; BP = start address of allocated memory.
mov[bp + BTree.fileID], al; save fileFileID
movedx, [di]; first extent of current file
callblockToSector; ECX = converted to sector unit
moval, 1; 1 sector is enough for
xoredx, edx; reading current file's header.
leadx, [bp + BTree.BTHeaderBuffer]; load into BTreeHeaderBuffer
callreadLBA; read
movax, [bp + BTree.BTHeaderBuffer + BTNodeDescriptor_size + BTHeaderRec.nodeSize]
xchgah, al; convert to little-endian
mov[bp + BTree.nodeSize], ax; save nodeSize
;
; Always start the lookup process with the root node.
;
movedx, [bp + BTree.BTHeaderBuffer + BTNodeDescriptor_size + BTHeaderRec.rootNode]
.readNode:
;
; Converting nodeID to sector unit
;
movax, [bp + BTree.nodeSize]
shrax, 9; convert nodeSize to sectors
movbx, ax; BX = read sector count
cwde
bswapedx; convert node ID to little-endian
muledx; multiply with nodeSize converted to sector unit
movecx, eax; ECX = file offset in BTree
moveax, [bp + BTree.fileID]
leaedx, [bp + BTree.nodeBuffer]
callreadExtent
;
; AX = lowerBound = 0
;
xorax, ax
;
; BX = upperBound = numRecords - 1
;
movbx, [bp + BTree.nodeBuffer + BTNodeDescriptor.numRecords]
xchgbh, bl
decbx
.bsearch:
cmpax, bx
ja.checkResult; jump if lowerBound > upperBound
movcx, ax
addcx, bx
shrcx, 1; test index = (lowerBound + upperBound / 2)
callgetBTreeRecord
%if UNUSED
pushad
jl.csearchLessThanTrial
jg.csearchGreaterThanTrial
PrintChar('=')
jmp.csearchCont
.csearchGreaterThanTrial:
PrintChar('>')
jmp.csearchCont
.csearchLessThanTrial:
PrintChar('<')
.csearchCont:
popad
%endif ; UNUSED
.adjustBounds:
je.checkResult
jl.searchLessThanTrial
jg.searchGreaterThanTrial
jmp.bsearch
.searchLessThanTrial:
movbx, cx
decbx; upperBound = index - 1
jmp.bsearch
.searchGreaterThanTrial:
movax, cx
incax; lowerBound = index + 1
jmp.bsearch
.checkResult:
cmpBYTE [bp + BTree.searchResult], 0
jge.foundKey
movcx, bx
callgetBTreeRecord
.foundKey:
cmpBYTE [bp + BTree.nodeBuffer + BTNodeDescriptor.kind], kBTIndexNode
jne.exit
leabx, [bp + BTree.recordDataPtr]
movbx, [bx]
movedx, [bx]
jmp.readNode
.exit:
cmpBYTE [bp + BTree.searchResult], 0
ret
;--------------------------------------------------------------------------
; getBTreeRecord - read and compare BTree record
;
; Arguments:
; CX = record index
; SI = address of search key
;
; Returns:
; [BTree.searchResult] = result of key compare
; [BTree.recordDataPtr] = address of record data
;
getBTreeRecord:
pushad
pushsi; save SI
leadi, [bp + BTree.nodeBuffer]; DI = start of nodeBuffer
pushdi; use later
movax, [bp + BTree.nodeSize]; get nodeSize
adddi, ax; DI = beyond nodeBuffer
inccx; increment index
shlcx, 1; * 2
subdi, cx; DI = pointer to record
movax, [di]; offset to record
xchgah, al; convert to little-endian
popdi; start of nodeBuffer
adddi, ax; DI = address of record key
movsi, di; save to SI
movax, [di]; keyLength
xchgah, al; convert to little-endian
incax; suppress keySize (2 bytes)
incax;
adddi, ax; DI = address of record data
mov[bp + BTree.recordDataPtr], di; save address of record data
leadi, [bp + BTree.trialKey]
pushdi; save address of trialKey
lodsw; suppress keySize (2 bytes)
;
; Don't need to compare as DWORD since all reserved CNIDs fits to a single byte
;
cmpBYTE [bp + BTree.fileID], kHFSCatalogFileID
je.prepareTrialCatalogKey
.prepareTrialExtentKey:
movbx, compareHFSPlusExtentKeys
movsw; copy forkType + pad
movcx, 2; copy fileID + startBlock
.extentLoop:
lodsd
bswapeax; convert to little-endian
stosd
loop.extentLoop
jmp.exit
.prepareTrialCatalogKey:
movbx, compareHFSPlusCatalogKeys
lodsd
bswapeax; convert ParentID to little-endian
stosd
callConvertHFSUniStr255ToLE; convert nodeName to little-endian
.exit:
popdi; restore address of trialKey
%if UNUSED
;
; Print catalog trial key
;
pushad
movsi, di
lodsd
PrintChar('k')
PrintHex()
lodsw
cmpax, 0
je.printExit
movcx, ax
.printLoop:
lodsw
callprint_char
loop.printLoop
.printExit:
popad
;
;
;
%endif ; UNUSED
%if UNUSED
;
; Print extent trial key
;
pushad
PrintChar('k')
movsi, di
xoreax, eax
lodsw
PrintHex()
lodsd
PrintHex()
lodsd
PrintHex()
popad
;
;
;
%endif ; UNUSED
popsi; restore SI
callbx; call key compare proc
popad
ret
;--------------------------------------------------------------------------
; readExtent - read extents from a HFS+ file (multiple extent support)
;
; Arguments:
; EAX = Catalog File ID
; BX = read size in sectors
; ECX = file offset in sectors
; EDX = address of read buffer
; DI = address of HFSPlusForkData.extents
;
readExtent:
pushad
;
; Save Catalog File ID as part of a search HFSPlusExtentKey
; for a possible Extents Overflow lookup.
;
mov[bp + BTree.searchExtentKey + HFSPlusExtentKey.fileID], eax
mov[bp + BTree.readBufferPtr], edx
movax, bx
cwde
mov[bp + BTree.readSize], eax
movebx, ecx; EBX = file offset
xoreax, eax
mov[bp + BTree.currentExtentOffs], eax
.beginExtentBlock:
movBYTE [bp + BTree.extentCount], 0
.extentSearch:
cmpBYTE [bp + BTree.extentCount], kHFSPlusExtentDensity
jb.continue
.getNextExtentBlock:
pushebx
moveax, [bp + BTree.currentExtentOffs]
;
; Converting sector unit to HFS+ allocation block unit.
;
xoredx, edx
divDWORD [gBlockSize]; divide with blockSize
;
; Preparing searchExtentKey's startBlock field.
;
mov[bp + BTree.searchExtentKey + HFSPlusExtentKey.startBlock], eax
moval, kHFSExtentsFileID
leasi, [bp + BTree.searchExtentKey]
leadi, [kHFSPlusBuffer + HFSPlusVolumeHeader.extentsFile + HFSPlusForkData.extents]
calllookUpBTree
jnzNEAR .exit
;
; BP points to the new workspace allocated by lookUpBTree.
;
leadi, [bp + BTree.recordDataPtr]
movdi, [di]
;
; Switch back to the previous workspace.
;
leabp, [gMallocPtr]
movbp, [bp]
mov[gMallocPtr], bp
popebx
jmp.beginExtentBlock
.continue:
movedx, [di + HFSPlusExtentDescriptor.blockCount]
callblockToSector; ECX = converted current extent's blockCount to sectors
moveax, [bp + BTree.currentExtentOffs]; EAX = current extent's start offset (sector)
movedx, eax
addedx, ecx; EDX = next extent's start offset (sector)
cmpebx, edx
mov[bp + BTree.currentExtentOffs], edx; set currentExtentOffs as the next extent's start offset
jae.nextExtent; jump to next extent if file offset > next extent's start offset
.foundExtent:
movedx, ebx
subedx, eax; EDX = relative offset within current extent
moveax, edx; will be used below to determine read size
movesi, [bp + BTree.readSize]; ESI = remaining sectors to be read
addedx, esi
cmpedx, ecx; test if relative offset + readSize fits to this extent
jbe.read; read all remaining sectors from this extent
.splitRead:
subecx, eax; read amount of sectors beginning at relative offset
movesi, ecx; of current extent up to the end of current extent
.read:
movedx, [di + HFSPlusExtentDescriptor.startBlock]
callblockToSector; ECX = converted to sectors
addecx, eax; file offset converted to sectors
pushsi
movax, si
movedx, [bp + BTree.readBufferPtr]
callreadSectors
popsi
addebx, esi
movax, si
cwde
shlax, 9; convert SI (read sector count) to byte unit
add[bp + BTree.readBufferPtr], eax
sub[bp + BTree.readSize], esi
jz.exit
.nextExtent:
adddi, kHFSPlusExtentDensity
incBYTE [bp + BTree.extentCount]
jmp.extentSearch
.exit:
popad
ret
;--------------------------------------------------------------------------
; Convert big-endian HFSPlus allocation block to sector unit
;
; Arguments:
; EDX = allocation block
;
; Returns:
; ECX = allocation block converted to sector unit
;
; Clobber list:
; EDX
;
blockToSector:
pusheax
moveax, [gBlockSize]
bswapedx; convert allocation block to little-endian
muledx ; multiply with block number
movecx, eax; result in EAX
popeax
ret
%if UNUSED
;--------------------------------------------------------------------------
; Convert sector unit to HFSPlus allocation block unit
;
; Arguments:
; EDX = sector
;
; Returns:
; ECX = converted to allocation block unit
;
; Clobber list:
; EDX
;
sectorToBlock:
pusheax
moveax, edx
xoredx, edx
divDWORD [gBlockSize]; divide with blockSize
movecx, eax; result in EAX
popeax
ret
%endif ; UNUSED
%if UNUSED
;--------------------------------------------------------------------------
; Convert big-endian BTree node ID to sector unit
;
; Arguments:
; EDX = node ID
;
; Returns:
; ECX = node ID converted to sector unit
;
; Clobber list:
; EDX
;
nodeToSector:
pusheax
movax, [bp + BTree.nodeSize]
shrax, 9; convert nodeSize to sectors
cwde
bswapedx; convert node ID to little-endian
muledx; multiply with node ID
movecx, eax; result in EAX
popeax
ret
%endif ; UNUSED
;--------------------------------------------------------------------------
; Static data.
;
%if VERBOSE
log_title_strdbCR, LF, 'boot1: ', NULL
error_strdb'error', NULL
%endif
searchCatalogKeyddkHFSRootFolderID
dwsearchCatKeyNameLen
searchCatKeyNamedw'b', 'o', 'o', 't'; must be lower case
searchCatKeyNameLenEQU($ - searchCatKeyName) / 2
;--------------------------------------------------------------------------
; Pad the rest of the 512 byte sized sector with zeroes. The last
; two bytes is the mandatory boot sector signature.
;
pad_sector_1:
times1022-($-$$) db 0
dwkBootSignature
;
; Local BTree variables
;
strucBTree
.mallocLinkresw1; pointer to previously allocated memory block
.fileIDresd1; will use as BYTE
.nodeSizeresd1; will use as WORD
.searchExtentKeyresbHFSPlusExtentKey_size
.searchResultresb1
.trialKeyresbkBTMaxRecordLength
.recordDataPtrresw1
.readBufferPtrresd1
.currentExtentOffsresd1
.readSizeresd1
.extentCountresb1
ALIGNB2
.BTHeaderBufferresbkSectorBytes
.nodeBufferresbmaxNodeSize
endstruc
;
; Global variables
;
ABSOLUTEkHFSPlusBuffer + HFSPlusVolumeHeader_size
gPartLBAresd1
gBIOSDriveNumberresw1
gBlockSizeresd1
gMallocPtrresw1
; END
branches/cparm/i386/boot2/boot.c
8989
9090
9191
92
92
9393
9494
9595
......
117117
118118
119119
120
120121
121122
122123
......
563564
564565
565566
566
567
567
568568
569
570
571
572
573
574
575
576
577
569
578570
571
572
573
574
579575
580576
577
578
579
580
581
582
581583
582
584
585
586
583587
584588
585589
......
612616
613617
614618
615
616619
617620
618621
......
623626
624627
625628
629
626630
627631
628632
......
631635
632636
633637
638
639
634640
635641
636642
......
639645
640646
641647
648
649
642650
643651
644652
......
649657
650658
651659
660
661
652662
653663
654664
655665
656
666
657667
658668
659669
......
698708
699709
700710
701
711
702712
703713
704714
705715
706
716
707717
708718
709719
......
765775
766776
767777
778
779
780
781
782
783
784
785
786
787
788
789
768790
769791
770792
......
794816
795817
796818
797
819
798820
799821
800822
......
843865
844866
845867
846
868
847869
848870
849871
......
878900
879901
880902
881
903
882904
883905
884906
885
907
908
886909
887
888
910
889911
890912
891913
......
929951
930952
931953
954
955
956
957
932958
933959
934960
......
9991025
10001026
10011027
1002
1003
1004
1005
1006
1028
1029
1030
1031
1032
1033
1034
10071035
1036
1037
1038
1039
1040
1041
1042
1043
10081044
10091045
1010
1046
10111047
1012
1048
1049
10131050
1014
1015
1016
1017
1051
1052
1053
1054
10181055
10191056
10201057
......
11211158
11221159
11231160
1124
1161
11251162
11261163
11271164
char gMKextName[512];
char gMacOSVersion[8];
char *gRootDevice = NULL;
bool uuidSet = false;
#ifndef OPTION_ROM
bool gEnableCDROMRescan;
bool gScanSingleDrive;
#endif
static bool find_file_with_ext(const char* dir, const char *ext, const char * name_compare, size_t ext_size);
static bool found_extra_kext(void);
static void determineCpuArch(void);
void getKernelCachePath();
// Find out which version mac os we're booting.
getOSVersion(gMacOSVersion);
//if (platformCPUFeature(CPU_FEATURE_EM64T)) {
if (cpu_mode_is64bit())
if (getValueForKey(karch, &val, &len, &bootInfo->bootConfig) && val)
{
archCpuType = CPU_TYPE_X86_64;
}
else
{
archCpuType = CPU_TYPE_I386;
}
if (getValueForKey(karch, &val, &len, &bootInfo->bootConfig))
{
if (strncmp(val, "i386", 4) == 0)
if (strncmp(val, "x86_64", 4) == 0)
{
archCpuType = CPU_TYPE_X86_64;
}
else if (strncmp(val, "i386", 4) == 0)
{
archCpuType = CPU_TYPE_I386;
}
else
{
DBG("Incorrect parameter for option 'arch =' , please use x86_64 or i386\n")
determineCpuArch();
}
}
else determineCpuArch();
getRootDevice();
// Notify to all modules that we are attempting to boot
}
verbose("Loading Darwin %s\n", gMacOSVersion);
{
long cachetime, kerneltime, exttime;
if (trycache ) do {
{
trycache = 0;
bootInfo->adler32 = 0;
DBG("No kernel found, kernelcache disabled !!!\n");
break;
}
ret = GetFileInfo(NULL, gBootKernelCacheFile, &flags, &cachetime);
{
trycache = 0;
bootInfo->adler32 = 0;
DBG("Warning: kernelcache too old, timestamp of the kernel > timestamp of the cache, kernelcache disabled !!!\n");
break;
}
ret = GetFileInfo("/System/Library/", "Extensions", &flags, &exttime);
{
trycache = 0;
bootInfo->adler32 = 0;
DBG("Warning: kernelcache too old, timestamp of S/L/E > timestamp of the cache, kernelcache disabled !!! \n");
break;
}
if (kerneltime > exttime)
{
trycache = 0;
bootInfo->adler32 = 0;
DBG("Warning: invalid timestamp, kernelcache disabled !!!\n");
break;
}
} while (0);
}
do {
if (trycache)
{
if (ret == -1)
{
// Not found any alternate locations, using the original kernel image path.
strcpy(bootFileSpec, bootFile,sizeof(bootFileSpec));
strlcpy(bootFileSpec, bootFile,sizeof(bootFileSpec)+1);
}
}
}
#else
strlcpy(bootFileSpec, bootFile,sizeof(bootFileSpec));
strlcpy(bootFileSpec, bootFile,sizeof(bootFileSpec)+1);
#endif
verbose("Loading kernel %s\n", bootFileSpec);
#endif
}
static void determineCpuArch(void)
{
if (cpu_mode_is64bit())
{
archCpuType = CPU_TYPE_X86_64;
}
else
{
archCpuType = CPU_TYPE_I386;
}
}
void getKernelCachePath()
{
{
len++;
}
}
strlcpy(gBootKernelCacheFile, buffer, sizeof(gBootKernelCacheFile));
strlcpy(gBootKernelCacheFile, buffer, sizeof(gBootKernelCacheFile)+1);
}
else
{
{
platformInfo->platformName[0] = platformInfo->rootPath[0] = 0;
}
//memcpy(gRootPath,platformInfo->rootPath, sizeof(platformInfo->rootPath));
//memcpy(gRootPath,platformInfo->rootPath, sizeof(gRootPath));
bootInfo->adler32 = OSSwapHostToBigInt32(adler32((unsigned char *)platformInfo, sizeof(*platformInfo)));
{
// Maximum config table value size
#define VALUE_SIZE 2048
bool uuidSet = false;
const char *val = 0;
int cnt = 0;
if (getValueForKey(kBootUUIDKey, &val, &cnt, &bootInfo->bootConfig)){
if (getValueForKey(kBootUUIDKey, &val, &cnt, &bootInfo->bootConfig))
{
uuidSet = true;
}
}
else
{
if (getValueForBootKey(bootArgs->CommandLine, kRootDeviceKey, &val, &cnt))
valueBuffer = malloc(VALUE_SIZE);
char * argP = bootArgs->CommandLine;
valueBuffer[0] = '*';
if (cnt > VALUE_SIZE)
{
cnt = VALUE_SIZE;
}
cnt++;
strlcpy(valueBuffer + 1, val, cnt);
if (!copyArgument( kRootDeviceKey, valueBuffer, cnt, &argP, &ArgCntRemaining))
struct dirstuff* moduleDir = opendir(dir);
while(readdir(moduleDir, (const char**)&name, &flags, &time) >= 0)
{
if(strcmp(&name[strlen(name) - ext_size], ext) == 0)
{
if (name_compare)
{
if (strcmp(name, name_compare) == 0)
int len = strlen(name);
if (len >= ext_size)
{
if(strcmp(&name[len - ext_size], ext) == 0)
{
if (name_compare)
{
if (strcmp(name, name_compare) == 0)
{
DBG("found : %s\n", name);
return true;
}
}
else
{
DBG("found : %s\n", name);
return true;
}
}
}
else
#if DEBUG_BOOT
else
{
DBG("found : %s\n", name);
return true;
}
}
DBG("Ignoring %s\n", name);
}
#endif
}
#if DEBUG_BOOT
else
{
if (!bootFileWithDevice && (str)[0] != '/')
sprintf(bootFile, "/%s", str); // append a leading /
else
strcpy(bootFile, bootInfo->bootFile);
strlcpy(bootFile, bootInfo->bootFile, sizeof(bootInfo->bootFile)+1);
return bootfile;
}
branches/cparm/i386/boot2/boot.h
119119
120120
121121
122
122
123123
124124
125125
//extern char gRootPath[];
extern char *gRootDevice;
extern bool uuidSet;
/*
* Boot Modes
*/
branches/cparm/i386/boot2/modules.c
100100
101101
102102
103
103
104
105
106
104107
105
106
107
108
109
108
110109
111
112
110
111
112
113
114
115
116
117
113118
114
115119
120
121
122
123
124
125
126
116127
117128
118129
{
if ((strcmp(SYMBOLS_MODULE,name)) == 0) continue; // if we found Symbols.dylib, just skip it
if(strcmp(&name[strlen(name) - sizeof("dylib")], ".dylib") == 0)
int len = strlen(name);
int ext_size = sizeof("dylib");
if (len >= ext_size)
{
char* tmp = malloc(strlen(name) + 1);
strcpy(tmp, name);
msglog("* Attempting to load module: %s\n", tmp);
if(load_module(tmp) != EFI_SUCCESS)
if(strcmp(&name[len - ext_size], ".dylib") == 0)
{
// failed to load or already loaded
free(tmp);
char* tmp = malloc(len /*+ 1*/);
strlcpy(tmp, name, len + 1);
msglog("* Attempting to load module: %s\n", tmp);
if(load_module(tmp) != EFI_SUCCESS)
{
// failed to load or already loaded
free(tmp);
}
}
}
#if DEBUG_MODULES
else
{
DBG("Ignoring %s\n", name);
}
#endif
}
#if DEBUG_MODULES
else
{
DBG("Ignoring %s\n", name);
branches/cparm/i386/boot2/mboot.c
308308
309309
310310
311
312
313311
314312
315313
// However, our caller must fix his return address if he wishes to return to
// his caller and so on and so forth.
//initPIC(0x20, 0x28);
//initIDT();
/* Zero the BSS and initialize malloc */
initialize_runtime();
branches/cparm/i386/boot2/options.c
111111
112112
113113
114
114
115115
116116
117
118
117119
118
119
120120
121121
122
122123
123124
124125
125126
126127
127
128
128129
129130
130131
......
964965
965966
966967
967
968
968969
969970
970971
......
973974
974975
975976
976
977
977978
978979
979980
moveCursor( 0, row );
printf(msg);
/*
int multi_buff = 18 * (timeout);
int multi = ++multi_buff;
*/
//unsigned int lasttime=0;
unsigned int lasttime=0;
for ( time = time18(), timeout++; timeout > 0; )
{
/*
if( time18() > lasttime)
{
multi--;
lasttime=time18();
}
*/
if ((ch = readKeyboardStatus()))
break;
gOverrideKernel = false;
if (( kernel = extractKernelName((char **)&cp) )) {
strlcpy( bootInfo->bootFile, kernel, sizeof(bootInfo->bootFile) );
strlcpy( bootInfo->bootFile, kernel, sizeof(bootInfo->bootFile)+1 );
gOverrideKernel = true;
} else {
if ( getValueForKey( kKernelNameKey, &val, &cnt, &bootInfo->bootConfig ) ) {
gOverrideKernel = true;
}
} else {
strlcpy( bootInfo->bootFile, kDefaultKernel, sizeof(bootInfo->bootFile) );
strlcpy( bootInfo->bootFile, kDefaultKernel, sizeof(bootInfo->bootFile)+1 );
}
}
branches/cparm/i386/boot2/Makefile
7777
7878
7979
80
80
8181
8282
8383
@echo "\t[LD] boot.sys"
@$(LD) -static -Wl,-preload -Wl,-segaddr,__INIT,$(BOOT2ADDR) \
-nostdlib -arch i386 -Wl,-segalign,20 \
-o $(SYMROOT)/boot.sys $(filter %.o,$^) $(LIBS) -lcc_kext
-o $(SYMROOT)/boot.sys $(filter %.o,$^) $(LIBS) -lcc_kext
@echo "\t[MACHOCONV] boot"
@$(SYMROOT)/machOconv $(SYMROOT)/boot.sys $(SYMROOT)/boot &> /dev/null
branches/cparm/i386/modules/ACPIPatcher/AcpiPatcher.c
3737
3838
3939
40
40
4141
4242
4343
enable = (execute_hook("isACPIRegistred", NULL, NULL, NULL, NULL, NULL, NULL) != EFI_SUCCESS);
if (enable) {
register_hook_callback("setupEfiConfigurationTable", &AcpiPatcher_setupEfiConfigurationTable_hook);
register_hook_callback("setupAcpiEfi", &AcpiPatcher_setupEfiConfigurationTable_hook);
register_hook_callback("isACPIRegistred", &is_ACPI_Patcher_Registred_Hook);
}
branches/cparm/i386/modules/GUI/gui.c
22242224
22252225
22262226
2227
22272228
22282229
22292230
for ( time = time18(), timeout++; timeout > 0; )
{
if( time18() > (unsigned)lasttime)
{
multi--;
branches/cparm/i386/modules/GraphicsEnabler/gma.c
1818
1919
2020
21
22
23
24
25
2126
2227
2328
......
6065
6166
6267
63
68
69
70
71
72
73
74
75
6476
6577
6678
......
151163
152164
153165
166
167
168
169
170
154171
155172
156173
#define DBG(x...)
#endif
uint8_t HD3000_os_info[20] = {
0x30,0x49,0x01,0x11,0x11,0x11,0x08,0x00,0x00,0x01,
0xf0,0x1f,0x01,0x00,0x00,0x00,0x10,0x07,0x00,0x00
};
uint8_t GMAX3100_vals[22][4] = {
{ 0x01,0x00,0x00,0x00 },
{ 0x01,0x00,0x00,0x00 },
{ 0x80862A12, "GMAX3100" },
{ 0x80862A13, "GMAX3100" },
{ 0x80862A42, "GMAX3100" },
{ 0x80862A43, "GMAX3100" }
{ 0x80862A43, "GMAX3100" },
{ 0x80860102, "Intel HD Graphics 3000" },
{ 0x80860106, "Intel HD Graphics 3000" },
{ 0x8086010A, "Intel HD Graphics 3000" },
{ 0x80860112, "Intel HD Graphics 3000" },
{ 0x80860116, "Intel HD Graphics 3000" },
{ 0x80860122, "Intel HD Graphics 3000" },
{ 0x80860126, "Intel HD Graphics 3000" }
};
static char *get_gma_model(uint32_t id);
devprop_add_value(device, "AAPL01,Stretch",GMAX3100_vals[21], 4);
devprop_add_value(device, "class-code", ClassFix, 4);
}
else if (model == (char *)"Intel HD Graphics 3000")
{
devprop_add_value(device, "AAPL,os-info", HD3000_os_info, 20);
}
stringdata = malloc(sizeof(uint8_t) * string->length);
if(!stringdata)
branches/cparm/i386/modules/GraphicsEnabler/nvidia.c
194194
195195
196196
197
197
198198
199199
200200
......
230230
231231
232232
233
233
234234
235235
236236
......
270270
271271
272272
273
273
274274
275
275
276276
277277
278278
......
394394
395395
396396
397
397398
398399
399400
......
491492
492493
493494
494
495
495
496496
497497
498498
499499
500500
501501
502
503
502
504503
505504
506505
......
557556
558557
559558
560
559
561560
562561
563562
......
810809
811810
812811
812
813813
814814
815815
......
13511351
13521352
13531353
1354
1355
1354
13561355
13571356
13581357
......
13651364
13661365
13671366
1368
1369
1367
13701368
13711369
13721370
{ 0x10DE01D0, "GeForce 7350 LE" },
{ 0x10DE01D1, "GeForce 7300 LE" },
{ 0x10DE01D2, "GeForce 7550 LE" },
{ 0x10DE01D3, "GeForce 7300 SE/7200 GS" },
{ 0x10DE01D3, "GeForce 7300 SE / 7200 GS" },
{ 0x10DE01D6, "GeForce Go 7200" },
{ 0x10DE01D7, "GeForce Go 7300" },
{ 0x10DE01D8, "GeForce Go 7400" },
// 0280 - 028F
// 0290 - 029F
{ 0x10DE0290, "GeForce 7900 GTX" },
{ 0x10DE0291, "GeForce 7900 GT/GTO" },
{ 0x10DE0291, "GeForce 7900 GT / GTO" },
{ 0x10DE0292, "GeForce 7900 GS" },
{ 0x10DE0293, "GeForce 7950 GX2" },
{ 0x10DE0294, "GeForce 7950 GX2" },
{ 0x10DE0324, "GeForce FX Go5200" },
{ 0x10DE0325, "GeForce FX Go5250" },
{ 0x10DE0326, "GeForce FX 5500" },
{ 0x10DE0328, "GeForce FX Go5200 32M/64M" },
{ 0x10DE0328, "GeForce FX Go5200 32M / 64M" },
{ 0x10DE032A, "Quadro NVS 55/280 PCI" },
{ 0x10DE032B, "Quadro FX 500/600 PCI" },
{ 0x10DE032B, "Quadro FX 500 / 600 PCI" },
{ 0x10DE032C, "GeForce FX Go53xx Series" },
{ 0x10DE032D, "GeForce FX Go5100" },
// 0330 - 033F
{ 0x10DE05E2, "GeForce GTX 260" },
{ 0x10DE05E3, "GeForce GTX 285" },
{ 0x10DE05E6, "GeForce GTX 275" },
{ 0x10DE05E7, "Tesla C1060" },
{ 0x10DE05EA, "GeForce GTX 260" },
{ 0x10DE05EB, "GeForce GTX 295" },
{ 0x10DE05ED, "Quadroplex 2200 D2" },
{ 0x10DE06CA, "GeForce GTX 480M" },
{ 0x10DE06CD, "GeForce GTX 470" },
// 06D0 - 06DF
{ 0x10DE06D1, "Tesla C2050" },// TODO: sub-device id: 0x0771
{ 0x10DE06D1, "Tesla C2070" },// TODO: sub-device id: 0x0772
{ 0x10DE06D1, "Tesla C2050 / C2070" },// TODO: sub-device id for the C2050: 0x0771, sub-device id for the C2070: 0x0772
{ 0x10DE06D2, "Tesla M2070" },
{ 0x10DE06D8, "Quadro 6000" },
{ 0x10DE06D9, "Quadro 5000" },
{ 0x10DE06DA, "Quadro 5000M" },
{ 0x10DE06DC, "Quadro 6000" },
{ 0x10DE06DD, "Quadro 4000" },
{ 0x10DE06DE, "Tesla M2050" },// TODO: sub-device id: 0x0846
{ 0x10DE06DE, "Tesla M2070" },// TODO: sub-device id: ?
{ 0x10DE06DE, "Tesla M2050 / M2070" },// TODO: sub-device id for the M2050: 0x0846
// 0x10DE06DE also applies to misc S2050, X2070, M2050, M2070
// 06E0 - 06EF
{ 0x10DE06E0, "GeForce 9300 GE" },
{ 0x10DE0849, "GeForce 8200" },
{ 0x10DE084A, "nForce 730a" },
{ 0x10DE084B, "GeForce 9200" },
{ 0x10DE084C, "nForce 980a/780a SLI" },
{ 0x10DE084C, "nForce 980a / 780a SLI" },
{ 0x10DE084D, "nForce 750a SLI" },
{ 0x10DE084F, "GeForce 8100 / nForce 720a" },
// 0850 - 085F
// 10B0 - 10BF
// 10C0 - 10CF
{ 0x10DE10C3, "GeForce 8400 GS" },
{ 0x10DE10C5, "GeForce 405" },
// 1200 -
{ 0x10DE1200, "GeForce GTX 560 Ti" },
{ 0x10DE1244, "GeForce GTX 550 Ti" },
{
memcpy(default_dcfg_0, new_dcfg0, DCFG0_LEN);
verbose("Using user supplied @0,display-cfg\n");
printf("@0,display-cfg: %02x%02x%02x%02x\n",
verbose("@0,display-cfg: %02x%02x%02x%02x\n",
default_dcfg_0[0], default_dcfg_0[1], default_dcfg_0[2], default_dcfg_0[3]);
}
}
{
memcpy(default_dcfg_1, new_dcfg1, DCFG1_LEN);
verbose("Using user supplied @1,display-cfg\n");
printf("@1,display-cfg: %02x%02x%02x%02x\n",
verbose("@1,display-cfg: %02x%02x%02x%02x\n",
default_dcfg_1[0], default_dcfg_1[1], default_dcfg_1[2], default_dcfg_1[3]);
}
}
branches/cparm/i386/modules/HibernateEnabler/resume.c
1717
1818
1919
20
21
2022
2123
2224
......
103105
104106
105107
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
106278
107279
108280
......
111283
112284
113285
286
287
288
289
290
291
114292
115293
116294
......
146324
147325
148326
149
150
151
152
153
154
155
156
327
157328
158329
159330
......
178349
179350
180351
181
352
182353
183354
184355
185
356
186357
187358
188359
#include "resume.h"
#include "graphic_utils.h"
extern char gMacOSVersion[];
extern int previewTotalSectors;
extern int previewLoadedSectors;
extern uint8_t *previewSaveunder;
return;
}
static void WakeKernel107(IOHibernateImageHeader107 * 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->restore1CodePhysPage << 12);
count = header->restore1PageCount;
proc = (header->restore1CodeOffset + ((uint32_t) dst));
newSP = header->restore1StackOffset + (header->restore1CodePhysPage << 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;
}
static void HibernateBoot107(char *image_filename)
{
long long size, imageSize, codeSize, allocSize;
long mem_base;
IOHibernateImageHeader107 _header;
IOHibernateImageHeader107 * header = &_header;
long buffer;
size = ReadFileAtOffset (image_filename, header, 0, sizeof(IOHibernateImageHeader107));
printf("header read size %x\n", size);
imageSize = header->image1Size;
codeSize = header->restore1PageCount << 12;
if (kIOHibernateHeaderSignature != header->signature)
{
printf ("Incorrect image signature, expected version 10.7\n");
getchar();
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);
bcopy(header, (void *) mem_base, sizeof(IOHibernateImageHeader107));
header = (IOHibernateImageHeader107 *) mem_base;
imageSize -= sizeof(IOHibernateImageHeader107);
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(IOHibernateImageHeader107), 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(IOHibernateImageHeader107)+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(IOHibernateImageHeader107), 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
WakeKernel107(header);
}
void HibernateBoot(char *image_filename)
{
long long size, imageSize, codeSize, allocSize;
IOHibernateImageHeader * header = &_header;
long buffer;
if(gMacOSVersion[3] == '7')
{
HibernateBoot107(image_filename);
return;
}
size = ReadFileAtOffset (image_filename, header, 0, sizeof(IOHibernateImageHeader));
printf("header read size %x\n", size);
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");
getc ();
return;
}
bcopy(header, (void *) mem_base, sizeof(IOHibernateImageHeader));
header = (IOHibernateImageHeader *) mem_base;
previewLoadedSectors = 0;
previewSaveunder = 0;
#if 0
AsereBLN:
/*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
remove it completely*/
#if UNUSED
setVideoMode(VGA_TEXT_MODE, 0);
#else
branches/cparm/i386/modules/HibernateEnabler/IOHibernatePrivate.h
9595
9696
9797
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
98159
160
161
162
99163
100164
101165
};
typedef struct IOHibernateImageHeader IOHibernateImageHeader;
struct IOHibernateImageHeader107
{
uint64_timageSize;
uint64_timage1Size;
uint32_trestore1CodePhysPage;
uint32_t reserved1;
uint64_trestore1CodeVirt;
uint32_trestore1PageCount;
uint32_trestore1CodeOffset;
uint32_trestore1StackOffset;
uint32_tpageCount;
uint32_tbitmapSize;
uint32_trestore1Sum;
uint32_timage1Sum;
uint32_timage2Sum;
uint32_tactualRestore1Sum;
uint32_tactualImage1Sum;
uint32_tactualImage2Sum;
uint32_tactualUncompressedPages;
uint32_tconflictCount;
uint32_tnextFree;
uint32_tsignature;
uint32_tprocessorFlags;
uint32_t runtimePages;
uint32_t runtimePageCount;
uint64_t runtimeVirtualPages __attribute__ ((packed));
uint32_t performanceDataStart;
uint32_t performanceDataSize;
uint64_tencryptStart __attribute__ ((packed));
uint64_tmachineSignature __attribute__ ((packed));
uint32_t previewSize;
uint32_t previewPageListSize;
uint32_tdiag[4];
uint32_t handoffPages;
uint32_t handoffPageCount;
uint32_t systemTableOffset;
uint32_tdebugFlags;
uint32_toptions;
uint32_treserved[70];// make sizeof == 512
uint64_tencryptEnd __attribute__ ((packed));
uint64_tdeviceBase __attribute__ ((packed));
uint32_tfileExtentMapSize;
IOPolledFileExtentfileExtentMap[2];
};
typedef struct IOHibernateImageHeader107 IOHibernateImageHeader107;
struct hibernate_bitmap_t
{
uint32_tfirst_page;
branches/cparm/i386/modules/HibernateEnabler/HibernateEnabler.c
22
33
44
5
6
7
5
86
97
108
* HibernateEnabler.c
* Chameleon
*
* Created by cparm. <armelcadetpetit@gmail.com>
* Copyright 2010. All rights reserved.
*
* Created by cparm.
*/
#include "bootstruct.h"
branches/cparm/i386/modules/Keymapper/Keymapper.c
1414
1515
1616
17
18
1719
20
21
22
23
24
25
26
27
28
29
30
31
1832
1933
2034
......
228242
229243
230244
231
245
246
232247
233248
#define kEnableKeyMap "EnableKeyMapper"
static int AZERTY_switch(int c);
void Keymapper_hook(void* arg1, void* arg2, void* arg3, void* arg4, void* arg5, void* arg6);
int Keymapper_getc();
int Keymapper_getc()
{
int c = bgetc();
//execute_hook("Keymapper", &c, NULL, NULL, NULL, NULL, NULL);
Keymapper_hook(&c, NULL, NULL, NULL, NULL, NULL);
if ((c & 0xff) == 0)
return c;
else
return (c & 0xff);
}
// CPARM's AZERTY_switch : A Basic QWERTY to AZERTY switcher
static int AZERTY_switch(int c)
if (enable)
{
register_hook_callback("Keymapper", &Keymapper_hook);
//register_hook_callback("Keymapper", &Keymapper_hook);
replace_function("_getc", &Keymapper_getc);
}
}
branches/cparm/i386/modules/ACPICodec/acpi_codec.c
9696
9797
9898
99
100
99
100
101101
102102
103103
......
145145
146146
147147
148
149
150
148151
149152
150153
......
176179
177180
178181
182
183
184
185
186
179187
180188
181189
......
291299
292300
293301
302
303
304
305
306
307
308
309
294310
295311
296312
......
311327
312328
313329
314
315
330
331
332
333
334
335
336
337
338
339
340
341
342
316343
317
318
319
320
321
322
323
324
325
344
326345
327346
328347
......
335354
336355
337356
357
358
359
360
361
362
363
338364
339365
340366
......
442468
443469
444470
471
472
473
474
475
476
445477
446478
447479
......
9941026
9951027
9961028
997
1029
9981030
9991031
10001032
......
13641396
13651397
13661398
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
13671425
13681426
13691427
......
13861444
13871445
13881446
1389
1390
1391
1392
1393
1394
1395
1447
13961448
13971449
13981450
......
14631515
14641516
14651517
1466
1467
1518
14681519
14691520
14701521
......
14891540
14901541
14911542
1492
1493
1494
1495
1496
1497
1498
1499
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
15001562
1501
1563
1564
1565
1566
1567
1568
15021569
1503
1570
15041571
1505
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
15061602
15071603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
15081614
15091615
1510
1511
1616
15121617
1513
1618
1619
1620
1621
15141622
1515
1516
1517
1518
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
15191638
1520
1521
1522
1523
1524
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
15251653
1526
1527
1528
1529
1530
1531
1532
1533
1654
1655
1656
1657
1658
1659
15341660
15351661
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
15361694
1537
1538
1539
1540
1541
1542
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
15431714
1544
1545
1546
1547
1548
1549
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
15501757
15511758
15521759
......
15861793
15871794
15881795
1589
1590
1591
1592
1593
1594
15951796
1596
1797
15971798
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1799
1800
1801
1802
16091803
1610
1611
1612
1613
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
16141842
1843
16151844
16161845
1617
1846
16181847
16191848
16201849
......
16281857
16291858
16301859
1631
1860
1861
1862
16321863
16331864
16341865
......
16441875
16451876
16461877
1878
16471879
16481880
16491881
......
16551887
16561888
16571889
1890
1891
1892
16581893
16591894
16601895
16611896
16621897
1663
1898
16641899
16651900
16661901
......
16961931
16971932
16981933
1699
1934
17001935
17011936
17021937
......
17221957
17231958
17241959
1725
1960
17261961
17271962
17281963
......
17411976
17421977
17431978
1744
1979
17451980
17461981
17471982
......
18102045
18112046
18122047
1813
1814
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
18152081
1816
1817
1818
1819
2082
2083
18202084
1821
1822
2085
2086
2087
18232088
18242089
18252090
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
2091
2092
18432093
18442094
18452095
......
18502100
18512101
18522102
1853
2103
18542104
18552105
18562106
......
21712421
21722422
21732423
2174
2424
21752425
2176
2426
21772427
21782428
21792429
21802430
21812431
21822432
2183
2433
21842434
2185
2435
21862436
21872437
21882438
21892439
21902440
21912441
2192
2442
21932443
2194
2444
21952445
21962446
21972447
......
22042454
22052455
22062456
2207
2457
22082458
22092459
22102460
......
22152465
22162466
22172467
2218
2468
22192469
22202470
22212471
......
22672517
22682518
22692519
2270
2520
22712521
22722522
22732523
22742524
22752525
22762526
2277
2527
22782528
2279
2280
2281
2282
2283
2284
2529
2530
2531
2532
2533
22852534
22862535
22872536
......
23172566
23182567
23192568
2320
2569
23212570
23222571
23232572
......
23252574
23262575
23272576
2328
2577
23292578
2330
2331
2332
2333
2334
2335
2336
2579
2580
2581
2582
2583
2584
23372585
23382586
23392587
......
24532701
24542702
24552703
2456
2704
24572705
24582706
24592707
24602708
2461
2709
24622710
2711
2712
2713
2714
2715
24632716
24642717
24652718
......
24742727
24752728
24762729
2477
2730
24782731
24792732
24802733
......
24822735
24832736
24842737
2485
2738
24862739
24872740
24882741
......
25062759
25072760
25082761
2762
2763
2764
2765
2766
25092767
25102768
25112769
......
35883846
35893847
35903848
3591
3592
3593
3594
3595
3596
3597
3849
35983850
35993851
36003852
......
36093861
36103862
36113863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
36123880
36133881
36143882
......
38794147
38804148
38814149
4150
4151
4152
4153
4154
38824155
38834156
38844157
......
39614234
39624235
39634236
3964
3965
3966
3967
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
39684247
39694248
39704249
3971
4250
4251
4252
4253
4254
4255
39724256
39734257
39744258
......
40034287
40044288
40054289
4290
4291
4292
4293
4294
40064295
40074296
40084297
......
40104299
40114300
40124301
4302
4303
4304
4305
4306
40134307
40144308
40154309
......
40244318
40254319
40264320
4321
4322
4323
4324
4325
40274326
40284327
40294328
......
40354334
40364335
40374336
4337
4338
4339
4340
4341
40384342
40394343
40404344
......
41784482
41794483
41804484
4181
4485
41824486
41834487
41844488
......
42004504
42014505
42024506
4203
4507
4508
4509
4510
4511
4512
42044513
42054514
42064515
......
43224631
43234632
43244633
4634
4635
43254636
4326
4327
4328
4329
4330
4331
4637
4638
4639
4640
4641
4642
43324643
4333
4644
43344645
4646
43354647
4336
43374648
43384649
43394650
......
43464657
43474658
43484659
4660
43494661
43504662
43514663
4352
4664
43534665
43544666
43554667
......
43614673
43624674
43634675
4676
4677
4678
4679
4680
4681
4682
43644683
43654684
43664685
......
44864805
44874806
44884807
4489
4490
4808
4809
44914810
4492
4493
4494
4495
4496
4497
4811
4812
4813
4814
4815
4816
44984817
4499
4818
45004819
45014820
4821
4822
45024823
4824
45034825
45044826
45054827
......
46304952
46314953
46324954
4633
4634
4635
46364955
46374956
46384957
......
46444963
46454964
46464965
4647
4648
4649
4650
4651
4966
46524967
46534968
46544969
......
46734988
46744989
46754990
4676
4677
4678
4679
4680
4991
46814992
46824993
46834994
......
47105021
47115022
47125023
4713
4714
4715
4716
4717
4718
5024
47195025
47205026
47215027
......
47235029
47245030
47255031
5032
5033
5034
47265035
47275036
47285037
......
47635072
47645073
47655074
4766
4767
4768
4769
5075
47705076
47715077
5078
47725079
47735080
47745081
......
47885095
47895096
47905097
5098
5099
47915100
47925101
47935102
static void *loadACPITable(char *dirspec, char *filename );
static int generate_cpu_map_from_acpi(ACPI_TABLE_DSDT * DsdtPointer);
static ACPI_GENERIC_ADDRESS FillGASStruct(U32 Address, U8 Length);
static void process_xsdt (ACPI_TABLE_RSDP *rsdp_mod , U32 *new_table_list);
static void process_rsdt(ACPI_TABLE_RSDP *rsdp_mod , bool gen_xsdt, U32 *new_table_list);
static U32 process_xsdt (ACPI_TABLE_RSDP *rsdp_mod , U32 *new_table_list);
static U32 process_rsdt(ACPI_TABLE_RSDP *rsdp_mod , bool gen_xsdt, U32 *new_table_list);
static ACPI_TABLE_FADT * patch_fadt(ACPI_TABLE_FADT *fadt, ACPI_TABLE_DSDT *new_dsdt, bool UpdateFADT);
#if OLD_SSDT
static bool is_jaketown(void);
static U32 encode_pstate(U32 ratio);
static void collect_cpu_info(CPU_DETAILS * cpu);
#ifndef BETA
static U32 BuildCoreIPstateInfo(CPU_DETAILS * cpu);
#endif
static U32 BuildCstateInfo(CPU_DETAILS * cpu, U32 pmbase);
static U32 BuildPstateInfo(CPU_DETAILS * cpu);
static U32 ProcessSsdt(U32 * new_table_list, ACPI_TABLE_DSDT *dsdt, bool enable_cstates, bool enable_pstates, bool enable_tstates );
static U64 divU64byU64(U64 n, U64 d, U64 * rem);
static U32 compute_tdp(CPU_DETAILS * cpu);
#endif
static bool is_sandybridge(void);
static bool is_jaketown(void);
static U32 get_bclk(void);
static U32 computePstateRatio(const U32 max, const U32 min, const U32 turboEnabled, const U32 numStates, const U32 pstate);
static U32 computeNumPstates(const U32 max, const U32 min, const U32 turboEnabled, const U32 pssLimit);
#endif // OLD_SSDT
{
void *tableAddr=(void*)AllocateKernelMemory(table_array[index]->Length);
if (!tableAddr) {
printf("Unable to allocate kernel memory for aml file ");
void *buf = (void*)new_table_list[index];
free(buf);
new_table_list[index] = 0ul ;
continue;
}
bcopy(table_array[index], tableAddr, table_array[index]->Length);
new_table_list[index] = 0ul ;
new_table_list[index] = (U32)tableAddr ;
{
ACPI_TABLE_RSDP * rsdp_conv = (ACPI_TABLE_RSDP *)AllocateKernelMemory(sizeof(ACPI_TABLE_RSDP));
bzero(rsdp_conv, sizeof(ACPI_TABLE_RSDP));
memcpy(rsdp_conv, rsdp, ACPI_RSDP_REV0_SIZE);
if (rsdp_conv) {
bzero(rsdp_conv, sizeof(ACPI_TABLE_RSDP));
memcpy(rsdp_conv, rsdp, ACPI_RSDP_REV0_SIZE);
/* Add/change fields */
rsdp_conv->Revision = 2; /* ACPI version 3 */
rsdp_conv->Length = sizeof(ACPI_TABLE_RSDP);
/* Correct checksums */
setRsdpchecksum(rsdp_conv);
setRsdpXchecksum(rsdp_conv);
}
/* Add/change fields */
rsdp_conv->Revision = 2; /* ACPI version 3 */
rsdp_conv->Length = sizeof(ACPI_TABLE_RSDP);
/* Correct checksums */
setRsdpchecksum(rsdp_conv);
setRsdpXchecksum(rsdp_conv);
return rsdp_conv;
return (rsdp_conv) ? rsdp_conv : (void*)0ul ;
}
static ACPI_TABLE_RSDT * gen_alloc_rsdt_from_xsdt(ACPI_TABLE_XSDT *xsdt)
num_tables= get_num_tables64(xsdt);
ACPI_TABLE_RSDT * rsdt_conv=(ACPI_TABLE_RSDT *)AllocateKernelMemory(sizeof(ACPI_TABLE_HEADER)+(num_tables * 4));
if (!rsdt_conv)
{
printf("Unable to allocate kernel memory for rsdt conv\n");
return (void*)0ul;
}
bzero(rsdt_conv, sizeof(ACPI_TABLE_HEADER)+(num_tables * 4));
memcpy(&rsdt_conv->Header, &xsdt->Header, sizeof(ACPI_TABLE_HEADER));
num_tables= get_num_tables(rsdt);
ACPI_TABLE_XSDT * xsdt_conv=(ACPI_TABLE_XSDT *)AllocateKernelMemory(sizeof(ACPI_TABLE_HEADER)+(num_tables * 8));
if (!xsdt_conv) {
printf("Unable to allocate kernel memory for xsdt conv\n");
return (void*)0ul;
}
bzero(xsdt_conv, sizeof(ACPI_TABLE_HEADER)+(num_tables * 8));
memcpy(&xsdt_conv->Header, &rsdt->Header, sizeof(ACPI_TABLE_HEADER));
bool cpu_noninteger_bus_ratio = (rdmsr64(MSR_IA32_PERF_STATUS) & (1ULL << 46));
//initial.Control = rdmsr64(MSR_IA32_PERF_STATUS);
initial.Control = rdmsr64(MSR_IA32_PERF_STATUS);
maximum.Control = ((rdmsr64(MSR_IA32_PERF_STATUS) >> 32) & 0x1F3F) | (0x4000 * cpu_noninteger_bus_ratio);
maximum.CID = ((maximum.FID & 0x1F) << 1) | cpu_noninteger_bus_ratio;
return Platform->CPU.Model == CPUID_MODEL_JAKETOWN;
}
static U32 get_bclk(void)
{
return (is_jaketown() || is_sandybridge()) ? 100 : 133;
}
//-----------------------------------------------------------------------------
static U32 computePstateRatio(const U32 max, const U32 min, const U32 turboEnabled, const U32 numStates, const U32 pstate)
{
U32 ratiorange = max-min;
U32 numGaps = numStates-1-turboEnabled;
U32 adjPstate = pstate-turboEnabled;
return (pstate == 0) ? (max + turboEnabled) :
(ratiorange == 0) ? max :
max-(((adjPstate*ratiorange)+(numGaps/2))/numGaps);
}
//-----------------------------------------------------------------------------
static U32 computeNumPstates(const U32 max, const U32 min, const U32 turboEnabled, const U32 pssLimit)
{
U32 ratiorange, maxStates, numStates;
ratiorange = max - min + 1;
maxStates = ratiorange + (turboEnabled ? 1 : 0);
numStates = (pssLimit < maxStates) ? pssLimit : maxStates;
return (numStates < 2) ? 0 : numStates;
}
#if BUILD_ACPI_TSS || pstate_power_support
static U64 divU64byU64(U64 n, U64 d, U64 * rem)
{
}
static U32 compute_tdp(CPU_DETAILS * cpu)
{
{
int tdp;
if (getIntForKey("TDP", &tdp, &bootInfo->bootConfig)) {
return (U32)tdp;
}
}
{
{
if (is_jaketown() || is_sandybridge())
// pstate_power[ratio] = (ratio/P1_ratio)^3 * Core_TDP + Uncore_TDP
// Core_TDP = (TURBO_POWER_CURRENT_LIMIT MSR 1ACh bit [30:16] / 8) Watts
//U32 Core_TDP = cpu->tdc_limit / 8;
U32 Core_TDP = compute_tdp(cpu);
U32 Core_TDP = cpu->tdc_limit / 8;
// Uncore_TDP = TDP - Core_TDP
U32 Uncore_TDP = TDP - Core_TDP;
}
//-----------------------------------------------------------------------------
static void collect_cpu_info(CPU_DETAILS * cpu)
{
U32 temp32;
U64 temp64;
if (Platform->CPU.MaxCoef)
{
if (Platform->CPU.MaxDiv)
void GetMaxRatio(U32 * max_non_turbo_ratio)
{
U32 index;
U32 max_ratio=0;
U32 frequency=0;
U32 multiplier = 0;
// Verify CPUID brand string function is supported
if (Platform->CPU.cpuid_max_ext < 80000004)
{
*max_non_turbo_ratio = max_ratio;
return;
}
// -2 to prevent buffer overrun because looking for y in yHz, so z is +2 from y
for (index=0; index<48-2; index++) {
// format is either “x.xxyHz” or “xxxxyHz”, where y=M,G,T and x is digits
// Search brand string for “yHz” where y is M, G, or T
// Set multiplier so frequency is in MHz
if ( Platform->CPU.BrandString[index+1] == 'H' && Platform->CPU.BrandString[index+2] == 'z')
{
cpu->max_ratio_as_cfg = cpu->max_ratio_as_mfg = (U32) (Platform->CPU.MaxCoef * 10) + 5;
if (Platform->CPU.BrandString[index] == 'M')
multiplier = 1;
else if (Platform->CPU.BrandString[index] == 'G')
multiplier = 1000;
else if (Platform->CPU.BrandString[index] == 'T')
multiplier = 1000000;
}
else
if (multiplier > 0 && index >= 4 /* who can i call that, buffer underflow :-) ??*/)
{
cpu->max_ratio_as_cfg = cpu->max_ratio_as_mfg = (U32) Platform->CPU.MaxCoef * 10;
// Copy 7 characters (length of “x.xxyHz”)
// index is at position of y in “x.xxyHz”
// Compute frequency (in MHz) from brand string
if (Platform->CPU.BrandString[index-3] == '.')
{ // If format is “x.xx”
if (isdigit(Platform->CPU.BrandString[index-4]) && isdigit(Platform->CPU.BrandString[index-2]) &&
isdigit(Platform->CPU.BrandString[index-1]))
{
frequency = (U32)(Platform->CPU.BrandString[index-4] - '0') * multiplier;
frequency += (U32)(Platform->CPU.BrandString[index-2] - '0') * (multiplier / 10);
frequency += (U32)(Platform->CPU.BrandString[index-1] - '0') * (multiplier / 100);
}
}
else
{ // If format is xxxx
if (isdigit(Platform->CPU.BrandString[index-4]) && isdigit(Platform->CPU.BrandString[index-3]) &&
isdigit(Platform->CPU.BrandString[index-2]) && isdigit(Platform->CPU.BrandString[index-1]))
{
frequency = (U32)(Platform->CPU.BrandString[index-4] - '0') * 1000;
frequency += (U32)(Platform->CPU.BrandString[index-3] - '0') * 100;
frequency += (U32)(Platform->CPU.BrandString[index-2] - '0') * 10;
frequency += (U32)(Platform->CPU.BrandString[index-1] - '0');
frequency *= multiplier;
}
}
max_ratio = frequency / get_bclk();
break;
}
}
// Return non-zero Max Non-Turbo Ratio obtained from CPUID brand string
// or return 0 indicating Max Non-Turbo Ratio not available
*max_non_turbo_ratio = max_ratio;
}
//-----------------------------------------------------------------------------
static void collect_cpu_info(CPU_DETAILS * cpu)
{
#if BUILD_ACPI_TSS || pstate_power_support
cpu->turbo_available = Platform->CPU.dynamic_acceleration;
if (!is_sandybridge() && !is_jaketown())
{
if (turbo_enabled && cpu->turbo_available)
U32 temp32 = 0;
U64 temp64= 0;
int tdp;
if (getIntForKey("TDP", &tdp, &bootInfo->bootConfig))
{
temp64 = rdmsr64(MSR_TURBO_POWER_CURRENT_LIMIT);
temp32 = (U32)temp64;
}
else
temp32 = (U32) (tdp*8) ;
int tdc;
if (getIntForKey("TDC", &tdc, &bootInfo->bootConfig))
{
temp32 = (U32) (temp32) | tdc<<16 ;
}
else if (tdp)
{
temp32 = (U32) (temp32) | ((tdp)*8)<<16 ;
}
}
else if (!is_sandybridge() && !is_jaketown())
{
// Unfortunately, Intel don't provide a better method for non turbo processors
// and it will give a TDP of 95w (for ex. mine is 65w) , to fix this issue,
// you can set this value by simply adding the option TDP = XX (XX is an integer)
// in your boot.plist (see compute_tdp)
temp32 = (U32)0x02a802f8;
if (turbo_enabled && cpu->turbo_available)
{
temp64 = rdmsr64(MSR_TURBO_POWER_CURRENT_LIMIT);
temp32 = (U32)temp64;
}
else
{
// Unfortunately, Intel don't provide a better method for non turbo processors
// and it will give a TDP of 95w (for ex. mine is 65w) , to fix this issue,
// you can set this value by simply adding the option TDP = XX (XX is an integer)
// in your boot.plist
temp32 = (U32)0x02a802f8;
}
}
cpu->tdp_limit = ( temp32 & 0x7fff );
cpu->tdc_limit = ( (temp32 >> 16) & 0x7fff );
}
if (is_sandybridge() || is_jaketown())
{
cpu->package_power_limit = rdmsr64(MSR_PKG_RAPL_POWER_LIMIT);
cpu->package_power_sku_unit = rdmsr64(MSR_RAPL_POWER_UNIT);
}
if (temp32) {
cpu->tdp_limit = ( temp32 & 0x7fff );
cpu->tdc_limit = ( (temp32 >> 16) & 0x7fff );
}
}
#endif
switch (Platform->CPU.Family)
{
case 0x06:
{
switch (Platform->CPU.Model)
{
case CPUID_MODEL_DOTHAN:
case CPUID_MODEL_YONAH: // Yonah
case CPUID_MODEL_MEROM: // Merom
case CPUID_MODEL_PENRYN: // Penryn
case CPUID_MODEL_ATOM: // Intel Atom (45nm)
{
cpu->core_c1_supported = ((Platform->CPU.sub_Cstates >> 4) & 0xf) ? 1 : 0;
cpu->core_c4_supported = ((Platform->CPU.sub_Cstates >> 16) & 0xf) ? 1 : 0;
if (Platform->CPU.Model == CPUID_MODEL_ATOM)
{
cpu->core_c2_supported = cpu->core_c3_supported = ((Platform->CPU.sub_Cstates >> 8) & 0xf) ? 1 : 0;
cpu->core_c6_supported = ((Platform->CPU.sub_Cstates >> 12) & 0xf) ? 1 : 0;
}
else
{
cpu->core_c3_supported = ((Platform->CPU.sub_Cstates >> 12) & 0xf) ? 1 : 0;
cpu->core_c2_supported = ((Platform->CPU.sub_Cstates >> 8) & 0xf) ? 1 : 0;
cpu->core_c6_supported = 0;
}
cpu->core_c7_supported = 0;
#if BETA
U64 msr = rdmsr64(MSR_IA32_PERF_STATUS);
U16 idlo = (msr >> 48) & 0xffff;
cpu->min_ratio = (U32)(idlo >> 8) & 0xff;
//U64 platform_info = rdmsr64(MSR_PLATFORM_INFO);
//cpu->min_ratio = (U32) ((platform_info >> 40) & 0xff); // This method don't work for me
GetMaxRatio(&cpu->max_ratio_as_mfg);
U64 msr = rdmsr64(MSR_IA32_PERF_STATUS);
U16 idlo = (msr >> 48) & 0xffff;
U16 idhi = (msr >> 32) & 0xffff;
cpu->min_ratio = (U32) (idlo >> 8) & 0xff;
cpu->max_ratio_as_cfg = (U32) (idhi >> 8) & 0xff;
#else
if (Platform->CPU.MaxCoef)
{
if (Platform->CPU.MaxDiv)
{
cpu->max_ratio_as_cfg = cpu->max_ratio_as_mfg = (U32) (Platform->CPU.MaxCoef * 10) + 5;
}
else
{
cpu->max_ratio_as_cfg = cpu->max_ratio_as_mfg = (U32) Platform->CPU.MaxCoef * 10;
}
}
#endif
// note: on c2d c6 & c7 cstates are not supported but it give me 1 with my e8500, i guess this mean that it can enter to c4
cpu->core_c1_supported = ((Platform->CPU.sub_Cstates >> 4) & 0xf) ? 1 : 0;
cpu->core_c3_supported = ((Platform->CPU.sub_Cstates >> 8) & 0xf) ? 1 : 0;
cpu->core_c6_supported = ((Platform->CPU.sub_Cstates >> 12) & 0xf) ? 1 : 0;
cpu->core_c7_supported = ((Platform->CPU.sub_Cstates >> 16) & 0xf) ? 1 : 0;
break;
}
case CPUID_MODEL_FIELDS:
case CPUID_MODEL_DALES:
case CPUID_MODEL_DALES_32NM:
case CPUID_MODEL_NEHALEM:
case CPUID_MODEL_NEHALEM_EX:
case CPUID_MODEL_WESTMERE:
case CPUID_MODEL_WESTMERE_EX:
case CPUID_MODEL_SANDYBRIDGE:
case CPUID_MODEL_JAKETOWN:
{
cpu->core_c1_supported = ((Platform->CPU.sub_Cstates >> 4) & 0xf) ? 1 : 0;
cpu->core_c3_supported = ((Platform->CPU.sub_Cstates >> 8) & 0xf) ? 1 : 0;
cpu->core_c6_supported = ((Platform->CPU.sub_Cstates >> 12) & 0xf) ? 1 : 0;
cpu->core_c7_supported = ((Platform->CPU.sub_Cstates >> 16) & 0xf) ? 1 : 0;
cpu->core_c2_supported = 0;
cpu->core_c4_supported = 0;
GetMaxRatio(&cpu->max_ratio_as_mfg);
U64 platform_info = rdmsr64(MSR_PLATFORM_INFO);
cpu->max_ratio_as_cfg = (U32) ((U32)platform_info >> 8) & 0xff;
cpu->min_ratio = (U32) ((platform_info >> 40) & 0xff);
if (is_sandybridge() || is_jaketown())
{
cpu->package_power_limit = rdmsr64(MSR_PKG_RAPL_POWER_LIMIT);
cpu->package_power_sku_unit = rdmsr64(MSR_RAPL_POWER_UNIT);
}
break;
}
default:
verbose ("Unsupported CPU\n");
return /*(0)*/;
break;
}
}
default:
break;
}
cpu->mwait_supported = (Platform->CPU.extensions & (1UL << 0)) ? 1 : 0;
}
#if BETA
static U32 get_bclk(void)
{
return (is_jaketown() || is_sandybridge()) ? 100 : 133;
}
//-----------------------------------------------------------------------------
static U32 computePstateRatio(const U32 max, const U32 min, const U32 turboEnabled, const U32 numStates, const U32 pstate)
static U32 BuildPstateInfo(CPU_DETAILS * cpu)
{
U32 ratiorange = max-min;
U32 numGaps = numStates-1-turboEnabled;
U32 adjPstate = pstate-turboEnabled;
return (pstate == 0) ? (max + turboEnabled) :
(ratiorange == 0) ? max :
max-(((adjPstate*ratiorange)+(numGaps/2))/numGaps);
}
//-----------------------------------------------------------------------------
static U32 computeNumPstates(const U32 max, const U32 min, const U32 turboEnabled, const U32 pssLimit)
{
U32 ratiorange, maxStates, numStates;
// Build P-state table info based on verified options
// Compute the number of p-states based on the ratio range
cpu->pkg_pstates.num_pstates = computeNumPstates(cpu->max_ratio_as_cfg, cpu->min_ratio, cpu->turbo_available, MAX_PSTATES);
ratiorange = max - min + 1;
maxStates = ratiorange + (turboEnabled ? 1 : 0);
numStates = (pssLimit < maxStates) ? pssLimit : maxStates;
return (numStates < 2) ? 0 : numStates;
if (!cpu->pkg_pstates.num_pstates)
{
return (0);
}
// Compute pstate data
{
U32 TDP = compute_tdp(cpu);
U32 index;
for (index=0; index < cpu->pkg_pstates.num_pstates; index ++)
{
PSTATE * pstate = &cpu->pkg_pstates.pstate[index];
// Set ratio
pstate->ratio = computePstateRatio(cpu->max_ratio_as_cfg, cpu->min_ratio, cpu->turbo_available, cpu->pkg_pstates.num_pstates, index);
// Compute frequency based on ratio
if ((index != 0) || (cpu->turbo_available == 0))
pstate->frequency = pstate->ratio * get_bclk();
else
pstate->frequency = ((pstate->ratio - 1) * get_bclk()) + 1;
// Compute power based on ratio and other data
if (pstate->ratio >= cpu->max_ratio_as_mfg)
// Use max power in mW
pstate->power = TDP * 1000;
else
{
pstate->power = compute_pstate_power(cpu, pstate->ratio, TDP);
// Convert to mW
pstate->power*= 1000;
}
}
}
return (1);
}
#else
//-----------------------------------------------------------------------------
static U32 BuildPstateInfo(CPU_DETAILS * cpu)
static U32 BuildCoreIPstateInfo(CPU_DETAILS * cpu)
{
// Build P-state table info based on verified options
// Compute pstate data
{
U32 TDP = compute_tdp(cpu);
#ifdef pstate_power_support
U32 TDP = compute_tdp(cpu);
#endif
U32 index;
for (index=0; index < cpu->pkg_pstates.num_pstates; index ++)
else
pstate->frequency = ((pstate->ratio - 1) * get_bclk()) + 1;
#ifdef pstate_power_support
// Compute power based on ratio and other data
if (pstate->ratio >= cpu->max_ratio_as_mfg)
// Use max power in mW
// Convert to mW
pstate->power*= 1000;
}
#else
pstate->power = 0;
#endif
}
}
return (1);
}
#else
//-----------------------------------------------------------------------------
static U32 BuildPstateInfo(CPU_DETAILS * cpu)
{
bool cpu_noninteger_bus_ratio = (rdmsr64(MSR_IA32_PERF_STATUS) & (1ULL << 46));
#if UNUSED
initial.Control = rdmsr64(MSR_IA32_PERF_STATUS);
//initial.Control = rdmsr64(MSR_IA32_PERF_STATUS);
#endif
maximum.Control = ((rdmsr64(MSR_IA32_PERF_STATUS) >> 32) & 0x1F3F) | (0x4000 * cpu_noninteger_bus_ratio);
maximum.CID = ((maximum.FID & 0x1F) << 1) | cpu_noninteger_bus_ratio;
wrmsr64(MSR_IA32_PERF_CONTROL, (msr & 0xFFFFFFFFFFFF0000ULL) | (maximum.FID << 8) | maximum.VID);
intel_waitforsts();
}
if (minimum.VID == maximum.VID)
{
U64 msr;
wrmsr64(MSR_IA32_PERF_CONTROL, (msr & 0xFFFFFFFFFFFF0000ULL) | (maximum.FID << 8) | maximum.VID);
intel_waitforsts();
}
minimum.CID = ((minimum.FID & 0x1F) << 1) >> cpu_dynamic_fsb;
// Sanity check
case CPUID_MODEL_SANDYBRIDGE:
case CPUID_MODEL_JAKETOWN:
{
maximum.Control = rdmsr64(MSR_IA32_PERF_STATUS) & 0xff; // Seems it always contains maximum multiplier value (with turbo, that's we need)...
minimum.Control = (rdmsr64(MSR_PLATFORM_INFO) >> 40) & 0xff;
/*
maximum.Control = rdmsr64(MSR_IA32_PERF_STATUS) & 0xff; // Seems it always contains maximum multiplier value (with turbo, that's we need)...
minimum.Control = (rdmsr64(MSR_PLATFORM_INFO) >> 40) & 0xff;
verbose("P-States: min 0x%x, max 0x%x\n", minimum.Control, maximum.Control);
// Sanity check
if (maximum.Control < minimum.Control)
{
DBG("Insane control values!");
p_states_count = 0;
}
else
{
U8 i;
p_states_count = 0;
for (i = maximum.Control; i >= minimum.Control; i--)
{
p_states[p_states_count].Control = i;
p_states[p_states_count].CID = p_states[p_states_count].Control << 1;
p_states[p_states_count].Frequency = (Platform->CPU.FSBFrequency / 1000000) * i;
p_states_count++;
if (p_states_count >= MAX_PSTATES) { // was 32
if (p_states_count > MAX_PSTATES) // was 32
p_states_count = MAX_PSTATES; // was 32
break;
}
}
}
*/
verbose("P-States: min 0x%x, max 0x%x\n", minimum.Control, maximum.Control);
// Sanity check
if (maximum.Control < minimum.Control)
bool sta = BuildCoreIPstateInfo(cpu);
if (sta)
{
DBG("Insane control values!");
p_states_count = 0;
DBG("_PSS PGK generated successfully\n");
return (1);
}
else
{
U8 i;
p_states_count = 0;
for (i = maximum.Control; i >= minimum.Control; i--)
{
p_states[p_states_count].Control = i;
p_states[p_states_count].CID = p_states[p_states_count].Control << 1;
p_states[p_states_count].Frequency = (Platform->CPU.FSBFrequency / 1000000) * i;
p_states_count++;
if (p_states_count >= MAX_PSTATES) { // was 32
if (p_states_count > MAX_PSTATES) // was 32
p_states_count = MAX_PSTATES; // was 32
break;
}
}
verbose("CoreI _PSS Generation failed !!\n");
return (0);
}
break;
break;
}
}
default:
default:
break;
}
}
static const ACPI_GENERIC_ADDRESS io_gas[] = {
{GAS_TYPE_FFH, 0,0,0,0x00}, // processor C1
{GAS_TYPE_SYSTEM_IO,8,0,0,0x14}, // processor C3 as ACPI C2
{GAS_TYPE_SYSTEM_IO,8,0,0,0x14}, // processor C3 as ACPI C2 or processor C2
{GAS_TYPE_SYSTEM_IO,8,0,0,0x14}, // processor C3 as ACPI C3
{GAS_TYPE_SYSTEM_IO,8,0,0,0x15}, // processor C3 as ACPI C4
{GAS_TYPE_SYSTEM_IO,8,0,0,0x15}, // processor C4 as ACPI C4
{GAS_TYPE_SYSTEM_IO,8,0,0,0x15}, // processor C6
{GAS_TYPE_SYSTEM_IO,8,0,0,0x16}, // processor C7
};
static const CSTATE mwait_cstate [] = {
{1,0x01,0x3e8}, // processor C1
{2,0x40,0x1f4}, // processor C3 as ACPI C2
{2,0x40,0x1f4}, // processor C3 as ACPI C2 or processor C2
{3,0x40,0x1f4}, // processor C3 as ACPI C3
{4,0x40,0x1f4}, // processor C3 as ACPI C4
{4,0x40,0x1f4}, // processor C4
{6/*was 3*/,0x60,0x15e}, // processor C6
{7/*was 3*/,0x60,0x0c8}, // processor C7
};
static const CSTATE io_cstate [] = {
{1,0x01,0x3e8}, // processor C1
{2,0x40,0x1f4}, // processor C3 as ACPI C2
{2,0x40,0x1f4}, // processor C3 as ACPI C2 or processor C2
{3,0x40,0x1f4}, // processor C3 as ACPI C3
{4,0x40,0x1f4}, // processor C3 as ACPI C4
{4,0x40,0x1f4}, // processor C4
{6/*was 3*/,0x60,0x15e}, // processor C6
{7/*was 3*/,0x60,0x0c8}, // processor C7
};
// ACPI C2 state.
// 1= processor core C3 can be used as an ACPI C2 state
// 0= processor core C3 cannot be used as an ACPI C2 state
int c2_enabled = 1;
int c2_enabled = 0;
// Desired state for the processor core C3 state included in the _CST
// 0= processor core C3 cannot be used as an ACPI C state
// 5= processor core C3 can be used as an ACPI C2 state
// if Invariant APIC Timer detected, else APIC C3 state
// 6= processor core C3 can be used as an ACPI C4 state
int c3_enabled = 2;
int c3_enabled = 3;
// Desired state for the processor core C3 state included in the _CST as an
// ACPI C4 state.
cpu->pkg_mwait_cstates.gas[cpu->pkg_mwait_cstates.num_cstates] = mwait_gas[cstate_2_index[CPU_C1]];
cpu->pkg_mwait_cstates.num_cstates++;
}
if (cpu->core_c3_supported && c2_enabled && (c2_enabled || (c3_enabled == 2) ||
if (((cpu->core_c3_supported || cpu->core_c2_supported) && (c2_enabled)) && ((c3_enabled == 2) ||
((c3_enabled == 4) && cpu->invariant_apic_timer_flag)))
{
cpu->pkg_mwait_cstates.cstate[cpu->pkg_mwait_cstates.num_cstates] = mwait_cstate[cstate_2_index[CPU_C3_ACPI_C2]];
cpu->pkg_mwait_cstates.gas[cpu->pkg_mwait_cstates.num_cstates] = mwait_gas[cstate_2_index[CPU_C3_ACPI_C2]];
cpu->pkg_mwait_cstates.num_cstates++;
}
if (c4_enabled)
if (cpu->core_c4_supported && c4_enabled)
{
if (cpu->core_c3_supported)
{
cpu->pkg_mwait_cstates.cstate[cpu->pkg_mwait_cstates.num_cstates] = mwait_cstate[cstate_2_index[CPU_C3_ACPI_C4]];
cpu->pkg_mwait_cstates.gas[cpu->pkg_mwait_cstates.num_cstates] = mwait_gas[cstate_2_index[CPU_C3_ACPI_C4]];
cpu->pkg_mwait_cstates.num_cstates++;
}
cpu->pkg_mwait_cstates.cstate[cpu->pkg_mwait_cstates.num_cstates] = mwait_cstate[cstate_2_index[CPU_C4]];
cpu->pkg_mwait_cstates.gas[cpu->pkg_mwait_cstates.num_cstates] = mwait_gas[cstate_2_index[CPU_C4]];
cpu->pkg_mwait_cstates.num_cstates++;
}
else
{
cpu->pkg_io_cstates.gas[cpu->pkg_io_cstates.num_cstates] = io_gas[cstate_2_index[CPU_C1]];
cpu->pkg_io_cstates.num_cstates++;
}
if (cpu->core_c3_supported && c2_enabled && (c2_enabled || (c3_enabled == 2) ||
if ((cpu->core_c3_supported || cpu->core_c2_supported) && (c2_enabled || (c3_enabled == 2) ||
((c3_enabled == 4) && cpu->invariant_apic_timer_flag)))
{
cpu->pkg_io_cstates.cstate[cpu->pkg_io_cstates.num_cstates] = io_cstate[cstate_2_index[CPU_C3_ACPI_C2]];
cpu->pkg_io_cstates.gas[cpu->pkg_io_cstates.num_cstates].Address += pmbase;
cpu->pkg_io_cstates.num_cstates++;
}
if (c4_enabled)
if (cpu->core_c4_supported && c4_enabled)
{
if (cpu->core_c3_supported)
{
cpu->pkg_io_cstates.cstate[cpu->pkg_io_cstates.num_cstates] = io_cstate[cstate_2_index[CPU_C3_ACPI_C4]];
cpu->pkg_io_cstates.gas[cpu->pkg_io_cstates.num_cstates] = io_gas[cstate_2_index[CPU_C3_ACPI_C4]];
cpu->pkg_io_cstates.gas[cpu->pkg_io_cstates.num_cstates].Address += pmbase;
cpu->pkg_io_cstates.num_cstates++;
}
cpu->pkg_io_cstates.cstate[cpu->pkg_io_cstates.num_cstates] = io_cstate[cstate_2_index[CPU_C4]];
cpu->pkg_io_cstates.gas[cpu->pkg_io_cstates.num_cstates] = io_gas[cstate_2_index[CPU_C4]];
cpu->pkg_io_cstates.gas[cpu->pkg_io_cstates.num_cstates].Address += pmbase;
cpu->pkg_io_cstates.num_cstates++;
}
else
{
if (Platform->CPU.Vendor != 0x756E6547) {
verbose ("Not an Intel platform: SSDT will not be generated !!!\n");
return(1);
return(0);
}
if (!(Platform->CPU.Features & CPUID_FEATURE_MSR)) {
verbose ("Unsupported CPU: SSDT will not be generated !!!\n");
return(1);
return(0);
}
if (dsdt == (void *)0ul) {
verbose ("DSDT not found: SSDT will not be generated !!!\n");
return (0);
}
{
bool tmpval;
{
printf("Error: not enought reserved space in the new acpi list for the SSDT table,\n ");
printf(" please increase the RESERVED_AERA\n");
return(1);
return(0);
}
if ((madt_file = (ACPI_TABLE_MADT *)get_new_table_in_list(new_table_list, NAMESEG("APIC"), &new_table_index)) != (void *)0ul)
if (oem_apic == false)
{
MadtPointer = (ACPI_TABLE_MADT *)madt_file;
new_table_list[new_table_index] = 0ul; // This way, the non-patched table will not be added in our new rsdt/xsdt table list // note: for now we don't patch this table
//new_table_list[new_table_index] = 0ul; // This way, the non-patched table will not be added in our new rsdt/xsdt table list // note: for now we don't patch this table
}
} else
// Reserved kernel memory for the ssdt table
ACPI_TABLE_SSDT *new_ssdt = (ACPI_TABLE_SSDT *)AllocateKernelMemory(old_ssdt->Header.Length);
if (!new_ssdt)
{
printf("Unable to allocate kernel memory for SSDT ");
return (0);
}
// Move the old stack buffer to kernel memory
memcpy(new_ssdt, old_ssdt, old_ssdt->Header.Length);
// (1) Setup pointers to SSDT memory location
void * current = buffer;
void * end = (U8 *)buffer + bufferSize;
// Check that we have a valid cpu_map (if it's not already done, it will try to generate it)
if (generate_cpu_map_from_acpi(dsdt) != 0)
{
return(0);
}
// Confirm a valid SSDT buffer was provided
if (!buffer)
{
return(0);
}
if (madt == (void*) 0ul)
{
return(0);
}
if (dsdt == (void*) 0ul)
{
return(0);
}
// Check that we have a valid cpu_map (if it's not already done, it will try to generate it)
if (generate_cpu_map_from_acpi(dsdt) != 0)
{
return(0);
}
collect_cpu_info(&cpu);
ProcessMadt(madt, &madt_info);
static ACPI_TABLE_FACS* generate_facs(bool updatefacs )
{
ACPI_TABLE_FACS* facs_mod=(ACPI_TABLE_FACS *)AllocateKernelMemory(sizeof(ACPI_TABLE_FACS));
if (!facs_mod)
{
printf("Unable to allocate kernel memory for facs mod\n");
return (void*)0ul;
}
bzero(facs_mod, sizeof(ACPI_TABLE_FACS));
ACPI_TABLE_FACS * FacsPointer =(acpi_tables.FacsPointer64 != (void *)0ul) ?
{
if (fadt->Header.Length < 0xF4)
{
fadt_mod=(ACPI_TABLE_FADT *)AllocateKernelMemory(0xF4);
bzero(fadt_mod, 0xF4);
memcpy(fadt_mod, fadt, fadt->Header.Length);
fadt_mod->Header.Length = 0xF4;
fadt_mod=(ACPI_TABLE_FADT *)AllocateKernelMemory(0xF4);
if (!fadt_mod)
{
printf("Unable to allocate kernel memory for fadt mod\n");
return (void*)0ul;
}
bzero(fadt_mod, 0xF4);
memcpy(fadt_mod, fadt, fadt->Header.Length);
fadt_mod->Header.Length = 0xF4;
}
else
{
fadt_mod=(ACPI_TABLE_FADT *)AllocateKernelMemory(fadt->Header.Length);
fadt_mod=(ACPI_TABLE_FADT *)AllocateKernelMemory(fadt->Header.Length);
if (!fadt_mod)
{
printf("Unable to allocate kernel memory for fadt mod\n");
return (void*)0ul;
}
memcpy(fadt_mod, fadt, fadt->Header.Length);
}
if (fadt->Header.Length < 0x84 )
{
fadt_mod=(ACPI_TABLE_FADT *)AllocateKernelMemory(0x84);
if (!fadt_mod)
{
printf("Unable to allocate kernel memory for fadt mod\n");
return (void*)0ul;
}
bzero(fadt_mod, 0x84);
memcpy(fadt_mod, fadt, fadt->Header.Length);
fadt_mod->Header.Length = 0x84;
else
{
fadt_mod=(ACPI_TABLE_FADT *)AllocateKernelMemory(fadt->Header.Length);
if (!fadt_mod)
{
printf("Unable to allocate kernel memory for fadt mod\n");
return (void*)0ul;
}
memcpy(fadt_mod, fadt, fadt->Header.Length);
}
if (fadt->Header.Length < 0x74 )
{
fadt_mod=(ACPI_TABLE_FADT *)AllocateKernelMemory(0x74);
if (!fadt_mod)
{
printf("Unable to allocate kernel memory for fadt mod\n");
return (void*)0ul;
}
bzero(fadt_mod, 0x74);
memcpy(fadt_mod, fadt, fadt->Header.Length);
fadt_mod->Header.Length = 0x74;
else
{
fadt_mod=(ACPI_TABLE_FADT *)AllocateKernelMemory(fadt->Header.Length);
if (!fadt_mod)
{
printf("Unable to allocate kernel memory for fadt mod\n");
return (void*)0ul;
}
memcpy(fadt_mod, fadt, fadt->Header.Length);
}
}
return fadt_mod;
}
static void process_xsdt (ACPI_TABLE_RSDP *rsdp_mod , U32 *new_table_list)
static U32 process_xsdt (ACPI_TABLE_RSDP *rsdp_mod , U32 *new_table_list)
{
TagPtr DropTables_p = XMLCastDict(XMLGetProperty(bootInfo->bootConfig.dictionary, (const char*)"ACPIDropTables"));
U32 new_table = 0ul;
U32 dropoffset=0, index;
table_added = 0;
xsdt_mod=(ACPI_TABLE_XSDT *)AllocateKernelMemory(xsdt->Header.Length);
xsdt_mod=(ACPI_TABLE_XSDT *)AllocateKernelMemory(xsdt->Header.Length);
if (!xsdt_mod)
{
printf("Unable to allocate kernel memory for xsdt mod\n");
return (0);
}
bzero(xsdt_mod, xsdt->Header.Length);
memcpy(&xsdt_mod->Header, &xsdt->Header, sizeof(ACPI_TABLE_HEADER));
rsdt_conv = (ACPI_TABLE_RSDT *)gen_alloc_rsdt_from_xsdt(xsdt_mod);
if (rsdt_conv != (void*)0ul)
{
#if DEBUG_ACPI
DBG("Attempting to update RSDP with RSDT \n");
{
U32 ret = update_rsdp_with_rsdt(rsdp_mod, rsdt_conv);
if (ret)
DBG("RSDP update with RSDT successfully !!! \n");
}
DBG("Attempting to update RSDP with RSDT \n");
{
U32 ret = update_rsdp_with_rsdt(rsdp_mod, rsdt_conv);
if (ret)
DBG("RSDP update with RSDT successfully !!! \n");
}
#else
update_rsdp_with_rsdt(rsdp_mod, rsdt_conv);
update_rsdp_with_rsdt(rsdp_mod, rsdt_conv);
#endif
}
}
else
{
rsdp_mod->XsdtPhysicalAddress=0xffffffffffffffffLL;
verbose("XSDT not found or XSDT incorrect\n");
}
return (1);
}
static void process_rsdt(ACPI_TABLE_RSDP *rsdp_mod , bool gen_xsdt, U32 *new_table_list)
static U32 process_rsdt(ACPI_TABLE_RSDP *rsdp_mod , bool gen_xsdt, U32 *new_table_list)
{
TagPtr DropTables_p = XMLCastDict(XMLGetProperty(bootInfo->bootConfig.dictionary, (const char*)"ACPIDropTables"));
U32 new_table = 0ul;
rsdt=(ACPI_TABLE_RSDT *)acpi_tables.RsdtPointer;
rsdt_mod=(ACPI_TABLE_RSDT *)AllocateKernelMemory(rsdt->Header.Length);
if (!rsdt_mod)
{
printf("Unable to allocate kernel memory for rsdt mod\n");
return (0);
}
bzero(rsdt_mod, rsdt->Header.Length);
memcpy (&rsdt_mod->Header, &rsdt->Header, sizeof(ACPI_TABLE_HEADER));
verbose("* Creating new XSDT from RSDT table\n");
xsdt_conv = (ACPI_TABLE_XSDT *)gen_alloc_xsdt_from_rsdt(rsdt_mod);
update_rsdp_with_xsdt(rsdp_mod, xsdt_conv);
if (xsdt_conv != (void *)0ul )
{
#if DEBUG_ACPI
DBG("Attempting to update RSDP with XSDT \n");
{
U32 ret = update_rsdp_with_xsdt(rsdp_mod, xsdt_conv);
if (ret)
DBG("RSDP update with XSDT successfully !!! \n");
}
DBG("Attempting to update RSDP with XSDT \n");
{
U32 ret = update_rsdp_with_xsdt(rsdp_mod, xsdt_conv);
if (ret)
DBG("RSDP update with XSDT successfully !!! \n");
}
#else
update_rsdp_with_xsdt(rsdp_mod, xsdt_conv);
update_rsdp_with_xsdt(rsdp_mod, xsdt_conv);
#endif
}
}
return (1);
}
EFI_STATUS setupAcpi(void)
continue;
}
//char* tmp = malloc(strlen(name) + 1);
//strcpy(tmp, name);
DBG("* Attempting to load acpi table: %s\n", name);
if ( (new_table_list[i]=(U32)loadACPITable(dirspec,name)))
{
{
break;
}
}
//else
//{
//free(tmp);
//}
}
}
#if DEBUG_ACPI
}
}
// TODO : Add an option for that
//cpuNamespace = CPU_NAMESPACE_PR; //Default
if (speed_step)
{
gen_psta= true;
rsdplength=(Revision == 2)?rsdp->Length:ACPI_RSDP_REV0_SIZE;
DBG("RSDP Revision %d found @%x. Length=%d\n",Revision,rsdp,rsdplength);
/* FIXME: no check that memory allocation succeeded
* Copy and patch RSDP,RSDT, XSDT and FADT
* For more info see ACPI Specification pages 110 and following
*/
if (gen_xsdt)
{
rsdp_mod=rsdp_conv;
else
{
rsdp_mod=(ACPI_TABLE_RSDP *) AllocateKernelMemory(rsdplength);
if (!rsdp_mod) return EFI_OUT_OF_RESOURCES;
memcpy(rsdp_mod, rsdp, rsdplength);
}
{
fadt_mod = patch_fadt(FacpPointer, (oem_dsdt == false) ? new_dsdt : (void*)0ul , (acpi_tables.FacpPointer64 != (void *)0ul ));
DsdtPtr = ((fadt_mod->Header.Revision >= 3) && (fadt_mod->XDsdt != 0)) ? (ACPI_TABLE_DSDT*)((U32)fadt_mod->XDsdt):(ACPI_TABLE_DSDT*)fadt_mod->Dsdt;
if (fadt_mod != (void*)0ul)
{
DsdtPtr = ((fadt_mod->Header.Revision >= 3) && (fadt_mod->XDsdt != 0)) ? (ACPI_TABLE_DSDT*)((U32)fadt_mod->XDsdt):(ACPI_TABLE_DSDT*)fadt_mod->Dsdt;
U8 empty = get_0ul_index_in_list(new_table_list,true);
if (empty != ACPI_TABLE_LIST_FULL)
fadt_mod = (acpi_tables.FacpPointer64 != (void *)0ul) ?
(ACPI_TABLE_FADT *)acpi_tables.FacpPointer64 : (ACPI_TABLE_FADT *)acpi_tables.FacpPointer;
DsdtPtr = ((fadt_mod->Header.Revision >= 3) && (fadt_mod->XDsdt != 0)) ? (ACPI_TABLE_DSDT*)((U32)fadt_mod->XDsdt):(ACPI_TABLE_DSDT*)fadt_mod->Dsdt;
U8 empty = get_0ul_index_in_list(new_table_list,true);
if (empty != ACPI_TABLE_LIST_FULL)
{
branches/cparm/i386/modules/ACPICodec/ACPICodec.c
3232
3333
3434
35
35
3636
3737
3838
if (enable)
{
register_hook_callback("setupEfiConfigurationTable", &ACPICodec_setupEfiConfigurationTable_hook);
register_hook_callback("setupAcpiEfi", &ACPICodec_setupEfiConfigurationTable_hook);
register_hook_callback("isACPIRegistred", &is_ACPI_Codec_Registred_Hook);
}
branches/cparm/Makefile
1919
2020
2121
22
22
2323
2424
2525
......
8686
8787
8888
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
104110
111
112
113
114
115
116
117
118
119
120
121
105122
106123
107124
OBJROOT = `pwd`/obj
SYMROOT = `pwd`/sym
DSTROOT = `pwd`/dst
SRCROOT = /tmp
SRCROOT = `pwd`
DOCROOT = `pwd`/doc
IMGROOT = `pwd`/sym/cache
IMGSKELROOT = `pwd`/imgskel
done
image:
@if [ -e "$(SYMROOT)" ]; then \
rm -r -f ${IMGROOT}; \
mkdir -p ${IMGROOT}/usr/standalone/i386; \
if [ -e "$(IMGSKELROOT)" ]; then \
cp -R -f "${IMGSKELROOT}"/* "${IMGROOT}"; \
fi; \
cp -f ${SYMROOT}/i386/cdboot ${CDBOOT}; \
cp -f ${SYMROOT}/i386/boot ${IMGROOT}/usr/standalone/i386; \
cp -f ${SYMROOT}/i386/boot0 ${IMGROOT}/usr/standalone/i386; \
cp -f ${SYMROOT}/i386/boot1h ${IMGROOT}/usr/standalone/i386; \
cp -f ${SYMROOT}/i386/boot1f32 ${IMGROOT}/usr/standalone/i386;\
$(shell hdiutil makehybrid -iso -joliet -hfs -hfs-volume-name \
${CDLABEL} -eltorito-boot ${CDBOOT} -no-emul-boot -ov -o \
"${ISOIMAGE}" ${IMGROOT} -quiet) \
fi;
@rm -rf ${IMGROOT}
@mkdir -p ${IMGROOT}/usr/standalone/i386
@mkdir -p ${IMGROOT}/Extra/modules
@mkdir -p ${IMGROOT}/Extra/Themes/Default
@mkdir -p ${IMGROOT}/usr/bin
@if [ -e "$(IMGSKELROOT)" ]; then\
@echo "\t[CP] ${IMGROOTSKEL} ${IMGROOT}"\
@cp -R -f "${IMGSKELROOT}"/* "${IMGROOT}";\
fi;
@cp -f ${SYMROOT}/i386/cdboot ${CDBOOT}
@#cp -f ${SYMROOT}/i386/Symbols.dylib ${IMGROOT}/Extra/modules
@#cp -f ${SYMROOT}/i386/AcpiCodec.dylib ${IMGROOT}/Extra/modules
@#cp -f ${SYMROOT}/i386/SmbiosGetters.dylib ${IMGROOT}/Extra/modules
@#cp -f ${SYMROOT}/i386/Memory.dylib ${IMGROOT}/Extra/modules
@#cp -f ${SYMROOT}/i386/keymapper.dylib ${IMGROOT}/Extra/modules
@#cp -f ${SYMROOT}/i386/Usbfix.dylib ${IMGROOT}/Extra/modules
@#cp -f ${SYMROOT}/i386/GraphicsEnabler.dylib ${IMGROOT}/Extra/modules
@#cp -f ${SYMROOT}/i386/GUI.dylib ${IMGROOT}/Extra/modules
@#cp -f ${SRCROOT}/artwork/themes/default/* ${IMGROOT}/Extra/Themes/Default
@cp -f ${SYMROOT}/i386/boot ${IMGROOT}/usr/standalone/i386
@cp -f ${SYMROOT}/i386/boot ${IMGROOT}/usr/standalone/i386
@cp -f ${SYMROOT}/i386/boot0 ${IMGROOT}/usr/standalone/i386
@cp -f ${SYMROOT}/i386/boot0hfs ${IMGROOT}/usr/standalone/i386
@cp -f ${SYMROOT}/i386/boot1h ${IMGROOT}/usr/standalone/i386
@cp -f ${SYMROOT}/i386/boot1f32 ${IMGROOT}/usr/standalone/i386
@hdiutil makehybrid -iso -joliet -hfs -hfs-volume-name \
${CDLABEL} -eltorito-boot ${CDBOOT} -no-emul-boot -ov -o \
"${ISOIMAGE}" ${IMGROOT} -quiet
pkg installer: embedtheme
@if [ -e "$(SYMROOT)" ]; then \
sudo `pwd`/package/buildpkg `pwd`/sym/package; \

Archive Download the corresponding diff file

Revision: 1525