summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordzwdz2021-09-05 18:55:32 +0200
committerdzwdz2021-09-05 18:55:32 +0200
commit0b2b263060907e8bf732c1d27c66b7358af01e9f (patch)
tree321e459503ed2694126b2556e3064f95006c0148 /src
parent838b142b7374150df63ec02b02377c114a14b314 (diff)
make virt_iter support iterating over physical memory too
Diffstat (limited to 'src')
-rw-r--r--src/kernel/mem/virt.c22
-rw-r--r--src/kernel/mem/virt.h1
-rw-r--r--src/kernel/syscalls.c30
3 files changed, 29 insertions, 24 deletions
diff --git a/src/kernel/mem/virt.c b/src/kernel/mem/virt.c
index 2990668..beeb54f 100644
--- a/src/kernel/mem/virt.c
+++ b/src/kernel/mem/virt.c
@@ -23,21 +23,25 @@ bool virt_iter_next(struct virt_iter *iter) {
* virtual and physical memory, which might not always be the case.
* TODO test this */
- user_ptr virt = iter->_virt;
size_t partial = iter->_remaining;
iter->prior += iter->frag_len;
if (partial <= 0) return false;
- // don't read past the page
- if ((virt & PAGE_MASK) + partial > PAGE_SIZE)
- partial = PAGE_SIZE - (virt & PAGE_MASK);
+ if (iter->_pages) { // if iterating over virtual memory
+ // don't read past the page
+ if ((iter->_virt & PAGE_MASK) + partial > PAGE_SIZE)
+ partial = PAGE_SIZE - (iter->_virt & PAGE_MASK);
- iter->frag = pagedir_virt2phys(iter->_pages,
- iter->_virt, iter->_user, iter->_writeable);
+ iter->frag = pagedir_virt2phys(iter->_pages,
+ iter->_virt, iter->_user, iter->_writeable);
- if (iter->frag == 0) {
- iter->error = true;
- return false;
+ if (iter->frag == 0) {
+ iter->error = true;
+ return false;
+ }
+ } else {
+ // "iterate" over physical memory
+ iter->frag = iter->_virt;
}
iter->frag_len = partial;
diff --git a/src/kernel/mem/virt.h b/src/kernel/mem/virt.h
index 98a7a16..e87a9fe 100644
--- a/src/kernel/mem/virt.h
+++ b/src/kernel/mem/virt.h
@@ -17,6 +17,7 @@ struct virt_iter {
bool _writeable;
};
+/* if pages == NULL, create an iterator over physical memory. */
void virt_iter_new(
struct virt_iter *iter, user_ptr virt, size_t length,
struct pagedir *pages, bool user, bool writeable);
diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c
index 416c815..2174791 100644
--- a/src/kernel/syscalls.c
+++ b/src/kernel/syscalls.c
@@ -68,36 +68,37 @@ int _syscall_fork(void) {
}
handle_t _syscall_open(const user_ptr path, int len) {
- struct virt_iter iter;
struct vfs_mount *mount;
- static char buffer[PATH_MAX]; // holds the path
+ static char path_buf[PATH_MAX];
- if (len > PATH_MAX) return -1;
+ if (len > PATH_MAX)
+ return -1;
// fail if there are no handles left
if (process_find_handle(process_current) < 0)
return -1;
// copy the path to the kernel
- virt_iter_new(&iter, path, len, process_current->pages, true, false);
- while (virt_iter_next(&iter))
- memcpy(buffer + iter.prior, iter.frag, iter.frag_len);
- if (iter.error) return -1;
+ // note: the cast is necessary because the function usually accepts user_ptrs
+ // it can handle copies to physical memory too, though
+ if (!virt_user_cpy(NULL, (uintptr_t)path_buf,
+ process_current->pages, path, len))
+ return -1;
- len = path_simplify(buffer, buffer, len);
+ len = path_simplify(path_buf, path_buf, len);
if (len < 0) return -1;
- mount = vfs_mount_resolve(process_current->mount, buffer, len);
+ mount = vfs_mount_resolve(process_current->mount, path_buf, len);
if (!mount) return -1;
vfs_backend_dispatch(mount->backend, (struct vfs_op) {
.type = VFSOP_OPEN,
.open = {
- .path = &buffer[mount->prefix_len],
+ .path = &path_buf[mount->prefix_len],
.path_len = len - mount->prefix_len,
}
});
- // doesn't return. TODO mark as noreturn
+ // doesn't return
}
int _syscall_mount(handle_t handle, const user_ptr path, int len) {
@@ -111,10 +112,9 @@ int _syscall_mount(handle_t handle, const user_ptr path, int len) {
// copy the path to the kernel
path_buf = kmalloc(len);
- virt_iter_new(&iter, path, len, process_current->pages, true, false);
- while (virt_iter_next(&iter))
- memcpy(path_buf + iter.prior, iter.frag, iter.frag_len);
- if (iter.error) goto fail;
+ if (!virt_user_cpy(NULL, (uintptr_t)path_buf,
+ process_current->pages, path, len))
+ goto fail;
// simplify it
len = path_simplify(path_buf, path_buf, len);