1 INTERFACE[ia32,amd64,ux]:
6 #include "per_cpu_data.h"
52 Lf_rdpmc = 0x00000001,
53 Lf_rdpmc32 = 0x00000002,
56 Unsigned64 time_us() const;
57 int can_wrmsr() const;
61 Unsigned64 _frequency;
65 Unsigned32 _ext_features;
66 Unsigned32 _ext_8000_0001_ecx;
67 Unsigned32 _ext_8000_0001_edx;
68 Unsigned32 _local_features;
70 Unsigned16 _inst_tlb_4k_entries;
71 Unsigned16 _data_tlb_4k_entries;
72 Unsigned16 _inst_tlb_4m_entries;
73 Unsigned16 _data_tlb_4m_entries;
74 Unsigned16 _inst_tlb_4k_4m_entries;
75 Unsigned16 _data_tlb_4k_4m_entries;
76 Unsigned16 _l2_inst_tlb_4k_entries;
77 Unsigned16 _l2_data_tlb_4k_entries;
78 Unsigned16 _l2_inst_tlb_4m_entries;
79 Unsigned16 _l2_data_tlb_4m_entries;
81 Unsigned16 _l1_trace_cache_size;
82 Unsigned16 _l1_trace_cache_asso;
84 Unsigned16 _l1_data_cache_size;
85 Unsigned16 _l1_data_cache_asso;
86 Unsigned16 _l1_data_cache_line_size;
88 Unsigned16 _l1_inst_cache_size;
89 Unsigned16 _l1_inst_cache_asso;
90 Unsigned16 _l1_inst_cache_line_size;
92 Unsigned16 _l2_cache_size;
93 Unsigned16 _l2_cache_asso;
94 Unsigned16 _l2_cache_line_size;
96 Unsigned32 _l3_cache_size;
97 Unsigned16 _l3_cache_asso;
98 Unsigned16 _l3_cache_line_size;
100 Unsigned8 _phys_bits;
101 Unsigned8 _virt_bits;
106 Unsigned32 _arch_perfmon_info_eax;
107 Unsigned32 _arch_perfmon_info_ebx;
108 Unsigned32 _arch_perfmon_info_ecx;
110 Unsigned32 _monitor_mwait_eax;
111 Unsigned32 _monitor_mwait_ebx;
112 Unsigned32 _monitor_mwait_ecx;
113 Unsigned32 _monitor_mwait_edx;
115 Unsigned32 scaler_tsc_to_ns;
116 Unsigned32 scaler_tsc_to_us;
117 Unsigned32 scaler_ns_to_tsc;
121 void disable(unsigned cpu, char const *reason);
123 char const *model_str() const { return _model_str; }
124 Vendor vendor() const { return _vendor; }
126 unsigned family() const
127 { return (_version >> 8 & 0xf) + (_version >> 20 & 0xff); }
129 char const *vendor_str() const
130 { return _vendor == Vendor_unknown ? "Unknown" : vendor_ident[_vendor]; }
132 unsigned model() const
133 { return (_version >> 4 & 0xf) + (_version >> 12 & 0xf0); }
135 unsigned stepping() const { return _version & 0xF; }
136 unsigned type() const { return (_version >> 12) & 0x3; }
137 Unsigned64 frequency() const { return _frequency; }
138 unsigned brand() const { return _brand & 0xFF; }
139 unsigned features() const { return _features; }
140 unsigned ext_features() const { return _ext_features; }
141 bool has_monitor_mwait() const { return _ext_features & (1 << 3); }
142 bool has_monitor_mwait_irq() const { return _monitor_mwait_ecx & 3; }
143 unsigned ext_8000_0001_ecx() const { return _ext_8000_0001_ecx; }
144 unsigned ext_8000_0001_edx() const { return _ext_8000_0001_edx; }
145 unsigned local_features() const { return _local_features; }
146 bool superpages() const { return features() & FEAT_PSE; }
147 bool tsc() const { return features() & FEAT_TSC; }
148 bool sysenter() const { return features() & FEAT_SEP; }
149 bool syscall() const { return ext_8000_0001_edx() & FEATA_SYSCALL; }
150 bool vmx() { return boot_cpu()->ext_features() & FEATX_VMX; }
151 bool svm() { return boot_cpu()->ext_8000_0001_ecx() & FEATA_SVM; }
152 bool has_amd_osvw() { return boot_cpu()->ext_8000_0001_ecx() & (1<<9); }
153 unsigned virt_bits() const { return _virt_bits; }
154 unsigned phys_bits() const { return _phys_bits; }
155 Unsigned32 get_scaler_tsc_to_ns() const { return scaler_tsc_to_ns; }
156 Unsigned32 get_scaler_tsc_to_us() const { return scaler_tsc_to_us; }
157 Unsigned32 get_scaler_ns_to_tsc() const { return scaler_ns_to_tsc; }
159 Address volatile &kernel_sp() const;
162 static Per_cpu<Cpu> cpus asm ("CPUS_BASE");
163 static Cpu *boot_cpu() { return _boot_cpu; }
165 static bool have_superpages() { return boot_cpu()->superpages(); }
166 static bool have_sysenter() { return boot_cpu()->sysenter(); }
167 static bool have_syscall() { return boot_cpu()->syscall(); }
168 static bool have_fxsr() { return boot_cpu()->features() & FEAT_FXSR; }
169 static bool have_pge() { return boot_cpu()->features() & FEAT_PGE; }
173 static Cpu *_boot_cpu;
175 struct Vendor_table {
176 Unsigned32 vendor_mask;
177 Unsigned32 vendor_code;
179 char vendor_string[32];
180 } __attribute__((packed));
190 static Vendor_table const intel_table[];
191 static Vendor_table const amd_table[];
192 static Vendor_table const cyrix_table[];
193 static Vendor_table const via_table[];
194 static Vendor_table const umc_table[];
195 static Vendor_table const nexgen_table[];
196 static Vendor_table const rise_table[];
197 static Vendor_table const transmeta_table[];
198 static Vendor_table const sis_table[];
199 static Vendor_table const nsc_table[];
201 static Cache_table const intel_cache_table[];
203 static char const * const vendor_ident[];
204 static Vendor_table const * const vendor_table[];
206 static char const * const exception_strings[];
210 //-----------------------------------------------------------------------------
213 * Architecture specific cpu init code
215 INTERFACE [ia32, amd64]:
217 #include "l4_types.h"
218 #include "initcalls.h"
219 #include "per_cpu_data.h"
231 Lbr_uninitialized = 0,
240 Bts_uninitialized = 0,
247 /** Flags if lbr or bts facilities are activated, used by double-fault
248 * handler to reset the debugging facilities
250 Unsigned32 debugctl_busy;
252 /** debugctl value for activating lbr or bts */
253 Unsigned32 debugctl_set;
255 /** debugctl value to reset activated lr/bts facilities in the double-faukt
258 Unsigned32 debugctl_reset;
260 /** supported lbr type */
263 /** supported bts type */
266 /** is lbr active ? */
269 /** is btf active ? */
272 /** is bts active ? */
280 Lbr lbr_type() const { return _lbr; }
281 Bts bts_type() const { return _bts; }
282 bool lbr_status() const { return lbr_active; }
283 bool bts_status() const { return bts_active; }
284 bool btf_status() const { return btf_active; }
286 Gdt* get_gdt() const { return gdt; }
287 Tss* get_tss() const { return tss; }
290 Pseudo_descriptor desc((Address)gdt, Gdt::gdt_max-1);
294 static void set_tss() { set_tr(Gdt::gdt_tss); }
297 void init_lbr_type();
298 void init_bts_type();
302 //-----------------------------------------------------------------------------
303 IMPLEMENTATION[ia32,amd64,ux]:
309 #include "processor.h"
311 Per_cpu<Cpu> DEFINE_PER_CPU_P(0) Cpu::cpus(true);
315 Cpu::Vendor_table const Cpu::intel_table[] FIASCO_INITDATA_CPU =
317 { 0xf0fF0, 0x00400, 0xFFFF, "i486 DX-25/33" },
318 { 0xf0fF0, 0x00410, 0xFFFF, "i486 DX-50" },
319 { 0xf0fF0, 0x00420, 0xFFFF, "i486 SX" },
320 { 0xf0fF0, 0x00430, 0xFFFF, "i486 DX/2" },
321 { 0xf0fF0, 0x00440, 0xFFFF, "i486 SL" },
322 { 0xf0fF0, 0x00450, 0xFFFF, "i486 SX/2" },
323 { 0xf0fF0, 0x00470, 0xFFFF, "i486 DX/2-WB" },
324 { 0xf0fF0, 0x00480, 0xFFFF, "i486 DX/4" },
325 { 0xf0fF0, 0x00490, 0xFFFF, "i486 DX/4-WB" },
326 { 0xf0fF0, 0x00500, 0xFFFF, "Pentium A-Step" },
327 { 0xf0fF0, 0x00510, 0xFFFF, "Pentium P5" },
328 { 0xf0fF0, 0x00520, 0xFFFF, "Pentium P54C" },
329 { 0xf0fF0, 0x00530, 0xFFFF, "Pentium P24T Overdrive" },
330 { 0xf0fF0, 0x00540, 0xFFFF, "Pentium P55C MMX" },
331 { 0xf0fF0, 0x00570, 0xFFFF, "Pentium Mobile" },
332 { 0xf0fF0, 0x00580, 0xFFFF, "Pentium MMX Mobile (Tillamook)" },
333 { 0xf0fF0, 0x00600, 0xFFFF, "Pentium-Pro A-Step" },
334 { 0xf0fF0, 0x00610, 0xFFFF, "Pentium-Pro" },
335 { 0xf0fF0, 0x00630, 512, "Pentium II (Klamath)" },
336 { 0xf0fF0, 0x00640, 512, "Pentium II (Deschutes)" },
337 { 0xf0fF0, 0x00650, 1024, "Pentium II (Drake)" },
338 { 0xf0fF0, 0x00650, 512, "Pentium II (Deschutes)" },
339 { 0xf0fF0, 0x00650, 256, "Pentium II Mobile (Dixon)" },
340 { 0xf0fF0, 0x00650, 0, "Celeron (Covington)" },
341 { 0xf0fF0, 0x00660, 128, "Celeron (Mendocino)" },
342 { 0xf0fF0, 0x00670, 1024, "Pentium III (Tanner)" },
343 { 0xf0fF0, 0x00670, 512, "Pentium III (Katmai)" },
344 { 0xf0fF0, 0x00680, 256, "Pentium III (Coppermine)" },
345 { 0xf0fF0, 0x00680, 128, "Celeron (Coppermine)" },
346 { 0xf0fF0, 0x00690, 1024, "Pentium-M (Banias)" },
347 { 0xf0fF0, 0x00690, 512, "Celeron-M (Banias)" },
348 { 0xf0fF0, 0x006a0, 1024, "Pentium III (Cascades)" },
349 { 0xf0fF0, 0x006b0, 512, "Pentium III-S" },
350 { 0xf0fF0, 0x006b0, 256, "Pentium III (Tualatin)" },
351 { 0xf0fF0, 0x006d0, 2048, "Pentium-M (Dothan)" },
352 { 0xf0fF0, 0x006d0, 1024, "Celeron-M (Dothan)" },
353 { 0xf0fF0, 0x006e0, 2048, "Core (Yonah)" },
354 { 0xf0fF0, 0x006f0, 2048, "Core 2 (Merom)" },
355 { 0xf0f00, 0x00700, 0xFFFF, "Itanium (Merced)" },
356 { 0xf0fF0, 0x00f00, 256, "Pentium 4 (Willamette/Foster)" },
357 { 0xf0fF0, 0x00f10, 256, "Pentium 4 (Willamette/Foster)" },
358 { 0xf0fF0, 0x00f10, 128, "Celeron (Willamette)" },
359 { 0xf0fF0, 0x00f20, 512, "Pentium 4 (Northwood/Prestonia)" },
360 { 0xf0fF0, 0x00f20, 128, "Celeron (Northwood)" },
361 { 0xf0fF0, 0x00f30, 1024, "Pentium 4E (Prescott/Nocona)" },
362 { 0xf0fF0, 0x00f30, 256, "Celeron D (Prescott)" },
363 { 0xf0fF4, 0x00f40, 1024, "Pentium 4E (Prescott/Nocona)" },
364 { 0xf0fF4, 0x00f44, 1024, "Pentium D (Smithfield)" },
365 { 0xf0fF0, 0x00f40, 256, "Celeron D (Prescott)" },
366 { 0xf0fF0, 0x00f60, 2048, "Pentium D (Cedarmill/Presler)" },
367 { 0xf0fF0, 0x00f60, 512, "Celeron D (Cedarmill)" },
368 { 0xf0ff0, 0x10600, 0, "Celeron, 65nm" },
369 { 0xf0ff0, 0x10670, 2048, "Core2 / Xeon (Wolfdale), 45nm" },
370 { 0xf0ff0, 0x106a0, 0xffff, "Core i7 / Xeon, 45nm" },
371 { 0xf0ff0, 0x106b0, 0xffff, "Xeon MP, 45nm" },
372 { 0xf0ff0, 0x106c0, 0xffff, "Atom" },
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)" },
431 Cpu::Vendor_table const Cpu::cyrix_table[] FIASCO_INITDATA_CPU =
433 { 0xFF0, 0x440, 0xFFFF, "Gx86 (Media GX)" },
434 { 0xFF0, 0x490, 0xFFFF, "5x86" },
435 { 0xFF0, 0x520, 0xFFFF, "6x86 (M1)" },
436 { 0xFF0, 0x540, 0xFFFF, "GXm" },
437 { 0xFF0, 0x600, 0xFFFF, "6x86MX (M2)" },
438 { 0x0, 0x0, 0xFFFF, "" }
441 Cpu::Vendor_table const Cpu::via_table[] FIASCO_INITDATA_CPU =
443 { 0xFF0, 0x540, 0xFFFF, "IDT Winchip C6" },
444 { 0xFF0, 0x580, 0xFFFF, "IDT Winchip 2A/B" },
445 { 0xFF0, 0x590, 0xFFFF, "IDT Winchip 3" },
446 { 0xFF0, 0x650, 0xFFFF, "Via Jalapeno (Joshua)" },
447 { 0xFF0, 0x660, 0xFFFF, "Via C5A (Samuel)" },
448 { 0xFF8, 0x670, 0xFFFF, "Via C5B (Samuel 2)" },
449 { 0xFF8, 0x678, 0xFFFF, "Via C5C (Ezra)" },
450 { 0xFF0, 0x680, 0xFFFF, "Via C5N (Ezra-T)" },
451 { 0xFF0, 0x690, 0xFFFF, "Via C5P (Nehemiah)" },
452 { 0xFF0, 0x6a0, 0xFFFF, "Via C5J (Esther)" },
453 { 0x0, 0x0, 0xFFFF, "" }
456 Cpu::Vendor_table const Cpu::umc_table[] FIASCO_INITDATA_CPU =
458 { 0xFF0, 0x410, 0xFFFF, "U5D" },
459 { 0xFF0, 0x420, 0xFFFF, "U5S" },
460 { 0x0, 0x0, 0xFFFF, "" }
463 Cpu::Vendor_table const Cpu::nexgen_table[] FIASCO_INITDATA_CPU =
465 { 0xFF0, 0x500, 0xFFFF, "Nx586" },
466 { 0x0, 0x0, 0xFFFF, "" }
469 Cpu::Vendor_table const Cpu::rise_table[] FIASCO_INITDATA_CPU =
471 { 0xFF0, 0x500, 0xFFFF, "mP6 (iDragon)" },
472 { 0xFF0, 0x520, 0xFFFF, "mP6 (iDragon)" },
473 { 0xFF0, 0x580, 0xFFFF, "mP6 (iDragon II)" },
474 { 0xFF0, 0x590, 0xFFFF, "mP6 (iDragon II)" },
475 { 0x0, 0x0, 0xFFFF, "" }
478 Cpu::Vendor_table const Cpu::transmeta_table[] FIASCO_INITDATA_CPU =
480 { 0xFFF, 0x542, 0xFFFF, "TM3x00 (Crusoe)" },
481 { 0xFFF, 0x543, 0xFFFF, "TM5x00 (Crusoe)" },
482 { 0xFF0, 0xf20, 0xFFFF, "TM8x00 (Efficeon)" },
483 { 0x0, 0x0, 0xFFFF, "" }
486 Cpu::Vendor_table const Cpu::sis_table[] FIASCO_INITDATA_CPU =
488 { 0xFF0, 0x500, 0xFFFF, "55x" },
489 { 0x0, 0x0, 0xFFFF, "" }
492 Cpu::Vendor_table const Cpu::nsc_table[] FIASCO_INITDATA_CPU =
494 { 0xFF0, 0x540, 0xFFFF, "Geode GX1" },
495 { 0xFF0, 0x550, 0xFFFF, "Geode GX2" },
496 { 0xFF0, 0x680, 0xFFFF, "Geode NX" },
497 { 0x0, 0x0, 0xFFFF, "" }
500 Cpu::Cache_table const Cpu::intel_cache_table[] FIASCO_INITDATA_CPU =
502 { 0x01, Tlb_inst_4k, 32, 4, 0 },
503 { 0x02, Tlb_inst_4M, 2, 4, 0 },
504 { 0x03, Tlb_data_4k, 64, 4, 0 },
505 { 0x04, Tlb_data_4M, 8, 4, 0 },
506 { 0x05, Tlb_data_4M, 32, 4, 0 },
507 { 0x06, Cache_l1_inst, 8, 4, 32 },
508 { 0x08, Cache_l1_inst, 16, 4, 32 },
509 { 0x09, Cache_l1_inst, 32, 4, 64 },
510 { 0x0A, Cache_l1_data, 8, 2, 32 },
511 { 0x0B, Tlb_inst_4M, 4, 4, 0 },
512 { 0x0C, Cache_l1_data, 16, 4, 32 },
513 { 0x0D, Cache_l1_data, 16, 4, 64 },
514 { 0x0E, Cache_l1_data, 24, 6, 64 },
515 { 0x21, Cache_l2, 256, 8, 64 },
516 { 0x22, Cache_l3, 512, 4, 64 }, /* sectored */
517 { 0x23, Cache_l3, 1024, 8, 64 }, /* sectored */
518 { 0x25, Cache_l3, 2048, 8, 64 }, /* sectored */
519 { 0x29, Cache_l3, 4096, 8, 64 }, /* sectored */
520 { 0x2C, Cache_l1_data, 32, 8, 64 },
521 { 0x30, Cache_l1_inst, 32, 8, 64 },
522 { 0x39, Cache_l2, 128, 4, 64 }, /* sectored */
523 { 0x3B, Cache_l2, 128, 2, 64 }, /* sectored */
524 { 0x3C, Cache_l2, 256, 4, 64 }, /* sectored */
525 { 0x41, Cache_l2, 128, 4, 32 },
526 { 0x42, Cache_l2, 256, 4, 32 },
527 { 0x43, Cache_l2, 512, 4, 32 },
528 { 0x44, Cache_l2, 1024, 4, 32 },
529 { 0x45, Cache_l2, 2048, 4, 32 },
530 { 0x46, Cache_l3, 4096, 4, 64 },
531 { 0x47, Cache_l3, 8192, 8, 64 },
532 { 0x48, Cache_l2, 3072, 12, 64 },
533 { 0x49, Cache_l2, 4096, 16, 64 },
534 { 0x4A, Cache_l3, 6144, 12, 64 },
535 { 0x4B, Cache_l3, 8192, 16, 64 },
536 { 0x4C, Cache_l3, 12288, 12, 64 },
537 { 0x4D, Cache_l3, 16384, 16, 64 },
538 { 0x4E, Cache_l3, 6144, 24, 64 },
539 { 0x4F, Tlb_inst_4k, 32, 0, 0 },
540 { 0x50, Tlb_inst_4k_4M, 64, 0, 0 },
541 { 0x51, Tlb_inst_4k_4M, 128, 0, 0 },
542 { 0x52, Tlb_inst_4k_4M, 256, 0, 0 },
543 { 0x56, Tlb_data_4M, 16, 4, 0 },
544 { 0x57, Tlb_data_4k, 16, 4, 0 },
545 { 0x59, Tlb_data_4k, 16, 0, 0 },
546 { 0x5A, Tlb_data_2M_4M, 32, 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 { 0x80, Cache_l2, 512, 16, 64 },
567 { 0x82, Cache_l2, 256, 8, 32 },
568 { 0x83, Cache_l2, 512, 8, 32 },
569 { 0x84, Cache_l2, 1024, 8, 32 },
570 { 0x85, Cache_l2, 2048, 8, 32 },
571 { 0x86, Cache_l2, 512, 4, 64 },
572 { 0x87, Cache_l2, 1024, 8, 64 },
573 { 0x8D, Cache_l3, 3072, 12, 128 },
574 { 0xB0, Tlb_inst_4k, 128, 4, 0 },
575 { 0xB3, Tlb_data_4k, 128, 4, 0 },
576 { 0xB4, Tlb_data_4k, 256, 4, 0 },
577 { 0xBA, Tlb_data_4k, 64, 4, 0 },
578 { 0xC0, Tlb_data_4k_4M, 8, 4, 0 },
579 { 0xCA, Tlb_data_4k_4M, 512, 4, 0 },
580 { 0xD0, Cache_l3, 512, 4, 64 },
581 { 0xD1, Cache_l3, 1024, 4, 64 },
582 { 0xD2, Cache_l3, 2048, 4, 64 },
583 { 0xD6, Cache_l3, 1024, 8, 64 },
584 { 0xD7, Cache_l3, 2048, 8, 64 },
585 { 0xD8, Cache_l3, 4096, 8, 64 },
586 { 0xDC, Cache_l3, 1536, 12, 64 },
587 { 0xDD, Cache_l3, 3072, 12, 64 },
588 { 0xDE, Cache_l3, 6144, 12, 64 },
589 { 0xE2, Cache_l3, 2048, 16, 64 },
590 { 0xE3, Cache_l3, 4096, 16, 64 },
591 { 0xE4, Cache_l3, 8192, 16, 64 },
592 { 0xEA, Cache_l3, 12288, 24, 64 },
593 { 0xEB, Cache_l3, 18432, 24, 64 },
594 { 0xEC, Cache_l3, 24576, 24, 64 },
595 { 0x0, Cache_unknown, 0, 0, 0 }
598 char const * const Cpu::vendor_ident[] =
613 Cpu::Vendor_table const * const Cpu::vendor_table[] =
628 char const * const Cpu::exception_strings[] =
630 /* 0 */ "Divide Error",
632 /* 2 */ "NMI Interrupt",
633 /* 3 */ "Breakpoint",
635 /* 5 */ "BOUND Range Exceeded",
636 /* 6 */ "Invalid Opcode",
637 /* 7 */ "Device Not Available",
638 /* 8 */ "Double Fault",
639 /* 9 */ "CoProcessor Segment Overrrun",
640 /* 10 */ "Invalid TSS",
641 /* 11 */ "Segment Not Present",
642 /* 12 */ "Stack Segment Fault",
643 /* 13 */ "General Protection",
644 /* 14 */ "Page Fault",
646 /* 16 */ "Floating-Point Error",
647 /* 17 */ "Alignment Check",
648 /* 18 */ "Machine Check",
649 /* 19 */ "SIMD Floating-Point Exception",
664 PUBLIC explicit FIASCO_INIT_CPU
665 Cpu::Cpu(unsigned cpu)
680 Cpu::init_global_features()
685 Cpu::exception_string(Mword trapno)
688 return "Maskable Interrupt";
689 return exception_strings[trapno];
692 PUBLIC static inline FIASCO_INIT_CPU
694 Cpu::cpuid(Unsigned32 const mode,
695 Unsigned32 *const eax, Unsigned32 *const ebx,
696 Unsigned32 *const ecx, Unsigned32 *const edx)
698 asm volatile ("cpuid" : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
704 PRIVATE FIASCO_INIT_CPU
706 Cpu::cache_tlb_intel()
709 unsigned i, count = 0;
710 Cache_table const *table;
714 cpuid(2, (Unsigned32 *)(desc),
715 (Unsigned32 *)(desc + 4),
716 (Unsigned32 *)(desc + 8),
717 (Unsigned32 *)(desc + 12));
719 for (i = 1; i < 16; i++)
721 // Null descriptor or register bit31 set (reserved)
722 if (!desc[i] || (desc[i / 4 * 4 + 3] & (1 << 7)))
725 for (table = intel_cache_table; table->desc; table++)
727 if (table->desc == desc[i])
729 switch (table->level)
732 _l1_data_cache_size = table->size;
733 _l1_data_cache_asso = table->asso;
734 _l1_data_cache_line_size = table->line_size;
737 _l1_inst_cache_size = table->size;
738 _l1_inst_cache_asso = table->asso;
739 _l1_inst_cache_line_size = table->line_size;
742 _l1_trace_cache_size = table->size;
743 _l1_trace_cache_asso = table->asso;
746 _l2_cache_size = table->size;
747 _l2_cache_asso = table->asso;
748 _l2_cache_line_size = table->line_size;
751 _l3_cache_size = table->size;
752 _l3_cache_asso = table->asso;
753 _l3_cache_line_size = table->line_size;
756 _inst_tlb_4k_entries += table->size;
759 _data_tlb_4k_entries += table->size;
762 _inst_tlb_4m_entries += table->size;
765 _data_tlb_4m_entries += table->size;
768 _inst_tlb_4k_4m_entries += table->size;
771 _data_tlb_4k_4m_entries += table->size;
781 while (++count < *desc);
784 PRIVATE FIASCO_INIT_CPU
788 Unsigned32 eax, ebx, ecx, edx;
789 cpuid(0x80000005, &eax, &ebx, &ecx, &edx);
791 _l1_data_cache_size = (ecx >> 24) & 0xFF;
792 _l1_data_cache_asso = (ecx >> 16) & 0xFF;
793 _l1_data_cache_line_size = ecx & 0xFF;
795 _l1_inst_cache_size = (edx >> 24) & 0xFF;
796 _l1_inst_cache_asso = (edx >> 16) & 0xFF;
797 _l1_inst_cache_line_size = edx & 0xFF;
799 _data_tlb_4k_entries = (ebx >> 16) & 0xFF;
800 _inst_tlb_4k_entries = ebx & 0xFF;
801 _data_tlb_4m_entries = (eax >> 16) & 0xFF;
802 _inst_tlb_4m_entries = eax & 0xFF;
805 PRIVATE FIASCO_INIT_CPU
807 Cpu::cache_tlb_l2_l3()
809 Unsigned32 eax, ebx, ecx, edx;
810 cpuid(0x80000006, &eax, &ebx, &ecx, &edx);
812 if (vendor() == Vendor_via)
814 _l2_cache_size = (ecx >> 24) & 0xFF;
815 _l2_cache_asso = (ecx >> 16) & 0xFF;
819 _l2_data_tlb_4m_entries = (eax >> 16) & 0xFFF;
820 _l2_inst_tlb_4m_entries = eax & 0xFFF;
821 _l2_data_tlb_4k_entries = (ebx >> 16) & 0xFFF;
822 _l2_inst_tlb_4k_entries = ebx & 0xFFF;
823 _l2_cache_size = (ecx >> 16) & 0xFFFF;
824 _l2_cache_asso = (ecx >> 12) & 0xF;
827 _l2_cache_line_size = ecx & 0xFF;
829 _l3_cache_size = (edx >> 18) << 9;
830 _l3_cache_asso = (edx >> 12) & 0xF;
831 _l3_cache_line_size = edx & 0xFF;
834 PRIVATE FIASCO_INIT_CPU
836 Cpu::addr_size_info()
838 Unsigned32 eax, ebx, ecx, edx;
839 cpuid(0x80000008, &eax, &ebx, &ecx, &edx);
841 _phys_bits = eax & 0xff;
842 _virt_bits = (eax & 0xff00) >> 8;
849 Unsigned32 eax, ebx, ecx, edx;
850 cpuid(0x80000008, &eax, &ebx, &ecx, &edx);
852 unsigned apicidcoreidsize = (ecx >> 12) & 0xf;
853 if (apicidcoreidsize == 0)
854 return (ecx & 0xf) + 1; // NC
855 return 1 << apicidcoreidsize;
858 PRIVATE FIASCO_INIT_CPU
862 Vendor_table const *table;
867 for (table = vendor_table[vendor()]; table && table->vendor_mask; table++)
868 if ((_version & table->vendor_mask) == table->vendor_code &&
869 (table->l2_cache == 0xFFFF || _l2_cache_size >= table->l2_cache))
871 snprintf(_model_str, sizeof (_model_str), "%s",
872 table->vendor_string);
876 snprintf(_model_str, sizeof (_model_str), "Unknown CPU");
879 PUBLIC inline FIASCO_INIT_CPU
881 Cpu::arch_perfmon_info(Unsigned32 *eax, Unsigned32 *ebx, Unsigned32 *ecx) const
883 *eax = _arch_perfmon_info_eax;
884 *ebx = _arch_perfmon_info_ebx;
885 *ecx = _arch_perfmon_info_ecx;
892 Unsigned32 eflags = get_flags();
893 // Check for Alignment Check Support
894 set_flags(eflags ^ EFLAGS_AC);
895 if (((get_flags() ^ eflags) & EFLAGS_AC) == 0)
898 // Check for CPUID Support
899 set_flags(eflags ^ EFLAGS_ID);
900 if (!((get_flags() ^ eflags) & EFLAGS_ID))
906 cpuid(0, &max, (Unsigned32 *)(vendor_id),
907 (Unsigned32 *)(vendor_id + 8),
908 (Unsigned32 *)(vendor_id + 4));
913 Unsigned32 dummy, dummy1, dummy2, features;
914 cpuid (1, &dummy, &dummy1, &dummy2, &features);
920 /** Identify the CPU features.
921 Attention: This function may be called more than once. The reason is
922 that enabling a Local APIC that was previously disabled by the BIOS
923 may change the processor features. Therefore, this function has to
924 be called again after the Local APIC was enabled.
926 PUBLIC FIASCO_INIT_CPU
930 Unsigned32 eflags = get_flags();
935 // Reset members in case we get called more than once
936 _inst_tlb_4k_entries =
937 _data_tlb_4k_entries =
938 _inst_tlb_4m_entries =
939 _data_tlb_4m_entries =
940 _inst_tlb_4k_4m_entries =
941 _data_tlb_4k_4m_entries = 0;
943 // Check for Alignment Check Support
944 set_flags(eflags ^ EFLAGS_AC);
945 if (((get_flags() ^ eflags) & EFLAGS_AC) == 0)
946 panic("CPU too old");
948 // Check for CPUID Support
949 set_flags(eflags ^ EFLAGS_ID);
950 if ((get_flags() ^ eflags) & EFLAGS_ID) {
955 cpuid(0, &max, (Unsigned32 *)(vendor_id),
956 (Unsigned32 *)(vendor_id + 8),
957 (Unsigned32 *)(vendor_id + 4));
959 for (i = sizeof (vendor_ident) / sizeof (*vendor_ident) - 1; i; i--)
960 if (!memcmp(vendor_id, vendor_ident[i], 12))
963 _vendor = (Cpu::Vendor)i;
968 // All cases fall through!
970 cpuid(10, &_arch_perfmon_info_eax,
971 &_arch_perfmon_info_ebx,
972 &_arch_perfmon_info_ecx, &i);
974 if (_vendor == Vendor_intel)
977 cpuid(1, &_version, &_brand, &_ext_features, &_features);
980 if (max >= 5 && has_monitor_mwait())
981 cpuid(5, &_monitor_mwait_eax, &_monitor_mwait_ebx,
982 &_monitor_mwait_ecx, &_monitor_mwait_edx);
984 if (_vendor == Vendor_intel)
989 // Avoid Pentium Erratum 74
990 if ((_features & FEAT_MMX) &&
992 (stepping() != 4 && (stepping() != 3 || type() != 1))))
993 _local_features |= Lf_rdpmc;
996 // Avoid Pentium Pro Erratum 26
997 if (model() >= 3 || stepping() > 9)
998 _local_features |= Lf_rdpmc;
1001 _local_features |= Lf_rdpmc;
1002 _local_features |= Lf_rdpmc32;
1006 else if (_vendor == Vendor_amd)
1012 _local_features |= Lf_rdpmc;
1017 // Get maximum number for extended functions
1018 cpuid(0x80000000, &max, &i, &i, &i);
1020 if (max > 0x80000000)
1025 // All cases fall through!
1027 if (_vendor == Vendor_amd || _vendor == Vendor_intel)
1031 if (_vendor == Vendor_amd || _vendor == Vendor_via)
1034 if (_vendor == Vendor_amd || _vendor == Vendor_via)
1038 Unsigned32 *s = (Unsigned32 *)_model_str;
1039 for (unsigned i = 0; i < 3; ++i)
1040 cpuid(0x80000002 + i, &s[0 + 4*i], &s[1 + 4*i],
1041 &s[2 + 4*i], &s[3 + 4*i]);
1047 if (_vendor == Vendor_intel || _vendor == Vendor_amd)
1048 cpuid(0x80000001, &i, &i, &_ext_8000_0001_ecx,
1049 &_ext_8000_0001_edx);
1054 // see Intel Spec on SYSENTER:
1055 // Some Pentium Pro pretend to have it, but actually lack it
1056 if ((_version & 0xFFF) < 0x633)
1057 _features &= ~FEAT_SEP;
1067 PUBLIC inline NEEDS["processor.h"]
1069 Cpu::busy_wait_ns(Unsigned64 ns)
1071 Unsigned64 stop = rdtsc () + ns_to_tsc(ns);
1073 while (rdtsc() < stop)
1080 Cpu::show_cache_tlb_info(const char *indent) const
1085 if (_l2_inst_tlb_4k_entries)
1086 snprintf(s, sizeof(s), "/%u", _l2_inst_tlb_4k_entries);
1087 if (_inst_tlb_4k_entries)
1088 printf("%s%4u%s Entry I TLB (4K pages)", indent, _inst_tlb_4k_entries, s);
1090 if (_l2_inst_tlb_4m_entries)
1091 snprintf(s, sizeof(s), "/%u", _l2_inst_tlb_4k_entries);
1092 if (_inst_tlb_4m_entries)
1093 printf(" %4u%s Entry I TLB (4M pages)", _inst_tlb_4m_entries, s);
1094 if (_inst_tlb_4k_4m_entries)
1095 printf("%s%4u Entry I TLB (4K or 4M pages)",
1096 indent, _inst_tlb_4k_4m_entries);
1097 if (_inst_tlb_4k_entries || _inst_tlb_4m_entries || _inst_tlb_4k_4m_entries)
1100 if (_l2_data_tlb_4k_entries)
1101 snprintf(s, sizeof(s), "/%u", _l2_data_tlb_4k_entries);
1102 if (_data_tlb_4k_entries)
1103 printf("%s%4u%s Entry D TLB (4K pages)", indent, _data_tlb_4k_entries, s);
1105 if (_l2_data_tlb_4m_entries)
1106 snprintf(s, sizeof(s), "/%u", _l2_data_tlb_4m_entries);
1107 if (_data_tlb_4m_entries)
1108 printf(" %4u%s Entry D TLB (4M pages)", _data_tlb_4m_entries, s);
1109 if (_data_tlb_4k_4m_entries)
1110 printf("%s%4u Entry D TLB (4k or 4M pages)",
1111 indent, _data_tlb_4k_4m_entries);
1112 if (_data_tlb_4k_entries || _data_tlb_4m_entries || _data_tlb_4k_4m_entries)
1115 if (_l1_trace_cache_size)
1116 printf("%s%3uK %c-ops T Cache (%u-way associative)\n",
1117 indent, _l1_trace_cache_size, Config::char_micro,
1118 _l1_trace_cache_asso);
1120 else if (_l1_inst_cache_size)
1121 printf("%s%4u KB L1 I Cache (%u-way associative, %u bytes per line)\n",
1122 indent, _l1_inst_cache_size, _l1_inst_cache_asso,
1123 _l1_inst_cache_line_size);
1125 if (_l1_data_cache_size)
1126 printf("%s%4u KB L1 D Cache (%u-way associative, %u bytes per line)\n"
1127 "%s%4u KB L2 U Cache (%u-way associative, %u bytes per line)\n",
1128 indent, _l1_data_cache_size, _l1_data_cache_asso,
1129 _l1_data_cache_line_size,
1130 indent, _l2_cache_size, _l2_cache_asso, _l2_cache_line_size);
1133 printf("%s%4u KB L3 U Cache (%u-way associative, %u bytes per line)\n",
1134 indent, _l3_cache_size, _l3_cache_asso, _l3_cache_line_size);
1139 Cpu::disable(unsigned cpu, char const *reason)
1141 printf("CPU%u: is disabled: %s\n", cpu, reason);
1144 // Function used for calculating apic scaler
1145 PUBLIC static inline
1147 Cpu::muldiv(Unsigned32 val, Unsigned32 mul, Unsigned32 div)
1151 asm volatile ("mull %3 ; divl %4\n\t"
1152 :"=a" (val), "=d" (dummy)
1153 : "0" (val), "d" (mul), "c" (div));
1158 PUBLIC static inline
1163 asm volatile ("mov %%cs, %0" : "=rm" (val));
1167 PUBLIC static inline
1172 asm volatile ("mov %%ds, %0" : "=rm" (val));
1176 PUBLIC static inline
1181 asm volatile ("mov %%es, %0" : "=rm" (val));
1185 PUBLIC static inline
1190 asm volatile ("mov %%ss, %0" : "=rm" (val));
1194 PUBLIC static inline
1196 Cpu::set_ds(Unsigned32 val)
1197 { asm volatile ("mov %0, %%ds" : : "rm" (val)); }
1199 PUBLIC static inline
1201 Cpu::set_es(Unsigned32 val)
1202 { asm volatile ("mov %0, %%es" : : "rm" (val)); }
1204 //----------------------------------------------------------------------------
1205 IMPLEMENTATION[ia32, amd64]:
1207 #include "boot_info.h"
1211 #include "globals.h"
1212 #include "initcalls.h"
1215 #include "processor.h"
1216 #include "regdefs.h"
1220 PUBLIC static inline
1222 Cpu::set_cr0(unsigned long val)
1223 { asm volatile ("mov %0, %%cr0" : : "r" (val)); }
1225 PUBLIC static inline
1227 Cpu::set_pdbr(unsigned long addr)
1228 { asm volatile ("mov %0, %%cr3" : : "r" (addr)); }
1230 PUBLIC static inline
1232 Cpu::set_cr4(unsigned long val)
1233 { asm volatile ("mov %0, %%cr4" : : "r" (val)); }
1235 PUBLIC static inline
1237 Cpu::set_ldt(Unsigned16 val)
1238 { asm volatile ("lldt %0" : : "rm" (val)); }
1241 PUBLIC static inline
1243 Cpu::set_ss(Unsigned32 val)
1244 { asm volatile ("mov %0, %%ss" : : "r" (val)); }
1246 PUBLIC static inline
1248 Cpu::set_tr(Unsigned16 val)
1249 { asm volatile ("ltr %0" : : "rm" (val)); }
1251 PUBLIC static inline
1256 asm volatile ("mov %%cr0, %0" : "=r" (val));
1260 PUBLIC static inline
1263 { Address addr; asm volatile ("mov %%cr3, %0" : "=r" (addr)); return addr; }
1265 PUBLIC static inline
1268 { Mword val; asm volatile ("mov %%cr4, %0" : "=r" (val)); return val; }
1270 PUBLIC static inline
1273 { Unsigned16 val; asm volatile ("sldt %0" : "=rm" (val)); return val; }
1275 PUBLIC static inline
1278 { Unsigned16 val; asm volatile ("str %0" : "=rm" (val)); return val; }
1282 Cpu::can_wrmsr() const
1283 { return features() & FEAT_MSR; }
1285 PUBLIC static inline
1287 Cpu::rdmsr(Unsigned32 reg)
1291 asm volatile ("rdmsr" : "=a" (l), "=d" (h) : "c" (reg));
1292 return ((Unsigned64)h << 32) + (Unsigned64)l;
1295 PUBLIC static inline
1297 Cpu::rdpmc(Unsigned32 idx, Unsigned32)
1301 asm volatile ("rdpmc" : "=a" (l), "=d" (h) : "c" (idx));
1302 return ((Unsigned64)h << 32) + (Unsigned64)l;
1305 PUBLIC static inline
1307 Cpu::wrmsr(Unsigned32 low, Unsigned32 high, Unsigned32 reg)
1308 { asm volatile ("wrmsr" : : "a" (low), "d" (high), "c" (reg)); }
1310 PUBLIC static inline
1312 Cpu::wrmsr(Unsigned64 msr, Unsigned32 reg)
1313 { asm volatile ("wrmsr" : : "a" ((Unsigned32)msr), "d" ((Unsigned32)(msr >> 32)), "c" (reg)); }
1315 PUBLIC static inline
1318 { set_cr4(get_cr4() | CR4_PCE); }
1321 IMPLEMENT FIASCO_INIT_CPU
1323 Cpu::init_lbr_type()
1325 _lbr = Lbr_unsupported;
1330 if (vendor() == Vendor_intel)
1333 _lbr = model() < 3 ? Lbr_pentium_4 : Lbr_pentium_4_ext; // P4
1334 else if (family() >= 6)
1335 _lbr = Lbr_pentium_6; // PPro, PIII
1337 else if (vendor() == Vendor_amd)
1339 if ((family() == 6) || (family() == 15))
1340 _lbr = Lbr_pentium_6; // K7/K8
1346 IMPLEMENT FIASCO_INIT_CPU
1348 Cpu::init_bts_type()
1350 _bts = Bts_unsupported;
1352 if (can_wrmsr() && vendor() == Vendor_intel)
1354 if (family() == 15 && (rdmsr(0x1A0) & (1<<11)) == 0)
1355 _bts = Bts_pentium_4;
1356 if (family() == 6 && (model() == 9 || (model() >= 13 &&
1358 _bts = Bts_pentium_m;
1359 if (!(features() & FEAT_DS))
1360 _bts = Bts_unsupported;
1367 Cpu::lbr_enable(bool on)
1369 if (lbr_type() != Lbr_unsupported)
1375 debugctl_busy = true;
1381 debugctl_busy = lbr_active || bts_active;
1382 wrmsr(debugctl_reset, MSR_DEBUGCTLA);
1390 Cpu::btf_enable(bool on)
1392 if (lbr_type() != Lbr_unsupported)
1398 debugctl_reset |= 2; /* don't disable bit in kernel */
1399 wrmsr(2, MSR_DEBUGCTLA); /* activate _now_ */
1405 debugctl_busy = lbr_active || bts_active;
1406 wrmsr(debugctl_reset, MSR_DEBUGCTLA);
1414 Cpu::bts_enable(bool on)
1416 if (bts_type() != Bts_unsupported)
1422 case Bts_pentium_4: bts_active = true; debugctl_set |= 0x0c; break;
1423 case Bts_pentium_m: bts_active = true; debugctl_set |= 0xc0; break;
1426 debugctl_busy = lbr_active || bts_active;
1433 case Bts_pentium_4: debugctl_set &= ~0x0c; break;
1434 case Bts_pentium_m: debugctl_set &= ~0xc0; break;
1437 debugctl_busy = lbr_active || bts_active;
1438 wrmsr(debugctl_reset, MSR_DEBUGCTLA);
1445 Cpu::debugctl_enable()
1448 wrmsr(debugctl_set, MSR_DEBUGCTLA);
1453 Cpu::debugctl_disable()
1456 wrmsr(debugctl_reset, MSR_DEBUGCTLA);
1460 * AMD OS-Visible Workaround Information
1461 * print a warning if a CPU is affected by any known erratum
1467 if (vendor() == Vendor_amd && has_amd_osvw() && can_wrmsr())
1469 Unsigned16 osvw_id_length, i;
1470 bool affected = false;
1471 osvw_id_length = rdmsr(0xc0010140) & 0xff;
1473 for (i = 1; ((i - 1) * 64) < osvw_id_length; i++)
1475 Unsigned64 osvw_msr = rdmsr(0xc0010140 + i);
1478 printf("\033[31mOSVW_MSR%d = 0x%016llx\033[m\n",
1479 i, rdmsr(0xc0010140 + i));
1484 printf("\033[31m#Errata known %d, affected by at least one\033[m\n",
1489 IMPLEMENT FIASCO_INIT_CPU
1500 if (scaler_tsc_to_ns)
1501 _frequency = ns_to_tsc(1000000000UL);
1503 Unsigned32 cr4 = get_cr4();
1505 if (features() & FEAT_FXSR)
1508 if (features() & FEAT_SSE)
1509 cr4 |= CR4_OSXMMEXCPT;
1513 // reset time stamp counter (better for debugging)
1514 if ((features() & FEAT_TSC) && can_wrmsr())
1515 wrmsr(0, 0, MSR_TSC);
1517 if ((features() & FEAT_PAT) && can_wrmsr())
1518 wrmsr(0x00010406, 0x00070406, MSR_PAT);
1527 printf ("CPU[%u:%u]: %s (%X:%X:%X:%X)[%08x] Model: %s at %llu MHz\n\n",
1528 id(), phys_id() >> 24,
1529 vendor_str(), family(), model(), stepping(), brand(), _version, model_str(),
1530 div32(frequency(), 1000000));
1535 Cpu::set_sysenter(void (*func)(void))
1537 // Check for Sysenter/Sysexit Feature
1539 wrmsr ((Mword) func, 0, MSR_SYSENTER_EIP);
1545 Cpu::set_fast_entry(void (*func)(void))
1550 extern "C" void entry_sys_fast_ipc (void);
1551 extern "C" void entry_sys_fast_ipc_c (void);
1553 PUBLIC FIASCO_INIT_CPU
1555 Cpu::init_sysenter()
1557 // Check for Sysenter/Sysexit Feature
1560 wrmsr (Gdt::gdt_code_kernel, 0, MSR_SYSENTER_CS);
1561 wrmsr ((unsigned long)&kernel_sp(), 0, MSR_SYSENTER_ESP);
1562 if (Config::Assembler_ipc_shortcut)
1563 set_sysenter(entry_sys_fast_ipc);
1565 set_sysenter(entry_sys_fast_ipc_c);
1570 // Return 2^32 / (tsc clocks per usec)
1573 Cpu::calibrate_tsc ()
1575 const unsigned calibrate_time = 50000 /*us*/ + 1;
1578 if (! (features() & FEAT_TSC))
1581 Unsigned64 tsc_start, tsc_end;
1582 Unsigned32 count, tsc_to_ns_div, dummy;
1585 // disable interrupts
1586 Proc::Status o = Proc::cli_save();
1588 Pit::setup_channel2_to_20hz();
1590 tsc_start = rdtsc ();
1596 while ((Io::in8 (0x61) & 0x20) == 0);
1600 Proc::sti_restore(o);
1603 // Error: ECTCNEVERSET
1607 tsc_end -= tsc_start;
1609 // prevent overflow in division (CPU too fast)
1610 if (tsc_end & 0xffffffff00000000LL)
1613 // prevent overflow in division (CPU too slow)
1614 if ((tsc_end & 0xffffffffL) < calibrate_time)
1617 // tsc_to_ns_div = calibrate_time * 2^32 / tsc
1619 :"=a" (tsc_to_ns_div), "=d" (dummy)
1620 :"r" ((Unsigned32)tsc_end), "a" (0), "d" (calibrate_time));
1622 // scaler_tsc_to_ns = (tsc_to_ns_div * 1000) / 32
1623 // not using muldiv(tsc_to_ns_div, 1000, 1 << 5), as div result > (1 << 32)
1624 // will get trap0 if system frequency is too low
1625 scaler_tsc_to_ns = tsc_to_ns_div * 31;
1626 scaler_tsc_to_ns += tsc_to_ns_div / 4;
1627 scaler_tsc_to_us = tsc_to_ns_div;
1628 scaler_ns_to_tsc = muldiv(1 << 31, ((Unsigned32)tsc_end),
1629 calibrate_time * 1000 >> 1 * 1 << 5);
1634 if (Config::kinfo_timer_uses_rdtsc)
1635 panic("Can't calibrate tsc");
1640 Cpu::time_us() const
1642 return tsc_to_us (rdtsc());
1648 Cpu::enable_ldt(Address addr, int size)
1652 get_gdt()->clear_entry (Gdt::gdt_ldt / 8);
1657 get_gdt()->set_entry_byte(Gdt::gdt_ldt / 8, addr, size-1, 2/*=ldt*/, 0);
1658 set_ldt(Gdt::gdt_ldt);
1663 PUBLIC static inline
1666 { Unsigned32 val; asm volatile ("mov %%fs, %0" : "=rm" (val)); return val; }
1668 PUBLIC static inline
1671 { Unsigned32 val; asm volatile ("mov %%gs, %0" : "=rm" (val)); return val; }
1673 PUBLIC static inline
1675 Cpu::set_fs(Unsigned32 val)
1676 { asm volatile ("mov %0, %%fs" : : "rm" (val)); }
1678 PUBLIC static inline
1680 Cpu::set_gs(Unsigned32 val)
1681 { asm volatile ("mov %0, %%gs" : : "rm" (val)); }
1685 Cpu::phys_id() const
1686 { return _brand & 0xff000000; }
1690 Cpu::phys_id_direct()
1693 cpuid (1, &a, &b, &c, &d);
1694 return b & 0xff000000;