An x86-64 operating system built from xv6, now largely rewritten: SMP, a copy-on-write root filesystem (SchFS), PCI/USB/virtio drivers, a TTF rasteriser, and a Linux-numbered syscall ABI. No history before this point -- the tree was never under version control. This commit exists so the rename that follows has something to undo to.
79 lines
1.8 KiB
C
79 lines
1.8 KiB
C
// User-memory access helpers — see include/uaccess.h for the rules.
|
|
//
|
|
// Everything here validates against the *current* process's page table
|
|
// (myproc()->pgdir), which is also the live CR3 while a syscall runs, so a
|
|
// range that passes access_ok() can be dereferenced directly by kernel
|
|
// code for the remainder of the syscall (single-threaded processes can't
|
|
// unmap it out from under us mid-call).
|
|
|
|
#include "types.h"
|
|
#include "defs.h"
|
|
#include "param.h"
|
|
#include "memlayout.h"
|
|
#include "mmu.h"
|
|
#include "proc.h"
|
|
#include "errno.h"
|
|
#include "uaccess.h"
|
|
|
|
int
|
|
access_ok(addr_t uaddr, uint64 size)
|
|
{
|
|
addr_t a, end;
|
|
|
|
if(size == 0)
|
|
return 1;
|
|
end = uaddr + size;
|
|
if(end < uaddr || end > KERNBASE)
|
|
return 0;
|
|
for(a = PGROUNDDOWN(uaddr); a < end; a += PGSIZE)
|
|
if(uva2ka(myproc()->pgdir, (char*)a) == 0)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
void*
|
|
user_ptr(addr_t uaddr, uint64 size)
|
|
{
|
|
if(uaddr == 0 || !access_ok(uaddr, size))
|
|
return 0;
|
|
return (void*)uaddr;
|
|
}
|
|
|
|
int
|
|
copy_from_user(void *dst, addr_t uaddr, uint64 n)
|
|
{
|
|
if(uaddr + n < uaddr || uaddr + n > KERNBASE)
|
|
return -EFAULT;
|
|
if(copyin(myproc()->pgdir, uaddr, dst, n) < 0)
|
|
return -EFAULT;
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
copy_to_user(addr_t uaddr, const void *src, uint64 n)
|
|
{
|
|
if(uaddr + n < uaddr || uaddr + n > KERNBASE)
|
|
return -EFAULT;
|
|
if(copyout(myproc()->pgdir, uaddr, (void*)src, n) < 0)
|
|
return -EFAULT;
|
|
return 0;
|
|
}
|
|
|
|
long
|
|
strlen_user(addr_t uaddr)
|
|
{
|
|
addr_t a = uaddr;
|
|
|
|
while(a - uaddr < USER_STR_MAX){
|
|
// Scan through the per-page kernel alias so an unmapped page is a
|
|
// clean failure instead of a fault.
|
|
char *ka = uva2ka(myproc()->pgdir, (char*)a);
|
|
if(ka == 0)
|
|
return -EFAULT;
|
|
addr_t pgend = PGROUNDDOWN(a) + PGSIZE;
|
|
for(; a < pgend; a++, ka++)
|
|
if(*ka == 0)
|
|
return a - uaddr;
|
|
}
|
|
return -EFAULT;
|
|
}
|