helper.c revision cec22f4b94382f5ebee9d2f6b6df672689681e07
/*
* i386 helpers (without register variable usage)
*
* Copyright (c) 2003 Fabrice Bellard
*
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
/*
* Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
* other than GPL or LGPL is available it will apply instead, Oracle elects to use only
* the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
* a choice of LGPL license versions is made available with the language indicating
* that LGPLv2 or any later version may be used, or where a choice of which version
* of the LGPL is applied is otherwise unspecified.
*/
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifndef VBOX
#include <inttypes.h>
#include <signal.h>
#endif /* !VBOX */
#include "cpu.h"
#include "exec-all.h"
#include "qemu-common.h"
#include "kvm.h"
//#define DEBUG_MMU
/* NOTE: must be called outside the CPU execute loop */
{
int i;
if (qemu_loglevel_mask(CPU_LOG_RESET)) {
}
/* init to reset state */
#ifdef CONFIG_SOFTMMU
#endif
#ifndef VBOX /* We'll get the right value from CPUM. */
#endif
/* FPU init */
for(i = 0;i < 8; i++)
#ifndef VBOX
env->mcg_status = 0;
#endif
}
{
#ifndef VBOX
#endif
}
/***********************************************************/
/* x86 debug */
static const char *cc_op_str[] = {
"DYNAMIC",
"EFLAGS",
"MULB",
"MULW",
"MULL",
"MULQ",
"ADDB",
"ADDW",
"ADDL",
"ADDQ",
"ADCB",
"ADCW",
"ADCL",
"ADCQ",
"SUBB",
"SUBW",
"SUBL",
"SUBQ",
"SBBB",
"SBBW",
"SBBL",
"SBBQ",
"LOGICB",
"LOGICW",
"LOGICL",
"LOGICQ",
"INCB",
"INCW",
"INCL",
"INCQ",
"DECB",
"DECW",
"DECL",
"DECQ",
"SHLB",
"SHLW",
"SHLL",
"SHLQ",
"SARB",
"SARW",
"SARL",
"SARQ",
};
static void
{
#ifdef VBOX
#endif
#ifdef TARGET_X86_64
} else
#endif
{
}
goto done;
} else {
}
} else {
{ /* 32 bit mode */
"Reserved", "TSS16-avl", "LDT", "TSS16-busy",
"CallGate16", "TaskGate", "IntGate16", "TrapGate16",
"Reserved", "TSS32-avl", "Reserved", "TSS32-busy",
"CallGate32", "Reserved", "IntGate32", "TrapGate32"
},
{ /* 64 bit mode */
"<hiword>", "Reserved", "LDT", "Reserved", "Reserved",
"Reserved", "Reserved", "Reserved", "Reserved",
"TSS64-avl", "Reserved", "TSS64-busy", "CallGate64",
"Reserved", "IntGate64", "TrapGate64"
}
};
cpu_fprintf(f, "%s",
>> DESC_TYPE_SHIFT]);
}
done:
cpu_fprintf(f, "\n");
#ifdef VBOX
#endif
}
int flags)
{
char cc_op_name[32];
#ifdef VBOX
#endif
#ifdef TARGET_X86_64
cpu_fprintf(f,
} else
#endif
{
cpu_fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
"ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
"EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
}
for(i = 0; i < 6; i++) {
}
#ifdef TARGET_X86_64
for(i = 0; i < 4; i++)
} else
#endif
{
cpu_fprintf(f, "GDT= %08x %08x\n",
cpu_fprintf(f, "IDT= %08x %08x\n",
cpu_fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n",
for(i = 0; i < 4; i++)
}
if (flags & X86_DUMP_CCOP) {
else
#ifdef TARGET_X86_64
} else
#endif
{
cpu_fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n",
}
}
if (flags & X86_DUMP_FPU) {
int fptag;
fptag = 0;
for(i = 0; i < 8; i++) {
}
cpu_fprintf(f, "FCW=%04x FSW=%04x [ST=%d] FTW=%02x MXCSR=%08x\n",
for(i=0;i<8;i++) {
#if defined(USE_X86LDOUBLE)
union {
long double d;
struct {
} l;
} tmp;
#else
#endif
if ((i & 1) == 1)
cpu_fprintf(f, "\n");
else
cpu_fprintf(f, " ");
}
nb = 16;
else
nb = 8;
for(i=0;i<nb;i++) {
cpu_fprintf(f, "XMM%02d=%08x%08x%08x%08x",
i,
if ((i & 1) == 1)
cpu_fprintf(f, "\n");
else
cpu_fprintf(f, " ");
}
}
#ifdef VBOX
#endif
}
/***********************************************************/
/* x86 mmu */
/* XXX: add PGE support */
{
#if defined(DEBUG_MMU)
#endif
/* if the cpu is currently executing code, we must unlink it and
all the potentially executing TB */
/* when a20 is changed, all the MMU mappings are invalid, so
we must flush everything */
}
}
{
int pe_state;
#if defined(DEBUG_MMU)
#endif
}
#ifdef TARGET_X86_64
/* enter in long mode */
/* XXX: generate an exception */
return;
/* exit long mode */
}
#endif
/* update PE flag in hidden flags */
/* ensure that ADDSEG is always set in real mode */
/* update FPU flags */
#ifdef VBOX
#endif
}
/* XXX: in legacy PAE mode, generate a GPF if reserved bits are set in
the PDPT */
{
#if defined(DEBUG_MMU)
#endif
}
}
{
#if defined(DEBUG_MMU)
#endif
}
/* SSE handling */
new_cr4 &= ~CR4_OSFXSR_MASK;
if (new_cr4 & CR4_OSFXSR_MASK)
else
#ifdef VBOX
#endif
}
#if defined(CONFIG_USER_ONLY)
{
/* user mode only emulation */
is_write &= 1;
return 1;
}
#else
/* XXX: This value should match the one returned by CPUID
* and in exec.c */
# if defined(TARGET_X86_64)
# define PHYS_ADDR_MASK 0xfffffff000LL
# else
# define PHYS_ADDR_MASK 0xffffff000LL
# endif
/* return value:
-1 = cannot handle fault
0 = nothing more to do
1 = generate PF fault
*/
{
#if defined(DEBUG_MMU)
#endif
page_size = 4096;
goto do_mapping;
}
#ifdef TARGET_X86_64
/* test virtual address sign extension */
env->error_code = 0;
return 1;
}
if (!(pml4e & PG_PRESENT_MASK)) {
error_code = 0;
goto do_fault;
}
goto do_fault;
}
if (!(pml4e & PG_ACCESSED_MASK)) {
}
if (!(pdpe & PG_PRESENT_MASK)) {
error_code = 0;
goto do_fault;
}
goto do_fault;
}
if (!(pdpe & PG_ACCESSED_MASK)) {
pdpe |= PG_ACCESSED_MASK;
}
} else
#endif
{
/* XXX: load them when cr3 is loaded ? */
if (!(pdpe & PG_PRESENT_MASK)) {
error_code = 0;
goto do_fault;
}
}
if (!(pde & PG_PRESENT_MASK)) {
error_code = 0;
goto do_fault;
}
goto do_fault;
}
if (pde & PG_PSE_MASK) {
/* 2 MB page */
ptep ^= PG_NX_MASK;
goto do_fault_protect;
if (is_user) {
if (!(ptep & PG_USER_MASK))
goto do_fault_protect;
goto do_fault_protect;
} else {
goto do_fault_protect;
}
pde |= PG_ACCESSED_MASK;
if (is_dirty)
pde |= PG_DIRTY_MASK;
}
/* align to page_size */
} else {
/* 4 KB page */
if (!(pde & PG_ACCESSED_MASK)) {
pde |= PG_ACCESSED_MASK;
}
if (!(pte & PG_PRESENT_MASK)) {
error_code = 0;
goto do_fault;
}
goto do_fault;
}
/* combine pde and pte nx, user and rw protections */
ptep ^= PG_NX_MASK;
goto do_fault_protect;
if (is_user) {
if (!(ptep & PG_USER_MASK))
goto do_fault_protect;
goto do_fault_protect;
} else {
goto do_fault_protect;
}
pte |= PG_ACCESSED_MASK;
if (is_dirty)
pte |= PG_DIRTY_MASK;
}
page_size = 4096;
}
} else {
/* page directory entry */
if (!(pde & PG_PRESENT_MASK)) {
error_code = 0;
goto do_fault;
}
/* if PSE bit is set, then we use a 4MB page */
if (is_user) {
if (!(pde & PG_USER_MASK))
goto do_fault_protect;
goto do_fault_protect;
} else {
goto do_fault_protect;
}
pde |= PG_ACCESSED_MASK;
if (is_dirty)
pde |= PG_DIRTY_MASK;
}
} else {
if (!(pde & PG_ACCESSED_MASK)) {
pde |= PG_ACCESSED_MASK;
}
/* page directory entry */
if (!(pte & PG_PRESENT_MASK)) {
error_code = 0;
goto do_fault;
}
/* combine pde and pte user and rw protections */
if (is_user) {
if (!(ptep & PG_USER_MASK))
goto do_fault_protect;
goto do_fault_protect;
} else {
goto do_fault_protect;
}
pte |= PG_ACCESSED_MASK;
if (is_dirty)
pte |= PG_DIRTY_MASK;
}
page_size = 4096;
}
}
/* the page can be put in the TLB */
if (!(ptep & PG_NX_MASK))
if (pte & PG_DIRTY_MASK) {
/* only set write access if already dirty... otherwise wait
for dirty access */
if (is_user) {
if (ptep & PG_RW_MASK)
prot |= PAGE_WRITE;
} else {
(ptep & PG_RW_MASK))
prot |= PAGE_WRITE;
}
}
/* Even if 4MB pages, we map only one 4KB page in the cache to
avoid filling it too fast */
return 0;
if (is_user)
if (is_write1 == 2 &&
/* cr2 is not modified in case of exceptions */
addr);
} else {
}
return 1;
}
{
int page_size;
#ifdef TARGET_X86_64
/* test virtual address sign extension */
return -1;
if (!(pml4e & PG_PRESENT_MASK))
return -1;
if (!(pdpe & PG_PRESENT_MASK))
return -1;
} else
#endif
{
if (!(pdpe & PG_PRESENT_MASK))
return -1;
}
if (!(pde & PG_PRESENT_MASK)) {
return -1;
}
if (pde & PG_PSE_MASK) {
/* 2 MB page */
} else {
/* 4 KB page */
page_size = 4096;
}
if (!(pte & PG_PRESENT_MASK))
return -1;
} else {
page_size = 4096;
} else {
/* page directory entry */
if (!(pde & PG_PRESENT_MASK))
return -1;
} else {
/* page directory entry */
if (!(pte & PG_PRESENT_MASK))
return -1;
page_size = 4096;
}
}
}
return paddr;
}
{
case 0:
break;
case 1:
goto insert_wp;
case 2:
/* No support for I/O watchpoints yet */
break;
case 3:
break;
}
if (err)
}
{
return;
case 0:
break;
case 1:
case 3:
break;
case 2:
/* No support for I/O watchpoints yet */
break;
}
}
{
int hit_enabled = 0;
hit_enabled = 1;
}
}
if (hit_enabled || force_dr6_update)
return hit_enabled;
}
{
if (env->watchpoint_hit) {
if (check_hw_breakpoints(env, 0))
else
}
} else {
}
break;
}
}
}
#ifndef VBOX
/* This should come from sysemu.h - if we could include it here... */
void qemu_system_reset_request(void);
{
return;
/*
* if MSR_MCG_CTL is not all 1s, the uncorrected error
* reporting is disabled
*/
return;
/*
* if MSR_MCi_CTL is not all 1s, the uncorrected error
* reporting is disabled for the bank
*/
return;
if (status & MCI_STATUS_UC) {
"one is in progress!\n");
return;
}
} else
}
#endif /* !VBOX */
#endif /* !CONFIG_USER_ONLY */
#ifndef VBOX
{
}
}
unsigned int *flags)
{
int index;
if (selector & 0x4)
else
return 0;
if (e2 & DESC_G_MASK)
return 1;
}
#endif /* !VBOX */
#ifndef VBOX
#else
#endif
{
#ifndef VBOX
#endif
static int inited;
#ifndef VBOX
#endif
/* init various static tables */
if (!inited) {
inited = 1;
#ifndef CONFIG_USER_ONLY
#endif
}
#ifndef VBOX
return NULL;
}
#endif
return env;
}
#ifndef VBOX
#if !defined(CONFIG_USER_ONLY)
{
}
{
}
#else
{
}
{
}
#endif
#endif /* !VBOX */