vserver 1.9.3
[linux-2.6.git] / arch / um / kernel / trap_kern.c
index 7925dc4..cba33ef 100644 (file)
 #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)
@@ -51,12 +54,10 @@ 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:
        do {
+ survive:
                switch (handle_mm_fault(mm, vma, address, is_write)){
                case VM_FAULT_MINOR:
                        current->min_flt++;
@@ -75,10 +76,10 @@ int handle_page_fault(unsigned long address, unsigned long ip,
                }
                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 +95,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 +136,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 +149,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 +183,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,6 +206,11 @@ 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)
 {
 }