From 6471ee9a2da977858c620096418a622c5a2763e7 Mon Sep 17 00:00:00 2001 From: Mathieu Maret Date: Tue, 9 Aug 2022 16:15:00 +0200 Subject: [PATCH] Implement brk syscall simple case --- core/elf.c | 10 +++- core/elf.h | 4 +- core/main.c | 2 +- core/process.c | 9 +++ core/process.h | 2 + core/syscall.c | 18 ++++++ core/syscall.h | 1 + core/uaddrspace.c | 119 +++++++++++++++++++++++++++++++++++++ core/uaddrspace.h | 14 +++++ userspace/kernel/syscall.h | 1 + userspace/libc.c | 4 ++ userspace/libc.h | 1 + userspace/main_user.c | 22 +++++++ 13 files changed, 204 insertions(+), 3 deletions(-) create mode 100644 core/uaddrspace.c create mode 100644 core/uaddrspace.h diff --git a/core/elf.c b/core/elf.c index 2098510..ace5818 100644 --- a/core/elf.c +++ b/core/elf.c @@ -3,6 +3,8 @@ #include "klibc.h" #include "mem.h" #include "paging.h" +#include "thread.h" +#include "types.h" /** * Make sure the program is in a valid ELF format, map it into memory, @@ -11,9 +13,10 @@ * @return 0 when the program is not a valid ELF */ -uaddr_t loadElfProg(const char *prog) +uaddr_t loadElfProg(const char *prog, struct process * proc) { int i; + uaddr_t lastUserAddr; /** * Typedefs, constants and structure definitions as given by the ELF @@ -176,7 +179,12 @@ uaddr_t loadElfProg(const char *prog) /* Copy segment into memory */ memcpy((void *)elf_phdrs[i].p_vaddr, (void *)(prog + elf_phdrs[i].p_offset), elf_phdrs[i].p_filesz); + if (lastUserAddr < uaddr) { + lastUserAddr = uaddr; + } } + processInitHeap(proc, lastUserAddr); + return elf_hdr->e_entry; } diff --git a/core/elf.h b/core/elf.h index efbeb58..808ce3a 100644 --- a/core/elf.h +++ b/core/elf.h @@ -1,4 +1,6 @@ #pragma once +#include "process.h" +#include "thread.h" #include "types.h" -uaddr_t loadElfProg(const char *prog); +uaddr_t loadElfProg(const char *prog, struct process *proc); diff --git a/core/main.c b/core/main.c index 90276f3..be781a1 100644 --- a/core/main.c +++ b/core/main.c @@ -86,7 +86,7 @@ void loadUserSpace() struct process *proc = processCreate("UserSpace"); threadChangeCurrentContext(processGetMMUContext(proc)); - uaddr_t prog = loadElfProg(buf + FILE_HEADER_SIZE); + uaddr_t prog = loadElfProg(buf + FILE_HEADER_SIZE, proc); if (prog == (uaddr_t)NULL) { free(buf); return; diff --git a/core/process.c b/core/process.c index 12232c7..34eaf91 100644 --- a/core/process.c +++ b/core/process.c @@ -4,6 +4,7 @@ #include "klibc.h" #include "list.h" #include "mmuContext.h" +#include "types.h" #include "uaddrspace.h" struct process { @@ -167,3 +168,11 @@ struct mmu_context *processGetMMUContext(struct process *proc) { return uAddrSpaceGetMMUContext(proc->addrSpace); } + +struct uAddrSpace *processGetAddrSpace(struct process *proc){ + return proc->addrSpace; +} + +int processInitHeap(struct process *proc, uaddr_t lastUserAddr){ + return uAddrSpaceSetHeap(proc->addrSpace, lastUserAddr, 0); +} diff --git a/core/process.h b/core/process.h index b6e11b9..64a92a7 100644 --- a/core/process.h +++ b/core/process.h @@ -15,3 +15,5 @@ int processSetName(struct process *proc, char *name); int processAddThread(struct process *proc, struct thread *th); int processRemoveThread(struct thread *th); struct mmu_context *processGetMMUContext(struct process *th); +struct uAddrSpace *processGetAddrSpace(struct process *proc); +int processInitHeap(struct process *proc, uaddr_t lastUserAddr); diff --git a/core/syscall.c b/core/syscall.c index e904867..1cff6cd 100644 --- a/core/syscall.c +++ b/core/syscall.c @@ -1,8 +1,11 @@ #include "syscall.h" #include "keyboard.h" #include "klibc.h" +#include "process.h" #include "stdarg.h" #include "thread.h" +#include "types.h" +#include "uaddrspace.h" int syscallExecute(int syscallId, const struct cpu_state *userCtx) { @@ -37,6 +40,21 @@ int syscallExecute(int syscallId, const struct cpu_state *userCtx) printf("Got 5args from userspace %d %d %d %d %d\n", arg1, arg2, arg3, arg4, arg5); break; } + case SYSCALL_ID_BRK:{ + + struct uAddrSpace *as; + uaddr_t newHeapTop; + + as = processGetAddrSpace(getCurrentThread()->process); + ret = syscallGet1arg(userCtx, (unsigned int *)&newHeapTop); + if (ret != 0) + break; + threadChangeCurrentContext(uAddrSpaceGetMMUContext(as)); + //TODO : what if *newHeapTop raise page fault? + ret = sysBrk(as, newHeapTop); + threadChangeCurrentContext(NULL); + break; + } default: printf("Unknon syscall id %d\n", syscallId); ret = -ENOENT; diff --git a/core/syscall.h b/core/syscall.h index 6d846de..dbf1858 100644 --- a/core/syscall.h +++ b/core/syscall.h @@ -8,6 +8,7 @@ #define SYSCALL_ID_PUTC 3 #define SYSCALL_ID_READ 4 #define SYSCALL_ID_TEST 5 +#define SYSCALL_ID_BRK 6 #ifdef __KERNEL__ int syscallExecute(int syscallId, const struct cpu_state *user_ctx); diff --git a/core/uaddrspace.c b/core/uaddrspace.c new file mode 100644 index 0000000..149f8ba --- /dev/null +++ b/core/uaddrspace.c @@ -0,0 +1,119 @@ +#include "uaddrspace.h" +#include "alloc.h" +#include "kernel.h" +#include "mem.h" +#include "mmuContext.h" +#include "process.h" +#include "stdarg.h" +#include "thread.h" +#include "types.h" +#include +#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 + + 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() +}; + +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) +{ + struct uAddrSpace *addr = (struct uAddrSpace *)malloc(sizeof(struct uAddrSpace)); + + if (addr == NULL) + return NULL; + + addr->ctx = mmuContextCreate(); + + if (addr->ctx == NULL) { + free(addr); + + return NULL; + } + + addr->process = proc; + + return addr; +} + +int uAddrSpaceDelete(struct uAddrSpace *addr) +{ + // TODO Work on Virtual Region + return mmuContextUnref(addr->ctx); +} + +struct mmu_context *uAddrSpaceGetMMUContext(struct uAddrSpace *addr) +{ + return addr->ctx; +} + +int uAddrSpaceSetHeap(struct uAddrSpace *as, uaddr_t addr, size_t size) +{ + as->heapStart = addr; + as->heapSize = size; + + return 0; +} + +uaddr_t sysBrk(struct uAddrSpace *as, uaddr_t newHeapTop) +{ + int incSize; + assert(as->heapStart); + if (!newHeapTop || newHeapTop < as->heapStart) + return as->heapStart + as->heapSize; + + newHeapTop = ALIGN(newHeapTop, PAGE_SIZE); + + if (newHeapTop == as->heapStart + as->heapSize) + return newHeapTop; + + incSize = ALIGN(newHeapTop - (as->heapStart + as->heapSize), PAGE_SIZE); + + if (incSize < 0){ + //FIXME + return as->heapStart + as->heapSize; + } + + //WIP do it manually + for (uaddr_t begin = ALIGN(as->heapStart + as->heapSize, PAGE_SIZE); begin < newHeapTop; begin += PAGE_SIZE) { + paddr_t ppage = allocPhyPage(1); + if (0 != pageMap(begin, ppage, + PAGING_MEM_USER | PAGING_MEM_WRITE | PAGING_MEM_READ)) + return (uaddr_t)NULL; + + unrefPhyPage(ppage); + } + + return 0; +} diff --git a/core/uaddrspace.h b/core/uaddrspace.h new file mode 100644 index 0000000..917aa02 --- /dev/null +++ b/core/uaddrspace.h @@ -0,0 +1,14 @@ +#pragma once +#include "mmuContext.h" +#include "process.h" +#include "types.h" +#include + +struct uAddrSpace; +struct uAddrVirtualReg; + +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); +uaddr_t sysBrk(struct uAddrSpace *as, uaddr_t newHeapTop); diff --git a/userspace/kernel/syscall.h b/userspace/kernel/syscall.h index 6d846de..dbf1858 100644 --- a/userspace/kernel/syscall.h +++ b/userspace/kernel/syscall.h @@ -8,6 +8,7 @@ #define SYSCALL_ID_PUTC 3 #define SYSCALL_ID_READ 4 #define SYSCALL_ID_TEST 5 +#define SYSCALL_ID_BRK 6 #ifdef __KERNEL__ int syscallExecute(int syscallId, const struct cpu_state *user_ctx); diff --git a/userspace/libc.c b/userspace/libc.c index 71d7e07..ed2bc2a 100644 --- a/userspace/libc.c +++ b/userspace/libc.c @@ -566,3 +566,7 @@ int readline(char *buf, int size) return i == (size-1); } +void *brk(void *addr) +{ + return (void *)syscall1(SYSCALL_ID_BRK, (unsigned int)addr); +} diff --git a/userspace/libc.h b/userspace/libc.h index f877897..0979557 100644 --- a/userspace/libc.h +++ b/userspace/libc.h @@ -45,3 +45,4 @@ int testSycall5(uint arg1, uint arg2, uint arg3, uint arg4, uint arg5); char readc(); char readcBlock(); int readline(char *buf, int size); +void *brk(void *addr); diff --git a/userspace/main_user.c b/userspace/main_user.c index 5dac99e..75f91e6 100644 --- a/userspace/main_user.c +++ b/userspace/main_user.c @@ -13,6 +13,7 @@ int func_help() printf(" suicide\n"); printf(" help\n"); printf(" syscall5\n"); + printf(" alloc\n"); return 0; } @@ -24,6 +25,23 @@ int func_suicide() return 0; } +void * initialHeap = 0; +int func_alloc(){ + + if(initialHeap == 0){ + initialHeap = brk(0); + } + void * currentHeap = brk(0); + if (currentHeap - initialHeap < 4096){ + brk(initialHeap + 4096); + } + int * allocatedData = (int *)initialHeap; + for(unsigned int i = 0 ; i < 4096/sizeof(int); i++){ + allocatedData[i] =i; + } + return 0; +} + int main(int argc, char *argv[]) { (void)argc; @@ -50,6 +68,10 @@ int main(int argc, char *argv[]) testSycall5(1, 2, 3, 4, 5); continue; } + if (strcmp(buf, "alloc") == 0) { + func_alloc(); + continue; + } } return 0; }