Okay. Thank you. Thank you, Rassan. Actually, after hearing your talk, I'm kind of considering
I should join the Unicraft community. Sounds to be fun there.
It's a threshold there, Kim.
Yeah, I see.
Well, you don't have to test it.
Okay. So, my name is Simon Kunzer. As you now heard, I'm the lead maintainer, also the
original person that started that Unicraft project while being still a researcher at
NEC Labs Europe. In the meantime, we spinned off. We have now a startup also called Unicraft.
It's the Unicraft GmbH, and I'm their CTO and co-founder. And, yeah, we're building
a community and a startup at the same time.
So first question into the room. Who has used Unicraft before? I would like to know. Okay.
Who has maybe more theoretical background, what our key concepts in Unicraft are? Okay.
So then, yeah, also, I have some background slides to bring everybody on the same stage.
And then we jump directly into the binary compatibility topic, but I won't spend too
much time here. Okay.
So with this picture, I usually start that. You see on the left side the traditional setup
when you have virtual machines and your applications running on them, so stuff that you know since
20 years now. Then you have a setup which is more recent and more popular is using containers
where you basically run a host address on your hardware and then you use isolation primitives
on your host kernel to separate your containers from each other. And then there's Unicurnals.
I don't know. Is this interrupted somewhere? Okay.
So we think this could be a different execution environment, especially for the container
setup bringing kind of marriage what you had before with virtual machines with strong isolation
and really more minimal hypervisors underneath that are much more secure as well. And don't
need to do a shared host base which can become an attack surface. And then you want the flexibility
of containers and this is where we think a Unicurnal can come in, so where you build
a kernel per application.
So the thing is, since you know the application that you run on, you can also give up a lot
of principles you had in standard operating systems and do simplifications which is totally
okay because it's not hitting your attack vector actually. So if you say one application
you can go for a flat and single address space because that kernel that you have underneath
is just for your application for nothing else.
We in Unicraft build a single monolithic binary usually, so it's your application plus the
kernel layers and everything ends up in function calls into drivers. And you get then further
benefits, first by this simple setup, but also since you know your environment, you
know where you run on, you know what you run, so you can specialize the kernel layers that
you need underneath. So you put only drivers that you need to run on your target hypervisor.
You build a separate image if you run that application on a different hypervisor. So
floppy drivers, forget it, you don't need it. VertiU only for KVM guests, Zen NetFront
for instance, only for Zen guests. And you know the application, you have knowledge
which features of the OS is needed and that way you can also from the top down specialize
the operating system to just provide that what you need. So this makes us also slightly
different from the other Unicraft projects maybe that you had heard of, so we are for
sure not the first ones. But we claim we are the ones that follow at least this principle
as the most strongest because we build it from the beginning with that in mind, which
is specialization. So everything that we implement should never dictate any design principles.
The concept is you know what you need for your application, you know what you need to
run your Unicron, so I want to give you a highly customizable base where you pick and
choose and configure of components and specialize the kernel layers for you. So that led us
to this principle, everything is a micro library, which means for us even OS primitives are
micro libraries, meaning a scheduler is a micro library, a specific scheduler implementation
is a micro library, so like a cooperative scheduler or some schedulers do preemptive scheduling,
different libraries, memory allocators, also things like VFS, network stacks, the architectures,
the platform supports and the drivers are all libraries and because we are also going
up the stack the application interfaces, so everything that has to do with POSIX even
that is split it into multiple subsystems, POSIX subsystem libraries. The Linux system
called ABI, which you will see in this talk now, and even language runtimes, if you let's
say run a JavaScript Unicron, you can build it with a JS engine. And the project consists
basically of a Kconfig based configuration system and a build system, also make based
to not come up with yet another build system, to make actually entrance easy when people
are familiar with Linux before, and our library pool actually. And to give you a rough idea
how this library pool is organized, I find this diagram nice, so let's see if this works
at this point. Yeah, so we divide roughly, so you don't find it that way in the repos,
but we divide roughly the libraries into these different categories, so you have like here
on the bottom, the platform layer, which basically includes drivers and platform support
where you run on. Then we have this OS preemptive layer, these are then libraries that implement
like a TCP IP stack, or file systems, or something regarding scheduling, memory allocation,
et cetera, et cetera. And then always in mind there's like, first the opportunity for you
to replace components in here, and also that we provide also alternatives, so you don't
need to stick with IP if you don't like it, so you can provide your own network stack
here as well, and reuse the rest of the stack too. Then we have this POSIX compatibility
layer, this is basically, you know, things here, FD tab, this is for instance file descriptor
handling, as you know it. POSIX process has then aspects about process IDs, process handling,
et cetera, pthread API, of course. And then we have a libc layer, where we also have at
the moment actually three libcs, muscle, which is becoming our main thing now, a new lib
that we had in the past, to actually provide all the libc functionally to the application,
but also actually for the other layers too, right, it provides also things like memcopy,
which is like all over the place used, right. Okay. Then Linux application compatibility,
that was now a big topic for this release. Why do we do application compatibility? It's
actually for us, for adoption, to drive the adoption, because most cloud software is developed
for Linux. People are used to their software, so we don't feel confident to ask them to
use something new or rewrite stuff from scratch. And if you provide something like Linux compatibility,
you remove also obstacles that people start using Unicraft, because they can run their
application with Unicraft. And our vision behind the project is to give seamless application
support. So the users that say, they tell you, I use that in that web server, and it
should be like with a push of a button, so including with some tooling that we provide,
that we can run that on Unicraft as they run it before on Linux, and they benefit from
all these nice unicolonial properties, which are lower boot times, less memory consumption,
and also improved performance. Okay. So now, speaking about which possibilities you have
for supporting Linux compatibility, we divide actually compatibility into two main tracks.
One track is so-called native, which means that we have the application sources, and
we compile that together and link that together with the Unicraft build system. And then we
have on the other side, the binary compatibility mode, where the story is that the application
is built externally, and we just get binary artifacts, or the final image event. And then
actually you can subdivide these two tracks on the native side. We have, which we did
actually quite a lot until recently, this Unicraft-driven compilation, which basically
meant that when you have your application, you have to port or mimic the application's
original build system with the Unicraft build system, and then you compile all the sources
with Unicraft. It has the benefit that you're then staying in one universe and don't have
potential conflicts with compiler flags or things that, I mean, influence your calling
conventions between objects. And then there is this way that you probably have also seen,
for instance, with RUM kernels. They did it a lot using an instrumented way, where you
actually utilize the build system of an application with the cross-compile feature, and then,
you know, you hook in, and that's your entry point into replacing the compile calls and
make it fit for your Unicom. And then on the binary compatibility side, we have, so let's
start here, because that's easier. So, of course, so externally built, and this means
basically you have ELF files, so like a shared library or an ELF application. What you need
here is basically just to support loading that and get that into your address space,
and then run it. And then there's also this flavor of, let's say, build time linking,
which means that you take some build artifacts from the original application build system,
like the intermediate object files, before it does a final link to the application image,
and you link those together with the Unicraft system. And they call it here binary compatible,
because, you know, you interface it on an API, right, and not on the API level, like
in the native cases. So, and here, this is just a little mark that in the Unicraft project,
you will mostly find these three modes in the project that people are working on. So,
here we, that we never tried with Unicraft, in fact. But I mean, there's some tooling
and this should work, too, actually. So, as you may have noticed, native is about
API compatibility, so really on the programming interface, and binary compatibility is about
the application binary interface. So, really, the compiled, sorry, the compiled artifacts
and how you have calling conventions here, et cetera, where your arguments in which register
or how's your stack layout, et cetera, right? And this is, this is here on a programming
language level, right? So, the requirements for providing you, let's say, a native experience
is POSIX, POSIX and POSIX, right? Most applications are written for POSIX, so we have to do POSIX,
no excuse, right? So, libcs will mostly cover that. But, yeah, it's all about POSIX. And
the second point is that you also need to port the libraries that your application additionally
uses. Let's say, yeah, let's take engine access and web. So, right, you have then tons of
library dependencies, for instance, for cryptographic things, like setting up HTTPS tunnels or doing
some other things. So, those libraries, you need also, you know, port here and add them
so that you have the, you know, the application sources available during the build, right?
On the binary compatibility side, the requirements are, you need to understand the L format, share
libraries or binaries, depending on which level you're driving it. And then, since this
stuff got built for Linux, you must be aware that it can happen that that binary will do
directly system calls. So, it's instrumented because it got built together with a libc
or something like that to do an syscall assembly instruction, which means on our side, we need
to be able to handle those system calls as well. And if we, you know, speak about shared
library support, we need to support all this library function or library symbol linking,
actually, right? And additionally, of course, each data that is exchanged, right, needs
to be in the same representation. This means, because this is ABI, right? Now imagine you
have a C struct. And here, it's fine to move some fields around, because if you use the
same definition for your compilation, it's all fine. You can sort the fields in the struct,
it will all work. Here, you can't because your application that got built externally,
that layout of that struct, that binary layout, that must fit. Otherwise, you will read different
fields, right, obviously. And then for both modes, which is important for us as an operating
system, we have, of course, also some things that we need to provide to the application,
which are things that the application just requires, because it is that way on Linux,
meaning providing a procfs or sysfs entries or files in slash etc. or something like that,
because, you know, they do sometimes silly things just to figure out in which time soon
they are, so they go to slash etc. and figure out what is configured and also the locales
and etc. So, I'm closing that, let's say, this high level view up, so that we have the
full understanding. Let's speak a bit about the pros and cons between these two modes.
The native side, what is really nice here, which is a really interesting pro, so if you
got everything put together, you have quite of a natural way to change code in the application,
to change code in the kernel, to make maybe shortcuts between the application kernel interaction
and can use that for driving your specialization even further and performance tune your unique
kernel for the application. The disadvantages, you always need the source codes, because
we are compiling everything here together, and which is also, let's say, for newcomers
a bit difficult, is if you require them that the application they have, and they say, okay,
I have the source codes, and I just run make and then it compiles, but I have the source
code, you need to instrument either the build system of the application, as we just saw
with the instrumented build that also ramped it, or you actually, we must say, okay, sorry,
you can't use that build system, now you need to mimic and write and Unicraft make file
equivalent to build your application. So, this is why binary compatibility is actually
interesting, really interesting for, let's say, newcomers, because you don't need the
source code, they can compile the application that they're interested in, so if they need
to compile it, let's say, right, the way as they usually do, they don't need to care about
Unicraft at all, and normally, also no modifications to the application is needed. Obviously, you
can still do things here, but it's not a requirement.
The risk that we saw by doing the work is, at least for the, let's say, on the unicolonial
side, is that you get into a risk that you need to implement things the way how Linux
does it, and one really stupid example, I get a bit nuts on that, is providing an implementation
for netlink sockets, because if you have, like, a web application, or, you know, any
application that does some networking, and that application wants to figure out which
network interfaces are configured, and what are the IP addresses there, so it will likely
lose the libc function get if address, and that is implemented with a netlink socket,
so this goes back here, right, here I can just provide a get if address, which is highly
optimized in that sense, right, which just returns in that struct all the interfaces,
but if I go binary compatible, and if I do it really on an extreme, means, because that
libc, which is part of your binary here, maybe, opens a socket, which is address family netlink,
and starts communicating about a socket with the kernel to figure out the interface addresses,
which can be really silly, right, for a unicolon, right, to do.
And then also, it's, maybe it's less opportunities, but also a bit harder to specialize and tune
the kernel application interaction, right, because assuming you don't have access to
the source code of the application, there's nothing you can do on the application side.
So to give you a rough idea, what that means in performance, because at Unicraft, let's
say, the second important thing for us is always performance, performance, performance.
Here we just show you engine x here compiled as a native version, so meaning it uses the
Unicraft build system to build the engine x sources versus we run engine x on, we call
it elf loader, so this is actually our Unicraft application to load elf binaries.
And then a comparison here with a standard Linux, and here this is the same binary.
What that means in performance, so this quick test, we have just the index page, the standard
default of any engine x installation served, and these are like the performance numbers.
The takeaway here is, if you just, you know, don't go into any special performance tuning
yet, and start just, you know, getting the thing compiled and run, you will end up in
a similar performance as if you just take the, you know, the elf loader to run that
application in binary compatibility mode.
That is interesting because you don't need to see necessarily huge performance drops.
The only thing that you lose is the potential to further optimize in this mode if you go
for this one.
But the nice thing is you can still see benefits, right, running your application on Unicraft.
And to just give you an impression, so this is here a Go HTTP application, where we go
a bit crazy about optimizing and specializing the interaction between the Go application
and Unicraft, yeah, we can get more out of this.
We can really performance tune and squeeze stuff out of it.
Okay, so now in the next slides, I go over how we implement these modes with Unicraft,
because as I said, we don't want to target just one mode, we want to target multiple
modes.
And it has also some implementation challenges, because as an engineer, you also want to
reuse code as much as possible.
So we'll talk about the structure here.
Okay, so to give you an overview, so this doesn't mean now that these applications run at the
same time, it could also be possible, but it's just to show you how the components get involved
in our ecosystem.
So if you take just the left part, the native port of application, we settle now on muscle
to provide all the libc functionality that the application needs.
And we have a library called syscall shim, which is actually the heart of our application
compatibility.
And this is actually, you can imagine, this is a bit of a registry where it knows where
in which sub-library a system called handler is implemented.
And it can forward then the muscle calls to those places.
On the binary compatibility side, you have a library called this elf loader, which is
the library that loads an elf binary into memory.
And then here's the syscall shim, taking care of handling binary system calls.
Now I will go into the individual items to show you a bit more zoomed in view what's
happening there.
And we, of course, will start with the heart, with the core, the syscall shim.
So here we have macros, so when you develop VFS queries, our VFS library actually ported
from OSV, or POSIX process, where you do some process functionality, like get PID or
something like that.
We have some macros that help you to define a system call handler.
And it's really a system call handler, it's just a function that is defined at that point.
And you will register this to the syscall shim.
Then the shim provides you two options, how that system call handler can be reached.
One is at compile time.
This is like macros, macros, and preprocessor, which allows you, when you have a native application
that does, or actually it's on the muscle side, to call a system call, it will replace
those calls or will return at compile time the function of that library that implements
that system call.
Then it also has a runtime handler, which is provided here, which does the typical syscall
chop and running that function behind the scenes.
Our aim, as I mentioned, we want to reuse code as much as possible.
The idea is that we implement that function for that system call just once, and the syscall
shim is helping us, depending on the mode, doing a link, or providing it as binary compileable.
So let's go back to the overview, and then you will see it a bit more concrete with muscle,
but probably I said everything already.
So we have muscle natively compiled with a Unicraft build system.
Now imagine you have the application, you have a write, goes to muscle, and muscle does
then a UK syscall R write, which is then actually the symbol that is provided by the
actual library that's implementing it.
And the rewriting happens, as I said, with the macros at compile time in lib muscle.
So what we did for that is to replace that syscall muscle internal function with our
syscall macro, which then kicks in the whole machinery to map a system call request to
the direct function call.
The thing is that in muscle, not all, but most of the system call requests have a static
argument with the system call number first.
So this, let's say, write is a libc wrapper, and internally there, they're setting, preparing
the arguments, maybe some checks before they go to the kernel, and then they have this
syscall function with the number of the system call, and then the arguments hand it over.
And as soon that number is a const static, just written down in your code literally,
we can do a direct mapping so that that write will directly do a function call with UK syscall
R write.
If it's not static, which is really happening only on two, three places, if I remember correctly,
then of course we can provide an intermediate function that then does a switch case and
jumps then to the actual system call handler.
And the thing is, since everything is configurable, means I can have a build where VVScore is
not part of the build or POSIX process is not part of the build.
Then the syscall scene will automatically, also with all this macro magic that we do,
replace calls to non-existing system call handers with an inosys stop, so that for the
applications look like a function not implemented.
And exactly, so at runtime the syscall shim is for that port out of the game, so everything
happens at compile time.
So for the binary compatibility side, that's unfortunately a runtime thing, and we have
actually two components here.
As I was mentioning, the ELF loader itself, which loads the ELF application.
What we support today is static pies, so if you have a static position independent executable
compiled, you can run that.
And what also works is using your, let's say, with your libc together provided dynamic linker,
meaning if you use glibc with the application, you can use that dynamic linker, so ld.so,
and also run dynamically linked applications with that.
What it needs is POSIX M-app as a library, which implements all these M-app, M-unm-app,
M-protect functions on the system call there.
Then system calls are trapped here in the syscall shim, and yeah, I think as I said that, when
the library is not selected, it's replaced with enosys, so the syscall shim knows which
system calls are available, which are not.
Then there's a bit of a specialty for handling a system call, so the system call trap handler.
So we provide it with a system call shim, and we don't need to do a domain switch, so
we have still a single address space, a single, what's called, I forgot the word, so it's
all kernel privilege, yeah, so we have, it's the same privilege domain, exactly, so we don't
have a privilege domain switch as well, right, now we have it, good, good, good, if you learn
it.
But we are slightly in a different environment, I will show you later in the slide exactly
what this means.
We have some different assumptions that you have on the Linux system call API, which requires
us to do some extra steps, unfortunately.
So the first thing is Linux does not use extended register, or if they use it, they
guard it, meaning extended registers are floating point units, vector units, MMX, SSE, you know.
We do, unfortunately, so we need to save that state, because that's unexpected for an application
that was compiled for Linux before, that these units could screw up when coming back from
a system call.
And the second thing is we don't have a TLS, you know, in the Linux kernel, but unfortunately
on Unicraft we have, so we use the same, even unfortunately the same TLS register, so we
also need to save and restore that so that the application keeps its TLS, and all the
Unicraft functions operate on the Unicraft TLS, good.
So I'll continue and give you some, let's say, lessons learned while implementing all
these things.
I would like to give you a short demo.
And then we speak a bit about what was tricky during the implementation and what are our
special considerations that we had to do.
So then let's hope that this works.
So this is a super fresh demo, don't touch it, you will burn your fingers.
My colleagues, so thank you, Mark, for getting that work, just, you know, half an hour before
the talk.
Well, it's the person that no one sees, but that's all the work.
Yeah, he's amazing, yeah.
Okay, so in this demo I have actually NGINX, it's a web server with a standard file system,
I'll show you a bit of the files around.
I have it once compiled natively, and once compiled as a Linux application, we'll run
it with the Elf loader, and you will see that the result is the same.
So let's start with the native one.
So I'm actually already, so probably I need to increase a bit the size, right, that you
can read it in the background.
Is that good?
Yeah.
Let's do it here too.
So I hope you can, also in the last row you can read, perfect.
So yeah, you have here the NGINX app checked out.
So we have menu config, so you can, oh, this window is somehow wider, no, just one second.
No, it's better, okay.
So you see, the application is here as a library here, lib NGINX, and then you have here the
configuration of all these HTTP modules that NGINX provides, and you can select and choose,
like this is really the Unicraft way to do things.
Because it builds a while, and for that my left side is not the fastest, I built it already.
So you see here the result of the build directory, you see each individual library that, because
of dependencies, where we're coming in and we're compiled, so like for instance POSIX
few tags, POSIX socket, RAMFS, which is an in-memory file system, and the, where is it
now, the application, here, that's the application image uncompressed, so what I can do.
So let's see how big it is.
So it's here 1.1 megabyte, so this is like a full image of NGINX, including muscle, including
all the kernel code and driver to run on a KEMU KVM X-rated machine.
Yeah, then let's run it, to see what happens, so exactly it's already up and running, to
show you, these were roughly the arguments, so we have them in the meantime, because I
found KEMU systems sometimes a bit brutal with command line arguments, a wrapper script
that shortens a few things, but in the end, I mean, this is running a KEMU system, and
then, you know, it's attaching to this virtual bridge, take that kernel image, load that
in ID file system, because we reserve a file from that RAMFS, and here's also some parameters
to set the IP address and that mask for that guest, and here and down there, so we can
check actually, you see here set IPv4, that's the address where the unicorn is up, and yeah,
you see here, with this W get line that, yeah, I get the page surfed, and to prove that this
is real, let us kill this, now the guest is gone, and this is dead, so no response anymore,
good, so now, let's go to the ELF loader, which is also treated as an application that
can run other applications, also here in the build directly, let's do the same thing, so
it has also like similar dependencies, of course, it's prepared to run NGINX, so POSIX
socket is there, et cetera, et cetera, where's the, here, so here's the image, it's a bit
smaller, it's now 526 kilobytes, which provides your environment to run, and Linux ELF, of
course the NGINX image is not included here anymore, right, so that is part of the root
file system, and if I run this now, so on purpose I enable now some debug output so that you
see the proof that it does system calls, but if you scroll up, so the initialization phase
looks a bit different, also sets the IP address, here it's extracting the INIDAR-D, and here
it's starting to load the NGINX binary, the Linux binary from the INIDAR-D, and then from
that point on, the ELF loader was jumping into the application, and you see every system
call that the application was doing, and you can even see that, you know, some stuff, probably
this is a first GWC initialization, here for instance an ETC local time, it's trying to
open and find some configuration, of course we don't have it, we could provide one, but
it's still fine, it's continuous booting, affinity, we don't have, but whatever, it
continues booting.
It's quite optimistic actually, but it works, a lot of files, if you look into proxies,
get PWName, all those items, it works, it works.
Yeah, yeah, exactly, and there's tons of Mabs, and you know, EDC password, etc, so those
files we had provide, so you get a file script returned back, otherwise it would have stopped,
etc, and then, you know, configuration, and so forth, and now you should see that some
system call happened when I accessed the page, and you saw it happened, index was opened,
file script is 7, and here is, there should be a write to the socket, you know, over here
this is probably the socket number 4, yeah, I mean, you get the impression what's going,
what's going on, right, so it's working the same way, okay, how much time do I have left?
Five minutes?
Five minutes, okay, then?
Actually three minutes, just to leave some room for questions.
Yeah, yeah, exactly, okay, so let's get quickly back.
So we had some learned lessons, learned lessons, for the native mode, I mean, the thing is
we have also this model, like you heard on OSV, we want to use just one libc in our build,
right, so meaning all the kernel implementation, and everything that the application needs
is one libc, we provide multiple implementations of libcs, because muscle might be for some
use cases too thick, still, or too big, so we have an alternative like no libc, and originally
we had new lib, and we need, so what we want as well in our project is to keep the libc
as vanilla as possible, like upstream as possible, because we want to keep the maintenance
effort for updating the libc versions low.
But these courses then, I mean, just list them, I speak just about one of these items,
some things that you stumble on, and one was quite interesting, was this get dense 64 issue
that cost us some headache, it was mainly a rust wound fixing it, which caused, or required
actually a patch.
I'm only fixing it.
Yeah, yeah, required a patch to muscle.
The thing what happened here is that in this drn.h, muscle is providing an alias, right,
to use the non-64 version for get dense, and if it finds code with using get dense 64 because
of this large file system support thing that was happening, it maps it to get dense, right.
On the other side, on the VFS core side, so this is the VFS implementation where we provide
the system call, we need to provide both, obviously, we need to provide the non-64 version
and the 64 version, and guess what, we include drn because we need a struct definition here.
And then you can imagine, so if you're familiar with CMP processor, there's a little hint
with this thunder, of course, I mean, this gets replaced, and then you have two times
the same symbol, and you're like, what the hell is going on here, all right.
So let's skip this because of time.
Upcoming features, Ruslan was telling a bit already, especially for this topic for application
compatibility, we will further improve it, so this will be now our first release to officially
release alpha loader and an updated muscle version.
We want to make that more seamless, which requires a bit more under the hood libraries
for that support.
You should also watch out for features that are coming up for a seamless integration of
Unicraft into your Kubernetes deployment.
No question, Alex.
Brandy Unicraft on your infrastructure provider, for instance, AWS, Google Cloud, et cetera,
and automatically packaging of your applications, right, and it would love, or actually all
of us, everyone within Unicraft will love to hear also your feedback and what you think
about, you know, turning the cloud with Unicrons to the next level.
Yeah, any feedback to me, please send to Simon.
Right, and these are, again, the project resources, if you're interested, you can just scan the
QR code.
I think that's it.
Okay.
Thank you, Simon.
Right.
So we can take a couple of questions, you can also address me to address them to me.
I mean, that's a joint talk, so any, yeah, please, first here and then on the back.
Yeah, thanks a lot, both of you, for your talks.
I have a question regarding dynamically linked applications in Linux.
As far as I can see, you only use muscle, and how does this work out if my application
is linked against GDFC, and I want to run it with my loader, what do I have to do?
Because in Linux world, when I link against GDFC and I only have muscle, nothing works.
Right.
So I'm assuming you're speaking about the binary compilability mode.
In the end, what you just need to do is providing the muscle loader, if you have compiled with
your application with muscle, or the GDFC loader, and then both works.
The things in that setup in memory, there is actually two libcs, there's the libc on
the Unicraft side, and there's the libc with your application.
So that's why it works seamless, actually.
Okay, thank you.
Just to add to that, when you build your Unicernal for binary compatibility, you don't use muscle.
You can if you want.
But the app loader doesn't use muscle because the entire libc is provided by the application,
either by the application of static binary, or the application plus its libc inside the
root file system, and it's loaded from there, there's no need to have anything like that.
Yeah, please.
Yeah.
So the question is about the API.
You spoke about the POSIX API.
You also add a diagram showing a direct link to Unicernal.
So the question is, is there some variable next diagram, perhaps?
One of the next diagram.
Okay.
Is it a variable use case?
Yes.
There is a link directly from the native application to the Unicernal.
Yeah.
This is what it shows you is how the calls are going.
It can happen because some system calls don't have a provided libc wrapper.
Yeah.
It's like for that completeness, this error is here.
For instance, the futex call, if you use futex directly from your application, there
is no wrapper function in libc.
You need to do a system call directly, and you can do that by also using the syscall,
macro then, or actually, I mean, the syscall shim will replace that with a direct function
call then to actually POSIX futex.
So is it valuable to have a kind of application that you develop specially for Unicernal and
the native API?
Yes.
That for sure.
In this talk, it's just about how we get application compatibility, even in case you
have your application already.
But if you write it anyway from scratch, I recommend forget everything about POSIX and
speak the native APIs.
You get much more performance and more directly connected to your driver layers and APIs that,
you know, POSIX has some implications, right?
There's a lot of things like read, write, imply there's a mem copy happening.
And with these lower level APIs, you can do way quicker transfers, just because you can
do a zero copy.
For instance.
Maybe even POSIX can be improved using POSIX.
Yeah, sure.
Of course.
Yeah.
Have you looked into patching the binary to remove the syscall overhead?
Patching the binary to remove?
For example, now with the syscalls, do you have to emulate the syscalls?
Have you looked into patching the binary itself?
Yeah.
Instead of doing it at runtime, handling the syscalls at runtime?
Yeah.
Let's say at least we thought about that, but we didn't do it.
I mean, the hardware talks, that is the other, exactly.
He's sitting in front of it.
They were doing some experiments with that, that works too, so you can patch it.
But yeah, I mean, just we didn't do it.
Okay.
In regards to memory usage, obviously Unicernel lowers it, but what if I ran multiple Unicernels
and multiple VMs, how do you support membalooning or something like that, or is it like just
over provision?
Yeah.
I mean, the idea is to have membalooning, but it's not upstream yet.
Of course.
There's also a really interesting research project, maybe I should mention, that works
on memory duplication.
So if you run the same Unicernel, the same like 100 times, you can share VM memory pages
on the hypervisor side, but you need hypervisor support for that.
Okay.
Thank you so much, Simon.
Let's end it here.
Yeah.
We're going to ask.
Yeah.
And get some speakers.
Anastasis and Babis for the next talk on VXL, so please.
So please get some stickers.
Yeah.
Stickers.
They are free.
Don't have to pay for it.
For now.
VXL 100 Euro each.