RustForge

rust-kernel

Rustbelt: a hobby x86_64 kernel written in Rust

rust-kernel / user / hello.rs
2160 bytes ยท raw
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
//! First user program: says hello, uses the VFS through syscalls, and checks
//! that bad syscall arguments get the right errors. Exit code = failed checks.
#![no_std]
#![no_main]

#[macro_use]
#[path = "ulib.rs"]
mod ulib;

use ulib::*;

fn check(failures: &mut i64, ok: bool, what: &str) {
    if !ok {
        println!("[hello] CHECK FAILED: {}", what);
        *failures += 1;
    }
}

fn main() -> i64 {
    let mut failures = 0;
    println!("Hello from user mode! I'm pid {}.", getpid());

    // Read a file from the ramfs.
    let mut buf = [0u8; 128];
    let fd = open("/hello.txt", 0);
    check(&mut failures, fd >= 3, "open /hello.txt");
    let n = read(fd, &mut buf);
    let text = core::str::from_utf8(&buf[..n.max(0) as usize]).unwrap_or("<not utf-8>");
    print!("[hello] /hello.txt says: {}", text);
    check(&mut failures, text.starts_with("Hello from the ramfs!"), "contents of /hello.txt");
    check(&mut failures, read(fd, &mut buf) == 0, "read at EOF returns 0");
    check(&mut failures, close(fd) == 0, "close");

    // Create a file on the second mount (/tmp), then read it back.
    let fd = open("/tmp/note.txt", O_WRONLY | O_CREAT);
    check(&mut failures, write(fd, b"written from ring 3") == 19, "write /tmp/note.txt");
    close(fd);
    let fd = open("/tmp/note.txt", 0);
    let n = read(fd, &mut buf);
    check(&mut failures, &buf[..n.max(0) as usize] == b"written from ring 3", "read back /tmp/note.txt");
    close(fd);
    println!("[hello] wrote and read back /tmp/note.txt");

    // Error cases.
    check(&mut failures, open("/does/not/exist", 0) == -ENOENT, "ENOENT");
    check(&mut failures, read(42, &mut buf) == -EBADF, "EBADF");
    check(&mut failures, close(fd) == -EBADF, "double close -> EBADF");
    // Ask the kernel to print *kernel* memory for us (0x200000 = kernel code).
    let r = syscall3(SYS_WRITE, 1, 0x20_0000, 16);
    check(&mut failures, r == -EFAULT, "kernel pointer -> EFAULT");
    check(&mut failures, syscall3(999, 0, 0, 0) == -38, "unknown syscall -> ENOSYS");

    if failures == 0 {
        println!("[hello] all syscall checks passed, exiting with 0");
    }
    failures
}