1 /* ----------------------------------------------------------------------- *
2 *
3 * Copyright 2006-2009 Erwan Velu - All Rights Reserved
4 *
5 * Portions of this file taken from the Linux kernel,
6 * Copyright 1991-2009 Linus Torvalds and contributors
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2
10 * as published by the Free Software Foundation, Inc.,
11 * 51 Franklin St, Fifth Floor, Boston MA 02110-1301;
12 * incorporated herein by reference.
13 *
14 * ----------------------------------------------------------------------- */
15
16 #ifndef _CPUID_H
17 #define _CPUID_H
18
19 #include <stdbool.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <cpufeature.h>
23 #include <sys/bitops.h>
24 #include <sys/cpu.h>
25 #include <sys/io.h>
26 #include <klibc/compiler.h>
27
28 #define PAGE_SIZE 4096
29
30 #define CPU_MODEL_SIZE 48
31 #define CPU_VENDOR_SIZE 48
32
33 #define CPU_FLAGS(m_) \
34 m_(bool, fpu, /* Onboard FPU */) \
35 m_(bool, vme, /* Virtual Mode Extensions */) \
36 m_(bool, de, /* Debugging Extensions */) \
37 m_(bool, pse, /* Page Size Extensions */) \
38 m_(bool, tsc, /* Time Stamp Counter */) \
39 m_(bool, msr, /* Model-Specific Registers, RDMSR, WRMSR */) \
40 m_(bool, pae, /* Physical Address Extensions */) \
41 m_(bool, mce, /* Machine Check Architecture */) \
42 m_(bool, cx8, /* CMPXCHG8 instruction */) \
43 m_(bool, apic, /* Onboard APIC */) \
44 m_(bool, sep, /* SYSENTER/SYSEXIT */) \
45 m_(bool, mtrr, /* Memory Type Range Registers */) \
46 m_(bool, pge, /* Page Global Enable */) \
47 m_(bool, mca, /* Machine Check Architecture */) \
48 m_(bool, cmov, /* CMOV instruction (FCMOVCC and FCOMI too if FPU present) */) \
49 m_(bool, pat, /* Page Attribute Table */) \
50 m_(bool, pse_36, /* 36-bit PSEs */) \
51 m_(bool, psn, /* Processor serial number */) \
52 m_(bool, clflsh, /* Supports the CLFLUSH instruction */) \
53 m_(bool, dts, /* Debug Trace Store */) \
54 m_(bool, acpi, /* ACPI via MSR */) \
55 m_(bool, pbe, /* Pending Break Enable */) \
56 m_(bool, mmx, /* Multimedia Extensions */) \
57 m_(bool, fxsr, /* FXSAVE and FXRSTOR instructions (fast save and restore of FPU context), and CR4.OSFXSR available */) \
58 m_(bool, sse, /* Streaming SIMD Extensions */) \
59 m_(bool, sse2, /* Streaming SIMD Extensions 2 */) \
60 m_(bool, ss, /* CPU self snoop */) \
61 m_(bool, htt, /* Hyper-Threading */) \
62 m_(bool, acc, /* Automatic clock control */) \
63 m_(bool, syscall, /* SYSCALL/SYSRET */) \
64 m_(bool, mp, /* MP Capable. */) \
65 m_(bool, nx, /* Execute Disable */) \
66 m_(bool, mmxext, /* AMD MMX extensions */) \
67 m_(bool, fxsr_opt, /* FXSAVE/FXRSTOR optimizations */) \
68 m_(bool, gbpages, /* "pdpe1gb" GB pages */) \
69 m_(bool, rdtscp, /* RDTSCP */) \
70 m_(bool, lm, /* Long Mode (x86-64) */) \
71 m_(bool, nowext, /* AMD 3DNow! extensions */) \
72 m_(bool, now, /* 3DNow! */) \
73 m_(bool, smp, /* A smp configuration has been found */) \
74 m_(bool, pni, /* Streaming SIMD Extensions-3 */) \
75 m_(bool, pclmulqd, /* PCLMULQDQ instruction */) \
76 m_(bool, dtes64, /* 64-bit Debug Store */) \
77 m_(bool, vmx, /* Hardware virtualization */) \
78 m_(bool, smx, /* Safer Mode */) \
79 m_(bool, est, /* Enhanced SpeedStep */) \
80 m_(bool, tm2, /* Thermal Monitor 2 */) \
81 m_(bool, sse3, /* Supplemental SSE-3 */) \
82 m_(bool, cid, /* Context ID */) \
83 m_(bool, fma, /* Fused multiply-add */) \
84 m_(bool, cx16, /* CMPXCHG16B */) \
85 m_(bool, xtpr, /* Send Task Priority Messages */) \
86 m_(bool, pdcm, /* Performance Capabilities */) \
87 m_(bool, dca, /* Direct Cache Access */) \
88 m_(bool, xmm4_1, /* "sse4_1" SSE-4.1 */) \
89 m_(bool, xmm4_2, /* "sse4_2" SSE-4.2 */) \
90 m_(bool, x2apic, /* x2APIC */) \
91 m_(bool, movbe, /* MOVBE instruction */) \
92 m_(bool, popcnt, /* POPCNT instruction */) \
93 m_(bool, aes, /* AES Instruction */) \
94 m_(bool, xsave, /* XSAVE/XRSTOR/XSETBV/XGETBV */) \
95 m_(bool, osxsave, /* XSAVE enabled in the OS */) \
96 m_(bool, avx, /* Advanced Vector Extensions */) \
97 m_(bool, hypervisor, /* Running on a hypervisor */) \
98 m_(bool, ace2, /* Advanced Cryptography Engine v2 */) \
99 m_(bool, ace2_en, /* ACE v2 enabled */) \
100 m_(bool, phe, /* PadLock Hash Engine */) \
101 m_(bool, phe_en, /* PadLock Hash Engine Enabled */) \
102 m_(bool, pmm, /* PadLock Montgomery Multiplier */) \
103 m_(bool, pmm_en, /* PadLock Montgomery Multiplier enabled */) \
104 m_(bool, svm, /* Secure virtual machine */) \
105 m_(bool, extapic, /* Extended APIC space */) \
106 m_(bool, cr8_legacy, /* CR8 in 32-bit mode */) \
107 m_(bool, abm, /* Advanced bit manipulation */) \
108 m_(bool, sse4a, /* SSE4-A */) \
109 m_(bool, misalignsse, /* Misaligned SSE mode */) \
110 m_(bool, nowprefetch, /* 3DNow prefetch instructions */) \
111 m_(bool, osvw, /* OS Visible Workaround */) \
112 m_(bool, ibs, /* Instruction Based Sampling */) \
113 m_(bool, sse5, /* SSE5 */) \
114 m_(bool, skinit, /* SKINIT/STGI instructions */) \
115 m_(bool, wdt, /* Watchdog Timer */) \
116 m_(bool, ida, /* Intel Dynamic Acceleration */) \
117 m_(bool, arat, /* Always Running APIC Timer */) \
118 m_(bool, tpr_shadow, /* Intel TPR Shadow */) \
119 m_(bool, vnmi, /* Intel Virtual NMI */) \
120 m_(bool, flexpriority, /* Intel FlexPriority */) \
121 m_(bool, ept, /* Intel Extended Page Table */) \
122 m_(bool, vpid, /* Intel Virtual Processor ID */)
123
124 #define STRUCT_MEMBERS(type_, name_, comment_) type_ name_;
125
126 #define STRUCT_MEMBER_NAMES(type_, name_, comment_) #name_ ,
127
128 #define STRUCTURE_MEMBER_OFFSETS(type_, name_, comment_) \
129 offsetof(s_cpu_flags, name_),
130
131 typedef struct {
132 CPU_FLAGS(STRUCT_MEMBERS)
133 } s_cpu_flags;
134
135 extern size_t cpu_flags_offset[];
136 extern const char *cpu_flags_names[];
137 extern size_t cpu_flags_count;
138
139 typedef struct {
140 char vendor[CPU_VENDOR_SIZE];
141 uint8_t vendor_id;
142 uint8_t family;
143 char model[CPU_MODEL_SIZE];
144 uint8_t model_id;
145 uint8_t stepping;
146 uint8_t num_cores;
147 uint16_t l1_data_cache_size;
148 uint16_t l1_instruction_cache_size;
149 uint16_t l2_cache_size;
150 s_cpu_flags flags;
151 } s_cpu;
152
153 extern bool get_cpu_flag_value_from_name(s_cpu *cpu, const char * flag);
154 /**********************************************************************************/
155 /**********************************************************************************/
156 /* From this point this is some internal stuff mainly taken from the linux kernel */
157 /**********************************************************************************/
158 /**********************************************************************************/
159
160 /*
161 * EFLAGS bits
162 */
163 #define X86_EFLAGS_CF 0x00000001 /* Carry Flag */
164 #define X86_EFLAGS_PF 0x00000004 /* Parity Flag */
165 #define X86_EFLAGS_AF 0x00000010 /* Auxillary carry Flag */
166 #define X86_EFLAGS_ZF 0x00000040 /* Zero Flag */
167 #define X86_EFLAGS_SF 0x00000080 /* Sign Flag */
168 #define X86_EFLAGS_TF 0x00000100 /* Trap Flag */
169 #define X86_EFLAGS_IF 0x00000200 /* Interrupt Flag */
170 #define X86_EFLAGS_DF 0x00000400 /* Direction Flag */
171 #define X86_EFLAGS_OF 0x00000800 /* Overflow Flag */
172 #define X86_EFLAGS_IOPL 0x00003000 /* IOPL mask */
173 #define X86_EFLAGS_NT 0x00004000 /* Nested Task */
174 #define X86_EFLAGS_RF 0x00010000 /* Resume Flag */
175 #define X86_EFLAGS_VM 0x00020000 /* Virtual Mode */
176 #define X86_EFLAGS_AC 0x00040000 /* Alignment Check */
177 #define X86_EFLAGS_VIF 0x00080000 /* Virtual Interrupt Flag */
178 #define X86_EFLAGS_VIP 0x00100000 /* Virtual Interrupt Pending */
179 #define X86_EFLAGS_ID 0x00200000 /* CPUID detection flag */
180
181 #define X86_VENDOR_INTEL 0
182 #define X86_VENDOR_CYRIX 1
183 #define X86_VENDOR_AMD 2
184 #define X86_VENDOR_UMC 3
185 #define X86_VENDOR_NEXGEN 4
186 #define X86_VENDOR_CENTAUR 5
187 #define X86_VENDOR_RISE 6
188 #define X86_VENDOR_TRANSMETA 7
189 #define X86_VENDOR_NSC 8
190 #define X86_VENDOR_UNKNOWN 9
191 #define X86_VENDOR_NUM 10
192
193 #define cpu_has(c, bit) test_bit(bit, (c)->x86_capability)
194
195 // Taken from asm/processor-flags.h
196 // NSC/Cyrix CPU configuration register indexes
197 #define CX86_CCR2 0xc2
198 #define CX86_CCR3 0xc3
199 #define CX86_DIR0 0xfe
200 #define CX86_DIR1 0xff
201
202 static const char Cx86_model[][9] = {
203 "Cx486", "Cx486", "5x86 ", "6x86", "MediaGX ", "6x86MX ",
204 "M II ", "Unknown"
205 };
206
207 static const char Cx486_name[][5] = {
208 "SLC", "DLC", "SLC2", "DLC2", "SRx", "DRx",
209 "SRx2", "DRx2"
210 };
211
212 static const char Cx486S_name[][4] = {
213 "S", "S2", "Se", "S2e"
214 };
215
216 static const char Cx486D_name[][4] = {
217 "DX", "DX2", "?", "?", "?", "DX4"
218 };
219
220
221 /*
222 * CPU type and hardware bug flags. Kept separately for each CPU.
223 * Members of this structure are referenced in head.S, so think twice
224 * before touching them. [mj]
225 */
226
227 struct cpuinfo_x86 {
228 uint8_t x86; /* CPU family */
229 uint8_t x86_vendor; /* CPU vendor */
230 uint8_t x86_model;
231 uint8_t x86_mask;
232 char wp_works_ok; /* It doesn't on 386's */
233 char hlt_works_ok; /* Problems on some 486Dx4's and old 386's */
234 char hard_math;
235 char rfu;
236 int cpuid_level; /* Maximum supported CPUID level, -1=no CPUID */
237 uint32_t x86_capability[NCAPINTS];
238 char x86_vendor_id[16];
239 char x86_model_id[64];
240 uint16_t x86_l1_data_cache_size; /* in KB, if available */
241 uint16_t x86_l1_instruction_cache_size; /* in KB, if available */
242 uint16_t x86_l2_cache_size; /* in KB, if available */
243 int x86_cache_alignment; /* in bytes */
244 char fdiv_bug;
245 char f00f_bug;
246 char coma_bug;
247 char pad0;
248 int x86_power;
249 unsigned long loops_per_jiffy;
250 #ifdef CONFIG_SMP
251 cpumask_t llc_shared_map; /* cpus sharing the last level cache */
252 #endif
253 unsigned char x86_num_cores; /* cpuid returned the number of cores */
254 unsigned char booted_cores; /* number of cores as seen by OS */
255 unsigned char apicid;
256 unsigned char x86_clflush_size;
257
258 } __attribute__ ((__packed__));
259
260 struct cpu_model_info {
261 int vendor;
262 int family;
263 char *model_names[16];
264 };
265
266 /* attempt to consolidate cpu attributes */
267 struct cpu_dev {
268 const char *c_vendor;
269
270 /* some have two possibilities for cpuid string */
271 const char *c_ident[2];
272
273 struct cpu_model_info c_models[4];
274
275 void (*c_init) (struct cpuinfo_x86 * c);
276 void (*c_identify) (struct cpuinfo_x86 * c);
277 unsigned int (*c_size_cache) (struct cpuinfo_x86 * c, unsigned int size);
278 };
279
280 /*
281 * Structure definitions for SMP machines following the
282 * Intel Multiprocessing Specification 1.1 and 1.4.
283 */
284
285 /*
286 * This tag identifies where the SMP configuration
287 * information is.
288 */
289
290 #define SMP_MAGIC_IDENT (('_'<<24)|('P'<<16)|('M'<<8)|'_')
291
292 struct intel_mp_floating {
293 char mpf_signature[4]; /* "_MP_" */
294 uint32_t mpf_physptr; /* Configuration table address */
295 uint8_t mpf_length; /* Our length (paragraphs) */
296 uint8_t mpf_specification; /* Specification version */
297 uint8_t mpf_checksum; /* Checksum (makes sum 0) */
298 uint8_t mpf_feature1; /* Standard or configuration ? */
299 uint8_t mpf_feature2; /* Bit7 set for IMCR|PIC */
300 uint8_t mpf_feature3; /* Unused (0) */
301 uint8_t mpf_feature4; /* Unused (0) */
302 uint8_t mpf_feature5; /* Unused (0) */
303 };
304
getCx86(uint8_t reg)305 static inline uint8_t getCx86(uint8_t reg) {
306 outb(reg, 0x22);
307 return inb(0x23);
308 }
309
setCx86(uint8_t reg,uint8_t data)310 static inline void setCx86(uint8_t reg, uint8_t data) {
311 outb(reg, 0x22);
312 outb(data, 0x23);
313 }
314
315 extern void get_cpu_vendor(struct cpuinfo_x86 *c);
316 extern void detect_cpu(s_cpu * cpu);
317 #endif
318