Compare commits

..

4 Commits

Author SHA1 Message Date
bellard
fd429f2f6c update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@66 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-30 20:59:46 +00:00
bellard
fb3e5849bb s390 support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@65 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 17:32:36 +00:00
bellard
7854b05654 endian fixes by Ulrich weigand
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@64 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 17:22:23 +00:00
bellard
500dab07e8 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@63 c046a42c-6fe2-441c-8c8c-71466251a162
2003-03-29 16:58:09 +00:00
12 changed files with 532 additions and 80 deletions

View File

@@ -19,6 +19,10 @@ ifeq ($(ARCH),ppc)
OP_CFLAGS=$(CFLAGS)
endif
ifeq ($(ARCH),s390)
OP_CFLAGS=$(CFLAGS)
endif
ifeq ($(GCC_MAJOR),3)
# very important to generate a return at the end of every operation
OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls
@@ -94,19 +98,20 @@ qemu-doc.html: qemu-doc.texi
texi2html -monolithic -number $<
FILES= \
README COPYING COPYING.LIB TODO Changelog VERSION \
dyngen.c ioctls.h ops_template.h syscall_types.h\
README README.distrib COPYING COPYING.LIB TODO Changelog VERSION \
dyngen.c ioctls.h ops_template.h op_string.h syscall_types.h\
Makefile elf.h linux_bin.h segment.h thunk.c\
elfload.c main.c signal.c thunk.h\
cpu-i386.h qemu.h op-i386.c opc-i386.h syscall-i386.h translate-i386.c\
cpu-i386.h qemu.h op-i386.c opc-i386.h syscall-i386.h translate-i386.c\
dis-asm.h gen-i386.h op-i386.h syscall.c\
dis-buf.c i386-dis.c opreg_template.h syscall_defs.h\
i386.ld ppc.ld exec-i386.h exec-i386.c configure \
i386.ld ppc.ld s390.ld exec-i386.h exec-i386.c configure \
tests/Makefile\
tests/test-i386.c tests/test-i386-shift.h tests/test-i386.h\
tests/test-i386-muldiv.h tests/test-i386-code16.S\
tests/hello.c tests/hello tests/sha1.c \
tests/testsig.c tests/testclone.c tests/testthread.c \
tests/runcom.c tests/pi_10.com \
qemu-doc.texi qemu-doc.html
FILE=qemu-$(VERSION)

2
README
View File

@@ -30,7 +30,7 @@ LD_LIBRARY_PATH is not set:
Then you can launch the precompiled 'ls' x86 executable:
./qemu /usr/local/qemu-i386/bin/ls
./qemu /usr/local/qemu-i386/bin/ls-i386
You can look at /usr/local/qemu-i386/bin/qemu-conf.sh so that QEMU is
automatically launched by the Linux kernel when you try to launch x86

View File

@@ -1 +1 @@
0.1.3
0.1.4

7
configure vendored
View File

@@ -42,6 +42,9 @@ case "$cpu" in
mips)
cpu="mips"
;;
s390)
cpu="s390"
;;
*)
cpu="unknown"
;;
@@ -137,7 +140,7 @@ fi
else
# if cross compiling, cannot launch a program, so make a static guess
if test "$cpu" = "powerpc" -o "$cpu" = "mips" ; then
if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" ; then
bigendian="yes"
fi
@@ -212,6 +215,8 @@ elif test "$cpu" = "powerpc" ; then
echo "ARCH=ppc" >> config.mak
elif test "$cpu" = "mips" ; then
echo "ARCH=mips" >> config.mak
elif test "$cpu" = "s390" ; then
echo "ARCH=s390" >> config.mak
else
echo "Unsupported CPU"
exit 1

View File

