From 36cff84e05620271fa1b5d56d3c7ccf17017f12b Mon Sep 17 00:00:00 2001 From: NAKAMURA Gou Date: Thu, 3 Jul 2014 13:58:05 +0900 Subject: [PATCH] add zeroobj for private anonymous mappings --- kernel/Makefile.build | 1 + kernel/include/memobj.h | 1 + kernel/syscall.c | 7 ++ kernel/zeroobj.c | 206 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 215 insertions(+) create mode 100644 kernel/zeroobj.c diff --git a/kernel/Makefile.build b/kernel/Makefile.build index ded7f58d..49e40193 100644 --- a/kernel/Makefile.build +++ b/kernel/Makefile.build @@ -1,6 +1,7 @@ IHKDIR=$(IHKBASE)/$(TARGETDIR) OBJS = init.o mem.o debug.o mikc.o listeners.o ap.o syscall.o cls.o host.o OBJS += process.o copy.o waitq.o futex.o timer.o plist.o fileobj.o shmobj.o +OBJS += zeroobj.o DEPSRCS=$(wildcard $(SRC)/*.c) CFLAGS += -I$(SRC)/include -mcmodel=kernel -D__KERNEL__ diff --git a/kernel/include/memobj.h b/kernel/include/memobj.h index 0ba9c838..6bfd2a0a 100644 --- a/kernel/include/memobj.h +++ b/kernel/include/memobj.h @@ -103,5 +103,6 @@ static inline int memobj_has_pager(struct memobj *obj) int fileobj_create(int fd, struct memobj **objp, int *maxprotp); int shmobj_create(struct shmid_ds *ds, struct memobj **objp); +int zeroobj_create(struct memobj **objp); #endif /* HEADER_MEMOBJ_H */ diff --git a/kernel/syscall.c b/kernel/syscall.c index 3187f35e..b0d86109 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -795,6 +795,13 @@ SYSCALL_DECLARE(mmap) goto out; } } + else { + error = zeroobj_create(&memobj); + if (error) { + ekprintf("sys_mmap:zeroobj_create failed. %d\n", error); + goto out; + } + } if ((flags & MAP_PRIVATE) && (maxprot & PROT_READ)) { maxprot |= PROT_WRITE; diff --git a/kernel/zeroobj.c b/kernel/zeroobj.c new file mode 100644 index 00000000..2305ea6a --- /dev/null +++ b/kernel/zeroobj.c @@ -0,0 +1,206 @@ +/** + * \file zeroobj.c + * License details are found in the file LICENSE. + * \brief + * read-only zeroed page object + * \author Gou Nakamura + */ +/* + * HISTORY: + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define dkprintf(...) do { if (0) kprintf(__VA_ARGS__); } while (0) +#define ekprintf(...) kprintf(__VA_ARGS__) +#define fkprintf(...) kprintf(__VA_ARGS__) + +struct zeroobj { + struct memobj memobj; /* must be first */ + struct list_head page_list; +}; + +static ihk_spinlock_t the_zeroobj_lock = SPIN_LOCK_UNLOCKED; +static struct zeroobj *the_zeroobj = NULL; /* singleton */ + +static memobj_get_page_func_t zeroobj_get_page; + +static struct memobj_ops zeroobj_ops = { + .get_page = &zeroobj_get_page, +}; + +static struct zeroobj *to_zeroobj(struct memobj *memobj) +{ + return (struct zeroobj *)memobj; +} + +static struct memobj *to_memobj(struct zeroobj *zeroobj) +{ + return &zeroobj->memobj; +} + +/*********************************************************************** + * page_list + */ +static void page_list_init(struct zeroobj *obj) +{ + INIT_LIST_HEAD(&obj->page_list); + return; +} + +static void page_list_insert(struct zeroobj *obj, struct page *page) +{ + list_add(&page->list, &obj->page_list); + return; +} + +static struct page *page_list_first(struct zeroobj *obj) +{ + if (list_empty(&obj->page_list)) { + return NULL; + } + + return list_first_entry(&obj->page_list, struct page, list); +} + +/*********************************************************************** + * zeroobj + */ +static int alloc_zeroobj(void) +{ + int error; + struct zeroobj *obj = NULL; + void *virt = NULL; + uintptr_t phys; + struct page *page; + + dkprintf("alloc_zeroobj()\n"); + ihk_mc_spinlock_lock_noirq(&the_zeroobj_lock); + if (the_zeroobj) { + error = 0; + dkprintf("alloc_zeroobj():already. %d\n", error); + goto out; + } + + obj = kmalloc(sizeof(*obj), IHK_MC_AP_NOWAIT); + if (!obj) { + error = -ENOMEM; + ekprintf("alloc_zeroobj():kmalloc failed. %d\n", error); + goto out; + } + + memset(obj, 0, sizeof(*obj)); + obj->memobj.ops = &zeroobj_ops; + page_list_init(obj); + ihk_mc_spinlock_init(&obj->memobj.lock); + + virt = ihk_mc_alloc_pages(1, IHK_MC_AP_NOWAIT); /* XXX:NYI:large page */ + if (!virt) { + error = -ENOMEM; + ekprintf("alloc_zeroobj():alloc pages failed. %d\n", error); + goto out; + } + phys = virt_to_phys(virt); + page = phys_to_page(phys); + + if (page->mode != PM_NONE) { + fkprintf("alloc_zeroobj():" + "page %p %#lx %d %d %#lx\n", + page, page_to_phys(page), page->mode, + page->count, page->offset); + panic("alloc_zeroobj:dup alloc"); + } + + memset(virt, 0, PAGE_SIZE); + page->mode = PM_MAPPED; + page->offset = 0; + ihk_atomic_set(&page->count, 1); + page_list_insert(obj, page); + virt = NULL; + + error = 0; + the_zeroobj = obj; + obj = NULL; + +out: + ihk_mc_spinlock_unlock_noirq(&the_zeroobj_lock); + if (virt) { + ihk_mc_free_pages(virt, 1); + } + if (obj) { + kfree(obj); + } + dkprintf("alloc_zeroobj():%d %p\n", error, the_zeroobj); + return error; +} + +int zeroobj_create(struct memobj **objp) +{ + int error; + + dkprintf("zeroobj_create(%p)\n", objp); + if (!the_zeroobj) { + error = alloc_zeroobj(); + if (error) { + goto out; + } + } + + error = 0; + *objp = to_memobj(the_zeroobj); + +out: + dkprintf("zeroobj_create(%p):%d %p\n", objp, error, *objp); + return error; +} + +static int zeroobj_get_page(struct memobj *memobj, off_t off, int p2align, + uintptr_t *physp) +{ + int error; + struct zeroobj *obj = to_zeroobj(memobj); + struct page *page; + + dkprintf("zeroobj_get_page(%p,%#lx,%d,%p)\n", + memobj, off, p2align, physp); + if (off & ~PAGE_MASK) { + error = -EINVAL; + ekprintf("zeroobj_get_page(%p,%#lx,%d,%p):invalid argument. %d\n", + memobj, off, p2align, physp, error); + goto out; + } + if (p2align != PAGE_P2ALIGN) { /* XXX:NYI:large pages */ + error = -ENOMEM; + ekprintf("zeroobj_get_page(%p,%#lx,%d,%p):large page. %d\n", + memobj, off, p2align, physp, error); + goto out; + } + + page = page_list_first(obj); + if (!page) { + error = -ENOMEM; + ekprintf("zeroobj_get_page(%p,%#lx,%d,%p):page not found. %d\n", + memobj, off, p2align, physp, error); + goto out; + } + + ihk_atomic_inc(&page->count); + + error = 0; + *physp = page_to_phys(page); + +out: + dkprintf("zeroobj_get_page(%p,%#lx,%d,%p):%d\n", + memobj, off, p2align, physp, error); + return error; +}