Merge pull request 'mmap' (#8) from mmap into master

Reviewed-on: #8
This commit is contained in:
mathieu 2024-02-11 15:29:57 +01:00
commit 607fcc7121
25 changed files with 801 additions and 110 deletions

2
.gitignore vendored
View File

@ -1,6 +1,6 @@
serialOut serialOut
disk.img disk.img
kernel kernel
kernel.sym kernel.debug
userspace/user userspace/user
docs/*.html docs/*.html

View File

@ -45,9 +45,9 @@ int exceptionSetRoutine(int exception, exception_handler handler)
void print_handler(struct cpu_state *frame, ulong intr) void print_handler(struct cpu_state *frame, ulong intr)
{ {
int intNbInt = intr; VGAPrintf(RED, BLACK, 0, VGA_HEIGHT - 1, "EXCEPTION %lu", intr);
VGAPrintf(RED, BLACK, 0, VGA_HEIGHT - 1, "EXCEPTION %d", intNbInt);
printf("Exception %lu at 0x%p\n", intr, (void *)cpu_context_get_PC(frame)); printf("Exception %lu at 0x%p\n", intr, (void *)cpu_context_get_PC(frame));
asm("hlt"); asm("hlt");
} }
@ -55,20 +55,43 @@ void pagefault_handler(struct cpu_state *frame, ulong intr)
{ {
struct thread *current = getCurrentThread(); struct thread *current = getCurrentThread();
assert(frame == current->cpuState);
if (cpu_context_is_in_user_mode(current->cpuState)) {
struct uAddrSpace *as = processGetAddrSpace(current->process); struct uAddrSpace *as = processGetAddrSpace(current->process);
vaddr_t faultAddr = cpu_context_get_EX_faulting_vaddr(frame); vaddr_t faultAddr = cpu_context_get_EX_faulting_vaddr(frame);
int needMMUSetup =
(uAddrSpaceGetMMUContext(as) != getCurrentThread()->squattedContext);
if(!uAddrSpaceCheckNAlloc(as, faultAddr)) if (needMMUSetup) {
return; threadChangeCurrentContext(uAddrSpaceGetMMUContext(as));
}
printf("page fault while in thread [%s] at 0x%p when trying to access 0x%p err_code 0x%x\n", current->name, if (!uAddrSpaceHeapCheckNAlloc(as, faultAddr))
(void *)cpu_context_get_PC(frame), (void *)faultAddr, cpu_context_get_EX_err(frame)); goto release_context;
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);
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",
current->name, (void *)cpu_context_get_PC(frame), (void *)faultAddr, error_code,
ret);
printf("Killing User Thread\n"); printf("Killing User Thread\n");
threadExit(); threadExit();
release_context:
if (needMMUSetup)
threadChangeCurrentContext(NULL);
return;
} }
VGAPrintf(RED, BLACK, 0, VGA_HEIGHT - 1, "PAGE FAULT %d", intr); VGAPrintf(RED, BLACK, 0, VGA_HEIGHT - 1, "PAGE FAULT %d", intr);
(void)intr;
for (;;) for (;;)
continue; continue;
} }
@ -79,5 +102,6 @@ int exceptionSetup()
exceptionSetRoutine(i, print_handler); exceptionSetRoutine(i, print_handler);
} }
exceptionSetRoutine(EXCEPTION_PAGE_FAULT, pagefault_handler); exceptionSetRoutine(EXCEPTION_PAGE_FAULT, pagefault_handler);
return 0; return 0;
} }

View File

@ -17,6 +17,7 @@
#define PAGING_MEM_USER (1U << 0) #define PAGING_MEM_USER (1U << 0)
#define PAGING_MEM_READ (1U << 1) #define PAGING_MEM_READ (1U << 1)
#define PAGING_MEM_WRITE (1U << 2) #define PAGING_MEM_WRITE (1U << 2)
#define PAGING_MEM_EXEC (1U << 3)
int pagingSetup(paddr_t lowerKernelAddr, paddr_t upperKernelAddr); int pagingSetup(paddr_t lowerKernelAddr, paddr_t upperKernelAddr);

View File

@ -3,11 +3,17 @@
#include "stddef.h" #include "stddef.h"
#include "types.h" #include "types.h"
/** Arbitrary size allocator **/
/* /*
* Initialize malloc system * Initialize malloc system
*/ */
int allocSetup(size_t sizeOfArea, vaddr_t *areaAddr, vaddr_t *descAddr, vaddr_t *entryAddr); int allocSetup(size_t sizeOfArea, vaddr_t *areaAddr, vaddr_t *descAddr, vaddr_t *entryAddr);
/*
* Add Slice for some simple/commun size
*/
int allocPopulate(); int allocPopulate();
/* /*
* Allow malloc to allocate elements of this precise size. * Allow malloc to allocate elements of this precise size.

View File

@ -7,6 +7,14 @@
#include "mem.h" #include "mem.h"
#include "stdarg.h" #include "stdarg.h"
struct memArea {
vaddr_t startAddr;
uint nbPages;
struct memArea *next;
struct memArea *prev;
};
static struct memArea *freeArea; static struct memArea *freeArea;
static struct memArea *usedArea; static struct memArea *usedArea;

View File

@ -9,19 +9,29 @@
#define AREA_PHY_MAP (1<<0) #define AREA_PHY_MAP (1<<0)
#define AREA_MEM_TOP PAGING_MIRROR_VADDR #define AREA_MEM_TOP PAGING_MIRROR_VADDR
struct memArea { /**
vaddr_t startAddr; * Initialize the Area subsystem
uint nbPages; **/
struct memArea *next;
struct memArea *prev;
};
void areaInit(vaddr_t firstMemUsed, vaddr_t lastUsed, vaddr_t stack_bottom, vaddr_t stack_top); 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); 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 * Free a virtual area
vaddr_t areaBook(unsigned int nbPages, uint32_t flags); **/
int areaFree(vaddr_t addr); 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); int areaAdd(vaddr_t begin, vaddr_t end, int isFree);

