akaros/kern/src/umem.c
<<
>>
Prefs
   1/* Copyright (c) 2009, 2010 The Regents of the University of California
   2 * Barret Rhoden <brho@cs.berkeley.edu>
   3 * Andrew Waterman <waterman@cs.berkeley.edu>
   4 * See LICENSE for details.
   5 *
   6 * Functions for working with userspace's address space.  The user_mem ones need
   7 * to involve some form of pinning (TODO), and that global static needs to go. */
   8
   9#include <ros/common.h>
  10#include <arch/uaccess.h>
  11#include <umem.h>
  12#include <process.h>
  13#include <error.h>
  14#include <kmalloc.h>
  15#include <assert.h>
  16#include <pmap.h>
  17#include <smp.h>
  18
  19static int string_copy_from_user(char *dst, const char *src)
  20{
  21        int error;
  22        const char *top = src + valid_user_rbytes_from(src);
  23
  24        for (;; dst++, src++) {
  25                if (unlikely(src >= top))
  26                        return -EFAULT;
  27                error = __get_user(dst, src, 1);
  28                if (unlikely(error))
  29                        return error;
  30                if (unlikely(!*dst))
  31                        break;
  32        }
  33
  34        return 0;
  35}
  36
  37static int string_copy_to_user(char *dst, const char *src)
  38{
  39        int error;
  40        char *top = dst + valid_user_rwbytes_from(dst);
  41
  42        for (;; dst++, src++) {
  43                if (unlikely(dst >= top))
  44                        return -EFAULT;
  45                error = __put_user(dst, src, 1);
  46                if (unlikely(error))
  47                        return error;
  48                if (unlikely(!*src))
  49                        break;
  50        }
  51
  52        return 0;
  53}
  54
  55int strcpy_from_user(struct proc *p, char *dst, const char *src)
  56{
  57        uintptr_t prev = switch_to(p);
  58        int error = string_copy_from_user(dst, src);
  59
  60        switch_back(p, prev);
  61
  62        return error;
  63}
  64
  65int strcpy_to_user(struct proc *p, char *dst, const char *src)
  66{
  67        uintptr_t prev = switch_to(p);
  68        int error = string_copy_to_user(dst, src);
  69
  70        switch_back(p, prev);
  71
  72        return error;
  73}
  74
  75int memcpy_from_user(struct proc *p, void *dest, const void *va, size_t len)
  76{
  77        uintptr_t prev = switch_to(p);
  78        int error = copy_from_user(dest, va, len);
  79
  80        switch_back(p, prev);
  81
  82        return error;
  83}
  84
  85int memcpy_to_user(struct proc *p, void *dest, const void *src, size_t len)
  86{
  87        uintptr_t prev = switch_to(p);
  88        int error = copy_to_user(dest, src, len);
  89
  90        switch_back(p, prev);
  91
  92        return error;
  93}
  94
  95/* Same as above, but sets errno */
  96int memcpy_from_user_errno(struct proc *p, void *dst, const void *src, int len)
  97{
  98        int error = memcpy_from_user(p, dst, src, len);
  99
 100        if (unlikely(error < 0))
 101                set_errno(-error);
 102
 103        return error;
 104}
 105
 106/* Same as above, but sets errno */
 107int memcpy_to_user_errno(struct proc *p, void *dst, const void *src, int len)
 108{
 109        int error = memcpy_to_user(p, dst, src, len);
 110
 111        if (unlikely(error < 0))
 112                set_errno(-error);
 113
 114        return error;
 115}
 116
 117/* Helpers for FSs that don't care if they copy to the user or the kernel.
 118 *
 119 * TODO: (KFOP) Probably shouldn't do this.  Either memcpy directly, or split
 120 * out the is_user_r(w)addr from copy_{to,from}_user().  Or throw from the fault
 121 * handler.  Right now, we ignore the ret/errors completely. */
 122int memcpy_to_safe(void *dst, const void *src, size_t amt)
 123{
 124        int error = 0;
 125
 126        if (!is_ktask(per_cpu_info[core_id()].cur_kthread))
 127                error = memcpy_to_user(current, dst, src, amt);
 128        else
 129                memcpy(dst, src, amt);
 130        return error;
 131}
 132
 133int memcpy_from_safe(void *dst, const void *src, size_t amt)
 134{
 135        int error = 0;
 136
 137        if (!is_ktask(per_cpu_info[core_id()].cur_kthread))
 138                error = memcpy_from_user(current, dst, src, amt);
 139        else
 140                memcpy(dst, src, amt);
 141        return error;
 142}
 143
 144/* Creates a buffer (kmalloc) and safely copies into it from va.  Can return an
 145 * error code.  Check its response with IS_ERR().  Must be paired with
 146 * user_memdup_free() if this succeeded. */
 147void *user_memdup(struct proc *p, const void *va, int len)
 148{
 149        void* kva = NULL;
 150
 151        if (len < 0 || (kva = kmalloc(len, 0)) == NULL)
 152                return ERR_PTR(-ENOMEM);
 153        if (memcpy_from_user(p, kva, va, len)) {
 154                kfree(kva);
 155                return ERR_PTR(-EFAULT);
 156        }
 157        return kva;
 158}
 159
 160void *user_memdup_errno(struct proc *p, const void *va, int len)
 161{
 162        void *kva = user_memdup(p, va, len);
 163
 164        if (IS_ERR(kva)) {
 165                set_errno(-PTR_ERR(kva));
 166                return NULL;
 167        }
 168        return kva;
 169}
 170
 171void user_memdup_free(struct proc *p, void *va)
 172{
 173        kfree(va);
 174}
 175
 176/* Same as memdup, but just does strings, and needs to know the actual strlen.
 177 * Still needs memdup_free()d.  This will enforce that the string is null
 178 * terminated.  The parameter strlen does not include the \0, though it can if
 179 * someone else is playing it safe.  Since strlen() doesn't count the \0, we'll
 180 * play it safe here. */
 181char *user_strdup(struct proc *p, const char *u_string, size_t strlen)
 182{
 183        char *k_string = user_memdup(p, u_string, strlen + 1);
 184
 185        if (!IS_ERR(k_string))
 186                k_string[strlen] = '\0';
 187        return k_string;
 188}
 189
 190/* user_strdup, but this handles the errno.  0 on failure, ptr on success */
 191char *user_strdup_errno(struct proc *p, const char *u_string, size_t strlen)
 192{
 193        void *k_string = user_strdup(p, u_string, strlen);
 194        if (IS_ERR(k_string)) {
 195                set_errno(-PTR_ERR(k_string));
 196                return NULL;
 197        }
 198        return k_string;
 199}
 200
 201void *kmalloc_errno(int len)
 202{
 203        void *kva = NULL;
 204
 205        if (len < 0 || (kva = kmalloc(len, 0)) == NULL)
 206                set_errno(ENOMEM);
 207        return kva;
 208}
 209
 210/* Returns true if uva and kva both resolve to the same phys addr.  If uva is
 211 * unmapped, it will return FALSE.  This is probably what you want, since after
 212 * all uva isn't kva. */
 213bool uva_is_kva(struct proc *p, void *uva, void *kva)
 214{
 215        struct page *u_page;
 216        assert(kva);                            /* catch bugs */
 217
 218        /* Check offsets first */
 219        if (PGOFF(uva) != PGOFF(kva))
 220                return FALSE;
 221        /* Check to see if it is the same physical page */
 222        u_page = page_lookup(p->env_pgdir, uva, 0);
 223        if (!u_page)
 224                return FALSE;
 225        return (kva2page(kva) == u_page) ? TRUE : FALSE;
 226}
 227
 228/* Given a proc and a user virtual address, gives us the KVA.  Useful for
 229 * debugging.  Returns 0 if the page is unmapped (page lookup fails).  This
 230 * doesn't play nice with Jumbo pages. */
 231uintptr_t uva2kva(struct proc *p, void *uva, size_t len, int prot)
 232{
 233        struct page *u_page;
 234        uintptr_t offset = PGOFF(uva);
 235
 236        if (!p)
 237                return 0;
 238        if (prot & PROT_WRITE) {
 239                if (!is_user_rwaddr(uva, len))
 240                        return 0;
 241        } else {
 242                if (!is_user_raddr(uva, len))
 243                        return 0;
 244        }
 245        u_page = page_lookup(p->env_pgdir, uva, 0);
 246        if (!u_page)
 247                return 0;
 248        return (uintptr_t)page2kva(u_page) + offset;
 249}
 250
 251/* Helper, copies a pathname from the process into the kernel.  Returns a string
 252 * on success, which you must free with free_path.  Returns 0 on failure and
 253 * sets errno. */
 254char *copy_in_path(struct proc *p, const char *path, size_t path_l)
 255{
 256        struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
 257        char *t_path;
 258
 259        /* PATH_MAX includes the \0 */
 260        if (path_l > PATH_MAX) {
 261                set_errno(ENAMETOOLONG);
 262                return 0;
 263        }
 264        t_path = user_strdup_errno(p, path, path_l);
 265        if (!t_path)
 266                return 0;
 267        return t_path;
 268}
 269
 270/* Helper, frees a path that was allocated with copy_in_path. */
 271void free_path(struct proc *p, char *t_path)
 272{
 273        user_memdup_free(p, t_path);
 274}
 275