vserver 1.9.5.x5
[linux-2.6.git] / arch / um / kernel / trap_kern.c
index 7925dc4..47e766e 100644 (file)
 #include "linux/ptrace.h"
 #include "asm/semaphore.h"
 #include "asm/pgtable.h"
+#include "asm/pgalloc.h"
 #include "asm/tlbflush.h"
 #include "asm/a.out.h"
 #include "asm/current.h"
+#include "asm/irq.h"
 #include "user_util.h"
 #include "kern_util.h"
 #include "kern.h"
 #include "chan_kern.h"
 #include "mconsole_kern.h"
 #include "2_5compat.h"
+#include "mem.h"
+#include "mem_kern.h"
 
 int handle_page_fault(unsigned long address, unsigned long ip, 
                      int is_write, int is_user, int *code_out)
@@ -29,6 +33,7 @@ int handle_page_fault(unsigned long address, unsigned long ip,
        struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma;
        pgd_t *pgd;
+       pud_t *pud;
        pmd_t *pmd;
        pte_t *pte;
        unsigned long page;
@@ -43,6 +48,8 @@ int handle_page_fault(unsigned long address, unsigned long ip,
                goto good_area;
        else if(!(vma->vm_flags & VM_GROWSDOWN)) 
                goto out;
+       else if(!ARCH_IS_STACKGROW(address))
+               goto out;
        else if(expand_stack(vma, address)) 
                goto out;
 
@@ -51,12 +58,11 @@ int handle_page_fault(unsigned long address, unsigned long ip,
        if(is_write && !(vma->vm_flags & VM_WRITE)) 
                goto out;
        page = address & PAGE_MASK;
-       if(page == (unsigned long) current->thread_info + PAGE_SIZE)
-               panic("Kernel stack overflow");
        pgd = pgd_offset(mm, page);
-       pmd = pmd_offset(pgd, page);
- survive:
+       pud = pud_offset(pgd, page);
+       pmd = pmd_offset(pud, page);
        do {
+ survive:
                switch (handle_mm_fault(mm, vma, address, is_write)){
                case VM_FAULT_MINOR:
                        current->min_flt++;
@@ -73,12 +79,15 @@ int handle_page_fault(unsigned long address, unsigned long ip,
                default:
                        BUG();
                }
+               pgd = pgd_offset(mm, page);
+               pud = pud_offset(pgd, page);
+               pmd = pmd_offset(pud, page);
                pte = pte_offset_kernel(pmd, page);
        } while(!pte_present(*pte));
+       err = 0;
        *pte = pte_mkyoung(*pte);
        if(pte_write(*pte)) *pte = pte_mkdirty(*pte);
        flush_tlb_page(vma, page);
-       err = 0;
  out:
        up_read(&mm->mmap_sem);
        return(err);
@@ -94,10 +103,36 @@ out_of_memory:
                down_read(&mm->mmap_sem);
                goto survive;
        }
-       err = -ENOMEM;
        goto out;
 }
 
+LIST_HEAD(physmem_remappers);
+
+void register_remapper(struct remapper *info)
+{
+       list_add(&info->list, &physmem_remappers);
+}
+
+static int check_remapped_addr(unsigned long address, int is_write)
+{
+       struct remapper *remapper;
+       struct list_head *ele;
+       __u64 offset;
+       int fd;
+
+       fd = phys_mapping(__pa(address), &offset);
+       if(fd == -1)
+               return(0);
+
+       list_for_each(ele, &physmem_remappers){
+               remapper = list_entry(ele, struct remapper, list);
+               if((*remapper->proc)(fd, address, is_write, offset))
+                       return(1);
+       }
+
+       return(0);
+}
+
 unsigned long segv(unsigned long address, unsigned long ip, int is_write, 
                   int is_user, void *sc)
 {
@@ -109,7 +144,9 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write,
                 flush_tlb_kernel_vm();
                 return(0);
         }
-        if(current->mm == NULL)
+       else if(check_remapped_addr(address & PAGE_MASK, is_write))
+               return(0);
+       else if(current->mm == NULL)
                panic("Segfault with no mm");
        err = handle_page_fault(address, ip, is_write, is_user, &si.si_code);
 
@@ -120,9 +157,8 @@ unsigned long segv(unsigned long address, unsigned long ip, int is_write,
                current->thread.fault_addr = (void *) address;
                do_longjmp(catcher, 1);
        } 
-       else if(current->thread.fault_addr != NULL){
+       else if(current->thread.fault_addr != NULL)
                panic("fault_addr set but no fault catcher");
-       }
        else if(arch_fixup(ip, sc))
                return(0);
 
@@ -155,8 +191,6 @@ void bad_segv(unsigned long address, unsigned long ip, int is_write)
 {
        struct siginfo si;
 
-       printk(KERN_ERR "Unfixable SEGV in '%s' (pid %d) at 0x%lx "
-              "(ip 0x%lx)\n", current->comm, current->pid, address, ip);
        si.si_signo = SIGSEGV;
        si.si_code = SEGV_ACCERR;
        si.si_addr = (void *) address;
@@ -180,11 +214,16 @@ void bus_handler(int sig, union uml_pt_regs *regs)
        else relay_signal(sig, regs);
 }
 
+void winch(int sig, union uml_pt_regs *regs)
+{
+       do_IRQ(WINCH_IRQ, regs);
+}
+
 void trap_init(void)
 {
 }
 
-spinlock_t trap_lock = SPIN_LOCK_UNLOCKED;
+DEFINE_SPINLOCK(trap_lock);
 
 static int trap_index = 0;