Lock depth checking allows panicy prints
[akaros.git] / kern / src / umem.c
index a974328..e2a776d 100644 (file)
@@ -13,6 +13,7 @@
 #include <kmalloc.h>
 #include <assert.h>
 #include <pmap.h>
+#include <smp.h>
 
 /**
  * @brief Global variable used to store erroneous virtual addresses as the
@@ -50,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 
@@ -110,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;
@@ -190,7 +188,7 @@ int memcpy_from_user(struct proc *p, void *dest, const void *DANGEROUS va,
 int memcpy_from_user_errno(struct proc *p, void *dst, const void *src, int len)
 {
        if (memcpy_from_user(p, dst, src, len)) {
-               set_errno(current_tf, EINVAL);
+               set_errno(EINVAL);
                return -1;
        }
        return 0;
@@ -254,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(current_tf, EINVAL);
+               set_errno(EINVAL);
                return -1;
        }
        return 0;
@@ -279,7 +277,7 @@ void *user_memdup_errno(struct proc *p, const void *va, int len)
 {
        void *kva = user_memdup(p, va, len);
        if (IS_ERR(kva)) {
-               set_errno(current_tf, -PTR_ERR(kva));
+               set_errno(-PTR_ERR(kva));
                return NULL;
        }
        return kva;
@@ -308,7 +306,7 @@ char *user_strdup_errno(struct proc *p, const char *u_string, size_t strlen)
 {
        void *k_string = user_strdup(p, u_string, strlen);
        if (IS_ERR(k_string)) {
-               set_errno(current_tf, -PTR_ERR(k_string));
+               set_errno(-PTR_ERR(k_string));
                return NULL;
        }
        return k_string;
@@ -318,6 +316,39 @@ void *kmalloc_errno(int len)
 {
        void *kva = NULL;
        if (len < 0 || (kva = kmalloc(len, 0)) == NULL)
-               set_errno(current_tf, ENOMEM);
+               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;
+}