parlib: Improve panic() and assert()
[akaros.git] / kern / arch / x86 / idle.c
1 #include <arch/arch.h>
2 #include <arch/x86.h>
3 #include <arch/mmu.h>
4 #include <cpu_feat.h>
5 #include <arch/uaccess.h>
6
7 static unsigned int x86_cstate;
8
9 /* This atomically enables interrupts and halts.
10  *
11  * Note that sti does not take effect until after the *next* instruction */
12 void cpu_halt(void)
13 {
14         if (cpu_has_feat(CPU_FEAT_X86_MWAIT)) {
15                 /* TODO: since we're monitoring anyway, x86 could use monitor/mwait for
16                  * KMSGs, instead of relying on IPIs.  (Maybe only for ROUTINE). */
17                 asm volatile("monitor" : : "a"(KERNBASE), "c"(0), "d"(0));
18                 asm volatile("sti; mwait" : : "c"(0x0), "a"(x86_cstate) : "memory");
19         } else {
20                 asm volatile("sti; hlt" : : : "memory");
21         }
22 }
23
24 void set_pstate(unsigned int pstate)
25 {
26         uint64_t perf_ctl;
27
28         /* This MSR was introduced in 0f_03 (family/model), so checking cpuid should
29          * suffice.  Though my Qemu says it is a later generation and still fails to
30          * support it (patches pending, I hear). */
31         if (read_msr_safe(MSR_IA32_PERF_CTL, &perf_ctl))
32                 return;
33         /* The p-state ratio is actually at 15:8, AFAIK, for both PERF_CTL and
34          * PERF_STATUS.  Not sure what the lower byte represents.  It's probably
35          * processor specific. */
36         perf_ctl &= ~0xff00ULL;
37         perf_ctl |= pstate << 8;
38         write_msr_safe(MSR_IA32_PERF_CTL, perf_ctl);
39 }
40
41 void set_fastest_pstate(void)
42 {
43         uint64_t turbo_ratio_limit;
44
45         /* Support for TURBO_RATIO_LIMIT varies from processor to processor.  In
46          * lieu of a full per-model driver, we can just take a peak. */
47         if (read_msr_safe(MSR_TURBO_RATIO_LIMIT, &turbo_ratio_limit))
48                 return;
49         /* The lowest byte is the max turbo ratio achievable by one active core. */
50         set_pstate(turbo_ratio_limit & 0xff);
51 }
52
53 /* This returns the desired pstate, which might be less than desired if other
54  * cores are active. */
55 unsigned int get_pstate(void)
56 {
57         uint64_t perf_ctl;
58
59         if (read_msr_safe(MSR_IA32_PERF_CTL, &perf_ctl))
60                 return 0;
61         return (perf_ctl & 0xff00) >> 8;
62 }
63
64 void set_cstate(unsigned int cstate)
65 {
66         /* No real need to lock for an assignment.  Any core can set this, and other
67          * cores will notice the next time they halt. */
68         x86_cstate = cstate;
69 }
70
71 unsigned int get_cstate(void)
72 {
73         /* We won't be able to use anything deeper than C1 without MWAIT */
74         if (!cpu_has_feat(CPU_FEAT_X86_MWAIT))
75                 return X86_MWAIT_C1;
76         return x86_cstate;
77 }