📄 cpu.c
字号:
{ 1000, 1100 }, { 800, 1052 }, { 600, 988 }};/* Intel Pentium M processor 765 2.1 GHz */static const struct fq_info pentium_m_n765[] = { { 2100, 1340 }, { 1800, 1276 }, { 1600, 1228 }, { 1400, 1180 }, { 1200, 1132 }, { 1000, 1084 }, { 800, 1036 }, { 600, 988 } };struct fqlist { const char *brand_tag; const struct fq_info *table; u_int n;};static const struct fqlist pentium_m[] = {#define ENTRY(s, v) { s, v, sizeof(v) / sizeof((v)[0]) } ENTRY(" 900", pentium_m_900), ENTRY("1000", pentium_m_1000), ENTRY("1100", pentium_m_1100), ENTRY("1200", pentium_m_1200), ENTRY("1300", pentium_m_1300), ENTRY("1400", pentium_m_1400), ENTRY("1500", pentium_m_1500), ENTRY("1600", pentium_m_1600), ENTRY("1700", pentium_m_1700),#undef ENTRY};static const struct fqlist pentium_m_dothan[] = {#define ENTRY(s, v) { s, v, sizeof(v) / sizeof((v)[0]) } ENTRY("1.00", pentium_m_n723), ENTRY("1.10", pentium_m_n733), ENTRY("1.20", pentium_m_n753), ENTRY("1.40", pentium_m_n738),#if 0 ENTRY("1.50", pentium_m_n758),#endif ENTRY("1.50", pentium_m_n715), ENTRY("1.60", pentium_m_n725), ENTRY("1.70", pentium_m_n735), ENTRY("1.80", pentium_m_n745), ENTRY("2.00", pentium_m_n755), ENTRY("2.10", pentium_m_n765),#undef ENTRY};struct est_cpu { const char *brand_prefix; const char *brand_suffix; const struct fqlist *list; int n;};static const struct est_cpu est_cpus[] = { { "Intel(R) Pentium(R) M processor ", "MHz", pentium_m, (sizeof(pentium_m) / sizeof(pentium_m[0])) }, { "Intel(R) Pentium(R) M processor ", "GHz", pentium_m_dothan, (sizeof(pentium_m_dothan) / sizeof(pentium_m_dothan[0])) },};#define NESTCPUS (sizeof(est_cpus) / sizeof(est_cpus[0]))#define MSRVALUE(mhz, mv) ((((mhz) / 100) << 8) | (((mv) - 700) / 16))#define MSR2MHZ(msr) ((((int) (msr) >> 8) & 0xff) * 100)#define MSR2MV(msr) (((int) (msr) & 0xff) * 16 + 700)static const struct fqlist *est_fqlist;static struct cpu_info cpu_info;static struct cpu_stat cpu_stat;#ifdef CONFIG_DVS_EMULATIONstatic int bochs;#endif/* * Get cpu id */static void cpuid(u_int eax, u_int *p){ __asm__ __volatile__( "cpuid\n\t" "movl %%eax, 0(%2)\n\t" "movl %%ebx, 4(%2)\n\t" "movl %%ecx, 8(%2)\n\t" "movl %%edx, 12(%2)\n\t" : "=a" (eax) : "0" (eax), "S" (p) : "bx", "cx", "dx");}/* * Set CPU performance * * @level: percent of cpu speed */int cpu_setperf(int level){ int i, fq; u_int msr_lo, msr_hi; int max_mhz; ASSERT(cpu_info.clock_ctrl); max_mhz = est_fqlist->table[0].mhz; fq = max_mhz * level / 100; for (i = est_fqlist->n - 1; i > 0; i--) if (est_fqlist->table[i].mhz >= fq) break; if (est_fqlist->table[i].mhz == cpu_stat.speed) return 0; cpu_stat.speed = est_fqlist->table[i].mhz; cpu_stat.power = est_fqlist->table[i].mv; cpu_dbg("setperf: %dMHz %dmV\n", cpu_stat.speed, cpu_stat.power);#ifdef CONFIG_DVS_EMULATION if (bochs) return 0;#endif rdmsr(MSR_PERF_CTL, msr_lo, msr_hi); msr_lo = (msr_lo & ~0xffff) | MSRVALUE(est_fqlist->table[i].mhz, est_fqlist->table[i].mv); wrmsr(MSR_PERF_CTL, msr_lo, msr_hi); return 0;}/* * Get CPU performance */int cpu_getperf(void){ int max_mhz; int level; ASSERT(cpu_info.clock_ctrl); max_mhz = est_fqlist->table[0].mhz; ASSERT(max_mhz); level = cpu_stat.speed * 100 / max_mhz; return level;}/* * Initialize CPU performance * Return false on error. */int cpu_initperf(void){ int i, j, n, mhz, mv; const struct est_cpu *cpu; u_int msr_lo, msr_hi; char *tag, *brand_str; const struct fqlist *fql; if (!cpu_info.clock_ctrl) return -1;#ifdef CONFIG_DVS_EMULATION if (bochs) { msr_lo = 0x1031; cpu = &est_cpus[0]; est_fqlist = &cpu->list[7]; } else rdmsr(MSR_PERF_STATUS, msr_lo, msr_hi);#else rdmsr(MSR_PERF_STATUS, msr_lo, msr_hi);#endif mhz = MSR2MHZ(msr_lo); mv = MSR2MV(msr_lo); printk("Enhanced SpeedStep %d MHz (%d mV)\n", mhz, mv);#ifdef CONFIG_DVS_EMULATION if (!bochs) {#endif /* * Look for a CPU matching brand_str. */ brand_str = cpu_info.name; for (i = 0; est_fqlist == NULL && i < NESTCPUS; i++) { cpu = &est_cpus[i]; n = strnlen(cpu->brand_prefix, 48); if (strncmp(cpu->brand_prefix, brand_str, n) != 0) continue; tag = brand_str + n; for (j = 0; j < cpu->n; j++) { fql = &cpu->list[j]; n = strnlen(fql->brand_tag, 48); if (!strncmp(fql->brand_tag, tag, n) && !strncmp(cpu->brand_suffix, tag + n, 48)) { est_fqlist = fql; break; } } } if (est_fqlist == NULL) { printk("Unknown EST cpu, no changes possible\n"); cpu_info.clock_ctrl = 0; return -1; } /* * Check that the current operating point is in our list. */ for (i = est_fqlist->n - 1; i >= 0; i--) if (est_fqlist->table[i].mhz == mhz) break; if (i < 0) { printk(" (not in table)\n"); cpu_info.clock_ctrl = 0; return -1; }#ifdef CONFIG_DVS_EMULATION }#endif /* * Store current state */ cpu_info.speed = est_fqlist->table[0].mhz; cpu_info.power = est_fqlist->table[0].mv; cpu_stat.speed = mhz; cpu_stat.power = mv; /* * OK, tell the user the available frequencies. */ printk("Speeds: "); for (i = 0; i < est_fqlist->n; i++) printk("%d%s", est_fqlist->table[i].mhz, i < est_fqlist->n - 1 ? ", " : " MHz\n"); return 0;}static int cpu_ioctl(device_t dev, int cmd, u_long arg){ switch (cmd) { case CPUIOC_GET_INFO: if (umem_copyout(&cpu_info, (void *)arg, sizeof(cpu_info))) return EFAULT; break; case CPUIOC_GET_STAT: if (umem_copyout(&cpu_stat, (void *)arg, sizeof(cpu_stat))) return EFAULT; break; default: return EINVAL; } return 0;}/* * Initialize CPU addon feature * * FIXME: i486 does not support cpuid instruction */static int cpu_init(void){ u_int regs[4]; char brand_str[49]; char *p, *q; /* Create device object */ cpu_dev = device_create(&cpu_io, "cpu"); ASSERT(cpu_dev);#ifdef CONFIG_DVS_EMULATION bochs = 0; if (inb(0xe9) == 0xe9) { /* * Detect Bochs. Fake the cpuid value. */ bochs = 1; cpu_info.id = 0x6d6; cpu_info.clock_ctrl = 1; strncpy(cpu_info.name, "Intel(R) Pentium(R) M processor 1600MHz", 50); printk("CPU brand: %s\n", cpu_info.name); return 0; }#endif /* * Check enhanced speed step capability */ cpuid(1, regs); cpu_info.id = regs[0]; cpu_dbg("cpu id=%x\n", regs[0]); if ((regs[2] & 0x80) == 0) { cpu_info.clock_ctrl = 0; return 0; } cpu_info.clock_ctrl = 1; /* * Get CPU brand string */ cpuid(0x80000002, regs); memcpy(brand_str, regs, sizeof(regs)); cpuid(0x80000003, regs); memcpy(brand_str + 16, regs, sizeof(regs)); cpuid(0x80000004, regs); memcpy(brand_str + 32, regs, sizeof(regs)); /* Store string with lef-align */ q = &cpu_info.name[0]; p = brand_str; while (*p == ' ') p++; while (*p) *q++ = *p++; *q = '\0'; printk("CPU brand: %s\n", cpu_info.name); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -