Experimental OS, built with rust

Related tags

Command-line Fomos
Overview

You can support this night time project by hiring me for a day time job !

Fomos

Experimental OS, built with Rust

output.mp4

Fun fact: there are 3 apps running in the video. A background app, a cursor app, and a console app.

Why

I wanted to experiment with Non-Unix OS ideas.

Exo-kernels are interesting, but it is mostly a theory. This project helps me understand the challenges involved in that pattern.

OS development is extremely hard, Rust makes it more bearable.

Features

  • Has a graphical output
  • Dynamic allocation
  • Load and run concurrent apps
  • All apps run in an async loop
  • Support Virtio mouse and keyboard (drivers are async tasks)
  • Cooperative scheduling (apps yield control as much as possible)
  • No context switches once booted
  • Nearly support Virgl

There is 5 examples of apps in this repo named app_*, some in Rust, one in C. The kernel is in bootloader.

What is unique

The signature of an app in Fomos:

pub extern "C" fn _start(ctx: &mut Context) -> i32

Apps do not need a standard library, any OS functionality is given to the app through the Context.

the Context is mostly a pointer to a bag of kernel functionnalities

pub extern "C" fn

In Fomos, an app is really just a function. There is nothing else ! This is a huge claim. An executable for a Unix or Windows OS is extremely complex compared to a freestanding function.

<rant>

It is out a frustration for all my Glibc problems during day job dev on linux that I chose to try this approach.

I want a flat contract between an app and the OS. So what if an app was a function ? The contract is then only the explicit argument type.

In Unix, an app has to know the target OS, but also what standard library it uses, that is 2 levels of indirections. Sometimes the os level has a conflict, sometimes the standard library level has a conflict, and sometimes I just don't have the level to understand why something doesn't work. I merely know it is related.

</rant>

I am trying to know if it is possible to have an OS-App ecosystem that does not suppose ANY implicit configuration. An app would JUST have to handle its explicit start context argument.

Context gives any OS function necessary, think alloc, free, access to a framebuffer, or any hardware, any system calls etc.

That way, apps could be freestanding, and compatible on multiple OS.

More about Context

Here is the Context for the last version of this OS

#[repr(C)]
pub struct Context<'a, T> {
    pub version: u8,
    pub start_time: u64,
    pub log: extern "C" fn(s: *const u8, l: u32),
    pub pid: u64,
    pub fb: FB<'a>,
    pub calloc: extern "C" fn(usize, usize) -> *mut u8,
    pub cdalloc: extern "C" fn(*mut u8, usize, usize),
    pub store: &'a mut Option<Box<T>>,
    pub input: &'a Input,
}

Note that app_test for instance, uses an old version of the Context, and still works on the newer version of the OS

Old Context used by app_test:

#[repr(C)]
pub struct Context<'a> {
    pub version: u8,
    start_time: u64,
    log: extern "C" fn(s: *const u8, l: u32),
    pid: u64,
    fb: FB<'a>,
}

Meaning Fomos already handles gracefully Apps designed for a much older version of itself. As long as the OS stays compatible with the old stuff in the context, it can add new functionalities for other App by just appending to the context the new functions (here calloc, cdalloc, store, and input).

app_test precedes the dynamic allocation age !

Could that pattern work in the long term ?

How about system calls

None. Lets try to put everything into Context functions. No voodoo cpu instruction magic.

But how do you give back control to the OS ?

Just

return;

How do you sleep, or wait asynchronously ?

Just

return;

Apps are cooperative in Fomos, They can just return (which would exit permanently an app on a classic OS), and assume that they are gonna be called through their only function start again soon, maybe even instantly if the "system call" works that way.

But an app loses all RAM data everytime it yields that way !

No, an app can store anything it wants in Context.store during its execution, and get it back every start call. The OS keeps everything in RAM (on the heap). The stack itself is "reset". But it is not more "reset" than it is after any function execution in a normal program. You don't lose anything. In Fomos, apps are merely a single function called multiple times!

Over simplification of the kernel loop:

loop {
    for app in apps.iter_mut() {
        app._start(Context::new(...));
    }
}

There are a lot of questions without answer yet, but by now you might be curious, what if all the question had an answer in the pattern ? It looks like it could actually work (with a lot of work).

