mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Linux user memory access API change (initial patch by Thayne Harbaugh)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3583 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
+1
-1
@@ -260,7 +260,7 @@ endif
|
||||
|
||||
ifdef CONFIG_LINUX_USER
|
||||
OBJS= main.o syscall.o strace.o mmap.o signal.o path.o osdep.o thunk.o \
|
||||
elfload.o linuxload.o
|
||||
elfload.o linuxload.o uaccess.o
|
||||
LIBS+= $(AIOLIBS)
|
||||
ifdef TARGET_HAS_BFLT
|
||||
OBJS+= flatload.o
|
||||
|
||||
+39
-13
@@ -184,9 +184,11 @@ uint32_t do_arm_semihosting(CPUState *env)
|
||||
args = env->regs[1];
|
||||
switch (nr) {
|
||||
case SYS_OPEN:
|
||||
s = lock_user_string(ARG(0));
|
||||
if (!(s = lock_user_string(ARG(0))))
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
return (uint32_t)-1;
|
||||
if (ARG(1) >= 12)
|
||||
return (uint32_t)-1;
|
||||
return (uint32_t)-1;
|
||||
if (strcmp(s, ":tt") == 0) {
|
||||
if (ARG(1) < 4)
|
||||
return STDIN_FILENO;
|
||||
@@ -221,7 +223,9 @@ uint32_t do_arm_semihosting(CPUState *env)
|
||||
}
|
||||
}
|
||||
case SYS_WRITE0:
|
||||
s = lock_user_string(args);
|
||||
if (!(s = lock_user_string(args)))
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
return (uint32_t)-1;
|
||||
len = strlen(s);
|
||||
if (use_gdb_syscalls()) {
|
||||
gdb_do_syscall(arm_semi_cb, "write,2,%x,%x\n", args, len);
|
||||
@@ -238,7 +242,9 @@ uint32_t do_arm_semihosting(CPUState *env)
|
||||
gdb_do_syscall(arm_semi_cb, "write,%x,%x,%x", ARG(0), ARG(1), len);
|
||||
return env->regs[0];
|
||||
} else {
|
||||
s = lock_user(ARG(1), len, 1);
|
||||
if (!(s = lock_user(VERIFY_READ, ARG(1), len, 1)))
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
return (uint32_t)-1;
|
||||
ret = set_swi_errno(ts, write(ARG(0), s, len));
|
||||
unlock_user(s, ARG(1), 0);
|
||||
if (ret == (uint32_t)-1)
|
||||
@@ -252,7 +258,9 @@ uint32_t do_arm_semihosting(CPUState *env)
|
||||
gdb_do_syscall(arm_semi_cb, "read,%x,%x,%x", ARG(0), ARG(1), len);
|
||||
return env->regs[0];
|
||||
} else {
|
||||
s = lock_user(ARG(1), len, 0);
|
||||
if (!(s = lock_user(VERIFY_WRITE, ARG(1), len, 0)))
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
return (uint32_t)-1;
|
||||
do
|
||||
ret = set_swi_errno(ts, read(ARG(0), s, len));
|
||||
while (ret == -1 && errno == EINTR);
|
||||
@@ -301,7 +309,9 @@ uint32_t do_arm_semihosting(CPUState *env)
|
||||
gdb_do_syscall(arm_semi_cb, "unlink,%s", ARG(0), (int)ARG(1)+1);
|
||||
ret = env->regs[0];
|
||||
} else {
|
||||
s = lock_user_string(ARG(0));
|
||||
if (!(s = lock_user_string(ARG(0))))
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
return (uint32_t)-1;
|
||||
ret = set_swi_errno(ts, remove(s));
|
||||
unlock_user(s, ARG(0), 0);
|
||||
}
|
||||
@@ -315,9 +325,15 @@ uint32_t do_arm_semihosting(CPUState *env)
|
||||
char *s2;
|
||||
s = lock_user_string(ARG(0));
|
||||
s2 = lock_user_string(ARG(2));
|
||||
ret = set_swi_errno(ts, rename(s, s2));
|
||||
unlock_user(s2, ARG(2), 0);
|
||||
unlock_user(s, ARG(0), 0);
|
||||
if (!s || !s2)
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
ret = (uint32_t)-1;
|
||||
else
|
||||
ret = set_swi_errno(ts, rename(s, s2));
|
||||
if (s2)
|
||||
unlock_user(s2, ARG(2), 0);
|
||||
if (s)
|
||||
unlock_user(s, ARG(0), 0);
|
||||
return ret;
|
||||
}
|
||||
case SYS_CLOCK:
|
||||
@@ -329,7 +345,9 @@ uint32_t do_arm_semihosting(CPUState *env)
|
||||
gdb_do_syscall(arm_semi_cb, "system,%s", ARG(0), (int)ARG(1)+1);
|
||||
return env->regs[0];
|
||||
} else {
|
||||
s = lock_user_string(ARG(0));
|
||||
if (!(s = lock_user_string(ARG(0))))
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
return (uint32_t)-1;
|
||||
ret = set_swi_errno(ts, system(s));
|
||||
unlock_user(s, ARG(0), 0);
|
||||
}
|
||||
@@ -346,7 +364,11 @@ uint32_t do_arm_semihosting(CPUState *env)
|
||||
char **arg = ts->info->host_argv;
|
||||
int len = ARG(1);
|
||||
/* lock the buffer on the ARM side */
|
||||
char *cmdline_buffer = (char*)lock_user(ARG(0), len, 0);
|
||||
char *cmdline_buffer = (char*)lock_user(VERIFY_WRITE, ARG(0), len, 0);
|
||||
|
||||
if (!cmdline_buffer)
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
return (uint32_t)-1;
|
||||
|
||||
s = cmdline_buffer;
|
||||
while (*arg && len > 2) {
|
||||
@@ -402,7 +424,9 @@ uint32_t do_arm_semihosting(CPUState *env)
|
||||
ts->heap_limit = limit;
|
||||
}
|
||||
|
||||
ptr = lock_user(ARG(0), 16, 0);
|
||||
if (!(ptr = lock_user(VERIFY_WRITE, ARG(0), 16, 0)))
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
return (uint32_t)-1;
|
||||
ptr[0] = tswap32(ts->heap_base);
|
||||
ptr[1] = tswap32(ts->heap_limit);
|
||||
ptr[2] = tswap32(ts->stack_base);
|
||||
@@ -410,7 +434,9 @@ uint32_t do_arm_semihosting(CPUState *env)
|
||||
unlock_user(ptr, ARG(0), 16);
|
||||
#else
|
||||
limit = ram_size;
|
||||
ptr = lock_user(ARG(0), 16, 0);
|
||||
if (!(ptr = lock_user(VERIFY_WRITE, ARG(0), 16, 0)))
|
||||
/* FIXME - should this error code be -TARGET_EFAULT ? */
|
||||
return (uint32_t)-1;
|
||||
/* TODO: Make this use the limit of the loaded application. */
|
||||
ptr[0] = tswap32(limit / 2);
|
||||
ptr[1] = tswap32(limit);
|
||||
|
||||
@@ -2510,13 +2510,19 @@ void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
|
||||
if (is_write) {
|
||||
if (!(flags & PAGE_WRITE))
|
||||
return;
|
||||
p = lock_user(addr, len, 0);
|
||||
/* XXX: this code should not depend on lock_user */
|
||||
if (!(p = lock_user(VERIFY_WRITE, addr, len, 0)))
|
||||
/* FIXME - should this return an error rather than just fail? */
|
||||
return;
|
||||
memcpy(p, buf, len);
|
||||
unlock_user(p, addr, len);
|
||||
} else {
|
||||
if (!(flags & PAGE_READ))
|
||||
return;
|
||||
p = lock_user(addr, len, 1);
|
||||
/* XXX: this code should not depend on lock_user */
|
||||
if (!(p = lock_user(VERIFY_READ, addr, len, 1)))
|
||||
/* FIXME - should this return an error rather than just fail? */
|
||||
return;
|
||||
memcpy(buf, p, len);
|
||||
unlock_user(p, addr, 0);
|
||||
}
|
||||
|
||||
@@ -677,7 +677,7 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
|
||||
for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
|
||||
if (bprm->page[i]) {
|
||||
info->rss++;
|
||||
|
||||
/* FIXME - check return value of memcpy_to_target() for failure */
|
||||
memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE);
|
||||
free(bprm->page[i]);
|
||||
}
|
||||
@@ -760,6 +760,7 @@ static abi_ulong create_elf_tables(abi_ulong p, int argc, int envc,
|
||||
size_t len = strlen(k_platform) + 1;
|
||||
sp -= (len + n - 1) & ~(n - 1);
|
||||
u_platform = sp;
|
||||
/* FIXME - check return value of memcpy_to_target() for failure */
|
||||
memcpy_to_target(sp, k_platform, len);
|
||||
}
|
||||
/*
|
||||
|
||||
@@ -108,7 +108,7 @@ int target_pread(int fd, abi_ulong ptr, abi_ulong len,
|
||||
void *buf;
|
||||
int ret;
|
||||
|
||||
buf = lock_user(ptr, len, 0);
|
||||
buf = lock_user(VERIFY_WRITE, ptr, len, 0);
|
||||
ret = pread(fd, buf, len, offset);
|
||||
unlock_user(buf, ptr, len);
|
||||
return ret;
|
||||
|
||||
@@ -13,14 +13,17 @@
|
||||
#define NGROUPS 32
|
||||
|
||||
/* ??? This should really be somewhere else. */
|
||||
void memcpy_to_target(abi_ulong dest, const void *src,
|
||||
unsigned long len)
|
||||
abi_long memcpy_to_target(abi_ulong dest, const void *src,
|
||||
unsigned long len)
|
||||
{
|
||||
void *host_ptr;
|
||||
|
||||
host_ptr = lock_user(dest, len, 0);
|
||||
host_ptr = lock_user(VERIFY_WRITE, dest, len, 0);
|
||||
if (!host_ptr)
|
||||
return -TARGET_EFAULT;
|
||||
memcpy(host_ptr, src, len);
|
||||
unlock_user(host_ptr, dest, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int in_group_p(gid_t g)
|
||||
|
||||
+74
-47
@@ -146,8 +146,8 @@ int load_elf_binary_multi(struct linux_binprm *bprm,
|
||||
struct image_info *info);
|
||||
#endif
|
||||
|
||||
void memcpy_to_target(abi_ulong dest, const void *src,
|
||||
unsigned long len);
|
||||
abi_long memcpy_to_target(abi_ulong dest, const void *src,
|
||||
unsigned long len);
|
||||
void target_set_brk(abi_ulong new_brk);
|
||||
abi_long do_brk(abi_ulong new_brk);
|
||||
void syscall_init(void);
|
||||
@@ -179,9 +179,7 @@ void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
|
||||
void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
|
||||
long do_sigreturn(CPUState *env);
|
||||
long do_rt_sigreturn(CPUState *env);
|
||||
int do_sigaltstack(const struct target_sigaltstack *uss,
|
||||
struct target_sigaltstack *uoss,
|
||||
abi_ulong sp);
|
||||
abi_long do_sigaltstack(abi_ulong uss_addr, abi_ulong uoss_addr, abi_ulong sp);
|
||||
|
||||
#ifdef TARGET_I386
|
||||
/* vm86.c */
|
||||
@@ -207,12 +205,15 @@ int target_msync(abi_ulong start, abi_ulong len, int flags);
|
||||
/* user access */
|
||||
|
||||
#define VERIFY_READ 0
|
||||
#define VERIFY_WRITE 1
|
||||
#define VERIFY_WRITE 1 /* implies read access */
|
||||
|
||||
#define access_ok(type,addr,size) \
|
||||
(page_check_range((target_ulong)addr,size,(type==VERIFY_READ)?PAGE_READ:PAGE_WRITE)==0)
|
||||
|
||||
/* NOTE __get_user and __put_user use host pointers and don't check access. */
|
||||
/* These are usually used to access struct data members once the
|
||||
* struct has been locked - usually with lock_user_struct().
|
||||
*/
|
||||
#define __put_user(x, hptr)\
|
||||
({\
|
||||
int size = sizeof(*hptr);\
|
||||
@@ -257,26 +258,44 @@ int target_msync(abi_ulong start, abi_ulong len, int flags);
|
||||
0;\
|
||||
})
|
||||
|
||||
#define put_user(x,ptr)\
|
||||
({\
|
||||
int __ret;\
|
||||
if (access_ok(VERIFY_WRITE, ptr, sizeof(*ptr)))\
|
||||
__ret = __put_user(x, ptr);\
|
||||
else\
|
||||
__ret = -EFAULT;\
|
||||
__ret;\
|
||||
/* put_user()/get_user() take a guest address and check access */
|
||||
/* These are usually used to access an atomic data type, such as an int,
|
||||
* that has been passed by address. These internally perform locking
|
||||
* and unlocking on the data type.
|
||||
*/
|
||||
#define put_user(x, gaddr, target_type) \
|
||||
({ \
|
||||
abi_ulong __gaddr = (gaddr); \
|
||||
target_type *__hptr; \
|
||||
abi_long __ret; \
|
||||
if ((__hptr = lock_user(VERIFY_WRITE, __gaddr, sizeof(target_type), 0))) { \
|
||||
__ret = __put_user((x), __hptr); \
|
||||
unlock_user(__hptr, __gaddr, sizeof(target_type)); \
|
||||
} else \
|
||||
__ret = -TARGET_EFAULT; \
|
||||
__ret; \
|
||||
})
|
||||
|
||||
#define get_user(x,ptr)\
|
||||
({\
|
||||
int __ret;\
|
||||
if (access_ok(VERIFY_READ, ptr, sizeof(*ptr)))\
|
||||
__ret = __get_user(x, ptr);\
|
||||
else\
|
||||
__ret = -EFAULT;\
|
||||
__ret;\
|
||||
#define get_user(x, gaddr, target_type) \
|
||||
({ \
|
||||
abi_ulong __gaddr = (gaddr); \
|
||||
target_type *__hptr; \
|
||||
abi_long __ret; \
|
||||
if ((__hptr = lock_user(VERIFY_READ, __gaddr, sizeof(target_type), 1))) { \
|
||||
__ret = __get_user((x), __hptr); \
|
||||
unlock_user(__hptr, __gaddr, 0); \
|
||||
} else \
|
||||
__ret = -TARGET_EFAULT; \
|
||||
__ret; \
|
||||
})
|
||||
|
||||
/* copy_from_user() and copy_to_user() are usually used to copy data
|
||||
* buffers between the target and host. These internally perform
|
||||
* locking/unlocking of the memory.
|
||||
*/
|
||||
abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len);
|
||||
abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len);
|
||||
|
||||
/* Functions for accessing guest memory. The tget and tput functions
|
||||
read/write single values, byteswapping as neccessary. The lock_user
|
||||
gets a pointer to a contiguous area of guest memory, but does not perform
|
||||
@@ -285,53 +304,61 @@ int target_msync(abi_ulong start, abi_ulong len, int flags);
|
||||
|
||||
/* Lock an area of guest memory into the host. If copy is true then the
|
||||
host area will have the same contents as the guest. */
|
||||
static inline void *lock_user(abi_ulong guest_addr, long len, int copy)
|
||||
static inline void *lock_user(int type, abi_ulong guest_addr, long len, int copy)
|
||||
{
|
||||
if (!access_ok(type, guest_addr, len))
|
||||
return NULL;
|
||||
#ifdef DEBUG_REMAP
|
||||
void *addr;
|
||||
addr = malloc(len);
|
||||
if (copy)
|
||||
memcpy(addr, g2h(guest_addr), len);
|
||||
else
|
||||
memset(addr, 0, len);
|
||||
return addr;
|
||||
{
|
||||
void *addr;
|
||||
addr = malloc(len);
|
||||
if (copy)
|
||||
memcpy(addr, g2h(guest_addr), len);
|
||||
else
|
||||
memset(addr, 0, len);
|
||||
return addr;
|
||||
}
|
||||
#else
|
||||
return g2h(guest_addr);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Unlock an area of guest memory. The first LEN bytes must be flushed back
|
||||
to guest memory. */
|
||||
static inline void unlock_user(void *host_addr, abi_ulong guest_addr,
|
||||
/* Unlock an area of guest memory. The first LEN bytes must be
|
||||
flushed back to guest memory. host_ptr = NULL is explicitely
|
||||
allowed and does nothing. */
|
||||
static inline void unlock_user(void *host_ptr, abi_ulong guest_addr,
|
||||
long len)
|
||||
{
|
||||
|
||||
#ifdef DEBUG_REMAP
|
||||
if (host_addr == g2h(guest_addr))
|
||||
if (!host_ptr)
|
||||
return;
|
||||
if (host_ptr == g2h(guest_addr))
|
||||
return;
|
||||
if (len > 0)
|
||||
memcpy(g2h(guest_addr), host_addr, len);
|
||||
free(host_addr);
|
||||
memcpy(g2h(guest_ptr), host_ptr, len);
|
||||
free(host_ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Return the length of a string in target memory. */
|
||||
static inline int target_strlen(abi_ulong ptr)
|
||||
{
|
||||
return strlen(g2h(ptr));
|
||||
}
|
||||
/* Return the length of a string in target memory or -TARGET_EFAULT if
|
||||
access error. */
|
||||
abi_long target_strlen(abi_ulong gaddr);
|
||||
|
||||
/* Like lock_user but for null terminated strings. */
|
||||
static inline void *lock_user_string(abi_ulong guest_addr)
|
||||
{
|
||||
long len;
|
||||
len = target_strlen(guest_addr) + 1;
|
||||
return lock_user(guest_addr, len, 1);
|
||||
abi_long len;
|
||||
len = target_strlen(guest_addr);
|
||||
if (len < 0)
|
||||
return NULL;
|
||||
return lock_user(VERIFY_READ, guest_addr, (long)(len + 1), 1);
|
||||
}
|
||||
|
||||
/* Helper macros for locking/ulocking a target struct. */
|
||||
#define lock_user_struct(host_ptr, guest_addr, copy) \
|
||||
host_ptr = lock_user(guest_addr, sizeof(*host_ptr), copy)
|
||||
#define unlock_user_struct(host_ptr, guest_addr, copy) \
|
||||
#define lock_user_struct(type, host_ptr, guest_addr, copy) \
|
||||
(host_ptr = lock_user(type, guest_addr, sizeof(*host_ptr), copy))
|
||||
#define unlock_user_struct(host_ptr, guest_addr, copy) \
|
||||
unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0)
|
||||
|
||||
#define tget8(addr) ldub(addr)
|
||||
|
||||
+135
-103
File diff suppressed because it is too large
Load Diff
+17
-16
@@ -81,14 +81,18 @@ print_fdset(int n, target_ulong target_fds_addr)
|
||||
|
||||
gemu_log("[");
|
||||
if( target_fds_addr ) {
|
||||
target_long *target_fds;
|
||||
abi_long *target_fds;
|
||||
|
||||
if (!access_ok(VERIFY_READ, target_fds_addr, sizeof(*target_fds)*(n / TARGET_LONG_BITS + 1)))
|
||||
target_fds = lock_user(VERIFY_READ,
|
||||
target_fds_addr,
|
||||
sizeof(*target_fds)*(n / TARGET_ABI_BITS + 1),
|
||||
1);
|
||||
|
||||
if (!target_fds)
|
||||
return;
|
||||
|
||||
target_fds = lock_user(target_fds_addr, sizeof(*target_fds)*(n / TARGET_LONG_BITS + 1), 1);
|
||||
for (i=n; i>=0; i--) {
|
||||
if ((tswapl(target_fds[i / TARGET_LONG_BITS]) >> (i & (TARGET_LONG_BITS - 1))) & 1)
|
||||
if ((tswapl(target_fds[i / TARGET_ABI_BITS]) >> (i & (TARGET_ABI_BITS - 1))) & 1)
|
||||
gemu_log("%d,", i );
|
||||
}
|
||||
unlock_user(target_fds, target_fds_addr, 0);
|
||||
@@ -102,10 +106,9 @@ print_timeval(target_ulong tv_addr)
|
||||
if( tv_addr ) {
|
||||
struct target_timeval *tv;
|
||||
|
||||
if (!access_ok(VERIFY_READ, tv_addr, sizeof(*tv)))
|
||||
tv = lock_user(VERIFY_READ, tv_addr, sizeof(*tv), 1);
|
||||
if (!tv)
|
||||
return;
|
||||
|
||||
tv = lock_user(tv_addr, sizeof(*tv), 1);
|
||||
gemu_log("{" TARGET_ABI_FMT_ld "," TARGET_ABI_FMT_ld "}",
|
||||
tv->tv_sec, tv->tv_usec);
|
||||
unlock_user(tv, tv_addr, 0);
|
||||
@@ -165,27 +168,25 @@ print_execve(struct syscallname *name,
|
||||
target_ulong arg_ptr_addr;
|
||||
char *s;
|
||||
|
||||
if (!access_ok(VERIFY_READ, arg1, 1))
|
||||
if (!(s = lock_user_string(arg1)))
|
||||
return;
|
||||
|
||||
s = lock_user_string(arg1);
|
||||
gemu_log("%s(\"%s\",{", name->name, s);
|
||||
unlock_user(s, arg1, 0);
|
||||
|
||||
for (arg_ptr_addr = arg2; ; arg_ptr_addr += sizeof(target_ulong)) {
|
||||
target_ulong *arg_ptr, arg_addr, s_addr;
|
||||
|
||||
if (!access_ok(VERIFY_READ, arg_ptr_addr, sizeof(target_ulong)))
|
||||
arg_ptr = lock_user(VERIFY_READ, arg_ptr_addr, sizeof(target_ulong), 1);
|
||||
if (!arg_ptr)
|
||||
return;
|
||||
|
||||
arg_ptr = lock_user(arg_ptr_addr, sizeof(target_ulong), 1);
|
||||
arg_addr = tswapl(*arg_ptr);
|
||||
unlock_user(arg_ptr, arg_ptr_addr, 0);
|
||||
if (!arg_addr)
|
||||
break;
|
||||
s = lock_user_string(arg_addr);
|
||||
gemu_log("\"%s\",", s);
|
||||
unlock_user(s, s_addr, 0);
|
||||
if ((s = lock_user_string(arg_addr))) {
|
||||
gemu_log("\"%s\",", s);
|
||||
unlock_user(s, s_addr, 0);
|
||||
}
|
||||
}
|
||||
|
||||
gemu_log("NULL})");
|
||||
|
||||
+573
-410
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,51 @@
|
||||
/* User memory access */
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "qemu.h"
|
||||
|
||||
/* copy_from_user() and copy_to_user() are usually used to copy data
|
||||
* buffers between the target and host. These internally perform
|
||||
* locking/unlocking of the memory.
|
||||
*/
|
||||
abi_long copy_from_user(void *hptr, abi_ulong gaddr, size_t len)
|
||||
{
|
||||
abi_long ret = 0;
|
||||
void *ghptr;
|
||||
|
||||
if ((ghptr = lock_user(VERIFY_READ, gaddr, len, 1))) {
|
||||
memcpy(hptr, ghptr, len);
|
||||
unlock_user(ghptr, gaddr, 0);
|
||||
} else
|
||||
ret = -TARGET_EFAULT;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
abi_long copy_to_user(abi_ulong gaddr, void *hptr, size_t len)
|
||||
{
|
||||
abi_long ret = 0;
|
||||
void *ghptr;
|
||||
|
||||
if ((ghptr = lock_user(VERIFY_WRITE, gaddr, len, 0))) {
|
||||
memcpy(ghptr, hptr, len);
|
||||
unlock_user(ghptr, gaddr, len);
|
||||
} else
|
||||
ret = -TARGET_EFAULT;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Return the length of a string in target memory. */
|
||||
/* FIXME - this doesn't check access_ok() - it's rather complicated to
|
||||
* do it correctly because we need to check the bytes in a page and then
|
||||
* skip to the next page and check the bytes there until we find the
|
||||
* terminator. There should be a general function to do this that
|
||||
* can look for any byte terminator in a buffer - not strlen().
|
||||
*/
|
||||
abi_long target_strlen(abi_ulong gaddr)
|
||||
{
|
||||
return strlen(g2h(gaddr));
|
||||
}
|
||||
+5
-2
@@ -64,7 +64,9 @@ void save_v86_state(CPUX86State *env)
|
||||
TaskState *ts = env->opaque;
|
||||
struct target_vm86plus_struct * target_v86;
|
||||
|
||||
lock_user_struct(target_v86, ts->target_v86, 0);
|
||||
if (!lock_user_struct(VERIFY_WRITE, target_v86, ts->target_v86, 0))
|
||||
/* FIXME - should return an error */
|
||||
return;
|
||||
/* put the VM86 registers in the userspace register structure */
|
||||
target_v86->regs.eax = tswap32(env->regs[R_EAX]);
|
||||
target_v86->regs.ebx = tswap32(env->regs[R_EBX]);
|
||||
@@ -424,7 +426,8 @@ int do_vm86(CPUX86State *env, long subfunction, abi_ulong vm86_addr)
|
||||
ts->vm86_saved_regs.gs = env->segs[R_GS].selector;
|
||||
|
||||
ts->target_v86 = vm86_addr;
|
||||
lock_user_struct(target_v86, vm86_addr, 1);
|
||||
if (!lock_user_struct(VERIFY_READ, target_v86, vm86_addr, 1))
|
||||
return -EFAULT;
|
||||
/* build vm86 CPU state */
|
||||
ts->v86flags = tswap32(target_v86->regs.eflags);
|
||||
env->eflags = (env->eflags & ~SAFE_MASK) |
|
||||
|
||||
+60
-24
@@ -107,7 +107,9 @@ static void translate_stat(CPUState *env, target_ulong addr, struct stat *s)
|
||||
{
|
||||
struct m68k_gdb_stat *p;
|
||||
|
||||
p = lock_user(addr, sizeof(struct m68k_gdb_stat), 0);
|
||||
if (!(p = lock_user(VERIFY_WRITE, addr, sizeof(struct m68k_gdb_stat), 0)))
|
||||
/* FIXME - should this return an error code? */
|
||||
return;
|
||||
p->gdb_st_dev = cpu_to_be32(s->st_dev);
|
||||
p->gdb_st_ino = cpu_to_be32(s->st_ino);
|
||||
p->gdb_st_mode = cpu_to_be32(s->st_mode);
|
||||
@@ -168,9 +170,13 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
|
||||
ARG(2), ARG(3));
|
||||
return;
|
||||
} else {
|
||||
p = lock_user_string(ARG(0));
|
||||
result = open(p, translate_openflags(ARG(2)), ARG(3));
|
||||
unlock_user(p, ARG(0), 0);
|
||||
if (!(p = lock_user_string(ARG(0)))) {
|
||||
/* FIXME - check error code? */
|
||||
result = -1;
|
||||
} else {
|
||||
result = open(p, translate_openflags(ARG(2)), ARG(3));
|
||||
unlock_user(p, ARG(0), 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HOSTED_CLOSE:
|
||||
@@ -196,9 +202,13 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
|
||||
ARG(0), ARG(1), len);
|
||||
return;
|
||||
} else {
|
||||
p = lock_user(ARG(1), len, 0);
|
||||
result = read(ARG(0), p, len);
|
||||
unlock_user(p, ARG(1), len);
|
||||
if (!(p = lock_user(VERIFY_WRITE, ARG(1), len, 0))) {
|
||||
/* FIXME - check error code? */
|
||||
result = -1;
|
||||
} else {
|
||||
result = read(ARG(0), p, len);
|
||||
unlock_user(p, ARG(1), len);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HOSTED_WRITE:
|
||||
@@ -208,9 +218,13 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
|
||||
ARG(0), ARG(1), len);
|
||||
return;
|
||||
} else {
|
||||
p = lock_user(ARG(1), len, 1);
|
||||
result = write(ARG(0), p, len);
|
||||
unlock_user(p, ARG(0), 0);
|
||||
if (!(p = lock_user(VERIFY_READ, ARG(1), len, 1))) {
|
||||
/* FIXME - check error code? */
|
||||
result = -1;
|
||||
} else {
|
||||
result = write(ARG(0), p, len);
|
||||
unlock_user(p, ARG(0), 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HOSTED_LSEEK:
|
||||
@@ -237,7 +251,12 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
|
||||
} else {
|
||||
p = lock_user_string(ARG(0));
|
||||
q = lock_user_string(ARG(2));
|
||||
result = rename(p, q);
|
||||
if (!p || !q) {
|
||||
/* FIXME - check error code? */
|
||||
result = -1;
|
||||
} else {
|
||||
result = rename(p, q);
|
||||
}
|
||||
unlock_user(p, ARG(0), 0);
|
||||
unlock_user(q, ARG(2), 0);
|
||||
}
|
||||
@@ -248,9 +267,13 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
|
||||
ARG(0), (int)ARG(1));
|
||||
return;
|
||||
} else {
|
||||
p = lock_user_string(ARG(0));
|
||||
result = unlink(p);
|
||||
unlock_user(p, ARG(0), 0);
|
||||
if (!(p = lock_user_string(ARG(0)))) {
|
||||
/* FIXME - check error code? */
|
||||
result = -1;
|
||||
} else {
|
||||
result = unlink(p);
|
||||
unlock_user(p, ARG(0), 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HOSTED_STAT:
|
||||
@@ -260,9 +283,13 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
|
||||
return;
|
||||
} else {
|
||||
struct stat s;
|
||||
p = lock_user_string(ARG(0));
|
||||
result = stat(p, &s);
|
||||
unlock_user(p, ARG(0), 0);
|
||||
if (!(p = lock_user_string(ARG(0)))) {
|
||||
/* FIXME - check error code? */
|
||||
result = -1;
|
||||
} else {
|
||||
result = stat(p, &s);
|
||||
unlock_user(p, ARG(0), 0);
|
||||
}
|
||||
if (result == 0) {
|
||||
translate_stat(env, ARG(2), &s);
|
||||
}
|
||||
@@ -291,10 +318,15 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
|
||||
struct gdb_timeval *p;
|
||||
result = qemu_gettimeofday(&tv);
|
||||
if (result != 0) {
|
||||
p = lock_user(ARG(0), sizeof(struct gdb_timeval), 0);
|
||||
p->tv_sec = cpu_to_be32(tv.tv_sec);
|
||||
p->tv_usec = cpu_to_be64(tv.tv_usec);
|
||||
unlock_user(p, ARG(0), sizeof(struct gdb_timeval));
|
||||
if (!(p = lock_user(VERIFY_WRITE,
|
||||
ARG(0), sizeof(struct gdb_timeval), 0))) {
|
||||
/* FIXME - check error code? */
|
||||
result = -1;
|
||||
} else {
|
||||
p->tv_sec = cpu_to_be32(tv.tv_sec);
|
||||
p->tv_usec = cpu_to_be64(tv.tv_usec);
|
||||
unlock_user(p, ARG(0), sizeof(struct gdb_timeval));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -312,9 +344,13 @@ void do_m68k_semihosting(CPUM68KState *env, int nr)
|
||||
ARG(0), (int)ARG(1));
|
||||
return;
|
||||
} else {
|
||||
p = lock_user_string(ARG(0));
|
||||
result = system(p);
|
||||
unlock_user(p, ARG(0), 0);
|
||||
if (!(p = lock_user_string(ARG(0)))) {
|
||||
/* FIXME - check error code? */
|
||||
result = -1;
|
||||
} else {
|
||||
result = system(p);
|
||||
unlock_user(p, ARG(0), 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HOSTED_INIT_SIM:
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ static void *softmmu_lock_user(CPUState *env, uint32_t addr, uint32_t len,
|
||||
cpu_memory_rw_debug(env, addr, p, len, 0);
|
||||
return p;
|
||||
}
|
||||
#define lock_user(p, len, copy) softmmu_lock_user(env, p, len, copy)
|
||||
#define lock_user(type, p, len, copy) softmmu_lock_user(env, p, len, copy)
|
||||
static char *softmmu_lock_user_string(CPUState *env, uint32_t addr)
|
||||
{
|
||||
char *p;
|
||||
|
||||
Reference in New Issue
Block a user