#pragma nosharc
#endif
+#ifdef __DEPUTY__
+#pragma nodeputy
+#endif
+
#include <arch/arch.h>
#include <arch/mmu.h>
/**
* @brief Global variable used to store erroneous virtual addresses as the
* result of a failed user_mem_check().
+ *
+ * zra: What if two checks fail at the same time? Maybe this should be per-cpu?
+ *
*/
-static void *DANGEROUS user_mem_check_addr;
+static void *DANGEROUS RACY user_mem_check_addr;
volatile uint32_t vpt_lock = 0;
volatile uint32_t vpd_lock = 0;
*/
void* user_mem_check(env_t *env, const void *DANGEROUS va, size_t len, int perm)
{
+ if (len == 0) {
+ warn("Called user_mem_check with a len of 0. Don't do that. Returning 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
warn("Blimey! Wrap around in VM range calculation!");
return NULL;
}
- num_pages = PPN(end - start);
+ num_pages = LA2PPN(end - start);
for (i = 0; i < num_pages; i++, start += PGSIZE) {
page_perms = get_va_perms(env->env_pgdir, start);
// ensures the bits we want on are turned on. if not, error out
* @return LEN the length of the new buffer copied into 'dst'
*/
size_t
-user_mem_strlcpy(env_t *env, char *dst, const char *DANGEROUS va,
+user_mem_strlcpy(env_t *env, char *_dst, const char *DANGEROUS va,
size_t _len, int perm)
{
const char *DANGEROUS src = va;
size_t len = _len;
- char *NT COUNT(_len-1) dst_in = dst;
+ char *NT COUNT(_len-1) dst_in = _dst;
+ char *NT BND(_dst,_dst + _len - 1) dst = _dst;
if (len > 0) {
while (1) {
void *
user_mem_assert(env_t *env, const void *DANGEROUS va, size_t len, int perm)
{
- void *COUNT(len) res = user_mem_check(env,va,len,perm | PTE_USER_RO);
+ 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(env,va,len,perm | PTE_USER_RO);
if (!res) {
cprintf("[%08x] user_mem_check assertion failure for "
- "va %08x\n", env->env_id, user_mem_check_addr);
+ "va %08x\n", env->pid, user_mem_check_addr);
proc_destroy(env); // may not return
return NULL;
}
if(start >= (void*SNT)ULIM || end >= (void*SNT)ULIM)
return -EFAULT;
- num_pages = PPN(end - start);
+ num_pages = LA2PPN(end - start);
for(i = 0; i < num_pages; i++)
{
pte = pgdir_walk(env->env_pgdir, start+i*PGSIZE, 0);
if(!pte || (*pte & perm) != perm)
return -EFAULT;
- void*COUNT(PGSIZE) kpage = KADDR(PTE_ADDR(pte));
- void* src_start = i > 0 ? kpage : kpage+(va-start);
+ void*COUNT(PGSIZE) kpage = KADDR(PTE_ADDR(*pte));
+ const void* src_start = i > 0 ? kpage : kpage+(va-start);
void* dst_start = dest+bytes_copied;
size_t copy_len = PGSIZE;
if(i == 0)
copy_len -= va-start;
if(i == num_pages-1)
- copy_len -= end-(start+len);
+ copy_len -= end-(va+len);
memcpy(dst_start,src_start,copy_len);
bytes_copied += copy_len;
return ESUCCESS;
}
+/**
+ * @brief Copies data to a user buffer from a kernel buffer.
+ *
+ * @param env the environment associated with the user program
+ * to which the buffer is being copied
+ * @param dest the destination address of the user buffer
+ * @param va the address of the kernel buffer from which we are copying
+ * @param len the length of the user buffer
+ *
+ * @return ESUCCESS on success
+ * @return -EFAULT the page assocaited with 'va' is not present, the user
+ * lacks the proper permissions, or there was an invalid 'va'
+ */
+error_t memcpy_to_user(env_t* env, void*DANGEROUS va,
+ const void *COUNT(len) src, size_t len)
+{
+ const void *DANGEROUS start, *DANGEROUS end;
+ size_t num_pages, i;
+ pte_t *pte;
+ uintptr_t perm = PTE_P | PTE_USER_RW;
+ size_t bytes_copied = 0;
+
+ static_assert(ULIM % PGSIZE == 0 && ULIM != 0); // prevent wrap-around
+
+ start = ROUNDDOWN(va, PGSIZE);
+ end = ROUNDUP(va + len, PGSIZE);
+
+ if(start >= (void*SNT)ULIM || end >= (void*SNT)ULIM)
+ return -EFAULT;
+
+ num_pages = LA2PPN(end - start);
+ for(i = 0; i < num_pages; i++)
+ {
+ pte = pgdir_walk(env->env_pgdir, start+i*PGSIZE, 0);
+ if(!pte || (*pte & perm) != perm)
+ return -EFAULT;
+
+ void*COUNT(PGSIZE) kpage = KADDR(PTE_ADDR(*pte));
+ void* dst_start = i > 0 ? kpage : kpage+(va-start);
+ const void* src_start = src+bytes_copied;
+ size_t copy_len = PGSIZE;
+ if(i == 0)
+ copy_len -= va-start;
+ if(i == num_pages-1)
+ copy_len -= end-(va+len);
+
+ memcpy(dst_start,src_start,copy_len);
+ bytes_copied += copy_len;
+ }
+
+ assert(bytes_copied == len);
+
+ return ESUCCESS;
+}