Index: branches/cparm/TODO =================================================================== --- branches/cparm/TODO (revision 1524) +++ branches/cparm/TODO (revision 1525) @@ -1,6 +1,8 @@ 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(...), Index: branches/cparm/CHANGES =================================================================== --- branches/cparm/CHANGES (revision 1524) +++ branches/cparm/CHANGES (revision 1525) @@ -1,3 +1,13 @@ +- 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) @@ -5,10 +15,10 @@ - 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) @@ -16,7 +26,7 @@ - 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 Index: branches/cparm/i386/libsaio/console.c =================================================================== --- branches/cparm/i386/libsaio/console.c (revision 1524) +++ branches/cparm/i386/libsaio/console.c (revision 1525) @@ -137,7 +137,7 @@ { 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; Index: branches/cparm/i386/libsaio/smp-imps.c =================================================================== --- branches/cparm/i386/libsaio/smp-imps.c (revision 1524) +++ branches/cparm/i386/libsaio/smp-imps.c (revision 1525) @@ -244,9 +244,9 @@ * 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. Index: branches/cparm/i386/libsaio/cpu.c =================================================================== --- branches/cparm/i386/libsaio/cpu.c (revision 1524) +++ branches/cparm/i386/libsaio/cpu.c (revision 1525) @@ -17,7 +17,33 @@ #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 @@ -146,8 +172,69 @@ 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 @@ -184,18 +271,18 @@ 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 @@ -319,11 +406,11 @@ // 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: @@ -335,7 +422,7 @@ void scan_cpu(PlatformInfo_t *p) { - uint64_t tscFrequency, fsbFrequency, cpuFrequency; + uint64_t tscFrequency = 0, fsbFrequency = 0, cpuFrequency = 0; uint64_t msr; uint8_t maxcoef = 0, maxdiv = 0, currcoef = 0, currdiv = 0; uint32_t reg[4]; @@ -351,13 +438,13 @@ /* 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; /* @@ -386,17 +473,20 @@ 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); @@ -406,6 +496,14 @@ 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; @@ -416,33 +514,39 @@ 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) { /* @@ -453,61 +557,146 @@ 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_STATUS 0xC0010042 +#define K10_COFVID_STATUS 0xC0010071 + 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))) { @@ -533,7 +722,7 @@ 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); @@ -567,7 +756,7 @@ } } } -#if OLD_STYLE +#if LEGACY_CPU if (bus_ratio_max) { fsbFrequency = (tscFrequency / bus_ratio_max); @@ -582,7 +771,7 @@ } else { -#if OLD_STYLE +#if LEGACY_CPU cpuFrequency = tscFrequency; #else cpuFrequency = bus_ratio_max * fsbFrequency; @@ -604,7 +793,7 @@ 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 { @@ -617,9 +806,11 @@ /* XXX */ maxcoef = currcoef; } -#if OLD_STYLE + if (!currcoef) currcoef = maxcoef; +#if LEGACY_CPU if (maxcoef) - { + { + if (maxdiv) { fsbFrequency = ((tscFrequency * 2) / ((maxcoef * 2) + 1)); @@ -642,6 +833,8 @@ #endif } #else + + if (currdiv) { cpuFrequency = (fsbFrequency * ((currcoef * 2) + 1) / 2); @@ -661,12 +854,12 @@ { 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 } } @@ -688,40 +881,47 @@ 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 } Index: branches/cparm/i386/libsaio/platform.h =================================================================== --- branches/cparm/i386/libsaio/platform.h (revision 1524) +++ branches/cparm/i386/libsaio/platform.h (revision 1525) @@ -131,6 +131,7 @@ boolean_t fine_grain_clock_mod; uint32_t cpuid_max_basic; + uint32_t cpuid_max_ext; uint32_t sub_Cstates; uint32_t extensions; Index: branches/cparm/i386/libsaio/acpi_tools.c =================================================================== --- branches/cparm/i386/libsaio/acpi_tools.c (revision 1524) +++ branches/cparm/i386/libsaio/acpi_tools.c (revision 1525) @@ -89,7 +89,7 @@ // Init memory address as F000 segment and scan 64KB region if (!success) success = GetRsdtPointer((void *)0x0F0000, 0x10000, acpi_tables); - + if (!success) return (0ul); @@ -192,10 +192,31 @@ // 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); @@ -210,9 +231,9 @@ } return (0); } +#endif - //------------------------------------------------------------------------------- // // Procedure: GetChecksum - Performs byte checksum @@ -259,7 +280,7 @@ // 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); Index: branches/cparm/i386/libsaio/ppm.h =================================================================== --- branches/cparm/i386/libsaio/ppm.h (revision 1524) +++ branches/cparm/i386/libsaio/ppm.h (revision 1525) @@ -138,9 +138,10 @@ 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; @@ -196,7 +197,9 @@ 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; Index: branches/cparm/i386/libsaio/saio_types.h =================================================================== --- branches/cparm/i386/libsaio/saio_types.h (revision 1524) +++ branches/cparm/i386/libsaio/saio_types.h (revision 1525) @@ -236,17 +236,6 @@ //#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 Index: branches/cparm/i386/libsaio/fake_efi.c =================================================================== --- branches/cparm/i386/libsaio/fake_efi.c (revision 1524) +++ branches/cparm/i386/libsaio/fake_efi.c (revision 1525) @@ -429,9 +429,11 @@ */ /* 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 @@ -469,7 +471,7 @@ { 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) { @@ -708,16 +710,20 @@ 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); @@ -928,6 +934,7 @@ if (smbios_p) addConfigurationTable(&gEfiSmbiosTableGuid, &smbios_p, NULL); + if (Platform->CPU.Vendor == 0x756E6547 /* Intel */) { int num_cpus; @@ -939,16 +946,15 @@ 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) { @@ -970,7 +976,8 @@ 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(); Index: branches/cparm/i386/boot0/boot0.s =================================================================== --- branches/cparm/i386/boot0/boot0.s (revision 1524) +++ branches/cparm/i386/boot0/boot0.s (revision 1525) @@ -60,6 +60,11 @@ VERBOSE EQU 1 ; +; Set to 1 to enable unstretch mode (WARNING: Verbose and Debug must be disabled) +; +UNSTRETCH EQU 0 + +; ; Various constants. ; kBoot0Segment EQU 0x0000 @@ -230,6 +235,10 @@ 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. @@ -775,13 +784,29 @@ 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_str db 10, 13, 'boot0: ', 0 boot_error_str db 'error', 0 +%if UNSTRETCH +nv_scaler_str db 'Unstretch', 0 +%endif ;DEBUG + %if VERBOSE gpt_str db 'GPT', 0 test_str db 'test', 0 Index: branches/cparm/i386/boot0/boot0md.s =================================================================== --- branches/cparm/i386/boot0/boot0md.s (revision 0) +++ branches/cparm/i386/boot0/boot0md.s (revision 1525) @@ -0,0 +1,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 +; +; Written by Tam‡s Kos‡rszky on 2008-03-10 +; +; 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. +; +DEBUG EQU 0 + +; +; Set to 1 to enable verbose mode +; +VERBOSE EQU 1 + +; +; Various constants. +; +kBoot0Segment EQU 0x0000 +kBoot0Stack EQU 0xFFF0 ; boot0 stack pointer +kBoot0LoadAddr EQU 0x7C00 ; boot0 load address +kBoot0RelocAddr EQU 0xE000 ; boot0 relocated address + +kMBRBuffer EQU 0x1000 ; MBR buffer address +kLBA1Buffer EQU 0x1200 ; LBA1 - GPT Partition Table Header buffer address +kGPTABuffer EQU 0x1400 ; GUID Partition Entry Array buffer address + +kPartTableOffset EQU 0x1be +kMBRPartTable EQU kMBRBuffer + kPartTableOffset + +kSectorBytes EQU 512 ; sector size in bytes +kBootSignature EQU 0xAA55 ; boot sector signature +kHFSPSignature EQU 'H+' ; HFS+ volume signature +kHFSPCaseSignature EQU 'HX' ; HFS+ volume case-sensitive signature +kFAT32BootCodeOffset EQU 0x5a ; offset of boot code in FAT32 boot sector +kBoot1FAT32Magic EQU 'BO' ; Magic string to detect our boot1f32 code + + +kGPTSignatureLow EQU 'EFI ' ; GUID Partition Table Header Signature +kGPTSignatureHigh EQU 'PART' +kGUIDLastDwordOffs EQU 12 ; last 4 byte offset of a GUID + +kPartCount EQU 4 ; number of paritions per table +kPartTypeHFS EQU 0xaf ; HFS+ Filesystem type +kPartTypePMBR EQU 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. +kAppleGUID EQU 0xACEC4365 ; last 4 bytes of Apple type GUIDs. +kEFISystemGUID EQU 0x3BC93EC9 ; last 4 bytes of EFI System Partition Type GUID: + ; C12A7328-F81F-11D2-BA4B-00A0C93EC93B + +%ifdef FLOPPY +kDriveNumber EQU 0x00 +%else +kDriveNumber EQU 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 +; + struc gpth +.Signature resb 8 +.Revision resb 4 +.HeaderSize resb 4 +.HeaderCRC32 resb 4 +.Reserved resb 4 +.MyLBA resb 8 +.AlternateLBA resb 8 +.FirstUsableLBA resb 8 +.LastUsableLBA resb 8 +.DiskGUID resb 16 +.PartitionEntryLBA resb 8 +.NumberOfPartitionEntries resb 4 +.SizeOfPartitionEntry resb 4 +.PartitionEntryArrayCRC32 resb 4 + endstruc + +; +; Format of GUID Partition Entry Array +; + struc gpta +.PartitionTypeGUID resb 16 +.UniquePartitionGUID resb 16 +.StartingLBA resb 8 +.EndingLBA resb 8 +.Attributes resb 8 +.PartitionName resb 72 + 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: + + push dx ; save dl (boot drive) for second pass. + ; will stay on stack if booter loaded in first pass. + ; this should not be a problem + mov bh, 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. + ; + + push bx ; 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 + pop bx ; 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 + inc dl + jmp scan_drives + + +.mbr_load_error: + ; all drives scanned - see if we need to run second pass + pop dx ; restore orig boot drive + dec bh ; decrement scan pass counter + jz scan_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 + mov dh, 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 + xor dh, 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 + ; + mov al, 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] + + cmp eax, kAppleGUID ; check current GUID Partition for Apple's GUID type + je .gpt_ok + + ; + ; Turbo - also try EFI System Partition + ; + + cmp eax, 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 + mov dh, 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 + + or dh, 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. + ; + mov ax, [kBoot0LoadAddr + 2 * kSectorBytes] + cmp ax, kHFSPSignature ; 'H+' + je .checkBootSignature + cmp ax, kHFSPCaseSignature ; 'HX' + je .checkBootSignature + + ; + ; Looking for boot1f32 magic string. + ; + mov ax, [kBoot0LoadAddr + kFAT32BootCodeOffset] + cmp ax, 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 + + push di + mov si, log_title_str + call print_string + + pop si + call print_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_str db 10, 13, 'boot0: ', 0 +boot_error_str db 'error', 0 + +%if VERBOSE +gpt_str db 'GPT', 0 +;test_str db 'test', 0 +done_str db '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_lba resd 1 ; Starting LBA for read_lba function + +; END Index: branches/cparm/i386/boot0/Makefile =================================================================== --- branches/cparm/i386/boot0/Makefile (revision 1524) +++ branches/cparm/i386/boot0/Makefile (revision 1525) @@ -6,7 +6,7 @@ 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)/$@ @@ -17,8 +17,11 @@ 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 Index: branches/cparm/i386/boot1/boot1.s =================================================================== --- branches/cparm/i386/boot1/boot1.s (revision 1524) +++ branches/cparm/i386/boot1/boot1.s (revision 1525) @@ -1,1477 +0,0 @@ -; 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. -; -; Written by Tamás Kosárszky on 2008-04-14 -; - -; -; Set to 1 to enable obscure debug messages. -; -DEBUG EQU 0 - -; -; Set to 1 to enable unused code. -; -UNUSED EQU 0 - -; -; Set to 1 to enable verbose mode. -; -VERBOSE EQU 1 - -; -; Various constants. -; -NULL EQU 0 -CR EQU 0x0D -LF EQU 0x0A - -mallocStart EQU 0x1000 ; start address of local workspace area -maxSectorCount EQU 64 ; maximum sector count for readSectors -maxNodeSize EQU 16384 - -kSectorBytes EQU 512 ; sector size in bytes -kBootSignature EQU 0xAA55 ; boot sector signature - -kBoot1StackAddress EQU 0xFFF0 ; boot1 stack pointer -kBoot1LoadAddr EQU 0x7C00 ; boot1 load address -kBoot1RelocAddr EQU 0xE000 ; boot1 relocated address -kBoot1Sector1Addr EQU kBoot1RelocAddr + kSectorBytes ; boot1 load address for sector 1 -kHFSPlusBuffer EQU kBoot1Sector1Addr + kSectorBytes ; HFS+ Volume Header address - -kBoot2Sectors EQU (448 * 1024 - 512) / kSectorBytes ; max size of 'boot' file in sectors -kBoot2Segment EQU 0x2000 ; boot2 load segment -kBoot2Address EQU kSectorBytes ; 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 -.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 - -;------------------------------------------------------------------------- -; HFS+ related structures and constants -; -kHFSPlusSignature EQU 'H+' ; HFS+ volume signature -kHFSPlusCaseSignature EQU 'HX' ; HFS+ volume case-sensitive signature -kHFSPlusCaseSigX EQU 'X' ; upper byte of HFS+ volume case-sensitive signature -kHFSPlusExtentDensity EQU 8 ; 8 extent descriptors / extent record - -; -; HFSUniStr255 -; - struc HFSUniStr255 -.length resw 1 -.unicode resw 255 - endstruc - -; -; HFSPlusExtentDescriptor -; - struc HFSPlusExtentDescriptor -.startBlock resd 1 -.blockCount resd 1 - endstruc - -; -; HFSPlusForkData -; - struc HFSPlusForkData -.logicalSize resq 1 -.clumpSize resd 1 -.totalBlocks resd 1 -.extents resb kHFSPlusExtentDensity * HFSPlusExtentDescriptor_size - endstruc - -; -; HFSPlusVolumeHeader -; - struc HFSPlusVolumeHeader -.signature resw 1 -.version resw 1 -.attributes resd 1 -.lastMountedVersion resd 1 -.journalInfoBlock resd 1 -.createDate resd 1 -.modifyDate resd 1 -.backupDate resd 1 -.checkedDate resd 1 -.fileCount resd 1 -.folderCount resd 1 -.blockSize resd 1 -.totalBlocks resd 1 -.freeBlocks resd 1 -.nextAllocation resd 1 -.rsrcClumpSize resd 1 -.dataClumpSize resd 1 -.nextCatalogID resd 1 -.writeCount resd 1 -.encodingsBitmap resq 1 -.finderInfo resd 8 -.allocationFile resb HFSPlusForkData_size -.extentsFile resb HFSPlusForkData_size -.catalogFile resb HFSPlusForkData_size -.attributesFile resb HFSPlusForkData_size -.startupFile resb HFSPlusForkData_size - endstruc - -; -; B-tree related structures and constants -; - -kBTIndexNode EQU 0 -kBTMaxRecordLength EQU 264 ; sizeof(kHFSPlusFileThreadRecord) -kHFSRootParentID EQU 1 ; Parent ID of the root folder -kHFSRootFolderID EQU 2 ; Folder ID of the root folder -kHFSExtentsFileID EQU 3 ; File ID of the extents overflow file -kHFSCatalogFileID EQU 4 ; File ID of the catalog file -kHFSPlusFileRecord EQU 0x200 -kForkTypeData EQU 0 -kForkTypeResource EQU 0xFF - -; -; BTNodeDescriptor -; - struc BTNodeDescriptor -.fLink resd 1 -.bLink resd 1 -.kind resb 1 -.height resb 1 -.numRecords resw 1 -.reserved resw 1 - endstruc - -; -; BTHeaderRec -; - struc BTHeaderRec -.treeDepth resw 1 -.rootNode resd 1 -.leafRecords resd 1 -.firstLeafNode resd 1 -.lastLeafNode resd 1 -.nodeSize resw 1 -.maxKeyLength resw 1 -.totalNodes resd 1 -.freeNodes resd 1 -.reserved1 resw 1 -.clumpSize resd 1 -.btreeType resb 1 -.keyCompareType resb 1 -.attributes resd 1 -.reserved3 resd 16 - endstruc - -; -; BTIndexRec -; - struc BTIndexRec -.childID resd 1 - endstruc - -; -; HFSPlusCatalogKey -; - struc HFSPlusCatalogKey -; -; won't use the keyLength field for easier addressing data inside this structure -; -;.keyLength resw 1 - -.parentID resd 1 -.nodeName resb HFSUniStr255_size - endstruc - -; -; HFSPlusExtentKey -; - struc HFSPlusExtentKey -; -; won't use the keyLength field for easier addressing data inside this structure -; -;.keyLength resw 1 - -.forkType resb 1 -.pad resb 1 -.fileID resd 1 -.startBlock resd 1 - endstruc - -; -; HFSPlusBSDInfo -; - struc HFSPlusBSDInfo -.ownerID resd 1 -.groupID resd 1 -.adminFlags resb 1 -.ownerFlags resb 1 -.fileMode resw 1 -.special resd 1 - endstruc - -; -; FileInfo -; - struc FileInfo -.fileType resd 1 -.fileCreator resd 1 -.finderFlags resw 1 -.location resw 2 -.reservedField resw 1 - endstruc - -; -; ExtendedFileInfo -; - struc ExtendedFileInfo -.reserved1 resw 4 -.extFinderFlags resw 1 -.reserved2 resw 1 -.putAwayFolderID resd 1 - endstruc - -; -; HFSPlusCatalogFile -; - struc HFSPlusCatalogFile -.recordType resw 1 -.flags resw 1 -.reserved1 resd 1 -.fileID resd 1 -.createDate resd 1 -.contentModDate resd 1 -.attributeModDate resd 1 -.accessDate resd 1 -.backupDate resd 1 -.permissions resb HFSPlusBSDInfo_size -.userInfo resb FileInfo_size -.finderInfo resb ExtendedFileInfo_size -.textEncoding resd 1 -.reserved2 resd 1 -.dataFork resb HFSPlusForkData_size -.resourceFork resb HFSPlusForkData_size - endstruc - -; -; Macros. -; -%macro jmpabs 1 - push WORD %1 - ret -%endmacro - -%macro DebugCharMacro 1 - pushad - mov al, %1 - call print_char - call getc - popad -%endmacro - -%macro PrintCharMacro 1 - pushad - mov al, %1 - call print_char - popad -%endmacro - -%macro PutCharMacro 1 - call print_char -%endmacro - -%macro PrintHexMacro 1 - call print_hex -%endmacro - -%macro PrintString 1 - mov si, %1 - call print_string -%endmacro - -%macro LogString 1 - mov di, %1 - call log_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 - - ORG kBoot1RelocAddr - -;-------------------------------------------------------------------------- -; 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 - xor ax, ax ; zero ax - mov ss, 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. - ; - push si - mov si, kBoot1LoadAddr ; si <- source - mov di, kBoot1RelocAddr ; di <- destination - cld ; auto-increment SI and/or DI registers - mov cx, kSectorBytes ; copy 256 words - rep movsb ; repeat string move (word) operation - pop si - - ; - ; 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? - ; - jmpabs startReloc - -;-------------------------------------------------------------------------- -; 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 - mov WORD [gMallocPtr], mallocStart ; set free space pointer - - ; - ; Loading upper 512 bytes of boot1h and HFS+ Volume Header. - ; - xor ecx, ecx ; sector 1 of current partition - inc ecx - mov al, 2 ; read 2 sectors: sector 1 of boot1h + HFS+ Volume Header - mov edx, kBoot1Sector1Addr - call readLBA - - ; - ; Initializing more global variables. - ; - mov eax, [kHFSPlusBuffer + HFSPlusVolumeHeader.blockSize] - bswap eax ; convert to little-endian - shr eax, 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. - ; - mov ax, [kHFSPlusBuffer + HFSPlusVolumeHeader.signature] - cmp ax, kHFSPlusCaseSignature - je findRootBoot - cmp ax, kHFSPlusSignature - jne error - -;-------------------------------------------------------------------------- -; Find stage2 boot file in a HFS+ Volume's root folder. -; -findRootBoot: - mov al, kHFSCatalogFileID - lea si, [searchCatalogKey] - lea di, [kHFSPlusBuffer + HFSPlusVolumeHeader.catalogFile + HFSPlusForkData.extents] - call lookUpBTree - jne error - - lea si, [bp + BTree.recordDataPtr] - mov si, [si] - cmp WORD [si], kHFSPlusFileRecord - jne error - -; 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 - ; - mov ebx, [si + HFSPlusCatalogFile.dataFork + HFSPlusForkData.logicalSize + 4] - bswap ebx ; convert file size to little-endian - add ebx, kSectorBytes - 1 ; adjust size before unit conversion - shr ebx, 9 ; convert file size to sector unit - cmp bx, kBoot2Sectors ; check if bigger than max stage2 size - ja error - mov eax, [si + HFSPlusCatalogFile.fileID] - bswap eax ; convert fileID to little-endian - xor ecx, ecx - mov edx, (kBoot2Segment << 4) + kBoot2Address - lea di, [si + HFSPlusCatalogFile.dataFork + HFSPlusForkData.extents] - call readExtent - -%if VERBOSE - LogString(root_str) -%endif - -boot2: - -%if DEBUG - DebugChar ('!') -%endif - -%if UNUSED - ; - ; Waiting for a key press. - ; - - mov ah, 0 - int 0x16 -%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 - mov bx, ax - -.loop: - xor eax, eax ; EAX = 0 - mov al, bl ; assume we reached the last block. - cmp bx, maxSectorCount ; check if we really reached the last block - jb .readBlock ; yes, BX < MaxSectorCount - mov al, maxSectorCount ; no, read MaxSectorCount - -.readBlock: - call readLBA - sub bx, ax ; decrease remaning sectors with the read amount - jz .exit ; exit if no more sectors left to be loaded - add ecx, eax ; adjust LBA sector offset - shl ax, 9 ; convert sectors to bytes - add edx, 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. - ; - - mov bx, dx ; save offset to BX - and bh, 0x0f ; keep low 12 bits - shr edx, 4 ; adjust linear address to segment base - xor dl, dl ; mask low 8 bits - mov es, 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 - - jc 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 - 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 - - push di - mov si, log_title_str - call print_string - - pop si - call print_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 - int 0x16 - 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 - push di ; save DI for unicode string length pointer - mov si, dx ; use SI as source string pointer - xor ax, ax ; AX = unicode character - mov cl, al ; CL = string length - -.loop: - stosw ; store unicode character (length 0 at first run) - lodsb ; load next character to AL - inc cl ; increment string length count - cmp al, NULL ; check for string terminator - jne .loop - - pop di ; restore unicode string length pointer - dec cl ; 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 - xchg ah, al - stosw - cmp al, 0 - je .exit - mov cx, ax - -.loop: - lodsw - xchg ah, al ; convert AX to little-endian - - ; - ; When working with a case-sensitive HFS+ (HX) filesystem, we shouldn't change the case. - ; - cmp BYTE [kHFSPlusBuffer + HFSPlusVolumeHeader.signature + 1], kHFSPlusCaseSigX - je .keepcase - - or ax, ax - jne .convertToLE - dec ax ; NULL must be the strongest char - -.convertToLE: - cmp ah, 0 - ja .keepcase - cmp al, 'A' - jb .keepcase - cmp al, 'Z' - ja .keepcase - add al, 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 - - mov dl, 0 ; DL = result of comparison, DH = bestGuess - mov eax, [si + HFSPlusExtentKey.fileID] - cmp eax, [di + HFSPlusExtentKey.fileID] - jne .checkFlags - - cmp BYTE [si + HFSPlusExtentKey.forkType], kForkTypeData - jne .checkFlags - - mov eax, [si + HFSPlusExtentKey.startBlock] - cmp eax, [di + HFSPlusExtentKey.startBlock] - je compareHFSPlusCatalogKeys.exit - -.checkFlags: - ja compareHFSPlusCatalogKeys.searchKeyGreater ; search key > trial key - jb compareHFSPlusCatalogKeys.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 - xor dx, dx ; DL = result of comparison, DH = bestGuess - xchg si, di - lodsd - mov ecx, eax ; ECX = trial parentID - xchg si, di - lodsd ; EAX = search parentID - cmp eax, ecx - ja .searchKeyGreater ; search parentID > trial parentID - jb .trialKeyGreater ; search parentID < trial parentID - -.compareNodeName: ; search parentID = trial parentID - xchg si, di - lodsw - mov cx, ax ; CX = trial nodeName.length - xchg si, di - lodsw ; AX = search nodeName.length - cmp cl, 0 ; trial nodeName.length = 0? - je .searchKeyGreater - - cmp ax, cx - je .strCompare - ja .searchStrLonger - -.trialStrLonger: - dec dh - mov cx, ax - jmp .strCompare - -.searchStrLonger: - inc dh - -.strCompare: - repe cmpsw - ja .searchKeyGreater - jb .trialKeyGreater - mov dl, dh - jmp .exit - -.trialKeyGreater: - dec dl - jmp .exit - -.searchKeyGreater: - inc dl - -.exit: - mov [bp + BTree.searchResult], dl - cmp dl, 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: - push ax ; save AX - push di ; save DI - mov di, [gMallocPtr] ; start address of free space - push di ; save free space start address - inc di ; - inc di ; keep the first word untouched - dec cx ; for the last memory block pointer. - dec cx ; - mov al, NULL ; fill with zero - rep stosb ; repeat fill - mov [gMallocPtr], di ; adjust free space pointer - pop bp ; BP = start address of allocated memory - mov [di], bp ; set start address of allocated memory at next - ; allocation block's free space address. - pop di ; restore DI - pop ax ; restore AX - ret - -%if UNUSED - -;-------------------------------------------------------------------------- -; Free allocated memory -; -; Returns: -; BP = start address of previously allocated memory -; -free: - lea bp, [gMallocPtr] - mov bp, [bp] - mov [gMallocPtr], bp - ret - -%endif ; UNUSED - -;-------------------------------------------------------------------------- -; Static data. -; - -%if VERBOSE -root_str db '/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: - times 510-($-$$) db 0 - dw kBootSignature - -; -; 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: - mov cx, BTree_size ; allocate memory with BTree_size - call malloc ; BP = start address of allocated memory. - mov [bp + BTree.fileID], al ; save fileFileID - mov edx, [di] ; first extent of current file - call blockToSector ; ECX = converted to sector unit - mov al, 1 ; 1 sector is enough for - xor edx, edx ; reading current file's header. - lea dx, [bp + BTree.BTHeaderBuffer] ; load into BTreeHeaderBuffer - call readLBA ; read - mov ax, [bp + BTree.BTHeaderBuffer + BTNodeDescriptor_size + BTHeaderRec.nodeSize] - xchg ah, al ; convert to little-endian - mov [bp + BTree.nodeSize], ax ; save nodeSize - - ; - ; Always start the lookup process with the root node. - ; - mov edx, [bp + BTree.BTHeaderBuffer + BTNodeDescriptor_size + BTHeaderRec.rootNode] - -.readNode: - ; - ; Converting nodeID to sector unit - ; - mov ax, [bp + BTree.nodeSize] - shr ax, 9 ; convert nodeSize to sectors - mov bx, ax ; BX = read sector count - cwde - bswap edx ; convert node ID to little-endian - mul edx ; multiply with nodeSize converted to sector unit - mov ecx, eax ; ECX = file offset in BTree - - mov eax, [bp + BTree.fileID] - lea edx, [bp + BTree.nodeBuffer] - call readExtent - - ; - ; AX = lowerBound = 0 - ; - xor ax, ax - - ; - ; BX = upperBound = numRecords - 1 - ; - mov bx, [bp + BTree.nodeBuffer + BTNodeDescriptor.numRecords] - xchg bh, bl - dec bx - -.bsearch: - cmp ax, bx - ja .checkResult ; jump if lowerBound > upperBound - - mov cx, ax - add cx, bx - shr cx, 1 ; test index = (lowerBound + upperBound / 2) - - call getBTreeRecord - -%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: - mov bx, cx - dec bx ; upperBound = index - 1 - jmp .bsearch - -.searchGreaterThanTrial: - mov ax, cx - inc ax ; lowerBound = index + 1 - jmp .bsearch - -.checkResult: - cmp BYTE [bp + BTree.searchResult], 0 - jge .foundKey - - mov cx, bx - call getBTreeRecord - -.foundKey: - cmp BYTE [bp + BTree.nodeBuffer + BTNodeDescriptor.kind], kBTIndexNode - jne .exit - - lea bx, [bp + BTree.recordDataPtr] - mov bx, [bx] - mov edx, [bx] - jmp .readNode - -.exit: - cmp BYTE [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 - push si ; save SI - lea di, [bp + BTree.nodeBuffer] ; DI = start of nodeBuffer - push di ; use later - mov ax, [bp + BTree.nodeSize] ; get nodeSize - add di, ax ; DI = beyond nodeBuffer - inc cx ; increment index - shl cx, 1 ; * 2 - sub di, cx ; DI = pointer to record - mov ax, [di] ; offset to record - xchg ah, al ; convert to little-endian - pop di ; start of nodeBuffer - add di, ax ; DI = address of record key - mov si, di ; save to SI - mov ax, [di] ; keyLength - xchg ah, al ; convert to little-endian - inc ax ; suppress keySize (2 bytes) - inc ax ; - add di, ax ; DI = address of record data - mov [bp + BTree.recordDataPtr], di ; save address of record data - lea di, [bp + BTree.trialKey] - push di ; 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 - ; - cmp BYTE [bp + BTree.fileID], kHFSCatalogFileID - je .prepareTrialCatalogKey - -.prepareTrialExtentKey: - mov bx, compareHFSPlusExtentKeys - movsw ; copy forkType + pad - mov cx, 2 ; copy fileID + startBlock - -.extentLoop: - lodsd - bswap eax ; convert to little-endian - stosd - loop .extentLoop - jmp .exit - -.prepareTrialCatalogKey: - mov bx, compareHFSPlusCatalogKeys - lodsd - bswap eax ; convert ParentID to little-endian - stosd - call ConvertHFSUniStr255ToLE ; convert nodeName to little-endian - -.exit: - pop di ; restore address of trialKey - -%if UNUSED -; -; Print catalog trial key -; - pushad - mov si, di - lodsd - PrintChar('k') - PrintHex() - lodsw - cmp ax, 0 - je .printExit - mov cx, ax -.printLoop: - lodsw - call print_char - loop .printLoop -.printExit: - popad -; -; -; -%endif ; UNUSED - -%if UNUSED -; -; Print extent trial key -; - pushad - PrintChar('k') - mov si, di - xor eax, eax - lodsw - PrintHex() - lodsd - PrintHex() - lodsd - PrintHex() - popad -; -; -; -%endif ; UNUSED - - pop si ; restore SI - call bx ; 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 - mov ax, bx - cwde - mov [bp + BTree.readSize], eax - mov ebx, ecx ; EBX = file offset - xor eax, eax - mov [bp + BTree.currentExtentOffs], eax - -.beginExtentBlock: - mov BYTE [bp + BTree.extentCount], 0 - -.extentSearch: - cmp BYTE [bp + BTree.extentCount], kHFSPlusExtentDensity - jb .continue - -.getNextExtentBlock: - push ebx - mov eax, [bp + BTree.currentExtentOffs] - - ; - ; Converting sector unit to HFS+ allocation block unit. - ; - xor edx, edx - div DWORD [gBlockSize] ; divide with blockSize - - ; - ; Preparing searchExtentKey's startBlock field. - ; - mov [bp + BTree.searchExtentKey + HFSPlusExtentKey.startBlock], eax - - mov al, kHFSExtentsFileID - lea si, [bp + BTree.searchExtentKey] - lea di, [kHFSPlusBuffer + HFSPlusVolumeHeader.extentsFile + HFSPlusForkData.extents] - call lookUpBTree - jnz NEAR .exit - - ; - ; BP points to the new workspace allocated by lookUpBTree. - ; - lea di, [bp + BTree.recordDataPtr] - mov di, [di] - - ; - ; Switch back to the previous workspace. - ; - lea bp, [gMallocPtr] - mov bp, [bp] - mov [gMallocPtr], bp - - pop ebx - jmp .beginExtentBlock - -.continue: - mov edx, [di + HFSPlusExtentDescriptor.blockCount] - call blockToSector ; ECX = converted current extent's blockCount to sectors - mov eax, [bp + BTree.currentExtentOffs] ; EAX = current extent's start offset (sector) - mov edx, eax - add edx, ecx ; EDX = next extent's start offset (sector) - cmp ebx, 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: - mov edx, ebx - sub edx, eax ; EDX = relative offset within current extent - mov eax, edx ; will be used below to determine read size - mov esi, [bp + BTree.readSize] ; ESI = remaining sectors to be read - add edx, esi - cmp edx, ecx ; test if relative offset + readSize fits to this extent - jbe .read ; read all remaining sectors from this extent - -.splitRead: - sub ecx, eax ; read amount of sectors beginning at relative offset - mov esi, ecx ; of current extent up to the end of current extent - -.read: - mov edx, [di + HFSPlusExtentDescriptor.startBlock] - call blockToSector ; ECX = converted to sectors - add ecx, eax ; file offset converted to sectors - - push si - mov ax, si - mov edx, [bp + BTree.readBufferPtr] - call readSectors - pop si - - add ebx, esi - mov ax, si - cwde - shl ax, 9 ; convert SI (read sector count) to byte unit - add [bp + BTree.readBufferPtr], eax - sub [bp + BTree.readSize], esi - - jz .exit - -.nextExtent: - add di, kHFSPlusExtentDensity - inc BYTE [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: - push eax - mov eax, [gBlockSize] - bswap edx ; convert allocation block to little-endian - mul edx ; multiply with block number - mov ecx, eax ; result in EAX - pop eax - 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: - push eax - mov eax, edx - xor edx, edx - div DWORD [gBlockSize] ; divide with blockSize - mov ecx, eax ; result in EAX - pop eax - 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: - push eax - mov ax, [bp + BTree.nodeSize] - shr ax, 9 ; convert nodeSize to sectors - cwde - bswap edx ; convert node ID to little-endian - mul edx ; multiply with node ID - mov ecx, eax ; result in EAX - pop eax - ret - -%endif ; UNUSED - -;-------------------------------------------------------------------------- -; Static data. -; - -%if VERBOSE -log_title_str db CR, LF, 'boot1: ', NULL -error_str db 'error', NULL -%endif - -searchCatalogKey dd kHFSRootFolderID - dw searchCatKeyNameLen -searchCatKeyName dw 'b', 'o', 'o', 't' ; must be lower case -searchCatKeyNameLen EQU ($ - 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: - times 1022-($-$$) db 0 - dw kBootSignature - -; -; Local BTree variables -; - struc BTree -.mallocLink resw 1 ; pointer to previously allocated memory block -.fileID resd 1 ; will use as BYTE -.nodeSize resd 1 ; will use as WORD -.searchExtentKey resb HFSPlusExtentKey_size -.searchResult resb 1 -.trialKey resb kBTMaxRecordLength -.recordDataPtr resw 1 -.readBufferPtr resd 1 -.currentExtentOffs resd 1 -.readSize resd 1 -.extentCount resb 1 - ALIGNB 2 -.BTHeaderBuffer resb kSectorBytes -.nodeBuffer resb maxNodeSize - endstruc - -; -; Global variables -; - - ABSOLUTE kHFSPlusBuffer + HFSPlusVolumeHeader_size - -gPartLBA resd 1 -gBIOSDriveNumber resw 1 -gBlockSize resd 1 -gMallocPtr resw 1 - -; END Index: branches/cparm/i386/boot1/Makefile =================================================================== --- branches/cparm/i386/boot1/Makefile (revision 1524) +++ branches/cparm/i386/boot1/Makefile (revision 1525) @@ -19,8 +19,8 @@ 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 Index: branches/cparm/i386/boot1/boot1h.s =================================================================== --- branches/cparm/i386/boot1/boot1h.s (revision 0) +++ branches/cparm/i386/boot1/boot1h.s (revision 1525) @@ -0,0 +1,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. +; +; Written by Tamás Kosárszky on 2008-04-14 +; + +; +; Set to 1 to enable obscure debug messages. +; +DEBUG EQU 0 + +; +; Set to 1 to enable unused code. +; +UNUSED EQU 0 + +; +; Set to 1 to enable verbose mode. +; +VERBOSE EQU 1 + +; +; Various constants. +; +NULL EQU 0 +CR EQU 0x0D +LF EQU 0x0A + +mallocStart EQU 0x1000 ; start address of local workspace area +maxSectorCount EQU 64 ; maximum sector count for readSectors +maxNodeSize EQU 16384 + +kSectorBytes EQU 512 ; sector size in bytes +kBootSignature EQU 0xAA55 ; boot sector signature + +kBoot1StackAddress EQU 0xFFF0 ; boot1 stack pointer +kBoot1LoadAddr EQU 0x7C00 ; boot1 load address +kBoot1RelocAddr EQU 0xE000 ; boot1 relocated address +kBoot1Sector1Addr EQU kBoot1RelocAddr + kSectorBytes ; boot1 load address for sector 1 +kHFSPlusBuffer EQU kBoot1Sector1Addr + kSectorBytes ; HFS+ Volume Header address + +kBoot2Sectors EQU (448 * 1024 - 512) / kSectorBytes ; max size of 'boot' file in sectors +kBoot2Segment EQU 0x2000 ; boot2 load segment +kBoot2Address EQU kSectorBytes ; 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 +.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 + +;------------------------------------------------------------------------- +; HFS+ related structures and constants +; +kHFSPlusSignature EQU 'H+' ; HFS+ volume signature +kHFSPlusCaseSignature EQU 'HX' ; HFS+ volume case-sensitive signature +kHFSPlusCaseSigX EQU 'X' ; upper byte of HFS+ volume case-sensitive signature +kHFSPlusExtentDensity EQU 8 ; 8 extent descriptors / extent record + +; +; HFSUniStr255 +; + struc HFSUniStr255 +.length resw 1 +.unicode resw 255 + endstruc + +; +; HFSPlusExtentDescriptor +; + struc HFSPlusExtentDescriptor +.startBlock resd 1 +.blockCount resd 1 + endstruc + +; +; HFSPlusForkData +; + struc HFSPlusForkData +.logicalSize resq 1 +.clumpSize resd 1 +.totalBlocks resd 1 +.extents resb kHFSPlusExtentDensity * HFSPlusExtentDescriptor_size + endstruc + +; +; HFSPlusVolumeHeader +; + struc HFSPlusVolumeHeader +.signature resw 1 +.version resw 1 +.attributes resd 1 +.lastMountedVersion resd 1 +.journalInfoBlock resd 1 +.createDate resd 1 +.modifyDate resd 1 +.backupDate resd 1 +.checkedDate resd 1 +.fileCount resd 1 +.folderCount resd 1 +.blockSize resd 1 +.totalBlocks resd 1 +.freeBlocks resd 1 +.nextAllocation resd 1 +.rsrcClumpSize resd 1 +.dataClumpSize resd 1 +.nextCatalogID resd 1 +.writeCount resd 1 +.encodingsBitmap resq 1 +.finderInfo resd 8 +.allocationFile resb HFSPlusForkData_size +.extentsFile resb HFSPlusForkData_size +.catalogFile resb HFSPlusForkData_size +.attributesFile resb HFSPlusForkData_size +.startupFile resb HFSPlusForkData_size + endstruc + +; +; B-tree related structures and constants +; + +kBTIndexNode EQU 0 +kBTMaxRecordLength EQU 264 ; sizeof(kHFSPlusFileThreadRecord) +kHFSRootParentID EQU 1 ; Parent ID of the root folder +kHFSRootFolderID EQU 2 ; Folder ID of the root folder +kHFSExtentsFileID EQU 3 ; File ID of the extents overflow file +kHFSCatalogFileID EQU 4 ; File ID of the catalog file +kHFSPlusFileRecord EQU 0x200 +kForkTypeData EQU 0 +kForkTypeResource EQU 0xFF + +; +; BTNodeDescriptor +; + struc BTNodeDescriptor +.fLink resd 1 +.bLink resd 1 +.kind resb 1 +.height resb 1 +.numRecords resw 1 +.reserved resw 1 + endstruc + +; +; BTHeaderRec +; + struc BTHeaderRec +.treeDepth resw 1 +.rootNode resd 1 +.leafRecords resd 1 +.firstLeafNode resd 1 +.lastLeafNode resd 1 +.nodeSize resw 1 +.maxKeyLength resw 1 +.totalNodes resd 1 +.freeNodes resd 1 +.reserved1 resw 1 +.clumpSize resd 1 +.btreeType resb 1 +.keyCompareType resb 1 +.attributes resd 1 +.reserved3 resd 16 + endstruc + +; +; BTIndexRec +; + struc BTIndexRec +.childID resd 1 + endstruc + +; +; HFSPlusCatalogKey +; + struc HFSPlusCatalogKey +; +; won't use the keyLength field for easier addressing data inside this structure +; +;.keyLength resw 1 + +.parentID resd 1 +.nodeName resb HFSUniStr255_size + endstruc + +; +; HFSPlusExtentKey +; + struc HFSPlusExtentKey +; +; won't use the keyLength field for easier addressing data inside this structure +; +;.keyLength resw 1 + +.forkType resb 1 +.pad resb 1 +.fileID resd 1 +.startBlock resd 1 + endstruc + +; +; HFSPlusBSDInfo +; + struc HFSPlusBSDInfo +.ownerID resd 1 +.groupID resd 1 +.adminFlags resb 1 +.ownerFlags resb 1 +.fileMode resw 1 +.special resd 1 + endstruc + +; +; FileInfo +; + struc FileInfo +.fileType resd 1 +.fileCreator resd 1 +.finderFlags resw 1 +.location resw 2 +.reservedField resw 1 + endstruc + +; +; ExtendedFileInfo +; + struc ExtendedFileInfo +.reserved1 resw 4 +.extFinderFlags resw 1 +.reserved2 resw 1 +.putAwayFolderID resd 1 + endstruc + +; +; HFSPlusCatalogFile +; + struc HFSPlusCatalogFile +.recordType resw 1 +.flags resw 1 +.reserved1 resd 1 +.fileID resd 1 +.createDate resd 1 +.contentModDate resd 1 +.attributeModDate resd 1 +.accessDate resd 1 +.backupDate resd 1 +.permissions resb HFSPlusBSDInfo_size +.userInfo resb FileInfo_size +.finderInfo resb ExtendedFileInfo_size +.textEncoding resd 1 +.reserved2 resd 1 +.dataFork resb HFSPlusForkData_size +.resourceFork resb HFSPlusForkData_size + endstruc + +; +; Macros. +; +%macro jmpabs 1 + push WORD %1 + ret +%endmacro + +%macro DebugCharMacro 1 + pushad + mov al, %1 + call print_char + call getc + popad +%endmacro + +%macro PrintCharMacro 1 + pushad + mov al, %1 + call print_char + popad +%endmacro + +%macro PutCharMacro 1 + call print_char +%endmacro + +%macro PrintHexMacro 1 + call print_hex +%endmacro + +%macro PrintString 1 + mov si, %1 + call print_string +%endmacro + +%macro LogString 1 + mov di, %1 + call log_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 + + ORG kBoot1RelocAddr + +;-------------------------------------------------------------------------- +; 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 + xor ax, ax ; zero ax + mov ss, 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. + ; + push si + mov si, kBoot1LoadAddr ; si <- source + mov di, kBoot1RelocAddr ; di <- destination + cld ; auto-increment SI and/or DI registers + mov cx, kSectorBytes ; copy 256 words + rep movsb ; repeat string move (word) operation + pop si + + ; + ; 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? + ; + jmpabs startReloc + +;-------------------------------------------------------------------------- +; 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 + mov WORD [gMallocPtr], mallocStart ; set free space pointer + + ; + ; Loading upper 512 bytes of boot1h and HFS+ Volume Header. + ; + xor ecx, ecx ; sector 1 of current partition + inc ecx + mov al, 2 ; read 2 sectors: sector 1 of boot1h + HFS+ Volume Header + mov edx, kBoot1Sector1Addr + call readLBA + + ; + ; Initializing more global variables. + ; + mov eax, [kHFSPlusBuffer + HFSPlusVolumeHeader.blockSize] + bswap eax ; convert to little-endian + shr eax, 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. + ; + mov ax, [kHFSPlusBuffer + HFSPlusVolumeHeader.signature] + cmp ax, kHFSPlusCaseSignature + je findRootBoot + cmp ax, kHFSPlusSignature + jne error + +;-------------------------------------------------------------------------- +; Find stage2 boot file in a HFS+ Volume's root folder. +; +findRootBoot: + mov al, kHFSCatalogFileID + lea si, [searchCatalogKey] + lea di, [kHFSPlusBuffer + HFSPlusVolumeHeader.catalogFile + HFSPlusForkData.extents] + call lookUpBTree + jne error + + lea si, [bp + BTree.recordDataPtr] + mov si, [si] + cmp WORD [si], kHFSPlusFileRecord + jne error + +; 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 + ; + mov ebx, [si + HFSPlusCatalogFile.dataFork + HFSPlusForkData.logicalSize + 4] + bswap ebx ; convert file size to little-endian + add ebx, kSectorBytes - 1 ; adjust size before unit conversion + shr ebx, 9 ; convert file size to sector unit + cmp bx, kBoot2Sectors ; check if bigger than max stage2 size + ja error + mov eax, [si + HFSPlusCatalogFile.fileID] + bswap eax ; convert fileID to little-endian + xor ecx, ecx + mov edx, (kBoot2Segment << 4) + kBoot2Address + lea di, [si + HFSPlusCatalogFile.dataFork + HFSPlusForkData.extents] + call readExtent + +%if VERBOSE + LogString(root_str) +%endif + +boot2: + +%if DEBUG + DebugChar ('!') +%endif + +%if UNUSED + ; + ; Waiting for a key press. + ; + + mov ah, 0 + int 0x16 +%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 + mov bx, ax + +.loop: + xor eax, eax ; EAX = 0 + mov al, bl ; assume we reached the last block. + cmp bx, maxSectorCount ; check if we really reached the last block + jb .readBlock ; yes, BX < MaxSectorCount + mov al, maxSectorCount ; no, read MaxSectorCount + +.readBlock: + call readLBA + sub bx, ax ; decrease remaning sectors with the read amount + jz .exit ; exit if no more sectors left to be loaded + add ecx, eax ; adjust LBA sector offset + shl ax, 9 ; convert sectors to bytes + add edx, 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. + ; + + mov bx, dx ; save offset to BX + and bh, 0x0f ; keep low 12 bits + shr edx, 4 ; adjust linear address to segment base + xor dl, dl ; mask low 8 bits + mov es, 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 + + jc 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 + 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 + + push di + mov si, log_title_str + call print_string + + pop si + call print_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 + int 0x16 + 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 + push di ; save DI for unicode string length pointer + mov si, dx ; use SI as source string pointer + xor ax, ax ; AX = unicode character + mov cl, al ; CL = string length + +.loop: + stosw ; store unicode character (length 0 at first run) + lodsb ; load next character to AL + inc cl ; increment string length count + cmp al, NULL ; check for string terminator + jne .loop + + pop di ; restore unicode string length pointer + dec cl ; 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 + xchg ah, al + stosw + cmp al, 0 + je .exit + mov cx, ax + +.loop: + lodsw + xchg ah, al ; convert AX to little-endian + + ; + ; When working with a case-sensitive HFS+ (HX) filesystem, we shouldn't change the case. + ; + cmp BYTE [kHFSPlusBuffer + HFSPlusVolumeHeader.signature + 1], kHFSPlusCaseSigX + je .keepcase + + or ax, ax + jne .convertToLE + dec ax ; NULL must be the strongest char + +.convertToLE: + cmp ah, 0 + ja .keepcase + cmp al, 'A' + jb .keepcase + cmp al, 'Z' + ja .keepcase + add al, 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 + + mov dl, 0 ; DL = result of comparison, DH = bestGuess + mov eax, [si + HFSPlusExtentKey.fileID] + cmp eax, [di + HFSPlusExtentKey.fileID] + jne .checkFlags + + cmp BYTE [si + HFSPlusExtentKey.forkType], kForkTypeData + jne .checkFlags + + mov eax, [si + HFSPlusExtentKey.startBlock] + cmp eax, [di + HFSPlusExtentKey.startBlock] + je compareHFSPlusCatalogKeys.exit + +.checkFlags: + ja compareHFSPlusCatalogKeys.searchKeyGreater ; search key > trial key + jb compareHFSPlusCatalogKeys.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 + xor dx, dx ; DL = result of comparison, DH = bestGuess + xchg si, di + lodsd + mov ecx, eax ; ECX = trial parentID + xchg si, di + lodsd ; EAX = search parentID + cmp eax, ecx + ja .searchKeyGreater ; search parentID > trial parentID + jb .trialKeyGreater ; search parentID < trial parentID + +.compareNodeName: ; search parentID = trial parentID + xchg si, di + lodsw + mov cx, ax ; CX = trial nodeName.length + xchg si, di + lodsw ; AX = search nodeName.length + cmp cl, 0 ; trial nodeName.length = 0? + je .searchKeyGreater + + cmp ax, cx + je .strCompare + ja .searchStrLonger + +.trialStrLonger: + dec dh + mov cx, ax + jmp .strCompare + +.searchStrLonger: + inc dh + +.strCompare: + repe cmpsw + ja .searchKeyGreater + jb .trialKeyGreater + mov dl, dh + jmp .exit + +.trialKeyGreater: + dec dl + jmp .exit + +.searchKeyGreater: + inc dl + +.exit: + mov [bp + BTree.searchResult], dl + cmp dl, 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: + push ax ; save AX + push di ; save DI + mov di, [gMallocPtr] ; start address of free space + push di ; save free space start address + inc di ; + inc di ; keep the first word untouched + dec cx ; for the last memory block pointer. + dec cx ; + mov al, NULL ; fill with zero + rep stosb ; repeat fill + mov [gMallocPtr], di ; adjust free space pointer + pop bp ; BP = start address of allocated memory + mov [di], bp ; set start address of allocated memory at next + ; allocation block's free space address. + pop di ; restore DI + pop ax ; restore AX + ret + +%if UNUSED + +;-------------------------------------------------------------------------- +; Free allocated memory +; +; Returns: +; BP = start address of previously allocated memory +; +free: + lea bp, [gMallocPtr] + mov bp, [bp] + mov [gMallocPtr], bp + ret + +%endif ; UNUSED + +;-------------------------------------------------------------------------- +; Static data. +; + +%if VERBOSE +root_str db '/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: + times 510-($-$$) db 0 + dw kBootSignature + +; +; 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: + mov cx, BTree_size ; allocate memory with BTree_size + call malloc ; BP = start address of allocated memory. + mov [bp + BTree.fileID], al ; save fileFileID + mov edx, [di] ; first extent of current file + call blockToSector ; ECX = converted to sector unit + mov al, 1 ; 1 sector is enough for + xor edx, edx ; reading current file's header. + lea dx, [bp + BTree.BTHeaderBuffer] ; load into BTreeHeaderBuffer + call readLBA ; read + mov ax, [bp + BTree.BTHeaderBuffer + BTNodeDescriptor_size + BTHeaderRec.nodeSize] + xchg ah, al ; convert to little-endian + mov [bp + BTree.nodeSize], ax ; save nodeSize + + ; + ; Always start the lookup process with the root node. + ; + mov edx, [bp + BTree.BTHeaderBuffer + BTNodeDescriptor_size + BTHeaderRec.rootNode] + +.readNode: + ; + ; Converting nodeID to sector unit + ; + mov ax, [bp + BTree.nodeSize] + shr ax, 9 ; convert nodeSize to sectors + mov bx, ax ; BX = read sector count + cwde + bswap edx ; convert node ID to little-endian + mul edx ; multiply with nodeSize converted to sector unit + mov ecx, eax ; ECX = file offset in BTree + + mov eax, [bp + BTree.fileID] + lea edx, [bp + BTree.nodeBuffer] + call readExtent + + ; + ; AX = lowerBound = 0 + ; + xor ax, ax + + ; + ; BX = upperBound = numRecords - 1 + ; + mov bx, [bp + BTree.nodeBuffer + BTNodeDescriptor.numRecords] + xchg bh, bl + dec bx + +.bsearch: + cmp ax, bx + ja .checkResult ; jump if lowerBound > upperBound + + mov cx, ax + add cx, bx + shr cx, 1 ; test index = (lowerBound + upperBound / 2) + + call getBTreeRecord + +%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: + mov bx, cx + dec bx ; upperBound = index - 1 + jmp .bsearch + +.searchGreaterThanTrial: + mov ax, cx + inc ax ; lowerBound = index + 1 + jmp .bsearch + +.checkResult: + cmp BYTE [bp + BTree.searchResult], 0 + jge .foundKey + + mov cx, bx + call getBTreeRecord + +.foundKey: + cmp BYTE [bp + BTree.nodeBuffer + BTNodeDescriptor.kind], kBTIndexNode + jne .exit + + lea bx, [bp + BTree.recordDataPtr] + mov bx, [bx] + mov edx, [bx] + jmp .readNode + +.exit: + cmp BYTE [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 + push si ; save SI + lea di, [bp + BTree.nodeBuffer] ; DI = start of nodeBuffer + push di ; use later + mov ax, [bp + BTree.nodeSize] ; get nodeSize + add di, ax ; DI = beyond nodeBuffer + inc cx ; increment index + shl cx, 1 ; * 2 + sub di, cx ; DI = pointer to record + mov ax, [di] ; offset to record + xchg ah, al ; convert to little-endian + pop di ; start of nodeBuffer + add di, ax ; DI = address of record key + mov si, di ; save to SI + mov ax, [di] ; keyLength + xchg ah, al ; convert to little-endian + inc ax ; suppress keySize (2 bytes) + inc ax ; + add di, ax ; DI = address of record data + mov [bp + BTree.recordDataPtr], di ; save address of record data + lea di, [bp + BTree.trialKey] + push di ; 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 + ; + cmp BYTE [bp + BTree.fileID], kHFSCatalogFileID + je .prepareTrialCatalogKey + +.prepareTrialExtentKey: + mov bx, compareHFSPlusExtentKeys + movsw ; copy forkType + pad + mov cx, 2 ; copy fileID + startBlock + +.extentLoop: + lodsd + bswap eax ; convert to little-endian + stosd + loop .extentLoop + jmp .exit + +.prepareTrialCatalogKey: + mov bx, compareHFSPlusCatalogKeys + lodsd + bswap eax ; convert ParentID to little-endian + stosd + call ConvertHFSUniStr255ToLE ; convert nodeName to little-endian + +.exit: + pop di ; restore address of trialKey + +%if UNUSED +; +; Print catalog trial key +; + pushad + mov si, di + lodsd + PrintChar('k') + PrintHex() + lodsw + cmp ax, 0 + je .printExit + mov cx, ax +.printLoop: + lodsw + call print_char + loop .printLoop +.printExit: + popad +; +; +; +%endif ; UNUSED + +%if UNUSED +; +; Print extent trial key +; + pushad + PrintChar('k') + mov si, di + xor eax, eax + lodsw + PrintHex() + lodsd + PrintHex() + lodsd + PrintHex() + popad +; +; +; +%endif ; UNUSED + + pop si ; restore SI + call bx ; 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 + mov ax, bx + cwde + mov [bp + BTree.readSize], eax + mov ebx, ecx ; EBX = file offset + xor eax, eax + mov [bp + BTree.currentExtentOffs], eax + +.beginExtentBlock: + mov BYTE [bp + BTree.extentCount], 0 + +.extentSearch: + cmp BYTE [bp + BTree.extentCount], kHFSPlusExtentDensity + jb .continue + +.getNextExtentBlock: + push ebx + mov eax, [bp + BTree.currentExtentOffs] + + ; + ; Converting sector unit to HFS+ allocation block unit. + ; + xor edx, edx + div DWORD [gBlockSize] ; divide with blockSize + + ; + ; Preparing searchExtentKey's startBlock field. + ; + mov [bp + BTree.searchExtentKey + HFSPlusExtentKey.startBlock], eax + + mov al, kHFSExtentsFileID + lea si, [bp + BTree.searchExtentKey] + lea di, [kHFSPlusBuffer + HFSPlusVolumeHeader.extentsFile + HFSPlusForkData.extents] + call lookUpBTree + jnz NEAR .exit + + ; + ; BP points to the new workspace allocated by lookUpBTree. + ; + lea di, [bp + BTree.recordDataPtr] + mov di, [di] + + ; + ; Switch back to the previous workspace. + ; + lea bp, [gMallocPtr] + mov bp, [bp] + mov [gMallocPtr], bp + + pop ebx + jmp .beginExtentBlock + +.continue: + mov edx, [di + HFSPlusExtentDescriptor.blockCount] + call blockToSector ; ECX = converted current extent's blockCount to sectors + mov eax, [bp + BTree.currentExtentOffs] ; EAX = current extent's start offset (sector) + mov edx, eax + add edx, ecx ; EDX = next extent's start offset (sector) + cmp ebx, 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: + mov edx, ebx + sub edx, eax ; EDX = relative offset within current extent + mov eax, edx ; will be used below to determine read size + mov esi, [bp + BTree.readSize] ; ESI = remaining sectors to be read + add edx, esi + cmp edx, ecx ; test if relative offset + readSize fits to this extent + jbe .read ; read all remaining sectors from this extent + +.splitRead: + sub ecx, eax ; read amount of sectors beginning at relative offset + mov esi, ecx ; of current extent up to the end of current extent + +.read: + mov edx, [di + HFSPlusExtentDescriptor.startBlock] + call blockToSector ; ECX = converted to sectors + add ecx, eax ; file offset converted to sectors + + push si + mov ax, si + mov edx, [bp + BTree.readBufferPtr] + call readSectors + pop si + + add ebx, esi + mov ax, si + cwde + shl ax, 9 ; convert SI (read sector count) to byte unit + add [bp + BTree.readBufferPtr], eax + sub [bp + BTree.readSize], esi + + jz .exit + +.nextExtent: + add di, kHFSPlusExtentDensity + inc BYTE [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: + push eax + mov eax, [gBlockSize] + bswap edx ; convert allocation block to little-endian + mul edx ; multiply with block number + mov ecx, eax ; result in EAX + pop eax + 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: + push eax + mov eax, edx + xor edx, edx + div DWORD [gBlockSize] ; divide with blockSize + mov ecx, eax ; result in EAX + pop eax + 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: + push eax + mov ax, [bp + BTree.nodeSize] + shr ax, 9 ; convert nodeSize to sectors + cwde + bswap edx ; convert node ID to little-endian + mul edx ; multiply with node ID + mov ecx, eax ; result in EAX + pop eax + ret + +%endif ; UNUSED + +;-------------------------------------------------------------------------- +; Static data. +; + +%if VERBOSE +log_title_str db CR, LF, 'boot1: ', NULL +error_str db 'error', NULL +%endif + +searchCatalogKey dd kHFSRootFolderID + dw searchCatKeyNameLen +searchCatKeyName dw 'b', 'o', 'o', 't' ; must be lower case +searchCatKeyNameLen EQU ($ - 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: + times 1022-($-$$) db 0 + dw kBootSignature + +; +; Local BTree variables +; + struc BTree +.mallocLink resw 1 ; pointer to previously allocated memory block +.fileID resd 1 ; will use as BYTE +.nodeSize resd 1 ; will use as WORD +.searchExtentKey resb HFSPlusExtentKey_size +.searchResult resb 1 +.trialKey resb kBTMaxRecordLength +.recordDataPtr resw 1 +.readBufferPtr resd 1 +.currentExtentOffs resd 1 +.readSize resd 1 +.extentCount resb 1 + ALIGNB 2 +.BTHeaderBuffer resb kSectorBytes +.nodeBuffer resb maxNodeSize + endstruc + +; +; Global variables +; + + ABSOLUTE kHFSPlusBuffer + HFSPlusVolumeHeader_size + +gPartLBA resd 1 +gBIOSDriveNumber resw 1 +gBlockSize resd 1 +gMallocPtr resw 1 + +; END Index: branches/cparm/i386/boot2/boot.c =================================================================== --- branches/cparm/i386/boot2/boot.c (revision 1524) +++ branches/cparm/i386/boot2/boot.c (revision 1525) @@ -89,7 +89,7 @@ char gMKextName[512]; char gMacOSVersion[8]; char *gRootDevice = NULL; -bool uuidSet = false; + #ifndef OPTION_ROM bool gEnableCDROMRescan; bool gScanSingleDrive; @@ -117,6 +117,7 @@ #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(); @@ -563,23 +564,26 @@ // 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 @@ -612,7 +616,6 @@ } verbose("Loading Darwin %s\n", gMacOSVersion); - { long cachetime, kerneltime, exttime; if (trycache ) do { @@ -623,6 +626,7 @@ { trycache = 0; bootInfo->adler32 = 0; + DBG("No kernel found, kernelcache disabled !!!\n"); break; } ret = GetFileInfo(NULL, gBootKernelCacheFile, &flags, &cachetime); @@ -631,6 +635,8 @@ { 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); @@ -639,6 +645,8 @@ { 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) @@ -649,11 +657,13 @@ { trycache = 0; bootInfo->adler32 = 0; + DBG("Warning: invalid timestamp, kernelcache disabled !!!\n"); + break; } } while (0); } - + do { if (trycache) { @@ -698,12 +708,12 @@ 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); @@ -765,6 +775,18 @@ #endif } +static void determineCpuArch(void) +{ + if (cpu_mode_is64bit()) + { + archCpuType = CPU_TYPE_X86_64; + } + else + { + archCpuType = CPU_TYPE_I386; + } +} + void getKernelCachePath() { { @@ -794,7 +816,7 @@ len++; } } - strlcpy(gBootKernelCacheFile, buffer, sizeof(gBootKernelCacheFile)); + strlcpy(gBootKernelCacheFile, buffer, sizeof(gBootKernelCacheFile)+1); } else { @@ -843,7 +865,7 @@ { 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))); @@ -878,14 +900,14 @@ { // 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)) @@ -929,6 +951,10 @@ 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)) @@ -999,22 +1025,33 @@ 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 { @@ -1121,7 +1158,7 @@ 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; } Index: branches/cparm/i386/boot2/boot.h =================================================================== --- branches/cparm/i386/boot2/boot.h (revision 1524) +++ branches/cparm/i386/boot2/boot.h (revision 1525) @@ -119,7 +119,7 @@ //extern char gRootPath[]; extern char *gRootDevice; -extern bool uuidSet; + /* * Boot Modes */ Index: branches/cparm/i386/boot2/modules.c =================================================================== --- branches/cparm/i386/boot2/modules.c (revision 1524) +++ branches/cparm/i386/boot2/modules.c (revision 1525) @@ -100,19 +100,30 @@ { 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); Index: branches/cparm/i386/boot2/mboot.c =================================================================== --- branches/cparm/i386/boot2/mboot.c (revision 1524) +++ branches/cparm/i386/boot2/mboot.c (revision 1525) @@ -308,8 +308,6 @@ // 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(); Index: branches/cparm/i386/boot2/options.c =================================================================== --- branches/cparm/i386/boot2/options.c (revision 1524) +++ branches/cparm/i386/boot2/options.c (revision 1525) @@ -111,20 +111,21 @@ 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; @@ -964,7 +965,7 @@ 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 ) ) { @@ -973,7 +974,7 @@ gOverrideKernel = true; } } else { - strlcpy( bootInfo->bootFile, kDefaultKernel, sizeof(bootInfo->bootFile) ); + strlcpy( bootInfo->bootFile, kDefaultKernel, sizeof(bootInfo->bootFile)+1 ); } } Index: branches/cparm/i386/boot2/Makefile =================================================================== --- branches/cparm/i386/boot2/Makefile (revision 1524) +++ branches/cparm/i386/boot2/Makefile (revision 1525) @@ -77,7 +77,7 @@ @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 Index: branches/cparm/i386/modules/ACPIPatcher/AcpiPatcher.c =================================================================== --- branches/cparm/i386/modules/ACPIPatcher/AcpiPatcher.c (revision 1524) +++ branches/cparm/i386/modules/ACPIPatcher/AcpiPatcher.c (revision 1525) @@ -37,7 +37,7 @@ 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); } Index: branches/cparm/i386/modules/GUI/gui.c =================================================================== --- branches/cparm/i386/modules/GUI/gui.c (revision 1524) +++ branches/cparm/i386/modules/GUI/gui.c (revision 1525) @@ -2224,6 +2224,7 @@ for ( time = time18(), timeout++; timeout > 0; ) { + if( time18() > (unsigned)lasttime) { multi--; Index: branches/cparm/i386/modules/GraphicsEnabler/gma.c =================================================================== --- branches/cparm/i386/modules/GraphicsEnabler/gma.c (revision 1524) +++ branches/cparm/i386/modules/GraphicsEnabler/gma.c (revision 1525) @@ -18,6 +18,11 @@ #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 }, @@ -60,7 +65,14 @@ { 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); @@ -151,6 +163,11 @@ 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) Index: branches/cparm/i386/modules/GraphicsEnabler/nvidia.c =================================================================== --- branches/cparm/i386/modules/GraphicsEnabler/nvidia.c (revision 1524) +++ branches/cparm/i386/modules/GraphicsEnabler/nvidia.c (revision 1525) @@ -194,7 +194,7 @@ { 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" }, @@ -230,7 +230,7 @@ // 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" }, @@ -270,9 +270,9 @@ { 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 @@ -394,6 +394,7 @@ { 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" }, @@ -491,16 +492,14 @@ { 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" }, @@ -557,7 +556,7 @@ { 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 @@ -810,6 +809,7 @@ // 10B0 - 10BF // 10C0 - 10CF { 0x10DE10C3, "GeForce 8400 GS" }, + { 0x10DE10C5, "GeForce 405" }, // 1200 - { 0x10DE1200, "GeForce GTX 560 Ti" }, { 0x10DE1244, "GeForce GTX 550 Ti" }, @@ -1351,8 +1351,7 @@ { 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]); } } @@ -1365,8 +1364,7 @@ { 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]); } } Index: branches/cparm/i386/modules/HibernateEnabler/resume.c =================================================================== --- branches/cparm/i386/modules/HibernateEnabler/resume.c (revision 1524) +++ branches/cparm/i386/modules/HibernateEnabler/resume.c (revision 1525) @@ -17,6 +17,8 @@ #include "resume.h" #include "graphic_utils.h" +extern char gMacOSVersion[]; + extern int previewTotalSectors; extern int previewLoadedSectors; extern uint8_t *previewSaveunder; @@ -103,6 +105,176 @@ 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->previewSizepreviewSize), + 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; @@ -111,6 +283,12 @@ 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); @@ -146,14 +324,7 @@ 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; @@ -178,11 +349,11 @@ 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 Index: branches/cparm/i386/modules/HibernateEnabler/IOHibernatePrivate.h =================================================================== --- branches/cparm/i386/modules/HibernateEnabler/IOHibernatePrivate.h (revision 1524) +++ branches/cparm/i386/modules/HibernateEnabler/IOHibernatePrivate.h (revision 1525) @@ -95,7 +95,71 @@ }; typedef struct IOHibernateImageHeader IOHibernateImageHeader; +struct IOHibernateImageHeader107 +{ + uint64_t imageSize; + uint64_t image1Size; + + uint32_t restore1CodePhysPage; + uint32_t reserved1; + uint64_t restore1CodeVirt; + uint32_t restore1PageCount; + uint32_t restore1CodeOffset; + uint32_t restore1StackOffset; + + uint32_t pageCount; + uint32_t bitmapSize; + + uint32_t restore1Sum; + uint32_t image1Sum; + uint32_t image2Sum; + + uint32_t actualRestore1Sum; + uint32_t actualImage1Sum; + uint32_t actualImage2Sum; + + uint32_t actualUncompressedPages; + uint32_t conflictCount; + uint32_t nextFree; + + uint32_t signature; + uint32_t processorFlags; + + uint32_t runtimePages; + uint32_t runtimePageCount; + uint64_t runtimeVirtualPages __attribute__ ((packed)); + + uint32_t performanceDataStart; + uint32_t performanceDataSize; + + uint64_t encryptStart __attribute__ ((packed)); + uint64_t machineSignature __attribute__ ((packed)); + + uint32_t previewSize; + uint32_t previewPageListSize; + + uint32_t diag[4]; + + uint32_t handoffPages; + uint32_t handoffPageCount; + + uint32_t systemTableOffset; + + uint32_t debugFlags; + uint32_t options; + + uint32_t reserved[70]; // make sizeof == 512 + + uint64_t encryptEnd __attribute__ ((packed)); + uint64_t deviceBase __attribute__ ((packed)); + + uint32_t fileExtentMapSize; + IOPolledFileExtent fileExtentMap[2]; +}; + +typedef struct IOHibernateImageHeader107 IOHibernateImageHeader107; + struct hibernate_bitmap_t { uint32_t first_page; Index: branches/cparm/i386/modules/HibernateEnabler/HibernateEnabler.c =================================================================== --- branches/cparm/i386/modules/HibernateEnabler/HibernateEnabler.c (revision 1524) +++ branches/cparm/i386/modules/HibernateEnabler/HibernateEnabler.c (revision 1525) @@ -2,9 +2,7 @@ * HibernateEnabler.c * Chameleon * - * Created by cparm. - * Copyright 2010. All rights reserved. - * + * Created by cparm. */ #include "bootstruct.h" Index: branches/cparm/i386/modules/Keymapper/Keymapper.c =================================================================== --- branches/cparm/i386/modules/Keymapper/Keymapper.c (revision 1524) +++ branches/cparm/i386/modules/Keymapper/Keymapper.c (revision 1525) @@ -14,7 +14,21 @@ #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) @@ -228,6 +242,7 @@ if (enable) { - register_hook_callback("Keymapper", &Keymapper_hook); + //register_hook_callback("Keymapper", &Keymapper_hook); + replace_function("_getc", &Keymapper_getc); } } \ No newline at end of file Index: branches/cparm/i386/modules/ACPICodec/acpi_codec.c =================================================================== --- branches/cparm/i386/modules/ACPICodec/acpi_codec.c (revision 1524) +++ branches/cparm/i386/modules/ACPICodec/acpi_codec.c (revision 1525) @@ -96,8 +96,8 @@ 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 @@ -145,6 +145,9 @@ 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 ); @@ -176,6 +179,11 @@ 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 @@ -291,6 +299,14 @@ { 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 ; @@ -311,18 +327,21 @@ { 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) @@ -335,6 +354,13 @@ 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)); @@ -442,6 +468,12 @@ 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)); @@ -994,7 +1026,7 @@ 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; @@ -1364,6 +1396,32 @@ 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) { @@ -1386,13 +1444,7 @@ } static U32 compute_tdp(CPU_DETAILS * cpu) -{ - { - int tdp; - if (getIntForKey("TDP", &tdp, &bootInfo->bootConfig)) { - return (U32)tdp; - } - } +{ { if (is_jaketown() || is_sandybridge()) @@ -1463,8 +1515,7 @@ // 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; @@ -1489,64 +1540,220 @@ } //----------------------------------------------------------------------------- -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; @@ -1586,35 +1793,57 @@ } #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 @@ -1628,7 +1857,9 @@ // 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 ++) @@ -1644,6 +1875,7 @@ 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 @@ -1655,12 +1887,15 @@ // Convert to mW pstate->power*= 1000; } +#else + pstate->power = 0; +#endif } } return (1); } -#else + //----------------------------------------------------------------------------- static U32 BuildPstateInfo(CPU_DETAILS * cpu) { @@ -1696,7 +1931,7 @@ 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; @@ -1722,7 +1957,7 @@ wrmsr64(MSR_IA32_PERF_CONTROL, (msr & 0xFFFFFFFFFFFF0000ULL) | (maximum.FID << 8) | maximum.VID); intel_waitforsts(); } - + if (minimum.VID == maximum.VID) { U64 msr; @@ -1741,7 +1976,7 @@ 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 @@ -1810,36 +2045,51 @@ 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; @@ -1850,7 +2100,7 @@ break; } } - default: + default: break; } } @@ -2171,27 +2421,27 @@ 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 }; @@ -2204,7 +2454,7 @@ // 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 @@ -2215,7 +2465,7 @@ // 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. @@ -2267,21 +2517,20 @@ 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 { @@ -2317,7 +2566,7 @@ 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]]; @@ -2325,15 +2574,14 @@ 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 { @@ -2453,13 +2701,18 @@ 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; @@ -2474,7 +2727,7 @@ { 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) @@ -2482,7 +2735,7 @@ 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 @@ -2506,6 +2759,11 @@ // 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); @@ -3588,13 +3846,7 @@ // (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) { @@ -3609,6 +3861,22 @@ 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); @@ -3879,6 +4147,11 @@ 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) ? @@ -3961,14 +4234,25 @@ { 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); } @@ -4003,6 +4287,11 @@ 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; @@ -4010,6 +4299,11 @@ 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); } @@ -4024,6 +4318,11 @@ 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; @@ -4035,6 +4334,11 @@ 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); } } @@ -4178,7 +4482,7 @@ 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; @@ -4200,7 +4504,12 @@ 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)); @@ -4322,18 +4631,20 @@ 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 { @@ -4346,10 +4657,11 @@ 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; @@ -4361,6 +4673,13 @@ 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)); @@ -4486,20 +4805,23 @@ 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) @@ -4630,9 +4952,6 @@ 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))) { @@ -4644,11 +4963,7 @@ { break; } - } - //else - //{ - // free(tmp); - //} + } } #if DEBUG_ACPI @@ -4673,11 +4988,7 @@ } } - - // TODO : Add an option for that - //cpuNamespace = CPU_NAMESPACE_PR; //Default - - + if (speed_step) { gen_psta= true; @@ -4710,12 +5021,7 @@ 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; @@ -4723,6 +5029,9 @@ else { rsdp_mod=(ACPI_TABLE_RSDP *) AllocateKernelMemory(rsdplength); + + if (!rsdp_mod) return EFI_OUT_OF_RESOURCES; + memcpy(rsdp_mod, rsdp, rsdplength); } @@ -4763,12 +5072,10 @@ { 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) @@ -4788,6 +5095,8 @@ 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) { Index: branches/cparm/i386/modules/ACPICodec/ACPICodec.c =================================================================== --- branches/cparm/i386/modules/ACPICodec/ACPICodec.c (revision 1524) +++ branches/cparm/i386/modules/ACPICodec/ACPICodec.c (revision 1525) @@ -32,7 +32,7 @@ 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); } Index: branches/cparm/Makefile =================================================================== --- branches/cparm/Makefile (revision 1524) +++ branches/cparm/Makefile (revision 1525) @@ -19,7 +19,7 @@ OBJROOT = `pwd`/obj SYMROOT = `pwd`/sym DSTROOT = `pwd`/dst -SRCROOT = /tmp +SRCROOT = `pwd` DOCROOT = `pwd`/doc IMGROOT = `pwd`/sym/cache IMGSKELROOT = `pwd`/imgskel @@ -86,22 +86,39 @@ 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; \