Merge branch 'sched-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / arch / um / sys-i386 / ldt.c
index a939a7e..a4846a8 100644 (file)
 /*
- * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
-#include "linux/sched.h"
-#include "linux/slab.h"
-#include "linux/types.h"
-#include "linux/errno.h"
-#include "linux/spinlock.h"
-#include "asm/uaccess.h"
-#include "asm/smp.h"
-#include "asm/ldt.h"
-#include "asm/unistd.h"
-#include "choose-mode.h"
-#include "kern.h"
-#include "mode_kern.h"
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <asm/unistd.h>
 #include "os.h"
-
-extern int modify_ldt(int func, void *ptr, unsigned long bytecount);
-
-#ifdef CONFIG_MODE_TT
-
-static long do_modify_ldt_tt(int func, void __user *ptr,
-                             unsigned long bytecount)
-{
-       struct user_desc info;
-       int res = 0;
-       void *buf = NULL;
-       void *p = NULL; /* What we pass to host. */
-
-       switch(func){
-       case 1:
-       case 0x11: /* write_ldt */
-               /* Do this check now to avoid overflows. */
-               if (bytecount != sizeof(struct user_desc)) {
-                       res = -EINVAL;
-                       goto out;
-               }
-
-               if(copy_from_user(&info, ptr, sizeof(info))) {
-                       res = -EFAULT;
-                       goto out;
-               }
-
-               p = &info;
-               break;
-       case 0:
-       case 2: /* read_ldt */
-
-               /* The use of info avoids kmalloc on the write case, not on the
-                * read one. */
-               buf = kmalloc(bytecount, GFP_KERNEL);
-               if (!buf) {
-                       res = -ENOMEM;
-                       goto out;
-               }
-               p = buf;
-               break;
-       default:
-               res = -ENOSYS;
-               goto out;
-       }
-
-       res = modify_ldt(func, p, bytecount);
-       if(res < 0)
-               goto out;
-
-       switch(func){
-       case 0:
-       case 2:
-               /* Modify_ldt was for reading and returned the number of read
-                * bytes.*/
-               if(copy_to_user(ptr, p, res))
-                       res = -EFAULT;
-               break;
-       }
-
-out:
-       kfree(buf);
-       return res;
-}
-
-#endif
-
-#ifdef CONFIG_MODE_SKAS
-
+#include "proc_mm.h"
 #include "skas.h"
 #include "skas_ptrace.h"
-#include "asm/mmu_context.h"
-#include "proc_mm.h"
+#include "sysdep/tls.h"
+
+extern int modify_ldt(int func, void *ptr, unsigned long bytecount);
 
-long write_ldt_entry(struct mm_id * mm_idp, int func, struct user_desc * desc,
-                    void **addr, int done)
+static long write_ldt_entry(struct mm_id *mm_idp, int func,
+                    struct user_desc *desc, void **addr, int done)
 {
        long res;
 
-       if(proc_mm){
-               /* This is a special handling for the case, that the mm to
+       if (proc_mm) {
+               /*
+                * This is a special handling for the case, that the mm to
                 * modify isn't current->active_mm.
                 * If this is called directly by modify_ldt,
                 *     (current->active_mm->context.skas.u == mm_idp)
-                * will be true. So no call to switch_mm_skas(mm_idp) is done.
+                * will be true. So no call to __switch_mm(mm_idp) is done.
                 * If this is called in case of init_new_ldt or PTRACE_LDT,
                 * mm_idp won't belong to current->active_mm, but child->mm.
                 * So we need to switch child's mm into our userspace, then
@@ -108,12 +33,12 @@ long write_ldt_entry(struct mm_id * mm_idp, int func, struct user_desc * desc,
                 *
                 * Note: I'm unsure: should interrupts be disabled here?
                 */
-               if(!current->active_mm || current->active_mm == &init_mm ||
-                  mm_idp != &current->active_mm->context.skas.id)
-                       switch_mm_skas(mm_idp);
+               if (!current->active_mm || current->active_mm == &init_mm ||
+                   mm_idp != &current->active_mm->context.id)
+                       __switch_mm(mm_idp);
        }
 
-       if(ptrace_ldt) {
+       if (ptrace_ldt) {
                struct ptrace_ldt ldt_op = (struct ptrace_ldt) {
                        .func = func,
                        .ptr = desc,
@@ -121,7 +46,7 @@ long write_ldt_entry(struct mm_id * mm_idp, int func, struct user_desc * desc,
                u32 cpu;
                int pid;
 
-               if(!proc_mm)
+               if (!proc_mm)
                        pid = mm_idp->u.pid;
                else {
                        cpu = get_cpu();
@@ -130,7 +55,7 @@ long write_ldt_entry(struct mm_id * mm_idp, int func, struct user_desc * desc,
 
                res = os_ptrace_ldt(pid, 0, (unsigned long) &ldt_op);
 
-               if(proc_mm)
+               if (proc_mm)
                        put_cpu();
        }
        else {
@@ -139,7 +64,7 @@ long write_ldt_entry(struct mm_id * mm_idp, int func, struct user_desc * desc,
                                        (sizeof(*desc) + sizeof(long) - 1) &
                                            ~(sizeof(long) - 1),
                                        addr, &stub_addr);
-               if(!res){
+               if (!res) {
                        unsigned long args[] = { func,
                                                 (unsigned long)stub_addr,
                                                 sizeof(*desc),
@@ -149,13 +74,14 @@ long write_ldt_entry(struct mm_id * mm_idp, int func, struct user_desc * desc,
                }
        }
 
-       if(proc_mm){
-               /* This is the second part of special handling, that makes
+       if (proc_mm) {
+               /*
+                * This is the second part of special handling, that makes
                 * PTRACE_LDT possible to implement.
                 */
-               if(current->active_mm && current->active_mm != &init_mm &&
-                  mm_idp != &current->active_mm->context.skas.id)
-                       switch_mm_skas(&current->active_mm->context.skas.id);
+               if (current->active_mm && current->active_mm != &init_mm &&
+                   mm_idp != &current->active_mm->context.id)
+                       __switch_mm(&current->active_mm->context.id);
        }
 
        return res;
@@ -170,21 +96,22 @@ static long read_ldt_from_host(void __user * ptr, unsigned long bytecount)
                        .ptr = kmalloc(bytecount, GFP_KERNEL)};
        u32 cpu;
 
-       if(ptrace_ldt.ptr == NULL)
+       if (ptrace_ldt.ptr == NULL)
                return -ENOMEM;
 
-       /* This is called from sys_modify_ldt only, so userspace_pid gives
+       /*
+        * This is called from sys_modify_ldt only, so userspace_pid gives
         * us the right number
         */
 
        cpu = get_cpu();
        res = os_ptrace_ldt(userspace_pid[cpu], 0, (unsigned long) &ptrace_ldt);
        put_cpu();
-       if(res < 0)
+       if (res < 0)
                goto out;
 
        n = copy_to_user(ptr, ptrace_ldt.ptr, res);
-       if(n != 0)
+       if (n != 0)
                res = -EFAULT;
 
   out:
@@ -209,35 +136,34 @@ static int read_ldt(void __user * ptr, unsigned long bytecount)
 {
        int i, err = 0;
        unsigned long size;
-       uml_ldt_t * ldt = &current->mm->context.skas.ldt;
+       uml_ldt_t * ldt = &current->mm->context.ldt;
 
-       if(!ldt->entry_count)
+       if (!ldt->entry_count)
                goto out;
-       if(bytecount > LDT_ENTRY_SIZE*LDT_ENTRIES)
+       if (bytecount > LDT_ENTRY_SIZE*LDT_ENTRIES)
                bytecount = LDT_ENTRY_SIZE*LDT_ENTRIES;
        err = bytecount;
 
-       if(ptrace_ldt){
+       if (ptrace_ldt)
                return read_ldt_from_host(ptr, bytecount);
-       }
 
-       down(&ldt->semaphore);
-       if(ldt->entry_count <= LDT_DIRECT_ENTRIES){
+       mutex_lock(&ldt->lock);
+       if (ldt->entry_count <= LDT_DIRECT_ENTRIES) {
                size = LDT_ENTRY_SIZE*LDT_DIRECT_ENTRIES;
-               if(size > bytecount)
+               if (size > bytecount)
                        size = bytecount;
-               if(copy_to_user(ptr, ldt->u.entries, size))
+               if (copy_to_user(ptr, ldt->u.entries, size))
                        err = -EFAULT;
                bytecount -= size;
                ptr += size;
        }
        else {
-               for(i=0; i<ldt->entry_count/LDT_ENTRIES_PER_PAGE && bytecount;
-                        i++){
+               for (i=0; i<ldt->entry_count/LDT_ENTRIES_PER_PAGE && bytecount;
+                    i++) {
                        size = PAGE_SIZE;
-                       if(size > bytecount)
+                       if (size > bytecount)
                                size = bytecount;
-                       if(copy_to_user(ptr, ldt->u.pages[i], size)){
+                       if (copy_to_user(ptr, ldt->u.pages[i], size)) {
                                err = -EFAULT;
                                break;
                        }
@@ -245,12 +171,12 @@ static int read_ldt(void __user * ptr, unsigned long bytecount)
                        ptr += size;
                }
        }
-       up(&ldt->semaphore);
+       mutex_unlock(&ldt->lock);
 
-       if(bytecount == 0 || err == -EFAULT)
+       if (bytecount == 0 || err == -EFAULT)
                goto out;
 
-       if(clear_user(ptr, bytecount))
+       if (clear_user(ptr, bytecount))
                err = -EFAULT;
 
 out:
@@ -261,15 +187,16 @@ static int read_default_ldt(void __user * ptr, unsigned long bytecount)
 {
        int err;
 
-       if(bytecount > 5*LDT_ENTRY_SIZE)
+       if (bytecount > 5*LDT_ENTRY_SIZE)
                bytecount = 5*LDT_ENTRY_SIZE;
 
        err = bytecount;
-       /* UML doesn't support lcall7 and lcall27.
+       /*
+        * UML doesn't support lcall7 and lcall27.
         * So, we don't really have a default ldt, but emulate
         * an empty ldt of common host default ldt size.
         */
-       if(clear_user(ptr, bytecount))
+       if (clear_user(ptr, bytecount))
                err = -EFAULT;
 
        return err;
@@ -277,60 +204,60 @@ static int read_default_ldt(void __user * ptr, unsigned long bytecount)
 
 static int write_ldt(void __user * ptr, unsigned long bytecount, int func)
 {
-       uml_ldt_t * ldt = &current->mm->context.skas.ldt;
-       struct mm_id * mm_idp = &current->mm->context.skas.id;
+       uml_ldt_t * ldt = &current->mm->context.ldt;
+       struct mm_id * mm_idp = &current->mm->context.id;
        int i, err;
        struct user_desc ldt_info;
        struct ldt_entry entry0, *ldt_p;
        void *addr = NULL;
 
        err = -EINVAL;
-       if(bytecount != sizeof(ldt_info))
+       if (bytecount != sizeof(ldt_info))
                goto out;
        err = -EFAULT;
-       if(copy_from_user(&ldt_info, ptr, sizeof(ldt_info)))
+       if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info)))
                goto out;
 
        err = -EINVAL;
-       if(ldt_info.entry_number >= LDT_ENTRIES)
+       if (ldt_info.entry_number >= LDT_ENTRIES)
                goto out;
-       if(ldt_info.contents == 3){
+       if (ldt_info.contents == 3) {
                if (func == 1)
                        goto out;
                if (ldt_info.seg_not_present == 0)
                        goto out;
        }
 
-        if(!ptrace_ldt)
-                down(&ldt->semaphore);
+       if (!ptrace_ldt)
+               mutex_lock(&ldt->lock);
 
        err = write_ldt_entry(mm_idp, func, &ldt_info, &addr, 1);
-       if(err)
+       if (err)
                goto out_unlock;
-        else if(ptrace_ldt) {
-       /* With PTRACE_LDT available, this is used as a flag only */
-                ldt->entry_count = 1;
-                goto out;
-        }
-
-       if(ldt_info.entry_number >= ldt->entry_count &&
-          ldt_info.entry_number >= LDT_DIRECT_ENTRIES){
-               for(i=ldt->entry_count/LDT_ENTRIES_PER_PAGE;
-                   i*LDT_ENTRIES_PER_PAGE <= ldt_info.entry_number;
-                   i++){
-                       if(i == 0)
+       else if (ptrace_ldt) {
+               /* With PTRACE_LDT available, this is used as a flag only */
+               ldt->entry_count = 1;
+               goto out;
+       }
+
+       if (ldt_info.entry_number >= ldt->entry_count &&
+           ldt_info.entry_number >= LDT_DIRECT_ENTRIES) {
+               for (i=ldt->entry_count/LDT_ENTRIES_PER_PAGE;
+                    i*LDT_ENTRIES_PER_PAGE <= ldt_info.entry_number;
+                    i++) {
+                       if (i == 0)
                                memcpy(&entry0, ldt->u.entries,
                                       sizeof(entry0));
                        ldt->u.pages[i] = (struct ldt_entry *)
                                __get_free_page(GFP_KERNEL|__GFP_ZERO);
-                       if(!ldt->u.pages[i]){
+                       if (!ldt->u.pages[i]) {
                                err = -ENOMEM;
                                /* Undo the change in host */
                                memset(&ldt_info, 0, sizeof(ldt_info));
                                write_ldt_entry(mm_idp, 1, &ldt_info, &addr, 1);
                                goto out_unlock;
                        }
-                       if(i == 0) {
+                       if (i == 0) {
                                memcpy(ldt->u.pages[0], &entry0,
                                       sizeof(entry0));
                                memcpy(ldt->u.pages[0]+1, ldt->u.entries+1,
@@ -339,17 +266,17 @@ static int write_ldt(void __user * ptr, unsigned long bytecount, int func)
                        ldt->entry_count = (i + 1) * LDT_ENTRIES_PER_PAGE;
                }
        }
-       if(ldt->entry_count <= ldt_info.entry_number)
+       if (ldt->entry_count <= ldt_info.entry_number)
                ldt->entry_count = ldt_info.entry_number + 1;
 
-       if(ldt->entry_count <= LDT_DIRECT_ENTRIES)
+       if (ldt->entry_count <= LDT_DIRECT_ENTRIES)
                ldt_p = ldt->u.entries + ldt_info.entry_number;
        else
                ldt_p = ldt->u.pages[ldt_info.entry_number/LDT_ENTRIES_PER_PAGE] +
                        ldt_info.entry_number%LDT_ENTRIES_PER_PAGE;
 
-       if(ldt_info.base_addr == 0 && ldt_info.limit == 0 &&
-          (func == 1 || LDT_empty(&ldt_info))){
+       if (ldt_info.base_addr == 0 && ldt_info.limit == 0 &&
+          (func == 1 || LDT_empty(&ldt_info))) {
                ldt_p->a = 0;
                ldt_p->b = 0;
        }
@@ -362,7 +289,7 @@ static int write_ldt(void __user * ptr, unsigned long bytecount, int func)
        err = 0;
 
 out_unlock:
-       up(&ldt->semaphore);
+       mutex_unlock(&ldt->lock);
 out:
        return err;
 }
@@ -400,7 +327,7 @@ static void ldt_get_host_info(void)
 
        spin_lock(&host_ldt_lock);
 
-       if(host_ldt_entries != NULL){
+       if (host_ldt_entries != NULL) {
                spin_unlock(&host_ldt_lock);
                return;
        }
@@ -408,49 +335,49 @@ static void ldt_get_host_info(void)
 
        spin_unlock(&host_ldt_lock);
 
-       for(i = LDT_PAGES_MAX-1, order=0; i; i>>=1, order++);
+       for (i = LDT_PAGES_MAX-1, order=0; i; i>>=1, order++)
+               ;
 
        ldt = (struct ldt_entry *)
              __get_free_pages(GFP_KERNEL|__GFP_ZERO, order);
-       if(ldt == NULL) {
-               printk("ldt_get_host_info: couldn't allocate buffer for host "
-                      "ldt\n");
+       if (ldt == NULL) {
+               printk(KERN_ERR "ldt_get_host_info: couldn't allocate buffer "
+                      "for host ldt\n");
                return;
        }
 
        ret = modify_ldt(0, ldt, (1<<order)*PAGE_SIZE);
-       if(ret < 0) {
-               printk("ldt_get_host_info: couldn't read host ldt\n");
+       if (ret < 0) {
+               printk(KERN_ERR "ldt_get_host_info: couldn't read host ldt\n");
                goto out_free;
        }
-       if(ret == 0) {
+       if (ret == 0) {
                /* default_ldt is active, simply write an empty entry 0 */
                host_ldt_entries = dummy_list;
                goto out_free;
        }
 
-       for(i=0, size=0; i<ret/LDT_ENTRY_SIZE; i++){
-               if(ldt[i].a != 0 || ldt[i].b != 0)
+       for (i=0, size=0; i<ret/LDT_ENTRY_SIZE; i++) {
+               if (ldt[i].a != 0 || ldt[i].b != 0)
                        size++;
        }
 
-       if(size < ARRAY_SIZE(dummy_list))
+       if (size < ARRAY_SIZE(dummy_list))
                host_ldt_entries = dummy_list;
        else {
                size = (size + 1) * sizeof(dummy_list[0]);
                tmp = kmalloc(size, GFP_KERNEL);
-               if(tmp == NULL) {
-                       printk("ldt_get_host_info: couldn't allocate host ldt "
-                              "list\n");
+               if (tmp == NULL) {
+                       printk(KERN_ERR "ldt_get_host_info: couldn't allocate "
+                              "host ldt list\n");
                        goto out_free;
                }
                host_ldt_entries = tmp;
        }
 
-       for(i=0, k=0; i<ret/LDT_ENTRY_SIZE; i++){
-               if(ldt[i].a != 0 || ldt[i].b != 0) {
+       for (i=0, k=0; i<ret/LDT_ENTRY_SIZE; i++) {
+               if (ldt[i].a != 0 || ldt[i].b != 0)
                        host_ldt_entries[k++] = i;
-               }
        }
        host_ldt_entries[k] = -1;
 
@@ -458,8 +385,7 @@ out_free:
        free_pages((unsigned long)ldt, order);
 }
 
-long init_new_ldt(struct mmu_context_skas * new_mm,
-                 struct mmu_context_skas * from_mm)
+long init_new_ldt(struct mm_context *new_mm, struct mm_context *from_mm)
 {
        struct user_desc desc;
        short * num_p;
@@ -469,15 +395,15 @@ long init_new_ldt(struct mmu_context_skas * new_mm,
        struct proc_mm_op copy;
 
 
-       if(!ptrace_ldt)
-               init_MUTEX(&new_mm->ldt.semaphore);
+       if (!ptrace_ldt)
+               mutex_init(&new_mm->ldt.lock);
 
-       if(!from_mm){
+       if (!from_mm) {
                memset(&desc, 0, sizeof(desc));
                /*
                 * We have to initialize a clean ldt.
                 */
-               if(proc_mm) {
+               if (proc_mm) {
                        /*
                         * If the new mm was created using proc_mm, host's
                         * default-ldt currently is assigned, which normally
@@ -485,8 +411,7 @@ long init_new_ldt(struct mmu_context_skas * new_mm,
                         * To remove these gates, we simply write an empty
                         * entry as number 0 to the host.
                         */
-                       err = write_ldt_entry(&new_mm->id, 1, &desc,
-                                             &addr, 1);
+                       err = write_ldt_entry(&new_mm->id, 1, &desc, &addr, 1);
                }
                else{
                        /*
@@ -495,11 +420,11 @@ long init_new_ldt(struct mmu_context_skas * new_mm,
                         * will be reset in the following loop
                         */
                        ldt_get_host_info();
-                       for(num_p=host_ldt_entries; *num_p != -1; num_p++){
+                       for (num_p=host_ldt_entries; *num_p != -1; num_p++) {
                                desc.entry_number = *num_p;
                                err = write_ldt_entry(&new_mm->id, 1, &desc,
                                                      &addr, *(num_p + 1) == -1);
-                               if(err)
+                               if (err)
                                        break;
                        }
                }
@@ -508,8 +433,9 @@ long init_new_ldt(struct mmu_context_skas * new_mm,
                goto out;
        }
 
-       if(proc_mm){
-               /* We have a valid from_mm, so we now have to copy the LDT of
+       if (proc_mm) {
+               /*
+                * We have a valid from_mm, so we now have to copy the LDT of
                 * from_mm to new_mm, because using proc_mm an new mm with
                 * an empty/default LDT was created in new_mm()
                 */
@@ -518,27 +444,27 @@ long init_new_ldt(struct mmu_context_skas * new_mm,
                                              { .copy_segments =
                                                        from_mm->id.u.mm_fd } } );
                i = os_write_file(new_mm->id.u.mm_fd, &copy, sizeof(copy));
-               if(i != sizeof(copy))
-                       printk("new_mm : /proc/mm copy_segments failed, "
-                              "err = %d\n", -i);
+               if (i != sizeof(copy))
+                       printk(KERN_ERR "new_mm : /proc/mm copy_segments "
+                              "failed, err = %d\n", -i);
        }
 
-       if(!ptrace_ldt) {
-               /* Our local LDT is used to supply the data for
+       if (!ptrace_ldt) {
+               /*
+                * Our local LDT is used to supply the data for
                 * modify_ldt(READLDT), if PTRACE_LDT isn't available,
                 * i.e., we have to use the stub for modify_ldt, which
                 * can't handle the big read buffer of up to 64kB.
                 */
-               down(&from_mm->ldt.semaphore);
-               if(from_mm->ldt.entry_count <= LDT_DIRECT_ENTRIES){
+               mutex_lock(&from_mm->ldt.lock);
+               if (from_mm->ldt.entry_count <= LDT_DIRECT_ENTRIES)
                        memcpy(new_mm->ldt.u.entries, from_mm->ldt.u.entries,
                               sizeof(new_mm->ldt.u.entries));
-               }
-               else{
+               else {
                        i = from_mm->ldt.entry_count / LDT_ENTRIES_PER_PAGE;
-                       while(i-->0){
+                       while (i-->0) {
                                page = __get_free_page(GFP_KERNEL|__GFP_ZERO);
-                               if (!page){
+                               if (!page) {
                                        err = -ENOMEM;
                                        break;
                                }
@@ -549,7 +475,7 @@ long init_new_ldt(struct mmu_context_skas * new_mm,
                        }
                }
                new_mm->ldt.entry_count = from_mm->ldt.entry_count;
-               up(&from_mm->ldt.semaphore);
+               mutex_unlock(&from_mm->ldt.lock);
        }
 
     out:
@@ -557,22 +483,19 @@ long init_new_ldt(struct mmu_context_skas * new_mm,
 }
 
 
-void free_ldt(struct mmu_context_skas * mm)
+void free_ldt(struct mm_context *mm)
 {
        int i;
 
-       if(!ptrace_ldt && mm->ldt.entry_count > LDT_DIRECT_ENTRIES){
+       if (!ptrace_ldt && mm->ldt.entry_count > LDT_DIRECT_ENTRIES) {
                i = mm->ldt.entry_count / LDT_ENTRIES_PER_PAGE;
-               while(i-- > 0){
-                       free_page((long )mm->ldt.u.pages[i]);
-               }
+               while (i-- > 0)
+                       free_page((long) mm->ldt.u.pages[i]);
        }
        mm->ldt.entry_count = 0;
 }
-#endif
 
 int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
 {
-       return CHOOSE_MODE_PROC(do_modify_ldt_tt, do_modify_ldt_skas, func,
-                               ptr, bytecount);
+       return do_modify_ldt_skas(func, ptr, bytecount);
 }