From 1e3be650f2a529f6dd296e72384950c43744288a Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Fri, 24 Mar 2023 00:12:23 +0100 Subject: [PATCH 01/22] Put back kernel sym in debug.gdb As gnu-debuglink does not seems to be working everwhere --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index bd25471..3068063 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ serialOut disk.img kernel -kernel.sym +kernel.debug userspace/user docs/*.html From 8af3ba07621d40fd1ca5c4bff02097275dc5aa7b Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Fri, 24 Mar 2023 23:43:09 +0100 Subject: [PATCH 02/22] mmap syscall declaration --- core/main.c | 1 + core/syscall.c | 19 +++++++++++++++++++ core/syscall.h | 1 + core/uaccess.c | 38 +++++++++++++++++++++++++++++++++++++- core/uaccess.h | 1 + disk.sfdisk | 1 - drivers/zero.h | 9 +++++++++ userspace/kernel/syscall.h | 1 + userspace/libc.c | 4 ++++ userspace/libc.h | 1 + userspace/main_user.c | 13 +++++++++++++ 11 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 drivers/zero.h diff --git a/core/main.c b/core/main.c index e52114b..ba1f9ef 100644 --- a/core/main.c +++ b/core/main.c @@ -28,6 +28,7 @@ #include "time.h" #include "types.h" #include "vga.h" +#include "zero.h" #define CHECK_FLAG(flags, bit) ((flags) & (1 << (bit))) diff --git a/core/syscall.c b/core/syscall.c index b836c67..8fac05a 100644 --- a/core/syscall.c +++ b/core/syscall.c @@ -5,6 +5,7 @@ #include "stdarg.h" #include "thread.h" #include "types.h" +#include "uaccess.h" #include "uaddrspace.h" int syscallExecute(int syscallId, const struct cpu_state *userCtx) @@ -55,6 +56,24 @@ int syscallExecute(int syscallId, const struct cpu_state *userCtx) threadChangeCurrentContext(NULL); break; } + case SYSCALL_ID_MMAP: { + struct uAddrSpace *as; + uaddr_t uaddr; + size_t size; + uint32_t rights; + uint32_t flags; + uaddr_t userPath; + + char path[256]; + + as = processGetAddrSpace(getCurrentThread()->process); + ret = syscallGet5args(userCtx, (unsigned int *)&uaddr, (unsigned int *)&size, (unsigned int *)&rights, + (unsigned int *)&flags, (unsigned int *)&userPath); + strzcpyFromUser((vaddr_t *)path, (uaddr_t *)userPath, sizeof(path)); + printf("Trying mmap for device %s\n", path); + (void)as; + break; + } default: printf("Unknon syscall id %d\n", syscallId); ret = -ENOENT; diff --git a/core/syscall.h b/core/syscall.h index 099e51a..6ac00c4 100644 --- a/core/syscall.h +++ b/core/syscall.h @@ -9,6 +9,7 @@ #define SYSCALL_ID_READ 4 #define SYSCALL_ID_TEST 5 #define SYSCALL_ID_BRK 6 +#define SYSCALL_ID_MMAP 7 #ifdef __KERNEL__ int syscallExecute(int syscallId, const struct cpu_state *user_ctx); diff --git a/core/uaccess.c b/core/uaccess.c index 852cc5e..023a591 100644 --- a/core/uaccess.c +++ b/core/uaccess.c @@ -1,10 +1,12 @@ +#include "uaccess.h" #include "assert.h" #include "errno.h" +#include "minmax.h" #include "mmuContext.h" #include "paging.h" #include "process.h" #include "thread.h" -#include "uaccess.h" +#include "types.h" static int bindtoUserContext() { @@ -52,3 +54,37 @@ int memcpyFromUser(vaddr_t to, uaddr_t from, size_t size) return memcpyUserMemNoCheck(to, from, size); } + +static int strzcpyFromUserNoCheck(char *to, char *from, size_t size) +{ + int ret; + + ret = bindtoUserContext(); + if (ret != 0) + return ret; + + for (unsigned int i = 0; i < size; i++) { + to[i] = from[i]; + if (from[i] == '\0') + break; + } + + if (size > 0) + to[size - 1] = '\0'; + + ret = unbindUserContext(); + if (ret != 0) + return ret; + + return size; +} + +int strzcpyFromUser(vaddr_t *to, uaddr_t *from, size_t size) +{ + if ((uint)from < PAGING_BASE_USER_ADDRESS) + return -EPERM; + if ((uint)from > PAGING_TOP_USER_ADDRESS - size) + return -EPERM; + + return strzcpyFromUserNoCheck((char *)to, (char *)from, size); +} diff --git a/core/uaccess.h b/core/uaccess.h index 465e268..bf97293 100644 --- a/core/uaccess.h +++ b/core/uaccess.h @@ -3,3 +3,4 @@ #include "stdarg.h" int memcpyFromUser(vaddr_t to, uaddr_t from, size_t size); +int strzcpyFromUser(vaddr_t *to, uaddr_t *from, size_t size); diff --git a/disk.sfdisk b/disk.sfdisk index 2004b3d..a1ecf61 100644 --- a/disk.sfdisk +++ b/disk.sfdisk @@ -2,7 +2,6 @@ label: dos label-id: 0x9ec19bcc device: disk.img unit: sectors -sector-size: 512 disk.img1 : start= 2048, size= 32768, type=6, bootable disk.img2 : start= 34816, size= 30720, type=83 diff --git a/drivers/zero.h b/drivers/zero.h new file mode 100644 index 0000000..83f4672 --- /dev/null +++ b/drivers/zero.h @@ -0,0 +1,9 @@ +#pragma once + + +#include "types.h" +#include +#include +int zeroSetup(); + +int zeroMmap(uaddr_t *uaddr, size_t size, uint32_t rights, uint32_t flags); diff --git a/userspace/kernel/syscall.h b/userspace/kernel/syscall.h index 099e51a..6ac00c4 100644 --- a/userspace/kernel/syscall.h +++ b/userspace/kernel/syscall.h @@ -9,6 +9,7 @@ #define SYSCALL_ID_READ 4 #define SYSCALL_ID_TEST 5 #define SYSCALL_ID_BRK 6 +#define SYSCALL_ID_MMAP 7 #ifdef __KERNEL__ int syscallExecute(int syscallId, const struct cpu_state *user_ctx); diff --git a/userspace/libc.c b/userspace/libc.c index 991b192..bbc1ff4 100644 --- a/userspace/libc.c +++ b/userspace/libc.c @@ -725,3 +725,7 @@ void *realloc(void *ptr, size_t size) return new_ptr; } +void *mmap(void *addr, size_t len, int prot, int flags, char *path){ + + return (void *)syscall5(SYSCALL_ID_MMAP, (unsigned int)addr, len, prot, flags, (unsigned int)path); +} diff --git a/userspace/libc.h b/userspace/libc.h index eb4c313..166e51c 100644 --- a/userspace/libc.h +++ b/userspace/libc.h @@ -36,6 +36,7 @@ int putc(const int c); int vsnprintf(char *str, size_t size, const char *format, va_list ap) __attribute__ ((__format__ (printf, 3, 0))); 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 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 420b3bc..3b7c1fb 100644 --- a/userspace/main_user.c +++ b/userspace/main_user.c @@ -55,6 +55,15 @@ int func_alloc() return 0; } +int func_mmap() +{ + + char *path ="/dev/zero"; + mmap(0, 4096, 0, 0, path); + + return 0; +} + int main(int argc, char *argv[]) { (void)argc; @@ -85,6 +94,10 @@ int main(int argc, char *argv[]) func_tiny(); continue; } + if (strcmp(buf, "mmap") == 0) { + func_mmap(); + continue; + } } return 0; } From b6fd550e7fcf1f56549c25371b8ed95868e08c76 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Mon, 1 May 2023 17:58:35 +0200 Subject: [PATCH 03/22] Add some documentation --- core/alloc.h | 6 ++++++ core/allocArea.c | 8 ++++++++ core/allocArea.h | 34 ++++++++++++++++++++++------------ core/mem.h | 26 +++++++++++++++++++++++++- core/uaddrspace.c | 4 +++- 5 files changed, 64 insertions(+), 14 deletions(-) diff --git a/core/alloc.h b/core/alloc.h index 174a325..bba2533 100644 --- a/core/alloc.h +++ b/core/alloc.h @@ -3,11 +3,17 @@ #include "stddef.h" #include "types.h" +/** Arbitrary size allocator **/ + /* * Initialize malloc system */ int allocSetup(size_t sizeOfArea, vaddr_t *areaAddr, vaddr_t *descAddr, vaddr_t *entryAddr); +/* + * Add Slice for some simple/commun size + */ + int allocPopulate(); /* * Allow malloc to allocate elements of this precise size. diff --git a/core/allocArea.c b/core/allocArea.c index 9fa4eee..d11a6cf 100644 --- a/core/allocArea.c +++ b/core/allocArea.c @@ -7,6 +7,14 @@ #include "mem.h" #include "stdarg.h" +struct memArea { + vaddr_t startAddr; + uint nbPages; + + struct memArea *next; + struct memArea *prev; +}; + static struct memArea *freeArea; static struct memArea *usedArea; diff --git a/core/allocArea.h b/core/allocArea.h index 4ceda6e..edb2135 100644 --- a/core/allocArea.h +++ b/core/allocArea.h @@ -9,19 +9,29 @@ #define AREA_PHY_MAP (1<<0) #define AREA_MEM_TOP PAGING_MIRROR_VADDR -struct memArea { - vaddr_t startAddr; - uint nbPages; - - struct memArea *next; - struct memArea *prev; -}; - +/** + * Initialize the Area subsystem + **/ void areaInit(vaddr_t firstMemUsed, vaddr_t lastUsed, vaddr_t stack_bottom, vaddr_t stack_top); + +/** + * Request a virtual memory area of @param nbPages + **/ vaddr_t areaAlloc(unsigned int nbPages, uint32_t flags); -// Remove an area from the free ones but do not add it into used ones. -// This area should be latter added woth areaAdd. -// Used by malloc to avoid recursivity issue -vaddr_t areaBook(unsigned int nbPages, uint32_t flags); + +/** + * Free a vietual area + **/ int areaFree(vaddr_t addr); + +/** + * Remove an area from the "free" ones but do not add it into used ones. + * This area should be latter added with areaAdd. + * Used by malloc to avoid recursivity issue + **/ +vaddr_t areaBook(unsigned int nbPages, uint32_t flags); + +/** + * Declare a virtual region to be managed by the subsytem + */ int areaAdd(vaddr_t begin, vaddr_t end, int isFree); diff --git a/core/mem.h b/core/mem.h index bead0d8..6a226fc 100644 --- a/core/mem.h +++ b/core/mem.h @@ -2,7 +2,8 @@ #include "stdint.h" #include "types.h" -/** Physical Page related function +/** + * Physical Page management */ #define PAGE_SHIFT 12U @@ -20,10 +21,33 @@ struct phyMemDesc { struct phyMemDesc *next, *prev; }; +/** + * Initi Physical Page management subsystem + **/ int memSetup(paddr_t upperMem, paddr_t * firstUsed, paddr_t *lastUsed); + +/** + * Declare a physical region to be managed by the physica page subsystem + **/ int memAddBank(paddr_t bottomMem, paddr_t topMem, int isFree); + +/** + * Request @params nbPage free physical pages + **/ paddr_t allocPhyPage(uint nbPage); + +/** + * Decrement the nb of user of a given physical page + **/ int unrefPhyPage(paddr_t addr); + +/** + * Increment the nb of user of a given physical page + **/ int refPhyPage(paddr_t addr); + +/** + * Return the number of physical allocated pages + **/ unsigned long getNbAllocatedPage(void); void memGetStat(uint *free, uint *used); diff --git a/core/uaddrspace.c b/core/uaddrspace.c index 6f4a4ee..2ee21e1 100644 --- a/core/uaddrspace.c +++ b/core/uaddrspace.c @@ -128,7 +128,9 @@ int uAddrSpaceCheckNAlloc(struct uAddrSpace *as, vaddr_t addr) struct uAddrVirtualReg *newReg; int right = PAGING_MEM_USER | PAGING_MEM_WRITE | PAGING_MEM_READ; - pr_devel("Checking 0x%lx inside 0x%lx and 0x%lx\n", addr, as->heapStart, as->heapStart +as->heapSize); + pr_devel("Checking 0x%lx inside 0x%lx and 0x%lx\n", addr, as->heapStart, + as->heapStart + as->heapSize); + if (addr < as->heapStart || addr >= as->heapStart + as->heapSize) { return -1; } From 44c5551655d4579dbf6fd449b35ff2d91213f97b Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Fri, 10 Nov 2023 09:01:55 +0100 Subject: [PATCH 04/22] Wip: zero mmap --- arch/x86/paging.h | 1 + core/main.c | 4 ++-- core/syscall.c | 5 +++++ core/uaddrspace.c | 39 +++++++++++++-------------------------- core/uaddrspace.h | 32 ++++++++++++++++++++++++++++++++ drivers/zero.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ drivers/zero.h | 4 +++- 7 files changed, 101 insertions(+), 29 deletions(-) create mode 100644 drivers/zero.c diff --git a/arch/x86/paging.h b/arch/x86/paging.h index 360d052..e18d1f0 100644 --- a/arch/x86/paging.h +++ b/arch/x86/paging.h @@ -17,6 +17,7 @@ #define PAGING_MEM_USER (1U << 0) #define PAGING_MEM_READ (1U << 1) #define PAGING_MEM_WRITE (1U << 2) +#define PAGING_MEM_EXEC (1U << 3) int pagingSetup(paddr_t lowerKernelAddr, paddr_t upperKernelAddr); diff --git a/core/main.c b/core/main.c index ba1f9ef..8bed568 100644 --- a/core/main.c +++ b/core/main.c @@ -84,7 +84,7 @@ void loadUserSpace() return; } - struct process *proc = processCreate("UserSpace"); + struct process *proc = processCreate("init"); threadChangeCurrentContext(processGetMMUContext(proc)); uaddr_t prog = loadElfProg(buf + FILE_HEADER_SIZE, proc); @@ -101,7 +101,7 @@ void loadUserSpace() PAGING_MEM_USER | PAGING_MEM_WRITE | PAGING_MEM_READ) == 0); unrefPhyPage(stackPhy); - threadCreateUser("UserProg", proc, prog, 0, 0, stackTop); + threadCreateUser("init", proc, prog, 0, 0, stackTop); processUnref(proc); threadChangeCurrentContext(NULL); diff --git a/core/syscall.c b/core/syscall.c index 8fac05a..5ebfc55 100644 --- a/core/syscall.c +++ b/core/syscall.c @@ -7,6 +7,8 @@ #include "types.h" #include "uaccess.h" #include "uaddrspace.h" +#include "zero.h" + int syscallExecute(int syscallId, const struct cpu_state *userCtx) { @@ -71,6 +73,9 @@ int syscallExecute(int syscallId, const struct cpu_state *userCtx) (unsigned int *)&flags, (unsigned int *)&userPath); strzcpyFromUser((vaddr_t *)path, (uaddr_t *)userPath, sizeof(path)); printf("Trying mmap for device %s\n", path); + if(strcmp(path, "/dev/zero") == 0){ + zeroMmap(as, &uaddr, size, rights,flags); + } (void)as; break; } diff --git a/core/uaddrspace.c b/core/uaddrspace.c index 2ee21e1..f621541 100644 --- a/core/uaddrspace.c +++ b/core/uaddrspace.c @@ -14,18 +14,6 @@ #include #include -struct uAddrVirtualReg { - uaddr_t addr; - size_t size; - int right; // PAGING_MEM_* - uint32_t offset; // in the mappedRessource - uint flags; - - struct mappedRessource *res; - struct uAddrVirtualReg *nextInAddrSpace, *prevInAddrSpace; - struct uAddrVirtualReg *nextInMappedRes, *prevInMappedRes; -}; - struct uAddrSpace { struct process *process; // The process that is represented by this AS struct mmu_context *ctx; // The corresponding MMU configuration @@ -33,22 +21,9 @@ struct uAddrSpace { struct uAddrVirtualReg *listVirtualReg; // List of Virtual Region used by this process uaddr_t heapStart; // Start of the Head - size_t heapSize; // Hep size -> modified by brk() + size_t heapSize; // Heap size -> modified by brk() }; -struct mappedRessourceOps { - int (*open)(struct uAddrVirtualReg *vreg); - int (*close)(struct uAddrVirtualReg *vreg); - int (*unmap)(struct uAddrVirtualReg *vregi, uaddr_t addr, size_t size); - int (*nopage)(struct uAddrVirtualReg *vregi, uaddr_t addr, - int right); // Called by the pageflt handler when the page is missing -}; - -struct mappedRessource { - int right; // PAGING_MEM_* - struct mappedRessourceOps *ops; - struct uAddrVirtualReg *listVirtualReg; -}; struct uAddrSpace *uAddrSpaceCreate(struct process *proc) { @@ -161,3 +136,15 @@ free_ppage: unrefPhyPage(ppage); return -1; } + +int uAddrSpaceMmap(struct uAddrSpace *as, uaddr_t *uaddr, size_t size, uint32_t rights, uint32_t flags, + struct mappedRessource *res) +{ + (void)as; + (void)uaddr; + (void)rights; + (void)size; + (void)flags; + (void)res; + return 0; +} diff --git a/core/uaddrspace.h b/core/uaddrspace.h index 37938de..8fa3e53 100644 --- a/core/uaddrspace.h +++ b/core/uaddrspace.h @@ -7,9 +7,41 @@ struct uAddrSpace; struct uAddrVirtualReg; +// TODO : move this struct to .c and add accessors +struct uAddrVirtualReg { + uaddr_t addr; + size_t size; + int right; // PAGING_MEM_* + uint32_t offset; // in the mappedRessource + uint flags; + + struct mappedRessource *res; + struct uAddrVirtualReg *nextInAddrSpace, *prevInAddrSpace; + struct uAddrVirtualReg *nextInMappedRes, *prevInMappedRes; +}; + +struct mappedRessourceOps { + int (*open)(struct uAddrVirtualReg *vreg); + int (*close)(struct uAddrVirtualReg *vreg); + int (*unmap)(struct uAddrVirtualReg *vreg, uaddr_t addr, size_t size); + int (*nopage)(struct uAddrVirtualReg *vreg, uaddr_t addr, + int right); // Called by the pageflt handler when the page is missing +}; + +struct mappedRessource { + int allowedRight; // PAGING_MEM_* + struct mappedRessourceOps *ops; + struct uAddrVirtualReg *listVirtualReg; + void *customData; +}; + + struct uAddrSpace * uAddrSpaceCreate(struct process *proc); int uAddrSpaceDelete(struct uAddrSpace *addr); struct mmu_context * uAddrSpaceGetMMUContext(struct uAddrSpace *addr); int uAddrSpaceSetHeap(struct uAddrSpace *as, uaddr_t addr, size_t size); int uAddrSpaceCheckNAlloc(struct uAddrSpace *as, vaddr_t addr); uaddr_t sysBrk(struct uAddrSpace *as, uaddr_t newHeapTop); + +int uAddrSpaceMmap(struct uAddrSpace *as, uaddr_t *uaddr, size_t size, uint32_t rights, uint32_t flags, + struct mappedRessource *res); diff --git a/drivers/zero.c b/drivers/zero.c new file mode 100644 index 0000000..0580a65 --- /dev/null +++ b/drivers/zero.c @@ -0,0 +1,45 @@ +#include "zero.h" +#include "alloc.h" + +struct zeroMappedEntry { + int refCnt; +}; + +static int zeroOpen(struct uAddrVirtualReg *vreg) +{ + (void)vreg; + return 0; +} +static int zeroClose(struct uAddrVirtualReg *vreg) +{ + (void)vreg; + return 0; +} +static int zeroNoPage(struct uAddrVirtualReg *vreg, uaddr_t addr, int right) +{ + (void)vreg; + (void)addr; + (void)right; + return 0; +} + +static struct mappedRessourceOps zeroOps = { + .open = zeroOpen, + .close = zeroClose, + .unmap = NULL, + .nopage = zeroNoPage, +}; + +int zeroMmap(struct uAddrSpace *as, uaddr_t *uaddr, size_t size, uint32_t rights, uint32_t flags) +{ + struct mappedRessource *res = (struct mappedRessource *)zalloc(sizeof(struct mappedRessource)); + struct zeroMappedEntry *cust = (struct zeroMappedEntry *)zalloc(sizeof(struct zeroMappedEntry)); + + res->allowedRight = PAGING_MEM_READ | PAGING_MEM_WRITE | PAGING_MEM_EXEC | PAGING_MEM_USER; + res->ops = &zeroOps; + res->customData = cust; + + uAddrSpaceMmap(as, uaddr, size, rights, flags, res); + + return 0; +} diff --git a/drivers/zero.h b/drivers/zero.h index 83f4672..3fbd6fd 100644 --- a/drivers/zero.h +++ b/drivers/zero.h @@ -2,8 +2,10 @@ #include "types.h" +#include "uaddrspace.h" + #include #include int zeroSetup(); -int zeroMmap(uaddr_t *uaddr, size_t size, uint32_t rights, uint32_t flags); +int zeroMmap(struct uAddrSpace *as, uaddr_t *uaddr, size_t size, uint32_t rights, uint32_t flags); From 1bb81fd57e4b21d6e255f9d044dc8d6d7dbbc598 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Wed, 31 Jan 2024 23:47:42 +0100 Subject: [PATCH 05/22] Typo fix --- core/allocArea.h | 2 +- core/uaccess.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/core/allocArea.h b/core/allocArea.h index edb2135..e65ab48 100644 --- a/core/allocArea.h +++ b/core/allocArea.h @@ -20,7 +20,7 @@ void areaInit(vaddr_t firstMemUsed, vaddr_t lastUsed, vaddr_t stack_bottom, vadd vaddr_t areaAlloc(unsigned int nbPages, uint32_t flags); /** - * Free a vietual area + * Free a virtual area **/ int areaFree(vaddr_t addr); diff --git a/core/uaccess.h b/core/uaccess.h index bf97293..53b619f 100644 --- a/core/uaccess.h +++ b/core/uaccess.h @@ -1,5 +1,6 @@ #pragma once #include "types.h" +#include "stddef.h" #include "stdarg.h" int memcpyFromUser(vaddr_t to, uaddr_t from, size_t size); From b9d741060fb3e4cf424e63214c1fb6764756c874 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Wed, 31 Jan 2024 23:49:07 +0100 Subject: [PATCH 06/22] Add the ability to map/unmap a ressource --- core/syscall.c | 3 +- core/uaddrspace.c | 242 ++++++++++++++++++++++++++++++++++++++++-- core/uaddrspace.h | 8 +- drivers/zero.c | 32 ++++-- userspace/main_user.c | 1 + 5 files changed, 264 insertions(+), 22 deletions(-) diff --git a/core/syscall.c b/core/syscall.c index 5ebfc55..aeb8184 100644 --- a/core/syscall.c +++ b/core/syscall.c @@ -74,8 +74,9 @@ int syscallExecute(int syscallId, const struct cpu_state *userCtx) strzcpyFromUser((vaddr_t *)path, (uaddr_t *)userPath, sizeof(path)); printf("Trying mmap for device %s\n", path); if(strcmp(path, "/dev/zero") == 0){ - zeroMmap(as, &uaddr, size, rights,flags); + ret = zeroMmap(as, &uaddr, size, rights,flags); } + printf("ret %d\n", ret); (void)as; break; } diff --git a/core/uaddrspace.c b/core/uaddrspace.c index f621541..4eebbd6 100644 --- a/core/uaddrspace.c +++ b/core/uaddrspace.c @@ -24,6 +24,82 @@ struct uAddrSpace { size_t heapSize; // Heap size -> modified by brk() }; +static int hasOverlap(uaddr_t addr1, size_t size1, uaddr_t addr2, size_t size2) +{ + return max(addr1, addr2) < min(addr1 + size1, addr2 + size2); +} + +static struct uAddrVirtualReg *findVirtualRegionFromAddr(struct uAddrSpace *as, uaddr_t uaddr, size_t size) +{ + struct uAddrVirtualReg *reg; + int idx; + + list_foreach_named(as->listVirtualReg, reg, idx, prevInAddrSpace, nextInAddrSpace) + { + if (hasOverlap(reg->addr, reg->size, uaddr, size)) + return reg; + } + return NULL; +} + +static struct uAddrVirtualReg *findVirtualRegionBeforeAddr(struct uAddrSpace *as, + uaddr_t uaddr) +{ + struct uAddrVirtualReg *reg, *prev = NULL; + int idx; + + list_foreach_named(as->listVirtualReg, reg, idx, prevInAddrSpace, nextInAddrSpace) + { + if (uaddr > reg->addr) + break; + prev = reg; + } + return prev; +} + +/** + * Find a address not alreay used in the virtual region of the AS. + * This address will be equals to uaddr if possible and could take size + */ +static uaddr_t findFreeAddrInVirtualRegion(struct uAddrSpace *as, uaddr_t uaddr, size_t size) +{ + struct uAddrVirtualReg *reg, *regNext, *regOver; + + if (uaddr < PAGING_BASE_USER_ADDRESS) + uaddr = PAGING_BASE_USER_ADDRESS; + if(uaddr > PAGING_TOP_USER_ADDRESS - size) + uaddr = PAGING_TOP_USER_ADDRESS - size; + + reg = findVirtualRegionFromAddr(as, uaddr, size); + + if (!reg) + return uaddr; + + int idx; + + regOver = reg; + + //Find last region that overlap + list_foreach_named(reg->nextInAddrSpace, regNext, idx, prevInAddrSpace, nextInAddrSpace){ + if(!hasOverlap(uaddr, size, regNext->addr, regNext->size)) + break; + regOver = regNext; + } + + uaddr = regOver->addr + regOver->size; + list_foreach_named(regOver->nextInAddrSpace, regNext, idx, prevInAddrSpace, + nextInAddrSpace) + { + if (!hasOverlap(uaddr, size, regNext->addr, regNext->size) && + uaddr <= (PAGING_TOP_USER_ADDRESS - size)) { + return uaddr; + } + if (reg == regNext) // Already checked region + break; + uaddr = regNext->addr + regNext->size; + } + return (uaddr_t)NULL; +} struct uAddrSpace *uAddrSpaceCreate(struct process *proc) { @@ -61,6 +137,91 @@ int uAddrSpaceDelete(struct uAddrSpace *addr) return mmuContextUnref(addr->ctx); } +/** + * Find the associated uAddrVirtualReg associated to the unmap space and free them; + */ +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) + return -EINVAL; + + size = ALIGN(size, PAGE_SIZE); + struct uAddrVirtualReg *reg = as->listVirtualReg; + struct uAddrVirtualReg *lastReg = reg ? reg->prevInAddrSpace : NULL; + + while (reg != NULL) { + if (reg->addr > uaddr + size) + break; + struct uAddrVirtualReg *next = reg->nextInAddrSpace; + // The Virtual Region is completly inside the unmaped space + 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->close) + reg->res->ops->close(reg); + + 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)) { + struct uAddrVirtualReg *new = + (struct uAddrVirtualReg *)zalloc(sizeof(struct uAddrSpace)); + if (!new) + return -ENOMEM; + + new->addr = uaddr + size; + new->size = reg->addr + reg->size - (uaddr + size); + new->right = reg->right; + new->offset = uaddr + size - reg->addr; + + reg->size = uaddr - reg->addr; + + list_insert_after_named(as->listVirtualReg, reg, new, prevInAddrSpace, + nextInAddrSpace); + list_insert_after_named(reg->res->listVirtualReg, reg, new, prevInMappedRes, + nextInMappedRes); + if (reg->res->ops && reg->res->ops->unmap) + reg->res->ops->unmap(reg, uaddr, size); + if (new->res->ops &&new->res->ops->open) + new->res->ops->open(new); + break; + // Only affect the beginning + } else if (uaddr <= reg->addr && uaddr + size > reg->addr) { + size_t offset = uaddr + size - reg->addr; + reg->size -= offset; + reg->offset += offset; + reg->addr += offset; + if (reg->res->ops && reg->res->ops->unmap) + reg->res->ops->unmap(reg, uaddr, size); + break; + // Only affect the end + } else if (uaddr > reg->addr && uaddr + size > reg->addr + reg->size) { + size_t unmapSize = reg->addr + reg->size - uaddr; + reg->size = uaddr - reg->addr; + + if (reg->res->ops && reg->res->ops->unmap) + reg->res->ops->unmap(reg, uaddr, unmapSize); + } + reg = next; + if (reg == lastReg) + break; + } + + int needMMUSetup = as->ctx != getCurrentThread()->squattedContext; + + if (needMMUSetup) + threadChangeCurrentContext(as->ctx); + for (vaddr_t addr = uaddr; addr < uaddr + size; addr += PAGE_SIZE) { + pageUnmap(addr); + } + if (needMMUSetup) + threadChangeCurrentContext(NULL); + + return 0; +} + struct mmu_context *uAddrSpaceGetMMUContext(struct uAddrSpace *addr) { return addr->ctx; @@ -137,14 +298,77 @@ free_ppage: return -1; } -int uAddrSpaceMmap(struct uAddrSpace *as, uaddr_t *uaddr, size_t size, uint32_t rights, uint32_t flags, - struct mappedRessource *res) +int uAddrSpaceMmap(struct uAddrSpace *as, uaddr_t *uaddr, size_t size, uint32_t rights, + uint32_t flags, struct mappedRessource *res, uint32_t offset ) { - (void)as; - (void)uaddr; - (void)rights; - (void)size; - (void)flags; - (void)res; - return 0; + int ret = 0; + uaddr_t hint_uaddr = *uaddr; + + if (res == NULL || res->ops == NULL || res->ops->nopage == NULL) + return -ENOENT; + if (!IS_ALIGNED(hint_uaddr, PAGE_SIZE) || size <= 0) + return -EINVAL; + if (flags & UA_MAP_SHARED) { + if (((rights & PAGING_MEM_READ) && !(res->allowedRight & PAGING_MEM_READ)) || + ((rights & PAGING_MEM_WRITE) && !(res->allowedRight & PAGING_MEM_WRITE)) || + ((rights & PAGING_MEM_EXEC) && !(res->allowedRight & PAGING_MEM_EXEC))) + return -EPERM; + } + + struct uAddrVirtualReg *reg = + (struct uAddrVirtualReg *)malloc(sizeof(struct uAddrVirtualReg)); + if (!reg) + return -ENOMEM; + + if (flags & UA_MAP_FIXED) { + if (hint_uaddr < PAGING_BASE_USER_ADDRESS || + hint_uaddr > PAGING_TOP_USER_ADDRESS - size) { + ret = -EINVAL; + goto free_reg; + } + ret = uAddrSpaceUnmap(as, hint_uaddr, size); + if (ret) + goto free_reg; + + } else { + hint_uaddr = findFreeAddrInVirtualRegion(as, hint_uaddr, size); + if (!hint_uaddr) { + ret = -ENOMEM; + goto free_reg; + } + } + + reg->addr = hint_uaddr; + reg->size = size; + reg->right = rights; + reg->res = res; + reg->offset = offset; + // TODO merge it with prev/next one + + // keep the AddrSpace list sorted + struct uAddrVirtualReg *prev = findVirtualRegionBeforeAddr(as, hint_uaddr); + if (prev) + list_insert_after_named(as->listVirtualReg, prev, reg, prevInAddrSpace, + nextInAddrSpace); + else + list_add_tail_named(as->listVirtualReg, reg, prevInAddrSpace, nextInAddrSpace); + + list_add_tail_named(reg->res->listVirtualReg, reg, prevInMappedRes, nextInMappedRes); + if (res->onResMapped) { + int cbret = res->onResMapped(reg); + if (cbret) { + pr_devel("Call back failed on ressource mmaped\n"); + ret = uAddrSpaceUnmap(as, reg->addr, reg->size); + } + } + + if (res->ops->open) + res->ops->open(reg); + + *uaddr = hint_uaddr; + + return ret; +free_reg: + free(reg); + return ret; } diff --git a/core/uaddrspace.h b/core/uaddrspace.h index 8fa3e53..77f49e6 100644 --- a/core/uaddrspace.h +++ b/core/uaddrspace.h @@ -7,6 +7,8 @@ struct uAddrSpace; struct uAddrVirtualReg; +#define UA_MAP_SHARED (1 << 0) +#define UA_MAP_FIXED (1 << 1) // TODO : move this struct to .c and add accessors struct uAddrVirtualReg { uaddr_t addr; @@ -33,6 +35,7 @@ struct mappedRessource { struct mappedRessourceOps *ops; struct uAddrVirtualReg *listVirtualReg; void *customData; + int (*onResMapped)(struct uAddrVirtualReg *reg); // Callabck for when the ressourced get mapped }; @@ -43,5 +46,6 @@ int uAddrSpaceSetHeap(struct uAddrSpace *as, uaddr_t addr, size_t size); int uAddrSpaceCheckNAlloc(struct uAddrSpace *as, vaddr_t addr); uaddr_t sysBrk(struct uAddrSpace *as, uaddr_t newHeapTop); -int uAddrSpaceMmap(struct uAddrSpace *as, uaddr_t *uaddr, size_t size, uint32_t rights, uint32_t flags, - struct mappedRessource *res); +int uAddrSpaceMmap(struct uAddrSpace *as, uaddr_t *uaddr, size_t size, uint32_t rights, + uint32_t flags, struct mappedRessource *res, uint32_t offset); +int uAddrSpaceUnmap(struct uAddrSpace *as, uaddr_t uaddr, size_t size); diff --git a/drivers/zero.c b/drivers/zero.c index 0580a65..9610658 100644 --- a/drivers/zero.c +++ b/drivers/zero.c @@ -1,5 +1,6 @@ -#include "zero.h" #include "alloc.h" +#include "klibc.h" +#include "zero.h" struct zeroMappedEntry { int refCnt; @@ -30,16 +31,27 @@ static struct mappedRessourceOps zeroOps = { .nopage = zeroNoPage, }; -int zeroMmap(struct uAddrSpace *as, uaddr_t *uaddr, size_t size, uint32_t rights, uint32_t flags) +int zeroOnMapped(struct uAddrVirtualReg *vreg) { - struct mappedRessource *res = (struct mappedRessource *)zalloc(sizeof(struct mappedRessource)); - struct zeroMappedEntry *cust = (struct zeroMappedEntry *)zalloc(sizeof(struct zeroMappedEntry)); + (void)vreg; - res->allowedRight = PAGING_MEM_READ | PAGING_MEM_WRITE | PAGING_MEM_EXEC | PAGING_MEM_USER; - res->ops = &zeroOps; - res->customData = cust; + printf("ZERO MAPPED !!\n"); - uAddrSpaceMmap(as, uaddr, size, rights, flags, res); - - return 0; + return 0; +} + +int zeroMmap(struct uAddrSpace *as, uaddr_t *uaddr, size_t size, uint32_t rights, + uint32_t flags) +{ + struct mappedRessource *res = + (struct mappedRessource *)zalloc(sizeof(struct mappedRessource)); + struct zeroMappedEntry *cust = + (struct zeroMappedEntry *)zalloc(sizeof(struct zeroMappedEntry)); + + res->allowedRight = PAGING_MEM_READ | PAGING_MEM_WRITE | PAGING_MEM_EXEC | PAGING_MEM_USER; + res->ops = &zeroOps; + res->customData = cust; + res->onResMapped = zeroOnMapped; + + return uAddrSpaceMmap(as, uaddr, size, rights, flags, res, 0); } diff --git a/userspace/main_user.c b/userspace/main_user.c index 3b7c1fb..cfdc52c 100644 --- a/userspace/main_user.c +++ b/userspace/main_user.c @@ -10,6 +10,7 @@ int func_help() printf(" syscall5: a syscall with parameters over the stack \n"); printf(" alloc: test allocation\n"); printf(" tiny: a tiny C-like interpreter\n"); + printf(" mmap: test mmap \n"); return 0; } From d9051ea59c7253b2bb081fbede09017c59f7926b Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Sun, 4 Feb 2024 21:42:29 +0100 Subject: [PATCH 07/22] Propagate page fault to ressource handler Fix mmap arguments handling --- arch/x86/exception.c | 28 +++++++++++++++++++--------- arch/x86/exception_wrappers.S | 2 +- core/syscall.c | 20 ++++++++++++++++---- core/uaccess.c | 11 +++++++++++ core/uaccess.h | 1 + core/uaddrspace.c | 29 +++++++++++++++++++++++++++-- core/uaddrspace.h | 3 ++- userspace/libc.c | 9 +++++++-- 8 files changed, 84 insertions(+), 19 deletions(-) diff --git a/arch/x86/exception.c b/arch/x86/exception.c index 68e5cee..ec8c0ef 100644 --- a/arch/x86/exception.c +++ b/arch/x86/exception.c @@ -45,9 +45,9 @@ int exceptionSetRoutine(int exception, exception_handler handler) void print_handler(struct cpu_state *frame, ulong intr) { - int intNbInt = intr; - VGAPrintf(RED, BLACK, 0, VGA_HEIGHT - 1, "EXCEPTION %d", intNbInt); + VGAPrintf(RED, BLACK, 0, VGA_HEIGHT - 1, "EXCEPTION %lu", intr); printf("Exception %lu at 0x%p\n", intr, (void *)cpu_context_get_PC(frame)); + asm("hlt"); } @@ -55,17 +55,26 @@ void pagefault_handler(struct cpu_state *frame, ulong intr) { struct thread *current = getCurrentThread(); - struct uAddrSpace *as = processGetAddrSpace(current->process); - vaddr_t faultAddr = cpu_context_get_EX_faulting_vaddr(frame); + assert(frame == current->cpuState); + if (cpu_context_is_in_user_mode(current->cpuState)) { + struct uAddrSpace *as = processGetAddrSpace(current->process); + vaddr_t faultAddr = cpu_context_get_EX_faulting_vaddr(frame); - if(!uAddrSpaceCheckNAlloc(as, faultAddr)) - return; + if (!uAddrSpaceHeapCheckNAlloc(as, faultAddr)) + return; - printf("page fault while in thread [%s] at 0x%p when trying to access 0x%p err_code 0x%x\n", current->name, - (void *)cpu_context_get_PC(frame), (void *)faultAddr, cpu_context_get_EX_err(frame)); - if (cpu_context_is_in_user_mode(frame)) { + // PAGE_FAULT is a interrupt with an error code (see exception_wrapper.S) + uint32_t error_code = cpu_context_get_EX_err(frame); + + if (!uAddrSpaceSolvePageFault(as, faultAddr, error_code & 0x2)) + return; + + printf( + "page fault while in thread [%s] at 0x%p when trying to access 0x%p err_code 0x%x\n", + current->name, (void *)cpu_context_get_PC(frame), (void *)faultAddr, error_code); printf("Killing User Thread\n"); threadExit(); + return; } VGAPrintf(RED, BLACK, 0, VGA_HEIGHT - 1, "PAGE FAULT %d", intr); (void)intr; @@ -79,5 +88,6 @@ int exceptionSetup() exceptionSetRoutine(i, print_handler); } exceptionSetRoutine(EXCEPTION_PAGE_FAULT, pagefault_handler); + return 0; } diff --git a/arch/x86/exception_wrappers.S b/arch/x86/exception_wrappers.S index 52f6a09..c490e13 100644 --- a/arch/x86/exception_wrappers.S +++ b/arch/x86/exception_wrappers.S @@ -165,7 +165,7 @@ iret .endm -/*List of exception w or w/o err codehttps://wiki.osdev.org/Exceptions*/ +/* List of exception w or w/o err code https://wiki.osdev.org/Exceptions */ .irp exception_id, 8, 10, 11, 12, 13, 14, 17, 30 exception_mac_with_errcode exception_id .endr diff --git a/core/syscall.c b/core/syscall.c index aeb8184..0cbdf25 100644 --- a/core/syscall.c +++ b/core/syscall.c @@ -61,6 +61,7 @@ int syscallExecute(int syscallId, const struct cpu_state *userCtx) case SYSCALL_ID_MMAP: { struct uAddrSpace *as; uaddr_t uaddr; + uaddr_t uaddr_ptr; size_t size; uint32_t rights; uint32_t flags; @@ -69,15 +70,26 @@ int syscallExecute(int syscallId, const struct cpu_state *userCtx) char path[256]; as = processGetAddrSpace(getCurrentThread()->process); - ret = syscallGet5args(userCtx, (unsigned int *)&uaddr, (unsigned int *)&size, (unsigned int *)&rights, + ret = syscallGet5args(userCtx, (unsigned int *)&uaddr_ptr, (unsigned int *)&size, (unsigned int *)&rights, (unsigned int *)&flags, (unsigned int *)&userPath); + + if (memcpyFromUser((vaddr_t)&uaddr, uaddr_ptr, sizeof(uaddr)) != sizeof(uaddr)) { + ret = -EFAULT; + break; + } + strzcpyFromUser((vaddr_t *)path, (uaddr_t *)userPath, sizeof(path)); - printf("Trying mmap for device %s\n", 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); } - printf("ret %d\n", ret); - (void)as; + if(!ret){ + if(memcpyToUser(uaddr_ptr, (vaddr_t)&uaddr, sizeof(uaddr)) != sizeof(uaddr)){ + ret = -EFAULT; + break; + } + } break; } default: diff --git a/core/uaccess.c b/core/uaccess.c index 023a591..1548faf 100644 --- a/core/uaccess.c +++ b/core/uaccess.c @@ -44,6 +44,17 @@ static int memcpyUserMemNoCheck(vaddr_t dest, vaddr_t src, size_t size) return size; } +int memcpyToUser(uaddr_t to, vaddr_t from, size_t size) +{ + + if ((uint)to < PAGING_BASE_USER_ADDRESS) + return -EPERM; + if ((uint)to > PAGING_TOP_USER_ADDRESS - size) + return -EPERM; + + return memcpyUserMemNoCheck(to, from, size); +} + int memcpyFromUser(vaddr_t to, uaddr_t from, size_t size) { diff --git a/core/uaccess.h b/core/uaccess.h index 53b619f..03d7685 100644 --- a/core/uaccess.h +++ b/core/uaccess.h @@ -4,4 +4,5 @@ #include "stdarg.h" int memcpyFromUser(vaddr_t to, uaddr_t from, size_t size); +int memcpyToUser(uaddr_t to, vaddr_t from, size_t size); int strzcpyFromUser(vaddr_t *to, uaddr_t *from, size_t size); diff --git a/core/uaddrspace.c b/core/uaddrspace.c index 4eebbd6..80f5ead 100644 --- a/core/uaddrspace.c +++ b/core/uaddrspace.c @@ -250,7 +250,7 @@ uaddr_t sysBrk(struct uAddrSpace *as, uaddr_t newHeapTop) incSize = ALIGN(newHeapTop - (as->heapStart + as->heapSize), PAGE_SIZE); if (incSize < 0){ - //TODO how to free allocated page by uAddrSpaceCheckNAlloc + //TODO how to free allocated page by uAddrSpaceHeapCheckNAlloc return as->heapStart + as->heapSize; } @@ -259,7 +259,7 @@ uaddr_t sysBrk(struct uAddrSpace *as, uaddr_t newHeapTop) return as->heapStart + as->heapSize; } -int uAddrSpaceCheckNAlloc(struct uAddrSpace *as, vaddr_t addr) +int uAddrSpaceHeapCheckNAlloc(struct uAddrSpace *as, vaddr_t addr) { struct uAddrVirtualReg *newReg; int right = PAGING_MEM_USER | PAGING_MEM_WRITE | PAGING_MEM_READ; @@ -372,3 +372,28 @@ free_reg: free(reg); return ret; } + +/** + * Check if @param faultAddr could be managed by the uAddrVirtualReg from @param as + **/ +int uAddrSpaceSolvePageFault(struct uAddrSpace *as, vaddr_t faultAddr, int isWriteAccess) +{ + struct uAddrVirtualReg *reg; + int rights = PAGING_MEM_READ; + + reg = findVirtualRegionFromAddr(as, faultAddr, 1); + + if (reg == NULL) + return -EFAULT; + + if (isWriteAccess && !(reg->right & PAGING_MEM_WRITE)) + return -EFAULT; + + if (isWriteAccess) + rights |= PAGING_MEM_WRITE; + + if (reg->res->ops->nopage(reg, faultAddr, rights)) + return -EFAULT; + + return 0; +} diff --git a/core/uaddrspace.h b/core/uaddrspace.h index 77f49e6..fa34190 100644 --- a/core/uaddrspace.h +++ b/core/uaddrspace.h @@ -43,9 +43,10 @@ struct uAddrSpace * uAddrSpaceCreate(struct process *proc); int uAddrSpaceDelete(struct uAddrSpace *addr); struct mmu_context * uAddrSpaceGetMMUContext(struct uAddrSpace *addr); int uAddrSpaceSetHeap(struct uAddrSpace *as, uaddr_t addr, size_t size); -int uAddrSpaceCheckNAlloc(struct uAddrSpace *as, vaddr_t addr); +int uAddrSpaceHeapCheckNAlloc(struct uAddrSpace *as, vaddr_t addr); uaddr_t sysBrk(struct uAddrSpace *as, uaddr_t newHeapTop); int uAddrSpaceMmap(struct uAddrSpace *as, uaddr_t *uaddr, size_t size, uint32_t rights, uint32_t flags, struct mappedRessource *res, uint32_t offset); int uAddrSpaceUnmap(struct uAddrSpace *as, uaddr_t uaddr, size_t size); +int uAddrSpaceSolvePageFault(struct uAddrSpace *as, vaddr_t faultAddr, int isWriteAccess); diff --git a/userspace/libc.c b/userspace/libc.c index bbc1ff4..5269949 100644 --- a/userspace/libc.c +++ b/userspace/libc.c @@ -4,6 +4,7 @@ #include "swintr.h" #include "syscall.h" +int errno = 0; int memcmp(const void *aptr, const void *bptr, size_t size) { const unsigned char *a = (const unsigned char *)aptr; @@ -725,7 +726,11 @@ void *realloc(void *ptr, size_t size) return new_ptr; } -void *mmap(void *addr, size_t len, int prot, int flags, char *path){ +void *mmap(void *addr, size_t len, int prot, int flags, char *path) { - return (void *)syscall5(SYSCALL_ID_MMAP, (unsigned int)addr, len, prot, flags, (unsigned int)path); + int ret = syscall5(SYSCALL_ID_MMAP, (unsigned int)&addr, len, prot, flags, (unsigned int)path); + if(!ret) + return addr; + errno = ret; + return (void *)-1; } From 205d174c8ab4254fedd07eb2b5474940982bb974 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Mon, 5 Feb 2024 23:44:59 +0100 Subject: [PATCH 08/22] pagefault_handler print error code before killing thread --- arch/x86/exception.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/x86/exception.c b/arch/x86/exception.c index ec8c0ef..a12a211 100644 --- a/arch/x86/exception.c +++ b/arch/x86/exception.c @@ -65,13 +65,15 @@ void pagefault_handler(struct cpu_state *frame, ulong intr) // PAGE_FAULT is a interrupt with an error code (see exception_wrapper.S) uint32_t error_code = cpu_context_get_EX_err(frame); - - if (!uAddrSpaceSolvePageFault(as, faultAddr, error_code & 0x2)) + int ret = uAddrSpaceSolvePageFault(as, faultAddr, error_code & 0x2); + if (!ret){ return; + } printf( - "page fault while in thread [%s] at 0x%p when trying to access 0x%p err_code 0x%x\n", - current->name, (void *)cpu_context_get_PC(frame), (void *)faultAddr, error_code); + "page fault while in thread [%s] at 0x%p when trying to access 0x%p err_code 0x%x ressource ret %d\n", + current->name, (void *)cpu_context_get_PC(frame), (void *)faultAddr, error_code, + ret); printf("Killing User Thread\n"); threadExit(); return; From a4873a7d30ace9bb9867b5b894ce40e6362ca924 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Mon, 5 Feb 2024 23:46:17 +0100 Subject: [PATCH 09/22] Implement freeing ressource on uAS destroy --- core/uaddrspace.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/core/uaddrspace.c b/core/uaddrspace.c index 80f5ead..e6bb34f 100644 --- a/core/uaddrspace.c +++ b/core/uaddrspace.c @@ -127,12 +127,21 @@ int uAddrSpaceDelete(struct uAddrSpace *addr) struct uAddrVirtualReg *reg; list_collapse_named(addr->listVirtualReg, reg, nextInAddrSpace, prevInAddrSpace) { - // TODO Implement me with real ressources - assertmsg(reg->res == NULL, "Unsupported mapper ressource"); - // This is memory allocated for the heap just unmap it to free it - pr_devel("Freeing heap 0x%lx for process %s\n", reg->addr, processGetName(addr->process)); - pageUnmap(reg->addr); - free(reg); + if (reg->res == NULL) { + // This is memory allocated for the heap just unmap it to free it + pr_devel("Freeing heap 0x%lx for process %s\n", reg->addr, + processGetName(addr->process)); + pageUnmap(reg->addr); + free(reg); + } else { + if(reg->res->ops){ + if(reg->res->ops->unmap) + reg->res->ops->unmap(reg, reg->addr, reg->size); + if(reg->res->ops->close) + reg->res->ops->close(reg); + } + free(reg); + } } return mmuContextUnref(addr->ctx); } @@ -387,7 +396,7 @@ int uAddrSpaceSolvePageFault(struct uAddrSpace *as, vaddr_t faultAddr, int isWri return -EFAULT; if (isWriteAccess && !(reg->right & PAGING_MEM_WRITE)) - return -EFAULT; + return -EACCES; if (isWriteAccess) rights |= PAGING_MEM_WRITE; From 9fa9bd0411163c324f4da6d244a09d2f6fad438d Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Mon, 5 Feb 2024 23:46:57 +0100 Subject: [PATCH 10/22] userspace: add PROT flag for mmap --- userspace/libc.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/userspace/libc.h b/userspace/libc.h index 166e51c..9ef9596 100644 --- a/userspace/libc.h +++ b/userspace/libc.h @@ -36,6 +36,10 @@ int putc(const int c); int vsnprintf(char *str, size_t size, const char *format, va_list ap) __attribute__ ((__format__ (printf, 3, 0))); int vprintf(const char *format, va_list ap) __attribute__ ((__format__ (printf, 1, 0))); int printf(const char *format, ...) __attribute__ ((__format__ (printf, 1, 2))); +/* To keep in sync with PAGING_MEM_* */ +#define PROT_EXEC (1<<3) +#define PROT_READ (1<<1) +#define PROT_WRITE (1<<2) void *mmap(void *addr, size_t len, int prot, int flags, char *path); int asprintf(char **strp, const char *fmt, ...) __attribute__ ((__format__ (printf, 2, 3))); From 5a2042e57717b456c02a96b369146624f56d25cc Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Wed, 7 Feb 2024 23:14:42 +0100 Subject: [PATCH 11/22] Fix MMU context on ressource checking --- arch/x86/exception.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/arch/x86/exception.c b/arch/x86/exception.c index a12a211..512f8c5 100644 --- a/arch/x86/exception.c +++ b/arch/x86/exception.c @@ -57,18 +57,25 @@ void pagefault_handler(struct cpu_state *frame, ulong intr) struct thread *current = getCurrentThread(); assert(frame == current->cpuState); if (cpu_context_is_in_user_mode(current->cpuState)) { + struct uAddrSpace *as = processGetAddrSpace(current->process); vaddr_t faultAddr = cpu_context_get_EX_faulting_vaddr(frame); + int needMMUSetup = + (uAddrSpaceGetMMUContext(as) != getCurrentThread()->squattedContext); + + if (needMMUSetup) { + threadChangeCurrentContext(uAddrSpaceGetMMUContext(as)); + } if (!uAddrSpaceHeapCheckNAlloc(as, faultAddr)) - return; + goto release_context; // PAGE_FAULT is a interrupt with an error code (see exception_wrapper.S) uint32_t error_code = cpu_context_get_EX_err(frame); - int ret = uAddrSpaceSolvePageFault(as, faultAddr, error_code & 0x2); - if (!ret){ - return; - } + int ret = uAddrSpaceSolvePageFault(as, faultAddr, error_code & 0x2); + + if (!ret) + goto release_context; printf( "page fault while in thread [%s] at 0x%p when trying to access 0x%p err_code 0x%x ressource ret %d\n", @@ -76,10 +83,15 @@ void pagefault_handler(struct cpu_state *frame, ulong intr) ret); printf("Killing User Thread\n"); threadExit(); + + release_context: + if (needMMUSetup) + threadChangeCurrentContext(NULL); + return; } + VGAPrintf(RED, BLACK, 0, VGA_HEIGHT - 1, "PAGE FAULT %d", intr); - (void)intr; for (;;) continue; } From f7518351151d878095dadc936a54b46ccec911e4 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Wed, 7 Feb 2024 23:15:30 +0100 Subject: [PATCH 12/22] Improve debug message --- core/uaddrspace.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/uaddrspace.c b/core/uaddrspace.c index e6bb34f..4278c47 100644 --- a/core/uaddrspace.c +++ b/core/uaddrspace.c @@ -273,7 +273,7 @@ int uAddrSpaceHeapCheckNAlloc(struct uAddrSpace *as, vaddr_t addr) struct uAddrVirtualReg *newReg; int right = PAGING_MEM_USER | PAGING_MEM_WRITE | PAGING_MEM_READ; - pr_devel("Checking 0x%lx inside 0x%lx and 0x%lx\n", addr, as->heapStart, + pr_devel("Heap check: 0x%lx inside 0x%lx and 0x%lx\n", addr, as->heapStart, as->heapStart + as->heapSize); if (addr < as->heapStart || addr >= as->heapStart + as->heapSize) { @@ -395,6 +395,8 @@ int uAddrSpaceSolvePageFault(struct uAddrSpace *as, vaddr_t faultAddr, int isWri if (reg == NULL) return -EFAULT; + pr_devel("Virtual Region for pageflt found\n"); + if (isWriteAccess && !(reg->right & PAGING_MEM_WRITE)) return -EACCES; From 62a1c1cefbab4f26ef20e4aefcd110e5710d035d Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Wed, 7 Feb 2024 23:15:56 +0100 Subject: [PATCH 13/22] zero: finish implementation --- drivers/zero.c | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/drivers/zero.c b/drivers/zero.c index 9610658..60235a6 100644 --- a/drivers/zero.c +++ b/drivers/zero.c @@ -1,27 +1,41 @@ -#include "alloc.h" -#include "klibc.h" #include "zero.h" +#include "alloc.h" +#include "kernel.h" +#include "klibc.h" + struct zeroMappedEntry { - int refCnt; + int refCnt; }; static int zeroOpen(struct uAddrVirtualReg *vreg) { - (void)vreg; - return 0; + struct zeroMappedEntry *ent = (struct zeroMappedEntry *)vreg->res->customData; + ent->refCnt++; + return 0; } + static int zeroClose(struct uAddrVirtualReg *vreg) { - (void)vreg; - return 0; + struct zeroMappedEntry *ent = (struct zeroMappedEntry *)vreg->res->customData; + ent->refCnt--; + return 0; } + static int zeroNoPage(struct uAddrVirtualReg *vreg, uaddr_t addr, int right) { - (void)vreg; - (void)addr; - (void)right; - return 0; + (void)vreg; + + int ret = 0; + paddr_t ppage = allocPhyPage(1); + ret = pageMap(ALIGN_DOWN(addr, PAGE_SIZE), ppage, right | PAGING_MEM_USER) ; + + unrefPhyPage(ppage); + if (ret) { + return ret; + } + memset((void *)ALIGN_DOWN(addr, PAGE_SIZE), 0, PAGE_SIZE); + return ret; } static struct mappedRessourceOps zeroOps = { From ccfafe4a04e454b9952766c2f670b19cdcad765a Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Wed, 7 Feb 2024 23:17:55 +0100 Subject: [PATCH 14/22] userspace: mmap test read and write --- userspace/main_user.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/userspace/main_user.c b/userspace/main_user.c index cfdc52c..9502c75 100644 --- a/userspace/main_user.c +++ b/userspace/main_user.c @@ -56,11 +56,13 @@ int func_alloc() return 0; } -int func_mmap() -{ +int func_mmap() { - char *path ="/dev/zero"; - mmap(0, 4096, 0, 0, path); + char *path = "/dev/zero"; + void *mapAddr = mmap((void *)4096, 4096, PROT_READ | PROT_WRITE, 0, path); + printf("Zero mmaped at %p\n", mapAddr); + int data = *(int *)mapAddr; + *(int *)mapAddr = data; return 0; } From bf7008fc98d019d6fad011a5bd3429d9fa541c62 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Wed, 7 Feb 2024 23:23:35 +0100 Subject: [PATCH 15/22] Fix write rights on pageflt --- core/uaddrspace.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/uaddrspace.c b/core/uaddrspace.c index 4278c47..0ae45f5 100644 --- a/core/uaddrspace.c +++ b/core/uaddrspace.c @@ -388,7 +388,7 @@ free_reg: int uAddrSpaceSolvePageFault(struct uAddrSpace *as, vaddr_t faultAddr, int isWriteAccess) { struct uAddrVirtualReg *reg; - int rights = PAGING_MEM_READ; + int rights = PAGING_MEM_READ | PAGING_MEM_USER; reg = findVirtualRegionFromAddr(as, faultAddr, 1); @@ -400,7 +400,7 @@ int uAddrSpaceSolvePageFault(struct uAddrSpace *as, vaddr_t faultAddr, int isWri if (isWriteAccess && !(reg->right & PAGING_MEM_WRITE)) return -EACCES; - if (isWriteAccess) + if (isWriteAccess || (reg->right & PAGING_MEM_WRITE)) rights |= PAGING_MEM_WRITE; if (reg->res->ops->nopage(reg, faultAddr, rights)) From cca78b269dd889233268bf47080c3fd2a655c25c Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Thu, 8 Feb 2024 00:07:12 +0100 Subject: [PATCH 16/22] init: use zero driver for stack alloc --- core/elf.c | 4 +--- core/main.c | 37 +++++++++++++++++++------------------ 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/core/elf.c b/core/elf.c index f87572d..7837143 100644 --- a/core/elf.c +++ b/core/elf.c @@ -13,13 +13,11 @@ * @return 0 when the program is not a valid ELF */ -uaddr_t loadElfProg(const char *prog, struct process * proc) +uaddr_t loadElfProg(const char *prog, struct process *proc) { int i; uaddr_t lastUserAddr = 0; - - /* e_ident value */ #define ELFMAG0 0x7f #define ELFMAG1 'E' diff --git a/core/main.c b/core/main.c index 8bed568..2db8bec 100644 --- a/core/main.c +++ b/core/main.c @@ -84,27 +84,28 @@ void loadUserSpace() return; } - struct process *proc = processCreate("init"); + { + struct process *proc = processCreate("init"); + struct uAddrSpace *as = processGetAddrSpace(proc); - threadChangeCurrentContext(processGetMMUContext(proc)); - uaddr_t prog = loadElfProg(buf + FILE_HEADER_SIZE, proc); - if (prog == (uaddr_t)NULL) { - free(buf); - return; + threadChangeCurrentContext(processGetMMUContext(proc)); + uaddr_t prog = loadElfProg(buf + FILE_HEADER_SIZE, proc); + if (prog == (uaddr_t)NULL) { + free(buf); + return; + } + + // Alloc user stack + size_t stackSize = PAGE_SIZE * 2; + uaddr_t stack = PAGING_TOP_USER_ADDRESS - stackSize + 1; + zeroMmap(as, &stack, stackSize, PAGING_MEM_USER | PAGING_MEM_WRITE | PAGING_MEM_READ, + 0); + + threadCreateUser("init", proc, prog, 0, 0, stack + stackSize - 4); + processUnref(proc); + threadChangeCurrentContext(NULL); } - // Alloc user stack - uaddr_t stackTop = 0xfffffffc; - uaddr_t stackBottom = ALIGN_DOWN(stackTop, PAGE_SIZE); - paddr_t stackPhy = allocPhyPage(1); - assert(pageMap(stackBottom, stackPhy, - PAGING_MEM_USER | PAGING_MEM_WRITE | PAGING_MEM_READ) == 0); - unrefPhyPage(stackPhy); - - threadCreateUser("init", proc, prog, 0, 0, stackTop); - processUnref(proc); - threadChangeCurrentContext(NULL); - free(buf); } From 18957812132ee76ddd864cf96fdf06c019e3d4e2 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Thu, 8 Feb 2024 20:54:29 +0100 Subject: [PATCH 17/22] Assign a mapped ressource to init prog --- core/elf.c | 7 +++++++ drivers/zero.c | 10 +++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/core/elf.c b/core/elf.c index 7837143..8f4ccc1 100644 --- a/core/elf.c +++ b/core/elf.c @@ -5,6 +5,7 @@ #include "paging.h" #include "thread.h" #include "types.h" +#include "zero.h" /** * Make sure the program is in a valid ELF format, map it into memory, @@ -17,6 +18,7 @@ uaddr_t loadElfProg(const char *prog, struct process *proc) { int i; uaddr_t lastUserAddr = 0; + struct uAddrSpace *as = processGetAddrSpace(proc); /* e_ident value */ #define ELFMAG0 0x7f @@ -136,6 +138,11 @@ uaddr_t loadElfProg(const char *prog, struct process *proc) unrefPhyPage(ppage); } + // Hack: Even if already allocated mark the adresse space as managed by a ressource + // So this address space is not used by another ressource. + uaddr = elf_phdrs[i].p_vaddr; + zeroMmap(as, &uaddr, elf_phdrs[i].p_memsz, PAGING_MEM_USER | PAGING_MEM_WRITE | PAGING_MEM_READ, 0); + /* Copy segment into memory */ memcpy((void *)elf_phdrs[i].p_vaddr, (void *)(prog + elf_phdrs[i].p_offset), elf_phdrs[i].p_filesz); diff --git a/drivers/zero.c b/drivers/zero.c index 60235a6..9799517 100644 --- a/drivers/zero.c +++ b/drivers/zero.c @@ -57,6 +57,7 @@ int zeroOnMapped(struct uAddrVirtualReg *vreg) int zeroMmap(struct uAddrSpace *as, uaddr_t *uaddr, size_t size, uint32_t rights, uint32_t flags) { + int ret = 0; struct mappedRessource *res = (struct mappedRessource *)zalloc(sizeof(struct mappedRessource)); struct zeroMappedEntry *cust = @@ -67,5 +68,12 @@ int zeroMmap(struct uAddrSpace *as, uaddr_t *uaddr, size_t size, uint32_t rights res->customData = cust; res->onResMapped = zeroOnMapped; - return uAddrSpaceMmap(as, uaddr, size, rights, flags, res, 0); + ret = uAddrSpaceMmap(as, uaddr, size, rights, flags, res, 0); + + if (ret) { + free(res); + free(cust); + } + + return ret; } From b8c4c782de9c92e91b8586c9e52919e831cd766f Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Thu, 8 Feb 2024 20:54:53 +0100 Subject: [PATCH 18/22] Fix findVirtualRegionBeforeAddr --- core/uaddrspace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/uaddrspace.c b/core/uaddrspace.c index 0ae45f5..babe64e 100644 --- a/core/uaddrspace.c +++ b/core/uaddrspace.c @@ -50,7 +50,7 @@ static struct uAddrVirtualReg *findVirtualRegionBeforeAddr(struct uAddrSpace *as list_foreach_named(as->listVirtualReg, reg, idx, prevInAddrSpace, nextInAddrSpace) { - if (uaddr > reg->addr) + if (uaddr < reg->addr) break; prev = reg; } From b352eab7986874e8e2e69f161a835746e6b97a57 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Thu, 8 Feb 2024 20:55:50 +0100 Subject: [PATCH 19/22] gdb: print_list can take the next element name in param --- custom_gdb_extension.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/custom_gdb_extension.py b/custom_gdb_extension.py index dd405b2..6c0bfd3 100644 --- a/custom_gdb_extension.py +++ b/custom_gdb_extension.py @@ -184,18 +184,19 @@ class ListDumpCmd(gdb.Command): "list_dump", gdb.COMMAND_USER ) - def _print_list(self, val): + def _print_list(self, val, next_name): """Walk through the linked list. - We will simply follow the 'next' pointers until we encounter the HEAD again """ idx = 0 head = val thread_ptr = val result = "" + while thread_ptr != 0 and (idx == 0 or thread_ptr != head): - result += gdb.execute('p *({}){}'.format(str(thread_ptr.type),thread_ptr), to_string=True) - thread_ptr = thread_ptr["next"] + result += gdb.execute('p *({}){}'.format(str(thread_ptr.type), + thread_ptr), to_string=True) + thread_ptr = thread_ptr[next_name] idx += 1 result = ("Found a Linked List with %d items:" % idx) + "\n" + result return result @@ -209,17 +210,21 @@ class ListDumpCmd(gdb.Command): # We can pass args here and use Python CLI utilities like argparse # to do argument parsing print("Args Passed: %s" % args) - if args: - ptr_val = gdb.parse_and_eval(args) - else: - ptr_val = gdb.parse_and_eval("currentThread") + thread_name = "currentThread" + next_name = "next" + if(args): + args_arr = args.split() + thread_name = args_arr[0] + if(len(args_arr) >= 2): + next_name = args_arr[1] + ptr_val = gdb.parse_and_eval(thread_name) try: - ptr_val["next"] + ptr_val[next_name] except: - print("Expected pointer argument with a next field") + print("Expected pointer argument with a %s field" % next_name) return - print(self._print_list(ptr_val)) + print(self._print_list(ptr_val, next_name)) register_pretty_printer(None, CustomPrettyPrinterLocator(), replace=True) From 88b9c3160b15b27419ef85cb54e14247fb71975f Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Sat, 10 Feb 2024 21:26:01 +0100 Subject: [PATCH 20/22] Improve headers and add sys/mman.h --- core/syscall.h | 4 ++-- core/uaddrspace.h | 9 +++++---- userspace/libc.h | 4 ---- userspace/main_user.c | 1 + userspace/sys/mman.h | 11 +++++++++++ 5 files changed, 19 insertions(+), 10 deletions(-) create mode 100644 userspace/sys/mman.h diff --git a/core/syscall.h b/core/syscall.h index 6ac00c4..40d6a8e 100644 --- a/core/syscall.h +++ b/core/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,7 +8,7 @@ #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 #ifdef __KERNEL__ diff --git a/core/uaddrspace.h b/core/uaddrspace.h index fa34190..9cf8cac 100644 --- a/core/uaddrspace.h +++ b/core/uaddrspace.h @@ -8,7 +8,9 @@ struct uAddrSpace; struct uAddrVirtualReg; #define UA_MAP_SHARED (1 << 0) -#define UA_MAP_FIXED (1 << 1) +#define UA_MAP_PRIVATE (1 << 1) +#define UA_MAP_FIXED (1 << 2) + // TODO : move this struct to .c and add accessors struct uAddrVirtualReg { uaddr_t addr; @@ -38,10 +40,9 @@ struct mappedRessource { int (*onResMapped)(struct uAddrVirtualReg *reg); // Callabck for when the ressourced get mapped }; - -struct uAddrSpace * uAddrSpaceCreate(struct process *proc); +struct uAddrSpace *uAddrSpaceCreate(struct process *proc); int uAddrSpaceDelete(struct uAddrSpace *addr); -struct mmu_context * uAddrSpaceGetMMUContext(struct uAddrSpace *addr); +struct mmu_context *uAddrSpaceGetMMUContext(struct uAddrSpace *addr); int uAddrSpaceSetHeap(struct uAddrSpace *as, uaddr_t addr, size_t size); int uAddrSpaceHeapCheckNAlloc(struct uAddrSpace *as, vaddr_t addr); uaddr_t sysBrk(struct uAddrSpace *as, uaddr_t newHeapTop); diff --git a/userspace/libc.h b/userspace/libc.h index 9ef9596..166e51c 100644 --- a/userspace/libc.h +++ b/userspace/libc.h @@ -36,10 +36,6 @@ int putc(const int c); int vsnprintf(char *str, size_t size, const char *format, va_list ap) __attribute__ ((__format__ (printf, 3, 0))); int vprintf(const char *format, va_list ap) __attribute__ ((__format__ (printf, 1, 0))); int printf(const char *format, ...) __attribute__ ((__format__ (printf, 1, 2))); -/* To keep in sync with PAGING_MEM_* */ -#define PROT_EXEC (1<<3) -#define PROT_READ (1<<1) -#define PROT_WRITE (1<<2) void *mmap(void *addr, size_t len, int prot, int flags, char *path); int asprintf(char **strp, const char *fmt, ...) __attribute__ ((__format__ (printf, 2, 3))); diff --git a/userspace/main_user.c b/userspace/main_user.c index 9502c75..b45750c 100644 --- a/userspace/main_user.c +++ b/userspace/main_user.c @@ -1,5 +1,6 @@ #include "libc.h" #include "stdarg.h" +#include "sys/mman.h" #include "tiny.h" int func_help() diff --git a/userspace/sys/mman.h b/userspace/sys/mman.h new file mode 100644 index 0000000..c9c46cc --- /dev/null +++ b/userspace/sys/mman.h @@ -0,0 +1,11 @@ +#pragma once + +/* To keep in sync with PAGING_MEM_* */ +#define PROT_EXEC (1<<3) +#define PROT_READ (1<<1) +#define PROT_WRITE (1<<2) + +#define MAP_SHARED (1 << 0) +#define MAP_PRIVATE (1 << 1) +#define MAP_FIXED (1 << 2) + From 3339f8b05955ad01eb3f31c2f7b9aa56a57cfc0c Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Sat, 10 Feb 2024 22:49:24 +0100 Subject: [PATCH 21/22] Fix customData free --- drivers/zero.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/zero.c b/drivers/zero.c index 9799517..a01bbe1 100644 --- a/drivers/zero.c +++ b/drivers/zero.c @@ -19,6 +19,9 @@ static int zeroClose(struct uAddrVirtualReg *vreg) { struct zeroMappedEntry *ent = (struct zeroMappedEntry *)vreg->res->customData; ent->refCnt--; + if (ent->refCnt == 0) { + free(vreg->res->customData); + } return 0; } From c3f3eb435e52c6d4620e0ed507073064f7aedd17 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Sat, 10 Feb 2024 23:25:24 +0100 Subject: [PATCH 22/22] 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