This book rocks! I took the OS class with Remzi’s wife my junior year and it was the one that made everything “click”, bridging the gap between the computer engineering/circuits and higher-level C code we otherwise did. OSTEP and Xv6 were really integral for understanding things inside and out because we had to implement what we learned about in class.
This is a really great book for anyone interested. My professor used this in place of the more traditional book by Tanenbaum. It's easy to read and provides good citations if you want to read more in-depth about a specific chapter.
While its available completely free online, I highly recommend anyone who plans on using the book in detail to purchase a printed copy on lulu, its pretty cheap and looks really nice
It's incredibly helpful to learn by example, in my opinion. My university course taught using Xv6 as well, and the exams often included a problem where you were asked to modify a portion of the code to change behavior in a particular way (we were also asked to have the entire code printed out for reference during the exam). Probably one of my favorite courses.
Aside from being small, Xv6 is a normal OS. MINIX was designed to chase the gravely ill-advised microkernel fad that took over academia. You can lump Xv6 in with Linux and BSD, while lumping MINIX in with GNU HURD. The trouble is that glue isn't free: breaking an OS down into simple parts doesn't make the OS simple; the resulting interactions between simple parts become complex.
Xv6 is also written in a more modern coding style, using stuff like C99 initializers. It runs on modern hardware, even supporting SMP.
The jury is still out on microkernels being "gravely ill-advised". Fuchsia, for example, is a modern microkernel that works quite well.
The performance concerns that famously killed the microkernel hype are very old at this point. Modern hardware significantly reduces IPC overhead. And lots of the modern application stack (e.g. multiprocess browsers) essentially cobble together microkernel primitives out of comparatively-clunky OS features (e.g. cmsg on Unix).
I think most of Linux's success relative to microkernel designs was due to being in the right place at the right time, not due to any fundamental technical factors.
It might be for some things like performance but they're very successful for small, reliable OS's in embedded scene. Tanenbaum cited a bunch in round 2 of the debate with Torvalds:
> Modern hardware significantly reduces IPC overhead.
In case you see this comment 5 days later, can you elaborate? And do the benefits of modern hardware in this area automatically apply to IPC on existing mainstream systems, or does the OS have to specifically use the new support?
> The jury is still out on microkernels being "gravely ill-advised". Fuchsia, for example, is a modern microkernel that works quite well.
They could have said "gravely ill-adopted". You know what they meant and are grinding your personal axe here... Microkernels for all their promise aren't in widespread use. Engineers with a resume headline "I build monolithic kernel operating systems for fun" vs "I build microkernel operating systems for fun" will have significant hiring delta biased towards the monolithic specialists.
> Microkernels for all their promise aren't in widespread use.
Ah, you haven't heard about MINIX, the operating system used in the ME in modern Intel chipsets and possibly now one of the most widely deployed operating systems on the planet.
It would be worse if it were a monolithic kernel. If you're going to deploy an always-on OS in the firmware, you should at least use an OS that obeys a sensible principle of least privilege.
> Engineers with a resume headline "I build monolithic kernel operating systems for fun" vs "I build microkernel operating systems for fun" will have significant hiring delta biased towards the monolithic specialists.
Ah, I have fond memories of staring at pages of Xv6 code. I took the OS class, 6.828, which uses Xv6 as a reference, while an undergrad at MIT. While relatively simple compared to most anything else you could think up, it gave great insight and intuition into code style and idiomatic OS patterns for working on JOS, the more substantial OS you end up writing in that class.
IMHO the source code is an example of good C style, and certainly quite pleasant to read --- no excessive verbosity, gratuitous indirections, PretentiouslyCapitalisedObscenelyLongIdentifiers, unnecessarily huge indents, or any of the other annoyances I tend to find with more "modern" source code. With the exception of a few minor stylistic choices I would've done differently, it's extremely close to my preferred source style.
Unfortunate that it isn't quite completely C89 (in particular regarding placement of variable declarations), since C89 compilers are much simpler than C99 ones and otherwise a compiler course could've been created around writing a compiler (and assembler) that can compile itself, Xv6, and then itself run inside Xv6 --- to become a self-contained, self-bootstrapping OS.
I mean, it's basically licensed under MIT. If somebody really wants to do something with the OS, they can just go and fork it, then get everybody else to hack on that instead. Given upstream is dead, it shouldn't be too hard to gain traction.
Some "basic" (actually very involved, but the modern-day PC is hell) requirement to get it to run on physical hardware past 2020[1] is UEFI support. USB keyboard support is probably also a hard requirement nowadays and would basically require a full USB stack.
Rather than incorporate them into the software, small enhancements are the sort of thing the authors of the project would prefer to leave as exercises for students, I'm sure.
If I have read through the closed PRs, then obviously I have looked at the open PRs too: Makefile trivialities, homework solutions, and duplicates. Not a whole lot there.
At a glance, the code seems reasonably well commented, but it definitely assumes some prior familiarity with x86 hardware. Do you have any specific questions?
Both my undergrad and grad OS courses used xv6 and I can tell you that the easiest way to get hacking on it is to spin up a VM (I used vagrant for this since I just wanted headless) and run it in QEMU. MIT has a patched version available that has some handy debug features. Feel free to contact me through keybase and I can provide you all the scripts I used.
Does anyone know how to extend xv6 with copy-on-write? I was implementing a multiprocessing lib based on xv6 but noticed a fork copied the entire parent page table.
I think it’s a matter of extending the page fault routine to check whether the missing page is flagged copy on write, but I wasn’t sure how to correctly track which source page it should be copied from. Every process has its own clone of the page table hierarchy, so how do you know which one to grab during the fault?
When you fork, your forked process get a copy of the parent's page table i.e. at this point it points to the same physical page for xyz address as the parent. There can be a metadata bit in the final PTE that says this page is COW (Copy on Write). For context, in a 32-bit system 2 Level page table with 4KB pages means only 20 bits are used in the final page table to get the page frame. There are 12 bits free for some metadata.
Your forked process already has the physical page frame number and the COW bit. If it's a write/modify on that page and the COW is set, your code should allocate a new physical page, copy the raw contents of the currently mapped physical page and then finally update the page table entry with this new physical page frame number. If you want an example with some numbers, I can reply further. Let me know :)
If you want an example with some numbers, I can reply further.
I appreciate that. I learn best from working models. But in this case, the solution after you pointed it out is extremely obvious: if the COW bit is set, unset it and alloc+copy the page. No other information is needed.
Perhaps you know of a similarly elegant solution to the other half of what I’ve been struggling with: xv6 is 32 bit, and gives little insight on how to do paging on a 64 bit architecture. So I have two questions.
1. I notice that although pages are 4KB, xv6 uses 4MB (large paging support). How does this impact the two-level page table design? Does it simply mean that fewer entries are required, but the design is unchanged?
2. On a 64 bit architecture, what are the fundamental differences between the 2 level page table design and whatever people do in practice? This is phrased poorly. What I mean is: I am trying to blindly extend xv6’s design for a 64bit environment, but I am concerned the design might need to change. Is that true, or do people do the same thing on 64 bit? I haven’t had time to think this through yet.
To put it more simply, is there anything I should watch out for on 64 bit when doing this? Or perhaps some overall simplification / better design for 64 bit that can’t be done on 32 bit?
These are mostly speculative questions, so perhaps I should wait until I’m stuck before asking. But your answer was insightful.
I’m trying to make something people will use, and xv6 has been my only model to learn from. Any advice or references about 64 bit design for multiprocess scheduling would be useful. Especially in contexts where performance and parallelism is the concern, not necessarily security. (Anything to do with GPU design would be a delightful bonus. But I do still need traditional function calls + lexical closures.)
Made me laugh (thanks for that!), but in fairness, MINIX 3 was designed for actual usage and not just education. From Wikipedia [1]:
> Although it still serves as an example for the new edition of Tanenbaum and Woodhull's textbook, it is comprehensively redesigned to be "usable as a serious system on resource-limited and embedded computers and for applications requiring high reliability."
Wikipedia says that there's a least one company using it for an ARM TrustZone kernel[1], but I can't seem to verify that on the linked vendor's home page.
http://pages.cs.wisc.edu/~remzi/OSTEP/