]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ia32/cpu-ia32.cpp
update
[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[52];
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   static void set_tss() { 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   { 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   { 0x0,        0x0,        0,      ""                             }
429 };
430
431 Cpu::Vendor_table const Cpu::cyrix_table[] FIASCO_INITDATA_CPU =
432 {
433   { 0xFF0, 0x440, 0xFFFF, "Gx86 (Media GX)"                 },
434   { 0xFF0, 0x490, 0xFFFF, "5x86"                            },
435   { 0xFF0, 0x520, 0xFFFF, "6x86 (M1)"                       },
436   { 0xFF0, 0x540, 0xFFFF, "GXm"                             },
437   { 0xFF0, 0x600, 0xFFFF, "6x86MX (M2)"                     },
438   { 0x0,   0x0,   0xFFFF, ""                                }
439 };
440
441 Cpu::Vendor_table const Cpu::via_table[] FIASCO_INITDATA_CPU =
442 {
443   { 0xFF0, 0x540, 0xFFFF, "IDT Winchip C6"                  },
444   { 0xFF0, 0x580, 0xFFFF, "IDT Winchip 2A/B"                },
445   { 0xFF0, 0x590, 0xFFFF, "IDT Winchip 3"                   },
446   { 0xFF0, 0x650, 0xFFFF, "Via Jalapeno (Joshua)"           },
447   { 0xFF0, 0x660, 0xFFFF, "Via C5A (Samuel)"                },
448   { 0xFF8, 0x670, 0xFFFF, "Via C5B (Samuel 2)"              },
449   { 0xFF8, 0x678, 0xFFFF, "Via C5C (Ezra)"                  },
450   { 0xFF0, 0x680, 0xFFFF, "Via C5N (Ezra-T)"                },
451   { 0xFF0, 0x690, 0xFFFF, "Via C5P (Nehemiah)"              },
452   { 0xFF0, 0x6a0, 0xFFFF, "Via C5J (Esther)"                },
453   { 0x0,   0x0,   0xFFFF, ""                                }
454 };
455
456 Cpu::Vendor_table const Cpu::umc_table[] FIASCO_INITDATA_CPU =
457 {
458   { 0xFF0, 0x410, 0xFFFF, "U5D"                             },
459   { 0xFF0, 0x420, 0xFFFF, "U5S"                             },
460   { 0x0,   0x0,   0xFFFF, ""                                }
461 };
462
463 Cpu::Vendor_table const Cpu::nexgen_table[] FIASCO_INITDATA_CPU =
464 {
465   { 0xFF0, 0x500, 0xFFFF, "Nx586"                           },
466   { 0x0,   0x0,   0xFFFF, ""                                }
467 };
468
469 Cpu::Vendor_table const Cpu::rise_table[] FIASCO_INITDATA_CPU =
470 {
471   { 0xFF0, 0x500, 0xFFFF, "mP6 (iDragon)"                   },
472   { 0xFF0, 0x520, 0xFFFF, "mP6 (iDragon)"                   },
473   { 0xFF0, 0x580, 0xFFFF, "mP6 (iDragon II)"                },
474   { 0xFF0, 0x590, 0xFFFF, "mP6 (iDragon II)"                },
475   { 0x0,   0x0,   0xFFFF, ""                                }
476 };
477
478 Cpu::Vendor_table const Cpu::transmeta_table[] FIASCO_INITDATA_CPU =
479 {
480   { 0xFFF, 0x542, 0xFFFF, "TM3x00 (Crusoe)"                 },
481   { 0xFFF, 0x543, 0xFFFF, "TM5x00 (Crusoe)"                 },
482   { 0xFF0, 0xf20, 0xFFFF, "TM8x00 (Efficeon)"               },
483   { 0x0,   0x0,   0xFFFF, ""                                }
484 };
485
486 Cpu::Vendor_table const Cpu::sis_table[] FIASCO_INITDATA_CPU =
487 {
488   { 0xFF0, 0x500, 0xFFFF, "55x"                             },
489   { 0x0,   0x0,   0xFFFF, ""                                }
490 };
491
492 Cpu::Vendor_table const Cpu::nsc_table[] FIASCO_INITDATA_CPU =
493 {
494   { 0xFF0, 0x540, 0xFFFF, "Geode GX1"                       },
495   { 0xFF0, 0x550, 0xFFFF, "Geode GX2"                       },
496   { 0xFF0, 0x680, 0xFFFF, "Geode NX"                        },
497   { 0x0,   0x0,   0xFFFF, ""                                }
498 };
499
500 Cpu::Cache_table const Cpu::intel_cache_table[] FIASCO_INITDATA_CPU =
501 {
502   { 0x01, Tlb_inst_4k,        32,   4,    0 },
503   { 0x02, Tlb_inst_4M,         2,   4,    0 },
504   { 0x03, Tlb_data_4k,        64,   4,    0 },
505   { 0x04, Tlb_data_4M,         8,   4,    0 },
506   { 0x05, Tlb_data_4M,        32,   4,    0 },
507   { 0x06, Cache_l1_inst,       8,   4,   32 },
508   { 0x08, Cache_l1_inst,      16,   4,   32 },
509   { 0x09, Cache_l1_inst,      32,   4,   64 },
510   { 0x0A, Cache_l1_data,       8,   2,   32 },
511   { 0x0B, Tlb_inst_4M,         4,   4,    0 },
512   { 0x0C, Cache_l1_data,      16,   4,   32 },
513   { 0x0D, Cache_l1_data,      16,   4,   64 },
514   { 0x0E, Cache_l1_data,      24,   6,   64 },
515   { 0x21, Cache_l2,          256,   8,   64 },
516   { 0x22, Cache_l3,          512,   4,   64 },  /* sectored */
517   { 0x23, Cache_l3,         1024,   8,   64 },  /* sectored */
518   { 0x25, Cache_l3,         2048,   8,   64 },  /* sectored */
519   { 0x29, Cache_l3,         4096,   8,   64 },  /* sectored */
520   { 0x2C, Cache_l1_data,      32,   8,   64 },
521   { 0x30, Cache_l1_inst,      32,   8,   64 },
522   { 0x39, Cache_l2,          128,   4,   64 },  /* sectored */
523   { 0x3B, Cache_l2,          128,   2,   64 },  /* sectored */
524   { 0x3C, Cache_l2,          256,   4,   64 },  /* sectored */
525   { 0x41, Cache_l2,          128,   4,   32 },
526   { 0x42, Cache_l2,          256,   4,   32 },
527   { 0x43, Cache_l2,          512,   4,   32 },
528   { 0x44, Cache_l2,         1024,   4,   32 },
529   { 0x45, Cache_l2,         2048,   4,   32 },
530   { 0x46, Cache_l3,         4096,   4,   64 },
531   { 0x47, Cache_l3,         8192,   8,   64 },
532   { 0x48, Cache_l2,         3072,  12,   64 },
533   { 0x49, Cache_l2,         4096,  16,   64 },
534   { 0x4A, Cache_l3,         6144,  12,   64 },
535   { 0x4B, Cache_l3,         8192,  16,   64 },
536   { 0x4C, Cache_l3,        12288,  12,   64 },
537   { 0x4D, Cache_l3,        16384,  16,   64 },
538   { 0x4E, Cache_l3,         6144,  24,   64 },
539   { 0x4F, Tlb_inst_4k,        32,   0,    0 },
540   { 0x50, Tlb_inst_4k_4M,     64,   0,    0 },
541   { 0x51, Tlb_inst_4k_4M,    128,   0,    0 },
542   { 0x52, Tlb_inst_4k_4M,    256,   0,    0 },
543   { 0x56, Tlb_data_4M,        16,   4,    0 },
544   { 0x57, Tlb_data_4k,        16,   4,    0 },
545   { 0x59, Tlb_data_4k,        16,   0,    0 },
546   { 0x5A, Tlb_data_2M_4M,     32,   4,    0 },
547   { 0x5B, Tlb_data_4k_4M,     64,   0,    0 },
548   { 0x5C, Tlb_data_4k_4M,    128,   0,    0 },
549   { 0x5D, Tlb_data_4k_4M,    256,   0,    0 },
550   { 0x60, Cache_l1_data,      16,   8,   64 },
551   { 0x66, Cache_l1_data,       8,   4,   64 },  /* sectored */
552   { 0x67, Cache_l1_data,      16,   4,   64 },  /* sectored */
553   { 0x68, Cache_l1_data,      32,   4,   64 },  /* sectored */
554   { 0x70, Cache_l1_trace,     12,   8,    0 },
555   { 0x71, Cache_l1_trace,     16,   8,    0 },
556   { 0x72, Cache_l1_trace,     32,   8,    0 },
557   { 0x77, Cache_l1_inst,      16,   4,   64 },
558   { 0x78, Cache_l2,         1024,   4,   64 },
559   { 0x79, Cache_l2,          128,   8,   64 },  /* sectored */
560   { 0x7A, Cache_l2,          256,   8,   64 },  /* sectored */
561   { 0x7B, Cache_l2,          512,   8,   64 },  /* sectored */
562   { 0x7C, Cache_l2,         1024,   8,   64 },  /* sectored */
563   { 0x7D, Cache_l2,         2048,   8,   64 },
564   { 0x7E, Cache_l2,          256,   8,  128 },
565   { 0x7F, Cache_l2,          512,   2,   64 },
566   { 0x80, Cache_l2,          512,  16,   64 },
567   { 0x82, Cache_l2,          256,   8,   32 },
568   { 0x83, Cache_l2,          512,   8,   32 },
569   { 0x84, Cache_l2,         1024,   8,   32 },
570   { 0x85, Cache_l2,         2048,   8,   32 },
571   { 0x86, Cache_l2,          512,   4,   64 },
572   { 0x87, Cache_l2,         1024,   8,   64 },
573   { 0x8D, Cache_l3,         3072,  12,  128 },
574   { 0xB0, Tlb_inst_4k,       128,   4,    0 },
575   { 0xB3, Tlb_data_4k,       128,   4,    0 },
576   { 0xB4, Tlb_data_4k,       256,   4,    0 },
577   { 0xBA, Tlb_data_4k,        64,   4,    0 },
578   { 0xC0, Tlb_data_4k_4M,      8,   4,    0 },
579   { 0xCA, Tlb_data_4k_4M,    512,   4,    0 },
580   { 0xD0, Cache_l3,          512,   4,   64 },
581   { 0xD1, Cache_l3,         1024,   4,   64 },
582   { 0xD2, Cache_l3,         2048,   4,   64 },
583   { 0xD6, Cache_l3,         1024,   8,   64 },
584   { 0xD7, Cache_l3,         2048,   8,   64 },
585   { 0xD8, Cache_l3,         4096,   8,   64 },
586   { 0xDC, Cache_l3,         1536,  12,   64 },
587   { 0xDD, Cache_l3,         3072,  12,   64 },
588   { 0xDE, Cache_l3,         6144,  12,   64 },
589   { 0xE2, Cache_l3,         2048,  16,   64 },
590   { 0xE3, Cache_l3,         4096,  16,   64 },
591   { 0xE4, Cache_l3,         8192,  16,   64 },
592   { 0xEA, Cache_l3,        12288,  24,   64 },
593   { 0xEB, Cache_l3,        18432,  24,   64 },
594   { 0xEC, Cache_l3,        24576,  24,   64 },
595   { 0x0,  Cache_unknown,       0,   0,    0 }
596 };
597
598 char const * const Cpu::vendor_ident[] =
599 {
600    0,
601   "GenuineIntel",
602   "AuthenticAMD",
603   "CyrixInstead",
604   "CentaurHauls",
605   "UMC UMC UMC ",
606   "NexGenDriven",
607   "RiseRiseRise",
608   "GenuineTMx86",
609   "SiS SiS SiS ",
610   "Geode by NSC"
611 };
612
613 Cpu::Vendor_table const * const Cpu::vendor_table[] =
614 {
615   0,
616   intel_table,
617   amd_table,
618   cyrix_table,
619   via_table,
620   umc_table,
621   nexgen_table,
622   rise_table,
623   transmeta_table,
624   sis_table,
625   nsc_table
626 };
627
628 char const * const Cpu::exception_strings[] =
629 {
630   /*  0 */ "Divide Error",
631   /*  1 */ "Debug",
632   /*  2 */ "NMI Interrupt",
633   /*  3 */ "Breakpoint",
634   /*  4 */ "Overflow",
635   /*  5 */ "BOUND Range Exceeded",
636   /*  6 */ "Invalid Opcode",
637   /*  7 */ "Device Not Available",
638   /*  8 */ "Double Fault",
639   /*  9 */ "CoProcessor Segment Overrrun",
640   /* 10 */ "Invalid TSS",
641   /* 11 */ "Segment Not Present",
642   /* 12 */ "Stack Segment Fault",
643   /* 13 */ "General Protection",
644   /* 14 */ "Page Fault",
645   /* 15 */ "Reserved",
646   /* 16 */ "Floating-Point Error",
647   /* 17 */ "Alignment Check",
648   /* 18 */ "Machine Check",
649   /* 19 */ "SIMD Floating-Point Exception",
650   /* 20 */ "Reserved",
651   /* 21 */ "Reserved",
652   /* 22 */ "Reserved",
653   /* 23 */ "Reserved",
654   /* 24 */ "Reserved",
655   /* 25 */ "Reserved",
656   /* 26 */ "Reserved",
657   /* 27 */ "Reserved",
658   /* 28 */ "Reserved",
659   /* 29 */ "Reserved",
660   /* 30 */ "Reserved",
661   /* 31 */ "Reserved"
662 };
663
664 PUBLIC explicit FIASCO_INIT_CPU
665 Cpu::Cpu(unsigned cpu)
666 {
667   set_id(cpu);
668   if (cpu == 0)
669     {
670       _boot_cpu = this;
671       set_online(1);
672     }
673
674   init();
675 }
676
677
678 PUBLIC static
679 void
680 Cpu::init_global_features()
681 {}
682
683 PUBLIC static
684 char const *
685 Cpu::exception_string(Mword trapno)
686 {
687   if (trapno > 32)
688     return "Maskable Interrupt";
689   return exception_strings[trapno];
690 }
691
692 PUBLIC static inline FIASCO_INIT_CPU
693 void
694 Cpu::cpuid(Unsigned32 const mode,
695            Unsigned32 *const eax, Unsigned32 *const ebx,
696            Unsigned32 *const ecx, Unsigned32 *const edx)
697 {
698   asm volatile ("cpuid" : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
699                         : "a" (mode));
700 }
701
702
703
704 PRIVATE FIASCO_INIT_CPU
705 void
706 Cpu::cache_tlb_intel()
707 {
708   Unsigned8 desc[16];
709   unsigned i, count = 0;
710   Cache_table const *table;
711
712   do
713     {
714       cpuid(2, (Unsigned32 *)(desc),
715                (Unsigned32 *)(desc + 4),
716                (Unsigned32 *)(desc + 8),
717                (Unsigned32 *)(desc + 12));
718
719       for (i = 1; i < 16; i++)
720         {
721           // Null descriptor or register bit31 set (reserved)
722           if (!desc[i] || (desc[i / 4 * 4 + 3] & (1 << 7)))
723             continue;
724
725           for (table = intel_cache_table; table->desc; table++)
726             {
727               if (table->desc == desc[i])
728                 {
729                   switch (table->level)
730                     {
731                     case Cache_l1_data:
732                       _l1_data_cache_size      = table->size;
733                       _l1_data_cache_asso      = table->asso;
734                       _l1_data_cache_line_size = table->line_size;
735                       break;
736                     case Cache_l1_inst:
737                       _l1_inst_cache_size      = table->size;
738                       _l1_inst_cache_asso      = table->asso;
739                       _l1_inst_cache_line_size = table->line_size;
740                       break;
741                     case Cache_l1_trace:
742                       _l1_trace_cache_size = table->size;
743                       _l1_trace_cache_asso = table->asso;
744                       break;
745                     case Cache_l2:
746                       _l2_cache_size      = table->size;
747                       _l2_cache_asso      = table->asso;
748                       _l2_cache_line_size = table->line_size;
749                       break;
750                     case Cache_l3:
751                       _l3_cache_size      = table->size;
752                       _l3_cache_asso      = table->asso;
753                       _l3_cache_line_size = table->line_size;
754                       break;
755                     case Tlb_inst_4k:
756                       _inst_tlb_4k_entries += table->size;
757                       break;
758                     case Tlb_data_4k:
759                       _data_tlb_4k_entries += table->size;
760                       break;
761                     case Tlb_inst_4M:
762                       _inst_tlb_4m_entries += table->size;
763                       break;
764                     case Tlb_data_4M:
765                       _data_tlb_4m_entries += table->size;
766                       break;
767                     case Tlb_inst_4k_4M:
768                       _inst_tlb_4k_4m_entries += table->size;
769                       break;
770                     case Tlb_data_4k_4M:
771                       _data_tlb_4k_4m_entries += table->size;
772                       break;
773                     default:
774                       break;
775                     }
776                   break;
777                 }
778             }
779         }
780     } 
781   while (++count < *desc);
782 }
783
784 PRIVATE FIASCO_INIT_CPU
785 void
786 Cpu::cache_tlb_l1()
787 {
788   Unsigned32 eax, ebx, ecx, edx;
789   cpuid(0x80000005, &eax, &ebx, &ecx, &edx);
790
791   _l1_data_cache_size      = (ecx >> 24) & 0xFF;
792   _l1_data_cache_asso      = (ecx >> 16) & 0xFF;
793   _l1_data_cache_line_size =  ecx        & 0xFF;
794
795   _l1_inst_cache_size      = (edx >> 24) & 0xFF;
796   _l1_inst_cache_asso      = (edx >> 16) & 0xFF;
797   _l1_inst_cache_line_size =  edx        & 0xFF;
798
799   _data_tlb_4k_entries     = (ebx >> 16) & 0xFF;
800   _inst_tlb_4k_entries     =  ebx        & 0xFF;
801   _data_tlb_4m_entries     = (eax >> 16) & 0xFF;
802   _inst_tlb_4m_entries     =  eax        & 0xFF;
803 }
804
805 PRIVATE FIASCO_INIT_CPU
806 void
807 Cpu::cache_tlb_l2_l3()
808 {
809   Unsigned32 eax, ebx, ecx, edx;
810   cpuid(0x80000006, &eax, &ebx, &ecx, &edx);
811
812   if (vendor() == Vendor_via)
813     {
814       _l2_cache_size          = (ecx >> 24) & 0xFF;
815       _l2_cache_asso          = (ecx >> 16) & 0xFF;
816     }
817   else
818     {
819       _l2_data_tlb_4m_entries = (eax >> 16) & 0xFFF;
820       _l2_inst_tlb_4m_entries =  eax        & 0xFFF;
821       _l2_data_tlb_4k_entries = (ebx >> 16) & 0xFFF;
822       _l2_inst_tlb_4k_entries =  ebx        & 0xFFF;
823       _l2_cache_size          = (ecx >> 16) & 0xFFFF;
824       _l2_cache_asso          = (ecx >> 12) & 0xF;
825     }
826
827   _l2_cache_line_size = ecx & 0xFF;
828
829   _l3_cache_size      = (edx >> 18) << 9;
830   _l3_cache_asso      = (edx >> 12) & 0xF;
831   _l3_cache_line_size = edx & 0xFF;
832 }
833
834 PRIVATE FIASCO_INIT_CPU
835 void
836 Cpu::addr_size_info()
837 {
838   Unsigned32 eax, ebx, ecx, edx;
839   cpuid(0x80000008, &eax, &ebx, &ecx, &edx);
840
841   _phys_bits = eax & 0xff;
842   _virt_bits = (eax & 0xff00) >> 8;
843 }
844
845 PUBLIC static
846 unsigned
847 Cpu::amd_cpuid_mnc()
848 {
849   Unsigned32 eax, ebx, ecx, edx;
850   cpuid(0x80000008, &eax, &ebx, &ecx, &edx);
851
852   unsigned apicidcoreidsize = (ecx >> 12) & 0xf;
853   if (apicidcoreidsize == 0)
854     return (ecx & 0xf) + 1; // NC
855   return 1 << apicidcoreidsize;
856 }
857
858 PRIVATE FIASCO_INIT_CPU
859 void
860 Cpu::set_model_str()
861 {
862   Vendor_table const *table;
863
864   if (_model_str[0])
865     return;
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             {
1038               Unsigned32 *s = (Unsigned32 *)_model_str;
1039               for (unsigned i = 0; i < 3; ++i)
1040                 cpuid(0x80000002 + i, &s[0 + 4*i], &s[1 + 4*i],
1041                                       &s[2 + 4*i], &s[3 + 4*i]);
1042               _model_str[48] = 0;
1043             }
1044           case 0x80000003:
1045           case 0x80000002:
1046           case 0x80000001:
1047             if (_vendor == Vendor_intel || _vendor == Vendor_amd)
1048               cpuid(0x80000001, &i, &i, &_ext_8000_0001_ecx,
1049                                 &_ext_8000_0001_edx);
1050             break;
1051           }
1052       }
1053
1054     // see Intel Spec on SYSENTER:
1055     // Some Pentium Pro pretend to have it, but actually lack it
1056     if ((_version & 0xFFF) < 0x633)
1057       _features &= ~FEAT_SEP;
1058
1059   } else
1060     _version = 0x400;
1061
1062   set_model_str();
1063
1064   set_flags(eflags);
1065 }
1066
1067 PUBLIC inline NEEDS["processor.h"]
1068 void
1069 Cpu::busy_wait_ns(Unsigned64 ns)
1070 {
1071   Unsigned64 stop = rdtsc () + ns_to_tsc(ns);
1072
1073   while (rdtsc() < stop)
1074     Proc::pause();
1075 }
1076
1077
1078 PUBLIC
1079 void
1080 Cpu::show_cache_tlb_info(const char *indent) const
1081 {
1082   char s[16];
1083
1084   *s = '\0';
1085   if (_l2_inst_tlb_4k_entries)
1086     snprintf(s, sizeof(s), "/%u", _l2_inst_tlb_4k_entries);
1087   if (_inst_tlb_4k_entries)
1088     printf("%s%4u%s Entry I TLB (4K pages)", indent, _inst_tlb_4k_entries, s);
1089   *s = '\0';
1090   if (_l2_inst_tlb_4m_entries)
1091     snprintf(s, sizeof(s), "/%u", _l2_inst_tlb_4k_entries);
1092   if (_inst_tlb_4m_entries)
1093     printf("   %4u%s Entry I TLB (4M pages)", _inst_tlb_4m_entries, s);
1094   if (_inst_tlb_4k_4m_entries)
1095     printf("%s%4u Entry I TLB (4K or 4M pages)",
1096            indent, _inst_tlb_4k_4m_entries);
1097   if (_inst_tlb_4k_entries || _inst_tlb_4m_entries || _inst_tlb_4k_4m_entries)
1098     putchar('\n');
1099   *s = '\0';
1100   if (_l2_data_tlb_4k_entries)
1101     snprintf(s, sizeof(s), "/%u", _l2_data_tlb_4k_entries);
1102   if (_data_tlb_4k_entries)
1103     printf("%s%4u%s Entry D TLB (4K pages)", indent, _data_tlb_4k_entries, s);
1104   *s = '\0';
1105   if (_l2_data_tlb_4m_entries)
1106     snprintf(s, sizeof(s), "/%u", _l2_data_tlb_4m_entries);
1107   if (_data_tlb_4m_entries)
1108     printf("   %4u%s Entry D TLB (4M pages)", _data_tlb_4m_entries, s);
1109   if (_data_tlb_4k_4m_entries)
1110     printf("%s%4u Entry D TLB (4k or 4M pages)",
1111            indent, _data_tlb_4k_4m_entries);
1112   if (_data_tlb_4k_entries || _data_tlb_4m_entries || _data_tlb_4k_4m_entries)
1113     putchar('\n');
1114
1115   if (_l1_trace_cache_size)
1116     printf("%s%3uK %c-ops T Cache (%u-way associative)\n",
1117            indent, _l1_trace_cache_size, Config::char_micro,
1118            _l1_trace_cache_asso);
1119
1120   else if (_l1_inst_cache_size)
1121     printf("%s%4u KB L1 I Cache (%u-way associative, %u bytes per line)\n",
1122            indent, _l1_inst_cache_size, _l1_inst_cache_asso,
1123            _l1_inst_cache_line_size);
1124
1125   if (_l1_data_cache_size)
1126     printf("%s%4u KB L1 D Cache (%u-way associative, %u bytes per line)\n"
1127            "%s%4u KB L2 U Cache (%u-way associative, %u bytes per line)\n",
1128            indent, _l1_data_cache_size, _l1_data_cache_asso,
1129            _l1_data_cache_line_size,
1130            indent, _l2_cache_size, _l2_cache_asso, _l2_cache_line_size);
1131
1132   if (_l3_cache_size)
1133     printf("%s%4u KB L3 U Cache (%u-way associative, %u bytes per line)\n",
1134            indent, _l3_cache_size, _l3_cache_asso, _l3_cache_line_size);
1135 }
1136
1137 IMPLEMENT
1138 void 
1139 Cpu::disable(unsigned cpu, char const *reason)
1140 {
1141   printf("CPU%u: is disabled: %s\n", cpu, reason);
1142 }
1143
1144 // Function used for calculating apic scaler
1145 PUBLIC static inline
1146 Unsigned32
1147 Cpu::muldiv(Unsigned32 val, Unsigned32 mul, Unsigned32 div)
1148 {
1149   Unsigned32 dummy;
1150
1151   asm volatile ("mull %3 ; divl %4\n\t"
1152                :"=a" (val), "=d" (dummy)
1153                : "0" (val),  "d" (mul),  "c" (div));
1154   return val;
1155 }
1156
1157
1158 PUBLIC static inline
1159 Unsigned32
1160 Cpu::get_cs()
1161 {
1162   Unsigned32 val;
1163   asm volatile ("mov %%cs, %0" : "=rm" (val));
1164   return val;
1165 }
1166
1167 PUBLIC static inline
1168 Unsigned32
1169 Cpu::get_ds()
1170 {
1171   Unsigned32 val;
1172   asm volatile ("mov %%ds, %0" : "=rm" (val));
1173   return val;
1174 }
1175
1176 PUBLIC static inline
1177 Unsigned32
1178 Cpu::get_es()
1179 {
1180   Unsigned32 val;
1181   asm volatile ("mov %%es, %0" : "=rm" (val));
1182   return val;
1183 }
1184
1185 PUBLIC static inline
1186 Unsigned32
1187 Cpu::get_ss()
1188 {
1189   Unsigned32 val;
1190   asm volatile ("mov %%ss, %0" : "=rm" (val));
1191   return val;
1192 }
1193
1194 PUBLIC static inline
1195 void
1196 Cpu::set_ds(Unsigned32 val)
1197 { asm volatile ("mov %0, %%ds" : : "rm" (val)); }
1198
1199 PUBLIC static inline
1200 void
1201 Cpu::set_es(Unsigned32 val)
1202 { asm volatile ("mov %0, %%es" : : "rm" (val)); }
1203
1204 //----------------------------------------------------------------------------
1205 IMPLEMENTATION[ia32, amd64]:
1206
1207 #include "boot_info.h"
1208 #include "config.h"
1209 #include "div32.h"
1210 #include "gdt.h"
1211 #include "globals.h"
1212 #include "initcalls.h"
1213 #include "io.h"
1214 #include "pit.h"
1215 #include "processor.h"
1216 #include "regdefs.h"
1217 #include "tss.h"
1218
1219
1220 PUBLIC static inline
1221 void
1222 Cpu::set_cr0(unsigned long val)
1223 { asm volatile ("mov %0, %%cr0" : : "r" (val)); }
1224
1225 PUBLIC static inline
1226 void
1227 Cpu::set_pdbr(unsigned long addr)
1228 { asm volatile ("mov %0, %%cr3" : : "r" (addr)); }
1229
1230 PUBLIC static inline
1231 void
1232 Cpu::set_cr4(unsigned long val)
1233 { asm volatile ("mov %0, %%cr4" : : "r" (val)); }
1234
1235 PUBLIC static inline
1236 void
1237 Cpu::set_ldt(Unsigned16 val)
1238 { asm volatile ("lldt %0" : : "rm" (val)); }
1239
1240
1241 PUBLIC static inline
1242 void
1243 Cpu::set_ss(Unsigned32 val)
1244 { asm volatile ("mov %0, %%ss" : : "r" (val)); }
1245
1246 PUBLIC static inline
1247 void
1248 Cpu::set_tr(Unsigned16 val)
1249 { asm volatile ("ltr %0" : : "rm" (val)); }
1250
1251 PUBLIC static inline
1252 Mword
1253 Cpu::get_cr0()
1254 {
1255   Mword val;
1256   asm volatile ("mov %%cr0, %0" : "=r" (val));
1257   return val;
1258 }
1259
1260 PUBLIC static inline
1261 Address
1262 Cpu::get_pdbr()
1263 { Address addr; asm volatile ("mov %%cr3, %0" : "=r" (addr)); return addr; }
1264
1265 PUBLIC static inline
1266 Mword
1267 Cpu::get_cr4()
1268 { Mword val; asm volatile ("mov %%cr4, %0" : "=r" (val)); return val; }
1269
1270 PUBLIC static inline
1271 Unsigned16
1272 Cpu::get_ldt()
1273 { Unsigned16 val; asm volatile ("sldt %0" : "=rm" (val)); return val; }
1274
1275 PUBLIC static inline
1276 Unsigned16
1277 Cpu::get_tr()
1278 { Unsigned16 val; asm volatile ("str %0" : "=rm" (val)); return val; }
1279
1280 IMPLEMENT inline
1281 int
1282 Cpu::can_wrmsr() const
1283 { return features() & FEAT_MSR; }
1284
1285 PUBLIC static inline
1286 Unsigned64
1287 Cpu::rdmsr(Unsigned32 reg)
1288 {
1289   Unsigned32 l,h;
1290
1291   asm volatile ("rdmsr" : "=a" (l), "=d" (h) : "c" (reg));
1292   return ((Unsigned64)h << 32) + (Unsigned64)l;
1293 }
1294
1295 PUBLIC static inline
1296 Unsigned64
1297 Cpu::rdpmc(Unsigned32 idx, Unsigned32)
1298 {
1299   Unsigned32 l,h;
1300
1301   asm volatile ("rdpmc" : "=a" (l), "=d" (h) : "c" (idx));
1302   return ((Unsigned64)h << 32) + (Unsigned64)l;
1303 }
1304
1305 PUBLIC static inline
1306 void
1307 Cpu::wrmsr(Unsigned32 low, Unsigned32 high, Unsigned32 reg)
1308 { asm volatile ("wrmsr" : : "a" (low), "d" (high), "c" (reg)); }
1309
1310 PUBLIC static inline
1311 void
1312 Cpu::wrmsr(Unsigned64 msr, Unsigned32 reg)
1313 { asm volatile ("wrmsr" : : "a" ((Unsigned32)msr), "d" ((Unsigned32)(msr >> 32)), "c" (reg)); }
1314
1315 PUBLIC static inline
1316 void
1317 Cpu::enable_rdpmc()
1318 { set_cr4(get_cr4() | CR4_PCE); }
1319
1320
1321 IMPLEMENT FIASCO_INIT_CPU
1322 void
1323 Cpu::init_lbr_type()
1324 {
1325   _lbr = Lbr_unsupported;
1326
1327   if (can_wrmsr())
1328     {
1329       // Intel
1330       if (vendor() == Vendor_intel)
1331         {
1332           if (family() == 15)
1333             _lbr = model() < 3 ? Lbr_pentium_4 : Lbr_pentium_4_ext; // P4
1334           else if (family() >= 6)
1335             _lbr = Lbr_pentium_6; // PPro, PIII
1336         }
1337       else if (vendor() == Vendor_amd)
1338         {
1339           if ((family() == 6) || (family() == 15))
1340             _lbr = Lbr_pentium_6; // K7/K8
1341         }
1342     }
1343 }
1344
1345
1346 IMPLEMENT FIASCO_INIT_CPU
1347 void
1348 Cpu::init_bts_type()
1349 {
1350   _bts = Bts_unsupported;
1351
1352   if (can_wrmsr() && vendor() == Vendor_intel)
1353     {
1354       if (family() == 15 && (rdmsr(0x1A0) & (1<<11)) == 0)
1355         _bts = Bts_pentium_4;
1356       if (family() == 6  && (model() == 9 || (model() >= 13 &&
1357               model() <= 15)))
1358         _bts = Bts_pentium_m;
1359       if (!(features() & FEAT_DS))
1360         _bts = Bts_unsupported;
1361     }
1362 }
1363
1364
1365 PUBLIC inline
1366 void
1367 Cpu::lbr_enable(bool on)
1368 {
1369   if (lbr_type() != Lbr_unsupported)
1370     {
1371       if (on)
1372         {
1373           lbr_active    = true;
1374           debugctl_set |= 1;
1375           debugctl_busy = true;
1376         }
1377       else
1378         {
1379           lbr_active    = false;
1380           debugctl_set &= ~1;
1381           debugctl_busy = lbr_active || bts_active;
1382           wrmsr(debugctl_reset, MSR_DEBUGCTLA);
1383         }
1384     }
1385 }
1386
1387
1388 PUBLIC inline
1389 void
1390 Cpu::btf_enable(bool on)
1391 {
1392   if (lbr_type() != Lbr_unsupported)
1393     {
1394       if (on)
1395         {
1396           btf_active      = true;
1397           debugctl_set   |= 2;
1398           debugctl_reset |= 2; /* don't disable bit in kernel */
1399           wrmsr(2, MSR_DEBUGCTLA);     /* activate _now_ */
1400         }
1401       else
1402         {
1403           btf_active    = false;
1404           debugctl_set &= ~2;
1405           debugctl_busy = lbr_active || bts_active;
1406           wrmsr(debugctl_reset, MSR_DEBUGCTLA);
1407         }
1408     }
1409 }
1410
1411
1412 PUBLIC
1413 void
1414 Cpu::bts_enable(bool on)
1415 {
1416   if (bts_type() != Bts_unsupported)
1417     {
1418       if (on)
1419         {
1420           switch (bts_type())
1421             {
1422             case Bts_pentium_4: bts_active = true; debugctl_set |= 0x0c; break;
1423             case Bts_pentium_m: bts_active = true; debugctl_set |= 0xc0; break;
1424             default:;
1425             }
1426           debugctl_busy = lbr_active || bts_active;
1427         }
1428       else
1429         {
1430           bts_active = false;
1431           switch (bts_type())
1432             {
1433             case Bts_pentium_4: debugctl_set &= ~0x0c; break;
1434             case Bts_pentium_m: debugctl_set &= ~0xc0; break;
1435             default:;
1436             }
1437           debugctl_busy = lbr_active || bts_active;
1438           wrmsr(debugctl_reset, MSR_DEBUGCTLA);
1439         }
1440     }
1441 }
1442
1443 PUBLIC inline
1444 void
1445 Cpu::debugctl_enable()
1446 {
1447   if (debugctl_busy)
1448     wrmsr(debugctl_set, MSR_DEBUGCTLA);
1449 }
1450
1451 PUBLIC inline
1452 void
1453 Cpu::debugctl_disable()
1454 {
1455   if (debugctl_busy)
1456     wrmsr(debugctl_reset, MSR_DEBUGCTLA);
1457 }
1458
1459 /*
1460  * AMD OS-Visible Workaround Information
1461  * print a warning if a CPU is affected by any known erratum
1462  */
1463 PUBLIC
1464 void
1465 Cpu::print_errata()
1466 {
1467   if (vendor() == Vendor_amd && has_amd_osvw() && can_wrmsr())
1468     {
1469       Unsigned16 osvw_id_length, i;
1470       bool affected = false;
1471       osvw_id_length = rdmsr(0xc0010140) & 0xff;
1472
1473       for (i = 1; ((i - 1) * 64) < osvw_id_length; i++)
1474         {
1475           Unsigned64 osvw_msr = rdmsr(0xc0010140 + i);
1476           if (osvw_msr != 0)
1477             {
1478               printf("\033[31mOSVW_MSR%d = 0x%016llx\033[m\n",
1479                      i, rdmsr(0xc0010140 + i));
1480               affected = true;
1481             }
1482         }
1483       if (affected)
1484         printf("\033[31m#Errata known %d, affected by at least one\033[m\n",
1485                osvw_id_length);
1486     }
1487 }
1488
1489 IMPLEMENT FIASCO_INIT_CPU
1490 void
1491 Cpu::init()
1492 {
1493   identify();
1494
1495   init_lbr_type();
1496   init_bts_type();
1497
1498   calibrate_tsc();
1499
1500   if (scaler_tsc_to_ns)
1501     _frequency = ns_to_tsc(1000000000UL);
1502
1503   Unsigned32 cr4 = get_cr4();
1504
1505   if (features() & FEAT_FXSR)
1506     cr4 |= CR4_OSFXSR;
1507
1508   if (features() & FEAT_SSE)
1509     cr4 |= CR4_OSXMMEXCPT;
1510
1511   set_cr4 (cr4);
1512
1513   // reset time stamp counter (better for debugging)
1514   if ((features() & FEAT_TSC) && can_wrmsr())
1515     wrmsr(0, 0, MSR_TSC);
1516
1517   if ((features() & FEAT_PAT) && can_wrmsr())
1518     wrmsr(0x00010406, 0x00070406, MSR_PAT);
1519
1520   print_errata();
1521 }
1522
1523 PUBLIC
1524 void
1525 Cpu::print() const
1526 {
1527   printf ("CPU[%u:%u]: %s (%X:%X:%X:%X)[%08x] Model: %s at %llu MHz\n\n",
1528           id(), phys_id() >> 24,
1529           vendor_str(), family(), model(), stepping(), brand(), _version, model_str(),
1530           div32(frequency(), 1000000));
1531 }
1532
1533 PUBLIC
1534 void
1535 Cpu::set_sysenter(void (*func)(void))
1536 {
1537   // Check for Sysenter/Sysexit Feature
1538   if (sysenter())
1539     wrmsr ((Mword) func, 0, MSR_SYSENTER_EIP);
1540 }
1541
1542
1543 PUBLIC
1544 void
1545 Cpu::set_fast_entry(void (*func)(void))
1546 {
1547   set_sysenter(func);
1548 }
1549
1550 extern "C" void entry_sys_fast_ipc (void);
1551 extern "C" void entry_sys_fast_ipc_c (void);
1552
1553 PUBLIC FIASCO_INIT_CPU
1554 void
1555 Cpu::init_sysenter()
1556 {
1557   // Check for Sysenter/Sysexit Feature
1558   if (sysenter())
1559     {
1560       wrmsr (Gdt::gdt_code_kernel, 0, MSR_SYSENTER_CS);
1561       wrmsr ((unsigned long)&kernel_sp(), 0, MSR_SYSENTER_ESP);
1562       if (Config::Assembler_ipc_shortcut)
1563         set_sysenter(entry_sys_fast_ipc);
1564       else
1565         set_sysenter(entry_sys_fast_ipc_c);
1566     }
1567 }
1568
1569
1570 // Return 2^32 / (tsc clocks per usec)
1571 FIASCO_INIT_CPU
1572 void
1573 Cpu::calibrate_tsc ()
1574 {
1575   const unsigned calibrate_time = 50000 /*us*/ + 1;
1576
1577   // sanity check
1578   if (! (features() & FEAT_TSC))
1579     goto bad_ctc;
1580
1581   Unsigned64 tsc_start, tsc_end;
1582   Unsigned32 count, tsc_to_ns_div, dummy;
1583
1584     {
1585       // disable interrupts
1586       Proc::Status o = Proc::cli_save();
1587
1588       Pit::setup_channel2_to_20hz();
1589
1590       tsc_start = rdtsc ();
1591       count = 0;
1592       do
1593         {
1594           count++;
1595         }
1596       while ((Io::in8 (0x61) & 0x20) == 0);
1597       tsc_end = rdtsc ();
1598
1599       // restore flags
1600       Proc::sti_restore(o);
1601     }
1602
1603   // Error: ECTCNEVERSET
1604   if (count <= 1)
1605     goto bad_ctc;
1606
1607   tsc_end -= tsc_start;
1608
1609   // prevent overflow in division (CPU too fast)
1610   if (tsc_end & 0xffffffff00000000LL)
1611     goto bad_ctc;
1612
1613   // prevent overflow in division (CPU too slow)
1614   if ((tsc_end & 0xffffffffL) < calibrate_time)
1615     goto bad_ctc;
1616
1617   // tsc_to_ns_div = calibrate_time * 2^32 / tsc
1618   asm ("divl %2"
1619        :"=a" (tsc_to_ns_div), "=d" (dummy)
1620        :"r" ((Unsigned32)tsc_end), "a" (0), "d" (calibrate_time));
1621
1622   // scaler_tsc_to_ns = (tsc_to_ns_div * 1000) / 32
1623   // not using muldiv(tsc_to_ns_div, 1000, 1 << 5), as div result > (1 << 32)
1624   // will get trap0 if system frequency is too low
1625   scaler_tsc_to_ns  = tsc_to_ns_div * 31;
1626   scaler_tsc_to_ns += tsc_to_ns_div / 4;
1627   scaler_tsc_to_us  = tsc_to_ns_div;
1628   scaler_ns_to_tsc  = muldiv(1 << 31, ((Unsigned32)tsc_end),
1629                              calibrate_time * 1000 >> 1 * 1 << 5);
1630
1631   return;
1632
1633 bad_ctc:
1634   if (Config::kinfo_timer_uses_rdtsc)
1635     panic("Can't calibrate tsc");
1636 }
1637
1638 IMPLEMENT inline
1639 Unsigned64
1640 Cpu::time_us() const
1641 {
1642   return tsc_to_us (rdtsc());
1643 }
1644
1645
1646 PUBLIC inline
1647 void
1648 Cpu::enable_ldt(Address addr, int size)
1649 {
1650   if (!size)
1651     {
1652       get_gdt()->clear_entry (Gdt::gdt_ldt / 8);
1653       set_ldt(0);
1654     }
1655   else
1656     {
1657       get_gdt()->set_entry_byte(Gdt::gdt_ldt / 8, addr, size-1, 2/*=ldt*/, 0);
1658       set_ldt(Gdt::gdt_ldt);
1659     }
1660 }
1661
1662
1663 PUBLIC static inline
1664 Unsigned32
1665 Cpu::get_fs()
1666 { Unsigned32 val; asm volatile ("mov %%fs, %0" : "=rm" (val)); return val; }
1667
1668 PUBLIC static inline
1669 Unsigned32
1670 Cpu::get_gs()
1671 { Unsigned32 val; asm volatile ("mov %%gs, %0" : "=rm" (val)); return val; }
1672
1673 PUBLIC static inline
1674 void
1675 Cpu::set_fs(Unsigned32 val)
1676 { asm volatile ("mov %0, %%fs" : : "rm" (val)); }
1677
1678 PUBLIC static inline
1679 void
1680 Cpu::set_gs(Unsigned32 val)
1681 { asm volatile ("mov %0, %%gs" : : "rm" (val)); }
1682
1683 IMPLEMENT inline
1684 unsigned
1685 Cpu::phys_id() const
1686 { return _brand & 0xff000000; }
1687
1688 PUBLIC static
1689 unsigned
1690 Cpu::phys_id_direct()
1691 {
1692   Unsigned32 a,b,c,d;
1693   cpuid (1, &a, &b, &c, &d);
1694   return b & 0xff000000;
1695 }