Commit a9f7de98 authored by Léo Grange's avatar Léo Grange

improve memory areas integration

parent 61093179
......@@ -4,17 +4,21 @@
#include <fs/inode.h>
#include <interface/fixos/errno.h>
#include "smemfs_primitives_ng.h"
// used for memory areas...
#include <fs/vfs_file.h>
const struct file_operations smemfs_file_operations = {
.release = smemfs_release,
.read = smemfs_read,
.lseek = smemfs_lseek
.lseek = smemfs_lseek,
.map_area = smemfs_map_area
};
const struct mem_area_ops smemfs_mem_ops = {
.area_pagefault = smemfs_area_pagefault
.area_pagefault = smemfs_area_pagefault,
.area_release = smemfs_area_release
};
......@@ -140,6 +144,17 @@ off_t smemfs_lseek (struct file *filep, off_t offset, int whence) {
}
int smemfs_map_area(struct file *filep, struct mem_area *area) {
// not a lot of stuff to do for now...
area->ops = &smemfs_mem_ops;
area->file.filep = filep;
// increase file usage count (mirrored in smemfs_area_release)
filep->count++;
return 0;
}
union pm_page smemfs_area_pagefault(struct mem_area *area, void *addr_fault) {
size_t readsize;
void *pmaddr;
......@@ -179,10 +194,13 @@ union pm_page smemfs_area_pagefault(struct mem_area *area, void *addr_fault) {
return pmpage;
}
int smemfs_area_resize(struct mem_area *area, const struct mem_area *new_area) {
/*
int smemfs_area_resize(struct mem_area *area, size_t new_size) {
return -1;
}
*/
void smemfs_area_release(struct mem_area *area) {
// release the file, by closing it at vfs level?
vfs_close(area->file.filep);
}
......@@ -24,6 +24,8 @@ off_t smemfs_lseek (struct file *filep, off_t offset, int whence);
// memory-mapped operations
int smemfs_map_area(struct file *filep, struct mem_area *area);
union pm_page smemfs_area_pagefault(struct mem_area *area, void *addr_fault);
int smemfs_area_resize(struct mem_area *area, const struct mem_area *new_area);
......
......@@ -15,6 +15,8 @@
struct file;
struct mem_area;
struct file_operations {
/**
* Release the file opened instance ("close" it).
......@@ -47,6 +49,24 @@ struct file_operations {
* data is specific to command and device, may be not used.
*/
int (*ioctl) (struct file *filep, int cmd, void *data);
/**
* Create a memory map of this object in memory.
* Devices may use it as they want to, for example to provide big buffers
* shared with userland.
* area should be set with all non-private fields having a valid value,
* which is not very well defined...
* At least field ops is not expected to be set, but the interface is not
* well designed for now.
* TODO either use a 'hints' argument with mem_area-like type, or define
* exactly what should be set and what is set by this function itself
*
* NULL if device of filesystem do not implements memory mapped areas.
*
* Return 0 if mapping is accepted, negative value else.
*/
int (*map_area) (struct file *filep, struct mem_area *area);
};
#endif //_FS_FILE_OPERATIONS_H
......
......@@ -7,6 +7,7 @@
#include "file_system.h"
#include "file_operations.h"
#include "vfs_directory.h"
#include <sys/mem_area.h>
// pool allocation for file struct
......@@ -157,3 +158,38 @@ int vfs_fstat(struct file *filep, struct stat *buf) {
return -1;
}
}
int vfs_map_area(struct file *filep, size_t size, size_t offset, void *address,
int flags, size_t infile_size, struct process *proc)
{
int ret = -EINVAL;
if(filep->op->map_area != NULL) {
struct mem_area *area;
area = mem_area_alloc();
if(area == NULL) {
ret = -ENOMEM;
}
else {
// prepare area struct from arguments
area->address = address;
area->max_size = size;
area->flags = flags | MEM_AREA_TYPE_FILE;
area->file.base_offset = offset;
area->file.infile_size = (flags & MEM_AREA_PARTIAL) ? infile_size : size;
area->file.filep = filep;
ret = filep->op->map_area(filep, area);
if(ret == 0) {
ret = mem_area_insert(proc, area);
}
else {
// failed, free area (do not *release* it, free directly)
mem_area_free(area);
}
}
}
return ret;
}
......@@ -90,4 +90,18 @@ int vfs_ioctl(struct file *filep, int cmd, void *data);
int vfs_fstat(struct file *filep, struct stat *buf);
struct process;
/**
* Map size bytes of the object in memory, from given offset, to given address
* in the address space of a given process.
* Area permissions, and additionnal flags, may be provided, using constants
* from sys/mem_area.h
* from_file is important only if flag contains MEM_AREA_PARTIAL
*
* TODO make a 'hints' structure to reduce number of arguments?
*/
int vfs_map_area(struct file *filep, size_t size, size_t offset, void *address,
int flags, size_t infile_size, struct process *proc);
#endif //_FS_VFS_FILE_H
......@@ -24,6 +24,7 @@
#define ESRCH 16
#define EACCES 17
#define EPERM 18
#define ENOMEM 19
#endif //_FIXOS_INTERFACE_ERRNO_H
......@@ -46,8 +46,7 @@ int elfloader_load(struct file *filep, struct process *dest) {
// set user stack (the size used *is* a maximum, not the allocated one)
struct mem_area *user_stack;
user_stack = mem_area_alloc();
mem_area_set_anon(user_stack, (void*)(ARCH_UNEWPROC_DEFAULT_STACK
user_stack = mem_area_make_anon((void*)(ARCH_UNEWPROC_DEFAULT_STACK
- PROCESS_DEFAULT_STACK_SIZE), PROCESS_DEFAULT_STACK_SIZE);
mem_area_insert(dest, user_stack);
......@@ -192,24 +191,12 @@ int elfloader_load_segment(struct file *filep, void *offset,
const struct elf_prog_header *ph, struct process *dest)
{
if(ph->vaddr % PM_PAGE_BYTES == 0) {
// TODO replace with appropriate mem_area helper!
struct mem_area *area;
area = mem_area_alloc();
filep->count ++;
area->flags = MEM_AREA_TYPE_FILE | MEM_AREA_PARTIAL;
area->file.filep = filep;
area->file.base_offset = ph->offset;
area->max_size = ph->memsz;
// allow to fill with 0 any 0-initialized sections (like .bss)
area->file.infile_size = ph->filesz;
area->address = offset + ph->vaddr;
// FIXME temporary
area->ops = & smemfs_mem_ops;
mem_area_insert(dest, area);
return 0;
int prot;
// TODO use real permissions from ELF
prot = MEM_AREA_PROT_R | MEM_AREA_PROT_W | MEM_AREA_PROT_X;
return vfs_map_area(filep, ph->memsz, ph->offset, offset + ph->vaddr,
MEM_AREA_PARTIAL | prot, ph->filesz, dest);
}
else {
printk(LOG_ERR, "elfloader: segment begin not page-aligned.\n");
......
......@@ -13,12 +13,13 @@ static struct pool_alloc _mem_area_pool = POOL_INIT(struct mem_area);
// anonymous area operations
static union pm_page anon_area_pagefault(struct mem_area *area, void *addr_fault);
static int anon_area_resize(struct mem_area *area, const struct mem_area *new_area);
static int anon_area_resize(struct mem_area *area, size_t new_size);
static void anon_area_release(struct mem_area *area);
//static void anon_area_release(struct mem_area *area);
static struct mem_area_ops _anon_area_ops = {
.area_pagefault = anon_area_pagefault
static const struct mem_area_ops _anon_area_ops = {
.area_pagefault = anon_area_pagefault,
.area_resize = anon_area_resize
};
......@@ -47,12 +48,19 @@ void mem_area_free(struct mem_area *area) {
void mem_area_set_anon(struct mem_area *area, void *vmaddr, size_t size) {
// nothing more, for now...
area->flags = MEM_AREA_TYPE_ANON;
area->address = vmaddr;
area->max_size = size;
area->ops = &_anon_area_ops;
struct mem_area *mem_area_make_anon(void *vmaddr, size_t size) {
struct mem_area *area;
area = mem_area_alloc();
if(area != NULL) {
// nothing more, for now...
area->flags = MEM_AREA_TYPE_ANON | MEM_AREA_PROT_R | MEM_AREA_PROT_W
| MEM_AREA_PROT_X;
area->address = vmaddr;
area->max_size = size;
area->ops = &_anon_area_ops;
}
return area;
}
......@@ -190,3 +198,12 @@ static union pm_page anon_area_pagefault(struct mem_area *area, void *addr_fault
return pmpage;
}
static int anon_area_resize(struct mem_area *area, size_t new_size) {
// handle only for debug purpose
printk(LOG_DEBUG, "mem_area: resize area @%p (%d->%d)\n", area->address,
area->max_size, new_size);
area->max_size = new_size;
return 0;
}
......@@ -34,7 +34,7 @@ struct mem_area {
size_t max_size;
// callback functions to manage this area
struct mem_area_ops *ops;
const struct mem_area_ops *ops;
// type-specific data (determined by flags)
union {
......@@ -108,15 +108,23 @@ void mem_area_init();
/**
* Return a newly allocated memory area, not initialized.
* This function is mainly designed for helper usage.
*/
struct mem_area *mem_area_alloc();
/**
* Free an allocated memory area, *without* any clean checkup!
* Should not be used unless you are sure the given area is not valid,
* or already clean.
* Use mem_area_release() in other cases!
*/
void mem_area_free(struct mem_area *area);
/**
* Helper to set an allocated memory area as an anonymous area.
* Helper to create an anonymous memory area, at given address.
*/
void mem_area_set_anon(struct mem_area *area, void *vmaddr, size_t size);
struct mem_area *mem_area_make_anon(void *vmaddr, size_t size);
/**
......@@ -152,6 +160,17 @@ extern inline union pm_page mem_area_pagefault(struct mem_area *area,
}
}
/**
* Release, and free if necessary, the given area, after calling the
* implementation-specific release callback if any.
*/
extern inline void mem_area_release(struct mem_area *area) {
if(area->ops != NULL && area->ops->area_release != NULL)
area->ops->area_release(area);
mem_area_free(area);
}
/**
* Resize an area to the given new_size.
* If size is decreased and some memory pages associated with corresponding
......
......@@ -204,7 +204,7 @@ void process_terminate(struct process *proc, int status) {
while(cur_area != & proc->mem_areas) {
struct list_head *next_area = cur_area->next;
struct mem_area *area = container_of(cur_area, struct mem_area, list);
mem_area_free(area);
mem_area_release(area);
cur_area = next_area;
}
INIT_LIST_HEAD(& proc->mem_areas);
......@@ -470,7 +470,7 @@ int sys_execve(const char *filename, char *const argv[], char *const envp[]) {
while(cur_area != & cur->mem_areas) {
struct list_head *next_area = cur_area->next;
struct mem_area *area = container_of(cur_area, struct mem_area, list);
mem_area_free(area);
mem_area_release(area);
cur_area = next_area;
}
INIT_LIST_HEAD(& cur->mem_areas);
......@@ -557,13 +557,12 @@ void *sys_sbrk(int incr) {
void *real_brk;
size_t brk_align;
heap = mem_area_alloc();
// create heap area, using initial location rounded to page align
brk_align = ((size_t)cur->initial_brk) % PM_PAGE_BYTES;
real_brk = brk_align == 0 ? cur->initial_brk
: cur->initial_brk + (PM_PAGE_BYTES - brk_align);
mem_area_set_anon(heap, real_brk, 0);
heap = mem_area_make_anon(real_brk, 0);
mem_area_insert(cur, heap);
cur->heap_area = heap;
......@@ -578,7 +577,8 @@ void *sys_sbrk(int incr) {
size_t new_size;
printk(LOG_DEBUG, "sbrk: incr=%d\n", incr);
new_size = -incr > heap->max_size ? 0 : heap->max_size + incr;
// avoid negative size (size_t is unsigned, be careful)
new_size = (incr < 0 && -incr > heap->max_size) ? 0 : heap->max_size + incr;
mem_area_resize(heap, new_size, cur);
return ret;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment