Commit 67867308 authored by bellard's avatar bellard
Browse files

PowerPC target support (Jocelyn Mayer) - added better support for uid16


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@474 c046a42c-6fe2-441c-8c8c-71466251a162
parent 28b6751f
......@@ -9,7 +9,8 @@ version 0.5.1:
- IRET and INT fixes in VM86 mode with IOPL=3
- Port I/Os use TSS io map
- Full task switching/task gate support
- added verr, verw, arpl
- added verr, verw, arpl, fcmovxx
- PowerPC target support (Jocelyn Mayer)
version 0.5.0:
......
......@@ -146,6 +146,10 @@ ifeq ($(TARGET_ARCH), i386)
LIBOBJS+=helper.o helper2.o
endif
ifeq ($(TARGET_ARCH), ppc)
LIBOBJS+=helper.o
endif
# NOTE: the disassembler code is only needed for debugging
LIBOBJS+=disas.o
ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
......
......@@ -27,7 +27,7 @@ ar="ar"
make="make"
strip="strip"
cpu=`uname -m`
target_list="i386-user i386 i386-softmmu arm-user sparc-user"
target_list="i386-user i386 i386-softmmu arm-user sparc-user ppc-user"
case "$cpu" in
i386|i486|i586|i686|i86pc|BePC)
cpu="i386"
......@@ -322,6 +322,7 @@ config_h=$target_dir/config.h
target_cpu=`echo $target | cut -d '-' -f 1`
target_bigendian="no"
[ "$target_cpu" = "sparc" ] && target_bigendian=yes
[ "$target_cpu" = "ppc" ] && target_bigendian=yes
target_softmmu="no"
if expr $target : '.*-softmmu' > /dev/null ; then
target_softmmu="yes"
......@@ -358,6 +359,10 @@ elif test "$target_cpu" = "sparc" ; then
echo "TARGET_ARCH=sparc" >> $config_mak
echo "#define TARGET_ARCH \"sparc\"" >> $config_h
echo "#define TARGET_SPARC 1" >> $config_h
elif test "$target_cpu" = "ppc" ; then
echo "TARGET_ARCH=ppc" >> $config_mak
echo "#define TARGET_ARCH \"ppc\"" >> $config_h
echo "#define TARGET_PPC 1" >> $config_h
else
echo "Unsupported target CPU"
exit 1
......
......@@ -395,6 +395,15 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
#define cpu_interrupt cpu_sparc_interrupt
#define cpu_signal_handler cpu_sparc_signal_handler
#elif defined(TARGET_PPC)
#define CPUState CPUPPCState
#define cpu_init cpu_ppc_init
#define cpu_exec cpu_ppc_exec
#define cpu_gen_code cpu_ppc_gen_code
#define cpu_interrupt cpu_ppc_interrupt
#define cpu_signal_handler cpu_ppc_signal_handler
#else
#error unsupported target CPU
......
......@@ -133,6 +133,7 @@ int cpu_exec(CPUState *env1)
env->cpsr = psr & ~0xf0000000;
}
#elif defined(TARGET_SPARC)
#elif defined(TARGET_PPC)
#else
#error unsupported target CPU
#endif
......@@ -228,6 +229,8 @@ int cpu_exec(CPUState *env1)
env->cpsr &= ~0xf0000000;
#elif defined(TARGET_SPARC)
cpu_sparc_dump_state (env, logfile, 0);
#elif defined(TARGET_PPC)
cpu_ppc_dump_state(env, logfile, 0);
#else
#error unsupported target CPU
#endif
......@@ -246,13 +249,17 @@ int cpu_exec(CPUState *env1)
cs_base = 0;
pc = (uint8_t *)env->regs[15];
#elif defined(TARGET_SPARC)
flags = 0;
cs_base = 0;
if (env->npc) {
env->pc = env->npc;
env->npc = 0;
}
pc = (uint8_t *) env->pc;
flags = 0;
cs_base = 0;
if (env->npc) {
env->pc = env->npc;
env->npc = 0;
}
pc = (uint8_t *) env->pc;
#elif defined(TARGET_PPC)
flags = 0;
cs_base = 0;
pc = (uint8_t *)env->nip;
#else
#error unsupported CPU
#endif
......@@ -376,6 +383,7 @@ int cpu_exec(CPUState *env1)
#elif defined(TARGET_ARM)
env->cpsr = compute_cpsr();
#elif defined(TARGET_SPARC)
#elif defined(TARGET_PPC)
#else
#error unsupported target CPU
#endif
......@@ -513,6 +521,43 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
{
return 0;
}
#elif defined (TARGET_PPC)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set)
{
TranslationBlock *tb;
#if 0
if (cpu_single_env)
env = cpu_single_env; /* XXX: find a correct solution for multithread */
#endif
#if defined(DEBUG_SIGNAL)
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(address)) {
return 1;
}
/* now we have a real cpu fault */
tb = tb_find_pc(pc);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
cpu_restore_state(tb, env, pc);
}
#if 0
printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
env->eip, env->cr[2], env->error_code);
#endif
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
raise_exception_err(EXCP_PROGRAM, env->error_code);
/* never comes here */
return 1;
}
#else
#error unsupported target CPU
#endif
......
......@@ -171,6 +171,8 @@ void disas(FILE *out, void *code, unsigned long size, int is_host, int flags)
print_insn = print_insn_arm;
#elif defined(TARGET_SPARC)
print_insn = print_insn_sparc;
#elif defined(TARGET_PPC)
print_insn = print_insn_ppc;
#else
fprintf(out, "Asm output not supported on this arch\n");
return;
......
......@@ -17,6 +17,9 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#if !defined(__DYNGEN_EXEC_H__)
#define __DYNGEN_EXEC_H__
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
......@@ -27,6 +30,19 @@ typedef signed short int16_t;
typedef signed int int32_t;
typedef signed long long int64_t;
#define INT8_MIN (-128)
#define INT16_MIN (-32767-1)
#define INT32_MIN (-2147483647-1)
#define INT64_MIN (-(int64_t)(9223372036854775807)-1)
#define INT8_MAX (127)
#define INT16_MAX (32767)
#define INT32_MAX (2147483647)
#define INT64_MAX ((int64_t)(9223372036854775807))
#define UINT8_MAX (255)
#define UINT16_MAX (65535)
#define UINT32_MAX (4294967295U)
#define UINT64_MAX ((uint64_t)(18446744073709551615))
#define bswap32(x) \
({ \
uint32_t __x = (x); \
......@@ -191,3 +207,5 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
#ifdef __mc68000
#define EXIT_TB() asm volatile ("rts")
#endif
#endif /* !defined(__DYNGEN_EXEC_H__) */
......@@ -104,6 +104,46 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i
#endif
#ifdef TARGET_PPC
#define ELF_START_MMAP 0x80000000
#define elf_check_arch(x) ( (x) == EM_PPC )
#define ELF_CLASS ELFCLASS32
#ifdef TARGET_WORDS_BIGENDIAN
#define ELF_DATA ELFDATA2MSB
#else
#define ELF_DATA ELFDATA2LSB
#endif
#define ELF_ARCH EM_PPC
/* Note that isn't exactly what regular kernel does
* but this is what the ABI wants and is needed to allow
* execution of PPC BSD programs.
*/
#define ELF_PLAT_INIT(_r) \
do { \
unsigned long *pos = (unsigned long *)bprm->p, tmp = 1; \
_r->gpr[3] = bprm->argc; \
_r->gpr[4] = (unsigned long)++pos; \
for (; tmp != 0; pos++) \
tmp = *pos; \
_r->gpr[5] = (unsigned long)pos; \
} while (0)
static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
{
_regs->msr = 1 << MSR_PR; /* Set user mode */
_regs->gpr[1] = infop->start_stack;
_regs->nip = infop->entry;
}
#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE 4096
#endif
#include "elf.h"
/*
......
......@@ -324,6 +324,127 @@ void cpu_loop (CPUSPARCState *env)
#endif
#ifdef TARGET_PPC
void cpu_loop(CPUPPCState *env)
{
int trapnr;
target_siginfo_t info;
for(;;) {
trapnr = cpu_ppc_exec(env);
switch(trapnr) {
case EXCP_NONE:
case EXCP_INTERRUPT:
case EXCP_MTMSR: /* mtmsr instruction: */
case EXCP_BRANCH: /* branch instruction */
/* Single step mode */
break;
#if 0
case EXCP_RESET: /* System reset */
fprintf(stderr, "RESET asked... Stop emulation\n");
cpu_ppc_dump_state(env, stderr, 0);
abort();
#endif
case EXCP_MACHINE_CHECK: /* Machine check exception */
fprintf(stderr, "Machine check exeption... "
"See you in kernel code !\n");
cpu_ppc_dump_state(env, stderr, 0);
abort();
case EXCP_DSI: /* Impossible memory access */
fprintf(stderr, "Invalid memory access\n");
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPN;
info._sifields._sigfault._addr = env->nip;
queue_signal(info.si_signo, &info);
break;
case EXCP_ISI: /* Impossible instruction fetch */
fprintf(stderr, "Invalid instruction fetch\n");
info.si_signo = SIGBUS;
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPN;
info._sifields._sigfault._addr = env->nip;
queue_signal(info.si_signo, &info);
break;
case EXCP_EXTERNAL: /* External interruption */
fprintf(stderr, "External access exeption\n");
cpu_ppc_dump_state(env, stderr, 0);
abort();
case EXCP_ALIGN: /* Alignment exception */
fprintf(stderr, "Alignment exception\n");
cpu_ppc_dump_state(env, stderr, 0);
abort();
case EXCP_PROGRAM: /* Program exception */
fprintf(stderr, "Program exception\n");
cpu_ppc_dump_state(env, stderr, 0);
abort();
break;
/* Trap */
case EXCP_TRAP: /* Trap */
case EXCP_TRACE: /* Trace exception (optional) */
info.si_signo = SIGTRAP;
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPN;
info._sifields._sigfault._addr = env->nip;
queue_signal(info.si_signo, &info);
break;
/* Invalid instruction */
case EXCP_INVAL:
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPN;
info._sifields._sigfault._addr = env->nip;
queue_signal(info.si_signo, &info);
break;
/* Privileged instruction */
case EXCP_PRIV: /* Privileged instruction */
info.si_signo = SIGILL;
info.si_errno = 0;
info.si_code = TARGET_ILL_ILLOPN;
info._sifields._sigfault._addr = env->nip;
queue_signal(info.si_signo, &info);
break;
case EXCP_NO_FP: /* No floating point */
case EXCP_DECR: /* Decrementer exception */
case EXCP_RESA: /* Implementation specific */
case EXCP_RESB: /* Implementation specific */
case EXCP_FP_ASSIST: /* Floating-point assist (optional) */
fprintf(stderr, "Misc expt...\n");
cpu_ppc_dump_state(env, stderr, 0);
abort();
case EXCP_SYSCALL:
{
uint32_t ret;
/* system call */
/* WARNING:
* PPC ABI uses overflow flag in cr0 to signal an error
* in syscalls.
*/
env->crf[0] &= ~0x1;
ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
env->gpr[5], env->gpr[6], env->gpr[7],
env->gpr[8]);
if (ret > (uint32_t)(-515)) {
env->crf[0] |= 0x1;
ret = -ret;
}
env->gpr[3] = ret;
break;
}
default:
// error:
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
trapnr);
cpu_ppc_dump_state(env, stderr, 0);
abort();
}
process_pending_signals(env);
}
}
#endif
void usage(void)
{
printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n"
......@@ -517,6 +638,16 @@ int main(int argc, char **argv)
#elif defined(TARGET_SPARC)
env->pc = regs->u_regs[0];
env->regwptr[6] = regs->u_regs[1]-0x40;
#elif defined(TARGET_PPC)
{
int i;
for (i = 0; i < 32; i++)
env->msr[i] = (regs->msr >> i) & 1;
env->nip = regs->nip;
for(i = 0; i < 32; i++) {
env->gpr[i] = regs->gpr[i];
}
}
#else
#error unsupported target CPU
#endif
......
......@@ -65,6 +65,11 @@
//#define DEBUG
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
/* 16 bit uid wrappers emulation */
#define USE_UID16
#endif
//#include <linux/msdos_fs.h>
#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2])
#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2])
......@@ -1264,7 +1269,16 @@ int do_fork(CPUState *env, unsigned int flags, unsigned long newsp)
new_env->regs[13] = newsp;
new_env->regs[0] = 0;
#elif defined(TARGET_SPARC)
printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
#elif defined(TARGET_PPC)
if (!newsp)
newsp = env->gpr[1];
new_env->gpr[1] = newsp;
{
int i;
for (i = 7; i < 32; i++)
new_env->gpr[i] = 0;
}
#else
#error unsupported target CPU
#endif
......@@ -1325,11 +1339,41 @@ static long do_fcntl(int fd, int cmd, unsigned long arg)
return ret;
}
#ifdef USE_UID16
#define high2lowuid(x) (x)
#define high2lowgid(x) (x)
#define low2highuid(x) (x)
#define low2highgid(x) (x)
static inline int high2lowuid(int uid)
{
if (uid > 65535)
return 65534;
else
return uid;
}
static inline int high2lowgid(int gid)
{
if (gid > 65535)
return 65534;
else
return gid;
}
static inline int low2highuid(int uid)
{
if ((int16_t)uid == -1)
return -1;
else
return uid;
}
static inline int low2highgid(int gid)
{
if ((int16_t)gid == -1)
return -1;
else
return gid;
}
#endif /* USE_UID16 */
void syscall_init(void)
{
......@@ -1472,9 +1516,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
case TARGET_NR_chmod:
ret = get_errno(chmod((const char *)arg1, arg2));
break;
case TARGET_NR_lchown:
ret = get_errno(chown((const char *)arg1, arg2, arg3));
break;
#ifdef TARGET_NR_break
case TARGET_NR_break:
goto unimplemented;
......@@ -1495,12 +1536,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
case TARGET_NR_umount:
ret = get_errno(umount((const char *)arg1));
break;
case TARGET_NR_setuid:
ret = get_errno(setuid(low2highuid(arg1)));
break;
case TARGET_NR_getuid:
ret = get_errno(getuid());
break;
case TARGET_NR_stime:
{
int *time_ptr = (int *)arg1;
......@@ -1596,20 +1631,9 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
case TARGET_NR_prof:
goto unimplemented;
#endif
case TARGET_NR_setgid:
ret = get_errno(setgid(low2highgid(arg1)));
break;
case TARGET_NR_getgid:
ret = get_errno(getgid());
break;
case TARGET_NR_signal:
goto unimplemented;
case TARGET_NR_geteuid:
ret = get_errno(geteuid());
break;
case TARGET_NR_getegid:
ret = get_errno(getegid());
break;
case TARGET_NR_acct:
goto unimplemented;
case TARGET_NR_umount2:
......@@ -1844,12 +1868,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
/* NOTE: ret is eax, so not transcoding must be done */
ret = do_rt_sigreturn(cpu_env);
break;
case TARGET_NR_setreuid:
ret = get_errno(setreuid(arg1, arg2));
break;
case TARGET_NR_setregid:
ret = get_errno(setregid(arg1, arg2));
break;
case TARGET_NR_sethostname:
ret = get_errno(sethostname((const char *)arg1, arg2));
break;
......@@ -1906,34 +1924,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
ret = get_errno(settimeofday(&tv, NULL));
}
break;
case TARGET_NR_getgroups:
{
int gidsetsize = arg1;
uint16_t *target_grouplist = (void *)arg2;
gid_t *grouplist;
int i;
grouplist = alloca(gidsetsize * sizeof(gid_t));
ret = get_errno(getgroups(gidsetsize, grouplist));
if (!is_error(ret)) {
for(i = 0;i < gidsetsize; i++)
target_grouplist[i] = tswap16(grouplist[i]);
}
}
break;
case TARGET_NR_setgroups:
{
int gidsetsize = arg1;
uint16_t *target_grouplist = (void *)arg2;
gid_t *grouplist;
int i;
grouplist = alloca(gidsetsize * sizeof(gid_t));
for(i = 0;i < gidsetsize; i++)
grouplist[i] = tswap16(target_grouplist[i]);
ret = get_errno(setgroups(gidsetsize, grouplist));
}
break;
case TARGET_NR_select:
{
struct target_sel_arg_struct *sel = (void *)arg1;
......@@ -2026,9 +2016,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
case TARGET_NR_fchmod:
ret = get_errno(fchmod(arg1, arg2));
break;
case TARGET_NR_fchown:
ret = get_errno(fchown(arg1, arg2, arg3));
break;
case TARGET_NR_getpriority:
ret = get_errno(getpriority(arg1, arg2));
break;
......@@ -2121,10 +2108,16 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
struct target_stat *target_st = (void *)arg2;
target_st->st_dev = tswap16(st.st_dev);
target_st->st_ino = tswapl(st.st_ino);
#if defined(TARGET_PPC)
target_st->st_mode = tswapl(st.st_mode); /* XXX: check this */
target_st->st_uid = tswap32(st.st_uid);
target_st->st_gid = tswap32(st.st_gid);
#else
target_st->st_mode = tswap16(st.st_mode);
target_st->st_nlink = tswap16(st.st_nlink);
target_st->st_uid = tswap16(st.st_uid);
target_st->st_gid = tswap16(st.st_gid);
#endif
target_st->st_nlink = tswap16(st.st_nlink);
target_st->st_rdev = tswap16(st.st_rdev);
target_st->st_size = tswapl(st.st_size);
target_st->st_blksize = tswapl(st.st_blksize);
......@@ -2230,12 +2223,6 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
break;
case TARGET_NR_afs_syscall:
goto unimplemented;
case TARGET_NR_setfsuid:
ret = get_errno(setfsuid(arg1));
break;
case TARGET_NR_setfsgid:
ret = get_errno(setfsgid(arg1));
break;
case TARGET_NR__llseek:
{
int64_t res;
......@@ -2465,52 +2452,13 @@ long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
}
}
break;
#ifdef TARGET_NR_setresuid
case TARGET_NR_setresuid:
ret = get_errno(setresuid(low2highuid(arg1),
low2highuid(arg2),
low2highuid(arg3)));
break;
#endif
#ifdef TARGET_NR_getresuid
case TARGET_NR_getresuid:
{
int ruid, euid, suid;
ret = get_errno(getresuid(&ruid, &euid, &suid));
if (!is_error(ret)) {
*(uint16_t *)arg1 = tswap16(high2lowuid(ruid));
*(uint16_t *)arg2 = tswap16(high2lowuid(euid));
*(uint16_t *)arg3 = tswap16(high2lowuid(suid));
}
}
break;
#endif
#ifdef TARGET_NR_getresgid
case TARGET_NR_setresgid:
ret = get_errno(setresgid(low2highgid(arg1),
low2highgid(arg2),
low2highgid(arg3)));
break;
#endif
#ifdef TARGET_NR_getresgid