Debug code to see remote kmsgs
[akaros.git] / kern / src / umem.c
index 5263d15..e2a776d 100644 (file)
@@ -13,6 +13,7 @@
 #include <kmalloc.h>
 #include <assert.h>
 #include <pmap.h>
 #include <kmalloc.h>
 #include <assert.h>
 #include <pmap.h>
+#include <smp.h>
 
 /**
  * @brief Global variable used to store erroneous virtual addresses as the
 
 /**
  * @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,
  * @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;
                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 
        // 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
  * @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,
 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);
        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;
         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)) {
 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;
                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)) {
 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;
                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)) {
 {
        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;
                return NULL;
        }
        return kva;
@@ -290,46 +288,67 @@ void user_memdup_free(struct proc *p, void *va)
        kfree(va);
 }
 
        kfree(va);
 }
 
-/* Same as memdup, but just does strings.  still needs memdup_freed */
-char *user_strdup(struct proc *p, const char *va0, int max)
+/* Same as memdup, but just does strings, and needs to know the actual strlen.
+ * Still needs memdup_free()d.  This will enforce that the string is null
+ * terminated.  The parameter strlen does not include the \0, though it can if
+ * someone else is playing it safe.  Since strlen() doesn't count the \0, we'll
+ * play it safe here. */
+char *user_strdup(struct proc *p, const char *u_string, size_t strlen)
 {
 {
-       max++;
-       char* kbuf = (char*)kmalloc(PGSIZE, 0);
-       if (kbuf == NULL)
-               return ERR_PTR(-ENOMEM);
-       int pos = 0, len = 0;
-       const char* va = va0;
-       while (max > 0 && len == 0) {
-               int thislen = MIN(PGSIZE - (uintptr_t)va % PGSIZE, max);
-               if (memcpy_from_user(p, kbuf, va, thislen)) {
-                       kfree(kbuf);
-                       return ERR_PTR(-EINVAL);
-               }
-               const char *nullterm = memchr(kbuf, 0, thislen);
-               if (nullterm)
-                       len = pos + (nullterm - kbuf) + 1;
-               pos += thislen;
-               va += thislen;
-               max -= thislen;
-       }
-       kfree(kbuf);
-       return len ? user_memdup(p, va0, len) : ERR_PTR(-EINVAL);
+       char *k_string = user_memdup(p, u_string, strlen + 1);
+       if (!IS_ERR(k_string))
+               k_string[strlen] = '\0';
+       return k_string;
 }
 
 }
 
-char *user_strdup_errno(struct proc *p, const char *va, int max)
+/* user_strdup, but this handles the errno.  0 on failure, ptr on success */
+char *user_strdup_errno(struct proc *p, const char *u_string, size_t strlen)
 {
 {
-       void *kva = user_strdup(p, va, max);
-       if (IS_ERR(kva)) {
-               set_errno(current_tf, -PTR_ERR(kva));
+       void *k_string = user_strdup(p, u_string, strlen);
+       if (IS_ERR(k_string)) {
+               set_errno(-PTR_ERR(k_string));
                return NULL;
        }
                return NULL;
        }
-       return kva;
+       return k_string;
 }
 
 void *kmalloc_errno(int len)
 {
        void *kva = NULL;
        if (len < 0 || (kva = kmalloc(len, 0)) == NULL)
 }
 
 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;
 }
        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;
+}