Commit 100dfe86 authored by Léo Grange's avatar Léo Grange
Browse files

add memory area operations for SMEM files and anonymous areas

parent e6d5a6cb
Loading
Loading
Loading
Loading
+2 −9
Original line number Diff line number Diff line
@@ -168,19 +168,12 @@ void tlbmiss_handler()
		area = mem_area_find(curpr, virtaddr);
		if(area != NULL) {
			union pm_page pmpage;
			void *pmaddr;

			// 'major' page fault, create and fill it
			// FIXME UNCACHED due to temporary hack to be sure nothing is retained in cache
			pmaddr = arch_pm_get_free_page(MEM_PM_UNCACHED);
			if(pmaddr != NULL) {
				pmpage.private.ppn = PM_PHYSICAL_PAGE(pmaddr);
				pmpage.private.flags = MEM_PAGE_PRIVATE | MEM_PAGE_VALID; // | MEM_PAGE_CACHED;
			pmpage = mem_area_pagefault(area, virtaddr);
			if(pmpage.private.ppn != 0) {
				mem_insert_page(& curpr->dir_list, &pmpage, virtaddr);

				// FIXME get min(PM_PAGE_BYTES, max allowed) bytes
				mem_area_copy_raw(area, (virtaddr - area->address), pmaddr, PM_PAGE_BYTES);	

				// not optimized, but ensure page points to a valid page struct
				page = mem_find_page(curpr->dir_list, virtaddr);

+114 −52
Original line number Diff line number Diff line
@@ -13,6 +13,10 @@ const struct file_operations smemfs_file_operations = {
};


const struct mem_area_ops smemfs_mem_ops = {
	.area_pagefault = smemfs_area_pagefault
};


int smemfs_release (struct file *filep) {
	// nothing special to do for now
@@ -21,23 +25,14 @@ int smemfs_release (struct file *filep) {
}




ssize_t smemfs_read (struct file *filep, void *dest, size_t len) {
	if(!(filep->flags & O_RDONLY)) {
		return -EBADF;
	}
	if(filep->inode->type_flags & INODE_TYPE_PARENT) {
		return -EISDIR;
	}

	if(len == 0) {
		return 0;
	}
	else {
/**
 * Internal helper for reading data from a file
 */
static ssize_t smemfs_read_data (struct smemfs_file_preheader *header,
		void *dest, size_t len, size_t atpos)
{
	int j, n;
		size_t max_read;
		struct smemfs_file_preheader *header;
	ssize_t max_read;
	struct smemfs_frag_header *frag;

	size_t pos_frag;
@@ -45,27 +40,26 @@ ssize_t smemfs_read (struct file *filep, void *dest, size_t len) {
	size_t pos_buf;
	size_t file_size;

		header = filep->inode->abstract;
	frag = (void*)(header+1);

	file_size = smemfs_prim_get_file_size(header);
		max_read = file_size - filep->pos;
	max_read = file_size - atpos;
	max_read = max_read < len ? max_read : len;

		n = filep->pos + max_read;
		j = filep->pos;
	n = atpos + max_read;
	j = atpos;

	// TODO check everything

	// look for fragment containing the first byte
	pos_tmp = 0;
		while(pos_tmp + frag->data_size+1 <= filep->pos) {
	while(pos_tmp + frag->data_size+1 <= atpos) {
		pos_tmp += frag->data_size + 1;
		frag++;
	}

	// compute offset inside the fragment
		pos_frag = filep->pos - pos_tmp;
	pos_frag = atpos - pos_tmp;

	// read data fragment after fragment
	pos_buf = 0;
@@ -86,10 +80,30 @@ ssize_t smemfs_read (struct file *filep, void *dest, size_t len) {
		else pos_frag += toread;
	}

		filep->pos += max_read;
		//if(filep->pos >= file_size) filep->flags |= _FILE_EOF_REATCHED;
	return max_read;
}


ssize_t smemfs_read (struct file *filep, void *dest, size_t len) {
	if(!(filep->flags & O_RDONLY)) {
		return -EBADF;
	}
	if(filep->inode->type_flags & INODE_TYPE_PARENT) {
		return -EISDIR;
	}

	if(len == 0) {
		return 0;
	}
	else {
		ssize_t ret;

		ret = smemfs_read_data(filep->inode->abstract, dest, len, filep->pos);
		if(ret > 0)
			filep->pos += ret;

		return ret;
	}
}


@@ -124,3 +138,51 @@ off_t smemfs_lseek (struct file *filep, off_t offset, int whence) {

	return filep->pos;
}


union pm_page smemfs_area_pagefault(struct mem_area *area, void *addr_fault) {
	size_t readsize;
	void *pmaddr;
	union pm_page pmpage;
	size_t offset = addr_fault - area->address;

	// allocate a physical memory page
	// FIXME UNCACHED due to temporary hack to be sure nothing is retained in cache
	pmaddr = arch_pm_get_free_page(MEM_PM_UNCACHED);
	if(pmaddr != NULL) {
		pmpage.private.ppn = PM_PHYSICAL_PAGE(pmaddr);
		pmpage.private.flags = MEM_PAGE_PRIVATE | MEM_PAGE_VALID; // | MEM_PAGE_CACHED;
	}
	// FIXME what to do if out of memory?
	
	// fill with zeroes if needed
	readsize = mem_area_fill_partial_page(area, offset, pmaddr);
	
	if(readsize > 0) {
		struct inode *inode = area->file.filep->inode;
		size_t absoffset = area->file.base_offset + offset;
		ssize_t nbread;
		
		nbread = smemfs_read_data(inode->abstract, pmaddr, readsize, absoffset);

		if(nbread != readsize) {
			printk(LOG_ERR, "smemfs_area: failed loading %d bytes from offset 0x%x"
					" [absolute 0x%x] (read returns %d)\n",
					readsize, offset, absoffset, nbread);
		}
		else {
			printk(LOG_DEBUG, "smemfs_area: loaded %d bytes @%p from file\n",
					readsize, pmaddr);
		}
	}

	return pmpage;
}

int smemfs_area_resize(struct mem_area *area, const struct mem_area *new_area) {
	return -1;
}

void smemfs_area_release(struct mem_area *area) {

}
+12 −0
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
#include <fs/file_operations.h>
#include <fs/file.h>
#include <interface/fixos/stat.h>
#include <sys/mem_area.h>

/**
 * Implementation of file operations for the Casio SMEM FS.
@@ -11,6 +12,9 @@

extern const struct file_operations smemfs_file_operations;

// for memory-mapped files
extern const struct mem_area_ops smemfs_mem_ops;


int smemfs_release (struct file *filep);

@@ -19,4 +23,12 @@ ssize_t smemfs_read (struct file *filep, void *dest, size_t len);
off_t smemfs_lseek (struct file *filep, off_t offset, int whence);


// memory-mapped operations
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);

void smemfs_area_release(struct mem_area *area);


#endif //_FS_SMEMFS_FILE_H
+6 −1
Original line number Diff line number Diff line
@@ -186,6 +186,7 @@ int check_elf_header(struct elf_header *h) {
}


#include <fs/casio_smemfs/file.h>

int elfloader_load_segment(struct file *filep, void *offset,
		const struct elf_prog_header *ph, struct process *dest)
@@ -196,13 +197,15 @@ int elfloader_load_segment(struct file *filep, void *offset,

		area = mem_area_alloc();
		filep->count ++;
		area->flags = MEM_AREA_TYPE_FILE;
		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);
	
@@ -235,6 +238,8 @@ int elfloader_load_dynlib(const char *soname, struct process *dest) {
			struct elf_section_header symtab;

			printk(LOG_DEBUG, "elfloader: library '%s' loaded!\n", absname);
			// FIXME don't work anymore with the new memory area system, should
			// be re-written!
			if(elf_get_symtab(lib, &header, &symtab) == 0) {
				struct elf_symbol sym;
				uint32 *reloc_got_b = NULL;
+47 −42
Original line number Diff line number Diff line
@@ -10,6 +10,19 @@
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 void anon_area_release(struct mem_area *area);

static struct mem_area_ops _anon_area_ops = {
	.area_pagefault = anon_area_pagefault
};



void mem_area_init() {
	printk(LOG_DEBUG, "mem_area: area/page=%d\n", _mem_area_pool.perpage);
}
@@ -39,6 +52,7 @@ void mem_area_set_anon(struct mem_area *area, void *vmaddr, size_t size) {
	area->flags = MEM_AREA_TYPE_ANON;
	area->address = vmaddr;
	area->max_size = size;
	area->ops = &_anon_area_ops;
}


@@ -92,64 +106,55 @@ int mem_area_insert(struct process *proc, struct mem_area *area) {
}


int mem_area_copy_raw(struct mem_area *area, size_t offset, void *dest, size_t size) {
	int ret = -1;

	if(area->flags & MEM_AREA_TYPE_ANON) {
		// anonymous area, the current implementation do nothing...
		if(offset + size > area->max_size) {
			printk(LOG_ERR, "mem_area: attempt to copy extra bytes (anon)\n");
		}
		else {
			ret = 0;
		}
	}
	else if(area->flags & MEM_AREA_TYPE_FILE) {
		// file mapped to memory, for now use a generic way to handle them
		// TODO improve this with map_area_ops struct to allow "override"
		size_t nbread;
		size_t readsize = size;
size_t mem_area_fill_partial_page(struct mem_area *area, size_t offset, void *dest) {
	size_t readsize = PM_PAGE_BYTES;

	if(area->flags & MEM_AREA_TYPE_FILE && area->flags & MEM_AREA_PARTIAL) {
		// fill with 0 if needed
		if(area->file.infile_size < offset + size) {
			size_t zeroed_offset;
		if(area->file.infile_size < offset + readsize) {
			size_t zeroed_size;

			// partially
			if(area->file.infile_size > offset) {
				readsize = area->file.infile_size - offset;
				zeroed_offset = readsize;
				zeroed_size = (offset + size) - area->file.infile_size;
				zeroed_size = (offset + PM_PAGE_BYTES) - area->file.infile_size;
			}
			else {
				zeroed_offset = 0;
				zeroed_size = size;
				zeroed_size = readsize;
				readsize = 0;
			}

			memset(dest + zeroed_offset, 0, zeroed_size);
			memset(dest + readsize, 0, zeroed_size);
		}
	}

		ret = 0;
		if(readsize > 0) {
			vfs_lseek(area->file.filep, area->file.base_offset + offset, SEEK_SET);
			nbread = vfs_read(area->file.filep, dest, readsize);
			ret = nbread == readsize ? 0 : -1;

			if(ret) {
				printk(LOG_ERR, "mem_area: failed loading %d bytes from offset 0x%x"
						" [absolute 0x%x] (read returns %d)\n",
						readsize, offset, area->file.base_offset + offset, nbread);
				ret = -1;
	return readsize;
}
			else {
				printk(LOG_DEBUG, "mem_area: loaded %d bytes @%p from file\n", readsize, dest);


// anonymous area operations :
static union pm_page anon_area_pagefault(struct mem_area *area, void *addr_fault) {
	union pm_page pmpage = { .private.ppn = 0, .private.flags = MEM_PAGE_PRIVATE };
	size_t offset = addr_fault - area->address;
	//size_t size = PM_PAGE_BYTES;

	// anonymous area, the current implementation only allocate a page
	if(offset < area->max_size) {
		void *pmaddr;

		// allocate a physical memory page
		// FIXME UNCACHED due to temporary hack to be sure nothing is retained in cache
		pmaddr = arch_pm_get_free_page(MEM_PM_UNCACHED);
		if(pmaddr != NULL) {
			pmpage.private.ppn = PM_PHYSICAL_PAGE(pmaddr);
			pmpage.private.flags = MEM_PAGE_PRIVATE | MEM_PAGE_VALID; // | MEM_PAGE_CACHED;
		}
		// FIXME what to do if out of memory?
	}

		//print_memory(LOG_DEBUG, dest, nbread);
	else {
		printk(LOG_ERR, "mem_area: attempt to copy extra bytes (anon)\n");
	}

	return ret;
	return pmpage;
}
Loading