]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ia32/cpu-ia32.cpp
e045f64b4a3d28aaf7a23310663a52fab3fcf1e0
[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   };
43
44   enum
45   {
46     Ldt_entry_size = 8,
47   };
48
49   enum Local_features
50   {
51     Lf_rdpmc            = 0x00000001,
52     Lf_rdpmc32          = 0x00000002,
53   };
54
55   Unsigned64 time_us() const;
56   int can_wrmsr() const;
57
58 private:
59   void init();
60   Unsigned64 _frequency;
61   Unsigned32 _version;
62   Unsigned32 _brand;
63   Unsigned32 _features;
64   Unsigned32 _ext_features;
65   Unsigned32 _ext_8000_0001_ecx;
66   Unsigned32 _ext_8000_0001_edx;
67   Unsigned32 _local_features;
68
69   Unsigned16 _inst_tlb_4k_entries;
70   Unsigned16 _data_tlb_4k_entries;
71   Unsigned16 _inst_tlb_4m_entries;
72   Unsigned16 _data_tlb_4m_entries;
73   Unsigned16 _inst_tlb_4k_4m_entries;
74   Unsigned16 _data_tlb_4k_4m_entries;
75   Unsigned16 _l2_inst_tlb_4k_entries;
76   Unsigned16 _l2_data_tlb_4k_entries;
77   Unsigned16 _l2_inst_tlb_4m_entries;
78   Unsigned16 _l2_data_tlb_4m_entries;
79
80   Unsigned16 _l1_trace_cache_size;
81   Unsigned16 _l1_trace_cache_asso;
82
83   Unsigned16 _l1_data_cache_size;
84   Unsigned16 _l1_data_cache_asso;
85   Unsigned16 _l1_data_cache_line_size;
86
87   Unsigned16 _l1_inst_cache_size;
88   Unsigned16 _l1_inst_cache_asso;
89   Unsigned16 _l1_inst_cache_line_size;
90
91   Unsigned16 _l2_cache_size;
92   Unsigned16 _l2_cache_asso;
93   Unsigned16 _l2_cache_line_size;
94
95   Unsigned32 _l3_cache_size;
96   Unsigned16 _l3_cache_asso;
97   Unsigned16 _l3_cache_line_size;
98   
99   Unsigned8 _phys_bits;
100   Unsigned8 _virt_bits;
101
102   Vendor _vendor;
103   char _model_str[32];
104
105   Unsigned32 _arch_perfmon_info_eax;
106   Unsigned32 _arch_perfmon_info_ebx;
107   Unsigned32 _arch_perfmon_info_ecx;
108
109   Unsigned32 _monitor_mwait_eax;
110   Unsigned32 _monitor_mwait_ebx;
111   Unsigned32 _monitor_mwait_ecx;
112   Unsigned32 _monitor_mwait_edx;
113
114   Unsigned32 scaler_tsc_to_ns;
115   Unsigned32 scaler_tsc_to_us;
116   Unsigned32 scaler_ns_to_tsc;
117
118 public:
119
120   void disable(unsigned cpu, char const *reason);
121
122   char const *model_str() const { return _model_str; }
123   Vendor vendor() const { return _vendor; }
124
125   unsigned family() const
126   { return (_version >> 8 & 0xf) + (_version >> 20 & 0xff); }
127
128   char const *vendor_str() const
129   { return _vendor == Vendor_unknown ? "Unknown" : vendor_ident[_vendor]; }
130
131   unsigned model() const
132   { return (_version >> 4 & 0xf) + (_version >> 12 & 0xf0); }
133
134   unsigned stepping() const { return _version & 0xF; }
135   unsigned type() const { return (_version >> 12) & 0x3; }
136   Unsigned64 frequency() const { return _frequency; }
137   unsigned brand() const { return _brand & 0xFF; }
138   unsigned features() const { return _features; }
139   unsigned ext_features() const { return _ext_features; }
140   bool has_monitor_mwait() const { return _ext_features & (1 << 3); }
141   bool has_monitor_mwait_irq() const { return _monitor_mwait_ecx & 3; }
142   unsigned ext_8000_0001_ecx() const { return _ext_8000_0001_ecx; }
143   unsigned ext_8000_0001_edx() const { return _ext_8000_0001_edx; }
144   unsigned local_features() const { return _local_features; }
145   bool superpages() const { return features() & FEAT_PSE; }
146   bool tsc() const { return features() & FEAT_TSC; }
147   bool sysenter() const { return features() & FEAT_SEP; }
148   bool syscall() const { return ext_8000_0001_edx() & FEATA_SYSCALL; }
149   bool vmx() { return boot_cpu()->ext_features() & FEATX_VMX; }
150   bool svm() { return boot_cpu()->ext_8000_0001_ecx() & FEATA_SVM; }
151   bool has_amd_osvw() { return  boot_cpu()->ext_8000_0001_ecx() & (1<<9); }
152   unsigned virt_bits() const { return _virt_bits; }
153   unsigned phys_bits() const { return _phys_bits; }
154   Unsigned32 get_scaler_tsc_to_ns() const { return scaler_tsc_to_ns; }
155   Unsigned32 get_scaler_tsc_to_us() const { return scaler_tsc_to_us; }
156   Unsigned32 get_scaler_ns_to_tsc() const { return scaler_ns_to_tsc; }
157
158   Address volatile &kernel_sp() const;
159
160 public:
161   static Per_cpu<Cpu> cpus asm ("CPUS_BASE");
162   static Cpu *boot_cpu() { return _boot_cpu; }
163
164   static bool have_superpages() { return boot_cpu()->superpages(); }
165   static bool have_sysenter() { return boot_cpu()->sysenter(); }
166   static bool have_syscall() { return boot_cpu()->syscall(); }
167   static bool have_fxsr() { return boot_cpu()->features() & FEAT_FXSR; }
168   static bool have_pge() { return boot_cpu()->features() & FEAT_PGE; }
169
170 private:
171
172   static Cpu *_boot_cpu;
173
174   struct Vendor_table {
175     Unsigned32 vendor_mask;
176     Unsigned32 vendor_code;
177     Unsigned16 l2_cache;
178     char       vendor_string[32];
179   } __attribute__((packed));
180
181   struct Cache_table {
182     Unsigned8  desc;
183     Unsigned8  level;
184     Unsigned16 size;
185     Unsigned8  asso;
186     Unsigned8  line_size;
187   };
188
189   static Vendor_table const intel_table[];
190   static Vendor_table const amd_table[];
191   static Vendor_table const cyrix_table[];
192   static Vendor_table const via_table[];
193   static Vendor_table const umc_table[];
194   static Vendor_table const nexgen_table[];
195   static Vendor_table const rise_table[];
196   static Vendor_table const transmeta_table[];
197   static Vendor_table const sis_table[];
198   static Vendor_table const nsc_table[];
199
200   static Cache_table const intel_cache_table[];
201
202   static char const * const vendor_ident[];
203   static Vendor_table const * const vendor_table[];
204
205   static char const * const exception_strings[];
206 };
207
208
209 //-----------------------------------------------------------------------------
210 /*
211  * Fiasco ia32-native
212  * Architecture specific cpu init code
213  */
214 INTERFACE [ia32, amd64]:
215
216 #include "l4_types.h"
217 #include "initcalls.h"
218 #include "per_cpu_data.h"
219 #include "gdt.h"
220
221 class Gdt;
222 class Tss;
223
224
225 EXTENSION class Cpu 
226 {
227 public:
228   enum Lbr
229   {
230     Lbr_uninitialized = 0,
231     Lbr_unsupported,
232     Lbr_pentium_6,
233     Lbr_pentium_4,
234     Lbr_pentium_4_ext,
235   };
236
237   enum Bts
238   {
239     Bts_uninitialized = 0,
240     Bts_unsupported,
241     Bts_pentium_m,
242     Bts_pentium_4,
243   };
244
245 private:
246   /** Flags if lbr or bts facilities are activated, used by double-fault
247    *  handler to reset the debugging facilities
248    */
249   Unsigned32 debugctl_busy;
250
251   /** debugctl value for activating lbr or bts */
252   Unsigned32 debugctl_set;
253
254   /** debugctl value to reset activated lr/bts facilities in the double-faukt
255    *  handler
256    */
257   Unsigned32 debugctl_reset;
258
259   /** supported lbr type */
260   Lbr _lbr;
261
262   /** supported bts type */
263   Bts _bts;
264
265   /** is lbr active ? */
266   char lbr_active;
267
268   /** is btf active ? */
269   char btf_active;
270
271   /** is bts active ? */
272   char bts_active;
273
274   Gdt *gdt;
275   Tss *tss;
276   Tss *tss_dbf;
277
278 public:
279   Lbr lbr_type() const { return _lbr; }
280   Bts bts_type() const { return _bts; }
281   bool lbr_status() const { return lbr_active; }
282   bool bts_status() const { return bts_active; }
283   bool btf_status() const { return btf_active; }
284
285   Gdt* get_gdt() const { return gdt; }
286   Tss* get_tss() const { return tss; }
287   void set_gdt() const
288   {
289     Pseudo_descriptor desc((Address)gdt, Gdt::gdt_max-1);
290     Gdt::set (&desc);
291   }
292
293   void set_tss() const { set_tr(Gdt::gdt_tss); }
294
295 private:
296   void init_lbr_type();
297   void init_bts_type();
298
299 };
300
301 //-----------------------------------------------------------------------------
302 IMPLEMENTATION[ia32,amd64,ux]:
303
304 #include <cstdio>
305 #include <cstring>
306 #include "config.h"
307 #include "panic.h"
308 #include "processor.h"
309
310 Per_cpu<Cpu> DEFINE_PER_CPU_P(0) Cpu::cpus(true);
311 Cpu *Cpu::_boot_cpu;
312
313
314 Cpu::Vendor_table const Cpu::intel_table[] FIASCO_INITDATA_CPU =
315 {
316   { 0xf0fF0, 0x00400, 0xFFFF, "i486 DX-25/33"                   },
317   { 0xf0fF0, 0x00410, 0xFFFF, "i486 DX-50"                      },
318   { 0xf0fF0, 0x00420, 0xFFFF, "i486 SX"                         },
319   { 0xf0fF0, 0x00430, 0xFFFF, "i486 DX/2"                       },
320   { 0xf0fF0, 0x00440, 0xFFFF, "i486 SL"                         },
321   { 0xf0fF0, 0x00450, 0xFFFF, "i486 SX/2"                       },
322   { 0xf0fF0, 0x00470, 0xFFFF, "i486 DX/2-WB"                    },
323   { 0xf0fF0, 0x00480, 0xFFFF, "i486 DX/4"                       },
324   { 0xf0fF0, 0x00490, 0xFFFF, "i486 DX/4-WB"                    },
325   { 0xf0fF0, 0x00500, 0xFFFF, "Pentium A-Step"                  },
326   { 0xf0fF0, 0x00510, 0xFFFF, "Pentium P5"                      },
327   { 0xf0fF0, 0x00520, 0xFFFF, "Pentium P54C"                    },
328   { 0xf0fF0, 0x00530, 0xFFFF, "Pentium P24T Overdrive"          },
329   { 0xf0fF0, 0x00540, 0xFFFF, "Pentium P55C MMX"                },
330   { 0xf0fF0, 0x00570, 0xFFFF, "Pentium Mobile"                  },
331   { 0xf0fF0, 0x00580, 0xFFFF, "Pentium MMX Mobile (Tillamook)"  },
332   { 0xf0fF0, 0x00600, 0xFFFF, "Pentium-Pro A-Step"              },
333   { 0xf0fF0, 0x00610, 0xFFFF, "Pentium-Pro"                     },
334   { 0xf0fF0, 0x00630, 512,    "Pentium II (Klamath)"            },
335   { 0xf0fF0, 0x00640, 512,    "Pentium II (Deschutes)"          },
336   { 0xf0fF0, 0x00650, 1024,   "Pentium II (Drake)"              },
337   { 0xf0fF0, 0x00650, 512,    "Pentium II (Deschutes)"          },
338   { 0xf0fF0, 0x00650, 256,    "Pentium II Mobile (Dixon)"       },
339   { 0xf0fF0, 0x00650, 0,      "Celeron (Covington)"             },
340   { 0xf0fF0, 0x00660, 128,    "Celeron (Mendocino)"             },
341   { 0xf0fF0, 0x00670, 1024,   "Pentium III (Tanner)"            },
342   { 0xf0fF0, 0x00670, 512,    "Pentium III (Katmai)"            },
343   { 0xf0fF0, 0x00680, 256,    "Pentium III (Coppermine)"        },
344   { 0xf0fF0, 0x00680, 128,    "Celeron (Coppermine)"            },
345   { 0xf0fF0, 0x00690, 1024,   "Pentium-M (Banias)"              },
346   { 0xf0fF0, 0x00690, 512,    "Celeron-M (Banias)"              },
347   { 0xf0fF0, 0x006a0, 1024,   "Pentium III (Cascades)"          },
348   { 0xf0fF0, 0x006b0, 512,    "Pentium III-S"                   },
349   { 0xf0fF0, 0x006b0, 256,    "Pentium III (Tualatin)"          },
350   { 0xf0fF0, 0x006d0, 2048,   "Pentium-M (Dothan)"              },
351   { 0xf0fF0, 0x006d0, 1024,   "Celeron-M (Dothan)"              },
352   { 0xf0fF0, 0x006e0, 2048,   "Core (Yonah)"                    },
353   { 0xf0fF0, 0x006f0, 2048,   "Core 2 (Merom)"                  },
354   { 0xf0f00, 0x00700, 0xFFFF, "Itanium (Merced)"                },
355   { 0xf0fF0, 0x00f00, 256,    "Pentium 4 (Willamette/Foster)"   },
356   { 0xf0fF0, 0x00f10, 256,    "Pentium 4 (Willamette/Foster)"   },
357   { 0xf0fF0, 0x00f10, 128,    "Celeron (Willamette)"            },
358   { 0xf0fF0, 0x00f20, 512,    "Pentium 4 (Northwood/Prestonia)" },
359   { 0xf0fF0, 0x00f20, 128,    "Celeron (Northwood)"             },
360   { 0xf0fF0, 0x00f30, 1024,   "Pentium 4E (Prescott/Nocona)"    },
361   { 0xf0fF0, 0x00f30, 256,    "Celeron D (Prescott)"            },
362   { 0xf0fF4, 0x00f40, 1024,   "Pentium 4E (Prescott/Nocona)"    },
363   { 0xf0fF4, 0x00f44, 1024,   "Pentium D (Smithfield)"          },
364   { 0xf0fF0, 0x00f40, 256,    "Celeron D (Prescott)"            },
365   { 0xf0fF0, 0x00f60, 2048,   "Pentium D (Cedarmill/Presler)"   },
366   { 0xf0fF0, 0x00f60, 512,    "Celeron D (Cedarmill)"           },
367   { 0xf0ff0, 0x10600,   0,    "Celeron, 65nm"                   },
368   { 0xf0ff0, 0x10670, 2048,   "Core2 / Xeon (Wolfdale), 45nm"   },
369   { 0xf0ff0, 0x106a0, 0xffff, "Core i7 / Xeon, 45nm"            },
370   { 0xf0ff0, 0x106b0, 0xffff, "Xeon MP, 45nm"                   },
371   { 0xf0ff0, 0x106c0, 0xffff, "Atom"                            },
372   { 0xf0ff0, 0x206c0, 0xffff, "Xeon X5680 (and others?)"        },
373   { 0x0,     0x0,     0xFFFF, ""                                }
374 };
375
376 Cpu::Vendor_table const Cpu::amd_table[] FIASCO_INITDATA_CPU =
377 {
378   { 0xFF0, 0x430, 0xFFFF, "Am486DX2-WT"                     },
379   { 0xFF0, 0x470, 0xFFFF, "Am486DX2-WB"                     },
380   { 0xFF0, 0x480, 0xFFFF, "Am486DX4-WT / Am5x86-WT"         },
381   { 0xFF0, 0x490, 0xFFFF, "Am486DX4-WB / Am5x86-WB"         },
382   { 0xFF0, 0x4a0, 0xFFFF, "SC400"                           },
383   { 0xFF0, 0x4e0, 0xFFFF, "Am5x86-WT"                       },
384   { 0xFF0, 0x4f0, 0xFFFF, "Am5x86-WB"                       },
385   { 0xFF0, 0x500, 0xFFFF, "K5 (SSA/5) PR75/90/100"          },
386   { 0xFF0, 0x510, 0xFFFF, "K5 (Godot) PR120/133"            },
387   { 0xFF0, 0x520, 0xFFFF, "K5 (Godot) PR150/166"            },
388   { 0xFF0, 0x530, 0xFFFF, "K5 (Godot) PR200"                },
389   { 0xFF0, 0x560, 0xFFFF, "K6 (Little Foot)"                },
390   { 0xFF0, 0x570, 0xFFFF, "K6 (Little Foot)"                },
391   { 0xFF0, 0x580, 0xFFFF, "K6-II (Chomper)"                 },
392   { 0xFF0, 0x590, 256,    "K6-III (Sharptooth)"             },
393   { 0xFF0, 0x5c0, 128,    "K6-2+"                           },
394   { 0xFF0, 0x5d0, 256,    "K6-3+"                           },
395   { 0xFF0, 0x600, 0xFFFF, "Athlon K7 (Argon)"               },
396   { 0xFF0, 0x610, 0xFFFF, "Athlon K7 (Pluto)"               },
397   { 0xFF0, 0x620, 0xFFFF, "Athlon K75 (Orion)"              },
398   { 0xFF0, 0x630, 64,     "Duron (Spitfire)"                },
399   { 0xFF0, 0x640, 256,    "Athlon (Thunderbird)"            },
400   { 0xFF0, 0x660, 256,    "Athlon (Palomino)"               },
401   { 0xFF0, 0x660, 64,     "Duron (Morgan)"                  },
402   { 0xFF0, 0x670, 64,     "Duron (Morgan)"                  },
403   { 0xFF0, 0x680, 256,    "Athlon (Thoroughbred)"           },
404   { 0xFF0, 0x680, 64,     "Duron (Applebred)"               },
405   { 0xFF0, 0x6A0, 512,    "Athlon (Barton)"                 },
406   { 0xFF0, 0x6A0, 256,    "Athlon (Thorton)"                },
407   { 0xfff0ff0,  0x000f00,   0,      "Athlon 64 (Clawhammer)"       },
408   { 0xfff0ff0,  0x000f10,   0,      "Opteron (Sledgehammer)"       },
409   { 0xfff0ff0,  0x000f40,   0,      "Athlon 64 (Clawhammer)"       },
410   { 0xfff0ff0,  0x000f50,   0,      "Opteron (Sledgehammer)"       },
411   { 0xfff0ff0,  0x000fc0,   512,    "Athlon64 (Newcastle)"         },
412   { 0xfff0ff0,  0x000fc0,   256,    "Sempron (Paris)"              },
413   { 0xfff0ff0,  0x010f50,   0,      "Opteron (Sledgehammer)"       },
414   { 0xfff0ff0,  0x010fc0,   0,      "Sempron (Oakville)"           },
415   { 0xfff0ff0,  0x010ff0,   0,      "Athlon 64 (Winchester)"       },
416   { 0xfff0ff0,  0x020f10,   0,      "Opteron (Jackhammer)"         },
417   { 0xfff0ff0,  0x020f30,   0,      "Athlon 64 X2 (Toledo)"        },
418   { 0xfff0ff0,  0x020f40,   0,      "Turion 64 (Lancaster)"        },
419   { 0xfff0ff0,  0x020f50,   0,      "Opteron (Venus)"              },
420   { 0xfff0ff0,  0x020f70,   0,      "Athlon 64 (San Diego)"        },
421   { 0xfff0ff0,  0x020fb0,   0,      "Athlon 64 X2 (Manchester)"    },
422   { 0xfff0ff0,  0x020fc0,   0,      "Sempron (Palermo)"            },
423   { 0xfff0ff0,  0x020ff0,   0,      "Athlon 64 (Venice)"           },
424   { 0xfff0ff0,  0x040f10,   0,      "Opteron (Santa Rosa)"         },
425   { 0xfff0ff0,  0x040f30,   0,      "Athlon 64 X2 (Windsor)"       },
426   { 0xfff0ff0,  0x040f80,   0,      "Turion 64 X2 (Taylor)"        },
427   { 0xfff0ff0,  0x060fb0,   0,      "Athlon 64 X2 (Brisbane)"      },
428   { 0xfff0ff0,  0x100f20,   0,      "Phenom X3/Toliman / X4/Agena" },
429   { 0xfff0ff0,  0x100f40,   0,      "Opteron (Shanghai)"           },
430   { 0x0,        0x0,        0,      ""                             }
431 };
432
433 Cpu::Vendor_table const Cpu::cyrix_table[] FIASCO_INITDATA_CPU =
434 {
435   { 0xFF0, 0x440, 0xFFFF, "Gx86 (Media GX)"                 },
436   { 0xFF0, 0x490, 0xFFFF, "5x86"                            },
437   { 0xFF0, 0x520, 0xFFFF, "6x86 (M1)"                       },
438   { 0xFF0, 0x540, 0xFFFF, "GXm"                             },
439   { 0xFF0, 0x600, 0xFFFF, "6x86MX (M2)"                     },
440   { 0x0,   0x0,   0xFFFF, ""                                }
441 };
442
443 Cpu::Vendor_table const Cpu::via_table[] FIASCO_INITDATA_CPU =
444 {
445   { 0xFF0, 0x540, 0xFFFF, "IDT Winchip C6"                  },
446   { 0xFF0, 0x580, 0xFFFF, "IDT Winchip 2A/B"                },
447   { 0xFF0, 0x590, 0xFFFF, "IDT Winchip 3"                   },
448   { 0xFF0, 0x650, 0xFFFF, "Via Jalapeno (Joshua)"           },
449   { 0xFF0, 0x660, 0xFFFF, "Via C5A (Samuel)"                },
450   { 0xFF8, 0x670, 0xFFFF, "Via C5B (Samuel 2)"              },
451   { 0xFF8, 0x678, 0xFFFF, "Via C5C (Ezra)"                  },
452   { 0xFF0, 0x680, 0xFFFF, "Via C5N (Ezra-T)"                },
453   { 0xFF0, 0x690, 0xFFFF, "Via C5P (Nehemiah)"              },
454   { 0xFF0, 0x6a0, 0xFFFF, "Via C5J (Esther)"                },
455   { 0x0,   0x0,   0xFFFF, ""                                }
456 };
457
458 Cpu::Vendor_table const Cpu::umc_table[] FIASCO_INITDATA_CPU =
459 {
460   { 0xFF0, 0x410, 0xFFFF, "U5D"                             },
461   { 0xFF0, 0x420, 0xFFFF, "U5S"                             },
462   { 0x0,   0x0,   0xFFFF, ""                                }
463 };
464
465 Cpu::Vendor_table const Cpu::nexgen_table[] FIASCO_INITDATA_CPU =
466 {
467   { 0xFF0, 0x500, 0xFFFF, "Nx586"                           },
468   { 0x0,   0x0,   0xFFFF, ""                                }
469 };
470
471 Cpu::Vendor_table const Cpu::rise_table[] FIASCO_INITDATA_CPU =
472 {
473   { 0xFF0, 0x500, 0xFFFF, "mP6 (iDragon)"                   },
474   { 0xFF0, 0x520, 0xFFFF, "mP6 (iDragon)"                   },
475   { 0xFF0, 0x580, 0xFFFF, "mP6 (iDragon II)"                },
476   { 0xFF0, 0x590, 0xFFFF, "mP6 (iDragon II)"                },
477   { 0x0,   0x0,   0xFFFF, ""                                }
478 };
479
480 Cpu::Vendor_table const Cpu::transmeta_table[] FIASCO_INITDATA_CPU =
481 {
482   { 0xFFF, 0x542, 0xFFFF, "TM3x00 (Crusoe)"                 },
483   { 0xFFF, 0x543, 0xFFFF, "TM5x00 (Crusoe)"                 },
484   { 0xFF0, 0xf20, 0xFFFF, "TM8x00 (Efficeon)"               },
485   { 0x0,   0x0,   0xFFFF, ""                                }
486 };
487
488 Cpu::Vendor_table const Cpu::sis_table[] FIASCO_INITDATA_CPU =
489 {
490   { 0xFF0, 0x500, 0xFFFF, "55x"                             },
491   { 0x0,   0x0,   0xFFFF, ""                                }
492 };
493
494 Cpu::Vendor_table const Cpu::nsc_table[] FIASCO_INITDATA_CPU =
495 {
496   { 0xFF0, 0x540, 0xFFFF, "Geode GX1"                       },
497   { 0xFF0, 0x550, 0xFFFF, "Geode GX2"                       },
498   { 0xFF0, 0x680, 0xFFFF, "Geode NX"                        },
499   { 0x0,   0x0,   0xFFFF, ""                                }
500 };
501
502 Cpu::Cache_table const Cpu::intel_cache_table[] FIASCO_INITDATA_CPU =
503 {
504   { 0x01, Tlb_inst_4k,        32,   4,    0 },
505   { 0x02, Tlb_inst_4M,         2,   4,    0 },
506   { 0x03, Tlb_data_4k,        64,   4,    0 },
507   { 0x04, Tlb_data_4M,         8,   4,    0 },
508   { 0x05, Tlb_data_4M,        32,   4,    0 },
509   { 0x06, Cache_l1_inst,       8,   4,   32 },
510   { 0x08, Cache_l1_inst,      16,   4,   32 },
511   { 0x09, Cache_l1_inst,      32,   4,   64 },
512   { 0x0A, Cache_l1_data,       8,   2,   32 },
513   { 0x0B, Tlb_inst_4M,         4,   4,    0 },
514   { 0x0C, Cache_l1_data,      16,   4,   32 },
515   { 0x0D, Cache_l1_data,      16,   4,   64 },
516   { 0x0E, Cache_l1_data,      24,   6,   64 },
517   { 0x21, Cache_l2,          256,   8,   64 },
518   { 0x22, Cache_l3,          512,   4,   64 },  /* sectored */
519   { 0x23, Cache_l3,         1024,   8,   64 },  /* sectored */
520   { 0x25, Cache_l3,         2048,   8,   64 },  /* sectored */
521   { 0x29, Cache_l3,         4096,   8,   64 },  /* sectored */
522   { 0x2C, Cache_l1_data,      32,   8,   64 },
523   { 0x30, Cache_l1_inst,      32,   8,   64 },
524   { 0x39, Cache_l2,          128,   4,   64 },  /* sectored */
525   { 0x3B, Cache_l2,          128,   2,   64 },  /* sectored */
526   { 0x3C, Cache_l2,          256,   4,   64 },  /* sectored */
527   { 0x41, Cache_l2,          128,   4,   32 },
528   { 0x42, Cache_l2,          256,   4,   32 },
529   { 0x43, Cache_l2,          512,   4,   32 },
530   { 0x44, Cache_l2,         1024,   4,   32 },
531   { 0x45, Cache_l2,         2048,   4,   32 },
532   { 0x46, Cache_l3,         4096,   4,   64 },
533   { 0x47, Cache_l3,         8192,   8,   64 },
534   { 0x48, Cache_l2,         3072,  12,   64 },
535   { 0x49, Cache_l2,         4096,  16,   64 },
536   { 0x4A, Cache_l3,         6144,  12,   64 },
537   { 0x4B, Cache_l3,         8192,  16,   64 },
538   { 0x4C, Cache_l3,        12288,  12,   64 },
539   { 0x4D, Cache_l3,        16384,  16,   64 },
540   { 0x4E, Cache_l3,         6144,  24,   64 },
541   { 0x4F, Tlb_inst_4k,        32,   0,    0 },
542   { 0x50, Tlb_inst_4k_4M,     64,   0,    0 },
543   { 0x51, Tlb_inst_4k_4M,    128,   0,    0 },
544   { 0x52, Tlb_inst_4k_4M,    256,   0,    0 },
545   { 0x56, Tlb_data_4M,        16,   4,    0 },
546   { 0x57, Tlb_data_4k,        16,   4,    0 },
547   { 0x5B, Tlb_data_4k_4M,     64,   0,    0 },
548   { 0x5C, Tlb_data_4k_4M,    128,   0,    0 },
549   { 0x5D, Tlb_data_4k_4M,    256,   0,    0 },
550   { 0x60, Cache_l1_data,      16,   8,   64 },
551   { 0x66, Cache_l1_data,       8,   4,   64 },  /* sectored */
552   { 0x67, Cache_l1_data,      16,   4,   64 },  /* sectored */
553   { 0x68, Cache_l1_data,      32,   4,   64 },  /* sectored */
554   { 0x70, Cache_l1_trace,     12,   8,    0 },
555   { 0x71, Cache_l1_trace,     16,   8,    0 },
556   { 0x72, Cache_l1_trace,     32,   8,    0 },
557   { 0x77, Cache_l1_inst,      16,   4,   64 },
558   { 0x78, Cache_l2,         1024,   4,   64 },
559   { 0x79, Cache_l2,          128,   8,   64 },  /* sectored */
560   { 0x7A, Cache_l2,          256,   8,   64 },  /* sectored */
561   { 0x7B, Cache_l2,          512,   8,   64 },  /* sectored */
562   { 0x7C, Cache_l2,         1024,   8,   64 },  /* sectored */
563   { 0x7D, Cache_l2,         2048,   8,   64 },
564   { 0x7E, Cache_l2,          256,   8,  128 },
565   { 0x7F, Cache_l2,          512,   2,   64 },
566   { 0x82, Cache_l2,          256,   8,   32 },
567   { 0x83, Cache_l2,          512,   8,   32 },
568   { 0x84, Cache_l2,         1024,   8,   32 },
569   { 0x85, Cache_l2,         2048,   8,   32 },
570   { 0x86, Cache_l2,          512,   4,   64 },
571   { 0x87, Cache_l2,         1024,   8,   64 },
572   { 0x8D, Cache_l3,         3072,  12,  128 },
573   { 0xB0, Tlb_inst_4k,       128,   4,    0 },
574   { 0xB3, Tlb_data_4k,       128,   4,    0 },
575   { 0xB4, Tlb_data_4k,       256,   4,    0 },
576   { 0xBA, Tlb_data_4k,        64,   4,    0 },
577   { 0xC0, Tlb_data_4k_4M,      8,   4,    0 },
578   { 0xCA, Tlb_data_4k_4M,    512,   4,    0 },
579   { 0xD0, Cache_l3,          512,   4,   64 },
580   { 0xD1, Cache_l3,         1024,   4,   64 },
581   { 0xD2, Cache_l3,         2048,   4,   64 },
582   { 0xD6, Cache_l3,         1024,   8,   64 },
583   { 0xD7, Cache_l3,         2048,   8,   64 },
584   { 0xD8, Cache_l3,         4096,   8,   64 },
585   { 0xDC, Cache_l3,         1536,  12,   64 },
586   { 0xDD, Cache_l3,         3072,  12,   64 },
587   { 0xDE, Cache_l3,         6144,  12,   64 },
588   { 0xE2, Cache_l3,         2048,  16,   64 },
589   { 0xE3, Cache_l3,         4096,  16,   64 },
590   { 0xE4, Cache_l3,         8192,  16,   64 },
591   { 0xEA, Cache_l3,        12288,  24,   64 },
592   { 0xEB, Cache_l3,        18432,  24,   64 },
593   { 0xEC, Cache_l3,        24576,  24,   64 },
594   { 0x0,  Cache_unknown,       0,   0,    0 }
595 };
596
597 char const * const Cpu::vendor_ident[] =
598 {
599    0,
600   "GenuineIntel",
601   "AuthenticAMD",
602   "CyrixInstead",
603   "CentaurHauls",
604   "UMC UMC UMC ",
605   "NexGenDriven",
606   "RiseRiseRise",
607   "GenuineTMx86",
608   "SiS SiS SiS ",
609   "Geode by NSC"
610 };
611
612 Cpu::Vendor_table const * const Cpu::vendor_table[] =
613 {
614   0,
615   intel_table,
616   amd_table,
617   cyrix_table,
618   via_table,
619   umc_table,
620   nexgen_table,
621   rise_table,
622   transmeta_table,
623   sis_table,
624   nsc_table
625 };
626
627 char const * const Cpu::exception_strings[] =
628 {
629   /*  0 */ "Divide Error",
630   /*  1 */ "Debug",
631   /*  2 */ "NMI Interrupt",
632   /*  3 */ "Breakpoint",
633   /*  4 */ "Overflow",
634   /*  5 */ "BOUND Range Exceeded",
635   /*  6 */ "Invalid Opcode",
636   /*  7 */ "Device Not Available",
637   /*  8 */ "Double Fault",
638   /*  9 */ "CoProcessor Segment Overrrun",
639   /* 10 */ "Invalid TSS",
640   /* 11 */ "Segment Not Present",
641   /* 12 */ "Stack Segment Fault",
642   /* 13 */ "General Protection",
643   /* 14 */ "Page Fault",
644   /* 15 */ "Reserved",
645   /* 16 */ "Floating-Point Error",
646   /* 17 */ "Alignment Check",
647   /* 18 */ "Machine Check",
648   /* 19 */ "SIMD Floating-Point Exception",
649   /* 20 */ "Reserved",
650   /* 21 */ "Reserved",
651   /* 22 */ "Reserved",
652   /* 23 */ "Reserved",
653   /* 24 */ "Reserved",
654   /* 25 */ "Reserved",
655   /* 26 */ "Reserved",
656   /* 27 */ "Reserved",
657   /* 28 */ "Reserved",
658   /* 29 */ "Reserved",
659   /* 30 */ "Reserved",
660   /* 31 */ "Reserved"
661 };
662
663 PUBLIC explicit FIASCO_INIT_CPU
664 Cpu::Cpu(unsigned cpu)
665 {
666   set_id(cpu);
667   if (cpu == 0)
668     {
669       _boot_cpu = this;
670       set_online(1);
671     }
672
673   init();
674 }
675
676
677 PUBLIC static
678 void
679 Cpu::init_global_features()
680 {}
681
682 PUBLIC static
683 char const *
684 Cpu::exception_string(Mword trapno)
685 {
686   if (trapno > 32)
687     return "Maskable Interrupt";
688   return exception_strings[trapno];
689 }
690
691 PUBLIC static inline FIASCO_INIT_CPU
692 void
693 Cpu::cpuid(Unsigned32 const mode,
694            Unsigned32 *const eax, Unsigned32 *const ebx,
695            Unsigned32 *const ecx, Unsigned32 *const edx)
696 {
697   asm volatile ("cpuid" : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
698                         : "a" (mode));
699 }
700
701
702
703 PRIVATE FIASCO_INIT_CPU
704 void
705 Cpu::cache_tlb_intel()
706 {
707   Unsigned8 desc[16];
708   unsigned i, count = 0;
709   Cache_table const *table;
710
711   do
712     {
713       cpuid(2, (Unsigned32 *)(desc),
714                (Unsigned32 *)(desc + 4),
715                (Unsigned32 *)(desc + 8),
716                (Unsigned32 *)(desc + 12));
717
718       for (i = 1; i < 16; i++)
719         {
720           // Null descriptor or register bit31 set (reserved)
721           if (!desc[i] || (desc[i / 4 * 4 + 3] & (1 << 7)))
722             continue;
723
724           for (table = intel_cache_table; table->desc; table++)
725             {
726               if (table->desc == desc[i])
727                 {
728                   switch (table->level)
729                     {
730                     case Cache_l1_data:
731                       _l1_data_cache_size      = table->size;
732                       _l1_data_cache_asso      = table->asso;
733                       _l1_data_cache_line_size = table->line_size;
734                       break;
735                     case Cache_l1_inst:
736                       _l1_inst_cache_size      = table->size;
737                       _l1_inst_cache_asso      = table->asso;
738                       _l1_inst_cache_line_size = table->line_size;
739                       break;
740                     case Cache_l1_trace:
741                       _l1_trace_cache_size = table->size;
742                       _l1_trace_cache_asso = table->asso;
743                       break;
744                     case Cache_l2:
745                       _l2_cache_size      = table->size;
746                       _l2_cache_asso      = table->asso;
747                       _l2_cache_line_size = table->line_size;
748                       break;
749                     case Cache_l3:
750                       _l3_cache_size      = table->size;
751                       _l3_cache_asso      = table->asso;
752                       _l3_cache_line_size = table->line_size;
753                       break;
754                     case Tlb_inst_4k:
755                       _inst_tlb_4k_entries += table->size;
756                       break;
757                     case Tlb_data_4k:
758                       _data_tlb_4k_entries += table->size;
759                       break;
760                     case Tlb_inst_4M:
761                       _inst_tlb_4m_entries += table->size;
762                       break;
763                     case Tlb_data_4M:
764                       _data_tlb_4m_entries += table->size;
765                       break;
766                     case Tlb_inst_4k_4M:
767                       _inst_tlb_4k_4m_entries += table->size;
768                       break;
769                     case Tlb_data_4k_4M:
770                       _data_tlb_4k_4m_entries += table->size;
771                       break;
772                     default:
773                       break;
774                     }
775                   break;
776                 }
777             }
778         }
779     } 
780   while (++count < *desc);
781 }
782
783 PRIVATE FIASCO_INIT_CPU
784 void
785 Cpu::cache_tlb_l1()
786 {
787   Unsigned32 eax, ebx, ecx, edx;
788   cpuid(0x80000005, &eax, &ebx, &ecx, &edx);
789
790   _l1_data_cache_size      = (ecx >> 24) & 0xFF;
791   _l1_data_cache_asso      = (ecx >> 16) & 0xFF;
792   _l1_data_cache_line_size =  ecx        & 0xFF;
793
794   _l1_inst_cache_size      = (edx >> 24) & 0xFF;
795   _l1_inst_cache_asso      = (edx >> 16) & 0xFF;
796   _l1_inst_cache_line_size =  edx        & 0xFF;
797
798   _data_tlb_4k_entries     = (ebx >> 16) & 0xFF;
799   _inst_tlb_4k_entries     =  ebx        & 0xFF;
800   _data_tlb_4m_entries     = (eax >> 16) & 0xFF;
801   _inst_tlb_4m_entries     =  eax        & 0xFF;
802 }
803
804 PRIVATE FIASCO_INIT_CPU
805 void
806 Cpu::cache_tlb_l2_l3()
807 {
808   Unsigned32 eax, ebx, ecx, edx;
809   cpuid(0x80000006, &eax, &ebx, &ecx, &edx);
810
811   if (vendor() == Vendor_via)
812     {
813       _l2_cache_size          = (ecx >> 24) & 0xFF;
814       _l2_cache_asso          = (ecx >> 16) & 0xFF;
815     }
816   else
817     {
818       _l2_data_tlb_4m_entries = (eax >> 16) & 0xFFF;
819       _l2_inst_tlb_4m_entries =  eax        & 0xFFF;
820       _l2_data_tlb_4k_entries = (ebx >> 16) & 0xFFF;
821       _l2_inst_tlb_4k_entries =  ebx        & 0xFFF;
822       _l2_cache_size          = (ecx >> 16) & 0xFFFF;
823       _l2_cache_asso          = (ecx >> 12) & 0xF;
824     }
825
826   _l2_cache_line_size = ecx & 0xFF;
827
828   _l3_cache_size      = (edx >> 18) << 9;
829   _l3_cache_asso      = (edx >> 12) & 0xF;
830   _l3_cache_line_size = edx & 0xFF;
831 }
832
833 PRIVATE FIASCO_INIT_CPU
834 void
835 Cpu::addr_size_info()
836 {
837   Unsigned32 eax, ebx, ecx, edx;
838   cpuid(0x80000008, &eax, &ebx, &ecx, &edx);
839
840   _phys_bits = eax & 0xff;
841   _virt_bits = (eax & 0xff00) >> 8;
842 }
843
844 PRIVATE FIASCO_INIT_CPU
845 void
846 Cpu::set_model_str()
847 {
848   Vendor_table const *table;
849
850   for (table = vendor_table[vendor()]; table && table->vendor_mask; table++)
851     if ((_version & table->vendor_mask) == table->vendor_code &&
852         (table->l2_cache == 0xFFFF || _l2_cache_size >= table->l2_cache))
853       {
854         snprintf(_model_str, sizeof (_model_str), "%s",
855                  table->vendor_string);
856         return;
857       }
858
859   snprintf(_model_str, sizeof (_model_str), "Unknown CPU");
860 }
861
862 PUBLIC inline FIASCO_INIT_CPU
863 void
864 Cpu::arch_perfmon_info(Unsigned32 *eax, Unsigned32 *ebx, Unsigned32 *ecx) const
865 {
866   *eax = _arch_perfmon_info_eax;
867   *ebx = _arch_perfmon_info_ebx;
868   *ecx = _arch_perfmon_info_ecx;
869 }
870
871 PUBLIC static
872 unsigned long
873 Cpu::get_features()
874 {
875   Unsigned32 eflags = get_flags();
876   // Check for Alignment Check Support
877   set_flags(eflags ^ EFLAGS_AC);
878   if (((get_flags() ^ eflags) & EFLAGS_AC) == 0)
879     return 0;
880
881   // Check for CPUID Support
882   set_flags(eflags ^ EFLAGS_ID);
883   if (!((get_flags() ^ eflags) & EFLAGS_ID))
884     return 0;
885
886   Unsigned32 max;
887   char vendor_id[12];
888
889   cpuid(0, &max, (Unsigned32 *)(vendor_id),
890                  (Unsigned32 *)(vendor_id + 8),
891                  (Unsigned32 *)(vendor_id + 4));
892
893   if (!max)
894     return 0;
895
896   Unsigned32 dummy, dummy1, dummy2, features;
897   cpuid (1, &dummy, &dummy1, &dummy2, &features);
898
899   return features;
900 }
901
902
903 /** Identify the CPU features.
904     Attention: This function may be called more than once. The reason is
905     that enabling a Local APIC that was previously disabled by the BIOS
906     may change the processor features. Therefore, this function has to
907     be called again after the Local APIC was enabled.
908  */
909 PUBLIC FIASCO_INIT_CPU
910 void
911 Cpu::identify()
912 {
913   Unsigned32 eflags = get_flags();
914
915   _phys_bits = 32;
916   _virt_bits = 32;
917
918   // Reset members in case we get called more than once
919   _inst_tlb_4k_entries    =
920   _data_tlb_4k_entries    =
921   _inst_tlb_4m_entries    =
922   _data_tlb_4m_entries    =
923   _inst_tlb_4k_4m_entries =
924   _data_tlb_4k_4m_entries = 0;
925
926   // Check for Alignment Check Support
927   set_flags(eflags ^ EFLAGS_AC);
928   if (((get_flags() ^ eflags) & EFLAGS_AC) == 0)
929     panic("CPU too old");
930
931   // Check for CPUID Support
932   set_flags(eflags ^ EFLAGS_ID);
933   if ((get_flags() ^ eflags) & EFLAGS_ID) {
934
935     Unsigned32 max, i;
936     char vendor_id[12];
937
938     cpuid(0, &max, (Unsigned32 *)(vendor_id),
939                    (Unsigned32 *)(vendor_id + 8),
940                    (Unsigned32 *)(vendor_id + 4));
941
942     for (i = sizeof (vendor_ident) / sizeof (*vendor_ident) - 1; i; i--)
943       if (!memcmp(vendor_id, vendor_ident[i], 12))
944         break;
945
946     _vendor = (Cpu::Vendor)i;
947
948     switch (max)
949       {
950       default:
951         // All cases fall through!
952       case 10:
953         cpuid(10, &_arch_perfmon_info_eax,
954                   &_arch_perfmon_info_ebx,
955                   &_arch_perfmon_info_ecx, &i);
956       case 2:
957         if (_vendor == Vendor_intel)
958           cache_tlb_intel();
959       case 1:
960         cpuid(1, &_version, &_brand, &_ext_features, &_features);
961       }
962
963     if (max >= 5 && has_monitor_mwait())
964       cpuid(5, &_monitor_mwait_eax, &_monitor_mwait_ebx,
965                &_monitor_mwait_ecx, &_monitor_mwait_edx);
966
967     if (_vendor == Vendor_intel)
968       {
969         switch (family())
970           {
971           case 5:
972             // Avoid Pentium Erratum 74
973             if ((_features & FEAT_MMX) &&
974                 (model() != 4 ||
975                  (stepping() != 4 && (stepping() != 3 || type() != 1))))
976               _local_features |= Lf_rdpmc;
977             break;
978           case 6:
979             // Avoid Pentium Pro Erratum 26
980             if (model() >= 3 || stepping() > 9)
981               _local_features |= Lf_rdpmc;
982             break;
983           case 15:
984             _local_features |= Lf_rdpmc;
985             _local_features |= Lf_rdpmc32;
986             break;
987           }
988       }
989     else if (_vendor == Vendor_amd)
990       {
991         switch (family())
992           {
993           case 6:
994           case 15:
995             _local_features |= Lf_rdpmc;
996             break;
997           }
998       }
999
1000     // Get maximum number for extended functions
1001     cpuid(0x80000000, &max, &i, &i, &i);
1002
1003     if (max > 0x80000000)
1004       {
1005         switch (max)
1006           {
1007           default:
1008             // All cases fall through!
1009           case 0x80000008:
1010             if (_vendor == Vendor_amd || _vendor == Vendor_intel)
1011               addr_size_info();
1012           case 0x80000007:
1013           case 0x80000006:
1014             if (_vendor == Vendor_amd || _vendor == Vendor_via)
1015               cache_tlb_l2_l3();
1016           case 0x80000005:
1017             if (_vendor == Vendor_amd || _vendor == Vendor_via)
1018               cache_tlb_l1();
1019           case 0x80000004:
1020           case 0x80000003:
1021           case 0x80000002:
1022           case 0x80000001:
1023             if (_vendor == Vendor_intel || _vendor == Vendor_amd)
1024               cpuid(0x80000001, &i, &i, &_ext_8000_0001_ecx,
1025                                 &_ext_8000_0001_edx);
1026             break;
1027           }
1028       }
1029
1030     // see Intel Spec on SYSENTER:
1031     // Some Pentium Pro pretend to have it, but actually lack it
1032     if ((_version & 0xFFF) < 0x633)
1033       _features &= ~FEAT_SEP;
1034
1035   } else
1036     _version = 0x400;
1037
1038   set_model_str();
1039
1040   set_flags(eflags);
1041 }
1042
1043 PUBLIC inline NEEDS["processor.h"]
1044 void
1045 Cpu::busy_wait_ns(Unsigned64 ns)
1046 {
1047   Unsigned64 stop = rdtsc () + ns_to_tsc(ns);
1048
1049   while (rdtsc() < stop)
1050     Proc::pause();
1051 }
1052
1053
1054 PUBLIC
1055 void
1056 Cpu::show_cache_tlb_info(const char *indent) const
1057 {
1058   char s[16];
1059
1060   *s = '\0';
1061   if (_l2_inst_tlb_4k_entries)
1062     snprintf(s, sizeof(s), "/%u", _l2_inst_tlb_4k_entries);
1063   if (_inst_tlb_4k_entries)
1064     printf("%s%4u%s Entry I TLB (4K pages)", indent, _inst_tlb_4k_entries, s);
1065   *s = '\0';
1066   if (_l2_inst_tlb_4m_entries)
1067     snprintf(s, sizeof(s), "/%u", _l2_inst_tlb_4k_entries);
1068   if (_inst_tlb_4m_entries)
1069     printf("   %4u%s Entry I TLB (4M pages)", _inst_tlb_4m_entries, s);
1070   if (_inst_tlb_4k_4m_entries)
1071     printf("%s%4u Entry I TLB (4K or 4M pages)",
1072            indent, _inst_tlb_4k_4m_entries);
1073   if (_inst_tlb_4k_entries || _inst_tlb_4m_entries || _inst_tlb_4k_4m_entries)
1074     putchar('\n');
1075   *s = '\0';
1076   if (_l2_data_tlb_4k_entries)
1077     snprintf(s, sizeof(s), "/%u", _l2_data_tlb_4k_entries);
1078   if (_data_tlb_4k_entries)
1079     printf("%s%4u%s Entry D TLB (4K pages)", indent, _data_tlb_4k_entries, s);
1080   *s = '\0';
1081   if (_l2_data_tlb_4m_entries)
1082     snprintf(s, sizeof(s), "/%u", _l2_data_tlb_4m_entries);
1083   if (_data_tlb_4m_entries)
1084     printf("   %4u%s Entry D TLB (4M pages)", _data_tlb_4m_entries, s);
1085   if (_data_tlb_4k_4m_entries)
1086     printf("%s%4u Entry D TLB (4k or 4M pages)",
1087            indent, _data_tlb_4k_4m_entries);
1088   if (_data_tlb_4k_entries || _data_tlb_4m_entries || _data_tlb_4k_4m_entries)
1089     putchar('\n');
1090
1091   if (_l1_trace_cache_size)
1092     printf("%s%3uK %c-ops T Cache (%u-way associative)\n",
1093            indent, _l1_trace_cache_size, Config::char_micro,
1094            _l1_trace_cache_asso);
1095
1096   else if (_l1_inst_cache_size)
1097     printf("%s%4u KB L1 I Cache (%u-way associative, %u bytes per line)\n",
1098            indent, _l1_inst_cache_size, _l1_inst_cache_asso,
1099            _l1_inst_cache_line_size);
1100
1101   if (_l1_data_cache_size)
1102     printf("%s%4u KB L1 D Cache (%u-way associative, %u bytes per line)\n"
1103            "%s%4u KB L2 U Cache (%u-way associative, %u bytes per line)\n",
1104            indent, _l1_data_cache_size, _l1_data_cache_asso,
1105            _l1_data_cache_line_size,
1106            indent, _l2_cache_size, _l2_cache_asso, _l2_cache_line_size);
1107
1108   if (_l3_cache_size)
1109     printf("%s%4u KB L3 U Cache (%u-way associative, %u bytes per line)\n",
1110            indent, _l3_cache_size, _l3_cache_asso, _l3_cache_line_size);
1111 }
1112
1113 IMPLEMENT
1114 void 
1115 Cpu::disable(unsigned cpu, char const *reason)
1116 {
1117   printf("CPU%u: is disabled: %s\n", cpu, reason);
1118 }
1119
1120 // Function used for calculating apic scaler
1121 PUBLIC static inline
1122 Unsigned32
1123 Cpu::muldiv(Unsigned32 val, Unsigned32 mul, Unsigned32 div)
1124 {
1125   Unsigned32 dummy;
1126
1127   asm volatile ("mull %3 ; divl %4\n\t"
1128                :"=a" (val), "=d" (dummy)
1129                : "0" (val),  "d" (mul),  "c" (div));
1130   return val;
1131 }
1132
1133
1134 PUBLIC static inline
1135 Unsigned32
1136 Cpu::get_cs()
1137 {
1138   Unsigned32 val;
1139   asm volatile ("mov %%cs, %0" : "=rm" (val));
1140   return val;
1141 }
1142
1143 PUBLIC static inline
1144 Unsigned32
1145 Cpu::get_ds()
1146 {
1147   Unsigned32 val;
1148   asm volatile ("mov %%ds, %0" : "=rm" (val));
1149   return val;
1150 }
1151
1152 PUBLIC static inline
1153 Unsigned32
1154 Cpu::get_es()
1155 {
1156   Unsigned32 val;
1157   asm volatile ("mov %%es, %0" : "=rm" (val));
1158   return val;
1159 }
1160
1161 PUBLIC static inline
1162 Unsigned32
1163 Cpu::get_ss()
1164 {
1165   Unsigned32 val;
1166   asm volatile ("mov %%ss, %0" : "=rm" (val));
1167   return val;
1168 }
1169
1170 PUBLIC static inline
1171 Unsigned32
1172 Cpu::get_fs()
1173 {
1174   Unsigned32 val;
1175   asm volatile ("mov %%fs, %0" : "=rm" (val));
1176   return val;
1177 }
1178
1179 PUBLIC static inline
1180 void
1181 Cpu::set_ds(Unsigned32 val)
1182 { asm volatile ("mov %0, %%ds" : : "rm" (val)); }
1183
1184 PUBLIC static inline
1185 void
1186 Cpu::set_es(Unsigned32 val)
1187 { asm volatile ("mov %0, %%es" : : "rm" (val)); }
1188
1189 PUBLIC static inline
1190 void
1191 Cpu::set_fs(Unsigned32 val)
1192 { asm volatile ("mov %0, %%fs" : : "rm" (val)); }
1193
1194
1195 //----------------------------------------------------------------------------
1196 IMPLEMENTATION[ia32, amd64]:
1197
1198 #include "boot_info.h"
1199 #include "config.h"
1200 #include "div32.h"
1201 #include "gdt.h"
1202 #include "globals.h"
1203 #include "initcalls.h"
1204 #include "io.h"
1205 #include "pit.h"
1206 #include "processor.h"
1207 #include "regdefs.h"
1208 #include "tss.h"
1209
1210
1211 PUBLIC static inline
1212 void
1213 Cpu::set_cr0(unsigned long val)
1214 { asm volatile ("mov %0, %%cr0" : : "r" (val)); }
1215
1216 PUBLIC static inline
1217 void
1218 Cpu::set_pdbr(unsigned long addr)
1219 { asm volatile ("mov %0, %%cr3" : : "r" (addr)); }
1220
1221 PUBLIC static inline
1222 void
1223 Cpu::set_cr4(unsigned long val)
1224 { asm volatile ("mov %0, %%cr4" : : "r" (val)); }
1225
1226 PUBLIC static inline
1227 void
1228 Cpu::set_ldt(Unsigned16 val)
1229 { asm volatile ("lldt %0" : : "rm" (val)); }
1230
1231
1232 PUBLIC static inline
1233 void
1234 Cpu::set_ss(Unsigned32 val)
1235 { asm volatile ("mov %0, %%ss" : : "r" (val)); }
1236
1237 PUBLIC static inline
1238 void
1239 Cpu::set_tr(Unsigned16 val)
1240 { asm volatile ("ltr %0" : : "rm" (val)); }
1241
1242 PUBLIC static inline
1243 Mword
1244 Cpu::get_cr0()
1245 {
1246   Mword val;
1247   asm volatile ("mov %%cr0, %0" : "=r" (val));
1248   return val;
1249 }
1250
1251 PUBLIC static inline
1252 Address
1253 Cpu::get_pdbr()
1254 { Address addr; asm volatile ("mov %%cr3, %0" : "=r" (addr)); return addr; }
1255
1256 PUBLIC static inline
1257 Mword
1258 Cpu::get_cr4()
1259 { Mword val; asm volatile ("mov %%cr4, %0" : "=r" (val)); return val; }
1260
1261 PUBLIC static inline
1262 Unsigned16
1263 Cpu::get_ldt()
1264 { Unsigned16 val; asm volatile ("sldt %0" : "=rm" (val)); return val; }
1265
1266 PUBLIC static inline
1267 Unsigned16
1268 Cpu::get_tr()
1269 { Unsigned16 val; asm volatile ("str %0" : "=rm" (val)); return val; }
1270
1271 IMPLEMENT inline
1272 int
1273 Cpu::can_wrmsr() const
1274 { return features() & FEAT_MSR; }
1275
1276 PUBLIC static inline
1277 Unsigned64
1278 Cpu::rdmsr(Unsigned32 reg)
1279 {
1280   Unsigned32 l,h;
1281
1282   asm volatile ("rdmsr" : "=a" (l), "=d" (h) : "c" (reg));
1283   return ((Unsigned64)h << 32) + (Unsigned64)l;
1284 }
1285
1286 PUBLIC static inline
1287 Unsigned64
1288 Cpu::rdpmc(Unsigned32 idx, Unsigned32)
1289 {
1290   Unsigned32 l,h;
1291
1292   asm volatile ("rdpmc" : "=a" (l), "=d" (h) : "c" (idx));
1293   return ((Unsigned64)h << 32) + (Unsigned64)l;
1294 }
1295
1296 PUBLIC static inline
1297 void
1298 Cpu::wrmsr(Unsigned32 low, Unsigned32 high, Unsigned32 reg)
1299 { asm volatile ("wrmsr" : : "a" (low), "d" (high), "c" (reg)); }
1300
1301 PUBLIC static inline
1302 void
1303 Cpu::wrmsr(Unsigned64 msr, Unsigned32 reg)
1304 { asm volatile ("wrmsr" : : "a" ((Unsigned32)msr), "d" ((Unsigned32)(msr >> 32)), "c" (reg)); }
1305
1306 PUBLIC static inline
1307 void
1308 Cpu::enable_rdpmc()
1309 { set_cr4(get_cr4() | CR4_PCE); }
1310
1311
1312 IMPLEMENT FIASCO_INIT_CPU
1313 void
1314 Cpu::init_lbr_type()
1315 {
1316   _lbr = Lbr_unsupported;
1317
1318   if (can_wrmsr())
1319     {
1320       // Intel
1321       if (vendor() == Vendor_intel)
1322         {
1323           if (family() == 15)
1324             _lbr = model() < 3 ? Lbr_pentium_4 : Lbr_pentium_4_ext; // P4
1325           else if (family() >= 6)
1326             _lbr = Lbr_pentium_6; // PPro, PIII
1327         }
1328       else if (vendor() == Vendor_amd)
1329         {
1330           if ((family() == 6) || (family() == 15))
1331             _lbr = Lbr_pentium_6; // K7/K8
1332         }
1333     }
1334 }
1335
1336
1337 IMPLEMENT FIASCO_INIT_CPU
1338 void
1339 Cpu::init_bts_type()
1340 {
1341   _bts = Bts_unsupported;
1342
1343   if (can_wrmsr() && vendor() == Vendor_intel)
1344     {
1345       if (family() == 15 && (rdmsr(0x1A0) & (1<<11)) == 0)
1346         _bts = Bts_pentium_4;
1347       if (family() == 6  && (model() == 9 || (model() >= 13 &&
1348               model() <= 15)))
1349         _bts = Bts_pentium_m;
1350       if (!(features() & FEAT_DS))
1351         _bts = Bts_unsupported;
1352     }
1353 }
1354
1355
1356 PUBLIC inline
1357 void
1358 Cpu::lbr_enable(bool on)
1359 {
1360   if (lbr_type() != Lbr_unsupported)
1361     {
1362       if (on)
1363         {
1364           lbr_active    = true;
1365           debugctl_set |= 1;
1366           debugctl_busy = true;
1367         }
1368       else
1369         {
1370           lbr_active    = false;
1371           debugctl_set &= ~1;
1372           debugctl_busy = lbr_active || bts_active;
1373           wrmsr(debugctl_reset, MSR_DEBUGCTLA);
1374         }
1375     }
1376 }
1377
1378
1379 PUBLIC inline
1380 void
1381 Cpu::btf_enable(bool on)
1382 {
1383   if (lbr_type() != Lbr_unsupported)
1384     {
1385       if (on)
1386         {
1387           btf_active      = true;
1388           debugctl_set   |= 2;
1389           debugctl_reset |= 2; /* don't disable bit in kernel */
1390           wrmsr(2, MSR_DEBUGCTLA);     /* activate _now_ */
1391         }
1392       else
1393         {
1394           btf_active    = false;
1395           debugctl_set &= ~2;
1396           debugctl_busy = lbr_active || bts_active;
1397           wrmsr(debugctl_reset, MSR_DEBUGCTLA);
1398         }
1399     }
1400 }
1401
1402
1403 PUBLIC
1404 void
1405 Cpu::bts_enable(bool on)
1406 {
1407   if (bts_type() != Bts_unsupported)
1408     {
1409       if (on)
1410         {
1411           switch (bts_type())
1412             {
1413             case Bts_pentium_4: bts_active = true; debugctl_set |= 0x0c; break;
1414             case Bts_pentium_m: bts_active = true; debugctl_set |= 0xc0; break;
1415             default:;
1416             }
1417           debugctl_busy = lbr_active || bts_active;
1418         }
1419       else
1420         {
1421           bts_active = false;
1422           switch (bts_type())
1423             {
1424             case Bts_pentium_4: debugctl_set &= ~0x0c; break;
1425             case Bts_pentium_m: debugctl_set &= ~0xc0; break;
1426             default:;
1427             }
1428           debugctl_busy = lbr_active || bts_active;
1429           wrmsr(debugctl_reset, MSR_DEBUGCTLA);
1430         }
1431     }
1432 }
1433
1434 PUBLIC inline
1435 void
1436 Cpu::debugctl_enable()
1437 {
1438   if (debugctl_busy)
1439     wrmsr(debugctl_set, MSR_DEBUGCTLA);
1440 }
1441
1442 PUBLIC inline
1443 void
1444 Cpu::debugctl_disable()
1445 {
1446   if (debugctl_busy)
1447     wrmsr(debugctl_reset, MSR_DEBUGCTLA);
1448 }
1449
1450 /*
1451  * AMD OS-Visible Workaround Information
1452  * print a warning if a CPU is affected by any known erratum
1453  */
1454 PUBLIC
1455 void
1456 Cpu::print_errata()
1457 {
1458   if (vendor() == Vendor_amd && has_amd_osvw() && can_wrmsr())
1459     {
1460       Unsigned16 osvw_id_length, i;
1461       bool affected = false;
1462       osvw_id_length = rdmsr(0xc0010140) & 0xff;
1463
1464       for (i = 1; ((i - 1) * 64) < osvw_id_length; i++)
1465         {
1466           Unsigned64 osvw_msr = rdmsr(0xc0010140 + i);
1467           if (osvw_msr != 0)
1468             {
1469               printf("\033[31mOSVW_MSR%d = 0x%016llx\033[m\n",
1470                      i, rdmsr(0xc0010140 + i));
1471               affected = true;
1472             }
1473         }
1474       if (affected)
1475         printf("\033[31m#Errata known %d, affected by at least one\033[m\n",
1476                osvw_id_length);
1477     }
1478 }
1479
1480 IMPLEMENT FIASCO_INIT_CPU
1481 void
1482 Cpu::init()
1483 {
1484   identify();
1485
1486   init_lbr_type();
1487   init_bts_type();
1488
1489   calibrate_tsc();
1490
1491   if (scaler_tsc_to_ns)
1492     _frequency = ns_to_tsc(1000000000UL);
1493
1494   Unsigned32 cr4 = get_cr4();
1495
1496   if (features() & FEAT_FXSR)
1497     cr4 |= CR4_OSFXSR;
1498
1499   if (features() & FEAT_SSE)
1500     cr4 |= CR4_OSXMMEXCPT;
1501
1502   set_cr4 (cr4);
1503
1504   // reset time stamp counter (better for debugging)
1505   if ((features() & FEAT_TSC) && can_wrmsr())
1506     wrmsr(0, 0, 0x10);
1507
1508   if ((features() & FEAT_PAT) && can_wrmsr())
1509     wrmsr(0x00010406, 0x00070406, 0x277);
1510
1511   print_errata();
1512 }
1513
1514 PUBLIC
1515 void
1516 Cpu::print() const
1517 {
1518   printf ("CPU[%u:%u]: %s (%X:%X:%X:%X) Model: %s at %llu MHz\n\n",
1519           id(), phys_id() >> 24,
1520           vendor_str(), family(), model(), stepping(), brand(), model_str(),
1521           div32(frequency(), 1000000));
1522 }
1523
1524 PUBLIC
1525 void
1526 Cpu::set_sysenter(void (*func)(void))
1527 {
1528   // Check for Sysenter/Sysexit Feature
1529   if (sysenter())
1530     wrmsr ((Mword) func, 0, MSR_SYSENTER_EIP);
1531 }
1532
1533
1534 PUBLIC
1535 void
1536 Cpu::set_fast_entry(void (*func)(void))
1537 {
1538   set_sysenter(func);
1539 }
1540
1541 extern "C" void entry_sys_fast_ipc (void);
1542 extern "C" void entry_sys_fast_ipc_c (void);
1543
1544 PUBLIC FIASCO_INIT_CPU
1545 void
1546 Cpu::init_sysenter()
1547 {
1548   // Check for Sysenter/Sysexit Feature
1549   if (sysenter())
1550     {
1551       wrmsr (Gdt::gdt_code_kernel, 0, MSR_SYSENTER_CS);
1552       wrmsr ((unsigned long)&kernel_sp(), 0, MSR_SYSENTER_ESP);
1553       if (Config::Assembler_ipc_shortcut)
1554         set_sysenter(entry_sys_fast_ipc);
1555       else
1556         set_sysenter(entry_sys_fast_ipc_c);
1557     }
1558 }
1559
1560
1561 // Return 2^32 / (tsc clocks per usec)
1562 FIASCO_INIT_CPU
1563 void
1564 Cpu::calibrate_tsc ()
1565 {
1566   const unsigned calibrate_time = 50000 /*us*/ + 1;
1567
1568   // sanity check
1569   if (! (features() & FEAT_TSC))
1570     goto bad_ctc;
1571
1572   Unsigned64 tsc_start, tsc_end;
1573   Unsigned32 count, tsc_to_ns_div, dummy;
1574
1575     {
1576       // disable interrupts
1577       Proc::Status o = Proc::cli_save();
1578
1579       Pit::setup_channel2_to_20hz();
1580
1581       tsc_start = rdtsc ();
1582       count = 0;
1583       do
1584         {
1585           count++;
1586         }
1587       while ((Io::in8 (0x61) & 0x20) == 0);
1588       tsc_end = rdtsc ();
1589
1590       // restore flags
1591       Proc::sti_restore(o);
1592     }
1593
1594   // Error: ECTCNEVERSET
1595   if (count <= 1)
1596     goto bad_ctc;
1597
1598   tsc_end -= tsc_start;
1599
1600   // prevent overflow in division (CPU too fast)
1601   if (tsc_end & 0xffffffff00000000LL)
1602     goto bad_ctc;
1603
1604   // prevent overflow in division (CPU too slow)
1605   if ((tsc_end & 0xffffffffL) < calibrate_time)
1606     goto bad_ctc;
1607
1608   // tsc_to_ns_div = calibrate_time * 2^32 / tsc
1609   asm ("divl %2"
1610        :"=a" (tsc_to_ns_div), "=d" (dummy)
1611        :"r" ((Unsigned32)tsc_end), "a" (0), "d" (calibrate_time));
1612
1613   scaler_tsc_to_ns = muldiv (tsc_to_ns_div, 1000, 1<<5);
1614   scaler_tsc_to_us =         tsc_to_ns_div;
1615   scaler_ns_to_tsc = muldiv (1<<31, ((Unsigned32)tsc_end),
1616                              calibrate_time * 1000>>1 * 1<<5);
1617
1618   return;
1619
1620 bad_ctc:
1621   if (Config::kinfo_timer_uses_rdtsc)
1622     panic("Can't calibrate tsc");
1623 }
1624
1625 IMPLEMENT inline
1626 Unsigned64
1627 Cpu::time_us() const
1628 {
1629   return tsc_to_us (rdtsc());
1630 }
1631
1632
1633 PUBLIC inline
1634 void
1635 Cpu::enable_ldt(Address addr, int size)
1636 {
1637   if (!size)
1638     {
1639       get_gdt()->clear_entry (Gdt::gdt_ldt / 8);
1640       set_ldt(0);
1641     }
1642   else
1643     {
1644       get_gdt()->set_entry_byte(Gdt::gdt_ldt / 8, addr, size-1, 2/*=ldt*/, 0);
1645       set_ldt(Gdt::gdt_ldt);
1646     }
1647 }
1648
1649
1650 PUBLIC static inline
1651 Unsigned32
1652 Cpu::get_gs()
1653 { Unsigned32 val; asm volatile ("mov %%gs, %0" : "=rm" (val)); return val; }
1654
1655 PUBLIC static inline
1656 void
1657 Cpu::set_gs(Unsigned32 val)
1658 { asm volatile ("mov %0, %%gs" : : "rm" (val)); }
1659
1660 IMPLEMENT inline
1661 unsigned
1662 Cpu::phys_id() const
1663 { return _brand & 0xff000000; }
1664
1665 PUBLIC static
1666 unsigned
1667 Cpu::phys_id_direct()
1668 {
1669   Unsigned32 a,b,c,d;
1670   cpuid (1, &a, &b, &c, &d);
1671   return b & 0xff000000;
1672 }