From c3f3eb435e52c6d4620e0ed507073064f7aedd17 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Sat, 10 Feb 2024 23:25:24 +0100 Subject: [PATCH] implement munmap Also add basic errno.h --- core/syscall.c | 30 ++++++++++++--- core/syscall.h | 1 + core/uaddrspace.c | 17 +++++++-- drivers/zero.c | 1 + userspace/kernel/syscall.h | 5 ++- userspace/libc.c | 13 ++++++- userspace/libc.h | 1 + userspace/main_user.c | 78 ++++++++++++++++++++++++++++++++------ userspace/sys/mman.h | 2 + 9 files changed, 124 insertions(+), 24 deletions(-) diff --git a/core/syscall.c b/core/syscall.c index 0cbdf25..a760424 100644 --- a/core/syscall.c +++ b/core/syscall.c @@ -70,8 +70,12 @@ int syscallExecute(int syscallId, const struct cpu_state *userCtx) char path[256]; as = processGetAddrSpace(getCurrentThread()->process); - ret = syscallGet5args(userCtx, (unsigned int *)&uaddr_ptr, (unsigned int *)&size, (unsigned int *)&rights, - (unsigned int *)&flags, (unsigned int *)&userPath); + ret = syscallGet5args(userCtx, (unsigned int *)&uaddr_ptr, (unsigned int *)&size, + (unsigned int *)&rights, (unsigned int *)&flags, + (unsigned int *)&userPath); + + if (ret) + break; if (memcpyFromUser((vaddr_t)&uaddr, uaddr_ptr, sizeof(uaddr)) != sizeof(uaddr)) { ret = -EFAULT; @@ -81,17 +85,31 @@ int syscallExecute(int syscallId, const struct cpu_state *userCtx) strzcpyFromUser((vaddr_t *)path, (uaddr_t *)userPath, sizeof(path)); printf("Trying mmap for device %s at %lu\n", path, (vaddr_t)uaddr); - if(strcmp(path, "/dev/zero") == 0){ - ret = zeroMmap(as, &uaddr, size, rights,flags); + if (strcmp(path, "/dev/zero") == 0) { + ret = zeroMmap(as, &uaddr, size, rights, flags); } - if(!ret){ - if(memcpyToUser(uaddr_ptr, (vaddr_t)&uaddr, sizeof(uaddr)) != sizeof(uaddr)){ + if (!ret) { + if (memcpyToUser(uaddr_ptr, (vaddr_t)&uaddr, sizeof(uaddr)) != sizeof(uaddr)) { ret = -EFAULT; break; } } break; } + case SYSCALL_ID_MUNMAP: { + struct uAddrSpace *as; + uaddr_t uaddr; + size_t size; + + ret = syscallGet2args(userCtx, (unsigned int *)&uaddr, (unsigned int *)&size); + + if (ret) + break; + + as = processGetAddrSpace(getCurrentThread()->process); + ret = uAddrSpaceUnmap(as, uaddr, size); + break; + } default: printf("Unknon syscall id %d\n", syscallId); ret = -ENOENT; diff --git a/core/syscall.h b/core/syscall.h index 40d6a8e..444789b 100644 --- a/core/syscall.h +++ b/core/syscall.h @@ -10,6 +10,7 @@ #define SYSCALL_ID_TEST 5 #define SYSCALL_ID_BRK 6 #define SYSCALL_ID_MMAP 7 +#define SYSCALL_ID_MUNMAP 8 #ifdef __KERNEL__ int syscallExecute(int syscallId, const struct cpu_state *user_ctx); diff --git a/core/uaddrspace.c b/core/uaddrspace.c index babe64e..aefd404 100644 --- a/core/uaddrspace.c +++ b/core/uaddrspace.c @@ -1,5 +1,6 @@ #include "uaddrspace.h" #include "alloc.h" +#include "errno.h" #include "kernel.h" #include "klibc.h" #include "list.h" @@ -153,7 +154,9 @@ int uAddrSpaceUnmap(struct uAddrSpace *as, uaddr_t uaddr, size_t size) { if (uaddr < PAGING_BASE_USER_ADDRESS || uaddr > PAGING_TOP_USER_ADDRESS - size) return -EINVAL; - if (!ALIGN(uaddr, PAGE_SIZE) || size <= 0) + if (!IS_ALIGNED(uaddr, PAGE_SIZE) || size <= 0) + return -EINVAL; + if(!as) return -EINVAL; size = ALIGN(size, PAGE_SIZE); @@ -168,13 +171,20 @@ int uAddrSpaceUnmap(struct uAddrSpace *as, uaddr_t uaddr, size_t size) if (reg->addr >= uaddr && (reg->addr + reg->size <= uaddr + size)) { list_delete_named(as->listVirtualReg, reg, prevInAddrSpace, nextInAddrSpace); list_delete_named(reg->res->listVirtualReg, reg, prevInMappedRes, nextInMappedRes); + + if (reg->res->ops && reg->res->ops->unmap) + reg->res->ops->unmap(reg, uaddr, size); + if (reg->res->ops && reg->res->ops->close) reg->res->ops->close(reg); + if (reg == next)//singleton + next = NULL; + free(reg); // Unmaped space is inside and smaller than the VR // VR should be splitted - } else if (reg->addr > uaddr && (reg->addr + reg->size <= uaddr + size)) { + } else if (reg->addr > uaddr && (reg->addr + reg->size < uaddr + size)) { struct uAddrVirtualReg *new = (struct uAddrVirtualReg *)zalloc(sizeof(struct uAddrSpace)); if (!new) @@ -193,7 +203,7 @@ int uAddrSpaceUnmap(struct uAddrSpace *as, uaddr_t uaddr, size_t size) nextInMappedRes); if (reg->res->ops && reg->res->ops->unmap) reg->res->ops->unmap(reg, uaddr, size); - if (new->res->ops &&new->res->ops->open) + if (new->res->ops && new->res->ops->open) new->res->ops->open(new); break; // Only affect the beginning @@ -324,6 +334,7 @@ int uAddrSpaceMmap(struct uAddrSpace *as, uaddr_t *uaddr, size_t size, uint32_t return -EPERM; } + size = ALIGN(size, PAGE_SIZE); struct uAddrVirtualReg *reg = (struct uAddrVirtualReg *)malloc(sizeof(struct uAddrVirtualReg)); if (!reg) diff --git a/drivers/zero.c b/drivers/zero.c index a01bbe1..c416c8f 100644 --- a/drivers/zero.c +++ b/drivers/zero.c @@ -21,6 +21,7 @@ static int zeroClose(struct uAddrVirtualReg *vreg) ent->refCnt--; if (ent->refCnt == 0) { free(vreg->res->customData); + free(vreg->res); } return 0; } diff --git a/userspace/kernel/syscall.h b/userspace/kernel/syscall.h index 6ac00c4..444789b 100644 --- a/userspace/kernel/syscall.h +++ b/userspace/kernel/syscall.h @@ -1,6 +1,6 @@ #pragma once #ifdef __KERNEL__ -#include "cpu_context.h" +#include "cpu_context.h" #endif #define SYSCALL_ID_EXIT 1 @@ -8,8 +8,9 @@ #define SYSCALL_ID_PUTC 3 #define SYSCALL_ID_READ 4 #define SYSCALL_ID_TEST 5 -#define SYSCALL_ID_BRK 6 +#define SYSCALL_ID_BRK 6 #define SYSCALL_ID_MMAP 7 +#define SYSCALL_ID_MUNMAP 8 #ifdef __KERNEL__ int syscallExecute(int syscallId, const struct cpu_state *user_ctx); diff --git a/userspace/libc.c b/userspace/libc.c index 5269949..eec4ccc 100644 --- a/userspace/libc.c +++ b/userspace/libc.c @@ -1,7 +1,9 @@ #include "libc.h" +#include "errno.h" #include "list.h" #include "minmax.h" #include "swintr.h" +#include "sys/mman.h" #include "syscall.h" int errno = 0; @@ -732,5 +734,14 @@ void *mmap(void *addr, size_t len, int prot, int flags, char *path) { if(!ret) return addr; errno = ret; - return (void *)-1; + + return MAP_FAILED; +} + +int munmap(void *addr, size_t len) +{ + if (len == 0) + return -EINVAL; + + return syscall2(SYSCALL_ID_MUNMAP, (unsigned int)addr, len); } diff --git a/userspace/libc.h b/userspace/libc.h index 166e51c..378d023 100644 --- a/userspace/libc.h +++ b/userspace/libc.h @@ -37,6 +37,7 @@ int vsnprintf(char *str, size_t size, const char *format, va_list ap) __attribut int vprintf(const char *format, va_list ap) __attribute__ ((__format__ (printf, 1, 0))); int printf(const char *format, ...) __attribute__ ((__format__ (printf, 1, 2))); void *mmap(void *addr, size_t len, int prot, int flags, char *path); +int munmap(void *addr, size_t len); int asprintf(char **strp, const char *fmt, ...) __attribute__ ((__format__ (printf, 2, 3))); int vasprintf(char **strp, const char *fmt, va_list ap) __attribute__ ((__format__ (printf, 2, 0))); diff --git a/userspace/main_user.c b/userspace/main_user.c index b45750c..65ce7c7 100644 --- a/userspace/main_user.c +++ b/userspace/main_user.c @@ -1,5 +1,7 @@ +#include "errno.h" #include "libc.h" #include "stdarg.h" +#include "stddef.h" #include "sys/mman.h" #include "tiny.h" @@ -12,6 +14,7 @@ int func_help() printf(" alloc: test allocation\n"); printf(" tiny: a tiny C-like interpreter\n"); printf(" mmap: test mmap \n"); + printf(" munmap: test munmap \n"); return 0; } @@ -27,29 +30,29 @@ char *initialHeap = 0; int func_alloc() { if (initialHeap == 0) { - initialHeap = sbrk(0); + initialHeap = sbrk(0); } printf("Testing allocation\n"); int allocSize = 4096 * 2; char *currentHeap = sbrk(0); if (currentHeap - initialHeap < allocSize) { - brk(initialHeap + allocSize); + brk(initialHeap + allocSize); } int *allocatedData = (int *)initialHeap; for (unsigned int i = 0; i < allocSize / sizeof(int); i++) { - allocatedData[i] = i; + allocatedData[i] = i; } printf("Success\nTesting malloc\n"); uintptr_t heap = (uintptr_t)sbrk(0); for (int i = 0; i < 12; i++) { - void *ptr = malloc(1 << i); - printf("malloc size %d: 0x%p\n", (1 << i), ptr); - if (ptr == NULL) { - printf("Malloc failed\n"); - } - memset(ptr, 0, 1 << i); - free(ptr); + void *ptr = malloc(1 << i); + printf("malloc size %d: 0x%p\n", (1 << i), ptr); + if (ptr == NULL) { + printf("Malloc failed\n"); + } + memset(ptr, 0, 1 << i); + free(ptr); } uintptr_t newHeap = (uintptr_t)sbrk(0); printf("Malloc used %dB\n", newHeap - heap); @@ -57,17 +60,64 @@ int func_alloc() return 0; } -int func_mmap() { +struct mmapedArea { + void *addr; + size_t size; + struct mmapedArea *next; +}; +static struct mmapedArea *listMmap = NULL; + +int func_mmap() +{ + struct mmapedArea *area = (struct mmapedArea *)malloc(sizeof(struct mmapedArea)); + + if (area == NULL) { + printf("Fail to allocate area\n"); + return -1; + } char *path = "/dev/zero"; - void *mapAddr = mmap((void *)4096, 4096, PROT_READ | PROT_WRITE, 0, path); + void *mapAddr = mmap((void *)0, 4096, PROT_READ | PROT_WRITE, 0, path); + + if (mapAddr == MAP_FAILED) { + printf("mmap failed errno %d\n", errno); + return -1; + } + printf("Zero mmaped at %p\n", mapAddr); int data = *(int *)mapAddr; *(int *)mapAddr = data; + area->addr = mapAddr; + area->size = 4096; + area->next = listMmap; + listMmap = area; + return 0; } +int func_munmap() +{ + if (!listMmap) { + printf("Nothing to unmap... mmap first! \n"); + return -1; + } + + struct mmapedArea *area = listMmap; + int ret = munmap(area->addr, area->size); + + if (ret) { + printf("Fail to unmap area at 0x%p (size %d) error %d\n", area->addr, area->size, ret); + return ret; + } + + printf("unmap done\n"); + listMmap = listMmap->next; + free(area); + + return ret; +} + int main(int argc, char *argv[]) { (void)argc; @@ -102,6 +152,10 @@ int main(int argc, char *argv[]) func_mmap(); continue; } + if (strcmp(buf, "munmap") == 0) { + func_munmap(); + continue; + } } return 0; } diff --git a/userspace/sys/mman.h b/userspace/sys/mman.h index c9c46cc..40e0237 100644 --- a/userspace/sys/mman.h +++ b/userspace/sys/mman.h @@ -9,3 +9,5 @@ #define MAP_PRIVATE (1 << 1) #define MAP_FIXED (1 << 2) + +#define MAP_FAILED (void *)-1