| 48 | | //#define DEBUG_PCALL |
|---|
| 49 | | |
|---|
| 50 | | #if 0 |
|---|
| 51 | | #define raise_exception_err(a, b)\ |
|---|
| 52 | | do {\ |
|---|
| 53 | | if (logfile)\ |
|---|
| 54 | | fprintf(logfile, "raise_exception line=%d\n", __LINE__);\ |
|---|
| 55 | | (raise_exception_err)(a, b);\ |
|---|
| 56 | | } while (0) |
|---|
| 57 | | #endif |
|---|
| 58 | | |
|---|
| 59 | | const uint8_t parity_table[256] = { |
|---|
| 60 | | CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, |
|---|
| 61 | | 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, |
|---|
| 62 | | 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, |
|---|
| 63 | | CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, |
|---|
| 64 | | 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, |
|---|
| 65 | | CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, |
|---|
| 66 | | CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, |
|---|
| 67 | | 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, |
|---|
| 68 | | 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, |
|---|
| 69 | | CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, |
|---|
| 70 | | CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, |
|---|
| 71 | | 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, |
|---|
| 72 | | CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, |
|---|
| 73 | | 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, |
|---|
| 74 | | 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, |
|---|
| 75 | | CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, |
|---|
| 76 | | 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, |
|---|
| 77 | | CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, |
|---|
| 78 | | CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, |
|---|
| 79 | | 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, |
|---|
| 80 | | CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, |
|---|
| 81 | | 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, |
|---|
| 82 | | 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, |
|---|
| 83 | | CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, |
|---|
| 84 | | CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, |
|---|
| 85 | | 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, |
|---|
| 86 | | 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, |
|---|
| 87 | | CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, |
|---|
| 88 | | 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, |
|---|
| 89 | | CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, |
|---|
| 90 | | CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, |
|---|
| 91 | | 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, |
|---|
| | 35 | //#define DEBUG_MMU |
|---|
| | 36 | |
|---|
| | 37 | static int cpu_x86_register (CPUX86State *env, const char *cpu_model); |
|---|
| | 38 | |
|---|
| | 39 | static void add_flagname_to_bitmaps(char *flagname, uint32_t *features, |
|---|
| | 40 | uint32_t *ext_features, |
|---|
| | 41 | uint32_t *ext2_features, |
|---|
| | 42 | uint32_t *ext3_features) |
|---|
| | 43 | { |
|---|
| | 44 | int i; |
|---|
| | 45 | /* feature flags taken from "Intel Processor Identification and the CPUID |
|---|
| | 46 | * Instruction" and AMD's "CPUID Specification". In cases of disagreement |
|---|
| | 47 | * about feature names, the Linux name is used. */ |
|---|
| | 48 | static const char *feature_name[] = { |
|---|
| | 49 | "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", |
|---|
| | 50 | "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov", |
|---|
| | 51 | "pat", "pse36", "pn" /* Intel psn */, "clflush" /* Intel clfsh */, NULL, "ds" /* Intel dts */, "acpi", "mmx", |
|---|
| | 52 | "fxsr", "sse", "sse2", "ss", "ht" /* Intel htt */, "tm", "ia64", "pbe", |
|---|
| | 53 | }; |
|---|
| | 54 | static const char *ext_feature_name[] = { |
|---|
| | 55 | "pni" /* Intel,AMD sse3 */, NULL, NULL, "monitor", "ds_cpl", "vmx", NULL /* Linux smx */, "est", |
|---|
| | 56 | "tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL, |
|---|
| | 57 | NULL, NULL, "dca", NULL, NULL, NULL, NULL, "popcnt", |
|---|
| | 58 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
|---|
| | 59 | }; |
|---|
| | 60 | static const char *ext2_feature_name[] = { |
|---|
| | 61 | "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce", |
|---|
| | 62 | "cx8" /* AMD CMPXCHG8B */, "apic", NULL, "syscall", "mttr", "pge", "mca", "cmov", |
|---|
| | 63 | "pat", "pse36", NULL, NULL /* Linux mp */, "nx" /* Intel xd */, NULL, "mmxext", "mmx", |
|---|
| | 64 | "fxsr", "fxsr_opt" /* AMD ffxsr */, "pdpe1gb" /* AMD Page1GB */, "rdtscp", NULL, "lm" /* Intel 64 */, "3dnowext", "3dnow", |
|---|
| | 65 | }; |
|---|
| | 66 | static const char *ext3_feature_name[] = { |
|---|
| | 67 | "lahf_lm" /* AMD LahfSahf */, "cmp_legacy", "svm", "extapic" /* AMD ExtApicSpace */, "cr8legacy" /* AMD AltMovCr8 */, "abm", "sse4a", "misalignsse", |
|---|
| | 68 | "3dnowprefetch", "osvw", NULL /* Linux ibs */, NULL, "skinit", "wdt", NULL, NULL, |
|---|
| | 69 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
|---|
| | 70 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
|---|
| | 71 | }; |
|---|
| | 72 | |
|---|
| | 73 | for ( i = 0 ; i < 32 ; i++ ) |
|---|
| | 74 | if (feature_name[i] && !strcmp (flagname, feature_name[i])) { |
|---|
| | 75 | *features |= 1 << i; |
|---|
| | 76 | return; |
|---|
| | 77 | } |
|---|
| | 78 | for ( i = 0 ; i < 32 ; i++ ) |
|---|
| | 79 | if (ext_feature_name[i] && !strcmp (flagname, ext_feature_name[i])) { |
|---|
| | 80 | *ext_features |= 1 << i; |
|---|
| | 81 | return; |
|---|
| | 82 | } |
|---|
| | 83 | for ( i = 0 ; i < 32 ; i++ ) |
|---|
| | 84 | if (ext2_feature_name[i] && !strcmp (flagname, ext2_feature_name[i])) { |
|---|
| | 85 | *ext2_features |= 1 << i; |
|---|
| | 86 | return; |
|---|
| | 87 | } |
|---|
| | 88 | for ( i = 0 ; i < 32 ; i++ ) |
|---|
| | 89 | if (ext3_feature_name[i] && !strcmp (flagname, ext3_feature_name[i])) { |
|---|
| | 90 | *ext3_features |= 1 << i; |
|---|
| | 91 | return; |
|---|
| | 92 | } |
|---|
| | 93 | fprintf(stderr, "CPU feature %s not found\n", flagname); |
|---|
| | 94 | } |
|---|
| | 95 | #ifndef VBOX |
|---|
| | 96 | CPUX86State *cpu_x86_init(const char *cpu_model) |
|---|
| | 97 | { |
|---|
| | 98 | CPUX86State *env; |
|---|
| | 99 | static int inited; |
|---|
| | 100 | |
|---|
| | 101 | env = qemu_mallocz(sizeof(CPUX86State)); |
|---|
| | 102 | if (!env) |
|---|
| | 103 | return NULL; |
|---|
| | 104 | #else |
|---|
| | 105 | CPUX86State *cpu_x86_init(CPUX86State *env, const char *cpu_model) |
|---|
| | 106 | { |
|---|
| | 107 | static int inited; |
|---|
| | 108 | #endif |
|---|
| | 109 | cpu_exec_init(env); |
|---|
| | 110 | env->cpu_model_str = cpu_model; |
|---|
| | 111 | |
|---|
| | 112 | /* init various static tables */ |
|---|
| | 113 | if (!inited) { |
|---|
| | 114 | inited = 1; |
|---|
| | 115 | optimize_flags_init(); |
|---|
| | 116 | } |
|---|
| | 117 | if (cpu_x86_register(env, cpu_model) < 0) { |
|---|
| | 118 | cpu_x86_close(env); |
|---|
| | 119 | return NULL; |
|---|
| | 120 | } |
|---|
| | 121 | cpu_reset(env); |
|---|
| | 122 | #ifdef USE_KQEMU |
|---|
| | 123 | kqemu_init(env); |
|---|
| | 124 | #endif |
|---|
| | 125 | return env; |
|---|
| | 126 | } |
|---|
| | 127 | |
|---|
| | 128 | typedef struct x86_def_t { |
|---|
| | 129 | const char *name; |
|---|
| | 130 | uint32_t level; |
|---|
| | 131 | uint32_t vendor1, vendor2, vendor3; |
|---|
| | 132 | int family; |
|---|
| | 133 | int model; |
|---|
| | 134 | int stepping; |
|---|
| | 135 | uint32_t features, ext_features, ext2_features, ext3_features; |
|---|
| | 136 | uint32_t xlevel; |
|---|
| | 137 | char model_id[48]; |
|---|
| | 138 | } x86_def_t; |
|---|
| | 139 | |
|---|
| | 140 | #define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE) |
|---|
| | 141 | #define PENTIUM_FEATURES (I486_FEATURES | CPUID_DE | CPUID_TSC | \ |
|---|
| | 142 | CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_MMX) |
|---|
| | 143 | #define PENTIUM2_FEATURES (PENTIUM_FEATURES | CPUID_PAE | CPUID_SEP | \ |
|---|
| | 144 | CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | CPUID_PAT | \ |
|---|
| | 145 | CPUID_PSE36 | CPUID_FXSR) |
|---|
| | 146 | #define PENTIUM3_FEATURES (PENTIUM2_FEATURES | CPUID_SSE) |
|---|
| | 147 | #define PPRO_FEATURES (CPUID_FP87 | CPUID_DE | CPUID_PSE | CPUID_TSC | \ |
|---|
| | 148 | CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_PGE | CPUID_CMOV | \ |
|---|
| | 149 | CPUID_PAT | CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | \ |
|---|
| | 150 | CPUID_PAE | CPUID_SEP | CPUID_APIC) |
|---|
| | 151 | static x86_def_t x86_defs[] = { |
|---|
| | 152 | #ifdef TARGET_X86_64 |
|---|
| | 153 | { |
|---|
| | 154 | .name = "qemu64", |
|---|
| | 155 | .level = 2, |
|---|
| | 156 | .vendor1 = CPUID_VENDOR_AMD_1, |
|---|
| | 157 | .vendor2 = CPUID_VENDOR_AMD_2, |
|---|
| | 158 | .vendor3 = CPUID_VENDOR_AMD_3, |
|---|
| | 159 | .family = 6, |
|---|
| | 160 | .model = 2, |
|---|
| | 161 | .stepping = 3, |
|---|
| | 162 | .features = PPRO_FEATURES | |
|---|
| | 163 | /* these features are needed for Win64 and aren't fully implemented */ |
|---|
| | 164 | CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | |
|---|
| | 165 | /* this feature is needed for Solaris and isn't fully implemented */ |
|---|
| | 166 | CPUID_PSE36, |
|---|
| | 167 | .ext_features = CPUID_EXT_SSE3, |
|---|
| | 168 | .ext2_features = (PPRO_FEATURES & 0x0183F3FF) | |
|---|
| | 169 | CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX | |
|---|
| | 170 | CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT, |
|---|
| | 171 | .ext3_features = CPUID_EXT3_SVM, |
|---|
| | 172 | .xlevel = 0x8000000A, |
|---|
| | 173 | .model_id = "QEMU Virtual CPU version " QEMU_VERSION, |
|---|
| | 174 | }, |
|---|
| | 175 | { |
|---|
| | 176 | .name = "core2duo", |
|---|
| | 177 | .level = 10, |
|---|
| | 178 | .family = 6, |
|---|
| | 179 | .model = 15, |
|---|
| | 180 | .stepping = 11, |
|---|
| | 181 | /* The original CPU also implements these features: |
|---|
| | 182 | CPUID_VME, CPUID_DTS, CPUID_ACPI, CPUID_SS, CPUID_HT, |
|---|
| | 183 | CPUID_TM, CPUID_PBE */ |
|---|
| | 184 | .features = PPRO_FEATURES | |
|---|
| | 185 | CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | |
|---|
| | 186 | CPUID_PSE36, |
|---|
| | 187 | /* The original CPU also implements these ext features: |
|---|
| | 188 | CPUID_EXT_DTES64, CPUID_EXT_DSCPL, CPUID_EXT_VMX, CPUID_EXT_EST, |
|---|
| | 189 | CPUID_EXT_TM2, CPUID_EXT_CX16, CPUID_EXT_XTPR, CPUID_EXT_PDCM */ |
|---|
| | 190 | .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_SSSE3, |
|---|
| | 191 | .ext2_features = CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX, |
|---|
| | 192 | /* Missing: .ext3_features = CPUID_EXT3_LAHF_LM */ |
|---|
| | 193 | .xlevel = 0x80000008, |
|---|
| | 194 | .model_id = "Intel(R) Core(TM)2 Duo CPU T7700 @ 2.40GHz", |
|---|
| | 195 | }, |
|---|
| | 196 | #endif |
|---|
| | 197 | { |
|---|
| | 198 | .name = "qemu32", |
|---|
| | 199 | .level = 2, |
|---|
| | 200 | .family = 6, |
|---|
| | 201 | .model = 3, |
|---|
| | 202 | .stepping = 3, |
|---|
| | 203 | .features = PPRO_FEATURES, |
|---|
| | 204 | .ext_features = CPUID_EXT_SSE3, |
|---|
| | 205 | .xlevel = 0, |
|---|
| | 206 | .model_id = "QEMU Virtual CPU version " QEMU_VERSION, |
|---|
| | 207 | }, |
|---|
| | 208 | { |
|---|
| | 209 | .name = "coreduo", |
|---|
| | 210 | .level = 10, |
|---|
| | 211 | .family = 6, |
|---|
| | 212 | .model = 14, |
|---|
| | 213 | .stepping = 8, |
|---|
| | 214 | /* The original CPU also implements these features: |
|---|
| | 215 | CPUID_DTS, CPUID_ACPI, CPUID_SS, CPUID_HT, |
|---|
| | 216 | CPUID_TM, CPUID_PBE */ |
|---|
| | 217 | .features = PPRO_FEATURES | CPUID_VME | |
|---|
| | 218 | CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA, |
|---|
| | 219 | /* The original CPU also implements these ext features: |
|---|
| | 220 | CPUID_EXT_VMX, CPUID_EXT_EST, CPUID_EXT_TM2, CPUID_EXT_XTPR, |
|---|
| | 221 | CPUID_EXT_PDCM */ |
|---|
| | 222 | .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR, |
|---|
| | 223 | .ext2_features = CPUID_EXT2_NX, |
|---|
| | 224 | .xlevel = 0x80000008, |
|---|
| | 225 | .model_id = "Genuine Intel(R) CPU T2600 @ 2.16GHz", |
|---|
| | 226 | }, |
|---|
| | 227 | { |
|---|
| | 228 | .name = "486", |
|---|
| | 229 | .level = 0, |
|---|
| | 230 | .family = 4, |
|---|
| | 231 | .model = 0, |
|---|
| | 232 | .stepping = 0, |
|---|
| | 233 | .features = I486_FEATURES, |
|---|
| | 234 | .xlevel = 0, |
|---|
| | 235 | }, |
|---|
| | 236 | { |
|---|
| | 237 | .name = "pentium", |
|---|
| | 238 | .level = 1, |
|---|
| | 239 | .family = 5, |
|---|
| | 240 | .model = 4, |
|---|
| | 241 | .stepping = 3, |
|---|
| | 242 | .features = PENTIUM_FEATURES, |
|---|
| | 243 | .xlevel = 0, |
|---|
| | 244 | }, |
|---|
| | 245 | { |
|---|
| | 246 | .name = "pentium2", |
|---|
| | 247 | .level = 2, |
|---|
| | 248 | .family = 6, |
|---|
| | 249 | .model = 5, |
|---|
| | 250 | .stepping = 2, |
|---|
| | 251 | .features = PENTIUM2_FEATURES, |
|---|
| | 252 | .xlevel = 0, |
|---|
| | 253 | }, |
|---|
| | 254 | { |
|---|
| | 255 | .name = "pentium3", |
|---|
| | 256 | .level = 2, |
|---|
| | 257 | .family = 6, |
|---|
| | 258 | .model = 7, |
|---|
| | 259 | .stepping = 3, |
|---|
| | 260 | .features = PENTIUM3_FEATURES, |
|---|
| | 261 | .xlevel = 0, |
|---|
| | 262 | }, |
|---|
| | 263 | { |
|---|
| | 264 | .name = "athlon", |
|---|
| | 265 | .level = 2, |
|---|
| | 266 | .vendor1 = 0x68747541, /* "Auth" */ |
|---|
| | 267 | .vendor2 = 0x69746e65, /* "enti" */ |
|---|
| | 268 | .vendor3 = 0x444d4163, /* "cAMD" */ |
|---|
| | 269 | .family = 6, |
|---|
| | 270 | .model = 2, |
|---|
| | 271 | .stepping = 3, |
|---|
| | 272 | .features = PPRO_FEATURES | CPUID_PSE36 | CPUID_VME | CPUID_MTRR | CPUID_MCA, |
|---|
| | 273 | .ext2_features = (PPRO_FEATURES & 0x0183F3FF) | CPUID_EXT2_MMXEXT | CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT, |
|---|
| | 274 | .xlevel = 0x80000008, |
|---|
| | 275 | /* XXX: put another string ? */ |
|---|
| | 276 | .model_id = "QEMU Virtual CPU version " QEMU_VERSION, |
|---|
| | 277 | }, |
|---|
| | 278 | { |
|---|
| | 279 | .name = "n270", |
|---|
| | 280 | /* original is on level 10 */ |
|---|
| | 281 | .level = 5, |
|---|
| | 282 | .family = 6, |
|---|
| | 283 | .model = 28, |
|---|
| | 284 | .stepping = 2, |
|---|
| | 285 | .features = PPRO_FEATURES | |
|---|
| | 286 | CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | CPUID_VME, |
|---|
| | 287 | /* Missing: CPUID_DTS | CPUID_ACPI | CPUID_SS | |
|---|
| | 288 | * CPUID_HT | CPUID_TM | CPUID_PBE */ |
|---|
| | 289 | /* Some CPUs got no CPUID_SEP */ |
|---|
| | 290 | .ext_features = CPUID_EXT_MONITOR | |
|---|
| | 291 | CPUID_EXT_SSE3 /* PNI */, |
|---|
| | 292 | /* Missing: CPUID_EXT_DSCPL | CPUID_EXT_EST | |
|---|
| | 293 | * CPUID_EXT_TM2 | CPUID_EXT_XTPR */ |
|---|
| | 294 | .ext2_features = (PPRO_FEATURES & 0x0183F3FF) | CPUID_EXT2_NX, |
|---|
| | 295 | /* Missing: .ext3_features = CPUID_EXT3_LAHF_LM */ |
|---|
| | 296 | .xlevel = 0x8000000A, |
|---|
| | 297 | .model_id = "Intel(R) Atom(TM) CPU N270 @ 1.60GHz", |
|---|
| | 298 | }, |
|---|
| 94 | | /* modulo 17 table */ |
|---|
| 95 | | const uint8_t rclw_table[32] = { |
|---|
| 96 | | 0, 1, 2, 3, 4, 5, 6, 7, |
|---|
| 97 | | 8, 9,10,11,12,13,14,15, |
|---|
| 98 | | 16, 0, 1, 2, 3, 4, 5, 6, |
|---|
| 99 | | 7, 8, 9,10,11,12,13,14, |
|---|
| | 301 | static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model) |
|---|
| | 302 | { |
|---|
| | 303 | unsigned int i; |
|---|
| | 304 | x86_def_t *def; |
|---|
| | 305 | |
|---|
| | 306 | char *s = strdup(cpu_model); |
|---|
| | 307 | char *featurestr, *name = strtok(s, ","); |
|---|
| | 308 | uint32_t plus_features = 0, plus_ext_features = 0, plus_ext2_features = 0, plus_ext3_features = 0; |
|---|
| | 309 | uint32_t minus_features = 0, minus_ext_features = 0, minus_ext2_features = 0, minus_ext3_features = 0; |
|---|
| | 310 | int family = -1, model = -1, stepping = -1; |
|---|
| | 311 | |
|---|
| | 312 | def = NULL; |
|---|
| | 313 | for (i = 0; i < sizeof(x86_defs) / sizeof(x86_def_t); i++) { |
|---|
| | 314 | if (strcmp(name, x86_defs[i].name) == 0) { |
|---|
| | 315 | def = &x86_defs[i]; |
|---|
| | 316 | break; |
|---|
| | 317 | } |
|---|
| | 318 | } |
|---|
| | 319 | if (!def) |
|---|
| | 320 | goto error; |
|---|
| | 321 | memcpy(x86_cpu_def, def, sizeof(*def)); |
|---|
| | 322 | |
|---|
| | 323 | featurestr = strtok(NULL, ","); |
|---|
| | 324 | |
|---|
| | 325 | while (featurestr) { |
|---|
| | 326 | char *val; |
|---|
| | 327 | if (featurestr[0] == '+') { |
|---|
| | 328 | add_flagname_to_bitmaps(featurestr + 1, &plus_features, &plus_ext_features, &plus_ext2_features, &plus_ext3_features); |
|---|
| | 329 | } else if (featurestr[0] == '-') { |
|---|
| | 330 | add_flagname_to_bitmaps(featurestr + 1, &minus_features, &minus_ext_features, &minus_ext2_features, &minus_ext3_features); |
|---|
| | 331 | } else if ((val = strchr(featurestr, '='))) { |
|---|
| | 332 | *val = 0; val++; |
|---|
| | 333 | if (!strcmp(featurestr, "family")) { |
|---|
| | 334 | char *err; |
|---|
| | 335 | family = strtol(val, &err, 10); |
|---|
| | 336 | if (!*val || *err || family < 0) { |
|---|
| | 337 | fprintf(stderr, "bad numerical value %s\n", val); |
|---|
| | 338 | goto error; |
|---|
| | 339 | } |
|---|
| | 340 | x86_cpu_def->family = family; |
|---|
| | 341 | } else if (!strcmp(featurestr, "model")) { |
|---|
| | 342 | char *err; |
|---|
| | 343 | model = strtol(val, &err, 10); |
|---|
| | 344 | if (!*val || *err || model < 0 || model > 0xf) { |
|---|
| | 345 | fprintf(stderr, "bad numerical value %s\n", val); |
|---|
| | 346 | goto error; |
|---|
| | 347 | } |
|---|
| | 348 | x86_cpu_def->model = model; |
|---|
| | 349 | } else if (!strcmp(featurestr, "stepping")) { |
|---|
| | 350 | char *err; |
|---|
| | 351 | stepping = strtol(val, &err, 10); |
|---|
| | 352 | if (!*val || *err || stepping < 0 || stepping > 0xf) { |
|---|
| | 353 | fprintf(stderr, "bad numerical value %s\n", val); |
|---|
| | 354 | goto error; |
|---|
| | 355 | } |
|---|
| | 356 | x86_cpu_def->stepping = stepping; |
|---|
| | 357 | } else if (!strcmp(featurestr, "vendor")) { |
|---|
| | 358 | if (strlen(val) != 12) { |
|---|
| | 359 | fprintf(stderr, "vendor string must be 12 chars long\n"); |
|---|
| | 360 | goto error; |
|---|
| | 361 | } |
|---|
| | 362 | x86_cpu_def->vendor1 = 0; |
|---|
| | 363 | x86_cpu_def->vendor2 = 0; |
|---|
| | 364 | x86_cpu_def->vendor3 = 0; |
|---|
| | 365 | for(i = 0; i < 4; i++) { |
|---|
| | 366 | x86_cpu_def->vendor1 |= ((uint8_t)val[i ]) << (8 * i); |
|---|
| | 367 | x86_cpu_def->vendor2 |= ((uint8_t)val[i + 4]) << (8 * i); |
|---|
| | 368 | x86_cpu_def->vendor3 |= ((uint8_t)val[i + 8]) << (8 * i); |
|---|
| | 369 | } |
|---|
| | 370 | } else if (!strcmp(featurestr, "model_id")) { |
|---|
| | 371 | pstrcpy(x86_cpu_def->model_id, sizeof(x86_cpu_def->model_id), |
|---|
| | 372 | val); |
|---|
| | 373 | } else { |
|---|
| | 374 | fprintf(stderr, "unrecognized feature %s\n", featurestr); |
|---|
| | 375 | goto error; |
|---|
| | 376 | } |
|---|
| | 377 | } else { |
|---|
| | 378 | fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr); |
|---|
| | 379 | goto error; |
|---|
| | 380 | } |
|---|
| | 381 | featurestr = strtok(NULL, ","); |
|---|
| | 382 | } |
|---|
| | 383 | x86_cpu_def->features |= plus_features; |
|---|
| | 384 | x86_cpu_def->ext_features |= plus_ext_features; |
|---|
| | 385 | x86_cpu_def->ext2_features |= plus_ext2_features; |
|---|
| | 386 | x86_cpu_def->ext3_features |= plus_ext3_features; |
|---|
| | 387 | x86_cpu_def->features &= ~minus_features; |
|---|
| | 388 | x86_cpu_def->ext_features &= ~minus_ext_features; |
|---|
| | 389 | x86_cpu_def->ext2_features &= ~minus_ext2_features; |
|---|
| | 390 | x86_cpu_def->ext3_features &= ~minus_ext3_features; |
|---|
| | 391 | free(s); |
|---|
| | 392 | return 0; |
|---|
| | 393 | |
|---|
| | 394 | error: |
|---|
| | 395 | free(s); |
|---|
| | 396 | return -1; |
|---|
| | 397 | } |
|---|
| | 398 | |
|---|
| | 399 | void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)) |
|---|
| | 400 | { |
|---|
| | 401 | unsigned int i; |
|---|
| | 402 | |
|---|
| | 403 | for (i = 0; i < sizeof(x86_defs) / sizeof(x86_def_t); i++) |
|---|
| | 404 | (*cpu_fprintf)(f, "x86 %16s\n", x86_defs[i].name); |
|---|
| | 405 | } |
|---|
| | 406 | |
|---|
| | 407 | static int cpu_x86_register (CPUX86State *env, const char *cpu_model) |
|---|
| | 408 | { |
|---|
| | 409 | #ifndef VBOX |
|---|
| | 410 | x86_def_t def1, *def = &def1; |
|---|
| | 411 | |
|---|
| | 412 | if (cpu_x86_find_by_name(def, cpu_model) < 0) |
|---|
| | 413 | return -1; |
|---|
| | 414 | if (def->vendor1) { |
|---|
| | 415 | env->cpuid_vendor1 = def->vendor1; |
|---|
| | 416 | env->cpuid_vendor2 = def->vendor2; |
|---|
| | 417 | env->cpuid_vendor3 = def->vendor3; |
|---|
| | 418 | } else { |
|---|
| | 419 | env->cpuid_vendor1 = CPUID_VENDOR_INTEL_1; |
|---|
| | 420 | env->cpuid_vendor2 = CPUID_VENDOR_INTEL_2; |
|---|
| | 421 | env->cpuid_vendor3 = CPUID_VENDOR_INTEL_3; |
|---|
| | 422 | } |
|---|
| | 423 | env->cpuid_level = def->level; |
|---|
| | 424 | env->cpuid_version = (def->family << 8) | (def->model << 4) | def->stepping; |
|---|
| | 425 | env->cpuid_features = def->features; |
|---|
| | 426 | env->pat = 0x0007040600070406ULL; |
|---|
| | 427 | env->cpuid_ext_features = def->ext_features; |
|---|
| | 428 | env->cpuid_ext2_features = def->ext2_features; |
|---|
| | 429 | env->cpuid_xlevel = def->xlevel; |
|---|
| | 430 | env->cpuid_ext3_features = def->ext3_features; |
|---|
| | 431 | { |
|---|
| | 432 | const char *model_id = def->model_id; |
|---|
| | 433 | int c, len, i; |
|---|
| | 434 | if (!model_id) |
|---|
| | 435 | model_id = ""; |
|---|
| | 436 | len = strlen(model_id); |
|---|
| | 437 | for(i = 0; i < 48; i++) { |
|---|
| | 438 | if (i >= len) |
|---|
| | 439 | c = '\0'; |
|---|
| | 440 | else |
|---|
| | 441 | c = (uint8_t)model_id[i]; |
|---|
| | 442 | env->cpuid_model[i >> 2] |= c << (8 * (i & 3)); |
|---|
| | 443 | } |
|---|
| | 444 | } |
|---|
| | 445 | #endif // !VBOX |
|---|
| | 446 | return 0; |
|---|
| | 447 | } |
|---|
| | 448 | |
|---|
| | 449 | /* NOTE: must be called outside the CPU execute loop */ |
|---|
| | 450 | void cpu_reset(CPUX86State *env) |
|---|
| | 451 | { |
|---|
| | 452 | int i; |
|---|
| | 453 | |
|---|
| | 454 | memset(env, 0, offsetof(CPUX86State, breakpoints)); |
|---|
| | 455 | |
|---|
| | 456 | tlb_flush(env, 1); |
|---|
| | 457 | |
|---|
| | 458 | env->old_exception = -1; |
|---|
| | 459 | |
|---|
| | 460 | /* init to reset state */ |
|---|
| | 461 | |
|---|
| | 462 | #ifdef CONFIG_SOFTMMU |
|---|
| | 463 | env->hflags |= HF_SOFTMMU_MASK; |
|---|
| | 464 | #endif |
|---|
| | 465 | env->hflags2 |= HF2_GIF_MASK; |
|---|
| | 466 | |
|---|
| | 467 | cpu_x86_update_cr0(env, 0x60000010); |
|---|
| | 468 | env->a20_mask = ~0x0; |
|---|
| | 469 | env->smbase = 0x30000; |
|---|
| | 470 | |
|---|
| | 471 | env->idt.limit = 0xffff; |
|---|
| | 472 | env->gdt.limit = 0xffff; |
|---|
| | 473 | env->ldt.limit = 0xffff; |
|---|
| | 474 | env->ldt.flags = DESC_P_MASK | (2 << DESC_TYPE_SHIFT); |
|---|
| | 475 | env->tr.limit = 0xffff; |
|---|
| | 476 | env->tr.flags = DESC_P_MASK | (11 << DESC_TYPE_SHIFT); |
|---|
| | 477 | |
|---|
| | 478 | cpu_x86_load_seg_cache(env, R_CS, 0xf000, 0xffff0000, 0xffff, |
|---|
| | 479 | DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK | DESC_R_MASK); |
|---|
| | 480 | cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffff, |
|---|
| | 481 | DESC_P_MASK | DESC_S_MASK | DESC_W_MASK); |
|---|
| | 482 | cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffff, |
|---|
| | 483 | DESC_P_MASK | DESC_S_MASK | DESC_W_MASK); |
|---|
| | 484 | cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffff, |
|---|
| | 485 | DESC_P_MASK | DESC_S_MASK | DESC_W_MASK); |
|---|
| | 486 | cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffff, |
|---|
| | 487 | DESC_P_MASK | DESC_S_MASK | DESC_W_MASK); |
|---|
| | 488 | cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffff, |
|---|
| | 489 | DESC_P_MASK | DESC_S_MASK | DESC_W_MASK); |
|---|
| | 490 | |
|---|
| | 491 | env->eip = 0xfff0; |
|---|
| | 492 | #ifndef VBOX |
|---|
| | 493 | env->regs[R_EDX] = env->cpuid_version; |
|---|
| | 494 | #else |
|---|
| | 495 | /** @todo: is it right? */ |
|---|
| | 496 | env->regs[R_EDX] = 0x600; /* indicate P6 processor */ |
|---|
| | 497 | #endif |
|---|
| | 498 | |
|---|
| | 499 | env->eflags = 0x2; |
|---|
| | 500 | |
|---|
| | 501 | /* FPU init */ |
|---|
| | 502 | for(i = 0;i < 8; i++) |
|---|
| | 503 | env->fptags[i] = 1; |
|---|
| | 504 | env->fpuc = 0x37f; |
|---|
| | 505 | |
|---|
| | 506 | env->mxcsr = 0x1f80; |
|---|
| | 507 | } |
|---|
| | 508 | |
|---|
| | 509 | #ifndef VBOX |
|---|
| | 510 | void cpu_x86_close(CPUX86State *env) |
|---|
| | 511 | { |
|---|
| | 512 | qemu_free(env); |
|---|
| | 513 | } |
|---|
| | 514 | #endif |
|---|
| | 515 | |
|---|
| | 516 | /***********************************************************/ |
|---|
| | 517 | /* x86 debug */ |
|---|
| | 518 | |
|---|
| | 519 | static const char *cc_op_str[] = { |
|---|
| | 520 | "DYNAMIC", |
|---|
| | 521 | "EFLAGS", |
|---|
| | 522 | |
|---|
| | 523 | "MULB", |
|---|
| | 524 | "MULW", |
|---|
| | 525 | "MULL", |
|---|
| | 526 | "MULQ", |
|---|
| | 527 | |
|---|
| | 528 | "ADDB", |
|---|
| | 529 | "ADDW", |
|---|
| | 530 | "ADDL", |
|---|
| | 531 | "ADDQ", |
|---|
| | 532 | |
|---|
| | 533 | "ADCB", |
|---|
| | 534 | "ADCW", |
|---|
| | 535 | "ADCL", |
|---|
| | 536 | "ADCQ", |
|---|
| | 537 | |
|---|
| | 538 | "SUBB", |
|---|
| | 539 | "SUBW", |
|---|
| | 540 | "SUBL", |
|---|
| | 541 | "SUBQ", |
|---|
| | 542 | |
|---|
| | 543 | "SBBB", |
|---|
| | 544 | "SBBW", |
|---|
| | 545 | "SBBL", |
|---|
| | 546 | "SBBQ", |
|---|
| | 547 | |
|---|
| | 548 | "LOGICB", |
|---|
| | 549 | "LOGICW", |
|---|
| | 550 | "LOGICL", |
|---|
| | 551 | "LOGICQ", |
|---|
| | 552 | |
|---|
| | 553 | "INCB", |
|---|
| | 554 | "INCW", |
|---|
| | 555 | "INCL", |
|---|
| | 556 | "INCQ", |
|---|
| | 557 | |
|---|
| | 558 | "DECB", |
|---|
| | 559 | "DECW", |
|---|
| | 560 | "DECL", |
|---|
| | 561 | "DECQ", |
|---|
| | 562 | |
|---|
| | 563 | "SHLB", |
|---|
| | 564 | "SHLW", |
|---|
| | 565 | "SHLL", |
|---|
| | 566 | "SHLQ", |
|---|
| | 567 | |
|---|
| | 568 | "SARB", |
|---|
| | 569 | "SARW", |
|---|
| | 570 | "SARL", |
|---|
| | 571 | "SARQ", |
|---|
| 102 | | /* modulo 9 table */ |
|---|
| 103 | | const uint8_t rclb_table[32] = { |
|---|
| 104 | | 0, 1, 2, 3, 4, 5, 6, 7, |
|---|
| 105 | | 8, 0, 1, 2, 3, 4, 5, 6, |
|---|
| 106 | | 7, 8, 0, 1, 2, 3, 4, 5, |
|---|
| 107 | | 6, 7, 8, 0, 1, 2, 3, 4, |
|---|
| 108 | | }; |
|---|
| 109 | | |
|---|
| 110 | | const CPU86_LDouble f15rk[7] = |
|---|
| 111 | | { |
|---|
| 112 | | 0.00000000000000000000L, |
|---|
| 113 | | 1.00000000000000000000L, |
|---|
| 114 | | 3.14159265358979323851L, /*pi*/ |
|---|
| 115 | | 0.30102999566398119523L, /*lg2*/ |
|---|
| 116 | | 0.69314718055994530943L, /*ln2*/ |
|---|
| 117 | | 1.44269504088896340739L, /*l2e*/ |
|---|
| 118 | | 3.32192809488736234781L, /*l2t*/ |
|---|
| 119 | | }; |
|---|
| 120 | | |
|---|
| 121 | | /* thread support */ |
|---|
| 122 | | |
|---|
| 123 | | spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; |
|---|
| 124 | | |
|---|
| 125 | | void cpu_lock(void) |
|---|
| 126 | | { |
|---|
| 127 | | spin_lock(&global_cpu_lock); |
|---|
| 128 | | } |
|---|
| 129 | | |
|---|
| 130 | | void cpu_unlock(void) |
|---|
| 131 | | { |
|---|
| 132 | | spin_unlock(&global_cpu_lock); |
|---|
| 133 | | } |
|---|
| 134 | | |
|---|
| 135 | | void cpu_loop_exit(void) |
|---|
| 136 | | { |
|---|
| 137 | | /* NOTE: the register at this point must be saved by hand because |
|---|
| 138 | | longjmp restore them */ |
|---|
| 139 | | regs_to_env(); |
|---|
| 140 | | longjmp(env->jmp_env, 1); |
|---|
| 141 | | } |
|---|
| 142 | | |
|---|
| 143 | | /* return non zero if error */ |
|---|
| 144 | | static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr, |
|---|
| 145 | | int selector) |
|---|
| 146 | | { |
|---|
| 147 | | SegmentCache *dt; |
|---|
| 148 | | int index; |
|---|
| 149 | | target_ulong ptr; |
|---|
| 150 | | |
|---|
| 151 | | if (selector & 0x4) |
|---|
| 152 | | dt = &env->ldt; |
|---|
| 153 | | else |
|---|
| 154 | | dt = &env->gdt; |
|---|
| 155 | | index = selector & ~7; |
|---|
| 156 | | if ((index + 7) > dt->limit) |
|---|
| 157 | | return -1; |
|---|
| 158 | | ptr = dt->base + index; |
|---|
| 159 | | *e1_ptr = ldl_kernel(ptr); |
|---|
| 160 | | *e2_ptr = ldl_kernel(ptr + 4); |
|---|
| 161 | | return 0; |
|---|
| 162 | | } |
|---|
| 163 | | |
|---|
| 164 | | static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2) |
|---|
| 165 | | { |
|---|
| 166 | | unsigned int limit; |
|---|
| 167 | | limit = (e1 & 0xffff) | (e2 & 0x000f0000); |
|---|
| 168 | | if (e2 & DESC_G_MASK) |
|---|
| 169 | | limit = (limit << 12) | 0xfff; |
|---|
| 170 | | return limit; |
|---|
| 171 | | } |
|---|
| 172 | | |
|---|
| 173 | | static inline uint32_t get_seg_base(uint32_t e1, uint32_t e2) |
|---|
| 174 | | { |
|---|
| 175 | | return ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); |
|---|
| 176 | | } |
|---|
| 177 | | |
|---|
| 178 | | static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2) |
|---|
| 179 | | { |
|---|
| 180 | | sc->base = get_seg_base(e1, e2); |
|---|
| 181 | | sc->limit = get_seg_limit(e1, e2); |
|---|
| 182 | | sc->flags = e2; |
|---|
| 183 | | } |
|---|
| 184 | | |
|---|
| 185 | | /* init the segment cache in vm86 mode. */ |
|---|
| 186 | | static inline void load_seg_vm(int seg, int selector) |
|---|
| 187 | | { |
|---|
| 188 | | selector &= 0xffff; |
|---|
| 189 | | cpu_x86_load_seg_cache(env, seg, selector, |
|---|
| 190 | | (selector << 4), 0xffff, 0); |
|---|
| 191 | | } |
|---|
| 192 | | |
|---|
| 193 | | static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, |
|---|
| 194 | | uint32_t *esp_ptr, int dpl) |
|---|
| 195 | | { |
|---|
| 196 | | int type, index, shift; |
|---|
| 197 | | |
|---|
| 198 | | #if 0 |
|---|
| | 574 | void cpu_dump_state(CPUState *env, FILE *f, |
|---|
| | 575 | int (*cpu_fprintf)(FILE *f, const char *fmt, ...), |
|---|
| | 576 | int flags) |
|---|
| | 577 | { |
|---|
| | 578 | int eflags, i, nb; |
|---|
| | 579 | char cc_op_name[32]; |
|---|
| | 580 | static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" }; |
|---|
| | 581 | |
|---|
| | 582 | eflags = env->eflags; |
|---|
| | 583 | #ifdef TARGET_X86_64 |
|---|
| | 584 | if (env->hflags & HF_CS64_MASK) { |
|---|
| | 585 | cpu_fprintf(f, |
|---|
| | 586 | "RAX=%016" PRIx64 " RBX=%016" PRIx64 " RCX=%016" PRIx64 " RDX=%016" PRIx64 "\n" |
|---|
| | 587 | "RSI=%016" PRIx64 " RDI=%016" PRIx64 " RBP=%016" PRIx64 " RSP=%016" PRIx64 "\n" |
|---|
| | 588 | "R8 =%016" PRIx64 " R9 =%016" PRIx64 " R10=%016" PRIx64 " R11=%016" PRIx64 "\n" |
|---|
| | 589 | "R12=%016" PRIx64 " R13=%016" PRIx64 " R14=%016" PRIx64 " R15=%016" PRIx64 "\n" |
|---|
| | 590 | "RIP=%016" PRIx64 " RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n", |
|---|
| | 591 | env->regs[R_EAX], |
|---|
| | 592 | env->regs[R_EBX], |
|---|
| | 593 | env->regs[R_ECX], |
|---|
| | 594 | env->regs[R_EDX], |
|---|
| | 595 | env->regs[R_ESI], |
|---|
| | 596 | env->regs[R_EDI], |
|---|
| | 597 | env->regs[R_EBP], |
|---|
| | 598 | env->regs[R_ESP], |
|---|
| | 599 | env->regs[8], |
|---|
| | 600 | env->regs[9], |
|---|
| | 601 | env->regs[10], |
|---|
| | 602 | env->regs[11], |
|---|
| | 603 | env->regs[12], |
|---|
| | 604 | env->regs[13], |
|---|
| | 605 | env->regs[14], |
|---|
| | 606 | env->regs[15], |
|---|
| | 607 | env->eip, eflags, |
|---|
| | 608 | eflags & DF_MASK ? 'D' : '-', |
|---|
| | 609 | eflags & CC_O ? 'O' : '-', |
|---|
| | 610 | eflags & CC_S ? 'S' : '-', |
|---|
| | 611 | eflags & CC_Z ? 'Z' : '-', |
|---|
| | 612 | eflags & CC_A ? 'A' : '-', |
|---|
| | 613 | eflags & CC_P ? 'P' : '-', |
|---|
| | 614 | eflags & CC_C ? 'C' : '-', |
|---|
| | 615 | env->hflags & HF_CPL_MASK, |
|---|
| | 616 | (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1, |
|---|
| | 617 | (int)(env->a20_mask >> 20) & 1, |
|---|
| | 618 | (env->hflags >> HF_SMM_SHIFT) & 1, |
|---|
| | 619 | env->halted); |
|---|
| | 620 | } else |
|---|
| | 621 | #endif |
|---|