// User-memory access API, modeled on Linux's . // // Rules for kernel code touching user pointers: // // 1. Never dereference a user-supplied address without validating it // first. A syscall argument can point anywhere, including at kernel // memory or at nothing at all. // // 2. Never assume a user buffer is physically contiguous. uva2ka() only // translates ONE page; the direct-map alias it returns runs into an // unrelated physical page at the next 4K boundary. Any multi-byte // access through it must stay within a single page. // // These helpers encapsulate both rules. Because SchOS (like old x86 // without SMAP) keeps the user page table active in kernel mode, a raw // user virtual address is directly dereferenceable once the whole range // has been validated — that is what user_ptr() hands back, and why the // result is safe across page boundaries where a uva2ka() pointer is not. #ifndef SCHOS_UACCESS_H #define SCHOS_UACCESS_H #include "types.h" // Nonzero if [uaddr, uaddr+size) is entirely mapped, user-accessible // memory in the current process. size == 0 is always ok. int access_ok(addr_t uaddr, uint64 size); // Validate the whole range and return it as a directly usable pointer // (the raw user VA). 0 on bad/NULL address. void *user_ptr(addr_t uaddr, uint64 size); // Copy between kernel and user memory, page by page. // Return 0 on success, -EFAULT on any unmapped page. int copy_from_user(void *dst, addr_t uaddr, uint64 n); int copy_to_user(addr_t uaddr, const void *src, uint64 n); // Fixed-size scalar variants, in the spirit of Linux's get_user/put_user. #define get_user(x, uaddr) copy_from_user(&(x), (addr_t)(uaddr), sizeof(x)) #define put_user(x, uaddr) copy_to_user((addr_t)(uaddr), &(x), sizeof(x)) // Longest string fetchstr()/strlen_user() will scan before giving up. #define USER_STR_MAX 32768 // Length of the NUL-terminated string at uaddr (excluding the NUL), // validating every page it spans. -EFAULT if it runs off mapped memory // or exceeds USER_STR_MAX. long strlen_user(addr_t uaddr); #endif // SCHOS_UACCESS_H