# Unikernels in rust

**URL:** <https://internals.rust-lang.org/t/unikernels-in-rust/2494>\
**Category:** Uncategorized\
**Created:** [August 12, 2015, 9:54pm UTC](https://internals.rust-lang.org/t/unikernels-in-rust/2494 "2015-08-12T21:54:11Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![pablochacin](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/pablochacin/32/1180_2.png) [@pablochacin](https://internals.rust-lang.org/u/pablochacin)\
**Post date:** [August 12, 2015, 9:54pm UTC](https://internals.rust-lang.org/t/unikernels-in-rust/2494/1 "2015-08-12T21:54:11Z")

</div>

[MirageOS](https://mirage.io/) is a library operating system that constructs [unikernels](http://queue.acm.org/detail.cfm?id=2566628) for secure, high-performance network applications across a variety of cloud computing and mobile platforms. The MirageOS crew has [been discussing the idea of using Rust as a language for a Unikernel](http://lists.xenproject.org/archives/html/mirageos-devel/2015-07/msg00091.html). The idea of this post is to bring together people interested in the idea and explore the real traction withing both communities.

---

<div class="post-metadata">

**Author:** ![steveklabnik](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steveklabnik/32/4524_2.png) [@steveklabnik](https://internals.rust-lang.org/u/steveklabnik)\
**Post date:** [August 12, 2015, 10:53pm UTC](https://internals.rust-lang.org/t/unikernels-in-rust/2494/2 "2015-08-12T22:53:01Z")

</div>

One reason I suggested this post for internals rather than users was that the “Write an OS in Rust” use-case still requires the use of nightly features.

Sorting out what we can do to help out people with these kinds of projects, and getting them to work on stable Rust, would be awesome.

---

<div class="post-metadata">

**Author:** ![Gankra](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/gankra/32/6002_2.png) [@Gankra](https://internals.rust-lang.org/u/Gankra)\
**Post date:** [August 12, 2015, 11:01pm UTC](https://internals.rust-lang.org/t/unikernels-in-rust/2494/3 "2015-08-12T23:01:56Z")

</div>

I don’t see kernel dev being stable for quite a while. no\_std still has a long way to come.

Otherwise, it wasn’t clear to me that kernels had any particularly novel requirements? inline asm and repr packed for dealing with hardware stuff, _maybe_? I was under the impression you kinda have to do everything from scratch, so there’s not a lot for us to provide other than making it as easy as possible to not have dependencies and to have precise control over certain operations.

---

<div class="post-metadata">

**Author:** ![aturon](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/aturon/32/3272_2.png) [@aturon](https://internals.rust-lang.org/u/aturon)\
**Post date:** [August 13, 2015, 4:48am UTC](https://internals.rust-lang.org/t/unikernels-in-rust/2494/4 "2015-08-13T04:48:00Z")

</div>

> [@Gankra](#):
>
> no\_std still has a long way to come.

We were talking today about having the basic `no_std` case fully stable by 1.4; basically this just entails stabilizing `libcore` and the crate-level attribute, both of which are fairly straightforward.

---

<div class="post-metadata">

**Author:** ![Geal](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/geal/32/1171_2.png) [@Geal](https://internals.rust-lang.org/u/Geal)\
**Post date:** [August 13, 2015, 8:25am UTC](https://internals.rust-lang.org/t/unikernels-in-rust/2494/5 "2015-08-13T08:25:50Z")

</div>

libcore still needs some dependencies that may not make sense in an embedded or kernel contexte: libpthread, libc and libm. From what I see, libm can still be useful, unless num gets separated from libcore. Libpthread is less useful when you want to write your own scheduler. What is libc used for in core, importing malloc?

Basically, for very low level code, reimplementing basic blocks of the system is not a problem, that’s part of the deal. But what must be reimplemented is a bit fuzzy, at least for me.

In the [code](https://github.com/Geal/mini-os/blob/rust/rust-mm/src/lib.rs) I’m writing with the MirageOS people, I just need the `no_std`, `lang_items` and `core` features.

---

<div class="post-metadata">

**Author:** ![pablochacin](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/pablochacin/32/1180_2.png) [@pablochacin](https://internals.rust-lang.org/u/pablochacin)\
**Post date:** [August 13, 2015, 1:13pm UTC](https://internals.rust-lang.org/t/unikernels-in-rust/2494/6 "2015-08-13T13:13:48Z")

</div>

@Geal. Could you please elaborate on what are you doing with mirageos? Maybe this will shed some light to the extend rust can be used to develop low level code not backed by os libraries. Thanks.

---

<div class="post-metadata">

**Author:** ![SimonSapin](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/simonsapin/32/3158_2.png) [@SimonSapin](https://internals.rust-lang.org/u/SimonSapin)\
**Post date:** [August 13, 2015, 1:28pm UTC](https://internals.rust-lang.org/t/unikernels-in-rust/2494/7 "2015-08-13T13:28:09Z")

</div>

> [@Geal](#):
>
> libcore still needs some dependencies that may not make sense in an embedded or kernel contexte: libpthread, libc and libm.

Does it? [The crate’s doc-comment](https://github.com/rust-lang/rust/blob/e9205a20a8a22ab066b6596502cafc036fd4557c/src/libcore/lib.rs#L11-L44) says “It links to no upstream libraries, no system libraries, and no libc.”

---

<div class="post-metadata">

**Author:** ![Geal](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/geal/32/1171_2.png) [@Geal](https://internals.rust-lang.org/u/Geal)\
**Post date:** [August 13, 2015, 4:35pm UTC](https://internals.rust-lang.org/t/unikernels-in-rust/2494/8 "2015-08-13T16:35:33Z")

</div>

I said “unikernels are cool, I want to do one in Rust” and went to the MirageOS people for advice. They proposed that I replace parts of Xen’s MiniOS (the bare minimum OS to run something above Xen) in Rust. That way, I don’t have to write everything from scratch to target Xen, and they could use the code right away.

MiniOS is quite small: it boots, starts some memory paging system, a scheduler, a console, and a bus to talk with the hypervisor. I am currently working on replacing the memory paging, so I’m mostly manipulating pointers.

---

<div class="post-metadata">

**Author:** ![Geal](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/geal/32/1171_2.png) [@Geal](https://internals.rust-lang.org/u/Geal)\
**Post date:** [August 13, 2015, 4:38pm UTC](https://internals.rust-lang.org/t/unikernels-in-rust/2494/9 "2015-08-13T16:38:39Z")

</div>

The compiler indicates that those libs are still necessary. In fact, If I carelessly play with numbers, it will use core::num, which will directly require libm to link correctly.

On #rust-osdev, Tobba compiled a l[ist of tips to work with low level Rust](https://gist.github.com/Tobba/5720dc8ee4d32606062c), which include using link time optimization to remove the code depending on those libraries.

---

<div class="post-metadata">

**Author:** ![eefriedman](https://avatars.discourse-cdn.com/v4/letter/e/ec9cab/32.png) [@eefriedman](https://internals.rust-lang.org/u/eefriedman)\
**Post date:** [August 13, 2015, 6:33pm UTC](https://internals.rust-lang.org/t/unikernels-in-rust/2494/10 "2015-08-13T18:33:10Z")

</div>

[https://github.com/rust-lang/rust/issues/27200](https://github.com/rust-lang/rust/issues/27200) has a complete list of the symbols libcore depends on.

The expectation is that you’ll link against libgcc plus a small library defining a few other necessary functions like memcpy.

---

<div class="post-metadata">

**Author:** ![lnmx](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/lnmx/32/1179_2.png) [@lnmx](https://internals.rust-lang.org/u/lnmx)\
**Post date:** [August 14, 2015, 8:08pm UTC](https://internals.rust-lang.org/t/unikernels-in-rust/2494/11 "2015-08-14T20:08:49Z")

</div>

FYI, MirageOS already depends on openlibm. It is introduced in the [mirage-xen-posix](https://github.com/mirage/mirage-platform/blob/master/xen-posix/mirage-xen-posix.pc) package, which fills in some gaps between Mini-OS and the OCaml runtime.

---

<div class="post-metadata">

**Author:** ![talex5](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/talex5/32/1174_2.png) [@talex5](https://internals.rust-lang.org/u/talex5)\
**Post date:** [August 15, 2015, 11:59am UTC](https://internals.rust-lang.org/t/unikernels-in-rust/2494/12 "2015-08-15T11:59:05Z")

</div>

Note that apparently you can’t link against libgcc on x86\_64, because it assumes a red zone exists, which isn’t the case for kernel code:

- [http://osdir.com/ml/general/2014-11/msg31036.html](http://osdir.com/ml/general/2014-11/msg31036.html)
- [http://lists.xen.org/archives/html/xen-ia64-devel/2008-02/msg00251.html](http://lists.xen.org/archives/html/xen-ia64-devel/2008-02/msg00251.html)

---

<div class="post-metadata">

**Author:** ![pablochacin](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/pablochacin/32/1180_2.png) [@pablochacin](https://internals.rust-lang.org/u/pablochacin)\
**Post date:** [August 15, 2015, 12:03pm UTC](https://internals.rust-lang.org/t/unikernels-in-rust/2494/13 "2015-08-15T12:03:31Z")

</div>

Sorry if I’m saying something extremely naive or uninformed , but I don’t understand much of this discussion about if it is possible when there’s actually a [bare bones rust kerne](https://github.com/thepowersgang/rust-barebones-kernel)l I haven’t tried it yet, but apparently it boots in bare metal.

---

<div class="post-metadata">

**Author:** ![Ericson2314](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ericson2314/32/246_2.png) [@Ericson2314](https://internals.rust-lang.org/u/Ericson2314)\
**Post date:** [August 25, 2015, 5:08am UTC](https://internals.rust-lang.org/t/unikernels-in-rust/2494/14 "2015-08-25T05:08:46Z")

</div>

In addition to the points mentioned, I think there are some interesting unanswered questions about what lifetimes _mean_ in the context of context-switching / scheduling code, and how they can or can’t be exploited to make such code safer. I expect similar issues as those we faced with scoped threads to pop up.

Also, there are a number of library considerations: e.g. custom allocators, more crates behind the facade (including moving hash{set,map} to libcollections).

There are also a couple proposed language features that are extra relevant with freestanding development:

- `&in` `&out` and `&uninit` are more essential when working with inline assembly, as passing things larger than a register by value is simply not an option.
- GC integration might help MirageOS and HalVM in particular

@pablochacin The issue is while such things can be, the experience is less nice than it could be. I’d like to see freestanding Rust beat freestanding C as much as hosted Rust beats hosted C, but we just aren’t there yet.

---

<div class="post-metadata">

**Author:** ![pablochacin](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/pablochacin/32/1180_2.png) [@pablochacin](https://internals.rust-lang.org/u/pablochacin)\
**Post date:** [September 1, 2015, 11:58am UTC](https://internals.rust-lang.org/t/unikernels-in-rust/2494/15 "2015-09-01T11:58:50Z")

</div>

@Ericson2314

> In addition to the points mentioned, I think there are some interesting unanswered questions about what lifetimes mean in the context of context-switching / scheduling code

My understanding is that on a unikernel, by definition, there is neither context-switching nor scheduling as in traditional multi-application/process kernels.

---

<div class="post-metadata">

**Author:** ![ehiggs](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ehiggs/32/3224_2.png) [@ehiggs](https://internals.rust-lang.org/u/ehiggs)\
**Post date:** [September 1, 2015, 8:46pm UTC](https://internals.rust-lang.org/t/unikernels-in-rust/2494/16 "2015-09-01T20:46:11Z")

</div>

> My understanding is that on a unikernel, by definition, there is neither context-switching nor scheduling as in traditional multi-application/process kernels.

[Threads on Linux are implemented in terms of processes](http://www.informit.com/articles/article.aspx?p=370047&seqNum=3). So there are issues of context switching for the stack and scheduling as with processes. Are Unikernels always single threaded? It seems like it would be a tedious limitation.

---

<div class="post-metadata">

**Author:** ![pablochacin](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/pablochacin/32/1180_2.png) [@pablochacin](https://internals.rust-lang.org/u/pablochacin)\
**Post date:** [September 2, 2015, 10:05am UTC](https://internals.rust-lang.org/t/unikernels-in-rust/2494/17 "2015-09-02T10:05:36Z")

</div>

> [@ehiggs](#):
>
> Are Unikernels always single threaded? It seems like it would be a tedious limitation.

No, but I was thinking more on this approach:

> "In MirageOS, the OCaml compiler receives the source code for an entire kernel's worth of code and links it into a stand-alone native-code object file. It is linked against a minimal runtime that provides boot support and the garbage collector. There is no preemptive threading, and the kernel is event-driven via an I/O loop that polls Xen devices." - [Unikernels: Rise of the Virtual Library Operating System](http://queue.acm.org/detail.cfm?id=2566628)

Does the context switching concern still apply here?

---

<div class="post-metadata">

**Author:** ![Geal](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/geal/32/1171_2.png) [@Geal](https://internals.rust-lang.org/u/Geal)\
**Post date:** [September 2, 2015, 10:20am UTC](https://internals.rust-lang.org/t/unikernels-in-rust/2494/18 "2015-09-02T10:20:16Z")

</div>

In a unikernel, you implement your own scheduler. You have to think in terms of cores instead of threads. On a single core, threads simulate multiple parallel running code. This is something that can be implemented with green threading, coroutines, etc. This happens more or less the same way on a traditional OS, except that processes separate the memory.

Of course, it gets harder if you want to address multiple cores.

---

<div class="post-metadata">

**Author:** ![pablochacin](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/pablochacin/32/1180_2.png) [@pablochacin](https://internals.rust-lang.org/u/pablochacin)\
**Post date:** [September 2, 2015, 10:34am UTC](https://internals.rust-lang.org/t/unikernels-in-rust/2494/19 "2015-09-02T10:34:35Z")

</div>

> [@Geal](#):
>
> Of course, it gets harder if you want to address multiple cores.

Good point.

---

<div class="post-metadata">

**Author:** ![Ericson2314](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ericson2314/32/246_2.png) [@Ericson2314](https://internals.rust-lang.org/u/Ericson2314)\
**Post date:** [September 18, 2015, 3:19am UTC](https://internals.rust-lang.org/t/unikernels-in-rust/2494/20 "2015-09-18T03:19:36Z")

</div>

Yeah I meant context switching and scheduling with threads. Consider making scoped threads from coroutines. I have a library where threads pass their current continuation to the new thread on context switches along with other data.

Consider:

1. Thread A switches to thread B, also passes pointer stack variable
2. Thread B switches back to thread A
3. Thread A switches back to thread B
4. Thread B uses the pointer

This is unsafe because the relevant stack frame in A could no longer be valid. The way to fix this is to ensure that the pointer may not outlive the continuation (which is consumed when switching back).

I think existential lifetimes (an I idea I came up with elsewhere) would accomplish this. Intuitively, there is a lifetime bound between the continuation and the pointer. But since the lifetime depends on A’s stack, there is no good “name” for it from B’s perspective, nor is it related to B’s other lifetimes. The thing to do is introduce a fresh lifetime (the “existential lifetime”) and say that the context outlives it but the pointer doesn’t.

[Next page](https://internals.rust-lang.org/t/unikernels-in-rust/2494.md?page=2)
