diff options
Diffstat (limited to 'arch/um/sys-x86_64')
-rw-r--r-- | arch/um/sys-x86_64/Makefile | 37 | ||||
-rw-r--r-- | arch/um/sys-x86_64/bugs.c | 122 | ||||
-rw-r--r-- | arch/um/sys-x86_64/delay.c | 26 | ||||
-rw-r--r-- | arch/um/sys-x86_64/fault.c | 23 | ||||
-rw-r--r-- | arch/um/sys-x86_64/mem.c | 25 | ||||
-rw-r--r-- | arch/um/sys-x86_64/ptrace.c | 138 | ||||
-rw-r--r-- | arch/um/sys-x86_64/ptrace_user.c | 51 | ||||
-rw-r--r-- | arch/um/sys-x86_64/sigcontext.c | 39 | ||||
-rw-r--r-- | arch/um/sys-x86_64/signal.c | 276 | ||||
-rw-r--r-- | arch/um/sys-x86_64/syscalls.c | 186 | ||||
-rw-r--r-- | arch/um/sys-x86_64/sysrq.c | 49 | ||||
-rw-r--r-- | arch/um/sys-x86_64/util/Makefile | 10 | ||||
-rw-r--r-- | arch/um/sys-x86_64/util/mk_sc.c | 58 | ||||
-rw-r--r-- | arch/um/sys-x86_64/util/mk_thread_kern.c | 21 | ||||
-rw-r--r-- | arch/um/sys-x86_64/util/mk_thread_user.c | 30 |
15 files changed, 1091 insertions, 0 deletions
diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile new file mode 100644 index 00000000000..2129e314355 --- /dev/null +++ b/arch/um/sys-x86_64/Makefile @@ -0,0 +1,37 @@ +# +# Copyright 2003 PathScale, Inc. +# +# Licensed under the GPL +# + +lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o mem.o memcpy.o \ + ptrace.o ptrace_user.o semaphore.o sigcontext.o signal.o \ + syscalls.o sysrq.o thunk.o + +USER_OBJS := ptrace_user.o sigcontext.o + +include arch/um/scripts/Makefile.rules + +SYMLINKS = bitops.c csum-copy.S csum-partial.c csum-wrappers.c memcpy.S \ + semaphore.c thunk.S + +# this needs to be before the foreach, because clean-files does not accept +# complete paths like $(src)/$f. +clean-files := $(SYMLINKS) + +targets += $(SYMLINKS) + +SYMLINKS := $(foreach f,$(SYMLINKS),$(obj)/$f) + +bitops.c-dir = lib +csum-copy.S-dir = lib +csum-partial.c-dir = lib +csum-wrappers.c-dir = lib +memcpy.S-dir = lib +semaphore.c-dir = kernel +thunk.S-dir = lib + +$(SYMLINKS): FORCE + $(call if_changed,make_link) + +CFLAGS_csum-partial.o := -Dcsum_partial=arch_csum_partial diff --git a/arch/um/sys-x86_64/bugs.c b/arch/um/sys-x86_64/bugs.c new file mode 100644 index 00000000000..fdce7ea98ca --- /dev/null +++ b/arch/um/sys-x86_64/bugs.c @@ -0,0 +1,122 @@ +/* + * Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ + +#include "linux/sched.h" +#include "linux/errno.h" +#include "asm/system.h" +#include "asm/pda.h" +#include "sysdep/ptrace.h" +#include "os.h" + +void arch_init_thread(void) +{ +} + +void arch_check_bugs(void) +{ +} + +int arch_handle_signal(int sig, union uml_pt_regs *regs) +{ + return(0); +} + +#define MAXTOKEN 64 + +/* Set during early boot */ +int host_has_cmov = 1; +int host_has_xmm = 0; + +static char token(int fd, char *buf, int len, char stop) +{ + int n; + char *ptr, *end, c; + + ptr = buf; + end = &buf[len]; + do { + n = os_read_file(fd, ptr, sizeof(*ptr)); + c = *ptr++; + if(n != sizeof(*ptr)){ + if(n == 0) return(0); + printk("Reading /proc/cpuinfo failed, err = %d\n", -n); + if(n < 0) + return(n); + else + return(-EIO); + } + } while((c != '\n') && (c != stop) && (ptr < end)); + + if(ptr == end){ + printk("Failed to find '%c' in /proc/cpuinfo\n", stop); + return(-1); + } + *(ptr - 1) = '\0'; + return(c); +} + +static int find_cpuinfo_line(int fd, char *key, char *scratch, int len) +{ + int n; + char c; + + scratch[len - 1] = '\0'; + while(1){ + c = token(fd, scratch, len - 1, ':'); + if(c <= 0) + return(0); + else if(c != ':'){ + printk("Failed to find ':' in /proc/cpuinfo\n"); + return(0); + } + + if(!strncmp(scratch, key, strlen(key))) + return(1); + + do { + n = os_read_file(fd, &c, sizeof(c)); + if(n != sizeof(c)){ + printk("Failed to find newline in " + "/proc/cpuinfo, err = %d\n", -n); + return(0); + } + } while(c != '\n'); + } + return(0); +} + +int cpu_feature(char *what, char *buf, int len) +{ + int fd, ret = 0; + + fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0); + if(fd < 0){ + printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd); + return(0); + } + + if(!find_cpuinfo_line(fd, what, buf, len)){ + printk("Couldn't find '%s' line in /proc/cpuinfo\n", what); + goto out_close; + } + + token(fd, buf, len, '\n'); + ret = 1; + + out_close: + os_close_file(fd); + return(ret); +} + +/* Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/sys-x86_64/delay.c b/arch/um/sys-x86_64/delay.c new file mode 100644 index 00000000000..f3b5187942b --- /dev/null +++ b/arch/um/sys-x86_64/delay.c @@ -0,0 +1,26 @@ +/* + * Copyright 2003 PathScale, Inc. + * Copied from arch/x86_64 + * + * Licensed under the GPL + */ + +#include "asm/processor.h" + +void __delay(unsigned long loops) +{ + unsigned long i; + + for(i = 0; i < loops; i++) ; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/sys-x86_64/fault.c b/arch/um/sys-x86_64/fault.c new file mode 100644 index 00000000000..cee1513c5c3 --- /dev/null +++ b/arch/um/sys-x86_64/fault.c @@ -0,0 +1,23 @@ +/* + * Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ + +#include "user.h" + +int arch_fixup(unsigned long address, void *sc_ptr) +{ + /* XXX search_exception_tables() */ + return(0); +} + +/* Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/sys-x86_64/mem.c b/arch/um/sys-x86_64/mem.c new file mode 100644 index 00000000000..3f59a0a4f15 --- /dev/null +++ b/arch/um/sys-x86_64/mem.c @@ -0,0 +1,25 @@ +/* + * Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ + +#include "linux/mm.h" +#include "asm/page.h" +#include "asm/mman.h" + +unsigned long vm_stack_flags = __VM_STACK_FLAGS; +unsigned long vm_stack_flags32 = __VM_STACK_FLAGS; +unsigned long vm_data_default_flags = __VM_DATA_DEFAULT_FLAGS; +unsigned long vm_data_default_flags32 = __VM_DATA_DEFAULT_FLAGS; +unsigned long vm_force_exec32 = PROT_EXEC; + +/* Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/sys-x86_64/ptrace.c b/arch/um/sys-x86_64/ptrace.c new file mode 100644 index 00000000000..8c146b2a1e0 --- /dev/null +++ b/arch/um/sys-x86_64/ptrace.c @@ -0,0 +1,138 @@ +/* + * Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ + +#define __FRAME_OFFSETS +#include "asm/ptrace.h" +#include "linux/sched.h" +#include "linux/errno.h" +#include "asm/elf.h" + +/* XXX x86_64 */ +unsigned long not_ss; +unsigned long not_ds; +unsigned long not_es; + +#define SC_SS(r) (not_ss) +#define SC_DS(r) (not_ds) +#define SC_ES(r) (not_es) + +/* determines which flags the user has access to. */ +/* 1 = access 0 = no access */ +#define FLAG_MASK 0x44dd5UL + +int putreg(struct task_struct *child, int regno, unsigned long value) +{ + unsigned long tmp; + +#ifdef TIF_IA32 + /* Some code in the 64bit emulation may not be 64bit clean. + Don't take any chances. */ + if (test_tsk_thread_flag(child, TIF_IA32)) + value &= 0xffffffff; +#endif + switch (regno){ + case FS: + case GS: + case DS: + case ES: + case SS: + case CS: + if (value && (value & 3) != 3) + return -EIO; + value &= 0xffff; + break; + + case FS_BASE: + case GS_BASE: + if (!((value >> 48) == 0 || (value >> 48) == 0xffff)) + return -EIO; + break; + + case EFLAGS: + value &= FLAG_MASK; + tmp = PT_REGS_EFLAGS(&child->thread.regs) & ~FLAG_MASK; + value |= tmp; + break; + } + + PT_REGS_SET(&child->thread.regs, regno, value); + return 0; +} + +unsigned long getreg(struct task_struct *child, int regno) +{ + unsigned long retval = ~0UL; + switch (regno) { + case FS: + case GS: + case DS: + case ES: + case SS: + case CS: + retval = 0xffff; + /* fall through */ + default: + retval &= PT_REG(&child->thread.regs, regno); +#ifdef TIF_IA32 + if (test_tsk_thread_flag(child, TIF_IA32)) + retval &= 0xffffffff; +#endif + } + return retval; +} + +void arch_switch(void) +{ +/* XXX + printk("arch_switch\n"); +*/ +} + +int is_syscall(unsigned long addr) +{ + panic("is_syscall"); +} + +int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu ) +{ + panic("dump_fpu"); + return(1); +} + +int get_fpregs(unsigned long buf, struct task_struct *child) +{ + panic("get_fpregs"); + return(0); +} + +int set_fpregs(unsigned long buf, struct task_struct *child) +{ + panic("set_fpregs"); + return(0); +} + +int get_fpxregs(unsigned long buf, struct task_struct *tsk) +{ + panic("get_fpxregs"); + return(0); +} + +int set_fpxregs(unsigned long buf, struct task_struct *tsk) +{ + panic("set_fxpregs"); + return(0); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/sys-x86_64/ptrace_user.c b/arch/um/sys-x86_64/ptrace_user.c new file mode 100644 index 00000000000..12e404c6fa4 --- /dev/null +++ b/arch/um/sys-x86_64/ptrace_user.c @@ -0,0 +1,51 @@ +/* + * Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ + +#include <stddef.h> +#include <errno.h> +#include "ptrace_user.h" +#include "user.h" +#include "kern_constants.h" + +int ptrace_getregs(long pid, unsigned long *regs_out) +{ + if(ptrace(PTRACE_GETREGS, pid, 0, regs_out) < 0) + return(-errno); + return(0); +} + +int ptrace_setregs(long pid, unsigned long *regs) +{ + if(ptrace(PTRACE_SETREGS, pid, 0, regs) < 0) + return(-errno); + return(0); +} + +void ptrace_pokeuser(unsigned long addr, unsigned long data) +{ + panic("ptrace_pokeuser"); +} + +#define DS 184 +#define ES 192 +#define __USER_DS 0x2b + +void arch_enter_kernel(void *task, int pid) +{ +} + +void arch_leave_kernel(void *task, int pid) +{ +#ifdef UM_USER_CS + if(ptrace(PTRACE_POKEUSR, pid, CS, UM_USER_CS) < 0) + printk("POKEUSR CS failed"); +#endif + + if(ptrace(PTRACE_POKEUSR, pid, DS, __USER_DS) < 0) + printk("POKEUSR DS failed"); + if(ptrace(PTRACE_POKEUSR, pid, ES, __USER_DS) < 0) + printk("POKEUSR ES failed"); +} diff --git a/arch/um/sys-x86_64/sigcontext.c b/arch/um/sys-x86_64/sigcontext.c new file mode 100644 index 00000000000..c88e64def6f --- /dev/null +++ b/arch/um/sys-x86_64/sigcontext.c @@ -0,0 +1,39 @@ +/* + * Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ + +#include <stdio.h> +#include <string.h> +#include <signal.h> +#include "user.h" + +void sc_to_sc(void *to_ptr, void *from_ptr) +{ + struct sigcontext *to = to_ptr, *from = from_ptr; + int size = sizeof(*to); /* + sizeof(struct _fpstate); */ + + memcpy(to, from, size); + if(from->fpstate != NULL) + to->fpstate = (struct _fpstate *) (to + 1); + + to->fpstate = NULL; +} + +unsigned long *sc_sigmask(void *sc_ptr) +{ + struct sigcontext *sc = sc_ptr; + + return(&sc->oldmask); +} + +/* Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c new file mode 100644 index 00000000000..5bc5a0d796e --- /dev/null +++ b/arch/um/sys-x86_64/signal.c @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2003 PathScale, Inc. + * Licensed under the GPL + */ + +#include "linux/stddef.h" +#include "linux/errno.h" +#include "linux/personality.h" +#include "linux/ptrace.h" +#include "asm/current.h" +#include "asm/uaccess.h" +#include "asm/sigcontext.h" +#include "asm/ptrace.h" +#include "asm/arch/ucontext.h" +#include "choose-mode.h" +#include "sysdep/ptrace.h" +#include "frame_kern.h" + +#ifdef CONFIG_MODE_SKAS + +#include "skas.h" + +static int copy_sc_from_user_skas(struct pt_regs *regs, + struct sigcontext *from) +{ + int err = 0; + +#define GETREG(regs, regno, sc, regname) \ + __get_user((regs)->regs.skas.regs[(regno) / sizeof(unsigned long)], \ + &(sc)->regname) + + err |= GETREG(regs, R8, from, r8); + err |= GETREG(regs, R9, from, r9); + err |= GETREG(regs, R10, from, r10); + err |= GETREG(regs, R11, from, r11); + err |= GETREG(regs, R12, from, r12); + err |= GETREG(regs, R13, from, r13); + err |= GETREG(regs, R14, from, r14); + err |= GETREG(regs, R15, from, r15); + err |= GETREG(regs, RDI, from, rdi); + err |= GETREG(regs, RSI, from, rsi); + err |= GETREG(regs, RBP, from, rbp); + err |= GETREG(regs, RBX, from, rbx); + err |= GETREG(regs, RDX, from, rdx); + err |= GETREG(regs, RAX, from, rax); + err |= GETREG(regs, RCX, from, rcx); + err |= GETREG(regs, RSP, from, rsp); + err |= GETREG(regs, RIP, from, rip); + err |= GETREG(regs, EFLAGS, from, eflags); + err |= GETREG(regs, CS, from, cs); + +#undef GETREG + + return(err); +} + +int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, + struct pt_regs *regs, unsigned long mask) +{ + unsigned long eflags; + int err = 0; + + err |= __put_user(0, &to->gs); + err |= __put_user(0, &to->fs); + +#define PUTREG(regs, regno, sc, regname) \ + __put_user((regs)->regs.skas.regs[(regno) / sizeof(unsigned long)], \ + &(sc)->regname) + + err |= PUTREG(regs, RDI, to, rdi); + err |= PUTREG(regs, RSI, to, rsi); + err |= PUTREG(regs, RBP, to, rbp); + err |= PUTREG(regs, RSP, to, rsp); + err |= PUTREG(regs, RBX, to, rbx); + err |= PUTREG(regs, RDX, to, rdx); + err |= PUTREG(regs, RCX, to, rcx); + err |= PUTREG(regs, RAX, to, rax); + err |= PUTREG(regs, R8, to, r8); + err |= PUTREG(regs, R9, to, r9); + err |= PUTREG(regs, R10, to, r10); + err |= PUTREG(regs, R11, to, r11); + err |= PUTREG(regs, R12, to, r12); + err |= PUTREG(regs, R13, to, r13); + err |= PUTREG(regs, R14, to, r14); + err |= PUTREG(regs, R15, to, r15); + err |= PUTREG(regs, CS, to, cs); /* XXX x86_64 doesn't do this */ + err |= __put_user(current->thread.err, &to->err); + err |= __put_user(current->thread.trap_no, &to->trapno); + err |= PUTREG(regs, RIP, to, rip); + err |= PUTREG(regs, EFLAGS, to, eflags); +#undef PUTREG + + err |= __put_user(mask, &to->oldmask); + err |= __put_user(current->thread.cr2, &to->cr2); + + return(err); +} + +#endif + +#ifdef CONFIG_MODE_TT +int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext *from, + int fpsize) +{ + struct _fpstate *to_fp, *from_fp; + unsigned long sigs; + int err; + + to_fp = to->fpstate; + from_fp = from->fpstate; + sigs = to->oldmask; + err = copy_from_user(to, from, sizeof(*to)); + to->oldmask = sigs; + return(err); +} + +int copy_sc_to_user_tt(struct sigcontext *to, struct _fpstate *fp, + struct sigcontext *from, int fpsize) +{ + struct _fpstate *to_fp, *from_fp; + int err; + + to_fp = (fp ? fp : (struct _fpstate *) (to + 1)); + from_fp = from->fpstate; + err = copy_to_user(to, from, sizeof(*to)); + return(err); +} + +#endif + +static int copy_sc_from_user(struct pt_regs *to, void __user *from) +{ + int ret; + + ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from, + sizeof(struct _fpstate)), + copy_sc_from_user_skas(to, from)); + return(ret); +} + +static int copy_sc_to_user(struct sigcontext *to, struct _fpstate *fp, + struct pt_regs *from, unsigned long mask) +{ + return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), + sizeof(*fp)), + copy_sc_to_user_skas(to, fp, from, mask))); +} + +struct rt_sigframe +{ + char *pretcode; + struct ucontext uc; + struct siginfo info; +}; + +#define round_down(m, n) (((m) / (n)) * (n)) + +int setup_signal_stack_si(unsigned long stack_top, int sig, + struct k_sigaction *ka, struct pt_regs * regs, + siginfo_t *info, sigset_t *set) +{ + struct rt_sigframe __user *frame; + struct _fpstate __user *fp = NULL; + int err = 0; + struct task_struct *me = current; + + frame = (struct rt_sigframe __user *) + round_down(stack_top - sizeof(struct rt_sigframe), 16) - 8; + frame -= 128; + + if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate))) + goto out; + +#if 0 /* XXX */ + if (save_i387(fp) < 0) + err |= -1; +#endif + if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) + goto out; + + if (ka->sa.sa_flags & SA_SIGINFO) { + err |= copy_siginfo_to_user(&frame->info, info); + if (err) + goto out; + } + + /* Create the ucontext. */ + err |= __put_user(0, &frame->uc.uc_flags); + err |= __put_user(0, &frame->uc.uc_link); + err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp); + err |= __put_user(sas_ss_flags(PT_REGS_SP(regs)), + &frame->uc.uc_stack.ss_flags); + err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size); + err |= copy_sc_to_user(&frame->uc.uc_mcontext, fp, regs, set->sig[0]); + err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate); + if (sizeof(*set) == 16) { + __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); + __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]); + } + else + err |= __copy_to_user(&frame->uc.uc_sigmask, set, + sizeof(*set)); + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + /* x86-64 should always use SA_RESTORER. */ + if (ka->sa.sa_flags & SA_RESTORER) + err |= __put_user(ka->sa.sa_restorer, &frame->pretcode); + else + /* could use a vstub here */ + goto out; + + if (err) + goto out; + + /* Set up registers for signal handler */ + { + struct exec_domain *ed = current_thread_info()->exec_domain; + if (unlikely(ed && ed->signal_invmap && sig < 32)) + sig = ed->signal_invmap[sig]; + } + + PT_REGS_RDI(regs) = sig; + /* In case the signal handler was declared without prototypes */ + PT_REGS_RAX(regs) = 0; + + /* This also works for non SA_SIGINFO handlers because they expect the + next argument after the signal number on the stack. */ + PT_REGS_RSI(regs) = (unsigned long) &frame->info; + PT_REGS_RDX(regs) = (unsigned long) &frame->uc; + PT_REGS_RIP(regs) = (unsigned long) ka->sa.sa_handler; + + PT_REGS_RSP(regs) = (unsigned long) frame; + out: + return(err); +} + +long sys_rt_sigreturn(struct pt_regs *regs) +{ + unsigned long sp = PT_REGS_SP(¤t->thread.regs); + struct rt_sigframe __user *frame = + (struct rt_sigframe __user *)(sp - 8); + struct ucontext __user *uc = &frame->uc; + sigset_t set; + + if(copy_from_user(&set, &uc->uc_sigmask, sizeof(set))) + goto segfault; + + sigdelsetmask(&set, ~_BLOCKABLE); + + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + if(copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext)) + goto segfault; + + /* Avoid ERESTART handling */ + PT_REGS_SYSCALL_NR(¤t->thread.regs) = -1; + return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); + + segfault: + force_sig(SIGSEGV, current); + return 0; +} +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/sys-x86_64/syscalls.c b/arch/um/sys-x86_64/syscalls.c new file mode 100644 index 00000000000..68205a03364 --- /dev/null +++ b/arch/um/sys-x86_64/syscalls.c @@ -0,0 +1,186 @@ +/* + * Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ + +#include "linux/linkage.h" +#include "linux/slab.h" +#include "linux/shm.h" +#include "asm/uaccess.h" +#define __FRAME_OFFSETS +#include "asm/ptrace.h" +#include "asm/unistd.h" +#include "asm/prctl.h" /* XXX This should get the constants from libc */ +#include "choose-mode.h" + +asmlinkage long wrap_sys_shmat(int shmid, char __user *shmaddr, int shmflg) +{ + unsigned long raddr; + + return do_shmat(shmid, shmaddr, shmflg, &raddr) ?: (long) raddr; +} + +#ifdef CONFIG_MODE_TT +extern int modify_ldt(int func, void *ptr, unsigned long bytecount); + +long sys_modify_ldt_tt(int func, void *ptr, unsigned long bytecount) +{ + /* XXX This should check VERIFY_WRITE depending on func, check this + * in i386 as well. + */ + if (!access_ok(VERIFY_READ, ptr, bytecount)) + return -EFAULT; + return(modify_ldt(func, ptr, bytecount)); +} +#endif + +#ifdef CONFIG_MODE_SKAS +extern int userspace_pid[]; + +long sys_modify_ldt_skas(int func, void *ptr, unsigned long bytecount) +{ + struct ptrace_ldt ldt; + void *buf; + int res, n; + + buf = kmalloc(bytecount, GFP_KERNEL); + if(buf == NULL) + return(-ENOMEM); + + res = 0; + + switch(func){ + case 1: + case 0x11: + res = copy_from_user(buf, ptr, bytecount); + break; + } + + if(res != 0){ + res = -EFAULT; + goto out; + } + + ldt = ((struct ptrace_ldt) { .func = func, + .ptr = buf, + .bytecount = bytecount }); +#warning Need to look up userspace_pid by cpu + res = ptrace(PTRACE_LDT, userspace_pid[0], 0, (unsigned long) &ldt); + if(res < 0) + goto out; + + switch(func){ + case 0: + case 2: + n = res; + res = copy_to_user(ptr, buf, n); + if(res != 0) + res = -EFAULT; + else + res = n; + break; + } + + out: + kfree(buf); + return(res); +} +#endif + +long sys_modify_ldt(int func, void *ptr, unsigned long bytecount) +{ + return(CHOOSE_MODE_PROC(sys_modify_ldt_tt, sys_modify_ldt_skas, func, + ptr, bytecount)); +} + +#ifdef CONFIG_MODE_TT +extern long arch_prctl(int code, unsigned long addr); + +static long arch_prctl_tt(int code, unsigned long addr) +{ + unsigned long tmp; + long ret; + + switch(code){ + case ARCH_SET_GS: + case ARCH_SET_FS: + ret = arch_prctl(code, addr); + break; + case ARCH_GET_FS: + case ARCH_GET_GS: + ret = arch_prctl(code, (unsigned long) &tmp); + if(!ret) + ret = put_user(tmp, &addr); + break; + default: + ret = -EINVAL; + break; + } + + return(ret); +} +#endif + +#ifdef CONFIG_MODE_SKAS + +static long arch_prctl_skas(int code, unsigned long addr) +{ + long ret = 0; + + switch(code){ + case ARCH_SET_GS: + current->thread.regs.regs.skas.regs[GS_BASE / sizeof(unsigned long)] = addr; + break; + case ARCH_SET_FS: + current->thread.regs.regs.skas.regs[FS_BASE / sizeof(unsigned long)] = addr; + break; + case ARCH_GET_FS: + ret = put_user(current->thread.regs.regs.skas.regs[GS / sizeof(unsigned long)], &addr); + break; + case ARCH_GET_GS: + ret = put_user(current->thread.regs.regs.skas.regs[FS / sizeof(unsigned \ +long)], &addr); + break; + default: + ret = -EINVAL; + break; + } + + return(ret); +} +#endif + +long sys_arch_prctl(int code, unsigned long addr) +{ + return(CHOOSE_MODE_PROC(arch_prctl_tt, arch_prctl_skas, code, addr)); +} + +long sys_clone(unsigned long clone_flags, unsigned long newsp, + void __user *parent_tid, void __user *child_tid) +{ + long ret; + + /* XXX: normal arch do here this pass, and also pass the regs to + * do_fork, instead of NULL. Currently the arch-independent code + * ignores these values, while the UML code (actually it's + * copy_thread) does the right thing. But this should change, + probably. */ + /*if (!newsp) + newsp = UPT_SP(current->thread.regs);*/ + current->thread.forking = 1; + ret = do_fork(clone_flags, newsp, NULL, 0, parent_tid, child_tid); + current->thread.forking = 0; + return(ret); +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/sys-x86_64/sysrq.c b/arch/um/sys-x86_64/sysrq.c new file mode 100644 index 00000000000..ddf74691a61 --- /dev/null +++ b/arch/um/sys-x86_64/sysrq.c @@ -0,0 +1,49 @@ +/* + * Copyright 2003 PathScale, Inc. + * + * Licensed under the GPL + */ + +#include "linux/kernel.h" +#include "linux/utsname.h" +#include "linux/module.h" +#include "asm/current.h" +#include "asm/ptrace.h" +#include "sysrq.h" + +void __show_regs(struct pt_regs * regs) +{ + printk("\n"); + print_modules(); + printk("Pid: %d, comm: %.20s %s %s\n", + current->pid, current->comm, print_tainted(), system_utsname.release); + printk("RIP: %04lx:[<%016lx>] ", PT_REGS_CS(regs) & 0xffff, + PT_REGS_RIP(regs)); + printk("\nRSP: %016lx EFLAGS: %08lx\n", PT_REGS_RSP(regs), + PT_REGS_EFLAGS(regs)); + printk("RAX: %016lx RBX: %016lx RCX: %016lx\n", + PT_REGS_RAX(regs), PT_REGS_RBX(regs), PT_REGS_RCX(regs)); + printk("RDX: %016lx RSI: %016lx RDI: %016lx\n", + PT_REGS_RDX(regs), PT_REGS_RSI(regs), PT_REGS_RDI(regs)); + printk("RBP: %016lx R08: %016lx R09: %016lx\n", + PT_REGS_RBP(regs), PT_REGS_R8(regs), PT_REGS_R9(regs)); + printk("R10: %016lx R11: %016lx R12: %016lx\n", + PT_REGS_R10(regs), PT_REGS_R11(regs), PT_REGS_R12(regs)); + printk("R13: %016lx R14: %016lx R15: %016lx\n", + PT_REGS_R13(regs), PT_REGS_R14(regs), PT_REGS_R15(regs)); +} + +void show_regs(struct pt_regs *regs) +{ + __show_regs(regs); + show_trace((unsigned long *) ®s); +} + +/* Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff --git a/arch/um/sys-x86_64/util/Makefile b/arch/um/sys-x86_64/util/Makefile new file mode 100644 index 00000000000..00260798086 --- /dev/null +++ b/arch/um/sys-x86_64/util/Makefile @@ -0,0 +1,10 @@ +# Copyright 2003 - 2004 Pathscale, Inc +# Released under the GPL + +hostprogs-y := mk_sc mk_thread +always := $(hostprogs-y) + +mk_thread-objs := mk_thread_kern.o mk_thread_user.o + +HOSTCFLAGS_mk_thread_kern.o := $(CFLAGS) $(CPPFLAGS) +HOSTCFLAGS_mk_thread_user.o := $(USER_CFLAGS) diff --git a/arch/um/sys-x86_64/util/mk_sc.c b/arch/um/sys-x86_64/util/mk_sc.c new file mode 100644 index 00000000000..c236e213918 --- /dev/null +++ b/arch/um/sys-x86_64/util/mk_sc.c @@ -0,0 +1,58 @@ +/* Copyright (C) 2003 - 2004 PathScale, Inc + * Released under the GPL + */ + +#include <stdio.h> +#include <signal.h> +#include <linux/stddef.h> + +#define SC_OFFSET(name, field) \ + printf("#define " name \ + "(sc) *((unsigned long *) &(((char *) (sc))[%ld]))\n",\ + offsetof(struct sigcontext, field)) + +#define SC_FP_OFFSET(name, field) \ + printf("#define " name \ + "(sc) *((unsigned long *) &(((char *) (SC_FPSTATE(sc)))[%ld]))\n",\ + offsetof(struct _fpstate, field)) + +#define SC_FP_OFFSET_PTR(name, field, type) \ + printf("#define " name \ + "(sc) ((" type " *) &(((char *) (SC_FPSTATE(sc)))[%d]))\n",\ + offsetof(struct _fpstate, field)) + +int main(int argc, char **argv) +{ + SC_OFFSET("SC_RBX", rbx); + SC_OFFSET("SC_RCX", rcx); + SC_OFFSET("SC_RDX", rdx); + SC_OFFSET("SC_RSI", rsi); + SC_OFFSET("SC_RDI", rdi); + SC_OFFSET("SC_RBP", rbp); + SC_OFFSET("SC_RAX", rax); + SC_OFFSET("SC_R8", r8); + SC_OFFSET("SC_R9", r9); + SC_OFFSET("SC_R10", r10); + SC_OFFSET("SC_R11", r11); + SC_OFFSET("SC_R12", r12); + SC_OFFSET("SC_R13", r13); + SC_OFFSET("SC_R14", r14); + SC_OFFSET("SC_R15", r15); + SC_OFFSET("SC_IP", rip); + SC_OFFSET("SC_SP", rsp); + SC_OFFSET("SC_CR2", cr2); + SC_OFFSET("SC_ERR", err); + SC_OFFSET("SC_TRAPNO", trapno); + SC_OFFSET("SC_CS", cs); + SC_OFFSET("SC_FS", fs); + SC_OFFSET("SC_GS", gs); + SC_OFFSET("SC_EFLAGS", eflags); + SC_OFFSET("SC_SIGMASK", oldmask); +#if 0 + SC_OFFSET("SC_ORIG_RAX", orig_rax); + SC_OFFSET("SC_DS", ds); + SC_OFFSET("SC_ES", es); + SC_OFFSET("SC_SS", ss); +#endif + return(0); +} diff --git a/arch/um/sys-x86_64/util/mk_thread_kern.c b/arch/um/sys-x86_64/util/mk_thread_kern.c new file mode 100644 index 00000000000..a281673f02b --- /dev/null +++ b/arch/um/sys-x86_64/util/mk_thread_kern.c @@ -0,0 +1,21 @@ +#include "linux/config.h" +#include "linux/stddef.h" +#include "linux/sched.h" + +extern void print_head(void); +extern void print_constant_ptr(char *name, int value); +extern void print_constant(char *name, char *type, int value); +extern void print_tail(void); + +#define THREAD_OFFSET(field) offsetof(struct task_struct, thread.field) + +int main(int argc, char **argv) +{ + print_head(); +#ifdef CONFIG_MODE_TT + print_constant("TASK_EXTERN_PID", "int", THREAD_OFFSET(mode.tt.extern_pid)); +#endif + print_tail(); + return(0); +} + diff --git a/arch/um/sys-x86_64/util/mk_thread_user.c b/arch/um/sys-x86_64/util/mk_thread_user.c new file mode 100644 index 00000000000..7989725568b --- /dev/null +++ b/arch/um/sys-x86_64/util/mk_thread_user.c @@ -0,0 +1,30 @@ +#include <stdio.h> + +void print_head(void) +{ + printf("/*\n"); + printf(" * Generated by mk_thread\n"); + printf(" */\n"); + printf("\n"); + printf("#ifndef __UM_THREAD_H\n"); + printf("#define __UM_THREAD_H\n"); + printf("\n"); +} + +void print_constant_ptr(char *name, int value) +{ + printf("#define %s(task) ((unsigned long *) " + "&(((char *) (task))[%d]))\n", name, value); +} + +void print_constant(char *name, char *type, int value) +{ + printf("#define %s(task) *((%s *) &(((char *) (task))[%d]))\n", name, type, + value); +} + +void print_tail(void) +{ + printf("\n"); + printf("#endif\n"); +} |