Preparation Questions

By 10pm the evening before lecture, submit 1) your answer to each lecture's question and 2) own questions via this survey link.

rustos

(optional, but highly recommended!) Are you convinced that it’s a right time to either rewrite or develop an operating system with Rust? If so, what do you think the most beneficial aspects of using Rust? If not, what are your concerns?

rusty

Watch the talk, “A Case for Oxidation: The Rust Programming Language”, given by Sergio Benitez, who originally designed the lab on RustOS.

In fact, various safety guarantees provided by Rust at compilation time are not limited to writing system software, but why Rust is particularly favorable in writing an operating system?

rust-ko

Although there have been several attempts to rewrite an OS with Rust, like Redox, it’s not any close to real-world adoption. What about incrementally _adopting_ Rust, perhaps like for writing a device driver? What are the potential benefits and challenges of writing a Linux device driver in Rust?

go-os

What are the pros and cons of using GC-backed, high-level programming language in writing an operating system? How would you compare this approach with one using Rust, like ours?

You can listen the author’s original presentation here; a few questions from audience are particularly interesting!

rust-ownership

Please carefully read these materials: Book: Ch04, and Ch 3.1 to Ch 3.6 of Nomicon Ch03.

You also find Primitive Type str, Struct std::string::String, and Primitive Type slice. very informative.

  • Q1. Explain move and copy semantics with examples

  • Q2. Compare &str with String

  • Q3. Compare &str with &String

  • Q4. Compare str with [u8; N]?

  • Q5. Compare str with [u8]?

  • Q6. Compare &str with &[u8]?

Please leave any questions to the Google form for in-class discussion.

rpi3

Watch Eben Upton’s introduction to Raspberry Pi 3.

  • What would be the benefit of supporting 64-bit (AArch64)? in particular, why it is important to support 64-bit by an operating system?

  • Have you ever used Raspberry in any chance? What was for?

intro-os

Watch Peter Denning’s talk, “Perspectives on OS Foundations”, presented at the SOSP History Day Workshop (SOSP’15).

  • What are the principles that you can observe from the modern operating systems you are using daily basis?

  • What are the principles that you see beyond operating systemes?

nostd

In rust, there are a few libraries that work without stdandard libaries, which mean we can import as part of our kernel code:

As an exercise, we’d like to make your blinky randomly fleshing the LED (1-blinky/phase4) by using a random number generator of Raspberry 3. In doing so, we’d like to use two libaries, namely, rand_core and rand.

You can modfy Cargo.toml to import two libraries in your code.

[dependencies]
rand_core = {version = "0.5.1" }
rand = {version = "0.7.3", default-features = false }

Then, your task is to implement the rest of functions in RngCore:

// Ref. https://rust-random.github.io/rand/rand_core/trait.RngCore.html#example
#[derive(Default)]
struct RdRand;

impl RngCore for RdRand {
    fn next_u32(&mut self) -> u32 {
        // implement!
    }

    fn next_u64(&mut self) -> u64 {
        // implement!
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        impls::fill_bytes_via_next(self, dest)
    }

    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        Ok(self.fill_bytes(dest))
    }
}

Then, in your kmain(), you can provide a randomly generated time to spin_sleep_ms().

let mut rng: RdRand = Default::default();
...
spin_sleep_ms(rng.gen_range(0, 1000));

You should first initialize the timer before using RdRand, so please refer rand.c and bcm2835-rng.c.

Please submit your src/main.rs!

traits

  1. How would you compare Traits to the object-oriented programming (OOP) paradigm?

  2. Pick two Traits in Vec and explain their implementation to us!

deref

struct S(i32);
impl S {
    fn func(&self) { println!("S:func({})", self.0); }
}

fn main() {
    let v = Box::new(S(1));
    v.func(); // Q. what's the type of v? whose func() is that?
}

Please first read Deref and Box::Deref.

Could you explain what’s going on? Why do we need this in Rust?

If you feel adventurous, check this Q&A in StackOverflow!

cell

let x = Rc::new(4);
let y = Rc::clone(&x);

When clone() is invoked, Rc internally increases the reference counter to prevent the object from being reclaimed.

Have you noticed that there is no mut keyword used in clone()?

If you see the definition of Rc and RcBox, the type of reference counters (both strong and weak) is Cell.

let c = Cell::new(5);
c.set(5);
println!("{}", c.get());
c.set(10);
println!("{}", c.get());

Note the variable c is not mutable. Is it really safe? What’s your reasoning behind this? You might find this document interesting.

pagealloc

Trait GlobalAlloc {
    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {}
    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {}
}

How would you compare them with malloc() and free()?

Wait, we are buliding an OS kernel. What does it mean to have an allocator? How does it different from the allocator in the uesrspace?

Please read Heap Allocation.

aarch64

Please read Fundamentals of ARMv8-A [Ch1. page 4-9] and answer following questions.

  1. Explain the concept of “Exception Level” (EL). Where is your RustOS currently running?

  2. Compare AArch32 vs. AArch64 vs. ARMv8-A?

interrupt

Please read AArch64 Exception and Interrupt Handling [Ch1. page 4-8] and answer following questions.

  1. How do “exception” and “interrupt”” differ? and how does it related to the “exception level”?

  2. What do you mean by synchronous or asynchronous exceptions?

process

Please read Scheduling: Introduction, and answer following questions.

Assume you have 5 processes P1 to P5. Compare these scheduling scenarios: 1) executing P1, P2, P3, P4 and P5 in sequence, v.s., 2) executing P1-5 based on their time quota/slice.

  1. If all processes are computation intensive tasks. Which scenario is faster in terms of the termination of all processes?

  2. In what situation, 2) would be faster in terms of the termination of all processes?

  3. Is “the termination of all processes” good way to compare scheduling polices? If not, can you think of any situation where this metrics doesn’t work?

  4. Any good suggestion to compare scheduling policies?

virtual-address

Please read The Abstraction: Address Spaces, and answer following questions:

  1. Can we use EL3 for userspace, EL0 for kernel (yes/no)? why not?

  2. Kernel can not read userspace memory (yes/no)?

  3. Userspace can not read kernel’s memory (yes/no)?

  4. Pointers in kernel are using physical address (yes/no)?

  5. Processes requiring 3GB memory cannot run on a machine with 2GB RAM (yes/no)?

etc

When designing a heap allocator, there were three critical performance optimization that the speaker emphasized: 1) TLB pollution by a heap allocator, 2) cache bouncing among objects, and 3) lock contention (e.g., increasing Magazines size when failed to hold a lock).

  1. Could you explain what are these problems, concisely?

  2. How does Rust help us (or not) to address these problems?