VirtualBox

source: vbox/trunk/src/recompiler/cpu-exec.c@ 39955

最後變更 在這個檔案從39955是 37702,由 vboxsync 提交於 13 年 前

REM/VMM: Don't flush the TLB if you don't hold the EM/REM lock, some other EMT may be executing code in the recompiler and could be really surprised by a TLB flush.

  • 屬性 svn:eol-style 設為 native
檔案大小: 52.5 KB
 
1/*
2 * i386 emulator main execution loop
3 *
4 * Copyright (c) 2003-2005 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library 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 GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20/*
21 * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
22 * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
23 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
24 * a choice of LGPL license versions is made available with the language indicating
25 * that LGPLv2 or any later version may be used, or where a choice of which version
26 * of the LGPL is applied is otherwise unspecified.
27 */
28
29#include "config.h"
30#include "exec.h"
31#include "disas.h"
32#include "tcg.h"
33#include "kvm.h"
34#include "qemu-barrier.h"
35
36#if !defined(CONFIG_SOFTMMU)
37#undef EAX
38#undef ECX
39#undef EDX
40#undef EBX
41#undef ESP
42#undef EBP
43#undef ESI
44#undef EDI
45#undef EIP
46#include <signal.h>
47#ifdef __linux__
48#include <sys/ucontext.h>
49#endif
50#endif
51
52#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
53// Work around ugly bugs in glibc that mangle global register contents
54#undef env
55#define env cpu_single_env
56#endif
57
58int tb_invalidated_flag;
59
60//#define CONFIG_DEBUG_EXEC
61//#define DEBUG_SIGNAL
62
63int qemu_cpu_has_work(CPUState *env)
64{
65 return cpu_has_work(env);
66}
67
68void cpu_loop_exit(void)
69{
70 env->current_tb = NULL;
71 longjmp(env->jmp_env, 1);
72}
73
74/* exit the current TB from a signal handler. The host registers are
75 restored in a state compatible with the CPU emulator
76 */
77void cpu_resume_from_signal(CPUState *env1, void *puc)
78{
79#if !defined(CONFIG_SOFTMMU)
80#ifdef __linux__
81 struct ucontext *uc = puc;
82#elif defined(__OpenBSD__)
83 struct sigcontext *uc = puc;
84#endif
85#endif
86
87 env = env1;
88
89 /* XXX: restore cpu registers saved in host registers */
90
91#if !defined(CONFIG_SOFTMMU)
92 if (puc) {
93 /* XXX: use siglongjmp ? */
94#ifdef __linux__
95#ifdef __ia64
96 sigprocmask(SIG_SETMASK, (sigset_t *)&uc->uc_sigmask, NULL);
97#else
98 sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
99#endif
100#elif defined(__OpenBSD__)
101 sigprocmask(SIG_SETMASK, &uc->sc_mask, NULL);
102#endif
103 }
104#endif
105 env->exception_index = -1;
106 longjmp(env->jmp_env, 1);
107}
108
109/* Execute the code without caching the generated code. An interpreter
110 could be used if available. */
111static void cpu_exec_nocache(int max_cycles, TranslationBlock *orig_tb)
112{
113 unsigned long next_tb;
114 TranslationBlock *tb;
115
116 /* Should never happen.
117 We only end up here when an existing TB is too long. */
118 if (max_cycles > CF_COUNT_MASK)
119 max_cycles = CF_COUNT_MASK;
120
121 tb = tb_gen_code(env, orig_tb->pc, orig_tb->cs_base, orig_tb->flags,
122 max_cycles);
123 env->current_tb = tb;
124 /* execute the generated code */
125#if defined(VBOX) && defined(GCC_WITH_BUGGY_REGPARM)
126 tcg_qemu_tb_exec(tb->tc_ptr, next_tb);
127#else
128 next_tb = tcg_qemu_tb_exec(tb->tc_ptr);
129#endif
130 env->current_tb = NULL;
131
132 if ((next_tb & 3) == 2) {
133 /* Restore PC. This may happen if async event occurs before
134 the TB starts executing. */
135 cpu_pc_from_tb(env, tb);
136 }
137 tb_phys_invalidate(tb, -1);
138 tb_free(tb);
139}
140
141static TranslationBlock *tb_find_slow(target_ulong pc,
142 target_ulong cs_base,
143 uint64_t flags)
144{
145 TranslationBlock *tb, **ptb1;
146 unsigned int h;
147 tb_page_addr_t phys_pc, phys_page1, phys_page2;
148 target_ulong virt_page2;
149
150 tb_invalidated_flag = 0;
151
152 /* find translated block using physical mappings */
153 phys_pc = get_page_addr_code(env, pc);
154 phys_page1 = phys_pc & TARGET_PAGE_MASK;
155 phys_page2 = -1;
156 h = tb_phys_hash_func(phys_pc);
157 ptb1 = &tb_phys_hash[h];
158 for(;;) {
159 tb = *ptb1;
160 if (!tb)
161 goto not_found;
162 if (tb->pc == pc &&
163 tb->page_addr[0] == phys_page1 &&
164 tb->cs_base == cs_base &&
165 tb->flags == flags) {
166 /* check next page if needed */
167 if (tb->page_addr[1] != -1) {
168 virt_page2 = (pc & TARGET_PAGE_MASK) +
169 TARGET_PAGE_SIZE;
170 phys_page2 = get_page_addr_code(env, virt_page2);
171 if (tb->page_addr[1] == phys_page2)
172 goto found;
173 } else {
174 goto found;
175 }
176 }
177 ptb1 = &tb->phys_hash_next;
178 }
179 not_found:
180 /* if no translated code available, then translate it now */
181 tb = tb_gen_code(env, pc, cs_base, flags, 0);
182
183 found:
184 /* we add the TB in the virtual pc hash table */
185 env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
186 return tb;
187}
188
189static inline TranslationBlock *tb_find_fast(void)
190{
191 TranslationBlock *tb;
192 target_ulong cs_base, pc;
193 int flags;
194
195 /* we record a subset of the CPU state. It will
196 always be the same before a given translated block
197 is executed. */
198 cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
199 tb = env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)];
200 if (unlikely(!tb || tb->pc != pc || tb->cs_base != cs_base ||
201 tb->flags != flags)) {
202 tb = tb_find_slow(pc, cs_base, flags);
203 }
204 return tb;
205}
206
207static CPUDebugExcpHandler *debug_excp_handler;
208
209CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler)
210{
211 CPUDebugExcpHandler *old_handler = debug_excp_handler;
212
213 debug_excp_handler = handler;
214 return old_handler;
215}
216
217static void cpu_handle_debug_exception(CPUState *env)
218{
219 CPUWatchpoint *wp;
220
221 if (!env->watchpoint_hit)
222 QTAILQ_FOREACH(wp, &env->watchpoints, entry)
223 wp->flags &= ~BP_WATCHPOINT_HIT;
224
225 if (debug_excp_handler)
226 debug_excp_handler(env);
227}
228
229/* main execution loop */
230
231volatile sig_atomic_t exit_request;
232
233int cpu_exec(CPUState *env1)
234{
235 volatile host_reg_t saved_env_reg;
236 int ret VBOX_ONLY(= 0), interrupt_request;
237 TranslationBlock *tb;
238 uint8_t *tc_ptr;
239#ifndef VBOX
240 uintptr_t next_tb;
241#else /* VBOX */
242 unsigned long next_tb;
243#endif /* VBOX */
244
245# ifndef VBOX
246 if (cpu_halted(env1) == EXCP_HALTED)
247 return EXCP_HALTED;
248# endif /* !VBOX */
249
250 cpu_single_env = env1;
251
252 /* the access to env below is actually saving the global register's
253 value, so that files not including target-xyz/exec.h are free to
254 use it. */
255 QEMU_BUILD_BUG_ON (sizeof (saved_env_reg) != sizeof (env));
256 saved_env_reg = (host_reg_t) env;
257 barrier();
258 env = env1;
259
260 if (unlikely(exit_request)) {
261 env->exit_request = 1;
262 }
263
264#if defined(TARGET_I386)
265 if (!kvm_enabled()) {
266 /* put eflags in CPU temporary format */
267 CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
268 DF = 1 - (2 * ((env->eflags >> 10) & 1));
269 CC_OP = CC_OP_EFLAGS;
270 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
271 }
272#elif defined(TARGET_SPARC)
273#elif defined(TARGET_M68K)
274 env->cc_op = CC_OP_FLAGS;
275 env->cc_dest = env->sr & 0xf;
276 env->cc_x = (env->sr >> 4) & 1;
277#elif defined(TARGET_ALPHA)
278#elif defined(TARGET_ARM)
279#elif defined(TARGET_PPC)
280#elif defined(TARGET_MICROBLAZE)
281#elif defined(TARGET_MIPS)
282#elif defined(TARGET_SH4)
283#elif defined(TARGET_CRIS)
284#elif defined(TARGET_S390X)
285 /* XXXXX */
286#else
287#error unsupported target CPU
288#endif
289#ifndef VBOX /* VBOX: We need to raise traps and suchlike from the outside. */
290 env->exception_index = -1;
291#endif /* !VBOX */
292
293 /* prepare setjmp context for exception handling */
294 for(;;) {
295 if (setjmp(env->jmp_env) == 0) {
296#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
297#undef env
298 env = cpu_single_env;
299#define env cpu_single_env
300#endif
301#ifdef VBOX
302 env->current_tb = NULL; /* probably not needed, but whatever... */
303
304 /*
305 * Check for fatal errors first
306 */
307 if (env->interrupt_request & CPU_INTERRUPT_RC) {
308 env->exception_index = EXCP_RC;
309 ASMAtomicAndS32((int32_t volatile *)&env->interrupt_request, ~CPU_INTERRUPT_RC);
310 ret = env->exception_index;
311 cpu_loop_exit();
312 }
313#endif
314
315 /* if an exception is pending, we execute it here */
316 if (env->exception_index >= 0) {
317 if (env->exception_index >= EXCP_INTERRUPT) {
318 /* exit request from the cpu execution loop */
319 ret = env->exception_index;
320#ifdef VBOX /* because of the above stuff */
321 env->exception_index = -1;
322#endif
323 if (ret == EXCP_DEBUG)
324 cpu_handle_debug_exception(env);
325 break;
326 } else {
327#if defined(CONFIG_USER_ONLY)
328 /* if user mode only, we simulate a fake exception
329 which will be handled outside the cpu execution
330 loop */
331#if defined(TARGET_I386)
332 do_interrupt_user(env->exception_index,
333 env->exception_is_int,
334 env->error_code,
335 env->exception_next_eip);
336 /* successfully delivered */
337 env->old_exception = -1;
338#endif
339 ret = env->exception_index;
340 break;
341#else
342#if defined(TARGET_I386)
343 /* simulate a real cpu exception. On i386, it can
344 trigger new exceptions, but we do not handle
345 double or triple faults yet. */
346# ifdef VBOX
347 RAWEx_ProfileStart(env, STATS_IRQ_HANDLING);
348 Log(("do_interrupt: vec=%#x int=%d pc=%04x:%RGv\n", env->exception_index, env->exception_is_int,
349 env->segs[R_CS].selector, (RTGCPTR)env->exception_next_eip));
350# endif /* VBOX */
351 do_interrupt(env->exception_index,
352 env->exception_is_int,
353 env->error_code,
354 env->exception_next_eip, 0);
355 /* successfully delivered */
356 env->old_exception = -1;
357# ifdef VBOX
358 RAWEx_ProfileStop(env, STATS_IRQ_HANDLING);
359# endif /* VBOX */
360#elif defined(TARGET_PPC)
361 do_interrupt(env);
362#elif defined(TARGET_MICROBLAZE)
363 do_interrupt(env);
364#elif defined(TARGET_MIPS)
365 do_interrupt(env);
366#elif defined(TARGET_SPARC)
367 do_interrupt(env);
368#elif defined(TARGET_ARM)
369 do_interrupt(env);
370#elif defined(TARGET_SH4)
371 do_interrupt(env);
372#elif defined(TARGET_ALPHA)
373 do_interrupt(env);
374#elif defined(TARGET_CRIS)
375 do_interrupt(env);
376#elif defined(TARGET_M68K)
377 do_interrupt(0);
378#endif
379 env->exception_index = -1;
380#endif
381 }
382 }
383
384# ifndef VBOX
385 if (kvm_enabled()) {
386 kvm_cpu_exec(env);
387 longjmp(env->jmp_env, 1);
388 }
389# endif /* !VBOX */
390
391 next_tb = 0; /* force lookup of first TB */
392 for(;;) {
393 interrupt_request = env->interrupt_request;
394 if (unlikely(interrupt_request)) {
395 if (unlikely(env->singlestep_enabled & SSTEP_NOIRQ)) {
396 /* Mask out external interrupts for this step. */
397 interrupt_request &= ~(CPU_INTERRUPT_HARD |
398 CPU_INTERRUPT_FIQ |
399 CPU_INTERRUPT_SMI |
400 CPU_INTERRUPT_NMI);
401 }
402 if (interrupt_request & CPU_INTERRUPT_DEBUG) {
403 env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
404 env->exception_index = EXCP_DEBUG;
405 cpu_loop_exit();
406 }
407#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
408 defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
409 defined(TARGET_MICROBLAZE)
410 if (interrupt_request & CPU_INTERRUPT_HALT) {
411 env->interrupt_request &= ~CPU_INTERRUPT_HALT;
412 env->halted = 1;
413 env->exception_index = EXCP_HLT;
414 cpu_loop_exit();
415 }
416#endif
417#if defined(TARGET_I386)
418# ifdef VBOX
419 /* Memory registration may post a tlb flush request, process it ASAP. */
420 if (interrupt_request & (CPU_INTERRUPT_EXTERNAL_FLUSH_TLB)) {
421 tlb_flush(env, true); /* (clears the flush flag) */
422 }
423
424 /* Single instruction exec request, we execute it and return (one way or the other).
425 The caller will always reschedule after doing this operation! */
426 if (interrupt_request & CPU_INTERRUPT_SINGLE_INSTR)
427 {
428 /* not in flight are we? (if we are, we trapped) */
429 if (!(env->interrupt_request & CPU_INTERRUPT_SINGLE_INSTR_IN_FLIGHT))
430 {
431 ASMAtomicOrS32((int32_t volatile *)&env->interrupt_request, CPU_INTERRUPT_SINGLE_INSTR_IN_FLIGHT);
432 env->exception_index = EXCP_SINGLE_INSTR;
433 if (emulate_single_instr(env) == -1)
434 AssertMsgFailed(("REM: emulate_single_instr failed for EIP=%RGv!!\n", (RTGCPTR)env->eip));
435
436 /* When we receive an external interrupt during execution of this single
437 instruction, then we should stay here. We will leave when we're ready
438 for raw-mode or when interrupted by pending EMT requests. */
439 interrupt_request = env->interrupt_request; /* reload this! */
440 if ( !(interrupt_request & CPU_INTERRUPT_HARD)
441 || !(env->eflags & IF_MASK)
442 || (env->hflags & HF_INHIBIT_IRQ_MASK)
443 || (env->state & CPU_RAW_HWACC)
444 )
445 {
446 env->exception_index = ret = EXCP_SINGLE_INSTR;
447 cpu_loop_exit();
448 }
449 }
450 /* Clear CPU_INTERRUPT_SINGLE_INSTR and leave CPU_INTERRUPT_SINGLE_INSTR_IN_FLIGHT set. */
451 ASMAtomicAndS32((int32_t volatile *)&env->interrupt_request, ~CPU_INTERRUPT_SINGLE_INSTR);
452# ifdef IEM_VERIFICATION_MODE
453 env->exception_index = ret = EXCP_SINGLE_INSTR;
454 cpu_loop_exit();
455# endif
456 }
457# endif /* VBOX */
458
459# ifndef VBOX /** @todo reconcile our code with the following... */
460 if (interrupt_request & CPU_INTERRUPT_INIT) {
461 svm_check_intercept(SVM_EXIT_INIT);
462 do_cpu_init(env);
463 env->exception_index = EXCP_HALTED;
464 cpu_loop_exit();
465 } else if (interrupt_request & CPU_INTERRUPT_SIPI) {
466 do_cpu_sipi(env);
467 } else if (env->hflags2 & HF2_GIF_MASK) {
468 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
469 !(env->hflags & HF_SMM_MASK)) {
470 svm_check_intercept(SVM_EXIT_SMI);
471 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
472 do_smm_enter();
473 next_tb = 0;
474 } else if ((interrupt_request & CPU_INTERRUPT_NMI) &&
475 !(env->hflags2 & HF2_NMI_MASK)) {
476 env->interrupt_request &= ~CPU_INTERRUPT_NMI;
477 env->hflags2 |= HF2_NMI_MASK;
478 do_interrupt(EXCP02_NMI, 0, 0, 0, 1);
479 next_tb = 0;
480 } else if (interrupt_request & CPU_INTERRUPT_MCE) {
481 env->interrupt_request &= ~CPU_INTERRUPT_MCE;
482 do_interrupt(EXCP12_MCHK, 0, 0, 0, 0);
483 next_tb = 0;
484 } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
485 (((env->hflags2 & HF2_VINTR_MASK) &&
486 (env->hflags2 & HF2_HIF_MASK)) ||
487 (!(env->hflags2 & HF2_VINTR_MASK) &&
488 (env->eflags & IF_MASK &&
489 !(env->hflags & HF_INHIBIT_IRQ_MASK))))) {
490 int intno;
491 svm_check_intercept(SVM_EXIT_INTR);
492 env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
493 intno = cpu_get_pic_interrupt(env);
494 qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing hardware INT=0x%02x\n", intno);
495#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
496#undef env
497 env = cpu_single_env;
498#define env cpu_single_env
499#endif
500 do_interrupt(intno, 0, 0, 0, 1);
501 /* ensure that no TB jump will be modified as
502 the program flow was changed */
503 next_tb = 0;
504#if !defined(CONFIG_USER_ONLY)
505 } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
506 (env->eflags & IF_MASK) &&
507 !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
508 int intno;
509 /* FIXME: this should respect TPR */
510 svm_check_intercept(SVM_EXIT_VINTR);
511 intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
512 qemu_log_mask(CPU_LOG_TB_IN_ASM, "Servicing virtual hardware INT=0x%02x\n", intno);
513 do_interrupt(intno, 0, 0, 0, 1);
514 env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
515 next_tb = 0;
516#endif
517 }
518 }
519# else /* VBOX */
520 RAWEx_ProfileStart(env, STATS_IRQ_HANDLING);
521 if ((interrupt_request & CPU_INTERRUPT_SMI) &&
522 !(env->hflags & HF_SMM_MASK)) {
523 env->interrupt_request &= ~CPU_INTERRUPT_SMI;
524 do_smm_enter();
525 next_tb = 0;
526 }
527 else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
528 (env->eflags & IF_MASK) &&
529 !(env->hflags & HF_INHIBIT_IRQ_MASK))
530 {
531 /* if hardware interrupt pending, we execute it */
532 int intno;
533 ASMAtomicAndS32((int32_t volatile *)&env->interrupt_request, ~CPU_INTERRUPT_HARD);
534 intno = cpu_get_pic_interrupt(env);
535 if (intno >= 0)
536 {
537 Log(("do_interrupt %d\n", intno));
538 do_interrupt(intno, 0, 0, 0, 1);
539 }
540 /* ensure that no TB jump will be modified as
541 the program flow was changed */
542 next_tb = 0;
543 }
544# endif /* VBOX */
545#elif defined(TARGET_PPC)
546#if 0
547 if ((interrupt_request & CPU_INTERRUPT_RESET)) {
548 cpu_reset(env);
549 }
550#endif
551 if (interrupt_request & CPU_INTERRUPT_HARD) {
552 ppc_hw_interrupt(env);
553 if (env->pending_interrupts == 0)
554 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
555 next_tb = 0;
556 }
557#elif defined(TARGET_MICROBLAZE)
558 if ((interrupt_request & CPU_INTERRUPT_HARD)
559 && (env->sregs[SR_MSR] & MSR_IE)
560 && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))
561 && !(env->iflags & (D_FLAG | IMM_FLAG))) {
562 env->exception_index = EXCP_IRQ;
563 do_interrupt(env);
564 next_tb = 0;
565 }
566#elif defined(TARGET_MIPS)
567 if ((interrupt_request & CPU_INTERRUPT_HARD) &&
568 (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
569 (env->CP0_Status & (1 << CP0St_IE)) &&
570 !(env->CP0_Status & (1 << CP0St_EXL)) &&
571 !(env->CP0_Status & (1 << CP0St_ERL)) &&
572 !(env->hflags & MIPS_HFLAG_DM)) {
573 /* Raise it */
574 env->exception_index = EXCP_EXT_INTERRUPT;
575 env->error_code = 0;
576 do_interrupt(env);
577 next_tb = 0;
578 }
579#elif defined(TARGET_SPARC)
580 if (interrupt_request & CPU_INTERRUPT_HARD) {
581 if (cpu_interrupts_enabled(env) &&
582 env->interrupt_index > 0) {
583 int pil = env->interrupt_index & 0xf;
584 int type = env->interrupt_index & 0xf0;
585
586 if (((type == TT_EXTINT) &&
587 cpu_pil_allowed(env, pil)) ||
588 type != TT_EXTINT) {
589 env->exception_index = env->interrupt_index;
590 do_interrupt(env);
591 next_tb = 0;
592 }
593 }
594 } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
595 //do_interrupt(0, 0, 0, 0, 0);
596 env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
597 }
598#elif defined(TARGET_ARM)
599 if (interrupt_request & CPU_INTERRUPT_FIQ
600 && !(env->uncached_cpsr & CPSR_F)) {
601 env->exception_index = EXCP_FIQ;
602 do_interrupt(env);
603 next_tb = 0;
604 }
605 /* ARMv7-M interrupt return works by loading a magic value
606 into the PC. On real hardware the load causes the
607 return to occur. The qemu implementation performs the
608 jump normally, then does the exception return when the
609 CPU tries to execute code at the magic address.
610 This will cause the magic PC value to be pushed to
611 the stack if an interrupt occured at the wrong time.
612 We avoid this by disabling interrupts when
613 pc contains a magic address. */
614 if (interrupt_request & CPU_INTERRUPT_HARD
615 && ((IS_M(env) && env->regs[15] < 0xfffffff0)
616 || !(env->uncached_cpsr & CPSR_I))) {
617 env->exception_index = EXCP_IRQ;
618 do_interrupt(env);
619 next_tb = 0;
620 }
621#elif defined(TARGET_SH4)
622 if (interrupt_request & CPU_INTERRUPT_HARD) {
623 do_interrupt(env);
624 next_tb = 0;
625 }
626#elif defined(TARGET_ALPHA)
627 if (interrupt_request & CPU_INTERRUPT_HARD) {
628 do_interrupt(env);
629 next_tb = 0;
630 }
631#elif defined(TARGET_CRIS)
632 if (interrupt_request & CPU_INTERRUPT_HARD
633 && (env->pregs[PR_CCS] & I_FLAG)
634 && !env->locked_irq) {
635 env->exception_index = EXCP_IRQ;
636 do_interrupt(env);
637 next_tb = 0;
638 }
639 if (interrupt_request & CPU_INTERRUPT_NMI
640 && (env->pregs[PR_CCS] & M_FLAG)) {
641 env->exception_index = EXCP_NMI;
642 do_interrupt(env);
643 next_tb = 0;
644 }
645#elif defined(TARGET_M68K)
646 if (interrupt_request & CPU_INTERRUPT_HARD
647 && ((env->sr & SR_I) >> SR_I_SHIFT)
648 < env->pending_level) {
649 /* Real hardware gets the interrupt vector via an
650 IACK cycle at this point. Current emulated
651 hardware doesn't rely on this, so we
652 provide/save the vector when the interrupt is
653 first signalled. */
654 env->exception_index = env->pending_vector;
655 do_interrupt(1);
656 next_tb = 0;
657 }
658#endif
659 /* Don't use the cached interupt_request value,
660 do_interrupt may have updated the EXITTB flag. */
661 if (env->interrupt_request & CPU_INTERRUPT_EXITTB) {
662#ifndef VBOX
663 env->interrupt_request &= ~CPU_INTERRUPT_EXITTB;
664#else /* VBOX */
665 ASMAtomicAndS32((int32_t volatile *)&env->interrupt_request, ~CPU_INTERRUPT_EXITTB);
666#endif /* VBOX */
667 /* ensure that no TB jump will be modified as
668 the program flow was changed */
669 next_tb = 0;
670 }
671#ifdef VBOX
672 RAWEx_ProfileStop(env, STATS_IRQ_HANDLING);
673 if (interrupt_request & CPU_INTERRUPT_RC) {
674 env->exception_index = EXCP_RC;
675 ASMAtomicAndS32((int32_t volatile *)&env->interrupt_request, ~CPU_INTERRUPT_RC);
676 ret = env->exception_index;
677 cpu_loop_exit();
678 }
679 if (interrupt_request & (CPU_INTERRUPT_EXTERNAL_EXIT)) {
680 ASMAtomicAndS32((int32_t volatile *)&env->interrupt_request, ~(CPU_INTERRUPT_EXTERNAL_EXIT));
681 env->exit_request = 1;
682 }
683#endif
684 }
685 if (unlikely(env->exit_request)) {
686 env->exit_request = 0;
687 env->exception_index = EXCP_INTERRUPT;
688 cpu_loop_exit();
689 }
690
691#ifdef VBOX
692 /*
693 * Check if we the CPU state allows us to execute the code in raw-mode.
694 */
695 RAWEx_ProfileStart(env, STATS_RAW_CHECK);
696 if (remR3CanExecuteRaw(env,
697 env->eip + env->segs[R_CS].base,
698 env->hflags | (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK)),
699 &env->exception_index))
700 {
701 RAWEx_ProfileStop(env, STATS_RAW_CHECK);
702 ret = env->exception_index;
703 cpu_loop_exit();
704 }
705 RAWEx_ProfileStop(env, STATS_RAW_CHECK);
706#endif /* VBOX */
707
708#if defined(DEBUG_DISAS) || defined(CONFIG_DEBUG_EXEC)
709 if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
710 /* restore flags in standard format */
711#if defined(TARGET_I386)
712 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
713 log_cpu_state(env, X86_DUMP_CCOP);
714 env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
715#elif defined(TARGET_M68K)
716 cpu_m68k_flush_flags(env, env->cc_op);
717 env->cc_op = CC_OP_FLAGS;
718 env->sr = (env->sr & 0xffe0)
719 | env->cc_dest | (env->cc_x << 4);
720 log_cpu_state(env, 0);
721#else
722 log_cpu_state(env, 0);
723#endif
724 }
725#endif /* DEBUG_DISAS || CONFIG_DEBUG_EXEC */
726#ifdef VBOX
727 RAWEx_ProfileStart(env, STATS_TLB_LOOKUP);
728#endif /*VBOX*/
729 spin_lock(&tb_lock);
730 tb = tb_find_fast();
731 /* Note: we do it here to avoid a gcc bug on Mac OS X when
732 doing it in tb_find_slow */
733 if (tb_invalidated_flag) {
734 /* as some TB could have been invalidated because
735 of memory exceptions while generating the code, we
736 must recompute the hash index here */
737 next_tb = 0;
738 tb_invalidated_flag = 0;
739 }
740#ifdef CONFIG_DEBUG_EXEC
741 qemu_log_mask(CPU_LOG_EXEC, "Trace 0x%08lx [" TARGET_FMT_lx "] %s\n",
742 (long)tb->tc_ptr, tb->pc,
743 lookup_symbol(tb->pc));
744#endif
745 /* see if we can patch the calling TB. When the TB
746 spans two pages, we cannot safely do a direct
747 jump. */
748#ifndef VBOX
749 if (next_tb != 0 && tb->page_addr[1] == -1) {
750#else /* VBOX */
751 if (next_tb != 0 && !(tb->cflags & CF_RAW_MODE) && tb->page_addr[1] == -1) {
752#endif /* VBOX */
753 tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb & 3, tb);
754 }
755 spin_unlock(&tb_lock);
756#ifdef VBOX
757 RAWEx_ProfileStop(env, STATS_TLB_LOOKUP);
758#endif
759
760 /* cpu_interrupt might be called while translating the
761 TB, but before it is linked into a potentially
762 infinite loop and becomes env->current_tb. Avoid
763 starting execution if there is a pending interrupt. */
764 env->current_tb = tb;
765 barrier();
766 if (likely(!env->exit_request)) {
767 tc_ptr = tb->tc_ptr;
768 /* execute the generated code */
769#ifdef VBOX
770 RAWEx_ProfileStart(env, STATS_QEMU_RUN_EMULATED_CODE);
771#endif
772#if defined(__sparc__) && !defined(CONFIG_SOLARIS)
773#undef env
774 env = cpu_single_env;
775#define env cpu_single_env
776#endif
777#if defined(VBOX) && defined(GCC_WITH_BUGGY_REGPARM)
778 tcg_qemu_tb_exec(tc_ptr, next_tb);
779#else
780 next_tb = tcg_qemu_tb_exec(tc_ptr);
781#endif
782#ifdef VBOX
783 RAWEx_ProfileStop(env, STATS_QEMU_RUN_EMULATED_CODE);
784#endif
785 if ((next_tb & 3) == 2) {
786 /* Instruction counter expired. */
787 int insns_left;
788 tb = (TranslationBlock *)(long)(next_tb & ~3);
789 /* Restore PC. */
790 cpu_pc_from_tb(env, tb);
791 insns_left = env->icount_decr.u32;
792 if (env->icount_extra && insns_left >= 0) {
793 /* Refill decrementer and continue execution. */
794 env->icount_extra += insns_left;
795 if (env->icount_extra > 0xffff) {
796 insns_left = 0xffff;
797 } else {
798 insns_left = env->icount_extra;
799 }
800 env->icount_extra -= insns_left;
801 env->icount_decr.u16.low = insns_left;
802 } else {
803 if (insns_left > 0) {
804 /* Execute remaining instructions. */
805 cpu_exec_nocache(insns_left, tb);
806 }
807 env->exception_index = EXCP_INTERRUPT;
808 next_tb = 0;
809 cpu_loop_exit();
810 }
811 }
812 }
813 env->current_tb = NULL;
814 /* reset soft MMU for next block (it can currently
815 only be set by a memory fault) */
816 } /* for(;;) */
817 }
818#ifdef VBOX_HIGH_RES_TIMERS_HACK
819 /* NULL the current_tb here so cpu_interrupt() doesn't do anything
820 unnecessary (like crashing during emulate single instruction).
821 Note! Don't use env1->pVM here, the code wouldn't run with
822 gcc-4.4/amd64 anymore, see #3883. */
823 env->current_tb = NULL;
824 if ( !(env->interrupt_request & ( CPU_INTERRUPT_DEBUG | CPU_INTERRUPT_EXTERNAL_EXIT | CPU_INTERRUPT_RC
825 | CPU_INTERRUPT_SINGLE_INSTR | CPU_INTERRUPT_SINGLE_INSTR_IN_FLIGHT))
826 && ( (env->interrupt_request & CPU_INTERRUPT_EXTERNAL_TIMER)
827 || TMTimerPollBool(env->pVM, env->pVCpu)) ) {
828 ASMAtomicAndS32((int32_t volatile *)&env->interrupt_request, ~CPU_INTERRUPT_EXTERNAL_TIMER);
829 remR3ProfileStart(STATS_QEMU_RUN_TIMERS);
830 TMR3TimerQueuesDo(env->pVM);
831 remR3ProfileStop(STATS_QEMU_RUN_TIMERS);
832 }
833#endif
834 } /* for(;;) */
835
836
837#if defined(TARGET_I386)
838 /* restore flags in standard format */
839 env->eflags = env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
840#elif defined(TARGET_ARM)
841 /* XXX: Save/restore host fpu exception state?. */
842#elif defined(TARGET_SPARC)
843#elif defined(TARGET_PPC)
844#elif defined(TARGET_M68K)
845 cpu_m68k_flush_flags(env, env->cc_op);
846 env->cc_op = CC_OP_FLAGS;
847 env->sr = (env->sr & 0xffe0)
848 | env->cc_dest | (env->cc_x << 4);
849#elif defined(TARGET_MICROBLAZE)
850#elif defined(TARGET_MIPS)
851#elif defined(TARGET_SH4)
852#elif defined(TARGET_ALPHA)
853#elif defined(TARGET_CRIS)
854#elif defined(TARGET_S390X)
855 /* XXXXX */
856#else
857#error unsupported target CPU
858#endif
859
860 /* restore global registers */
861 barrier();
862 env = (void *) saved_env_reg;
863
864# ifndef VBOX /* we might be using elsewhere, we only have one. */
865 /* fail safe : never use cpu_single_env outside cpu_exec() */
866 cpu_single_env = NULL;
867# endif
868 return ret;
869}
870
871/* must only be called from the generated code as an exception can be
872 generated */
873void tb_invalidate_page_range(target_ulong start, target_ulong end)
874{
875 /* XXX: cannot enable it yet because it yields to MMU exception
876 where NIP != read address on PowerPC */
877#if 0
878 target_ulong phys_addr;
879 phys_addr = get_phys_addr_code(env, start);
880 tb_invalidate_phys_page_range(phys_addr, phys_addr + end - start, 0);
881#endif
882}
883
884#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
885
886void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
887{
888 CPUX86State *saved_env;
889
890 saved_env = env;
891 env = s;
892 if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
893 selector &= 0xffff;
894 cpu_x86_load_seg_cache(env, seg_reg, selector,
895 (selector << 4), 0xffff, 0);
896 } else {
897 helper_load_seg(seg_reg, selector);
898 }
899 env = saved_env;
900}
901
902void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
903{
904 CPUX86State *saved_env;
905
906 saved_env = env;
907 env = s;
908
909 helper_fsave(ptr, data32);
910
911 env = saved_env;
912}
913
914void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
915{
916 CPUX86State *saved_env;
917
918 saved_env = env;
919 env = s;
920
921 helper_frstor(ptr, data32);
922
923 env = saved_env;
924}
925
926#endif /* TARGET_I386 */
927
928#if !defined(CONFIG_SOFTMMU)
929
930#if defined(TARGET_I386)
931#define EXCEPTION_ACTION raise_exception_err(env->exception_index, env->error_code)
932#else
933#define EXCEPTION_ACTION cpu_loop_exit()
934#endif
935
936/* 'pc' is the host PC at which the exception was raised. 'address' is
937 the effective address of the memory exception. 'is_write' is 1 if a
938 write caused the exception and otherwise 0'. 'old_set' is the
939 signal set which should be restored */
940static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
941 int is_write, sigset_t *old_set,
942 void *puc)
943{
944 TranslationBlock *tb;
945 int ret;
946
947 if (cpu_single_env)
948 env = cpu_single_env; /* XXX: find a correct solution for multithread */
949#if defined(DEBUG_SIGNAL)
950 qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
951 pc, address, is_write, *(unsigned long *)old_set);
952#endif
953 /* XXX: locking issue */
954 if (is_write && page_unprotect(h2g(address), pc, puc)) {
955 return 1;
956 }
957
958 /* see if it is an MMU fault */
959 ret = cpu_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 0);
960 if (ret < 0)
961 return 0; /* not an MMU fault */
962 if (ret == 0)
963 return 1; /* the MMU fault was handled without causing real CPU fault */
964 /* now we have a real cpu fault */
965 tb = tb_find_pc(pc);
966 if (tb) {
967 /* the PC is inside the translated code. It means that we have
968 a virtual CPU fault */
969 cpu_restore_state(tb, env, pc, puc);
970 }
971
972 /* we restore the process signal mask as the sigreturn should
973 do it (XXX: use sigsetjmp) */
974 sigprocmask(SIG_SETMASK, old_set, NULL);
975 EXCEPTION_ACTION;
976
977 /* never comes here */
978 return 1;
979}
980
981#if defined(__i386__)
982
983#if defined(__APPLE__)
984# include <sys/ucontext.h>
985
986# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext->ss.eip))
987# define TRAP_sig(context) ((context)->uc_mcontext->es.trapno)
988# define ERROR_sig(context) ((context)->uc_mcontext->es.err)
989# define MASK_sig(context) ((context)->uc_sigmask)
990#elif defined (__NetBSD__)
991# include <ucontext.h>
992
993# define EIP_sig(context) ((context)->uc_mcontext.__gregs[_REG_EIP])
994# define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
995# define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR])
996# define MASK_sig(context) ((context)->uc_sigmask)
997#elif defined (__FreeBSD__) || defined(__DragonFly__)
998# include <ucontext.h>
999
1000# define EIP_sig(context) (*((unsigned long*)&(context)->uc_mcontext.mc_eip))
1001# define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno)
1002# define ERROR_sig(context) ((context)->uc_mcontext.mc_err)
1003# define MASK_sig(context) ((context)->uc_sigmask)
1004#elif defined(__OpenBSD__)
1005# define EIP_sig(context) ((context)->sc_eip)
1006# define TRAP_sig(context) ((context)->sc_trapno)
1007# define ERROR_sig(context) ((context)->sc_err)
1008# define MASK_sig(context) ((context)->sc_mask)
1009#else
1010# define EIP_sig(context) ((context)->uc_mcontext.gregs[REG_EIP])
1011# define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1012# define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1013# define MASK_sig(context) ((context)->uc_sigmask)
1014#endif
1015
1016int cpu_signal_handler(int host_signum, void *pinfo,
1017 void *puc)
1018{
1019 siginfo_t *info = pinfo;
1020#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
1021 ucontext_t *uc = puc;
1022#elif defined(__OpenBSD__)
1023 struct sigcontext *uc = puc;
1024#else
1025 struct ucontext *uc = puc;
1026#endif
1027 unsigned long pc;
1028 int trapno;
1029
1030#ifndef REG_EIP
1031/* for glibc 2.1 */
1032#define REG_EIP EIP
1033#define REG_ERR ERR
1034#define REG_TRAPNO TRAPNO
1035#endif
1036 pc = EIP_sig(uc);
1037 trapno = TRAP_sig(uc);
1038 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1039 trapno == 0xe ?
1040 (ERROR_sig(uc) >> 1) & 1 : 0,
1041 &MASK_sig(uc), puc);
1042}
1043
1044#elif defined(__x86_64__)
1045
1046#ifdef __NetBSD__
1047#define PC_sig(context) _UC_MACHINE_PC(context)
1048#define TRAP_sig(context) ((context)->uc_mcontext.__gregs[_REG_TRAPNO])
1049#define ERROR_sig(context) ((context)->uc_mcontext.__gregs[_REG_ERR])
1050#define MASK_sig(context) ((context)->uc_sigmask)
1051#elif defined(__OpenBSD__)
1052#define PC_sig(context) ((context)->sc_rip)
1053#define TRAP_sig(context) ((context)->sc_trapno)
1054#define ERROR_sig(context) ((context)->sc_err)
1055#define MASK_sig(context) ((context)->sc_mask)
1056#elif defined (__FreeBSD__) || defined(__DragonFly__)
1057#include <ucontext.h>
1058
1059#define PC_sig(context) (*((unsigned long*)&(context)->uc_mcontext.mc_rip))
1060#define TRAP_sig(context) ((context)->uc_mcontext.mc_trapno)
1061#define ERROR_sig(context) ((context)->uc_mcontext.mc_err)
1062#define MASK_sig(context) ((context)->uc_sigmask)
1063#else
1064#define PC_sig(context) ((context)->uc_mcontext.gregs[REG_RIP])
1065#define TRAP_sig(context) ((context)->uc_mcontext.gregs[REG_TRAPNO])
1066#define ERROR_sig(context) ((context)->uc_mcontext.gregs[REG_ERR])
1067#define MASK_sig(context) ((context)->uc_sigmask)
1068#endif
1069
1070int cpu_signal_handler(int host_signum, void *pinfo,
1071 void *puc)
1072{
1073 siginfo_t *info = pinfo;
1074 unsigned long pc;
1075#if defined(__NetBSD__) || defined (__FreeBSD__) || defined(__DragonFly__)
1076 ucontext_t *uc = puc;
1077#elif defined(__OpenBSD__)
1078 struct sigcontext *uc = puc;
1079#else
1080 struct ucontext *uc = puc;
1081#endif
1082
1083 pc = PC_sig(uc);
1084 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1085 TRAP_sig(uc) == 0xe ?
1086 (ERROR_sig(uc) >> 1) & 1 : 0,
1087 &MASK_sig(uc), puc);
1088}
1089
1090#elif defined(_ARCH_PPC)
1091
1092/***********************************************************************
1093 * signal context platform-specific definitions
1094 * From Wine
1095 */
1096#ifdef linux
1097/* All Registers access - only for local access */
1098# define REG_sig(reg_name, context) ((context)->uc_mcontext.regs->reg_name)
1099/* Gpr Registers access */
1100# define GPR_sig(reg_num, context) REG_sig(gpr[reg_num], context)
1101# define IAR_sig(context) REG_sig(nip, context) /* Program counter */
1102# define MSR_sig(context) REG_sig(msr, context) /* Machine State Register (Supervisor) */
1103# define CTR_sig(context) REG_sig(ctr, context) /* Count register */
1104# define XER_sig(context) REG_sig(xer, context) /* User's integer exception register */
1105# define LR_sig(context) REG_sig(link, context) /* Link register */
1106# define CR_sig(context) REG_sig(ccr, context) /* Condition register */
1107/* Float Registers access */
1108# define FLOAT_sig(reg_num, context) (((double*)((char*)((context)->uc_mcontext.regs+48*4)))[reg_num])
1109# define FPSCR_sig(context) (*(int*)((char*)((context)->uc_mcontext.regs+(48+32*2)*4)))
1110/* Exception Registers access */
1111# define DAR_sig(context) REG_sig(dar, context)
1112# define DSISR_sig(context) REG_sig(dsisr, context)
1113# define TRAP_sig(context) REG_sig(trap, context)
1114#endif /* linux */
1115
1116#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
1117#include <ucontext.h>
1118# define IAR_sig(context) ((context)->uc_mcontext.mc_srr0)
1119# define MSR_sig(context) ((context)->uc_mcontext.mc_srr1)
1120# define CTR_sig(context) ((context)->uc_mcontext.mc_ctr)
1121# define XER_sig(context) ((context)->uc_mcontext.mc_xer)
1122# define LR_sig(context) ((context)->uc_mcontext.mc_lr)
1123# define CR_sig(context) ((context)->uc_mcontext.mc_cr)
1124/* Exception Registers access */
1125# define DAR_sig(context) ((context)->uc_mcontext.mc_dar)
1126# define DSISR_sig(context) ((context)->uc_mcontext.mc_dsisr)
1127# define TRAP_sig(context) ((context)->uc_mcontext.mc_exc)
1128#endif /* __FreeBSD__|| __FreeBSD_kernel__ */
1129
1130#ifdef __APPLE__
1131# include <sys/ucontext.h>
1132typedef struct ucontext SIGCONTEXT;
1133/* All Registers access - only for local access */
1134# define REG_sig(reg_name, context) ((context)->uc_mcontext->ss.reg_name)
1135# define FLOATREG_sig(reg_name, context) ((context)->uc_mcontext->fs.reg_name)
1136# define EXCEPREG_sig(reg_name, context) ((context)->uc_mcontext->es.reg_name)
1137# define VECREG_sig(reg_name, context) ((context)->uc_mcontext->vs.reg_name)
1138/* Gpr Registers access */
1139# define GPR_sig(reg_num, context) REG_sig(r##reg_num, context)
1140# define IAR_sig(context) REG_sig(srr0, context) /* Program counter */
1141# define MSR_sig(context) REG_sig(srr1, context) /* Machine State Register (Supervisor) */
1142# define CTR_sig(context) REG_sig(ctr, context)
1143# define XER_sig(context) REG_sig(xer, context) /* Link register */
1144# define LR_sig(context) REG_sig(lr, context) /* User's integer exception register */
1145# define CR_sig(context) REG_sig(cr, context) /* Condition register */
1146/* Float Registers access */
1147# define FLOAT_sig(reg_num, context) FLOATREG_sig(fpregs[reg_num], context)
1148# define FPSCR_sig(context) ((double)FLOATREG_sig(fpscr, context))
1149/* Exception Registers access */
1150# define DAR_sig(context) EXCEPREG_sig(dar, context) /* Fault registers for coredump */
1151# define DSISR_sig(context) EXCEPREG_sig(dsisr, context)
1152# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
1153#endif /* __APPLE__ */
1154
1155int cpu_signal_handler(int host_signum, void *pinfo,
1156 void *puc)
1157{
1158 siginfo_t *info = pinfo;
1159#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
1160 ucontext_t *uc = puc;
1161#else
1162 struct ucontext *uc = puc;
1163#endif
1164 unsigned long pc;
1165 int is_write;
1166
1167 pc = IAR_sig(uc);
1168 is_write = 0;
1169#if 0
1170 /* ppc 4xx case */
1171 if (DSISR_sig(uc) & 0x00800000)
1172 is_write = 1;
1173#else
1174 if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
1175 is_write = 1;
1176#endif
1177 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1178 is_write, &uc->uc_sigmask, puc);
1179}
1180
1181#elif defined(__alpha__)
1182
1183int cpu_signal_handler(int host_signum, void *pinfo,
1184 void *puc)
1185{
1186 siginfo_t *info = pinfo;
1187 struct ucontext *uc = puc;
1188 uint32_t *pc = uc->uc_mcontext.sc_pc;
1189 uint32_t insn = *pc;
1190 int is_write = 0;
1191
1192 /* XXX: need kernel patch to get write flag faster */
1193 switch (insn >> 26) {
1194 case 0x0d: // stw
1195 case 0x0e: // stb
1196 case 0x0f: // stq_u
1197 case 0x24: // stf
1198 case 0x25: // stg
1199 case 0x26: // sts
1200 case 0x27: // stt
1201 case 0x2c: // stl
1202 case 0x2d: // stq
1203 case 0x2e: // stl_c
1204 case 0x2f: // stq_c
1205 is_write = 1;
1206 }
1207
1208 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1209 is_write, &uc->uc_sigmask, puc);
1210}
1211#elif defined(__sparc__)
1212
1213int cpu_signal_handler(int host_signum, void *pinfo,
1214 void *puc)
1215{
1216 siginfo_t *info = pinfo;
1217 int is_write;
1218 uint32_t insn;
1219#if !defined(__arch64__) || defined(CONFIG_SOLARIS)
1220 uint32_t *regs = (uint32_t *)(info + 1);
1221 void *sigmask = (regs + 20);
1222 /* XXX: is there a standard glibc define ? */
1223 unsigned long pc = regs[1];
1224#else
1225#ifdef __linux__
1226 struct sigcontext *sc = puc;
1227 unsigned long pc = sc->sigc_regs.tpc;
1228 void *sigmask = (void *)sc->sigc_mask;
1229#elif defined(__OpenBSD__)
1230 struct sigcontext *uc = puc;
1231 unsigned long pc = uc->sc_pc;
1232 void *sigmask = (void *)(long)uc->sc_mask;
1233#endif
1234#endif
1235
1236 /* XXX: need kernel patch to get write flag faster */
1237 is_write = 0;
1238 insn = *(uint32_t *)pc;
1239 if ((insn >> 30) == 3) {
1240 switch((insn >> 19) & 0x3f) {
1241 case 0x05: // stb
1242 case 0x15: // stba
1243 case 0x06: // sth
1244 case 0x16: // stha
1245 case 0x04: // st
1246 case 0x14: // sta
1247 case 0x07: // std
1248 case 0x17: // stda
1249 case 0x0e: // stx
1250 case 0x1e: // stxa
1251 case 0x24: // stf
1252 case 0x34: // stfa
1253 case 0x27: // stdf
1254 case 0x37: // stdfa
1255 case 0x26: // stqf
1256 case 0x36: // stqfa
1257 case 0x25: // stfsr
1258 case 0x3c: // casa
1259 case 0x3e: // casxa
1260 is_write = 1;
1261 break;
1262 }
1263 }
1264 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1265 is_write, sigmask, NULL);
1266}
1267
1268#elif defined(__arm__)
1269
1270int cpu_signal_handler(int host_signum, void *pinfo,
1271 void *puc)
1272{
1273 siginfo_t *info = pinfo;
1274 struct ucontext *uc = puc;
1275 unsigned long pc;
1276 int is_write;
1277
1278#if (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
1279 pc = uc->uc_mcontext.gregs[R15];
1280#else
1281 pc = uc->uc_mcontext.arm_pc;
1282#endif
1283 /* XXX: compute is_write */
1284 is_write = 0;
1285 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1286 is_write,
1287 &uc->uc_sigmask, puc);
1288}
1289
1290#elif defined(__mc68000)
1291
1292int cpu_signal_handler(int host_signum, void *pinfo,
1293 void *puc)
1294{
1295 siginfo_t *info = pinfo;
1296 struct ucontext *uc = puc;
1297 unsigned long pc;
1298 int is_write;
1299
1300 pc = uc->uc_mcontext.gregs[16];
1301 /* XXX: compute is_write */
1302 is_write = 0;
1303 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1304 is_write,
1305 &uc->uc_sigmask, puc);
1306}
1307
1308#elif defined(__ia64)
1309
1310#ifndef __ISR_VALID
1311 /* This ought to be in <bits/siginfo.h>... */
1312# define __ISR_VALID 1
1313#endif
1314
1315int cpu_signal_handler(int host_signum, void *pinfo, void *puc)
1316{
1317 siginfo_t *info = pinfo;
1318 struct ucontext *uc = puc;
1319 unsigned long ip;
1320 int is_write = 0;
1321
1322 ip = uc->uc_mcontext.sc_ip;
1323 switch (host_signum) {
1324 case SIGILL:
1325 case SIGFPE:
1326 case SIGSEGV:
1327 case SIGBUS:
1328 case SIGTRAP:
1329 if (info->si_code && (info->si_segvflags & __ISR_VALID))
1330 /* ISR.W (write-access) is bit 33: */
1331 is_write = (info->si_isr >> 33) & 1;
1332 break;
1333
1334 default:
1335 break;
1336 }
1337 return handle_cpu_signal(ip, (unsigned long)info->si_addr,
1338 is_write,
1339 (sigset_t *)&uc->uc_sigmask, puc);
1340}
1341
1342#elif defined(__s390__)
1343
1344int cpu_signal_handler(int host_signum, void *pinfo,
1345 void *puc)
1346{
1347 siginfo_t *info = pinfo;
1348 struct ucontext *uc = puc;
1349 unsigned long pc;
1350 uint16_t *pinsn;
1351 int is_write = 0;
1352
1353 pc = uc->uc_mcontext.psw.addr;
1354
1355 /* ??? On linux, the non-rt signal handler has 4 (!) arguments instead
1356 of the normal 2 arguments. The 3rd argument contains the "int_code"
1357 from the hardware which does in fact contain the is_write value.
1358 The rt signal handler, as far as I can tell, does not give this value
1359 at all. Not that we could get to it from here even if it were. */
1360 /* ??? This is not even close to complete, since it ignores all
1361 of the read-modify-write instructions. */
1362 pinsn = (uint16_t *)pc;
1363 switch (pinsn[0] >> 8) {
1364 case 0x50: /* ST */
1365 case 0x42: /* STC */
1366 case 0x40: /* STH */
1367 is_write = 1;
1368 break;
1369 case 0xc4: /* RIL format insns */
1370 switch (pinsn[0] & 0xf) {
1371 case 0xf: /* STRL */
1372 case 0xb: /* STGRL */
1373 case 0x7: /* STHRL */
1374 is_write = 1;
1375 }
1376 break;
1377 case 0xe3: /* RXY format insns */
1378 switch (pinsn[2] & 0xff) {
1379 case 0x50: /* STY */
1380 case 0x24: /* STG */
1381 case 0x72: /* STCY */
1382 case 0x70: /* STHY */
1383 case 0x8e: /* STPQ */
1384 case 0x3f: /* STRVH */
1385 case 0x3e: /* STRV */
1386 case 0x2f: /* STRVG */
1387 is_write = 1;
1388 }
1389 break;
1390 }
1391 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1392 is_write, &uc->uc_sigmask, puc);
1393}
1394
1395#elif defined(__mips__)
1396
1397int cpu_signal_handler(int host_signum, void *pinfo,
1398 void *puc)
1399{
1400 siginfo_t *info = pinfo;
1401 struct ucontext *uc = puc;
1402 greg_t pc = uc->uc_mcontext.pc;
1403 int is_write;
1404
1405 /* XXX: compute is_write */
1406 is_write = 0;
1407 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1408 is_write, &uc->uc_sigmask, puc);
1409}
1410
1411#elif defined(__hppa__)
1412
1413int cpu_signal_handler(int host_signum, void *pinfo,
1414 void *puc)
1415{
1416 struct siginfo *info = pinfo;
1417 struct ucontext *uc = puc;
1418 unsigned long pc = uc->uc_mcontext.sc_iaoq[0];
1419 uint32_t insn = *(uint32_t *)pc;
1420 int is_write = 0;
1421
1422 /* XXX: need kernel patch to get write flag faster. */
1423 switch (insn >> 26) {
1424 case 0x1a: /* STW */
1425 case 0x19: /* STH */
1426 case 0x18: /* STB */
1427 case 0x1b: /* STWM */
1428 is_write = 1;
1429 break;
1430
1431 case 0x09: /* CSTWX, FSTWX, FSTWS */
1432 case 0x0b: /* CSTDX, FSTDX, FSTDS */
1433 /* Distinguish from coprocessor load ... */
1434 is_write = (insn >> 9) & 1;
1435 break;
1436
1437 case 0x03:
1438 switch ((insn >> 6) & 15) {
1439 case 0xa: /* STWS */
1440 case 0x9: /* STHS */
1441 case 0x8: /* STBS */
1442 case 0xe: /* STWAS */
1443 case 0xc: /* STBYS */
1444 is_write = 1;
1445 }
1446 break;
1447 }
1448
1449 return handle_cpu_signal(pc, (unsigned long)info->si_addr,
1450 is_write, &uc->uc_sigmask, puc);
1451}
1452
1453#else
1454
1455#error host CPU specific signal handler needed
1456
1457#endif
1458
1459#endif /* !defined(CONFIG_SOFTMMU) */
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette