diff options
author | Ian Moffett <ian@osmora.org> | 2024-12-15 22:57:21 -0500 |
---|---|---|
committer | Ian Moffett <ian@osmora.org> | 2024-12-15 22:57:21 -0500 |
commit | 0bdb884b331c58d33c3ccf29070e2955095a1acc (patch) | |
tree | 1397186ea6ba20e3addc5b98d072d958500ff3af /sys/vm | |
parent | 5504521882fc4f12dc0c25fea57d53c583789492 (diff) |
kernel: vm: Add objects, page struct and pagers
This commit expands the virtual memory subsystem by providing the
initial implementation of virtual memory objects, pager descriptors and
pagers. This change currently implemenents a minimal vnode pager.
Signed-off-by: Ian Moffett <ian@osmora.org>
Diffstat (limited to 'sys/vm')
-rw-r--r-- | sys/vm/vm_obj.c | 51 | ||||
-rw-r--r-- | sys/vm/vm_page.c | 106 | ||||
-rw-r--r-- | sys/vm/vm_pager.c | 45 | ||||
-rw-r--r-- | sys/vm/vm_vnode.c | 185 |
4 files changed, 387 insertions, 0 deletions
diff --git a/sys/vm/vm_obj.c b/sys/vm/vm_obj.c new file mode 100644 index 0000000..75545dc --- /dev/null +++ b/sys/vm/vm_obj.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <vm/vm_obj.h> +#include <vm/vm_pager.h> + +int +vm_obj_init(struct vm_object *obp, const struct vm_pagerops *pgops, int refs) +{ + if (obp == NULL || pgops == NULL) + return -1; + + obp->pgops = pgops; + obp->refs = refs; + obp->npages = 0; + RBT_INIT(vm_objtree, &obp->objt); + return 0; +} + +void +vm_obj_release(struct vm_object *obp) +{ + /* STUB */ + (void)obp; +} diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c new file mode 100644 index 0000000..8ada183 --- /dev/null +++ b/sys/vm/vm_page.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <vm/vm_page.h> +#include <vm/vm_obj.h> +#include <vm/physmem.h> +#include <vm/dynalloc.h> +#include <vm/vm.h> +#include <assert.h> +#include <string.h> + +RBT_GENERATE(vm_objtree, vm_page, objt, vm_pagecmp); + +/* + * Insert a page into an object. + */ +static inline void +vm_pageinsert(struct vm_page *pg, struct vm_object *obp) +{ + struct vm_page *tmp; + + tmp = RBT_INSERT(vm_objtree, &obp->objt, pg); + __assert(tmp == NULL); + ++obp->npages; +} + +static inline void +vm_pageremove(struct vm_page *pg, struct vm_object *obp) +{ + RBT_REMOVE(vm_objtree, &obp->objt, pg); + --obp->npages; +} + +struct vm_page * +vm_pagelookup(struct vm_object *obj, off_t off) +{ + struct vm_page tmp; + + tmp.offset = off; + return RBT_FIND(vm_objtree, &obj->objt, &tmp); +} + +struct vm_page * +vm_pagealloc(struct vm_object *obj, int flags) +{ + struct vm_page *tmp; + + tmp = dynalloc(sizeof(*tmp)); + if (tmp == NULL) { + return NULL; + } + + memset(tmp, 0, sizeof(*tmp)); + tmp->phys_addr = vm_alloc_frame(1); + tmp->flags |= (PG_VALID | PG_CLEAN); + __assert(tmp->phys_addr != 0); + + if (ISSET(flags, PALLOC_ZERO)) { + memset(PHYS_TO_VIRT(tmp->phys_addr), 0, DEFAULT_PAGESIZE); + } + + vm_pageinsert(tmp, obj); + return tmp; +} + +void +vm_pagefree(struct vm_object *obj, struct vm_page *pg, int flags) +{ + __assert(pg->phys_addr != 0); + + vm_pageremove(pg, obj); + vm_free_frame(pg->phys_addr, 1); + dynfree(pg); +} + +int +vm_pagecmp(const struct vm_page *a, const struct vm_page *b) +{ + return (a->offset < b->offset) ? -1 : a->offset > b->offset; +} diff --git a/sys/vm/vm_pager.c b/sys/vm/vm_pager.c new file mode 100644 index 0000000..2a85d55 --- /dev/null +++ b/sys/vm/vm_pager.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/errno.h> +#include <vm/vm_pager.h> +#include <vm/vm_obj.h> + +int +vm_pager_get(struct vm_object *obp, struct vm_page **pgs, off_t off, size_t len) +{ + const struct vm_pagerops *pgops = obp->pgops; + + if (pgops->get == NULL) { + return -ENOTSUP; + } + + return pgops->get(obp, pgs, off, len); +} diff --git a/sys/vm/vm_vnode.c b/sys/vm/vm_vnode.c new file mode 100644 index 0000000..31e74cc --- /dev/null +++ b/sys/vm/vm_vnode.c @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/cdefs.h> +#include <sys/errno.h> +#include <sys/syslog.h> +#include <sys/systm.h> +#include <sys/vnode.h> +#include <vm/vm_vnode.h> +#include <vm/vm_page.h> +#include <vm/pmap.h> +#include <vm/vm.h> + +#define VN_TIMEOUT_USEC 200000 + +#define pr_trace(fmt, ...) kprintf("vm_vnode: " fmt, ##__VA_ARGS__) +#define pr_error(...) pr_trace(__VA_ARGS__) + +/* Debug print helper */ +#if defined(PR_DEBUG) +#define pr_debug(...) pr_trace(__VA_ARGS__) +#else +#define pr_debug(...) __nothing +#endif /* PR_DEBUG */ + +const struct vm_pagerops vm_vnops; + +/* + * Perform read/write operation on vnode to/from pages. + * + * Returns number of bytes read. + */ +static int +vn_io(struct vnode *vp, struct vm_page **pgs, unsigned int npages, int rw) +{ + struct vop_getattr_args args; + struct sio_txn sio; + struct vattr vattr; + size_t c, read = 0; + int err; + + /* TODO: Add support for writes */ + if (rw != 0) { + return -ENOTSUP; + } + + args.vp = vp; + args.res = &vattr; + c = MAX(vattr.size / DEFAULT_PAGESIZE, 1); + + if ((err = vfs_vop_getattr(vp, &args)) != 0) { + return err; + } + + if (npages > c) { + npages = c; + } + + /* Prepare SIO constants */ + sio.len = DEFAULT_PAGESIZE; + sio.offset = 0; + + /* Copy in each page */ + for (size_t i = 0; i < npages; ++i) { + sio.buf = PHYS_TO_VIRT(pgs[i]->phys_addr); + read = vfs_vop_read(vp, &sio); + if (read < 0) + pr_debug("vn_io: page-in @ %p failed (err=%d)\n", err); + } + + return read; +} + +/* + * Get pages from backing store. + * + * @obp: Object representing the backing store. + * @pgs: Page descriptors to be filled. + * @off: Offset to read from in backing store. + * @len: Length to read in bytes. + */ +static int +vn_get(struct vm_object *obp, struct vm_page **pgs, off_t off, size_t len) +{ + struct vm_page *pgtmp; + size_t j, pgcnt; + + spinlock_acquire(&obp->lock); + + for (int i = off; i < len; i += DEFAULT_PAGESIZE) { + j = i / DEFAULT_PAGESIZE; + pgtmp = vm_pagelookup(obp, i); + + /* + * If we have no corresponding page in the object + * at this offset, we will need to make our own. + */ + if (pgtmp == NULL) { + pgtmp = vm_pagealloc(obp, PALLOC_ZERO); + if (pgtmp == NULL) { + pgs[j]->flags &= ~PG_VALID; + continue; + } + pgtmp->offset = i; + pgs[j] = pgtmp; + } + + if (spinlock_usleep(&pgtmp->lock, VN_TIMEOUT_USEC) != 0) { + pgs[j]->flags &= ~PG_VALID; + continue; + } + + /* Set the page count and ensure it is valid */ + pgcnt = ALIGN_DOWN(len, DEFAULT_PAGESIZE); + pgcnt = MAX(pgcnt, 1); + + /* Page in and save this pgtmp */ + vn_io(obp->data, &pgtmp, pgcnt, 0); + pgs[j] = pgtmp; + spinlock_release(&pgtmp->lock); + } + + spinlock_release(&obp->lock); + return 0; +} + +/* + * Attach a virtual memory object to a vnode. + * + * @vp: Vnode to attach to. + */ +struct vm_object * +vn_attach(struct vnode *vp, vm_prot_t prot) +{ + struct vm_object *vmobj; + int error; + + if (vp->type != VREG) { + pr_error("vn_attach: vp=%p, prot=%x\n", vp, prot); + pr_error("vn_attach: Special files not supported yet!\n"); + return NULL; + } + + error = vm_obj_init(&vp->vobj, &vm_vnops, 1); + if (error != 0) { + return NULL; + } + + vmobj = &vp->vobj; + vmobj->prot = prot; + vmobj->data = vp; + vmobj->pgops = &vm_vnops; + return vmobj; +} + +const struct vm_pagerops vm_vnops = { + .get = vn_get +}; |