/* * 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; }
static void mca_get_availability(void) { uint64_t features = cpuid_info()->cpuid_features; uint32_t family = cpuid_info()->cpuid_family; mca_MCE_present = (features & CPUID_FEATURE_MCE) != 0; mca_MCA_present = (features & CPUID_FEATURE_MCA) != 0; mca_family = family; /* * If MCA, the number of banks etc is reported by the IA32_MCG_CAP MSR. */ if (mca_MCA_present) { ia32_mcg_cap.u64 = rdmsr64(IA32_MCG_CAP); mca_error_bank_count = ia32_mcg_cap.bits.count; mca_control_MSR_present = ia32_mcg_cap.bits.mcg_ctl_p; mca_threshold_status_present = ia32_mcg_cap.bits.mcg_tes_p; mca_sw_error_recovery_present = ia32_mcg_cap.bits.mcg_ser_p; mca_cmci_present = ia32_mcg_cap.bits.mcg_ext_corr_err_p; if (family == 0x0F) { mca_extended_MSRs_present = ia32_mcg_cap.bits.mcg_ext_p; mca_extended_MSRs_count = ia32_mcg_cap.bits.mcg_ext_cnt; } } }
void panic(const char *errormsg, ...) { va_list list; kprintf("\nKERNEL PANIC: "); if (can_use_serial) { bool early = false; if (rdmsr64(MSR_IA32_GS_BASE) == 0 && enable == false) { early = true; } if (early) { va_start(list, errormsg); _doprnt_log(errormsg, &list, serial_putc, 16); va_end(list); goto panicing; } else { normal_print: va_start(list, errormsg); _doprnt(errormsg, &list, putc, 16); va_end(list); goto panicing; } } else { goto normal_print; } panicing: kprintf("\nCPU Halted"); pal_stop_cpu(true); }
void scan_cpu_intel() { uint32_t cpuid_reg[4]; // Get Number of cores per package /* Initially set the EAX register to 4 and the ECX register to 0 prior to executing the CPUID instruction. After executing the CPUID instruction, (EAX[31:26] + 1) contains the number of cores. */ cpuid_reg[2]=1; do_cpuid(4, cpuid_reg); do_cpuid(4, cpuid_reg); // FIXME: why does this only work the 2nd time ? Platform.CPU.NoCores = bitfield(cpuid_reg[0], 31, 26) + 1; // Find Number of Concurrent Threads Processed (HyperThreading) do_cpuid(1,cpuid_reg); if(bitfield(cpuid_reg[1], 23, 16) > 1) Platform.CPU.NoThreads=Platform.CPU.NoCores; else Platform.CPU.NoThreads=Platform.CPU.NoCores * 2; // Mobile CPU ? if (rdmsr64(0x17) & (1<<28)) Platform.CPU.Mobile = 1; else Platform.CPU.Mobile = 0; }
static void mca_get_availability(void) { uint64_t features = cpuid_info()->cpuid_features; uint32_t family = cpuid_info()->cpuid_family; uint32_t model = cpuid_info()->cpuid_model; uint32_t stepping = cpuid_info()->cpuid_stepping; mca_MCE_present = (features & CPUID_FEATURE_MCE) != 0; mca_MCA_present = (features & CPUID_FEATURE_MCA) != 0; mca_family = family; if ((model == CPUID_MODEL_HASWELL && stepping < 3) || (model == CPUID_MODEL_HASWELL_ULT && stepping < 1) || (model == CPUID_MODEL_CRYSTALWELL && stepping < 1)) panic("Haswell pre-C0 steppings are not supported"); /* * If MCA, the number of banks etc is reported by the IA32_MCG_CAP MSR. */ if (mca_MCA_present) { ia32_mcg_cap.u64 = rdmsr64(IA32_MCG_CAP); mca_error_bank_count = ia32_mcg_cap.bits.count; mca_control_MSR_present = ia32_mcg_cap.bits.mcg_ctl_p; mca_threshold_status_present = ia32_mcg_cap.bits.mcg_tes_p; mca_sw_error_recovery_present = ia32_mcg_cap.bits.mcg_ser_p; mca_cmci_present = ia32_mcg_cap.bits.mcg_ext_corr_err_p; if (family == 0x0F) { mca_extended_MSRs_present = ia32_mcg_cap.bits.mcg_ext_p; mca_extended_MSRs_count = ia32_mcg_cap.bits.mcg_ext_cnt; } } }
/* * thread_fast_set_cthread_self: Sets the machine kernel thread ID of the * current thread to the given thread ID; fast version for 32-bit processes * * Parameters: self Thread ID to set * * Returns: 0 Success * !0 Not success */ kern_return_t thread_fast_set_cthread_self(uint32_t self) { thread_t thread = current_thread(); pcb_t pcb = thread->machine.pcb; struct real_descriptor desc = { .limit_low = 1, .limit_high = 0, .base_low = self & 0xffff, .base_med = (self >> 16) & 0xff, .base_high = (self >> 24) & 0xff, .access = ACC_P|ACC_PL_U|ACC_DATA_W, .granularity = SZ_32|SZ_G, }; current_thread()->machine.pcb->cthread_self = (uint64_t) self; /* preserve old func too */ /* assign descriptor */ mp_disable_preemption(); pcb->cthread_desc = desc; *ldt_desc_p(USER_CTHREAD) = desc; saved_state32(pcb->iss)->gs = USER_CTHREAD; mp_enable_preemption(); return (USER_CTHREAD); } /* * thread_fast_set_cthread_self64: Sets the machine kernel thread ID of the * current thread to the given thread ID; fast version for 64-bit processes * * Parameters: self Thread ID * * Returns: 0 Success * !0 Not success */ kern_return_t thread_fast_set_cthread_self64(uint64_t self) { pcb_t pcb = current_thread()->machine.pcb; cpu_data_t *cdp; /* check for canonical address, set 0 otherwise */ if (!IS_USERADDR64_CANONICAL(self)) self = 0ULL; pcb->cthread_self = self; mp_disable_preemption(); cdp = current_cpu_datap(); #if defined(__x86_64__) if ((cdp->cpu_uber.cu_user_gs_base != pcb->cthread_self) || (pcb->cthread_self != rdmsr64(MSR_IA32_KERNEL_GS_BASE))) wrmsr64(MSR_IA32_KERNEL_GS_BASE, self); #endif cdp->cpu_uber.cu_user_gs_base = self; mp_enable_preemption(); return (USER_CTHREAD); }
inline void read_cpu_thermal(void* cpu_index) { UInt8 * cpn = (UInt8 *)cpu_index; *cpn = get_cpu_number(); if(*cpn < kCPUSensorsMaxCpus) { UInt64 msr = rdmsr64(MSR_IA32_THERM_STS); if (msr & 0x80000000) cpu_thermal[*cpn] = (msr >> 16) & 0x7F; }
static inline void read_cpu_thermal(void *magic) { UInt32 number = get_cpu_number(); if (number < kCPUSensorsMaxCpus) { UInt64 msr = rdmsr64(MSR_IA32_THERM_STS); if (msr & 0x80000000) { cpu_thermal[number] = (msr >> 16) & 0x7F; cpu_thermal_updated[number] = true; }
// Real timer filter bool driver::perfTimerEvent(IOTimerEventSource *src, int count) { uint64_t msr; uint32_t vid; uint32_t next_check_delay; uint32_t wantspeed,wantstep; long i,idle,used,total; if (driverStatus != driverDrive) return(false); //ok, so we're using adaptive mode.. if (get_cpu_ticks(&idle, &total)) fail("get_cpu_load"); // Used = % used x 10 used = ((total-idle)*1000)/total; // If used > 95% we can't really guess how much is needed, so step to highest speed if (used>=950) wantspeed=speedstep_cpu_setting[num_speeds-1].cpuMhz; // Otherwise wantspeed is the ideal frequency to maintain idle % target else wantspeed = (speedstep_cpu_setting[stepCurrent].cpuMhz * (used+1)) / TARGET_CPULOAD; if (wantspeed>=speedstep_cpu_setting[num_speeds-1].cpuMhz) wantstep = num_speeds-1; // We want something higher than our highest else if (wantspeed<=speedstep_cpu_setting[0].cpuMhz) wantstep = 0; // We want something lower than our lowest // Otherwise, find the best step else for (i = 0; i < (num_speeds-1); i++) if ((wantspeed >= speedstep_cpu_setting[i].cpuMhz) && (wantspeed < speedstep_cpu_setting[i+1].cpuMhz)) wantstep=i; //dbg("pctused=%u idle=%u total=%u wantspeed=%u wantstep=%u\n",used,idle,total,wantspeed,wantstep); if (wantstep == stepCurrent) goto check_soon; stepCurrent = wantstep; // Assume we got the one we wanted eist_update_all_cpus(speedstep_cpu_setting[wantstep].VID); // IOSleep(1); msr = rdmsr64(MSR_PERF_CTL); vid = msr & 0xFFFF; dbg("Stepping to %u pctused=%u VID=0x%04x\n",speedstep_cpu_setting[wantstep].cpuMhz,used,vid); perfTimer->setTimeoutMS(512 * (wantstep+1)); // Make the delay until the next check proportional to the speed we picked return(true); perfTimer->setTimeoutMS(1024); success: return(true); check_soon: perfTimer->setTimeoutMS(512); return(true); fail: return(false); }
static void mca_save_state(mca_state_t *mca_state) { mca_mci_bank_t *bank; unsigned int i; assert(!ml_get_interrupts_enabled() || get_preemption_level() > 0); if (mca_state == NULL) return; mca_state->mca_mcg_ctl = mca_control_MSR_present ? rdmsr64(IA32_MCG_CTL) : 0ULL; mca_state->mca_mcg_status.u64 = rdmsr64(IA32_MCG_STATUS); bank = (mca_mci_bank_t *) &mca_state->mca_error_bank[0]; for (i = 0; i < mca_error_bank_count; i++, bank++) { bank->mca_mci_ctl = rdmsr64(IA32_MCi_CTL(i)); bank->mca_mci_status.u64 = rdmsr64(IA32_MCi_STATUS(i)); if (!bank->mca_mci_status.bits.val) continue; bank->mca_mci_misc = (bank->mca_mci_status.bits.miscv)? rdmsr64(IA32_MCi_MISC(i)) : 0ULL; bank->mca_mci_addr = (bank->mca_mci_status.bits.addrv)? rdmsr64(IA32_MCi_ADDR(i)) : 0ULL; } /* * If we're the first thread with MCA state, point our package to it * and don't care about races */ if (x86_package()->mca_state == NULL) x86_package()->mca_state = mca_state; }
/* * Set MSRs for sysenter/sysexit for 64-bit. */ static void fast_syscall_init64(void) { wrmsr64(MSR_IA32_SYSENTER_CS, SYSENTER_CS); wrmsr64(MSR_IA32_SYSENTER_EIP, UBER64(hi64_sysenter)); wrmsr64(MSR_IA32_SYSENTER_ESP, UBER64(current_sstk())); /* Enable syscall/sysret */ wrmsr64(MSR_IA32_EFER, rdmsr64(MSR_IA32_EFER) | MSR_IA32_EFER_SCE); /* * MSRs for 64-bit syscall/sysret * Note USER_CS because sysret uses this + 16 when returning to * 64-bit code. */ wrmsr64(MSR_IA32_LSTAR, UBER64(hi64_syscall)); wrmsr64(MSR_IA32_STAR, (((uint64_t)USER_CS) << 48) | (((uint64_t)KERNEL64_CS) << 32)); /* * Emulate eflags cleared by sysenter but note that * we also clear the trace trap to avoid the complications * of single-stepping into a syscall. The nested task bit * is also cleared to avoid a spurious "task switch" * should we choose to return via an IRET. */ wrmsr64(MSR_IA32_FMASK, EFL_DF|EFL_IF|EFL_TF|EFL_NT); /* * Set the Kernel GS base MSR to point to per-cpu data in uber-space. * The uber-space handler (hi64_syscall) uses the swapgs instruction. */ wrmsr64(MSR_IA32_KERNEL_GS_BASE, UBER64((unsigned long)current_cpu_datap())); #if ONLY_SAFE_FOR_LINDA_SERIAL kprintf("fast_syscall_init64() KERNEL_GS_BASE=0x%016llx\n", rdmsr64(MSR_IA32_KERNEL_GS_BASE)); #endif }
static void eist_update_action(void *t) { uint64_t msr; uint16_t vid; uint64_t v64; bcopy(t,&vid,2); v64=vid; msr = rdmsr64(MSR_PERF_CTL); msr = (msr & ~(uint64_t)(0xffff)) | v64; wrmsr64(MSR_PERF_CTL, msr); //intdbg("CPU%d: %s vid=%d\n", get_cpu_number(), __FUNCTION__,vid); }
void kprintf(const char *fmt, ...) { va_list listp; boolean_t state; if (!disable_serial_output) { boolean_t early = FALSE; if (rdmsr64(MSR_IA32_GS_BASE) == 0) { early = TRUE; } /* If PE_kputc has not yet been initialized, don't * take any locks, just dump to serial */ if (!PE_kputc || early) { va_start(listp, fmt); _doprnt(fmt, &listp, pal_serial_putc, 16); va_end(listp); return; } /* * Spin to get kprintf lock but re-enable interrupts while * failing. * This allows interrupts to be handled while waiting but * interrupts are disabled once we have the lock. */ state = ml_set_interrupts_enabled(FALSE); pal_preemption_assert(); while (!simple_lock_try(&kprintf_lock)) { ml_set_interrupts_enabled(state); ml_set_interrupts_enabled(FALSE); } if (cpu_number() != cpu_last_locked) { MP_DEBUG_KPRINTF("[cpu%d...]\n", cpu_number()); cpu_last_locked = cpu_number(); } va_start(listp, fmt); _doprnt(fmt, &listp, PE_kputc, 16); va_end(listp); simple_unlock(&kprintf_lock); ml_set_interrupts_enabled(state); } }
static inline void cpu_check(void *magic) { int number = cpu_number(); if (number < kCPUSensorsMaxCpus) { cpu_enabled[number] = true; uint32_t cpuid_reg[4]; do_cpuid(0x0b, cpuid_reg); cpu_lapic[number] = cpuid_reg[edx]; cpu_check_value[number] = rdmsr64(MSR_IA32_PACKAGE_THERM_STATUS); } }
static void vmx_init(void) { uint64_t msr_image; if (!vmx_is_available()) return; /* * We don't count on EFI initializing MSR_IA32_FEATURE_CONTROL * and turning VMXON on and locking the bit, so we do that now. */ msr_image = rdmsr64(MSR_IA32_FEATURE_CONTROL); if (0 == ((msr_image & MSR_IA32_FEATCTL_LOCK))) wrmsr64(MSR_IA32_FEATURE_CONTROL, (msr_image | MSR_IA32_FEATCTL_VMXON | MSR_IA32_FEATCTL_LOCK)); }
bool AutoThrottler::perfTimerEvent(IOTimerEventSource* src, int count) { uint32_t wantspeed,wantstep; long idle, used, total; uint64_t msr; msr = rdmsr64(INTEL_MSR_PERF_STS); // read current MSR // For clock recalibration if (!enabled || !setupDone) return false; // gather stats PStates[currentPState].TimesChosen++; totalTimerEvents++; GetCPUTicks(&idle, &total); // Used = % used x 10 used = ((total - idle) * 1000) / total; dbg( "used %ld ", used ); // If used > 95% we can't really guess how much is needed, so step to highest speed // if (used >= 950) // wantspeed = PStates[0].AcpiFreq; // else // Otherwise wantspeed is the ideal frequency to maintain idle % target wantspeed = (PStates[currentPState].AcpiFreq * (used + 1)) / targetCPULoad; wantstep = FindClosestPState(wantspeed); // 20110802 WTF? // if (VID(msr) == 975) goto check_soon; currentPState = wantstep; // Assume we got the one we wanted throttleAllCPUs(&PStates[currentPState]); perfTimer->setTimeoutMS(throttleQuantum * (NumberOfPStates - wantstep)); // Make the delay until the next check proportional to the speed we picked return true; check_soon: perfTimer->setTimeoutMS(throttleQuantum); return true; }
void kprintf(const char *fmt, ...) { va_list listp; //bool state; if (can_use_serial) { bool early = false; if (rdmsr64(MSR_IA32_GS_BASE) == 0&&enable==false) { early = true; } if (early) { va_start(listp, fmt); _doprnt_log(fmt, &listp, serial_putc, 16); va_end(listp); return; } /* * Spin to get kprintf lock but poll for incoming signals * while interrupts are masked. */ /*state = ml_set_interrupts_enabled(FALSE); pal_preemption_assert(); while (!simple_lock_try(&kprintf_lock)) { (void) cpu_signal_handler(NULL); } if (cpu_number() != cpu_last_locked) { MP_DEBUG_KPRINTF("[cpu%d...]\n", cpu_number()); cpu_last_locked = cpu_number(); }*/ va_start(listp, fmt); _doprnt(fmt, &listp, putc, 16); va_end(listp); /*simple_unlock(&kprintf_lock); ml_set_interrupts_enabled(state);*/ } }
void throttleCPU(void *t) { uint64_t msr; PState p; uint32_t newfreq, oldfreq; bcopy(t,&p,sizeof(PState)); // get the ctl we want msr = rdmsr64(INTEL_MSR_PERF_STS); // read current MSR // For clock recalibration oldfreq = FID_to_Hz(FID(msr)); // blank out last 32 bits and put our ctl there msr = (msr & 0xffffffffffff0000ULL) | CTL(p.Frequency, p.Voltage); newfreq = FID_to_Hz(FID(msr)); // after setting ctl in msr //if (RtcFixKernel && !ConstantTSC) { //rtc_clock_stepping(newfreq, oldfreq); //} wrmsr64(INTEL_MSR_PERF_CTL, msr); // and write it to the processor //if (RtcFixKernel && !ConstantTSC) //rtc_clock_stepped(newfreq, oldfreq); }
static uint32_t rdmsr32(uint32_t msr) { return (uint32_t) rdmsr64(msr); }
static void mca_dump_64bit_state(void) { kdb_printf("Extended Machine Check State:\n"); kdb_printf(" IA32_MCG_RAX: 0x%016qx\n", rdmsr64(IA32_MCG_RAX)); kdb_printf(" IA32_MCG_RBX: 0x%016qx\n", rdmsr64(IA32_MCG_RBX)); kdb_printf(" IA32_MCG_RCX: 0x%016qx\n", rdmsr64(IA32_MCG_RCX)); kdb_printf(" IA32_MCG_RDX: 0x%016qx\n", rdmsr64(IA32_MCG_RDX)); kdb_printf(" IA32_MCG_RSI: 0x%016qx\n", rdmsr64(IA32_MCG_RSI)); kdb_printf(" IA32_MCG_RDI: 0x%016qx\n", rdmsr64(IA32_MCG_RDI)); kdb_printf(" IA32_MCG_RBP: 0x%016qx\n", rdmsr64(IA32_MCG_RBP)); kdb_printf(" IA32_MCG_RSP: 0x%016qx\n", rdmsr64(IA32_MCG_RSP)); kdb_printf(" IA32_MCG_RFLAGS: 0x%016qx\n", rdmsr64(IA32_MCG_RFLAGS)); kdb_printf(" IA32_MCG_RIP: 0x%016qx\n", rdmsr64(IA32_MCG_RIP)); kdb_printf(" IA32_MCG_MISC: 0x%016qx\n", rdmsr64(IA32_MCG_MISC)); kdb_printf(" IA32_MCG_R8: 0x%016qx\n", rdmsr64(IA32_MCG_R8)); kdb_printf(" IA32_MCG_R9: 0x%016qx\n", rdmsr64(IA32_MCG_R9)); kdb_printf(" IA32_MCG_R10: 0x%016qx\n", rdmsr64(IA32_MCG_R10)); kdb_printf(" IA32_MCG_R11: 0x%016qx\n", rdmsr64(IA32_MCG_R11)); kdb_printf(" IA32_MCG_R12: 0x%016qx\n", rdmsr64(IA32_MCG_R12)); kdb_printf(" IA32_MCG_R13: 0x%016qx\n", rdmsr64(IA32_MCG_R13)); kdb_printf(" IA32_MCG_R14: 0x%016qx\n", rdmsr64(IA32_MCG_R14)); kdb_printf(" IA32_MCG_R15: 0x%016qx\n", rdmsr64(IA32_MCG_R15)); }
/* * Calculates the FSB and CPU frequencies using specific MSRs for each CPU * - multi. is read from a specific MSR. In the case of Intel, there is: * a max multi. (used to calculate the FSB freq.), * and a current multi. (used to calculate the CPU freq.) * - fsbFrequency = tscFrequency / multi * - cpuFrequency = fsbFrequency * multi */ void scan_cpu(PlatformInfo_t *p) { uint64_t tscFrequency, fsbFrequency, cpuFrequency; uint64_t msr, flex_ratio; uint8_t maxcoef, maxdiv, currcoef, bus_ratio_max, currdiv; const char *newratio; int len, myfsb; uint8_t bus_ratio_min; uint32_t max_ratio, min_ratio; max_ratio = min_ratio = myfsb = bus_ratio_min = 0; maxcoef = maxdiv = bus_ratio_max = currcoef = currdiv = 0; /* get cpuid values */ do_cpuid(0x00000000, p->CPU.CPUID[CPUID_0]); do_cpuid(0x00000001, p->CPU.CPUID[CPUID_1]); do_cpuid(0x00000002, p->CPU.CPUID[CPUID_2]); do_cpuid(0x00000003, p->CPU.CPUID[CPUID_3]); do_cpuid2(0x00000004, 0, p->CPU.CPUID[CPUID_4]); do_cpuid(0x80000000, p->CPU.CPUID[CPUID_80]); if (p->CPU.CPUID[CPUID_0][0] >= 0x5) { do_cpuid(5, p->CPU.CPUID[CPUID_5]); } if (p->CPU.CPUID[CPUID_0][0] >= 6) { do_cpuid(6, p->CPU.CPUID[CPUID_6]); } if ((p->CPU.CPUID[CPUID_80][0] & 0x0000000f) >= 8) { do_cpuid(0x80000008, p->CPU.CPUID[CPUID_88]); do_cpuid(0x80000001, p->CPU.CPUID[CPUID_81]); } else if ((p->CPU.CPUID[CPUID_80][0] & 0x0000000f) >= 1) { do_cpuid(0x80000001, p->CPU.CPUID[CPUID_81]); } #if DEBUG_CPU { int i; printf("CPUID Raw Values:\n"); for (i=0; i<CPUID_MAX; i++) { printf("%02d: %08x-%08x-%08x-%08x\n", i, p->CPU.CPUID[i][0], p->CPU.CPUID[i][1], p->CPU.CPUID[i][2], p->CPU.CPUID[i][3]); } } #endif p->CPU.Vendor = p->CPU.CPUID[CPUID_0][1]; p->CPU.Signature = p->CPU.CPUID[CPUID_1][0]; p->CPU.Stepping = bitfield(p->CPU.CPUID[CPUID_1][0], 3, 0); p->CPU.Model = bitfield(p->CPU.CPUID[CPUID_1][0], 7, 4); p->CPU.Family = bitfield(p->CPU.CPUID[CPUID_1][0], 11, 8); p->CPU.ExtModel = bitfield(p->CPU.CPUID[CPUID_1][0], 19, 16); p->CPU.ExtFamily = bitfield(p->CPU.CPUID[CPUID_1][0], 27, 20); p->CPU.Model += (p->CPU.ExtModel << 4); if (p->CPU.Vendor == CPUID_VENDOR_INTEL && p->CPU.Family == 0x06 && p->CPU.Model >= CPUID_MODEL_NEHALEM && p->CPU.Model != CPUID_MODEL_ATOM // MSR is *NOT* available on the Intel Atom CPU ) { msr = rdmsr64(MSR_CORE_THREAD_COUNT); // Undocumented MSR in Nehalem and newer CPUs p->CPU.NoCores = bitfield((uint32_t)msr, 31, 16); // Using undocumented MSR to get actual values p->CPU.NoThreads = bitfield((uint32_t)msr, 15, 0); // Using undocumented MSR to get actual values } else if (p->CPU.Vendor == CPUID_VENDOR_AMD) { p->CPU.NoThreads = bitfield(p->CPU.CPUID[CPUID_1][1], 23, 16); p->CPU.NoCores = bitfield(p->CPU.CPUID[CPUID_88][2], 7, 0) + 1; } else { // Use previous method for Cores and Threads p->CPU.NoThreads = bitfield(p->CPU.CPUID[CPUID_1][1], 23, 16); p->CPU.NoCores = bitfield(p->CPU.CPUID[CPUID_4][0], 31, 26) + 1; } /* get brand string (if supported) */ /* Copyright: from Apple's XNU cpuid.c */ if (p->CPU.CPUID[CPUID_80][0] > 0x80000004) { uint32_t reg[4]; char str[128], *s; /* * The brand string 48 bytes (max), guaranteed to * be NULL terminated. */ do_cpuid(0x80000002, reg); bcopy((char *)reg, &str[0], 16); do_cpuid(0x80000003, reg); bcopy((char *)reg, &str[16], 16); do_cpuid(0x80000004, reg); bcopy((char *)reg, &str[32], 16); for (s = str; *s != '\0'; s++) { if (*s != ' ') break; } strlcpy(p->CPU.BrandString, s, sizeof(p->CPU.BrandString)); if (!strncmp(p->CPU.BrandString, CPU_STRING_UNKNOWN, MIN(sizeof(p->CPU.BrandString), strlen(CPU_STRING_UNKNOWN) + 1))) { /* * This string means we have a firmware-programmable brand string, * and the firmware couldn't figure out what sort of CPU we have. */ p->CPU.BrandString[0] = '\0'; } } /* setup features */ if ((bit(23) & p->CPU.CPUID[CPUID_1][3]) != 0) { p->CPU.Features |= CPU_FEATURE_MMX; } if ((bit(25) & p->CPU.CPUID[CPUID_1][3]) != 0) { p->CPU.Features |= CPU_FEATURE_SSE; } if ((bit(26) & p->CPU.CPUID[CPUID_1][3]) != 0) { p->CPU.Features |= CPU_FEATURE_SSE2; } if ((bit(0) & p->CPU.CPUID[CPUID_1][2]) != 0) { p->CPU.Features |= CPU_FEATURE_SSE3; } if ((bit(19) & p->CPU.CPUID[CPUID_1][2]) != 0) { p->CPU.Features |= CPU_FEATURE_SSE41; } if ((bit(20) & p->CPU.CPUID[CPUID_1][2]) != 0) { p->CPU.Features |= CPU_FEATURE_SSE42; } if ((bit(29) & p->CPU.CPUID[CPUID_81][3]) != 0) { p->CPU.Features |= CPU_FEATURE_EM64T; } if ((bit(5) & p->CPU.CPUID[CPUID_1][3]) != 0) { p->CPU.Features |= CPU_FEATURE_MSR; } //if ((bit(28) & p->CPU.CPUID[CPUID_1][3]) != 0) { if (p->CPU.NoThreads > p->CPU.NoCores) { p->CPU.Features |= CPU_FEATURE_HTT; } tscFrequency = measure_tsc_frequency(); /* if usual method failed */ if ( tscFrequency < 1000 ) { tscFrequency = timeRDTSC() * 20; } fsbFrequency = 0; cpuFrequency = 0; if ((p->CPU.Vendor == CPUID_VENDOR_INTEL) && ((p->CPU.Family == 0x06) || (p->CPU.Family == 0x0f))) { int intelCPU = p->CPU.Model; if ((p->CPU.Family == 0x06 && p->CPU.Model >= 0x0c) || (p->CPU.Family == 0x0f && p->CPU.Model >= 0x03)) { /* Nehalem CPU model */ if (p->CPU.Family == 0x06 && (p->CPU.Model == CPU_MODEL_NEHALEM || p->CPU.Model == CPU_MODEL_FIELDS || p->CPU.Model == CPU_MODEL_DALES || p->CPU.Model == CPU_MODEL_DALES_32NM || p->CPU.Model == CPU_MODEL_WESTMERE || p->CPU.Model == CPU_MODEL_NEHALEM_EX || p->CPU.Model == CPU_MODEL_WESTMERE_EX || p->CPU.Model == CPU_MODEL_SANDYBRIDGE || p->CPU.Model == CPU_MODEL_JAKETOWN || p->CPU.Model == CPU_MODEL_IVYBRIDGE)) { msr = rdmsr64(MSR_PLATFORM_INFO); DBG("msr(%d): platform_info %08x\n", __LINE__, bitfield(msr, 31, 0)); bus_ratio_max = bitfield(msr, 14, 8); bus_ratio_min = bitfield(msr, 46, 40); //valv: not sure about this one (Remarq.1) msr = rdmsr64(MSR_FLEX_RATIO); DBG("msr(%d): flex_ratio %08x\n", __LINE__, bitfield(msr, 31, 0)); if (bitfield(msr, 16, 16)) { flex_ratio = bitfield(msr, 14, 8); /* bcc9: at least on the gigabyte h67ma-ud2h, where the cpu multipler can't be changed to allow overclocking, the flex_ratio msr has unexpected (to OSX) contents. These contents cause mach_kernel to fail to compute the bus ratio correctly, instead causing the system to crash since tscGranularity is inadvertently set to 0. */ if (flex_ratio == 0) { /* Clear bit 16 (evidently the presence bit) */ wrmsr64(MSR_FLEX_RATIO, (msr & 0xFFFFFFFFFFFEFFFFULL)); msr = rdmsr64(MSR_FLEX_RATIO); verbose("Unusable flex ratio detected. Patched MSR now %08x\n", bitfield(msr, 31, 0)); } else { if (bus_ratio_max > flex_ratio) { bus_ratio_max = flex_ratio; } } } if (bus_ratio_max) { fsbFrequency = (tscFrequency / bus_ratio_max); } //valv: Turbo Ratio Limit if ((intelCPU != 0x2e) && (intelCPU != 0x2f)) { msr = rdmsr64(MSR_TURBO_RATIO_LIMIT); cpuFrequency = bus_ratio_max * fsbFrequency; max_ratio = bus_ratio_max * 10; } else { cpuFrequency = tscFrequency; } if ((getValueForKey(kbusratio, &newratio, &len, &bootInfo->chameleonConfig)) && (len <= 4)) { max_ratio = atoi(newratio); max_ratio = (max_ratio * 10); if (len >= 3) max_ratio = (max_ratio + 5); verbose("Bus-Ratio: min=%d, max=%s\n", bus_ratio_min, newratio); // extreme overclockers may love 320 ;) if ((max_ratio >= min_ratio) && (max_ratio <= 320)) { cpuFrequency = (fsbFrequency * max_ratio) / 10; if (len >= 3) maxdiv = 1; else maxdiv = 0; } else { max_ratio = (bus_ratio_max * 10); } } //valv: to be uncommented if Remarq.1 didn't stick /*if (bus_ratio_max > 0) bus_ratio = flex_ratio;*/ p->CPU.MaxRatio = max_ratio; p->CPU.MinRatio = min_ratio; myfsb = fsbFrequency / 1000000; verbose("Sticking with [BCLK: %dMhz, Bus-Ratio: %d]\n", myfsb, max_ratio); currcoef = bus_ratio_max; } else { msr = rdmsr64(MSR_IA32_PERF_STATUS); DBG("msr(%d): ia32_perf_stat 0x%08x\n", __LINE__, bitfield(msr, 31, 0)); currcoef = bitfield(msr, 12, 8); /* Non-integer bus ratio for the max-multi*/ maxdiv = bitfield(msr, 46, 46); /* Non-integer bus ratio for the current-multi (undocumented)*/ currdiv = bitfield(msr, 14, 14); // This will always be model >= 3 if ((p->CPU.Family == 0x06 && p->CPU.Model >= 0x0e) || (p->CPU.Family == 0x0f)) { /* On these models, maxcoef defines TSC freq */ maxcoef = bitfield(msr, 44, 40); } else { /* On lower models, currcoef defines TSC freq */ /* XXX */ maxcoef = currcoef; } if (maxcoef) { if (maxdiv) { fsbFrequency = ((tscFrequency * 2) / ((maxcoef * 2) + 1)); } else { fsbFrequency = (tscFrequency / maxcoef); } if (currdiv) { cpuFrequency = (fsbFrequency * ((currcoef * 2) + 1) / 2); } else { cpuFrequency = (fsbFrequency * currcoef); } DBG("max: %d%s current: %d%s\n", maxcoef, maxdiv ? ".5" : "",currcoef, currdiv ? ".5" : ""); } } } /* Mobile CPU */ if (rdmsr64(MSR_IA32_PLATFORM_ID) & (1<<28)) { p->CPU.Features |= CPU_FEATURE_MOBILE; } } else if ((p->CPU.Vendor == CPUID_VENDOR_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 */ msr = rdmsr64(K10_COFVID_STATUS); do_cpuid2(0x00000006, 0, p->CPU.CPUID[CPUID_6]); // EffFreq: effective frequency interface if (bitfield(p->CPU.CPUID[CPUID_6][2], 0, 0) == 1) { //uint64_t mperf = measure_mperf_frequency(); 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 */ // not implimented break; } 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); } } if (!cpuFrequency) cpuFrequency = tscFrequency; } #if 0 if (!fsbFrequency) { fsbFrequency = (DEFAULT_FSB * 1000); cpuFrequency = tscFrequency; DBG("0 ! using the default value for FSB !\n"); } #endif p->CPU.MaxCoef = maxcoef; p->CPU.MaxDiv = maxdiv; p->CPU.CurrCoef = currcoef; p->CPU.CurrDiv = currdiv; p->CPU.TSCFrequency = tscFrequency; p->CPU.FSBFrequency = fsbFrequency; p->CPU.CPUFrequency = cpuFrequency; // keep formatted with spaces instead of tabs DBG("CPU: Brand String: %s\n", p->CPU.BrandString); DBG("CPU: Vendor/Family/ExtFamily: 0x%x/0x%x/0x%x\n", p->CPU.Vendor, p->CPU.Family, p->CPU.ExtFamily); DBG("CPU: Model/ExtModel/Stepping: 0x%x/0x%x/0x%x\n", p->CPU.Model, p->CPU.ExtModel, p->CPU.Stepping); DBG("CPU: MaxCoef/CurrCoef: 0x%x/0x%x\n", p->CPU.MaxCoef, p->CPU.CurrCoef); DBG("CPU: MaxDiv/CurrDiv: 0x%x/0x%x\n", p->CPU.MaxDiv, p->CPU.CurrDiv); DBG("CPU: TSCFreq: %dMHz\n", p->CPU.TSCFrequency / 1000000); DBG("CPU: FSBFreq: %dMHz\n", p->CPU.FSBFrequency / 1000000); DBG("CPU: CPUFreq: %dMHz\n", p->CPU.CPUFrequency / 1000000); DBG("CPU: NoCores/NoThreads: %d/%d\n", p->CPU.NoCores, p->CPU.NoThreads); DBG("CPU: Features: 0x%08x\n", p->CPU.Features); #if DEBUG_CPU pause(); #endif }
/* * Calculates the FSB and CPU frequencies using specific MSRs for each CPU * - multi. is read from a specific MSR. In the case of Intel, there is: * a max multi. (used to calculate the FSB freq.), * and a current multi. (used to calculate the CPU freq.) * - fsbFrequency = tscFrequency / multi * - cpuFrequency = fsbFrequency * multi */ void scan_cpu(PlatformInfo_t *p) { uint64_t tscFrequency = 0; uint64_t fsbFrequency = 0; uint64_t cpuFrequency = 0; uint64_t msr = 0; uint64_t flex_ratio = 0; uint32_t max_ratio = 0; uint32_t min_ratio = 0; uint8_t bus_ratio_max = 0; uint8_t currdiv = 0; uint8_t currcoef = 0; uint8_t maxdiv = 0; uint8_t maxcoef = 0; const char *newratio; int len = 0; int myfsb = 0; uint8_t bus_ratio_min = 0; uint32_t reg[4]; char str[128]; /* get cpuid values */ do_cpuid(0x00000000, p->CPU.CPUID[CPUID_0]); do_cpuid(0x00000001, p->CPU.CPUID[CPUID_1]); do_cpuid(0x00000002, p->CPU.CPUID[CPUID_2]); do_cpuid(0x00000003, p->CPU.CPUID[CPUID_3]); do_cpuid2(0x00000004, 0, p->CPU.CPUID[CPUID_4]); do_cpuid(0x80000000, p->CPU.CPUID[CPUID_80]); if (p->CPU.CPUID[CPUID_0][0] >= 0x5) { do_cpuid(5, p->CPU.CPUID[CPUID_5]); } if (p->CPU.CPUID[CPUID_0][0] >= 6) { do_cpuid(6, p->CPU.CPUID[CPUID_6]); } if ((p->CPU.CPUID[CPUID_80][0] & 0x0000000f) >= 8) { do_cpuid(0x80000008, p->CPU.CPUID[CPUID_88]); do_cpuid(0x80000001, p->CPU.CPUID[CPUID_81]); } else if ((p->CPU.CPUID[CPUID_80][0] & 0x0000000f) >= 1) { do_cpuid(0x80000001, p->CPU.CPUID[CPUID_81]); } // #if DEBUG_CPU { int i; DBG("CPUID Raw Values:\n"); for (i = 0; i < CPUID_MAX; i++) { DBG("%02d: %08x-%08x-%08x-%08x\n", i, p->CPU.CPUID[i][0], p->CPU.CPUID[i][1], p->CPU.CPUID[i][2], p->CPU.CPUID[i][3]); } } // #endif /* EAX (Intel): 31 28 27 20 19 16 1514 1312 11 8 7 4 3 0 +--------+----------------+--------+----+----+--------+--------+--------+ |########|Extended family |Extmodel|####|type|familyid| model |stepping| +--------+----------------+--------+----+----+--------+--------+--------+ EAX (AMD): 31 28 27 20 19 16 1514 1312 11 8 7 4 3 0 +--------+----------------+--------+----+----+--------+--------+--------+ |########|Extended family |Extmodel|####|####|familyid| model |stepping| +--------+----------------+--------+----+----+--------+--------+--------+ */ p->CPU.Vendor = p->CPU.CPUID[CPUID_0][1]; p->CPU.Signature = p->CPU.CPUID[CPUID_1][0]; p->CPU.Stepping = (uint8_t)bitfield(p->CPU.CPUID[CPUID_1][0], 3, 0); // stepping = cpu_feat_eax & 0xF; p->CPU.Model = (uint8_t)bitfield(p->CPU.CPUID[CPUID_1][0], 7, 4); // model = (cpu_feat_eax >> 4) & 0xF; p->CPU.Family = (uint8_t)bitfield(p->CPU.CPUID[CPUID_1][0], 11, 8); // family = (cpu_feat_eax >> 8) & 0xF; //p->CPU.Type = (uint8_t)bitfield(p->CPU.CPUID[CPUID_1][0], 13, 12); // type = (cpu_feat_eax >> 12) & 0x3; p->CPU.ExtModel = (uint8_t)bitfield(p->CPU.CPUID[CPUID_1][0], 19, 16); // ext_model = (cpu_feat_eax >> 16) & 0xF; p->CPU.ExtFamily = (uint8_t)bitfield(p->CPU.CPUID[CPUID_1][0], 27, 20); // ext_family = (cpu_feat_eax >> 20) & 0xFF; p->CPU.Model += (p->CPU.ExtModel << 4); if (p->CPU.Vendor == CPUID_VENDOR_INTEL) { /* * Find the number of enabled cores and threads * (which determines whether SMT/Hyperthreading is active). */ switch (p->CPU.Model) { case CPU_MODEL_NEHALEM: case CPU_MODEL_FIELDS: case CPU_MODEL_DALES: case CPU_MODEL_NEHALEM_EX: case CPU_MODEL_JAKETOWN: case CPU_MODEL_SANDYBRIDGE: case CPU_MODEL_IVYBRIDGE: case CPU_MODEL_HASWELL: case CPU_MODEL_HASWELL_SVR: //case CPU_MODEL_HASWELL_H: case CPU_MODEL_HASWELL_ULT: case CPU_MODEL_CRYSTALWELL: msr = rdmsr64(MSR_CORE_THREAD_COUNT); p->CPU.NoCores = (uint8_t)bitfield((uint32_t)msr, 31, 16); p->CPU.NoThreads = (uint8_t)bitfield((uint32_t)msr, 15, 0); break; case CPU_MODEL_DALES_32NM: case CPU_MODEL_WESTMERE: case CPU_MODEL_WESTMERE_EX: msr = rdmsr64(MSR_CORE_THREAD_COUNT); p->CPU.NoCores = (uint8_t)bitfield((uint32_t)msr, 19, 16); p->CPU.NoThreads = (uint8_t)bitfield((uint32_t)msr, 15, 0); break; default: p->CPU.NoCores = 0; break; } // end switch } if (p->CPU.NoCores == 0) { p->CPU.NoCores = (uint8_t)(p->CPU.CoresPerPackage & 0xff); p->CPU.NoThreads = (uint8_t)(p->CPU.LogicalPerPackage & 0xff); } /* get BrandString (if supported) */ /* Copyright: from Apple's XNU cpuid.c */ if (p->CPU.CPUID[CPUID_80][0] > 0x80000004) { char *s; bzero(str, 128); /* * The BrandString 48 bytes (max), guaranteed to * be NULL terminated. */ do_cpuid(0x80000002, reg); memcpy(&str[0], (char *)reg, 16); do_cpuid(0x80000003, reg); memcpy(&str[16], (char *)reg, 16); do_cpuid(0x80000004, reg); memcpy(&str[32], (char *)reg, 16); for (s = str; *s != '\0'; s++) { if (*s != ' ') { break; } } strlcpy(p->CPU.BrandString, s, 48); if (!strncmp(p->CPU.BrandString, CPU_STRING_UNKNOWN, MIN(sizeof(p->CPU.BrandString), strlen(CPU_STRING_UNKNOWN) + 1))) { /* * This string means we have a firmware-programmable brand string, * and the firmware couldn't figure out what sort of CPU we have. */ p->CPU.BrandString[0] = '\0'; } p->CPU.BrandString[47] = '\0'; // DBG("Brandstring = %s\n", p->CPU.BrandString); } //workaround for N270. I don't know why it detected wrong // MSR is *NOT* available on the Intel Atom CPU if ((p->CPU.Model == CPU_MODEL_ATOM) && (strstr(p->CPU.BrandString, "270"))) { p->CPU.NoCores = 1; p->CPU.NoThreads = 2; } if (p->CPU.Vendor == CPUID_VENDOR_AMD) { p->CPU.NoThreads = (uint8_t)bitfield(p->CPU.CPUID[CPUID_1][1], 23, 16); p->CPU.NoCores = (uint8_t)bitfield(p->CPU.CPUID[CPUID_88][2], 7, 0) + 1; } /* setup features */ if ((bit(23) & p->CPU.CPUID[CPUID_1][3]) != 0) { p->CPU.Features |= CPU_FEATURE_MMX; } if ((bit(25) & p->CPU.CPUID[CPUID_1][3]) != 0) { p->CPU.Features |= CPU_FEATURE_SSE; } if ((bit(26) & p->CPU.CPUID[CPUID_1][3]) != 0) { p->CPU.Features |= CPU_FEATURE_SSE2; } if ((bit(0) & p->CPU.CPUID[CPUID_1][2]) != 0) { p->CPU.Features |= CPU_FEATURE_SSE3; } if ((bit(19) & p->CPU.CPUID[CPUID_1][2]) != 0) { p->CPU.Features |= CPU_FEATURE_SSE41; } if ((bit(20) & p->CPU.CPUID[CPUID_1][2]) != 0) { p->CPU.Features |= CPU_FEATURE_SSE42; } if ((bit(29) & p->CPU.CPUID[CPUID_81][3]) != 0) { p->CPU.Features |= CPU_FEATURE_EM64T; } if ((bit(5) & p->CPU.CPUID[CPUID_1][3]) != 0) { p->CPU.Features |= CPU_FEATURE_MSR; } //if ((bit(28) & p->CPU.CPUID[CPUID_1][3]) != 0) { if (p->CPU.NoThreads > p->CPU.NoCores) { p->CPU.Features |= CPU_FEATURE_HTT; } tscFrequency = measure_tsc_frequency(); DBG("cpu freq classic = 0x%016llx\n", tscFrequency); /* if usual method failed */ if ( tscFrequency < 1000 ) //TEST { tscFrequency = timeRDTSC() * 20;//measure_tsc_frequency(); // DBG("cpu freq timeRDTSC = 0x%016llx\n", tscFrequency); } else { // DBG("cpu freq timeRDTSC = 0x%016llxn", timeRDTSC() * 20); } fsbFrequency = 0; cpuFrequency = 0; if (p->CPU.Vendor == CPUID_VENDOR_INTEL && ((p->CPU.Family == 0x06 && p->CPU.Model >= 0x0c) || (p->CPU.Family == 0x0f && p->CPU.Model >= 0x03))) { int intelCPU = p->CPU.Model; if (p->CPU.Family == 0x06) { /* Nehalem CPU model */ switch (p->CPU.Model) { case CPU_MODEL_NEHALEM: case CPU_MODEL_FIELDS: case CPU_MODEL_DALES: case CPU_MODEL_DALES_32NM: case CPU_MODEL_WESTMERE: case CPU_MODEL_NEHALEM_EX: case CPU_MODEL_WESTMERE_EX: /* --------------------------------------------------------- */ case CPU_MODEL_SANDYBRIDGE: case CPU_MODEL_JAKETOWN: case CPU_MODEL_IVYBRIDGE_XEON: case CPU_MODEL_IVYBRIDGE: case CPU_MODEL_HASWELL: case CPU_MODEL_HASWELL_SVR: case CPU_MODEL_HASWELL_ULT: case CPU_MODEL_CRYSTALWELL: /* --------------------------------------------------------- */ msr = rdmsr64(MSR_PLATFORM_INFO); DBG("msr(%d): platform_info %08x\n", __LINE__, bitfield(msr, 31, 0)); bus_ratio_max = bitfield(msr, 15, 8); bus_ratio_min = bitfield(msr, 47, 40); //valv: not sure about this one (Remarq.1) msr = rdmsr64(MSR_FLEX_RATIO); DBG("msr(%d): flex_ratio %08x\n", __LINE__, bitfield(msr, 31, 0)); if (bitfield(msr, 16, 16)) { flex_ratio = bitfield(msr, 15, 8); /* bcc9: at least on the gigabyte h67ma-ud2h, where the cpu multipler can't be changed to allow overclocking, the flex_ratio msr has unexpected (to OSX) contents. These contents cause mach_kernel to fail to compute the bus ratio correctly, instead causing the system to crash since tscGranularity is inadvertently set to 0. */ if (flex_ratio == 0) { /* Clear bit 16 (evidently the presence bit) */ wrmsr64(MSR_FLEX_RATIO, (msr & 0xFFFFFFFFFFFEFFFFULL)); msr = rdmsr64(MSR_FLEX_RATIO); DBG("Unusable flex ratio detected. Patched MSR now %08x\n", bitfield(msr, 31, 0)); } else { if (bus_ratio_max > flex_ratio) { bus_ratio_max = flex_ratio; } } } if (bus_ratio_max) { fsbFrequency = (tscFrequency / bus_ratio_max); } //valv: Turbo Ratio Limit if ((intelCPU != 0x2e) && (intelCPU != 0x2f)) { msr = rdmsr64(MSR_TURBO_RATIO_LIMIT); cpuFrequency = bus_ratio_max * fsbFrequency; max_ratio = bus_ratio_max * 10; } else { cpuFrequency = tscFrequency; } if ((getValueForKey(kbusratio, &newratio, &len, &bootInfo->chameleonConfig)) && (len <= 4)) { max_ratio = atoi(newratio); max_ratio = (max_ratio * 10); if (len >= 3) { max_ratio = (max_ratio + 5); } verbose("Bus-Ratio: min=%d, max=%s\n", bus_ratio_min, newratio); // extreme overclockers may love 320 ;) if ((max_ratio >= min_ratio) && (max_ratio <= 320)) { cpuFrequency = (fsbFrequency * max_ratio) / 10; if (len >= 3) { maxdiv = 1; } else { maxdiv = 0; } } else { max_ratio = (bus_ratio_max * 10); } } //valv: to be uncommented if Remarq.1 didn't stick /*if (bus_ratio_max > 0) bus_ratio = flex_ratio;*/ p->CPU.MaxRatio = max_ratio; p->CPU.MinRatio = min_ratio; myfsb = fsbFrequency / 1000000; verbose("Sticking with [BCLK: %dMhz, Bus-Ratio: %d]\n", myfsb, max_ratio/10); // Bungo: fixed wrong Bus-Ratio readout currcoef = bus_ratio_max; break; default: msr = rdmsr64(MSR_IA32_PERF_STATUS); DBG("msr(%d): ia32_perf_stat 0x%08x\n", __LINE__, bitfield(msr, 31, 0)); currcoef = bitfield(msr, 12, 8); // Bungo: reverted to 2263 state because of wrong old CPUs freq. calculating /* Non-integer bus ratio for the max-multi*/ maxdiv = bitfield(msr, 46, 46); /* Non-integer bus ratio for the current-multi (undocumented)*/ currdiv = bitfield(msr, 14, 14); // This will always be model >= 3 if ((p->CPU.Family == 0x06 && p->CPU.Model >= 0x0e) || (p->CPU.Family == 0x0f)) { /* On these models, maxcoef defines TSC freq */ maxcoef = bitfield(msr, 44, 40); } else { /* On lower models, currcoef defines TSC freq */ /* XXX */ maxcoef = currcoef; } if (maxcoef) { if (maxdiv) { fsbFrequency = ((tscFrequency * 2) / ((maxcoef * 2) + 1)); } else { fsbFrequency = (tscFrequency / maxcoef); } if (currdiv) { cpuFrequency = (fsbFrequency * ((currcoef * 2) + 1) / 2); } else { cpuFrequency = (fsbFrequency * currcoef); } DBG("max: %d%s current: %d%s\n", maxcoef, maxdiv ? ".5" : "",currcoef, currdiv ? ".5" : ""); } break; } } /* Mobile CPU */ if (rdmsr64(MSR_IA32_PLATFORM_ID) & (1<<28)) { p->CPU.Features |= CPU_FEATURE_MOBILE; } } else if ((p->CPU.Vendor == CPUID_VENDOR_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 */ msr = rdmsr64(K10_COFVID_STATUS); do_cpuid2(0x00000006, 0, p->CPU.CPUID[CPUID_6]); // EffFreq: effective frequency interface if (bitfield(p->CPU.CPUID[CPUID_6][2], 0, 0) == 1) { //uint64_t mperf = measure_mperf_frequency(); 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 */ // not implimented break; } 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); } } if (!cpuFrequency) cpuFrequency = tscFrequency; } #if 0 if (!fsbFrequency) { fsbFrequency = (DEFAULT_FSB * 1000); cpuFrequency = tscFrequency; DBG("0 ! using the default value for FSB !\n"); } DBG("cpu freq = 0x%016llxn", timeRDTSC() * 20); #endif p->CPU.MaxCoef = maxcoef; p->CPU.MaxDiv = maxdiv; p->CPU.CurrCoef = currcoef; p->CPU.CurrDiv = currdiv; p->CPU.TSCFrequency = tscFrequency; p->CPU.FSBFrequency = fsbFrequency; p->CPU.CPUFrequency = cpuFrequency; // keep formatted with spaces instead of tabs DBG("\n---------------------------------------------\n"); DBG("------------------ CPU INFO -----------------\n"); DBG("---------------------------------------------\n"); DBG("Brand String: %s\n", p->CPU.BrandString); // Processor name (BIOS) DBG("Vendor: 0x%x\n", p->CPU.Vendor); // Vendor ex: GenuineIntel DBG("Family: 0x%x\n", p->CPU.Family); // Family ex: 6 (06h) DBG("ExtFamily: 0x%x\n", p->CPU.ExtFamily); DBG("Signature: %x\n", p->CPU.Signature); // CPUID signature DBG("Model: 0x%x\n", p->CPU.Model); // Model ex: 37 (025h) DBG("ExtModel: 0x%x\n", p->CPU.ExtModel); DBG("Stepping: 0x%x\n", p->CPU.Stepping); // Stepping ex: 5 (05h) DBG("MaxCoef: 0x%x\n", p->CPU.MaxCoef); DBG("CurrCoef: 0x%x\n", p->CPU.CurrCoef); DBG("MaxDiv: 0x%x\n", p->CPU.MaxDiv); DBG("CurrDiv: 0x%x\n", p->CPU.CurrDiv); DBG("TSCFreq: %dMHz\n", p->CPU.TSCFrequency / 1000000); DBG("FSBFreq: %dMHz\n", p->CPU.FSBFrequency / 1000000); DBG("CPUFreq: %dMHz\n", p->CPU.CPUFrequency / 1000000); DBG("Cores: %d\n", p->CPU.NoCores); // Cores DBG("Logical processor: %d\n", p->CPU.NoThreads); // Logical procesor DBG("Features: 0x%08x\n", p->CPU.Features); DBG("\n---------------------------------------------\n"); #if DEBUG_CPU pause(); #endif }
static void commpage_init_cpu_capabilities( void ) { uint64_t bits; int cpus; ml_cpu_info_t cpu_info; bits = 0; ml_cpu_get_info(&cpu_info); switch (cpu_info.vector_unit) { case 9: bits |= kHasAVX1_0; /* fall thru */ case 8: bits |= kHasSSE4_2; /* fall thru */ case 7: bits |= kHasSSE4_1; /* fall thru */ case 6: bits |= kHasSupplementalSSE3; /* fall thru */ case 5: bits |= kHasSSE3; /* fall thru */ case 4: bits |= kHasSSE2; /* fall thru */ case 3: bits |= kHasSSE; /* fall thru */ case 2: bits |= kHasMMX; default: break; } switch (cpu_info.cache_line_size) { case 128: bits |= kCache128; break; case 64: bits |= kCache64; break; case 32: bits |= kCache32; break; default: break; } cpus = commpage_cpus(); // how many CPUs do we have bits |= (cpus << kNumCPUsShift); bits |= kFastThreadLocalStorage; // we use %gs for TLS #define setif(_bits, _bit, _condition) \ if (_condition) _bits |= _bit setif(bits, kUP, cpus == 1); setif(bits, k64Bit, cpu_mode_is64bit()); setif(bits, kSlow, tscFreq <= SLOW_TSC_THRESHOLD); setif(bits, kHasAES, cpuid_features() & CPUID_FEATURE_AES); setif(bits, kHasF16C, cpuid_features() & CPUID_FEATURE_F16C); setif(bits, kHasRDRAND, cpuid_features() & CPUID_FEATURE_RDRAND); setif(bits, kHasFMA, cpuid_features() & CPUID_FEATURE_FMA); setif(bits, kHasBMI1, cpuid_leaf7_features() & CPUID_LEAF7_FEATURE_BMI1); setif(bits, kHasBMI2, cpuid_leaf7_features() & CPUID_LEAF7_FEATURE_BMI2); setif(bits, kHasRTM, cpuid_leaf7_features() & CPUID_LEAF7_FEATURE_RTM); setif(bits, kHasHLE, cpuid_leaf7_features() & CPUID_LEAF7_FEATURE_HLE); setif(bits, kHasAVX2_0, cpuid_leaf7_features() & CPUID_LEAF7_FEATURE_AVX2); setif(bits, kHasRDSEED, cpuid_features() & CPUID_LEAF7_FEATURE_RDSEED); setif(bits, kHasADX, cpuid_features() & CPUID_LEAF7_FEATURE_ADX); setif(bits, kHasMPX, cpuid_leaf7_features() & CPUID_LEAF7_FEATURE_MPX); setif(bits, kHasSGX, cpuid_leaf7_features() & CPUID_LEAF7_FEATURE_SGX); uint64_t misc_enable = rdmsr64(MSR_IA32_MISC_ENABLE); setif(bits, kHasENFSTRG, (misc_enable & 1ULL) && (cpuid_leaf7_features() & CPUID_LEAF7_FEATURE_ERMS)); _cpu_capabilities = bits; // set kernel version for use by drivers etc }
bool SMBIOSResolver::start(IOService * provider) { if( super::start(provider) != true ) return false; // Oh no if( IOService::getResourceService()->getProperty("SMBIOS-Resolver") ) return false; // We should exist only once if( !IOService::getResourceService()->getProperty("SMBIOS") ) return false; // AppleSMBIOS.kext didnĀ“t start we bail out IOService * iosRoot = getServiceRoot(); if( !iosRoot ) return false; // Unable to get IOServiceRoot int doVerbose = 0; // PE_parse_boot_arg("smbios", &doVerbose); // bootarg SMBIOS=1 will give a verbose output to log (when I find something verbose worth outputting) // Dictionary from plist OSDictionary * hwDict = OSDynamicCast( OSDictionary, getProperty("Override")); // /rom/version IORegistryEntry * dtROMNode = fromPath("/rom", gIODTPlane); if( dtROMNode ) { OSString * romVersion = OSDynamicCast( OSString, hwDict->getObject("rom-version")); if(romVersion->getLength() > 0) dtROMNode->setProperty("version", OSData::withBytes(romVersion->getCStringNoCopy(), romVersion->getLength() + 1) ); dtROMNode->release(); } else { return false; // No /rom node in IODeviceTree plane } // root entries OSObject * dictString = 0; dictString = hwDict->getObject("manufacturer"); if(dictString) { OSString * rootManufacturer = OSDynamicCast( OSString, dictString); if(rootManufacturer->getLength() > 1) iosRoot->setProperty("manufacturer", OSData::withBytes(rootManufacturer->getCStringNoCopy(), rootManufacturer->getLength() + 1) ); } dictString = hwDict->getObject("system-type"); if(dictString) { OSData * systemType = OSDynamicCast( OSData, dictString); if(systemType) iosRoot->setProperty("system-type", systemType ); } dictString = hwDict->getObject("compatible"); if(dictString) { OSString * rootCompatible = OSDynamicCast( OSString, dictString); if(rootCompatible->getLength() > 1) iosRoot->setProperty("compatible", OSData::withBytes(rootCompatible->getCStringNoCopy(), rootCompatible->getLength() + 1) ); } dictString = hwDict->getObject("product-name"); if(dictString) { OSString * rootProductName = OSDynamicCast( OSString, dictString); if(rootProductName->getLength() > 1) iosRoot->setProperty("product-name", OSData::withBytes(rootProductName->getCStringNoCopy(), rootProductName->getLength() + 1) ); } dictString = hwDict->getObject("model"); if(dictString) { OSString * rootModel = OSDynamicCast( OSString, dictString); if(rootModel->getLength() > 1) { iosRoot->setProperty("model", OSData::withBytes(rootModel->getCStringNoCopy(), rootModel->getLength() + 1) ); iosRoot->setName(rootModel->getCStringNoCopy()); } } dictString = hwDict->getObject("version"); if(dictString) { OSString * rootVersion = OSDynamicCast( OSString, dictString); if(rootVersion->getLength() > 1) iosRoot->setProperty("version", OSData::withBytes(rootVersion->getCStringNoCopy(), rootVersion->getLength() + 1) ); } dictString = hwDict->getObject("board-id"); if(dictString) { OSString * rootBoardId = OSDynamicCast( OSString, dictString); if(rootBoardId->getLength() > 1) iosRoot->setProperty("board-id", OSData::withBytes(rootBoardId->getCStringNoCopy(), rootBoardId->getLength() + 1) ); } dictString = hwDict->getObject("serial-number"); if(dictString) { OSString * rootSerial = OSDynamicCast( OSString, dictString); if(rootSerial->getLength() > 1) { UInt8 length = rootSerial->getLength(); const char *serialNumberString = rootSerial->getCStringNoCopy(); // The serial-number property in the IORegistry is a 43-byte data object. // Bytes 0 through 2 are the last three bytes of the serial number string. // Bytes 11 through 20, inclusive, are the serial number string itself. // All other bytes are '\0'. OSData * data = OSData::withCapacity(43); if (data) { data->appendBytes(serialNumberString + (length - 3), 3); data->appendBytes(NULL, 10); data->appendBytes(serialNumberString, length); data->appendBytes(NULL, 43 - length - 10 - 3); iosRoot->setProperty("serial-number", data); data->release(); } iosRoot->setProperty(kIOPlatformSerialNumberKey, rootSerial); } } dictString = hwDict->getObject("UUID-key"); if(dictString) { OSString * rootUUIDKey = OSDynamicCast( OSString, hwDict->getObject("UUID-key")); iosRoot->setProperty(kIOPlatformUUIDKey, rootUUIDKey); publishResource(kIOPlatformUUIDKey, rootUUIDKey); } bool useEfiBus = false; UInt64 fsbFrequency = 0; UInt64 msr; dictString = hwDict->getObject("use-efi-bus"); if (dictString) useEfiBus = (OSDynamicCast(OSBoolean, dictString))->getValue(); IORegistryEntry * efiPlatform = fromPath("/efi/platform", gIODTPlane); if (efiPlatform && useEfiBus) { OSData * efiFSBFreq = OSDynamicCast(OSData, efiPlatform->getProperty("FSBFrequency")); bcopy(efiFSBFreq->getBytesNoCopy(), &fsbFrequency, efiFSBFreq->getLength()); efiPlatform->release(); } else { // No /efi/platform found fsbFrequency = gPEClockFrequencyInfo.bus_frequency_hz; // Value previously set by AppleSMBIOS if (!strncmp(cpuid_info()->cpuid_vendor, CPUID_VID_INTEL, sizeof(CPUID_VID_INTEL)) && (cpuid_info()->cpuid_features & CPUID_FEATURE_SSE2)) fsbFrequency /= 4; } dictString = hwDict->getObject("hardcode-bus"); if(dictString) { fsbFrequency = (OSDynamicCast(OSNumber, dictString))->unsigned64BitValue(); if (fsbFrequency) { if (fsbFrequency <= 10000) fsbFrequency *= 1000000; } else { if (!strncmp(cpuid_info()->cpuid_vendor, CPUID_VID_INTEL, sizeof(CPUID_VID_INTEL))) { if ((cpuid_info()->cpuid_family == 0x0f) && (cpuid_info()->cpuid_model >= 2)) { msr = rdmsr64(0x0000002C); switch ((msr >> 16) & 0x7) { case 0: if (cpuid_info()->cpuid_model == 2) fsbFrequency = 100 * 1000000; else { fsbFrequency = (800 * 1000000) / 3; // 266 fsbFrequency++; } break; case 1: fsbFrequency = (400 * 1000000) / 3; // 133 break; case 2: fsbFrequency = (600 * 1000000) / 3; // 200 break; case 3: fsbFrequency = (500 * 1000000) / 3; // 166 fsbFrequency++; break; case 4: fsbFrequency = (1000 * 1000000) / 3; // 333 break; default: break; } } else { fsbFrequency = 100 * 1000000; } if (cpuid_info()->cpuid_family == 0x06) { msr = rdmsr64(0x000000CD); switch (msr & 0x7) { case 0: fsbFrequency = (800 * 1000000) / 3; // 266 fsbFrequency++; break; case 1: fsbFrequency = (400 * 1000000) / 3; // 133 break; case 2: fsbFrequency = (600 * 1000000) / 3; // 200 break; case 3: fsbFrequency = (500 * 1000000) / 3; // 166 fsbFrequency++; break; case 4: fsbFrequency = (1000 * 1000000) / 3;// 333 break; case 5: fsbFrequency = (300 * 1000000) / 3; // 100 break; case 6: fsbFrequency = (1200 * 1000000) / 3;// 400 break; case 7: // should check fsbFrequency = (1400 * 1000000) / 3;// 466 fsbFrequency++; break; default: break; } } } }
static void commpage_init_cpu_capabilities( void ) { uint64_t bits; int cpus; ml_cpu_info_t cpu_info; bits = 0; ml_cpu_get_info(&cpu_info); switch (cpu_info.vector_unit) { case 9: bits |= kHasAVX1_0; /* fall thru */ case 8: bits |= kHasSSE4_2; /* fall thru */ case 7: bits |= kHasSSE4_1; /* fall thru */ case 6: bits |= kHasSupplementalSSE3; /* fall thru */ case 5: bits |= kHasSSE3; /* fall thru */ case 4: bits |= kHasSSE2; /* fall thru */ case 3: bits |= kHasSSE; /* fall thru */ case 2: bits |= kHasMMX; default: break; } switch (cpu_info.cache_line_size) { case 128: bits |= kCache128; break; case 64: bits |= kCache64; break; case 32: bits |= kCache32; break; default: break; } cpus = commpage_cpus(); // how many CPUs do we have /** Sinetek: by default we'd like some reasonable values, ** so that the userspace runs correctly. ** ** On Mountain Lion, kHasSSE4_2 provides vanilla SSE2 routines. ** On Mavericks, we need a bit more support: SSE3, SSE3X. **/ if (IsAmdCPU()) { bits |= kHasSSE4_2; bits &= ~kHasSupplementalSSE3; #define MAVERICKS_AMD #ifdef MAVERICKS_AMD bits |= kHasSSE3; // bits |= kHasSupplementalSSE3; bits &= ~kHasSSE4_2; #endif } bits |= (cpus << kNumCPUsShift); bits |= kFastThreadLocalStorage; // we use %gs for TLS #define setif(_bits, _bit, _condition) \ if (_condition) _bits |= _bit setif(bits, kUP, cpus == 1); setif(bits, k64Bit, cpu_mode_is64bit()); setif(bits, kSlow, tscFreq <= SLOW_TSC_THRESHOLD); setif(bits, kHasAES, cpuid_features() & CPUID_FEATURE_AES); setif(bits, kHasF16C, cpuid_features() & CPUID_FEATURE_F16C); setif(bits, kHasRDRAND, cpuid_features() & CPUID_FEATURE_RDRAND); setif(bits, kHasFMA, cpuid_features() & CPUID_FEATURE_FMA); setif(bits, kHasBMI1, cpuid_leaf7_features() & CPUID_LEAF7_FEATURE_BMI1); setif(bits, kHasBMI2, cpuid_leaf7_features() & CPUID_LEAF7_FEATURE_BMI2); setif(bits, kHasRTM, cpuid_leaf7_features() & CPUID_LEAF7_FEATURE_RTM); setif(bits, kHasHLE, cpuid_leaf7_features() & CPUID_LEAF7_FEATURE_HLE); setif(bits, kHasAVX2_0, cpuid_leaf7_features() & CPUID_LEAF7_FEATURE_AVX2); uint64_t misc_enable = rdmsr64(MSR_IA32_MISC_ENABLE); setif(bits, kHasENFSTRG, (misc_enable & 1ULL) && (cpuid_leaf7_features() & CPUID_LEAF7_FEATURE_ENFSTRG)); _cpu_capabilities = bits; // set kernel version for use by drivers etc }
void checkForNby2Ratio() { uint64_t sts; sts = rdmsr64(INTEL_MSR_PERF_STS); Nby2Ratio = (sts & (1ULL << 46)); // bit 46 is set }
void mca_dump(void) { ia32_mcg_status_t status; mca_state_t *mca_state = current_cpu_datap()->cpu_mca_state; /* * Capture local MCA registers to per-cpu data. */ mca_save_state(mca_state); /* * Serialize in case of multiple simultaneous machine-checks. * Only the first caller is allowed to dump MCA registers, * other threads spin meantime. */ simple_lock(&mca_lock); if (mca_dump_state > CLEAR) { simple_unlock(&mca_lock); while (mca_dump_state == DUMPING) cpu_pause(); return; } mca_dump_state = DUMPING; simple_unlock(&mca_lock); /* * Report machine-check capabilities: */ kdb_printf( "Machine-check capabilities (cpu %d) 0x%016qx:\n", cpu_number(), ia32_mcg_cap.u64); mca_report_cpu_info(); kdb_printf( " %d error-reporting banks\n%s%s%s", mca_error_bank_count, IF(mca_control_MSR_present, " control MSR present\n"), IF(mca_threshold_status_present, " threshold-based error status present\n"), IF(mca_cmci_present, " extended corrected memory error handling present\n")); if (mca_extended_MSRs_present) kdb_printf( " %d extended MSRs present\n", mca_extended_MSRs_count); /* * Report machine-check status: */ status.u64 = rdmsr64(IA32_MCG_STATUS); kdb_printf( "Machine-check status 0x%016qx:\n%s%s%s", status.u64, IF(status.bits.ripv, " restart IP valid\n"), IF(status.bits.eipv, " error IP valid\n"), IF(status.bits.mcip, " machine-check in progress\n")); /* * Dump error-reporting registers: */ mca_dump_error_banks(mca_state); /* * Dump any extended machine state: */ if (mca_extended_MSRs_present) { if (cpu_mode_is64bit()) mca_dump_64bit_state(); else mca_dump_32bit_state(); } /* Update state to release any other threads. */ mca_dump_state = DUMPED; }
uint16_t getCurrentVoltage() { // Apple recommends not to return cached value, but to read it from the processor uint64_t msr = rdmsr64(INTEL_MSR_PERF_STS); return VID_to_mV(VID(msr)); }
uint16_t getCurrentFrequency() { uint64_t msr = rdmsr64(INTEL_MSR_PERF_STS); return FID_to_MHz(FID(msr)); }
/* * Calculates the FSB and CPU frequencies using specific MSRs for each CPU * - multi. is read from a specific MSR. In the case of Intel, there is: * a max multi. (used to calculate the FSB freq.), * and a current multi. (used to calculate the CPU freq.) * - fsbFrequency = tscFrequency / multi * - cpuFrequency = fsbFrequency * multi */ void scan_cpu(PlatformInfo_t *p) { uint64_t tscFrequency = 0; uint64_t fsbFrequency = 0; uint64_t cpuFrequency =0; uint64_t msr = 0; uint64_t flex_ratio = 0; uint32_t max_ratio = 0; uint32_t min_ratio = 0; uint8_t bus_ratio_max = 0; uint8_t bus_ratio_min = 0; uint8_t currdiv = 0; uint8_t currcoef = 0; uint8_t maxdiv = 0; uint8_t maxcoef = 0; const char *newratio; int len = 0; /* get cpuid values */ do_cpuid(0x00000000, p->CPU.CPUID[CPUID_0]); do_cpuid(0x00000001, p->CPU.CPUID[CPUID_1]); do_cpuid(0x00000002, p->CPU.CPUID[CPUID_2]); do_cpuid(0x00000003, p->CPU.CPUID[CPUID_3]); do_cpuid2(0x00000004, 0, p->CPU.CPUID[CPUID_4]); do_cpuid(0x80000000, p->CPU.CPUID[CPUID_80]); if (p->CPU.CPUID[CPUID_0][0] >= 0x5) { do_cpuid(5, p->CPU.CPUID[CPUID_5]); } if (p->CPU.CPUID[CPUID_0][0] >= 6) { do_cpuid(6, p->CPU.CPUID[CPUID_6]); } if ((p->CPU.CPUID[CPUID_80][0] & 0x0000000f) >= 8) { do_cpuid(0x80000008, p->CPU.CPUID[CPUID_88]); do_cpuid(0x80000001, p->CPU.CPUID[CPUID_81]); } else if ((p->CPU.CPUID[CPUID_80][0] & 0x0000000f) >= 1) { do_cpuid(0x80000001, p->CPU.CPUID[CPUID_81]); } #if DEBUG_CPU { int i; printf("CPUID Raw Values:\n"); for (i=0; i<CPUID_MAX; i++) { printf("%02d: %08x-%08x-%08x-%08x\n", i, p->CPU.CPUID[i][0], p->CPU.CPUID[i][1], p->CPU.CPUID[i][2], p->CPU.CPUID[i][3]); } } #endif /* EAX (Intel): 31 28 27 20 19 16 1514 1312 11 8 7 4 3 0 +--------+----------------+--------+----+----+--------+--------+--------+ |########|Extended family |Extmodel|####|type|familyid| model |stepping| +--------+----------------+--------+----+----+--------+--------+--------+ EAX (AMD): 31 28 27 20 19 16 1514 1312 11 8 7 4 3 0 +--------+----------------+--------+----+----+--------+--------+--------+ |########|Extended family |Extmodel|####|####|familyid| model |stepping| +--------+----------------+--------+----+----+--------+--------+--------+ */ p->CPU.Vendor = p->CPU.CPUID[CPUID_0][1]; p->CPU.Signature = p->CPU.CPUID[CPUID_1][0]; // stepping = cpu_feat_eax & 0xF; p->CPU.Stepping = bitfield(p->CPU.CPUID[CPUID_1][0], 3, 0); // model = (cpu_feat_eax >> 4) & 0xF; p->CPU.Model = bitfield(p->CPU.CPUID[CPUID_1][0], 7, 4); // family = (cpu_feat_eax >> 8) & 0xF; p->CPU.Family = bitfield(p->CPU.CPUID[CPUID_1][0], 11, 8); // type = (cpu_feat_eax >> 12) & 0x3; //p->CPU.Type = bitfield(p->CPU.CPUID[CPUID_1][0], 13, 12); // ext_model = (cpu_feat_eax >> 16) & 0xF; p->CPU.ExtModel = bitfield(p->CPU.CPUID[CPUID_1][0], 19, 16); // ext_family = (cpu_feat_eax >> 20) & 0xFF; p->CPU.ExtFamily = bitfield(p->CPU.CPUID[CPUID_1][0], 27, 20); p->CPU.Model += (p->CPU.ExtModel << 4); if (p->CPU.Vendor == CPUID_VENDOR_INTEL && p->CPU.Family == 0x06 && p->CPU.Model >= CPU_MODEL_NEHALEM && p->CPU.Model != CPU_MODEL_ATOM // MSR is *NOT* available on the Intel Atom CPU ) { msr = rdmsr64(MSR_CORE_THREAD_COUNT); // MacMan: Undocumented MSR in Nehalem and newer CPUs p->CPU.NoCores = bitfield((uint32_t)msr, 31, 16); // MacMan: Using undocumented MSR to get actual values p->CPU.NoThreads = bitfield((uint32_t)msr, 15, 0); // MacMan: Using undocumented MSR to get actual values } else if (p->CPU.Vendor == CPUID_VENDOR_AMD) { p->CPU.NoThreads = bitfield(p->CPU.CPUID[CPUID_1][1], 23, 16); p->CPU.NoCores = bitfield(p->CPU.CPUID[CPUID_88][2], 7, 0) + 1; } else { // Use previous method for Cores and Threads p->CPU.NoThreads = bitfield(p->CPU.CPUID[CPUID_1][1], 23, 16); p->CPU.NoCores = bitfield(p->CPU.CPUID[CPUID_4][0], 31, 26) + 1; } /* get brand string (if supported) */ /* Copyright: from Apple's XNU cpuid.c */ if (p->CPU.CPUID[CPUID_80][0] > 0x80000004) { uint32_t reg[4]; char str[128], *s; /* * The brand string 48 bytes (max), guaranteed to * be NULL terminated. */ do_cpuid(0x80000002, reg); bcopy((char *)reg, &str[0], 16); do_cpuid(0x80000003, reg); bcopy((char *)reg, &str[16], 16); do_cpuid(0x80000004, reg); bcopy((char *)reg, &str[32], 16); for (s = str; *s != '\0'; s++) { if (*s != ' ') { break; } } strlcpy(p->CPU.BrandString, s, sizeof(p->CPU.BrandString)); if (!strncmp(p->CPU.BrandString, CPU_STRING_UNKNOWN, MIN(sizeof(p->CPU.BrandString), strlen(CPU_STRING_UNKNOWN) + 1))) { /* * This string means we have a firmware-programmable brand string, * and the firmware couldn't figure out what sort of CPU we have. */ p->CPU.BrandString[0] = '\0'; } } /* setup features */ if ((bit(23) & p->CPU.CPUID[CPUID_1][3]) != 0) { p->CPU.Features |= CPU_FEATURE_MMX; } if ((bit(25) & p->CPU.CPUID[CPUID_1][3]) != 0) { p->CPU.Features |= CPU_FEATURE_SSE; } if ((bit(26) & p->CPU.CPUID[CPUID_1][3]) != 0) { p->CPU.Features |= CPU_FEATURE_SSE2; } if ((bit(0) & p->CPU.CPUID[CPUID_1][2]) != 0) { p->CPU.Features |= CPU_FEATURE_SSE3; } if ((bit(19) & p->CPU.CPUID[CPUID_1][2]) != 0) { p->CPU.Features |= CPU_FEATURE_SSE41; } if ((bit(20) & p->CPU.CPUID[CPUID_1][2]) != 0) { p->CPU.Features |= CPU_FEATURE_SSE42; } if ((bit(29) & p->CPU.CPUID[CPUID_81][3]) != 0) { p->CPU.Features |= CPU_FEATURE_EM64T; } if ((bit(5) & p->CPU.CPUID[CPUID_1][3]) != 0) { p->CPU.Features |= CPU_FEATURE_MSR; } //if ((bit(28) & p->CPU.CPUID[CPUID_1][3]) != 0) { if (p->CPU.NoThreads > p->CPU.NoCores) { p->CPU.Features |= CPU_FEATURE_HTT; } tscFrequency = measure_tsc_frequency(); /* if usual method failed */ if ( tscFrequency < 1000 ) { //TEST tscFrequency = timeRDTSC() * 20; } fsbFrequency = 0; cpuFrequency = 0; if ((p->CPU.Vendor == CPUID_VENDOR_INTEL) && ((p->CPU.Family == 0x06) || (p->CPU.Family == 0x0f))) { int intelCPU = p->CPU.Model; if ((p->CPU.Family == 0x06 && p->CPU.Model >= 0x0c) || (p->CPU.Family == 0x0f && p->CPU.Model >= 0x03)) { /* Nehalem CPU model */ if (p->CPU.Family == 0x06 && ( p->CPU.Model == CPU_MODEL_NEHALEM || p->CPU.Model == CPU_MODEL_FIELDS || p->CPU.Model == CPU_MODEL_DALES || p->CPU.Model == CPU_MODEL_DALES_32NM || p->CPU.Model == CPU_MODEL_WESTMERE || p->CPU.Model == CPU_MODEL_NEHALEM_EX || p->CPU.Model == CPU_MODEL_WESTMERE_EX || p->CPU.Model == CPU_MODEL_SANDYBRIDGE || p->CPU.Model == CPU_MODEL_JAKETOWN || p->CPU.Model == CPU_MODEL_IVYBRIDGE || p->CPU.Model == CPU_MODEL_IVYBRIDGE_XEON|| p->CPU.Model == CPU_MODEL_HASWELL || p->CPU.Model == CPU_MODEL_HASWELL_SVR || p->CPU.Model == CPU_MODEL_HASWELL_ULT || p->CPU.Model == CPU_MODEL_CRYSTALWELL )){ msr = rdmsr64(MSR_PLATFORM_INFO); // DBG("msr(%d): platform_info %08x\n", __LINE__, bitfield(msr, 31, 0)); bus_ratio_max = bitfield(msr, 15, 8); //MacMan: Changed bitfield to match Apple tsc.c bus_ratio_min = bitfield(msr, 47, 40); //MacMan: Changed bitfield to match Apple tsc.c msr = rdmsr64(MSR_FLEX_RATIO); // DBG("msr(%d): flex_ratio %08x\n", __LINE__, bitfield(msr, 31, 0)); if (bitfield(msr, 16, 16)) { flex_ratio = bitfield(msr, 15, 8); //MacMan: Changed bitfield to match Apple tsc.c if (flex_ratio == 0) { /* Clear bit 16 (evidently the presence bit) */ wrmsr64(MSR_FLEX_RATIO, (msr & 0xFFFFFFFFFFFEFFFFULL)); msr = rdmsr64(MSR_FLEX_RATIO); // verbose("Unusable flex ratio detected. Patched MSR now %08x\n", bitfield(msr, 31, 0)); } else { if (bus_ratio_max > flex_ratio) { bus_ratio_max = flex_ratio; } } } if (bus_ratio_max) { fsbFrequency = (tscFrequency / bus_ratio_max); } //MacMan: Turbo Ratio Limit switch (intelCPU) { case CPU_MODEL_WESTMERE_EX: // Intel Xeon E7 case CPU_MODEL_NEHALEM_EX: // Intel Xeon X75xx, Xeon X65xx, Xeon E75xx, Xeon E65xx { cpuFrequency = tscFrequency; DBG("cpu.c (%d)CPU_MODEL_NEHALEM_EX or CPU_MODEL_WESTMERE_EX Found\n", __LINE__); break; } case CPU_MODEL_SANDYBRIDGE: // Intel Core i3, i5, i7 LGA1155 (32nm) case CPU_MODEL_IVYBRIDGE: // Intel Core i3, i5, i7 LGA1155 (22nm) case CPU_MODEL_JAKETOWN: // Intel Core i7, Xeon E5 LGA2011 (32nm) case CPU_MODEL_IVYBRIDGE_XEON: // Intel Core i7, Xeon E5 LGA2011 (22nm) case CPU_MODEL_HASWELL: // Intel Core i3, i5, i7, Xeon E3 LGA1050 (22nm) case CPU_MODEL_HASWELL_ULT: case CPU_MODEL_CRYSTALWELL: { msr = rdmsr64(MSR_IA32_PERF_STATUS); currcoef = bitfield(msr, 15, 8); cpuFrequency = currcoef * fsbFrequency; maxcoef = bus_ratio_max; break; } default: { msr = rdmsr64(MSR_IA32_PERF_STATUS); currcoef = bitfield(msr, 7, 0); cpuFrequency = currcoef * fsbFrequency; maxcoef = bus_ratio_max; break; } } if ((getValueForKey(kbusratio, &newratio, &len, &bootInfo->chameleonConfig)) && (len <= 4)) { max_ratio = atoi(newratio); max_ratio = (max_ratio * 10); if (len >= 3) { max_ratio = (max_ratio + 5); } verbose("Bus-Ratio: min=%d, max=%s\n", bus_ratio_min, newratio); // extreme overclockers may love 320 ;) if ((max_ratio >= min_ratio) && (max_ratio <= 320)) { cpuFrequency = (fsbFrequency * max_ratio) / 10; if (len >= 3) { maxdiv = 1; } else { maxdiv = 0; } } else { max_ratio = (bus_ratio_max * 10); } } p->CPU.MaxRatio = bus_ratio_max; p->CPU.MinRatio = bus_ratio_min; } else { msr = rdmsr64(MSR_IA32_PERF_STATUS); DBG("msr(%d): ia32_perf_stat 0x%08x\n", __LINE__, bitfield(msr, 31, 0)); currcoef = bitfield(msr, 15, 8); //MacMan: Fixed bitfield to Intel documentation /* Non-integer bus ratio for the max-multi*/ maxdiv = bitfield(msr, 46, 46); /* Non-integer bus ratio for the current-multi (undocumented)*/ currdiv = bitfield(msr, 14, 14); // This will always be model >= 3 if ((p->CPU.Family == 0x06 && p->CPU.Model >= 0x0e) || (p->CPU.Family == 0x0f)) { /* On these models, maxcoef defines TSC freq */ maxcoef = bitfield(msr, 44, 40); } else { /* On lower models, currcoef defines TSC freq */ /* XXX */ maxcoef = currcoef; } if (maxcoef) { if (maxdiv) { fsbFrequency = ((tscFrequency * 2) / ((maxcoef * 2) + 1)); } else { fsbFrequency = (tscFrequency / maxcoef); } if (currdiv) { cpuFrequency = (fsbFrequency * ((currcoef * 2) + 1) / 2); } else { cpuFrequency = (fsbFrequency * currcoef); } DBG("max: %d%s current: %d%s\n", maxcoef, maxdiv ? ".5" : "",currcoef, currdiv ? ".5" : ""); } } } /* Mobile CPU */ if (rdmsr64(MSR_IA32_PLATFORM_ID) & (1<<28)) { p->CPU.Features |= CPU_FEATURE_MOBILE; } } else if ((p->CPU.Vendor == CPUID_VENDOR_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 */ msr = rdmsr64(K10_COFVID_STATUS); do_cpuid2(0x00000006, 0, p->CPU.CPUID[CPUID_6]); // EffFreq: effective frequency interface if (bitfield(p->CPU.CPUID[CPUID_6][2], 0, 0) == 1) { //uint64_t mperf = measure_mperf_frequency(); 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 */ // not implimented break; } 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); } } if (!cpuFrequency) cpuFrequency = tscFrequency; } #if 0 if (!fsbFrequency) { fsbFrequency = (DEFAULT_FSB * 1000); cpuFrequency = tscFrequency; DBG("0 ! using the default value for FSB !\n"); } #endif p->CPU.MaxCoef = maxcoef; if (maxdiv == 0){ p->CPU.MaxDiv = bus_ratio_max; } else { p->CPU.MaxDiv = maxdiv; } p->CPU.CurrCoef = currcoef; if (currdiv == 0){ p->CPU.CurrDiv = currcoef; } else { p->CPU.CurrDiv = currdiv; } p->CPU.TSCFrequency = tscFrequency; p->CPU.FSBFrequency = fsbFrequency; p->CPU.CPUFrequency = cpuFrequency; // keep formatted with spaces instead of tabs DBG("CPU: Brand String: %s\n", p->CPU.BrandString); DBG("CPU: Vendor: 0x%x\n", p->CPU.Vendor); DBG("CPU: Family / ExtFamily: 0x%x / 0x%x\n", p->CPU.Family, p->CPU.ExtFamily); DBG("CPU: Model / ExtModel / Stepping: 0x%x / 0x%x / 0x%x\n", p->CPU.Model, p->CPU.ExtModel, p->CPU.Stepping); DBG("CPU: Number of Cores / Threads: %d / %d\n", p->CPU.NoCores, p->CPU.NoThreads); DBG("CPU: Features: 0x%08x\n", p->CPU.Features); DBG("CPU: TSC Frequency: %d MHz\n", p->CPU.TSCFrequency / 1000000); DBG("CPU: FSB Frequency: %d MHz\n", p->CPU.FSBFrequency / 1000000); DBG("CPU: CPU Frequency: %d MHz\n", p->CPU.CPUFrequency / 1000000); DBG("CPU: Minimum Bus Ratio: %d\n", p->CPU.MinRatio); DBG("CPU: Maximum Bus Ratio: %d\n", p->CPU.MaxRatio); DBG("CPU: Current Bus Ratio: %d\n", p->CPU.CurrCoef); // DBG("CPU: Maximum Multiplier: %d\n", p->CPU.MaxCoef); // DBG("CPU: Maximum Divider: %d\n", p->CPU.MaxDiv); // DBG("CPU: Current Divider: %d\n", p->CPU.CurrDiv); #if DEBUG_CPU pause(); #endif }