diff --git a/src/arch/arm/exception.c b/src/arch/arm/exception.c index ba72956..2e6b3e5 100644 --- a/src/arch/arm/exception.c +++ b/src/arch/arm/exception.c @@ -18,7 +18,7 @@ #include INC_SUBARCH(mm.h) /* Abort debugging conditions */ -#define DEBUG_ABORTS +// #define DEBUG_ABORTS #if defined (DEBUG_ABORTS) #define dbg_abort(...) dprintk(__VA_ARGS__) #else diff --git a/tasks/fs0/src/syscalls.c b/tasks/fs0/src/syscalls.c index fc1eaaf..cc30902 100644 --- a/tasks/fs0/src/syscalls.c +++ b/tasks/fs0/src/syscalls.c @@ -30,7 +30,7 @@ int pager_sys_open(l4id_t sender, int fd, unsigned long vnum, unsigned long size { int err; - // printf("%s/%s\n", __TASKNAME__, __FUNCTION__); + printf("%s/%s\n", __TASKNAME__, __FUNCTION__); l4_save_ipcregs(); diff --git a/tasks/fs0/src/task.c b/tasks/fs0/src/task.c index 453c354..a5a8233 100644 --- a/tasks/fs0/src/task.c +++ b/tasks/fs0/src/task.c @@ -88,6 +88,38 @@ struct tcb *create_tcb(void) return t; } +/* + * Attaches to task's utcb. FIXME: Add SHM_RDONLY and test it. + * FIXME: This calls the pager and is a potential for deadlock + */ +int task_utcb_attach(struct tcb *t) +{ + int shmid; + void *shmaddr; + + /* Use it as a key to create a shared memory region */ + if ((shmid = shmget((key_t)t->utcb_address, PAGE_SIZE, 0)) == -1) + goto out_err; + + /* Attach to the region */ + if ((int)(shmaddr = shmat(shmid, (void *)t->utcb_address, 0)) == -1) + goto out_err; + + /* Ensure address is right */ + if ((unsigned long)shmaddr != t->utcb_address) + return -EINVAL; + + // printf("%s: Mapped utcb of task %d @ 0x%x\n", + // __TASKNAME__, t->tid, shmaddr); + + return 0; + +out_err: + printf("%s: Mapping utcb of task %d failed with err: %d.\n", + __TASKNAME__, t->tid, errno); + return -EINVAL; +} + /* * Receives ipc from pager about a new fork event and * the information on the resulting child task. @@ -121,6 +153,7 @@ int pager_notify_fork(l4id_t sender, l4id_t parid, memcpy(child->fd, parent->fd, TASK_FILES_MAX * sizeof(int)); l4_ipc_return(0); + printf("%s/%s: Exiting...\n", __TASKNAME__, __FUNCTION__); return 0; @@ -152,35 +185,6 @@ struct task_data_head *receive_pager_taskdata(void) return (struct task_data_head *)utcb_page; } -/* Attaches to task's utcb. FIXME: Add SHM_RDONLY and test it. */ -int task_utcb_attach(struct tcb *t) -{ - int shmid; - void *shmaddr; - - /* Use it as a key to create a shared memory region */ - if ((shmid = shmget((key_t)t->utcb_address, PAGE_SIZE, 0)) == -1) - goto out_err; - - /* Attach to the region */ - if ((int)(shmaddr = shmat(shmid, (void *)t->utcb_address, 0)) == -1) - goto out_err; - - /* Ensure address is right */ - if ((unsigned long)shmaddr != t->utcb_address) - return -EINVAL; - - // printf("%s: Mapped utcb of task %d @ 0x%x\n", - // __TASKNAME__, t->tid, shmaddr); - - return 0; - -out_err: - printf("%s: Mapping utcb of task %d failed with err: %d.\n", - __TASKNAME__, t->tid, errno); - return -EINVAL; -} - int init_task_structs(struct task_data_head *tdata_head) { diff --git a/tasks/libmem/kmalloc/kmalloc.h b/tasks/libmem/kmalloc/kmalloc.h index ba519e5..49f5302 100644 --- a/tasks/libmem/kmalloc/kmalloc.h +++ b/tasks/libmem/kmalloc/kmalloc.h @@ -23,9 +23,9 @@ extern struct list_head km_area_start; void kmalloc_init(void); /* Kmalloc allocation functions */ -void *kmalloc(int size); -void *kzalloc(int size); -int kfree(void *vaddr); +void *kmalloc(int size) __attribute__((weak)); +void *kzalloc(int size) __attribute__((weak)); +int kfree(void *vaddr) __attribute__((weak)); #endif /* __KMALLOC_H__ */ diff --git a/tasks/mm0/include/lib/malloc.h b/tasks/mm0/include/lib/malloc.h new file mode 100644 index 0000000..37479ff --- /dev/null +++ b/tasks/mm0/include/lib/malloc.h @@ -0,0 +1,19 @@ +#ifndef __PRIVATE_MALLOC_H__ +#define __PRIVATE_MALLOC_H__ + +#include +#include + +void *kmalloc(size_t size); +void kfree(void *blk); + +static inline void *kzalloc(size_t size) +{ + void *buf = kmalloc(size); + + memset(buf, 0, size); + return buf; +} + + +#endif /*__PRIVATE_MALLOC_H__ */ diff --git a/tasks/mm0/include/shm.h b/tasks/mm0/include/shm.h index 1a6866c..0457154 100644 --- a/tasks/mm0/include/shm.h +++ b/tasks/mm0/include/shm.h @@ -43,7 +43,7 @@ struct shm_descriptor { /* Initialises shared memory bookkeeping structures */ void shm_init(); -void *shmat_shmget_internal(key_t key, void *shmaddr); +void *shmat_shmget_internal(struct tcb *task, key_t key, void *shmaddr); struct vm_file *shm_new(key_t key, unsigned long npages); #endif /* __SHM_H__ */ diff --git a/tasks/mm0/include/task.h b/tasks/mm0/include/task.h index 9431d85..d6b0c72 100644 --- a/tasks/mm0/include/task.h +++ b/tasks/mm0/include/task.h @@ -101,5 +101,6 @@ void init_pm(struct initdata *initdata); struct tcb *task_create(struct task_ids *ids, unsigned int flags); int send_task_data(l4id_t requester); +void task_map_prefault_utcb(struct tcb *mapper, struct tcb *owner); #endif /* __TASK_H__ */ diff --git a/tasks/mm0/include/vm_area.h b/tasks/mm0/include/vm_area.h index b2c351f..3fc95eb 100644 --- a/tasks/mm0/include/vm_area.h +++ b/tasks/mm0/include/vm_area.h @@ -14,7 +14,7 @@ #include #include -#define DEBUG_FAULT_HANDLING +// #define DEBUG_FAULT_HANDLING #ifdef DEBUG_FAULT_HANDLING #define dprintf(...) printf(__VA_ARGS__) #else diff --git a/tasks/mm0/src/clone.c b/tasks/mm0/src/clone.c index 952a135..f6c0606 100755 --- a/tasks/mm0/src/clone.c +++ b/tasks/mm0/src/clone.c @@ -120,6 +120,7 @@ int vfs_notify_fork(struct tcb *child, struct tcb *parent) return err; } + int do_fork(struct tcb *parent) { struct tcb *child; @@ -155,7 +156,13 @@ int do_fork(struct tcb *parent) } /* FIXME: We should munmap() parent's utcb page from child */ - /* Notify fs0 about forked process */ + /* + * Map and prefault child utcb to vfs so that vfs need not + * call us with such requests + */ + task_map_prefault_utcb(find_task(VFS_TID), child); + + /* We can now notify vfs about forked process */ vfs_notify_fork(child, parent); /* Add child to global task list */ diff --git a/tasks/mm0/src/lib/malloc.c b/tasks/mm0/src/lib/malloc.c new file mode 100644 index 0000000..52824cc --- /dev/null +++ b/tasks/mm0/src/lib/malloc.c @@ -0,0 +1,418 @@ +/***************************************************************************** +Simple malloc +Chris Giese http://www.execpc.com/~geezer +Release date: Oct 30, 2002 +This code is public domain (no copyright). +You can do whatever you want with it. + +Features: +- First-fit +- free() coalesces adjacent free blocks +- Uses variable-sized heap, enlarged with kbrk()/sbrk() function +- Does not use mmap() +- Can be easily modified to use fixed-size heap +- Works with 16- or 32-bit compilers + +Build this program with either of the two main() functions, then run it. +Messages that indicate a software error will contain three asterisks (***). +*****************************************************************************/ +#include /* memcpy(), memset() */ +#include /* printf() */ +#include +#define _32BIT 1 + +/* use small (32K) heap for 16-bit compilers, +large (500K) heap for 32-bit compilers */ +#if defined(_32BIT) +#define HEAP_SIZE 500000uL +#else +#define HEAP_SIZE 32768u +#endif + +#define MALLOC_MAGIC 0x6D92 /* must be < 0x8000 */ + +typedef struct _malloc /* Turbo C DJGPP */ +{ + size_t size; /* 2 bytes 4 bytes */ + struct _malloc *next; /* 2 bytes 4 bytes */ + unsigned magic : 15; /* 2 bytes total 4 bytes total */ + unsigned used : 1; +} malloc_t; /* total 6 bytes 12 bytes */ + +static char *g_heap_bot, *g_kbrk, *g_heap_top; +/***************************************************************************** +*****************************************************************************/ +void dump_heap(void) +{ + unsigned blks_used = 0, blks_free = 0; + size_t bytes_used = 0, bytes_free = 0; + malloc_t *m; + int total; + + printf("===============================================\n"); + for(m = (malloc_t *)g_heap_bot; m != NULL; m = m->next) + { + printf("blk %5p: %6u bytes %s\n", m, + m->size, m->used ? "used" : "free"); + if(m->used) + { + blks_used++; + bytes_used += m->size; + } + else + { + blks_free++; + bytes_free += m->size; + } + } + printf("blks: %6u used, %6u free, %6u total\n", blks_used, + blks_free, blks_used + blks_free); + printf("bytes: %6u used, %6u free, %6u total\n", bytes_used, + bytes_free, bytes_used + bytes_free); + printf("g_heap_bot=0x%p, g_kbrk=0x%p, g_heap_top=0x%p\n", + g_heap_bot, g_kbrk, g_heap_top); + total = (bytes_used + bytes_free) + + (blks_used + blks_free) * sizeof(malloc_t); + if(total != g_kbrk - g_heap_bot) + printf("*** some heap memory is not accounted for\n"); + printf("===============================================\n"); +} +/***************************************************************************** +POSIX sbrk() looks like this + void *sbrk(int incr); +Mine is a bit different so I can signal the calling function +if more memory than desired was allocated (e.g. in a system with paging) +If your kbrk()/sbrk() always allocates the amount of memory you ask for, +this code can be easily changed. + + int brk( void *sbrk( void *kbrk( +function void *adr); int delta); int *delta); +---------------------- ------------ ------------ ------------- +POSIX? yes yes NO +return value if error -1 -1 NULL +get break value . sbrk(0) int x=0; kbrk(&x); +set break value to X brk(X) sbrk(X - sbrk(0)) int x=X, y=0; kbrk(&x) - kbrk(&y); +enlarge heap by N bytes . sbrk(+N) int x=N; kbrk(&x); +shrink heap by N bytes . sbrk(-N) int x=-N; kbrk(&x); +can you tell if you're + given more memory + than you wanted? no no yes +*****************************************************************************/ +static void *kbrk(int *delta) +{ + static char heap[HEAP_SIZE]; +/**/ + char *new_brk, *old_brk; + +/* heap doesn't exist yet */ + if(g_heap_bot == NULL) + { + g_heap_bot = g_kbrk = heap; + g_heap_top = g_heap_bot + HEAP_SIZE; + } + new_brk = g_kbrk + (*delta); +/* too low: return NULL */ + if(new_brk < g_heap_bot) + return NULL; +/* too high: return NULL */ + if(new_brk >= g_heap_top) + return NULL; +/* success: adjust brk value... */ + old_brk = g_kbrk; + g_kbrk = new_brk; +/* ...return actual delta... (for this sbrk(), they are the same) + (*delta) = (*delta); */ +/* ...return old brk value */ + return old_brk; +} +/***************************************************************************** +kmalloc() and kfree() use g_heap_bot, but not g_kbrk nor g_heap_top +*****************************************************************************/ +void *kmalloc(size_t size) +{ + unsigned total_size; + malloc_t *m, *n; + int delta; + + if(size == 0) + return NULL; + total_size = size + sizeof(malloc_t); +/* search heap for free block (FIRST FIT) */ + m = (malloc_t *)g_heap_bot; +/* g_heap_bot == 0 == NULL if heap does not yet exist */ + if(m != NULL) + { + if(m->magic != MALLOC_MAGIC) +// panic("kernel heap is corrupt in kmalloc()"); + { + printf("*** kernel heap is corrupt in kmalloc()\n"); + return NULL; + } + for(; m->next != NULL; m = m->next) + { + if(m->used) + continue; +/* size == m->size is a perfect fit */ + if(size == m->size) + m->used = 1; + else + { +/* otherwise, we need an extra sizeof(malloc_t) bytes for the header +of a second, free block */ + if(total_size > m->size) + continue; +/* create a new, smaller free block after this one */ + n = (malloc_t *)((char *)m + total_size); + n->size = m->size - total_size; + n->next = m->next; + n->magic = MALLOC_MAGIC; + n->used = 0; +/* reduce the size of this block and mark it used */ + m->size = size; + m->next = n; + m->used = 1; + } + return (char *)m + sizeof(malloc_t); + } + } +/* use kbrk() to enlarge (or create!) heap */ + delta = total_size; + n = kbrk(&delta); +/* uh-oh */ + if(n == NULL) + return NULL; + if(m != NULL) + m->next = n; + n->size = size; + n->magic = MALLOC_MAGIC; + n->used = 1; +/* did kbrk() return the exact amount of memory we wanted? +cast to make "gcc -Wall -W ..." shut the hell up */ + if((int)total_size == delta) + n->next = NULL; + else + { +/* it returned more than we wanted (it will never return less): +create a new, free block */ + m = (malloc_t *)((char *)n + total_size); + m->size = delta - total_size - sizeof(malloc_t); + m->next = NULL; + m->magic = MALLOC_MAGIC; + m->used = 0; + + n->next = m; + } + return (char *)n + sizeof(malloc_t); +} + +static inline void *kzalloc(size_t size) +{ + void *buf = kmalloc(size); + + memset(buf, 0, size); + return buf; +} + +/***************************************************************************** +*****************************************************************************/ +void kfree(void *blk) +{ + malloc_t *m, *n; + +/* get address of header */ + m = (malloc_t *)((char *)blk - sizeof(malloc_t)); + if(m->magic != MALLOC_MAGIC) +// panic("attempt to kfree() block at 0x%p " +// "with bad magic value", blk); + { + printf("*** attempt to kfree() block at 0x%p " + "with bad magic value\n", blk); + BUG(); + return; + } +/* find this block in the heap */ + n = (malloc_t *)g_heap_bot; + if(n->magic != MALLOC_MAGIC) +// panic("kernel heap is corrupt in kfree()"); + { + printf("*** kernel heap is corrupt in kfree()\n"); + return; + } + for(; n != NULL; n = n->next) + { + if(n == m) + break; + } +/* not found? bad pointer or no heap or something else? */ + if(n == NULL) +// panic("attempt to kfree() block at 0x%p " +// "that is not in the heap", blk); + { + printf("*** attempt to kfree() block at 0x%p " + "that is not in the heap\n", blk); + return; + } +/* free the block */ + m->used = 0; +/* coalesce adjacent free blocks +Hard to spell, hard to do */ + for(m = (malloc_t *)g_heap_bot; m != NULL; m = m->next) + { + while(!m->used && m->next != NULL && !m->next->used) + { +/* resize this block */ + m->size += sizeof(malloc_t) + m->next->size; +/* merge with next block */ + m->next = m->next->next; + } + } +} +/***************************************************************************** +*****************************************************************************/ +void *krealloc(void *blk, size_t size) +{ + void *new_blk; + malloc_t *m; + +/* size == 0: free block */ + if(size == 0) + { + if(blk != NULL) + kfree(blk); + new_blk = NULL; + } + else + { +/* allocate new block */ + new_blk = kmalloc(size); +/* if allocation OK, and if old block exists, copy old block to new */ + if(new_blk != NULL && blk != NULL) + { + m = (malloc_t *)((char *)blk - sizeof(malloc_t)); + if(m->magic != MALLOC_MAGIC) +// panic("attempt to krealloc() block at " +// "0x%p with bad magic value", blk); + { + printf("*** attempt to krealloc() block at " + "0x%p with bad magic value\n", blk); + return NULL; + } +/* copy minimum of old and new block sizes */ + if(size > m->size) + size = m->size; + memcpy(new_blk, blk, size); +/* free the old block */ + kfree(blk); + } + } + return new_blk; +} +/***************************************************************************** +*****************************************************************************/ + +#if 0 + +#include /* rand() */ + + +#define SLOTS 17 + +int main(void) +{ + unsigned lifetime[SLOTS]; + void *blk[SLOTS]; + int i, j, k; + + dump_heap(); + memset(lifetime, 0, sizeof(lifetime)); + memset(blk, 0, sizeof(blk)); + for(i = 0; i < 1000; i++) + { + printf("Pass %6u\n", i); + for(j = 0; j < SLOTS; j++) + { +/* age the block */ + if(lifetime[j] != 0) + { + (lifetime[j])--; + continue; + } +/* too old; free it */ + if(blk[j] != NULL) + { + kfree(blk[j]); + blk[j] = NULL; + } +/* alloc new block of random size +Note that size_t==unsigned, but kmalloc() uses integer math, +so block size must be positive integer */ +#if defined(_32BIT) + k = rand() % 40960 + 1; +#else + k = rand() % 4096 + 1; +#endif + blk[j] = kmalloc(k); + if(blk[j] == NULL) + printf("failed to alloc %u bytes\n", k); + else +/* give it a random lifetime 0-20 */ + lifetime[j] = rand() % 21; + } + } +/* let's see what we've wrought */ + printf("\n\n"); + dump_heap(); +/* free everything */ + for(j = 0; j < SLOTS; j++) + { + if(blk[j] != NULL) + { + kfree(blk[j]); + blk[j] = NULL; + } + (lifetime[j]) = 0; + } +/* after all that, we should have a single, unused block */ + dump_heap(); + return 0; +} +/***************************************************************************** +*****************************************************************************/ + +int main(void) +{ + void *b1, *b2, *b3; + + dump_heap(); + + b1 = kmalloc(42); + dump_heap(); + + b2 = kmalloc(23); + dump_heap(); + + b3 = kmalloc(7); + dump_heap(); + + b2 = krealloc(b2, 24); + dump_heap(); + + kfree(b1); + dump_heap(); + + b1 = kmalloc(5); + dump_heap(); + + kfree(b2); + dump_heap(); + + kfree(b3); + dump_heap(); + + kfree(b1); + dump_heap(); + + return 0; +} +#endif + diff --git a/tasks/mm0/src/pagers.c b/tasks/mm0/src/pagers.c index 4a7e609..82c311f 100644 --- a/tasks/mm0/src/pagers.c +++ b/tasks/mm0/src/pagers.c @@ -52,8 +52,11 @@ int default_release_pages(struct vm_object *vm_obj) /* Return page back to allocator */ free_page((void *)page_to_phys(p)); - /* Free the page structure */ - kfree(p); + /* + * Reset the page structure. + * No freeing for page_array pages + */ + memset(p, 0, sizeof(*p)); /* Reduce object page count */ BUG_ON(--vm_obj->npages < 0); diff --git a/tasks/mm0/src/shm.c b/tasks/mm0/src/shm.c index e4e4290..0eb9188 100644 --- a/tasks/mm0/src/shm.c +++ b/tasks/mm0/src/shm.c @@ -220,7 +220,7 @@ struct vm_file *shm_new(key_t key, unsigned long npages) * Fast internal path to do shmget/shmat() together for mm0's * convenience. Works for existing areas. */ -void *shmat_shmget_internal(key_t key, void *shmaddr) +void *shmat_shmget_internal(struct tcb *task, key_t key, void *shmaddr) { struct vm_file *shm_file; struct shm_descriptor *shm_desc; @@ -230,7 +230,7 @@ void *shmat_shmget_internal(key_t key, void *shmaddr) /* Found the key, shmat that area */ if (shm_desc->key == key) return do_shmat(shm_file, shmaddr, - 0, find_task(self_tid())); + 0, task); } return PTR_ERR(-EEXIST); diff --git a/tasks/mm0/src/task.c b/tasks/mm0/src/task.c index d9496e3..09dbd6f 100644 --- a/tasks/mm0/src/task.c +++ b/tasks/mm0/src/task.c @@ -512,6 +512,27 @@ void init_pm(struct initdata *initdata) start_boot_tasks(initdata); } +/* Maps and prefaults the utcb of a task into another task */ +void task_map_prefault_utcb(struct tcb *mapper, struct tcb *owner) +{ + BUG_ON(!owner->utcb); + + /* + * First internally map the tcb as a shm area. We use + * such posix semantics on purpose to have a unified + * way of doing similar operations. + */ + BUG_ON(IS_ERR(shmat_shmget_internal(mapper, + (key_t)owner->utcb, + owner->utcb))); + + /* Prefault the owner's utcb to mapper's address space */ + for (int i = 0; i < __pfn(DEFAULT_UTCB_SIZE); i++) + prefault_page(mapper, (unsigned long)owner->utcb + + __pfn_to_addr(i), VM_READ | VM_WRITE); + +} + /* * During its initialisation FS0 wants to learn how many boot tasks * are running, and their tids, which includes itself. This function @@ -535,7 +556,7 @@ int send_task_data(l4id_t requester) BUG_ON(!vfs->utcb); /* Attach mm0 to vfs's utcb segment just like a normal task */ - BUG_ON(IS_ERR(shmat_shmget_internal((key_t)vfs->utcb, vfs->utcb))); + BUG_ON(IS_ERR(shmat_shmget_internal(self, (key_t)vfs->utcb, vfs->utcb))); /* Prefault those pages to self. */ for (int i = 0; i < __pfn(DEFAULT_UTCB_SIZE); i++)