@@ -28,6 +28,15 @@
#include "thunk.h"
/* temporary fix to make it compile with old elf headers (XXX: use
included elf.h in all cases) */
#ifndef EM_390
#define EM_S390 22 /* IBM S390 */
#define R_390_8 1 /* Direct 8 bit. */
#define R_390_16 3 /* Direct 16 bit. */
#define R_390_32 4 /* Direct 32 bit. */
#endif
/* all dynamically generated functions begin with this code */
#define OP_PREFIX "op_"
@@ -236,6 +245,17 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
copy_size = p - p_start;
}
break;
case EM_S390:
{
uint8_t *p;
p = (void *)(p_end - 2);
if (p == p_start)
error("empty code for %s", name);
if (get16((uint16_t *)p) != 0x07fe && get16((uint16_t *)p) != 0x07f4)
error("br %r14 expected at the end of %s", name);
copy_size = p - p_start;
}
break;
default:
error("unsupported CPU (%d)", e_machine);
}
@@ -405,6 +425,42 @@ void gen_code(const char *name, unsigned long offset, unsigned long size,
}
}
break;
case EM_S390:
{
Elf32_Rela *rel;
char name[256];
int type;
long addend;
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
if (rel->r_offset >= offset && rel->r_offset < offset + copy_size) {
sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
if (strstart(sym_name, "__op_param", &p)) {
snprintf(name, sizeof(name), "param%s", p);
} else {
snprintf(name, sizeof(name), "(long)(&%s)", sym_name);
}
type = ELF32_R_TYPE(rel->r_info);
addend = rel->r_addend;
switch(type) {
case R_390_32:
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %ld) = %s + %ld;\n",
rel->r_offset - offset, name, addend);
break;
case R_390_16:
fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %ld) = %s + %ld;\n",
rel->r_offset - offset, name, addend);
break;
case R_390_8:
fprintf(outfile, " *(uint8_t *)(gen_code_ptr + %ld) = %s + %ld;\n",
rel->r_offset - offset, name, addend);
break;
default:
error("unsupported s390 relocation (%d)", type);
}
}
}
}
break;
default:
error("unsupported CPU for relocations (%d)", e_machine);
}
@@ -556,6 +612,9 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
case EM_SPARC:
cpu_name = "sparc";
break;
case EM_S390:
cpu_name = "s390";
break;
default:
error("unsupported CPU (e_machine=%d)", e_machine);
}
@@ -617,6 +676,9 @@ fprintf(outfile,
case EM_PPC:
fprintf(outfile, "*((uint32_t *)gen_code_ptr)++ = 0x4e800020; /* blr */\n");
break;
case EM_S390:
fprintf(outfile, "*((uint16_t *)gen_code_ptr)++ = 0x07fe; /* br %%r14 */\n");
break;
default:
error("no return generation for cpu '%s'", cpu_name);
}

View File

@@ -87,6 +87,20 @@ static inline int testandset (int *p)
}
#endif
#ifdef __s390__
static inline int testandset (int *p)
{
int ret;
__asm__ __volatile__ ("0: cs %0,%1,0(%2)\n"
" jl 0b"
: "=&d" (ret)
: "r" (1), "a" (p), "0" (*p)
: "cc", "memory" );
return ret;
}
#endif
int global_cpu_lock = 0;
void cpu_lock(void)

View File

@@ -93,6 +93,12 @@ register unsigned int T1 asm("l1");
register unsigned int A0 asm("l2");
register struct CPUX86State *env asm("l3");
#endif
#ifdef __s390__
register unsigned int T0 asm("r7");
register unsigned int T1 asm("r8");
register unsigned int A0 asm("r9");
register struct CPUX86State *env asm("r10");
#endif
/* force GCC to generate only one epilog at the end of the function */
#define FORCE_RET() asm volatile ("");

View File

