1 INTERFACE[ia32,amd64,ux]:
6 #include "per_cpu_data.h"
51 Lf_rdpmc = 0x00000001,
52 Lf_rdpmc32 = 0x00000002,
55 Unsigned64 time_us() const;
56 int can_wrmsr() const;
60 Unsigned64 _frequency;
64 Unsigned32 _ext_features;
65 Unsigned32 _ext_8000_0001_ecx;
66 Unsigned32 _ext_8000_0001_edx;
67 Unsigned32 _local_features;
69 Unsigned16 _inst_tlb_4k_entries;
70 Unsigned16 _data_tlb_4k_entries;
71 Unsigned16 _inst_tlb_4m_entries;
72 Unsigned16 _data_tlb_4m_entries;
73 Unsigned16 _inst_tlb_4k_4m_entries;
74 Unsigned16 _data_tlb_4k_4m_entries;
75 Unsigned16 _l2_inst_tlb_4k_entries;
76 Unsigned16 _l2_data_tlb_4k_entries;
77 Unsigned16 _l2_inst_tlb_4m_entries;
78 Unsigned16 _l2_data_tlb_4m_entries;
80 Unsigned16 _l1_trace_cache_size;
81 Unsigned16 _l1_trace_cache_asso;
83 Unsigned16 _l1_data_cache_size;
84 Unsigned16 _l1_data_cache_asso;
85 Unsigned16 _l1_data_cache_line_size;
87 Unsigned16 _l1_inst_cache_size;
88 Unsigned16 _l1_inst_cache_asso;
89 Unsigned16 _l1_inst_cache_line_size;
91 Unsigned16 _l2_cache_size;
92 Unsigned16 _l2_cache_asso;
93 Unsigned16 _l2_cache_line_size;
95 Unsigned32 _l3_cache_size;
96 Unsigned16 _l3_cache_asso;
97 Unsigned16 _l3_cache_line_size;
100 Unsigned8 _virt_bits;
105 Unsigned32 _arch_perfmon_info_eax;
106 Unsigned32 _arch_perfmon_info_ebx;
107 Unsigned32 _arch_perfmon_info_ecx;
109 Unsigned32 _monitor_mwait_eax;
110 Unsigned32 _monitor_mwait_ebx;
111 Unsigned32 _monitor_mwait_ecx;
112 Unsigned32 _monitor_mwait_edx;
114 Unsigned32 scaler_tsc_to_ns;
115 Unsigned32 scaler_tsc_to_us;
116 Unsigned32 scaler_ns_to_tsc;
120 void disable(unsigned cpu, char const *reason);
122 char const *model_str() const { return _model_str; }
123 Vendor vendor() const { return _vendor; }
125 unsigned family() const
126 { return (_version >> 8 & 0xf) + (_version >> 20 & 0xff); }
128 char const *vendor_str() const
129 { return _vendor == Vendor_unknown ? "Unknown" : vendor_ident[_vendor]; }
131 unsigned model() const
132 { return (_version >> 4 & 0xf) + (_version >> 12 & 0xf0); }
134 unsigned stepping() const { return _version & 0xF; }
135 unsigned type() const { return (_version >> 12) & 0x3; }
136 Unsigned64 frequency() const { return _frequency; }
137 unsigned brand() const { return _brand & 0xFF; }
138 unsigned features() const { return _features; }
139 unsigned ext_features() const { return _ext_features; }
140 bool has_monitor_mwait() const { return _ext_features & (1 << 3); }
141 bool has_monitor_mwait_irq() const { return _monitor_mwait_ecx & 3; }
142 unsigned ext_8000_0001_ecx() const { return _ext_8000_0001_ecx; }
143 unsigned ext_8000_0001_edx() const { return _ext_8000_0001_edx; }
144 unsigned local_features() const { return _local_features; }
145 bool superpages() const { return features() & FEAT_PSE; }
146 bool tsc() const { return features() & FEAT_TSC; }
147 bool sysenter() const { return features() & FEAT_SEP; }
148 bool syscall() const { return ext_8000_0001_edx() & FEATA_SYSCALL; }
149 bool vmx() { return boot_cpu()->ext_features() & FEATX_VMX; }
150 bool svm() { return boot_cpu()->ext_8000_0001_ecx() & FEATA_SVM; }
151 bool has_amd_osvw() { return boot_cpu()->ext_8000_0001_ecx() & (1<<9); }
152 unsigned virt_bits() const { return _virt_bits; }
153 unsigned phys_bits() const { return _phys_bits; }
154 Unsigned32 get_scaler_tsc_to_ns() const { return scaler_tsc_to_ns; }
155 Unsigned32 get_scaler_tsc_to_us() const { return scaler_tsc_to_us; }
156 Unsigned32 get_scaler_ns_to_tsc() const { return scaler_ns_to_tsc; }
158 Address volatile &kernel_sp() const;
161 static Per_cpu<Cpu> cpus asm ("CPUS_BASE");
162 static Cpu *boot_cpu() { return _boot_cpu; }
164 static bool have_superpages() { return boot_cpu()->superpages(); }
165 static bool have_sysenter() { return boot_cpu()->sysenter(); }
166 static bool have_syscall() { return boot_cpu()->syscall(); }
167 static bool have_fxsr() { return boot_cpu()->features() & FEAT_FXSR; }
168 static bool have_pge() { return boot_cpu()->features() & FEAT_PGE; }
172 static Cpu *_boot_cpu;
174 struct Vendor_table {
175 Unsigned32 vendor_mask;
176 Unsigned32 vendor_code;
178 char vendor_string[32];
179 } __attribute__((packed));
189 static Vendor_table const intel_table[];
190 static Vendor_table const amd_table[];
191 static Vendor_table const cyrix_table[];
192 static Vendor_table const via_table[];
193 static Vendor_table const umc_table[];
194 static Vendor_table const nexgen_table[];
195 static Vendor_table const rise_table[];
196 static Vendor_table const transmeta_table[];
197 static Vendor_table const sis_table[];
198 static Vendor_table const nsc_table[];
200 static Cache_table const intel_cache_table[];
202 static char const * const vendor_ident[];
203 static Vendor_table const * const vendor_table[];
205 static char const * const exception_strings[];
209 //-----------------------------------------------------------------------------
212 * Architecture specific cpu init code
214 INTERFACE [ia32, amd64]:
216 #include "l4_types.h"
217 #include "initcalls.h"
218 #include "per_cpu_data.h"
230 Lbr_uninitialized = 0,
239 Bts_uninitialized = 0,
246 /** Flags if lbr or bts facilities are activated, used by double-fault
247 * handler to reset the debugging facilities
249 Unsigned32 debugctl_busy;
251 /** debugctl value for activating lbr or bts */
252 Unsigned32 debugctl_set;
254 /** debugctl value to reset activated lr/bts facilities in the double-faukt
257 Unsigned32 debugctl_reset;
259 /** supported lbr type */
262 /** supported bts type */
265 /** is lbr active ? */
268 /** is btf active ? */
271 /** is bts active ? */
279 Lbr lbr_type() const { return _lbr; }
280 Bts bts_type() const { return _bts; }
281 bool lbr_status() const { return lbr_active; }
282 bool bts_status() const { return bts_active; }
283 bool btf_status() const { return btf_active; }
285 Gdt* get_gdt() const { return gdt; }
286 Tss* get_tss() const { return tss; }
289 Pseudo_descriptor desc((Address)gdt, Gdt::gdt_max-1);
293 void set_tss() const { set_tr(Gdt::gdt_tss); }
296 void init_lbr_type();
297 void init_bts_type();
301 //-----------------------------------------------------------------------------
302 IMPLEMENTATION[ia32,amd64,ux]:
308 #include "processor.h"
310 Per_cpu<Cpu> DEFINE_PER_CPU_P(0) Cpu::cpus(true);
314 Cpu::Vendor_table const Cpu::intel_table[] FIASCO_INITDATA_CPU =
316 { 0xf0fF0, 0x00400, 0xFFFF, "i486 DX-25/33" },
317 { 0xf0fF0, 0x00410, 0xFFFF, "i486 DX-50" },
318 { 0xf0fF0, 0x00420, 0xFFFF, "i486 SX" },
319 { 0xf0fF0, 0x00430, 0xFFFF, "i486 DX/2" },
320 { 0xf0fF0, 0x00440, 0xFFFF, "i486 SL" },
321 { 0xf0fF0, 0x00450, 0xFFFF, "i486 SX/2" },
322 { 0xf0fF0, 0x00470, 0xFFFF, "i486 DX/2-WB" },
323 { 0xf0fF0, 0x00480, 0xFFFF, "i486 DX/4" },
324 { 0xf0fF0, 0x00490, 0xFFFF, "i486 DX/4-WB" },
325 { 0xf0fF0, 0x00500, 0xFFFF, "Pentium A-Step" },
326 { 0xf0fF0, 0x00510, 0xFFFF, "Pentium P5" },
327 { 0xf0fF0, 0x00520, 0xFFFF, "Pentium P54C" },
328 { 0xf0fF0, 0x00530, 0xFFFF, "Pentium P24T Overdrive" },
329 { 0xf0fF0, 0x00540, 0xFFFF, "Pentium P55C MMX" },
330 { 0xf0fF0, 0x00570, 0xFFFF, "Pentium Mobile" },
331 { 0xf0fF0, 0x00580, 0xFFFF, "Pentium MMX Mobile (Tillamook)" },
332 { 0xf0fF0, 0x00600, 0xFFFF, "Pentium-Pro A-Step" },
333 { 0xf0fF0, 0x00610, 0xFFFF, "Pentium-Pro" },
334 { 0xf0fF0, 0x00630, 512, "Pentium II (Klamath)" },
335 { 0xf0fF0, 0x00640, 512, "Pentium II (Deschutes)" },
336 { 0xf0fF0, 0x00650, 1024, "Pentium II (Drake)" },
337 { 0xf0fF0, 0x00650, 512, "Pentium II (Deschutes)" },
338 { 0xf0fF0, 0x00650, 256, "Pentium II Mobile (Dixon)" },
339 { 0xf0fF0, 0x00650, 0, "Celeron (Covington)" },
340 { 0xf0fF0, 0x00660, 128, "Celeron (Mendocino)" },
341 { 0xf0fF0, 0x00670, 1024, "Pentium III (Tanner)" },
342 { 0xf0fF0, 0x00670, 512, "Pentium III (Katmai)" },
343 { 0xf0fF0, 0x00680, 256, "Pentium III (Coppermine)" },
344 { 0xf0fF0, 0x00680, 128, "Celeron (Coppermine)" },
345 { 0xf0fF0, 0x00690, 1024, "Pentium-M (Banias)" },
346 { 0xf0fF0, 0x00690, 512, "Celeron-M (Banias)" },
347 { 0xf0fF0, 0x006a0, 1024, "Pentium III (Cascades)" },
348 { 0xf0fF0, 0x006b0, 512, "Pentium III-S" },
349 { 0xf0fF0, 0x006b0, 256, "Pentium III (Tualatin)" },
350 { 0xf0fF0, 0x006d0, 2048, "Pentium-M (Dothan)" },
351 { 0xf0fF0, 0x006d0, 1024, "Celeron-M (Dothan)" },
352 { 0xf0fF0, 0x006e0, 2048, "Core (Yonah)" },
353 { 0xf0fF0, 0x006f0, 2048, "Core 2 (Merom)" },
354 { 0xf0f00, 0x00700, 0xFFFF, "Itanium (Merced)" },
355 { 0xf0fF0, 0x00f00, 256, "Pentium 4 (Willamette/Foster)" },
356 { 0xf0fF0, 0x00f10, 256, "Pentium 4 (Willamette/Foster)" },
357 { 0xf0fF0, 0x00f10, 128, "Celeron (Willamette)" },
358 { 0xf0fF0, 0x00f20, 512, "Pentium 4 (Northwood/Prestonia)" },
359 { 0xf0fF0, 0x00f20, 128, "Celeron (Northwood)" },
360 { 0xf0fF0, 0x00f30, 1024, "Pentium 4E (Prescott/Nocona)" },
361 { 0xf0fF0, 0x00f30, 256, "Celeron D (Prescott)" },
362 { 0xf0fF4, 0x00f40, 1024, "Pentium 4E (Prescott/Nocona)" },
363 { 0xf0fF4, 0x00f44, 1024, "Pentium D (Smithfield)" },
364 { 0xf0fF0, 0x00f40, 256, "Celeron D (Prescott)" },
365 { 0xf0fF0, 0x00f60, 2048, "Pentium D (Cedarmill/Presler)" },
366 { 0xf0fF0, 0x00f60, 512, "Celeron D (Cedarmill)" },
367 { 0xf0ff0, 0x10600, 0, "Celeron, 65nm" },
368 { 0xf0ff0, 0x10670, 2048, "Core2 / Xeon (Wolfdale), 45nm" },
369 { 0xf0ff0, 0x106a0, 0xffff, "Core i7 / Xeon, 45nm" },
370 { 0xf0ff0, 0x106b0, 0xffff, "Xeon MP, 45nm" },
371 { 0xf0ff0, 0x106c0, 0xffff, "Atom" },
372 { 0xf0ff0, 0x206c0, 0xffff, "Xeon X5680 (and others?)" },
373 { 0x0, 0x0, 0xFFFF, "" }
376 Cpu::Vendor_table const Cpu::amd_table[] FIASCO_INITDATA_CPU =
378 { 0xFF0, 0x430, 0xFFFF, "Am486DX2-WT" },
379 { 0xFF0, 0x470, 0xFFFF, "Am486DX2-WB" },
380 { 0xFF0, 0x480, 0xFFFF, "Am486DX4-WT / Am5x86-WT" },
381 { 0xFF0, 0x490, 0xFFFF, "Am486DX4-WB / Am5x86-WB" },
382 { 0xFF0, 0x4a0, 0xFFFF, "SC400" },
383 { 0xFF0, 0x4e0, 0xFFFF, "Am5x86-WT" },
384 { 0xFF0, 0x4f0, 0xFFFF, "Am5x86-WB" },
385 { 0xFF0, 0x500, 0xFFFF, "K5 (SSA/5) PR75/90/100" },
386 { 0xFF0, 0x510, 0xFFFF, "K5 (Godot) PR120/133" },
387 { 0xFF0, 0x520, 0xFFFF, "K5 (Godot) PR150/166" },
388 { 0xFF0, 0x530, 0xFFFF, "K5 (Godot) PR200" },
389 { 0xFF0, 0x560, 0xFFFF, "K6 (Little Foot)" },
390 { 0xFF0, 0x570, 0xFFFF, "K6 (Little Foot)" },
391 { 0xFF0, 0x580, 0xFFFF, "K6-II (Chomper)" },
392 { 0xFF0, 0x590, 256, "K6-III (Sharptooth)" },
393 { 0xFF0, 0x5c0, 128, "K6-2+" },
394 { 0xFF0, 0x5d0, 256, "K6-3+" },
395 { 0xFF0, 0x600, 0xFFFF, "Athlon K7 (Argon)" },
396 { 0xFF0, 0x610, 0xFFFF, "Athlon K7 (Pluto)" },
397 { 0xFF0, 0x620, 0xFFFF, "Athlon K75 (Orion)" },
398 { 0xFF0, 0x630, 64, "Duron (Spitfire)" },
399 { 0xFF0, 0x640, 256, "Athlon (Thunderbird)" },
400 { 0xFF0, 0x660, 256, "Athlon (Palomino)" },
401 { 0xFF0, 0x660, 64, "Duron (Morgan)" },
402 { 0xFF0, 0x670, 64, "Duron (Morgan)" },
403 { 0xFF0, 0x680, 256, "Athlon (Thoroughbred)" },
404 { 0xFF0, 0x680, 64, "Duron (Applebred)" },
405 { 0xFF0, 0x6A0, 512, "Athlon (Barton)" },
406 { 0xFF0, 0x6A0, 256, "Athlon (Thorton)" },
407 { 0xfff0ff0, 0x000f00, 0, "Athlon 64 (Clawhammer)" },
408 { 0xfff0ff0, 0x000f10, 0, "Opteron (Sledgehammer)" },
409 { 0xfff0ff0, 0x000f40, 0, "Athlon 64 (Clawhammer)" },
410 { 0xfff0ff0, 0x000f50, 0, "Opteron (Sledgehammer)" },
411 { 0xfff0ff0, 0x000fc0, 512, "Athlon64 (Newcastle)" },
412 { 0xfff0ff0, 0x000fc0, 256, "Sempron (Paris)" },
413 { 0xfff0ff0, 0x010f50, 0, "Opteron (Sledgehammer)" },
414 { 0xfff0ff0, 0x010fc0, 0, "Sempron (Oakville)" },
415 { 0xfff0ff0, 0x010ff0, 0, "Athlon 64 (Winchester)" },
416 { 0xfff0ff0, 0x020f10, 0, "Opteron (Jackhammer)" },
417 { 0xfff0ff0, 0x020f30, 0, "Athlon 64 X2 (Toledo)" },
418 { 0xfff0ff0, 0x020f40, 0, "Turion 64 (Lancaster)" },
419 { 0xfff0ff0, 0x020f50, 0, "Opteron (Venus)" },
420 { 0xfff0ff0, 0x020f70, 0, "Athlon 64 (San Diego)" },
421 { 0xfff0ff0, 0x020fb0, 0, "Athlon 64 X2 (Manchester)" },
422 { 0xfff0ff0, 0x020fc0, 0, "Sempron (Palermo)" },
423 { 0xfff0ff0, 0x020ff0, 0, "Athlon 64 (Venice)" },
424 { 0xfff0ff0, 0x040f10, 0, "Opteron (Santa Rosa)" },
425 { 0xfff0ff0, 0x040f30, 0, "Athlon 64 X2 (Windsor)" },
426 { 0xfff0ff0, 0x040f80, 0, "Turion 64 X2 (Taylor)" },
427 { 0xfff0ff0, 0x060fb0, 0, "Athlon 64 X2 (Brisbane)" },
428 { 0xfff0ff0, 0x100f20, 0, "Phenom X3/Toliman / X4/Agena" },
429 { 0xfff0ff0, 0x100f40, 0, "Opteron (Shanghai)" },
433 Cpu::Vendor_table const Cpu::cyrix_table[] FIASCO_INITDATA_CPU =
435 { 0xFF0, 0x440, 0xFFFF, "Gx86 (Media GX)" },
436 { 0xFF0, 0x490, 0xFFFF, "5x86" },
437 { 0xFF0, 0x520, 0xFFFF, "6x86 (M1)" },
438 { 0xFF0, 0x540, 0xFFFF, "GXm" },
439 { 0xFF0, 0x600, 0xFFFF, "6x86MX (M2)" },
440 { 0x0, 0x0, 0xFFFF, "" }
443 Cpu::Vendor_table const Cpu::via_table[] FIASCO_INITDATA_CPU =
445 { 0xFF0, 0x540, 0xFFFF, "IDT Winchip C6" },
446 { 0xFF0, 0x580, 0xFFFF, "IDT Winchip 2A/B" },
447 { 0xFF0, 0x590, 0xFFFF, "IDT Winchip 3" },
448 { 0xFF0, 0x650, 0xFFFF, "Via Jalapeno (Joshua)" },
449 { 0xFF0, 0x660, 0xFFFF, "Via C5A (Samuel)" },
450 { 0xFF8, 0x670, 0xFFFF, "Via C5B (Samuel 2)" },
451 { 0xFF8, 0x678, 0xFFFF, "Via C5C (Ezra)" },
452 { 0xFF0, 0x680, 0xFFFF, "Via C5N (Ezra-T)" },
453 { 0xFF0, 0x690, 0xFFFF, "Via C5P (Nehemiah)" },
454 { 0xFF0, 0x6a0, 0xFFFF, "Via C5J (Esther)" },
455 { 0x0, 0x0, 0xFFFF, "" }
458 Cpu::Vendor_table const Cpu::umc_table[] FIASCO_INITDATA_CPU =
460 { 0xFF0, 0x410, 0xFFFF, "U5D" },
461 { 0xFF0, 0x420, 0xFFFF, "U5S" },
462 { 0x0, 0x0, 0xFFFF, "" }
465 Cpu::Vendor_table const Cpu::nexgen_table[] FIASCO_INITDATA_CPU =
467 { 0xFF0, 0x500, 0xFFFF, "Nx586" },
468 { 0x0, 0x0, 0xFFFF, "" }
471 Cpu::Vendor_table const Cpu::rise_table[] FIASCO_INITDATA_CPU =
473 { 0xFF0, 0x500, 0xFFFF, "mP6 (iDragon)" },
474 { 0xFF0, 0x520, 0xFFFF, "mP6 (iDragon)" },
475 { 0xFF0, 0x580, 0xFFFF, "mP6 (iDragon II)" },
476 { 0xFF0, 0x590, 0xFFFF, "mP6 (iDragon II)" },
477 { 0x0, 0x0, 0xFFFF, "" }
480 Cpu::Vendor_table const Cpu::transmeta_table[] FIASCO_INITDATA_CPU =
482 { 0xFFF, 0x542, 0xFFFF, "TM3x00 (Crusoe)" },
483 { 0xFFF, 0x543, 0xFFFF, "TM5x00 (Crusoe)" },
484 { 0xFF0, 0xf20, 0xFFFF, "TM8x00 (Efficeon)" },
485 { 0x0, 0x0, 0xFFFF, "" }
488 Cpu::Vendor_table const Cpu::sis_table[] FIASCO_INITDATA_CPU =
490 { 0xFF0, 0x500, 0xFFFF, "55x" },
491 { 0x0, 0x0, 0xFFFF, "" }
494 Cpu::Vendor_table const Cpu::nsc_table[] FIASCO_INITDATA_CPU =
496 { 0xFF0, 0x540, 0xFFFF, "Geode GX1" },
497 { 0xFF0, 0x550, 0xFFFF, "Geode GX2" },
498 { 0xFF0, 0x680, 0xFFFF, "Geode NX" },
499 { 0x0, 0x0, 0xFFFF, "" }
502 Cpu::Cache_table const Cpu::intel_cache_table[] FIASCO_INITDATA_CPU =
504 { 0x01, Tlb_inst_4k, 32, 4, 0 },
505 { 0x02, Tlb_inst_4M, 2, 4, 0 },
506 { 0x03, Tlb_data_4k, 64, 4, 0 },
507 { 0x04, Tlb_data_4M, 8, 4, 0 },
508 { 0x05, Tlb_data_4M, 32, 4, 0 },
509 { 0x06, Cache_l1_inst, 8, 4, 32 },
510 { 0x08, Cache_l1_inst, 16, 4, 32 },
511 { 0x09, Cache_l1_inst, 32, 4, 64 },
512 { 0x0A, Cache_l1_data, 8, 2, 32 },
513 { 0x0B, Tlb_inst_4M, 4, 4, 0 },
514 { 0x0C, Cache_l1_data, 16, 4, 32 },
515 { 0x0D, Cache_l1_data, 16, 4, 64 },
516 { 0x0E, Cache_l1_data, 24, 6, 64 },
517 { 0x21, Cache_l2, 256, 8, 64 },
518 { 0x22, Cache_l3, 512, 4, 64 }, /* sectored */
519 { 0x23, Cache_l3, 1024, 8, 64 }, /* sectored */
520 { 0x25, Cache_l3, 2048, 8, 64 }, /* sectored */
521 { 0x29, Cache_l3, 4096, 8, 64 }, /* sectored */
522 { 0x2C, Cache_l1_data, 32, 8, 64 },
523 { 0x30, Cache_l1_inst, 32, 8, 64 },
524 { 0x39, Cache_l2, 128, 4, 64 }, /* sectored */
525 { 0x3B, Cache_l2, 128, 2, 64 }, /* sectored */
526 { 0x3C, Cache_l2, 256, 4, 64 }, /* sectored */
527 { 0x41, Cache_l2, 128, 4, 32 },
528 { 0x42, Cache_l2, 256, 4, 32 },
529 { 0x43, Cache_l2, 512, 4, 32 },
530 { 0x44, Cache_l2, 1024, 4, 32 },
531 { 0x45, Cache_l2, 2048, 4, 32 },
532 { 0x46, Cache_l3, 4096, 4, 64 },
533 { 0x47, Cache_l3, 8192, 8, 64 },
534 { 0x48, Cache_l2, 3072, 12, 64 },
535 { 0x49, Cache_l2, 4096, 16, 64 },
536 { 0x4A, Cache_l3, 6144, 12, 64 },
537 { 0x4B, Cache_l3, 8192, 16, 64 },
538 { 0x4C, Cache_l3, 12288, 12, 64 },
539 { 0x4D, Cache_l3, 16384, 16, 64 },
540 { 0x4E, Cache_l3, 6144, 24, 64 },
541 { 0x4F, Tlb_inst_4k, 32, 0, 0 },
542 { 0x50, Tlb_inst_4k_4M, 64, 0, 0 },
543 { 0x51, Tlb_inst_4k_4M, 128, 0, 0 },
544 { 0x52, Tlb_inst_4k_4M, 256, 0, 0 },
545 { 0x56, Tlb_data_4M, 16, 4, 0 },
546 { 0x57, Tlb_data_4k, 16, 4, 0 },
547 { 0x5B, Tlb_data_4k_4M, 64, 0, 0 },
548 { 0x5C, Tlb_data_4k_4M, 128, 0, 0 },
549 { 0x5D, Tlb_data_4k_4M, 256, 0, 0 },
550 { 0x60, Cache_l1_data, 16, 8, 64 },
551 { 0x66, Cache_l1_data, 8, 4, 64 }, /* sectored */
552 { 0x67, Cache_l1_data, 16, 4, 64 }, /* sectored */
553 { 0x68, Cache_l1_data, 32, 4, 64 }, /* sectored */
554 { 0x70, Cache_l1_trace, 12, 8, 0 },
555 { 0x71, Cache_l1_trace, 16, 8, 0 },
556 { 0x72, Cache_l1_trace, 32, 8, 0 },
557 { 0x77, Cache_l1_inst, 16, 4, 64 },
558 { 0x78, Cache_l2, 1024, 4, 64 },
559 { 0x79, Cache_l2, 128, 8, 64 }, /* sectored */
560 { 0x7A, Cache_l2, 256, 8, 64 }, /* sectored */
561 { 0x7B, Cache_l2, 512, 8, 64 }, /* sectored */
562 { 0x7C, Cache_l2, 1024, 8, 64 }, /* sectored */
563 { 0x7D, Cache_l2, 2048, 8, 64 },
564 { 0x7E, Cache_l2, 256, 8, 128 },
565 { 0x7F, Cache_l2, 512, 2, 64 },
566 { 0x82, Cache_l2, 256, 8, 32 },
567 { 0x83, Cache_l2, 512, 8, 32 },
568 { 0x84, Cache_l2, 1024, 8, 32 },
569 { 0x85, Cache_l2, 2048, 8, 32 },
570 { 0x86, Cache_l2, 512, 4, 64 },
571 { 0x87, Cache_l2, 1024, 8, 64 },
572 { 0x8D, Cache_l3, 3072, 12, 128 },
573 { 0xB0, Tlb_inst_4k, 128, 4, 0 },
574 { 0xB3, Tlb_data_4k, 128, 4, 0 },
575 { 0xB4, Tlb_data_4k, 256, 4, 0 },
576 { 0xBA, Tlb_data_4k, 64, 4, 0 },
577 { 0xC0, Tlb_data_4k_4M, 8, 4, 0 },
578 { 0xCA, Tlb_data_4k_4M, 512, 4, 0 },
579 { 0xD0, Cache_l3, 512, 4, 64 },
580 { 0xD1, Cache_l3, 1024, 4, 64 },
581 { 0xD2, Cache_l3, 2048, 4, 64 },
582 { 0xD6, Cache_l3, 1024, 8, 64 },
583 { 0xD7, Cache_l3, 2048, 8, 64 },
584 { 0xD8, Cache_l3, 4096, 8, 64 },
585 { 0xDC, Cache_l3, 1536, 12, 64 },
586 { 0xDD, Cache_l3, 3072, 12, 64 },
587 { 0xDE, Cache_l3, 6144, 12, 64 },
588 { 0xE2, Cache_l3, 2048, 16, 64 },
589 { 0xE3, Cache_l3, 4096, 16, 64 },
590 { 0xE4, Cache_l3, 8192, 16, 64 },
591 { 0xEA, Cache_l3, 12288, 24, 64 },
592 { 0xEB, Cache_l3, 18432, 24, 64 },
593 { 0xEC, Cache_l3, 24576, 24, 64 },
594 { 0x0, Cache_unknown, 0, 0, 0 }
597 char const * const Cpu::vendor_ident[] =
612 Cpu::Vendor_table const * const Cpu::vendor_table[] =
627 char const * const Cpu::exception_strings[] =
629 /* 0 */ "Divide Error",
631 /* 2 */ "NMI Interrupt",
632 /* 3 */ "Breakpoint",
634 /* 5 */ "BOUND Range Exceeded",
635 /* 6 */ "Invalid Opcode",
636 /* 7 */ "Device Not Available",
637 /* 8 */ "Double Fault",
638 /* 9 */ "CoProcessor Segment Overrrun",
639 /* 10 */ "Invalid TSS",
640 /* 11 */ "Segment Not Present",
641 /* 12 */ "Stack Segment Fault",
642 /* 13 */ "General Protection",
643 /* 14 */ "Page Fault",
645 /* 16 */ "Floating-Point Error",
646 /* 17 */ "Alignment Check",
647 /* 18 */ "Machine Check",
648 /* 19 */ "SIMD Floating-Point Exception",
663 PUBLIC explicit FIASCO_INIT_CPU
664 Cpu::Cpu(unsigned cpu)
679 Cpu::init_global_features()
684 Cpu::exception_string(Mword trapno)
687 return "Maskable Interrupt";
688 return exception_strings[trapno];
691 PUBLIC static inline FIASCO_INIT_CPU
693 Cpu::cpuid(Unsigned32 const mode,
694 Unsigned32 *const eax, Unsigned32 *const ebx,
695 Unsigned32 *const ecx, Unsigned32 *const edx)
697 asm volatile ("cpuid" : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
703 PRIVATE FIASCO_INIT_CPU
705 Cpu::cache_tlb_intel()
708 unsigned i, count = 0;
709 Cache_table const *table;
713 cpuid(2, (Unsigned32 *)(desc),
714 (Unsigned32 *)(desc + 4),
715 (Unsigned32 *)(desc + 8),
716 (Unsigned32 *)(desc + 12));
718 for (i = 1; i < 16; i++)
720 // Null descriptor or register bit31 set (reserved)
721 if (!desc[i] || (desc[i / 4 * 4 + 3] & (1 << 7)))
724 for (table = intel_cache_table; table->desc; table++)
726 if (table->desc == desc[i])
728 switch (table->level)
731 _l1_data_cache_size = table->size;
732 _l1_data_cache_asso = table->asso;
733 _l1_data_cache_line_size = table->line_size;
736 _l1_inst_cache_size = table->size;
737 _l1_inst_cache_asso = table->asso;
738 _l1_inst_cache_line_size = table->line_size;
741 _l1_trace_cache_size = table->size;
742 _l1_trace_cache_asso = table->asso;
745 _l2_cache_size = table->size;
746 _l2_cache_asso = table->asso;
747 _l2_cache_line_size = table->line_size;
750 _l3_cache_size = table->size;
751 _l3_cache_asso = table->asso;
752 _l3_cache_line_size = table->line_size;
755 _inst_tlb_4k_entries += table->size;
758 _data_tlb_4k_entries += table->size;
761 _inst_tlb_4m_entries += table->size;
764 _data_tlb_4m_entries += table->size;
767 _inst_tlb_4k_4m_entries += table->size;
770 _data_tlb_4k_4m_entries += table->size;
780 while (++count < *desc);
783 PRIVATE FIASCO_INIT_CPU
787 Unsigned32 eax, ebx, ecx, edx;
788 cpuid(0x80000005, &eax, &ebx, &ecx, &edx);
790 _l1_data_cache_size = (ecx >> 24) & 0xFF;
791 _l1_data_cache_asso = (ecx >> 16) & 0xFF;
792 _l1_data_cache_line_size = ecx & 0xFF;
794 _l1_inst_cache_size = (edx >> 24) & 0xFF;
795 _l1_inst_cache_asso = (edx >> 16) & 0xFF;
796 _l1_inst_cache_line_size = edx & 0xFF;
798 _data_tlb_4k_entries = (ebx >> 16) & 0xFF;
799 _inst_tlb_4k_entries = ebx & 0xFF;
800 _data_tlb_4m_entries = (eax >> 16) & 0xFF;
801 _inst_tlb_4m_entries = eax & 0xFF;
804 PRIVATE FIASCO_INIT_CPU
806 Cpu::cache_tlb_l2_l3()
808 Unsigned32 eax, ebx, ecx, edx;
809 cpuid(0x80000006, &eax, &ebx, &ecx, &edx);
811 if (vendor() == Vendor_via)
813 _l2_cache_size = (ecx >> 24) & 0xFF;
814 _l2_cache_asso = (ecx >> 16) & 0xFF;
818 _l2_data_tlb_4m_entries = (eax >> 16) & 0xFFF;
819 _l2_inst_tlb_4m_entries = eax & 0xFFF;
820 _l2_data_tlb_4k_entries = (ebx >> 16) & 0xFFF;
821 _l2_inst_tlb_4k_entries = ebx & 0xFFF;
822 _l2_cache_size = (ecx >> 16) & 0xFFFF;
823 _l2_cache_asso = (ecx >> 12) & 0xF;
826 _l2_cache_line_size = ecx & 0xFF;
828 _l3_cache_size = (edx >> 18) << 9;
829 _l3_cache_asso = (edx >> 12) & 0xF;
830 _l3_cache_line_size = edx & 0xFF;
833 PRIVATE FIASCO_INIT_CPU
835 Cpu::addr_size_info()
837 Unsigned32 eax, ebx, ecx, edx;
838 cpuid(0x80000008, &eax, &ebx, &ecx, &edx);
840 _phys_bits = eax & 0xff;
841 _virt_bits = (eax & 0xff00) >> 8;
844 PRIVATE FIASCO_INIT_CPU
848 Vendor_table const *table;
850 for (table = vendor_table[vendor()]; table && table->vendor_mask; table++)
851 if ((_version & table->vendor_mask) == table->vendor_code &&
852 (table->l2_cache == 0xFFFF || _l2_cache_size >= table->l2_cache))
854 snprintf(_model_str, sizeof (_model_str), "%s",
855 table->vendor_string);
859 snprintf(_model_str, sizeof (_model_str), "Unknown CPU");
862 PUBLIC inline FIASCO_INIT_CPU
864 Cpu::arch_perfmon_info(Unsigned32 *eax, Unsigned32 *ebx, Unsigned32 *ecx) const
866 *eax = _arch_perfmon_info_eax;
867 *ebx = _arch_perfmon_info_ebx;
868 *ecx = _arch_perfmon_info_ecx;
875 Unsigned32 eflags = get_flags();
876 // Check for Alignment Check Support
877 set_flags(eflags ^ EFLAGS_AC);
878 if (((get_flags() ^ eflags) & EFLAGS_AC) == 0)
881 // Check for CPUID Support
882 set_flags(eflags ^ EFLAGS_ID);
883 if (!((get_flags() ^ eflags) & EFLAGS_ID))
889 cpuid(0, &max, (Unsigned32 *)(vendor_id),
890 (Unsigned32 *)(vendor_id + 8),
891 (Unsigned32 *)(vendor_id + 4));
896 Unsigned32 dummy, dummy1, dummy2, features;
897 cpuid (1, &dummy, &dummy1, &dummy2, &features);
903 /** Identify the CPU features.
904 Attention: This function may be called more than once. The reason is
905 that enabling a Local APIC that was previously disabled by the BIOS
906 may change the processor features. Therefore, this function has to
907 be called again after the Local APIC was enabled.
909 PUBLIC FIASCO_INIT_CPU
913 Unsigned32 eflags = get_flags();
918 // Reset members in case we get called more than once
919 _inst_tlb_4k_entries =
920 _data_tlb_4k_entries =
921 _inst_tlb_4m_entries =
922 _data_tlb_4m_entries =
923 _inst_tlb_4k_4m_entries =
924 _data_tlb_4k_4m_entries = 0;
926 // Check for Alignment Check Support
927 set_flags(eflags ^ EFLAGS_AC);
928 if (((get_flags() ^ eflags) & EFLAGS_AC) == 0)
929 panic("CPU too old");
931 // Check for CPUID Support
932 set_flags(eflags ^ EFLAGS_ID);
933 if ((get_flags() ^ eflags) & EFLAGS_ID) {
938 cpuid(0, &max, (Unsigned32 *)(vendor_id),
939 (Unsigned32 *)(vendor_id + 8),
940 (Unsigned32 *)(vendor_id + 4));
942 for (i = sizeof (vendor_ident) / sizeof (*vendor_ident) - 1; i; i--)
943 if (!memcmp(vendor_id, vendor_ident[i], 12))
946 _vendor = (Cpu::Vendor)i;
951 // All cases fall through!
953 cpuid(10, &_arch_perfmon_info_eax,
954 &_arch_perfmon_info_ebx,
955 &_arch_perfmon_info_ecx, &i);
957 if (_vendor == Vendor_intel)
960 cpuid(1, &_version, &_brand, &_ext_features, &_features);
963 if (max >= 5 && has_monitor_mwait())
964 cpuid(5, &_monitor_mwait_eax, &_monitor_mwait_ebx,
965 &_monitor_mwait_ecx, &_monitor_mwait_edx);
967 if (_vendor == Vendor_intel)
972 // Avoid Pentium Erratum 74
973 if ((_features & FEAT_MMX) &&
975 (stepping() != 4 && (stepping() != 3 || type() != 1))))
976 _local_features |= Lf_rdpmc;
979 // Avoid Pentium Pro Erratum 26
980 if (model() >= 3 || stepping() > 9)
981 _local_features |= Lf_rdpmc;
984 _local_features |= Lf_rdpmc;
985 _local_features |= Lf_rdpmc32;
989 else if (_vendor == Vendor_amd)
995 _local_features |= Lf_rdpmc;
1000 // Get maximum number for extended functions
1001 cpuid(0x80000000, &max, &i, &i, &i);
1003 if (max > 0x80000000)
1008 // All cases fall through!
1010 if (_vendor == Vendor_amd || _vendor == Vendor_intel)
1014 if (_vendor == Vendor_amd || _vendor == Vendor_via)
1017 if (_vendor == Vendor_amd || _vendor == Vendor_via)
1023 if (_vendor == Vendor_intel || _vendor == Vendor_amd)
1024 cpuid(0x80000001, &i, &i, &_ext_8000_0001_ecx,
1025 &_ext_8000_0001_edx);
1030 // see Intel Spec on SYSENTER:
1031 // Some Pentium Pro pretend to have it, but actually lack it
1032 if ((_version & 0xFFF) < 0x633)
1033 _features &= ~FEAT_SEP;
1043 PUBLIC inline NEEDS["processor.h"]
1045 Cpu::busy_wait_ns(Unsigned64 ns)
1047 Unsigned64 stop = rdtsc () + ns_to_tsc(ns);
1049 while (rdtsc() < stop)
1056 Cpu::show_cache_tlb_info(const char *indent) const
1061 if (_l2_inst_tlb_4k_entries)
1062 snprintf(s, sizeof(s), "/%u", _l2_inst_tlb_4k_entries);
1063 if (_inst_tlb_4k_entries)
1064 printf("%s%4u%s Entry I TLB (4K pages)", indent, _inst_tlb_4k_entries, s);
1066 if (_l2_inst_tlb_4m_entries)
1067 snprintf(s, sizeof(s), "/%u", _l2_inst_tlb_4k_entries);
1068 if (_inst_tlb_4m_entries)
1069 printf(" %4u%s Entry I TLB (4M pages)", _inst_tlb_4m_entries, s);
1070 if (_inst_tlb_4k_4m_entries)
1071 printf("%s%4u Entry I TLB (4K or 4M pages)",
1072 indent, _inst_tlb_4k_4m_entries);
1073 if (_inst_tlb_4k_entries || _inst_tlb_4m_entries || _inst_tlb_4k_4m_entries)
1076 if (_l2_data_tlb_4k_entries)
1077 snprintf(s, sizeof(s), "/%u", _l2_data_tlb_4k_entries);
1078 if (_data_tlb_4k_entries)
1079 printf("%s%4u%s Entry D TLB (4K pages)", indent, _data_tlb_4k_entries, s);
1081 if (_l2_data_tlb_4m_entries)
1082 snprintf(s, sizeof(s), "/%u", _l2_data_tlb_4m_entries);
1083 if (_data_tlb_4m_entries)
1084 printf(" %4u%s Entry D TLB (4M pages)", _data_tlb_4m_entries, s);
1085 if (_data_tlb_4k_4m_entries)
1086 printf("%s%4u Entry D TLB (4k or 4M pages)",
1087 indent, _data_tlb_4k_4m_entries);
1088 if (_data_tlb_4k_entries || _data_tlb_4m_entries || _data_tlb_4k_4m_entries)
1091 if (_l1_trace_cache_size)
1092 printf("%s%3uK %c-ops T Cache (%u-way associative)\n",
1093 indent, _l1_trace_cache_size, Config::char_micro,
1094 _l1_trace_cache_asso);
1096 else if (_l1_inst_cache_size)
1097 printf("%s%4u KB L1 I Cache (%u-way associative, %u bytes per line)\n",
1098 indent, _l1_inst_cache_size, _l1_inst_cache_asso,
1099 _l1_inst_cache_line_size);
1101 if (_l1_data_cache_size)
1102 printf("%s%4u KB L1 D Cache (%u-way associative, %u bytes per line)\n"
1103 "%s%4u KB L2 U Cache (%u-way associative, %u bytes per line)\n",
1104 indent, _l1_data_cache_size, _l1_data_cache_asso,
1105 _l1_data_cache_line_size,
1106 indent, _l2_cache_size, _l2_cache_asso, _l2_cache_line_size);
1109 printf("%s%4u KB L3 U Cache (%u-way associative, %u bytes per line)\n",
1110 indent, _l3_cache_size, _l3_cache_asso, _l3_cache_line_size);
1115 Cpu::disable(unsigned cpu, char const *reason)
1117 printf("CPU%u: is disabled: %s\n", cpu, reason);
1120 // Function used for calculating apic scaler
1121 PUBLIC static inline
1123 Cpu::muldiv(Unsigned32 val, Unsigned32 mul, Unsigned32 div)
1127 asm volatile ("mull %3 ; divl %4\n\t"
1128 :"=a" (val), "=d" (dummy)
1129 : "0" (val), "d" (mul), "c" (div));
1134 PUBLIC static inline
1139 asm volatile ("mov %%cs, %0" : "=rm" (val));
1143 PUBLIC static inline
1148 asm volatile ("mov %%ds, %0" : "=rm" (val));
1152 PUBLIC static inline
1157 asm volatile ("mov %%es, %0" : "=rm" (val));
1161 PUBLIC static inline
1166 asm volatile ("mov %%ss, %0" : "=rm" (val));
1170 PUBLIC static inline
1175 asm volatile ("mov %%fs, %0" : "=rm" (val));
1179 PUBLIC static inline
1181 Cpu::set_ds(Unsigned32 val)
1182 { asm volatile ("mov %0, %%ds" : : "rm" (val)); }
1184 PUBLIC static inline
1186 Cpu::set_es(Unsigned32 val)
1187 { asm volatile ("mov %0, %%es" : : "rm" (val)); }
1189 PUBLIC static inline
1191 Cpu::set_fs(Unsigned32 val)
1192 { asm volatile ("mov %0, %%fs" : : "rm" (val)); }
1195 //----------------------------------------------------------------------------
1196 IMPLEMENTATION[ia32, amd64]:
1198 #include "boot_info.h"
1202 #include "globals.h"
1203 #include "initcalls.h"
1206 #include "processor.h"
1207 #include "regdefs.h"
1211 PUBLIC static inline
1213 Cpu::set_cr0(unsigned long val)
1214 { asm volatile ("mov %0, %%cr0" : : "r" (val)); }
1216 PUBLIC static inline
1218 Cpu::set_pdbr(unsigned long addr)
1219 { asm volatile ("mov %0, %%cr3" : : "r" (addr)); }
1221 PUBLIC static inline
1223 Cpu::set_cr4(unsigned long val)
1224 { asm volatile ("mov %0, %%cr4" : : "r" (val)); }
1226 PUBLIC static inline
1228 Cpu::set_ldt(Unsigned16 val)
1229 { asm volatile ("lldt %0" : : "rm" (val)); }
1232 PUBLIC static inline
1234 Cpu::set_ss(Unsigned32 val)
1235 { asm volatile ("mov %0, %%ss" : : "r" (val)); }
1237 PUBLIC static inline
1239 Cpu::set_tr(Unsigned16 val)
1240 { asm volatile ("ltr %0" : : "rm" (val)); }
1242 PUBLIC static inline
1247 asm volatile ("mov %%cr0, %0" : "=r" (val));
1251 PUBLIC static inline
1254 { Address addr; asm volatile ("mov %%cr3, %0" : "=r" (addr)); return addr; }
1256 PUBLIC static inline
1259 { Mword val; asm volatile ("mov %%cr4, %0" : "=r" (val)); return val; }
1261 PUBLIC static inline
1264 { Unsigned16 val; asm volatile ("sldt %0" : "=rm" (val)); return val; }
1266 PUBLIC static inline
1269 { Unsigned16 val; asm volatile ("str %0" : "=rm" (val)); return val; }
1273 Cpu::can_wrmsr() const
1274 { return features() & FEAT_MSR; }
1276 PUBLIC static inline
1278 Cpu::rdmsr(Unsigned32 reg)
1282 asm volatile ("rdmsr" : "=a" (l), "=d" (h) : "c" (reg));
1283 return ((Unsigned64)h << 32) + (Unsigned64)l;
1286 PUBLIC static inline
1288 Cpu::rdpmc(Unsigned32 idx, Unsigned32)
1292 asm volatile ("rdpmc" : "=a" (l), "=d" (h) : "c" (idx));
1293 return ((Unsigned64)h << 32) + (Unsigned64)l;
1296 PUBLIC static inline
1298 Cpu::wrmsr(Unsigned32 low, Unsigned32 high, Unsigned32 reg)
1299 { asm volatile ("wrmsr" : : "a" (low), "d" (high), "c" (reg)); }
1301 PUBLIC static inline
1303 Cpu::wrmsr(Unsigned64 msr, Unsigned32 reg)
1304 { asm volatile ("wrmsr" : : "a" ((Unsigned32)msr), "d" ((Unsigned32)(msr >> 32)), "c" (reg)); }
1306 PUBLIC static inline
1309 { set_cr4(get_cr4() | CR4_PCE); }
1312 IMPLEMENT FIASCO_INIT_CPU
1314 Cpu::init_lbr_type()
1316 _lbr = Lbr_unsupported;
1321 if (vendor() == Vendor_intel)
1324 _lbr = model() < 3 ? Lbr_pentium_4 : Lbr_pentium_4_ext; // P4
1325 else if (family() >= 6)
1326 _lbr = Lbr_pentium_6; // PPro, PIII
1328 else if (vendor() == Vendor_amd)
1330 if ((family() == 6) || (family() == 15))
1331 _lbr = Lbr_pentium_6; // K7/K8
1337 IMPLEMENT FIASCO_INIT_CPU
1339 Cpu::init_bts_type()
1341 _bts = Bts_unsupported;
1343 if (can_wrmsr() && vendor() == Vendor_intel)
1345 if (family() == 15 && (rdmsr(0x1A0) & (1<<11)) == 0)
1346 _bts = Bts_pentium_4;
1347 if (family() == 6 && (model() == 9 || (model() >= 13 &&
1349 _bts = Bts_pentium_m;
1350 if (!(features() & FEAT_DS))
1351 _bts = Bts_unsupported;
1358 Cpu::lbr_enable(bool on)
1360 if (lbr_type() != Lbr_unsupported)
1366 debugctl_busy = true;
1372 debugctl_busy = lbr_active || bts_active;
1373 wrmsr(debugctl_reset, MSR_DEBUGCTLA);
1381 Cpu::btf_enable(bool on)
1383 if (lbr_type() != Lbr_unsupported)
1389 debugctl_reset |= 2; /* don't disable bit in kernel */
1390 wrmsr(2, MSR_DEBUGCTLA); /* activate _now_ */
1396 debugctl_busy = lbr_active || bts_active;
1397 wrmsr(debugctl_reset, MSR_DEBUGCTLA);
1405 Cpu::bts_enable(bool on)
1407 if (bts_type() != Bts_unsupported)
1413 case Bts_pentium_4: bts_active = true; debugctl_set |= 0x0c; break;
1414 case Bts_pentium_m: bts_active = true; debugctl_set |= 0xc0; break;
1417 debugctl_busy = lbr_active || bts_active;
1424 case Bts_pentium_4: debugctl_set &= ~0x0c; break;
1425 case Bts_pentium_m: debugctl_set &= ~0xc0; break;
1428 debugctl_busy = lbr_active || bts_active;
1429 wrmsr(debugctl_reset, MSR_DEBUGCTLA);
1436 Cpu::debugctl_enable()
1439 wrmsr(debugctl_set, MSR_DEBUGCTLA);
1444 Cpu::debugctl_disable()
1447 wrmsr(debugctl_reset, MSR_DEBUGCTLA);
1451 * AMD OS-Visible Workaround Information
1452 * print a warning if a CPU is affected by any known erratum
1458 if (vendor() == Vendor_amd && has_amd_osvw() && can_wrmsr())
1460 Unsigned16 osvw_id_length, i;
1461 bool affected = false;
1462 osvw_id_length = rdmsr(0xc0010140) & 0xff;
1464 for (i = 1; ((i - 1) * 64) < osvw_id_length; i++)
1466 Unsigned64 osvw_msr = rdmsr(0xc0010140 + i);
1469 printf("\033[31mOSVW_MSR%d = 0x%016llx\033[m\n",
1470 i, rdmsr(0xc0010140 + i));
1475 printf("\033[31m#Errata known %d, affected by at least one\033[m\n",
1480 IMPLEMENT FIASCO_INIT_CPU
1491 if (scaler_tsc_to_ns)
1492 _frequency = ns_to_tsc(1000000000UL);
1494 Unsigned32 cr4 = get_cr4();
1496 if (features() & FEAT_FXSR)
1499 if (features() & FEAT_SSE)
1500 cr4 |= CR4_OSXMMEXCPT;
1504 // reset time stamp counter (better for debugging)
1505 if ((features() & FEAT_TSC) && can_wrmsr())
1508 if ((features() & FEAT_PAT) && can_wrmsr())
1509 wrmsr(0x00010406, 0x00070406, 0x277);
1518 printf ("CPU[%u:%u]: %s (%X:%X:%X:%X) Model: %s at %llu MHz\n\n",
1519 id(), phys_id() >> 24,
1520 vendor_str(), family(), model(), stepping(), brand(), model_str(),
1521 div32(frequency(), 1000000));
1526 Cpu::set_sysenter(void (*func)(void))
1528 // Check for Sysenter/Sysexit Feature
1530 wrmsr ((Mword) func, 0, MSR_SYSENTER_EIP);
1536 Cpu::set_fast_entry(void (*func)(void))
1541 extern "C" void entry_sys_fast_ipc (void);
1542 extern "C" void entry_sys_fast_ipc_c (void);
1544 PUBLIC FIASCO_INIT_CPU
1546 Cpu::init_sysenter()
1548 // Check for Sysenter/Sysexit Feature
1551 wrmsr (Gdt::gdt_code_kernel, 0, MSR_SYSENTER_CS);
1552 wrmsr ((unsigned long)&kernel_sp(), 0, MSR_SYSENTER_ESP);
1553 if (Config::Assembler_ipc_shortcut)
1554 set_sysenter(entry_sys_fast_ipc);
1556 set_sysenter(entry_sys_fast_ipc_c);
1561 // Return 2^32 / (tsc clocks per usec)
1564 Cpu::calibrate_tsc ()
1566 const unsigned calibrate_time = 50000 /*us*/ + 1;
1569 if (! (features() & FEAT_TSC))
1572 Unsigned64 tsc_start, tsc_end;
1573 Unsigned32 count, tsc_to_ns_div, dummy;
1576 // disable interrupts
1577 Proc::Status o = Proc::cli_save();
1579 Pit::setup_channel2_to_20hz();
1581 tsc_start = rdtsc ();
1587 while ((Io::in8 (0x61) & 0x20) == 0);
1591 Proc::sti_restore(o);
1594 // Error: ECTCNEVERSET
1598 tsc_end -= tsc_start;
1600 // prevent overflow in division (CPU too fast)
1601 if (tsc_end & 0xffffffff00000000LL)
1604 // prevent overflow in division (CPU too slow)
1605 if ((tsc_end & 0xffffffffL) < calibrate_time)
1608 // tsc_to_ns_div = calibrate_time * 2^32 / tsc
1610 :"=a" (tsc_to_ns_div), "=d" (dummy)
1611 :"r" ((Unsigned32)tsc_end), "a" (0), "d" (calibrate_time));
1613 scaler_tsc_to_ns = muldiv (tsc_to_ns_div, 1000, 1<<5);
1614 scaler_tsc_to_us = tsc_to_ns_div;
1615 scaler_ns_to_tsc = muldiv (1<<31, ((Unsigned32)tsc_end),
1616 calibrate_time * 1000>>1 * 1<<5);
1621 if (Config::kinfo_timer_uses_rdtsc)
1622 panic("Can't calibrate tsc");
1627 Cpu::time_us() const
1629 return tsc_to_us (rdtsc());
1635 Cpu::enable_ldt(Address addr, int size)
1639 get_gdt()->clear_entry (Gdt::gdt_ldt / 8);
1644 get_gdt()->set_entry_byte(Gdt::gdt_ldt / 8, addr, size-1, 2/*=ldt*/, 0);
1645 set_ldt(Gdt::gdt_ldt);
1650 PUBLIC static inline
1653 { Unsigned32 val; asm volatile ("mov %%gs, %0" : "=rm" (val)); return val; }
1655 PUBLIC static inline
1657 Cpu::set_gs(Unsigned32 val)
1658 { asm volatile ("mov %0, %%gs" : : "rm" (val)); }
1662 Cpu::phys_id() const
1663 { return _brand & 0xff000000; }
1667 Cpu::phys_id_direct()
1670 cpuid (1, &a, &b, &c, &d);
1671 return b & 0xff000000;