]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ia32/cpu-ia32.cpp
07d468d053bd9c95799cdd873eb03439bb030b37
[l4.git] / kernel / fiasco / src / kern / ia32 / cpu-ia32.cpp
1 INTERFACE[ia32,amd64,ux]:
2
3 #include "types.h"
4 #include "initcalls.h"
5 #include "regdefs.h"
6 #include "per_cpu_data.h"
7
8 EXTENSION
9 class Cpu
10 {
11 public:
12
13   enum Vendor
14   {
15     Vendor_unknown = 0,
16     Vendor_intel,
17     Vendor_amd,
18     Vendor_cyrix,
19     Vendor_via,
20     Vendor_umc,
21     Vendor_nexgen,
22     Vendor_rise,
23     Vendor_transmeta,
24     Vendor_sis,
25     Vendor_nsc
26   };
27
28   enum CacheTLB
29   {
30     Cache_unknown = 0,
31     Cache_l1_data,
32     Cache_l1_inst,
33     Cache_l1_trace,
34     Cache_l2,
35     Cache_l3,
36     Tlb_data_4k,
37     Tlb_inst_4k,
38     Tlb_data_4M,
39     Tlb_inst_4M,
40     Tlb_data_4k_4M,
41     Tlb_inst_4k_4M,
42     Tlb_data_2M_4M,
43   };
44
45   enum
46   {
47     Ldt_entry_size = 8,
48   };
49
50   enum Local_features
51   {
52     Lf_rdpmc            = 0x00000001,
53     Lf_rdpmc32          = 0x00000002,
54   };
55
56   Unsigned64 time_us() const;
57   int can_wrmsr() const;
58
59 private:
60   void init();
61   Unsigned64 _frequency;
62   Unsigned32 _version;
63   Unsigned32 _brand;
64   Unsigned32 _features;
65   Unsigned32 _ext_features;
66   Unsigned32 _ext_8000_0001_ecx;
67   Unsigned32 _ext_8000_0001_edx;
68   Unsigned32 _local_features;
69
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;
80
81   Unsigned16 _l1_trace_cache_size;
82   Unsigned16 _l1_trace_cache_asso;
83
84   Unsigned16 _l1_data_cache_size;
85   Unsigned16 _l1_data_cache_asso;
86   Unsigned16 _l1_data_cache_line_size;
87
88   Unsigned16 _l1_inst_cache_size;
89   Unsigned16 _l1_inst_cache_asso;
90   Unsigned16 _l1_inst_cache_line_size;
91
92   Unsigned16 _l2_cache_size;
93   Unsigned16 _l2_cache_asso;
94   Unsigned16 _l2_cache_line_size;
95
96   Unsigned32 _l3_cache_size;
97   Unsigned16 _l3_cache_asso;
98   Unsigned16 _l3_cache_line_size;
99   
100   Unsigned8 _phys_bits;
101   Unsigned8 _virt_bits;
102
103   Vendor _vendor;
104   char _model_str[32];
105
106   Unsigned32 _arch_perfmon_info_eax;
107   Unsigned32 _arch_perfmon_info_ebx;
108   Unsigned32 _arch_perfmon_info_ecx;
109
110   Unsigned32 _monitor_mwait_eax;
111   Unsigned32 _monitor_mwait_ebx;
112   Unsigned32 _monitor_mwait_ecx;
113   Unsigned32 _monitor_mwait_edx;
114
115   Unsigned32 scaler_tsc_to_ns;
116   Unsigned32 scaler_tsc_to_us;
117   Unsigned32 scaler_ns_to_tsc;
118
119 public:
120
121   void disable(unsigned cpu, char const *reason);
122
123   char const *model_str() const { return _model_str; }
124   Vendor vendor() const { return _vendor; }
125
126   unsigned family() const
127   { return (_version >> 8 & 0xf) + (_version >> 20 & 0xff); }
128
129   char const *vendor_str() const
130   { return _vendor == Vendor_unknown ? "Unknown" : vendor_ident[_vendor]; }
131
132   unsigned model() const
133   { return (_version >> 4 & 0xf) + (_version >> 12 & 0xf0); }
134
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; }
158
159   Address volatile &kernel_sp() const;
160
161 public:
162   static Per_cpu<Cpu> cpus asm ("CPUS_BASE");
163   static Cpu *boot_cpu() { return _boot_cpu; }
164
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; }
170
171 private:
172
173   static Cpu *_boot_cpu;
174
175   struct Vendor_table {
176     Unsigned32 vendor_mask;
177     Unsigned32 vendor_code;
178     Unsigned16 l2_cache;
179     char       vendor_string[32];
180   } __attribute__((packed));
181
182   struct Cache_table {
183     Unsigned8  desc;
184     Unsigned8  level;
185     Unsigned16 size;
186     Unsigned8  asso;
187     Unsigned8  line_size;
188   };
189
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[];
200
201   static Cache_table const intel_cache_table[];
202
203   static char const * const vendor_ident[];
204   static Vendor_table const * const vendor_table[];
205
206   static char const * const exception_strings[];
207 };
208
209
210 //-----------------------------------------------------------------------------
211 /*
212  * Fiasco ia32-native
213  * Architecture specific cpu init code
214  */
215 INTERFACE [ia32, amd64]:
216
217 #include "l4_types.h"
218 #include "initcalls.h"
219 #include "per_cpu_data.h"
220 #include "gdt.h"
221
222 class Gdt;
223 class Tss;
224
225
226 EXTENSION class Cpu 
227 {
228 public:
229   enum Lbr
230   {
231     Lbr_uninitialized = 0,
232     Lbr_unsupported,
233     Lbr_pentium_6,
234     Lbr_pentium_4,
235     Lbr_pentium_4_ext,
236   };
237
238   enum Bts
239   {
240     Bts_uninitialized = 0,
241     Bts_unsupported,
242     Bts_pentium_m,
243     Bts_pentium_4,
244   };
245
246 private:
247   /** Flags if lbr or bts facilities are activated, used by double-fault
248    *  handler to reset the debugging facilities
249    */
250   Unsigned32 debugctl_busy;
251
252   /** debugctl value for activating lbr or bts */
253   Unsigned32 debugctl_set;
254
255   /** debugctl value to reset activated lr/bts facilities in the double-faukt
256    *  handler
257    */
258   Unsigned32 debugctl_reset;
259
260   /** supported lbr type */
261   Lbr _lbr;
262
263   /** supported bts type */
264   Bts _bts;
265
266   /** is lbr active ? */
267   char lbr_active;
268
269   /** is btf active ? */
270   char btf_active;
271
272   /** is bts active ? */
273   char bts_active;
274
275   Gdt *gdt;
276   Tss *tss;
277   Tss *tss_dbf;
278
279 public:
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; }
285
286   Gdt* get_gdt() const { return gdt; }
287   Tss* get_tss() const { return tss; }
288   void set_gdt() const
289   {
290     Pseudo_descriptor desc((Address)gdt, Gdt::gdt_max-1);
291     Gdt::set (&desc);
292   }
293
294   void set_tss() const { set_tr(Gdt::gdt_tss); }
295
296 private:
297   void init_lbr_type();
298   void init_bts_type();
299
300 };
301
302 //-----------------------------------------------------------------------------
303 IMPLEMENTATION[ia32,amd64,ux]:
304
305 #include <cstdio>
306 #include <cstring>
307 #include "config.h"
308 #include "panic.h"
309 #include "processor.h"
310
311 Per_cpu<Cpu> DEFINE_PER_CPU_P(0) Cpu::cpus(true);
312 Cpu *Cpu::_boot_cpu;
313
314
315 Cpu::Vendor_table const Cpu::intel_table[] FIASCO_INITDATA_CPU =
316 {
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, ""                                }
375 };
376
377 Cpu::Vendor_table const Cpu::amd_table[] FIASCO_INITDATA_CPU =
378 {
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)"           },
431   { 0x0,        0x0,        0,      ""                             }
432 };
433
434 Cpu::Vendor_table const Cpu::cyrix_table[] FIASCO_INITDATA_CPU =
435 {
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, ""                                }
442 };
443
444 Cpu::Vendor_table const Cpu::via_table[] FIASCO_INITDATA_CPU =
445 {
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, ""                                }
457 };
458
459 Cpu::Vendor_table const Cpu::umc_table[] FIASCO_INITDATA_CPU =
460 {
461   { 0xFF0, 0x410, 0xFFFF, "U5D"                             },
462   { 0xFF0, 0x420, 0xFFFF, "U5S"                             },
463   { 0x0,   0x0,   0xFFFF, ""                                }
464 };
465
466 Cpu::Vendor_table const Cpu::nexgen_table[] FIASCO_INITDATA_CPU =
467 {
468   { 0xFF0, 0x500, 0xFFFF, "Nx586"                           },
469   { 0x0,   0x0,   0xFFFF, ""                                }
470 };
471
472 Cpu::Vendor_table const Cpu::rise_table[] FIASCO_INITDATA_CPU =
473 {
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, ""                                }
479 };
480
481 Cpu::Vendor_table const Cpu::transmeta_table[] FIASCO_INITDATA_CPU =
482 {
483   { 0xFFF, 0x542, 0xFFFF, "TM3x00 (Crusoe)"                 },
484   { 0xFFF, 0x543, 0xFFFF, "TM5x00 (Crusoe)"                 },
485   { 0xFF0, 0xf20, 0xFFFF, "TM8x00 (Efficeon)"               },
486   { 0x0,   0x0,   0xFFFF, ""                                }
487 };
488
489 Cpu::Vendor_table const Cpu::sis_table[] FIASCO_INITDATA_CPU =
490 {
491   { 0xFF0, 0x500, 0xFFFF, "55x"                             },
492   { 0x0,   0x0,   0xFFFF, ""                                }
493 };
494
495 Cpu::Vendor_table const Cpu::nsc_table[] FIASCO_INITDATA_CPU =
496 {
497   { 0xFF0, 0x540, 0xFFFF, "Geode GX1"                       },
498   { 0xFF0, 0x550, 0xFFFF, "Geode GX2"                       },
499   { 0xFF0, 0x680, 0xFFFF, "Geode NX"                        },
500   { 0x0,   0x0,   0xFFFF, ""                                }
501 };
502
503 Cpu::Cache_table const Cpu::intel_cache_table[] FIASCO_INITDATA_CPU =
504 {
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 }
599 };
600
601 char const * const Cpu::vendor_ident[] =
602 {
603    0,
604   "GenuineIntel",
605   "AuthenticAMD",
606   "CyrixInstead",
607   "CentaurHauls",
608   "UMC UMC UMC ",
609   "NexGenDriven",
610   "RiseRiseRise",
611   "GenuineTMx86",
612   "SiS SiS SiS ",
613   "Geode by NSC"
614 };
615
616 Cpu::Vendor_table const * const Cpu::vendor_table[] =
617 {
618   0,
619   intel_table,
620   amd_table,
621   cyrix_table,
622   via_table,
623   umc_table,
624   nexgen_table,
625   rise_table,
626   transmeta_table,
627   sis_table,
628   nsc_table
629 };
630
631 char const * const Cpu::exception_strings[] =
632 {
633   /*  0 */ "Divide Error",
634   /*  1 */ "Debug",
635   /*  2 */ "NMI Interrupt",
636   /*  3 */ "Breakpoint",
637   /*  4 */ "Overflow",
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",
648   /* 15 */ "Reserved",
649   /* 16 */ "Floating-Point Error",
650   /* 17 */ "Alignment Check",
651   /* 18 */ "Machine Check",
652   /* 19 */ "SIMD Floating-Point Exception",
653   /* 20 */ "Reserved",
654   /* 21 */ "Reserved",
655   /* 22 */ "Reserved",
656   /* 23 */ "Reserved",
657   /* 24 */ "Reserved",
658   /* 25 */ "Reserved",
659   /* 26 */ "Reserved",
660   /* 27 */ "Reserved",
661   /* 28 */ "Reserved",
662   /* 29 */ "Reserved",
663   /* 30 */ "Reserved",
664   /* 31 */ "Reserved"
665 };
666
667 PUBLIC explicit FIASCO_INIT_CPU
668 Cpu::Cpu(unsigned cpu)
669 {
670   set_id(cpu);
671   if (cpu == 0)
672     {
673       _boot_cpu = this;
674       set_online(1);
675     }
676
677   init();
678 }
679
680
681 PUBLIC static
682 void
683 Cpu::init_global_features()
684 {}
685
686 PUBLIC static
687 char const *
688 Cpu::exception_string(Mword trapno)
689 {
690   if (trapno > 32)
691     return "Maskable Interrupt";
692   return exception_strings[trapno];
693 }
694
695 PUBLIC static inline FIASCO_INIT_CPU
696 void
697 Cpu::cpuid(Unsigned32 const mode,
698            Unsigned32 *const eax, Unsigned32 *const ebx,
699            Unsigned32 *const ecx, Unsigned32 *const edx)
700 {
701   asm volatile ("cpuid" : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
702                         : "a" (mode));
703 }
704
705
706
707 PRIVATE FIASCO_INIT_CPU
708 void
709 Cpu::cache_tlb_intel()
710 {
711   Unsigned8 desc[16];
712   unsigned i, count = 0;
713   Cache_table const *table;
714
715   do
716     {
717       cpuid(2, (Unsigned32 *)(desc),
718                (Unsigned32 *)(desc + 4),
719                (Unsigned32 *)(desc + 8),
720                (Unsigned32 *)(desc + 12));
721
722       for (i = 1; i < 16; i++)
723         {
724           // Null descriptor or register bit31 set (reserved)
725           if (!desc[i] || (desc[i / 4 * 4 + 3] & (1 << 7)))
726             continue;
727
728           for (table = intel_cache_table; table->desc; table++)
729             {
730               if (table->desc == desc[i])
731                 {
732                   switch (table->level)
733                     {
734                     case Cache_l1_data:
735                       _l1_data_cache_size      = table->size;
736                       _l1_data_cache_asso      = table->asso;
737                       _l1_data_cache_line_size = table->line_size;
738                       break;
739                     case Cache_l1_inst:
740                       _l1_inst_cache_size      = table->size;
741                       _l1_inst_cache_asso      = table->asso;
742                       _l1_inst_cache_line_size = table->line_size;
743                       break;
744                     case Cache_l1_trace:
745                       _l1_trace_cache_size = table->size;
746                       _l1_trace_cache_asso = table->asso;
747                       break;
748                     case Cache_l2:
749                       _l2_cache_size      = table->size;
750                       _l2_cache_asso      = table->asso;
751                       _l2_cache_line_size = table->line_size;
752                       break;
753                     case Cache_l3:
754                       _l3_cache_size      = table->size;
755                       _l3_cache_asso      = table->asso;
756                       _l3_cache_line_size = table->line_size;
757                       break;
758                     case Tlb_inst_4k:
759                       _inst_tlb_4k_entries += table->size;
760                       break;
761                     case Tlb_data_4k:
762                       _data_tlb_4k_entries += table->size;
763                       break;
764                     case Tlb_inst_4M:
765                       _inst_tlb_4m_entries += table->size;
766                       break;
767                     case Tlb_data_4M:
768                       _data_tlb_4m_entries += table->size;
769                       break;
770                     case Tlb_inst_4k_4M:
771                       _inst_tlb_4k_4m_entries += table->size;
772                       break;
773                     case Tlb_data_4k_4M:
774                       _data_tlb_4k_4m_entries += table->size;
775                       break;
776                     default:
777                       break;
778                     }
779                   break;
780                 }
781             }
782         }
783     } 
784   while (++count < *desc);
785 }
786
787 PRIVATE FIASCO_INIT_CPU
788 void
789 Cpu::cache_tlb_l1()
790 {
791   Unsigned32 eax, ebx, ecx, edx;
792   cpuid(0x80000005, &eax, &ebx, &ecx, &edx);
793
794   _l1_data_cache_size      = (ecx >> 24) & 0xFF;
795   _l1_data_cache_asso      = (ecx >> 16) & 0xFF;
796   _l1_data_cache_line_size =  ecx        & 0xFF;
797
798   _l1_inst_cache_size      = (edx >> 24) & 0xFF;
799   _l1_inst_cache_asso      = (edx >> 16) & 0xFF;
800   _l1_inst_cache_line_size =  edx        & 0xFF;
801
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;
806 }
807
808 PRIVATE FIASCO_INIT_CPU
809 void
810 Cpu::cache_tlb_l2_l3()
811 {
812   Unsigned32 eax, ebx, ecx, edx;
813   cpuid(0x80000006, &eax, &ebx, &ecx, &edx);
814
815   if (vendor() == Vendor_via)
816     {
817       _l2_cache_size          = (ecx >> 24) & 0xFF;
818       _l2_cache_asso          = (ecx >> 16) & 0xFF;
819     }
820   else
821     {
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;
828     }
829
830   _l2_cache_line_size = ecx & 0xFF;
831
832   _l3_cache_size      = (edx >> 18) << 9;
833   _l3_cache_asso      = (edx >> 12) & 0xF;
834   _l3_cache_line_size = edx & 0xFF;
835 }
836
837 PRIVATE FIASCO_INIT_CPU
838 void
839 Cpu::addr_size_info()
840 {
841   Unsigned32 eax, ebx, ecx, edx;
842   cpuid(0x80000008, &eax, &ebx, &ecx, &edx);
843
844   _phys_bits = eax & 0xff;
845   _virt_bits = (eax & 0xff00) >> 8;
846 }
847
848 PUBLIC static
849 unsigned
850 Cpu::amd_cpuid_mnc()
851 {
852   Unsigned32 eax, ebx, ecx, edx;
853   cpuid(0x80000008, &eax, &ebx, &ecx, &edx);
854
855   unsigned apicidcoreidsize = (ecx >> 12) & 0xf;
856   if (apicidcoreidsize == 0)
857     return (ecx & 0xf) + 1; // NC
858   return 1 << apicidcoreidsize;
859 }
860
861 PRIVATE FIASCO_INIT_CPU
862 void
863 Cpu::set_model_str()
864 {
865   Vendor_table const *table;
866
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))
870       {
871         snprintf(_model_str, sizeof (_model_str), "%s",
872                  table->vendor_string);
873         return;
874       }
875
876   snprintf(_model_str, sizeof (_model_str), "Unknown CPU");
877 }
878
879 PUBLIC inline FIASCO_INIT_CPU
880 void
881 Cpu::arch_perfmon_info(Unsigned32 *eax, Unsigned32 *ebx, Unsigned32 *ecx) const
882 {
883   *eax = _arch_perfmon_info_eax;
884   *ebx = _arch_perfmon_info_ebx;
885   *ecx = _arch_perfmon_info_ecx;
886 }
887
888 PUBLIC static
889 unsigned long
890 Cpu::get_features()
891 {
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)
896     return 0;
897
898   // Check for CPUID Support
899   set_flags(eflags ^ EFLAGS_ID);
900   if (!((get_flags() ^ eflags) & EFLAGS_ID))
901     return 0;
902
903   Unsigned32 max;
904   char vendor_id[12];
905
906   cpuid(0, &max, (Unsigned32 *)(vendor_id),
907                  (Unsigned32 *)(vendor_id + 8),
908                  (Unsigned32 *)(vendor_id + 4));
909
910   if (!max)
911     return 0;
912
913   Unsigned32 dummy, dummy1, dummy2, features;
914   cpuid (1, &dummy, &dummy1, &dummy2, &features);
915
916   return features;
917 }
918
919
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.
925  */
926 PUBLIC FIASCO_INIT_CPU
927 void
928 Cpu::identify()
929 {
930   Unsigned32 eflags = get_flags();
931
932   _phys_bits = 32;
933   _virt_bits = 32;
934
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;
942
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");
947
948   // Check for CPUID Support
949   set_flags(eflags ^ EFLAGS_ID);
950   if ((get_flags() ^ eflags) & EFLAGS_ID) {
951
952     Unsigned32 max, i;
953     char vendor_id[12];
954
955     cpuid(0, &max, (Unsigned32 *)(vendor_id),
956                    (Unsigned32 *)(vendor_id + 8),
957                    (Unsigned32 *)(vendor_id + 4));
958
959     for (i = sizeof (vendor_ident) / sizeof (*vendor_ident) - 1; i; i--)
960       if (!memcmp(vendor_id, vendor_ident[i], 12))
961         break;
962
963     _vendor = (Cpu::Vendor)i;
964
965     switch (max)
966       {
967       default:
968         // All cases fall through!
969       case 10:
970         cpuid(10, &_arch_perfmon_info_eax,
971                   &_arch_perfmon_info_ebx,
972                   &_arch_perfmon_info_ecx, &i);
973       case 2:
974         if (_vendor == Vendor_intel)
975           cache_tlb_intel();
976       case 1:
977         cpuid(1, &_version, &_brand, &_ext_features, &_features);
978       }
979
980     if (max >= 5 && has_monitor_mwait())
981       cpuid(5, &_monitor_mwait_eax, &_monitor_mwait_ebx,
982                &_monitor_mwait_ecx, &_monitor_mwait_edx);
983
984     if (_vendor == Vendor_intel)
985       {
986         switch (family())
987           {
988           case 5:
989             // Avoid Pentium Erratum 74
990             if ((_features & FEAT_MMX) &&
991                 (model() != 4 ||
992                  (stepping() != 4 && (stepping() != 3 || type() != 1))))
993               _local_features |= Lf_rdpmc;
994             break;
995           case 6:
996             // Avoid Pentium Pro Erratum 26
997             if (model() >= 3 || stepping() > 9)
998               _local_features |= Lf_rdpmc;
999             break;
1000           case 15:
1001             _local_features |= Lf_rdpmc;
1002             _local_features |= Lf_rdpmc32;
1003             break;
1004           }
1005       }
1006     else if (_vendor == Vendor_amd)
1007       {
1008         switch (family())
1009           {
1010           case 6:
1011           case 15:
1012             _local_features |= Lf_rdpmc;
1013             break;
1014           }
1015       }
1016
1017     // Get maximum number for extended functions
1018     cpuid(0x80000000, &max, &i, &i, &i);
1019
1020     if (max > 0x80000000)
1021       {
1022         switch (max)
1023           {
1024           default:
1025             // All cases fall through!
1026           case 0x80000008:
1027             if (_vendor == Vendor_amd || _vendor == Vendor_intel)
1028               addr_size_info();
1029           case 0x80000007:
1030           case 0x80000006:
1031             if (_vendor == Vendor_amd || _vendor == Vendor_via)
1032               cache_tlb_l2_l3();
1033           case 0x80000005:
1034             if (_vendor == Vendor_amd || _vendor == Vendor_via)
1035               cache_tlb_l1();
1036           case 0x80000004:
1037           case 0x80000003:
1038           case 0x80000002:
1039           case 0x80000001:
1040             if (_vendor == Vendor_intel || _vendor == Vendor_amd)
1041               cpuid(0x80000001, &i, &i, &_ext_8000_0001_ecx,
1042                                 &_ext_8000_0001_edx);
1043             break;
1044           }
1045       }
1046
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;
1051
1052   } else
1053     _version = 0x400;
1054
1055   set_model_str();
1056
1057   set_flags(eflags);
1058 }
1059
1060 PUBLIC inline NEEDS["processor.h"]
1061 void
1062 Cpu::busy_wait_ns(Unsigned64 ns)
1063 {
1064   Unsigned64 stop = rdtsc () + ns_to_tsc(ns);
1065
1066   while (rdtsc() < stop)
1067     Proc::pause();
1068 }
1069
1070
1071 PUBLIC
1072 void
1073 Cpu::show_cache_tlb_info(const char *indent) const
1074 {
1075   char s[16];
1076
1077   *s = '\0';
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);
1082   *s = '\0';
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)
1091     putchar('\n');
1092   *s = '\0';
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);
1097   *s = '\0';
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)
1106     putchar('\n');
1107
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);
1112
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);
1117
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);
1124
1125   if (_l3_cache_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);
1128 }
1129
1130 IMPLEMENT
1131 void 
1132 Cpu::disable(unsigned cpu, char const *reason)
1133 {
1134   printf("CPU%u: is disabled: %s\n", cpu, reason);
1135 }
1136
1137 // Function used for calculating apic scaler
1138 PUBLIC static inline
1139 Unsigned32
1140 Cpu::muldiv(Unsigned32 val, Unsigned32 mul, Unsigned32 div)
1141 {
1142   Unsigned32 dummy;
1143
1144   asm volatile ("mull %3 ; divl %4\n\t"
1145                :"=a" (val), "=d" (dummy)
1146                : "0" (val),  "d" (mul),  "c" (div));
1147   return val;
1148 }
1149
1150
1151 PUBLIC static inline
1152 Unsigned32
1153 Cpu::get_cs()
1154 {
1155   Unsigned32 val;
1156   asm volatile ("mov %%cs, %0" : "=rm" (val));
1157   return val;
1158 }
1159
1160 PUBLIC static inline
1161 Unsigned32
1162 Cpu::get_ds()
1163 {
1164   Unsigned32 val;
1165   asm volatile ("mov %%ds, %0" : "=rm" (val));
1166   return val;
1167 }
1168
1169 PUBLIC static inline
1170 Unsigned32
1171 Cpu::get_es()
1172 {
1173   Unsigned32 val;
1174   asm volatile ("mov %%es, %0" : "=rm" (val));
1175   return val;
1176 }
1177
1178 PUBLIC static inline
1179 Unsigned32
1180 Cpu::get_ss()
1181 {
1182   Unsigned32 val;
1183   asm volatile ("mov %%ss, %0" : "=rm" (val));
1184   return val;
1185 }
1186
1187 PUBLIC static inline
1188 Unsigned32
1189 Cpu::get_fs()
1190 {
1191   Unsigned32 val;
1192   asm volatile ("mov %%fs, %0" : "=rm" (val));
1193   return val;
1194 }
1195
1196 PUBLIC static inline
1197 void
1198 Cpu::set_ds(Unsigned32 val)
1199 { asm volatile ("mov %0, %%ds" : : "rm" (val)); }
1200
1201 PUBLIC static inline
1202 void
1203 Cpu::set_es(Unsigned32 val)
1204 { asm volatile ("mov %0, %%es" : : "rm" (val)); }
1205
1206 PUBLIC static inline
1207 void
1208 Cpu::set_fs(Unsigned32 val)
1209 { asm volatile ("mov %0, %%fs" : : "rm" (val)); }
1210
1211
1212 //----------------------------------------------------------------------------
1213 IMPLEMENTATION[ia32, amd64]:
1214
1215 #include "boot_info.h"
1216 #include "config.h"
1217 #include "div32.h"
1218 #include "gdt.h"
1219 #include "globals.h"
1220 #include "initcalls.h"
1221 #include "io.h"
1222 #include "pit.h"
1223 #include "processor.h"
1224 #include "regdefs.h"
1225 #include "tss.h"
1226
1227
1228 PUBLIC static inline
1229 void
1230 Cpu::set_cr0(unsigned long val)
1231 { asm volatile ("mov %0, %%cr0" : : "r" (val)); }
1232
1233 PUBLIC static inline
1234 void
1235 Cpu::set_pdbr(unsigned long addr)
1236 { asm volatile ("mov %0, %%cr3" : : "r" (addr)); }
1237
1238 PUBLIC static inline
1239 void
1240 Cpu::set_cr4(unsigned long val)
1241 { asm volatile ("mov %0, %%cr4" : : "r" (val)); }
1242
1243 PUBLIC static inline
1244 void
1245 Cpu::set_ldt(Unsigned16 val)
1246 { asm volatile ("lldt %0" : : "rm" (val)); }
1247
1248
1249 PUBLIC static inline
1250 void
1251 Cpu::set_ss(Unsigned32 val)
1252 { asm volatile ("mov %0, %%ss" : : "r" (val)); }
1253
1254 PUBLIC static inline
1255 void
1256 Cpu::set_tr(Unsigned16 val)
1257 { asm volatile ("ltr %0" : : "rm" (val)); }
1258
1259 PUBLIC static inline
1260 Mword
1261 Cpu::get_cr0()
1262 {
1263   Mword val;
1264   asm volatile ("mov %%cr0, %0" : "=r" (val));
1265   return val;
1266 }
1267
1268 PUBLIC static inline
1269 Address
1270 Cpu::get_pdbr()
1271 { Address addr; asm volatile ("mov %%cr3, %0" : "=r" (addr)); return addr; }
1272
1273 PUBLIC static inline
1274 Mword
1275 Cpu::get_cr4()
1276 { Mword val; asm volatile ("mov %%cr4, %0" : "=r" (val)); return val; }
1277
1278 PUBLIC static inline
1279 Unsigned16
1280 Cpu::get_ldt()
1281 { Unsigned16 val; asm volatile ("sldt %0" : "=rm" (val)); return val; }
1282
1283 PUBLIC static inline
1284 Unsigned16
1285 Cpu::get_tr()
1286 { Unsigned16 val; asm volatile ("str %0" : "=rm" (val)); return val; }
1287
1288 IMPLEMENT inline
1289 int
1290 Cpu::can_wrmsr() const
1291 { return features() & FEAT_MSR; }
1292
1293 PUBLIC static inline
1294 Unsigned64
1295 Cpu::rdmsr(Unsigned32 reg)
1296 {
1297   Unsigned32 l,h;
1298
1299   asm volatile ("rdmsr" : "=a" (l), "=d" (h) : "c" (reg));
1300   return ((Unsigned64)h << 32) + (Unsigned64)l;
1301 }
1302
1303 PUBLIC static inline
1304 Unsigned64
1305 Cpu::rdpmc(Unsigned32 idx, Unsigned32)
1306 {
1307   Unsigned32 l,h;
1308
1309   asm volatile ("rdpmc" : "=a" (l), "=d" (h) : "c" (idx));
1310   return ((Unsigned64)h << 32) + (Unsigned64)l;
1311 }
1312
1313 PUBLIC static inline
1314 void
1315 Cpu::wrmsr(Unsigned32 low, Unsigned32 high, Unsigned32 reg)
1316 { asm volatile ("wrmsr" : : "a" (low), "d" (high), "c" (reg)); }
1317
1318 PUBLIC static inline
1319 void
1320 Cpu::wrmsr(Unsigned64 msr, Unsigned32 reg)
1321 { asm volatile ("wrmsr" : : "a" ((Unsigned32)msr), "d" ((Unsigned32)(msr >> 32)), "c" (reg)); }
1322
1323 PUBLIC static inline
1324 void
1325 Cpu::enable_rdpmc()
1326 { set_cr4(get_cr4() | CR4_PCE); }
1327
1328
1329 IMPLEMENT FIASCO_INIT_CPU
1330 void
1331 Cpu::init_lbr_type()
1332 {
1333   _lbr = Lbr_unsupported;
1334
1335   if (can_wrmsr())
1336     {
1337       // Intel
1338       if (vendor() == Vendor_intel)
1339         {
1340           if (family() == 15)
1341             _lbr = model() < 3 ? Lbr_pentium_4 : Lbr_pentium_4_ext; // P4
1342           else if (family() >= 6)
1343             _lbr = Lbr_pentium_6; // PPro, PIII
1344         }
1345       else if (vendor() == Vendor_amd)
1346         {
1347           if ((family() == 6) || (family() == 15))
1348             _lbr = Lbr_pentium_6; // K7/K8
1349         }
1350     }
1351 }
1352
1353
1354 IMPLEMENT FIASCO_INIT_CPU
1355 void
1356 Cpu::init_bts_type()
1357 {
1358   _bts = Bts_unsupported;
1359
1360   if (can_wrmsr() && vendor() == Vendor_intel)
1361     {
1362       if (family() == 15 && (rdmsr(0x1A0) & (1<<11)) == 0)
1363         _bts = Bts_pentium_4;
1364       if (family() == 6  && (model() == 9 || (model() >= 13 &&
1365               model() <= 15)))
1366         _bts = Bts_pentium_m;
1367       if (!(features() & FEAT_DS))
1368         _bts = Bts_unsupported;
1369     }
1370 }
1371
1372
1373 PUBLIC inline
1374 void
1375 Cpu::lbr_enable(bool on)
1376 {
1377   if (lbr_type() != Lbr_unsupported)
1378     {
1379       if (on)
1380         {
1381           lbr_active    = true;
1382           debugctl_set |= 1;
1383           debugctl_busy = true;
1384         }
1385       else
1386         {
1387           lbr_active    = false;
1388           debugctl_set &= ~1;
1389           debugctl_busy = lbr_active || bts_active;
1390           wrmsr(debugctl_reset, MSR_DEBUGCTLA);
1391         }
1392     }
1393 }
1394
1395
1396 PUBLIC inline
1397 void
1398 Cpu::btf_enable(bool on)
1399 {
1400   if (lbr_type() != Lbr_unsupported)
1401     {
1402       if (on)
1403         {
1404           btf_active      = true;
1405           debugctl_set   |= 2;
1406           debugctl_reset |= 2; /* don't disable bit in kernel */
1407           wrmsr(2, MSR_DEBUGCTLA);     /* activate _now_ */
1408         }
1409       else
1410         {
1411           btf_active    = false;
1412           debugctl_set &= ~2;
1413           debugctl_busy = lbr_active || bts_active;
1414           wrmsr(debugctl_reset, MSR_DEBUGCTLA);
1415         }
1416     }
1417 }
1418
1419
1420 PUBLIC
1421 void
1422 Cpu::bts_enable(bool on)
1423 {
1424   if (bts_type() != Bts_unsupported)
1425     {
1426       if (on)
1427         {
1428           switch (bts_type())
1429             {
1430             case Bts_pentium_4: bts_active = true; debugctl_set |= 0x0c; break;
1431             case Bts_pentium_m: bts_active = true; debugctl_set |= 0xc0; break;
1432             default:;
1433             }
1434           debugctl_busy = lbr_active || bts_active;
1435         }
1436       else
1437         {
1438           bts_active = false;
1439           switch (bts_type())
1440             {
1441             case Bts_pentium_4: debugctl_set &= ~0x0c; break;
1442             case Bts_pentium_m: debugctl_set &= ~0xc0; break;
1443             default:;
1444             }
1445           debugctl_busy = lbr_active || bts_active;
1446           wrmsr(debugctl_reset, MSR_DEBUGCTLA);
1447         }
1448     }
1449 }
1450
1451 PUBLIC inline
1452 void
1453 Cpu::debugctl_enable()
1454 {
1455   if (debugctl_busy)
1456     wrmsr(debugctl_set, MSR_DEBUGCTLA);
1457 }
1458
1459 PUBLIC inline
1460 void
1461 Cpu::debugctl_disable()
1462 {
1463   if (debugctl_busy)
1464     wrmsr(debugctl_reset, MSR_DEBUGCTLA);
1465 }
1466
1467 /*
1468  * AMD OS-Visible Workaround Information
1469  * print a warning if a CPU is affected by any known erratum
1470  */
1471 PUBLIC
1472 void
1473 Cpu::print_errata()
1474 {
1475   if (vendor() == Vendor_amd && has_amd_osvw() && can_wrmsr())
1476     {
1477       Unsigned16 osvw_id_length, i;
1478       bool affected = false;
1479       osvw_id_length = rdmsr(0xc0010140) & 0xff;
1480
1481       for (i = 1; ((i - 1) * 64) < osvw_id_length; i++)
1482         {
1483           Unsigned64 osvw_msr = rdmsr(0xc0010140 + i);
1484           if (osvw_msr != 0)
1485             {
1486               printf("\033[31mOSVW_MSR%d = 0x%016llx\033[m\n",
1487                      i, rdmsr(0xc0010140 + i));
1488               affected = true;
1489             }
1490         }
1491       if (affected)
1492         printf("\033[31m#Errata known %d, affected by at least one\033[m\n",
1493                osvw_id_length);
1494     }
1495 }
1496
1497 IMPLEMENT FIASCO_INIT_CPU
1498 void
1499 Cpu::init()
1500 {
1501   identify();
1502
1503   init_lbr_type();
1504   init_bts_type();
1505
1506   calibrate_tsc();
1507
1508   if (scaler_tsc_to_ns)
1509     _frequency = ns_to_tsc(1000000000UL);
1510
1511   Unsigned32 cr4 = get_cr4();
1512
1513   if (features() & FEAT_FXSR)
1514     cr4 |= CR4_OSFXSR;
1515
1516   if (features() & FEAT_SSE)
1517     cr4 |= CR4_OSXMMEXCPT;
1518
1519   set_cr4 (cr4);
1520
1521   // reset time stamp counter (better for debugging)
1522   if ((features() & FEAT_TSC) && can_wrmsr())
1523     wrmsr(0, 0, 0x10);
1524
1525   if ((features() & FEAT_PAT) && can_wrmsr())
1526     wrmsr(0x00010406, 0x00070406, 0x277);
1527
1528   print_errata();
1529 }
1530
1531 PUBLIC
1532 void
1533 Cpu::print() const
1534 {
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));
1539 }
1540
1541 PUBLIC
1542 void
1543 Cpu::set_sysenter(void (*func)(void))
1544 {
1545   // Check for Sysenter/Sysexit Feature
1546   if (sysenter())
1547     wrmsr ((Mword) func, 0, MSR_SYSENTER_EIP);
1548 }
1549
1550
1551 PUBLIC
1552 void
1553 Cpu::set_fast_entry(void (*func)(void))
1554 {
1555   set_sysenter(func);
1556 }
1557
1558 extern "C" void entry_sys_fast_ipc (void);
1559 extern "C" void entry_sys_fast_ipc_c (void);
1560
1561 PUBLIC FIASCO_INIT_CPU
1562 void
1563 Cpu::init_sysenter()
1564 {
1565   // Check for Sysenter/Sysexit Feature
1566   if (sysenter())
1567     {
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);
1572       else
1573         set_sysenter(entry_sys_fast_ipc_c);
1574     }
1575 }
1576
1577
1578 // Return 2^32 / (tsc clocks per usec)
1579 FIASCO_INIT_CPU
1580 void
1581 Cpu::calibrate_tsc ()
1582 {
1583   const unsigned calibrate_time = 50000 /*us*/ + 1;
1584
1585   // sanity check
1586   if (! (features() & FEAT_TSC))
1587     goto bad_ctc;
1588
1589   Unsigned64 tsc_start, tsc_end;
1590   Unsigned32 count, tsc_to_ns_div, dummy;
1591
1592     {
1593       // disable interrupts
1594       Proc::Status o = Proc::cli_save();
1595
1596       Pit::setup_channel2_to_20hz();
1597
1598       tsc_start = rdtsc ();
1599       count = 0;
1600       do
1601         {
1602           count++;
1603         }
1604       while ((Io::in8 (0x61) & 0x20) == 0);
1605       tsc_end = rdtsc ();
1606
1607       // restore flags
1608       Proc::sti_restore(o);
1609     }
1610
1611   // Error: ECTCNEVERSET
1612   if (count <= 1)
1613     goto bad_ctc;
1614
1615   tsc_end -= tsc_start;
1616
1617   // prevent overflow in division (CPU too fast)
1618   if (tsc_end & 0xffffffff00000000LL)
1619     goto bad_ctc;
1620
1621   // prevent overflow in division (CPU too slow)
1622   if ((tsc_end & 0xffffffffL) < calibrate_time)
1623     goto bad_ctc;
1624
1625   // tsc_to_ns_div = calibrate_time * 2^32 / tsc
1626   asm ("divl %2"
1627        :"=a" (tsc_to_ns_div), "=d" (dummy)
1628        :"r" ((Unsigned32)tsc_end), "a" (0), "d" (calibrate_time));
1629
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);
1634
1635   return;
1636
1637 bad_ctc:
1638   if (Config::kinfo_timer_uses_rdtsc)
1639     panic("Can't calibrate tsc");
1640 }
1641
1642 IMPLEMENT inline
1643 Unsigned64
1644 Cpu::time_us() const
1645 {
1646   return tsc_to_us (rdtsc());
1647 }
1648
1649
1650 PUBLIC inline
1651 void
1652 Cpu::enable_ldt(Address addr, int size)
1653 {
1654   if (!size)
1655     {
1656       get_gdt()->clear_entry (Gdt::gdt_ldt / 8);
1657       set_ldt(0);
1658     }
1659   else
1660     {
1661       get_gdt()->set_entry_byte(Gdt::gdt_ldt / 8, addr, size-1, 2/*=ldt*/, 0);
1662       set_ldt(Gdt::gdt_ldt);
1663     }
1664 }
1665
1666
1667 PUBLIC static inline
1668 Unsigned32
1669 Cpu::get_gs()
1670 { Unsigned32 val; asm volatile ("mov %%gs, %0" : "=rm" (val)); return val; }
1671
1672 PUBLIC static inline
1673 void
1674 Cpu::set_gs(Unsigned32 val)
1675 { asm volatile ("mov %0, %%gs" : : "rm" (val)); }
1676
1677 IMPLEMENT inline
1678 unsigned
1679 Cpu::phys_id() const
1680 { return _brand & 0xff000000; }
1681
1682 PUBLIC static
1683 unsigned
1684 Cpu::phys_id_direct()
1685 {
1686   Unsigned32 a,b,c,d;
1687   cpuid (1, &a, &b, &c, &d);
1688   return b & 0xff000000;
1689 }