Advantages

A lot of stuff comes free once you accept the premises.

Sandboxing, instrumentation, debugging

Every functionnality and side effect given to an app goes explicitely through the Context. The Context is just a struct, we can wrap or replace anything in it. Lets instrument an app we'll call special_app. Over simplification :

loop {
    for normal_app in normal_apps.iter_mut() {
        app._start(Context::new(alloc,..));
    }
    // special_app alloc instrumentation
    fn alloc_log(..){log("allocation detected!"); return alloc(..);}
    special_app._start(Context::new(alloc_log,..));
}

Restart, sleep, change of hardware

An app memory lives in its context. The stack is fleeting. It is reset after each yield and doesn't mean much in Fomos. Since the Context is explicit, it can be stored. A restart can be made completely transparent to an app.

Pseudo code:

//kernel just started
...
let app = App::new(..);
let ctx = disk.load(app.id).unwrap_or(Context::new(..));
loop{
    app._start(ctx);
    if restart_request{
        disk.save(app.id, ctx)
        break;
    }
}
//handle restart
...

Quickload and quicksave of an app complete state is trivial. Note that some change of hardware could make an app bug. It would be a problem if it was transparent. However, it could be made opaque and obvious, in an opt-in manner, again through the Context.

Disadvantages

Security

Right now it is not implemented, any app can casually check the ram of another app ^^. This is going to be a hard problem to solve. I have plans to have data security without context switch, and without giving every damn app its own virtual memory stack.

Cooperative vs preemptive scheduling

The argument that a cooperative scheduling is doomed to fail is overblown. Apps are already very much cooperative. For proof, run a version of that on your nice preemptive system :

