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 void set_tss() const { 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 { 0xf0ff0, 0x206c0, 0xffff, "Xeon X5680 (and others?)" },
374 { 0x0, 0x0, 0xFFFF, "" }
377 Cpu::Vendor_table const Cpu::amd_table[] FIASCO_INITDATA_CPU =
379 { 0xFF0, 0x430, 0xFFFF, "Am486DX2-WT" },
380 { 0xFF0, 0x470, 0xFFFF, "Am486DX2-WB" },
381 { 0xFF0, 0x480, 0xFFFF, "Am486DX4-WT / Am5x86-WT" },
382 { 0xFF0, 0x490, 0xFFFF, "Am486DX4-WB / Am5x86-WB" },
383 { 0xFF0, 0x4a0, 0xFFFF, "SC400" },
384 { 0xFF0, 0x4e0, 0xFFFF, "Am5x86-WT" },
385 { 0xFF0, 0x4f0, 0xFFFF, "Am5x86-WB" },
386 { 0xFF0, 0x500, 0xFFFF, "K5 (SSA/5) PR75/90/100" },
387 { 0xFF0, 0x510, 0xFFFF, "K5 (Godot) PR120/133" },
388 { 0xFF0, 0x520, 0xFFFF, "K5 (Godot) PR150/166" },
389 { 0xFF0, 0x530, 0xFFFF, "K5 (Godot) PR200" },
390 { 0xFF0, 0x560, 0xFFFF, "K6 (Little Foot)" },
391 { 0xFF0, 0x570, 0xFFFF, "K6 (Little Foot)" },
392 { 0xFF0, 0x580, 0xFFFF, "K6-II (Chomper)" },
393 { 0xFF0, 0x590, 256, "K6-III (Sharptooth)" },
394 { 0xFF0, 0x5c0, 128, "K6-2+" },
395 { 0xFF0, 0x5d0, 256, "K6-3+" },
396 { 0xFF0, 0x600, 0xFFFF, "Athlon K7 (Argon)" },
397 { 0xFF0, 0x610, 0xFFFF, "Athlon K7 (Pluto)" },
398 { 0xFF0, 0x620, 0xFFFF, "Athlon K75 (Orion)" },
399 { 0xFF0, 0x630, 64, "Duron (Spitfire)" },
400 { 0xFF0, 0x640, 256, "Athlon (Thunderbird)" },
401 { 0xFF0, 0x660, 256, "Athlon (Palomino)" },
402 { 0xFF0, 0x660, 64, "Duron (Morgan)" },
403 { 0xFF0, 0x670, 64, "Duron (Morgan)" },
404 { 0xFF0, 0x680, 256, "Athlon (Thoroughbred)" },
405 { 0xFF0, 0x680, 64, "Duron (Applebred)" },
406 { 0xFF0, 0x6A0, 512, "Athlon (Barton)" },
407 { 0xFF0, 0x6A0, 256, "Athlon (Thorton)" },
408 { 0xfff0ff0, 0x000f00, 0, "Athlon 64 (Clawhammer)" },
409 { 0xfff0ff0, 0x000f10, 0, "Opteron (Sledgehammer)" },
410 { 0xfff0ff0, 0x000f40, 0, "Athlon 64 (Clawhammer)" },
411 { 0xfff0ff0, 0x000f50, 0, "Opteron (Sledgehammer)" },
412 { 0xfff0ff0, 0x000fc0, 512, "Athlon64 (Newcastle)" },
413 { 0xfff0ff0, 0x000fc0, 256, "Sempron (Paris)" },
414 { 0xfff0ff0, 0x010f50, 0, "Opteron (Sledgehammer)" },
415 { 0xfff0ff0, 0x010fc0, 0, "Sempron (Oakville)" },
416 { 0xfff0ff0, 0x010ff0, 0, "Athlon 64 (Winchester)" },
417 { 0xfff0ff0, 0x020f10, 0, "Opteron (Jackhammer)" },
418 { 0xfff0ff0, 0x020f30, 0, "Athlon 64 X2 (Toledo)" },
419 { 0xfff0ff0, 0x020f40, 0, "Turion 64 (Lancaster)" },
420 { 0xfff0ff0, 0x020f50, 0, "Opteron (Venus)" },
421 { 0xfff0ff0, 0x020f70, 0, "Athlon 64 (San Diego)" },
422 { 0xfff0ff0, 0x020fb0, 0, "Athlon 64 X2 (Manchester)" },
423 { 0xfff0ff0, 0x020fc0, 0, "Sempron (Palermo)" },
424 { 0xfff0ff0, 0x020ff0, 0, "Athlon 64 (Venice)" },
425 { 0xfff0ff0, 0x040f10, 0, "Opteron (Santa Rosa)" },
426 { 0xfff0ff0, 0x040f30, 0, "Athlon 64 X2 (Windsor)" },
427 { 0xfff0ff0, 0x040f80, 0, "Turion 64 X2 (Taylor)" },
428 { 0xfff0ff0, 0x060fb0, 0, "Athlon 64 X2 (Brisbane)" },
429 { 0xfff0ff0, 0x100f20, 0, "Phenom X3/Toliman / X4/Agena" },
430 { 0xfff0ff0, 0x100f40, 0, "Opteron (Shanghai)" },
434 Cpu::Vendor_table const Cpu::cyrix_table[] FIASCO_INITDATA_CPU =
436 { 0xFF0, 0x440, 0xFFFF, "Gx86 (Media GX)" },
437 { 0xFF0, 0x490, 0xFFFF, "5x86" },
438 { 0xFF0, 0x520, 0xFFFF, "6x86 (M1)" },
439 { 0xFF0, 0x540, 0xFFFF, "GXm" },
440 { 0xFF0, 0x600, 0xFFFF, "6x86MX (M2)" },
441 { 0x0, 0x0, 0xFFFF, "" }
444 Cpu::Vendor_table const Cpu::via_table[] FIASCO_INITDATA_CPU =
446 { 0xFF0, 0x540, 0xFFFF, "IDT Winchip C6" },
447 { 0xFF0, 0x580, 0xFFFF, "IDT Winchip 2A/B" },
448 { 0xFF0, 0x590, 0xFFFF, "IDT Winchip 3" },
449 { 0xFF0, 0x650, 0xFFFF, "Via Jalapeno (Joshua)" },
450 { 0xFF0, 0x660, 0xFFFF, "Via C5A (Samuel)" },
451 { 0xFF8, 0x670, 0xFFFF, "Via C5B (Samuel 2)" },
452 { 0xFF8, 0x678, 0xFFFF, "Via C5C (Ezra)" },
453 { 0xFF0, 0x680, 0xFFFF, "Via C5N (Ezra-T)" },
454 { 0xFF0, 0x690, 0xFFFF, "Via C5P (Nehemiah)" },
455 { 0xFF0, 0x6a0, 0xFFFF, "Via C5J (Esther)" },
456 { 0x0, 0x0, 0xFFFF, "" }
459 Cpu::Vendor_table const Cpu::umc_table[] FIASCO_INITDATA_CPU =
461 { 0xFF0, 0x410, 0xFFFF, "U5D" },
462 { 0xFF0, 0x420, 0xFFFF, "U5S" },
463 { 0x0, 0x0, 0xFFFF, "" }
466 Cpu::Vendor_table const Cpu::nexgen_table[] FIASCO_INITDATA_CPU =
468 { 0xFF0, 0x500, 0xFFFF, "Nx586" },
469 { 0x0, 0x0, 0xFFFF, "" }
472 Cpu::Vendor_table const Cpu::rise_table[] FIASCO_INITDATA_CPU =
474 { 0xFF0, 0x500, 0xFFFF, "mP6 (iDragon)" },
475 { 0xFF0, 0x520, 0xFFFF, "mP6 (iDragon)" },
476 { 0xFF0, 0x580, 0xFFFF, "mP6 (iDragon II)" },
477 { 0xFF0, 0x590, 0xFFFF, "mP6 (iDragon II)" },
478 { 0x0, 0x0, 0xFFFF, "" }
481 Cpu::Vendor_table const Cpu::transmeta_table[] FIASCO_INITDATA_CPU =
483 { 0xFFF, 0x542, 0xFFFF, "TM3x00 (Crusoe)" },
484 { 0xFFF, 0x543, 0xFFFF, "TM5x00 (Crusoe)" },
485 { 0xFF0, 0xf20, 0xFFFF, "TM8x00 (Efficeon)" },
486 { 0x0, 0x0, 0xFFFF, "" }
489 Cpu::Vendor_table const Cpu::sis_table[] FIASCO_INITDATA_CPU =
491 { 0xFF0, 0x500, 0xFFFF, "55x" },
492 { 0x0, 0x0, 0xFFFF, "" }
495 Cpu::Vendor_table const Cpu::nsc_table[] FIASCO_INITDATA_CPU =
497 { 0xFF0, 0x540, 0xFFFF, "Geode GX1" },
498 { 0xFF0, 0x550, 0xFFFF, "Geode GX2" },
499 { 0xFF0, 0x680, 0xFFFF, "Geode NX" },
500 { 0x0, 0x0, 0xFFFF, "" }
503 Cpu::Cache_table const Cpu::intel_cache_table[] FIASCO_INITDATA_CPU =
505 { 0x01, Tlb_inst_4k, 32, 4, 0 },
506 { 0x02, Tlb_inst_4M, 2, 4, 0 },
507 { 0x03, Tlb_data_4k, 64, 4, 0 },
508 { 0x04, Tlb_data_4M, 8, 4, 0 },
509 { 0x05, Tlb_data_4M, 32, 4, 0 },
510 { 0x06, Cache_l1_inst, 8, 4, 32 },
511 { 0x08, Cache_l1_inst, 16, 4, 32 },
512 { 0x09, Cache_l1_inst, 32, 4, 64 },
513 { 0x0A, Cache_l1_data, 8, 2, 32 },
514 { 0x0B, Tlb_inst_4M, 4, 4, 0 },
515 { 0x0C, Cache_l1_data, 16, 4, 32 },
516 { 0x0D, Cache_l1_data, 16, 4, 64 },
517 { 0x0E, Cache_l1_data, 24, 6, 64 },
518 { 0x21, Cache_l2, 256, 8, 64 },
519 { 0x22, Cache_l3, 512, 4, 64 }, /* sectored */
520 { 0x23, Cache_l3, 1024, 8, 64 }, /* sectored */
521 { 0x25, Cache_l3, 2048, 8, 64 }, /* sectored */
522 { 0x29, Cache_l3, 4096, 8, 64 }, /* sectored */
523 { 0x2C, Cache_l1_data, 32, 8, 64 },
524 { 0x30, Cache_l1_inst, 32, 8, 64 },
525 { 0x39, Cache_l2, 128, 4, 64 }, /* sectored */
526 { 0x3B, Cache_l2, 128, 2, 64 }, /* sectored */
527 { 0x3C, Cache_l2, 256, 4, 64 }, /* sectored */
528 { 0x41, Cache_l2, 128, 4, 32 },
529 { 0x42, Cache_l2, 256, 4, 32 },
530 { 0x43, Cache_l2, 512, 4, 32 },
531 { 0x44, Cache_l2, 1024, 4, 32 },
532 { 0x45, Cache_l2, 2048, 4, 32 },
533 { 0x46, Cache_l3, 4096, 4, 64 },
534 { 0x47, Cache_l3, 8192, 8, 64 },
535 { 0x48, Cache_l2, 3072, 12, 64 },
536 { 0x49, Cache_l2, 4096, 16, 64 },
537 { 0x4A, Cache_l3, 6144, 12, 64 },
538 { 0x4B, Cache_l3, 8192, 16, 64 },
539 { 0x4C, Cache_l3, 12288, 12, 64 },
540 { 0x4D, Cache_l3, 16384, 16, 64 },
541 { 0x4E, Cache_l3, 6144, 24, 64 },
542 { 0x4F, Tlb_inst_4k, 32, 0, 0 },
543 { 0x50, Tlb_inst_4k_4M, 64, 0, 0 },
544 { 0x51, Tlb_inst_4k_4M, 128, 0, 0 },
545 { 0x52, Tlb_inst_4k_4M, 256, 0, 0 },
546 { 0x56, Tlb_data_4M, 16, 4, 0 },
547 { 0x57, Tlb_data_4k, 16, 4, 0 },
548 { 0x59, Tlb_data_4k, 16, 0, 0 },
549 { 0x5A, Tlb_data_2M_4M, 32, 4, 0 },
550 { 0x5B, Tlb_data_4k_4M, 64, 0, 0 },
551 { 0x5C, Tlb_data_4k_4M, 128, 0, 0 },
552 { 0x5D, Tlb_data_4k_4M, 256, 0, 0 },
553 { 0x60, Cache_l1_data, 16, 8, 64 },
554 { 0x66, Cache_l1_data, 8, 4, 64 }, /* sectored */
555 { 0x67, Cache_l1_data, 16, 4, 64 }, /* sectored */
556 { 0x68, Cache_l1_data, 32, 4, 64 }, /* sectored */
557 { 0x70, Cache_l1_trace, 12, 8, 0 },
558 { 0x71, Cache_l1_trace, 16, 8, 0 },
559 { 0x72, Cache_l1_trace, 32, 8, 0 },
560 { 0x77, Cache_l1_inst, 16, 4, 64 },
561 { 0x78, Cache_l2, 1024, 4, 64 },
562 { 0x79, Cache_l2, 128, 8, 64 }, /* sectored */
563 { 0x7A, Cache_l2, 256, 8, 64 }, /* sectored */
564 { 0x7B, Cache_l2, 512, 8, 64 }, /* sectored */
565 { 0x7C, Cache_l2, 1024, 8, 64 }, /* sectored */
566 { 0x7D, Cache_l2, 2048, 8, 64 },
567 { 0x7E, Cache_l2, 256, 8, 128 },
568 { 0x7F, Cache_l2, 512, 2, 64 },
569 { 0x80, Cache_l2, 512, 16, 64 },
570 { 0x82, Cache_l2, 256, 8, 32 },
571 { 0x83, Cache_l2, 512, 8, 32 },
572 { 0x84, Cache_l2, 1024, 8, 32 },
573 { 0x85, Cache_l2, 2048, 8, 32 },
574 { 0x86, Cache_l2, 512, 4, 64 },
575 { 0x87, Cache_l2, 1024, 8, 64 },
576 { 0x8D, Cache_l3, 3072, 12, 128 },
577 { 0xB0, Tlb_inst_4k, 128, 4, 0 },
578 { 0xB3, Tlb_data_4k, 128, 4, 0 },
579 { 0xB4, Tlb_data_4k, 256, 4, 0 },
580 { 0xBA, Tlb_data_4k, 64, 4, 0 },
581 { 0xC0, Tlb_data_4k_4M, 8, 4, 0 },
582 { 0xCA, Tlb_data_4k_4M, 512, 4, 0 },
583 { 0xD0, Cache_l3, 512, 4, 64 },
584 { 0xD1, Cache_l3, 1024, 4, 64 },
585 { 0xD2, Cache_l3, 2048, 4, 64 },
586 { 0xD6, Cache_l3, 1024, 8, 64 },
587 { 0xD7, Cache_l3, 2048, 8, 64 },
588 { 0xD8, Cache_l3, 4096, 8, 64 },
589 { 0xDC, Cache_l3, 1536, 12, 64 },
590 { 0xDD, Cache_l3, 3072, 12, 64 },
591 { 0xDE, Cache_l3, 6144, 12, 64 },
592 { 0xE2, Cache_l3, 2048, 16, 64 },
593 { 0xE3, Cache_l3, 4096, 16, 64 },
594 { 0xE4, Cache_l3, 8192, 16, 64 },
595 { 0xEA, Cache_l3, 12288, 24, 64 },
596 { 0xEB, Cache_l3, 18432, 24, 64 },
597 { 0xEC, Cache_l3, 24576, 24, 64 },
598 { 0x0, Cache_unknown, 0, 0, 0 }
601 char const * const Cpu::vendor_ident[] =
616 Cpu::Vendor_table const * const Cpu::vendor_table[] =
631 char const * const Cpu::exception_strings[] =
633 /* 0 */ "Divide Error",
635 /* 2 */ "NMI Interrupt",
636 /* 3 */ "Breakpoint",
638 /* 5 */ "BOUND Range Exceeded",
639 /* 6 */ "Invalid Opcode",
640 /* 7 */ "Device Not Available",
641 /* 8 */ "Double Fault",
642 /* 9 */ "CoProcessor Segment Overrrun",
643 /* 10 */ "Invalid TSS",
644 /* 11 */ "Segment Not Present",
645 /* 12 */ "Stack Segment Fault",
646 /* 13 */ "General Protection",
647 /* 14 */ "Page Fault",
649 /* 16 */ "Floating-Point Error",
650 /* 17 */ "Alignment Check",
651 /* 18 */ "Machine Check",
652 /* 19 */ "SIMD Floating-Point Exception",
667 PUBLIC explicit FIASCO_INIT_CPU
668 Cpu::Cpu(unsigned cpu)
683 Cpu::init_global_features()
688 Cpu::exception_string(Mword trapno)
691 return "Maskable Interrupt";
692 return exception_strings[trapno];
695 PUBLIC static inline FIASCO_INIT_CPU
697 Cpu::cpuid(Unsigned32 const mode,
698 Unsigned32 *const eax, Unsigned32 *const ebx,
699 Unsigned32 *const ecx, Unsigned32 *const edx)
701 asm volatile ("cpuid" : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
707 PRIVATE FIASCO_INIT_CPU
709 Cpu::cache_tlb_intel()
712 unsigned i, count = 0;
713 Cache_table const *table;
717 cpuid(2, (Unsigned32 *)(desc),
718 (Unsigned32 *)(desc + 4),
719 (Unsigned32 *)(desc + 8),
720 (Unsigned32 *)(desc + 12));
722 for (i = 1; i < 16; i++)
724 // Null descriptor or register bit31 set (reserved)
725 if (!desc[i] || (desc[i / 4 * 4 + 3] & (1 << 7)))
728 for (table = intel_cache_table; table->desc; table++)
730 if (table->desc == desc[i])
732 switch (table->level)
735 _l1_data_cache_size = table->size;
736 _l1_data_cache_asso = table->asso;
737 _l1_data_cache_line_size = table->line_size;
740 _l1_inst_cache_size = table->size;
741 _l1_inst_cache_asso = table->asso;
742 _l1_inst_cache_line_size = table->line_size;
745 _l1_trace_cache_size = table->size;
746 _l1_trace_cache_asso = table->asso;
749 _l2_cache_size = table->size;
750 _l2_cache_asso = table->asso;
751 _l2_cache_line_size = table->line_size;
754 _l3_cache_size = table->size;
755 _l3_cache_asso = table->asso;
756 _l3_cache_line_size = table->line_size;
759 _inst_tlb_4k_entries += table->size;
762 _data_tlb_4k_entries += table->size;
765 _inst_tlb_4m_entries += table->size;
768 _data_tlb_4m_entries += table->size;
771 _inst_tlb_4k_4m_entries += table->size;
774 _data_tlb_4k_4m_entries += table->size;
784 while (++count < *desc);
787 PRIVATE FIASCO_INIT_CPU
791 Unsigned32 eax, ebx, ecx, edx;
792 cpuid(0x80000005, &eax, &ebx, &ecx, &edx);
794 _l1_data_cache_size = (ecx >> 24) & 0xFF;
795 _l1_data_cache_asso = (ecx >> 16) & 0xFF;
796 _l1_data_cache_line_size = ecx & 0xFF;
798 _l1_inst_cache_size = (edx >> 24) & 0xFF;
799 _l1_inst_cache_asso = (edx >> 16) & 0xFF;
800 _l1_inst_cache_line_size = edx & 0xFF;
802 _data_tlb_4k_entries = (ebx >> 16) & 0xFF;
803 _inst_tlb_4k_entries = ebx & 0xFF;
804 _data_tlb_4m_entries = (eax >> 16) & 0xFF;
805 _inst_tlb_4m_entries = eax & 0xFF;
808 PRIVATE FIASCO_INIT_CPU
810 Cpu::cache_tlb_l2_l3()
812 Unsigned32 eax, ebx, ecx, edx;
813 cpuid(0x80000006, &eax, &ebx, &ecx, &edx);
815 if (vendor() == Vendor_via)
817 _l2_cache_size = (ecx >> 24) & 0xFF;
818 _l2_cache_asso = (ecx >> 16) & 0xFF;
822 _l2_data_tlb_4m_entries = (eax >> 16) & 0xFFF;
823 _l2_inst_tlb_4m_entries = eax & 0xFFF;
824 _l2_data_tlb_4k_entries = (ebx >> 16) & 0xFFF;
825 _l2_inst_tlb_4k_entries = ebx & 0xFFF;
826 _l2_cache_size = (ecx >> 16) & 0xFFFF;
827 _l2_cache_asso = (ecx >> 12) & 0xF;
830 _l2_cache_line_size = ecx & 0xFF;
832 _l3_cache_size = (edx >> 18) << 9;
833 _l3_cache_asso = (edx >> 12) & 0xF;
834 _l3_cache_line_size = edx & 0xFF;
837 PRIVATE FIASCO_INIT_CPU
839 Cpu::addr_size_info()
841 Unsigned32 eax, ebx, ecx, edx;
842 cpuid(0x80000008, &eax, &ebx, &ecx, &edx);
844 _phys_bits = eax & 0xff;
845 _virt_bits = (eax & 0xff00) >> 8;
852 Unsigned32 eax, ebx, ecx, edx;
853 cpuid(0x80000008, &eax, &ebx, &ecx, &edx);
855 unsigned apicidcoreidsize = (ecx >> 12) & 0xf;
856 if (apicidcoreidsize == 0)
857 return (ecx & 0xf) + 1; // NC
858 return 1 << apicidcoreidsize;
861 PRIVATE FIASCO_INIT_CPU
865 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)
1040 if (_vendor == Vendor_intel || _vendor == Vendor_amd)
1041 cpuid(0x80000001, &i, &i, &_ext_8000_0001_ecx,
1042 &_ext_8000_0001_edx);
1047 // see Intel Spec on SYSENTER:
1048 // Some Pentium Pro pretend to have it, but actually lack it
1049 if ((_version & 0xFFF) < 0x633)
1050 _features &= ~FEAT_SEP;
1060 PUBLIC inline NEEDS["processor.h"]
1062 Cpu::busy_wait_ns(Unsigned64 ns)
1064 Unsigned64 stop = rdtsc () + ns_to_tsc(ns);
1066 while (rdtsc() < stop)
1073 Cpu::show_cache_tlb_info(const char *indent) const
1078 if (_l2_inst_tlb_4k_entries)
1079 snprintf(s, sizeof(s), "/%u", _l2_inst_tlb_4k_entries);
1080 if (_inst_tlb_4k_entries)
1081 printf("%s%4u%s Entry I TLB (4K pages)", indent, _inst_tlb_4k_entries, s);
1083 if (_l2_inst_tlb_4m_entries)
1084 snprintf(s, sizeof(s), "/%u", _l2_inst_tlb_4k_entries);
1085 if (_inst_tlb_4m_entries)
1086 printf(" %4u%s Entry I TLB (4M pages)", _inst_tlb_4m_entries, s);
1087 if (_inst_tlb_4k_4m_entries)
1088 printf("%s%4u Entry I TLB (4K or 4M pages)",
1089 indent, _inst_tlb_4k_4m_entries);
1090 if (_inst_tlb_4k_entries || _inst_tlb_4m_entries || _inst_tlb_4k_4m_entries)
1093 if (_l2_data_tlb_4k_entries)
1094 snprintf(s, sizeof(s), "/%u", _l2_data_tlb_4k_entries);
1095 if (_data_tlb_4k_entries)
1096 printf("%s%4u%s Entry D TLB (4K pages)", indent, _data_tlb_4k_entries, s);
1098 if (_l2_data_tlb_4m_entries)
1099 snprintf(s, sizeof(s), "/%u", _l2_data_tlb_4m_entries);
1100 if (_data_tlb_4m_entries)
1101 printf(" %4u%s Entry D TLB (4M pages)", _data_tlb_4m_entries, s);
1102 if (_data_tlb_4k_4m_entries)
1103 printf("%s%4u Entry D TLB (4k or 4M pages)",
1104 indent, _data_tlb_4k_4m_entries);
1105 if (_data_tlb_4k_entries || _data_tlb_4m_entries || _data_tlb_4k_4m_entries)
1108 if (_l1_trace_cache_size)
1109 printf("%s%3uK %c-ops T Cache (%u-way associative)\n",
1110 indent, _l1_trace_cache_size, Config::char_micro,
1111 _l1_trace_cache_asso);
1113 else if (_l1_inst_cache_size)
1114 printf("%s%4u KB L1 I Cache (%u-way associative, %u bytes per line)\n",
1115 indent, _l1_inst_cache_size, _l1_inst_cache_asso,
1116 _l1_inst_cache_line_size);
1118 if (_l1_data_cache_size)
1119 printf("%s%4u KB L1 D Cache (%u-way associative, %u bytes per line)\n"
1120 "%s%4u KB L2 U Cache (%u-way associative, %u bytes per line)\n",
1121 indent, _l1_data_cache_size, _l1_data_cache_asso,
1122 _l1_data_cache_line_size,
1123 indent, _l2_cache_size, _l2_cache_asso, _l2_cache_line_size);
1126 printf("%s%4u KB L3 U Cache (%u-way associative, %u bytes per line)\n",
1127 indent, _l3_cache_size, _l3_cache_asso, _l3_cache_line_size);
1132 Cpu::disable(unsigned cpu, char const *reason)
1134 printf("CPU%u: is disabled: %s\n", cpu, reason);
1137 // Function used for calculating apic scaler
1138 PUBLIC static inline
1140 Cpu::muldiv(Unsigned32 val, Unsigned32 mul, Unsigned32 div)
1144 asm volatile ("mull %3 ; divl %4\n\t"
1145 :"=a" (val), "=d" (dummy)
1146 : "0" (val), "d" (mul), "c" (div));
1151 PUBLIC static inline
1156 asm volatile ("mov %%cs, %0" : "=rm" (val));
1160 PUBLIC static inline
1165 asm volatile ("mov %%ds, %0" : "=rm" (val));
1169 PUBLIC static inline
1174 asm volatile ("mov %%es, %0" : "=rm" (val));
1178 PUBLIC static inline
1183 asm volatile ("mov %%ss, %0" : "=rm" (val));
1187 PUBLIC static inline
1192 asm volatile ("mov %%fs, %0" : "=rm" (val));
1196 PUBLIC static inline
1198 Cpu::set_ds(Unsigned32 val)
1199 { asm volatile ("mov %0, %%ds" : : "rm" (val)); }
1201 PUBLIC static inline
1203 Cpu::set_es(Unsigned32 val)
1204 { asm volatile ("mov %0, %%es" : : "rm" (val)); }
1206 PUBLIC static inline
1208 Cpu::set_fs(Unsigned32 val)
1209 { asm volatile ("mov %0, %%fs" : : "rm" (val)); }
1212 //----------------------------------------------------------------------------
1213 IMPLEMENTATION[ia32, amd64]:
1215 #include "boot_info.h"
1219 #include "globals.h"
1220 #include "initcalls.h"
1223 #include "processor.h"
1224 #include "regdefs.h"
1228 PUBLIC static inline
1230 Cpu::set_cr0(unsigned long val)
1231 { asm volatile ("mov %0, %%cr0" : : "r" (val)); }
1233 PUBLIC static inline
1235 Cpu::set_pdbr(unsigned long addr)
1236 { asm volatile ("mov %0, %%cr3" : : "r" (addr)); }
1238 PUBLIC static inline
1240 Cpu::set_cr4(unsigned long val)
1241 { asm volatile ("mov %0, %%cr4" : : "r" (val)); }
1243 PUBLIC static inline
1245 Cpu::set_ldt(Unsigned16 val)
1246 { asm volatile ("lldt %0" : : "rm" (val)); }
1249 PUBLIC static inline
1251 Cpu::set_ss(Unsigned32 val)
1252 { asm volatile ("mov %0, %%ss" : : "r" (val)); }
1254 PUBLIC static inline
1256 Cpu::set_tr(Unsigned16 val)
1257 { asm volatile ("ltr %0" : : "rm" (val)); }
1259 PUBLIC static inline
1264 asm volatile ("mov %%cr0, %0" : "=r" (val));
1268 PUBLIC static inline
1271 { Address addr; asm volatile ("mov %%cr3, %0" : "=r" (addr)); return addr; }
1273 PUBLIC static inline
1276 { Mword val; asm volatile ("mov %%cr4, %0" : "=r" (val)); return val; }
1278 PUBLIC static inline
1281 { Unsigned16 val; asm volatile ("sldt %0" : "=rm" (val)); return val; }
1283 PUBLIC static inline
1286 { Unsigned16 val; asm volatile ("str %0" : "=rm" (val)); return val; }
1290 Cpu::can_wrmsr() const
1291 { return features() & FEAT_MSR; }
1293 PUBLIC static inline
1295 Cpu::rdmsr(Unsigned32 reg)
1299 asm volatile ("rdmsr" : "=a" (l), "=d" (h) : "c" (reg));
1300 return ((Unsigned64)h << 32) + (Unsigned64)l;
1303 PUBLIC static inline
1305 Cpu::rdpmc(Unsigned32 idx, Unsigned32)
1309 asm volatile ("rdpmc" : "=a" (l), "=d" (h) : "c" (idx));
1310 return ((Unsigned64)h << 32) + (Unsigned64)l;
1313 PUBLIC static inline
1315 Cpu::wrmsr(Unsigned32 low, Unsigned32 high, Unsigned32 reg)
1316 { asm volatile ("wrmsr" : : "a" (low), "d" (high), "c" (reg)); }
1318 PUBLIC static inline
1320 Cpu::wrmsr(Unsigned64 msr, Unsigned32 reg)
1321 { asm volatile ("wrmsr" : : "a" ((Unsigned32)msr), "d" ((Unsigned32)(msr >> 32)), "c" (reg)); }
1323 PUBLIC static inline
1326 { set_cr4(get_cr4() | CR4_PCE); }
1329 IMPLEMENT FIASCO_INIT_CPU
1331 Cpu::init_lbr_type()
1333 _lbr = Lbr_unsupported;
1338 if (vendor() == Vendor_intel)
1341 _lbr = model() < 3 ? Lbr_pentium_4 : Lbr_pentium_4_ext; // P4
1342 else if (family() >= 6)
1343 _lbr = Lbr_pentium_6; // PPro, PIII
1345 else if (vendor() == Vendor_amd)
1347 if ((family() == 6) || (family() == 15))
1348 _lbr = Lbr_pentium_6; // K7/K8
1354 IMPLEMENT FIASCO_INIT_CPU
1356 Cpu::init_bts_type()
1358 _bts = Bts_unsupported;
1360 if (can_wrmsr() && vendor() == Vendor_intel)
1362 if (family() == 15 && (rdmsr(0x1A0) & (1<<11)) == 0)
1363 _bts = Bts_pentium_4;
1364 if (family() == 6 && (model() == 9 || (model() >= 13 &&
1366 _bts = Bts_pentium_m;
1367 if (!(features() & FEAT_DS))
1368 _bts = Bts_unsupported;
1375 Cpu::lbr_enable(bool on)
1377 if (lbr_type() != Lbr_unsupported)
1383 debugctl_busy = true;
1389 debugctl_busy = lbr_active || bts_active;
1390 wrmsr(debugctl_reset, MSR_DEBUGCTLA);
1398 Cpu::btf_enable(bool on)
1400 if (lbr_type() != Lbr_unsupported)
1406 debugctl_reset |= 2; /* don't disable bit in kernel */
1407 wrmsr(2, MSR_DEBUGCTLA); /* activate _now_ */
1413 debugctl_busy = lbr_active || bts_active;
1414 wrmsr(debugctl_reset, MSR_DEBUGCTLA);
1422 Cpu::bts_enable(bool on)
1424 if (bts_type() != Bts_unsupported)
1430 case Bts_pentium_4: bts_active = true; debugctl_set |= 0x0c; break;
1431 case Bts_pentium_m: bts_active = true; debugctl_set |= 0xc0; break;
1434 debugctl_busy = lbr_active || bts_active;
1441 case Bts_pentium_4: debugctl_set &= ~0x0c; break;
1442 case Bts_pentium_m: debugctl_set &= ~0xc0; break;
1445 debugctl_busy = lbr_active || bts_active;
1446 wrmsr(debugctl_reset, MSR_DEBUGCTLA);
1453 Cpu::debugctl_enable()
1456 wrmsr(debugctl_set, MSR_DEBUGCTLA);
1461 Cpu::debugctl_disable()
1464 wrmsr(debugctl_reset, MSR_DEBUGCTLA);
1468 * AMD OS-Visible Workaround Information
1469 * print a warning if a CPU is affected by any known erratum
1475 if (vendor() == Vendor_amd && has_amd_osvw() && can_wrmsr())
1477 Unsigned16 osvw_id_length, i;
1478 bool affected = false;
1479 osvw_id_length = rdmsr(0xc0010140) & 0xff;
1481 for (i = 1; ((i - 1) * 64) < osvw_id_length; i++)
1483 Unsigned64 osvw_msr = rdmsr(0xc0010140 + i);
1486 printf("\033[31mOSVW_MSR%d = 0x%016llx\033[m\n",
1487 i, rdmsr(0xc0010140 + i));
1492 printf("\033[31m#Errata known %d, affected by at least one\033[m\n",
1497 IMPLEMENT FIASCO_INIT_CPU
1508 if (scaler_tsc_to_ns)
1509 _frequency = ns_to_tsc(1000000000UL);
1511 Unsigned32 cr4 = get_cr4();
1513 if (features() & FEAT_FXSR)
1516 if (features() & FEAT_SSE)
1517 cr4 |= CR4_OSXMMEXCPT;
1521 // reset time stamp counter (better for debugging)
1522 if ((features() & FEAT_TSC) && can_wrmsr())
1525 if ((features() & FEAT_PAT) && can_wrmsr())
1526 wrmsr(0x00010406, 0x00070406, 0x277);
1535 printf ("CPU[%u:%u]: %s (%X:%X:%X:%X)[%08x] Model: %s at %llu MHz\n\n",
1536 id(), phys_id() >> 24,
1537 vendor_str(), family(), model(), stepping(), brand(), _version, model_str(),
1538 div32(frequency(), 1000000));
1543 Cpu::set_sysenter(void (*func)(void))
1545 // Check for Sysenter/Sysexit Feature
1547 wrmsr ((Mword) func, 0, MSR_SYSENTER_EIP);
1553 Cpu::set_fast_entry(void (*func)(void))
1558 extern "C" void entry_sys_fast_ipc (void);
1559 extern "C" void entry_sys_fast_ipc_c (void);
1561 PUBLIC FIASCO_INIT_CPU
1563 Cpu::init_sysenter()
1565 // Check for Sysenter/Sysexit Feature
1568 wrmsr (Gdt::gdt_code_kernel, 0, MSR_SYSENTER_CS);
1569 wrmsr ((unsigned long)&kernel_sp(), 0, MSR_SYSENTER_ESP);
1570 if (Config::Assembler_ipc_shortcut)
1571 set_sysenter(entry_sys_fast_ipc);
1573 set_sysenter(entry_sys_fast_ipc_c);
1578 // Return 2^32 / (tsc clocks per usec)
1581 Cpu::calibrate_tsc ()
1583 const unsigned calibrate_time = 50000 /*us*/ + 1;
1586 if (! (features() & FEAT_TSC))
1589 Unsigned64 tsc_start, tsc_end;
1590 Unsigned32 count, tsc_to_ns_div, dummy;
1593 // disable interrupts
1594 Proc::Status o = Proc::cli_save();
1596 Pit::setup_channel2_to_20hz();
1598 tsc_start = rdtsc ();
1604 while ((Io::in8 (0x61) & 0x20) == 0);
1608 Proc::sti_restore(o);
1611 // Error: ECTCNEVERSET
1615 tsc_end -= tsc_start;
1617 // prevent overflow in division (CPU too fast)
1618 if (tsc_end & 0xffffffff00000000LL)
1621 // prevent overflow in division (CPU too slow)
1622 if ((tsc_end & 0xffffffffL) < calibrate_time)
1625 // tsc_to_ns_div = calibrate_time * 2^32 / tsc
1627 :"=a" (tsc_to_ns_div), "=d" (dummy)
1628 :"r" ((Unsigned32)tsc_end), "a" (0), "d" (calibrate_time));
1630 scaler_tsc_to_ns = muldiv (tsc_to_ns_div, 1000, 1<<5);
1631 scaler_tsc_to_us = tsc_to_ns_div;
1632 scaler_ns_to_tsc = muldiv (1<<31, ((Unsigned32)tsc_end),
1633 calibrate_time * 1000>>1 * 1<<5);
1638 if (Config::kinfo_timer_uses_rdtsc)
1639 panic("Can't calibrate tsc");
1644 Cpu::time_us() const
1646 return tsc_to_us (rdtsc());
1652 Cpu::enable_ldt(Address addr, int size)
1656 get_gdt()->clear_entry (Gdt::gdt_ldt / 8);
1661 get_gdt()->set_entry_byte(Gdt::gdt_ldt / 8, addr, size-1, 2/*=ldt*/, 0);
1662 set_ldt(Gdt::gdt_ldt);
1667 PUBLIC static inline
1670 { Unsigned32 val; asm volatile ("mov %%gs, %0" : "=rm" (val)); return val; }
1672 PUBLIC static inline
1674 Cpu::set_gs(Unsigned32 val)
1675 { asm volatile ("mov %0, %%gs" : : "rm" (val)); }
1679 Cpu::phys_id() const
1680 { return _brand & 0xff000000; }
1684 Cpu::phys_id_direct()
1687 cpuid (1, &a, &b, &c, &d);
1688 return b & 0xff000000;