Specifically, you will divide the user's memory into eight equal parts, and you will allow up to eight user processes to be in memory at any one time. There will be a timer that you can use to perform time-slicing.
Also, you will be able to compile and execute C programs under KOS that make use of malloc() and the standard I/O library.
When you are done, you will have implemented the following system calls:
/cs/faculty/rich/cs170/lib/main_lab2.o and /cs/faculty/rich/cs170/lib/libsim.a. There is a Makefile in this directory.
extern int User_base; extern int User_limit;These define what KOS addresses the user sees as its memory. When a user job is executing, its address 0 is KOS's (main_memory + User_Base), and it can use up to User_Limit bytes of memory. It is KOS's job to partition the memory that it has allocated for users to multiple processes in the correct way. A user process cannot access any memory outside of the current values of User_Base and (User_Base + User_Limit). Otherwise a segmentation violation will occur.
We also have to implement one case of ioctl() and one case of fstat(). Read the man page on ioctl(). I don't expect you to understand much about ioctl() except for its syntax. You are going to need to implement ioctl() when the first argument is 1 and the second argument is JOS_TCGETP. Your job is to fill in the third argument which is a pointer to a (struct JOStermios). You do this by calling ioctl_console_fill(char *addr), where addr is the KOS address of the third argument. Then return zero. This is probably confusing, but it must be done.
Fstat() is called by the standard I/O library in order to find out how it should buffer I/O on file descriptors 0, 1 and 2. You will service these system calls by calling stat_buf_fill(char *addr, int blk_size), where addr is the KOS address of the stat struct that the user passed to fstat(), and blk_size is the amount of buffering that the file descriptor should allow. For file descriptor zero, this should be one. For file descriptors one and two, try 256.
Last, you must implement sbrk(). Read the nearest man page for more detail. As before, the stack and the heap can collide if the user messes up. However, sbrk() should not be allowed to increase past User_limit.
When you have implemented all of these system calls, the a.out programs should be allowed to use the standard I/O library (most notably printf() and malloc()). Look at the programs in
/cs/faculty/rich/cs170/test_execs
, and try ones like hw2.c that use printf(). You can write, compile and run your own programs too -- just follow the compilation steps in Makefile.xcomp and the instructions from lab 1.
You'll need to modify the exit() system call so that instead of halting KOS, it simply terminates a process. Fork() and execve() are rather straightforward. You should ignore the third argument to execve() -- we won't have any environment variables. You also must implement wait() and process id's, which should work as in Unix. In particular, processes have parents; otherwise they are orphans. If a process exits and its parent hasn't called wait() it becomes a zombie -- it releases its memory but maintains a PCB until its parent either dies or calls wait(). Orphans must do the correct thing when they die.
To test this, run
/cs/faculty/rich/cs170/test_execs/ksh
in your version of kos.
WARNING: This is a simple shell with few features. You do not need to use it and can instead, write your own test codes.
The ksh binary is capable of running other programs. For example you can run hw from ksh thus:
./kos -a /cs/faculty/rich/cs170/test_execs/kshand you should see
KOS booting... done. Probing console... done. ksh:now run hw
ksh:/cs/faculty/rich/cs170/test_execs/hw Hello world the write statement just returned 12 ksh:The ksh binary forked and execed the hw binary and called wait() to wait for it to complete before printing the ksh: prompt again.
This binary has few features and many bugs. You can use it to test fork, exec, and wait or you can write your own test codes. If it doesn't work for you, then you must write your own test codes (which is a good idea anyway). The TAs will not be able to answer questions about ksh -- either it works for you and you trust it or it doesn't and/or you don't in which case write your own testers.
As in the last lab, there is a cook book of things that you might do to get this lab working. As before, it is not mandatory that you do things the same way that I did. However, it may make your life easier.
man getpidon your favorite Linux system in the CSIL. What you get are the header files (for the types) and the prototype for the getpid() system call. When you call getpid() on a Linux system, the program traps into the kernel and the kernel figures out how to service the call, and return the necessary values -- just like in KOS. You are implementing the KOS kernel so you have to implement the system calls that KOS supports. The ones that are specified in the lab are necessary to run a small shell called ksh. The lab gives you some details on what they should do, but for many of them, you can simply look at the man page on the CSIL systems to see what they do, what their arguments are, and what their return values are. In other words, your system calls really implement the same thing that the "real" system calls do, so the man pages are relevant.
There are some exceptions, however, which the lab points out. These have to do with the way things like the standard I/O libraries work. In these cases, the lab will tell you what values to return regardless of what the man page says.
Thus, if you find yourself a little confused over the system calls, speak to the TAs, but also consult your local man page for details.
This requirement has a few ramifications. First, this list is the file list -- not a subset of the file list. Thus, you can't include extra files and then use "#include" to include those files in these file names. The submission program will use these files and a prepared Makefile to build your program. It will not be prepared for hidden dependencies introduced by extra included files.
This requirement also means that you simply can't concatenate a bunch of files that contain your solution to create one of more of these files. The concatenation is likely to cause double definitions as header files are included multiple times which will cause your compile to fail.
Header files and libraries that are included with the makefiles we have been using in class (like libfdr, kt.h, etc.) will be referenced using the same paths that the class makefile use. Thus you should modify the class makefiles and use them as well or use the example included here.