print_user_ctx helper
[akaros.git] / kern / src / umem.c
index ab00b74..e8d83c5 100644 (file)
@@ -51,13 +51,12 @@ static void *DANGEROUS RACY user_mem_check_addr;
  * @return NULL trying to access this range of virtual addresses is not allowed
  */
 void *user_mem_check(struct proc *p, const void *DANGEROUS va, size_t len,
-                     int perm)
+                     size_t align, int perm)
 {
-       if (len == 0) {
-               warn("Called user_mem_check with a len of 0. Don't do that. Returning NULL");
+       align--;
+       if(((align+1) & align) || ((uintptr_t)va & align) || (len & align))
                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 
@@ -67,8 +66,8 @@ void *user_mem_check(struct proc *p, const void *DANGEROUS va, size_t len,
        int page_perms = 0;
 
        perm |= PTE_P;
-       start = ROUNDDOWN((void*DANGEROUS)va, PGSIZE);
-       end = ROUNDUP((void*DANGEROUS)va + len, PGSIZE);
+       start = (void*)ROUNDDOWN((uintptr_t)va, PGSIZE);
+       end = (void*)ROUNDUP((uintptr_t)va + len, PGSIZE);
        if (start >= end) {
                warn("Blimey!  Wrap around in VM range calculation!");  
                return NULL;
@@ -111,20 +110,18 @@ void *user_mem_check(struct proc *p, const void *DANGEROUS va, size_t len,
  * @return VA a pointer of type COUNT(len) to the address range
  * @return NULL trying to access this range of virtual addresses is not allowed
  *              process 'p' is destroyed
- */
+ *
+ * GIANT WARNING: this could fuck up your refcnting for p if p was an
+ * edible/refcounted reference.  (fix is to return, or just not use this) */
 void *user_mem_assert(struct proc *p, const void *DANGEROUS va, size_t len,
-                       int perm)
+                      size_t align, int perm)
 {
-       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(p, va, len, perm | PTE_USER_RO);
+       void* res = user_mem_check(p, va, len, align, perm | PTE_USER_RO);
        if (!res) {
                cprintf("[%08x] user_mem_check assertion failure for "
                        "va %08x\n", p->pid, user_mem_check_addr);
-               proc_destroy(p);        // may not return
+               /* won't be freed til the caller decrefs */
+               proc_destroy(p);
         return NULL;
        }
     return res;
@@ -154,8 +151,8 @@ int memcpy_from_user(struct proc *p, void *dest, const void *DANGEROUS va,
 
        static_assert(ULIM % PGSIZE == 0 && ULIM != 0); // prevent wrap-around
 
-       start = ROUNDDOWN(va, PGSIZE);
-       end = ROUNDUP(va + len, PGSIZE);
+       start = (void*)ROUNDDOWN((uintptr_t)va, PGSIZE);
+       end = (void*)ROUNDUP((uintptr_t)va + len, PGSIZE);
 
        if (start >= (void*SNT)ULIM || end > (void*SNT)ULIM)
                return -EFAULT;
@@ -220,8 +217,8 @@ int memcpy_to_user(struct proc *p, void *va, const void *src, size_t len)
 
        static_assert(ULIM % PGSIZE == 0 && ULIM != 0); // prevent wrap-around
 
-       start = ROUNDDOWN(va, PGSIZE);
-       end = ROUNDUP(va + len, PGSIZE);
+       start = (void*)ROUNDDOWN((uintptr_t)va, PGSIZE);
+       end = (void*)ROUNDUP((uintptr_t)va + len, PGSIZE);
 
        if (start >= (void*SNT)ULIM || end > (void*SNT)ULIM)
                return -EFAULT;
@@ -255,7 +252,7 @@ int memcpy_to_user(struct proc *p, void *va, const void *src, size_t len)
 int memcpy_to_user_errno(struct proc *p, void *dst, const void *src, int len)
 {
        if (memcpy_to_user(p, dst, src, len)) {
-               set_errno(EINVAL);
+               set_errno(EFAULT);
                return -1;
        }
        return 0;
@@ -271,7 +268,7 @@ void *user_memdup(struct proc *p, const void *va, int len)
                return ERR_PTR(-ENOMEM);
        if (memcpy_from_user(p, kva, va, len)) {
                kfree(kva);
-               return ERR_PTR(-EINVAL);
+               return ERR_PTR(-EFAULT);
        }
        return kva;
 }
@@ -322,3 +319,36 @@ void *kmalloc_errno(int len)
                set_errno(ENOMEM);
        return kva;
 }
+
+/* Returns true if uva and kva both resolve to the same phys addr.  If uva is
+ * unmapped, it will return FALSE.  This is probably what you want, since after
+ * all uva isn't kva. */
+bool uva_is_kva(struct proc *p, void *uva, void *kva)
+{
+       struct page *u_page;
+       assert(kva);                            /* catch bugs */
+       /* Check offsets first */
+       if (PGOFF(uva) != PGOFF(kva))
+               return FALSE;
+       /* Check to see if it is the same physical page */
+       u_page = page_lookup(p->env_pgdir, uva, 0);
+       if (!u_page)
+               return FALSE;
+       return (kva2page(kva) == u_page) ? TRUE : FALSE;
+}
+
+/* Given a proc and a user virtual address, gives us the KVA.  Useful for
+ * debugging.  Returns 0 if the page is unmapped (page lookup fails).  If you
+ * give it a kva, it'll give you that same KVA, but this doesn't play nice with
+ * Jumbo pages. */
+uintptr_t uva2kva(struct proc *p, void *uva)
+{
+       struct page *u_page;
+       uintptr_t offset = PGOFF(uva);
+       if (!p)
+               return 0;
+       u_page = page_lookup(p->env_pgdir, uva, 0);
+       if (!u_page)
+               return 0;
+       return (uintptr_t)page2kva(u_page) + offset;
+}