At least 4 bugs in the above C code!
int fd: fd can be negative or zerovoid *buf: buf can be nullremain = count: remain can be negative due to unmatched typebuf = (char *)buf + ret: ret can be negative, causing out-of-bound accessWhat features of Rust can help?
Same thing implemented in Rust:
fn someos_file_write(fd: FileDescriptor, buf: &mut [u8]) -> SomeOsResult<usize> {
    let count = buf.len();
    let mut written = 0usize;
    while written < count {
        let buf_slice = &mut buf[written..min(written + FS_BUF_SIZE, count)];
        let n = ipc_call(buf_slice)?;
        written += n;
        if n < buf_slice.len() {
            break;
        }
    }
    Ok(written)
}
 What if forgot min(written + FS_BUF_SIZE, count)?
let buf_slice = &mut buf[written..written + FS_BUF_SIZE];
 If written + FS_BUF_SIZE is larger than buf.len(), it'll panic:
thread 'main' panicked at 'range end index 1024 out of range for slice of length 512', src/main.rs:23:30
 A bad example in C:
void usb_request_async(int req, void *buffer, void (*callback)(int, void *)) {
    global_urb->req = req;
    global_urb->buffer = buffer;
    global_urb->callback = callback;
    usb_send_urb_async(global_urb);
}
void usb_request_cb(int req, void *buffer) { /* access buffer */ }
void func() {
    unsigned char buf[4096];
    usb_request_async(USB_REQ_GET_XXX, buf, usb_request_cb);
}
 What features of Rust can help?
Try the same in Rust (consider only immutable buffer for simplicity):
fn usb_request_async<'a>(
    req: UsbRequest,
    buffer: &'a [u8],
    callback: Box<dyn Fn(UsbRequest, &[u8]) + Send + 'static>,
) {
    std::thread::spawn(move || { // simulate async usb request callback
        callback(req, buffer);
    });
}
 error[E0759]: `buffer` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
 Change a little bit according to the error message:
fn usb_request_async(
    req: UsbRequest,
    buffer: &'static [u8],
    callback: Box<dyn Fn(UsbRequest, &[u8]) + Send + 'static>,
) {
    std::thread::spawn(move || { // simulate async usb request callback
        callback(req, buffer);
    });
}
 Then use usb_request_async:
fn usb_request_cb(req: UsbRequest, buffer: &[u8]) {
    println!("{:?}", buffer);
}
fn func() {
    let buffer: [u8; 1024] = [0; 1024];
    usb_request_async(UsbRequest::GetXxx, &buffer, Box::new(usb_request_cb));
}
 error[E0597]: `buffer` does not live long enough
 Possibly a better design:
struct Urb {
    req: UsbRequest,
    buffer: Vec<u8>,
    callback: Box<dyn Fn(UsbRequest, &[u8]) + Send + 'static>,
}
impl Urb {
    fn new(req: UsbRequest, buf_size: usize,
           callback: impl Fn(UsbRequest, &[u8]) + Send + 'static) -> Self {
        Self { req, buffer: vec![0; buf_size], callback: Box::new(callback) }
    }
}
 fn usb_send_urb_async(urb: Urb) {
    std::thread::spawn(move || { // simulate async usb request callback
        let cb = urb.callback;
        cb(urb.req, &urb.buffer);
    });
}
fn usb_request_cb(req: UsbRequest, buffer: &[u8]) {
    println!("{:?}", buffer);
}
fn func() {
    let urb = Urb::new(UsbRequest::GetXxx, 1024, usb_request_cb);
    usb_send_urb_async(urb);
}
 Features of Rust to prevent from data races:
Global static variables can't be modified safely
static mut GLOBAL_INT: u32 = 1;
fn func() {
    // bad practice
    std::thread::spawn(|| unsafe { GLOBAL_INT = 3 });
    unsafe { GLOBAL_INT = 2 }
}
 Sync// static GLOBAL_INT_BAD: RefCell<u32> = RefCell::new(1);
lazy_static! {
    static ref GLOBAL_INT: Mutex<u32> = Mutex::new(1);
}
fn func() {
    std::thread::spawn(|| *GLOBAL_INT.lock().unwrap() = 3);
    *GLOBAL_INT.lock().unwrap() = 2;
}
 Variables that are sent across threads must impl Send
fn func() {
    let shared_int = Arc::new(Mutex::new(1));
    let shared_int_clone = shared_int.clone();
    std::thread::spawn(move || *shared_int_clone.lock().unwrap() = 3);
    *shared_int.lock().unwrap() = 2;
}
 Can Rust express everything that C can?
In theory, YES, both are turing-complete.
In practice, ALMOST, with some unsafe code. When you can't implement some logic in Rust, you probably should rethink the design.
Example for booting:
#[no_mangle]
#[link_section = ".text.boot"]
extern "C" fn _start_rust() -> ! {
    #[link_section = ".data.boot"]
    static START: spin::Once<()> = spin::Once::new();
    START.call_once(|| {
        clear_bss();
        memory::create_boot_pt();
    });
    memory::enable_mmu();
    unsafe { _start_kernel() }
}
 Example for driver:
fn handle_irq(&self) {
    loop {
        let irqstat = self.read_cpu_reg(GICC_IAR);
        let irqnr = irqstat & GICC_IAR_INT_ID_MASK;
        match irqnr {
            0..=15 => crate::irq::handle_inter_processor(irqnr),
            16..=31 => crate::irq::handle_local(irqnr - 16),
            32..=1020 => crate::irq::handle_shared(irqnr - 32),
            _ => break,
        }
        self.write_cpu_reg(GICC_EOIR, irqstat);
    }
}
 Much better than C:
Compared to C++:
core and alloc crates without need for stdCall C from Rust:
extern "C" {
    fn some_function_in_c(buf: *mut u8, n: usize) -> usize;
}
fn func() {
    let mut buf = [0u8; 1024];
    let buf_raw_ptr = &mut buf[0] as *mut u8;
    let ret = unsafe { some_function_in_c(buf_raw_ptr, buf.len()) };
}
 Call Rust from C:
#[no_mangle]
extern "C" fn some_function_in_rust(buf: *mut u8, n: usize) -> usize {
    let buf = unsafe { core::slice::from_raw_parts_mut(buf, n) };
    println!("{:?}", buf); buf.len()
}
 extern size_t some_function_in_rust(unsigned char *buf, size_t n);
void func() {
    unsigned char buf[1024];
    some_function_in_rust(buf, 1024);
}
 According to The Computer Language Benchmarks Game, Rust achieves same or even better performance than C and C++.
Features that make Rust fast:
Open source projects (re)written in Rust that're proved to be fast(er):
Tools:
Example for dependency management:
[dependencies]
spin = "0.7.0"
buddy_system_allocator = { git = "https://github.com/richardchien/buddy_system_allocator.git" }
log = "0.4.0"
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
bitflags = "1.2.1"
[target.'cfg(target_arch = "aarch64")'.dependencies]
aarch64 = { git = "https://github.com/richardchien/aarch64", rev = "5dc2a13" }
 Debug trait for easy debugging:
#[repr(u8)]
#[derive(Debug)]
enum IntType {
    SyncEl1t = 1,
    IrqEl1t = 2,
    // ...
}
#[no_mangle]
extern "C" fn _handle_interrupt(int_type: IntType) {
    println!("Interrupt occurred, type: {:?}", int_type);
}
 stdSpecial thanks to Alex Chi for reviewing the slides.