diff --git a/README b/README index 866afec..7e1ab74 100644 --- a/README +++ b/README @@ -33,8 +33,8 @@ the project is written from scratch, so the name emphasises that. Design & Features: -Codezero microkernel: Based on L4 microkernel principles, there are only a few -system calls and the microkernel provides purely mechanism; threads and address +Based on L4 microkernel principles, there are only a few system calls in +Codezero. These system calls provide purely mechanism; threads and address spaces, and the methods of inter-process communication between them. Anything beyond these are policy and they are implemented in the userspace. Due to this rigorously simple design the same microkernel can be used to design completely @@ -42,13 +42,13 @@ different operating systems. In terms of other features, the microkernel is preemptive, and smp-ready. Currently only synchronous communication is implemented, but this will change in the near future. -MM0: Implements memory management. It contains memory and page allocators. It -implements demand paging by managing page faults, physical pages and their -file/task associations. +MM0 is the systm task that implements memory management. It contains memory and +page allocators. It implements demand paging by managing page faults, physical +pages and their file/task associations. -FS0: Implements a simple, modern virtual filesystem layer. Since it abstracts -the low-level filesystem details, it is a relatively easy job to port a new -filesystem to be used under FS0. +FS0 is the system task implements a simple, modern virtual filesystem layer. +Since it abstracts the low-level filesystem details, it is a relatively easy job +to port a new filesystem to be used under FS0. License: @@ -65,9 +65,9 @@ party source code is open source in the OSI definition. Please check these directories for their respective licenses. -Why yet another Posix (micro) kernel? +Why yet another POSIX microkernel? -There are many open source Posix operating systems with advanced features such +There are many open source POSIX operating systems with advanced features such as *BSD and Linux. However these were originally not designed for embedded systems. Unix itself and all the tools built upon weren't meant for using on small devices. Accordingly, these operating systems contain a lot of historical diff --git a/include/l4/lib/bit.h b/include/l4/lib/bit.h index 858e403..94bd191 100644 --- a/include/l4/lib/bit.h +++ b/include/l4/lib/bit.h @@ -4,6 +4,7 @@ unsigned int __clz(unsigned int bitvector); int find_and_set_first_free_bit(u32 *word, unsigned int lastbit); int check_and_clear_bit(u32 *word, int bit); +int check_and_set_bit(u32 *word, int bit); /* Set */ diff --git a/include/l4/lib/idpool.h b/include/l4/lib/idpool.h index 9787a77..c3d9668 100644 --- a/include/l4/lib/idpool.h +++ b/include/l4/lib/idpool.h @@ -11,5 +11,6 @@ struct id_pool { struct id_pool *id_pool_new_init(int mapsize); int id_new(struct id_pool *pool); int id_del(struct id_pool *pool, int id); +int id_get(struct id_pool *pool, int id); #endif /* __IDPOOL_H__ */ diff --git a/src/api/thread.c b/src/api/thread.c index 3c4697b..28102f6 100644 --- a/src/api/thread.c +++ b/src/api/thread.c @@ -83,11 +83,29 @@ int thread_create(struct task_ids *ids) copy_pgd_kern_all(new->pgd); /* Get new space id */ - ids->spid = id_new(space_id_pool); + if (ids->spid == TASK_ID_INVALID) { + ids->spid = id_new(space_id_pool); + printk("Got new space id: %d\n", ids->spid); + } else { + printk("Try new space id: %d\n", ids->spid); + if ((ids->spid = id_get(space_id_pool, ids->spid)) < 0) + ids->spid = id_new(space_id_pool); + else + printk("Success.\n"); + } spc_found: /* Get a new thread id */ - ids->tid = id_new(thread_id_pool); + if (ids->tid == TASK_ID_INVALID) { + ids->tid = id_new(thread_id_pool); + printk("Got new thread id: %d\n", ids->tid); + } else { + printk("Try new thread id: %d\n", ids->tid); + if ((ids->tid = id_get(thread_id_pool, ids->tid)) < 0) + ids->tid = id_new(thread_id_pool); + else + printk("Success.\n"); + } /* Set all ids */ set_task_ids(new, ids); diff --git a/src/glue/arm/init.c b/src/glue/arm/init.c index f2b27be..d46ca84 100644 --- a/src/glue/arm/init.c +++ b/src/glue/arm/init.c @@ -250,7 +250,7 @@ void switch_to_user(struct ktcb *task) jump(task); } -void init_inittask(char *name, struct task_ids *ids) +void init_pager(char *name, struct task_ids *ids) { struct svc_image *taskimg = 0; struct ktcb *task; @@ -262,7 +262,7 @@ void init_inittask(char *name, struct task_ids *ids) * This also solves the problem of freeing the bootstack and making use * of the initial kspace pgd. */ - if (!strcmp(name, "mm0")) + if (!strcmp(name, __PAGERNAME__)) task = current; /* mm0 is the mockup current during init */ else task = (struct ktcb *)zalloc_page(); @@ -341,7 +341,7 @@ void init_tasks() * This must come last so that other tasks can copy its pgd before it * modifies it for its own specifics. */ - init_inittask("mm0", &ids); + init_pager(__PAGERNAME__, &ids); } void start_kernel(void) diff --git a/src/lib/bit.c b/src/lib/bit.c index e0f1810..27f9988 100644 --- a/src/lib/bit.c +++ b/src/lib/bit.c @@ -50,3 +50,15 @@ int check_and_clear_bit(u32 *word, int bit) } } +int check_and_set_bit(u32 *word, int bit) +{ + /* Check that bit was clear */ + if (!(word[BITWISE_GETWORD(bit)] & BITWISE_GETBIT(bit))) { + word[BITWISE_GETWORD(bit)] |= BITWISE_GETBIT(bit); + return 0; + } else { + //printf("Trying to set already set bit\n"); + return -1; + } +} + diff --git a/src/lib/idpool.c b/src/lib/idpool.c index 6869e7b..3745dd3 100644 --- a/src/lib/idpool.c +++ b/src/lib/idpool.c @@ -33,3 +33,14 @@ int id_del(struct id_pool *pool, int id) return ret; } +/* Return a specific id, if available */ +int id_get(struct id_pool *pool, int id) +{ + int ret = check_and_set_bit(pool->bitmap, id); + + if (ret < 0) + return ret; + else + return id; +} + diff --git a/tasks/fs0/include/vfs.h b/tasks/fs0/include/vfs.h index d1874da..b753d1f 100644 --- a/tasks/fs0/include/vfs.h +++ b/tasks/fs0/include/vfs.h @@ -71,6 +71,7 @@ static inline struct superblock *vfs_alloc_superblock(void) { struct superblock *sb = kmalloc(sizeof(struct superblock)); INIT_LIST_HEAD(&sb->list); + return sb; } diff --git a/tasks/fs0/src/memfs/memfs.c b/tasks/fs0/src/memfs/memfs.c index 3d38f21..42e8699 100644 --- a/tasks/fs0/src/memfs/memfs.c +++ b/tasks/fs0/src/memfs/memfs.c @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include #include #include @@ -138,11 +140,16 @@ struct superblock *memfs_get_superblock(void *block) struct memfs_superblock *sb = block; struct superblock *vfs_sb; + printf("%s: %s: Reading superblock.\n", __TASKNAME__, __FUNCTION__); /* We don't do sanity checks here, just confirm id. */ - if (!strcmp(sb->name, "memfs")) + if (strcmp(sb->name, "memfs")) { + printf("%s: Name does not match: %s\n", __FUNCTION__, sb->name); return 0; - if (sb->magic != MEMFS_MAGIC) + } + if (sb->magic != MEMFS_MAGIC) { + printf("%s: Magic number not match: %s\n", __FUNCTION__, sb->magic); return 0; + } /* Allocate a vfs superblock. */ vfs_sb = vfs_alloc_superblock(); @@ -154,6 +161,10 @@ struct superblock *memfs_get_superblock(void *block) /* Registers sfs as an available filesystem type */ void memfs_register_fstype(struct list_head *fslist) { + /* Initialise superblock list for this fstype */ + INIT_LIST_HEAD(&memfs_fstype.sblist); + + /* Add this fstype to list of available fstypes. */ list_add(&memfs_fstype.list, fslist); } diff --git a/tasks/mm0/include/kdata.h b/tasks/mm0/include/kdata.h index d941c83..d2fbbee 100644 --- a/tasks/mm0/include/kdata.h +++ b/tasks/mm0/include/kdata.h @@ -16,8 +16,6 @@ #include INC_ARCH(bootdesc.h) #include -#define BOOTDESC_IMAGE_START 1 - struct initdata { struct bootdesc *bootdesc; struct list_head boot_file_list; diff --git a/tasks/mm0/main.c b/tasks/mm0/main.c index 8b0c60e..6ff48ae 100644 --- a/tasks/mm0/main.c +++ b/tasks/mm0/main.c @@ -34,7 +34,7 @@ void handle_requests(void) u32 tag; int err; - printf("%s: Initiating ipc.\n", __TASKNAME__); + // printf("%s: Initiating ipc.\n", __TASKNAME__); if ((err = l4_receive(L4_ANYTHREAD)) < 0) { printf("%s: %s: IPC Error: %d. Quitting...\n", __TASKNAME__, __FUNCTION__, err); @@ -55,7 +55,7 @@ void handle_requests(void) * A thread that wants to sync with us would have * started here. */ - printf("%s: Synced with waiting thread.\n", __TASKNAME__); + // printf("%s: Synced with waiting thread.\n", __TASKNAME__); break; case L4_IPC_TAG_PFAULT: diff --git a/tasks/mm0/src/init.c b/tasks/mm0/src/init.c index e191b1e..3f64246 100644 --- a/tasks/mm0/src/init.c +++ b/tasks/mm0/src/init.c @@ -50,44 +50,13 @@ void init_mm(struct initdata *initdata) l4_kmem_grant(__pfn(alloc_page(__pfn(SZ_1MB))), __pfn(SZ_1MB)); } -/* Create temporary run-time files in memory to test with mmap */ -void init_boot_files(struct initdata *initdata) -{ - struct vm_file *f; - struct svc_image *img; - struct bootdesc *bd = initdata->bootdesc; - - INIT_LIST_HEAD(&initdata->boot_file_list); - for (int i = BOOTDESC_IMAGE_START; i < bd->total_images; i++) { - img = &bd->images[i]; - if (!(!strcmp(img->name, "fs0") || !strcmp(img->name, "test0"))) - continue; /* Img is not what we want */ - - f = kzalloc(sizeof(*f)); - INIT_LIST_HEAD(&f->list); - INIT_LIST_HEAD(&f->page_cache_list); - list_add(&f->list, &initdata->boot_file_list); - - /* - * For boot files, we use the physical address of the memory - * file as its inode. - */ - f->inode.i_addr = img->phys_start; - f->length = img->phys_end - img->phys_start; - f->pager = &default_file_pager; - } -} - void initialise(void) { request_initdata(&initdata); init_mm(&initdata); - init_boot_files(&initdata); - // printf("INITTASK: Initialised mock-up bootfiles.\n"); - init_pm(&initdata); - // printf("INITTASK: Initialised the memory/process manager.\n"); + printf("%s: Initialised the memory/process manager.\n", __TASKNAME__); } diff --git a/tasks/mm0/src/task.c b/tasks/mm0/src/task.c index 5e6ad8e..356f7ed 100644 --- a/tasks/mm0/src/task.c +++ b/tasks/mm0/src/task.c @@ -8,6 +8,7 @@ #include #include #include +#include #include INC_GLUE(memory.h) #include #include @@ -72,17 +73,62 @@ struct tcb *create_init_tcb(struct tcb_head *tcbs) return task; } +/* Create temporary run-time files in memory to test with mmap */ +struct vm_file *create_init_vmfile(struct list_head *vmfile_head) +{ + struct vm_file *file = kzalloc(sizeof(*file)); + + INIT_LIST_HEAD(&file->list); + INIT_LIST_HEAD(&file->page_cache_list); + list_add(&file->list, vmfile_head); + + return file; +} + int start_boot_tasks(struct initdata *initdata, struct tcb_head *tcbs) { - struct vm_file *file; int err; + struct vm_file *file; + struct svc_image *img; + unsigned int sp, pc; + struct tcb *task; + struct task_ids ids; + struct bootdesc *bd = initdata->bootdesc; INIT_LIST_HEAD(&tcb_head.list); - list_for_each_entry(file, &initdata->boot_file_list, list) { - struct tcb *task = create_init_tcb(tcbs); - unsigned int sp = align(USER_AREA_END - 1, 8); - unsigned int pc = USER_AREA_START; - struct task_ids ids = { .tid = task->tid, .spid = task->spid }; + INIT_LIST_HEAD(&initdata->boot_file_list); + + for (int i = 0; i < bd->total_images; i++) { + img = &bd->images[i]; + + /* Skip self */ + if (!strcmp(img->name, __PAGERNAME__)) + continue; + + /* Set up task ids */ + if (!strcmp(img->name, __VFSNAME__)) { + ids.tid = VFS_TID; + ids.spid = VFS_TID; + } else { + ids.tid = -1; + ids.spid = -1; + } + + /* Set up task's registers */ + sp = align(USER_AREA_END - 1, 8); + pc = USER_AREA_START; + + /* Create vm file and tcb */ + file = create_init_vmfile(&initdata->boot_file_list); + task = create_init_tcb(tcbs); + + /* + * For boot files, we use the physical address of the memory + * file as its mock-up inode. + */ + file->inode.i_addr = img->phys_start; + file->length = img->phys_end - img->phys_start; + file->pager = &default_file_pager; /* mmap each task's physical image to task's address space. */ if ((err = do_mmap(file, 0, task, USER_AREA_START, @@ -102,7 +148,7 @@ int start_boot_tasks(struct initdata *initdata, struct tcb_head *tcbs) /* mmap each task's utcb as single page anonymous memory. */ if ((err = do_mmap(0, 0, task, (unsigned long)__L4_ARM_Utcb(), VM_READ | VM_WRITE | VMA_ANON, 1) < 0)) { - printf("do_mmap: Mapping stack failed with %d.\n", err); + printf("do_mmap: Mapping utcb failed with %d.\n", err); goto error; } @@ -113,8 +159,8 @@ int start_boot_tasks(struct initdata *initdata, struct tcb_head *tcbs) goto error; } - printf("New task with id: %d, space id: %d\n", ids.tid, ids.spid); /* Use returned space and thread ids. */ + printf("New task with id: %d, space id: %d\n", ids.tid, ids.spid); task->tid = ids.tid; task->spid = ids.spid; @@ -154,7 +200,9 @@ void send_task_data(l4id_t requester) int li, err; if (requester != VFS_TID) { - printf("Task data is not requested by FS0, ignoring.\n"); + printf("%s: Task data requested by %d, which is not " + "FS0 id %d, ignoring.\n", __TASKNAME__, requester, + VFS_TID); return; } diff --git a/tasks/test0/main.c b/tasks/test0/main.c index 6ed7223..4a0e118 100644 --- a/tasks/test0/main.c +++ b/tasks/test0/main.c @@ -16,11 +16,11 @@ void wait_pager(l4id_t partner) { - printf("%s: Syncing with pager.\n", __TASKNAME__); + // printf("%s: Syncing with pager.\n", __TASKNAME__); for (int i = 0; i < 6; i++) write_mr(i, i); l4_send(partner, L4_IPC_TAG_WAIT); - printf("Pager synced with us.\n"); + // printf("Pager synced with us.\n"); } void main(void)