Merge remote branch 'origin/sparc-dev'
[akaros.git] / kern / src / pmap.c
index 871774e..cc12b7c 100644 (file)
 #pragma nosharc
 #endif
 
+#ifdef __DEPUTY__
+#pragma nodeputy
+#endif
+
 #include <arch/arch.h>
 #include <arch/mmu.h>
 
 /**
  * @brief Global variable used to store erroneous virtual addresses as the
  *        result of a failed user_mem_check().
+ *
+ * zra: What if two checks fail at the same time? Maybe this should be per-cpu?
+ *
  */
-static void *DANGEROUS user_mem_check_addr;
+static void *DANGEROUS RACY user_mem_check_addr;
 
 volatile uint32_t vpt_lock = 0;
 volatile uint32_t vpd_lock = 0;
@@ -262,6 +269,11 @@ void tlb_invalidate(pde_t *pgdir, void *va)
  */
 void* user_mem_check(env_t *env, const void *DANGEROUS va, size_t len, int perm)
 {
+       if (len == 0) {
+               warn("Called user_mem_check with a len of 0. Don't do that. Returning NULL");
+               return NULL;
+       }
+       
        // TODO - will need to sort this out wrt page faulting / PTE_P
        // also could be issues with sleeping and waking up to find pages
        // are unmapped, though i think the lab ignores this since the 
@@ -277,7 +289,7 @@ void* user_mem_check(env_t *env, const void *DANGEROUS va, size_t len, int perm)
                warn("Blimey!  Wrap around in VM range calculation!");  
                return NULL;
        }
-       num_pages = PPN(end - start);
+       num_pages = LA2PPN(end - start);
        for (i = 0; i < num_pages; i++, start += PGSIZE) {
                page_perms = get_va_perms(env->env_pgdir, start);
                // ensures the bits we want on are turned on.  if not, error out
@@ -314,12 +326,13 @@ void* user_mem_check(env_t *env, const void *DANGEROUS va, size_t len, int perm)
  * @return LEN the length of the new buffer copied into 'dst'
  */
 size_t
-user_mem_strlcpy(env_t *env, char *dst, const char *DANGEROUS va,
+user_mem_strlcpy(env_t *env, char *_dst, const char *DANGEROUS va,
                  size_t _len, int perm)
 {
        const char *DANGEROUS src = va;
        size_t len = _len;
-       char *NT COUNT(_len-1) dst_in = dst;
+       char *NT COUNT(_len-1) dst_in = _dst;
+       char *NT BND(_dst,_dst + _len - 1) dst = _dst;
 
        if (len > 0) {
                while (1) {
@@ -361,10 +374,15 @@ user_mem_strlcpy(env_t *env, char *dst, const char *DANGEROUS va,
 void *
 user_mem_assert(env_t *env, const void *DANGEROUS va, size_t len, int perm)
 {
-    void *COUNT(len) res = user_mem_check(env,va,len,perm | PTE_USER_RO);
+       if (len == 0) {
+               warn("Called user_mem_assert with a len of 0. Don't do that. Returning NULL");
+               return NULL;
+       }
+       
+       void *COUNT(len) res = user_mem_check(env,va,len,perm | PTE_USER_RO);
        if (!res) {
                cprintf("[%08x] user_mem_check assertion failure for "
-                       "va %08x\n", env->env_id, user_mem_check_addr);
+                       "va %08x\n", env->pid, user_mem_check_addr);
                proc_destroy(env);      // may not return
         return NULL;
        }
@@ -401,21 +419,21 @@ error_t memcpy_from_user(env_t* env, void* COUNT(len) dest,
        if(start >= (void*SNT)ULIM || end >= (void*SNT)ULIM)
                return -EFAULT;
 
-       num_pages = PPN(end - start);
+       num_pages = LA2PPN(end - start);
        for(i = 0; i < num_pages; i++)
        {
                pte = pgdir_walk(env->env_pgdir, start+i*PGSIZE, 0);
                if(!pte || (*pte & perm) != perm)
                        return -EFAULT;
 
-               void*COUNT(PGSIZE) kpage = KADDR(PTE_ADDR(pte));
-               void* src_start = i > 0 ? kpage : kpage+(va-start);
+               void*COUNT(PGSIZE) kpage = KADDR(PTE_ADDR(*pte));
+               const void* src_start = i > 0 ? kpage : kpage+(va-start);
                void* dst_start = dest+bytes_copied;
                size_t copy_len = PGSIZE;
                if(i == 0)
                        copy_len -= va-start;
                if(i == num_pages-1)
-                       copy_len -= end-(start+len);
+                       copy_len -= end-(va+len);
 
                memcpy(dst_start,src_start,copy_len);
                bytes_copied += copy_len;
@@ -426,15 +444,57 @@ error_t memcpy_from_user(env_t* env, void* COUNT(len) dest,
        return ESUCCESS;
 }
 
-/* mmap2() semantics on the offset */
-void *mmap(struct proc *p, uintptr_t addr, size_t len, int prot, int flags, int fd,
-           size_t offset)
+/**
+ * @brief Copies data to a user buffer from a kernel buffer.
+ * 
+ * @param env  the environment associated with the user program
+ *             to which the buffer is being copied
+ * @param dest the destination address of the user buffer
+ * @param va   the address of the kernel buffer from which we are copying
+ * @param len  the length of the user buffer
+ *
+ * @return ESUCCESS on success
+ * @return -EFAULT  the page assocaited with 'va' is not present, the user 
+ *                  lacks the proper permissions, or there was an invalid 'va'
+ */
+error_t memcpy_to_user(env_t* env, void*DANGEROUS va,
+                 const void *COUNT(len) src, size_t len)
 {
-       if (fd || offset) {
-               printk("[kernel] mmap() does not support files yet.\n");
-               return (void*SAFE)TC(-1);
+       const void *DANGEROUS start, *DANGEROUS end;
+       size_t num_pages, i;
+       pte_t *pte;
+       uintptr_t perm = PTE_P | PTE_USER_RW;
+       size_t bytes_copied = 0;
+
+       static_assert(ULIM % PGSIZE == 0 && ULIM != 0); // prevent wrap-around
+
+       start = ROUNDDOWN(va, PGSIZE);
+       end = ROUNDUP(va + len, PGSIZE);
+
+       if(start >= (void*SNT)ULIM || end >= (void*SNT)ULIM)
+               return -EFAULT;
+
+       num_pages = LA2PPN(end - start);
+       for(i = 0; i < num_pages; i++)
+       {
+               pte = pgdir_walk(env->env_pgdir, start+i*PGSIZE, 0);
+               if(!pte || (*pte & perm) != perm)
+                       return -EFAULT;
+
+               void*COUNT(PGSIZE) kpage = KADDR(PTE_ADDR(*pte));
+               void* dst_start = i > 0 ? kpage : kpage+(va-start);
+               const void* src_start = src+bytes_copied;
+               size_t copy_len = PGSIZE;
+               if(i == 0)
+                       copy_len -= va-start;
+               if(i == num_pages-1)
+                       copy_len -= end-(va+len);
+
+               memcpy(dst_start,src_start,copy_len);
+               bytes_copied += copy_len;
        }
-       void *tmp = get_free_va_range(p->env_pgdir, addr, len);
-       printk("tmp = 0x%08x\n", tmp);
-       return 0;
+
+       assert(bytes_copied == len);
+
+       return ESUCCESS;
 }