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.
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. */
9 #include <ros/common.h>
10 #include <arch/uaccess.h>
19 static int string_copy_from_user(char *dst, const char *src)
22 const char *top = src + valid_user_rbytes_from(src);
24 for (;; dst++, src++) {
25 if (unlikely(src >= top))
27 error = __get_user(dst, src, 1);
37 static int string_copy_to_user(char *dst, const char *src)
40 char *top = dst + valid_user_rwbytes_from(dst);
42 for (;; dst++, src++) {
43 if (unlikely(dst >= top))
45 error = __put_user(dst, src, 1);
55 int strcpy_from_user(struct proc *p, char *dst, const char *src)
57 uintptr_t prev = switch_to(p);
58 int error = string_copy_from_user(dst, src);
65 int strcpy_to_user(struct proc *p, char *dst, const char *src)
67 uintptr_t prev = switch_to(p);
68 int error = string_copy_to_user(dst, src);
75 int memcpy_from_user(struct proc *p, void *dest, const void *va, size_t len)
77 uintptr_t prev = switch_to(p);
78 int error = copy_from_user(dest, va, len);
85 int memcpy_to_user(struct proc *p, void *dest, const void *src, size_t len)
87 uintptr_t prev = switch_to(p);
88 int error = copy_to_user(dest, src, len);
95 /* Same as above, but sets errno */
96 int memcpy_from_user_errno(struct proc *p, void *dst, const void *src, int len)
98 int error = memcpy_from_user(p, dst, src, len);
100 if (unlikely(error < 0))
106 /* Same as above, but sets errno */
107 int memcpy_to_user_errno(struct proc *p, void *dst, const void *src, int len)
109 int error = memcpy_to_user(p, dst, src, len);
111 if (unlikely(error < 0))
117 /* Creates a buffer (kmalloc) and safely copies into it from va. Can return an
118 * error code. Check its response with IS_ERR(). Must be paired with
119 * user_memdup_free() if this succeeded. */
120 void *user_memdup(struct proc *p, const void *va, int len)
123 if (len < 0 || (kva = kmalloc(len, 0)) == NULL)
124 return ERR_PTR(-ENOMEM);
125 if (memcpy_from_user(p, kva, va, len)) {
127 return ERR_PTR(-EFAULT);
132 void *user_memdup_errno(struct proc *p, const void *va, int len)
134 void *kva = user_memdup(p, va, len);
136 set_errno(-PTR_ERR(kva));
142 void user_memdup_free(struct proc *p, void *va)
147 /* Same as memdup, but just does strings, and needs to know the actual strlen.
148 * Still needs memdup_free()d. This will enforce that the string is null
149 * terminated. The parameter strlen does not include the \0, though it can if
150 * someone else is playing it safe. Since strlen() doesn't count the \0, we'll
151 * play it safe here. */
152 char *user_strdup(struct proc *p, const char *u_string, size_t strlen)
154 char *k_string = user_memdup(p, u_string, strlen + 1);
155 if (!IS_ERR(k_string))
156 k_string[strlen] = '\0';
160 /* user_strdup, but this handles the errno. 0 on failure, ptr on success */
161 char *user_strdup_errno(struct proc *p, const char *u_string, size_t strlen)
163 void *k_string = user_strdup(p, u_string, strlen);
164 if (IS_ERR(k_string)) {
165 set_errno(-PTR_ERR(k_string));
171 void *kmalloc_errno(int len)
174 if (len < 0 || (kva = kmalloc(len, 0)) == NULL)
179 /* Returns true if uva and kva both resolve to the same phys addr. If uva is
180 * unmapped, it will return FALSE. This is probably what you want, since after
181 * all uva isn't kva. */
182 bool uva_is_kva(struct proc *p, void *uva, void *kva)
185 assert(kva); /* catch bugs */
186 /* Check offsets first */
187 if (PGOFF(uva) != PGOFF(kva))
189 /* Check to see if it is the same physical page */
190 u_page = page_lookup(p->env_pgdir, uva, 0);
193 return (kva2page(kva) == u_page) ? TRUE : FALSE;
196 /* Given a proc and a user virtual address, gives us the KVA. Useful for
197 * debugging. Returns 0 if the page is unmapped (page lookup fails). This
198 * doesn't play nice with Jumbo pages. */
199 uintptr_t uva2kva(struct proc *p, void *uva, size_t len, int prot)
202 uintptr_t offset = PGOFF(uva);
205 if (prot & PROT_WRITE) {
206 if (!is_user_rwaddr(uva, len))
209 if (!is_user_raddr(uva, len))
212 u_page = page_lookup(p->env_pgdir, uva, 0);
215 return (uintptr_t)page2kva(u_page) + offset;
218 /* Helper, copies a pathname from the process into the kernel. Returns a string
219 * on success, which you must free with free_path. Returns 0 on failure and
221 char *copy_in_path(struct proc *p, const char *path, size_t path_l)
223 struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
226 /* PATH_MAX includes the \0 */
227 if (path_l > PATH_MAX) {
228 set_errno(ENAMETOOLONG);
231 t_path = user_strdup_errno(p, path, path_l);
237 /* Helper, frees a path that was allocated with copy_in_path. */
238 void free_path(struct proc *p, char *t_path)
240 user_memdup_free(p, t_path);