Loading arch/sh/exception.c +52 −2 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ #include <sys/memory.h> #include <utils/log.h> #include <sys/kdebug.h> #include <sys/mem_area.h> //void exception_handler() __attribute__ ((interrupt_handler, section(".handler.exception"))); Loading Loading @@ -83,7 +84,7 @@ void exception_handler() printk(LOG_ERR, "> TEA value = %p\n", (void*)tea); printk(LOG_ERR, "> *TEA = (%p)\n", (void*)(*(int*)(tea-(tea%4)))); printk(LOG_ERR, "> SPC Value = %p\n", spcval); if(EXP_CODE_BAD_SLOTINSTR) if(evt == EXP_CODE_BAD_SLOTINSTR) kdebug_oops("Illegal slot instruction"); else kdebug_oops("Illegal instruction"); Loading Loading @@ -134,6 +135,9 @@ void exception_handler() } // used to avoid infinite tlb fault loops when exception are allowed inside // a page fault resolving process... static int _recurcive_tlbfault = 0; /** * This handler is very important for Virtual Memory, it has to check Loading @@ -151,11 +155,57 @@ void tlbmiss_handler() // the process which cause the TLB miss should be the current one curpr = _proc_current; if(_recurcive_tlbfault) { void *spcval; asm volatile("stc spc, %0":"=r"(spcval)); printk(LOG_EMERG, "> [%d] Page fault %p, PC=%p\n", MMU.PTEH.BIT.ASID, PM_PHYSICAL_ADDR(MMU.PTEH.BIT.VPN), spcval); kdebug_oops("Recurcive page fault"); } // find the corresponding page, if exists vpn = MMU.PTEH.BIT.VPN; page = mem_find_page(curpr->dir_list, (void*)(vpn << PM_PAGE_ORDER) ); // if page is not in dir list (or is invalid), maybe it exists in memory // area (allocate it) // FIXME not working for shared pages if(page == NULL || !(page->private.flags & MEM_PAGE_VALID)) { struct mem_area *area; void *virtaddr; // allow exception to occurs (realy helpful for debugging...) sched_preempt_block(); _recurcive_tlbfault = 1; arch_int_weak_atomic_block(1); interrupt_inhibit_all(0); virtaddr = PM_PHYSICAL_ADDR(vpn); area = mem_area_find(curpr, virtaddr); if(area != NULL) { union pm_page pmpage; // 'major' page fault, create and fill it pmpage = mem_area_pagefault(area, virtaddr); if(pmpage.private.ppn != 0) { mem_insert_page(& curpr->dir_list, &pmpage, virtaddr); // not optimized, but ensure page points to a valid page struct page = mem_find_page(curpr->dir_list, virtaddr); printk(LOG_DEBUG, "tlb major fault: page inserted (virt %p -> phy %p)\n", virtaddr, PM_PHYSICAL_ADDR(page->private.ppn)); } } interrupt_inhibit_all(1); _recurcive_tlbfault = 0; sched_preempt_unblock(); } if(page != NULL) { unsigned int flags; uint32 ppn = 0; Loading fs/casio_smemfs/file.c +141 −53 Original line number Diff line number Diff line Loading @@ -4,15 +4,24 @@ #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_release = smemfs_area_release, .area_duplicate = smemfs_area_duplicate }; int smemfs_release (struct file *filep) { // nothing special to do for now Loading @@ -21,23 +30,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; Loading @@ -45,27 +45,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; Loading @@ -86,10 +85,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; } } Loading Loading @@ -124,3 +143,72 @@ off_t smemfs_lseek (struct file *filep, off_t offset, int whence) { return filep->pos; } 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; 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, 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); } int smemfs_area_duplicate(struct mem_area *orig, struct mem_area *copy) { copy->file.filep->count++; return 0; } fs/casio_smemfs/file.h +15 −0 Original line number Diff line number Diff line Loading @@ -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. Loading @@ -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); Loading @@ -19,4 +23,15 @@ 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 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); void smemfs_area_release(struct mem_area *area); int smemfs_area_duplicate(struct mem_area *orig, struct mem_area *copy); #endif //_FS_SMEMFS_FILE_H fs/file_operations.h +20 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,8 @@ struct file; struct mem_area; struct file_operations { /** * Release the file opened instance ("close" it). Loading Loading @@ -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 Loading fs/vfs_file.c +36 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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; } Loading
arch/sh/exception.c +52 −2 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ #include <sys/memory.h> #include <utils/log.h> #include <sys/kdebug.h> #include <sys/mem_area.h> //void exception_handler() __attribute__ ((interrupt_handler, section(".handler.exception"))); Loading Loading @@ -83,7 +84,7 @@ void exception_handler() printk(LOG_ERR, "> TEA value = %p\n", (void*)tea); printk(LOG_ERR, "> *TEA = (%p)\n", (void*)(*(int*)(tea-(tea%4)))); printk(LOG_ERR, "> SPC Value = %p\n", spcval); if(EXP_CODE_BAD_SLOTINSTR) if(evt == EXP_CODE_BAD_SLOTINSTR) kdebug_oops("Illegal slot instruction"); else kdebug_oops("Illegal instruction"); Loading Loading @@ -134,6 +135,9 @@ void exception_handler() } // used to avoid infinite tlb fault loops when exception are allowed inside // a page fault resolving process... static int _recurcive_tlbfault = 0; /** * This handler is very important for Virtual Memory, it has to check Loading @@ -151,11 +155,57 @@ void tlbmiss_handler() // the process which cause the TLB miss should be the current one curpr = _proc_current; if(_recurcive_tlbfault) { void *spcval; asm volatile("stc spc, %0":"=r"(spcval)); printk(LOG_EMERG, "> [%d] Page fault %p, PC=%p\n", MMU.PTEH.BIT.ASID, PM_PHYSICAL_ADDR(MMU.PTEH.BIT.VPN), spcval); kdebug_oops("Recurcive page fault"); } // find the corresponding page, if exists vpn = MMU.PTEH.BIT.VPN; page = mem_find_page(curpr->dir_list, (void*)(vpn << PM_PAGE_ORDER) ); // if page is not in dir list (or is invalid), maybe it exists in memory // area (allocate it) // FIXME not working for shared pages if(page == NULL || !(page->private.flags & MEM_PAGE_VALID)) { struct mem_area *area; void *virtaddr; // allow exception to occurs (realy helpful for debugging...) sched_preempt_block(); _recurcive_tlbfault = 1; arch_int_weak_atomic_block(1); interrupt_inhibit_all(0); virtaddr = PM_PHYSICAL_ADDR(vpn); area = mem_area_find(curpr, virtaddr); if(area != NULL) { union pm_page pmpage; // 'major' page fault, create and fill it pmpage = mem_area_pagefault(area, virtaddr); if(pmpage.private.ppn != 0) { mem_insert_page(& curpr->dir_list, &pmpage, virtaddr); // not optimized, but ensure page points to a valid page struct page = mem_find_page(curpr->dir_list, virtaddr); printk(LOG_DEBUG, "tlb major fault: page inserted (virt %p -> phy %p)\n", virtaddr, PM_PHYSICAL_ADDR(page->private.ppn)); } } interrupt_inhibit_all(1); _recurcive_tlbfault = 0; sched_preempt_unblock(); } if(page != NULL) { unsigned int flags; uint32 ppn = 0; Loading
fs/casio_smemfs/file.c +141 −53 Original line number Diff line number Diff line Loading @@ -4,15 +4,24 @@ #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_release = smemfs_area_release, .area_duplicate = smemfs_area_duplicate }; int smemfs_release (struct file *filep) { // nothing special to do for now Loading @@ -21,23 +30,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; Loading @@ -45,27 +45,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; Loading @@ -86,10 +85,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; } } Loading Loading @@ -124,3 +143,72 @@ off_t smemfs_lseek (struct file *filep, off_t offset, int whence) { return filep->pos; } 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; 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, 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); } int smemfs_area_duplicate(struct mem_area *orig, struct mem_area *copy) { copy->file.filep->count++; return 0; }
fs/casio_smemfs/file.h +15 −0 Original line number Diff line number Diff line Loading @@ -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. Loading @@ -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); Loading @@ -19,4 +23,15 @@ 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 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); void smemfs_area_release(struct mem_area *area); int smemfs_area_duplicate(struct mem_area *orig, struct mem_area *copy); #endif //_FS_SMEMFS_FILE_H
fs/file_operations.h +20 −0 Original line number Diff line number Diff line Loading @@ -15,6 +15,8 @@ struct file; struct mem_area; struct file_operations { /** * Release the file opened instance ("close" it). Loading Loading @@ -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 Loading
fs/vfs_file.c +36 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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; }