Index: linux-2.6.10/lib/Kconfig.debug =================================================================== --- linux-2.6.10.orig/lib/Kconfig.debug 2004-12-25 05:35:24.000000000 +0800 +++ linux-2.6.10/lib/Kconfig.debug 2005-04-07 22:05:29.475761192 +0800 @@ -23,7 +23,6 @@ config MAGIC_SYSRQ bool "Magic SysRq key" depends on DEBUG_KERNEL && (H8300 || M68KNOMMU || V850) - depends (USERMODE && MCONSOLE) help Enables console device to interpret special characters as commands to dump state information. Index: linux-2.6.10/mm/mprotect.c =================================================================== --- linux-2.6.10.orig/mm/mprotect.c 2004-12-25 05:35:50.000000000 +0800 +++ linux-2.6.10/mm/mprotect.c 2005-04-07 22:05:29.475761192 +0800 @@ -93,19 +93,20 @@ { pgd_t *dir; unsigned long beg = start; + struct mm_struct * mm = vma->vm_mm; - dir = pgd_offset(current->mm, start); + dir = pgd_offset(mm, start); flush_cache_range(vma, beg, end); if (start >= end) BUG(); - spin_lock(¤t->mm->page_table_lock); + spin_lock(&mm->page_table_lock); do { change_pmd_range(dir, start, end - start, newprot); start = (start + PGDIR_SIZE) & PGDIR_MASK; dir++; } while (start && (start < end)); flush_tlb_range(vma, beg, end); - spin_unlock(¤t->mm->page_table_lock); + spin_unlock(&mm->page_table_lock); return; } @@ -190,8 +191,9 @@ return error; } -asmlinkage long -sys_mprotect(unsigned long start, size_t len, unsigned long prot) +long +do_mprotect(struct mm_struct *mm, unsigned long start, size_t len, + unsigned long prot) { unsigned long vm_flags, nstart, end, tmp; struct vm_area_struct *vma, *prev; @@ -220,9 +222,9 @@ vm_flags = calc_vm_prot_bits(prot); - down_write(¤t->mm->mmap_sem); + down_write(&mm->mmap_sem); - vma = find_vma_prev(current->mm, start, &prev); + vma = find_vma_prev(mm, start, &prev); error = -ENOMEM; if (!vma) goto out; @@ -288,6 +290,11 @@ } } out: - up_write(¤t->mm->mmap_sem); + up_write(&mm->mmap_sem); return error; } + +asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot) +{ + return(do_mprotect(current->mm, start, len, prot)); +} Index: linux-2.6.10/mm/mmap.c =================================================================== --- linux-2.6.10.orig/mm/mmap.c 2005-04-06 23:38:33.000000000 +0800 +++ linux-2.6.10/mm/mmap.c 2005-04-07 22:05:29.476761040 +0800 @@ -759,11 +759,11 @@ * The caller must hold down_write(current->mm->mmap_sem). */ -unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, - unsigned long len, unsigned long prot, - unsigned long flags, unsigned long pgoff) +unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file * file, + unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long pgoff) { - struct mm_struct * mm = current->mm; struct vm_area_struct * vma, * prev; struct inode *inode; unsigned int vm_flags; @@ -1037,7 +1037,7 @@ return error; } -EXPORT_SYMBOL(do_mmap_pgoff); +EXPORT_SYMBOL(__do_mmap_pgoff); /* Get an address range which is currently unmapped. * For shmat() with addr=0. Index: linux-2.6.10/mm/proc_mm.c =================================================================== --- linux-2.6.10.orig/mm/proc_mm.c 2005-04-07 19:34:21.197950744 +0800 +++ linux-2.6.10/mm/proc_mm.c 2005-04-07 22:05:29.476761040 +0800 @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/mm.h" +#include "linux/init.h" +#include "linux/proc_fs.h" +#include "linux/proc_mm.h" +#include "linux/file.h" +#include "linux/mman.h" +#include "asm/uaccess.h" +#include "asm/mmu_context.h" + +static struct file_operations proc_mm_fops; + +struct mm_struct *proc_mm_get_mm(int fd) +{ + struct mm_struct *ret = ERR_PTR(-EBADF); + struct file *file; + + file = fget(fd); + if (!file) + goto out; + + ret = ERR_PTR(-EINVAL); + if(file->f_op != &proc_mm_fops) + goto out_fput; + + ret = file->private_data; + out_fput: + fput(file); + out: + return(ret); +} + +extern long do_mmap2(struct mm_struct *mm, unsigned long addr, + unsigned long len, unsigned long prot, + unsigned long flags, unsigned long fd, + unsigned long pgoff); + +static ssize_t write_proc_mm(struct file *file, const char *buffer, + size_t count, loff_t *ppos) +{ + struct mm_struct *mm = file->private_data; + struct proc_mm_op req; + int n, ret; + + if(count > sizeof(req)) + return(-EINVAL); + + n = copy_from_user(&req, buffer, count); + if(n != 0) + return(-EFAULT); + + ret = count; + switch(req.op){ + case MM_MMAP: { + struct mm_mmap *map = &req.u.mmap; + + /* Nobody ever noticed it, but do_mmap_pgoff() calls + * get_unmapped_area() which checks current->mm, if + * MAP_FIXED is not set, so mmap() could replace + * an old mapping. + */ + if (! (map->flags & MAP_FIXED)) + return(-EINVAL); + + ret = do_mmap2(mm, map->addr, map->len, map->prot, + map->flags, map->fd, map->offset >> PAGE_SHIFT); + if((ret & ~PAGE_MASK) == 0) + ret = count; + + break; + } + case MM_MUNMAP: { + struct mm_munmap *unmap = &req.u.munmap; + + down_write(&mm->mmap_sem); + ret = do_munmap(mm, unmap->addr, unmap->len); + up_write(&mm->mmap_sem); + + if(ret == 0) + ret = count; + break; + } + case MM_MPROTECT: { + struct mm_mprotect *protect = &req.u.mprotect; + + ret = do_mprotect(mm, protect->addr, protect->len, + protect->prot); + if(ret == 0) + ret = count; + break; + } + + case MM_COPY_SEGMENTS: { + struct mm_struct *from = proc_mm_get_mm(req.u.copy_segments); + + if(IS_ERR(from)){ + ret = PTR_ERR(from); + break; + } + + ret = copy_context(mm, from); + if(ret == 0) + ret = count; + break; + } + default: + ret = -EINVAL; + break; + } + + return(ret); +} + +static int open_proc_mm(struct inode *inode, struct file *file) +{ + struct mm_struct *mm = mm_alloc(); + int ret; + + ret = -ENOMEM; + if(mm == NULL) + goto out_mem; + + init_new_empty_context(mm); + arch_pick_mmap_layout(mm); + + spin_lock(&mmlist_lock); + list_add(&mm->mmlist, ¤t->mm->mmlist); + spin_unlock(&mmlist_lock); + + file->private_data = mm; + + return(0); + + out_mem: + return(ret); +} + +static int release_proc_mm(struct inode *inode, struct file *file) +{ + struct mm_struct *mm = file->private_data; + + mmput(mm); + return(0); +} + +static struct file_operations proc_mm_fops = { + .open = open_proc_mm, + .release = release_proc_mm, + .write = write_proc_mm, +}; + +static int make_proc_mm(void) +{ + struct proc_dir_entry *ent; + + ent = create_proc_entry("mm", 0222, &proc_root); + if(ent == NULL){ + printk("make_proc_mm : Failed to register /proc/mm\n"); + return(0); + } + ent->proc_fops = &proc_mm_fops; + + return(0); +} + +__initcall(make_proc_mm); + +/* + * 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: + */ Index: linux-2.6.10/mm/Makefile =================================================================== --- linux-2.6.10.orig/mm/Makefile 2004-12-25 05:35:00.000000000 +0800 +++ linux-2.6.10/mm/Makefile 2005-04-07 22:05:29.477760888 +0800 @@ -18,3 +18,4 @@ obj-$(CONFIG_SHMEM) += shmem.o obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o +obj-$(CONFIG_PROC_MM) += proc_mm.o Index: linux-2.6.10/arch/um/drivers/mconsole_kern.c =================================================================== --- linux-2.6.10.orig/arch/um/drivers/mconsole_kern.c 2004-12-25 05:33:49.000000000 +0800 +++ linux-2.6.10/arch/um/drivers/mconsole_kern.c 2005-04-07 22:05:29.477760888 +0800 @@ -204,6 +204,68 @@ } #endif +/* This is a more convoluted version of mconsole_proc, which has some stability + * problems; however, we need it fixed, because it is expected that UML users + * mount HPPFS instead of procfs on /proc. And we want mconsole_proc to still + * show the real procfs content, not the ones from hppfs.*/ +#if 0 +void mconsole_proc(struct mc_request *req) +{ + char path[64]; + char *buf; + int len; + int fd; + int first_chunk = 1; + char *ptr = req->request.data; + + ptr += strlen("proc"); + while(isspace(*ptr)) ptr++; + snprintf(path, sizeof(path), "/proc/%s", ptr); + + fd = sys_open(path, 0, 0); + if (fd < 0) { + mconsole_reply(req, "Failed to open file", 1, 0); + printk("open %s: %d\n",path,fd); + goto out; + } + + buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + if(buf == NULL){ + mconsole_reply(req, "Failed to allocate buffer", 1, 0); + goto out_close; + } + + for (;;) { + len = sys_read(fd, buf, PAGE_SIZE-1); + if (len < 0) { + mconsole_reply(req, "Read of file failed", 1, 0); + goto out_free; + } + /*Begin the file content on his own line.*/ + if (first_chunk) { + mconsole_reply(req, "\n", 0, 1); + first_chunk = 0; + } + if (len == PAGE_SIZE-1) { + buf[len] = '\0'; + mconsole_reply(req, buf, 0, 1); + } else { + buf[len] = '\0'; + mconsole_reply(req, buf, 0, 0); + break; + } + } + /*END*/ + + out_free: + kfree(buf); + out_close: + sys_close(fd); + out: + /* nothing */; +} +#endif + void mconsole_proc(struct mc_request *req) { char path[64]; Index: linux-2.6.10/arch/um/drivers/net_kern.c =================================================================== --- linux-2.6.10.orig/arch/um/drivers/net_kern.c 2004-12-25 05:34:44.000000000 +0800 +++ linux-2.6.10/arch/um/drivers/net_kern.c 2005-04-07 22:05:29.478760736 +0800 @@ -126,10 +126,6 @@ lp->tl.data = (unsigned long) &lp->user; netif_start_queue(dev); - spin_lock(&opened_lock); - list_add(&lp->list, &opened); - spin_unlock(&opened_lock); - /* clear buffer - it can happen that the host side of the interface * is full when we get here. In this case, new data is never queued, * SIGIOs never arrive, and the net never works. @@ -152,9 +148,6 @@ free_irq(dev->irq, dev); if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user); lp->fd = -1; - spin_lock(&opened_lock); - list_del(&lp->list); - spin_unlock(&opened_lock); spin_unlock(&lp->lock); return 0; @@ -397,6 +390,11 @@ if (device->have_mac) set_ether_mac(dev, device->mac); + + spin_lock(&opened_lock); + list_add(&lp->list, &opened); + spin_unlock(&opened_lock); + return(0); } @@ -705,7 +703,7 @@ static void close_devices(void) { struct list_head *ele; - struct uml_net_private *lp; + struct uml_net_private *lp; list_for_each(ele, &opened){ lp = list_entry(ele, struct uml_net_private, list); Index: linux-2.6.10/arch/um/drivers/net_user.c =================================================================== --- linux-2.6.10.orig/arch/um/drivers/net_user.c 2004-12-25 05:34:26.000000000 +0800 +++ linux-2.6.10/arch/um/drivers/net_user.c 2005-04-07 22:05:29.478760736 +0800 @@ -173,10 +173,12 @@ pe_data.stdout = fds[1]; pid = run_helper(change_pre_exec, &pe_data, argv, NULL); - os_close_file(fds[1]); read_output(fds[0], output, output_len); + os_close_file(fds[0]); + os_close_file(fds[1]); - CATCH_EINTR(err = waitpid(pid, NULL, 0)); + if (pid > 0) + CATCH_EINTR(err = waitpid(pid, NULL, 0)); return(pid); } Index: linux-2.6.10/arch/um/os-Linux/process.c =================================================================== --- linux-2.6.10.orig/arch/um/os-Linux/process.c 2004-12-25 05:34:00.000000000 +0800 +++ linux-2.6.10/arch/um/os-Linux/process.c 2005-04-07 22:14:57.660384000 +0800 @@ -94,10 +94,16 @@ CATCH_EINTR(waitpid(pid, NULL, 0)); } +/* Kill off a ptraced child by all means available. kill it normally first, + * then PTRACE_KILL it, then PTRACE_CONT it in case it's in a run state from + * which it can't exit directly. + */ void os_kill_ptraced_process(int pid, int reap_child) { + kill(pid, SIGKILL); ptrace(PTRACE_KILL, pid); + ptrace(PTRACE_CONT, pid); if(reap_child) CATCH_EINTR(waitpid(pid, NULL, 0)); } Index: linux-2.6.10/arch/um/os-Linux/elf_aux.c =================================================================== --- linux-2.6.10.orig/arch/um/os-Linux/elf_aux.c 2005-04-07 19:34:21.197950744 +0800 +++ linux-2.6.10/arch/um/os-Linux/elf_aux.c 2005-04-07 22:05:29.478760736 +0800 @@ -0,0 +1,67 @@ +/* + * arch/um/kernel/elf_aux.c + * + * Scan the Elf auxiliary vector provided by the host to extract + * information about vsyscall-page, etc. + * + * Copyright (C) 2004 Fujitsu Siemens Computers GmbH + * Author: Bodo Stroesser (bodo.stroesser@fujitsu-siemens.com) + */ +#include +#include +#include "init.h" +#include "elf_user.h" + +#if ELF_CLASS == ELFCLASS32 +typedef Elf32_auxv_t elf_auxv_t; +#else +typedef Elf64_auxv_t elf_auxv_t; +#endif + +char * elf_aux_platform; +long elf_aux_hwcap; + +unsigned long vsyscall_ehdr; +unsigned long vsyscall_end; + +unsigned long __kernel_vsyscall; + + +__init void scan_elf_aux( char **envp) +{ + long page_size = 0; + elf_auxv_t * auxv; + + while ( *envp++ != NULL) ; + + for ( auxv = (elf_auxv_t *)envp; auxv->a_type != AT_NULL; auxv++) { + switch ( auxv->a_type ) { + case AT_SYSINFO: + __kernel_vsyscall = auxv->a_un.a_val; + break; + case AT_SYSINFO_EHDR: + vsyscall_ehdr = auxv->a_un.a_val; + break; + case AT_HWCAP: + elf_aux_hwcap = auxv->a_un.a_val; + break; + case AT_PLATFORM: + elf_aux_platform = auxv->a_un.a_ptr; + break; + case AT_PAGESZ: + page_size = auxv->a_un.a_val; + break; + } + } + if ( ! __kernel_vsyscall || ! vsyscall_ehdr || + ! elf_aux_hwcap || ! elf_aux_platform || + ! page_size || (vsyscall_ehdr % page_size) ) { + __kernel_vsyscall = 0; + vsyscall_ehdr = 0; + elf_aux_hwcap = 0; + elf_aux_platform = "i586"; + } + else { + vsyscall_end = vsyscall_ehdr + page_size; + } +} Index: linux-2.6.10/arch/um/os-Linux/user_syms.c =================================================================== --- linux-2.6.10.orig/arch/um/os-Linux/user_syms.c 2004-12-25 05:35:23.000000000 +0800 +++ linux-2.6.10/arch/um/os-Linux/user_syms.c 2005-04-07 22:05:29.478760736 +0800 @@ -26,6 +26,9 @@ EXPORT_SYMBOL(strstr); +EXPORT_SYMBOL(vsyscall_ehdr); +EXPORT_SYMBOL(vsyscall_end); + /* Here, instead, I can provide a fake prototype. Yes, someone cares: genksyms. * However, the modules will use the CRC defined *here*, no matter if it is * good; so the versions of these symbols will always match Index: linux-2.6.10/arch/um/os-Linux/Makefile =================================================================== --- linux-2.6.10.orig/arch/um/os-Linux/Makefile 2004-12-25 05:35:00.000000000 +0800 +++ linux-2.6.10/arch/um/os-Linux/Makefile 2005-04-07 22:05:29.479760584 +0800 @@ -3,9 +3,9 @@ # Licensed under the GPL # -obj-y = file.o process.o time.o tty.o user_syms.o drivers/ +obj-y = elf_aux.o file.o process.o time.o tty.o user_syms.o drivers/ -USER_OBJS := $(foreach file,file.o process.o time.o tty.o,$(obj)/$(file)) +USER_OBJS := $(foreach file,elf_aux.o file.o process.o time.o tty.o,$(obj)/$(file)) $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< Index: linux-2.6.10/arch/um/sys-i386/signal.c =================================================================== --- linux-2.6.10.orig/arch/um/sys-i386/signal.c 2005-04-07 19:34:21.197950744 +0800 +++ linux-2.6.10/arch/um/sys-i386/signal.c 2005-04-07 22:05:29.479760584 +0800 @@ -0,0 +1,374 @@ +/* + * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) + * Licensed under the GPL + */ + +#include "linux/signal.h" +#include "linux/ptrace.h" +#include "asm/current.h" +#include "asm/ucontext.h" +#include "asm/uaccess.h" +#include "asm/unistd.h" +#include "frame_kern.h" +#include "signal_user.h" +#include "ptrace_user.h" +#include "sigcontext.h" +#include "mode.h" + +#ifdef CONFIG_MODE_SKAS + +#include "skas.h" + +static int copy_sc_from_user_skas(struct pt_regs *regs, + struct sigcontext *from) +{ + struct sigcontext sc; + unsigned long fpregs[HOST_FP_SIZE]; + int err; + + err = copy_from_user(&sc, from, sizeof(sc)); + err |= copy_from_user(fpregs, sc.fpstate, sizeof(fpregs)); + if(err) + return(err); + + REGS_GS(regs->regs.skas.regs) = sc.gs; + REGS_FS(regs->regs.skas.regs) = sc.fs; + REGS_ES(regs->regs.skas.regs) = sc.es; + REGS_DS(regs->regs.skas.regs) = sc.ds; + REGS_EDI(regs->regs.skas.regs) = sc.edi; + REGS_ESI(regs->regs.skas.regs) = sc.esi; + REGS_EBP(regs->regs.skas.regs) = sc.ebp; + REGS_SP(regs->regs.skas.regs) = sc.esp; + REGS_EBX(regs->regs.skas.regs) = sc.ebx; + REGS_EDX(regs->regs.skas.regs) = sc.edx; + REGS_ECX(regs->regs.skas.regs) = sc.ecx; + REGS_EAX(regs->regs.skas.regs) = sc.eax; + REGS_IP(regs->regs.skas.regs) = sc.eip; + REGS_CS(regs->regs.skas.regs) = sc.cs; + REGS_EFLAGS(regs->regs.skas.regs) = sc.eflags; + REGS_SS(regs->regs.skas.regs) = sc.ss; + regs->regs.skas.fault_addr = sc.cr2; + regs->regs.skas.fault_type = FAULT_WRITE(sc.err); + regs->regs.skas.trap_type = sc.trapno; + + err = ptrace_setfpregs(userspace_pid[0], fpregs); + if(err < 0){ + printk("copy_sc_from_user_skas - PTRACE_SETFPREGS failed, " + "errno = %d\n", err); + return(1); + } + + return(0); +} + +int copy_sc_to_user_skas(struct sigcontext *to, struct _fpstate *to_fp, + struct pt_regs *regs, unsigned long fault_addr, + int fault_type) +{ + struct sigcontext sc; + unsigned long fpregs[HOST_FP_SIZE]; + int err; + + sc.gs = REGS_GS(regs->regs.skas.regs); + sc.fs = REGS_FS(regs->regs.skas.regs); + sc.es = REGS_ES(regs->regs.skas.regs); + sc.ds = REGS_DS(regs->regs.skas.regs); + sc.edi = REGS_EDI(regs->regs.skas.regs); + sc.esi = REGS_ESI(regs->regs.skas.regs); + sc.ebp = REGS_EBP(regs->regs.skas.regs); + sc.esp = REGS_SP(regs->regs.skas.regs); + sc.ebx = REGS_EBX(regs->regs.skas.regs); + sc.edx = REGS_EDX(regs->regs.skas.regs); + sc.ecx = REGS_ECX(regs->regs.skas.regs); + sc.eax = REGS_EAX(regs->regs.skas.regs); + sc.eip = REGS_IP(regs->regs.skas.regs); + sc.cs = REGS_CS(regs->regs.skas.regs); + sc.eflags = REGS_EFLAGS(regs->regs.skas.regs); + sc.esp_at_signal = regs->regs.skas.regs[UESP]; + sc.ss = regs->regs.skas.regs[SS]; + sc.cr2 = fault_addr; + sc.err = TO_SC_ERR(fault_type); + sc.trapno = regs->regs.skas.trap_type; + + err = ptrace_getfpregs(userspace_pid[0], fpregs); + if(err < 0){ + printk("copy_sc_to_user_skas - PTRACE_GETFPREGS failed, " + "errno = %d\n", err); + return(1); + } + to_fp = (to_fp ? to_fp : (struct _fpstate *) (to + 1)); + sc.fpstate = to_fp; + + if(err) + return(err); + + return(copy_to_user(to, &sc, sizeof(sc)) || + copy_to_user(to_fp, fpregs, sizeof(fpregs))); +} +#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; + if(to_fp != NULL){ + err |= copy_from_user(&to->fpstate, &to_fp, + sizeof(to->fpstate)); + err |= copy_from_user(to_fp, from_fp, fpsize); + } + 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)); + if(from_fp != NULL){ + err |= copy_to_user(&to->fpstate, &to_fp, + sizeof(to->fpstate)); + err |= copy_to_user(to_fp, from_fp, fpsize); + } + return(err); +} +#endif + +static int copy_sc_from_user(struct pt_regs *to, void *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) +{ + return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), + sizeof(*fp)), + copy_sc_to_user_skas(to, fp, from, + current->thread.cr2, + current->thread.err))); +} + +static int copy_ucontext_to_user(struct ucontext *uc, struct _fpstate *fp, + sigset_t *set, unsigned long sp) +{ + int err = 0; + + err |= put_user(current->sas_ss_sp, &uc->uc_stack.ss_sp); + err |= put_user(sas_ss_flags(sp), &uc->uc_stack.ss_flags); + err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size); + err |= copy_sc_to_user(&uc->uc_mcontext, fp, ¤t->thread.regs); + err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set)); + return(err); +} + +struct sigframe +{ + char *pretcode; + int sig; + struct sigcontext sc; + struct _fpstate fpstate; + unsigned long extramask[_NSIG_WORDS-1]; + char retcode[8]; +}; + +struct rt_sigframe +{ + char *pretcode; + int sig; + struct siginfo *pinfo; + void *puc; + struct siginfo info; + struct ucontext uc; + struct _fpstate fpstate; + char retcode[8]; +}; + +int setup_signal_stack_sc(unsigned long stack_top, int sig, + struct k_sigaction *ka, struct pt_regs *regs, + sigset_t *mask) +{ + struct sigframe __user *frame; + void *restorer; + int err = 0; + + stack_top &= -8UL; + frame = (struct sigframe *) stack_top - 1; + if(verify_area(VERIFY_WRITE, frame, sizeof(*frame))) + return(1); + + restorer = (void *) frame->retcode; + if(ka->sa.sa_flags & SA_RESTORER) + restorer = ka->sa.sa_restorer; + + err |= __put_user(restorer, &frame->pretcode); + err |= __put_user(sig, &frame->sig); + err |= copy_sc_to_user(&frame->sc, NULL, regs); + err |= __put_user(mask->sig[0], &frame->sc.oldmask); + if (_NSIG_WORDS > 1) + err |= __copy_to_user(&frame->extramask, &mask->sig[1], + sizeof(frame->extramask)); + + /* + * This is popl %eax ; movl $,%eax ; int $0x80 + * + * WE DO NOT USE IT ANY MORE! It's only left here for historical + * reasons and because gdb uses it as a signature to notice + * signal handler stack frames. + */ + err |= __put_user(0xb858, (short __user *)(frame->retcode+0)); + err |= __put_user(__NR_sigreturn, (int __user *)(frame->retcode+2)); + err |= __put_user(0x80cd, (short __user *)(frame->retcode+6)); + + if(err) + return(err); + + PT_REGS_SP(regs) = (unsigned long) frame; + PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler; + PT_REGS_EAX(regs) = (unsigned long) sig; + PT_REGS_EDX(regs) = (unsigned long) 0; + PT_REGS_ECX(regs) = (unsigned long) 0; + + if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED)) + ptrace_notify(SIGTRAP); + return(0); +} + +int setup_signal_stack_si(unsigned long stack_top, int sig, + struct k_sigaction *ka, struct pt_regs *regs, + siginfo_t *info, sigset_t *mask) +{ + struct rt_sigframe __user *frame; + void *restorer; + int err = 0; + + stack_top &= -8UL; + frame = (struct rt_sigframe *) stack_top - 1; + if(verify_area(VERIFY_WRITE, frame, sizeof(*frame))) + return(1); + + restorer = (void *) frame->retcode; + if(ka->sa.sa_flags & SA_RESTORER) + restorer = ka->sa.sa_restorer; + + err |= __put_user(restorer, &frame->pretcode); + err |= __put_user(sig, &frame->sig); + err |= __put_user(&frame->info, &frame->pinfo); + err |= __put_user(&frame->uc, &frame->puc); + err |= copy_siginfo_to_user(&frame->info, info); + err |= copy_ucontext_to_user(&frame->uc, &frame->fpstate, mask, + PT_REGS_SP(regs)); + + /* + * This is movl $,%eax ; int $0x80 + * + * WE DO NOT USE IT ANY MORE! It's only left here for historical + * reasons and because gdb uses it as a signature to notice + * signal handler stack frames. + */ + err |= __put_user(0xb8, (char __user *)(frame->retcode+0)); + err |= __put_user(__NR_rt_sigreturn, (int __user *)(frame->retcode+1)); + err |= __put_user(0x80cd, (short __user *)(frame->retcode+5)); + + if(err) + return(err); + + PT_REGS_SP(regs) = (unsigned long) frame; + PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler; + PT_REGS_EAX(regs) = (unsigned long) sig; + PT_REGS_EDX(regs) = (unsigned long) &frame->info; + PT_REGS_ECX(regs) = (unsigned long) &frame->uc; + + if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED)) + ptrace_notify(SIGTRAP); + return(0); +} + +long sys_sigreturn(struct pt_regs regs) +{ + unsigned long __user sp = PT_REGS_SP(¤t->thread.regs); + struct sigframe __user *frame = (struct sigframe *)(sp - 8); + sigset_t set; + struct sigcontext __user *sc = &frame->sc; + unsigned long __user *oldmask = &sc->oldmask; + unsigned long __user *extramask = &frame->extramask; + int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long); + + if(copy_from_user(&set.sig[0], oldmask, sizeof(&set.sig[0])) || + copy_from_user(&set.sig[1], extramask, sig_size)) + 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, sc)) + goto segfault; + + PT_REGS_SYSCALL_NR(¤t->thread.regs) = -1; /* Avoid ERESTART handling */ + return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); + + segfault: + force_sig(SIGSEGV, current); + return 0; +} + +long sys_rt_sigreturn(struct pt_regs regs) +{ + unsigned long __user sp = PT_REGS_SP(¤t->thread.regs); + struct rt_sigframe __user *frame = (struct rt_sigframe *) (sp - 4); + sigset_t set; + struct ucontext __user *uc = &frame->uc; + int sig_size = _NSIG_WORDS * sizeof(unsigned long); + + if(copy_from_user(&set, &uc->uc_sigmask, sig_size)) + 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; + + PT_REGS_SYSCALL_NR(¤t->thread.regs) = -1; /* Avoid ERESTART handling */ + 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: + */ Index: linux-2.6.10/arch/um/sys-i386/ptrace_user.c =================================================================== --- linux-2.6.10.orig/arch/um/sys-i386/ptrace_user.c 2004-12-25 05:35:50.000000000 +0800 +++ linux-2.6.10/arch/um/sys-i386/ptrace_user.c 2005-04-07 22:05:29.480760432 +0800 @@ -17,17 +17,30 @@ int ptrace_getregs(long pid, unsigned long *regs_out) { - return(ptrace(PTRACE_GETREGS, pid, 0, regs_out)); + if(ptrace(PTRACE_GETREGS, pid, 0, regs_out) < 0) + return(-errno); + return(0); } int ptrace_setregs(long pid, unsigned long *regs) { - return(ptrace(PTRACE_SETREGS, pid, 0, regs)); + if(ptrace(PTRACE_SETREGS, pid, 0, regs) < 0) + return(-errno); + return(0); } int ptrace_getfpregs(long pid, unsigned long *regs) { - return(ptrace(PTRACE_GETFPREGS, pid, 0, regs)); + if(ptrace(PTRACE_GETFPREGS, pid, 0, regs) < 0) + return(-errno); + return(0); +} + +int ptrace_setfpregs(long pid, unsigned long *regs) +{ + if(ptrace(PTRACE_SETFPREGS, pid, 0, regs) < 0) + return(-errno); + return(0); } static void write_debugregs(int pid, unsigned long *regs) Index: linux-2.6.10/arch/um/sys-i386/sysrq.c =================================================================== --- linux-2.6.10.orig/arch/um/sys-i386/sysrq.c 2004-12-25 05:33:49.000000000 +0800 +++ linux-2.6.10/arch/um/sys-i386/sysrq.c 2005-04-07 22:05:29.480760432 +0800 @@ -33,3 +33,13 @@ show_trace((unsigned long *) ®s); } + +/* 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: + */ Index: linux-2.6.10/arch/um/sys-i386/Makefile =================================================================== --- linux-2.6.10.orig/arch/um/sys-i386/Makefile 2004-12-25 05:34:01.000000000 +0800 +++ linux-2.6.10/arch/um/sys-i386/Makefile 2005-04-07 22:05:29.480760432 +0800 @@ -1,5 +1,5 @@ obj-y = bitops.o bugs.o checksum.o fault.o ksyms.o ldt.o ptrace.o \ - ptrace_user.o semaphore.o sigcontext.o syscalls.o sysrq.o + ptrace_user.o semaphore.o signal.o sigcontext.o syscalls.o sysrq.o obj-$(CONFIG_HIGHMEM) += highmem.o obj-$(CONFIG_MODULES) += module.o Index: linux-2.6.10/arch/um/sys-i386/sigcontext.c =================================================================== --- linux-2.6.10.orig/arch/um/sys-i386/sigcontext.c 2004-12-25 05:33:49.000000000 +0800 +++ linux-2.6.10/arch/um/sys-i386/sigcontext.c 2005-04-07 22:05:29.480760432 +0800 @@ -9,22 +9,14 @@ #include #include "sysdep/ptrace.h" #include "kern_util.h" -#include "frame_user.h" - -int sc_size(void *data) -{ - struct arch_frame_data *arch = data; - - return(sizeof(struct sigcontext) + arch->fpstate_size); -} void sc_to_sc(void *to_ptr, void *from_ptr) { struct sigcontext *to = to_ptr, *from = from_ptr; - int size = sizeof(*to) + signal_frame_sc.common.arch.fpstate_size; - memcpy(to, from, size); - if(from->fpstate != NULL) to->fpstate = (struct _fpstate *) (to + 1); + memcpy(to, from, sizeof(*to) + sizeof(struct _fpstate)); + if(from->fpstate != NULL) + to->fpstate = (struct _fpstate *) (to + 1); } unsigned long *sc_sigmask(void *sc_ptr) Index: linux-2.6.10/arch/um/kernel/main.c =================================================================== --- linux-2.6.10.orig/arch/um/kernel/main.c 2004-12-25 05:35:24.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/main.c 2005-04-07 22:05:29.480760432 +0800 @@ -81,6 +81,8 @@ extern int uml_exitcode; +extern void scan_elf_aux( char **envp); + int main(int argc, char **argv, char **envp) { char **new_argv; @@ -147,6 +149,8 @@ set_handler(SIGTERM, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); set_handler(SIGHUP, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); + scan_elf_aux( envp); + do_uml_initcalls(); ret = linux_main(argc, argv); @@ -155,18 +159,20 @@ int err; printf("\n"); - - /* Let any pending signals fire, then disable them. This - * ensures that they won't be delivered after the exec, when - * they are definitely not expected. - */ - unblock_signals(); + /* stop timers and set SIG*ALRM to be ignored */ disable_timer(); + /* disable SIGIO for the fds and set SIGIO to be ignored */ err = deactivate_all_fds(); if(err) printf("deactivate_all_fds failed, errno = %d\n", -err); + /* Let any pending signals fire now. This ensures + * that they won't be delivered after the exec, when + * they are definitely not expected. + */ + unblock_signals(); + execvp(new_argv[0], new_argv); perror("Failed to exec kernel"); ret = 1; Index: linux-2.6.10/arch/um/kernel/process.c =================================================================== --- linux-2.6.10.orig/arch/um/kernel/process.c 2004-12-25 05:35:25.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/process.c 2005-04-07 22:05:29.481760280 +0800 @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -285,6 +286,9 @@ printk("Checking that ptrace can change system call numbers..."); pid = start_ptraced_child(&stack); + if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) + panic("check_ptrace: PTRACE_SETOPTIONS failed, errno = %d", errno); + while(1){ if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) panic("check_ptrace : ptrace failed, errno = %d", @@ -292,8 +296,8 @@ CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); if(n < 0) panic("check_ptrace : wait failed, errno = %d", errno); - if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) - panic("check_ptrace : expected SIGTRAP, " + if(!WIFSTOPPED(status) || (WSTOPSIG(status) != (SIGTRAP|SYSCALL_TRAP))) + panic("check_ptrace : expected (SIGTRAP|SYSCALL_TRAP), " "got status = %d", status); syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET, Index: linux-2.6.10/arch/um/kernel/initrd_user.c =================================================================== --- linux-2.6.10.orig/arch/um/kernel/initrd_user.c 2004-12-25 05:34:26.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/initrd_user.c 2005-04-07 22:05:29.481760280 +0800 @@ -29,6 +29,8 @@ filename, -n); return(-1); } + + os_close_file(fd); return(0); } Index: linux-2.6.10/arch/um/kernel/time_kern.c =================================================================== --- linux-2.6.10.orig/arch/um/kernel/time_kern.c 2004-12-25 05:35:00.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/time_kern.c 2005-04-07 22:05:29.481760280 +0800 @@ -170,7 +170,7 @@ void timer_handler(int sig, union uml_pt_regs *regs) { local_irq_disable(); - update_process_times(user_context(UPT_SP(regs))); + update_process_times(CHOOSE_MODE(user_context(UPT_SP(regs)), (regs)->skas.is_user)); local_irq_enable(); if(current_thread->cpu == 0) timer_irq(regs); Index: linux-2.6.10/arch/um/kernel/helper.c =================================================================== --- linux-2.6.10.orig/arch/um/kernel/helper.c 2004-12-25 05:34:45.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/helper.c 2005-04-07 22:05:29.482760128 +0800 @@ -49,14 +49,14 @@ return(0); } -/* XXX The alloc_stack here breaks if this is called in the tracing thread */ - +/* Returns either the pid of the child process we run or -E* on failure. + * XXX The alloc_stack here breaks if this is called in the tracing thread */ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, unsigned long *stack_out) { struct helper_data data; unsigned long stack, sp; - int pid, fds[2], err, n; + int pid, fds[2], ret, n; if((stack_out != NULL) && (*stack_out != 0)) stack = *stack_out; @@ -64,16 +64,16 @@ if(stack == 0) return(-ENOMEM); - err = os_pipe(fds, 1, 0); - if(err < 0){ - printk("run_helper : pipe failed, err = %d\n", -err); + ret = os_pipe(fds, 1, 0); + if(ret < 0){ + printk("run_helper : pipe failed, ret = %d\n", -ret); goto out_free; } - err = os_set_exec_close(fds[1], 1); - if(err < 0){ - printk("run_helper : setting FD_CLOEXEC failed, err = %d\n", - -err); + ret = os_set_exec_close(fds[1], 1); + if(ret < 0){ + printk("run_helper : setting FD_CLOEXEC failed, ret = %d\n", + -ret); goto out_close; } @@ -85,34 +85,36 @@ pid = clone(helper_child, (void *) sp, CLONE_VM | SIGCHLD, &data); if(pid < 0){ printk("run_helper : clone failed, errno = %d\n", errno); - err = -errno; + ret = -errno; goto out_close; } os_close_file(fds[1]); - n = os_read_file(fds[0], &err, sizeof(err)); + fds[1] = -1; + + /*Read the errno value from the child.*/ + n = os_read_file(fds[0], &ret, sizeof(ret)); if(n < 0){ - printk("run_helper : read on pipe failed, err = %d\n", -n); - err = n; - goto out_kill; + printk("run_helper : read on pipe failed, ret = %d\n", -n); + ret = n; + os_kill_process(pid, 1); } else if(n != 0){ CATCH_EINTR(n = waitpid(pid, NULL, 0)); - pid = -errno; + ret = -errno; + } else { + ret = pid; } - if(stack_out == NULL) free_stack(stack, 0); - else *stack_out = stack; - return(pid); - - out_kill: - os_kill_process(pid, 1); out_close: + if (fds[1] != -1) + os_close_file(fds[1]); os_close_file(fds[0]); - os_close_file(fds[1]); out_free: - free_stack(stack, 0); - return(err); + if(stack_out == NULL) + free_stack(stack, 0); + else *stack_out = stack; + return(ret); } int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, Index: linux-2.6.10/arch/um/kernel/irq_user.c =================================================================== --- linux-2.6.10.orig/arch/um/kernel/irq_user.c 2004-12-25 05:34:32.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/irq_user.c 2005-04-07 22:05:29.482760128 +0800 @@ -374,6 +374,8 @@ if(err) return(err); } + /* If there is a signal already queued, after unblocking ignore it */ + set_handler(SIGIO, SIG_IGN, 0, -1); return(0); } Index: linux-2.6.10/arch/um/kernel/mem.c =================================================================== --- linux-2.6.10.orig/arch/um/kernel/mem.c 2004-12-25 05:34:32.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/mem.c 2005-04-07 22:05:29.482760128 +0800 @@ -175,6 +175,30 @@ } #endif /* CONFIG_HIGHMEM */ +static void __init fixaddr_user_init( void) +{ + long size = FIXADDR_USER_END - FIXADDR_USER_START; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; + unsigned long paddr, vaddr = FIXADDR_USER_START; + + if ( ! size ) + return; + + fixrange_init( FIXADDR_USER_START, FIXADDR_USER_END, swapper_pg_dir); + paddr = (unsigned long)alloc_bootmem_low_pages( size); + memcpy( (void *)paddr, (void *)FIXADDR_USER_START, size); + paddr = __pa(paddr); + for ( ; size > 0; size-=PAGE_SIZE, vaddr+=PAGE_SIZE, paddr+=PAGE_SIZE) { + pgd = swapper_pg_dir + pgd_index(vaddr); + pmd = pmd_offset(pgd, vaddr); + pte = pte_offset_kernel(pmd, vaddr); + /*pte_set_val( (*pte), paddr, PAGE_READONLY);*/ + pte_val(*pte) = paddr | pgprot_val(PAGE_READONLY); + } +} + void paging_init(void) { unsigned long zones_size[MAX_NR_ZONES], vaddr; @@ -195,6 +219,8 @@ vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; fixrange_init(vaddr, FIXADDR_TOP, swapper_pg_dir); + fixaddr_user_init(); + #ifdef CONFIG_HIGHMEM init_highmem(); #endif Index: linux-2.6.10/arch/um/kernel/skas/process.c =================================================================== --- linux-2.6.10.orig/arch/um/kernel/skas/process.c 2004-12-25 05:35:39.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/skas/process.c 2005-04-07 22:05:29.483759976 +0800 @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -60,15 +61,10 @@ /*To use the same value of using_sysemu as the caller, ask it that value (in local_using_sysemu)*/ static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu) { - int err, syscall_nr, status; - - syscall_nr = PT_SYSCALL_NR(regs->skas.regs); - UPT_SYSCALL_NR(regs) = syscall_nr; - if(syscall_nr < 0){ - relay_signal(SIGTRAP, regs); - return; - } + int err, status; + + UPT_SYSCALL_NR(regs) = PT_SYSCALL_NR(regs->skas.regs); /* Mark this as a syscall */ if (!local_using_sysemu) { err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid); @@ -82,7 +78,8 @@ "errno = %d\n", errno); CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED)); - if((err < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) + if((err < 0) || !WIFSTOPPED(status) || + (WSTOPSIG(status) != (SIGTRAP|SYSCALL_TRAP))) panic("handle_trap - failed to wait at end of syscall, " "errno = %d, status = %d\n", errno, status); } @@ -131,6 +128,10 @@ panic("start_userspace : expected SIGSTOP, got status = %d", status); + if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, (void *)PTRACE_O_TRACESYSGOOD) < 0) + panic("start_userspace : PTRACE_SETOPTIONS failed, errno=%d\n", + errno); + if(munmap(stack, PAGE_SIZE) < 0) panic("start_userspace : munmap failed, errno = %d\n", errno); @@ -160,15 +161,19 @@ regs->skas.is_user = 1; save_registers(regs); + UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */ if(WIFSTOPPED(status)){ switch(WSTOPSIG(status)){ case SIGSEGV: handle_segv(pid); break; - case SIGTRAP: + case (SIGTRAP|SYSCALL_TRAP): handle_trap(pid, regs, local_using_sysemu); break; + case SIGTRAP: + relay_signal(SIGTRAP, regs); + break; case SIGIO: case SIGVTALRM: case SIGILL: @@ -222,9 +227,10 @@ block_signals(); if(sigsetjmp(fork_buf, 1) == 0) new_thread_proc(stack, handler); - set_signals(flags); remove_sigstack(); + + set_signals(flags); } void thread_wait(void *sw, void *fb) Index: linux-2.6.10/arch/um/kernel/skas/sys-i386/Makefile =================================================================== --- linux-2.6.10.orig/arch/um/kernel/skas/sys-i386/Makefile 2004-12-25 05:35:27.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/skas/sys-i386/Makefile 2005-04-07 19:34:21.197950744 +0800 @@ -1,12 +0,0 @@ -# -# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) -# Licensed under the GPL -# - -obj-y = sigcontext.o - -USER_OBJS = sigcontext.o -USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) - -$(USER_OBJS) : %.o: %.c - $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< Index: linux-2.6.10/arch/um/kernel/skas/sys-i386/sigcontext.c =================================================================== --- linux-2.6.10.orig/arch/um/kernel/skas/sys-i386/sigcontext.c 2004-12-25 05:33:51.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/skas/sys-i386/sigcontext.c 2005-04-07 19:34:21.197950744 +0800 @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include -#include -#include -#include -#include "sysdep/ptrace.h" -#include "sysdep/ptrace_user.h" -#include "kern_util.h" -#include "user.h" -#include "sigcontext.h" -#include "mode.h" - -int copy_sc_from_user_skas(int pid, union uml_pt_regs *regs, void *from_ptr) -{ - struct sigcontext sc, *from = from_ptr; - unsigned long fpregs[FP_FRAME_SIZE]; - int err; - - err = copy_from_user_proc(&sc, from, sizeof(sc)); - err |= copy_from_user_proc(fpregs, sc.fpstate, sizeof(fpregs)); - if(err) - return(err); - - regs->skas.regs[GS] = sc.gs; - regs->skas.regs[FS] = sc.fs; - regs->skas.regs[ES] = sc.es; - regs->skas.regs[DS] = sc.ds; - regs->skas.regs[EDI] = sc.edi; - regs->skas.regs[ESI] = sc.esi; - regs->skas.regs[EBP] = sc.ebp; - regs->skas.regs[UESP] = sc.esp; - regs->skas.regs[EBX] = sc.ebx; - regs->skas.regs[EDX] = sc.edx; - regs->skas.regs[ECX] = sc.ecx; - regs->skas.regs[EAX] = sc.eax; - regs->skas.regs[EIP] = sc.eip; - regs->skas.regs[CS] = sc.cs; - regs->skas.regs[EFL] = sc.eflags; - regs->skas.regs[SS] = sc.ss; - regs->skas.fault_addr = sc.cr2; - regs->skas.fault_type = FAULT_WRITE(sc.err); - regs->skas.trap_type = sc.trapno; - - err = ptrace(PTRACE_SETFPREGS, pid, 0, fpregs); - if(err < 0){ - printk("copy_sc_to_user - PTRACE_SETFPREGS failed, " - "errno = %d\n", errno); - return(1); - } - - return(0); -} - -int copy_sc_to_user_skas(int pid, void *to_ptr, void *fp, - union uml_pt_regs *regs, unsigned long fault_addr, - int fault_type) -{ - struct sigcontext sc, *to = to_ptr; - struct _fpstate *to_fp; - unsigned long fpregs[FP_FRAME_SIZE]; - int err; - - sc.gs = regs->skas.regs[GS]; - sc.fs = regs->skas.regs[FS]; - sc.es = regs->skas.regs[ES]; - sc.ds = regs->skas.regs[DS]; - sc.edi = regs->skas.regs[EDI]; - sc.esi = regs->skas.regs[ESI]; - sc.ebp = regs->skas.regs[EBP]; - sc.esp = regs->skas.regs[UESP]; - sc.ebx = regs->skas.regs[EBX]; - sc.edx = regs->skas.regs[EDX]; - sc.ecx = regs->skas.regs[ECX]; - sc.eax = regs->skas.regs[EAX]; - sc.eip = regs->skas.regs[EIP]; - sc.cs = regs->skas.regs[CS]; - sc.eflags = regs->skas.regs[EFL]; - sc.esp_at_signal = regs->skas.regs[UESP]; - sc.ss = regs->skas.regs[SS]; - sc.cr2 = fault_addr; - sc.err = TO_SC_ERR(fault_type); - sc.trapno = regs->skas.trap_type; - - err = ptrace(PTRACE_GETFPREGS, pid, 0, fpregs); - if(err < 0){ - printk("copy_sc_to_user - PTRACE_GETFPREGS failed, " - "errno = %d\n", errno); - return(1); - } - to_fp = (struct _fpstate *) - (fp ? (unsigned long) fp : ((unsigned long) to + sizeof(*to))); - sc.fpstate = to_fp; - - if(err) - return(err); - - return(copy_to_user_proc(to, &sc, sizeof(sc)) || - copy_to_user_proc(to_fp, fpregs, sizeof(fpregs))); -} - -/* - * 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: - */ Index: linux-2.6.10/arch/um/kernel/skas/process_kern.c =================================================================== --- linux-2.6.10.orig/arch/um/kernel/skas/process_kern.c 2004-12-25 05:35:50.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/skas/process_kern.c 2005-04-07 22:05:29.488759216 +0800 @@ -19,7 +19,6 @@ #include "os.h" #include "user_util.h" #include "tlb.h" -#include "frame.h" #include "kern.h" #include "mode.h" #include "proc_mm.h" @@ -183,7 +182,6 @@ int start_uml_skas(void) { start_userspace(0); - capture_signal_stack(); init_new_thread_signals(1); uml_idle_timer(); Index: linux-2.6.10/arch/um/kernel/skas/trap_user.c =================================================================== --- linux-2.6.10.orig/arch/um/kernel/skas/trap_user.c 2004-12-25 05:34:32.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/skas/trap_user.c 2005-04-07 22:05:29.488759216 +0800 @@ -21,6 +21,14 @@ int save_errno = errno; int save_user; + /* This is done because to allow SIGSEGV to be delivered inside a SEGV + * handler. This can happen in copy_user, and if SEGV is disabled, + * the process will die. + * XXX Figure out why this is better than SA_NODEFER + */ + if(sig == SIGSEGV) + change_sig(SIGSEGV, 1); + r = &TASK_REGS(get_current())->skas; save_user = r->is_user; r->is_user = 0; Index: linux-2.6.10/arch/um/kernel/skas/syscall_kern.c =================================================================== --- linux-2.6.10.orig/arch/um/kernel/skas/syscall_kern.c 2004-12-25 05:35:00.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/skas/syscall_kern.c 2005-04-07 22:05:29.488759216 +0800 @@ -6,6 +6,7 @@ #include "linux/sys.h" #include "linux/ptrace.h" #include "asm/errno.h" +#include "linux/ptrace.h" #include "asm/unistd.h" #include "asm/ptrace.h" #include "asm/current.h" Index: linux-2.6.10/arch/um/kernel/skas/Makefile =================================================================== --- linux-2.6.10.orig/arch/um/kernel/skas/Makefile 2004-12-25 05:34:30.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/skas/Makefile 2005-04-07 22:05:29.488759216 +0800 @@ -4,8 +4,7 @@ # obj-y := exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \ - syscall_kern.o syscall_user.o time.o tlb.o trap_user.o uaccess.o \ - sys-$(SUBARCH)/ + syscall_kern.o syscall_user.o time.o tlb.o trap_user.o uaccess.o subdir-y := util Index: linux-2.6.10/arch/um/kernel/skas/include/mmu-skas.h =================================================================== --- linux-2.6.10.orig/arch/um/kernel/skas/include/mmu-skas.h 2004-12-25 05:35:24.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/skas/include/mmu-skas.h 2005-04-07 22:05:29.488759216 +0800 @@ -22,3 +22,27 @@ * c-file-style: "linux" * End: */ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SKAS_MMU_H +#define __SKAS_MMU_H + +struct mmu_context_skas { + int mm_fd; +}; + +#endif + +/* + * 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: + */ Index: linux-2.6.10/arch/um/kernel/skas/include/mode-skas.h =================================================================== --- linux-2.6.10.orig/arch/um/kernel/skas/include/mode-skas.h 2004-12-25 05:34:58.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/skas/include/mode-skas.h 2005-04-07 22:05:29.489759064 +0800 @@ -14,6 +14,40 @@ extern int have_fpx_regs; extern void user_time_init_skas(void); +extern void sig_handler_common_skas(int sig, void *sc_ptr); +extern void halt_skas(void); +extern void reboot_skas(void); +extern void kill_off_processes_skas(void); +extern int is_skas_winch(int pid, int fd, void *data); + +#endif + +/* + * 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: + */ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __MODE_SKAS_H__ +#define __MODE_SKAS_H__ + +#include + +extern unsigned long exec_regs[]; +extern unsigned long exec_fp_regs[]; +extern unsigned long exec_fpx_regs[]; +extern int have_fpx_regs; + +extern void user_time_init_skas(void); extern int copy_sc_from_user_skas(int pid, union uml_pt_regs *regs, void *from_ptr); extern int copy_sc_to_user_skas(int pid, void *to_ptr, void *fp, Index: linux-2.6.10/arch/um/kernel/skas/include/uaccess-skas.h =================================================================== --- linux-2.6.10.orig/arch/um/kernel/skas/include/uaccess-skas.h 2004-12-25 05:34:32.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/skas/include/uaccess-skas.h 2005-04-07 22:05:29.489759064 +0800 @@ -7,6 +7,51 @@ #define __SKAS_UACCESS_H #include "asm/errno.h" +#include "asm/fixmap.h" + +#define access_ok_skas(type, addr, size) \ + ((segment_eq(get_fs(), KERNEL_DS)) || \ + (((unsigned long) (addr) < TASK_SIZE) && \ + ((unsigned long) (addr) + (size) <= TASK_SIZE)) || \ + ((type == VERIFY_READ ) && \ + ((unsigned long) (addr) >= FIXADDR_USER_START) && \ + ((unsigned long) (addr) + (size) <= FIXADDR_USER_END) && \ + ((unsigned long) (addr) + (size) >= (unsigned long)(addr)))) + +static inline int verify_area_skas(int type, const void * addr, + unsigned long size) +{ + return(access_ok_skas(type, addr, size) ? 0 : -EFAULT); +} + +extern int copy_from_user_skas(void *to, const void *from, int n); +extern int copy_to_user_skas(void *to, const void *from, int n); +extern int strncpy_from_user_skas(char *dst, const char *src, int count); +extern int __clear_user_skas(void *mem, int len); +extern int clear_user_skas(void *mem, int len); +extern int strnlen_user_skas(const void *str, int len); + +#endif + +/* + * 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: + */ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __SKAS_UACCESS_H +#define __SKAS_UACCESS_H + +#include "asm/errno.h" #define access_ok_skas(type, addr, size) \ ((segment_eq(get_fs(), KERNEL_DS)) || \ Index: linux-2.6.10/arch/um/kernel/tt/syscall_user.c =================================================================== --- linux-2.6.10.orig/arch/um/kernel/tt/syscall_user.c 2004-12-25 05:35:01.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/tt/syscall_user.c 2005-04-07 22:05:29.489759064 +0800 @@ -42,37 +42,31 @@ syscall_trace(regs, 1); record_syscall_end(index, result); } - -int do_syscall(void *task, int pid, int local_using_sysemu) -{ - unsigned long proc_regs[FRAME_SIZE]; - union uml_pt_regs *regs; - int syscall; - - if(ptrace_getregs(pid, proc_regs) < 0) - tracer_panic("Couldn't read registers"); - syscall = PT_SYSCALL_NR(proc_regs); - - regs = TASK_REGS(task); - UPT_SYSCALL_NR(regs) = syscall; - - if(syscall < 0) - return(0); - - if((syscall != __NR_sigreturn) && - ((unsigned long *) PT_IP(proc_regs) >= &_stext) && - ((unsigned long *) PT_IP(proc_regs) <= &_etext)) - tracer_panic("I'm tracing myself and I can't get out"); - - if(local_using_sysemu) - return(1); - - if(ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, - __NR_getpid) < 0) - tracer_panic("do_syscall : Nullifying syscall failed, " - "errno = %d", errno); - return(1); -} + + void do_sigtrap(void *task) + { + UPT_SYSCALL_NR(TASK_REGS(task)) = -1; + } + + void do_syscall(void *task, int pid, int local_using_sysemu) + { + unsigned long proc_regs[FRAME_SIZE]; + + if(ptrace_getregs(pid, proc_regs) < 0) + tracer_panic("Couldn't read registers"); + + UPT_SYSCALL_NR(TASK_REGS(task)) = PT_SYSCALL_NR(proc_regs); + + if(((unsigned long *) PT_IP(proc_regs) >= &_stext) && + ((unsigned long *) PT_IP(proc_regs) <= &_etext)) + tracer_panic("I'm tracing myself and I can't get out"); + + /* syscall number -1 in sysemu skips syscall restarting in host */ + if(ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, + local_using_sysemu ? -1 : __NR_getpid) < 0) + tracer_panic("do_syscall : Nullifying syscall failed, " + "errno = %d", errno); + } /* * Overrides for Emacs so that we follow Linus's tabbing style. Index: linux-2.6.10/arch/um/kernel/tt/sys-i386/Makefile =================================================================== --- linux-2.6.10.orig/arch/um/kernel/tt/sys-i386/Makefile 2004-12-25 05:34:32.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/tt/sys-i386/Makefile 2005-04-07 19:34:21.197950744 +0800 @@ -1,12 +0,0 @@ -# -# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) -# Licensed under the GPL -# - -obj-y = sigcontext.o - -USER_OBJS = sigcontext.o -USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file)) - -$(USER_OBJS) : %.o: %.c - $(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $< Index: linux-2.6.10/arch/um/kernel/tt/sys-i386/sigcontext.c =================================================================== --- linux-2.6.10.orig/arch/um/kernel/tt/sys-i386/sigcontext.c 2004-12-25 05:35:39.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/tt/sys-i386/sigcontext.c 2005-04-07 19:34:21.197950744 +0800 @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include -#include -#include "kern_util.h" -#include "sysdep/frame.h" - -int copy_sc_from_user_tt(void *to_ptr, void *from_ptr, void *data) -{ - struct arch_frame_data *arch = data; - struct sigcontext *to = to_ptr, *from = from_ptr; - 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_proc(to, from, sizeof(*to)); - to->oldmask = sigs; - if(to_fp != NULL){ - err |= copy_from_user_proc(&to->fpstate, &to_fp, - sizeof(to->fpstate)); - err |= copy_from_user_proc(to_fp, from_fp, arch->fpstate_size); - } - return(err); -} - -int copy_sc_to_user_tt(void *to_ptr, void *fp, void *from_ptr, void *data) -{ - struct arch_frame_data *arch = data; - struct sigcontext *to = to_ptr, *from = from_ptr; - struct _fpstate *to_fp, *from_fp; - int err; - - to_fp = (struct _fpstate *) - (fp ? (unsigned long) fp : ((unsigned long) to + sizeof(*to))); - from_fp = from->fpstate; - err = copy_to_user_proc(to, from, sizeof(*to)); - if(from_fp != NULL){ - err |= copy_to_user_proc(&to->fpstate, &to_fp, - sizeof(to->fpstate)); - err |= copy_to_user_proc(to_fp, from_fp, arch->fpstate_size); - } - return(err); -} - -/* - * 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: - */ Index: linux-2.6.10/arch/um/kernel/tt/exec_user.c =================================================================== --- linux-2.6.10.orig/arch/um/kernel/tt/exec_user.c 2004-12-25 05:35:24.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/tt/exec_user.c 2005-04-07 22:05:29.490758912 +0800 @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "user_util.h" #include "kern_util.h" @@ -35,7 +36,10 @@ tracer_panic("do_exec failed to get registers - errno = %d", errno); - kill(old_pid, SIGKILL); + os_kill_ptraced_process(old_pid, 0); + + if (ptrace(PTRACE_OLDSETOPTIONS, new_pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) + tracer_panic("do_exec: PTRACE_SETOPTIONS failed, errno = %d", errno); if(ptrace_setregs(new_pid, regs) < 0) tracer_panic("do_exec failed to start new proc - errno = %d", Index: linux-2.6.10/arch/um/kernel/tt/tracer.c =================================================================== --- linux-2.6.10.orig/arch/um/kernel/tt/tracer.c 2004-12-25 05:33:49.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/tt/tracer.c 2005-04-07 22:10:59.446598000 +0800 @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include "user.h" @@ -25,7 +26,6 @@ #include "mem_user.h" #include "process.h" #include "kern_util.h" -#include "frame.h" #include "chan_user.h" #include "ptrace_user.h" #include "mode.h" @@ -72,6 +72,8 @@ (ptrace(PTRACE_CONT, pid, 0, 0) < 0)) tracer_panic("OP_FORK failed to attach pid"); wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL); + if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) + tracer_panic("OP_FORK: PTRACE_SETOPTIONS failed, errno = %d", errno); if(ptrace(PTRACE_CONT, pid, 0, 0) < 0) tracer_panic("OP_FORK failed to continue process"); } @@ -141,7 +143,7 @@ * any more, the trace of those will land here. So, we need to just * PTRACE_SYSCALL it. */ - case SIGTRAP: + case (SIGTRAP|SYSCALL_TRAP): if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) tracer_panic("sleeping_process_signal : Failed to " "PTRACE_SYSCALL pid %d, errno = %d\n", @@ -184,9 +186,8 @@ unsigned long eip = 0; int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0; int last_index, proc_id = 0, n, err, old_tracing = 0, strace = 0; - int pt_syscall_parm, local_using_sysemu; + int pt_syscall_parm, local_using_sysemu = 0; - capture_signal_stack(); signal(SIGPIPE, SIG_IGN); setup_tracer_winch(); tracing_pid = os_getpid(); @@ -198,6 +199,10 @@ printf("waitpid on idle thread failed, errno = %d\n", errno); exit(1); } + if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0) { + printf("Failed to PTRACE_SETOPTIONS for idle thread, errno = %d\n", errno); + exit(1); + } if((ptrace(PTRACE_CONT, pid, 0, 0) < 0)){ printf("Failed to continue idle thread, errno = %d\n", errno); exit(1); @@ -265,7 +270,25 @@ #endif else if(WIFSIGNALED(status)){ sig = WTERMSIG(status); - if(sig != 9){ + if(sig == SIGKILL){ + /* This is to make sure that processes die + * immediately without becoming zombies on + * all hosts. Before 2.6.9, kill(pid, SIGKILL) + * was enough to make sure a process went away + * immediately. After 2.6.9, they don't run + * any more, but they remain as zombies. So, + * a PTRACE_CONT is necessary in order to put + * them in a normal run state so that they die. + * I do a PTRACE_KILL here for good measure. + * Might as well kill it by all available + * means. These calls will likely fail when + * they are not needed because the process has + * already disappeared. However, they don't + * hurt. + */ + ptrace(PTRACE_KILL, pid, 0, 0); + ptrace(PTRACE_CONT, pid, 0, 0); + } else { printf("Child %d exited with signal %d\n", pid, sig); } @@ -297,7 +320,8 @@ task = cpu_tasks[proc_id].task; tracing = is_tracing(task); old_tracing = tracing; - + if ( tracing ) /* Assume: no syscall, when coming from user */ + do_sigtrap(task); local_using_sysemu = get_using_sysemu(); pt_syscall_parm = local_using_sysemu ? PTRACE_SYSEMU : PTRACE_SYSCALL; @@ -306,6 +330,15 @@ sig = 0; op = do_proc_op(task, proc_id); switch(op){ + /* + * This is called when entering user mode; after + * this, we start intercepting syscalls. + * + * In fact, a process is started in kernel mode, + * so with is_tracing() == 0 (and that is reset + * when executing syscalls, since UML kernel has + * the right to do syscalls); + */ case OP_TRACE_ON: arch_leave_kernel(task, pid); tracing = 1; @@ -314,7 +347,13 @@ case OP_HALT: unmap_physmem(); kmalloc_ok = 0; - ptrace(PTRACE_KILL, pid, 0, 0); + os_kill_ptraced_process(pid, 0); + /* Now let's reap remaining zombies */ + errno = 0; + do { + waitpid(-1, &status, + WUNTRACED); + } while (errno != ECHILD); return(op == OP_REBOOT); case OP_NONE: printf("Detaching pid %d\n", pid); @@ -328,14 +367,26 @@ */ pid = cpu_tasks[proc_id].pid; break; + case (SIGTRAP|SYSCALL_TRAP): + if(!tracing && (debugger_pid != -1)){ + child_signal(pid, W_STOPCODE(SIGTRAP)); + continue; + } + tracing = 0; + /* local_using_sysemu has been already set + * below, since if we are here, is_tracing() on + * the traced task was 1, i.e. the process had + * already run through one iteration of the + * loop which executed a OP_TRACE_ON request.*/ + do_syscall(task, pid, local_using_sysemu); + sig = SIGUSR2; + break; case SIGTRAP: if(!tracing && (debugger_pid != -1)){ child_signal(pid, status); continue; } tracing = 0; - if(do_syscall(task, pid, local_using_sysemu)) - sig = SIGUSR2; break; case SIGPROF: if(tracing) sig = 0; @@ -371,6 +422,9 @@ continue; } + local_using_sysemu = get_using_sysemu(); + pt_syscall_parm = local_using_sysemu ? PTRACE_SYSEMU : PTRACE_SYSCALL; + if(tracing){ if(singlestepping(task)) cont_type = PTRACE_SINGLESTEP; Index: linux-2.6.10/arch/um/kernel/tt/Makefile =================================================================== --- linux-2.6.10.orig/arch/um/kernel/tt/Makefile 2004-12-25 05:34:57.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/tt/Makefile 2005-04-07 22:05:29.491758760 +0800 @@ -8,7 +8,7 @@ obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \ syscall_kern.o syscall_user.o time.o tlb.o tracer.o trap_user.o \ - uaccess.o uaccess_user.o sys-$(SUBARCH)/ + uaccess.o uaccess_user.o obj-$(CONFIG_PT_PROXY) += gdb_kern.o ptproxy/ Index: linux-2.6.10/arch/um/kernel/tt/include/mode-tt.h =================================================================== --- linux-2.6.10.orig/arch/um/kernel/tt/include/mode-tt.h 2004-12-25 05:35:01.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/tt/include/mode-tt.h 2005-04-07 22:05:29.491758760 +0800 @@ -14,6 +14,41 @@ extern int tracer(int (*init_proc)(void *), void *sp); extern void user_time_init_tt(void); +extern void sig_handler_common_tt(int sig, void *sc); +extern void syscall_handler_tt(int sig, union uml_pt_regs *regs); +extern void reboot_tt(void); +extern void halt_tt(void); +extern int is_tracer_winch(int pid, int fd, void *data); +extern void kill_off_processes_tt(void); + +#endif + +/* + * 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: + */ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __MODE_TT_H__ +#define __MODE_TT_H__ + +#include "sysdep/ptrace.h" + +enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB }; + +extern int tracing_pid; + +extern int tracer(int (*init_proc)(void *), void *sp); +extern void user_time_init_tt(void); extern int copy_sc_from_user_tt(void *to_ptr, void *from_ptr, void *data); extern int copy_sc_to_user_tt(void *to_ptr, void *fp, void *from_ptr, void *data); Index: linux-2.6.10/arch/um/kernel/tt/include/tt.h =================================================================== --- linux-2.6.10.orig/arch/um/kernel/tt/include/tt.h 2004-12-25 05:34:58.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/tt/include/tt.h 2005-04-07 22:05:29.491758760 +0800 @@ -26,7 +26,8 @@ extern int is_tracing(void *task); extern void syscall_handler(int sig, union uml_pt_regs *regs); extern void exit_kernel(int pid, void *task); -extern int do_syscall(void *task, int pid, int local_using_sysemu); +extern void do_syscall(void *task, int pid, int local_using_sysemu); +extern void do_sigtrap(void *task); extern int is_valid_pid(int pid); extern void remap_data(void *segment_start, void *segment_end, int w); Index: linux-2.6.10/arch/um/kernel/ptrace.c =================================================================== --- linux-2.6.10.orig/arch/um/kernel/ptrace.c 2004-12-25 05:35:50.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/ptrace.c 2005-04-07 22:05:29.491758760 +0800 @@ -16,6 +16,7 @@ #include "asm/uaccess.h" #include "kern_util.h" #include "ptrace_user.h" +#include "signal_user.h" /* * Called by kernel/ptrace.c when detaching.. @@ -328,8 +329,10 @@ /* the 0x80 provides a way for the tracing parent to distinguish between a syscall stop and SIGTRAP delivery */ tracesysgood = (current->ptrace & PT_TRACESYSGOOD) && !is_singlestep; - ptrace_notify(SIGTRAP | (tracesysgood ? 0x80 : 0)); - + ptrace_notify(SIGTRAP | (tracesysgood ? SYSCALL_TRAP : 0)); + if ( entryexit ) /* force do_signal() --> is_syscall() */ + set_thread_flag(TIF_SIGPENDING); + /* force do_signal() --> is_syscall() */ set_thread_flag(TIF_SIGPENDING); Index: linux-2.6.10/arch/um/kernel/dyn.lds.S =================================================================== --- linux-2.6.10.orig/arch/um/kernel/dyn.lds.S 2004-12-25 05:34:48.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/dyn.lds.S 2005-04-07 22:05:29.492758608 +0800 @@ -7,8 +7,11 @@ SECTIONS { + PROVIDE (__executable_start = START); . = START + SIZEOF_HEADERS; .interp : { *(.interp) } + /* Used in arch/um/kernel/mem.c. Any memory between START and __binary_start + * is remapped.*/ __binary_start = .; . = ALIGN(4096); /* Init code and data */ _stext = .; Index: linux-2.6.10/arch/um/kernel/um_arch.c =================================================================== --- linux-2.6.10.orig/arch/um/kernel/um_arch.c 2004-12-25 05:35:24.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/um_arch.c 2005-04-07 22:05:29.492758608 +0800 @@ -44,11 +44,6 @@ .ipi_pipe = { -1, -1 } }; -/* Placeholder to make UML link until the vsyscall stuff is actually - * implemented - */ -void *__kernel_vsyscall; - unsigned long thread_saved_pc(struct task_struct *task) { return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas, @@ -326,6 +321,11 @@ */ check_tmpexec(); + /* Need to check this early because mmapping happens before the + * kernel is running. + */ + check_tmpexec(); + brk_start = (unsigned long) sbrk(0); CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start); /* Increase physical memory size for exec-shield users Index: linux-2.6.10/arch/um/kernel/time.c =================================================================== --- linux-2.6.10.orig/arch/um/kernel/time.c 2004-12-25 05:34:26.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/time.c 2005-04-07 22:05:29.492758608 +0800 @@ -60,6 +60,9 @@ (setitimer(ITIMER_REAL, &disable, NULL) < 0)) printk("disnable_timer - setitimer failed, errno = %d\n", errno); + /* If there are signals already queued, after unblocking ignore them */ + set_handler(SIGALRM, SIG_IGN, 0, -1); + set_handler(SIGVTALRM, SIG_IGN, 0, -1); } void switch_timers(int to_real) Index: linux-2.6.10/arch/um/kernel/process_kern.c =================================================================== --- linux-2.6.10.orig/arch/um/kernel/process_kern.c 2004-12-25 05:34:57.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/process_kern.c 2005-04-07 22:05:29.493758456 +0800 @@ -291,8 +291,6 @@ EXPORT_SYMBOL(disable_hlt); -extern int signal_frame_size; - void *um_kmalloc(int size) { return(kmalloc(size, GFP_KERNEL)); Index: linux-2.6.10/arch/um/kernel/trap_user.c =================================================================== --- linux-2.6.10.orig/arch/um/kernel/trap_user.c 2004-12-25 05:34:44.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/trap_user.c 2005-04-07 22:05:29.493758456 +0800 @@ -18,7 +18,6 @@ #include "sigcontext.h" #include "sysdep/sigcontext.h" #include "irq_user.h" -#include "frame_user.h" #include "signal_user.h" #include "time_user.h" #include "task.h" Index: linux-2.6.10/arch/um/kernel/signal_kern.c =================================================================== --- linux-2.6.10.orig/arch/um/kernel/signal_kern.c 2004-12-25 05:34:58.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/signal_kern.c 2005-04-07 22:05:29.493758456 +0800 @@ -230,53 +230,6 @@ return(do_sigaltstack(uss, uoss, PT_REGS_SP(¤t->thread.regs))); } -extern int userspace_pid[]; - -static int copy_sc_from_user(struct pt_regs *to, void *from, - struct arch_frame_data *arch) -{ - int ret; - - ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from, arch), - copy_sc_from_user_skas(userspace_pid[0], - &to->regs, from)); - return(ret); -} - -long sys_sigreturn(struct pt_regs regs) -{ - void __user *sc = sp_to_sc(PT_REGS_SP(¤t->thread.regs)); - void __user *mask = sp_to_mask(PT_REGS_SP(¤t->thread.regs)); - int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long); - - spin_lock_irq(¤t->sighand->siglock); - copy_from_user(¤t->blocked.sig[0], sc_sigmask(sc), - sizeof(current->blocked.sig[0])); - copy_from_user(¤t->blocked.sig[1], mask, sig_size); - sigdelsetmask(¤t->blocked, ~_BLOCKABLE); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - copy_sc_from_user(¤t->thread.regs, sc, - &signal_frame_sc.common.arch); - return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); -} - -long sys_rt_sigreturn(struct pt_regs regs) -{ - unsigned long sp = PT_REGS_SP(¤t->thread.regs); - struct ucontext __user *uc = sp_to_uc(sp); - int sig_size = _NSIG_WORDS * sizeof(unsigned long); - - spin_lock_irq(¤t->sighand->siglock); - copy_from_user(¤t->blocked, &uc->uc_sigmask, sig_size); - sigdelsetmask(¤t->blocked, ~_BLOCKABLE); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); - copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext, - &signal_frame_si.common.arch); - return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); -} - /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically Index: linux-2.6.10/arch/um/kernel/uml.lds.S =================================================================== --- linux-2.6.10.orig/arch/um/kernel/uml.lds.S 2004-12-25 05:34:44.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/uml.lds.S 2005-04-07 22:05:29.494758304 +0800 @@ -7,8 +7,12 @@ SECTIONS { + /*This must contain the right address - not quite the default ELF one.*/ + PROVIDE (__executable_start = START); . = START + SIZEOF_HEADERS; + /* Used in arch/um/kernel/mem.c. Any memory between START and __binary_start + * is remapped.*/ __binary_start = .; #ifdef MODE_TT .thread_private : { @@ -20,9 +24,13 @@ } . = ALIGN(4096); .remap : { arch/um/kernel/tt/unmap_fin.o (.text) } -#endif + /*If you put this after #endif, STATIC build without TT mode + gives a segfaulting binary. And after all, a hole just after + binary_start is not very polite to glibc.*/ . = ALIGN(4096); /* Init code and data */ +#endif + _stext = .; __init_begin = .; .init.text : { Index: linux-2.6.10/arch/um/kernel/ksyms.c =================================================================== --- linux-2.6.10.orig/arch/um/kernel/ksyms.c 2004-12-25 05:33:50.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/ksyms.c 2005-04-07 22:05:29.494758304 +0800 @@ -48,6 +48,7 @@ EXPORT_SYMBOL(mode_tt); EXPORT_SYMBOL(handle_page_fault); EXPORT_SYMBOL(find_iomem); +EXPORT_SYMBOL(end_iomem); #ifdef CONFIG_MODE_TT EXPORT_SYMBOL(strncpy_from_user_tt); Index: linux-2.6.10/arch/um/kernel/signal_user.c =================================================================== --- linux-2.6.10.orig/arch/um/kernel/signal_user.c 2004-12-25 05:35:23.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/signal_user.c 2005-04-07 22:05:29.494758304 +0800 @@ -61,6 +61,10 @@ * disable profiling; it's safe because the profiling code does not interact * with the kernel code at all.*/ +/* Both here and in set/get_signal we don't touch SIGPROF, because we must not + * disable profiling; it's safe because the profiling code does not interact + * with the kernel code at all.*/ + static void change_signals(int type) { sigset_t mask; Index: linux-2.6.10/arch/um/kernel/mem_user.c =================================================================== --- linux-2.6.10.orig/arch/um/kernel/mem_user.c 2004-12-25 05:34:57.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/mem_user.c 2005-04-07 22:05:29.494758304 +0800 @@ -101,6 +101,8 @@ } printf("OK\n"); munmap(addr, UM_KERN_PAGE_SIZE); + + os_close_file(fd); } static int have_devanon = 0; @@ -261,6 +263,39 @@ } #endif +#if 0 +/* Debugging facility for dumping stuff out to the host, avoiding the timing + * problems that come with printf and breakpoints. + * Enable in case of emergency. + */ + +int logging = 1; +int logging_fd = -1; + +int logging_line = 0; +char logging_buf[512]; + +void log(char *fmt, ...) +{ + va_list ap; + struct timeval tv; + struct openflags flags; + + if(logging == 0) return; + if(logging_fd < 0){ + flags = of_create(of_trunc(of_rdwr(OPENFLAGS()))); + logging_fd = os_open_file("log", flags, 0644); + } + gettimeofday(&tv, NULL); + sprintf(logging_buf, "%d\t %u.%u ", logging_line++, tv.tv_sec, + tv.tv_usec); + va_start(ap, fmt); + vsprintf(&logging_buf[strlen(logging_buf)], fmt, ap); + va_end(ap); + write(logging_fd, logging_buf, strlen(logging_buf)); +} +#endif + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically Index: linux-2.6.10/arch/um/kernel/Makefile =================================================================== --- linux-2.6.10.orig/arch/um/kernel/Makefile 2004-12-25 05:35:01.000000000 +0800 +++ linux-2.6.10/arch/um/kernel/Makefile 2005-04-07 22:05:29.495758152 +0800 @@ -6,7 +6,7 @@ extra-y := vmlinux.lds clean-files := vmlinux.lds.S -obj-y = checksum.o config.o exec_kern.o exitcode.o frame_kern.o frame.o \ +obj-y = checksum.o config.o exec_kern.o exitcode.o \ helper.o init_task.o irq.o irq_user.o ksyms.o main.o mem.o mem_user.o \ physmem.o process.o process_kern.o ptrace.o reboot.o resource.o \ sigio_user.o sigio_kern.o signal_kern.o signal_user.o smp.o \ Index: linux-2.6.10/arch/um/Kconfig =================================================================== --- linux-2.6.10.orig/arch/um/Kconfig 2004-12-25 05:34:45.000000000 +0800 +++ linux-2.6.10/arch/um/Kconfig 2005-04-07 22:05:29.495758152 +0800 @@ -139,6 +139,25 @@ It is safe to say 'Y' here. +config MAGIC_SYSRQ + bool "Magic SysRq key" + depends on MCONSOLE + ---help--- + If you say Y here, you will have some control over the system even + if the system crashes for example during kernel debugging (e.g., you + will be able to flush the buffer cache to disk, reboot the system + immediately or dump some status information). A key for each of the + possible requests is provided. + + This is the feature normally accomplished by pressing a key + while holding SysRq (Alt+PrintScreen). + + On UML, this is accomplished by sending a "sysrq" command with + mconsole, followed by the letter for the requested command. + + The keys are documented in . Don't say Y + unless you really know what this hack does. + config HOST_2G_2G bool "2G/2G host address space split" default n @@ -153,28 +172,28 @@ So, if you do not know what to do here, say 'N'. config SMP - bool "Symmetric multi-processing support (EXPERIMENTAL)" - default n - depends on MODE_TT && EXPERIMENTAL - help - This option enables UML SMP support. - It is NOT related to having a real SMP box. Not directly, at least. + bool "Symmetric multi-processing support (EXPERIMENTAL)" + default n + depends on MODE_TT && EXPERIMENTAL + help + This option enables UML SMP support. + It is NOT related to having a real SMP box. Not directly, at least. + + UML implements virtual SMP by allowing as many processes to run + simultaneously on the host as there are virtual processors configured. + + Obviously, if the host is a uniprocessor, those processes will + timeshare, but, inside UML, will appear to be running simultaneously. + If the host is a multiprocessor, then UML processes may run + simultaneously, depending on the host scheduler. + + This, however, is supported only in TT mode. So, if you use the SKAS + patch on your host, switching to TT mode and enabling SMP usually gives + you worse performances. + Also, since the support for SMP has been under-developed, there could + be some bugs being exposed by enabling SMP. - UML implements virtual SMP by allowing as many processes to run - simultaneously on the host as there are virtual processors configured. - - Obviously, if the host is a uniprocessor, those processes will - timeshare, but, inside UML, will appear to be running simultaneously. - If the host is a multiprocessor, then UML processes may run - simultaneously, depending on the host scheduler. - - This, however, is supported only in TT mode. So, if you use the SKAS - patch on your host, switching to TT mode and enabling SMP usually gives - you worse performances. - Also, since the support for SMP has been under-developed, there could - be some bugs being exposed by enabling SMP. - - If you don't know what to do, say N. + If you don't know what to do, say N. config NR_CPUS int "Maximum number of CPUs (2-32)" @@ -282,4 +301,8 @@ bool default n +config INPUT + bool + default n + source "arch/um/Kconfig.debug" Index: linux-2.6.10/arch/um/include/frame.h =================================================================== --- linux-2.6.10.orig/arch/um/include/frame.h 2004-12-25 05:34:31.000000000 +0800 +++ linux-2.6.10/arch/um/include/frame.h 2005-04-07 19:34:21.197950744 +0800 @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __FRAME_H_ -#define __FRAME_H_ - -#include "sysdep/frame.h" - -struct frame_common { - void *data; - int len; - int sig_index; - int sr_index; - int sr_relative; - int sp_index; - struct arch_frame_data arch; -}; - -struct sc_frame { - struct frame_common common; - int sc_index; -}; - -extern struct sc_frame signal_frame_sc; - -extern struct sc_frame signal_frame_sc_sr; - -struct si_frame { - struct frame_common common; - int sip_index; - int si_index; - int ucp_index; - int uc_index; -}; - -extern struct si_frame signal_frame_si; - -extern void capture_signal_stack(void); - -#endif - -/* - * 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: - */ Index: linux-2.6.10/arch/um/include/elf_user.h =================================================================== --- linux-2.6.10.orig/arch/um/include/elf_user.h 2005-04-07 19:34:21.197950744 +0800 +++ linux-2.6.10/arch/um/include/elf_user.h 2005-04-07 22:05:29.495758152 +0800 @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2004 Fujitsu Siemens Computers GmbH + * Author: Bodo Stroesser + * Licensed under the GPL + */ + +#ifndef __ELF_USER_H__ +#define __ELF_USER_H__ + +/* For compilation on a host that doesn't support AT_SYSINFO (Linux 2.4) */ + +#ifndef AT_SYSINFO +#define AT_SYSINFO 32 +#endif +#ifndef AT_SYSINFO_EHDR +#define AT_SYSINFO_EHDR 33 +#endif + +#endif Index: linux-2.6.10/arch/um/include/signal_user.h =================================================================== --- linux-2.6.10.orig/arch/um/include/signal_user.h 2004-12-25 05:33:49.000000000 +0800 +++ linux-2.6.10/arch/um/include/signal_user.h 2005-04-07 22:05:29.496758000 +0800 @@ -14,6 +14,8 @@ extern int set_signals(int enable); extern int get_signals(void); +#define SYSCALL_TRAP 0x80 + #endif /* Index: linux-2.6.10/arch/um/include/skas_ptrace.h =================================================================== --- linux-2.6.10.orig/arch/um/include/skas_ptrace.h 2004-12-25 05:35:27.000000000 +0800 +++ linux-2.6.10/arch/um/include/skas_ptrace.h 2005-04-07 22:05:29.496758000 +0800 @@ -6,6 +6,7 @@ #ifndef __SKAS_PTRACE_H #define __SKAS_PTRACE_H +#ifndef PTRACE_FAULTINFO struct ptrace_faultinfo { int is_write; unsigned long addr; @@ -21,6 +22,7 @@ #define PTRACE_SIGPENDING 53 #define PTRACE_LDT 54 #define PTRACE_SWITCH_MM 55 +#endif #endif Index: linux-2.6.10/arch/um/include/frame_kern.h =================================================================== --- linux-2.6.10.orig/arch/um/include/frame_kern.h 2004-12-25 05:34:57.000000000 +0800 +++ linux-2.6.10/arch/um/include/frame_kern.h 2005-04-07 22:05:29.496758000 +0800 @@ -6,8 +6,8 @@ #ifndef __FRAME_KERN_H_ #define __FRAME_KERN_H_ -#include "frame.h" -#include "sysdep/frame_kern.h" +#define _S(nr) (1<<((nr)-1)) +#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) extern int setup_signal_stack_sc(unsigned long stack_top, int sig, struct k_sigaction *ka, Index: linux-2.6.10/arch/um/include/ptrace_user.h =================================================================== --- linux-2.6.10.orig/arch/um/include/ptrace_user.h 2004-12-25 05:33:51.000000000 +0800 +++ linux-2.6.10/arch/um/include/ptrace_user.h 2005-04-07 22:05:29.496758000 +0800 @@ -26,4 +26,35 @@ int get_using_sysemu(void); extern int sysemu_supported; + +/* syscall emulation path in ptrace */ + +#ifndef PTRACE_SYSEMU +#define PTRACE_SYSEMU 31 +#endif + +/* On architectures, that started to support PTRACE_O_TRACESYSGOOD + * in linux 2.4, there are two different definitions of + * PTRACE_SETOPTIONS: linux 2.4 uses 21 while linux 2.6 uses 0x4200. + * For binary compatibility, 2.6 also supports the old "21", named + * PTRACE_OLDSETOPTION. On these architectures, UML always must use + * "21", to ensure the kernel runs on 2.4 and 2.6 host without + * recompilation. So, we use PTRACE_OLDSETOPTIONS in UML. + * We also want to be able to build the kernel on 2.4, which doesn't + * have PTRACE_OLDSETOPTIONS. So, if it is missing, we declare + * PTRACE_OLDSETOPTIONS to to be the same as PTRACE_SETOPTIONS. + * + * On architectures, that start to support PTRACE_O_TRACESYSGOOD on + * linux 2.6, PTRACE_OLDSETOPTIONS never is defined, and also isn't + * supported by the host kernel. In that case, our trick lets us use + * the new 0x4200 with the name PTRACE_OLDSETOPTIONS. + */ +#ifndef PTRACE_OLDSETOPTIONS +#define PTRACE_OLDSETOPTIONS PTRACE_SETOPTIONS +#endif + +void set_using_sysemu(int value); +int get_using_sysemu(void); +extern int sysemu_supported; + #endif Index: linux-2.6.10/arch/um/include/sysdep-i386/frame.h =================================================================== --- linux-2.6.10.orig/arch/um/include/sysdep-i386/frame.h 2004-12-25 05:35:01.000000000 +0800 +++ linux-2.6.10/arch/um/include/sysdep-i386/frame.h 2005-04-07 19:34:21.197950744 +0800 @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __FRAME_I386_H -#define __FRAME_I386_H - -struct arch_frame_data_raw { - unsigned long fp_start; - unsigned long sr; -}; - -struct arch_frame_data { - int fpstate_size; -}; - -#endif - -/* - * 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: - */ Index: linux-2.6.10/arch/um/include/sysdep-i386/frame_kern.h =================================================================== --- linux-2.6.10.orig/arch/um/include/sysdep-i386/frame_kern.h 2004-12-25 05:34:26.000000000 +0800 +++ linux-2.6.10/arch/um/include/sysdep-i386/frame_kern.h 2005-04-07 19:34:21.197950744 +0800 @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __FRAME_KERN_I386_H -#define __FRAME_KERN_I386_H - -/* This is called from sys_sigreturn. It takes the sp at the point of the - * sigreturn system call and returns the address of the sigcontext struct - * on the stack. - */ - -static inline void *sp_to_sc(unsigned long sp) -{ - return((void *) sp); -} - -static inline void *sp_to_uc(unsigned long sp) -{ - unsigned long uc; - - uc = sp + signal_frame_si.uc_index - - signal_frame_si.common.sp_index - 4; - return((void *) uc); -} - -static inline void *sp_to_rt_sc(unsigned long sp) -{ - unsigned long sc; - - sc = sp - signal_frame_si.common.sp_index + - signal_frame_si.common.len - 4; - return((void *) sc); -} - -static inline void *sp_to_mask(unsigned long sp) -{ - unsigned long mask; - - mask = sp - signal_frame_sc.common.sp_index + - signal_frame_sc.common.len - 8; - return((void *) mask); -} - -extern int sc_size(void *data); - -static inline void *sp_to_rt_mask(unsigned long sp) -{ - unsigned long mask; - - mask = sp - signal_frame_si.common.sp_index + - signal_frame_si.common.len + - sc_size(&signal_frame_si.common.arch) - 4; - return((void *) mask); -} - -#endif - -/* - * 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: - */ Index: linux-2.6.10/arch/um/include/sysdep-i386/frame_user.h =================================================================== --- linux-2.6.10.orig/arch/um/include/sysdep-i386/frame_user.h 2004-12-25 05:35:28.000000000 +0800 +++ linux-2.6.10/arch/um/include/sysdep-i386/frame_user.h 2005-04-07 19:34:21.197950744 +0800 @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __FRAME_USER_I386_H -#define __FRAME_USER_I386_H - -#include -#include "sysdep/frame.h" - -/* This stuff is to calculate the size of the fp state struct at runtime - * because it has changed between 2.2 and 2.4 and it would be good for a - * UML compiled on one to work on the other. - * So, setup_arch_frame_raw fills in the arch struct with the raw data, which - * just contains the address of the end of the sigcontext. This is invoked - * from the signal handler. - * setup_arch_frame uses that data to figure out what - * arch_frame_data.fpstate_size should be. It really has no idea, since it's - * not allowed to do sizeof(struct fpstate) but it's safe to consider that it's - * everything from the end of the sigcontext up to the top of the stack. So, - * it masks off the page number to get the offset within the page and subtracts - * that from the page size, and that's how big the fpstate struct will be - * considered to be. - */ - -static inline void setup_arch_frame_raw(struct arch_frame_data_raw *data, - void *end, unsigned long srp) -{ - unsigned long sr = *((unsigned long *) srp); - - data->fp_start = (unsigned long) end; - if((sr & PAGE_MASK) == ((unsigned long) end & PAGE_MASK)) - data->sr = sr; - else data->sr = 0; -} - -static inline void setup_arch_frame(struct arch_frame_data_raw *in, - struct arch_frame_data *out) -{ - unsigned long fpstate_start = in->fp_start; - - if(in->sr == 0){ - fpstate_start &= ~PAGE_MASK; - out->fpstate_size = PAGE_SIZE - fpstate_start; - } - else { - out->fpstate_size = in->sr - fpstate_start; - } -} - -/* This figures out where on the stack the SA_RESTORER function address - * is stored. For i386, it's the signal handler return address, so it's - * located next to the frame pointer. - * This is inlined, so __builtin_frame_address(0) is correct. Otherwise, - * it would have to be __builtin_frame_address(1). - */ - -#define frame_restorer() \ -({ \ - unsigned long *fp; \ -\ - fp = __builtin_frame_address(0); \ - ((unsigned long) (fp + 1)); \ -}) - -/* Similarly, this returns the value of sp when the handler was first - * entered. This is used to calculate the proper sp when delivering - * signals. - */ - -#define frame_sp() \ -({ \ - unsigned long *fp; \ -\ - fp = __builtin_frame_address(0); \ - ((unsigned long) (fp + 1)); \ -}) - -#endif - -/* - * 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: - */ Index: linux-2.6.10/arch/um/include/frame_user.h =================================================================== --- linux-2.6.10.orig/arch/um/include/frame_user.h 2004-12-25 05:33:50.000000000 +0800 +++ linux-2.6.10/arch/um/include/frame_user.h 2005-04-07 19:34:21.197950744 +0800 @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __FRAME_USER_H_ -#define __FRAME_USER_H_ - -#include "sysdep/frame_user.h" -#include "frame.h" - -#endif - -/* - * 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: - */ Index: linux-2.6.10/arch/i386/kernel/ptrace.c =================================================================== --- linux-2.6.10.orig/arch/i386/kernel/ptrace.c 2004-12-25 05:34:29.000000000 +0800 +++ linux-2.6.10/arch/i386/kernel/ptrace.c 2005-04-07 22:05:29.498757696 +0800 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -406,15 +407,27 @@ } break; + case PTRACE_SYSEMU: /* continue and stop at next syscall, which will not be executed */ case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ case PTRACE_CONT: /* restart after signal. */ ret = -EIO; if ((unsigned long) data > _NSIG) break; + /* If we came here with PTRACE_SYSEMU and now continue with + * PTRACE_SYSCALL, entry.S used to intercept the syscall return. + * But it shouldn't! + * So we don't clear TIF_SYSCALL_EMU, which is always unused in + * this special case, to remember, we came from SYSEMU. That + * flag will be cleared by do_syscall_trace(). + */ + if (request == PTRACE_SYSEMU) { + set_tsk_thread_flag(child, TIF_SYSCALL_EMU); + } else if (request == PTRACE_CONT) { + clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); + } if (request == PTRACE_SYSCALL) { set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - } - else { + } else { clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); } child->exit_code = data; @@ -443,6 +456,8 @@ ret = -EIO; if ((unsigned long) data > _NSIG) break; + /*See do_syscall_trace to know why we don't clear + * TIF_SYSCALL_EMU.*/ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); set_singlestep(child); child->exit_code = data; @@ -542,6 +557,58 @@ (struct user_desc __user *) data); break; +#ifdef CONFIG_PROC_MM + case PTRACE_FAULTINFO: { + struct ptrace_faultinfo fault; + + fault = ((struct ptrace_faultinfo) + { .is_write = child->thread.error_code, + .addr = child->thread.cr2 }); + ret = copy_to_user((unsigned long *) data, &fault, + sizeof(fault)); + if(ret) + break; + break; + } + + case PTRACE_SIGPENDING: + ret = copy_to_user((unsigned long *) data, + &child->pending.signal, + sizeof(child->pending.signal)); + break; + + case PTRACE_LDT: { + struct ptrace_ldt ldt; + + if(copy_from_user(&ldt, (unsigned long *) data, + sizeof(ldt))){ + ret = -EIO; + break; + } + ret = __modify_ldt(child->mm, ldt.func, ldt.ptr, ldt.bytecount); + break; + } + + case PTRACE_SWITCH_MM: { + struct mm_struct *old = child->mm; + struct mm_struct *new = proc_mm_get_mm(data); + + if(IS_ERR(new)){ + ret = PTR_ERR(new); + break; + } + + atomic_inc(&new->mm_users); + task_lock(child); + child->mm = new; + child->active_mm = new; + task_unlock(child); + mmput(old); + ret = 0; + break; + } +#endif + default: ret = ptrace_request(child, request, addr, data); break; @@ -557,8 +624,9 @@ * - triggered by current->work.syscall_trace */ __attribute__((regparm(3))) -void do_syscall_trace(struct pt_regs *regs, int entryexit) +int do_syscall_trace(struct pt_regs *regs, int entryexit) { + int is_sysemu, is_systrace, is_singlestep; if (unlikely(current->audit_context)) { if (!entryexit) audit_syscall_entry(current, regs->orig_eax, @@ -567,16 +635,27 @@ else audit_syscall_exit(current, regs->eax); } - - if (!test_thread_flag(TIF_SYSCALL_TRACE) && - !test_thread_flag(TIF_SINGLESTEP)) - return; + is_sysemu = test_thread_flag(TIF_SYSCALL_EMU); + is_systrace = test_thread_flag(TIF_SYSCALL_TRACE); + is_singlestep = test_thread_flag(TIF_SINGLESTEP); + + if (!is_systrace && !is_singlestep && !is_sysemu) + return 0; + /* We can detect the case of coming from PTRACE_SYSEMU and now running + * with PTRACE_SYSCALL or PTRACE_SINGLESTEP, by TIF_SYSCALL_EMU being + * set additionally. + * If so let's reset the flag and return without action. + */ + if (is_sysemu && (is_systrace || is_singlestep)) { + clear_thread_flag(TIF_SYSCALL_EMU); + return 0; + } if (!(current->ptrace & PT_PTRACED)) - return; + return 0; /* the 0x80 provides a way for the tracing parent to distinguish between a syscall stop and SIGTRAP delivery */ ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) && - !test_thread_flag(TIF_SINGLESTEP) ? 0x80 : 0)); + !is_singlestep ? 0x80 : 0)); /* * this isn't the same as continuing with a signal, but it will do @@ -587,4 +666,6 @@ send_sig(current->exit_code, current, 1); current->exit_code = 0; } + /* != 0 if nullifying the syscall, 0 if running it normally */ + return is_sysemu; } Index: linux-2.6.10/arch/i386/kernel/ldt.c =================================================================== --- linux-2.6.10.orig/arch/i386/kernel/ldt.c 2004-12-25 05:35:23.000000000 +0800 +++ linux-2.6.10/arch/i386/kernel/ldt.c 2005-04-07 22:05:29.498757696 +0800 @@ -18,6 +18,7 @@ #include #include #include +#include #ifdef CONFIG_SMP /* avoids "defined but not used" warnig */ static void flush_ldt(void *null) @@ -27,11 +28,12 @@ } #endif -static int alloc_ldt(mm_context_t *pc, int mincount, int reload) +static int alloc_ldt(struct mm_struct *mm, int mincount, int reload) { void *oldldt; void *newldt; int oldsize; + mm_context_t * pc = &mm->context; if (mincount <= pc->size) return 0; @@ -58,13 +60,15 @@ #ifdef CONFIG_SMP cpumask_t mask; preempt_disable(); - load_LDT(pc); + if (¤t->active_mm->context == pc) + load_LDT(pc); mask = cpumask_of_cpu(smp_processor_id()); - if (!cpus_equal(current->mm->cpu_vm_mask, mask)) + if (!cpus_equal(mm->cpu_vm_mask, mask)) smp_call_function(flush_ldt, NULL, 1, 1); preempt_enable(); #else - load_LDT(pc); + if (¤t->active_mm->context == pc) + load_LDT(pc); #endif } if (oldsize) { @@ -76,12 +80,12 @@ return 0; } -static inline int copy_ldt(mm_context_t *new, mm_context_t *old) +static inline int copy_ldt(struct mm_struct *new, struct mm_struct *old) { - int err = alloc_ldt(new, old->size, 0); + int err = alloc_ldt(new, old->context.size, 0); if (err < 0) return err; - memcpy(new->ldt, old->ldt, old->size*LDT_ENTRY_SIZE); + memcpy(new->context.ldt, old->context.ldt, old->context.size*LDT_ENTRY_SIZE); return 0; } @@ -89,22 +93,24 @@ * we do not have to muck with descriptors here, that is * done in switch_mm() as needed. */ -int init_new_context(struct task_struct *tsk, struct mm_struct *mm) +int copy_context(struct mm_struct *mm, struct mm_struct *old_mm) { - struct mm_struct * old_mm; int retval = 0; - init_MUTEX(&mm->context.sem); - mm->context.size = 0; - old_mm = current->mm; if (old_mm && old_mm->context.size > 0) { down(&old_mm->context.sem); - retval = copy_ldt(&mm->context, &old_mm->context); + retval = copy_ldt(mm, old_mm); up(&old_mm->context.sem); } return retval; } +int init_new_context(struct task_struct *tsk, struct mm_struct *mm) +{ + init_new_empty_context(mm); + return copy_context(mm, current->mm); +} + /* * No need to lock the MM as we are the last user */ @@ -121,11 +127,11 @@ } } -static int read_ldt(void __user * ptr, unsigned long bytecount) +static int read_ldt(struct mm_struct * mm, void __user * ptr, + unsigned long bytecount) { int err; unsigned long size; - struct mm_struct * mm = current->mm; if (!mm->context.size) return 0; @@ -174,9 +180,8 @@ return err; } -static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode) +static int write_ldt(struct mm_struct * mm, void __user * ptr, unsigned long bytecount, int oldmode) { - struct mm_struct * mm = current->mm; __u32 entry_1, entry_2, *lp; int error; struct user_desc ldt_info; @@ -200,7 +205,7 @@ down(&mm->context.sem); if (ldt_info.entry_number >= mm->context.size) { - error = alloc_ldt(¤t->mm->context, ldt_info.entry_number+1, 1); + error = alloc_ldt(mm, ldt_info.entry_number+1, 1); if (error < 0) goto out_unlock; } @@ -233,23 +238,29 @@ return error; } -asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) +int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr, + unsigned long bytecount) { int ret = -ENOSYS; switch (func) { case 0: - ret = read_ldt(ptr, bytecount); + ret = read_ldt(mm, ptr, bytecount); break; case 1: - ret = write_ldt(ptr, bytecount, 1); + ret = write_ldt(mm, ptr, bytecount, 1); break; case 2: ret = read_default_ldt(ptr, bytecount); break; case 0x11: - ret = write_ldt(ptr, bytecount, 0); + ret = write_ldt(mm, ptr, bytecount, 0); break; } return ret; } + +asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) +{ + return __modify_ldt(current->mm, func, ptr, bytecount); +} Index: linux-2.6.10/arch/i386/kernel/sys_i386.c =================================================================== --- linux-2.6.10.orig/arch/i386/kernel/sys_i386.c 2004-12-25 05:35:39.000000000 +0800 +++ linux-2.6.10/arch/i386/kernel/sys_i386.c 2005-04-07 22:05:29.499757544 +0800 @@ -41,7 +41,7 @@ } /* common code for old and new mmaps */ -static inline long do_mmap2( +long do_mmap2(struct mm_struct *mm, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff) @@ -56,9 +56,9 @@ goto out; } - down_write(¤t->mm->mmap_sem); - error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); - up_write(¤t->mm->mmap_sem); + down_write(&mm->mmap_sem); + error = __do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff); + up_write(&mm->mmap_sem); if (file) fput(file); @@ -70,7 +70,7 @@ unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff) { - return do_mmap2(addr, len, prot, flags, fd, pgoff); + return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff); } /* @@ -101,7 +101,7 @@ if (a.offset & ~PAGE_MASK) goto out; - err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); + err = do_mmap2(current->mm, a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); out: return err; } Index: linux-2.6.10/arch/i386/kernel/entry.S =================================================================== --- linux-2.6.10.orig/arch/i386/kernel/entry.S 2005-04-06 23:38:35.000000000 +0800 +++ linux-2.6.10/arch/i386/kernel/entry.S 2005-04-07 22:05:29.499757544 +0800 @@ -222,7 +222,7 @@ SAVE_ALL GET_THREAD_INFO(%ebp) - testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) + testb $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) jnz syscall_trace_entry cmpl $(nr_syscalls), %eax jae syscall_badsys @@ -245,8 +245,8 @@ pushl %eax # save orig_eax SAVE_ALL GET_THREAD_INFO(%ebp) - # system call tracing in operation - testb $(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) + # system call tracing in operation / emulation + testb $(_TIF_SYSCALL_EMU|_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT),TI_flags(%ebp) jnz syscall_trace_entry cmpl $(nr_syscalls), %eax jae syscall_badsys @@ -307,6 +307,9 @@ movl %esp, %eax xorl %edx,%edx call do_syscall_trace + cmpl $0, %eax + jne syscall_exit # ret != 0 -> running under PTRACE_SYSEMU, + # so must skip actual syscall movl ORIG_EAX(%esp), %eax cmpl $(nr_syscalls), %eax jnae syscall_call Index: linux-2.6.10/arch/i386/Kconfig =================================================================== --- linux-2.6.10.orig/arch/i386/Kconfig 2005-04-06 23:38:33.000000000 +0800 +++ linux-2.6.10/arch/i386/Kconfig 2005-04-07 22:05:29.500757392 +0800 @@ -738,6 +738,10 @@ depends on HIGHMEM64G default y +config PROC_MM + bool "/proc/mm support" + default y + # Common NUMA Features config NUMA bool "Numa Memory Allocation and Scheduler Support" Index: linux-2.6.10/fs/hostfs/hostfs.h =================================================================== --- linux-2.6.10.orig/fs/hostfs/hostfs.h 2004-12-25 05:35:24.000000000 +0800 +++ linux-2.6.10/fs/hostfs/hostfs.h 2005-04-07 22:05:29.500757392 +0800 @@ -16,9 +16,30 @@ #define HOSTFS_ATTR_CTIME 64 #define HOSTFS_ATTR_ATIME_SET 128 #define HOSTFS_ATTR_MTIME_SET 256 + +/* These two are unused by hostfs. */ #define HOSTFS_ATTR_FORCE 512 /* Not a change, but a change it */ #define HOSTFS_ATTR_ATTR_FLAG 1024 +/* If you are very careful, you'll notice that these two are missing: + * + * #define ATTR_KILL_SUID 2048 + * #define ATTR_KILL_SGID 4096 + * + * and this is because they were added in 2.5 development in this patch: + * + * http://linux.bkbits.net:8080/linux-2.5/ + * cset@3caf4a12k4XgDzK7wyK-TGpSZ9u2Ww?nav=index.html + * |src/.|src/include|src/include/linux|related/include/linux/fs.h + * + * Actually, they are not needed by most ->setattr() methods - they are set by + * callers of notify_change() to notify that the setuid/setgid bits must be + * dropped. + * notify_change() will delete those flags, make sure attr->ia_valid & ATTR_MODE + * is on, and remove the appropriate bits from attr->ia_mode (attr is a + * "struct iattr *"). -BlaisorBlade + */ + struct hostfs_iattr { unsigned int ia_valid; mode_t ia_mode; Index: linux-2.6.10/fs/hostfs/hostfs_kern.c =================================================================== --- linux-2.6.10.orig/fs/hostfs/hostfs_kern.c 2004-12-25 05:34:01.000000000 +0800 +++ linux-2.6.10/fs/hostfs/hostfs_kern.c 2005-04-07 22:05:29.501757240 +0800 @@ -393,6 +393,7 @@ static struct file_operations hostfs_file_fops = { .llseek = generic_file_llseek, .read = generic_file_read, + .sendfile = generic_file_sendfile, .write = generic_file_write, .mmap = generic_file_mmap, .open = hostfs_file_open, @@ -818,6 +819,10 @@ char *name; int err; + err = inode_change_ok(dentry->d_inode, attr); + if (err) + return err; + if(append) attr->ia_valid &= ~ATTR_SIZE; Index: linux-2.6.10/kernel/fork.c =================================================================== --- linux-2.6.10.orig/kernel/fork.c 2005-04-06 23:38:35.000000000 +0800 +++ linux-2.6.10/kernel/fork.c 2005-04-07 22:05:29.502757088 +0800 @@ -927,6 +927,9 @@ * of CLONE_PTRACE. */ clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE); +#ifdef TIF_SYSCALL_EMU + clear_tsk_thread_flag(p, TIF_SYSCALL_EMU); +#endif /* Our parent execution domain becomes current domain These must match for thread signalling to apply */ Index: linux-2.6.10/include/linux/ptrace.h =================================================================== --- linux-2.6.10.orig/include/linux/ptrace.h 2005-04-06 23:38:33.000000000 +0800 +++ linux-2.6.10/include/linux/ptrace.h 2005-04-07 22:05:29.503756936 +0800 @@ -20,6 +20,7 @@ #define PTRACE_DETACH 0x11 #define PTRACE_SYSCALL 24 +#define PTRACE_SYSEMU 31 /* 0x4200-0x4300 are reserved for architecture-independent additions. */ #define PTRACE_SETOPTIONS 0x4200 Index: linux-2.6.10/include/linux/mm.h =================================================================== --- linux-2.6.10.orig/include/linux/mm.h 2005-04-06 23:38:33.000000000 +0800 +++ linux-2.6.10/include/linux/mm.h 2005-04-07 22:05:29.503756936 +0800 @@ -625,6 +625,9 @@ extern struct shrinker *set_shrinker(int, shrinker_t); extern void remove_shrinker(struct shrinker *shrinker); +extern long do_mprotect(struct mm_struct *mm, unsigned long start, + size_t len, unsigned long prot); + /* * On a two-level page table, this ends up being trivial. Thus the * inlining and the symmetry break with pte_alloc_map() that does all @@ -684,9 +687,15 @@ extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); -extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, +extern unsigned long __do_mmap_pgoff(struct mm_struct *mm, struct file *file, + unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flag, + unsigned long pgoff); +static inline unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, unsigned long len, unsigned long prot, - unsigned long flag, unsigned long pgoff); + unsigned long flag, unsigned long pgoff) { + return __do_mmap_pgoff(current->mm, file, addr, len, prot, flag, pgoff); +} static inline unsigned long do_mmap(struct file *file, unsigned long addr, unsigned long len, unsigned long prot, Index: linux-2.6.10/include/linux/proc_mm.h =================================================================== --- linux-2.6.10.orig/include/linux/proc_mm.h 2005-04-07 19:34:21.197950744 +0800 +++ linux-2.6.10/include/linux/proc_mm.h 2005-04-07 22:05:29.503756936 +0800 @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __PROC_MM_H +#define __PROC_MM_H + +#include "linux/sched.h" + +#define MM_MMAP 54 +#define MM_MUNMAP 55 +#define MM_MPROTECT 56 +#define MM_COPY_SEGMENTS 57 + +struct mm_mmap { + unsigned long addr; + unsigned long len; + unsigned long prot; + unsigned long flags; + unsigned long fd; + unsigned long offset; +}; + +struct mm_munmap { + unsigned long addr; + unsigned long len; +}; + +struct mm_mprotect { + unsigned long addr; + unsigned long len; + unsigned int prot; +}; + +struct proc_mm_op { + int op; + union { + struct mm_mmap mmap; + struct mm_munmap munmap; + struct mm_mprotect mprotect; + int copy_segments; + } u; +}; + +extern struct mm_struct *proc_mm_get_mm(int fd); + +#endif Index: linux-2.6.10/include/asm-um/elf.h =================================================================== --- linux-2.6.10.orig/include/asm-um/elf.h 2004-12-25 05:35:01.000000000 +0800 +++ linux-2.6.10/include/asm-um/elf.h 2005-04-07 22:05:29.504756784 +0800 @@ -3,7 +3,8 @@ #include "asm/archparam.h" -#define ELF_HWCAP (0) +extern long elf_aux_hwcap; +#define ELF_HWCAP (elf_aux_hwcap) #define SET_PERSONALITY(ex, ibcs2) do ; while(0) Index: linux-2.6.10/include/asm-um/archparam-i386.h =================================================================== --- linux-2.6.10.orig/include/asm-um/archparam-i386.h 2004-12-25 05:35:24.000000000 +0800 +++ linux-2.6.10/include/asm-um/archparam-i386.h 2005-04-07 22:05:29.504756784 +0800 @@ -10,7 +10,8 @@ #include "user.h" -#define ELF_PLATFORM "i586" +extern char * elf_aux_platform; +#define ELF_PLATFORM (elf_aux_platform) #define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) @@ -56,15 +57,13 @@ pr_reg[16] = PT_REGS_SS(regs); \ } while(0); -#if 0 /* Turn this back on when UML has VSYSCALL working */ -#define VSYSCALL_BASE (__fix_to_virt(FIX_VSYSCALL)) -#else -#define VSYSCALL_BASE 0 -#endif -#define VSYSCALL_EHDR ((const struct elfhdr *) VSYSCALL_BASE) -#define VSYSCALL_ENTRY ((unsigned long) &__kernel_vsyscall) -extern void *__kernel_vsyscall; +extern unsigned long vsyscall_ehdr; +extern unsigned long vsyscall_end; +extern unsigned long __kernel_vsyscall; + +#define VSYSCALL_BASE vsyscall_ehdr +#define VSYSCALL_END vsyscall_end /* * Architecture-neutral AT_ values in 0-17, leave some room @@ -75,8 +74,10 @@ #define ARCH_DLINFO \ do { \ - NEW_AUX_ENT(AT_SYSINFO, VSYSCALL_ENTRY); \ - NEW_AUX_ENT(AT_SYSINFO_EHDR, VSYSCALL_BASE); \ + if ( vsyscall_ehdr ) { \ + NEW_AUX_ENT(AT_SYSINFO, __kernel_vsyscall); \ + NEW_AUX_ENT(AT_SYSINFO_EHDR, vsyscall_ehdr); \ + } \ } while (0) /* @@ -87,22 +88,18 @@ * Dumping its extra ELF program headers includes all the other information * a debugger needs to easily find how the vsyscall DSO was being used. */ -#if 0 -#define ELF_CORE_EXTRA_PHDRS (VSYSCALL_EHDR->e_phnum) -#endif - -#undef ELF_CORE_EXTRA_PHDRS +#define ELF_CORE_EXTRA_PHDRS \ + (vsyscall_ehdr ? (((struct elfhdr *)vsyscall_ehdr)->e_phnum) : 0 ) -#if 0 #define ELF_CORE_WRITE_EXTRA_PHDRS \ -do { \ - const struct elf_phdr *const vsyscall_phdrs = \ - (const struct elf_phdr *) (VSYSCALL_BASE \ - + VSYSCALL_EHDR->e_phoff); \ +if ( vsyscall_ehdr ) { \ + const struct elfhdr *const ehdrp = (struct elfhdr *)vsyscall_ehdr; \ + const struct elf_phdr *const phdrp = \ + (const struct elf_phdr *) (vsyscall_ehdr + ehdrp->e_phoff); \ int i; \ Elf32_Off ofs = 0; \ - for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) { \ - struct elf_phdr phdr = vsyscall_phdrs[i]; \ + for (i = 0; i < ehdrp->e_phnum; ++i) { \ + struct elf_phdr phdr = phdrp[i]; \ if (phdr.p_type == PT_LOAD) { \ ofs = phdr.p_offset = offset; \ offset += phdr.p_filesz; \ @@ -112,23 +109,19 @@ phdr.p_paddr = 0; /* match other core phdrs */ \ DUMP_WRITE(&phdr, sizeof(phdr)); \ } \ -} while (0) +} #define ELF_CORE_WRITE_EXTRA_DATA \ -do { \ - const struct elf_phdr *const vsyscall_phdrs = \ - (const struct elf_phdr *) (VSYSCALL_BASE \ - + VSYSCALL_EHDR->e_phoff); \ +if ( vsyscall_ehdr ) { \ + const struct elfhdr *const ehdrp = (struct elfhdr *)vsyscall_ehdr; \ + const struct elf_phdr *const phdrp = \ + (const struct elf_phdr *) (vsyscall_ehdr + ehdrp->e_phoff); \ int i; \ - for (i = 0; i < VSYSCALL_EHDR->e_phnum; ++i) { \ - if (vsyscall_phdrs[i].p_type == PT_LOAD) \ - DUMP_WRITE((void *) vsyscall_phdrs[i].p_vaddr, \ - vsyscall_phdrs[i].p_filesz); \ + for (i = 0; i < ehdrp->e_phnum; ++i) { \ + if (phdrp[i].p_type == PT_LOAD) \ + DUMP_WRITE((void *) phdrp[i].p_vaddr, \ + phdrp[i].p_filesz); \ } \ -} while (0) -#endif - -#undef ELF_CORE_WRITE_EXTRA_PHDRS -#undef ELF_CORE_WRITE_EXTRA_DATA +} #define R_386_NONE 0 #define R_386_32 1 Index: linux-2.6.10/include/asm-um/fixmap.h =================================================================== --- linux-2.6.10.orig/include/asm-um/fixmap.h 2004-12-25 05:35:28.000000000 +0800 +++ linux-2.6.10/include/asm-um/fixmap.h 2005-04-07 22:05:29.504756784 +0800 @@ -3,6 +3,7 @@ #include #include +#include /* * Here we define all the compile-time 'special' virtual @@ -34,7 +35,6 @@ FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, #endif - FIX_VSYSCALL, __end_of_fixed_addresses }; @@ -68,8 +68,8 @@ * This is the range that is readable by user mode, and things * acting like user mode such as get_user_pages. */ -#define FIXADDR_USER_START (__fix_to_virt(FIX_VSYSCALL)) -#define FIXADDR_USER_END (FIXADDR_USER_START + PAGE_SIZE) +#define FIXADDR_USER_START VSYSCALL_BASE +#define FIXADDR_USER_END VSYSCALL_END extern void __this_fixmap_does_not_exist(void); Index: linux-2.6.10/include/asm-i386/thread_info.h =================================================================== --- linux-2.6.10.orig/include/asm-i386/thread_info.h 2004-12-25 05:34:00.000000000 +0800 +++ linux-2.6.10/include/asm-i386/thread_info.h 2005-04-07 22:05:29.505756632 +0800 @@ -139,6 +139,7 @@ #define TIF_NEED_RESCHED 3 /* rescheduling necessary */ #define TIF_SINGLESTEP 4 /* restore singlestep on return to user mode */ #define TIF_IRET 5 /* return with iret */ +#define TIF_SYSCALL_EMU 6 /* syscall emulation active */ #define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */ #define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */ @@ -148,12 +149,14 @@ #define _TIF_NEED_RESCHED (1< #include #include +#include /* - * Used for LDT copy/destruction. + * Used for LDT initialization/destruction. You cannot copy an LDT with + * init_new_context, since it thinks you are passing it a new LDT and won't + * deallocate its old content. */ int init_new_context(struct task_struct *tsk, struct mm_struct *mm); void destroy_context(struct mm_struct *mm); +/* LDT initialization for a clean environment - needed for SKAS.*/ +static inline void init_new_empty_context(struct mm_struct *mm) +{ + init_MUTEX(&mm->context.sem); + mm->context.size = 0; +} + +/* LDT copy for SKAS - for the above problem.*/ +int copy_context(struct mm_struct *mm, struct mm_struct *old_mm); static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { @@ -29,6 +41,10 @@ { int cpu = smp_processor_id(); +#ifdef CONFIG_SMP + prev = per_cpu(cpu_tlbstate, cpu).active_mm; +#endif + if (likely(prev != next)) { /* stop flush ipis for the previous mm */ cpu_clear(cpu, prev->cpu_vm_mask); @@ -50,7 +66,6 @@ #ifdef CONFIG_SMP else { per_cpu(cpu_tlbstate, cpu).state = TLBSTATE_OK; - BUG_ON(per_cpu(cpu_tlbstate, cpu).active_mm != next); if (!cpu_test_and_set(cpu, next->cpu_vm_mask)) { /* We were in lazy tlb mode and leave_mm disabled Index: linux-2.6.10/include/asm-i386/desc.h =================================================================== --- linux-2.6.10.orig/include/asm-i386/desc.h 2004-12-25 05:33:48.000000000 +0800 +++ linux-2.6.10/include/asm-i386/desc.h 2005-04-07 22:05:29.505756632 +0800 @@ -126,6 +126,9 @@ put_cpu(); } +extern int __modify_ldt(struct mm_struct * mm, int func, void __user *ptr, + unsigned long bytecount); + #endif /* !__ASSEMBLY__ */ #endif