a1362f392b
bsd-user fork into qemu. It contains a number of style commits, as well as 3 commits that start to change things: Some unused files are deleted, building the sparc and sparc64 targets are removed, and a structure is renamed. The next set of pull requests will start to execute the following plan: 1. Move existing code around to have a structure similar to the bsd-user fork. 2. Incrementally merge groups of system calls, focused on making x86 work. 3. Once the groups of system calls are all merged, additional platforms will be added back. 4. Concurrently, as changes are requested as part of the merge happen, those changes will be merged into the fork. An experimental merge to tip of master is under test and is what will be updated. 5. Eventually, there will be no diference, and the bsd-user fork will only be a staging area for cutting-edge features prior to upstreaming into qemu mainline. The bsd-user code in qemu has a lot of style issues. This cleans up a number in the files touched. However, the checkpatch.pl detects some incremental issues in the commits. The following are expected, but are corrected in later hashes in this branch. MAINTAINERS does not need to be updated, since all the files added or deleted are covered under existing regexp in MAINTAINERS. Checking all commits since f9a576a818044133f8564e0d243ebd97df0b3280... d60c3b932e2fa06aba5d7aa1c451b5d287095dc8:101: ERROR: consider using qemu_strtol in preference to strtol d60c3b932e2fa06aba5d7aa1c451b5d287095dc8:142: ERROR: braces {} are necessary for all arms of this statement d60c3b932e2fa06aba5d7aa1c451b5d287095dc8:145: ERROR: braces {} are necessary for all arms of this statement total: 3 errors, 0 warnings, 119 lines checked b4bebeee1dee8d333bfa105a6c28fec5eb34b147:148: WARNING: line over 80 characters b4bebeee1dee8d333bfa105a6c28fec5eb34b147:330: ERROR: braces {} are necessary for all arms of this statement b4bebeee1dee8d333bfa105a6c28fec5eb34b147:340: ERROR: braces {} are necessary for all arms of this statement b4bebeee1dee8d333bfa105a6c28fec5eb34b147:381: ERROR: space prohibited between function name and open parenthesis '(' b4bebeee1dee8d333bfa105a6c28fec5eb34b147:390: ERROR: spaces required around that '<' (ctx:VxV) b4bebeee1dee8d333bfa105a6c28fec5eb34b147:408: WARNING: Block comments use a leading /* on a separate line b4bebeee1dee8d333bfa105a6c28fec5eb34b147:409: WARNING: Block comments use * on subsequent lines b4bebeee1dee8d333bfa105a6c28fec5eb34b147:409: WARNING: Block comments use a trailing */ on a separate line b4bebeee1dee8d333bfa105a6c28fec5eb34b147:441: WARNING: line over 80 characters b4bebeee1dee8d333bfa105a6c28fec5eb34b147:445: WARNING: line over 80 characters b4bebeee1dee8d333bfa105a6c28fec5eb34b147:502: ERROR: line over 90 characters b4bebeee1dee8d333bfa105a6c28fec5eb34b147:551: ERROR: space required after that ',' (ctx:VxV) b4bebeee1dee8d333bfa105a6c28fec5eb34b147:552: ERROR: space required after that ',' (ctx:VxV) b4bebeee1dee8d333bfa105a6c28fec5eb34b147:587: ERROR: space required after that ';' (ctx:VxV) b4bebeee1dee8d333bfa105a6c28fec5eb34b147:623: ERROR: suspect code indent for conditional statements (12, 14) total: 9 errors, 6 warnings, 664 lines checked 86545e7afe3f822b8561c7ceee7540fc3b19c3f0:31: ERROR: space required after that ';' (ctx:VxV) 86545e7afe3f822b8561c7ceee7540fc3b19c3f0:40: ERROR: space required after that ';' (ctx:VxV) total: 2 errors, 0 warnings, 60 lines checked Use of uninitialized value $acpi_testexpected in string eq at scripts/checkpatch.pl line 1529. 65d58c91ef1a15ad945ece367983437576f8e82b:22: WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? total: 0 errors, 1 warnings, 14 lines checked Use of uninitialized value $acpi_testexpected in string eq at scripts/checkpatch.pl line 1529. f8ce39701b5be032fb3f9c05e8adb4055f70eec2:21: WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? total: 0 errors, 1 warnings, 0 lines checked FAIL one or more commits failed scripts/checkpatch.pl Cleaning up file based variables ERROR: Job failed: exit code 1 -----BEGIN PGP SIGNATURE----- Comment: GPGTools - https://gpgtools.org iQIzBAABCgAdFiEEIDX4lLAKo898zeG3bBzRKH2wEQAFAmCcBQIACgkQbBzRKH2w EQD4+A/9E3Yr7cIBegz0km6pTHX89y6AW4+qd6QkQgYkZ9PloIVCjSn3NxvvPy3d sCVhZu2FutEuoI2EOjzBpgQCp8mhSfayPKiZIzvHeJn9yiTmNnuHd/Opr2NaxkUV WT9Eli7aB5AhYL1AD6RVEyYQYQJLq/ULdJXUVaOe5X2werk/FT7izhVqA4hkMFUm Rx3RrMZDAyhgPT1+EUrNMgw2/dQw7QEH3w0RREc/Btfs8Wwisqq+Uy0Z8p9+khSU K5ES6FnYAoOU9EP1LMjOzuh54B2Ta9J0Z4vfjlul8+WM9DBap5FogiNChVd/mjvL 1NYJUPFIC9KaV+5xNAJanW7h531lFKwHzZka68Dmzsbjdj0sUg2GkPhneOXEH8lX Q6Kmoxpg8IpfwfB/VDPM4eL3SdNQd8d/1VSUkLOS0reOc8L9RmLXSYlJILzNkDR9 yODoBgSktX2e4wnyuknyXi1JuIx2yHCsPHq+PtBYUnHEfc8W7V9yxwhAYshuRQDy sZO1AdwEQHzgNjnCPK8ru6DqrizHwKnlE1KUy5KxUOcmfaacZ//t9ezf8qSd19eC 6deGfmfvp3Xxtz38eCLogKJXzIDjf+FMaN+0znOd0ut9qPPCqBgALZNnkeaDz+zx 2ZGhjwcRAsKZmGSLQoKPN+YkM5POwzWvEPNApPsVJjpTXpoZcJ8= =pW6n -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/bsdimp/tags/pull-bsd-user-20210511' into staging pull-bsd-user-20210511 is the next round of cleanups to bsd-user in merging the bsd-user fork into qemu. It contains a number of style commits, as well as 3 commits that start to change things: Some unused files are deleted, building the sparc and sparc64 targets are removed, and a structure is renamed. The next set of pull requests will start to execute the following plan: 1. Move existing code around to have a structure similar to the bsd-user fork. 2. Incrementally merge groups of system calls, focused on making x86 work. 3. Once the groups of system calls are all merged, additional platforms will be added back. 4. Concurrently, as changes are requested as part of the merge happen, those changes will be merged into the fork. An experimental merge to tip of master is under test and is what will be updated. 5. Eventually, there will be no diference, and the bsd-user fork will only be a staging area for cutting-edge features prior to upstreaming into qemu mainline. The bsd-user code in qemu has a lot of style issues. This cleans up a number in the files touched. However, the checkpatch.pl detects some incremental issues in the commits. The following are expected, but are corrected in later hashes in this branch. MAINTAINERS does not need to be updated, since all the files added or deleted are covered under existing regexp in MAINTAINERS. Checking all commits since f9a576a818044133f8564e0d243ebd97df0b3280... d60c3b932e2fa06aba5d7aa1c451b5d287095dc8:101: ERROR: consider using qemu_strtol in preference to strtol d60c3b932e2fa06aba5d7aa1c451b5d287095dc8:142: ERROR: braces {} are necessary for all arms of this statement d60c3b932e2fa06aba5d7aa1c451b5d287095dc8:145: ERROR: braces {} are necessary for all arms of this statement total: 3 errors, 0 warnings, 119 lines checked b4bebeee1dee8d333bfa105a6c28fec5eb34b147:148: WARNING: line over 80 characters b4bebeee1dee8d333bfa105a6c28fec5eb34b147:330: ERROR: braces {} are necessary for all arms of this statement b4bebeee1dee8d333bfa105a6c28fec5eb34b147:340: ERROR: braces {} are necessary for all arms of this statement b4bebeee1dee8d333bfa105a6c28fec5eb34b147:381: ERROR: space prohibited between function name and open parenthesis '(' b4bebeee1dee8d333bfa105a6c28fec5eb34b147:390: ERROR: spaces required around that '<' (ctx:VxV) b4bebeee1dee8d333bfa105a6c28fec5eb34b147:408: WARNING: Block comments use a leading /* on a separate line b4bebeee1dee8d333bfa105a6c28fec5eb34b147:409: WARNING: Block comments use * on subsequent lines b4bebeee1dee8d333bfa105a6c28fec5eb34b147:409: WARNING: Block comments use a trailing */ on a separate line b4bebeee1dee8d333bfa105a6c28fec5eb34b147:441: WARNING: line over 80 characters b4bebeee1dee8d333bfa105a6c28fec5eb34b147:445: WARNING: line over 80 characters b4bebeee1dee8d333bfa105a6c28fec5eb34b147:502: ERROR: line over 90 characters b4bebeee1dee8d333bfa105a6c28fec5eb34b147:551: ERROR: space required after that ',' (ctx:VxV) b4bebeee1dee8d333bfa105a6c28fec5eb34b147:552: ERROR: space required after that ',' (ctx:VxV) b4bebeee1dee8d333bfa105a6c28fec5eb34b147:587: ERROR: space required after that ';' (ctx:VxV) b4bebeee1dee8d333bfa105a6c28fec5eb34b147:623: ERROR: suspect code indent for conditional statements (12, 14) total: 9 errors, 6 warnings, 664 lines checked 86545e7afe3f822b8561c7ceee7540fc3b19c3f0:31: ERROR: space required after that ';' (ctx:VxV) 86545e7afe3f822b8561c7ceee7540fc3b19c3f0:40: ERROR: space required after that ';' (ctx:VxV) total: 2 errors, 0 warnings, 60 lines checked Use of uninitialized value $acpi_testexpected in string eq at scripts/checkpatch.pl line 1529. 65d58c91ef1a15ad945ece367983437576f8e82b:22: WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? total: 0 errors, 1 warnings, 14 lines checked Use of uninitialized value $acpi_testexpected in string eq at scripts/checkpatch.pl line 1529. f8ce39701b5be032fb3f9c05e8adb4055f70eec2:21: WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? total: 0 errors, 1 warnings, 0 lines checked FAIL one or more commits failed scripts/checkpatch.pl Cleaning up file based variables ERROR: Job failed: exit code 1 # gpg: Signature made Wed 12 May 2021 17:40:34 BST # gpg: using RSA key 2035F894B00AA3CF7CCDE1B76C1CD1287DB01100 # gpg: Good signature from "Warner Losh <wlosh@netflix.com>" [unknown] # gpg: aka "Warner Losh <imp@bsdimp.com>" [unknown] # gpg: aka "Warner Losh <imp@freebsd.org>" [unknown] # gpg: aka "Warner Losh <imp@village.org>" [unknown] # gpg: aka "Warner Losh <wlosh@bsdimp.com>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 2035 F894 B00A A3CF 7CCD E1B7 6C1C D128 7DB0 1100 * remotes/bsdimp/tags/pull-bsd-user-20210511: bsd-user: rename linux_binprm to bsd_binprm bsd-user: Stop building the sparc targets bsd-user: remove target_signal.h, it's unused bsd-user: style tweak: keyword space ( bsd-user: style tweak: Remove #if 0'd code bsd-user: style tweak: keyword space ( bsd-user: style tweak: keyword space ( bsd-user: whitespace changes bsd-user: use qemu_strtoul in preference to strtol bsd-user: style tweak: use {} consistently in for / if / else statements bsd-user: style tweak: use {} for all if statements, format else correctly bsd-user: style tweak: don't assign in if statements bsd-user: style tweak: Use preferred block comments bsd-user: style tweak: remove spacing after '*' and add after } bsd-user: style tweak: move extern to header file bsd-user: Remove commented out code bsd-user: style tweak: Use preferred block comments bsd-user: style tweak: Remove #if 0'd code bsd-user: style tweak: use C not C++ comments bsd-user: whitespace changes Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
1030 lines
31 KiB
C
1030 lines
31 KiB
C
/*
|
|
* qemu user main
|
|
*
|
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "qemu/osdep.h"
|
|
#include "qemu-common.h"
|
|
#include "qemu/units.h"
|
|
#include "qemu/accel.h"
|
|
#include "sysemu/tcg.h"
|
|
#include "qemu-version.h"
|
|
#include <machine/trap.h>
|
|
|
|
#include "qapi/error.h"
|
|
#include "qemu.h"
|
|
#include "qemu/config-file.h"
|
|
#include "qemu/error-report.h"
|
|
#include "qemu/path.h"
|
|
#include "qemu/help_option.h"
|
|
#include "qemu/module.h"
|
|
#include "exec/exec-all.h"
|
|
#include "tcg/tcg.h"
|
|
#include "qemu/timer.h"
|
|
#include "qemu/envlist.h"
|
|
#include "qemu/cutils.h"
|
|
#include "exec/log.h"
|
|
#include "trace/control.h"
|
|
|
|
int singlestep;
|
|
unsigned long mmap_min_addr;
|
|
uintptr_t guest_base;
|
|
bool have_guest_base;
|
|
unsigned long reserved_va;
|
|
|
|
static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
|
|
const char *qemu_uname_release;
|
|
enum BSDType bsd_type;
|
|
|
|
/*
|
|
* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
|
|
* we allocate a bigger stack. Need a better solution, for example
|
|
* by remapping the process stack directly at the right place
|
|
*/
|
|
unsigned long x86_stack_size = 512 * 1024;
|
|
|
|
void gemu_log(const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
vfprintf(stderr, fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
#if defined(TARGET_I386)
|
|
int cpu_get_pic_interrupt(CPUX86State *env)
|
|
{
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
void fork_start(void)
|
|
{
|
|
}
|
|
|
|
void fork_end(int child)
|
|
{
|
|
if (child) {
|
|
gdbserver_fork(thread_cpu);
|
|
}
|
|
}
|
|
|
|
#ifdef TARGET_I386
|
|
/***********************************************************/
|
|
/* CPUX86 core interface */
|
|
|
|
uint64_t cpu_get_tsc(CPUX86State *env)
|
|
{
|
|
return cpu_get_host_ticks();
|
|
}
|
|
|
|
static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
|
|
int flags)
|
|
{
|
|
unsigned int e1, e2;
|
|
uint32_t *p;
|
|
e1 = (addr << 16) | (limit & 0xffff);
|
|
e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
|
|
e2 |= flags;
|
|
p = ptr;
|
|
p[0] = tswap32(e1);
|
|
p[1] = tswap32(e2);
|
|
}
|
|
|
|
static uint64_t *idt_table;
|
|
#ifdef TARGET_X86_64
|
|
static void set_gate64(void *ptr, unsigned int type, unsigned int dpl,
|
|
uint64_t addr, unsigned int sel)
|
|
{
|
|
uint32_t *p, e1, e2;
|
|
e1 = (addr & 0xffff) | (sel << 16);
|
|
e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
|
|
p = ptr;
|
|
p[0] = tswap32(e1);
|
|
p[1] = tswap32(e2);
|
|
p[2] = tswap32(addr >> 32);
|
|
p[3] = 0;
|
|
}
|
|
/* only dpl matters as we do only user space emulation */
|
|
static void set_idt(int n, unsigned int dpl)
|
|
{
|
|
set_gate64(idt_table + n * 2, 0, dpl, 0, 0);
|
|
}
|
|
#else
|
|
static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
|
|
uint32_t addr, unsigned int sel)
|
|
{
|
|
uint32_t *p, e1, e2;
|
|
e1 = (addr & 0xffff) | (sel << 16);
|
|
e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
|
|
p = ptr;
|
|
p[0] = tswap32(e1);
|
|
p[1] = tswap32(e2);
|
|
}
|
|
|
|
/* only dpl matters as we do only user space emulation */
|
|
static void set_idt(int n, unsigned int dpl)
|
|
{
|
|
set_gate(idt_table + n, 0, dpl, 0, 0);
|
|
}
|
|
#endif
|
|
|
|
void cpu_loop(CPUX86State *env)
|
|
{
|
|
CPUState *cs = env_cpu(env);
|
|
int trapnr;
|
|
abi_ulong pc;
|
|
/* target_siginfo_t info; */
|
|
|
|
for (;;) {
|
|
cpu_exec_start(cs);
|
|
trapnr = cpu_exec(cs);
|
|
cpu_exec_end(cs);
|
|
process_queued_cpu_work(cs);
|
|
|
|
switch (trapnr) {
|
|
case 0x80:
|
|
/* syscall from int $0x80 */
|
|
if (bsd_type == target_freebsd) {
|
|
abi_ulong params = (abi_ulong) env->regs[R_ESP] +
|
|
sizeof(int32_t);
|
|
int32_t syscall_nr = env->regs[R_EAX];
|
|
int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
|
|
|
|
if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
|
|
get_user_s32(syscall_nr, params);
|
|
params += sizeof(int32_t);
|
|
} else if (syscall_nr == TARGET_FREEBSD_NR___syscall) {
|
|
get_user_s32(syscall_nr, params);
|
|
params += sizeof(int64_t);
|
|
}
|
|
get_user_s32(arg1, params);
|
|
params += sizeof(int32_t);
|
|
get_user_s32(arg2, params);
|
|
params += sizeof(int32_t);
|
|
get_user_s32(arg3, params);
|
|
params += sizeof(int32_t);
|
|
get_user_s32(arg4, params);
|
|
params += sizeof(int32_t);
|
|
get_user_s32(arg5, params);
|
|
params += sizeof(int32_t);
|
|
get_user_s32(arg6, params);
|
|
params += sizeof(int32_t);
|
|
get_user_s32(arg7, params);
|
|
params += sizeof(int32_t);
|
|
get_user_s32(arg8, params);
|
|
env->regs[R_EAX] = do_freebsd_syscall(env,
|
|
syscall_nr,
|
|
arg1,
|
|
arg2,
|
|
arg3,
|
|
arg4,
|
|
arg5,
|
|
arg6,
|
|
arg7,
|
|
arg8);
|
|
} else { /* if (bsd_type == target_openbsd) */
|
|
env->regs[R_EAX] = do_openbsd_syscall(env,
|
|
env->regs[R_EAX],
|
|
env->regs[R_EBX],
|
|
env->regs[R_ECX],
|
|
env->regs[R_EDX],
|
|
env->regs[R_ESI],
|
|
env->regs[R_EDI],
|
|
env->regs[R_EBP]);
|
|
}
|
|
if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
|
|
env->regs[R_EAX] = -env->regs[R_EAX];
|
|
env->eflags |= CC_C;
|
|
} else {
|
|
env->eflags &= ~CC_C;
|
|
}
|
|
break;
|
|
#ifndef TARGET_ABI32
|
|
case EXCP_SYSCALL:
|
|
/* syscall from syscall instruction */
|
|
if (bsd_type == target_freebsd) {
|
|
env->regs[R_EAX] = do_freebsd_syscall(env,
|
|
env->regs[R_EAX],
|
|
env->regs[R_EDI],
|
|
env->regs[R_ESI],
|
|
env->regs[R_EDX],
|
|
env->regs[R_ECX],
|
|
env->regs[8],
|
|
env->regs[9], 0, 0);
|
|
} else { /* if (bsd_type == target_openbsd) */
|
|
env->regs[R_EAX] = do_openbsd_syscall(env,
|
|
env->regs[R_EAX],
|
|
env->regs[R_EDI],
|
|
env->regs[R_ESI],
|
|
env->regs[R_EDX],
|
|
env->regs[10],
|
|
env->regs[8],
|
|
env->regs[9]);
|
|
}
|
|
env->eip = env->exception_next_eip;
|
|
if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
|
|
env->regs[R_EAX] = -env->regs[R_EAX];
|
|
env->eflags |= CC_C;
|
|
} else {
|
|
env->eflags &= ~CC_C;
|
|
}
|
|
break;
|
|
#endif
|
|
case EXCP_INTERRUPT:
|
|
/* just indicate that signals should be handled asap */
|
|
break;
|
|
default:
|
|
pc = env->segs[R_CS].base + env->eip;
|
|
fprintf(stderr,
|
|
"qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
|
|
(long)pc, trapnr);
|
|
abort();
|
|
}
|
|
process_pending_signals(env);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef TARGET_SPARC
|
|
#define SPARC64_STACK_BIAS 2047
|
|
|
|
/* #define DEBUG_WIN */
|
|
/*
|
|
* WARNING: dealing with register windows _is_ complicated. More info
|
|
* can be found at http://www.sics.se/~psm/sparcstack.html
|
|
*/
|
|
static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
|
|
{
|
|
index = (index + cwp * 16) % (16 * env->nwindows);
|
|
/*
|
|
* wrap handling : if cwp is on the last window, then we use the
|
|
* registers 'after' the end
|
|
*/
|
|
if (index < 8 && env->cwp == env->nwindows - 1) {
|
|
index += 16 * env->nwindows;
|
|
}
|
|
return index;
|
|
}
|
|
|
|
/* save the register window 'cwp1' */
|
|
static inline void save_window_offset(CPUSPARCState *env, int cwp1)
|
|
{
|
|
unsigned int i;
|
|
abi_ulong sp_ptr;
|
|
|
|
sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
|
|
#ifdef TARGET_SPARC64
|
|
if (sp_ptr & 3) {
|
|
sp_ptr += SPARC64_STACK_BIAS;
|
|
}
|
|
#endif
|
|
#if defined(DEBUG_WIN)
|
|
printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
|
|
sp_ptr, cwp1);
|
|
#endif
|
|
for (i = 0; i < 16; i++) {
|
|
/* FIXME - what to do if put_user() fails? */
|
|
put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
|
|
sp_ptr += sizeof(abi_ulong);
|
|
}
|
|
}
|
|
|
|
static void save_window(CPUSPARCState *env)
|
|
{
|
|
#ifndef TARGET_SPARC64
|
|
unsigned int new_wim;
|
|
new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) &
|
|
((1LL << env->nwindows) - 1);
|
|
save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
|
|
env->wim = new_wim;
|
|
#else
|
|
/*
|
|
* cansave is zero if the spill trap handler is triggered by `save` and
|
|
* nonzero if triggered by a `flushw`
|
|
*/
|
|
save_window_offset(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2));
|
|
env->cansave++;
|
|
env->canrestore--;
|
|
#endif
|
|
}
|
|
|
|
static void restore_window(CPUSPARCState *env)
|
|
{
|
|
#ifndef TARGET_SPARC64
|
|
unsigned int new_wim;
|
|
#endif
|
|
unsigned int i, cwp1;
|
|
abi_ulong sp_ptr;
|
|
|
|
#ifndef TARGET_SPARC64
|
|
new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) &
|
|
((1LL << env->nwindows) - 1);
|
|
#endif
|
|
|
|
/* restore the invalid window */
|
|
cwp1 = cpu_cwp_inc(env, env->cwp + 1);
|
|
sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
|
|
#ifdef TARGET_SPARC64
|
|
if (sp_ptr & 3) {
|
|
sp_ptr += SPARC64_STACK_BIAS;
|
|
}
|
|
#endif
|
|
#if defined(DEBUG_WIN)
|
|
printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
|
|
sp_ptr, cwp1);
|
|
#endif
|
|
for (i = 0; i < 16; i++) {
|
|
/* FIXME - what to do if get_user() fails? */
|
|
get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
|
|
sp_ptr += sizeof(abi_ulong);
|
|
}
|
|
#ifdef TARGET_SPARC64
|
|
env->canrestore++;
|
|
if (env->cleanwin < env->nwindows - 1) {
|
|
env->cleanwin++;
|
|
}
|
|
env->cansave--;
|
|
#else
|
|
env->wim = new_wim;
|
|
#endif
|
|
}
|
|
|
|
static void flush_windows(CPUSPARCState *env)
|
|
{
|
|
int offset, cwp1;
|
|
|
|
offset = 1;
|
|
for (;;) {
|
|
/* if restore would invoke restore_window(), then we can stop */
|
|
cwp1 = cpu_cwp_inc(env, env->cwp + offset);
|
|
#ifndef TARGET_SPARC64
|
|
if (env->wim & (1 << cwp1)) {
|
|
break;
|
|
}
|
|
#else
|
|
if (env->canrestore == 0) {
|
|
break;
|
|
}
|
|
env->cansave++;
|
|
env->canrestore--;
|
|
#endif
|
|
save_window_offset(env, cwp1);
|
|
offset++;
|
|
}
|
|
cwp1 = cpu_cwp_inc(env, env->cwp + 1);
|
|
#ifndef TARGET_SPARC64
|
|
/* set wim so that restore will reload the registers */
|
|
env->wim = 1 << cwp1;
|
|
#endif
|
|
#if defined(DEBUG_WIN)
|
|
printf("flush_windows: nb=%d\n", offset - 1);
|
|
#endif
|
|
}
|
|
|
|
void cpu_loop(CPUSPARCState *env)
|
|
{
|
|
CPUState *cs = env_cpu(env);
|
|
int trapnr, ret, syscall_nr;
|
|
/* target_siginfo_t info; */
|
|
|
|
while (1) {
|
|
cpu_exec_start(cs);
|
|
trapnr = cpu_exec(cs);
|
|
cpu_exec_end(cs);
|
|
process_queued_cpu_work(cs);
|
|
|
|
switch (trapnr) {
|
|
#ifndef TARGET_SPARC64
|
|
case 0x80:
|
|
#else
|
|
/* FreeBSD uses 0x141 for syscalls too */
|
|
case 0x141:
|
|
if (bsd_type != target_freebsd) {
|
|
goto badtrap;
|
|
}
|
|
/* fallthrough */
|
|
case 0x100:
|
|
#endif
|
|
syscall_nr = env->gregs[1];
|
|
if (bsd_type == target_freebsd)
|
|
ret = do_freebsd_syscall(env, syscall_nr,
|
|
env->regwptr[0], env->regwptr[1],
|
|
env->regwptr[2], env->regwptr[3],
|
|
env->regwptr[4], env->regwptr[5],
|
|
0, 0);
|
|
else if (bsd_type == target_netbsd)
|
|
ret = do_netbsd_syscall(env, syscall_nr,
|
|
env->regwptr[0], env->regwptr[1],
|
|
env->regwptr[2], env->regwptr[3],
|
|
env->regwptr[4], env->regwptr[5]);
|
|
else { /* if (bsd_type == target_openbsd) */
|
|
#if defined(TARGET_SPARC64)
|
|
syscall_nr &= ~(TARGET_OPENBSD_SYSCALL_G7RFLAG |
|
|
TARGET_OPENBSD_SYSCALL_G2RFLAG);
|
|
#endif
|
|
ret = do_openbsd_syscall(env, syscall_nr,
|
|
env->regwptr[0], env->regwptr[1],
|
|
env->regwptr[2], env->regwptr[3],
|
|
env->regwptr[4], env->regwptr[5]);
|
|
}
|
|
if ((unsigned int)ret >= (unsigned int)(-515)) {
|
|
ret = -ret;
|
|
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
|
|
env->xcc |= PSR_CARRY;
|
|
#else
|
|
env->psr |= PSR_CARRY;
|
|
#endif
|
|
} else {
|
|
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
|
|
env->xcc &= ~PSR_CARRY;
|
|
#else
|
|
env->psr &= ~PSR_CARRY;
|
|
#endif
|
|
}
|
|
env->regwptr[0] = ret;
|
|
/* next instruction */
|
|
#if defined(TARGET_SPARC64)
|
|
if (bsd_type == target_openbsd &&
|
|
env->gregs[1] & TARGET_OPENBSD_SYSCALL_G2RFLAG) {
|
|
env->pc = env->gregs[2];
|
|
env->npc = env->pc + 4;
|
|
} else if (bsd_type == target_openbsd &&
|
|
env->gregs[1] & TARGET_OPENBSD_SYSCALL_G7RFLAG) {
|
|
env->pc = env->gregs[7];
|
|
env->npc = env->pc + 4;
|
|
} else {
|
|
env->pc = env->npc;
|
|
env->npc = env->npc + 4;
|
|
}
|
|
#else
|
|
env->pc = env->npc;
|
|
env->npc = env->npc + 4;
|
|
#endif
|
|
break;
|
|
case 0x83: /* flush windows */
|
|
#ifdef TARGET_ABI32
|
|
case 0x103:
|
|
#endif
|
|
flush_windows(env);
|
|
/* next instruction */
|
|
env->pc = env->npc;
|
|
env->npc = env->npc + 4;
|
|
break;
|
|
#ifndef TARGET_SPARC64
|
|
case TT_WIN_OVF: /* window overflow */
|
|
save_window(env);
|
|
break;
|
|
case TT_WIN_UNF: /* window underflow */
|
|
restore_window(env);
|
|
break;
|
|
case TT_TFAULT:
|
|
case TT_DFAULT:
|
|
break;
|
|
#else
|
|
case TT_SPILL: /* window overflow */
|
|
save_window(env);
|
|
break;
|
|
case TT_FILL: /* window underflow */
|
|
restore_window(env);
|
|
break;
|
|
case TT_TFAULT:
|
|
case TT_DFAULT:
|
|
break;
|
|
#endif
|
|
case EXCP_INTERRUPT:
|
|
/* just indicate that signals should be handled asap */
|
|
break;
|
|
case EXCP_DEBUG:
|
|
{
|
|
gdb_handlesig(cs, TARGET_SIGTRAP);
|
|
}
|
|
break;
|
|
default:
|
|
#ifdef TARGET_SPARC64
|
|
badtrap:
|
|
#endif
|
|
printf("Unhandled trap: 0x%x\n", trapnr);
|
|
cpu_dump_state(cs, stderr, 0);
|
|
exit(1);
|
|
}
|
|
process_pending_signals(env);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
static void usage(void)
|
|
{
|
|
printf("qemu-" TARGET_NAME " version " QEMU_FULL_VERSION
|
|
"\n" QEMU_COPYRIGHT "\n"
|
|
"usage: qemu-" TARGET_NAME " [options] program [arguments...]\n"
|
|
"BSD CPU emulator (compiled for %s emulation)\n"
|
|
"\n"
|
|
"Standard options:\n"
|
|
"-h print this help\n"
|
|
"-g port wait gdb connection to port\n"
|
|
"-L path set the elf interpreter prefix (default=%s)\n"
|
|
"-s size set the stack size in bytes (default=%ld)\n"
|
|
"-cpu model select CPU (-cpu help for list)\n"
|
|
"-drop-ld-preload drop LD_PRELOAD for target process\n"
|
|
"-E var=value sets/modifies targets environment variable(s)\n"
|
|
"-U var unsets targets environment variable(s)\n"
|
|
"-B address set guest_base address to address\n"
|
|
"-bsd type select emulated BSD type FreeBSD/NetBSD/OpenBSD (default)\n"
|
|
"\n"
|
|
"Debug options:\n"
|
|
"-d item1[,...] enable logging of specified items\n"
|
|
" (use '-d help' for a list of log items)\n"
|
|
"-D logfile write logs to 'logfile' (default stderr)\n"
|
|
"-p pagesize set the host page size to 'pagesize'\n"
|
|
"-singlestep always run in singlestep mode\n"
|
|
"-strace log system calls\n"
|
|
"-trace [[enable=]<pattern>][,events=<file>][,file=<file>]\n"
|
|
" specify tracing options\n"
|
|
"\n"
|
|
"Environment variables:\n"
|
|
"QEMU_STRACE Print system calls and arguments similar to the\n"
|
|
" 'strace' program. Enable by setting to any value.\n"
|
|
"You can use -E and -U options to set/unset environment variables\n"
|
|
"for target process. It is possible to provide several variables\n"
|
|
"by repeating the option. For example:\n"
|
|
" -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
|
|
"Note that if you provide several changes to single variable\n"
|
|
"last change will stay in effect.\n"
|
|
"\n"
|
|
QEMU_HELP_BOTTOM "\n"
|
|
,
|
|
TARGET_NAME,
|
|
interp_prefix,
|
|
x86_stack_size);
|
|
exit(1);
|
|
}
|
|
|
|
THREAD CPUState *thread_cpu;
|
|
|
|
bool qemu_cpu_is_self(CPUState *cpu)
|
|
{
|
|
return thread_cpu == cpu;
|
|
}
|
|
|
|
void qemu_cpu_kick(CPUState *cpu)
|
|
{
|
|
cpu_exit(cpu);
|
|
}
|
|
|
|
/* Assumes contents are already zeroed. */
|
|
void init_task_state(TaskState *ts)
|
|
{
|
|
int i;
|
|
|
|
ts->used = 1;
|
|
ts->first_free = ts->sigqueue_table;
|
|
for (i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) {
|
|
ts->sigqueue_table[i].next = &ts->sigqueue_table[i + 1];
|
|
}
|
|
ts->sigqueue_table[i].next = NULL;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
const char *filename;
|
|
const char *cpu_model;
|
|
const char *cpu_type;
|
|
const char *log_file = NULL;
|
|
const char *log_mask = NULL;
|
|
struct target_pt_regs regs1, *regs = ®s1;
|
|
struct image_info info1, *info = &info1;
|
|
TaskState ts1, *ts = &ts1;
|
|
CPUArchState *env;
|
|
CPUState *cpu;
|
|
int optind, rv;
|
|
const char *r;
|
|
const char *gdbstub = NULL;
|
|
char **target_environ, **wrk;
|
|
envlist_t *envlist = NULL;
|
|
bsd_type = target_openbsd;
|
|
|
|
if (argc <= 1) {
|
|
usage();
|
|
}
|
|
|
|
error_init(argv[0]);
|
|
module_call_init(MODULE_INIT_TRACE);
|
|
qemu_init_cpu_list();
|
|
module_call_init(MODULE_INIT_QOM);
|
|
|
|
envlist = envlist_create();
|
|
|
|
/* add current environment into the list */
|
|
for (wrk = environ; *wrk != NULL; wrk++) {
|
|
(void) envlist_setenv(envlist, *wrk);
|
|
}
|
|
|
|
cpu_model = NULL;
|
|
|
|
qemu_add_opts(&qemu_trace_opts);
|
|
|
|
optind = 1;
|
|
for (;;) {
|
|
if (optind >= argc) {
|
|
break;
|
|
}
|
|
r = argv[optind];
|
|
if (r[0] != '-') {
|
|
break;
|
|
}
|
|
optind++;
|
|
r++;
|
|
if (!strcmp(r, "-")) {
|
|
break;
|
|
} else if (!strcmp(r, "d")) {
|
|
if (optind >= argc) {
|
|
break;
|
|
}
|
|
log_mask = argv[optind++];
|
|
} else if (!strcmp(r, "D")) {
|
|
if (optind >= argc) {
|
|
break;
|
|
}
|
|
log_file = argv[optind++];
|
|
} else if (!strcmp(r, "E")) {
|
|
r = argv[optind++];
|
|
if (envlist_setenv(envlist, r) != 0) {
|
|
usage();
|
|
}
|
|
} else if (!strcmp(r, "ignore-environment")) {
|
|
envlist_free(envlist);
|
|
envlist = envlist_create();
|
|
} else if (!strcmp(r, "U")) {
|
|
r = argv[optind++];
|
|
if (envlist_unsetenv(envlist, r) != 0) {
|
|
usage();
|
|
}
|
|
} else if (!strcmp(r, "s")) {
|
|
r = argv[optind++];
|
|
rv = qemu_strtoul(r, &r, 0, &x86_stack_size);
|
|
if (rv < 0 || x86_stack_size <= 0) {
|
|
usage();
|
|
}
|
|
if (*r == 'M') {
|
|
x86_stack_size *= MiB;
|
|
} else if (*r == 'k' || *r == 'K') {
|
|
x86_stack_size *= KiB;
|
|
}
|
|
} else if (!strcmp(r, "L")) {
|
|
interp_prefix = argv[optind++];
|
|
} else if (!strcmp(r, "p")) {
|
|
qemu_host_page_size = atoi(argv[optind++]);
|
|
if (qemu_host_page_size == 0 ||
|
|
(qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
|
|
fprintf(stderr, "page size must be a power of two\n");
|
|
exit(1);
|
|
}
|
|
} else if (!strcmp(r, "g")) {
|
|
gdbstub = g_strdup(argv[optind++]);
|
|
} else if (!strcmp(r, "r")) {
|
|
qemu_uname_release = argv[optind++];
|
|
} else if (!strcmp(r, "cpu")) {
|
|
cpu_model = argv[optind++];
|
|
if (is_help_option(cpu_model)) {
|
|
/* XXX: implement xxx_cpu_list for targets that still miss it */
|
|
#if defined(cpu_list)
|
|
cpu_list();
|
|
#endif
|
|
exit(1);
|
|
}
|
|
} else if (!strcmp(r, "B")) {
|
|
rv = qemu_strtoul(argv[optind++], NULL, 0, &guest_base);
|
|
if (rv < 0) {
|
|
usage();
|
|
}
|
|
have_guest_base = true;
|
|
} else if (!strcmp(r, "drop-ld-preload")) {
|
|
(void) envlist_unsetenv(envlist, "LD_PRELOAD");
|
|
} else if (!strcmp(r, "bsd")) {
|
|
if (!strcasecmp(argv[optind], "freebsd")) {
|
|
bsd_type = target_freebsd;
|
|
} else if (!strcasecmp(argv[optind], "netbsd")) {
|
|
bsd_type = target_netbsd;
|
|
} else if (!strcasecmp(argv[optind], "openbsd")) {
|
|
bsd_type = target_openbsd;
|
|
} else {
|
|
usage();
|
|
}
|
|
optind++;
|
|
} else if (!strcmp(r, "singlestep")) {
|
|
singlestep = 1;
|
|
} else if (!strcmp(r, "strace")) {
|
|
do_strace = 1;
|
|
} else if (!strcmp(r, "trace")) {
|
|
trace_opt_parse(optarg);
|
|
} else {
|
|
usage();
|
|
}
|
|
}
|
|
|
|
/* init debug */
|
|
qemu_log_needs_buffers();
|
|
qemu_set_log_filename(log_file, &error_fatal);
|
|
if (log_mask) {
|
|
int mask;
|
|
|
|
mask = qemu_str_to_log_mask(log_mask);
|
|
if (!mask) {
|
|
qemu_print_log_usage(stdout);
|
|
exit(1);
|
|
}
|
|
qemu_set_log(mask);
|
|
}
|
|
|
|
if (optind >= argc) {
|
|
usage();
|
|
}
|
|
filename = argv[optind];
|
|
|
|
if (!trace_init_backends()) {
|
|
exit(1);
|
|
}
|
|
trace_init_file();
|
|
|
|
/* Zero out regs */
|
|
memset(regs, 0, sizeof(struct target_pt_regs));
|
|
|
|
/* Zero out image_info */
|
|
memset(info, 0, sizeof(struct image_info));
|
|
|
|
/* Scan interp_prefix dir for replacement files. */
|
|
init_paths(interp_prefix);
|
|
|
|
if (cpu_model == NULL) {
|
|
#if defined(TARGET_I386)
|
|
#ifdef TARGET_X86_64
|
|
cpu_model = "qemu64";
|
|
#else
|
|
cpu_model = "qemu32";
|
|
#endif
|
|
#elif defined(TARGET_SPARC)
|
|
#ifdef TARGET_SPARC64
|
|
cpu_model = "TI UltraSparc II";
|
|
#else
|
|
cpu_model = "Fujitsu MB86904";
|
|
#endif
|
|
#else
|
|
cpu_model = "any";
|
|
#endif
|
|
}
|
|
|
|
cpu_type = parse_cpu_option(cpu_model);
|
|
/* init tcg before creating CPUs and to get qemu_host_page_size */
|
|
{
|
|
AccelClass *ac = ACCEL_GET_CLASS(current_accel());
|
|
|
|
accel_init_interfaces(ac);
|
|
ac->init_machine(NULL);
|
|
}
|
|
cpu = cpu_create(cpu_type);
|
|
env = cpu->env_ptr;
|
|
#if defined(TARGET_SPARC) || defined(TARGET_PPC)
|
|
cpu_reset(cpu);
|
|
#endif
|
|
thread_cpu = cpu;
|
|
|
|
if (getenv("QEMU_STRACE")) {
|
|
do_strace = 1;
|
|
}
|
|
|
|
target_environ = envlist_to_environ(envlist, NULL);
|
|
envlist_free(envlist);
|
|
|
|
/*
|
|
* Now that page sizes are configured in tcg_exec_init() we can do
|
|
* proper page alignment for guest_base.
|
|
*/
|
|
guest_base = HOST_PAGE_ALIGN(guest_base);
|
|
|
|
/*
|
|
* Read in mmap_min_addr kernel parameter. This value is used
|
|
* When loading the ELF image to determine whether guest_base
|
|
* is needed.
|
|
*
|
|
* When user has explicitly set the quest base, we skip this
|
|
* test.
|
|
*/
|
|
if (!have_guest_base) {
|
|
FILE *fp;
|
|
|
|
fp = fopen("/proc/sys/vm/mmap_min_addr", "r");
|
|
if (fp != NULL) {
|
|
unsigned long tmp;
|
|
if (fscanf(fp, "%lu", &tmp) == 1) {
|
|
mmap_min_addr = tmp;
|
|
qemu_log_mask(CPU_LOG_PAGE, "host mmap_min_addr=0x%lx\n",
|
|
mmap_min_addr);
|
|
}
|
|
fclose(fp);
|
|
}
|
|
}
|
|
|
|
if (loader_exec(filename, argv + optind, target_environ, regs, info) != 0) {
|
|
printf("Error loading %s\n", filename);
|
|
_exit(1);
|
|
}
|
|
|
|
for (wrk = target_environ; *wrk; wrk++) {
|
|
g_free(*wrk);
|
|
}
|
|
|
|
g_free(target_environ);
|
|
|
|
if (qemu_loglevel_mask(CPU_LOG_PAGE)) {
|
|
qemu_log("guest_base %p\n", (void *)guest_base);
|
|
log_page_dump("binary load");
|
|
|
|
qemu_log("start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
|
|
qemu_log("end_code 0x" TARGET_ABI_FMT_lx "\n", info->end_code);
|
|
qemu_log("start_code 0x" TARGET_ABI_FMT_lx "\n",
|
|
info->start_code);
|
|
qemu_log("start_data 0x" TARGET_ABI_FMT_lx "\n",
|
|
info->start_data);
|
|
qemu_log("end_data 0x" TARGET_ABI_FMT_lx "\n", info->end_data);
|
|
qemu_log("start_stack 0x" TARGET_ABI_FMT_lx "\n",
|
|
info->start_stack);
|
|
qemu_log("brk 0x" TARGET_ABI_FMT_lx "\n", info->brk);
|
|
qemu_log("entry 0x" TARGET_ABI_FMT_lx "\n", info->entry);
|
|
}
|
|
|
|
target_set_brk(info->brk);
|
|
syscall_init();
|
|
signal_init();
|
|
|
|
/*
|
|
* Now that we've loaded the binary, GUEST_BASE is fixed. Delay
|
|
* generating the prologue until now so that the prologue can take
|
|
* the real value of GUEST_BASE into account.
|
|
*/
|
|
tcg_prologue_init(tcg_ctx);
|
|
tcg_region_init();
|
|
|
|
/* build Task State */
|
|
memset(ts, 0, sizeof(TaskState));
|
|
init_task_state(ts);
|
|
ts->info = info;
|
|
cpu->opaque = ts;
|
|
|
|
#if defined(TARGET_I386)
|
|
env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
|
|
env->hflags |= HF_PE_MASK | HF_CPL_MASK;
|
|
if (env->features[FEAT_1_EDX] & CPUID_SSE) {
|
|
env->cr[4] |= CR4_OSFXSR_MASK;
|
|
env->hflags |= HF_OSFXSR_MASK;
|
|
}
|
|
#ifndef TARGET_ABI32
|
|
/* enable 64 bit mode if possible */
|
|
if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) {
|
|
fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
|
|
exit(1);
|
|
}
|
|
env->cr[4] |= CR4_PAE_MASK;
|
|
env->efer |= MSR_EFER_LMA | MSR_EFER_LME;
|
|
env->hflags |= HF_LMA_MASK;
|
|
#endif
|
|
|
|
/* flags setup : we activate the IRQs by default as in user mode */
|
|
env->eflags |= IF_MASK;
|
|
|
|
/* linux register setup */
|
|
#ifndef TARGET_ABI32
|
|
env->regs[R_EAX] = regs->rax;
|
|
env->regs[R_EBX] = regs->rbx;
|
|
env->regs[R_ECX] = regs->rcx;
|
|
env->regs[R_EDX] = regs->rdx;
|
|
env->regs[R_ESI] = regs->rsi;
|
|
env->regs[R_EDI] = regs->rdi;
|
|
env->regs[R_EBP] = regs->rbp;
|
|
env->regs[R_ESP] = regs->rsp;
|
|
env->eip = regs->rip;
|
|
#else
|
|
env->regs[R_EAX] = regs->eax;
|
|
env->regs[R_EBX] = regs->ebx;
|
|
env->regs[R_ECX] = regs->ecx;
|
|
env->regs[R_EDX] = regs->edx;
|
|
env->regs[R_ESI] = regs->esi;
|
|
env->regs[R_EDI] = regs->edi;
|
|
env->regs[R_EBP] = regs->ebp;
|
|
env->regs[R_ESP] = regs->esp;
|
|
env->eip = regs->eip;
|
|
#endif
|
|
|
|
/* linux interrupt setup */
|
|
#ifndef TARGET_ABI32
|
|
env->idt.limit = 511;
|
|
#else
|
|
env->idt.limit = 255;
|
|
#endif
|
|
env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
|
|
PROT_READ | PROT_WRITE,
|
|
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
|
idt_table = g2h_untagged(env->idt.base);
|
|
set_idt(0, 0);
|
|
set_idt(1, 0);
|
|
set_idt(2, 0);
|
|
set_idt(3, 3);
|
|
set_idt(4, 3);
|
|
set_idt(5, 0);
|
|
set_idt(6, 0);
|
|
set_idt(7, 0);
|
|
set_idt(8, 0);
|
|
set_idt(9, 0);
|
|
set_idt(10, 0);
|
|
set_idt(11, 0);
|
|
set_idt(12, 0);
|
|
set_idt(13, 0);
|
|
set_idt(14, 0);
|
|
set_idt(15, 0);
|
|
set_idt(16, 0);
|
|
set_idt(17, 0);
|
|
set_idt(18, 0);
|
|
set_idt(19, 0);
|
|
set_idt(0x80, 3);
|
|
|
|
/* linux segment setup */
|
|
{
|
|
uint64_t *gdt_table;
|
|
env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
|
|
PROT_READ | PROT_WRITE,
|
|
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
|
env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
|
|
gdt_table = g2h_untagged(env->gdt.base);
|
|
#ifdef TARGET_ABI32
|
|
write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
|
|
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
|
|
(3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
|
|
#else
|
|
/* 64 bit code segment */
|
|
write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
|
|
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
|
|
DESC_L_MASK |
|
|
(3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
|
|
#endif
|
|
write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
|
|
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
|
|
(3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
|
|
}
|
|
|
|
cpu_x86_load_seg(env, R_CS, __USER_CS);
|
|
cpu_x86_load_seg(env, R_SS, __USER_DS);
|
|
#ifdef TARGET_ABI32
|
|
cpu_x86_load_seg(env, R_DS, __USER_DS);
|
|
cpu_x86_load_seg(env, R_ES, __USER_DS);
|
|
cpu_x86_load_seg(env, R_FS, __USER_DS);
|
|
cpu_x86_load_seg(env, R_GS, __USER_DS);
|
|
/* This hack makes Wine work... */
|
|
env->segs[R_FS].selector = 0;
|
|
#else
|
|
cpu_x86_load_seg(env, R_DS, 0);
|
|
cpu_x86_load_seg(env, R_ES, 0);
|
|
cpu_x86_load_seg(env, R_FS, 0);
|
|
cpu_x86_load_seg(env, R_GS, 0);
|
|
#endif
|
|
#elif defined(TARGET_SPARC)
|
|
{
|
|
int i;
|
|
env->pc = regs->pc;
|
|
env->npc = regs->npc;
|
|
env->y = regs->y;
|
|
for (i = 0; i < 8; i++) {
|
|
env->gregs[i] = regs->u_regs[i];
|
|
}
|
|
for (i = 0; i < 8; i++) {
|
|
env->regwptr[i] = regs->u_regs[i + 8];
|
|
}
|
|
}
|
|
#else
|
|
#error unsupported target CPU
|
|
#endif
|
|
|
|
if (gdbstub) {
|
|
gdbserver_start(gdbstub);
|
|
gdb_handlesig(cpu, 0);
|
|
}
|
|
cpu_loop(env);
|
|
/* never exits */
|
|
return 0;
|
|
}
|