View File

@ -5,6 +5,7 @@
#include "paging.h" #include "paging.h"
#include "thread.h" #include "thread.h"
#include "types.h" #include "types.h"
#include "zero.h"
/** /**
* Make sure the program is in a valid ELF format, map it into memory, * Make sure the program is in a valid ELF format, map it into memory,
@ -17,8 +18,7 @@ uaddr_t loadElfProg(const char *prog, struct process * proc)
{ {
int i; int i;
uaddr_t lastUserAddr = 0; uaddr_t lastUserAddr = 0;
struct uAddrSpace *as = processGetAddrSpace(proc);
/* e_ident value */ /* e_ident value */
#define ELFMAG0 0x7f #define ELFMAG0 0x7f
@ -138,6 +138,11 @@ uaddr_t loadElfProg(const char *prog, struct process * proc)
unrefPhyPage(ppage); 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 */ /* Copy segment into memory */
memcpy((void *)elf_phdrs[i].p_vaddr, (void *)(prog + elf_phdrs[i].p_offset), memcpy((void *)elf_phdrs[i].p_vaddr, (void *)(prog + elf_phdrs[i].p_offset),
elf_phdrs[i].p_filesz); elf_phdrs[i].p_filesz);

View File

@ -28,6 +28,7 @@
#include "time.h" #include "time.h"
#include "types.h" #include "types.h"
#include "vga.h" #include "vga.h"
#include "zero.h"
#define CHECK_FLAG(flags, bit) ((flags) & (1 << (bit))) #define CHECK_FLAG(flags, bit) ((flags) & (1 << (bit)))
@ -83,7 +84,9 @@ void loadUserSpace()
return; return;
} }
struct process *proc = processCreate("UserSpace"); {
struct process *proc = processCreate("init");
struct uAddrSpace *as = processGetAddrSpace(proc);
threadChangeCurrentContext(processGetMMUContext(proc)); threadChangeCurrentContext(processGetMMUContext(proc));
uaddr_t prog = loadElfProg(buf + FILE_HEADER_SIZE, proc); uaddr_t prog = loadElfProg(buf + FILE_HEADER_SIZE, proc);
@ -93,16 +96,15 @@ void loadUserSpace()
} }
// Alloc user stack // Alloc user stack
uaddr_t stackTop = 0xfffffffc; size_t stackSize = PAGE_SIZE * 2;
uaddr_t stackBottom = ALIGN_DOWN(stackTop, PAGE_SIZE); uaddr_t stack = PAGING_TOP_USER_ADDRESS - stackSize + 1;
paddr_t stackPhy = allocPhyPage(1); zeroMmap(as, &stack, stackSize, PAGING_MEM_USER | PAGING_MEM_WRITE | PAGING_MEM_READ,
assert(pageMap(stackBottom, stackPhy, 0);
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, stack + stackSize - 4);
processUnref(proc); processUnref(proc);
threadChangeCurrentContext(NULL); threadChangeCurrentContext(NULL);
}
free(buf); free(buf);
} }