while(true){
  new Thread( () => {
    fs.writeFile("/home/"+randomString(),randomString())
    malloc(randomInt())
    curl("http://"+randomString()+".com")
  }
}
  • Blender does a compelling impression of that when you increase the level of details one too many times. Might fill your swap and crash unsaved work on other apps.
  • Badly written Webgl websites crash my gpu driver.

Not only is preemptive scheduling not enough, IMO it is not necessary. Also it is a spectrum. A system can be optimistically cooperative, and turn preemptive pessimistically.

However the ecosystem is made for preemptive OS. There is friction in doing things differently.

Missing

  • Permanent storage (should be easy since virtio is already implemented)
  • Gpu support (virgl wip)
  • Networking
  • A nice abstraction for apps to share data and functionnalities between themselves

The rest should live in userland.

Building

run

./build.sh

You might need rust nightly, gcc, qemu with virgl & sdl flag

More info here

Credit

Heavily inspired by Philipp Oppermann's blog.

Thanks to darbysauter for the advice given.

You might also like...
Gm microoptimisation war crime - An experimental optimisation for Garry's Mod

Wat This attractively named repository contains a Garry's Mod module that performs a micro optimisation that makes use of LuaJIT's constant folding on

Experimental implementation of the Privacy Preserving Measurement (PPM) specification.

janus Janus is an experimental implementation of the Privacy Preserving Measurement (PPM) specification. It is currently in active development. Runnin

Wraps cargo to move target directories to a central location [super experimental]

targo Wraps cargo to move target directories to a central location [super experimental] To use, cargo install --git https://github.com/sunshowers/targ

Experimental extension that brings OpenAI API to your PostgreSQL to run queries in human language.

Postgres ChatGPT Experimental PostgreSQL extension that enables the use of OpenAI GPT API inside PostgreSQL, allowing for queries to be written usi

Experimental integration of `fedimint-client` with the Leptos web frontend framework
Experimental integration of `fedimint-client` with the Leptos web frontend framework

CAUTION: highly experimental, the Database implementation is likely horribly broken Fedimint Client built with Leptos This repo contains a proof-of-co

🛠 SmartGPT is an experimental program meant to provide LLMs

🛠 SmartGPT is an experimental program meant to provide LLMs (particularly GPT-3.5 and GPT-4) with the ability to complete complex tasks without user input by breaking them down into smaller problems, and collecting information using the internet and other external sources.

RustGPT is a ChatGPT UI built with Rust + HTMX: the power of Rust coupled with the simplicity of HTMX 💚

RustGPT 🦀✨ RustGPT.Blog.Post.mp4 Welcome to the RustGPT repository! Here, you'll find a web ChatGPT clone entirely crafted using Rust and HTMX, where

Real-time CLI level meter built in Rust.
Real-time CLI level meter built in Rust.

Meter This is a very simple command line utility written in Rust for measuring the gain of a microphone. It displays the values in dBFS. This is usefu

🔭 Search Dash.app from Neovim with Telescope. Built with Rust 🦀 and Lua
🔭 Search Dash.app from Neovim with Telescope. Built with Rust 🦀 and Lua

Dash.nvim Query Dash.app within Neovim with a Telescope picker! The theme used in the recording is lighthaus.nvim. Note: Dash is a Mac-only app, so yo

Comments
  • maybe using WASM would address the security issues

    maybe using WASM would address the security issues

    Cool project!

    I was thinking that perhaps using wasm for the executables would address the security disadvantages. Processes couldn't snoop on whatever memory they wanted.

    You could start with a wasm interpreter to get something running quickly, and then use a JIT later. Also an interpreter could stop after executing some number of instructions, so a process can't hang the OS (and a JIT could instrument loops to occasionally check for excessive runtime).

    Just some thoughts. I also found this project https://github.com/kwast-os/kwast. Good luck!

    opened by wtholliday 1
  • Any future plans? Maybe a server version?

    Any future plans? Maybe a server version?

    Hi,

    Very interesting experiment. I was wondering, do you foresee any ongoing development? Any plans perhaps for a dedicated server OS? This last one sort of triggered my imagination, would be interesting to be able to work in an environment where I can extend the environment with my own functionality written in Rust, run various other services also written in Rust.

    ed

    opened by edimoldovan 9
Owner
Thomas SIMON
Software engineer, consultant Looking for work !
Thomas SIMON
Experimental engine agnostic 3D CSG library for game development written in Rust. Started as a port of csg.js to Rust.

brusher Experimental engine agnostic 3D CSG library for game development written in Rust. Started as a port of csg.js to Rust. ultimate goal My hope i

Brian Howard 17 Sep 4, 2024
Experimental Rust UI library for Audulus. "rui" is a temporary name.

Experimental Rust UI library for Audulus. "rui" is a temporary name.

Audulus LLC 1.1k Dec 28, 2022
An experimental real-time operating system (RTOS) written in Rust

An experimental real-time operating system (RTOS) written in Rust

null 0 Nov 14, 2022
Experimental language build in Rust to make it fast and robust

Reg-lang Experimental language build with Rust. Its aim is : To be simple to help learning programmation with, and in a second hand, to be robust enou

Gipson62 1 Dec 29, 2022
An experimental GUI library for Rust 🦀

guee ?? Nothing to see here ?? ... But if you insist: This is an experimental UI library I'm working on for Blackjack. The idea is to find a very prag

null 12 Feb 1, 2023
An experimental cross-platform UI framework in rust.

Cross-platform UI framework in Rust with Easy functional composasbles Flexible state management Desktop and mobile support Accessibility Native skia r

null 76 Feb 6, 2023
Cuprate, an upcoming experimental, modern & secure monero node. Written in Rust

Cuprate an upcoming experimental, modern & secure monero node. Written in Rust (there is nothing working at the moment, stay tuned if you want to see

Someone Else 16 Feb 20, 2023
🛠️ An experimental functional systems programming language, written in Rust and powered by LLVM as a backend.

An experimental functional systems programming language, written in Rust, and powered by LLVM as a backend. ?? Goal: The intent is to create a program

codex 3 Nov 15, 2023
An experimental project for rust version of Hertz written by GPT4.

Ryze: An experimental Rust Web Framework Ryze is a minimal web framework for Rust inspired by Hertz and written by GPT4. Example Here is a simple exam

Wenju Gao 3 Nov 28, 2023
An experimental, work-in-progress PAM module for Tailscale

Experimental Tailscale PAM Module This is a very very experimental Tailscale PAM module that allows you to SSH using your Tailscale credentials. This

Tailscale 129 Nov 20, 2022