sim-card
/
qemu
Archived
10
0
Fork 0

Merge remote-tracking branch 'riku/linux-user-for-upstream' into staging

This commit is contained in:
Anthony Liguori 2011-09-26 07:59:13 -05:00
commit 11ddeea91a
4 changed files with 579 additions and 220 deletions

View File

@ -332,6 +332,49 @@ enum
ARM_HWCAP_ARM_VFPv3D16 = 1 << 13,
};
#define TARGET_HAS_GUEST_VALIDATE_BASE
/* We want the opportunity to check the suggested base */
bool guest_validate_base(unsigned long guest_base)
{
unsigned long real_start, test_page_addr;
/* We need to check that we can force a fault on access to the
* commpage at 0xffff0fxx
*/
test_page_addr = guest_base + (0xffff0f00 & qemu_host_page_mask);
/* Note it needs to be writeable to let us initialise it */
real_start = (unsigned long)
mmap((void *)test_page_addr, qemu_host_page_size,
PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
/* If we can't map it then try another address */
if (real_start == -1ul) {
return 0;
}
if (real_start != test_page_addr) {
/* OS didn't put the page where we asked - unmap and reject */
munmap((void *)real_start, qemu_host_page_size);
return 0;
}
/* Leave the page mapped
* Populate it (mmap should have left it all 0'd)
*/
/* Kernel helper versions */
__put_user(5, (uint32_t *)g2h(0xffff0ffcul));
/* Now it's populated make it RO */
if (mprotect((void *)test_page_addr, qemu_host_page_size, PROT_READ)) {
perror("Protecting guest commpage");
exit(-1);
}
return 1; /* All good */
}
#define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF \
| ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT \
| ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP \
@ -1309,6 +1352,14 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
return sp;
}
#ifndef TARGET_HAS_GUEST_VALIDATE_BASE
/* If the guest doesn't have a validation function just agree */
bool guest_validate_base(unsigned long guest_base)
{
return 1;
}
#endif
static void probe_guest_base(const char *image_name,
abi_ulong loaddr, abi_ulong hiaddr)
{
@ -1345,7 +1396,9 @@ static void probe_guest_base(const char *image_name,
if (real_start == (unsigned long)-1) {
goto exit_perror;
}
if (real_start == host_start) {
guest_base = real_start - loaddr;
if ((real_start == host_start) &&
guest_validate_base(guest_base)) {
break;
}
/* That address didn't work. Unmap and try a different one.
@ -1368,7 +1421,6 @@ static void probe_guest_base(const char *image_name,
qemu_log("Relocating guest address space from 0x"
TARGET_ABI_FMT_lx " to 0x%lx\n",
loaddr, real_start);
guest_base = real_start - loaddr;
}
return;

View File

@ -39,6 +39,11 @@
char *exec_path;
int singlestep;
const char *filename;
const char *argv0;
int gdbstub_port;
envlist_t *envlist;
const char *cpu_model;
unsigned long mmap_min_addr;
#if defined(CONFIG_USE_GUEST_BASE)
unsigned long guest_base;
@ -46,6 +51,8 @@ int have_guest_base;
unsigned long reserved_va;
#endif
static void usage(void);
static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
@ -456,6 +463,83 @@ void cpu_loop(CPUX86State *env)
#ifdef TARGET_ARM
/*
* See the Linux kernel's Documentation/arm/kernel_user_helpers.txt
* Input:
* r0 = pointer to oldval
* r1 = pointer to newval
* r2 = pointer to target value
*
* Output:
* r0 = 0 if *ptr was changed, non-0 if no exchange happened
* C set if *ptr was changed, clear if no exchange happened
*
* Note segv's in kernel helpers are a bit tricky, we can set the
* data address sensibly but the PC address is just the entry point.
*/
static void arm_kernel_cmpxchg64_helper(CPUARMState *env)
{
uint64_t oldval, newval, val;
uint32_t addr, cpsr;
target_siginfo_t info;
/* Based on the 32 bit code in do_kernel_trap */
/* XXX: This only works between threads, not between processes.
It's probably possible to implement this with native host
operations. However things like ldrex/strex are much harder so
there's not much point trying. */
start_exclusive();
cpsr = cpsr_read(env);
addr = env->regs[2];
if (get_user_u64(oldval, env->regs[0])) {
env->cp15.c6_data = env->regs[0];
goto segv;
};
if (get_user_u64(newval, env->regs[1])) {
env->cp15.c6_data = env->regs[1];
goto segv;
};
if (get_user_u64(val, addr)) {
env->cp15.c6_data = addr;
goto segv;
}
if (val == oldval) {
val = newval;
if (put_user_u64(val, addr)) {
env->cp15.c6_data = addr;
goto segv;
};
env->regs[0] = 0;
cpsr |= CPSR_C;
} else {
env->regs[0] = -1;
cpsr &= ~CPSR_C;
}
cpsr_write(env, cpsr, CPSR_C);
end_exclusive();
return;
segv:
end_exclusive();
/* We get the PC of the entry address - which is as good as anything,
on a real kernel what you get depends on which mode it uses. */
info.si_signo = SIGSEGV;
info.si_errno = 0;
/* XXX: check env->error_code */
info.si_code = TARGET_SEGV_MAPERR;
info._sifields._sigfault._addr = env->cp15.c6_data;
queue_signal(env, info.si_signo, &info);
end_exclusive();
}
/* Handle a jump to the kernel code page. */
static int
do_kernel_trap(CPUARMState *env)
@ -495,6 +579,10 @@ do_kernel_trap(CPUARMState *env)
case 0xffff0fe0: /* __kernel_get_tls */
env->regs[0] = env->cp15.c13_tls2;
break;
case 0xffff0f60: /* __kernel_cmpxchg64 */
arm_kernel_cmpxchg64_helper(env);
break;
default:
return 1;
}
@ -752,7 +840,6 @@ void cpu_loop(CPUARMState *env)
goto do_segv;
case EXCP_DATA_ABORT:
addr = env->cp15.c6_data;
goto do_segv;
do_segv:
{
info.si_signo = SIGSEGV;
@ -1669,7 +1756,7 @@ void cpu_loop(CPUPPCState *env)
#define MIPS_SYS(name, args) args,
static const uint8_t mips_syscall_args[] = {
MIPS_SYS(sys_syscall , 0) /* 4000 */
MIPS_SYS(sys_syscall , 8) /* 4000 */
MIPS_SYS(sys_exit , 1)
MIPS_SYS(sys_fork , 0)
MIPS_SYS(sys_read , 3)
@ -2090,11 +2177,22 @@ void cpu_loop(CPUMIPSState *env)
sp_reg = env->active_tc.gpr[29];
switch (nb_args) {
/* these arguments are taken from the stack */
/* FIXME - what to do if get_user() fails? */
case 8: get_user_ual(arg8, sp_reg + 28);
case 7: get_user_ual(arg7, sp_reg + 24);
case 6: get_user_ual(arg6, sp_reg + 20);
case 5: get_user_ual(arg5, sp_reg + 16);
case 8:
if ((ret = get_user_ual(arg8, sp_reg + 28)) != 0) {
goto done_syscall;
}
case 7:
if ((ret = get_user_ual(arg7, sp_reg + 24)) != 0) {
goto done_syscall;
}
case 6:
if ((ret = get_user_ual(arg6, sp_reg + 20)) != 0) {
goto done_syscall;
}
case 5:
if ((ret = get_user_ual(arg5, sp_reg + 16)) != 0) {
goto done_syscall;
}
default:
break;
}
@ -2105,6 +2203,7 @@ void cpu_loop(CPUMIPSState *env)
env->active_tc.gpr[7],
arg5, arg6, arg7, arg8);
}
done_syscall:
if (ret == -TARGET_QEMU_ESIGRETURN) {
/* Returning from a successful sigreturn syscall.
Avoid clobbering register state. */
@ -2787,57 +2886,6 @@ void cpu_loop(CPUS390XState *env)
#endif /* TARGET_S390X */
static void version(void)
{
printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION
", Copyright (c) 2003-2008 Fabrice Bellard\n");
}
static void usage(void)
{
version();
printf("usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n"
"Linux CPU emulator (compiled for %s emulation)\n"
"\n"
"Standard options:\n"
"-h print this help\n"
"-version display version information and exit\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 ? 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"
"-0 argv0 forces target process argv[0] to be argv0\n"
#if defined(CONFIG_USE_GUEST_BASE)
"-B address set guest_base address to address\n"
"-R size reserve size bytes for guest virtual address space\n"
#endif
"\n"
"Debug options:\n"
"-d options activate log (logfile=%s)\n"
"-p pagesize set the host page size to 'pagesize'\n"
"-singlestep always run in singlestep mode\n"
"-strace log system calls\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"
,
TARGET_ARCH,
interp_prefix,
guest_stack_size,
DEBUG_LOGFILE);
exit(1);
}
THREAD CPUState *thread_env;
void task_settid(TaskState *ts)
@ -2873,26 +2921,358 @@ void init_task_state(TaskState *ts)
}
ts->sigqueue_table[i].next = NULL;
}
static void handle_arg_help(const char *arg)
{
usage();
}
static void handle_arg_log(const char *arg)
{
int mask;
const CPULogItem *item;
mask = cpu_str_to_log_mask(arg);
if (!mask) {
printf("Log items (comma separated):\n");
for (item = cpu_log_items; item->mask != 0; item++) {
printf("%-10s %s\n", item->name, item->help);
}
exit(1);
}
cpu_set_log(mask);
}
static void handle_arg_set_env(const char *arg)
{
char *r, *p, *token;
r = p = strdup(arg);
while ((token = strsep(&p, ",")) != NULL) {
if (envlist_setenv(envlist, token) != 0) {
usage();
}
}
free(r);
}
static void handle_arg_unset_env(const char *arg)
{
char *r, *p, *token;
r = p = strdup(arg);
while ((token = strsep(&p, ",")) != NULL) {
if (envlist_unsetenv(envlist, token) != 0) {
usage();
}
}
free(r);
}
static void handle_arg_argv0(const char *arg)
{
argv0 = strdup(arg);
}
static void handle_arg_stack_size(const char *arg)
{
char *p;
guest_stack_size = strtoul(arg, &p, 0);
if (guest_stack_size == 0) {
usage();
}
if (*p == 'M') {
guest_stack_size *= 1024 * 1024;
} else if (*p == 'k' || *p == 'K') {
guest_stack_size *= 1024;
}
}
static void handle_arg_ld_prefix(const char *arg)
{
interp_prefix = strdup(arg);
}
static void handle_arg_pagesize(const char *arg)
{
qemu_host_page_size = atoi(arg);
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);
}
}
static void handle_arg_gdb(const char *arg)
{
gdbstub_port = atoi(arg);
}
static void handle_arg_uname(const char *arg)
{
qemu_uname_release = strdup(arg);
}
static void handle_arg_cpu(const char *arg)
{
cpu_model = strdup(arg);
if (cpu_model == NULL || strcmp(cpu_model, "?") == 0) {
/* XXX: implement xxx_cpu_list for targets that still miss it */
#if defined(cpu_list_id)
cpu_list_id(stdout, &fprintf, "");
#elif defined(cpu_list)
cpu_list(stdout, &fprintf); /* deprecated */
#endif
exit(1);
}
}
#if defined(CONFIG_USE_GUEST_BASE)
static void handle_arg_guest_base(const char *arg)
{
guest_base = strtol(arg, NULL, 0);
have_guest_base = 1;
}
static void handle_arg_reserved_va(const char *arg)
{
char *p;
int shift = 0;
reserved_va = strtoul(arg, &p, 0);
switch (*p) {
case 'k':
case 'K':
shift = 10;
break;
case 'M':
shift = 20;
break;
case 'G':
shift = 30;
break;
}
if (shift) {
unsigned long unshifted = reserved_va;
p++;
reserved_va <<= shift;
if (((reserved_va >> shift) != unshifted)
#if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
|| (reserved_va > (1ul << TARGET_VIRT_ADDR_SPACE_BITS))
#endif
) {
fprintf(stderr, "Reserved virtual address too big\n");
exit(1);
}
}
if (*p) {
fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p);
exit(1);
}
}
#endif
static void handle_arg_singlestep(const char *arg)
{
singlestep = 1;
}
static void handle_arg_strace(const char *arg)
{
do_strace = 1;
}
static void handle_arg_version(const char *arg)
{
printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION
", Copyright (c) 2003-2008 Fabrice Bellard\n");
}
struct qemu_argument {
const char *argv;
const char *env;
bool has_arg;
void (*handle_opt)(const char *arg);
const char *example;
const char *help;
};
struct qemu_argument arg_table[] = {
{"h", "", false, handle_arg_help,
"", "print this help"},
{"g", "QEMU_GDB", true, handle_arg_gdb,
"port", "wait gdb connection to 'port'"},
{"L", "QEMU_LD_PREFIX", true, handle_arg_ld_prefix,
"path", "set the elf interpreter prefix to 'path'"},
{"s", "QEMU_STACK_SIZE", true, handle_arg_stack_size,
"size", "set the stack size to 'size' bytes"},
{"cpu", "QEMU_CPU", true, handle_arg_cpu,
"model", "select CPU (-cpu ? for list)"},
{"E", "QEMU_SET_ENV", true, handle_arg_set_env,
"var=value", "sets targets environment variable (see below)"},
{"U", "QEMU_UNSET_ENV", true, handle_arg_unset_env,
"var", "unsets targets environment variable (see below)"},
{"0", "QEMU_ARGV0", true, handle_arg_argv0,
"argv0", "forces target process argv[0] to be 'argv0'"},
{"r", "QEMU_UNAME", true, handle_arg_uname,
"uname", "set qemu uname release string to 'uname'"},
#if defined(CONFIG_USE_GUEST_BASE)
{"B", "QEMU_GUEST_BASE", true, handle_arg_guest_base,
"address", "set guest_base address to 'address'"},
{"R", "QEMU_RESERVED_VA", true, handle_arg_reserved_va,
"size", "reserve 'size' bytes for guest virtual address space"},
#endif
{"d", "QEMU_LOG", true, handle_arg_log,
"options", "activate log"},
{"p", "QEMU_PAGESIZE", true, handle_arg_pagesize,
"pagesize", "set the host page size to 'pagesize'"},
{"singlestep", "QEMU_SINGLESTEP", false, handle_arg_singlestep,
"", "run in singlestep mode"},
{"strace", "QEMU_STRACE", false, handle_arg_strace,
"", "log system calls"},
{"version", "QEMU_VERSION", false, handle_arg_version,
"", "log system calls"},
{NULL, NULL, false, NULL, NULL, NULL}
};
static void usage(void)
{
struct qemu_argument *arginfo;
int maxarglen;
int maxenvlen;
printf("usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n"
"Linux CPU emulator (compiled for " TARGET_ARCH " emulation)\n"
"\n"
"Options and associated environment variables:\n"
"\n");
maxarglen = maxenvlen = 0;
for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
if (strlen(arginfo->env) > maxenvlen) {
maxenvlen = strlen(arginfo->env);
}
if (strlen(arginfo->argv) > maxarglen) {
maxarglen = strlen(arginfo->argv);
}
}
printf("%-*s%-*sDescription\n", maxarglen+3, "Argument",
maxenvlen+1, "Env-variable");
for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
if (arginfo->has_arg) {
printf("-%s %-*s %-*s %s\n", arginfo->argv,
(int)(maxarglen-strlen(arginfo->argv)), arginfo->example,
maxenvlen, arginfo->env, arginfo->help);
} else {
printf("-%-*s %-*s %s\n", maxarglen+1, arginfo->argv,
maxenvlen, arginfo->env,
arginfo->help);
}
}
printf("\n"
"Defaults:\n"
"QEMU_LD_PREFIX = %s\n"
"QEMU_STACK_SIZE = %ld byte\n"
"QEMU_LOG = %s\n",
interp_prefix,
guest_stack_size,
DEBUG_LOGFILE);
printf("\n"
"You can use -E and -U options or the QEMU_SET_ENV and\n"
"QEMU_UNSET_ENV environment variables to set and unset\n"
"environment variables for the target process.\n"
"It is possible to provide several variables by separating them\n"
"by commas in getsubopt(3) style. Additionally it is possible to\n"
"provide the -E and -U options multiple times.\n"
"The following lines are equivalent:\n"
" -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
" -E var1=val2,var2=val2 -U LD_PRELOAD,LD_DEBUG\n"
" QEMU_SET_ENV=var1=val2,var2=val2 QEMU_UNSET_ENV=LD_PRELOAD,LD_DEBUG\n"
"Note that if you provide several changes to a single variable\n"
"the last change will stay in effect.\n");
exit(1);
}
static int parse_args(int argc, char **argv)
{
const char *r;
int optind;
struct qemu_argument *arginfo;
for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
if (arginfo->env == NULL) {
continue;
}
r = getenv(arginfo->env);
if (r != NULL) {
arginfo->handle_opt(r);
}
}
optind = 1;
for (;;) {
if (optind >= argc) {
break;
}
r = argv[optind];
if (r[0] != '-') {
break;
}
optind++;
r++;
if (!strcmp(r, "-")) {
break;
}
for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
if (!strcmp(r, arginfo->argv)) {
if (optind >= argc) {
usage();
}
arginfo->handle_opt(argv[optind]);
if (arginfo->has_arg) {
optind++;
}
break;
}
}
/* no option matched the current argv */
if (arginfo->handle_opt == NULL) {
usage();
}
}
if (optind >= argc) {
usage();
}
filename = argv[optind];
exec_path = argv[optind];
return optind;
}
int main(int argc, char **argv, char **envp)
{
const char *filename;
const char *cpu_model;
const char *log_file = DEBUG_LOGFILE;
const char *log_mask = NULL;
struct target_pt_regs regs1, *regs = &regs1;
struct image_info info1, *info = &info1;
struct linux_binprm bprm;
TaskState *ts;
CPUState *env;
int optind;
const char *r;
int gdbstub_port = 0;
char **target_environ, **wrk;
char **target_argv;
int target_argc;
envlist_t *envlist = NULL;
const char *argv0 = NULL;
int i;
int ret;
@ -2927,156 +3307,9 @@ int main(int argc, char **argv, char **envp)
cpudef_setup(); /* parse cpu definitions in target config file (TBD) */
#endif
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);
if ((envlist = envlist_create()) == NULL) {
(void) fprintf(stderr, "Unable to allocate envlist\n");
exit(1);
}
} else if (!strcmp(r, "U")) {
r = argv[optind++];
if (envlist_unsetenv(envlist, r) != 0)
usage();
} else if (!strcmp(r, "0")) {
r = argv[optind++];
argv0 = r;
} else if (!strcmp(r, "s")) {
if (optind >= argc)
break;
r = argv[optind++];
guest_stack_size = strtoul(r, (char **)&r, 0);
if (guest_stack_size == 0)
usage();
if (*r == 'M')
guest_stack_size *= 1024 * 1024;
else if (*r == 'k' || *r == 'K')
guest_stack_size *= 1024;
} else if (!strcmp(r, "L")) {
interp_prefix = argv[optind++];
} else if (!strcmp(r, "p")) {
if (optind >= argc)
break;
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")) {
if (optind >= argc)
break;
gdbstub_port = atoi(argv[optind++]);
} else if (!strcmp(r, "r")) {
qemu_uname_release = argv[optind++];
} else if (!strcmp(r, "cpu")) {
cpu_model = argv[optind++];
if (cpu_model == NULL || strcmp(cpu_model, "?") == 0) {
/* XXX: implement xxx_cpu_list for targets that still miss it */
#if defined(cpu_list_id)
cpu_list_id(stdout, &fprintf, "");
#elif defined(cpu_list)
cpu_list(stdout, &fprintf); /* deprecated */
#endif
exit(1);
}
#if defined(CONFIG_USE_GUEST_BASE)
} else if (!strcmp(r, "B")) {
guest_base = strtol(argv[optind++], NULL, 0);
have_guest_base = 1;
} else if (!strcmp(r, "R")) {
char *p;
int shift = 0;
reserved_va = strtoul(argv[optind++], &p, 0);
switch (*p) {
case 'k':
case 'K':
shift = 10;
break;
case 'M':
shift = 20;
break;
case 'G':
shift = 30;
break;
}
if (shift) {
unsigned long unshifted = reserved_va;
p++;
reserved_va <<= shift;
if (((reserved_va >> shift) != unshifted)
#if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
|| (reserved_va > (1ul << TARGET_VIRT_ADDR_SPACE_BITS))
#endif
) {
fprintf(stderr, "Reserved virtual address too big\n");
exit(1);
}
}
if (*p) {
fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p);
exit(1);
}
#endif
} else if (!strcmp(r, "drop-ld-preload")) {
(void) envlist_unsetenv(envlist, "LD_PRELOAD");
} else if (!strcmp(r, "singlestep")) {
singlestep = 1;
} else if (!strcmp(r, "strace")) {
do_strace = 1;
} else if (!strcmp(r, "version")) {
version();
exit(0);
} else {
usage();
}
}
/* init debug */
cpu_set_log_filename(log_file);
if (log_mask) {
int mask;
const CPULogItem *item;
mask = cpu_str_to_log_mask(log_mask);
if (!mask) {
printf("Log items (comma separated):\n");
for (item = cpu_log_items; item->mask != 0; item++) {
printf("%-10s %s\n", item->name, item->help);
}
exit(1);
}
cpu_set_log(mask);
}
if (optind >= argc) {
usage();
}
filename = argv[optind];
exec_path = argv[optind];
optind = parse_args(argc, argv);
/* Zero out regs */
memset(regs, 0, sizeof(struct target_pt_regs));
@ -3180,6 +3413,13 @@ int main(int argc, char **argv, char **envp)
}
qemu_log("Reserved 0x%lx bytes of guest address space\n", reserved_va);
}
if (reserved_va || have_guest_base) {
if (!guest_validate_base(guest_base)) {
fprintf(stderr, "Guest base/Reserved VA rejected by guest code\n");
exit(1);
}
}
#endif /* CONFIG_USE_GUEST_BASE */
/*
@ -3568,7 +3808,11 @@ int main(int argc, char **argv, char **envp)
#endif
if (gdbstub_port) {
gdbserver_start (gdbstub_port);
if (gdbserver_start(gdbstub_port) < 0) {
fprintf(stderr, "qemu: could not open gdbserver on port %d\n",
gdbstub_port);
exit(1);
}
gdb_handlesig(env, 0);
}
cpu_loop(env);

View File

@ -202,6 +202,12 @@ int get_osversion(void);
void fork_start(void);
void fork_end(int child);
/* Return true if the proposed guest_base is suitable for the guest.
* The guest code may leave a page mapped and populate it if the
* address is suitable.
*/
bool guest_validate_base(unsigned long guest_base);
#include "qemu-log.h"
/* strace.c */

