mmap #8
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,6 +1,6 @@
|
|||||||
serialOut
|
serialOut
|
||||||
disk.img
|
disk.img
|
||||||
kernel
|
kernel
|
||||||
kernel.sym
|
kernel.debug
|
||||||
userspace/user
|
userspace/user
|
||||||
docs/*.html
|
docs/*.html
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -165,7 +165,7 @@
|
|||||||
iret
|
iret
|
||||||
.endm
|
.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
|
.irp exception_id, 8, 10, 11, 12, 13, 14, 17, 30
|
||||||
exception_mac_with_errcode exception_id
|
exception_mac_with_errcode exception_id
|
||||||
.endr
|
.endr
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
11
core/elf.c
11
core/elf.c
@ -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,
|
||||||
@ -13,12 +14,11 @@
|
|||||||
* @return 0 when the program is not a valid ELF
|
* @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;
|
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);
|
||||||
|
18
core/main.c
18
core/main.c
@ -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);
|
||||||
}
|
}
|
||||||
|
26
core/mem.h
26
core/mem.h
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -7,9 +7,47 @@
|
|||||||
struct uAddrSpace;
|
struct uAddrSpace;
|
||||||
struct uAddrVirtualReg;
|
struct uAddrVirtualReg;
|
||||||
|
|
||||||
struct uAddrSpace * uAddrSpaceCreate(struct process *proc);
|
#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);
|
||||||
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);
|
||||||
|
@ -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)
|
||||||
|
@ -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
83
drivers/zero.c
Normal 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
11
drivers/zero.h
Normal 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);
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
@ -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)));
|
||||||
|
@ -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
13
userspace/sys/mman.h
Normal 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
|
Loading…
Reference in New Issue
Block a user