More and more people have shown their interests in this project, because, um hum, implementing an OS in a pure FPL is so interesting. However, if I wasn't clear
enough, I want to make it clear that I'm only studying House as a hobby project. If you find the information here useful, then great. If you feel like contributing, drop me an email at weihu AT virginia DOT edu
. I can grant you the permission to edit this site.
According to the official maintainer
, he has confirmed my bug report and integrated my fixes. As for the status of the project, it's "pretty maintenance-only". Some ongoing, but unavailable work includes HalVM from Galois Connections and probably L4. Kenny built his patches based off the HalVM patches, so that sort of explains why the patch process is kinda weird (to me).
As stated previously, House doesn't support file systems and the files must be loaded in memory by Grub. Then, you can do "run prog_name" in the shell.
The control flow of running a userland process is roughly:
execute3 (House.hs): interprets commands typed in the shell
buildUProc (UserProc.hs): sets up the context for the user process in a UProc data structure
buildAOut (AOutModel.hs): sets up the entry point and the segments
execUProc (UserProc.hs): runs "UProc", in a CPS style
execute (userspace.c): handles the magic context switching
More information can be found in the paper
I found two bugs in the code. Below is the bug report I sent to the maintainer:
To trigger the first bug, just run any program after you boot into the
shell. You'll get an error saying "Invalid page fault at 40000000."
This error happens when the process starts up and tries to access the
stack -- %esp points to 0x40000000 at startup. The valid stack range
and %esp are initialized by buildUProc defined in UserProc.hs. Because
inVRegion, the function that determines if an address is within a
given range is defined as [lower_bound, upper_bound), we should point
%esp to (endStack - 4), rather than endStack.
After fixing this bug, we can trigger the second bug by allocating <=
128M memory to the VM. Technically, this is not really a bug -- the
user processes run with no problem if the VM has >128M memory.
However, this is a bug in the sense that this behavior contradicts the
documentation and the paper. The paper suggests that user processes'
physical memory is allocated at 32M and above. However, the actual
code allocates the pages at 128M and above. This behavior is very
confusing to newcomers. I changed the USER_SPACE macro defined in
config.h back to 0x02000000 /* 32M */, and the user processes run just
fine. I'm wondering why we start user pages from 128M? Is it just for
safety so that the Haskell heap has enough space to grow? Do we have a
precise idea how much space the Haskell heap consumes?
A Haskell program needs three supporting pieces: Haskell runtime system (RTS), base Haskell libraries (e.g. Prelude definitions), and C libraries (libc, libm, libgmp, etc). The RTS and the Haskell libs have to be patched to run on bare metal
, and the tiny C libraries under support/ replace real ones.
Compared to the original monolithic patch file, the updated version divides the patch into a set of individual patch files. This is good, but the division itself is done in a somewhat confusing way. The Makefile first applies a set of patches in "halvm" and then applies patches in "house" that depends on "halvm". It looks like the halvm patches are there to port ghc to Xen, so we shouldn't be concerned. Also, some of the patches seem unnecessary. I tried to figure out the minimal patches required to support House:
- build-related configs and makefiles. They add a new backend target i386-unknown-house to ghc. This way all changes can be limited to this target only. They also disable certain features such as SMP, and avoids dependency on certain libraries such as gmp and readline.
- Haskell libraries. boot-packages is changed to remove some libraries that require OS. Makefile is changed to skip building some libraries. The base library's Prelude.hs is changed to get rid of some IO functions. base.cabal is changed to remove dependencies on some libs. Some concurrency-related files are changed. Due to the changes in the base library, other libs affected by the changes also need adjustments.
- rts is changed to remove file IO operations, profiling support, etc.
- misc files.
- Missing functions are defined in patches/new/rts/house/, and external libraries in support/.
House is compiled by ghc stage1. It would be really interesting to bootstrap ghc and make ghci runnable on House. Think about it: House's shell is ghci, and House's editor is Yi. Native APIs are Haskell functions. All processes share the RTS code. How exciting it will be! It's like the Lisp Machine resurrected!
The boot process is rougly:
Vbe-patched GRUB -> start (cbits/start.S) -> c_start (cbits/c_start.c) -> main (ghc-6.8.2/rts/Main.c in libHSrts.a) -> ... -> main (House.hs)
The original House
operating system uses a patched ghc-6.2 and must be built with gcc-3.4. There's an updated version
that uses ghc-6.8.2 and gcc-4.3. I looked at House before, and I'm going to study the updated version again. I now have a better understanding since I just happened to go through the steps of building a minimal multiboot-compliant kernel that's bootable by Grub.
The kernel is linked by the script "kernel/ldhouse", and the output is "kernel/house". "house" is then gzipped and copied to "floppy_dir/boot/kernel". Userland C programs (kernel/user/) are compiled and placed under "floppy_dir/". In the end, another script "kernel/top/mkbe2gbf" is invoked to create the floppy image from that directory.
The GUI (aka Gadget) is compiled into the kernel.
The kernel has no file system support. It relies on Grub to load the userland programs. The available programs are hardcoded in grub's config file. To build them, do "cd kernel/user; chmod +x doit; make; make install".
Makefile has the following line to create fonts:
LANG=C runhugs -h1000000 -Pkernel: createFontFile.hs >$@
Replacing it with ghc doesn't work:
LANG=C runghc6 -ikernel createFontFile.hs >$@
We get a ghc panic
saying "linkBCO: >= 64k insns in BCO". The error seems to be related to processing large files.
Besides the web page, the paper and hOp's README, kernel/README.HOUSE is also very important!
The newer version builds a 2.88M floppy instead of a 1.44M one, probably because ghc-6.8 is bigger. Qemu doesn't have any problem, but VMWare and Bochs both fail to load the floppy. We can do "make cdrom" to create a .iso file.