@@ -26,6 +26,7 @@
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
@@ -40,6 +41,7 @@
#include <sys/uio.h>
#include <sys/poll.h>
//#include <sys/user.h>
#include <netinet/tcp.h>
#define termios host_termios
#define winsize host_winsize
@@ -166,7 +168,7 @@ static long do_brk(char *new_brk)
static inline fd_set *target_to_host_fds(fd_set *fds,
target_long *target_fds, int n)
{
#if !defined(BSWP_NEEDED) && !defined(WORD_BIGENDIAN)
#if !defined(BSWAP_NEEDED) && !defined(WORDS_BIGENDIAN)
return (fd_set *)target_fds;
#else
int i, b;
@@ -188,7 +190,7 @@ static inline fd_set *target_to_host_fds(fd_set *fds,
static inline void host_to_target_fds(target_long *target_fds,
fd_set *fds, int n)
{
#if !defined(BSWP_NEEDED) && !defined(WORD_BIGENDIAN)
#if !defined(BSWAP_NEEDED) && !defined(WORDS_BIGENDIAN)
/* nothing to do */
#else
int i, nw, j, k;
@@ -256,55 +258,267 @@ static long do_select(long n,
return ret;
}
static long do_socketcall(int num, long *vptr)
static inline void target_to_host_sockaddr(struct sockaddr *addr,
struct target_sockaddr *target_addr,
socklen_t len)
{
memcpy(addr, target_addr, len);
addr->sa_family = tswap16(target_addr->sa_family);
}
static inline void host_to_target_sockaddr(struct target_sockaddr *target_addr,
struct sockaddr *addr,
socklen_t len)
{
memcpy(target_addr, addr, len);
target_addr->sa_family = tswap16(addr->sa_family);
}
static inline void target_to_host_cmsg(struct msghdr *msgh,
struct target_msghdr *target_msgh)
{
struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
struct target_cmsghdr *target_cmsg = TARGET_CMSG_FIRSTHDR(target_msgh);
socklen_t space = 0;
while (cmsg && target_cmsg) {
void *data = CMSG_DATA(cmsg);
void *target_data = TARGET_CMSG_DATA(target_cmsg);
int len = tswapl(target_cmsg->cmsg_len)
- TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
space += CMSG_SPACE(len);
if (space > msgh->msg_controllen) {
space -= CMSG_SPACE(len);
gemu_log("Host cmsg overflow");
break;
}
cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
cmsg->cmsg_len = CMSG_LEN(len);
if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
memcpy(data, target_data, len);
} else {
int *fd = (int *)data;
int *target_fd = (int *)target_data;
int i, numfds = len / sizeof(int);
for (i = 0; i < numfds; i++)
fd[i] = tswap32(target_fd[i]);
}
cmsg = CMSG_NXTHDR(msgh, cmsg);
target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
}
msgh->msg_controllen = space;
}
static inline void host_to_target_cmsg(struct target_msghdr *target_msgh,
struct msghdr *msgh)
{
struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
struct target_cmsghdr *target_cmsg = TARGET_CMSG_FIRSTHDR(target_msgh);
socklen_t space = 0;
while (cmsg && target_cmsg) {
void *data = CMSG_DATA(cmsg);
void *target_data = TARGET_CMSG_DATA(target_cmsg);
int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
space += TARGET_CMSG_SPACE(len);
if (space > tswapl(target_msgh->msg_controllen)) {
space -= TARGET_CMSG_SPACE(len);
gemu_log("Target cmsg overflow");
break;
}
target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
target_cmsg->cmsg_len = tswapl(TARGET_CMSG_LEN(len));
if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
memcpy(target_data, data, len);
} else {
int *fd = (int *)data;
int *target_fd = (int *)target_data;
int i, numfds = len / sizeof(int);
for (i = 0; i < numfds; i++)
target_fd[i] = tswap32(fd[i]);
}
cmsg = CMSG_NXTHDR(msgh, cmsg);
target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
}
msgh->msg_controllen = tswapl(space);
}
static long do_setsockopt(int sockfd, int level, int optname,
void *optval, socklen_t optlen)
{
if (level == SOL_TCP) {
/* TCP options all take an 'int' value. */
int val;
if (optlen < sizeof(uint32_t))
return -EINVAL;
val = tswap32(*(uint32_t *)optval);
return get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
}
else if (level != SOL_SOCKET) {
gemu_log("Unsupported setsockopt level: %d\n", level);
return -ENOSYS;
}
switch (optname) {
/* Options with 'int' argument. */
case SO_DEBUG:
case SO_REUSEADDR:
case SO_TYPE:
case SO_ERROR:
case SO_DONTROUTE:
case SO_BROADCAST:
case SO_SNDBUF:
case SO_RCVBUF:
case SO_KEEPALIVE:
case SO_OOBINLINE:
case SO_NO_CHECK:
case SO_PRIORITY:
case SO_BSDCOMPAT:
case SO_PASSCRED:
case SO_TIMESTAMP:
case SO_RCVLOWAT:
case SO_RCVTIMEO:
case SO_SNDTIMEO:
{
int val;
if (optlen < sizeof(uint32_t))
return -EINVAL;
val = tswap32(*(uint32_t *)optval);
return get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
}
default:
gemu_log("Unsupported setsockopt SOL_SOCKET option: %d\n", optname);
return -ENOSYS;
}
}
static long do_getsockopt(int sockfd, int level, int optname,
void *optval, socklen_t *optlen)
{
gemu_log("getsockopt not yet supported\n");
return -ENOSYS;
}
static long do_socketcall(int num, int32_t *vptr)
{
long ret;
switch(num) {
case SOCKOP_socket:
ret = get_errno(socket(vptr[0], vptr[1], vptr[2]));
{
int domain = tswap32(vptr[0]);
int type = tswap32(vptr[1]);
int protocol = tswap32(vptr[2]);
ret = get_errno(socket(domain, type, protocol));
}
break;
case SOCKOP_bind:
ret = get_errno(bind(vptr[0], (struct sockaddr *)vptr[1], vptr[2]));
{
int sockfd = tswap32(vptr[0]);
void *target_addr = (void *)tswap32(vptr[1]);
socklen_t addrlen = tswap32(vptr[2]);
void *addr = alloca(addrlen);
target_to_host_sockaddr(addr, target_addr, addrlen);
ret = get_errno(bind(sockfd, addr, addrlen));
}
break;
case SOCKOP_connect:
ret = get_errno(connect(vptr[0], (struct sockaddr *)vptr[1], vptr[2]));
{
int sockfd = tswap32(vptr[0]);
void *target_addr = (void *)tswap32(vptr[1]);
socklen_t addrlen = tswap32(vptr[2]);
void *addr = alloca(addrlen);
target_to_host_sockaddr(addr, target_addr, addrlen);
ret = get_errno(connect(sockfd, addr, addrlen));
}
break;
case SOCKOP_listen:
ret = get_errno(listen(vptr[0], vptr[1]));
{
int sockfd = tswap32(vptr[0]);
int backlog = tswap32(vptr[1]);
ret = get_errno(listen(sockfd, backlog));
}
break;
case SOCKOP_accept:
{
socklen_t size;
size = tswap32(*(int32_t *)vptr[2]);
ret = get_errno(accept(vptr[0], (struct sockaddr *)vptr[1], &size));
if (!is_error(ret))
*(int32_t *)vptr[2] = size;
int sockfd = tswap32(vptr[0]);
void *target_addr = (void *)tswap32(vptr[1]);
uint32_t *target_addrlen = (void *)tswap32(vptr[2]);
socklen_t addrlen = tswap32(*target_addrlen);
void *addr = alloca(addrlen);
ret = get_errno(accept(sockfd, addr, &addrlen));
if (!is_error(ret)) {
host_to_target_sockaddr(target_addr, addr, addrlen);
*target_addrlen = tswap32(addrlen);
}
}
break;
case SOCKOP_getsockname:
{
socklen_t size;
size = tswap32(*(int32_t *)vptr[2]);
ret = get_errno(getsockname(vptr[0], (struct sockaddr *)vptr[1], &size));
if (!is_error(ret))
*(int32_t *)vptr[2] = size;
int sockfd = tswap32(vptr[0]);
void *target_addr = (void *)tswap32(vptr[1]);
uint32_t *target_addrlen = (void *)tswap32(vptr[2]);
socklen_t addrlen = tswap32(*target_addrlen);
void *addr = alloca(addrlen);
ret = get_errno(getsockname(sockfd, addr, &addrlen));
if (!is_error(ret)) {
host_to_target_sockaddr(target_addr, addr, addrlen);
*target_addrlen = tswap32(addrlen);
}
}
break;
case SOCKOP_getpeername:
{
socklen_t size;
size = tswap32(*(int32_t *)vptr[2]);
ret = get_errno(getpeername(vptr[0], (struct sockaddr *)vptr[1], &size));
if (!is_error(ret))
*(int32_t *)vptr[2] = size;
int sockfd = tswap32(vptr[0]);
void *target_addr = (void *)tswap32(vptr[1]);
uint32_t *target_addrlen = (void *)tswap32(vptr[2]);
socklen_t addrlen = tswap32(*target_addrlen);
void *addr = alloca(addrlen);
ret = get_errno(getpeername(sockfd, addr, &addrlen));
if (!is_error(ret)) {
host_to_target_sockaddr(target_addr, addr, addrlen);
*target_addrlen = tswap32(addrlen);
}
}
break;
case SOCKOP_socketpair:
{
int domain = tswap32(vptr[0]);
int type = tswap32(vptr[1]);
int protocol = tswap32(vptr[2]);
int32_t *target_tab = (void *)tswap32(vptr[3]);
int tab[2];
int32_t *target_tab = (int32_t *)vptr[3];
ret = get_errno(socketpair(vptr[0], vptr[1], vptr[2], tab));
ret = get_errno(socketpair(domain, type, protocol, tab));
if (!is_error(ret)) {
target_tab[0] = tswap32(tab[0]);
target_tab[1] = tswap32(tab[1]);
@@ -312,27 +526,64 @@ static long do_socketcall(int num, long *vptr)
}
break;
case SOCKOP_send:
ret = get_errno(send(vptr[0], (void *)vptr[1], vptr[2], vptr[3]));
{
int sockfd = tswap32(vptr[0]);
void *msg = (void *)tswap32(vptr[1]);
size_t len = tswap32(vptr[2]);
int flags = tswap32(vptr[3]);
ret = get_errno(send(sockfd, msg, len, flags));
}
break;
case SOCKOP_recv:
ret = get_errno(recv(vptr[0], (void *)vptr[1], vptr[2], vptr[3]));
{
int sockfd = tswap32(vptr[0]);
void *msg = (void *)tswap32(vptr[1]);
size_t len = tswap32(vptr[2]);
int flags = tswap32(vptr[3]);
ret = get_errno(recv(sockfd, msg, len, flags));
}
break;
case SOCKOP_sendto:
ret = get_errno(sendto(vptr[0], (void *)vptr[1], vptr[2], vptr[3],
(struct sockaddr *)vptr[4], vptr[5]));
{
int sockfd = tswap32(vptr[0]);
void *msg = (void *)tswap32(vptr[1]);
size_t len = tswap32(vptr[2]);
int flags = tswap32(vptr[3]);
void *target_addr = (void *)tswap32(vptr[4]);
socklen_t addrlen = tswap32(vptr[5]);
void *addr = alloca(addrlen);
target_to_host_sockaddr(addr, target_addr, addrlen);
ret = get_errno(sendto(sockfd, msg, len, flags, addr, addrlen));
}
break;
case SOCKOP_recvfrom:
{
socklen_t size;
size = tswap32(*(int32_t *)vptr[5]);
ret = get_errno(recvfrom(vptr[0], (void *)vptr[1], vptr[2],
vptr[3], (struct sockaddr *)vptr[4], &size));
if (!is_error(ret))
*(int32_t *)vptr[5] = size;
int sockfd = tswap32(vptr[0]);
void *msg = (void *)tswap32(vptr[1]);
size_t len = tswap32(vptr[2]);
int flags = tswap32(vptr[3]);
void *target_addr = (void *)tswap32(vptr[4]);
uint32_t *target_addrlen = (void *)tswap32(vptr[5]);
socklen_t addrlen = tswap32(*target_addrlen);
void *addr = alloca(addrlen);
ret = get_errno(recvfrom(sockfd, msg, len, flags, addr, &addrlen));
if (!is_error(ret)) {
host_to_target_sockaddr(target_addr, addr, addrlen);
*target_addrlen = tswap32(addrlen);
}
}
break;
case SOCKOP_shutdown:
ret = get_errno(shutdown(vptr[0], vptr[1]));
{
int sockfd = tswap32(vptr[0]);
int how = tswap32(vptr[1]);
ret = get_errno(shutdown(sockfd, how));
}
break;
case SOCKOP_sendmsg:
case SOCKOP_recvmsg:
@@ -344,11 +595,11 @@ static long do_socketcall(int num, long *vptr)
struct iovec *vec;
struct target_iovec *target_vec;
msgp = (void *)vptr[1];
msgp = (void *)tswap32(vptr[1]);
msg.msg_name = (void *)tswapl(msgp->msg_name);
msg.msg_namelen = tswapl(msgp->msg_namelen);
msg.msg_control = (void *)tswapl(msgp->msg_control);
msg.msg_controllen = tswapl(msgp->msg_controllen);
msg.msg_controllen = 2 * tswapl(msgp->msg_controllen);
msg.msg_control = alloca(msg.msg_controllen);
msg.msg_flags = tswap32(msgp->msg_flags);
count = tswapl(msgp->msg_iovlen);
@@ -361,17 +612,43 @@ static long do_socketcall(int num, long *vptr)
msg.msg_iovlen = count;
msg.msg_iov = vec;
fd = vptr[0];
flags = vptr[2];
if (num == SOCKOP_sendmsg)
ret = sendmsg(fd, &msg, flags);
else
ret = recvmsg(fd, &msg, flags);
ret = get_errno(ret);
fd = tswap32(vptr[0]);
flags = tswap32(vptr[2]);
if (num == SOCKOP_sendmsg) {
target_to_host_cmsg(&msg, msgp);
ret = get_errno(sendmsg(fd, &msg, flags));
} else {
ret = get_errno(recvmsg(fd, &msg, flags));
if (!is_error(ret))
host_to_target_cmsg(msgp, &msg);
}
}
break;
case SOCKOP_setsockopt:
{
int sockfd = tswap32(vptr[0]);
int level = tswap32(vptr[1]);
int optname = tswap32(vptr[2]);
void *optval = (void *)tswap32(vptr[3]);
socklen_t optlen = tswap32(vptr[4]);
ret = do_setsockopt(sockfd, level, optname, optval, optlen);
}
break;
case SOCKOP_getsockopt:
{
int sockfd = tswap32(vptr[0]);
int level = tswap32(vptr[1]);
int optname = tswap32(vptr[2]);
void *optval = (void *)tswap32(vptr[3]);
uint32_t *target_len = (void *)tswap32(vptr[4]);
socklen_t optlen = tswap32(*target_len);
ret = do_getsockopt(sockfd, level, optname, optval, &optlen);
if (!is_error(ret))
*target_len = tswap32(optlen);
}
break;
default:
gemu_log("Unsupported socketcall: %d\n", num);
ret = -ENOSYS;
@@ -960,7 +1237,27 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
ret = get_errno(unlink((const char *)arg1));
break;
case TARGET_NR_execve:
ret = get_errno(execve((const char *)arg1, (void *)arg2, (void *)arg3));
{
char **argp, **envp;
int argc = 0, envc = 0;
uint32_t *p;
char **q;
for (p = (void *)arg2; *p; p++)
argc++;
for (p = (void *)arg3; *p; p++)
envc++;
argp = alloca(argc * sizeof(void *));
envp = alloca(envc * sizeof(void *));
for (p = (void *)arg2, q = argp; *p; p++, q++)
*q = (void *)tswap32(*p);
for (p = (void *)arg3, q = envp; *p; p++, q++)
*q = (void *)tswap32(*p);
ret = get_errno(execve((const char *)arg1, argp, envp));
}
break;
case TARGET_NR_chdir:
ret = get_errno(chdir((const char *)arg1));
@@ -1484,7 +1781,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
case TARGET_NR_ioperm:
goto unimplemented;
case TARGET_NR_socketcall:
ret = do_socketcall(arg1, (long *)arg2);
ret = do_socketcall(arg1, (int32_t *)arg2);
break;
case TARGET_NR_syslog:
goto unimplemented;
@@ -1548,9 +1845,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
target_st->st_size = tswapl(st.st_size);
target_st->st_blksize = tswapl(st.st_blksize);
target_st->st_blocks = tswapl(st.st_blocks);
target_st->st_atime = tswapl(st.st_atime);
target_st->st_mtime = tswapl(st.st_mtime);
target_st->st_ctime = tswapl(st.st_ctime);
target_st->target_st_atime = tswapl(st.st_atime);
target_st->target_st_mtime = tswapl(st.st_mtime);
target_st->target_st_ctime = tswapl(st.st_ctime);
}
}
break;
@@ -1727,7 +2024,7 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
unsigned int nfds = arg2;
int timeout = arg3;
struct pollfd *pfd;
int i;
unsigned int i;
pfd = alloca(sizeof(struct pollfd) * nfds);
for(i = 0; i < nfds; i++) {
@@ -1940,9 +2237,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
target_st->st_size = tswapl(st.st_size);
target_st->st_blksize = tswapl(st.st_blksize);
target_st->st_blocks = tswapl(st.st_blocks);
target_st->st_atime = tswapl(st.st_atime);
target_st->st_mtime = tswapl(st.st_mtime);
target_st->st_ctime = tswapl(st.st_ctime);
target_st->target_st_atime = tswapl(st.st_atime);
target_st->target_st_mtime = tswapl(st.st_mtime);
target_st->target_st_ctime = tswapl(st.st_ctime);
}
}
break;

