My Kernel v0.1.0
cpu.h
1#ifndef KERNEL_ARCH_I686_UTILS_CPU_OPS_H
2#define KERNEL_ARCH_I686_UTILS_CPU_OPS_H
3
4#include <kernel/types.h>
5
6#include <dailyrun/arch/i686/cpu.h>
7
8#include <utils/bits.h>
9#include <utils/compiler.h>
10#include <utils/map.h>
11
12#define CPU_CACHE_ALIGN 64 /* 64B L1 cache lines */
13
14#define X86_FEATURE_WORDS 2 /* Number of CPUID leaves that contain features. */
15
16struct x86_cpuinfo {
17 const char *vendor;
18 u32 features[X86_FEATURE_WORDS];
19};
20
21extern struct x86_cpuinfo cpuinfo;
22
23/*
24 * Register read/write wrappers.
25 */
26
27// Read from a 32-bits register
28#define READ_REGISTER_OPS(_reg) \
29 static ALWAYS_INLINE u32 read_##_reg() \
30 { \
31 u32 res; \
32 ASM("movl %%" #_reg ", %0" : "=r"(res)); \
33 return res; \
34 }
35
36// Write into a 32-bits register
37#define WRITE_REGISTER_OPS(_reg) \
38 static ALWAYS_INLINE void write_##_reg(u32 value) \
39 { \
40 ASM("movl %0, %%" #_reg : : "r"(value)); \
41 }
42
43#define CPU_32BIT_REGISTERS \
44 cr0, cr1, cr2, cr3, cr4, esp, cs, ds, es, fs, gs, ss, eax
45
46MAP(READ_REGISTER_OPS, CPU_32BIT_REGISTERS)
47MAP(WRITE_REGISTER_OPS, CPU_32BIT_REGISTERS)
48
49#undef CPU_32BIT_REGISTERS
50#undef WRITE_REGISTER_OPS
51#undef READ_REGISTER_OPS
52
53/*
54 * CPU control registers.
55 */
56
57#define CR0_PG BIT(31) /* Paging enable */
58#define CR0_CD BIT(30) /* Cache disable */
59#define CR0_NW BIT(29) /* Not write-through */
60
61#define CR4_PAE BIT(5) /* PAE paging enable */
62
63/*
64 * ASM instruction wrappers.
65 */
66
67/* Write a single byte at a given I/O port address. */
68static ALWAYS_INLINE void outb(uint16_t port, uint8_t val)
69{
70 ASM("out %0,%1" : : "a"(val), "Nd"(port) : "memory");
71}
72
73/* Write 2 bytes at a given I/O port address. */
74static ALWAYS_INLINE void outw(uint16_t port, uint16_t val)
75{
76 ASM("out %0,%1" : : "a"(val), "Nd"(port) : "memory");
77}
78
79/* Write 4 bytes at a given I/O port address. */
80static ALWAYS_INLINE void outl(uint16_t port, uint32_t val)
81{
82 ASM("out %0,%1" : : "a"(val), "Nd"(port) : "memory");
83}
84
85/* Read a single byte from a given I/O port address. */
86static ALWAYS_INLINE uint8_t inb(uint16_t port)
87{
88 uint8_t val;
89 ASM("in %1, %0" : "=a"(val) : "Nd"(port) : "memory");
90 return val;
91}
92
93/* Read 2 bytes from a given I/O port address. */
94static ALWAYS_INLINE uint16_t inw(uint16_t port)
95{
96 uint16_t val;
97 ASM("in %1, %0" : "=a"(val) : "Nd"(port) : "memory");
98 return val;
99}
100
101/* Read 4 bytes from a given I/O port address. */
102static ALWAYS_INLINE uint32_t inl(uint16_t port)
103{
104 uint32_t val;
105 ASM("in %1,%0" : "=a"(val) : "Nd"(port) : "memory");
106 return val;
107}
108
109static ALWAYS_INLINE void hlt(void)
110{
111 ASM("hlt");
112}
113
114static ALWAYS_INLINE void insb(uint16_t port, uint8_t *buffer, size_t size)
115{
116 size_t count = size / sizeof(*buffer);
117
118 asm volatile("cld; rep insb"
119 : "+D"(buffer), "+c"(count)
120 : "d"(port)
121 : "memory");
122}
123
124static ALWAYS_INLINE void insw(uint16_t port, uint16_t *buffer, size_t size)
125{
126 size_t count = size / sizeof(*buffer);
127
128 asm volatile("cld; rep insw"
129 : "+D"(buffer), "+c"(count)
130 : "d"(port)
131 : "memory");
132}
133
134static ALWAYS_INLINE void insl(uint16_t port, uint32_t *buffer, size_t size)
135{
136 size_t count = size / sizeof(*buffer);
137
138 asm volatile("cld; rep insl"
139 : "+D"(buffer), "+c"(count)
140 : "d"(port)
141 : "memory");
142}
143
144#include <cpuid.h> /* provided by GCC */
145
146#define cpuid(leaf, eax, ebx, ecx, edx) __get_cpuid(leaf, eax, ebx, ecx, edx)
147
148/*
149 * Define quick helper functions for CPUID calls that only need to access one
150 * of the result registers.
151 */
152#define CPUID_FUNCTION(_reg) \
153 static inline uint32_t cpuid_##_reg(uint32_t leaf) \
154 { \
155 uint32_t eax; \
156 uint32_t ebx; \
157 uint32_t ecx; \
158 uint32_t edx; \
159 \
160 cpuid(leaf, &eax, &ebx, &ecx, &edx); \
161 return _reg; \
162 }
163
164CPUID_FUNCTION(eax)
165CPUID_FUNCTION(ebx)
166CPUID_FUNCTION(ecx)
167CPUID_FUNCTION(edx)
168
169#undef CPUID_FUNCTION
170
171#define CPUID_LEAF_GETVENDOR 0
172#define CPUID_LEAF_GETFEATURES 1
173#define CPUID_LEAF_GETFEATURES_EXT 7
174
175/* Vendor codes used by popular hypervisors. */
176#define signature_QEMU_ebx 0x47435443 // [TCGT]CGTCGTCG
177#define signature_KVM_ebx 0x4D564B20 // [ KVM]KVMKVM
178#define signature_VMWARE_ebx 0x61774D56 // [VMwa]reVMware
179#define signature_VIRTUALBOX_ebx 0x786F4256 // [VBox]VBoxVBox
180#define signature_XEN_ebx 0x566E6558 // [XenV]MMXenVMM
181#define signature_HYPERV_ebx 0x7263694D // [Micr]osoft Hv
182#define signature_PARALLELS_ebx 0x6C727020 // [ prl] hyperv
183#define signature_PARALLELS_ALT_ebx 0x6570726C // [lrpe]pyh vr
184#define signature_BHYVE_ebx 0x76796862 // [bhyv]e bhyve
185#define signature_QNX_ebx 0x20584E51 // [ QNX]QVMBSQG
186
187#define X86_FEATURES(F) \
188 \
189 /* Features in %ecx for leaf 1 */ \
190 F(SSE3, 0, 0), \
191 F(PCLMUL, 0, 1), \
192 F(DTES64, 0, 2), \
193 F(MONITOR, 0, 3), \
194 F(DSCPL, 0, 4), \
195 F(VMX, 0, 5), \
196 F(SMX, 0, 6), \
197 F(EIST, 0, 7), \
198 F(TM2, 0, 8), \
199 F(SSSE3, 0, 9), \
200 F(CNXTID, 0, 10), \
201 F(FMA, 0, 12), \
202 F(CMPXCHG16B, 0, 13), \
203 F(xTPR, 0, 14), \
204 F(PDCM, 0, 15), \
205 F(PCID, 0, 17), \
206 F(DCA, 0, 18), \
207 F(SSE41, 0, 19), \
208 F(SSE42, 0, 20), \
209 F(x2APIC, 0, 21), \
210 F(MOVBE, 0, 22), \
211 F(POPCNT, 0, 23), \
212 F(TSCDeadline, 0, 24), \
213 F(AES, 0, 25), \
214 F(XSAVE, 0, 26), \
215 F(OSXSAVE, 0, 27), \
216 F(AVX, 0, 28), \
217 F(F16C, 0, 29), \
218 F(RDRND, 0, 30), \
219 \
220 /* Features in %edx for leaf 1 */ \
221 F(FPU, 1, 0), \
222 F(VME, 1, 1), \
223 F(DE, 1, 2), \
224 F(PSE, 1, 3), \
225 F(TSC, 1, 4), \
226 F(MSR, 1, 5), \
227 F(PAE, 1, 6), \
228 F(MCE, 1, 7), \
229 F(CMPXCHG8B, 1, 8), \
230 F(APIC, 1, 9), \
231 F(SEP, 1, 11), \
232 F(MTRR, 1, 12), \
233 F(PGE, 1, 13), \
234 F(MCA, 1, 14), \
235 F(CMOV, 1, 15), \
236 F(PAT, 1, 16), \
237 F(PSE36, 1, 17), \
238 F(PSN, 1, 18), \
239 F(CLFSH, 1, 19), \
240 F(DS, 1, 21), \
241 F(ACPI, 1, 22), \
242 F(MMX, 1, 23), \
243 F(FXSAVE, 1, 24), \
244 F(SSE, 1, 25), \
245 F(SSE2, 1, 26), \
246 F(SS, 1, 27), \
247 F(HTT, 1, 28), \
248 F(TM, 1, 29), \
249 F(PBE, 1, 31), \
250
251#define X86_FEATURE_NAME(_feature) X86_FEATURE_##_feature
252#define X86_FEATURE_VAL(_word, _bit) ((_word << X86_FEATURE_WORD_OFF) | (_bit & 0xff))
253#define X86_FEATURE_WORD_OFF 8
254
255enum x86_cpu_feature {
256#define DEFINE_X86_FEATURE(_name, _word, _bit) \
257 X86_FEATURE_NAME(_name) = X86_FEATURE_VAL(_word, _bit)
258X86_FEATURES(DEFINE_X86_FEATURE)
259#undef DEFINE_X86_FEATURE
260};
261
262static inline bool cpu_test_feature(enum x86_cpu_feature feature)
263{
264 int leaf = (feature >> X86_FEATURE_WORD_OFF);
265 int bit = feature & (BIT(X86_FEATURE_WORD_OFF) - 1);
266
267 return BIT_READ(cpuinfo.features[leaf], bit);
268}
269
270#define cpu_has_feature(_feature) cpu_test_feature(X86_FEATURE_NAME(_feature))
271
272enum x86_msr {
273 MSR_PAT = 0x277,
274};
275
276/* Read from specific register */
277static inline uint64_t rdmsr(uint32_t msr)
278{
279 uint32_t eax;
280 uint32_t edx;
281 ASM("rdmsr" : "=a"(eax), "=d"(edx) : "c"(msr));
282 return (((uint64_t)edx) << 32) | eax;
283}
284
285/* Write into model specific register */
286static inline void wrmsr(uint32_t msr, uint64_t val)
287{
288 uint32_t eax = val;
289 uint32_t edx = val >> 32;
290 ASM("wrmsr" : : "a"(eax), "d"(edx), "c"(msr));
291}
292
293#endif /* KERNEL_I686_UTILS_CPU_OPS_H */
#define BIT(_n)
Generate the nth power of 2 (nth bit set)
Definition: bits.h:20
#define BIT_READ(_x, _n)
Read the nth bit.
Definition: bits.h:30
#define MAP(f,...)
Applies the function macro f to each of the remaining parameters.
Definition: map.h:60