1 /* 2 * qemu user cpu loop 3 * 4 * Copyright (c) 2003-2008 Fabrice Bellard 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "qemu/osdep.h" 21 #include "qemu.h" 22 #include "cpu_loop-common.h" 23 24 /***********************************************************/ 25 /* CPUX86 core interface */ 26 27 uint64_t cpu_get_tsc(CPUX86State *env) 28 { 29 return cpu_get_host_ticks(); 30 } 31 32 static void write_dt(void *ptr, unsigned long addr, unsigned long limit, 33 int flags) 34 { 35 unsigned int e1, e2; 36 uint32_t *p; 37 e1 = (addr << 16) | (limit & 0xffff); 38 e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000); 39 e2 |= flags; 40 p = ptr; 41 p[0] = tswap32(e1); 42 p[1] = tswap32(e2); 43 } 44 45 static uint64_t *idt_table; 46 #ifdef TARGET_X86_64 47 static void set_gate64(void *ptr, unsigned int type, unsigned int dpl, 48 uint64_t addr, unsigned int sel) 49 { 50 uint32_t *p, e1, e2; 51 e1 = (addr & 0xffff) | (sel << 16); 52 e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8); 53 p = ptr; 54 p[0] = tswap32(e1); 55 p[1] = tswap32(e2); 56 p[2] = tswap32(addr >> 32); 57 p[3] = 0; 58 } 59 /* only dpl matters as we do only user space emulation */ 60 static void set_idt(int n, unsigned int dpl) 61 { 62 set_gate64(idt_table + n * 2, 0, dpl, 0, 0); 63 } 64 #else 65 static void set_gate(void *ptr, unsigned int type, unsigned int dpl, 66 uint32_t addr, unsigned int sel) 67 { 68 uint32_t *p, e1, e2; 69 e1 = (addr & 0xffff) | (sel << 16); 70 e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8); 71 p = ptr; 72 p[0] = tswap32(e1); 73 p[1] = tswap32(e2); 74 } 75 76 /* only dpl matters as we do only user space emulation */ 77 static void set_idt(int n, unsigned int dpl) 78 { 79 set_gate(idt_table + n, 0, dpl, 0, 0); 80 } 81 #endif 82 83 void cpu_loop(CPUX86State *env) 84 { 85 CPUState *cs = CPU(x86_env_get_cpu(env)); 86 int trapnr; 87 abi_ulong pc; 88 abi_ulong ret; 89 target_siginfo_t info; 90 91 for(;;) { 92 cpu_exec_start(cs); 93 trapnr = cpu_exec(cs); 94 cpu_exec_end(cs); 95 process_queued_cpu_work(cs); 96 97 switch(trapnr) { 98 case 0x80: 99 /* linux syscall from int $0x80 */ 100 ret = do_syscall(env, 101 env->regs[R_EAX], 102 env->regs[R_EBX], 103 env->regs[R_ECX], 104 env->regs[R_EDX], 105 env->regs[R_ESI], 106 env->regs[R_EDI], 107 env->regs[R_EBP], 108 0, 0); 109 if (ret == -TARGET_ERESTARTSYS) { 110 env->eip -= 2; 111 } else if (ret != -TARGET_QEMU_ESIGRETURN) { 112 env->regs[R_EAX] = ret; 113 } 114 break; 115 #ifndef TARGET_ABI32 116 case EXCP_SYSCALL: 117 /* linux syscall from syscall instruction */ 118 ret = do_syscall(env, 119 env->regs[R_EAX], 120 env->regs[R_EDI], 121 env->regs[R_ESI], 122 env->regs[R_EDX], 123 env->regs[10], 124 env->regs[8], 125 env->regs[9], 126 0, 0); 127 if (ret == -TARGET_ERESTARTSYS) { 128 env->eip -= 2; 129 } else if (ret != -TARGET_QEMU_ESIGRETURN) { 130 env->regs[R_EAX] = ret; 131 } 132 break; 133 #endif 134 case EXCP0B_NOSEG: 135 case EXCP0C_STACK: 136 info.si_signo = TARGET_SIGBUS; 137 info.si_errno = 0; 138 info.si_code = TARGET_SI_KERNEL; 139 info._sifields._sigfault._addr = 0; 140 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); 141 break; 142 case EXCP0D_GPF: 143 /* XXX: potential problem if ABI32 */ 144 #ifndef TARGET_X86_64 145 if (env->eflags & VM_MASK) { 146 handle_vm86_fault(env); 147 } else 148 #endif 149 { 150 info.si_signo = TARGET_SIGSEGV; 151 info.si_errno = 0; 152 info.si_code = TARGET_SI_KERNEL; 153 info._sifields._sigfault._addr = 0; 154 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); 155 } 156 break; 157 case EXCP0E_PAGE: 158 info.si_signo = TARGET_SIGSEGV; 159 info.si_errno = 0; 160 if (!(env->error_code & 1)) 161 info.si_code = TARGET_SEGV_MAPERR; 162 else 163 info.si_code = TARGET_SEGV_ACCERR; 164 info._sifields._sigfault._addr = env->cr[2]; 165 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); 166 break; 167 case EXCP00_DIVZ: 168 #ifndef TARGET_X86_64 169 if (env->eflags & VM_MASK) { 170 handle_vm86_trap(env, trapnr); 171 } else 172 #endif 173 { 174 /* division by zero */ 175 info.si_signo = TARGET_SIGFPE; 176 info.si_errno = 0; 177 info.si_code = TARGET_FPE_INTDIV; 178 info._sifields._sigfault._addr = env->eip; 179 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); 180 } 181 break; 182 case EXCP01_DB: 183 case EXCP03_INT3: 184 #ifndef TARGET_X86_64 185 if (env->eflags & VM_MASK) { 186 handle_vm86_trap(env, trapnr); 187 } else 188 #endif 189 { 190 info.si_signo = TARGET_SIGTRAP; 191 info.si_errno = 0; 192 if (trapnr == EXCP01_DB) { 193 info.si_code = TARGET_TRAP_BRKPT; 194 info._sifields._sigfault._addr = env->eip; 195 } else { 196 info.si_code = TARGET_SI_KERNEL; 197 info._sifields._sigfault._addr = 0; 198 } 199 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); 200 } 201 break; 202 case EXCP04_INTO: 203 case EXCP05_BOUND: 204 #ifndef TARGET_X86_64 205 if (env->eflags & VM_MASK) { 206 handle_vm86_trap(env, trapnr); 207 } else 208 #endif 209 { 210 info.si_signo = TARGET_SIGSEGV; 211 info.si_errno = 0; 212 info.si_code = TARGET_SI_KERNEL; 213 info._sifields._sigfault._addr = 0; 214 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); 215 } 216 break; 217 case EXCP06_ILLOP: 218 info.si_signo = TARGET_SIGILL; 219 info.si_errno = 0; 220 info.si_code = TARGET_ILL_ILLOPN; 221 info._sifields._sigfault._addr = env->eip; 222 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); 223 break; 224 case EXCP_INTERRUPT: 225 /* just indicate that signals should be handled asap */ 226 break; 227 case EXCP_DEBUG: 228 { 229 int sig; 230 231 sig = gdb_handlesig(cs, TARGET_SIGTRAP); 232 if (sig) 233 { 234 info.si_signo = sig; 235 info.si_errno = 0; 236 info.si_code = TARGET_TRAP_BRKPT; 237 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); 238 } 239 } 240 break; 241 case EXCP_ATOMIC: 242 cpu_exec_step_atomic(cs); 243 break; 244 default: 245 pc = env->segs[R_CS].base + env->eip; 246 EXCP_DUMP(env, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", 247 (long)pc, trapnr); 248 abort(); 249 } 250 process_pending_signals(env); 251 } 252 } 253 254 void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs) 255 { 256 env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK; 257 env->hflags |= HF_PE_MASK | HF_CPL_MASK; 258 if (env->features[FEAT_1_EDX] & CPUID_SSE) { 259 env->cr[4] |= CR4_OSFXSR_MASK; 260 env->hflags |= HF_OSFXSR_MASK; 261 } 262 #ifndef TARGET_ABI32 263 /* enable 64 bit mode if possible */ 264 if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) { 265 fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n"); 266 exit(EXIT_FAILURE); 267 } 268 env->cr[4] |= CR4_PAE_MASK; 269 env->efer |= MSR_EFER_LMA | MSR_EFER_LME; 270 env->hflags |= HF_LMA_MASK; 271 #endif 272 273 /* flags setup : we activate the IRQs by default as in user mode */ 274 env->eflags |= IF_MASK; 275 276 /* linux register setup */ 277 #ifndef TARGET_ABI32 278 env->regs[R_EAX] = regs->rax; 279 env->regs[R_EBX] = regs->rbx; 280 env->regs[R_ECX] = regs->rcx; 281 env->regs[R_EDX] = regs->rdx; 282 env->regs[R_ESI] = regs->rsi; 283 env->regs[R_EDI] = regs->rdi; 284 env->regs[R_EBP] = regs->rbp; 285 env->regs[R_ESP] = regs->rsp; 286 env->eip = regs->rip; 287 #else 288 env->regs[R_EAX] = regs->eax; 289 env->regs[R_EBX] = regs->ebx; 290 env->regs[R_ECX] = regs->ecx; 291 env->regs[R_EDX] = regs->edx; 292 env->regs[R_ESI] = regs->esi; 293 env->regs[R_EDI] = regs->edi; 294 env->regs[R_EBP] = regs->ebp; 295 env->regs[R_ESP] = regs->esp; 296 env->eip = regs->eip; 297 #endif 298 299 /* linux interrupt setup */ 300 #ifndef TARGET_ABI32 301 env->idt.limit = 511; 302 #else 303 env->idt.limit = 255; 304 #endif 305 env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1), 306 PROT_READ|PROT_WRITE, 307 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); 308 idt_table = g2h(env->idt.base); 309 set_idt(0, 0); 310 set_idt(1, 0); 311 set_idt(2, 0); 312 set_idt(3, 3); 313 set_idt(4, 3); 314 set_idt(5, 0); 315 set_idt(6, 0); 316 set_idt(7, 0); 317 set_idt(8, 0); 318 set_idt(9, 0); 319 set_idt(10, 0); 320 set_idt(11, 0); 321 set_idt(12, 0); 322 set_idt(13, 0); 323 set_idt(14, 0); 324 set_idt(15, 0); 325 set_idt(16, 0); 326 set_idt(17, 0); 327 set_idt(18, 0); 328 set_idt(19, 0); 329 set_idt(0x80, 3); 330 331 /* linux segment setup */ 332 { 333 uint64_t *gdt_table; 334 env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES, 335 PROT_READ|PROT_WRITE, 336 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); 337 env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1; 338 gdt_table = g2h(env->gdt.base); 339 #ifdef TARGET_ABI32 340 write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, 341 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | 342 (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); 343 #else 344 /* 64 bit code segment */ 345 write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff, 346 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | 347 DESC_L_MASK | 348 (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT)); 349 #endif 350 write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff, 351 DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | 352 (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT)); 353 } 354 cpu_x86_load_seg(env, R_CS, __USER_CS); 355 cpu_x86_load_seg(env, R_SS, __USER_DS); 356 #ifdef TARGET_ABI32 357 cpu_x86_load_seg(env, R_DS, __USER_DS); 358 cpu_x86_load_seg(env, R_ES, __USER_DS); 359 cpu_x86_load_seg(env, R_FS, __USER_DS); 360 cpu_x86_load_seg(env, R_GS, __USER_DS); 361 /* This hack makes Wine work... */ 362 env->segs[R_FS].selector = 0; 363 #else 364 cpu_x86_load_seg(env, R_DS, 0); 365 cpu_x86_load_seg(env, R_ES, 0); 366 cpu_x86_load_seg(env, R_FS, 0); 367 cpu_x86_load_seg(env, R_GS, 0); 368 #endif 369 } 370