View File

@ -2,7 +2,8 @@
#include "stdint.h" #include "stdint.h"
#include "types.h" #include "types.h"
/** Physical Page related function /**
* Physical Page management
*/ */
#define PAGE_SHIFT 12U #define PAGE_SHIFT 12U
@ -20,10 +21,33 @@ struct phyMemDesc {
struct phyMemDesc *next, *prev; struct phyMemDesc *next, *prev;
}; };
/**
* Initi Physical Page management subsystem
**/
int memSetup(paddr_t upperMem, paddr_t * firstUsed, paddr_t *lastUsed); 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); int memAddBank(paddr_t bottomMem, paddr_t topMem, int isFree);
/**
* Request @params nbPage free physical pages
**/
paddr_t allocPhyPage(uint nbPage); paddr_t allocPhyPage(uint nbPage);
/**
* Decrement the nb of user of a given physical page
**/
int unrefPhyPage(paddr_t addr); int unrefPhyPage(paddr_t addr);
/**
* Increment the nb of user of a given physical page
**/
int refPhyPage(paddr_t addr); int refPhyPage(paddr_t addr);
/**
* Return the number of physical allocated pages
**/
unsigned long getNbAllocatedPage(void); unsigned long getNbAllocatedPage(void);
void memGetStat(uint *free, uint *used); void memGetStat(uint *free, uint *used);

View File