View File

@ -70,6 +70,9 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
#ifdef CONFIG_EPOLL
#include <sys/epoll.h>
#endif
#ifdef CONFIG_ATTR
#include <attr/xattr.h>
#endif
#define termios host_termios
#define winsize host_winsize
@ -796,6 +799,15 @@ abi_long do_brk(abi_ulong new_brk)
MAP_ANON|MAP_PRIVATE, 0, 0));
if (mapped_addr == brk_page) {
/* Heap contents are initialized to zero, as for anonymous
* mapped pages. Technically the new pages are already
* initialized to zero since they *are* anonymous mapped
* pages, however we have to take care with the contents that
* come from the remaining part of the previous page: it may
* contains garbage data due to a previous heap usage (grown
* then shrunken). */
memset(g2h(target_brk), 0, brk_page - target_brk);
target_brk = new_brk;
brk_page = HOST_PAGE_ALIGN(target_brk);
DEBUGF_BRK("%#010x (mapped_addr == brk_page)\n", target_brk);
@ -7632,22 +7644,67 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
#endif
break;
#endif
#ifdef CONFIG_ATTR
#ifdef TARGET_NR_setxattr
case TARGET_NR_setxattr:
case TARGET_NR_lsetxattr:
case TARGET_NR_fsetxattr:
case TARGET_NR_getxattr:
case TARGET_NR_lgetxattr:
case TARGET_NR_fgetxattr:
case TARGET_NR_listxattr:
case TARGET_NR_llistxattr:
case TARGET_NR_flistxattr:
case TARGET_NR_removexattr:
case TARGET_NR_lremovexattr:
case TARGET_NR_fremovexattr:
ret = -TARGET_EOPNOTSUPP;
break;
case TARGET_NR_setxattr:
{
void *p, *n, *v;
p = lock_user_string(arg1);
n = lock_user_string(arg2);
v = lock_user(VERIFY_READ, arg3, arg4, 1);
if (p && n && v) {
ret = get_errno(setxattr(p, n, v, arg4, arg5));
} else {
ret = -TARGET_EFAULT;
}
unlock_user(p, arg1, 0);
unlock_user(n, arg2, 0);
unlock_user(v, arg3, 0);
}
break;
case TARGET_NR_getxattr:
{
void *p, *n, *v;
p = lock_user_string(arg1);
n = lock_user_string(arg2);
v = lock_user(VERIFY_WRITE, arg3, arg4, 0);
if (p && n && v) {
ret = get_errno(getxattr(p, n, v, arg4));
} else {
ret = -TARGET_EFAULT;
}
unlock_user(p, arg1, 0);
unlock_user(n, arg2, 0);
unlock_user(v, arg3, arg4);
}
break;
case TARGET_NR_removexattr:
{
void *p, *n;
p = lock_user_string(arg1);
n = lock_user_string(arg2);
if (p && n) {
ret = get_errno(removexattr(p, n));
} else {
ret = -TARGET_EFAULT;
}
unlock_user(p, arg1, 0);
unlock_user(n, arg2, 0);
}
break;
#endif
#endif /* CONFIG_ATTR */
#ifdef TARGET_NR_set_thread_area
case TARGET_NR_set_thread_area:
#if defined(TARGET_MIPS)