The aim of this milestone is to design
the RPC
protocol for the system call interface. You should implement
both the client and system side of this interface. This
client-side system-call interface must conform to the interface
provided in libs/libsos/include
. You will be
adding to the code in libs/libsos/src/sos.c
that will
eventually contain the implementation of the
client-side sos.h
interface within the library.
libsos
defines two kinds of syscalls. Some are
prefixed with sos_sys_
and others are prefixed with
just sos_
. Syscalls starting
with sos_sys_
are called as a result of invoking musl
C library functions. Syscalls starting with just sos_
have no C library wrapper and your application code will either
invoke them directly, or you can write your own wrappers.
For example, the shell does not call sos_sys_open
directly. Instead it uses the standard C library open
function (it could also have used fopen
), musl libc will
translate this into an internal call to a POSIX style open
syscall, which is implemented in the sys_open
function
in libs/libsos/src/sys_stdio.c
. This function is a small
wrapper to extract arguments out of a va_list
and call
your sos_sys_open
function.
Not all syscalls have been implemented through musl libc as in
some cases the POSIX semantics are unnecessarily complex. You are
free to implement more of the functionality in any of the syscalls
defined in libs/libsos/src/sys_*.c
or implement
additional syscalls
from libs/libsos/src/sys_stubs.c
At this stage you will not actually be able to implement most
of the SOS (server-side) system calls, however you should be able to partially
implement sos_sys_open/sos_sys_close, sos_sys_read/sos_sys_write
for the
console
device. You should also be able to
implement sos_sys_usleep
, sos_sys_time_stamp
and sos_process_wait
, which only needs to work for
the console. In other words, you need to modify your timer driver
to be able to sleep and wake up sosh. This will allow you to run
a simple shell on your system, which will allow you to perform
interactive testing.
You should also change the implementation of sys_brk
in libs/libsos/src/sys_morecore.c
to dynamically
manage the heap memory region by implementing your own system call
to the in SOS to set the brk
point for the virtual
address space.
Other system calls defined in sos.h
should
output system call not implemented
.
When a program opens the file console
it should
access the console on the serial device. The console is a multiple
writer, single reader device, i.e., more than one process can
concurrently open the device for writing, but only one process can
open the device for reading.
Reading the console is a blocking operation. If a process reads from the console and there is no data available it should block until data becomes available.
Be careful not to implement the console device as a 'hack'. You should think about being able to support multiple serial ports and other stream devices in your design (although not necessarily implement them). This means designing a consistent interface for interacting with all devices. You may want to read up on how Linux treats devices.
You may once again find the documentation on libserial handy.
You will need to modify the libsos library to add implementations
of the interface defined in libs/libsos/include/sos.h
.
You should copy the contents of tty_test/ttyout.c to
libs/libsos/src/sos.c to import your sos_write
implementation from M0.
You will also need to add sosh to the cpio archive that is linked
to SOS and instruct SOS to run this application. Both of these tasks
are achieved through the configuration menu. Run
$ make menuconfig
and navigate to the
Applications
submenu. Move the curser to the the SOSH
application and hit space
to select it. Next, expand
the sub menu for the SOS application by navigating to the SOS
application and hitting enter
. Finally, navigate to the
Startup application
option and hit enter
to modify the option. Don't forget to save the configuration when
you exit!
At this stage of the project you will need to decide whether you want to have a simple single-threaded server, or to multi-thread it. A multi-threaded design could be advantageous to deal with the inherent concurrency your system will have (e.g. between paging, system calls, asynchronous I/O and clock interrupts), but it will require careful design of synchronisation in order to avoid race conditions and deadlocks. A single threaded model will require extra attention to ensure liveness.
Another design decision is how to transfer data between the kernel and user processes. Some options you have are:
memcpy
data into
it when you need to transfer data.Whatever you do, remember the basic engineering rule: keep it simple, stupid!(KISS).
This milestone is larger than it seems. The system call interface of an OS determines how user applications receive data they request. You will need to consider how you can move data in various quantities between your root server and clients. Scenarios to consider include:
Recall how OS/161 used an internal framework for safely transporting data between the OS and the application. The OS avoided simply reaching into application address spaces based on app-supplied pointers. You'll need to think about a framework (or at least a convention within your code) that can provide SOS with safe access to application memory. In later milestones, your approach will have to evolve to function in the presence in paging to disk, including paging application buffers.
For this assessment you should be able to demonstrate
sosh
running, and SOS outputting system call
not implemented
for the relevant SOS system calls.
sosh
makes use of the SOS system calls in its
ls
and ps
commands. This should be
sufficient to demonstrate that your SOS system calls work. Of
course, you can also write your own test code, but ensure that your
solution also works with an unmodified sosh
.
You should also show some sos application-level test code that
uses the time_stamp
and sleep
system
calls. sosh
also has some sample commands for sleeping
and getting the current time via different libc functions.
The sleep
implemention must use your
clock driver.
Demonstrate your sbrk
system call implementation
increasing the application heap size during repeated
application malloc
calls.
As always, you should be able to explain both the design and your implementation.
Note: In line with the comments in the advice section, streaming large blocks of data over multiple IPCs is a sure-fire way not to get full marks!