Add the ability to map/unmap a ressource
This commit is contained in:
parent
1bb81fd57e
commit
b9d741060f
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user