@ -5,7 +5,10 @@
#include "stdarg.h" #include "stdarg.h"
#include "thread.h" #include "thread.h"
#include "types.h" #include "types.h"
#include "uaccess.h"
#include "uaddrspace.h" #include "uaddrspace.h"
#include "zero.h"
int syscallExecute(int syscallId, const struct cpu_state *userCtx) int syscallExecute(int syscallId, const struct cpu_state *userCtx)
{ {
@ -55,6 +58,58 @@ int syscallExecute(int syscallId, const struct cpu_state *userCtx)
threadChangeCurrentContext(NULL); threadChangeCurrentContext(NULL);
break; break;
} }
case SYSCALL_ID_MMAP: {
struct uAddrSpace *as;
uaddr_t uaddr;
uaddr_t uaddr_ptr;
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_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;
break;
}
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 (!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: default:
printf("Unknon syscall id %d\n", syscallId); printf("Unknon syscall id %d\n", syscallId);
ret = -ENOENT; ret = -ENOENT;

View File

@ -9,6 +9,8 @@
#define SYSCALL_ID_READ 4 #define SYSCALL_ID_READ 4
#define SYSCALL_ID_TEST 5 #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__ #ifdef __KERNEL__
int syscallExecute(int syscallId, const struct cpu_state *user_ctx); int syscallExecute(int syscallId, const struct cpu_state *user_ctx);

View File

@ -1,10 +1,12 @@
#include "uaccess.h"
#include "assert.h" #include "assert.h"
#include "errno.h" #include "errno.h"
#include "minmax.h"
#include "mmuContext.h" #include "mmuContext.h"
#include "paging.h" #include "paging.h"
#include "process.h" #include "process.h"
#include "thread.h" #include "thread.h"
#include "uaccess.h" #include "types.h"
static int bindtoUserContext() static int bindtoUserContext()
{ {
@ -42,6 +44,17 @@ static int memcpyUserMemNoCheck(vaddr_t dest, vaddr_t src, size_t size)
return 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) int memcpyFromUser(vaddr_t to, uaddr_t from, size_t size)
{ {
@ -52,3 +65,37 @@ int memcpyFromUser(vaddr_t to, uaddr_t from, size_t size)
return memcpyUserMemNoCheck(to, from, 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);
}

View File

@ -1,5 +1,8 @@
#pragma once #pragma once
#include "types.h" #include "types.h"
#include "stddef.h"
#include "stdarg.h" #include "stdarg.h"
int memcpyFromUser(vaddr_t to, uaddr_t from, size_t size); 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);

View File

@ -1,5 +1,6 @@
#include "uaddrspace.h" #include "uaddrspace.h"
#include "alloc.h" #include "alloc.h"
#include "errno.h"
#include "kernel.h" #include "kernel.h"
#include "klibc.h" #include "klibc.h"
#include "list.h" #include "list.h"
@ -14,18 +15,6 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
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 uAddrSpace {
struct process *process; // The process that is represented by this AS struct process *process; // The process that is represented by this AS
struct mmu_context *ctx; // The corresponding MMU configuration struct mmu_context *ctx; // The corresponding MMU configuration
@ -33,22 +22,85 @@ struct uAddrSpace {
struct uAddrVirtualReg *listVirtualReg; // List of Virtual Region used by this process struct uAddrVirtualReg *listVirtualReg; // List of Virtual Region used by this process
uaddr_t heapStart; // Start of the Head 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 { static int hasOverlap(uaddr_t addr1, size_t size1, uaddr_t addr2, size_t size2)
int (*open)(struct uAddrVirtualReg *vreg); {
int (*close)(struct uAddrVirtualReg *vreg); return max(addr1, addr2) < min(addr1 + size1, addr2 + size2);
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 { static struct uAddrVirtualReg *findVirtualRegionFromAddr(struct uAddrSpace *as, uaddr_t uaddr, size_t size)
int right; // PAGING_MEM_* {
struct mappedRessourceOps *ops; struct uAddrVirtualReg *reg;
struct uAddrVirtualReg *listVirtualReg; 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) struct uAddrSpace *uAddrSpaceCreate(struct process *proc)
{ {
@ -76,16 +128,119 @@ int uAddrSpaceDelete(struct uAddrSpace *addr)
struct uAddrVirtualReg *reg; struct uAddrVirtualReg *reg;
list_collapse_named(addr->listVirtualReg, reg, nextInAddrSpace, prevInAddrSpace) { list_collapse_named(addr->listVirtualReg, reg, nextInAddrSpace, prevInAddrSpace) {
// TODO Implement me with real ressources if (reg->res == NULL) {
assertmsg(reg->res == NULL, "Unsupported mapper ressource");
// This is memory allocated for the heap just unmap it to free it // 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)); pr_devel("Freeing heap 0x%lx for process %s\n", reg->addr,
processGetName(addr->process));
pageUnmap(reg->addr); pageUnmap(reg->addr);
free(reg); 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); 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 (!IS_ALIGNED(uaddr, PAGE_SIZE) || size <= 0)
return -EINVAL;
if(!as)
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->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)) {
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) struct mmu_context *uAddrSpaceGetMMUContext(struct uAddrSpace *addr)
{ {
return addr->ctx; return addr->ctx;
@ -114,7 +269,7 @@ uaddr_t sysBrk(struct uAddrSpace *as, uaddr_t newHeapTop)
incSize = ALIGN(newHeapTop - (as->heapStart + as->heapSize), PAGE_SIZE); incSize = ALIGN(newHeapTop - (as->heapStart + as->heapSize), PAGE_SIZE);
if (incSize < 0){ if (incSize < 0){
//TODO how to free allocated page by uAddrSpaceCheckNAlloc //TODO how to free allocated page by uAddrSpaceHeapCheckNAlloc
return as->heapStart + as->heapSize; return as->heapStart + as->heapSize;
} }
@ -123,12 +278,14 @@ uaddr_t sysBrk(struct uAddrSpace *as, uaddr_t newHeapTop)
return as->heapStart + as->heapSize; return as->heapStart + as->heapSize;
} }
int uAddrSpaceCheckNAlloc(struct uAddrSpace *as, vaddr_t addr) int uAddrSpaceHeapCheckNAlloc(struct uAddrSpace *as, vaddr_t addr)
{ {
struct uAddrVirtualReg *newReg; struct uAddrVirtualReg *newReg;
int right = PAGING_MEM_USER | PAGING_MEM_WRITE | PAGING_MEM_READ; 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("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) { if (addr < as->heapStart || addr >= as->heapStart + as->heapSize) {
return -1; return -1;
} }
@ -159,3 +316,106 @@ free_ppage:
unrefPhyPage(ppage); unrefPhyPage(ppage);
return -1; return -1;
} }
int uAddrSpaceMmap(struct uAddrSpace *as, uaddr_t *uaddr, size_t size, uint32_t rights,
uint32_t flags, struct mappedRessource *res, uint32_t offset )
{
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;
}
size = ALIGN(size, PAGE_SIZE);
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;
}
/**
* 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 | PAGING_MEM_USER;
reg = findVirtualRegionFromAddr(as, faultAddr, 1);
if (reg == NULL)
return -EFAULT;
pr_devel("Virtual Region for pageflt found\n");
if (isWriteAccess && !(reg->right & PAGING_MEM_WRITE))
return -EACCES;
if (isWriteAccess || (reg->right & PAGING_MEM_WRITE))
rights |= PAGING_MEM_WRITE;
if (reg->res->ops->nopage(reg, faultAddr, rights))
return -EFAULT;
return 0;
}

View File

@ -7,9 +7,47 @@
struct uAddrSpace; struct uAddrSpace;
struct uAddrVirtualReg; struct uAddrVirtualReg;
#define UA_MAP_SHARED (1 << 0)
#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;
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;
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); 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 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); 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);

View File

@ -184,18 +184,19 @@ class ListDumpCmd(gdb.Command):
"list_dump", gdb.COMMAND_USER "list_dump", gdb.COMMAND_USER
) )
def _print_list(self, val): def _print_list(self, val, next_name):
"""Walk through the linked list. """Walk through the linked list.
We will simply follow the 'next' pointers until we encounter the HEAD again We will simply follow the 'next' pointers until we encounter the HEAD again
""" """
idx = 0 idx = 0
head = val head = val
thread_ptr = val thread_ptr = val
result = "" result = ""
while thread_ptr != 0 and (idx == 0 or thread_ptr != head): 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) result += gdb.execute('p *({}){}'.format(str(thread_ptr.type),
thread_ptr = thread_ptr["next"] thread_ptr), to_string=True)
thread_ptr = thread_ptr[next_name]
idx += 1 idx += 1
result = ("Found a Linked List with %d items:" % idx) + "\n" + result result = ("Found a Linked List with %d items:" % idx) + "\n" + result
return result return result
@ -209,17 +210,21 @@ class ListDumpCmd(gdb.Command):
# We can pass args here and use Python CLI utilities like argparse # We can pass args here and use Python CLI utilities like argparse
# to do argument parsing # to do argument parsing
print("Args Passed: %s" % args) print("Args Passed: %s" % args)
if args: thread_name = "currentThread"
ptr_val = gdb.parse_and_eval(args) next_name = "next"
else: if(args):
ptr_val = gdb.parse_and_eval("currentThread") 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: try:
ptr_val["next"] ptr_val[next_name]
except: except:
print("Expected pointer argument with a next field") print("Expected pointer argument with a %s field" % next_name)
return return
print(self._print_list(ptr_val)) print(self._print_list(ptr_val, next_name))
register_pretty_printer(None, CustomPrettyPrinterLocator(), replace=True) register_pretty_printer(None, CustomPrettyPrinterLocator(), replace=True)

View File

@ -2,7 +2,6 @@ label: dos
label-id: 0x9ec19bcc label-id: 0x9ec19bcc
device: disk.img device: disk.img
unit: sectors unit: sectors
sector-size: 512
disk.img1 : start= 2048, size= 32768, type=6, bootable disk.img1 : start= 2048, size= 32768, type=6, bootable
disk.img2 : start= 34816, size= 30720, type=83 disk.img2 : start= 34816, size= 30720, type=83

83
drivers/zero.c Normal file
View File

@ -0,0 +1,83 @@
#include "zero.h"
#include "alloc.h"
#include "kernel.h"
#include "klibc.h"
struct zeroMappedEntry {
int refCnt;
};
static int zeroOpen(struct uAddrVirtualReg *vreg)
{
struct zeroMappedEntry *ent = (struct zeroMappedEntry *)vreg->res->customData;
ent->refCnt++;
return 0;
}
static int zeroClose(struct uAddrVirtualReg *vreg)
{
struct zeroMappedEntry *ent = (struct zeroMappedEntry *)vreg->res->customData;
ent->refCnt--;
if (ent->refCnt == 0) {
free(vreg->res->customData);
free(vreg->res);
}
return 0;
}
static int zeroNoPage(struct uAddrVirtualReg *vreg, uaddr_t addr, int right)
{
(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 = {
.open = zeroOpen,
.close = zeroClose,
.unmap = NULL,
.nopage = zeroNoPage,
};
int zeroOnMapped(struct uAddrVirtualReg *vreg)
{
(void)vreg;
printf("ZERO MAPPED !!\n");
return 0;
}
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 =
(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;
ret = uAddrSpaceMmap(as, uaddr, size, rights, flags, res, 0);
if (ret) {
free(res);
free(cust);
}
return ret;
}

11
drivers/zero.h Normal file
View File

@ -0,0 +1,11 @@
#pragma once
#include "types.h"
#include "uaddrspace.h"
#include <stddef.h>
#include <stdint.h>
int zeroSetup();
int zeroMmap(struct uAddrSpace *as, uaddr_t *uaddr, size_t size, uint32_t rights, uint32_t flags);

View File

@ -9,6 +9,8 @@
#define SYSCALL_ID_READ 4 #define SYSCALL_ID_READ 4
#define SYSCALL_ID_TEST 5 #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__ #ifdef __KERNEL__
int syscallExecute(int syscallId, const struct cpu_state *user_ctx); int syscallExecute(int syscallId, const struct cpu_state *user_ctx);

View File

@ -1,9 +1,12 @@
#include "libc.h" #include "libc.h"
#include "errno.h"
#include "list.h" #include "list.h"
#include "minmax.h" #include "minmax.h"
#include "swintr.h" #include "swintr.h"
#include "sys/mman.h"
#include "syscall.h" #include "syscall.h"
int errno = 0;
int memcmp(const void *aptr, const void *bptr, size_t size) int memcmp(const void *aptr, const void *bptr, size_t size)
{ {
const unsigned char *a = (const unsigned char *)aptr; const unsigned char *a = (const unsigned char *)aptr;
@ -725,3 +728,20 @@ void *realloc(void *ptr, size_t size)
return new_ptr; return new_ptr;
} }
void *mmap(void *addr, size_t len, int prot, int flags, char *path) {
int ret = syscall5(SYSCALL_ID_MMAP, (unsigned int)&addr, len, prot, flags, (unsigned int)path);
if(!ret)
return addr;
errno = ret;
return MAP_FAILED;
}
int munmap(void *addr, size_t len)
{
if (len == 0)
return -EINVAL;
return syscall2(SYSCALL_ID_MUNMAP, (unsigned int)addr, len);
}

View File

@ -36,6 +36,8 @@ int putc(const int c);
int vsnprintf(char *str, size_t size, const char *format, va_list ap) __attribute__ ((__format__ (printf, 3, 0))); 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 vprintf(const char *format, va_list ap) __attribute__ ((__format__ (printf, 1, 0)));
int printf(const char *format, ...) __attribute__ ((__format__ (printf, 1, 2))); 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 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))); int vasprintf(char **strp, const char *fmt, va_list ap) __attribute__ ((__format__ (printf, 2, 0)));

View File

@ -1,5 +1,8 @@
#include "errno.h"
#include "libc.h" #include "libc.h"
#include "stdarg.h" #include "stdarg.h"
#include "stddef.h"
#include "sys/mman.h"
#include "tiny.h" #include "tiny.h"
int func_help() int func_help()
@ -10,6 +13,8 @@ int func_help()
printf(" syscall5: a syscall with parameters over the stack \n"); printf(" syscall5: a syscall with parameters over the stack \n");
printf(" alloc: test allocation\n"); printf(" alloc: test allocation\n");
printf(" tiny: a tiny C-like interpreter\n"); printf(" tiny: a tiny C-like interpreter\n");
printf(" mmap: test mmap \n");
printf(" munmap: test munmap \n");
return 0; return 0;
} }
@ -55,6 +60,64 @@ int func_alloc()
return 0; return 0;
} }
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 *)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[]) int main(int argc, char *argv[])
{ {
(void)argc; (void)argc;
@ -85,6 +148,14 @@ int main(int argc, char *argv[])
func_tiny(); func_tiny();
continue; continue;
} }
if (strcmp(buf, "mmap") == 0) {
func_mmap();
continue;
}
if (strcmp(buf, "munmap") == 0) {
func_munmap();
continue;
}
} }
return 0; return 0;
} }

13
userspace/sys/mman.h Normal file
View File

@ -0,0 +1,13 @@
#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)
#define MAP_FAILED (void *)-1