diff --git a/README b/README index 6313d5d..ca9fed4 100644 --- a/README +++ b/README @@ -44,10 +44,11 @@ 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 is the system 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. It provides the default paging mechanism -on Codezero. +There are two system tasks built upon the base microkernel that manage memory +and file-based I/O, called MM0 and FS0. MM0 is the system 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. +It provides the default paging mechanism on Codezero. FS0 is the system task that implements a simple, modern virtual filesystem layer. It is designed to serve file requests from MM0. Since it abstracts the low-level @@ -118,19 +119,30 @@ more closely. Many embedded software projects still use older or closed development methods and the right open source methodology would prove favorable in the fast-paced nature of embedded software development. -Finally, POSIX compliance is only a step, or a temporary aim for the Codezero +Finally, POSIX compliance is only a step, or a partial aim for the Codezero microkernel. It is not limited to the goal of just complying with POSIX, which -has been done many times by other operating systems. There are new ideas in -literature that would improve systems software but aren't implemented either -because they have no existing users or may break compatibility (e.g. some are -presented in Plan 9). For example file abstractions could be used more -liberally to cover data exchange and control of devices, services and network -communication. Existing kernels already have established methods of doing such -operations and they would oppose major design overhauls, which limits their -innovation capability for this kind of experimentation. As well as practising -realistic development strategies such as POSIX compliance, Codezero project aims -to keep up with the latest OS literature and provide the opportunity to -incorporate the latest ideas in OS technology. +has been done many times by other operating systems. The idea is to implement +a generic software environment where multiple system services can reside in +the same run-time, but on the other hand, provide natively implemented resource +management services to be used as the default solution. In other words, the +project will provide the mechanism to accomodate multiple operating systems, +and it will also supply its own set of system services with a POSIX-like API. +By providing a variety of system-level software options, the applications +will be able to choose among different speed, safety, determinism policies at +the same run-time. This is expected to prove useful in embedded software +problems. + +Furthermore there are new ideas in literature that would improve systems +software but aren't implemented either because they have no existing users or +may break compatibility (e.g. some are presented in Plan 9). For example file +abstractions could be used more liberally to cover data exchange and control of +devices, services and network communication. Existing kernels already have +established methods of doing such operations and they would oppose major design +overhauls, which limits their innovation capability for this kind of +experimentation. As well as practising realistic development strategies such as +native POSIX support, Codezero project aims to keep up with the latest OS +literature and provide the opportunity to incorporate the latest ideas in OS +technology. Can you summarise all this? Why should I use Codezero, again? @@ -138,13 +150,14 @@ Can you summarise all this? Why should I use Codezero, again? Codezero is an operating system that targets embedded systems. It supports the most fundamental posix calls and it implements modern features such as demand-paging and virtual filesystem layer. Different from most other posix-like -systems, it is based on a microkernel design. It has a cleanly separated set of -services, it is small and well-focused. Its design is carefully thought out, so -it's not just a mock-up implementation of the existing POSIX API. Its source -code is also freely available (See LICENSE heading). For these reasons it is a -good candidate as systems software to be used on embedded platforms. Currently -it has little or no users, therefore compared to systems with a saturated user -base it is possible to tailor it rapidly towards the needs of any users who want -to be the first to incorporate it for their needs. +systems, it is based on a microkernel design. This makes it possible to use it +also as a base for implementing or running other operating systems. It has a +cleanly separated set of system services, it is small and well-focused. Its +design is carefully thought out, so it's not simply a mock-up implementation of +the existing POSIX API. Its source code is also freely available (See LICENSE +heading). For these reasons it is a good candidate as systems software to be +used on embedded platforms. Currently it has little or no users, therefore +compared to systems with a saturated user base project developers are available +to tailor it rapidly towards the needs of any interested users. diff --git a/src/api/thread.c b/src/api/thread.c index 80bc054..0fd717d 100644 --- a/src/api/thread.c +++ b/src/api/thread.c @@ -62,6 +62,14 @@ int thread_start(struct task_ids *ids) /* * Creates a thread, with a new thread id, and depending on whether the space * id exists, either adds it to an existing space or creates a new space. + * + * NOTE: Add: Depending on whether the thread id exists, it creates a new space + * copying the space of that thread id. + * + * For example: + * thread id = inval, space id = inval, -> new thread, new space. + * thread id = x, space id = inval, -> new thread, new space, copying space of x + * thread id = inval, space id = x, -> new thread, use space x. */ int thread_create(struct task_ids *ids) { diff --git a/tasks/libposix/fork.c b/tasks/libposix/fork.c new file mode 100644 index 0000000..8fbc255 --- /dev/null +++ b/tasks/libposix/fork.c @@ -0,0 +1,46 @@ +/* + * l4/posix glue for fork() + * + * Copyright (C) 2008 Bahadir Balban + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include INC_GLUE(memory.h) + +static inline int l4_fork(void) +{ + int err; + + /* Call pager with open() request. Check ipc error. */ + if ((err = l4_sendrecv(PAGER_TID, PAGER_TID, L4_IPC_TAG_FORK)) < 0) { + printf("%s: L4 IPC Error: %d.\n", __FUNCTION__, err); + return err; + } + /* Check if syscall itself was successful */ + if ((err = l4_get_retval()) < 0) { + printf("%s: OPEN Error: %d.\n", __FUNCTION__, err); + return err; + } + return err; +} + +int fork(void) +{ + int ret = l4_fork(); + + /* If error, return positive error code */ + if (ret < 0) { + errno = -ret; + return -1; + } + /* else return value */ + return ret; + +} + diff --git a/tasks/mm0/include/syscalls.h b/tasks/mm0/include/syscalls.h index 390580c..8fc3e46 100644 --- a/tasks/mm0/include/syscalls.h +++ b/tasks/mm0/include/syscalls.h @@ -43,5 +43,7 @@ struct sys_shmget_args { int sys_shmget(key_t key, int size, int shmflg); +int sys_fork(void); + #endif /* __MM0_SYSARGS_H__ */ diff --git a/tasks/mm0/main.c b/tasks/mm0/main.c index 60ef1b7..f15aa7a 100644 --- a/tasks/mm0/main.c +++ b/tasks/mm0/main.c @@ -100,7 +100,7 @@ void handle_requests(void) case L4_IPC_TAG_CLOSE: sys_close(sender, (int)mr[0]); break; - + case L4_IPC_TAG_FSYNC: sys_fsync(sender, (int)mr[0]); break; @@ -120,6 +120,10 @@ void handle_requests(void) args->flags, args->fd, __pfn(args->offset)); break; } + case L4_IPC_TAG_MMAP: { + sys_fork(sender); + break; + } case L4_IPC_TAG_BRK: { // sys_brk(sender, (void *)mr[0]); // break; diff --git a/tasks/mm0/src/clone.c b/tasks/mm0/src/clone.c index 7f1f8bf..c88b16c 100755 --- a/tasks/mm0/src/clone.c +++ b/tasks/mm0/src/clone.c @@ -3,7 +3,7 @@ * * Copyright (C) 2008 Bahadir Balban */ - +#include int copy_tcb(struct tcb *p, struct tcb *c) { @@ -28,20 +28,33 @@ int do_fork(struct tcb *parent) { struct tcb *child; + /* Make all parent shadows read only */ + vm_freeze_shadows(parent); + /* Create a new L4 thread with new space */ l4_thread_create(parent); /* Create a new local tcb */ child = tcb_alloc_init(); - /* Make all parent shadows read only */ - vm_freeze_shadows(parent); - /* Copy parent tcb to child */ copy_tcb(struct tcb *parent, struct tcb *child); - /* FIXME: Copy parent page tables to child ??? */ - /* FIXME: Copy parent register values to child ??? */ + /* + * Allocate and copy parent pgd + all pmds to child. + * + * When a write fault occurs on any of the frozen shadows, + * fault handler creates a new shadow on top, if it hasn't, + * and then starts adding writeable pages to the new shadow. + * Every forked task will fault on every page of the frozen shadow, + * until all pages have been made copy-on-write'ed, in which case + * the underlying frozen shadow is collapsed. + * + * Every forked task must have its own copy of pgd + pmds because + * every one of them will have to fault on frozen shadows individually. + */ + + /* FIXME: Need to copy parent register values to child ??? */ /* Notify fs0 about forked process */ vfs_send_fork(parent, child); diff --git a/tasks/test0/main.c b/tasks/test0/main.c index 0e01e84..a1d3304 100644 --- a/tasks/test0/main.c +++ b/tasks/test0/main.c @@ -10,7 +10,8 @@ #include #include #include - +#include +#include void wait_pager(l4id_t partner) { @@ -23,23 +24,32 @@ void wait_pager(l4id_t partner) void main(void) { + pid_t pid; + printf("\n%s: Started with tid %d.\n", __TASKNAME__, self_tid()); /* Sync with pager */ wait_pager(0); dirtest(); - printf("File IO test 1:\n"); - if (fileio() == 0) - printf("-- PASSED --\n"); - else - printf("-- FAILED --\n"); - printf("File IO test 2:\n"); - if (fileio2() == 0) - printf("-- PASSED --\n"); - else - printf("-- FAILED --\n"); + printf("Forking...\n"); + if ((pid = fork()) < 0) + printf("Error forking...\n"); + + if (pid == 0) { + printf("File IO test 1, done by child:\n"); + if (fileio() == 0) + printf("-- PASSED --\n"); + else + printf("-- FAILED --\n"); + } else { + printf("File IO test 2, done by parent, with child pid %d:\n", pid); + if (fileio2() == 0) + printf("-- PASSED --\n"); + else + printf("-- FAILED --\n"); + } while (1) wait_pager(0); #if 0