View File

@@ -19,6 +19,11 @@
#define SOCKOP_sendmsg 16
#define SOCKOP_recvmsg 17
struct target_sockaddr {
uint16_t sa_family;
uint8_t sa_data[14];
};
struct target_timeval {
target_long tv_sec;
target_long tv_usec;
@@ -49,6 +54,43 @@ struct target_msghdr {
unsigned int msg_flags;
};
struct target_cmsghdr {
target_long cmsg_len;
int cmsg_level;
int cmsg_type;
};
#define TARGET_CMSG_DATA(cmsg) ((unsigned char *) ((struct target_cmsghdr *) (cmsg) + 1))
#define TARGET_CMSG_NXTHDR(mhdr, cmsg) __target_cmsg_nxthdr (mhdr, cmsg)
#define TARGET_CMSG_FIRSTHDR(mhdr) \
((size_t) tswapl((mhdr)->msg_controllen) >= sizeof (struct target_cmsghdr) \
? (struct target_cmsghdr *) tswapl((mhdr)->msg_control) : (struct target_cmsghdr *) NULL)
#define TARGET_CMSG_ALIGN(len) (((len) + sizeof (target_long) - 1) \
& (size_t) ~(sizeof (target_long) - 1))
#define TARGET_CMSG_SPACE(len) (TARGET_CMSG_ALIGN (len) \
+ TARGET_CMSG_ALIGN (sizeof (struct target_cmsghdr)))
#define TARGET_CMSG_LEN(len) (TARGET_CMSG_ALIGN (sizeof (struct target_cmsghdr)) + (len))
static __inline__ struct target_cmsghdr *
__target_cmsg_nxthdr (struct target_msghdr *__mhdr, struct target_cmsghdr *__cmsg)
{
if (tswapl(__cmsg->cmsg_len) < sizeof (struct target_cmsghdr))
/* The kernel header does this so there may be a reason. */
return 0;
__cmsg = (struct target_cmsghdr *) ((unsigned char *) __cmsg
+ TARGET_CMSG_ALIGN (tswapl(__cmsg->cmsg_len)));
if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) tswapl(__mhdr->msg_control)
+ tswapl(__mhdr->msg_controllen))
|| ((unsigned char *) __cmsg + TARGET_CMSG_ALIGN (tswapl(__cmsg->cmsg_len))
> ((unsigned char *) tswapl(__mhdr->msg_control)
+ tswapl(__mhdr->msg_controllen))))
/* No more entries. */
return 0;
return __cmsg;
}
struct target_rusage {
struct target_timeval ru_utime; /* user time used */
struct target_timeval ru_stime; /* system time used */

View File

@@ -12,8 +12,9 @@
QEMU is an x86 processor emulator. Its purpose is to run x86 Linux
processes on non-x86 Linux architectures such as PowerPC or ARM. By
using dynamic translation it achieves a reasonnable speed while being
easy to port on new host CPUs. An obviously interesting x86 only process
is 'wine' (Windows emulation).
easy to port on new host CPUs. Its main goal is to be able to launch the
@code{Wine} Windows API emulator (@url{http://www.winehq.org}) on
non-x86 CPUs.
QEMU features:
@@ -21,12 +22,13 @@ QEMU features:
@item User space only x86 emulator.
@item Currently ported on i386 and PowerPC.
@item Currently ported on i386, PowerPC and S390.
@item Using dynamic translation for reasonnable speed.
@item Using dynamic translation to native code for reasonnable speed.
@item The virtual x86 CPU supports 16 bit and 32 bit addressing with segmentation.
User space LDT and GDT are emulated.
User space LDT and GDT are emulated. VM86 mode is also supported
(experimental).
@item Generic Linux system call converter, including most ioctls.
@@ -52,10 +54,6 @@ Current QEMU Limitations:
@item No support for self modifying code (yet). [Very few programs need that, a notable exception is QEMU itself !].
@item No VM86 mode (yet), althought the virtual
CPU has support for most of it. [VM86 support is useful to launch old 16
bit DOS programs with dosemu or wine].
@item No SSE/MMX support (yet).
@item No x86-64 support.
@@ -123,10 +121,10 @@ able to do:
qemu /usr/local/qemu-i386/bin/ls-i386
@end example
@item Download the binary x86 wine install
@item Download the binary x86 Wine install
(@file{qemu-i386-wine.tar.gz} on the QEMU web page).
@item Configure wine on your account. Look at the provided script
@item Configure Wine on your account. Look at the provided script
@file{/usr/local/qemu-i386/bin/wine-conf.sh}. Your previous
@code{$@{HOME@}/.wine} directory is saved to @code{$@{HOME@}/.wine.org}.
@@ -177,6 +175,13 @@ code, in particular the ELF file loader). EM86 was limited to an alpha
host and used a proprietary and slow interpreter (the interpreter part
of the FX!32 Digital Win32 code translator [5]).
TWIN [6] is a Windows API emulator like Wine. It is less accurate than
Wine but includes a protected mode x86 interpreter to launch x86 Windows
executables. Such an approach as greater potential because most of the
Windows API is executed natively but it is far more difficult to develop
because all the data structures and function parameters exchanged
between the API and the x86 code must be converted.
@section Portable dynamic translation
QEMU is a dynamic translator. When it first encounters a piece of code,
@@ -218,7 +223,7 @@ doing complicated register allocation.
Good CPU condition codes emulation (@code{EFLAGS} register on x86) is a
critical point to get good performances. QEMU uses lazy condition code
evaluation: instead of computing the condition codes after each x86
instruction, it store justs one operand (called @code{CC_CRC}), the
instruction, it just stores one operand (called @code{CC_SRC}), the
result (called @code{CC_DST}) and the type of operation (called
@code{CC_OP}).
@@ -231,7 +236,7 @@ generated simple instructions (see
the condition codes are not needed by the next instructions, no
condition codes are computed at all.
@section Translation CPU state optimisations
@section CPU state optimisations
The x86 CPU has many internal states which change the way it evaluates
instructions. In order to achieve a good speed, the translation phase
@@ -323,6 +328,10 @@ x86 emulator on Alpha-Linux.
DIGITAL FX!32: Running 32-Bit x86 Applications on Alpha NT, by Anton
Chernoff and Ray Hookway.
@item [6]
@url{http://www.willows.com/}, Windows API library emulation from
Willows Software.
@end table
@chapter Regression Tests
@@ -365,3 +374,9 @@ It is a simple benchmark. Care must be taken to interpret the results
because it mostly tests the ability of the virtual CPU to optimize the
@code{rol} x86 instruction and the condition code computations.
@section @file{runcom}
A very simple MSDOS emulator to test the Linux vm86() system call
emulation. The excellent 54 byte @file{pi_10.com} PI number calculator
can be launched with it. @file{pi_10.com} was written by Bertram
Felgenhauer (more information at @url{http://www.boo.net/~jasonp/pipage.html}).

View File

@@ -285,11 +285,11 @@ struct target_stat {
target_ulong st_size;
target_ulong st_blksize;
target_ulong st_blocks;
target_ulong st_atime;
target_ulong target_st_atime;
target_ulong __unused1;
target_ulong st_mtime;
target_ulong target_st_mtime;
target_ulong __unused2;
target_ulong st_ctime;
target_ulong target_st_ctime;
target_ulong __unused3;
target_ulong __unused4;
target_ulong __unused5;
@@ -320,13 +320,13 @@ struct target_stat64 {
target_ulong st_blocks; /* Number 512-byte blocks allocated. */
target_ulong __pad4; /* future possible st_blocks high bits */
target_ulong st_atime;
target_ulong target_st_atime;
target_ulong __pad5;
target_ulong st_mtime;
target_ulong target_st_mtime;
target_ulong __pad6;
target_ulong st_ctime;
target_ulong target_st_ctime;
target_ulong __pad7; /* will be high 32 bits of ctime someday */
unsigned long long st_ino;

View File

@@ -50,6 +50,12 @@ static inline void flush_icache_range(unsigned long start, unsigned long stop)
}
#endif
#ifdef __s390__
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
}
#endif
#ifdef __powerpc__
#define MIN_CACHE_LINE_SIZE 8 /* conservative value */